diff --git a/assets/css/about.css b/assets/css/about.css new file mode 100644 index 00000000..6ebf1129 --- /dev/null +++ b/assets/css/about.css @@ -0,0 +1,410 @@ +#dup-admin-about{ + margin-top: 20px; +} + +#dup-admin-about *, +#dup-admin-about *::before, +#dup-admin-about *::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +#dup-admin-about .dup-admin-about-section { + margin-bottom: 20px; + padding: 30px; + background: #ffffff; + border: 1px solid #dddddd; + line-height: 2; +} + +#dup-admin-about .dup-admin-about-section h1, +#dup-admin-about .dup-admin-about-section h2, +#dup-admin-about .dup-admin-about-section h3, +#dup-admin-about .dup-admin-about-section h4, +#dup-admin-about .dup-admin-about-section h5 { + margin-top: 0; + padding-top: 0; + line-height: 1.6; +} + +#dup-admin-about .dup-admin-about-section h2 { + font-size: 24px; +} + +#dup-admin-about .dup-admin-about-section h3 { + font-size: 18px; + margin-bottom: 30px; + color: #23282c; +} + +#dup-admin-about .dup-admin-about-section ul, +#dup-admin-about .dup-admin-about-section p { + font-size: 16px; +} + +#dup-admin-about .dup-admin-about-section p { + margin-bottom: 20px; +} + +#dup-admin-about .dup-admin-about-section p.bigger { + font-size: 18px; +} + +#dup-admin-about .dup-admin-about-section p.smaller { + font-size: 14px; +} + +#dup-admin-about .dup-admin-about-section p:last-child { + margin-bottom: 0; +} + +#dup-admin-about .dup-admin-about-section hr { + margin: 30px 0; +} + +#dup-admin-about .dup-admin-about-section figure { + margin: 0; +} + +#dup-admin-about .dup-admin-about-section figure img { + width: 100%; +} + +#dup-admin-about .dup-admin-about-section figure figcaption { + font-size: 14px; + color: #888888; + margin-top: 5px; + text-align: center; + line-height: initial; +} + +#dup-admin-about .dup-admin-about-section .dup-admin-column-40 { + padding-left: 15px; +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section .dup-admin-column-40 { + width: 100%; + padding-left: 0; + padding-top: 20px; + } +} + +#dup-admin-about .dup-admin-about-section .dup-admin-column-60 { + padding-right: 15px; +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section .dup-admin-column-60 { + width: 100%; + padding-right: 0; + } +} + +#dup-admin-about .dup-admin-about-section ul.list-plain { + margin-top: 0; + margin-bottom: 0; +} + +#dup-admin-about .dup-admin-about-section ul.list-plain li { + margin-bottom: 0; +} + +#dup-admin-about .dup-admin-about-section ul.list-features li .fa { + color: #2a9b39; + margin: 0 8px 0 0; +} + +#dup-admin-about .dup-admin-about-section .fa-star { + color: gold; +} + +#dup-admin-about .dup-admin-about-section .no-margin { + margin: 0 !important; +} + +#dup-admin-about .dup-admin-about-section .no-padding { + padding: 0 !important; +} + +#dup-admin-about .dup-admin-about-section .centered { + text-align: center !important; +} + +#dup-admin-about .dup-admin-about-section-first-form { + display: flex; +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section-first-form { + display: block !important; + } +} + +#dup-admin-about .dup-admin-about-section-first-form .dup-admin-about-section-first-form-text { + flex: 1; + padding-right: 30px; +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section-first-form .dup-admin-about-section-first-form-text { + flex: none; + } +} + +#dup-admin-about .dup-admin-about-section-first-form .dup-admin-about-section-first-form-video iframe { + border: 1px solid #dddddd; +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section-first-form .dup-admin-about-section-first-form-video { + padding-top: 20px; + } +} + +#dup-admin-about .dup-admin-about-section-hero { + padding: 0; +} + +#dup-admin-about .dup-admin-about-section-hero .dup-admin-about-section-hero-main, +#dup-admin-about .dup-admin-about-section-hero .dup-admin-about-section-hero-extra { + padding: 30px; +} + +#dup-admin-about .dup-admin-about-section-features { + display: flex; + flex-direction: row; + align-items: start; + justify-content: left; +} + +#dup-admin-about .dup-admin-about-section-features .list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + color: #555; + font-size: 14px; + list-style: none; + margin: 0; +} + +#dup-admin-about .dup-admin-about-section-features .list > .item { + flex: 33.33% 0; + box-sizing: border-box; + padding: 0 0 2px 0; +} + +#dup-admin-about .dup-admin-about-section-features .list > .item span::before { + font-family: "Font Awesome 5 Free"; + content: "\f00c"; + color: #00a32a; + margin: 0 8px 0 0; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + font-weight: 900; +} + +@media (max-width: 1000px) { + #dup-admin-about .dup-admin-about-section-features .list > .item { + flex: 50% 0; + } +} + +@media (max-width: 600px) { + #dup-admin-about .dup-admin-about-section-features .list > .item { + flex: 100% 0; + } +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section-hero .dup-admin-about-section-hero-extra .dup-admin-column-50 { + float: none; + width: 100%; + } +} + +#dup-admin-about .dup-admin-about-section-hero .dup-admin-about-section-hero-main { + background-color: #fafafa; + border-bottom: 1px solid #dddddd; +} + +#dup-admin-about .dup-admin-about-section-hero .dup-admin-about-section-hero-main.no-border { + border-bottom: 0; +} + +#dup-admin-about .dup-admin-about-section-hero .dup-admin-about-section-hero-main p { + color: #666; +} + +#dup-admin-about .dup-admin-about-section-hero h3.call-to-action { + margin-bottom: -10px; +} + +#dup-admin-about .dup-admin-about-section-hero span.price-20-off { + color: #6ab255; +} + +#dup-admin-about .dup-admin-about-section-squashed { + margin-bottom: 0; +} + +#dup-admin-about .dup-admin-about-section-squashed:not(:last-of-type) { + border-bottom: 0; +} + +#dup-admin-about .dup-admin-about-section-post h2 { + margin-bottom: -10px; +} + +#dup-admin-about .dup-admin-about-section-post h3 { + margin-bottom: 15px; +} + +#dup-admin-about .dup-admin-about-section-post p:last-of-type { + margin-bottom: 30px; +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-column-20 { + padding-right: 20px; + width: auto; +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-column-20 img { + width: 270px; +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section-post .dup-admin-column-20 { + width: 20%; + } + #dup-admin-about .dup-admin-about-section-post .dup-admin-column-20 img { + width: auto; + max-width: 100%; + } +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-column-80 { + padding-left: 20px; + width: calc(100% - 20px - 270px); +} + +@media (max-width: 767px) { + #dup-admin-about .dup-admin-about-section-post .dup-admin-column-80 { + width: 80%; + } +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-about-section-post-link { + padding: 10px 15px; + background-color: #df7739; + color: #fff; + border-radius: 3px; + text-decoration: none; + margin-top: 15px; + font-size: 14px; +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-about-section-post-link:hover, #dup-admin-about .dup-admin-about-section-post .dup-admin-about-section-post-link:focus { + background-color: #b85a1b; + color: #fff; +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-about-section-post-link:focus { + box-shadow: 0 0 0 1px #fff, 0 0 0 3px #b85a1b; + outline: 0; +} + +#dup-admin-about .dup-admin-about-section-post .dup-admin-about-section-post-link .fa { + color: #edba9e; + vertical-align: middle; + margin-left: 8px; +} + +#dup-admin-about .dup-admin-about-section-table table { + border-collapse: collapse; +} + +#dup-admin-about .dup-admin-about-section-table table tr td, +#dup-admin-about .dup-admin-about-section-table table tr th{ + border-bottom: 1px solid #dddddd; + border-right: 1px solid #dddddd; + padding: 30px; + vertical-align: top; +} + +#dup-admin-about .dup-admin-about-section-table table tr th { + padding: 20px; +} + +#dup-admin-about .dup-admin-about-section-table table tr td:last-of-type { + border-right: 0; +} + +#dup-admin-about .dup-admin-about-section-table table tr:last-child td { + border-bottom: none; +} + +#dup-admin-about .dup-admin-about-section-table table p { + background-repeat: no-repeat; + background-size: 15px auto; + background-position: 0 6px; + margin: 0; +} + +#dup-admin-about .dup-admin-about-section-table table p.features-full { + padding-left: 30px; + background-image: url(../img/about/icon-full.svg); +} + +#dup-admin-about .dup-admin-about-section-table table p.features-none { + padding-left: 30px; + background-image: url(../img/about/icon-none.svg); +} + +#dup-admin-about .dup-admin-about-section-table table p.features-partial { + padding-left: 30px; + background-position: -3px 0; + background-size: 23px auto; + background-image: url(../img/about/icon-partial.svg); +} + +#dup-admin-about .dup-admin-about-section-table .dup-admin-about-section-hero-main { + padding: 0; +} + +#dup-admin-about .dup-admin-about-section-table .dup-admin-about-section-hero-main h3 { + padding: 30px 30px 30px 60px; +} + +#dup-admin-about .dup-admin-about-section-table .dup-admin-about-section-hero-main .dup-admin-column-33:first-child h3 { + padding: 30px; +} + +#dup-admin-about #dup-admin-addons .addon-container { + padding: 0 10px; +} + +#dup-admin-about #dup-admin-addons .addon-item .details { + padding: 20px; +} + +#dup-admin-about #dup-admin-addons .addon-item h5 { + margin-bottom: 10px; +} + +#dup-admin-about #dup-admin-addons .addon-item img { + padding: 10px; +} + +#dup-admin-about #dup-admin-addons .addon-item img[src*="-mi"] { + padding: 13px; +} + +#dup-admin-about #dup-admin-addons .addon-item .action-button .button.disabled, #dup-admin-about #dup-admin-addons .addon-item .action-button .button.loading { + cursor: default; +} \ No newline at end of file diff --git a/assets/css/admin-notifications.css b/assets/css/admin-notifications.css new file mode 100644 index 00000000..2d47f07b --- /dev/null +++ b/assets/css/admin-notifications.css @@ -0,0 +1,212 @@ +#dup-notifications { + position: relative; + background: #ffffff 0 0 no-repeat padding-box; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + border-radius: 6px; + opacity: 1; + min-height: 48px; + margin: 10px 0 20px 0; +} + +#dup-notifications * { + box-sizing: border-box; +} + +#dup-notifications .dup-notifications-header { + display: flex; + align-items: center; + padding: 10px 16px; + border-bottom: 1px solid rgba(204, 208, 212, 0.5); +} + +#dup-notifications .dup-notifications-header .dup-notifications-bell { + position: relative; + width: 16px; + height: 20px; + top: 3px; + margin-right: 10px; +} + +#dup-notifications .dup-notifications-header .dup-notifications-circle { + position: absolute; + width: 11px; + height: 11px; + border-radius: 50%; + top: -4px; + right: -1px; + border: 2px solid #ffffff; +} + +#dup-notifications .dup-notifications-header .dup-notifications-title { + font-style: normal; + font-weight: 500; + font-size: 14px; + line-height: 17px; + color: #23282d; +} + +#dup-notifications .dup-notifications-body { + position: relative; +} + +#dup-notifications .dup-notifications-messages { + padding: 16px 100px 16px 16px; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-message { + display: none; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-message.current { + display: block; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-title { + color: #444444; + font-size: 17px; + font-weight: 600; + line-height: 17px; + margin: 0 0 -2px 0; + min-height: 19px; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-content { + font-weight: normal; + font-size: 14px; + line-height: 18px; + margin: 8px 0 20px 0; + color: #777777; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-content p { + font-size: inherit; + line-height: inherit; + margin: 0 0 5px; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-buttons { + margin: -30px 80px 0 0; +} + +#dup-notifications .dup-notifications-messages .dup-notifications-buttons a { + margin: 0 10px 0 0; + min-height: unset; +} + +#dup-notifications .dup-notifications-badge { + background-color: #f6f7f7; + border-radius: 3px; + color: #2c3338; + cursor: pointer; + font-size: 11px; + margin-left: 10px; + padding: 6px 8px; + position: relative; + text-decoration: none; + text-transform: uppercase; + top: -1px; + white-space: nowrap; +} + +#dup-notifications .dup-notifications-badge:focus, #dup-notifications .dup-notifications-badge:hover { + background-color: #f0f0f1; + box-shadow: none; + color: initial; +} + +#dup-notifications .dup-notifications-badge .fa { + color: black; + padding-right: 6px; + position: relative; +} + +#dup-notifications .dismiss { + position: absolute; + top: 15px; + right: 16px; + width: 16px; + height: 16px; + color: #a7aaad; + font-size: 16px; + cursor: pointer; + text-align: center; + vertical-align: middle; + line-height: 16px; +} + +#dup-notifications .dismiss:hover { + color: #dc3232; +} + +#dup-notifications .navigation { + position: absolute; + bottom: 20px; + right: 16px; + width: 63px; + height: 30px; +} + +#dup-notifications .navigation a { + display: block; + width: 30px; + height: 30px; + border: 1px solid #7e8993; + border-radius: 3px; + font-size: 16px; + line-height: 1.625; + text-align: center; + cursor: pointer; + background-color: #ffffff; + color: #41454a; +} + +#dup-notifications .navigation a:hover { + background-color: #f1f1f1; +} + +#dup-notifications .navigation .prev { + float: left; +} + +#dup-notifications .navigation .next { + float: right; +} + +#dup-notifications .navigation .disabled { + border-color: #dddddd; + color: #a0a5aa; + cursor: default; +} + +#dup-notifications .navigation .disabled:hover { + background-color: #ffffff; +} + +.lity-iframe .lity-content { + margin: 0 auto; +} + +@media screen and (max-width: 768px) { + #dup-notifications .dup-notifications-messages { + padding: 15px 50px 20px 16px; + } + #dup-notifications .dup-notifications-messages .dup-notifications-message .dup-notifications-title { + line-height: 22px; + margin: 0 30px -2px 0; + min-height: 24px; + } + #dup-notifications .dup-notifications-messages .dup-notifications-message .dup-notifications-content { + font-size: 16px; + line-height: 22px; + } + #dup-notifications .dup-notifications-messages .dup-notifications-message .dup-notifications-buttons { + margin: -30px 80px 0 0; + } + #dup-notifications .dup-notifications-messages .dup-notifications-message .dup-notifications-buttons a { + margin: 0; + display: table; + } + #dup-notifications .dup-notifications-messages .dup-notifications-message .dup-notifications-buttons .button-secondary { + margin-top: 6px; + } +} diff --git a/assets/css/font-awesome.min.css b/assets/css/font-awesome.min.css deleted file mode 100644 index 24fcc04c..00000000 --- a/assets/css/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} \ No newline at end of file diff --git a/assets/css/fontawesome-all.min.css b/assets/css/fontawesome-all.min.css new file mode 100644 index 00000000..e69f4d1d --- /dev/null +++ b/assets/css/fontawesome-all.min.css @@ -0,0 +1 @@ +.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/assets/css/global_admin_style.css b/assets/css/global_admin_style.css new file mode 100644 index 00000000..fa46cb67 --- /dev/null +++ b/assets/css/global_admin_style.css @@ -0,0 +1,156 @@ +/* ================================================ + * DUPLICATOR STYLE + * Included in all admin pages + * ================================================ */ + +.no_display { + display: none; +} + +.dup-updated, +.dup-notice-success { + margin-left: 0; + background: #fff; + border-left: 4px solid #fff; + box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 ); + margin: 5px 15px 2px 2px; + padding: 1px 12px; +} + +.dup-notice-success { + border-left-color: #46b450; +} + +.dup-updated p { + margin: 0.5em 0; + padding: 2px; +} + +.dup-updated a { + padding-bottom: 2px; +} + +.dup-updated { + border-left-color: #46b450; +} + +.wrap .dup-updated { + margin: 5px 0 15px; + margin: 20px 0 10px 0; + padding: 5px 10px; + font-size: 14px; + line-height: 175%; +} + +.duplicator-plugin-activation-admin-notice { + display: block; +} + +.dup-plugins-list-pro-upgrade { + color: #1da867!important; +} + +.dup-dashboard-widget-content .maroon { + color: maroon; +} + +.dup-dashboard-widget-content .green { + color: #00a32a; +} + +.dup-dashboard-widget-content .gary { + color: #646970; +} + +.dup-dashboard-widget-content a.disabled { + pointer-events: none; + cursor: default; +} + +.dup-dashboard-widget-content .separator { + margin: 1em 0; +} + +.dup-dashboard-widget-content .dup-packages-counts { + text-align: right; +} + +.dup-dashboard-widget-content .dup-section-last-packages ul, +.dup-dashboard-widget-content .dup-section-sections ul { + list-style: none; + padding: 0; + margin: 0; +} + +.dup-dashboard-widget-content .dup-section-last-packages ul li, +.dup-dashboard-widget-content .dup-section-sections ul li { + margin: 0 0 10px 0; +} + +.dup-dashboard-widget-content .dup-section-last-packages ul li:last-child, +.dup-dashboard-widget-content .dup-section-sections ul li:last-child { + margin: 0; +} + +.dup-dashboard-widget-content .dup-section-label-fixed-width { + display: inline-block; + min-width: 120px; +} + +.dup-dashboard-widget-content .dup-section-sections .dashicons { + margin-right: 5px; +} + +.dup-dashboard-widget-content .dup-section-sections .dashicons-image-rotate { + font-size: 16px; +} + +.dup-dashboard-widget-content .spinner { + float: none; + visibility: visible; + margin: 0; +} + +.dup-dashboard-widget-content .dup-section-recommended { + line-height: 20px; +} + +.dup-dashboard-widget-content .dup-section-recommended .action-links a:after { + content: "|"; + cursor: not-allowed; + margin: 0 5px; + color: #646970; +} + +.dup-dashboard-widget-content .dup-section-recommended .action-links a:last-child:after { + content: ""; + margin: 0; +} + +.dup-dashboard-widget-content .dup-recommended-label { + color: #787c82; +} + +.dup-dashboard-widget-content #dup-dash-widget-section-recommended { + margin: 0; + padding: 0; + border: 0 none; + background: transparent; + color: #787c82; + cursor: pointer; +} + +.dup-dashboard-widget-content .dup-flex-content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.dup-dashboard-widget-content .dup-flex-content > * { + padding-right: 5px; +} + +.dup-dashboard-widget-content .dup-flex-content > *:last-child { + padding-right: 0; +} + diff --git a/assets/css/images/index.php b/assets/css/images/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/assets/css/images/index.php @@ -0,0 +1,3 @@ + div { + float: left; + padding:10px 0 15px 0; + font-size: 16px; + border-bottom: 2px solid transparent; + min-width: 250px; + text-align: center; + cursor: pointer; +} + +#dup-pro-import-mode-tab-header > div.active { + border-bottom: 3px solid #91BCE3; + font-weight: bold; +} + +.dup-pro-import-upload-box > div { + width: 100%; +} + +.dup-pro-import-upload-box .dup-import-button { + display: inline-block; + padding: 0 30px !important; + font-weight: normal; + box-sizing: border-box; + height: 40px; +} + +table.dup-import-avail-packs th { + background-color: #e2e2e2; +} + +table.dup-import-avail-packs tbody tr:nth-child(even) { + border: 1px solid #e2e2e2; +} + +table.dup-import-avail-packs { + width: 100%; + min-height: inherit; + border: 1px solid #ccd0d4; + border-collapse: collapse; +} + +table.dup-import-avail-packs thead { + border-bottom: 1px solid #ccd0d4; +} + +table.dup-import-avail-packs th { + font-weight: bold; +} + +table.dup-import-avail-packs th, +table.dup-import-avail-packs td { + padding: 10px; + text-align: left; + vertical-align: top; + line-height: 30px; +} + +table.dup-import-avail-packs .size { + width: 100px; +} + +table.dup-import-avail-packs .created { + text-align: left; + width: 125px; +} + +table.dup-import-avail-packs .funcs { + text-align: center; + width: 400px; + box-sizing: border-box; + white-space: nowrap; +} + +table.dup-import-avail-packs .funcs button, +table.dup-import-avail-packs .funcs .button { + min-width: 120px; +} + +table.dup-import-avail-packs .funcs .separator { + margin-left: 5px; +} + +table.dup-import-avail-packs .funcs div.actions { + text-align: right; +} + +div#dpro-pro-import-available-packages { + background-color: #fff; +} + +@media only screen and (max-width: 1200px) { + #dpro-pro-import-available-packages.view-list-item .size, + #dpro-pro-import-available-packages.view-list-item .created, + #dpro-pro-import-available-packages.view-list-item thead .funcs { + display: none; + } + + #dpro-pro-import-available-packages.view-list-item td { + display: block; + text-align: left !important; + padding: 0 20px; + } + + #dpro-pro-import-available-packages.view-list-item tbody tr { + border-bottom: 1px solid #ccd0d4; + padding-bottom: 10px; + display: block; + } +} + +.fs-upload-input{ + position:absolute; + top:0; + right:0; + bottom:0; + left:0; + z-index:-1; + opacity:0; + pointer-events:none +} + +.margin-bottom-2 { + margin-bottom: 40px; +} + +/* IMPORT MOCK STYLE */ + +.dup-pro-recovery-widget-wrapper { + font-size: 14px; +} + +.dup-pro-recovery-widget-wrapper .button { + margin-left: 10px; + min-width: 150px; + text-align: center; +} + +.dup-pro-recovery-details-max-width-wrapper { + max-width: 900px; +} + +.dup-pro-recovery-point-selector .recovery-select { + width: 100%; + max-width: 100%; + box-sizing: border-box; + margin: 0 0 10px 0; +} + +.dup-pro-recovery-point-selector-area-wrapper { + margin-bottom: 20px; +} + +.dup-pro-recovery-widget-wrapper label { + margin-bottom: 5px; + display: block; +} + +.dup-pro-recovery-point-selector-area-wrapper .dup-pro-opening-packages-windows { + float: right; +} + +.dup-pro-recovery-point-selector-area { + text-align: right; +} + +.dup-pro-recovery-package-detail-content { + margin-top: 30px; +} + +.dup-pro-recovery-package-small-icon i { + font-size: 14px; + position: relative; +} + +.dup-pro-recovery-package-info table { + border-collapse: collapse; +} + +.dup-pro-recovery-package-info table td { + padding: 0 5px 5px 0; +} + +.dup-pro-recovery-active-link-header > .main-icon { + display: inline-block; + width: 30px; + height: 30px; + color: #000; + text-align: center; + line-height: 30px; + font-size: 23px; + margin-right: 10px; +} + +.dup-pro-recovery-active-link-header > .main-title { + font-size: 16px; + line-height: 1; + font-weight: bold; +} + +.dup-pro-recovery-active-link-header > .main-subtitle { + font-style: italic; + font-size: 12px; + margin-top: 2px; +} + +.dup-pro-recovery-point-actions > .copy-link { + position: relative; + white-space: nowrap; + box-sizing: border-box; + border: 1px solid silver; + height: 30px; + line-height: 30px; + background: #fff; + color: #000; + padding: 0 35px 0 5px; + border-radius: 2px; +} + +.dup-pro-recovery-point-actions > .copy-link .content { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; +} + +.dup-pro-recovery-point-actions > .copy-link .copy-icon { + position: absolute; + right: -1px; + top: -1px; + width: 30px; + line-height: 30px; + text-align: center; + color: white; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + background-color: silver; +} + +.dup-pro-recovery-point-actions > .dup-pro-recovery-buttons { + margin-top: 10px; + text-align: right; +} + +.dup-pro-recovery-details-max-width-wrapper .dup-pro-recovery-buttons { + text-align: right; +} + +.toplevel_page_duplicator-pro .dup-pro-opening-packages-windows { + display: none; +} + +/* SCHEDULES MOCK STYLE */ + +table.schedule-tbl tr:nth-child(odd), +table.storage-tbl tr:nth-child(odd) { + background-color: #f6f7f7; +} + +table.schedule-tbl td { + height: 45px +} + +table.schedule-tbl a.name { + font-weight: bold +} + +table.schedule-tbl input[type='checkbox'] { + margin-left: 5px +} + +table.schedule-tbl div.sub-menu { + margin: 5px 0 0 2px; + display: none +} + +table.schedule-tbl div.sub-menu a:hover { + text-decoration: underline +} + +tr.schedule-detail td { + padding: 2px 2px 2px 15px; + margin: -5px 0 2px 0; + height: 22px +} + +.dpro-edit-toolbar { + margin: 15px 0 5px 0; + width: 100%; +} + +.dpro-edit-toolbar .btnnav { + float: right; +} + +/* SCHEDULES MOCK STYLE */ + +.dup-template-list-tbl td { + height: 45px +} + +.dup-template-list-tbl a.name { + font-weight: bold +} + +.dup-template-list-tbl input[type='checkbox'] { + margin-left: 5px +} + +.dup-template-list-tbl tr.package-detail td { + padding: 2px 2px 2px 15px; + margin: -5px 0 2px 0; + height: 22px +} + +.dup-template-list-tbl .col-check { + width: 10px; +} + +.dup-template-list-tbl .col-name { + width: 425px; + overflow-wrap: break-word; + word-break: break-all; +} + +.dup-template-list-tbl .col-empty { + width: 25px; +} + +/* TRANSFER TAB */ + +h3 { + margin: 10px 0 5px 5px +} + +h2.title { + font-size: 18px +} + +div.transfer-panel { + padding: 5px 5px 10px 10px; +} + +div.transfer-hdr { + margin: 0 0 20px 0 +} + +div.transfer-hdr hr { + margin: -10px 0 0 0 +} + +div#step2-section { + margin: 5px 0 40px 0 +} + +div#location-quick-opts input[type=text] { + width: 300px +} + +div.dup-box-title { + font-size: 15px +} + +div.dpro-progress-bar-container { + margin: 0 auto 10px auto; + text-align: center; +} + +div#step3-section { + margin: 65px 0 0 0 +} + +div#dpro-progress-bar-area { + width: 300px; + margin: 5px auto 0 auto; + ext-align: center +} + +div.dpro-active-status-area { + display: none; +} + +tr.dup-choose-loc-new-pack td { + text-align: right; + padding: 5px 15px 5px 5px; + border-top: 1px solid #c3c4c7 +} + +button#dup-pro-transfer-btn { + float: right; + margin: -20px 15px 0 0; + font-size: 14px; + padding: 2px 20px 2px 20px; + font-size: 14px +} + +#dup-pro-stop-transfer-btn { + margin-top: 10px; +} + +button.dpro-btn-stop { + width: 150px !important +} + +tr.status-pending td { + font-style: italic; + color: #999 +} + +tr.status-running td { + font-style: italic; + color: green +} + +tr.status-failed td { + color: maroon +} + +tr.status-normal td { + color: #000 +} + +table.package-tbl tfoot td { + font-size: 12px; + text-align: right +} + +/* STATIC POPUP STYLE */ + +.static-popup { + text-align: center; + width: 730px; + box-shadow: 0 0 60px 30px rgba(0, 0, 0, 0.15); + border-radius: 6px; + position: fixed; + top: calc(50% + 16px); + left: calc(50% + 80px); + z-index: 100; + overflow: hidden; + transform: translate(-50%, -50%); +} + +.static-popup *, +.static-popup *::before, +.static-popup *::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.static-popup h2 { + font-size: 20px; + margin: 0 0 16px 0; + padding: 0; +} + +.static-popup p { + font-size: 16px; + line-height: 24px; + color: #777777; + margin: 0 0 30px 0; + padding: 0; +} + +.static-popup p:last-of-type { + margin: 20px 0; +} + +.static-popup-content-top-notice { + padding: 10px; + text-align: center; + font-style: normal; + font-weight: normal; + font-size: 15px; + line-height: 24px; + color: #444444; + background: #fcf9e8; +} + +.static-popup-content-top-notice .fa-exclamation-triangle { + margin-right: 10px; + color: #e27730; + font-size: 16px; +} + +.static-popup-content { + background-color: #ffffff; + border-radius: 3px 3px 0 0; + padding: 40px 40px 20px; +} + +.static-popup ul { + float: left; + width: 50%; + margin: 0; + padding: 0 0 0 30px; + text-align: left; +} + +.static-popup li { + color: #777777; + font-size: 16px; + line-height: 19px; + padding: 6px 0; +} + +.static-popup li .fa { + color: #2a9b39; + margin: 0 8px 0 0; +} + +.static-popup-button { + border-radius: 0 0 3px 3px; + padding: 30px; + background: #f5f5f5; + text-align: center; +} + +.static-popup-button p { + margin: 20px 0 0 0; + font-size: 15px; + line-height: 18px; + text-align: center; +} + +.static-popup-button p span { + display: inline-block; + margin-left: 20px; + vertical-align: bottom; + font-size: 14px; + line-height: 17px; +} + +/* Settings > Access tab */ +.mock-select2 { + width: 500px; + background: white; + border-radius: 3px; + min-height: 50px; + padding: 3px 5px; + border: 1px solid gray; + font-size: 14px; +} + + +.access-mock .form-table th { + width: 250px; +} + +.access-mock .form-table th i{ + color: #888888; +} + +.mock-select2 .select2-option { + float: left; + background: #e4e4e4; + background-color: #e4e4e4; + border: 1px solid #aaa; + border-radius: 4px; + cursor: default; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; +} + +.mock-select2 .select2-option::before { + content: "×"; + color: #999; + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; +} diff --git a/assets/css/modal.css b/assets/css/modal.css new file mode 100644 index 00000000..9e66e015 --- /dev/null +++ b/assets/css/modal.css @@ -0,0 +1,132 @@ +.duplicator-modal { + position: fixed; + overflow: auto; + height: 100%; + width: 100%; + top: 0; + z-index: 100000; + display: none; + background: rgba(0, 0, 0, 0.6); +} +.duplicator-modal.active { + display: block; +} +.duplicator-modal.active:before { + display: block; +} +.duplicator-modal a[disabled] { pointer-events: none; } + +.duplicator-modal .duplicator-modal-dialog { + background: transparent; + position: absolute; + left: 50%; + margin-left: -298px; + padding-bottom: 30px; + top: -100%; + z-index: 100001; + width: 596px; +} +.duplicator-modal.active .duplicator-modal-dialog { + top: 10%; +} +.duplicator-modal .duplicator-modal-body, +.duplicator-modal .duplicator-modal-footer { + border: 0; + background: #fff; + padding: 15px; +} +.duplicator-modal .duplicator-modal-body { + border-bottom: 0; +} +.duplicator-modal .duplicator-modal-body p { + font-size: 1.3em; +} +.duplicator-modal .duplicator-modal-body h2 { + font-size: 1.6em; + font-weight: bold; + margin-top: 0; +} +.duplicator-modal .duplicator-modal-footer { + border-top: #eeeeee solid 1px; + text-align: right; +} +.duplicator-modal .duplicator-modal-footer .duplicator-modal-button-deactivate { + min-width: 124px; + text-align: center; +} +.duplicator-modal .duplicator-modal-footer .button { + margin: 0 5px; +} +.duplicator-modal .duplicator-modal-footer .button:last-child { + margin-right: 0; +} +.duplicator-modal .duplicator-modal-panel>.notice.inline { + margin: 0; + display: none; +} +.duplicator-modal .duplicator-modal-panel:not(.active) { + display: none; +} +body.has-duplicator-modal { + overflow: hidden; +} +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-reason-input, +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-internal-message { + margin: 3px 0 3px 22px; background-color:#e0f3e8; +} +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-reason-input input, +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-reason-input textarea, +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-internal-message input, +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-internal-message textarea { + width: 100%; +} +.duplicator-modal.duplicator-modal-deactivation-feedback li.duplicator-modal-reason.has-internal-message .duplicator-modal-internal-message { + border: 1px solid #ccc; + padding: 7px; + display: none; +} +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-anonymous-label { + padding-top: 15px; +} +.duplicator-modal.duplicator-modal-deactivation-feedback .duplicator-modal-panel { + margin-top: 0 !important; +} + +.duplicator-modal .duplicator-modal-resp-msg { + font-size: 11px; + font-weight: bold; + margin-top: 10px; + display: block; +} + +.duplicator-modal .duplicator-modal-button-skip, .duplicator-modal .duplicator-modal-resp-msg { + /*display: none;*/ +} + + +@media (max-width: 650px) { + .duplicator-modal .duplicator-modal-dialog { + margin-left: -50%; + box-sizing: border-box; + padding-left: 10px; + padding-right: 10px; + width: 100%; + } + .duplicator-modal .duplicator-modal-dialog .duplicator-modal-panel>h3>strong { + font-size: 1.3em; + } + .duplicator-modal.duplicator-modal-deactivation-feedback li.duplicator-modal-reason li.duplicator-modal-reason { + margin-bottom: 10px; + } + .duplicator-modal.duplicator-modal-deactivation-feedback li.duplicator-modal-reason li.duplicator-modal-reason .duplicator-modal-reason-input, + .duplicator-modal.duplicator-modal-deactivation-feedback li.duplicator-modal-reason li.duplicator-modal-reason .duplicator-modal-internal-message { + margin-left: 29px; + } + .duplicator-modal.duplicator-modal-deactivation-feedback li.duplicator-modal-reason li.duplicator-modal-reason label { + display: table; + } + .duplicator-modal.duplicator-modal-deactivation-feedback li.duplicator-modal-reason li.duplicator-modal-reason label>span { + display: table-cell; + font-size: 1.3em; + } +} \ No newline at end of file diff --git a/assets/css/parsley.css b/assets/css/parsley.css new file mode 100644 index 00000000..e30094ca --- /dev/null +++ b/assets/css/parsley.css @@ -0,0 +1,37 @@ +div.parsley-success, +input.parsley-success, +select.parsley-success, +textarea.parsley-success { + color: #468847; + background-color: #DFF0D8; + border: 1px solid #D6E9C6; +} + +div.parsley-error, +input.parsley-error, +select.parsley-error, +textarea.parsley-error { + color: #B94A48; + background-color: #F2DEDE; + border: 1px solid #EED3D7; +} + +.parsley-errors-list { + margin: 2px 0 3px; + padding: 0; + list-style-type: none; + font-size: 0.9em; + line-height: 0.9em; + opacity: 0; + -moz-opacity: 0; + -webkit-opacity: 0; + + transition: all .3s ease-in; + -o-transition: all .3s ease-in; + -moz-transition: all .3s ease-in; + -webkit-transition: all .3s ease-in; +} + +.parsley-errors-list.filled { + opacity: 1; +} diff --git a/assets/css/style.css b/assets/css/style.css index dc79b107..95a59484 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -1,67 +1,1257 @@ -/* ================================================ - * DUPLICATOR STYLE - * Common elements shared across the duplicator plugin - * Copyright:lifeinthegrid.com 2011-2014 - * ================================================ */ - -/*Global Elements*/ -input[type=button]{cursor:pointer;padding:5px;cursor:pointer;} -input[type=submit]{cursor:pointer;padding:5px;cursor:pointer;} -fieldset {border:1px solid gray; padding:0px 5px 5px 5px; } -label {font-size:13px} -.no-select {user-select:none; -o-user-select:none; -moz-user-select:none; -khtml-user-select:none; -webkit-user-select:none;} -hr {border: 0; border-top: 1px solid #ddd; border-bottom: 1px solid #fafafa; margin: 10px 0px 2px 0px;} - -/* HEADER BAR */ -div.dup-header {padding:0px 0px 0px 0px; margin:0px 0px 7px 0px;} -div.dup-header input {border:1px solid silver; border-radius:4px} -div.dup-header input:hover {border:1px solid black;} - -/*BOXES: Expandable sections */ -div.dup-box {padding:0px; display: block; background-color: #fff; border: 1px solid #e5e5e5; box-shadow: 0 1px 1px rgba(0,0,0,.04);} -div.dup-box-title {font-size: 14px; padding: 10px 0px 0px 15px; font-weight: bold; cursor: pointer; height:28px; margin:0px; } -div.dup-box-title:hover {background-color: #FCFCFC;} -div.dup-box-arrow {text-decoration:none!important; float:right; width:27px; height:30px; font-size:16px; cursor:pointer; padding:1px 0px 0px 0px; white-space: nowrap} -div.dup-box-panel {padding:10px 15px 10px 15px; border-top:1px solid #EEEEEE; margin:-1px 0px 0px 0px;} - -/*PANELS: Boxes that do not exapand */ -div.dup-panel {padding:0px; display: block; background-color: #fff; border: 1px solid #e5e5e5; box-shadow: 0 1px 1px rgba(0,0,0,.04);} -div.dup-panel-title {font-size: 14px; padding: 10px 0px 0px 15px; font-weight: 600; height:28px; margin:0px; } -div.dup-panel-panel {padding:10px 15px 10px 15px; border-top:1px solid #EEEEEE; margin:-1px 0px 0px 0px;} - -/*PANELS: Fancy */ -div.dup-box-title-fancy { - border-color: #DFDFDF; - background: #eeeeee; - background: -moz-linear-gradient(top, #eeeeee 0%, #e0e0e0 100%); - background: -ms-linear-gradient(top, #eeeeee 0%,#e0e0e0 100%); - background: linear-gradient(to bottom, #eeeeee 0%,#e0e0e0 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#e0e0e0',GradientType=0 ); -} - -/*INFO-BOX: Simple box with no title */ -div.dup-info-box {padding:8px; border:1px solid #ccc; border-radius:4px; background-color:#F7FCFE; margin: 0px 0px 5px 20px; line-height:16px} -div.dup-info-box small {margin-top:10px; display:block} - -/*PACKAGE: Progress Boxes */ -div#dup-progress-bar-area {width:500px; margin:40px auto 0px auto; padding:25px 50px 35px 50px; border:1px solid #ccc; box-shadow:0 8px 6px -6px #999; text-align:center; border-radius:4px;} -div#dup-progress-bar-area h2 {margin-bottom: 15px} - -/*HEADER MESSAGES*/ -div.dup-hdr-success {color:#196512; font-size: 20px; font-weight: bold} -div.dup-hdr-error {color:#A62426; font-size: 20px; font-weight: bold} - -/*================================================ -JQUERY UI:Overrides */ -.ui-tabs-hide {display:none !important} /*fix for WP 3.5 setting */ - -/*================================================ -PARSLEY:Overrides*/ -input.parsley-error, textarea.parsley-error { - color:#B94A48 !important; - background-color:#F2DEDE !important; - border:1px solid #EED3D7 !important; -} -ul.parsley-error-list {margin:1px 0px -7px 0px} - - +/* ================================================ + * DUPLICATOR STYLE + * Common elements shared across the duplicator plugin + * ================================================ */ + +/*Global Elements*/ +.duplicator-pages #wpcontent{padding-left: 0px; position: relative;} +.duplicator-pages #wpbody{padding-left: 20px;} +input[type=button]{cursor:pointer;padding:5px;cursor:pointer;} +input[type=submit]{cursor:pointer;padding:5px;cursor:pointer;} +fieldset {border:1px solid gray; padding:0px 5px 5px 5px; } +label {font-size:13px} +.no-select {user-select:none; -o-user-select:none; -moz-user-select:none; -khtml-user-select:none; -webkit-user-select:none;} +hr {border:0; border-top:1px solid #cecece; border-bottom:1px solid #fafafa; margin:10px 0px 10px 0px;} +i[data-tooltip].fa-question-circle {cursor:pointer; color:#C3C3C3} +i[data-tooltip].fa-lightbulb-o {cursor:pointer; color:gray} +span.btn-separator {content:''; display:inline-block; background:silver; margin:2px 3px; height:25px; width:1px; vertical-align:top;} +a.grey-icon i.fa {color:#777} +i.grey-icon {color:#777} +.maroon {color:maroon} + +.no-display {display:none !important;} +.link-style {color:#0074ab; cursor:pointer; text-decoration:underline;} +.link-style:hover {color:#00a0d2;} +.no-decoration {text-decoration:none;} +p.description {padding-top:3px} +.dup-guide-txt-color {color:#b0b0b0;} +i.shield-on {color:#337114} +i.shield-off {color:maroon} +.green {color: #008000;} +.red {color: #DB4B38;} +ul.dup-pro-simple-style-disc {list-style: disc; margin-left: 20px;} + +/*TABS*/ +ul.category-tabs li { + cursor:pointer; + user-select: none; +} + +ul.category-tabs { + font-size: 14px; +} + +/*BOXES:Expandable sections */ +div.dup-box {padding:0px; display:block; background-color:#fff; border:1px solid #e5e5e5; box-shadow:0 1px 1px rgba(0,0,0,.04);} +div.dup-box-title {font-size:20px; padding:12px 0 3px 12px; font-weight:bold; cursor:pointer; height:30px; margin:0; color:#000; user-select:none; } +div.dup-box-title:hover {background-color: #f9f9f9;} +div.dup-box-arrow {text-decoration:none!important; float:right; width:27px; height:30px; font-size:16px; cursor:pointer; padding:1px 0 0 0; white-space:nowrap} +div.dup-box-panel {padding:10px 15px 10px 15px; border-top:1px solid #EEEEEE; margin:-1px 0 0 0;} +div.dup-redirect {font-size:16px; font-weight:bold; padding:10px} + +/*PANELS:Boxes that do not exapand */ +div.dup-panel {padding:0px; display:block; background-color:#fff; border:1px solid #e5e5e5; box-shadow:0 1px 1px rgba(0,0,0,.04);} +div.dup-panel-title {font-size:14px; padding:10px 0 0 15px; font-weight:600; height:28px; margin:0px; color:#000; } +div.dup-panel-panel {padding:10px 15px 10px 15px; border-top:1px solid #EEEEEE; margin:-1px 0 0 0;} + +/*INFO-BOX:Simple box with no title */ +div.dup-info-box {padding:8px; border:1px solid #ccc; border-radius:4px; background-color:#F7FCFE; margin:0px 0px 5px 20px; line-height:16px} +div.dup-info-box small {margin-top:10px; display:block} + +/*PACKAGE:Progress Boxes */ +div#dup-scan-progress-bar-wrapper, +div#dup-build-progress-bar-wrapper { + width: 700px; + margin: 40px auto 0px auto; + border: 1px solid #ccc; + box-shadow: 0 8px 6px -6px #999; + text-align: center; + border-radius: 4px; + color: #000; + overflow: hidden; +} +div#dup-progress-bar-area {padding:40px 50px;} +div#dup-progress-bar-area h2 {margin-bottom:15px} + +/*HEADER MESSAGES*/ +div.dup-hdr-success {color:#23282d; font-size:22px; font-weight:bold} +div.dup-hdr-error {color:#A62426; font-size:22px; font-weight:bold} + +/*DIALOGS:THICKBOX */ +#TB_title { padding-bottom:3px!important; margin-bottom:5px!important; font-size:16px!important;} +div.dup-dlg-alert-txt {padding:8px 0; font-size:16px; line-height:22px} +div.dup-dlg-alert-btns {position:absolute; bottom:20px; right:20px;} +div.dup-dlg-confirm-txt {padding:10px 0; font-size:16px} +div.dup-dlg-confirm-btns {position:absolute; bottom:20px; right:20px;} +div.dup-dlg-confirm-progress {display:none} + +/*ADMIN:NOTICES */ +div.dup-global-error-reserved-files p {font-size:14px} +div.dup-global-error-reserved-files b.pass-msg {color:green; font-size:20px} +div.dup-global-error-reserved-files p.pass-lnks {line-height:24px; margin:-7px 0 0 5px} +div.dup-global-error-reserved-files div.pass-msg {padding:5px 0 0 10px; font-size:11px; color:#999; font-style:italic} +div.dup-wpnotice-box {display:none;} + +.dup-migration-pass-wrapper p { + font-size: 14px; +} + +.dup-migration-pass-title { + color: green; + font-size: 20px; + margin: 10px 0; + font-weight: bold; +} + +.dup-stored-minstallation-files { + margin-left: 20px; + line-height: 1; + font-style: italic; + margin-top: 0; + font-size: 12px; +} + +.dup-migration-pass-wrapper .sub-note { + font-size: 12px; +} + +label.dup-store-lbl:hover { + color:#000; + font-weight:500; +} + +/*================================================ +PARSLEY:Overrides*/ +input.parsley-error, textarea.parsley-error { + color:#B94A48 !important; + background-color:#F2DEDE !important; + border:1px solid #EED3D7 !important; +} +div.qtip-content {line-height:16px} +ul.parsley-error-list {margin:1px 0px -7px 0px} +div.notice-safemode {color:maroon;} +div.cleanup-notice b.title {color:green;font-size:20px;} + +/*SCREEN TABS*/ +div.dup-screen-hlp-info {line-height:26px; padding:10px 0 10px 0} +#screen-meta-links .button { font-size:13px !important; height:auto !important;font-weight:normal; padding:3px 6px 3px 16px !important;min-width:72px !important} + +/*= Duplicator Message +---------------------------------------*/ +.notice.duplicator-message { + border:none; + padding:20px; +} + +.notice.duplicator-message .duplicator-message-inner { + display:-webkit-box; + display:-webkit-flex; + display:-ms-flexbox; + display:flex; + -webkit-box-align:center; + -webkit-align-items:center; + -ms-flex-align:center; + align-items:center; +} + +.notice.duplicator-message .duplicator-message-icon { + font-size:20px; +} + +.notice.duplicator-message .duplicator-message-content { + padding:0 20px; +} + +.notice.duplicator-message p { + padding:0; + margin:0; +} + +.notice.duplicator-message h3 { + margin:0 0 5px; +} + +.notice.duplicator-message .duplicator-message-action { + text-align:center; + display:-webkit-box; + display:-webkit-flex; + display:-ms-flexbox; + display:flex; + -webkit-box-orient:vertical; + -webkit-box-direction:normal; + -webkit-flex-direction:column; + -ms-flex-direction:column; + flex-direction:column; + margin-left:auto; +} + +.notice.duplicator-message .duplicator-message-action .duplicator-button { + background-color:#D30C5C; + color:#fff; + border-color:#7c1337; + -webkit-box-shadow:0 1px 0 #7c1337; + box-shadow:0 1px 0 #7c1337; + padding:5px 30px; + height:auto; + line-height:20px; + text-transform:capitalize; +} + +.notice.duplicator-message .duplicator-message-action .duplicator-button i { + margin-right:5px; +} + +.notice.duplicator-message .duplicator-message-action .duplicator-button:hover { + background-color:#a0124a; +} + +.notice.duplicator-message .duplicator-message-action .duplicator-button:active { + -webkit-box-shadow:inset 0 1px 0 #7c1337; + box-shadow:inset 0 1px 0 #7c1337; + -webkit-transform:translateY(1px); + -ms-transform:translateY(1px); + transform:translateY(1px); +} + +.notice.duplicator-message .duplicator-message-action .duplicator-link { + padding-top:5px; +} + +.notice.duplicator-message .duplicator-message-actions { + margin-top:10px; +} + +.notice.duplicator-message .duplicator-message-actions .button.button-primary { + margin-right:5px; +} + +.notice.duplicator-message-announcement { + border-color:#D30C5C; +} + +.notice.duplicator-message-announcement a { + color:#D30C5C; +} + +@media (min-width:1200px) { + .duplicator-message-action { + padding-right:10px; + } +} + +@media (max-width:600px) { + .notice.duplicator-message { + padding:20px; + } + .notice.duplicator-message .duplicator-message-inner { + display:block; + text-align:center; + } + .notice.duplicator-message .duplicator-message-inner .duplicator-message-icon, + .notice.duplicator-message .duplicator-message-inner .duplicator-message-content, + .notice.duplicator-message .duplicator-message-inner .duplicator-message-action { + display:block; + } + .notice.duplicator-message .duplicator-message-inner .duplicator-message-action { + text-align:center; + } + .notice.duplicator-message .duplicator-message-inner .duplicator-message-icon { + width:auto; + } + .notice.duplicator-message .duplicator-message-inner .duplicator-message-content { + padding:10px 0; + } +} + +/** Settings **/ +.dup-settings-pages p.description {max-width:700px; font-size:13px; color:#666; padding-left:15px; text-align:justify; } +.licenses-table .description p {margin-bottom: 15px;} +.licenses-table .description p.discount-note {font-style: italic;color: #666;} +.licenses-table .description p.discount-note strong {color: green;} +#dup-lite-inst-mode-details p { margin:1em 0; max-width:700px; font-size:13px; color:#666; padding-left:15px; text-align:justify;} +#installer-name-mode-option { + line-height:25px; +} + +#dup-lite-inst-mode-details { + display:none; + max-width:825px; + padding-left:20px; + line-height:18px; +} + + + +.storage_pos_fixed_label { + display:inline-block; + width:120px; +} + +/** Call to action **/ +div.txt-call-action-title { + margin:40px auto 20px auto; + font-size:22px; + line-height:30px; + font-weight:bold; + width:100%; +} + +div.txt-call-action-sub { + font-size:16px; line-height:24px; font-weight:bold; width:100%; + margin:20px auto 40px auto; +} + +a.dup-btn-call-action { + box-shadow:0px 10px 14px -7px #3e7327; + background:linear-gradient(to bottom, #5ca53a 5%, #72b352 100%); + background-color:#4f8e32; + border-radius:4px; + border:1px solid #4b8f29; + display:block; + cursor:pointer; + color:#ffffff; + font-family:Arial; + font-size:18px; + font-weight:bold; + padding:10px 30px; + text-decoration:none; + text-shadow:0px 1px 0px #5b8a3c; + width:150px; + margin:auto; + text-align:center; +} + +a.dup-btn-call-action:hover { + background:linear-gradient(to bottom, #72b352 5%, #337114 100%); + background-color:#337114; + color:#fff; +} + +.dup-btn-call-action:active { + color:#fff; +} + +td.dup-store-promo-area { + padding:7px 0 7px 7px; + border-top:1px solid silver; + background-color: #fcf9e8 +} + +td.dup-store-promo-area i[data-tooltip].fa-question-circle { + color: #e27730; +} + +/* Notice bar */ +#dup-notice-bar { + display: flex; + align-items: center; + justify-content: center; + background-color: #dddddd!important; + color: #777777; + text-align: center; + position: relative; + padding: 7px; + margin-bottom: -4px; + max-height: 100px; + overflow: hidden; + border-top: #fe4716 3px solid; + z-index: 999; +} + +#dup-notice-bar a { + color: #fe4716; +} + +#dup-notice-bar .dup-dismiss-button{ + position: absolute; + top: 0; + right: 0; + border: none; + padding: 5px; + margin-top: 1px; + background: 0 0; + color: #777777; + cursor: pointer; + margin-right: 10px; +} + +#dup-notice-bar .dup-dismiss-button:before { + background: 0 0; + content: "\f335"; + display: block; + font: normal 20px/20px dashicons; + height: 20px; + text-align: center; + width: 20px; + -webkit-font-smoothing: antialiased; +} + +#dup-notice-bar .dup-upgrade-arrow { + font-weight: bold; + text-decoration: none; +} + +#dup-notice-bar .dup-notice-logo { + line-height: 0; +} + +#dup-notice-bar .dup-notice-logo img { + width: 20px; + height: 20px; + margin-right: 6px; +} + +.dup-header { + border-top: 3px solid #fe4716; + padding: 20px; + padding-bottom: 0px; +} + +/* Allow screen meta to go over other content and not push it */ +#dup-meta-screen { + margin: 0; + position: absolute; + top: -1px; + left: 0px; + right: 0; + z-index: 99; +} + +#dup-notice-bar+#dup-meta-screen { + top:34px +} + +.duplicator-pages #screen-meta { + margin: 0 20px -1px 20px; + position: relative; + background-color: #fff; + border: 1px solid #c3c4c7; + border-top: none; + box-shadow: 0 0 0 transparent; +} + +#screen-meta-links .screen-meta-toggle { + position: absolute; + right: 20px; + top: auto; +} + +.duplicator-pages #screen-meta-links, +.duplicator-pages #screen-meta { + display: none; +} + +.duplicator-pages .wrap > h1 { + margin: 0; + padding: 0; +} + +.mock-blur { + filter: blur(4px); + pointer-events: none; +} + +.dup-clearfix:before { + content: " "; + display: table; +} + +.dup-clearfix:after { + clear: both; + content: " "; + display: table; +} + +/* New button designs in the red color of the logo */ +.dup-btn { + border-radius: 4px; + cursor: pointer; + display: inline-block; + margin: 0; + text-decoration: none; + text-align: center; + vertical-align: middle; + white-space: nowrap; + box-shadow: none; + border: none; +} + +.dup-btn-block { + display: block; + width: 100%; +} + +.dup-btn-lg { + font-size: 16px; + font-weight: 600; + padding: 16px 28px; +} + +.dup-btn-md { + font-size: 13px; + font-weight: 600; + padding: 8px 12px; +} + +.dup-btn-orange { + background-color: #e27730; + color: white; +} + +.dup-btn-orange:hover, +.dup-btn-orange:focus { + color: white; + background-color: #b85a1b; +} + +.dup-btn-orange:focus { + box-shadow: 0 0 0 1px #fff, 0 0 0 3px #b85a1b; +} + +.dup-btn-grey { + background-color: #eee; + border: 1px solid #ccc; + color: #666; +} + +.dup-btn-grey:hover, +.dup-btn-grey:focus { + background-color: #d7d7d7; + color: #444; +} + +.dup-btn-grey:focus { + box-shadow: 0 0 0 1px #fff, 0 0 0 3px #d7d7d7; +} + +.dup-btn-green { + background-color: #1da867; + color: white; +} + +.dup-btn-green:hover, +.dup-btn-green:focus { + color: white; + background-color: #199a5e; +} + +.dup-btn-green:focus { + box-shadow: 0 0 0 1px #fff, 0 0 0 3px #199a5e; +} + +.dup-btn-trans-green { + color: #1da867; +} + +.dup-btn-trans-green:hover, +.dup-btn-trans-green:focus { + color: white; + background-color: #1da867; +} + +.dup-btn-trans-green:focus { + box-shadow: 0 0 0 1px #fff, 0 0 0 3px #1da867; +} + +.dup-btn-trans-green .underline { + position: relative; +} + +.dup-btn-trans-green .underline:after { + content: " "; + border-bottom: 1px dashed #1da867; + position: absolute; + bottom: -5px; + left: 0; + width: 100%; +} + +/* ADDONS LIST STYLE */ +.dup-btn-green { + background-color: #1da867; + color: white; +} + +.dup-btn-green:hover, +.dup-btn-green:focus { + color: white; + background-color: #199a5e; +} + +.dup-btn-green:focus { + box-shadow: 0 0 0 1px #fff, 0 0 0 3px #199a5e; +} + +/* STORAGE PAGE STYLE */ + +#dup-admin-addons *, +#dup-admin-addons *::before, +#dup-admin-addons *::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +#dup-admin-addons #dup-admin-addons-list .list { + display: flex; + flex-wrap: wrap; + align-items: stretch; + margin-left: -20px; + margin-right: -20px; +} + +#dup-admin-addons #dup-admin-addons-list .list .action-button button, +#dup-admin-addons #dup-admin-addons-list .list .action-button a { + border: 1px solid #ddd; + border-radius: 3px; + box-shadow: none; + font-weight: 600; + width: 140px; + text-align: center; +} + +#dup-admin-addons #dup-admin-addons-list .list .action-button button:focus, +#dup-admin-addons #dup-admin-addons-list .list .action-button a:focus { + border-color: #2271b1; + box-shadow: 0 0 0 1px #2271b1; + outline: none; +} + +#dup-admin-addons .unlock-msg h4 { + margin: 1.5em 0 8px; +} + +#dup-admin-addons .unlock-msg p { + margin: 0 0 1.5em; +} + +#dup-admin-addons .addons-container { + padding: 0 20px; + width: 33.333333%; + margin-bottom: 20px; +} + +@media (max-width: 1249px) { + #dup-admin-addons .addons-container { + width: 50%; + } +} + +@media (max-width: 767px) { + #dup-admin-addons .addons-container { + width: 100%; + } +} + +#dup-admin-addons h4 { + font-size: 17px; + font-weight: 700; +} + +#dup-admin-addons .addon-item { + background-color: #fff; + border: 1px solid #ddd; + border-radius: 3px; + margin: 0; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + overflow: hidden; +} + +#dup-admin-addons .addon-item img { + border: 1px solid #eee; + float: left; + width: 75px; +} + +#dup-admin-addons .addon-item h5 { + margin: 0 0 0 100px; + font-size: 16px; +} + +#dup-admin-addons .addon-item h5 a { + color: #444; + display: inline-block; + margin: 0 10px 10px 0; +} + +#dup-admin-addons .addon-item h5 a:hover { + color: #006799; +} + +#dup-admin-addons .addon-item p { + margin: 0 0 0 100px; +} + +#dup-admin-addons .addon-item .status { + flex-grow: 1; +} + +#dup-admin-addons .addon-item .details { + padding: 30px 20px; +} + +#dup-admin-addons .addon-item .actions { + display: flex; + align-items: center; + background-color: #f7f7f7; + border-top: 1px solid #ddd; + padding: 20px; + min-height: 75px; + position: relative; +} + +#dup-admin-addons .addon-item .actions .msg p { + margin: 0; +} + +#dup-admin-addons .addon-item .actions .msg a, +#dup-admin-addons .addon-item .actions .msg a:hover { + color: inherit; +} + +#dup-admin-addons .addon-item .upgrade-button { + text-align: center; +} + +#dup-admin-addons .addon-item .upgrade-button a { + font-weight: 600; + width: 140px; + text-align: center; + padding: 8px 5px; +} + +#dup-admin-addons .addon-item .action-button button { + width: 140px; +} + +#dup-admin-addons .addon-item .dup-storage-recommended i { + opacity: 0.8; +} + +.addon-item .upgrade-button { + text-align: center; +} + +.addon-item .upgrade-button a { + font-weight: 600; + width: 140px; + text-align: center; +} + +.addon-item .action-button button { + cursor: pointer; +} + +.addon-item .action-button a { + text-decoration: none; +} + + +#dup-admin-addons .addon-item .status .status-active { + color: #00a32a +} + +#dup-admin-addons .addon-item .status .status-installed { + color: #d63638 +} + +#dup-admin-addons .addon-item .actions .msg.error { + color: #d63638 +} + +.addon-item .action-button button.status-installed .fa { + color: #d63638 +} + +.addon-item .action-button button.status-active .fa { + color: #00a32a +} + +.addon-item .action-button button.loading .fa { + color: #666 +} + + +/* COLUMN STYLES */ + +.dup-admin-columns > div[class*="-column-"] { + float: left; +} + +.dup-admin-columns .dup-admin-column-20 { + width: 20%; +} + +.dup-admin-columns .dup-admin-column-33 { + width: 33.33333%; +} + +.dup-admin-columns .dup-admin-column-40 { + width: 40%; +} + +.dup-admin-columns .dup-admin-column-50 { + width: 50%; +} + +.dup-admin-columns .dup-admin-column-60 { + width: 60%; +} + +.dup-admin-columns .dup-admin-column-80 { + width: 80%; +} + +.dup-admin-columns .dup-admin-column-last { + float: right !important; +} + +.dup-admin-columns:after { + content: ""; + display: table; + clear: both; +} + +.dup-subscribe-form{ + color: #3c434a; +} + +#dup-scan-progress-bar-wrapper .dup-subscribe-form, +#dup-build-progress-bar-wrapper .dup-subscribe-form { + padding-bottom: 35px; +} + +#dup-msg-success .dup-subscribe-form { + padding-bottom: 10px; +} + +.dup-subscribe-form input[type=email] { + padding: 4px 12px; + vertical-align: middle; + margin: 0; + width: 320px; + border-radius: 3px 0 0 3px; + font-size: 14px; + border: 1px solid #c5c5c5; + border-right: 0; +} + +.dup-subscribe-form .dup-btn { + border-radius: 0 3px 3px 0; + margin: 0; + font-size: 15px; + padding: 10px 12px; +} + +.dup-subscribe-form .desc { + margin-top: 10px; +} +.dup-subscribe-form small { + font-size: 13px; +} + +/* PACKAGES BOTTOM BAR */ +#dup-packages-bottom-bar { + display: flex; + flex-direction: row; + align-items: center; +} + +#dup-packages-bottom-bar .feature { + flex-grow: 4; + } + +#dup-packages-bottom-bar .fa-info-circle { + text-align: center; + padding: 0 20px 0 10px; + font-size: 40px; + color: #fe4716; +} + +#dup-packages-bottom-bar p { + margin: 0; + white-space: normal; + word-break: break-word; + max-width: 600px; +} + +#dup-packages-bottom-bar-dismiss { + margin: 0; + padding: 0 0 0 15px; + border: 0 none; + background: transparent; + color: #787c82; + cursor: pointer; +} + +/** Callout CTA */ + +.dup-settings-lite-cta { + background-color: #fff; + border: 1px solid #dadada; + padding: 25px 20px; + margin: 10px 0 0 0; + position: relative; +} + +.dup-settings-lite-cta .dismiss { + position: absolute; + top: 10px; + right: 10px; + color: #666; + font-size: 16px; +} + +.dup-settings-lite-cta h5 { + margin: 0 0 16px; + font-size: 18px; + font-weight: 700; +} + +.dup-settings-lite-cta h6 { + font-weight: 700; + font-size: 14px; + margin: 0 0 16px; +} + +.dup-settings-lite-cta p { + color: #555; + font-size: 14px; + margin: 0 0 16px; +} + +.dup-settings-lite-cta p:last-of-type { + margin: 0; +} + +.dup-settings-lite-cta p a { + color: #fe4716; +} + +.dup-settings-lite-cta p a:hover { + color: #b85a1b; +} + +.dup-settings-lite-cta .list { + display: flex; + margin: 0 0 16px 0; + overflow: auto; + max-width: 900px; + flex-direction: row; + flex-wrap: wrap; + color: #555; + font-size: 14px; + list-style: none; +} + +.dup-settings-lite-cta .list > .item { + flex: 33.33% 0; + box-sizing: border-box; + padding: 0 0 2px 0; +} + +.dup-settings-lite-cta .list > .item > span::before { + content: '+ '; +} + +@media (max-width: 900px) { + .dup-settings-lite-cta .list > .item { + flex: 50% 0; + } +} + +@media (max-width: 600px) { + .dup-settings-lite-cta .list > .item { + flex: 100% 1; + } +} + +.dup-settings-lite-cta .green { + color: #218900; + font-weight: 700; +} + +.dup-settings-lite-cta .fa-star { + color: #ff982d; +} + +/* DID YOU KNOW STYLE */ + +#duplicator-did-you-know { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 10px; + text-align: center; + font-style: normal; + font-weight: normal; + font-size: 15px; + line-height: 24px; + color: #444444; + background: #fcf9e8; + border-bottom: 1px solid #ede2a0; +} + +#duplicator-did-you-know a { + margin-left: 5px; +} + +#duplicator-did-you-know .fa-info-circle { + font-size: 20px; + margin-right: 5px; + vertical-align: text-top; + color: #e27730; +} + +/* ADVANCED STORAGES POPUP */ +.advanced-storages-popup-content { + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 20px +} + +.advanced-storages-popup-content img { + width: 250px; +} + +.advanced-storages-popup-content .storage-icon { + vertical-align: middle; + margin-right: 5px; + width: 20px +} + +.advanced-storages-popup-content ul { + text-align: left; + display: flex; + flex-direction: row; + flex-wrap: wrap; + color: #555; + font-size: 14px; + list-style: none; + margin: 0 auto; + justify-content: end; +} + +.advanced-storages-popup-content ul li { + flex: 45% 0; + box-sizing: border-box; + padding: 0 0 8px 0; +} + +#dup-settings-upgrade-license-key { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 3px; + box-shadow: none; + color: #333; + display: inline-block; + vertical-align: middle; + padding: 7px 12px; + margin: 0 10px 0 0; + width: 400px; + min-height: 35px; + line-height: 1.3; +} + +#redirect-to-remote-upgrade-endpoint { + visibility: hidden; + position: absolute; + left: -1000; + top: -1000; +} + +/** Package Components **/ + +.filter-files-tab-content { + padding: 0!important; +} + +.dup-package-components { + display: flex; + flex-direction: row; + border-bottom: 1px solid #dcdcde; + min-height: 300px; +} + +.dup-radio-button-group-wrapper { + width: 100%; + display: flex; + border-top: 1px solid #dcdcde; + border-bottom: 1px solid #dcdcde; +} + +.dup-radio-button-group-wrapper input[type="radio"] { + position: absolute; + left: -9999em; +} + +.dup-radio-button-group-wrapper label { + flex: 1 1 25%; + padding: .5em 1em; + cursor: pointer; + text-align: center; + color: #2271b1; + border-right: 1px solid #dcdcde; + background: #f6f7f7; + box-sizing: border-box; +} + +.dup-radio-button-group-wrapper input[type="radio"] + label:last-child { + border-right: none; +} + +.dup-radio-button-group-wrapper input[type="radio"] + label:hover, +.dup-radio-button-group-wrapper input[type="radio"]:focus + label, +.dup-radio-button-group-wrapper input[type="radio"]:checked + label { + background: #2271b1; + border-color: #2271b1; + color: #fff; +} + +#dup-upgrade-license-info { + padding: 10px; + background: #fcf9e8; +} + +@media only screen and (max-width: 1150px) { + .dup-package-components { + flex-direction: column; + } + + .dup-package-components .section-title { + font-size: 14px; + } + + .dup-package-components .filter-section { + border-left: 0 none!important; + } + + .dup-package-components .section-title { + height: auto!important; + } + + .dup-package-components .component-section { + max-width: 100%!important; + } +} + +.dup-package-components label input[type="checkbox"] { + margin: 0!important; +} + +.dup-package-components .section-title { + margin: 0; + height: 20px; + padding: 10px; + background: #f0f0f1; + font-size: 16px; + font-weight: bold; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.dup-package-components .section-title label { + font-size: 16px; +} + +.dup-package-components .db-only-message { + display: none; + padding: 40px 20px 20px; +} + +.dup-package-components .component-section { + flex: 1 1 33.33%; + max-width: 500px; + font-size: 14px; +} + +.dup-package-components .component-section label.secondary { + margin-left: 40px; +} + +.dup-package-components .custom-components-select { + margin-left: 20px; +} + +.dup-package-components .component-section label.disabled, +.dup-package-components .component-section label.disabled input { + pointer-events: none; + color: gray; + opacity: 0.7; +} + +.dup-package-components .filter-section { + flex: 1 3 66.66%; + border-left: 1px solid #dcdcde; +} + +.dup-package-components .filter-section .filters { + display: flex; + flex-direction: column; +} + +.dup-package-components .component-section { + padding-bottom: 20px; +} + +.dup-package-components .filter-section .filters{ + height: 100%; +} +.dup-package-components .filter-section textarea{ + border: none; + border-radius: 0; +} + +.dup-package-components .filter-section textarea[readonly]{ + background-image: linear-gradient(45deg, #f0f0f0 41.67%, #e0e0e0 41.67%, #e0e0e0 50%, #f0f0f0 50%, #f0f0f0 91.67%, #e0e0e0 91.67%, #e0e0e0 100%); + background-size: 12px 12px; + opacity: 0.7; +} + +.dup-package-components .filter-section textarea#filter-paths{ + flex: 4 1 auto; +} + +.dup-package-components .filter-section .section-title .filter-links { + font-size: 12px; + font-weight: normal; +} + +.dup-package-components i[data-tooltip].fa-question-circle { + color: gray; +} + +.dup-tabs-opts-help { + font-style: italic; + font-size: 12px; + padding: 10px; + color: #666; +} + +.dup-package-components .pro-badge { + display: inline-block; + padding: 0px 5px; + background: #e27730; + color: #fff; + font-size: 8px; + font-weight: bold; + border-radius: 10px; + margin-left: 5px; + text-decoration: none; + vertical-align: middle; +} + +#component-section-title { + position: relative; +} + +#component-section-title i[data-tooltip].fa-question-circle { + color: #e27730; +} diff --git a/assets/css/welcome.css b/assets/css/welcome.css new file mode 100644 index 00000000..ade9f82b --- /dev/null +++ b/assets/css/welcome.css @@ -0,0 +1,352 @@ +#wpcontent { + padding-left: 0; + position: relative; +} + +#duplicator-welcome { + border-top: 3px solid #fe4716; + color: #555; + padding-top: 110px; +} + +@media (max-width: 767px) { + #duplicator-welcome { + padding-top: 64px; + } +} + +#duplicator-welcome *, +#duplicator-welcome *::before, +#duplicator-welcome *::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +#duplicator-welcome .container { + margin: 0 auto; + max-width: 760px; + padding: 0; +} + +#duplicator-welcome .block { + padding: 40px; +} + +@media (max-width: 767px) { + #duplicator-welcome .block { + padding: 20px; + } +} + +#duplicator-welcome img { + max-width: 100%; + height: auto; +} + +#duplicator-welcome h1 { + color: #222; + font-size: 24px; + text-align: center; + margin: 0 0 16px 0; +} + +#duplicator-welcome h5 { + color: #222; + font-size: 16px; + margin: 0 0 8px 0; +} + +#duplicator-welcome h6 { + font-size: 16px; + font-weight: 400; + line-height: 1.6; + text-align: center; + margin: 0; +} + +#duplicator-welcome p { + font-size: 14px; + margin: 0 0 20px 0; +} + +#duplicator-welcome .button-wrap { + max-width: 590px; + margin: 0 auto 0 auto; +} + +#duplicator-welcome .button-wrap .left { + float: left; + width: 50%; + padding-right: 20px; +} + +@media (max-width: 767px) { + #duplicator-welcome .button-wrap .left { + float: none; + width: 100%; + padding: 0; + margin-bottom: 20px; + } +} + +#duplicator-welcome .button-wrap .right { + float: right; + width: 50%; + padding-left: 20px; +} + +@media (max-width: 767px) { + #duplicator-welcome .button-wrap .right { + float: none; + width: 100%; + padding: 0; + } +} + +#duplicator-welcome .intro { + background-color: #fff; + border: 2px solid #e1e1e1; + border-radius: 2px; + margin-bottom: 30px; + position: relative; + padding-top: 40px; +} + +#duplicator-welcome .intro .sullie { + background-color: #fff; + border: 2px solid #e1e1e1; + border-radius: 50%; + height: 110px; + width: 110px; + padding: 18px; + position: absolute; + top: -58px; + left: 50%; + margin-left: -55px; +} + +#duplicator-welcome .intro .video-thumbnail { + display: block; + margin: 0 auto; +} + +#duplicator-welcome .intro .button-wrap { + margin-top: 25px; +} + +#duplicator-welcome .features { + background-color: #fff; + border: 2px solid #e1e1e1; + border-bottom: 0; + border-radius: 2px 2px 0 0; + position: relative; + padding-top: 20px; + padding-bottom: 20px; +} + +#duplicator-welcome .features .feature-list { + margin-top: 60px; +} + +#duplicator-welcome .features .feature-block { + float: left; + width: 50%; + padding-bottom: 35px; + overflow: auto; +} + +@media (max-width: 767px) { + #duplicator-welcome .features .feature-block { + float: none; + width: 100%; + } +} + +#duplicator-welcome .features .feature-block.first { + padding-right: 20px; + clear: both; +} + +@media (max-width: 767px) { + #duplicator-welcome .features .feature-block.first { + padding-right: 0; + } +} + +#duplicator-welcome .features .feature-block.last { + padding-left: 20px; +} + +@media (max-width: 767px) { + #duplicator-welcome .features .feature-block.last { + padding-left: 0; + } +} + +#duplicator-welcome .features .feature-block img { + float: left; + max-width: 46px; +} + +#duplicator-welcome .features .feature-block h5 { + margin-left: 68px; +} + +#duplicator-welcome .features .feature-block p { + margin: 0; + margin-left: 68px; +} + +#duplicator-welcome .features .button-wrap { + margin-top: 25px; + text-align: center; +} + +#duplicator-welcome .upgrade-cta { + background-color: #000; + border: 2px solid #e1e1e1; + border-top: 0; + border-bottom: 0; + color: #fff; +} + +#duplicator-welcome .upgrade-cta h2 { + color: #fff; + font-size: 20px; + margin: 0 0 30px 0; +} + +#duplicator-welcome .upgrade-cta ul { + display: -ms-flex; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + font-size: 15px; + margin: 0; + padding: 0; +} + +#duplicator-welcome .upgrade-cta ul li { + flex: 33.33%; + margin: 0 0 8px 0; + padding: 0; +} + +#duplicator-welcome .upgrade-cta ul li .dashicons { + color: #2a9b39; + margin-right: 5px; +} + +#duplicator-welcome .upgrade-cta .dup-btn { + width: 33.33%; + margin: 30px auto 0; +} + +#duplicator-welcome .upgrade-cta h2 { + text-align: center; + width: 50%; + border-bottom: 1px solid white; + padding-bottom: 10px; + margin: 0 auto 30px; +} + +#duplicator-welcome .upgrade-cta .right h2 span { + display: inline-block; + border-bottom: 1px solid #555; + padding: 0 15px 12px; +} + +#duplicator-welcome .upgrade-cta .right .price { + padding: 26px 0; +} + +#duplicator-welcome .upgrade-cta .right .price .amount { + font-size: 48px; + font-weight: 600; + position: relative; + display: inline-block; +} + +#duplicator-welcome .upgrade-cta .right .price .amount:before { + content: '$'; + position: absolute; + top: -8px; + left: -16px; + font-size: 18px; +} + +#duplicator-welcome .upgrade-cta .right .price .term { + font-size: 12px; + display: inline-block; +} + +#duplicator-welcome .testimonials { + background-color: #fff; + border: 2px solid #e1e1e1; + border-top: 0; + padding: 20px 0; +} + +#duplicator-welcome .testimonials .testimonial-block { + margin: 50px 0 0 0; +} + +#duplicator-welcome .testimonials .testimonial-block img { + border-radius: 50%; + float: left; + max-width: 100px; + box-shadow: 0 0 18px rgba(0, 0, 0, 0.2); +} + +@media (max-width: 767px) { + #duplicator-welcome .testimonials .testimonial-block img { + width: 65px; + } +} + +#duplicator-welcome .testimonials .testimonial-block p { + font-size: 14px; + margin: 0 0 12px 140px; +} + +@media (max-width: 767px) { + #duplicator-welcome .testimonials .testimonial-block p { + margin-left: 100px; + } +} + +#duplicator-welcome .testimonials .testimonial-block p:last-of-type { + margin-bottom: 0; +} + +#duplicator-welcome .footer { + background-color: #f1f1f1; + border: 2px solid #e1e1e1; + border-top: 0; + border-radius: 0 0 2px 2px; +} + +#duplicator-welcome.pro .features { + border: 2px solid #e1e1e1; + margin-bottom: 30px; +} + +#duplicator-welcome.pro .upgrade, +#duplicator-welcome.pro .footer { + display: none; +} + +#duplicator-welcome.pro .testimonials { + border: 2px solid #e1e1e1; +} + +.dashboard_page_duplicator-getting-started .video-container { + border: 2px solid #e1e1e1; +} + +.dashboard_page_duplicator-getting-started #wpfooter, +.dashboard_page_duplicator-getting-started div.notice { + display: none !important; +} \ No newline at end of file diff --git a/assets/fonts/FontAwesome.otf b/assets/fonts/FontAwesome.otf deleted file mode 100644 index f7936cc1..00000000 Binary files a/assets/fonts/FontAwesome.otf and /dev/null differ diff --git a/assets/fonts/fontawesome-webfont.eot b/assets/fonts/fontawesome-webfont.eot deleted file mode 100644 index 33b2bb80..00000000 Binary files a/assets/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/assets/fonts/fontawesome-webfont.svg b/assets/fonts/fontawesome-webfont.svg deleted file mode 100644 index 1ee89d43..00000000 --- a/assets/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,565 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/fonts/fontawesome-webfont.ttf b/assets/fonts/fontawesome-webfont.ttf deleted file mode 100644 index ed9372f8..00000000 Binary files a/assets/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/assets/fonts/fontawesome-webfont.woff b/assets/fonts/fontawesome-webfont.woff deleted file mode 100644 index 8b280b98..00000000 Binary files a/assets/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/assets/fonts/fontawesome-webfont.woff2 b/assets/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 3311d585..00000000 Binary files a/assets/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/assets/img/about/icon-full.svg b/assets/img/about/icon-full.svg new file mode 100644 index 00000000..0865544d --- /dev/null +++ b/assets/img/about/icon-full.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/about/icon-none.svg b/assets/img/about/icon-none.svg new file mode 100644 index 00000000..9617560b --- /dev/null +++ b/assets/img/about/icon-none.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/about/icon-partial.svg b/assets/img/about/icon-partial.svg new file mode 100644 index 00000000..38881639 --- /dev/null +++ b/assets/img/about/icon-partial.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/about/plugin-affwp.png b/assets/img/about/plugin-affwp.png new file mode 100644 index 00000000..cda0cc14 Binary files /dev/null and b/assets/img/about/plugin-affwp.png differ diff --git a/assets/img/about/plugin-aioseo.png b/assets/img/about/plugin-aioseo.png new file mode 100644 index 00000000..3636ad57 Binary files /dev/null and b/assets/img/about/plugin-aioseo.png differ diff --git a/assets/img/about/plugin-edd.png b/assets/img/about/plugin-edd.png new file mode 100644 index 00000000..69d4c267 Binary files /dev/null and b/assets/img/about/plugin-edd.png differ diff --git a/assets/img/about/plugin-mi.png b/assets/img/about/plugin-mi.png new file mode 100644 index 00000000..b9e4bedd Binary files /dev/null and b/assets/img/about/plugin-mi.png differ diff --git a/assets/img/about/plugin-om.png b/assets/img/about/plugin-om.png new file mode 100644 index 00000000..4c1232e0 Binary files /dev/null and b/assets/img/about/plugin-om.png differ diff --git a/assets/img/about/plugin-pushengage.png b/assets/img/about/plugin-pushengage.png new file mode 100644 index 00000000..4a92d9de Binary files /dev/null and b/assets/img/about/plugin-pushengage.png differ diff --git a/assets/img/about/plugin-rp.png b/assets/img/about/plugin-rp.png new file mode 100644 index 00000000..2c85a213 Binary files /dev/null and b/assets/img/about/plugin-rp.png differ diff --git a/assets/img/about/plugin-sb-fb.png b/assets/img/about/plugin-sb-fb.png new file mode 100644 index 00000000..5f60be12 Binary files /dev/null and b/assets/img/about/plugin-sb-fb.png differ diff --git a/assets/img/about/plugin-sb-instagram.png b/assets/img/about/plugin-sb-instagram.png new file mode 100644 index 00000000..2940cf59 Binary files /dev/null and b/assets/img/about/plugin-sb-instagram.png differ diff --git a/assets/img/about/plugin-sb-twitter.png b/assets/img/about/plugin-sb-twitter.png new file mode 100644 index 00000000..a05b020e Binary files /dev/null and b/assets/img/about/plugin-sb-twitter.png differ diff --git a/assets/img/about/plugin-sb-youtube.png b/assets/img/about/plugin-sb-youtube.png new file mode 100644 index 00000000..e9e36616 Binary files /dev/null and b/assets/img/about/plugin-sb-youtube.png differ diff --git a/assets/img/about/plugin-searchwp.png b/assets/img/about/plugin-searchwp.png new file mode 100644 index 00000000..e0faa75d Binary files /dev/null and b/assets/img/about/plugin-searchwp.png differ diff --git a/assets/img/about/plugin-seedprod.png b/assets/img/about/plugin-seedprod.png new file mode 100644 index 00000000..b6d7f30e Binary files /dev/null and b/assets/img/about/plugin-seedprod.png differ diff --git a/assets/img/about/plugin-smtp.png b/assets/img/about/plugin-smtp.png new file mode 100644 index 00000000..adcccd22 Binary files /dev/null and b/assets/img/about/plugin-smtp.png differ diff --git a/assets/img/about/plugin-sugarcalendar.png b/assets/img/about/plugin-sugarcalendar.png new file mode 100644 index 00000000..b5b426e2 Binary files /dev/null and b/assets/img/about/plugin-sugarcalendar.png differ diff --git a/assets/img/about/plugin-trustpulse.png b/assets/img/about/plugin-trustpulse.png new file mode 100644 index 00000000..d91063e5 Binary files /dev/null and b/assets/img/about/plugin-trustpulse.png differ diff --git a/assets/img/about/plugin-wp-simple-pay.png b/assets/img/about/plugin-wp-simple-pay.png new file mode 100644 index 00000000..9d14d6a3 Binary files /dev/null and b/assets/img/about/plugin-wp-simple-pay.png differ diff --git a/assets/img/about/plugin-wpforms.png b/assets/img/about/plugin-wpforms.png new file mode 100644 index 00000000..985b5346 Binary files /dev/null and b/assets/img/about/plugin-wpforms.png differ diff --git a/assets/img/about/team.jpeg b/assets/img/about/team.jpeg new file mode 100644 index 00000000..d44550d5 Binary files /dev/null and b/assets/img/about/team.jpeg differ diff --git a/assets/img/aws.svg b/assets/img/aws.svg new file mode 100644 index 00000000..4715937f --- /dev/null +++ b/assets/img/aws.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + diff --git a/assets/img/backblaze.svg b/assets/img/backblaze.svg new file mode 100644 index 00000000..6718539d --- /dev/null +++ b/assets/img/backblaze.svg @@ -0,0 +1,50 @@ + + + + + + + + diff --git a/assets/img/cloudflare.svg b/assets/img/cloudflare.svg new file mode 100644 index 00000000..76559f1d --- /dev/null +++ b/assets/img/cloudflare.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/cpanel-48.png b/assets/img/cpanel-48.png new file mode 100644 index 00000000..ddf383ef Binary files /dev/null and b/assets/img/cpanel-48.png differ diff --git a/assets/img/create.png b/assets/img/create.png deleted file mode 100644 index 4db7d010..00000000 Binary files a/assets/img/create.png and /dev/null differ diff --git a/assets/img/digital-ocean.svg b/assets/img/digital-ocean.svg new file mode 100644 index 00000000..b62daa5a --- /dev/null +++ b/assets/img/digital-ocean.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/dreamhost.svg b/assets/img/dreamhost.svg new file mode 100644 index 00000000..9e4a5aee --- /dev/null +++ b/assets/img/dreamhost.svg @@ -0,0 +1,45 @@ + + + + + + + diff --git a/assets/img/dropbox.svg b/assets/img/dropbox.svg new file mode 100644 index 00000000..84ac8602 --- /dev/null +++ b/assets/img/dropbox.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/img/duplicator-header-logo.svg b/assets/img/duplicator-header-logo.svg new file mode 100644 index 00000000..992d7b0c --- /dev/null +++ b/assets/img/duplicator-header-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/img/duplicator-logo-icon-menu.svg b/assets/img/duplicator-logo-icon-menu.svg new file mode 100644 index 00000000..e6773893 --- /dev/null +++ b/assets/img/duplicator-logo-icon-menu.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/img/duplicator-logo-icon-white.svg b/assets/img/duplicator-logo-icon-white.svg new file mode 100644 index 00000000..14d057df --- /dev/null +++ b/assets/img/duplicator-logo-icon-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/email-logo.png b/assets/img/email-logo.png new file mode 100644 index 00000000..51ec1857 Binary files /dev/null and b/assets/img/email-logo.png differ diff --git a/assets/img/exclamation-triangle-orange.svg b/assets/img/exclamation-triangle-orange.svg new file mode 100644 index 00000000..607bd61f --- /dev/null +++ b/assets/img/exclamation-triangle-orange.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/google-cloud.svg b/assets/img/google-cloud.svg new file mode 100644 index 00000000..657a5abc --- /dev/null +++ b/assets/img/google-cloud.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + diff --git a/assets/img/google-drive.svg b/assets/img/google-drive.svg new file mode 100644 index 00000000..a8cefd5b --- /dev/null +++ b/assets/img/google-drive.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/assets/img/hdivider.png b/assets/img/hdivider.png deleted file mode 100644 index dc77cece..00000000 Binary files a/assets/img/hdivider.png and /dev/null differ diff --git a/assets/img/index.php b/assets/img/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/assets/img/index.php @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/onedrive.svg b/assets/img/onedrive.svg new file mode 100644 index 00000000..f7d7a6a6 --- /dev/null +++ b/assets/img/onedrive.svg @@ -0,0 +1 @@ +OfficeCore10_32x_24x_20x_16x_01-22-2019 \ No newline at end of file diff --git a/assets/img/paypal.png b/assets/img/paypal.png deleted file mode 100644 index 694919dd..00000000 Binary files a/assets/img/paypal.png and /dev/null differ diff --git a/assets/img/vultr.svg b/assets/img/vultr.svg new file mode 100644 index 00000000..53ed4497 --- /dev/null +++ b/assets/img/vultr.svg @@ -0,0 +1 @@ +sygnet__on-white \ No newline at end of file diff --git a/assets/img/wasabi.svg b/assets/img/wasabi.svg new file mode 100644 index 00000000..f194b2a3 --- /dev/null +++ b/assets/img/wasabi.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/welcome/cloud-backups.svg b/assets/img/welcome/cloud-backups.svg new file mode 100644 index 00000000..a9426da8 --- /dev/null +++ b/assets/img/welcome/cloud-backups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/file-and-database-filters.svg b/assets/img/welcome/file-and-database-filters.svg new file mode 100644 index 00000000..939bc352 --- /dev/null +++ b/assets/img/welcome/file-and-database-filters.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/large-site-support.svg b/assets/img/welcome/large-site-support.svg new file mode 100644 index 00000000..10171fbb --- /dev/null +++ b/assets/img/welcome/large-site-support.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/multisite-support.svg b/assets/img/welcome/multisite-support.svg new file mode 100644 index 00000000..f2ebee3f --- /dev/null +++ b/assets/img/welcome/multisite-support.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/recovery-points.svg b/assets/img/welcome/recovery-points.svg new file mode 100644 index 00000000..8f82c4d9 --- /dev/null +++ b/assets/img/welcome/recovery-points.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/scheduled-backups.svg b/assets/img/welcome/scheduled-backups.svg new file mode 100644 index 00000000..a84bbf24 --- /dev/null +++ b/assets/img/welcome/scheduled-backups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/secure-file-encryption.svg b/assets/img/welcome/secure-file-encryption.svg new file mode 100644 index 00000000..17d48f48 --- /dev/null +++ b/assets/img/welcome/secure-file-encryption.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/server-to-server-import.svg b/assets/img/welcome/server-to-server-import.svg new file mode 100644 index 00000000..7eab9993 --- /dev/null +++ b/assets/img/welcome/server-to-server-import.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/welcome/welcome-testimonial-Blake.png b/assets/img/welcome/welcome-testimonial-Blake.png new file mode 100644 index 00000000..d4688bd1 Binary files /dev/null and b/assets/img/welcome/welcome-testimonial-Blake.png differ diff --git a/assets/img/welcome/welcome-testimonial-Karina.png b/assets/img/welcome/welcome-testimonial-Karina.png new file mode 100644 index 00000000..81fe9cfe Binary files /dev/null and b/assets/img/welcome/welcome-testimonial-Karina.png differ diff --git a/assets/img/welcome/willie.svg b/assets/img/welcome/willie.svg new file mode 100644 index 00000000..073b6337 --- /dev/null +++ b/assets/img/welcome/willie.svg @@ -0,0 +1,126 @@ + +image/svg+xml \ No newline at end of file diff --git a/assets/js/duplicator-tooltip.js b/assets/js/duplicator-tooltip.js new file mode 100644 index 00000000..21c7222d --- /dev/null +++ b/assets/js/duplicator-tooltip.js @@ -0,0 +1,122 @@ +/*! dup tooltip */ +(function ($) { + DuplicatorTooltip = { + initialized: false, + messages: { + 'copy': 'Copy to clipboard', + 'copied': 'copied to clipboard', + 'copyUnable': 'Unable to copy' + }, + load: function () { + if (this.initialized) { + return; + } + + this.loadSelector('[data-tooltip]'); + this.loadCopySelector('[data-dup-copy-value]'); + + this.initialized = true; + }, + loadSelector: function (selector) { + $(selector).each(function () { + if (this._tippy) { + // already init + return; + } + + tippy(this, { + content: function (ref) { + var header = ref.dataset.tooltipTitle; + var body = ref.dataset.tooltip; + var res = header !== undefined ? '

' + header + '

' : ''; + res += '
' + body + '
'; + return res; + }, + allowHTML: true, + interactive: true, + placement: this.dataset.tooltipPlacement ? this.dataset.tooltipPlacement : 'bottom-start', + theme: 'duplicator', + zIndex: 900000, + appendTo: document.body + }); + $(this).data('dup-tooltip-loaded', true); + }); + }, + loadCopySelector: function (selector) { + $(selector).each(function () { + if (this._tippy) { + // already init + return; + } + + var element = $(this); + if (element.hasClass('disabled')) { + return; + } + + var tippyElement = tippy(this, { + allowHTML: true, + placement: this.dataset.tooltipPlacement ? this.dataset.tooltipPlacement : 'bottom-start', + theme: 'duplicator', + zIndex: 900000, + hideOnClick: false, + trigger: 'manual' + }); + + var copyTitle = element.is('[data-dup-copy-title]') ? element.data('dup-copy-title') : DuplicatorTooltip.messages.copy; + tippyElement.setContent('
' + copyTitle + '
'); + + //Have to set manually otherwise might hide on click. + element.mouseover(function () { + tippyElement.show(); + }).mouseout(function () { + tippyElement.hide(); + }); + + element.click(function () { + var valueToCopy = element.data('dup-copy-value'); + var copiedTitle = element.is('[data-dup-copied-title]') ? element.data('dup-copied-title') : valueToCopy + ' ' + DuplicatorTooltip.messages.copied; + var message = DuplicatorTooltip.messages.copyUnable; + var tmpArea = jQuery("").css({ + position: 'absolute', + top: '-10000px' + }).text(valueToCopy).appendTo("body"); + tmpArea.select(); + + try { + message = document.execCommand('copy') ? copiedTitle : 'Unable to copy'; + } catch (err) { + console.log(err); + } + + tippyElement.setContent('
' + message + '
'); + tippyElement.setProps({ theme: 'duplicator-filled' }); + + setTimeout(function () { + tippyElement.setContent('
' + copyTitle + '
'); + tippyElement.setProps({ theme: 'duplicator' }); + }, 2000); + }); + }); + }, + updateElementContent: function (selector, content) { + if ($(selector).get(0)) { + $(selector).get(0)._tippy.setContent('
' + content + '
'); + } + }, + unload: function () { + var tooltips = document.querySelectorAll('[data-tooltip], [data-dup-copy-value]'); + tooltips.forEach(function (element) { + if (element._tippy) { + element._tippy.destroy(); + element._tippy = null; + } + }); + this.initialized = false; + }, + reload: function () { + this.unload(); + this.load(); + } + } +})(jQuery); \ No newline at end of file diff --git a/assets/js/extra-plugins.js b/assets/js/extra-plugins.js new file mode 100644 index 00000000..29039f2b --- /dev/null +++ b/assets/js/extra-plugins.js @@ -0,0 +1,102 @@ +/** + * Duplicator Dismissible Notices. + * + */ + +'use strict'; + +var DupExtraPlugins = window.DupExtraPlugins || (function (document, window, $) { + + /** + * Public functions and properties. + */ + var app = { + + /** + * Start the engine. + */ + init: function () { + $(app.ready); + }, + + /** + * Document ready. + */ + ready: function () { + app.events(); + }, + + /** + * Dismissible notices events. + */ + events: function () { + $(document).on( + 'click', + 'button.dup-extra-plugin-item[data-plugin]', + function (e) { + e.preventDefault(); + + if ($(this).hasClass('disabled')) { + return; + } + + let button = $(this); + let status = $(this).closest('.actions').find('.status').eq(0); + let statusLabel = status.find('.status-label').eq(0) + let statusLabelText = statusLabel.html(); + let buttonText = $(this).html(); + + $(this).addClass('disabled'); + $(this).html('Loading...'); + + $.post( + duplicator_extra_plugins.ajax_url, + { + action: 'duplicator_install_extra_plugin', + nonce: duplicator_extra_plugins.extra_plugin_install_nonce, + plugin: $(this).data('plugin'), + } + ).done(function (response) { + console.log(response); + if (response.success !== true) { + console.log("Plugin installed failed with message: " + response.data.message); + statusLabel.html('Failure'); + statusLabel.addClass('status-installed'); + button.fadeOut(300); + + setTimeout(function () { + statusLabel.html(statusLabelText); + statusLabel.removeClass('status-installed'); + button.html(buttonText); + button.removeClass('disabled'); + button.fadeIn(100); + }, 3000); + return; + } + + button.fadeOut(500); + status.fadeOut(500); + + button.html('Activated'); + statusLabel.html('Active'); + + statusLabel.removeClass('status-missing'); + statusLabel.removeClass('status-installed'); + statusLabel.addClass('status-active'); + + button.fadeIn(300); + status.fadeIn(300); + }); + } + ); + }, + + + }; + + return app; + +}(document, window, jQuery)); + +// Initialize. +DupExtraPlugins.init(); diff --git a/assets/js/global-admin-script.js b/assets/js/global-admin-script.js new file mode 100644 index 00000000..ca171743 --- /dev/null +++ b/assets/js/global-admin-script.js @@ -0,0 +1,139 @@ +jQuery(document).ready(function ($) { + $('.duplicator-admin-notice[data-to-dismiss]').each(function () { + var notice = $(this); + var notice_to_dismiss = notice.data('to-dismiss'); + + notice.find('.notice-dismiss').on('click', function (event) { + event.preventDefault(); + $.post(ajaxurl, { + action: 'duplicator_admin_notice_to_dismiss', + notice: notice_to_dismiss, + nonce: dup_global_script_data.nonce_admin_notice_to_dismiss + }); + }); + }); + + $('.dup-settings-lite-cta .dismiss').on('click', function (event) { + event.preventDefault(); + $.post( + ajaxurl, + { + action: 'duplicator_settings_callout_cta_dismiss', + nonce: dup_global_script_data.nonce_settings_callout_to_dismiss + }, + function (response) { + if (response.success) { + $('.dup-settings-lite-cta').fadeOut(300); + } + } + ); + }); + + $('#dup-packages-bottom-bar-dismiss').on('click', function (event) { + event.preventDefault(); + + $.post( + ajaxurl, + { + action: 'duplicator_packages_bottom_bar_dismiss', + nonce: dup_global_script_data.nonce_packages_bottom_bar_dismiss + }, + function (response) { + if (response.success) { + $('#dup-packages-bottom-bar').closest('tr').fadeOut(300); + } + } + ); + }); + + $('.dup-subscribe-form button').on('click', function (event) { + event.preventDefault(); + var button = $('.dup-subscribe-form button'); + var wrapper = $('.dup-subscribe-form'); + var input = $('.dup-subscribe-form input[name="email"]'); + + button.html('Subscribing...'); + input.attr('disabled', 'disabled'); + $.post( + ajaxurl, + { + action: 'duplicator_email_subscribe', + email: input.val(), + nonce: dup_global_script_data.nonce_email_subscribe + }, + function (response) { + if (response.success) { + wrapper.fadeOut(300); + button.html('Subscribed ✓'); + wrapper.fadeIn(300); + + setTimeout(function () { + wrapper.fadeOut(300); + }, 3000); + } else { + console.log("Email subscription failed with message: " + response.message); + button.html('Failed ✗'); + + setTimeout(function () { + button.html('Subscribe'); + input.removeAttr('disabled'); + }, 3000); + } + } + ); + }); + + function dupDashboardUpdate() { + jQuery.ajax({ + type: "POST", + url: dup_global_script_data.ajaxurl, + dataType: "json", + data: { + action: 'duplicator_dashboad_widget_info', + nonce: dup_global_script_data.nonce_dashboard_widged_info + }, + success: function (result, textStatus, jqXHR) { + if (result.success) { + $('#duplicator_dashboard_widget .dup-last-backup-info').html(result.data.funcData.lastBackupInfo); + + if (result.data.funcData.isRunning) { + $('#duplicator_dashboard_widget #dup-pro-create-new').addClass('disabled'); + } else { + $('#duplicator_dashboard_widget #dup-pro-create-new').removeClass('disabled'); + } + } + }, + complete: function() { + setTimeout( + function(){ + dupDashboardUpdate(); + }, + 5000 + ); + } + }); + } + + if ($('#duplicator_dashboard_widget').length) { + dupDashboardUpdate(); + + $('#duplicator_dashboard_widget #dup-dash-widget-section-recommended').on('click', function (event) { + event.stopPropagation(); + + $(this).closest('.dup-section-recommended').fadeOut(); + + jQuery.ajax({ + type: "POST", + url: dup_global_script_data.ajaxurl, + dataType: "json", + data: { + action: 'duplicator_dismiss_recommended_plugin', + nonce: dup_global_script_data.nonce_dashboard_widged_dismiss_recommended + }, + success: function (result, textStatus, jqXHR) { + // do nothing + } + }); + }); + } +}); diff --git a/assets/js/handlebars.min.js b/assets/js/handlebars.min.js new file mode 100644 index 00000000..1ebc2606 --- /dev/null +++ b/assets/js/handlebars.min.js @@ -0,0 +1,29 @@ +/**! + + @license + handlebars v4.7.7 + +Copyright (C) 2011-2019 by Yehuda Katz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +!function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?exports.Handlebars=b():a.Handlebars=b()}(this,function(){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a,b,c){"use strict";function d(){var a=r();return a.compile=function(b,c){return k.compile(b,c,a)},a.precompile=function(b,c){return k.precompile(b,c,a)},a.AST=i["default"],a.Compiler=k.Compiler,a.JavaScriptCompiler=m["default"],a.Parser=j.parser,a.parse=j.parse,a.parseWithoutProcessing=j.parseWithoutProcessing,a}var e=c(1)["default"];b.__esModule=!0;var f=c(2),g=e(f),h=c(45),i=e(h),j=c(46),k=c(51),l=c(52),m=e(l),n=c(49),o=e(n),p=c(44),q=e(p),r=g["default"].create,s=d();s.create=d,q["default"](s),s.Visitor=o["default"],s["default"]=s,b["default"]=s,a.exports=b["default"]},function(a,b){"use strict";b["default"]=function(a){return a&&a.__esModule?a:{"default":a}},b.__esModule=!0},function(a,b,c){"use strict";function d(){var a=new h.HandlebarsEnvironment;return n.extend(a,h),a.SafeString=j["default"],a.Exception=l["default"],a.Utils=n,a.escapeExpression=n.escapeExpression,a.VM=p,a.template=function(b){return p.template(b,a)},a}var e=c(3)["default"],f=c(1)["default"];b.__esModule=!0;var g=c(4),h=e(g),i=c(37),j=f(i),k=c(6),l=f(k),m=c(5),n=e(m),o=c(38),p=e(o),q=c(44),r=f(q),s=d();s.create=d,r["default"](s),s["default"]=s,b["default"]=s,a.exports=b["default"]},function(a,b){"use strict";b["default"]=function(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b["default"]=a,b},b.__esModule=!0},function(a,b,c){"use strict";function d(a,b,c){this.helpers=a||{},this.partials=b||{},this.decorators=c||{},i.registerDefaultHelpers(this),j.registerDefaultDecorators(this)}var e=c(1)["default"];b.__esModule=!0,b.HandlebarsEnvironment=d;var f=c(5),g=c(6),h=e(g),i=c(10),j=c(30),k=c(32),l=e(k),m=c(33),n="4.7.7";b.VERSION=n;var o=8;b.COMPILER_REVISION=o;var p=7;b.LAST_COMPATIBLE_COMPILER_REVISION=p;var q={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:"== 1.x.x",5:"== 2.0.0-alpha.x",6:">= 2.0.0-beta.1",7:">= 4.0.0 <4.3.0",8:">= 4.3.0"};b.REVISION_CHANGES=q;var r="[object Object]";d.prototype={constructor:d,logger:l["default"],log:l["default"].log,registerHelper:function(a,b){if(f.toString.call(a)===r){if(b)throw new h["default"]("Arg not supported with multiple helpers");f.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){if(f.toString.call(a)===r)f.extend(this.partials,a);else{if("undefined"==typeof b)throw new h["default"]('Attempting to register a partial called "'+a+'" as undefined');this.partials[a]=b}},unregisterPartial:function(a){delete this.partials[a]},registerDecorator:function(a,b){if(f.toString.call(a)===r){if(b)throw new h["default"]("Arg not supported with multiple decorators");f.extend(this.decorators,a)}else this.decorators[a]=b},unregisterDecorator:function(a){delete this.decorators[a]},resetLoggedPropertyAccesses:function(){m.resetLoggedProperties()}};var s=l["default"].log;b.log=s,b.createFrame=f.createFrame,b.logger=l["default"]},function(a,b){"use strict";function c(a){return k[a]}function d(a){for(var b=1;b":">",'"':""","'":"'","`":"`","=":"="},l=/[&<>"'`=]/g,m=/[&<>"'`=]/,n=Object.prototype.toString;b.toString=n;var o=function(a){return"function"==typeof a};o(/x/)&&(b.isFunction=o=function(a){return"function"==typeof a&&"[object Function]"===n.call(a)}),b.isFunction=o;var p=Array.isArray||function(a){return!(!a||"object"!=typeof a)&&"[object Array]"===n.call(a)};b.isArray=p},function(a,b,c){"use strict";function d(a,b){var c=b&&b.loc,g=void 0,h=void 0,i=void 0,j=void 0;c&&(g=c.start.line,h=c.end.line,i=c.start.column,j=c.end.column,a+=" - "+g+":"+i);for(var k=Error.prototype.constructor.call(this,a),l=0;l0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):e(this);if(c.data&&c.ids){var g=d.createFrame(c.data);g.contextPath=d.appendContextPath(c.data.contextPath,c.name),c={data:g}}return f(b,c)})},a.exports=b["default"]},function(a,b,c){(function(d){"use strict";var e=c(13)["default"],f=c(1)["default"];b.__esModule=!0;var g=c(5),h=c(6),i=f(h);b["default"]=function(a){a.registerHelper("each",function(a,b){function c(b,c,d){l&&(l.key=b,l.index=c,l.first=0===c,l.last=!!d,m&&(l.contextPath=m+b)),k+=f(a[b],{data:l,blockParams:g.blockParams([a[b],b],[m+b,null])})}if(!b)throw new i["default"]("Must pass iterator to #each");var f=b.fn,h=b.inverse,j=0,k="",l=void 0,m=void 0;if(b.data&&b.ids&&(m=g.appendContextPath(b.data.contextPath,b.ids[0])+"."),g.isFunction(a)&&(a=a.call(this)),b.data&&(l=g.createFrame(b.data)),a&&"object"==typeof a)if(g.isArray(a))for(var n=a.length;j=0?b:parseInt(a,10)}return a},log:function(a){if(a=e.lookupLevel(a),"undefined"!=typeof console&&e.lookupLevel(e.level)<=a){var b=e.methodMap[a];console[b]||(b="log");for(var c=arguments.length,d=Array(c>1?c-1:0),f=1;f=v.LAST_COMPATIBLE_COMPILER_REVISION&&b<=v.COMPILER_REVISION)){if(b2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},c=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;gb[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substring(a,b.yyleng-c+a)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 15;break;case 1:return 15;case 2:return this.popState(),15;case 3:return this.begin("raw"),15;case 4:return this.popState(),"raw"===this.conditionStack[this.conditionStack.length-1]?15:(e(5,9),"END_RAW_BLOCK");case 5:return 15;case 6:return this.popState(),14;case 7:return 65;case 8:return 68;case 9:return 19;case 10:return this.popState(),this.begin("raw"),23;case 11:return 55;case 12:return 60;case 13:return 29;case 14:return 47;case 15:return this.popState(),44;case 16:return this.popState(),44;case 17:return 34;case 18:return 39;case 19:return 51;case 20:return 48;case 21:this.unput(b.yytext),this.popState(),this.begin("com");break;case 22:return this.popState(),14;case 23:return 48;case 24:return 73;case 25:return 72;case 26:return 72;case 27:return 87;case 28:break;case 29:return this.popState(),54;case 30:return this.popState(),33;case 31:return b.yytext=e(1,2).replace(/\\"/g,'"'),80;case 32:return b.yytext=e(1,2).replace(/\\'/g,"'"),80;case 33:return 85;case 34:return 82;case 35:return 82;case 36:return 83;case 37:return 84;case 38:return 81;case 39:return 75;case 40:return 77;case 41:return 72;case 42:return b.yytext=b.yytext.replace(/\\([\\\]])/g,"$1"),72;case 43:return"INVALID";case 44:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{(?=[^\/]))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]+?(?=(\{\{\{\{)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#>)/,/^(?:\{\{(~)?#\*?)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?\*?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:undefined(?=([~}\s)])))/,/^(?:null(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[(\\\]|[^\]])*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[6],inclusive:!1},raw:{rules:[3,4,5],inclusive:!1},INITIAL:{rules:[0,1,44],inclusive:!0}},a}();return b.lexer=c,a.prototype=b,b.Parser=a,new a}();b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(){var a=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.options=a}function e(a,b,c){void 0===b&&(b=a.length);var d=a[b-1],e=a[b-2];return d?"ContentStatement"===d.type?(e||!c?/\r?\n\s*?$/:/(^|\r?\n)\s*?$/).test(d.original):void 0:c}function f(a,b,c){void 0===b&&(b=-1);var d=a[b+1],e=a[b+2];return d?"ContentStatement"===d.type?(e||!c?/^\s*?\r?\n/:/^\s*?(\r?\n|$)/).test(d.original):void 0:c}function g(a,b,c){var d=a[null==b?0:b+1];if(d&&"ContentStatement"===d.type&&(c||!d.rightStripped)){var e=d.value;d.value=d.value.replace(c?/^\s+/:/^[ \t]*\r?\n?/,""),d.rightStripped=d.value!==e}}function h(a,b,c){var d=a[null==b?a.length-1:b-1];if(d&&"ContentStatement"===d.type&&(c||!d.leftStripped)){var e=d.value;return d.value=d.value.replace(c?/\s+$/:/[ \t]+$/,""),d.leftStripped=d.value!==e,d.leftStripped}}var i=c(1)["default"];b.__esModule=!0;var j=c(49),k=i(j);d.prototype=new k["default"],d.prototype.Program=function(a){var b=!this.options.ignoreStandalone,c=!this.isRootSeen;this.isRootSeen=!0;for(var d=a.body,i=0,j=d.length;i0)throw new q["default"]("Invalid path: "+d,{loc:c});".."===i&&f++}}return{type:"PathExpression",data:a,depth:f,parts:e,original:d,loc:c}}function j(a,b,c,d,e,f){var g=d.charAt(3)||d.charAt(2),h="{"!==g&&"&"!==g,i=/\*/.test(d);return{type:i?"Decorator":"MustacheStatement",path:a,params:b,hash:c,escaped:h,strip:e,loc:this.locInfo(f)}}function k(a,b,c,e){d(a,c),e=this.locInfo(e);var f={type:"Program",body:b,strip:{},loc:e};return{type:"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:f,openStrip:{},inverseStrip:{},closeStrip:{},loc:e}}function l(a,b,c,e,f,g){e&&e.path&&d(a,e);var h=/\*/.test(a.open);b.blockParams=a.blockParams;var i=void 0,j=void 0;if(c){if(h)throw new q["default"]("Unexpected inverse block on decorator",c);c.chain&&(c.program.body[0].closeStrip=e.strip),j=c.strip,i=c.program}return f&&(f=i,i=b,b=f),{type:h?"DecoratorBlock":"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:b,inverse:i,openStrip:a.strip,inverseStrip:j,closeStrip:e&&e.strip,loc:this.locInfo(g)}}function m(a,b){if(!b&&a.length){var c=a[0].loc,d=a[a.length-1].loc;c&&d&&(b={source:c.source,start:{line:c.start.line,column:c.start.column},end:{line:d.end.line,column:d.end.column}})}return{type:"Program",body:a,strip:{},loc:b}}function n(a,b,c,e){return d(a,c),{type:"PartialBlockStatement",name:a.path,params:a.params,hash:a.hash,program:b,openStrip:a.strip,closeStrip:c&&c.strip,loc:this.locInfo(e)}}var o=c(1)["default"];b.__esModule=!0,b.SourceLocation=e,b.id=f,b.stripFlags=g,b.stripComment=h,b.preparePath=i,b.prepareMustache=j,b.prepareRawBlock=k,b.prepareBlock=l,b.prepareProgram=m,b.preparePartialBlock=n;var p=c(6),q=o(p)},function(a,b,c){"use strict";function d(){}function e(a,b,c){if(null==a||"string"!=typeof a&&"Program"!==a.type)throw new l["default"]("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var d=c.parse(a,b),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function f(a,b,c){function d(){var d=c.parse(a,b),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}function e(a,b){return f||(f=d()),f.call(this,a,b)}if(void 0===b&&(b={}),null==a||"string"!=typeof a&&"Program"!==a.type)throw new l["default"]("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);b=m.extend({},b),"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var f=void 0;return e._setup=function(a){return f||(f=d()),f._setup(a)},e._child=function(a,b,c,e){return f||(f=d()),f._child(a,b,c,e)},e}function g(a,b){if(a===b)return!0;if(m.isArray(a)&&m.isArray(b)&&a.length===b.length){for(var c=0;c1)throw new l["default"]("Unsupported number of partial arguments: "+c.length,a);c.length||(this.options.explicitPartialContext?this.opcode("pushLiteral","undefined"):c.push({type:"PathExpression",parts:[],depth:0}));var d=a.name.original,e="SubExpression"===a.name.type;e&&this.accept(a.name),this.setupFullMustacheParams(a,b,void 0,!0);var f=a.indent||"";this.options.preventIndent&&f&&(this.opcode("appendContent",f),f=""),this.opcode("invokePartial",e,d,f),this.opcode("append")},PartialBlockStatement:function(a){this.PartialStatement(a)},MustacheStatement:function(a){this.SubExpression(a),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},Decorator:function(a){this.DecoratorBlock(a)},ContentStatement:function(a){a.value&&this.opcode("appendContent",a.value)},CommentStatement:function(){},SubExpression:function(a){h(a);var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ambiguousSexpr:function(a,b,c){var d=a.path,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),d.strict=!0,this.accept(d),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.path;b.strict=!0,this.accept(b),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.path,f=e.parts[0];if(this.options.knownHelpers[f])this.opcode("invokeKnownHelper",d.length,f);else{if(this.options.knownHelpersOnly)throw new l["default"]("You specified knownHelpersOnly, but used the unknown helper "+f,a);e.strict=!0,e.falsy=!0,this.accept(e),this.opcode("invokeHelper",d.length,e.original,o["default"].helpers.simpleId(e))}},PathExpression:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0],c=o["default"].helpers.scopedId(a),d=!a.depth&&!c&&this.blockParamIndex(b);d?this.opcode("lookupBlockParam",d,a.parts):b?a.data?(this.options.data=!0,this.opcode("lookupData",a.depth,a.parts,a.strict)):this.opcode("lookupOnContext",a.parts,a.falsy,a.strict,c):this.opcode("pushContext")},StringLiteral:function(a){this.opcode("pushString",a.value)},NumberLiteral:function(a){this.opcode("pushLiteral",a.value)},BooleanLiteral:function(a){this.opcode("pushLiteral",a.value)},UndefinedLiteral:function(){this.opcode("pushLiteral","undefined")},NullLiteral:function(){this.opcode("pushLiteral","null")},Hash:function(a){var b=a.pairs,c=0,d=b.length;for(this.opcode("pushHash");c=0)return[b,e]}}}},function(a,b,c){"use strict";function d(a){this.value=a}function e(){}function f(a,b,c,d){var e=b.popStack(),f=0,g=c.length;for(a&&g--;f0&&(c+=", "+d.join(", "));var e=0;g(this.aliases).forEach(function(a){var d=b.aliases[a];d.children&&d.referenceCount>1&&(c+=", alias"+ ++e+"="+a,d.children[0]="alias"+e)}),this.lookupPropertyFunctionIsUsed&&(c+=", "+this.lookupPropertyFunctionVarDeclaration());var f=["container","depth0","helpers","partials","data"];(this.useBlockParams||this.useDepths)&&f.push("blockParams"),this.useDepths&&f.push("depths");var h=this.mergeSource(c);return a?(f.push(h),Function.apply(this,f)):this.source.wrap(["function(",f.join(","),") {\n ",h,"}"])},mergeSource:function(a){var b=this.environment.isSimple,c=!this.forceBuffer,d=void 0,e=void 0,f=void 0,g=void 0;return this.source.each(function(a){a.appendToBuffer?(f?a.prepend(" + "):f=a,g=a):(f&&(e?f.prepend("buffer += "):d=!0,g.add(";"),f=g=void 0),e=!0,b||(c=!1))}),c?f?(f.prepend("return "),g.add(";")):e||this.source.push('return "";'):(a+=", buffer = "+(d?"":this.initializeBuffer()),f?(f.prepend("return buffer + "),g.add(";")):this.source.push("return buffer;")),a&&this.source.prepend("var "+a.substring(2)+(d?"":";\n")),this.source.merge()},lookupPropertyFunctionVarDeclaration:function(){return"\n lookupProperty = container.lookupProperty || function(parent, propertyName) {\n if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {\n return parent[propertyName];\n }\n return undefined\n }\n ".trim()},blockValue:function(a){var b=this.aliasable("container.hooks.blockHelperMissing"),c=[this.contextName(0)];this.setupHelperArgs(a,0,c);var d=this.popStack();c.splice(1,0,d),this.push(this.source.functionCall(b,"call",c))},ambiguousBlockValue:function(){var a=this.aliasable("container.hooks.blockHelperMissing"),b=[this.contextName(0)];this.setupHelperArgs("",0,b,!0),this.flushInline();var c=this.topStack();b.splice(1,0,c),this.pushSource(["if (!",this.lastHelper,") { ",c," = ",this.source.functionCall(a,"call",b),"}"])},appendContent:function(a){this.pendingContent?a=this.pendingContent+a:this.pendingLocation=this.source.currentLocation,this.pendingContent=a},append:function(){if(this.isInline())this.replaceStack(function(a){return[" != null ? ",a,' : ""']}),this.pushSource(this.appendToBuffer(this.popStack()));else{var a=this.popStack();this.pushSource(["if (",a," != null) { ",this.appendToBuffer(a,void 0,!0)," }"]),this.environment.isSimple&&this.pushSource(["else { ",this.appendToBuffer("''",void 0,!0)," }"])}},appendEscaped:function(){this.pushSource(this.appendToBuffer([this.aliasable("container.escapeExpression"),"(",this.popStack(),")"]))},getContext:function(a){this.lastContext=a},pushContext:function(){this.pushStackLiteral(this.contextName(this.lastContext))},lookupOnContext:function(a,b,c,d){var e=0;d||!this.options.compat||this.lastContext?this.pushContext():this.push(this.depthedLookup(a[e++])),this.resolvePath("context",a,e,b,c)},lookupBlockParam:function(a,b){this.useBlockParams=!0,this.push(["blockParams[",a[0],"][",a[1],"]"]),this.resolvePath("context",b,1)},lookupData:function(a,b,c){a?this.pushStackLiteral("container.data(data, "+a+")"):this.pushStackLiteral("data"),this.resolvePath("data",b,0,!0,c)},resolvePath:function(a,b,c,d,e){var g=this;if(this.options.strict||this.options.assumeObjects)return void this.push(f(this.options.strict&&e,this,b,a));for(var h=b.length;cthis.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;this.inlineStack=[];for(var b=0,c=a.length;b + \ No newline at end of file diff --git a/assets/js/jquery.qtip/index.php b/assets/js/jquery.qtip/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/assets/js/jquery.qtip/index.php @@ -0,0 +1,3 @@ +0?setTimeout(d.proxy(a,this),b):void a.call(this)}function m(a){this.tooltip.hasClass(ab)||(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=l.call(this,function(){this.toggle(D,a)},this.options.show.delay))}function n(a){if(!this.tooltip.hasClass(ab)&&!this.destroyed){var b=d(a.relatedTarget),c=b.closest(W)[0]===this.tooltip[0],e=b[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==b[0]&&"mouse"===this.options.position.target&&c||this.options.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(c||e))try{a.preventDefault(),a.stopImmediatePropagation()}catch(f){}else this.timers.hide=l.call(this,function(){this.toggle(E,a)},this.options.hide.delay,this)}}function o(a){!this.tooltip.hasClass(ab)&&this.options.hide.inactive&&(clearTimeout(this.timers.inactive),this.timers.inactive=l.call(this,function(){this.hide(a)},this.options.hide.inactive))}function p(a){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(a)}function q(a,c,e){d(b.body).delegate(a,(c.split?c:c.join("."+S+" "))+"."+S,function(){var a=y.api[d.attr(this,U)];a&&!a.disabled&&e.apply(a,arguments)})}function r(a,c,f){var g,i,j,k,l,m=d(b.body),n=a[0]===b?m:a,o=a.metadata?a.metadata(f.metadata):F,p="html5"===f.metadata.type&&o?o[f.metadata.name]:F,q=a.data(f.metadata.name||"qtipopts");try{q="string"==typeof q?d.parseJSON(q):q}catch(r){}if(k=d.extend(D,{},y.defaults,f,"object"==typeof q?h(q):F,h(p||o)),i=k.position,k.id=c,"boolean"==typeof k.content.text){if(j=a.attr(k.content.attr),k.content.attr===E||!j)return E;k.content.text=j}if(i.container.length||(i.container=m),i.target===E&&(i.target=n),k.show.target===E&&(k.show.target=n),k.show.solo===D&&(k.show.solo=i.container.closest("body")),k.hide.target===E&&(k.hide.target=n),k.position.viewport===D&&(k.position.viewport=i.container),i.container=i.container.eq(0),i.at=new A(i.at,D),i.my=new A(i.my),a.data(S))if(k.overwrite)a.qtip("destroy",!0);else if(k.overwrite===E)return E;return a.attr(T,c),k.suppress&&(l=a.attr("title"))&&a.removeAttr("title").attr(cb,l).attr("title",""),g=new e(a,k,c,!!j),a.data(S,g),g}function s(a){return a.charAt(0).toUpperCase()+a.slice(1)}function t(a,b){var d,e,f=b.charAt(0).toUpperCase()+b.slice(1),g=(b+" "+rb.join(f+" ")+f).split(" "),h=0;if(qb[b])return a.css(qb[b]);for(;d=g[h++];)if((e=a.css(d))!==c)return qb[b]=d,e}function u(a,b){return Math.ceil(parseFloat(t(a,b)))}function v(a,b){this._ns="tip",this.options=b,this.offset=b.offset,this.size=[b.width,b.height],this.init(this.qtip=a)}function w(a,b){this.options=b,this._ns="-modal",this.init(this.qtip=a)}function x(a){this._ns="ie6",this.init(this.qtip=a)}var y,z,A,B,C,D=!0,E=!1,F=null,G="x",H="y",I="width",J="height",K="top",L="left",M="bottom",N="right",O="center",P="flipinvert",Q="shift",R={},S="qtip",T="data-hasqtip",U="data-qtip-id",V=["ui-widget","ui-tooltip"],W="."+S,X="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),Y=S+"-fixed",Z=S+"-default",$=S+"-focus",_=S+"-hover",ab=S+"-disabled",bb="_replacedByqTip",cb="oldtitle",db={ie:function(){for(var a=4,c=b.createElement("div");(c.innerHTML="")&&c.getElementsByTagName("i")[0];a+=1);return a>4?a:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||E};z=e.prototype,z._when=function(a){return d.when.apply(d,a)},z.render=function(a){if(this.rendered||this.destroyed)return this;var b,c=this,e=this.options,f=this.cache,g=this.elements,h=e.content.text,i=e.content.title,j=e.content.button,k=e.position,l=("."+this._id+" ",[]);return d.attr(this.target[0],"aria-describedby",this._id),f.posClass=this._createPosClass((this.position={my:k.my,at:k.at}).my),this.tooltip=g.tooltip=b=d("
",{id:this._id,"class":[S,Z,e.style.classes,f.posClass].join(" "),width:e.style.width||"",height:e.style.height||"",tracking:"mouse"===k.target&&k.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":E,"aria-describedby":this._id+"-content","aria-hidden":D}).toggleClass(ab,this.disabled).attr(U,this.id).data(S,this).appendTo(k.container).append(g.content=d("
",{"class":S+"-content",id:this._id+"-content","aria-atomic":D})),this.rendered=-1,this.positioning=D,i&&(this._createTitle(),d.isFunction(i)||l.push(this._updateTitle(i,E))),j&&this._createButton(),d.isFunction(h)||l.push(this._updateContent(h,E)),this.rendered=D,this._setWidget(),d.each(R,function(a){var b;"render"===this.initialize&&(b=this(c))&&(c.plugins[a]=b)}),this._unassignEvents(),this._assignEvents(),this._when(l).then(function(){c._trigger("render"),c.positioning=E,c.hiddenDuringWait||!e.show.ready&&!a||c.toggle(D,f.event,E),c.hiddenDuringWait=E}),y.api[this.id]=this,this},z.destroy=function(a){function b(){if(!this.destroyed){this.destroyed=D;var a,b=this.target,c=b.attr(cb);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),d.each(this.plugins,function(){this.destroy&&this.destroy()});for(a in this.timers)clearTimeout(this.timers[a]);b.removeData(S).removeAttr(U).removeAttr(T).removeAttr("aria-describedby"),this.options.suppress&&c&&b.attr("title",c).removeAttr(cb),this._unassignEvents(),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=F,delete y.api[this.id]}}return this.destroyed?this.target:(a===D&&"hide"!==this.triggering||!this.rendered?b.call(this):(this.tooltip.one("tooltiphidden",d.proxy(b,this)),!this.triggering&&this.hide()),this.target)},B=z.checks={builtin:{"^id$":function(a,b,c,e){var f=c===D?y.nextid:c,g=S+"-"+f;f!==E&&f.length>0&&!d("#"+g).length?(this._id=g,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):a[b]=e},"^prerender":function(a,b,c){c&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(a,b,c){this._updateContent(c)},"^content.attr$":function(a,b,c,d){this.options.content.text===this.target.attr(d)&&this._updateContent(this.target.attr(c))},"^content.title$":function(a,b,c){return c?(c&&!this.elements.title&&this._createTitle(),void this._updateTitle(c)):this._removeTitle()},"^content.button$":function(a,b,c){this._updateButton(c)},"^content.title.(text|button)$":function(a,b,c){this.set("content."+b,c)},"^position.(my|at)$":function(a,b,c){"string"==typeof c&&(this.position[b]=a[b]=new A(c,"at"===b))},"^position.container$":function(a,b,c){this.rendered&&this.tooltip.appendTo(c)},"^show.ready$":function(a,b,c){c&&(!this.rendered&&this.render(D)||this.toggle(D))},"^style.classes$":function(a,b,c,d){this.rendered&&this.tooltip.removeClass(d).addClass(c)},"^style.(width|height)":function(a,b,c){this.rendered&&this.tooltip.css(b,c)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(a,b,c){this.rendered&&this.tooltip.toggleClass(Z,!!c)},"^events.(render|show|move|hide|focus|blur)$":function(a,b,c){this.rendered&&this.tooltip[(d.isFunction(c)?"":"un")+"bind"]("tooltip"+b,c)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var a=this.options.position;this.tooltip.attr("tracking","mouse"===a.target&&a.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},z.get=function(a){if(this.destroyed)return this;var b=i(this.options,a.toLowerCase()),c=b[0][b[1]];return c.precedance?c.string():c};var eb=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,fb=/^prerender|show\.ready/i;z.set=function(a,b){if(this.destroyed)return this;{var c,e=this.rendered,f=E,g=this.options;this.checks}return"string"==typeof a?(c=a,a={},a[c]=b):a=d.extend({},a),d.each(a,function(b,c){if(e&&fb.test(b))return void delete a[b];var h,j=i(g,b.toLowerCase());h=j[0][j[1]],j[0][j[1]]=c&&c.nodeType?d(c):c,f=eb.test(b)||f,a[b]=[j[0],j[1],c,h]}),h(g),this.positioning=D,d.each(a,d.proxy(j,this)),this.positioning=E,this.rendered&&this.tooltip[0].offsetWidth>0&&f&&this.reposition("mouse"===g.position.target?F:this.cache.event),this},z._update=function(a,b){var c=this,e=this.cache;return this.rendered&&a?(d.isFunction(a)&&(a=a.call(this.elements.target,e.event,this)||""),d.isFunction(a.then)?(e.waiting=D,a.then(function(a){return e.waiting=E,c._update(a,b)},F,function(a){return c._update(a,b)})):a===E||!a&&""!==a?E:(a.jquery&&a.length>0?b.empty().append(a.css({display:"block",visibility:"visible"})):b.html(a),this._waitForContent(b).then(function(a){c.rendered&&c.tooltip[0].offsetWidth>0&&c.reposition(e.event,!a.length)}))):E},z._waitForContent=function(a){var b=this.cache;return b.waiting=D,(d.fn.imagesLoaded?a.imagesLoaded():d.Deferred().resolve([])).done(function(){b.waiting=E}).promise()},z._updateContent=function(a,b){this._update(a,this.elements.content,b)},z._updateTitle=function(a,b){this._update(a,this.elements.title,b)===E&&this._removeTitle(E)},z._createTitle=function(){var a=this.elements,b=this._id+"-title";a.titlebar&&this._removeTitle(),a.titlebar=d("
",{"class":S+"-titlebar "+(this.options.style.widget?k("header"):"")}).append(a.title=d("
",{id:b,"class":S+"-title","aria-atomic":D})).insertBefore(a.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(a){d(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(a){d(this).toggleClass("ui-state-hover","mouseover"===a.type)}),this.options.content.button&&this._createButton()},z._removeTitle=function(a){var b=this.elements;b.title&&(b.titlebar.remove(),b.titlebar=b.title=b.button=F,a!==E&&this.reposition())},z._createPosClass=function(a){return S+"-pos-"+(a||this.options.position.my).abbrev()},z.reposition=function(c,e){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=D;var f,g,h,i,j=this.cache,k=this.tooltip,l=this.options.position,m=l.target,n=l.my,o=l.at,p=l.viewport,q=l.container,r=l.adjust,s=r.method.split(" "),t=k.outerWidth(E),u=k.outerHeight(E),v=0,w=0,x=k.css("position"),y={left:0,top:0},z=k[0].offsetWidth>0,A=c&&"scroll"===c.type,B=d(a),C=q[0].ownerDocument,F=this.mouse;if(d.isArray(m)&&2===m.length)o={x:L,y:K},y={left:m[0],top:m[1]};else if("mouse"===m)o={x:L,y:K},(!r.mouse||this.options.hide.distance)&&j.origin&&j.origin.pageX?c=j.origin:!c||c&&("resize"===c.type||"scroll"===c.type)?c=j.event:F&&F.pageX&&(c=F),"static"!==x&&(y=q.offset()),C.body.offsetWidth!==(a.innerWidth||C.documentElement.clientWidth)&&(g=d(b.body).offset()),y={left:c.pageX-y.left+(g&&g.left||0),top:c.pageY-y.top+(g&&g.top||0)},r.mouse&&A&&F&&(y.left-=(F.scrollX||0)-B.scrollLeft(),y.top-=(F.scrollY||0)-B.scrollTop());else{if("event"===m?c&&c.target&&"scroll"!==c.type&&"resize"!==c.type?j.target=d(c.target):c.target||(j.target=this.elements.target):"event"!==m&&(j.target=d(m.jquery?m:this.elements.target)),m=j.target,m=d(m).eq(0),0===m.length)return this;m[0]===b||m[0]===a?(v=db.iOS?a.innerWidth:m.width(),w=db.iOS?a.innerHeight:m.height(),m[0]===a&&(y={top:(p||m).scrollTop(),left:(p||m).scrollLeft()})):R.imagemap&&m.is("area")?f=R.imagemap(this,m,o,R.viewport?s:E):R.svg&&m&&m[0].ownerSVGElement?f=R.svg(this,m,o,R.viewport?s:E):(v=m.outerWidth(E),w=m.outerHeight(E),y=m.offset()),f&&(v=f.width,w=f.height,g=f.offset,y=f.position),y=this.reposition.offset(m,y,q),(db.iOS>3.1&&db.iOS<4.1||db.iOS>=4.3&&db.iOS<4.33||!db.iOS&&"fixed"===x)&&(y.left-=B.scrollLeft(),y.top-=B.scrollTop()),(!f||f&&f.adjustable!==E)&&(y.left+=o.x===N?v:o.x===O?v/2:0,y.top+=o.y===M?w:o.y===O?w/2:0)}return y.left+=r.x+(n.x===N?-t:n.x===O?-t/2:0),y.top+=r.y+(n.y===M?-u:n.y===O?-u/2:0),R.viewport?(h=y.adjusted=R.viewport(this,y,l,v,w,t,u),g&&h.left&&(y.left+=g.left),g&&h.top&&(y.top+=g.top),h.my&&(this.position.my=h.my)):y.adjusted={left:0,top:0},j.posClass!==(i=this._createPosClass(this.position.my))&&k.removeClass(j.posClass).addClass(j.posClass=i),this._trigger("move",[y,p.elem||p],c)?(delete y.adjusted,e===E||!z||isNaN(y.left)||isNaN(y.top)||"mouse"===m||!d.isFunction(l.effect)?k.css(y):d.isFunction(l.effect)&&(l.effect.call(k,this,d.extend({},y)),k.queue(function(a){d(this).css({opacity:"",height:""}),db.ie&&this.style.removeAttribute("filter"),a()})),this.positioning=E,this):this},z.reposition.offset=function(a,c,e){function f(a,b){c.left+=b*a.scrollLeft(),c.top+=b*a.scrollTop()}if(!e[0])return c;var g,h,i,j,k=d(a[0].ownerDocument),l=!!db.ie&&"CSS1Compat"!==b.compatMode,m=e[0];do"static"!==(h=d.css(m,"position"))&&("fixed"===h?(i=m.getBoundingClientRect(),f(k,-1)):(i=d(m).position(),i.left+=parseFloat(d.css(m,"borderLeftWidth"))||0,i.top+=parseFloat(d.css(m,"borderTopWidth"))||0),c.left-=i.left+(parseFloat(d.css(m,"marginLeft"))||0),c.top-=i.top+(parseFloat(d.css(m,"marginTop"))||0),g||"hidden"===(j=d.css(m,"overflow"))||"visible"===j||(g=d(m)));while(m=m.offsetParent);return g&&(g[0]!==k[0]||l)&&f(g,1),c};var gb=(A=z.reposition.Corner=function(a,b){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,O).toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!b;var c=a.charAt(0);this.precedance="t"===c||"b"===c?H:G}).prototype;gb.invert=function(a,b){this[a]=this[a]===L?N:this[a]===N?L:b||this[a]},gb.string=function(a){var b=this.x,c=this.y,d=b!==c?"center"===b||"center"!==c&&(this.precedance===H||this.forceY)?[c,b]:[b,c]:[b];return a!==!1?d.join(" "):d},gb.abbrev=function(){var a=this.string(!1);return a[0].charAt(0)+(a[1]&&a[1].charAt(0)||"")},gb.clone=function(){return new A(this.string(),this.forceY)},z.toggle=function(a,c){var e=this.cache,f=this.options,g=this.tooltip;if(c){if(/over|enter/.test(c.type)&&e.event&&/out|leave/.test(e.event.type)&&f.show.target.add(c.target).length===f.show.target.length&&g.has(c.relatedTarget).length)return this;e.event=d.event.fix(c)}if(this.waiting&&!a&&(this.hiddenDuringWait=D),!this.rendered)return a?this.render(1):this;if(this.destroyed||this.disabled)return this;var h,i,j,k=a?"show":"hide",l=this.options[k],m=(this.options[a?"hide":"show"],this.options.position),n=this.options.content,o=this.tooltip.css("width"),p=this.tooltip.is(":visible"),q=a||1===l.target.length,r=!c||l.target.length<2||e.target[0]===c.target;return(typeof a).search("boolean|number")&&(a=!p),h=!g.is(":animated")&&p===a&&r,i=h?F:!!this._trigger(k,[90]),this.destroyed?this:(i!==E&&a&&this.focus(c),!i||h?this:(d.attr(g[0],"aria-hidden",!a),a?(this.mouse&&(e.origin=d.event.fix(this.mouse)),d.isFunction(n.text)&&this._updateContent(n.text,E),d.isFunction(n.title)&&this._updateTitle(n.title,E),!C&&"mouse"===m.target&&m.adjust.mouse&&(d(b).bind("mousemove."+S,this._storeMouse),C=D),o||g.css("width",g.outerWidth(E)),this.reposition(c,arguments[2]),o||g.css("width",""),l.solo&&("string"==typeof l.solo?d(l.solo):d(W,l.solo)).not(g).not(l.target).qtip("hide",d.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete e.origin,C&&!d(W+'[tracking="true"]:visible',l.solo).not(g).length&&(d(b).unbind("mousemove."+S),C=E),this.blur(c)),j=d.proxy(function(){a?(db.ie&&g[0].style.removeAttribute("filter"),g.css("overflow",""),"string"==typeof l.autofocus&&d(this.options.show.autofocus,g).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):g.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(a?"visible":"hidden")},this),l.effect===E||q===E?(g[k](),j()):d.isFunction(l.effect)?(g.stop(1,1),l.effect.call(g,this),g.queue("fx",function(a){j(),a()})):g.fadeTo(90,a?1:0,j),a&&l.target.trigger("qtip-"+this.id+"-inactive"),this))},z.show=function(a){return this.toggle(D,a)},z.hide=function(a){return this.toggle(E,a)},z.focus=function(a){if(!this.rendered||this.destroyed)return this;var b=d(W),c=this.tooltip,e=parseInt(c[0].style.zIndex,10),f=y.zindex+b.length;return c.hasClass($)||this._trigger("focus",[f],a)&&(e!==f&&(b.each(function(){this.style.zIndex>e&&(this.style.zIndex=this.style.zIndex-1)}),b.filter("."+$).qtip("blur",a)),c.addClass($)[0].style.zIndex=f),this},z.blur=function(a){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass($),this._trigger("blur",[this.tooltip.css("zIndex")],a),this)},z.disable=function(a){return this.destroyed?this:("toggle"===a?a=!(this.rendered?this.tooltip.hasClass(ab):this.disabled):"boolean"!=typeof a&&(a=D),this.rendered&&this.tooltip.toggleClass(ab,a).attr("aria-disabled",a),this.disabled=!!a,this)},z.enable=function(){return this.disable(E)},z._createButton=function(){var a=this,b=this.elements,c=b.tooltip,e=this.options.content.button,f="string"==typeof e,g=f?e:"Close tooltip";b.button&&b.button.remove(),b.button=e.jquery?e:d("",{"class":"qtip-close "+(this.options.style.widget?"":S+"-icon"),title:g,"aria-label":g}).prepend(d("",{"class":"ui-icon ui-icon-close",html:"×"})),b.button.appendTo(b.titlebar||c).attr("role","button").click(function(b){return c.hasClass(ab)||a.hide(b),E})},z._updateButton=function(a){if(!this.rendered)return E;var b=this.elements.button;a?this._createButton():b.remove()},z._setWidget=function(){var a=this.options.style.widget,b=this.elements,c=b.tooltip,d=c.hasClass(ab);c.removeClass(ab),ab=a?"ui-state-disabled":"qtip-disabled",c.toggleClass(ab,d),c.toggleClass("ui-helper-reset "+k(),a).toggleClass(Z,this.options.style.def&&!a),b.content&&b.content.toggleClass(k("content"),a),b.titlebar&&b.titlebar.toggleClass(k("header"),a),b.button&&b.button.toggleClass(S+"-icon",!a)},z._storeMouse=function(a){return(this.mouse=d.event.fix(a)).type="mousemove",this},z._bind=function(a,b,c,e,f){if(a&&c&&b.length){var g="."+this._id+(e?"-"+e:"");return d(a).bind((b.split?b:b.join(g+" "))+g,d.proxy(c,f||this)),this}},z._unbind=function(a,b){return a&&d(a).unbind("."+this._id+(b?"-"+b:"")),this},z._trigger=function(a,b,c){var e=d.Event("tooltip"+a);return e.originalEvent=c&&d.extend({},c)||this.cache.event||F,this.triggering=a,this.tooltip.trigger(e,[this].concat(b||[])),this.triggering=E,!e.isDefaultPrevented()},z._bindEvents=function(a,b,c,e,f,g){var h=c.filter(e).add(e.filter(c)),i=[];h.length&&(d.each(b,function(b,c){var e=d.inArray(c,a);e>-1&&i.push(a.splice(e,1)[0])}),i.length&&(this._bind(h,i,function(a){var b=this.rendered?this.tooltip[0].offsetWidth>0:!1;(b?g:f).call(this,a)}),c=c.not(h),e=e.not(h))),this._bind(c,a,f),this._bind(e,b,g)},z._assignInitialEvents=function(a){function b(a){return this.disabled||this.destroyed?E:(this.cache.event=a&&d.event.fix(a),this.cache.target=a&&d(a.target),clearTimeout(this.timers.show),void(this.timers.show=l.call(this,function(){this.render("object"==typeof a||c.show.ready)},c.prerender?0:c.show.delay)))}var c=this.options,e=c.show.target,f=c.hide.target,g=c.show.event?d.trim(""+c.show.event).split(" "):[],h=c.hide.event?d.trim(""+c.hide.event).split(" "):[];this._bind(this.elements.target,["remove","removeqtip"],function(){this.destroy(!0)},"destroy"),/mouse(over|enter)/i.test(c.show.event)&&!/mouse(out|leave)/i.test(c.hide.event)&&h.push("mouseleave"),this._bind(e,"mousemove",function(a){this._storeMouse(a),this.cache.onTarget=D}),this._bindEvents(g,h,e,f,b,function(){return this.timers?void clearTimeout(this.timers.show):E}),(c.show.ready||c.prerender)&&b.call(this,a)},z._assignEvents=function(){var c=this,e=this.options,f=e.position,g=this.tooltip,h=e.show.target,i=e.hide.target,j=f.container,k=f.viewport,l=d(b),q=(d(b.body),d(a)),r=e.show.event?d.trim(""+e.show.event).split(" "):[],s=e.hide.event?d.trim(""+e.hide.event).split(" "):[];d.each(e.events,function(a,b){c._bind(g,"toggle"===a?["tooltipshow","tooltiphide"]:["tooltip"+a],b,null,g)}),/mouse(out|leave)/i.test(e.hide.event)&&"window"===e.hide.leave&&this._bind(l,["mouseout","blur"],function(a){/select|option/.test(a.target.nodeName)||a.relatedTarget||this.hide(a)}),e.hide.fixed?i=i.add(g.addClass(Y)):/mouse(over|enter)/i.test(e.show.event)&&this._bind(i,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+e.hide.event).indexOf("unfocus")>-1&&this._bind(j.closest("html"),["mousedown","touchstart"],function(a){var b=d(a.target),c=this.rendered&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0,e=b.parents(W).filter(this.tooltip[0]).length>0;b[0]===this.target[0]||b[0]===this.tooltip[0]||e||this.target.has(b[0]).length||!c||this.hide(a)}),"number"==typeof e.hide.inactive&&(this._bind(h,"qtip-"+this.id+"-inactive",o,"inactive"),this._bind(i.add(g),y.inactiveEvents,o)),this._bindEvents(r,s,h,i,m,n),this._bind(h.add(g),"mousemove",function(a){if("number"==typeof e.hide.distance){var b=this.cache.origin||{},c=this.options.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&this.hide(a)}this._storeMouse(a)}),"mouse"===f.target&&f.adjust.mouse&&(e.hide.event&&this._bind(h,["mouseenter","mouseleave"],function(a){return this.cache?void(this.cache.onTarget="mouseenter"===a.type):E}),this._bind(l,"mousemove",function(a){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0&&this.reposition(a)})),(f.adjust.resize||k.length)&&this._bind(d.event.special.resize?k:q,"resize",p),f.adjust.scroll&&this._bind(q.add(f.container),"scroll",p)},z._unassignEvents=function(){var c=this.options,e=c.show.target,f=c.hide.target,g=d.grep([this.elements.target[0],this.rendered&&this.tooltip[0],c.position.container[0],c.position.viewport[0],c.position.container.closest("html")[0],a,b],function(a){return"object"==typeof a});e&&e.toArray&&(g=g.concat(e.toArray())),f&&f.toArray&&(g=g.concat(f.toArray())),this._unbind(g)._unbind(g,"destroy")._unbind(g,"inactive")},d(function(){q(W,["mouseenter","mouseleave"],function(a){var b="mouseenter"===a.type,c=d(a.currentTarget),e=d(a.relatedTarget||a.target),f=this.options;b?(this.focus(a),c.hasClass(Y)&&!c.hasClass(ab)&&clearTimeout(this.timers.hide)):"mouse"===f.position.target&&f.position.adjust.mouse&&f.hide.event&&f.show.target&&!e.closest(f.show.target[0]).length&&this.hide(a),c.toggleClass(_,b)}),q("["+U+"]",X,o)}),y=d.fn.qtip=function(a,b,e){var f=(""+a).toLowerCase(),g=F,i=d.makeArray(arguments).slice(1),j=i[i.length-1],k=this[0]?d.data(this[0],S):F;return!arguments.length&&k||"api"===f?k:"string"==typeof a?(this.each(function(){var a=d.data(this,S);if(!a)return D;if(j&&j.timeStamp&&(a.cache.event=j),!b||"option"!==f&&"options"!==f)a[f]&&a[f].apply(a,i);else{if(e===c&&!d.isPlainObject(b))return g=a.get(b),E;a.set(b,e)}}),g!==F?g:this):"object"!=typeof a&&arguments.length?void 0:(k=h(d.extend(D,{},a)),this.each(function(a){var b,c;return c=d.isArray(k.id)?k.id[a]:k.id,c=!c||c===E||c.length<1||y.api[c]?y.nextid++:c,b=r(d(this),c,k),b===E?D:(y.api[c]=b,d.each(R,function(){"initialize"===this.initialize&&this(b)}),void b._assignInitialEvents(j))}))},d.qtip=e,y.api={},d.each({attr:function(a,b){if(this.length){var c=this[0],e="title",f=d.data(c,"qtip");if(a===e&&f&&"object"==typeof f&&f.options.suppress)return arguments.length<2?d.attr(c,cb):(f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",b),this.attr(cb,b))}return d.fn["attr"+bb].apply(this,arguments)},clone:function(a){var b=(d([]),d.fn["clone"+bb].apply(this,arguments));return a||b.filter("["+cb+"]").attr("title",function(){return d.attr(this,cb)}).removeAttr(cb),b}},function(a,b){if(!b||d.fn[a+bb])return D;var c=d.fn[a+bb]=d.fn[a];d.fn[a]=function(){return b.apply(this,arguments)||c.apply(this,arguments)}}),d.ui||(d["cleanData"+bb]=d.cleanData,d.cleanData=function(a){for(var b,c=0;(b=d(a[c])).length;c++)if(b.attr(T))try{b.triggerHandler("removeqtip")}catch(e){}d["cleanData"+bb].apply(this,arguments)}),y.version="2.2.1",y.nextid=0,y.inactiveEvents=X,y.zindex=15e3,y.defaults={prerender:E,id:E,overwrite:D,suppress:D,content:{text:D,attr:"title",title:E,button:E},position:{my:"top left",at:"bottom right",target:E,container:E,viewport:E,adjust:{x:0,y:0,mouse:D,scroll:D,resize:D,method:"flipinvert flipinvert"},effect:function(a,b){d(this).animate(b,{duration:200,queue:E})}},show:{target:E,event:"mouseenter",effect:D,delay:90,solo:E,ready:E,autofocus:E},hide:{target:E,event:"mouseleave",effect:D,delay:0,fixed:E,inactive:E,leave:"window",distance:E},style:{classes:"",widget:E,width:E,height:E,def:D},events:{render:F,move:F,show:F,hide:F,toggle:F,visible:F,hidden:F,focus:F,blur:F}};var hb,ib="margin",jb="border",kb="color",lb="background-color",mb="transparent",nb=" !important",ob=!!b.createElement("canvas").getContext,pb=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,qb={},rb=["Webkit","O","Moz","ms"];if(ob)var sb=a.devicePixelRatio||1,tb=function(){var a=b.createElement("canvas").getContext("2d");return a.backingStorePixelRatio||a.webkitBackingStorePixelRatio||a.mozBackingStorePixelRatio||a.msBackingStorePixelRatio||a.oBackingStorePixelRatio||1}(),ub=sb/tb;else var vb=function(a,b,c){return"'};d.extend(v.prototype,{init:function(a){var b,c;c=this.element=a.elements.tip=d("
",{"class":S+"-tip"}).prependTo(a.tooltip),ob?(b=d("").appendTo(this.element)[0].getContext("2d"),b.lineJoin="miter",b.miterLimit=1e5,b.save()):(b=vb("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(b+b),a._bind(d("*",c).add(c),["click","mousedown"],function(a){a.stopPropagation()},this._ns)),a._bind(a.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(a){var b=this.qtip.elements.titlebar;return b&&(a.y===K||a.y===O&&this.element.position().top+this.size[1]/2+this.options.offsetl&&!pb.test(e[1])&&(e[0]=e[1]),this.border=l=p.border!==D?p.border:l):this.border=l=0,k=this.size=this._calculateSize(b),n.css({width:k[0],height:k[1],lineHeight:k[1]+"px"}),j=b.precedance===H?[s(r.x===L?l:r.x===N?k[0]-q[0]-l:(k[0]-q[0])/2),s(r.y===K?k[1]-q[1]:0)]:[s(r.x===L?k[0]-q[0]:0),s(r.y===K?l:r.y===M?k[1]-q[1]-l:(k[1]-q[1])/2)],ob?(g=o[0].getContext("2d"),g.restore(),g.save(),g.clearRect(0,0,6e3,6e3),h=this._calculateTip(r,q,ub),i=this._calculateTip(r,this.size,ub),o.attr(I,k[0]*ub).attr(J,k[1]*ub),o.css(I,k[0]).css(J,k[1]),this._drawCoords(g,i),g.fillStyle=e[1],g.fill(),g.translate(j[0]*ub,j[1]*ub),this._drawCoords(g,h),g.fillStyle=e[0],g.fill()):(h=this._calculateTip(r),h="m"+h[0]+","+h[1]+" l"+h[2]+","+h[3]+" "+h[4]+","+h[5]+" xe",j[2]=l&&/^(r|b)/i.test(b.string())?8===db.ie?2:1:0,o.css({coordsize:k[0]+l+" "+(k[1]+l),antialias:""+(r.string().indexOf(O)>-1),left:j[0]-j[2]*Number(f===G),top:j[1]-j[2]*Number(f===H),width:k[0]+l,height:k[1]+l}).each(function(a){var b=d(this);b[b.prop?"prop":"attr"]({coordsize:k[0]+l+" "+(k[1]+l),path:h,fillcolor:e[0],filled:!!a,stroked:!a}).toggle(!(!l&&!a)),!a&&b.html(vb("stroke",'weight="'+2*l+'px" color="'+e[1]+'" miterlimit="1000" joinstyle="miter"'))})),a.opera&&setTimeout(function(){m.tip.css({display:"inline-block",visibility:"visible"})},1),c!==E&&this.calculate(b,k)},calculate:function(a,b){if(!this.enabled)return E;var c,e,f=this,g=this.qtip.elements,h=this.element,i=this.options.offset,j=(g.tooltip.hasClass("ui-widget"),{});return a=a||this.corner,c=a.precedance,b=b||this._calculateSize(a),e=[a.x,a.y],c===G&&e.reverse(),d.each(e,function(d,e){var h,k,l; +e===O?(h=c===H?L:K,j[h]="50%",j[ib+"-"+h]=-Math.round(b[c===H?0:1]/2)+i):(h=f._parseWidth(a,e,g.tooltip),k=f._parseWidth(a,e,g.content),l=f._parseRadius(a),j[e]=Math.max(-f.border,d?k:i+(l>h?l:-h)))}),j[a[c]]-=b[c===G?0:1],h.css({margin:"",top:"",bottom:"",left:"",right:""}).css(j),j},reposition:function(a,b,d){function e(a,b,c,d,e){a===Q&&j.precedance===b&&k[d]&&j[c]!==O?j.precedance=j.precedance===G?H:G:a!==Q&&k[d]&&(j[b]=j[b]===O?k[d]>0?d:e:j[b]===d?e:d)}function f(a,b,e){j[a]===O?p[ib+"-"+b]=o[a]=g[ib+"-"+b]-k[b]:(h=g[e]!==c?[k[b],-g[b]]:[-k[b],g[b]],(o[a]=Math.max(h[0],h[1]))>h[0]&&(d[b]-=k[b],o[b]=E),p[g[e]!==c?e:b]=o[a])}if(this.enabled){var g,h,i=b.cache,j=this.corner.clone(),k=d.adjusted,l=b.options.position.adjust.method.split(" "),m=l[0],n=l[1]||l[0],o={left:E,top:E,x:0,y:0},p={};this.corner.fixed!==D&&(e(m,G,H,L,N),e(n,H,G,K,M),(j.string()!==i.corner.string()||i.cornerTop!==k.top||i.cornerLeft!==k.left)&&this.update(j,E)),g=this.calculate(j),g.right!==c&&(g.left=-g.right),g.bottom!==c&&(g.top=-g.bottom),g.user=this.offset,(o.left=m===Q&&!!k.left)&&f(G,L,N),(o.top=n===Q&&!!k.top)&&f(H,K,M),this.element.css(p).toggle(!(o.x&&o.y||j.x===O&&o.y||j.y===O&&o.x)),d.left-=g.left.charAt?g.user:m!==Q||o.top||!o.left&&!o.top?g.left+this.border:0,d.top-=g.top.charAt?g.user:n!==Q||o.left||!o.left&&!o.top?g.top+this.border:0,i.cornerLeft=k.left,i.cornerTop=k.top,i.corner=j.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),hb=R.tip=function(a){return new v(a,a.options.style.tip)},hb.initialize="render",hb.sanitize=function(a){if(a.style&&"tip"in a.style){var b=a.style.tip;"object"!=typeof b&&(b=a.style.tip={corner:b}),/string|boolean/i.test(typeof b.corner)||(b.corner=D)}},B.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(a){this.size=[a.width,a.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},d.extend(D,y.defaults,{style:{tip:{corner:D,mimic:E,width:6,height:6,border:D,offset:0}}});var wb,xb,yb="qtip-modal",zb="."+yb;xb=function(){function a(a){if(d.expr[":"].focusable)return d.expr[":"].focusable;var b,c,e,f=!isNaN(d.attr(a,"tabindex")),g=a.nodeName&&a.nodeName.toLowerCase();return"area"===g?(b=a.parentNode,c=b.name,a.href&&c&&"map"===b.nodeName.toLowerCase()?(e=d("img[usemap=#"+c+"]")[0],!!e&&e.is(":visible")):!1):/input|select|textarea|button|object/.test(g)?!a.disabled:"a"===g?a.href||f:f}function c(a){k.length<1&&a.length?a.not("body").blur():k.first().focus()}function e(a){if(i.is(":visible")){var b,e=d(a.target),h=f.tooltip,j=e.closest(W);b=j.length<1?E:parseInt(j[0].style.zIndex,10)>parseInt(h[0].style.zIndex,10),b||e.closest(W)[0]===h[0]||c(e),g=a.target===k[k.length-1]}}var f,g,h,i,j=this,k={};d.extend(j,{init:function(){return i=j.elem=d("
",{id:"qtip-overlay",html:"
",mousedown:function(){return E}}).hide(),d(b.body).bind("focusin"+zb,e),d(b).bind("keydown"+zb,function(a){f&&f.options.show.modal.escape&&27===a.keyCode&&f.hide(a)}),i.bind("click"+zb,function(a){f&&f.options.show.modal.blur&&f.hide(a)}),j},update:function(b){f=b,k=b.options.show.modal.stealfocus!==E?b.tooltip.find("*").filter(function(){return a(this)}):[]},toggle:function(a,e,g){var k=(d(b.body),a.tooltip),l=a.options.show.modal,m=l.effect,n=e?"show":"hide",o=i.is(":visible"),p=d(zb).filter(":visible:not(:animated)").not(k);return j.update(a),e&&l.stealfocus!==E&&c(d(":focus")),i.toggleClass("blurs",l.blur),e&&i.appendTo(b.body),i.is(":animated")&&o===e&&h!==E||!e&&p.length?j:(i.stop(D,E),d.isFunction(m)?m.call(i,e):m===E?i[n]():i.fadeTo(parseInt(g,10)||90,e?1:0,function(){e||i.hide()}),e||i.queue(function(a){i.css({left:"",top:""}),d(zb).length||i.detach(),a()}),h=e,f.destroyed&&(f=F),j)}}),j.init()},xb=new xb,d.extend(w.prototype,{init:function(a){var b=a.tooltip;return this.options.on?(a.elements.overlay=xb.elem,b.addClass(yb).css("z-index",y.modal_zindex+d(zb).length),a._bind(b,["tooltipshow","tooltiphide"],function(a,c,e){var f=a.originalEvent;if(a.target===b[0])if(f&&"tooltiphide"===a.type&&/mouse(leave|enter)/.test(f.type)&&d(f.relatedTarget).closest(xb.elem[0]).length)try{a.preventDefault()}catch(g){}else(!f||f&&"tooltipsolo"!==f.type)&&this.toggle(a,"tooltipshow"===a.type,e)},this._ns,this),a._bind(b,"tooltipfocus",function(a,c){if(!a.isDefaultPrevented()&&a.target===b[0]){var e=d(zb),f=y.modal_zindex+e.length,g=parseInt(b[0].style.zIndex,10);xb.elem[0].style.zIndex=f-1,e.each(function(){this.style.zIndex>g&&(this.style.zIndex-=1)}),e.filter("."+$).qtip("blur",a.originalEvent),b.addClass($)[0].style.zIndex=f,xb.update(c);try{a.preventDefault()}catch(h){}}},this._ns,this),void a._bind(b,"tooltiphide",function(a){a.target===b[0]&&d(zb).filter(":visible").not(b).last().qtip("focus",a)},this._ns,this)):this},toggle:function(a,b,c){return a&&a.isDefaultPrevented()?this:void xb.toggle(this.qtip,!!b,c)},destroy:function(){this.qtip.tooltip.removeClass(yb),this.qtip._unbind(this.qtip.tooltip,this._ns),xb.toggle(this.qtip,E),delete this.qtip.elements.overlay}}),wb=R.modal=function(a){return new w(a,a.options.show.modal)},wb.sanitize=function(a){a.show&&("object"!=typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"==typeof a.show.modal.on&&(a.show.modal.on=D))},y.modal_zindex=y.zindex-200,wb.initialize="render",B.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},d.extend(D,y.defaults,{show:{modal:{on:E,effect:D,blur:D,stealfocus:D,escape:D}}}),R.viewport=function(c,d,e,f,g,h,i){function j(a,b,c,e,f,g,h,i,j){var k=d[f],s=u[a],t=v[a],w=c===Q,x=s===f?j:s===g?-j:-j/2,y=t===f?i:t===g?-i:-i/2,z=q[f]+r[f]-(n?0:m[f]),A=z-k,B=k+j-(h===I?o:p)-z,C=x-(u.precedance===a||s===u[b]?y:0)-(t===O?i/2:0);return w?(C=(s===f?1:-1)*x,d[f]+=A>0?A:B>0?-B:0,d[f]=Math.max(-m[f]+r[f],k-C,Math.min(Math.max(-m[f]+r[f]+(h===I?o:p),k+C),d[f],"center"===s?k-x:1e9))):(e*=c===P?2:0,A>0&&(s!==f||B>0)?(d[f]-=C+e,l.invert(a,f)):B>0&&(s!==g||A>0)&&(d[f]-=(s===O?-C:C)+e,l.invert(a,g)),d[f]B&&(d[f]=k,l=u.clone())),d[f]-k}var k,l,m,n,o,p,q,r,s=e.target,t=c.elements.tooltip,u=e.my,v=e.at,w=e.adjust,x=w.method.split(" "),y=x[0],z=x[1]||x[0],A=e.viewport,B=e.container,C=(c.cache,{left:0,top:0});return A.jquery&&s[0]!==a&&s[0]!==b.body&&"none"!==w.method?(m=B.offset()||C,n="static"===B.css("position"),k="fixed"===t.css("position"),o=A[0]===a?A.width():A.outerWidth(E),p=A[0]===a?A.height():A.outerHeight(E),q={left:k?0:A.scrollLeft(),top:k?0:A.scrollTop()},r=A.offset()||C,("shift"!==y||"shift"!==z)&&(l=u.clone()),C={left:"none"!==y?j(G,H,y,w.x,L,N,I,f,h):0,top:"none"!==z?j(H,G,z,w.y,K,M,J,g,i):0,my:l}):C},R.polys={polygon:function(a,b){var c,d,e,f={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:E},g=0,h=[],i=1,j=1,k=0,l=0;for(g=a.length;g--;)c=[parseInt(a[--g],10),parseInt(a[g+1],10)],c[0]>f.position.right&&(f.position.right=c[0]),c[0]f.position.bottom&&(f.position.bottom=c[1]),c[1]0&&e>0&&i>0&&j>0;)for(d=Math.floor(d/2),e=Math.floor(e/2),b.x===L?i=d:b.x===N?i=f.width-d:i+=Math.floor(d/2),b.y===K?j=e:b.y===M?j=f.height-e:j+=Math.floor(e/2),g=h.length;g--&&!(h.length<2);)k=h[g][0]-f.position.left,l=h[g][1]-f.position.top,(b.x===L&&k>=i||b.x===N&&i>=k||b.x===O&&(i>k||k>f.width-i)||b.y===K&&l>=j||b.y===M&&j>=l||b.y===O&&(j>l||l>f.height-j))&&h.splice(g,1);f.position={left:h[0][0],top:h[0][1]}}return f},rect:function(a,b,c,d){return{width:Math.abs(c-a),height:Math.abs(d-b),position:{left:Math.min(a,c),top:Math.min(b,d)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(a,b,c,d,e){var f=R.polys._angles[e.abbrev()],g=0===f?0:c*Math.cos(f*Math.PI),h=d*Math.sin(f*Math.PI);return{width:2*c-Math.abs(g),height:2*d-Math.abs(h),position:{left:a+g,top:b+h},adjustable:E}},circle:function(a,b,c,d){return R.polys.ellipse(a,b,c,c,d)}},R.svg=function(a,c,e){for(var f,g,h,i,j,k,l,m,n,o=(d(b),c[0]),p=d(o.ownerSVGElement),q=o.ownerDocument,r=(parseInt(c.css("stroke-width"),10)||0)/2;!o.getBBox;)o=o.parentNode;if(!o.getBBox||!o.parentNode)return E;switch(o.nodeName){case"ellipse":case"circle":m=R.polys.ellipse(o.cx.baseVal.value,o.cy.baseVal.value,(o.rx||o.r).baseVal.value+r,(o.ry||o.r).baseVal.value+r,e);break;case"line":case"polygon":case"polyline":for(l=o.points||[{x:o.x1.baseVal.value,y:o.y1.baseVal.value},{x:o.x2.baseVal.value,y:o.y2.baseVal.value}],m=[],k=-1,i=l.numberOfItems||l.length;++k';d.extend(x.prototype,{_scroll:function(){var b=this.qtip.elements.overlay;b&&(b[0].style.top=d(a).scrollTop()+"px")},init:function(c){var e=c.tooltip;d("select, object").length<1&&(this.bgiframe=c.elements.bgiframe=d(Bb).appendTo(e),c._bind(e,"tooltipmove",this.adjustBGIFrame,this._ns,this)),this.redrawContainer=d("
",{id:S+"-rcontainer"}).appendTo(b.body),c.elements.overlay&&c.elements.overlay.addClass("qtipmodal-ie6fix")&&(c._bind(a,["scroll","resize"],this._scroll,this._ns,this),c._bind(e,["tooltipshow"],this._scroll,this._ns,this)),this.redraw()},adjustBGIFrame:function(){var a,b,c=this.qtip.tooltip,d={height:c.outerHeight(E),width:c.outerWidth(E)},e=this.qtip.plugins.tip,f=this.qtip.elements.tip;b=parseInt(c.css("borderLeftWidth"),10)||0,b={left:-b,top:-b},e&&f&&(a="x"===e.corner.precedance?[I,L]:[J,K],b[a[1]]-=f[a[0]]()),this.bgiframe.css(b).css(d)},redraw:function(){if(this.qtip.rendered<1||this.drawing)return this;var a,b,c,d,e=this.qtip.tooltip,f=this.qtip.options.style,g=this.qtip.options.position.container;return this.qtip.drawing=1,f.height&&e.css(J,f.height),f.width?e.css(I,f.width):(e.css(I,"").appendTo(this.redrawContainer),b=e.width(),1>b%2&&(b+=1),c=e.css("maxWidth")||"",d=e.css("minWidth")||"",a=(c+d).indexOf("%")>-1?g.width()/100:0,c=(c.indexOf("%")>-1?a:1)*parseInt(c,10)||b,d=(d.indexOf("%")>-1?a:1)*parseInt(d,10)||0,b=c+d?Math.min(Math.max(b,d),c):b,e.css(I,Math.round(b)).appendTo(g)),this.drawing=0,this},destroy:function(){this.bgiframe&&this.bgiframe.remove(),this.qtip._unbind([a,this.qtip.tooltip],this._ns)}}),Ab=R.ie6=function(a){return 6===db.ie?new x(a):E},Ab.initialize="render",B.ie6={"^content|style$":function(){this.redraw()}}})}(window,document); +//# sourceMappingURL=jquery.qtip.min.js.map \ No newline at end of file diff --git a/assets/js/jquery.qtip/jquery.qtip.min.js.map b/assets/js/jquery.qtip/jquery.qtip.min.js.map new file mode 100644 index 00000000..e3b4f414 --- /dev/null +++ b/assets/js/jquery.qtip/jquery.qtip.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"jquery.qtip.min.js","sources":["jquery.qtip.js"],"names":["window","document","undefined","factory","define","amd","jQuery","fn","qtip","$","QTip","target","options","id","attr","this","tooltip","NULL","elements","_id","NAMESPACE","timers","img","plugins","cache","event","disabled","FALSE","onTooltip","lastClass","rendered","destroyed","waiting","hiddenDuringWait","positioning","triggering","invalidOpt","a","type","invalidContent","c","isFunction","length","jquery","then","sanitizeOptions","opts","content","text","ajax","once","metadata","done","api","loading","deferred","extend","context","success","error","set","xhr","status","isPlainObject","title","button","position","my","at","show","TRUE","ready","hide","style","classes","each","PLUGINS","sanitize","convertNotation","notation","obj","i","option","levels","split","pop","setCallback","args","category","rule","match","checks","RegExp","exec","push","apply","createWidgetClass","cls","WIDGET","concat","join","delay","callback","duration","setTimeout","proxy","call","showMethod","hasClass","CLASS_DISABLED","clearTimeout","toggle","hideMethod","relatedTarget","ontoTooltip","closest","SELECTOR","ontoTarget","fixed","test","preventDefault","stopImmediatePropagation","e","inactiveMethod","inactive","repositionMethod","offsetWidth","reposition","delegate","selector","events","method","body","QTIP","ATTR_ID","arguments","init","elem","posOptions","config","docBody","newTarget","metadata5","name","html5","data","parseJSON","defaults","container","solo","viewport","eq","CORNER","overwrite","ATTR_HAS","suppress","removeAttr","oldtitle","camel","s","charAt","toUpperCase","slice","vendorCss","prop","cur","val","ucProp","props","cssPrefixes","cssProps","css","intCss","Math","ceil","parseFloat","Tip","_ns","offset","size","width","height","Modal","Ie6","PROTOTYPE","CHECKS","trackingBound","X","Y","WIDTH","HEIGHT","TOP","LEFT","BOTTOM","RIGHT","CENTER","FLIPINVERT","SHIFT","INACTIVE_EVENTS","CLASS_FIXED","CLASS_DEFAULT","CLASS_FOCUS","CLASS_HOVER","replaceSuffix","BROWSER","ie","v","createElement","innerHTML","getElementsByTagName","NaN","iOS","navigator","userAgent","replace","prototype","_when","deferreds","when","render","self","posClass","_createPosClass","class","tracking","adjust","mouse","role","aria-live","aria-atomic","aria-describedby","aria-hidden","toggleClass","appendTo","append","_createTitle","_updateTitle","_createButton","_updateContent","_setWidget","instance","initialize","_unassignEvents","_assignEvents","_trigger","destroy","immediate","process","timer","stop","find","remove","end","removeData","one","builtin","^id$","o","prev","nextid","new_id","^prerender","^content.text$","^content.attr$","^content.title$","_removeTitle","^content.button$","_updateButton","^content.title.(text|button)$","^position.(my|at)$","^position.container$","^show.ready$","^style.classes$","p","removeClass","addClass","^style.(width|height)","^style.widget|content.title","^style.def","^events.(render|show|move|hide|focus|blur)$","^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)","get","toLowerCase","result","precedance","string","rmove","rrender","value","previous","nodeType","_update","element","empty","display","visibility","html","_waitForContent","images","imagesLoaded","Deferred","resolve","promise","titlebar","widget","insertBefore","substr","abbrev","effect","pluginCalculations","adjusted","newClass","tooltipWidth","outerWidth","tooltipHeight","outerHeight","targetWidth","targetHeight","left","top","visible","isScroll","win","doc","ownerDocument","isArray","x","y","distance","origin","pageX","innerWidth","documentElement","clientWidth","pageY","scrollX","scrollLeft","scrollY","scrollTop","innerHeight","imagemap","is","svg","ownerSVGElement","adjustable","isNaN","queue","next","opacity","removeAttribute","pos","scroll","scrolled","parentOffset","overflow","quirks","compatMode","parent","getBoundingClientRect","offsetParent","C","Corner","corner","forceY","f","invert","z","center","clone","state","add","has","fix","identicalState","allow","after","contentOptions","animate","sameTarget","search","focus","bind","_storeMouse","not","Event","unbind","blur","autofocus","trigger","n","fadeTo","qtips","curIndex","parseInt","zIndex","newIndex","zindex","filter","disable","enable","isString","close","aria-label","prepend","click","on","def","_bind","targets","suffix","ns","_unbind","originalEvent","isDefaultPrevented","_bindEvents","showEvents","hideEvents","showTargets","hideTargets","similarTargets","toggleEvents","showIndex","inArray","splice","_assignInitialEvents","hoverIntent","prerender","showTarget","hideTarget","trim","onTarget","containerTarget","viewportTarget","documentTarget","windowTarget","leave","nodeName","indexOf","enabled","isAncestor","parents","inactiveEvents","limit","abs","resize","special","grep","toArray","currentTarget","newValue","command","returned","makeArray","timeStamp","keepData","elems","func","old","ui","cleanData","triggerHandler","version","move","hidden","TIP","MARGIN","BORDER","COLOR","BG_COLOR","TRANSPARENT","IMPORTANT","HASCANVAS","getContext","INVALID","PIXEL_RATIO","devicePixelRatio","BACKING_STORE_RATIO","backingStorePixelRatio","webkitBackingStorePixelRatio","mozBackingStorePixelRatio","msBackingStorePixelRatio","oBackingStorePixelRatio","SCALE","createVML","tag","tip","prependTo","lineJoin","miterLimit","save","stopPropagation","create","_swapDimensions","_resetDimensions","_useTitle","_parseCorner","_parseWidth","side","use","_parseRadius","_invalidColour","compare","_parseColours","borderSide","colorElem","color","_calculateSize","bigHyp","ratio","isCenter","base","pow","round","smallHyp","sqrt","hyp","border","reverse","_calculateTip","scale","width2","height2","tips","br","bl","tr","tl","tc","bc","rc","lc","lt","rt","lb","rb","_drawCoords","coords","beginPath","moveTo","lineTo","closePath","update","bigCoords","translate","newSize","inner","children","curSize","mimic","lineHeight","restore","clearRect","fillStyle","fill","coordsize","antialias","Number","$this","path","fillcolor","filled","stroked","opera","calculate","corners","userOffset","b","max","margin","bottom","right","shiftflip","direction","popposite","opposite","newCorner","shiftonly","xy","shift","horizontal","vertical","cornerTop","cornerLeft","user","^position.my|style.tip.(corner|mimic|border)$","^style.tip.(height|width)$","^content.title|style.(classes|widget)$","MODAL","OVERLAY","MODALCLASS","MODALSELECTOR","focusable","expr","map","mapName","isTabIndexNotNaN","parentNode","href","focusInputs","blurElems","focusableElems","first","stealFocus","targetOnTop","current","onLast","prevState","mousedown","modal","escape","keyCode","stealfocus","visibleModals","detach","overlay","modal_zindex","oEvent","last","^show.modal.(on|blur)$","elemWidth","elemHeight","otherSide","side1","side2","lengthName","targetLength","elemLength","initialPos","mySide","atSide","isShift","myLength","atLength","sideOffset","viewportScroll","viewportOffset","containerStatic","containerOffset","overflow1","overflow2","viewportWidth","viewportHeight","min","newMy","methodX","methodY","polys","polygon","baseCoords","newWidth","newHeight","compareX","compareY","realX","realY","floor","rect","ax","ay","bx","by","_angles","ellipse","cx","cy","rx","ry","rxc","cos","PI","rys","sin","circle","r","frameOffset","mtx","transformed","len","points","root","strokeWidth2","getBBox","baseVal","x1","y1","x2","y2","numberOfItems","getItem","createSVGPoint","getScreenCTM","matrixTransform","defaultView","parentWindow","frameElement","area","imageOffset","shape","image","coordsString","coordsArray","IE6","BGIFRAME","_scroll","bgiframe","adjustBGIFrame","redrawContainer","redraw","tipAdjust","dimensions","plugin","drawing","perc","ie6","^content|style$"],"mappings":";;CAaC,SAAUA,EAAQC,EAAUC,IAG5B,SAAUC,GACV,YACqB,mBAAXC,SAAyBA,OAAOC,IACzCD,QAAQ,UAAWD,GAEZG,SAAWA,OAAOC,GAAGC,MAC5BL,EAAQG,SAGT,SAASG,GACT,YAoEA,SAASC,GAAKC,EAAQC,EAASC,EAAIC,GAEnCC,KAAKF,GAAKA,EACVE,KAAKJ,OAASA,EACdI,KAAKC,QAAUC,EACfF,KAAKG,UAAaP,OAAQA,GAG1BI,KAAKI,IAAMC,EAAY,IAAMP,EAC7BE,KAAKM,QAAWC,QAChBP,KAAKH,QAAUA,EACfG,KAAKQ,WAGLR,KAAKS,OACJC,SACAd,OAAQF,IACRiB,SAAUC,EACVb,KAAMA,EACNc,UAAWD,EACXE,UAAW,IAIZd,KAAKe,SAAWf,KAAKgB,UAAYhB,KAAKW,SAAWX,KAAKiB,QACrDjB,KAAKkB,iBAAmBlB,KAAKmB,YAAcnB,KAAKoB,WAAaR,EAoL9D,QAASS,GAAWC,GACpB,MAAOA,KAAMpB,GAAsB,WAAdR,EAAE6B,KAAKD,GAG7B,QAASE,GAAeC,GACvB,QAAU/B,EAAEgC,WAAWD,IAAOA,GAAKA,EAAE1B,MAAS0B,EAAEE,QAAyB,WAAdjC,EAAE6B,KAAKE,KAAoBA,EAAEG,QAAUH,EAAEI,OAIrG,QAASC,GAAgBC,GACxB,GAAIC,GAASC,EAAMC,EAAMC,CAEzB,OAAGd,GAAWU,GAAgBnB,GAE3BS,EAAWU,EAAKK,YAClBL,EAAKK,UAAab,KAAMQ,EAAKK,WAG3B,WAAaL,KACfC,EAAUD,EAAKC,QAEZX,EAAWW,IAAYA,EAAQJ,QAAUI,EAAQK,KACnDL,EAAUD,EAAKC,SACdC,KAAOA,EAAOT,EAAeQ,GAAWpB,EAAQoB,GAG3CC,EAAOD,EAAQC,KAInB,QAAUD,KACZE,EAAOF,EAAQE,KACfC,EAAOD,GAAQA,EAAKC,OAASvB,QACtBoB,GAAQE,KAEfF,EAAQC,KAAO,SAASvB,EAAO4B,GAC9B,GAAIC,GAAUN,GAAQvC,EAAEM,MAAMD,KAAKuC,EAAIzC,QAAQmC,QAAQjC,OAAS,aAEhEyC,EAAW9C,EAAEwC,KACZxC,EAAE+C,UAAWP,GAAQQ,QAASJ,KAE9BT,KAAKK,EAAKS,QAASzC,EAAMgC,EAAKU,OAC9Bf,KAAK,SAASG,GAEd,MADGA,IAAWG,GAAQG,EAAIO,IAAI,eAAgBb,GACvCA,GAER,SAASc,EAAKC,EAAQH,GAClBN,EAAItB,WAA4B,IAAf8B,EAAIC,QACxBT,EAAIO,IAAI,eAAgBE,EAAS,KAAOH,IAGzC,OAAQT,GAAsDI,GAA9CD,EAAIO,IAAI,eAAgBN,GAAUC,KAIjD,SAAWR,KACVtC,EAAEsD,cAAchB,EAAQiB,SAC1BjB,EAAQkB,OAASlB,EAAQiB,MAAMC,OAC/BlB,EAAQiB,MAAQjB,EAAQiB,MAAMhB,MAG5BT,EAAeQ,EAAQiB,OAASrC,KAClCoB,EAAQiB,MAAQrC,KAKhB,YAAcmB,IAAQV,EAAWU,EAAKoB,YACxCpB,EAAKoB,UAAaC,GAAIrB,EAAKoB,SAAUE,GAAItB,EAAKoB,WAG5C,QAAUpB,IAAQV,EAAWU,EAAKuB,QACpCvB,EAAKuB,KAAOvB,EAAKuB,KAAK1B,QAAWhC,OAAQmC,EAAKuB,MAC7CvB,EAAKuB,OAASC,GAASC,MAAOD,IAAW7C,MAAOqB,EAAKuB,OAGpD,QAAUvB,IAAQV,EAAWU,EAAK0B,QACpC1B,EAAK0B,KAAO1B,EAAK0B,KAAK7B,QAAWhC,OAAQmC,EAAK0B,OAAW/C,MAAOqB,EAAK0B,OAGnE,SAAW1B,IAAQV,EAAWU,EAAK2B,SACrC3B,EAAK2B,OAAUC,QAAS5B,EAAK2B,QAI9BhE,EAAEkE,KAAKC,EAAS,WACf7D,KAAK8D,UAAY9D,KAAK8D,SAAS/B,KAGzBA,GAkGR,QAASgC,GAAgBlE,EAASmE,GAOjC,IANA,GAAWC,GAAPC,EAAI,EAAQC,EAAStE,EAGzBuE,EAASJ,EAASK,MAAM,KAGjBF,EAASA,EAAQC,EAAOF,OAC3BA,EAAIE,EAAOzC,SAAUsC,EAAME,EAG/B,QAAQF,GAAOpE,EAASuE,EAAOE,OAYhC,QAASC,GAAYP,EAAUQ,GAC9B,GAAIC,GAAUC,EAAMC,CAEpB,KAAIF,IAAYzE,MAAK4E,OACpB,IAAIF,IAAQ1E,MAAK4E,OAAOH,IACpBE,EAAQ,GAAKE,QAAOH,EAAM,KAAMI,KAAKd,MACvCQ,EAAKO,KAAKJ,IAEM,YAAbF,GAA0BzE,KAAKQ,QAAQiE,KACzCzE,KAAK4E,OAAOH,GAAUC,GAAMM,MAC3BhF,KAAKQ,QAAQiE,IAAazE,KAAMwE,IAkuBtC,QAASS,GAAkBC,GAC1B,MAAOC,GAAOC,OAAO,IAAIC,KAAKH,EAAM,IAAIA,EAAI,IAAM,KA2BlD,QAASI,GAAMC,EAAUC,GAEzB,MAAGA,GAAW,EACNC,WACN/F,EAAEgG,MAAMH,EAAUvF,MAAOwF,OAGrBD,GAASI,KAAK3F,MAGrB,QAAS4F,GAAWlF,GAChBV,KAAKC,QAAQ4F,SAASC,MAGzBC,aAAa/F,KAAKM,OAAOgD,MACzByC,aAAa/F,KAAKM,OAAOmD,MAGzBzD,KAAKM,OAAOgD,KAAOgC,EAAMK,KAAK3F,KAC7B,WAAaA,KAAKgG,OAAOzC,EAAM7C,IAC/BV,KAAKH,QAAQyD,KAAKgC,QAIpB,QAASW,GAAWvF,GACnB,IAAGV,KAAKC,QAAQ4F,SAASC,MAAmB9F,KAAKgB,UAAjD,CAGA,GAAIkF,GAAgBxG,EAAEgB,EAAMwF,eAC3BC,EAAcD,EAAcE,QAAQC,GAAU,KAAOrG,KAAKC,QAAQ,GAClEqG,EAAaJ,EAAc,KAAOlG,KAAKH,QAAQyD,KAAK1D,OAAO,EAQ5D,IALAmG,aAAa/F,KAAKM,OAAOgD,MACzByC,aAAa/F,KAAKM,OAAOmD,MAItBzD,OAASkG,EAAc,IACS,UAAjClG,KAAKH,QAAQsD,SAASvD,QAAsBuG,GAC5CnG,KAAKH,QAAQ4D,KAAK8C,OAClB,wBAA0BC,KAAK9F,EAAMa,QAAU4E,GAAeG,GAG/D,IACC5F,EAAM+F,iBACN/F,EAAMgG,2BACL,MAAMC,QAMT3G,MAAKM,OAAOmD,KAAO6B,EAAMK,KAAK3F,KAC7B,WAAaA,KAAKgG,OAAOpF,EAAOF,IAChCV,KAAKH,QAAQ4D,KAAK6B,MAClBtF,OAIF,QAAS4G,GAAelG,IACpBV,KAAKC,QAAQ4F,SAASC,KAAoB9F,KAAKH,QAAQ4D,KAAKoD,WAG/Dd,aAAa/F,KAAKM,OAAOuG,UAEzB7G,KAAKM,OAAOuG,SAAWvB,EAAMK,KAAK3F,KACjC,WAAYA,KAAKyD,KAAK/C,IACtBV,KAAKH,QAAQ4D,KAAKoD,WAIpB,QAASC,GAAiBpG,GACtBV,KAAKe,UAAYf,KAAKC,QAAQ,GAAG8G,YAAc,GAAK/G,KAAKgH,WAAWtG,GAyBxE,QAASuG,GAASC,EAAUC,EAAQC,GACnC1H,EAAER,EAASmI,MAAMJ,SAASC,GACxBC,EAAO9C,MAAQ8C,EAASA,EAAO9B,KAAK,IAAIhF,EAAY,MAAQ,IAAIA,EACjE,WACC,GAAIiC,GAAMgF,EAAKhF,IAAK5C,EAAEK,KAAKC,KAAMuH,GACjCjF,KAAQA,EAAI3B,UAAYyG,EAAOpC,MAAM1C,EAAKkF,aA6S7C,QAASC,GAAKC,EAAM5H,EAAIiC,GACvB,GAAIkC,GAAK0D,EAAY5H,EAAM6H,EAAQ3E,EAGnC4E,EAAUnI,EAAER,EAASmI,MAGrBS,EAAYJ,EAAK,KAAOxI,EAAW2I,EAAUH,EAG7CtF,EAAYsF,EAAa,SAAIA,EAAKtF,SAASL,EAAKK,UAAYlC,EAG5D6H,EAAmC,UAAvBhG,EAAKK,SAASb,MAAoBa,EAAWA,EAASL,EAAKK,SAAS4F,MAAQ9H,EAGxF+H,EAAQP,EAAKQ,KAAKnG,EAAKK,SAAS4F,MAAQ,WAGxC,KAAMC,EAAyB,gBAAVA,GAAqBvI,EAAEyI,UAAUF,GAASA,EAAS,MAAMtB,IAY9E,GATAiB,EAASlI,EAAE+C,OAAOc,KAAU+D,EAAKc,SAAUrG,EACzB,gBAAVkG,GAAqBnG,EAAgBmG,GAAS/H,EACrD4B,EAAgBiG,GAAa3F,IAG9BuF,EAAaC,EAAOzE,SACpByE,EAAO9H,GAAKA,EAGT,iBAAqB8H,GAAO5F,QAAQC,KAAM,CAI5C,GAHAlC,EAAO2H,EAAK3H,KAAK6H,EAAO5F,QAAQjC,MAG7B6H,EAAO5F,QAAQjC,OAASa,IAASb,EAG7B,MAAOa,EAH8BgH,GAAO5F,QAAQC,KAAOlC,EAsBnE,GAfI4H,EAAWU,UAAU1G,SAAUgG,EAAWU,UAAYR,GACvDF,EAAW/H,SAAWgB,IAAS+G,EAAW/H,OAASkI,GACnDF,EAAOtE,KAAK1D,SAAWgB,IAASgH,EAAOtE,KAAK1D,OAASkI,GACrDF,EAAOtE,KAAKgF,OAAS/E,IAAQqE,EAAOtE,KAAKgF,KAAOX,EAAWU,UAAUjC,QAAQ,SAC7EwB,EAAOnE,KAAK7D,SAAWgB,IAASgH,EAAOnE,KAAK7D,OAASkI,GACrDF,EAAOzE,SAASoF,WAAahF,IAAQqE,EAAOzE,SAASoF,SAAWZ,EAAWU,WAG9EV,EAAWU,UAAYV,EAAWU,UAAUG,GAAG,GAG/Cb,EAAWtE,GAAK,GAAIoF,GAAOd,EAAWtE,GAAIE,GAC1CoE,EAAWvE,GAAK,GAAIqF,GAAOd,EAAWvE,IAGnCsE,EAAKQ,KAAK7H,GACZ,GAAGuH,EAAOc,UACThB,EAAKjI,KAAK,WAAW,OAEjB,IAAGmI,EAAOc,YAAc9H,EAC5B,MAAOA,EAiBT,OAZA8G,GAAK3H,KAAK4I,EAAU7I,GAGjB8H,EAAOgB,WAAa3F,EAAQyE,EAAK3H,KAAK,WAExC2H,EAAKmB,WAAW,SAAS9I,KAAK+I,GAAU7F,GAAOlD,KAAK,QAAS,IAI9DkE,EAAM,GAAItE,GAAK+H,EAAME,EAAQ9H,IAAMC,GACnC2H,EAAKQ,KAAK7H,EAAW4D,GAEdA,EA0PR,QAAS8E,GAAMC,GAAK,MAAOA,GAAEC,OAAO,GAAGC,cAAgBF,EAAEG,MAAM,GAO/D,QAASC,GAAU1B,EAAM2B,GACxB,GAECC,GAAKC,EAFFC,EAASH,EAAKJ,OAAO,GAAGC,cAAgBG,EAAKF,MAAM,GACtDM,GAASJ,EAAO,IAAMK,GAAYrE,KAAKmE,EAAS,KAAOA,GAAQnF,MAAM,KAC3DH,EAAI,CAGf,IAAGyF,GAASN,GAAS,MAAO3B,GAAKkC,IAAID,GAASN,GAE9C,MAAOC,EAAMG,EAAMvF,MAClB,IAAIqF,EAAM7B,EAAKkC,IAAIN,MAAUnK,EAC5B,MAAOwK,IAASN,GAAQC,EAAKC,EAMhC,QAASM,GAAOnC,EAAM2B,GACrB,MAAOS,MAAKC,KAAKC,WAAWZ,EAAU1B,EAAM2B,KAwB7C,QAASY,GAAIxK,EAAMI,GAClBG,KAAKkK,IAAM,MACXlK,KAAKH,QAAUA,EACfG,KAAKmK,OAAStK,EAAQsK,OACtBnK,KAAKoK,MAASvK,EAAQwK,MAAOxK,EAAQyK,QAGrCtK,KAAKyH,KAAOzH,KAAKP,KAAOA,GAguBzB,QAAS8K,GAAMjI,EAAKzC,GACnBG,KAAKH,QAAUA,EACfG,KAAKkK,IAAM,SAEXlK,KAAKyH,KAAOzH,KAAKP,KAAO6C,GAyfzB,QAASkI,GAAIlI,GACZtC,KAAKkK,IAAM,MACXlK,KAAKyH,KAAOzH,KAAKP,KAAO6C,GA5tGzB,GAsBAgF,GAAMmD,EAAWhC,EAAQiC,EAiBzBC,EAvCIpH,GAAO,EACX3C,GAAQ,EACRV,EAAO,KAGP0K,EAAI,IAAKC,EAAI,IACbC,EAAQ,QACRC,EAAS,SAGTC,EAAM,MACNC,EAAO,OACPC,EAAS,SACTC,EAAQ,QACRC,EAAS,SAITC,EAAa,aACbC,EAAQ,QAIRzH,KACAxD,EAAY,OACZsI,EAAW,eACXpB,EAAU,eACVpC,GAAU,YAAa,cACvBkB,EAAW,IAAIhG,EACfkL,EAAkB,mEAAmElH,MAAM,KAE3FmH,EAAcnL,EAAU,SACxBoL,EAAgBpL,EAAY,WAC5BqL,EAAcrL,EAAY,SAC1BsL,EAActL,EAAY,SAC1ByF,GAAiBzF,EAAU,YAE3BuL,GAAgB,kBAChB9C,GAAW,WAIX+C,IAOCC,GAAK,WACJ,IACC,GAAIC,GAAI,EAAG7H,EAAIhF,EAAS8M,cAAc,QACrC9H,EAAE+H,UAAY,iBAAmBF,EAAI,0BAA4B7H,EAAEgI,qBAAqB,KAAK,GAC9FH,GAAG,GAEJ,MAAOA,GAAI,EAAIA,EAAII,OAMpBC,IAAKpC,YACH,IAAM,yDAAyDlF,KAAKuH,UAAUC,aAAe,EAAE,KAAK,IACpGC,QAAQ,YAAa,OAAOA,QAAQ,IAAK,KAAKA,QAAQ,IAAK,MACxD3L,EA6BN6J,GAAY9K,EAAK6M,UAEjB/B,EAAUgC,MAAQ,SAASC,GAC1B,MAAOhN,GAAEiN,KAAK3H,MAAMtF,EAAGgN,IAGxBjC,EAAUmC,OAAS,SAAStJ,GAC3B,GAAGtD,KAAKe,UAAYf,KAAKgB,UAAa,MAAOhB,KAE7C,IAUCC,GAVG4M,EAAO7M,KACVH,EAAUG,KAAKH,QACfY,EAAQT,KAAKS,MACbN,EAAWH,KAAKG,SAChB8B,EAAOpC,EAAQmC,QAAQC,KACvBgB,EAAQpD,EAAQmC,QAAQiB,MACxBC,EAASrD,EAAQmC,QAAQkB,OACzByE,EAAa9H,EAAQsD,SAErBuJ,GADY,IAAI1M,KAAKI,IAAI,OAgG1B,OA3FAV,GAAEK,KAAKC,KAAKJ,OAAO,GAAI,mBAAoBI,KAAKI,KAGhDK,EAAMqM,SAAW9M,KAAK+M,iBACpB/M,KAAKmD,UAAaC,GAAIuE,EAAWvE,GAAIC,GAAIsE,EAAWtE,KAAMD,IAI5DpD,KAAKC,QAAUE,EAASF,QAAUA,EAAUP,EAAE,UAC7CI,GAAME,KAAKI,IACX4M,SAAW3M,EAAWoL,EAAe5L,EAAQ6D,MAAMC,QAASlD,EAAMqM,UAAWzH,KAAK,KAClFgF,MAASxK,EAAQ6D,MAAM2G,OAAS,GAChCC,OAAUzK,EAAQ6D,MAAM4G,QAAU,GAClC2C,SAAkC,UAAtBtF,EAAW/H,QAAsB+H,EAAWuF,OAAOC,MAG/DC,KAAQ,QACRC,YAAa,SACbC,cAAe1M,EACf2M,mBAAoBvN,KAAKI,IAAM,WAC/BoN,cAAejK,IAEfkK,YAAY3H,GAAgB9F,KAAKW,UACjCZ,KAAKwH,EAASvH,KAAKF,IACnBoI,KAAK7H,EAAWL,MAChB0N,SAAS/F,EAAWU,WACpBsF,OAEAxN,EAAS6B,QAAUtC,EAAE,WACpBsN,QAAS3M,EAAY,WACrBP,GAAME,KAAKI,IAAM,WACjBkN,cAAe/J,KAKjBvD,KAAKe,SAAW,GAChBf,KAAKmB,YAAcoC,EAGhBN,IACFjD,KAAK4N,eAGDlO,EAAEgC,WAAWuB,IAChByJ,EAAU3H,KAAM/E,KAAK6N,aAAa5K,EAAOrC,KAKxCsC,GAAUlD,KAAK8N,gBAGdpO,EAAEgC,WAAWO,IAChByK,EAAU3H,KAAM/E,KAAK+N,eAAe9L,EAAMrB,IAE3CZ,KAAKe,SAAWwC,EAGhBvD,KAAKgO,aAGLtO,EAAEkE,KAAKC,EAAS,SAASmE,GACxB,GAAIiG,EACmB,YAApBjO,KAAKkO,aAA4BD,EAAWjO,KAAK6M,MACnDA,EAAKrM,QAAQwH,GAAQiG,KAKvBjO,KAAKmO,kBACLnO,KAAKoO,gBAGLpO,KAAKyM,MAAMC,GAAW7K,KAAK,WAE1BgL,EAAKwB,SAAS,UAGdxB,EAAK1L,YAAcP,EAGfiM,EAAK3L,mBAAqBrB,EAAQyD,KAAKE,QAASF,GACnDuJ,EAAK7G,OAAOzC,EAAM9C,EAAMC,MAAOE,GAEhCiM,EAAK3L,iBAAmBN,IAIzB0G,EAAKhF,IAAItC,KAAKF,IAAME,KAEbA,MAGRyK,EAAU6D,QAAU,SAASC,GAK5B,QAASC,KACR,IAAGxO,KAAKgB,UAAR,CACAhB,KAAKgB,UAAYuC,CAEjB,IAECkL,GAFG7O,EAASI,KAAKJ,OACjBqD,EAAQrD,EAAOG,KAAK+I,GAIlB9I,MAAKe,UACPf,KAAKC,QAAQyO,KAAK,EAAE,GAAGC,KAAK,KAAKC,SAASC,MAAMD,SAIjDlP,EAAEkE,KAAK5D,KAAKQ,QAAS,WACpBR,KAAKsO,SAAWtO,KAAKsO,WAItB,KAAIG,IAASzO,MAAKM,OACjByF,aAAa/F,KAAKM,OAAOmO,GAI1B7O,GAAOkP,WAAWzO,GAChBwI,WAAWtB,GACXsB,WAAWF,GACXE,WAAW,oBAGV7I,KAAKH,QAAQ+I,UAAY3F,GAC3BrD,EAAOG,KAAK,QAASkD,GAAO4F,WAAWC,IAIxC9I,KAAKmO,kBAILnO,KAAKH,QAAUG,KAAKG,SAAWH,KAAKS,MAAQT,KAAKM,OAChDN,KAAKQ,QAAUR,KAAKmN,MAAQjN,QAGtBoH,GAAKhF,IAAItC,KAAKF,KA7CtB,MAAGE,MAAKgB,UAAoBhB,KAAKJ,QAiD7B2O,IAAchL,GAA4B,SAApBvD,KAAKoB,aAA0BpB,KAAKe,SAMvDyN,EAAQ7I,KAAK3F,OALnBA,KAAKC,QAAQ8O,IAAI,gBAAiBrP,EAAEgG,MAAM8I,EAASxO,QAClDA,KAAKoB,YAAcpB,KAAKyD,QAMnBzD,KAAKJ,SA+Fb8K,EAASD,EAAU7F,QAClBoK,SAECC,OAAQ,SAAShL,EAAKiL,EAAGnD,EAAGoD,GAC3B,GAAIrP,GAAKiM,IAAMxI,EAAO+D,EAAK8H,OAASrD,EACnCsD,EAAShP,EAAY,IAAMP,CAEzBA,KAAOc,GAASd,EAAG6B,OAAS,IAAMjC,EAAE,IAAI2P,GAAQ1N,QAClD3B,KAAKI,IAAMiP,EAERrP,KAAKe,WACPf,KAAKC,QAAQ,GAAGH,GAAKE,KAAKI,IAC1BJ,KAAKG,SAAS6B,QAAQ,GAAGlC,GAAKE,KAAKI,IAAM,WACzCJ,KAAKG,SAAS8C,MAAM,GAAGnD,GAAKE,KAAKI,IAAM,WAGlC6D,EAAIiL,GAAKC,GAEjBG,aAAc,SAASrL,EAAKiL,EAAGnD,GAC9BA,IAAM/L,KAAKe,UAAYf,KAAK4M,OAAO5M,KAAKH,QAAQyD,KAAKE,QAItD+L,iBAAkB,SAAStL,EAAKiL,EAAGnD,GAClC/L,KAAK+N,eAAehC,IAErByD,iBAAkB,SAASvL,EAAKiL,EAAGnD,EAAGoD,GAClCnP,KAAKH,QAAQmC,QAAQC,OAASjC,KAAKJ,OAAOG,KAAKoP,IACjDnP,KAAK+N,eAAgB/N,KAAKJ,OAAOG,KAAKgM,KAGxC0D,kBAAmB,SAASxL,EAAKiL,EAAGnD,GAEnC,MAAIA,IAGJA,IAAM/L,KAAKG,SAAS8C,OAASjD,KAAK4N,mBAClC5N,MAAK6N,aAAa9B,IAJF/L,KAAK0P,gBAMtBC,mBAAoB,SAAS1L,EAAKiL,EAAGnD,GACpC/L,KAAK4P,cAAc7D,IAEpB8D,gCAAiC,SAAS5L,EAAKiL,EAAGnD,GACjD/L,KAAK6C,IAAI,WAAWqM,EAAGnD,IAIxB+D,qBAAsB,SAAS7L,EAAKiL,EAAGnD,GACtC,gBAAoBA,KAAM/L,KAAKmD,SAAS+L,GAAKjL,EAAIiL,GAAK,GAAIzG,GAAOsD,EAAS,OAANmD,KAErEa,uBAAwB,SAAS9L,EAAKiL,EAAGnD,GACxC/L,KAAKe,UAAYf,KAAKC,QAAQyN,SAAS3B,IAIxCiE,eAAgB,SAAS/L,EAAKiL,EAAGnD,GAChCA,KAAO/L,KAAKe,UAAYf,KAAK4M,OAAOrJ,IAASvD,KAAKgG,OAAOzC,KAI1D0M,kBAAmB,SAAShM,EAAKiL,EAAGnD,EAAGmE,GACtClQ,KAAKe,UAAYf,KAAKC,QAAQkQ,YAAYD,GAAGE,SAASrE,IAEvDsE,wBAAyB,SAASpM,EAAKiL,EAAGnD,GACzC/L,KAAKe,UAAYf,KAAKC,QAAQ2J,IAAIsF,EAAGnD,IAEtCuE,8BAA+B,WAC9BtQ,KAAKe,UAAYf,KAAKgO,cAEvBuC,aAAc,SAAStM,EAAKiL,EAAGnD,GAC9B/L,KAAKe,UAAYf,KAAKC,QAAQwN,YAAYhC,IAAiBM,IAI5DyE,8CAA+C,SAASvM,EAAKiL,EAAGnD,GAC/D/L,KAAKe,UAAYf,KAAKC,SAASP,EAAEgC,WAAWqK,GAAK,GAAK,MAAQ,QAAQ,UAAUmD,EAAGnD,IAIpF0E,qFAAsF,WACrF,GAAIzQ,KAAKe,SAAT,CAGA,GAAI4G,GAAa3H,KAAKH,QAAQsD,QAC9BnD,MAAKC,QAAQF,KAAK,WAAkC,UAAtB4H,EAAW/H,QAAsB+H,EAAWuF,OAAOC,OAGjFnN,KAAKmO,kBACLnO,KAAKoO,oBAoBR3D,EAAUiG,IAAM,SAAS1M,GACxB,GAAGhE,KAAKgB,UAAa,MAAOhB,KAE5B,IAAIkP,GAAInL,EAAgB/D,KAAKH,QAASmE,EAAS2M,eAC9CC,EAAS1B,EAAE,GAAIA,EAAE,GAElB,OAAO0B,GAAOC,WAAaD,EAAOE,SAAWF,EAqB9C,IAAIG,IAAQ,iFACXC,GAAU,yBAEXvG,GAAU5H,IAAM,SAASsB,EAAQ8M,GAChC,GAAGjR,KAAKgB,UAAa,MAAOhB,KAE5B,EAAA,GAICgI,GAJGjH,EAAWf,KAAKe,SACnBiG,EAAapG,EACbf,EAAUG,KAAKH,OACNG,MAAK4E,OA2Cf,MAvCG,gBAAoBT,IACtB6D,EAAO7D,EAAQA,KAAaA,EAAO6D,GAAQiJ,GAErC9M,EAASzE,EAAE+C,UAAW0B,GAG7BzE,EAAEkE,KAAKO,EAAQ,SAASH,EAAUiN,GACjC,GAAGlQ,GAAYiQ,GAAQxK,KAAKxC,GACF,kBAAlBG,GAAOH,EAIf,IAA4DkN,GAAxDjN,EAAMF,EAAgBlE,EAASmE,EAAS2M,cAC5CO,GAAWjN,EAAI,GAAIA,EAAI,IACvBA,EAAI,GAAIA,EAAI,IAAOgN,GAASA,EAAME,SAAWzR,EAAEuR,GAASA,EAGxDjK,EAAa+J,GAAMvK,KAAKxC,IAAagD,EAGrC7C,EAAOH,IAAaC,EAAI,GAAIA,EAAI,GAAIgN,EAAOC,KAI5CpP,EAAgBjC,GAMhBG,KAAKmB,YAAcoC,EACnB7D,EAAEkE,KAAKO,EAAQzE,EAAEgG,MAAMnB,EAAavE,OACpCA,KAAKmB,YAAcP,EAGhBZ,KAAKe,UAAYf,KAAKC,QAAQ,GAAG8G,YAAc,GAAKC,GACtDhH,KAAKgH,WAAwC,UAA5BnH,EAAQsD,SAASvD,OAAqBM,EAAOF,KAAKS,MAAMC,OAGnEV,MAEPyK,EAAU2G,QAAU,SAASpP,EAASqP,GACtC,GAAIxE,GAAO7M,KACVS,EAAQT,KAAKS,KAGd,OAAIT,MAAKe,UAAaiB,GAGnBtC,EAAEgC,WAAWM,KACfA,EAAUA,EAAQ2D,KAAK3F,KAAKG,SAASP,OAAQa,EAAMC,MAAOV,OAAS,IAIjEN,EAAEgC,WAAWM,EAAQH,OACvBpB,EAAMQ,QAAUsC,EACTvB,EAAQH,KAAK,SAASJ,GAE5B,MADAhB,GAAMQ,QAAUL,EACTiM,EAAKuE,QAAQ3P,EAAG4P,IACrBnR,EAAM,SAASyG,GACjB,MAAOkG,GAAKuE,QAAQzK,EAAG0K,MAKtBrP,IAAYpB,IAAWoB,GAAuB,KAAZA,EAA0BpB,GAG5DoB,EAAQJ,QAAUI,EAAQL,OAAS,EACrC0P,EAAQC,QAAQ3D,OACf3L,EAAQ4H,KAAM2H,QAAS,QAASC,WAAY,aAKvCH,EAAQI,KAAKzP,GAGbhC,KAAK0R,gBAAgBL,GAASxP,KAAK,SAAS8P,GAC/C9E,EAAK9L,UAAY8L,EAAK5M,QAAQ,GAAG8G,YAAc,GACjD8F,EAAK7F,WAAWvG,EAAMC,OAAQiR,EAAOhQ,YAlCCf,GAuCzC6J,EAAUiH,gBAAkB,SAASL,GACpC,GAAI5Q,GAAQT,KAAKS,KAMjB,OAHAA,GAAMQ,QAAUsC,GAGP7D,EAAEF,GAAGoS,aAAeP,EAAQO,eAAiBlS,EAAEmS,WAAWC,aACjEzP,KAAK,WAAa5B,EAAMQ,QAAUL,IAClCmR,WAGHtH,EAAUsD,eAAiB,SAAS/L,EAASgF,GAC5ChH,KAAKoR,QAAQpP,EAAShC,KAAKG,SAAS6B,QAASgF,IAG9CyD,EAAUoD,aAAe,SAAS7L,EAASgF,GACvChH,KAAKoR,QAAQpP,EAAShC,KAAKG,SAAS8C,MAAO+D,KAAgBpG,GAC7DZ,KAAK0P,aAAa9O,IAIpB6J,EAAUmD,aAAe,WAExB,GAAIzN,GAAWH,KAAKG,SACnBL,EAAKE,KAAKI,IAAI,QAGZD,GAAS6R,UAAYhS,KAAK0P,eAG7BvP,EAAS6R,SAAWtS,EAAE,WACrBsN,QAAS3M,EAAY,cAAgBL,KAAKH,QAAQ6D,MAAMuO,OAAShN,EAAkB,UAAY,MAE/F0I,OACAxN,EAAS8C,MAAQvD,EAAE,WAClBI,GAAMA,EACNkN,QAAS3M,EAAY,SACrBiN,cAAe/J,KAGhB2O,aAAa/R,EAAS6B,SAGtBiF,SAAS,cAAe,2CAA4C,SAASvG,GAC7EhB,EAAEM,MAAMyN,YAAY,iCAA4D,SAA1B/M,EAAMa,KAAK4Q,OAAO,OAExElL,SAAS,cAAe,qBAAsB,SAASvG,GACvDhB,EAAEM,MAAMyN,YAAY,iBAAiC,cAAf/M,EAAMa,QAI1CvB,KAAKH,QAAQmC,QAAQkB,QAAUlD,KAAK8N,iBAGxCrD,EAAUiF,aAAe,SAAS1I,GAEjC,GAAI7G,GAAWH,KAAKG,QAEjBA,GAAS8C,QACX9C,EAAS6R,SAASpD,SAClBzO,EAAS6R,SAAW7R,EAAS8C,MAAQ9C,EAAS+C,OAAShD,EAGpD8G,IAAepG,GAASZ,KAAKgH,eAGjCyD,EAAUsC,gBAAkB,SAAS3J,GACrC,MAAO/C,GAAY,SAAW+C,GAAMpD,KAAKH,QAAQsD,SAASC,IAAIgP,UAG/D3H,EAAUzD,WAAa,SAAStG,EAAO2R,GACtC,IAAIrS,KAAKe,UAAYf,KAAKmB,aAAenB,KAAKgB,UAAa,MAAOhB,KAGlEA,MAAKmB,YAAcoC,CAEnB,IAqBC+O,GAAoBnI,EAAQoI,EAAUC,EArBnC/R,EAAQT,KAAKS,MAChBR,EAAUD,KAAKC,QACf0H,EAAa3H,KAAKH,QAAQsD,SAC1BvD,EAAS+H,EAAW/H,OACpBwD,EAAKuE,EAAWvE,GAChBC,EAAKsE,EAAWtE,GAChBkF,EAAWZ,EAAWY,SACtBF,EAAYV,EAAWU,UACvB6E,EAASvF,EAAWuF,OACpB9F,EAAS8F,EAAO9F,OAAO/C,MAAM,KAC7BoO,EAAexS,EAAQyS,WAAW9R,GAClC+R,EAAgB1S,EAAQ2S,YAAYhS,GACpCiS,EAAc,EACdC,EAAe,EACfvR,EAAOtB,EAAQ2J,IAAI,YACnBzG,GAAa4P,KAAM,EAAGC,IAAK,GAC3BC,EAAUhT,EAAQ,GAAG8G,YAAc,EACnCmM,EAAWxS,GAAwB,WAAfA,EAAMa,KAC1B4R,EAAMzT,EAAET,GACRmU,EAAM/K,EAAU,GAAGgL,cACnBlG,EAAQnN,KAAKmN,KAId,IAAGzN,EAAE4T,QAAQ1T,IAA6B,IAAlBA,EAAO+B,OAE9B0B,GAAOkQ,EAAGtI,EAAMuI,EAAGxI,GACnB7H,GAAa4P,KAAMnT,EAAO,GAAIoT,IAAKpT,EAAO,QAItC,IAAc,UAAXA,EAEPyD,GAAOkQ,EAAGtI,EAAMuI,EAAGxI,KAGdkC,EAAOC,OAASnN,KAAKH,QAAQ4D,KAAKgQ,WAAahT,EAAMiT,QAAUjT,EAAMiT,OAAOC,MAChFjT,EAASD,EAAMiT,QAIPhT,GAAUA,IAAyB,WAAfA,EAAMa,MAAoC,WAAfb,EAAMa,MAC7Db,EAAQD,EAAMC,MAIPyM,GAASA,EAAMwG,QACtBjT,EAAQyM,GAIG,WAAT5L,IAAqB4B,EAAWkF,EAAU8B,UAC1CiJ,EAAI/L,KAAKN,eAAiB9H,EAAO2U,YAAcR,EAAIS,gBAAgBC,eACrE3J,EAASzK,EAAER,EAASmI,MAAM8C,UAI3BhH,GACC4P,KAAMrS,EAAMiT,MAAQxQ,EAAS4P,MAAQ5I,GAAUA,EAAO4I,MAAQ,GAC9DC,IAAKtS,EAAMqT,MAAQ5Q,EAAS6P,KAAO7I,GAAUA,EAAO6I,KAAO,IAIzD9F,EAAOC,OAAS+F,GAAY/F,IAC9BhK,EAAS4P,OAAS5F,EAAM6G,SAAW,GAAKb,EAAIc,aAC5C9Q,EAAS6P,MAAQ7F,EAAM+G,SAAW,GAAKf,EAAIgB,iBAKxC,CAiBJ,GAfc,UAAXvU,EACCc,GAASA,EAAMd,QAAyB,WAAfc,EAAMa,MAAoC,WAAfb,EAAMa,KAC5Dd,EAAMb,OAASF,EAAEgB,EAAMd,QAEfc,EAAMd,SACda,EAAMb,OAASI,KAAKG,SAASP,QAGZ,UAAXA,IACPa,EAAMb,OAASF,EAAEE,EAAOgC,OAAShC,EAASI,KAAKG,SAASP,SAEzDA,EAASa,EAAMb,OAGfA,EAASF,EAAEE,GAAQ4I,GAAG,GACD,IAAlB5I,EAAO+B,OAAgB,MAAO3B,KAGzBJ,GAAO,KAAOV,GAAYU,EAAO,KAAOX,GAC/C4T,EAAchH,GAAQO,IAAMnN,EAAO2U,WAAahU,EAAOyK,QACvDyI,EAAejH,GAAQO,IAAMnN,EAAOmV,YAAcxU,EAAO0K,SAEtD1K,EAAO,KAAOX,IAChBkE,GACC6P,KAAMzK,GAAY3I,GAAQuU,YAC1BpB,MAAOxK,GAAY3I,GAAQqU,gBAMtBpQ,EAAQwQ,UAAYzU,EAAO0U,GAAG,QACrChC,EAAqBzO,EAAQwQ,SAASrU,KAAMJ,EAAQyD,EAAIQ,EAAQ0E,SAAWnB,EAASxG,GAI7EiD,EAAQ0Q,KAAO3U,GAAUA,EAAO,GAAG4U,gBAC1ClC,EAAqBzO,EAAQ0Q,IAAIvU,KAAMJ,EAAQyD,EAAIQ,EAAQ0E,SAAWnB,EAASxG,IAK/EiS,EAAcjT,EAAO8S,WAAW9R,GAChCkS,EAAelT,EAAOgT,YAAYhS,GAClCuC,EAAWvD,EAAOuK,UAIhBmI,IACFO,EAAcP,EAAmBjI,MACjCyI,EAAeR,EAAmBhI,OAClCH,EAASmI,EAAmBnI,OAC5BhH,EAAWmP,EAAmBnP,UAI/BA,EAAWnD,KAAKgH,WAAWmD,OAAOvK,EAAQuD,EAAUkF,IAGhDwD,GAAQO,IAAM,KAAOP,GAAQO,IAAM,KACrCP,GAAQO,KAAO,KAAOP,GAAQO,IAAM,OACnCP,GAAQO,KAAgB,UAAT7K,KAEjB4B,EAAS4P,MAAQI,EAAIc,aACrB9Q,EAAS6P,KAAOG,EAAIgB,eAIjB7B,GAAuBA,GAAsBA,EAAmBmC,aAAe7T,KAClFuC,EAAS4P,MAAQ1P,EAAGkQ,IAAMpI,EAAQ0H,EAAcxP,EAAGkQ,IAAMnI,EAASyH,EAAc,EAAI,EACpF1P,EAAS6P,KAAO3P,EAAGmQ,IAAMtI,EAAS4H,EAAezP,EAAGmQ,IAAMpI,EAAS0H,EAAe,EAAI,GA+BxF,MA1BA3P,GAAS4P,MAAQ7F,EAAOqG,GAAKnQ,EAAGmQ,IAAMpI,GAASsH,EAAerP,EAAGmQ,IAAMnI,GAAUqH,EAAe,EAAI,GACpGtP,EAAS6P,KAAO9F,EAAOsG,GAAKpQ,EAAGoQ,IAAMtI,GAAUyH,EAAgBvP,EAAGoQ,IAAMpI,GAAUuH,EAAgB,EAAI,GAGnG9O,EAAQ0E,UACVgK,EAAWpP,EAASoP,SAAW1O,EAAQ0E,SACtCvI,KAAMmD,EAAUwE,EAAYkL,EAAaC,EAAcL,EAAcE,GAInExI,GAAUoI,EAASQ,OAAQ5P,EAAS4P,MAAQ5I,EAAO4I,MACnD5I,GAAUoI,EAASS,MAAQ7P,EAAS6P,KAAO7I,EAAO6I,KAGlDT,EAASnP,KAAMpD,KAAKmD,SAASC,GAAKmP,EAASnP,KAIxCD,EAASoP,UAAaQ,KAAM,EAAGC,IAAK,GAGxCvS,EAAMqM,YAAc0F,EAAWxS,KAAK+M,gBAAgB/M,KAAKmD,SAASC,MACpEnD,EAAQkQ,YAAY1P,EAAMqM,UAAUsD,SAAW3P,EAAMqM,SAAW0F,GAI7DxS,KAAKqO,SAAS,QAASlL,EAAUoF,EAASb,MAAQa,GAAW7H,UAC1DyC,GAASoP,SAGbF,IAAWzR,IAAUqS,GAAWyB,MAAMvR,EAAS4P,OAAS2B,MAAMvR,EAAS6P,MAAmB,UAAXpT,IAAuBF,EAAEgC,WAAWiG,EAAW0K,QAChIpS,EAAQ2J,IAAIzG,GAILzD,EAAEgC,WAAWiG,EAAW0K,UAC/B1K,EAAW0K,OAAO1M,KAAK1F,EAASD,KAAMN,EAAE+C,UAAWU,IACnDlD,EAAQ0U,MAAM,SAASC,GAEtBlV,EAAEM,MAAM4J,KAAMiL,QAAS,GAAIvK,OAAQ,KAChCuB,GAAQC,IAAM9L,KAAK0D,MAAMoR,gBAAgB,UAE5CF,OAKF5U,KAAKmB,YAAcP,EAEZZ,MAvB2EA,MA2BnFyK,EAAUzD,WAAWmD,OAAS,SAASzC,EAAMqN,EAAK1M,GAQjD,QAAS2M,GAAOrO,EAAGzC,GAClB6Q,EAAIhC,MAAQ7O,EAAIyC,EAAEsN,aAClBc,EAAI/B,KAAO9O,EAAIyC,EAAEwN,YATlB,IAAI9L,EAAU,GAAM,MAAO0M,EAE3B,IAGCE,GAAU9R,EAAU+R,EAAcC,EAH/B9B,EAAgB3T,EAAEgI,EAAK,GAAG2L,eAC7B+B,IAAWvJ,GAAQC,IAA8B,eAAxB5M,EAASmW,WAClCC,EAASjN,EAAU,EASpB,GAC+C,YAA1ClF,EAAWzD,EAAEkK,IAAI0L,EAAQ,eACZ,UAAbnS,GACF+R,EAAeI,EAAOC,wBACtBP,EAAO3B,EAAe,MAGtB6B,EAAexV,EAAE4V,GAAQnS,WACzB+R,EAAanC,MAAS/I,WAAWtK,EAAEkK,IAAI0L,EAAQ,qBAAuB,EACtEJ,EAAalC,KAAQhJ,WAAWtK,EAAEkK,IAAI0L,EAAQ,oBAAsB,GAGrEP,EAAIhC,MAAQmC,EAAanC,MAAQ/I,WAAWtK,EAAEkK,IAAI0L,EAAQ,gBAAkB,GAC5EP,EAAI/B,KAAOkC,EAAalC,KAAOhJ,WAAWtK,EAAEkK,IAAI0L,EAAQ,eAAiB,GAGrEL,GAAuD,YAA1CE,EAAWzV,EAAEkK,IAAI0L,EAAQ,cAA0C,YAAbH,IAA0BF,EAAWvV,EAAE4V,WAGzGA,EAASA,EAAOE,aAOvB,OAJGP,KAAaA,EAAS,KAAO5B,EAAc,IAAM+B,IACnDJ,EAAOC,EAAU,GAGXF,EAIR,IAAIU,KAAKhN,EAASgC,EAAUzD,WAAW0O,OAAS,SAASC,EAAQC,GAChED,GAAU,GAAKA,GAAQpJ,QAAQ,UAAW,OAAOA,QAAQ,WAAYnB,GAAQuF,cAC7E3Q,KAAKuT,GAAKoC,EAAOhR,MAAM,gBAAkBgR,EAAOhR,MAAM,YAAc,YAAY,GAAGgM,cACnF3Q,KAAKwT,GAAKmC,EAAOhR,MAAM,wBAA0B,YAAY,GAAGgM,cAChE3Q,KAAK4V,SAAWA,CAEhB,IAAIC,GAAIF,EAAO1M,OAAO,EACtBjJ,MAAK6Q,WAAoB,MAANgF,GAAmB,MAANA,EAAYhL,EAAID,IAC9C4B,SAEHiJ,IAAEK,OAAS,SAASC,EAAGC,GACtBhW,KAAK+V,GAAK/V,KAAK+V,KAAO9K,EAAOE,EAAQnL,KAAK+V,KAAO5K,EAAQF,EAAO+K,GAAUhW,KAAK+V,IAGhFN,GAAE3E,OAAS,SAASzL,GACnB,GAAIkO,GAAIvT,KAAKuT,EAAGC,EAAIxT,KAAKwT,EAErB5C,EAAS2C,IAAMC,EACX,WAAND,GAAwB,WAANC,IAAmBxT,KAAK6Q,aAAehG,GAAK7K,KAAK4V,SAClEpC,EAAED,IAAMA,EAAEC,IAEZD,EAED,OAAOlO,MAAS,EAAQuL,EAAOvL,KAAK,KAAOuL,GAG5C6E,GAAErD,OAAS,WACV,GAAIxB,GAAS5Q,KAAK8Q,QAAO,EACzB,OAAOF,GAAO,GAAG3H,OAAO,IAAM2H,EAAO,IAAMA,EAAO,GAAG3H,OAAO,IAAM,KAGnEwM,GAAEQ,MAAQ,WACT,MAAO,IAAIxN,GAAQzI,KAAK8Q,SAAU9Q,KAAK4V,SAIxCnL,EAAUzE,OAAS,SAASkQ,EAAOxV,GAClC,GAAID,GAAQT,KAAKS,MAChBZ,EAAUG,KAAKH,QACfI,EAAUD,KAAKC,OAGhB,IAAGS,EAAO,CACT,GAAG,aAAe8F,KAAK9F,EAAMa,OAASd,EAAMC,OAAS,YAAc8F,KAAK/F,EAAMC,MAAMa,OACnF1B,EAAQyD,KAAK1D,OAAOuW,IAAIzV,EAAMd,QAAQ+B,SAAW9B,EAAQyD,KAAK1D,OAAO+B,QACrE1B,EAAQmW,IAAI1V,EAAMwF,eAAevE,OACjC,MAAO3B,KAIRS,GAAMC,MAAQhB,EAAEgB,MAAM2V,IAAI3V,GAO3B,GAHAV,KAAKiB,UAAYiV,IAAUlW,KAAKkB,iBAAmBqC,IAG/CvD,KAAKe,SAAY,MAAOmV,GAAQlW,KAAK4M,OAAO,GAAK5M,IAChD,IAAGA,KAAKgB,WAAahB,KAAKW,SAAY,MAAOX,KAElD,IASCsW,GAAgBC,EAAyBC,EATtCjV,EAAO2U,EAAQ,OAAS,OAC3BnU,EAAO/B,KAAKH,QAAQ0B,GAEpBoG,GADY3H,KAAKH,QAAUqW,EAAiB,OAAT,QACtBlW,KAAKH,QAAQsD,UAC1BsT,EAAiBzW,KAAKH,QAAQmC,QAC9BqI,EAAQrK,KAAKC,QAAQ2J,IAAI,SACzBqJ,EAAUjT,KAAKC,QAAQqU,GAAG,YAC1BoC,EAAUR,GAAgC,IAAvBnU,EAAKnC,OAAO+B,OAC/BgV,GAAcjW,GAASqB,EAAKnC,OAAO+B,OAAS,GAAKlB,EAAMb,OAAO,KAAOc,EAAMd,MAa5E,cATWsW,IAAOU,OAAO,oBAAqBV,GAASjD,GAGvDqD,GAAkBrW,EAAQqU,GAAG,cAAgBrB,IAAYiD,GAASS,EAGlEJ,EAASD,EAA+CpW,IAA5BF,KAAKqO,SAAS9M,GAAO,KAG9CvB,KAAKgB,UAAoBhB,MAGzBuW,IAAU3V,GAASsV,GAASlW,KAAK6W,MAAMnW,IAGtC6V,GAASD,EAAyBtW,MAGtCN,EAAEK,KAAKE,EAAQ,GAAI,eAAkBiW,GAGlCA,GAEFlW,KAAKmN,QAAU1M,EAAMiT,OAAShU,EAAEgB,MAAM2V,IAAIrW,KAAKmN,QAG5CzN,EAAEgC,WAAW+U,EAAexU,OAASjC,KAAK+N,eAAe0I,EAAexU,KAAMrB,GAC9ElB,EAAEgC,WAAW+U,EAAexT,QAAUjD,KAAK6N,aAAa4I,EAAexT,MAAOrC,IAG7E+J,GAAuC,UAAtBhD,EAAW/H,QAAsB+H,EAAWuF,OAAOC,QACvEzN,EAAER,GAAU4X,KAAK,aAAazW,EAAWL,KAAK+W,aAC9CpM,EAAgBpH,GAIb8G,GAASpK,EAAQ2J,IAAI,QAAS3J,EAAQyS,WAAW9R,IACrDZ,KAAKgH,WAAWtG,EAAO8G,UAAU,IAC7B6C,GAASpK,EAAQ2J,IAAI,QAAS,IAG7B7H,EAAKuG,OACa,gBAAdvG,GAAKuG,KAAoB5I,EAAEqC,EAAKuG,MAAQ5I,EAAE2G,EAAUtE,EAAKuG,OAC/D0O,IAAI/W,GAAS+W,IAAIjV,EAAKnC,QAAQH,KAAK,OAAQC,EAAEuX,MAAM,kBAKtDlR,aAAa/F,KAAKM,OAAOgD,YAGlB7C,GAAMiT,OAGV/I,IAAkBjL,EAAE2G,EAAS,4BAA6BtE,EAAKuG,MAAM0O,IAAI/W,GAAS0B,SACpFjC,EAAER,GAAUgY,OAAO,aAAa7W,GAChCsK,EAAgB/J,GAIjBZ,KAAKmX,KAAKzW,IAIX8V,EAAQ9W,EAAEgG,MAAM,WACZwQ,GAECrK,GAAQC,IAAM7L,EAAQ,GAAGyD,MAAMoR,gBAAgB,UAGlD7U,EAAQ2J,IAAI,WAAY,IAGrB,gBAAoB7H,GAAKqV,WAC3B1X,EAAEM,KAAKH,QAAQyD,KAAK8T,UAAWnX,GAAS4W,QAIzC7W,KAAKH,QAAQyD,KAAK1D,OAAOyX,QAAQ,QAAQrX,KAAKF,GAAG,cAIjDG,EAAQ2J,KACP2H,QAAS,GACTC,WAAY,GACZqD,QAAS,GACT9B,KAAM,GACNC,IAAK,KAKPhT,KAAKqO,SAAS6H,EAAQ,UAAY,WAChClW,MAGA+B,EAAKsQ,SAAWzR,GAAS8V,IAAY9V,GACvCX,EAASsB,KACTiV,KAIO9W,EAAEgC,WAAWK,EAAKsQ,SACzBpS,EAAQyO,KAAK,EAAG,GAChB3M,EAAKsQ,OAAO1M,KAAK1F,EAASD,MAC1BC,EAAQ0U,MAAM,KAAM,SAAS2C,GAC5Bd,IAASc,OAKJrX,EAAQsX,OAAO,GAAIrB,EAAQ,EAAI,EAAGM,GAGtCN,GAASnU,EAAKnC,OAAOyX,QAAQ,QAAQrX,KAAKF,GAAG,aAEzCE,QAGRyK,EAAUnH,KAAO,SAAS5C,GAAS,MAAOV,MAAKgG,OAAOzC,EAAM7C,IAE5D+J,EAAUhH,KAAO,SAAS/C,GAAS,MAAOV,MAAKgG,OAAOpF,EAAOF,IAC5D+J,EAAUoM,MAAQ,SAASnW,GAC3B,IAAIV,KAAKe,UAAYf,KAAKgB,UAAa,MAAOhB,KAE9C,IAAIwX,GAAQ9X,EAAE2G,GACbpG,EAAUD,KAAKC,QACfwX,EAAWC,SAASzX,EAAQ,GAAGyD,MAAMiU,OAAQ,IAC7CC,EAAWtQ,EAAKuQ,OAASL,EAAM7V,MAyBhC,OArBI1B,GAAQ4F,SAAS6F,IAEjB1L,KAAKqO,SAAS,SAAUuJ,GAAWlX,KAElC+W,IAAaG,IAEfJ,EAAM5T,KAAK,WACP5D,KAAK0D,MAAMiU,OAASF,IACtBzX,KAAK0D,MAAMiU,OAAS3X,KAAK0D,MAAMiU,OAAS,KAK1CH,EAAMM,OAAO,IAAMpM,GAAajM,KAAK,OAAQiB,IAI9CT,EAAQmQ,SAAS1E,GAAa,GAAGhI,MAAMiU,OAASC,GAI3C5X,MAGRyK,EAAU0M,KAAO,SAASzW,GACzB,OAAIV,KAAKe,UAAYf,KAAKgB,UAAoBhB,MAG9CA,KAAKC,QAAQkQ,YAAYzE,GAGzB1L,KAAKqO,SAAS,QAAUrO,KAAKC,QAAQ2J,IAAI,WAAalJ,GAE/CV,OAEPyK,EAAUsN,QAAU,SAAS7B,GAC7B,MAAGlW,MAAKgB,UAAoBhB,MAGf,WAAVkW,EACFA,IAAUlW,KAAKe,SAAWf,KAAKC,QAAQ4F,SAASC,IAAkB9F,KAAKW,UAIhE,iBAAqBuV,KAC5BA,EAAQ3S,GAGNvD,KAAKe,UACPf,KAAKC,QAAQwN,YAAY3H,GAAgBoQ,GACvCnW,KAAK,gBAAiBmW,GAGzBlW,KAAKW,WAAauV,EAEXlW,OAGRyK,EAAUuN,OAAS,WAAa,MAAOhY,MAAK+X,QAAQnX,IACnD6J,EAAUqD,cAAgB,WAE1B,GAAIjB,GAAO7M,KACVG,EAAWH,KAAKG,SAChBF,EAAUE,EAASF,QACnBiD,EAASlD,KAAKH,QAAQmC,QAAQkB,OAC9B+U,EAA6B,gBAAX/U,GAClBgV,EAAQD,EAAW/U,EAAS,eAE1B/C,GAAS+C,QAAU/C,EAAS+C,OAAO0L,SAIrCzO,EAAS+C,OADPA,EAAOtB,OACSsB,EAGAxD,EAAE,SACnBsN,QAAS,eAAiBhN,KAAKH,QAAQ6D,MAAMuO,OAAS,GAAK5R,EAAU,SACrE4C,MAASiV,EACTC,aAAcD,IAEdE,QACA1Y,EAAE,YACDsN,QAAS,wBACTyE,KAAQ,aAMXtR,EAAS+C,OAAOwK,SAASvN,EAAS6R,UAAY/R,GAC5CF,KAAK,OAAQ,UACbsY,MAAM,SAAS3X,GAEf,MADIT,GAAQ4F,SAASC,KAAmB+G,EAAKpJ,KAAK/C,GAC3CE,KAIV6J,EAAUmF,cAAgB,SAAS1M,GAGlC,IAAIlD,KAAKe,SAAY,MAAOH,EAE5B,IAAI8G,GAAO1H,KAAKG,SAAS+C,MACtBA,GAAUlD,KAAK8N,gBACXpG,EAAKkH,UAQbnE,EAAUuD,WAAa,WAEtB,GAAIsK,GAAKtY,KAAKH,QAAQ6D,MAAMuO,OAC3B9R,EAAWH,KAAKG,SAChBF,EAAUE,EAASF,QACnBU,EAAWV,EAAQ4F,SAASC,GAE7B7F,GAAQkQ,YAAYrK,IACpBA,GAAiBwS,EAAK,oBAAsB,gBAC5CrY,EAAQwN,YAAY3H,GAAgBnF,GAEpCV,EAAQwN,YAAY,mBAAmBxI,IAAqBqT,GAAI7K,YAAYhC,EAAezL,KAAKH,QAAQ6D,MAAM6U,MAAQD,GAEnHnY,EAAS6B,SACX7B,EAAS6B,QAAQyL,YAAaxI,EAAkB,WAAYqT,GAE1DnY,EAAS6R,UACX7R,EAAS6R,SAASvE,YAAaxI,EAAkB,UAAWqT,GAE1DnY,EAAS+C,QACX/C,EAAS+C,OAAOuK,YAAYpN,EAAU,SAAUiY,IAgFlD7N,EAAUsM,YAAc,SAASrW,GAEhC,OADCV,KAAKmN,MAAQzN,EAAEgB,MAAM2V,IAAI3V,IAAQa,KAAO,YAClCvB,MAIRyK,EAAU+N,MAAQ,SAASC,EAAStR,EAAQC,EAAQsR,EAAQhW,GAC3D,GAAI+V,GAAYrR,GAAWD,EAAOxF,OAAlC,CACA,GAAIgX,GAAK,IAAM3Y,KAAKI,KAAOsY,EAAS,IAAIA,EAAS,GAKjD,OAJAhZ,GAAE+Y,GAAS3B,MACT3P,EAAO9C,MAAQ8C,EAASA,EAAO9B,KAAKsT,EAAK,MAAQA,EAClDjZ,EAAEgG,MAAM0B,EAAQ1E,GAAW1C,OAErBA,OAERyK,EAAUmO,QAAU,SAASH,EAASC,GAErC,MADAD,IAAW/Y,EAAE+Y,GAASvB,OAAO,IAAMlX,KAAKI,KAAOsY,EAAS,IAAIA,EAAS,KAC9D1Y,MAcRyK,EAAU4D,SAAW,SAAS9M,EAAMiD,EAAM9D,GACzC,GAAI6E,GAAW7F,EAAEuX,MAAM,UAAU1V,EAOjC,OANAgE,GAASsT,cAAiBnY,GAAShB,EAAE+C,UAAW/B,IAAWV,KAAKS,MAAMC,OAASR,EAE/EF,KAAKoB,WAAaG,EAClBvB,KAAKC,QAAQoX,QAAQ9R,GAAWvF,MAAMoF,OAAOZ,QAC7CxE,KAAKoB,WAAaR,GAEV2E,EAASuT,sBAGlBrO,EAAUsO,YAAc,SAASC,EAAYC,EAAYC,EAAaC,EAAavT,EAAYK,GAE9F,GAAImT,GAAiBF,EAAYpB,OAAQqB,GAAchD,IAAKgD,EAAYrB,OAAOoB,IAC9EG,IAGED,GAAezX,SAGjBjC,EAAEkE,KAAKqV,EAAY,SAAS/U,EAAG3C,GAC9B,GAAI+X,GAAY5Z,EAAE6Z,QAAQhY,EAAMyX,EAIhCM,GAAY,IAAMD,EAAatU,KAAMiU,EAAWQ,OAAQF,EAAW,GAAI,MAIrED,EAAa1X,SAEf3B,KAAKwY,MAAMY,EAAgBC,EAAc,SAAS3Y,GACjD,GAAIwV,GAAQlW,KAAKe,SAAWf,KAAKC,QAAQ,GAAG8G,YAAc,GAAI,GAC7DmP,EAAQjQ,EAAaL,GAAYD,KAAK3F,KAAMU,KAI9CwY,EAAcA,EAAYlC,IAAIoC,GAC9BD,EAAcA,EAAYnC,IAAIoC,KAKhCpZ,KAAKwY,MAAMU,EAAaF,EAAYpT,GACpC5F,KAAKwY,MAAMW,EAAaF,EAAYhT,IAGrCwE,EAAUgP,qBAAuB,SAAS/Y,GA+BzC,QAASgZ,GAAYhZ,GAEpB,MAAGV,MAAKW,UAAYX,KAAKgB,UAAoBJ,GAG7CZ,KAAKS,MAAMC,MAAQA,GAAShB,EAAEgB,MAAM2V,IAAI3V,GACxCV,KAAKS,MAAMb,OAASc,GAAShB,EAAEgB,EAAMd,QAGrCmG,aAAa/F,KAAKM,OAAOgD,WACzBtD,KAAKM,OAAOgD,KAAOgC,EAAMK,KAAK3F,KAC7B,WAAaA,KAAK4M,OAAwB,gBAAVlM,IAAsBb,EAAQyD,KAAKE,QACnE3D,EAAQ8Z,UAAY,EAAI9Z,EAAQyD,KAAKgC,SA1CvC,GAAIzF,GAAUG,KAAKH,QAClB+Z,EAAa/Z,EAAQyD,KAAK1D,OAC1Bia,EAAaha,EAAQ4D,KAAK7D,OAC1BoZ,EAAanZ,EAAQyD,KAAK5C,MAAQhB,EAAEoa,KAAK,GAAKja,EAAQyD,KAAK5C,OAAO2D,MAAM,QACxE4U,EAAapZ,EAAQ4D,KAAK/C,MAAQhB,EAAEoa,KAAK,GAAKja,EAAQ4D,KAAK/C,OAAO2D,MAAM,OAGzErE,MAAKwY,MAAMxY,KAAKG,SAASP,QAAS,SAAU,cAAe,WAC1DI,KAAKsO,SAAQ,IACX,WAMA,qBAAqB9H,KAAK3G,EAAQyD,KAAK5C,SAAW,oBAAoB8F,KAAK3G,EAAQ4D,KAAK/C,QAC1FuY,EAAWlU,KAAK,cAQjB/E,KAAKwY,MAAMoB,EAAY,YAAa,SAASlZ,GAC5CV,KAAK+W,YAAYrW,GACjBV,KAAKS,MAAMsZ,SAAWxW,IAqBvBvD,KAAK+Y,YAAYC,EAAYC,EAAYW,EAAYC,EAAYH,EAAa,WAC7E,MAAI1Z,MAAKM,WACTyF,cAAa/F,KAAKM,OAAOgD,MADC1C,KAKxBf,EAAQyD,KAAKE,OAAS3D,EAAQ8Z,YAAaD,EAAY/T,KAAK3F,KAAMU,IAItE+J,EAAU2D,cAAgB,WACzB,GAAIvB,GAAO7M,KACVH,EAAUG,KAAKH,QACf8H,EAAa9H,EAAQsD,SAErBlD,EAAUD,KAAKC,QACf2Z,EAAa/Z,EAAQyD,KAAK1D,OAC1Bia,EAAaha,EAAQ4D,KAAK7D,OAC1Boa,EAAkBrS,EAAWU,UAC7B4R,EAAiBtS,EAAWY,SAC5B2R,EAAiBxa,EAAER,GAEnBib,GADaza,EAAER,EAASmI,MACT3H,EAAET,IAEjB+Z,EAAanZ,EAAQyD,KAAK5C,MAAQhB,EAAEoa,KAAK,GAAKja,EAAQyD,KAAK5C,OAAO2D,MAAM,QACxE4U,EAAapZ,EAAQ4D,KAAK/C,MAAQhB,EAAEoa,KAAK,GAAKja,EAAQ4D,KAAK/C,OAAO2D,MAAM,OAIzE3E,GAAEkE,KAAK/D,EAAQsH,OAAQ,SAASa,EAAMzC,GACrCsH,EAAK2L,MAAMvY,EAAkB,WAAT+H,GAAqB,cAAc,gBAAkB,UAAUA,GAAOzC,EAAU,KAAMtF,KAIxG,oBAAoBuG,KAAK3G,EAAQ4D,KAAK/C,QAAiC,WAAvBb,EAAQ4D,KAAK2W,OAC/Dpa,KAAKwY,MAAM0B,GAAiB,WAAY,QAAS,SAASxZ,GACrD,gBAAgB8F,KAAK9F,EAAMd,OAAOya,WAAc3Z,EAAMwF,eACzDlG,KAAKyD,KAAK/C,KAMVb,EAAQ4D,KAAK8C,MACfsT,EAAaA,EAAW1D,IAAKlW,EAAQmQ,SAAS5E,IAOvC,qBAAqBhF,KAAK3G,EAAQyD,KAAK5C,QAC9CV,KAAKwY,MAAMqB,EAAY,aAAc,WACpC9T,aAAa/F,KAAKM,OAAOgD,SAKvB,GAAKzD,EAAQ4D,KAAK/C,OAAO4Z,QAAQ,WAAa,IACjDta,KAAKwY,MAAMwB,EAAgB5T,QAAQ,SAAU,YAAa,cAAe,SAAS1F,GACjF,GAAIgH,GAAOhI,EAAEgB,EAAMd,QAClB2a,EAAUva,KAAKe,WAAaf,KAAKC,QAAQ4F,SAASC,KAAmB9F,KAAKC,QAAQ,GAAG8G,YAAc,EACnGyT,EAAa9S,EAAK+S,QAAQpU,GAAUyR,OAAO9X,KAAKC,QAAQ,IAAI0B,OAAS,CAEnE+F,GAAK,KAAO1H,KAAKJ,OAAO,IAAM8H,EAAK,KAAO1H,KAAKC,QAAQ,IAAOua,GAC/Dxa,KAAKJ,OAAOwW,IAAI1O,EAAK,IAAI/F,SAAU4Y,GAEpCva,KAAKyD,KAAK/C,KAMV,gBAAoBb,GAAQ4D,KAAKoD,WAEnC7G,KAAKwY,MAAMoB,EAAY,QAAQ5Z,KAAKF,GAAG,YAAa8G,EAAgB,YAGpE5G,KAAKwY,MAAMqB,EAAW1D,IAAIlW,GAAUqH,EAAKoT,eAAgB9T,IAI1D5G,KAAK+Y,YAAYC,EAAYC,EAAYW,EAAYC,EAAYjU,EAAYK,GAG7EjG,KAAKwY,MAAMoB,EAAWzD,IAAIlW,GAAU,YAAa,SAASS,GAEzD,GAAG,gBAAoBb,GAAQ4D,KAAKgQ,SAAU,CAC7C,GAAIC,GAAS1T,KAAKS,MAAMiT,WACvBiH,EAAQ3a,KAAKH,QAAQ4D,KAAKgQ,SAC1BmH,EAAM9Q,KAAK8Q,KAGTA,EAAIla,EAAMiT,MAAQD,EAAOC,QAAUgH,GAASC,EAAIla,EAAMqT,MAAQL,EAAOK,QAAU4G,IACjF3a,KAAKyD,KAAK/C,GAKZV,KAAK+W,YAAYrW,KAIO,UAAtBiH,EAAW/H,QAEV+H,EAAWuF,OAAOC,QAEjBtN,EAAQ4D,KAAK/C,OAEfV,KAAKwY,MAAMoB,GAAa,aAAc,cAAe,SAASlZ,GAC7D,MAAIV,MAAKS,WACTT,KAAKS,MAAMsZ,SAA0B,eAAfrZ,EAAMa,MADJX,IAM1BZ,KAAKwY,MAAM0B,EAAgB,YAAa,SAASxZ,GAE7CV,KAAKe,UAAYf,KAAKS,MAAMsZ,WAAa/Z,KAAKC,QAAQ4F,SAASC,KAAmB9F,KAAKC,QAAQ,GAAG8G,YAAc,GAClH/G,KAAKgH,WAAWtG,OAOjBiH,EAAWuF,OAAO2N,QAAUZ,EAAetY,SAC7C3B,KAAKwY,MAAO9Y,EAAEgB,MAAMoa,QAAQD,OAASZ,EAAiBE,EAAc,SAAUrT,GAI5Ea,EAAWuF,OAAO8H,QACpBhV,KAAKwY,MAAO2B,EAAahE,IAAIxO,EAAWU,WAAY,SAAUvB,IAKhE2D,EAAU0D,gBAAkB,WAC3B,GAAItO,GAAUG,KAAKH,QAClBqZ,EAAcrZ,EAAQyD,KAAK1D,OAC3BuZ,EAActZ,EAAQ4D,KAAK7D,OAC3B6Y,EAAU/Y,EAAEqb,MACX/a,KAAKG,SAASP,OAAO,GACrBI,KAAKe,UAAYf,KAAKC,QAAQ,GAC9BJ,EAAQsD,SAASkF,UAAU,GAC3BxI,EAAQsD,SAASoF,SAAS,GAC1B1I,EAAQsD,SAASkF,UAAUjC,QAAQ,QAAQ,GAC3CnH,EACAC,GACE,SAASgF,GACX,MAAoB,gBAANA,IAIbgV,IAAeA,EAAY8B,UAC7BvC,EAAUA,EAAQrT,OAAO8T,EAAY8B,YAEnC7B,GAAeA,EAAY6B,UAC7BvC,EAAUA,EAAQrT,OAAO+T,EAAY6B,YAItChb,KAAK4Y,QAAQH,GACXG,QAAQH,EAAS,WACjBG,QAAQH,EAAS,aAIpB/Y,EAAE,WACDuH,EAASZ,GAAW,aAAc,cAAe,SAAS3F,GACzD,GAAIwV,GAAuB,eAAfxV,EAAMa,KACjBtB,EAAUP,EAAEgB,EAAMua,eAClBrb,EAASF,EAAEgB,EAAMwF,eAAiBxF,EAAMd,QACxCC,EAAUG,KAAKH,OAGbqW,IAEFlW,KAAK6W,MAAMnW,GAGXT,EAAQ4F,SAAS2F,KAAiBvL,EAAQ4F,SAASC,KAAmBC,aAAa/F,KAAKM,OAAOmD,OAMhE,UAA5B5D,EAAQsD,SAASvD,QAAsBC,EAAQsD,SAAS+J,OAAOC,OACjEtN,EAAQ4D,KAAK/C,OAASb,EAAQyD,KAAK1D,SAAWA,EAAOwG,QAAQvG,EAAQyD,KAAK1D,OAAO,IAAI+B,QACrF3B,KAAKyD,KAAK/C,GAKZT,EAAQwN,YAAY9B,EAAauK,KAIlCjP,EAAS,IAAIM,EAAQ,IAAKgE,EAAiB3E,KAsF5CU,EAAO5H,EAAEF,GAAGC,KAAO,SAASI,EAASmE,EAAUkX,GAE9C,GAAIC,IAAW,GAAKtb,GAAS8Q,cAC5ByK,EAAWlb,EACXsE,EAAO9E,EAAE2b,UAAU7T,WAAW2B,MAAM,GACpCzI,EAAQ8D,EAAKA,EAAK7C,OAAS,GAC3BI,EAAO/B,KAAK,GAAKN,EAAEwI,KAAKlI,KAAK,GAAIK,GAAaH,CAG/C,QAAKsH,UAAU7F,QAAUI,GAAqB,QAAZoZ,EAC1BpZ,EAIA,gBAAoBlC,IAC3BG,KAAK4D,KAAK,WACT,GAAItB,GAAM5C,EAAEwI,KAAKlI,KAAMK,EACvB,KAAIiC,EAAO,MAAOiB,EAMlB,IAHG7C,GAASA,EAAM4a,YAAahZ,EAAI7B,MAAMC,MAAQA,IAG9CsD,GAAyB,WAAZmX,GAAoC,YAAZA,EAWhC7Y,EAAI6Y,IACX7Y,EAAI6Y,GAASnW,MAAM1C,EAAKkC,OAZuC,CAC/D,GAAG0W,IAAa/b,IAAaO,EAAEsD,cAAcgB,GAK5C,MADAoX,GAAW9Y,EAAIoO,IAAI1M,GACZpD,CAJP0B,GAAIO,IAAImB,EAAUkX,MAcdE,IAAalb,EAAOkb,EAAWpb,MAI/B,gBAAoBH,IAAY2H,UAAU7F,OAA7C,QAEJI,EAAOD,EAAgBpC,EAAE+C,OAAOc,KAAU1D,IAEnCG,KAAK4D,KAAK,SAASM,GACzB,GAAI5B,GAAKxC,CAQT,OALAA,GAAKJ,EAAE4T,QAAQvR,EAAKjC,IAAMiC,EAAKjC,GAAGoE,GAAKnC,EAAKjC,GAC5CA,GAAMA,GAAMA,IAAOc,GAASd,EAAG6B,OAAS,GAAK2F,EAAKhF,IAAIxC,GAAMwH,EAAK8H,SAAWtP,EAG5EwC,EAAMmF,EAAK/H,EAAEM,MAAOF,EAAIiC,GACrBO,IAAQ1B,EAAgB2C,GACpB+D,EAAKhF,IAAIxC,GAAMwC,EAGtB5C,EAAEkE,KAAKC,EAAS,WACQ,eAApB7D,KAAKkO,YAA+BlO,KAAKsC,SAI7CA,GAAImX,qBAAqB/Y,QAM5BhB,EAAED,KAAOE,EAGT2H,EAAKhF,OACJ5C,EAAEkE,MAEF7D,KAAM,SAASA,EAAMwJ,GACpB,GAAGvJ,KAAK2B,OAAQ,CACf,GAAIkL,GAAO7M,KAAK,GACfiD,EAAQ,QACRX,EAAM5C,EAAEwI,KAAK2E,EAAM,OAEpB,IAAG9M,IAASkD,GAASX,GAAO,gBAAoBA,IAAOA,EAAIzC,QAAQ+I,SAClE,MAAGpB,WAAU7F,OAAS,EACdjC,EAAEK,KAAK8M,EAAM/D,KAIlBxG,GAAOA,EAAIzC,QAAQmC,QAAQjC,OAASkD,GAASX,EAAI7B,MAAMV,MACzDuC,EAAIO,IAAI,eAAgB0G,GAIlBvJ,KAAKD,KAAK+I,GAAUS,IAI7B,MAAO7J,GAAEF,GAAG,OAAOoM,IAAe5G,MAAMhF,KAAMwH,YAI/CyO,MAAO,SAASsF,GACf,GAGAC,IAHa9b,MAGLA,EAAEF,GAAG,QAAQoM,IAAe5G,MAAMhF,KAAMwH,WAUhD,OAPI+T,IACHC,EAAM1D,OAAO,IAAIhP,GAAS,KAAK/I,KAAK,QAAS,WAC5C,MAAOL,GAAEK,KAAKC,KAAM8I,MAEpBD,WAAWC,IAGN0S,IAEN,SAASxT,EAAMyT,GACjB,IAAIA,GAAQ/b,EAAEF,GAAGwI,EAAK4D,IAAkB,MAAOrI,EAE/C,IAAImY,GAAMhc,EAAEF,GAAGwI,EAAK4D,IAAiBlM,EAAEF,GAAGwI,EAC1CtI,GAAEF,GAAGwI,GAAQ,WACZ,MAAOyT,GAAKzW,MAAMhF,KAAMwH,YAAckU,EAAI1W,MAAMhF,KAAMwH,cAQpD9H,EAAEic,KACLjc,EAAE,YAAYkM,IAAiBlM,EAAEkc,UACjClc,EAAEkc,UAAY,SAAUJ,GACvB,IAAI,GAAW9T,GAAPxD,EAAI,GAAUwD,EAAOhI,EAAG8b,EAAMtX,KAAMvC,OAAQuC,IACnD,GAAGwD,EAAK3H,KAAK4I,GACZ,IAAMjB,EAAKmU,eAAe,cAC1B,MAAOlV,IAGTjH,EAAE,YAAYkM,IAAe5G,MAAMhF,KAAMwH,aAI3CF,EAAKwU,QAAU,YAGfxU,EAAK8H,OAAS,EAGd9H,EAAKoT,eAAiBnP,EAGtBjE,EAAKuQ,OAAS,KAGdvQ,EAAKc,UACJuR,UAAW/Y,EACXd,GAAIc,EACJ8H,UAAWnF,EACXqF,SAAUrF,EACVvB,SACCC,KAAMsB,EACNxD,KAAM,QACNkD,MAAOrC,EACPsC,OAAQtC,GAETuC,UACCC,GAAI,WACJC,GAAI,eACJzD,OAAQgB,EACRyH,UAAWzH,EACX2H,SAAU3H,EACVsM,QACCqG,EAAG,EAAGC,EAAG,EACTrG,MAAO5J,EACPyR,OAAQzR,EACRsX,OAAQtX,EACR6D,OAAQ,yBAETiL,OAAQ,SAAS/P,EAAKyS,GACrBrV,EAAEM,MAAM0W,QAAQ3B,GACfvP,SAAU,IACVmP,MAAO/T,MAIV0C,MACC1D,OAAQgB,EACRF,MAAO,aACP2R,OAAQ9O,EACR+B,MAAO,GACPgD,KAAM1H,EACN4C,MAAO5C,EACPwW,UAAWxW,GAEZ6C,MACC7D,OAAQgB,EACRF,MAAO,aACP2R,OAAQ9O,EACR+B,MAAO,EACPiB,MAAO3F,EACPiG,SAAUjG,EACVwZ,MAAO,SACP3G,SAAU7S,GAEX8C,OACCC,QAAS,GACTsO,OAAQrR,EACRyJ,MAAOzJ,EACP0J,OAAQ1J,EACR2X,IAAKhV,GAEN4D,QACCyF,OAAQ1M,EACR6b,KAAM7b,EACNoD,KAAMpD,EACNuD,KAAMvD,EACN8F,OAAQ9F,EACR+S,QAAS/S,EACT8b,OAAQ9b,EACR2W,MAAO3W,EACPiX,KAAMjX,GAGP,IAAI+b,IAMLC,GAAS,SACTC,GAAS,SACTC,GAAQ,QACRC,GAAW,mBACXC,GAAc,cACdC,GAAY,cAGZC,KAActd,EAAS8M,cAAc,UAAUyQ,WAG/CC,GAAU,8CAUN/S,MAAeD,IAAe,SAAU,IAAK,MAAO,KAuBxD,IAAI8S,GASH,GAAIG,IAAc1d,EAAO2d,kBAAoB,EAC5CC,GAAuB,WACtB,GAAIna,GAAUxD,EAAS8M,cAAc,UAAUyQ,WAAW,KAC1D,OAAO/Z,GAAQoa,wBAA0Bpa,EAAQqa,8BAAgCra,EAAQsa,2BACvFta,EAAQua,0BAA4Bva,EAAQwa,yBAA2B,KAE1EC,GAAQR,GAAcE,OAdvB,IAAIO,IAAY,SAASC,EAAK5T,EAAO/F,GACpC,MAAO,YAAY2Z,EAAI,4DAA4D5T,GAAO,IACzF,yCAAyC/F,GAAO,IAAK,OA0BxDhE,GAAE+C,OAAOwH,EAAIuC,WACZ/E,KAAM,SAAShI,GACd,GAAIiD,GAAS4a,CAGbA,GAAMtd,KAAKqR,QAAU5R,EAAKU,SAASmd,IAAM5d,EAAE,WAAasN,QAAS3M,EAAU,SAAUkd,UAAU9d,EAAKQ,SAGjGuc,IAEF9Z,EAAUhD,EAAE,cAAcgO,SAAS1N,KAAKqR,SAAS,GAAGoL,WAAW,MAG/D/Z,EAAQ8a,SAAW,QACnB9a,EAAQ+a,WAAa,IACrB/a,EAAQgb,SAGRhb,EAAU0a,GAAU,QAAS,oBAAqB,sBAClDpd,KAAKqR,QAAQI,KAAK/O,EAAUA,GAG5BjD,EAAK+Y,MAAO9Y,EAAE,IAAK4d,GAAKnH,IAAImH,IAAO,QAAS,aAAc,SAAS5c,GAASA,EAAMid,mBAAsB3d,KAAKkK,MAI9GzK,EAAK+Y,MAAM/Y,EAAKQ,QAAS,cAAeD,KAAKgH,WAAYhH,KAAKkK,IAAKlK,MAGnEA,KAAK4d,UAGNC,gBAAiB,WAChB7d,KAAKoK,KAAK,GAAKpK,KAAKH,QAAQyK,OAC5BtK,KAAKoK,KAAK,GAAKpK,KAAKH,QAAQwK,OAE7ByT,iBAAkB,WACjB9d,KAAKoK,KAAK,GAAKpK,KAAKH,QAAQwK,MAC5BrK,KAAKoK,KAAK,GAAKpK,KAAKH,QAAQyK,QAG7ByT,UAAW,SAASpI,GACnB,GAAI3D,GAAWhS,KAAKP,KAAKU,SAAS6R,QAClC,OAAOA,KACN2D,EAAOnC,IAAMxI,GAAQ2K,EAAOnC,IAAMpI,GAAUpL,KAAKqR,QAAQlO,WAAW6P,IAAOhT,KAAKoK,KAAK,GAAK,EAAKpK,KAAKH,QAAQsK,OAAS6H,EAASY,YAAYrP,KAI5Iya,aAAc,SAASrI,GACtB,GAAIvS,GAAKpD,KAAKP,KAAKI,QAAQsD,SAASC,EAcpC,OAXGuS,KAAW/U,GAASwC,IAAOxC,EAC7B+U,EAAS/U,EAEF+U,IAAWpS,EAClBoS,EAAS,GAAIlN,GAAQrF,EAAG0N,UAEhB6E,EAAO7E,SACf6E,EAAS,GAAIlN,GAAOkN,GACpBA,EAAOpP,MAAQhD,GAGToS,GAGRsI,YAAa,SAAStI,EAAQuI,EAAMC,GACnC,GAAIhe,GAAWH,KAAKP,KAAKU,SACxBkJ,EAAO8S,GAASpT,EAAMmV,GAAQ,OAE/B,QAAQC,EAAMtU,EAAOsU,EAAK9U,GACzBQ,EAAO1J,EAAS6B,QAASqH,IACzBQ,EAAO7J,KAAK+d,UAAUpI,IAAWxV,EAAS6R,UAAY7R,EAAS6B,QAASqH,IACxEQ,EAAO1J,EAASF,QAASoJ,KACpB,GAGP+U,aAAc,SAASzI,GACtB,GAAIxV,GAAWH,KAAKP,KAAKU,SACxBkJ,EAAO8S,GAASpT,EAAM4M,EAAOnC,GAAKzK,EAAM4M,EAAOpC,GAAK,QAErD,OAAO1H,IAAQC,GAAK,EAAI,EACvBjC,EAAO7J,KAAK+d,UAAUpI,IAAWxV,EAAS6R,UAAY7R,EAAS6B,QAASqH,IACxEQ,EAAO1J,EAASF,QAASoJ,IAAS,GAGpCgV,eAAgB,SAAS3W,EAAM2B,EAAMiV,GACpC,GAAI/U,GAAM7B,EAAKkC,IAAIP,EACnB,QAAQE,GAAQ+U,GAAW/U,IAAQ7B,EAAKkC,IAAI0U,IAAa5B,GAAQlW,KAAK+C,GAAO3I,EAAQ2I,GAGtFgV,cAAe,SAAS5I,GACvB,GAAIxV,GAAWH,KAAKP,KAAKU,SACxBmd,EAAMtd,KAAKqR,QAAQzH,IAAI,UAAW,IAClC4U,EAAarC,GAASpT,EAAM4M,EAAQA,EAAO9E,aAAgB9H,EAAMqT,IACjEqC,EAAYze,KAAK+d,UAAUpI,IAAWxV,EAAS6R,UAAY7R,EAAS6B,QACpE4H,EAAM5J,KAAKqe,eAAgBK,IAa5B,OAVAA,GAAM,GAAK9U,EAAI0T,EAAKjB,KAAazS,EAAI6U,EAAWpC,KAAazS,EAAIzJ,EAAS6B,QAASqa,KAClFzS,EAAIzJ,EAASF,QAASoc,KAAaiB,EAAI1T,IAAIyS,IAG5CqC,EAAM,GAAK9U,EAAI0T,EAAKkB,EAAYpC,KAAUxS,EAAI6U,EAAWD,EAAYpC,KACpExS,EAAIzJ,EAAS6B,QAASwc,EAAYpC,KAAUxS,EAAIzJ,EAASF,QAASue,EAAYpC,KAAUjc,EAASF,QAAQ2J,IAAI4U,GAG9G9e,EAAE,IAAK4d,GAAKnH,IAAImH,GAAK1T,IAAI,UAAWyS,GAAS,IAAIC,GAAYC,GAAU,IAAIJ,GAAO,KAAKI,GAAU,KAE1FmC,GAGRC,eAAgB,SAAShJ,GACxB,GAOCiJ,GAAQC,EAAOjO,EAPZ4C,EAAImC,EAAO9E,aAAehG,EAC7BR,EAAQrK,KAAKH,QAAe,MAC5ByK,EAAStK,KAAKH,QAAgB,OAC9Bif,EAA+B,MAApBnJ,EAAOvD,SAClB2M,GAAQvL,EAAInJ,EAAOC,IAAWwU,EAAW,GAAM,GAC/CE,EAAMlV,KAAKkV,IACXC,EAAQnV,KAAKmV,MAGdC,EAAWpV,KAAKqV,KAAMH,EAAID,EAAM,GAAKC,EAAI1U,EAAQ,IACjD8U,GAASpf,KAAKqf,OAASN,EAAQG,EAAWlf,KAAKqf,OAAS/U,EAAU4U,EASlE,OAPAE,GAAI,GAAKtV,KAAKqV,KAAMH,EAAII,EAAI,GAAI,GAAKJ,EAAIhf,KAAKqf,OAAQ,IACtDD,EAAI,GAAKtV,KAAKqV,KAAMH,EAAII,EAAI,GAAI,GAAKJ,EAAIhf,KAAKqf,OAAQ,IAEtDT,EAASM,EAAWE,EAAI,GAAKA,EAAI,IAAMN,EAAW,EAAIM,EAAI,IAC1DP,EAAQD,EAASM,EAEjBtO,GAAWqO,EAAMJ,EAAQxU,GAAQ4U,EAAMJ,EAAQvU,IACxCkJ,EAAI5C,EAASA,EAAO0O,WAI5BC,cAAe,SAAS5J,EAAQvL,EAAMoV,GACrCA,EAAQA,GAAS,EACjBpV,EAAOA,GAAQpK,KAAKoK,IAEpB,IAAIC,GAAQD,EAAK,GAAKoV,EACrBlV,EAASF,EAAK,GAAKoV,EACnBC,EAAS3V,KAAKC,KAAKM,EAAQ,GAAIqV,EAAU5V,KAAKC,KAAKO,EAAS,GAG7DqV,GACCC,IAAK,EAAE,EAAIvV,EAAMC,EAAQD,EAAM,GAC/BwV,IAAK,EAAE,EAAIxV,EAAM,EAAI,EAAEC,GACvBwV,IAAK,EAAExV,EAAQD,EAAM,EAAIA,EAAMC,GAC/ByV,IAAK,EAAE,EAAI,EAAEzV,EAASD,EAAMC,GAC5B0V,IAAK,EAAE1V,EAAQmV,EAAO,EAAIpV,EAAMC,GAChC2V,IAAK,EAAE,EAAI5V,EAAM,EAAIoV,EAAOnV,GAC5B4V,IAAK,EAAE,EAAI7V,EAAMqV,EAAS,EAAEpV,GAC5B6V,IAAK9V,EAAM,EAAGA,EAAMC,EAAQ,EAAEoV,GAO/B,OAHAC,GAAKS,GAAKT,EAAKC,GAAID,EAAKU,GAAKV,EAAKE,GAClCF,EAAKW,GAAKX,EAAKG,GAAIH,EAAKY,GAAKZ,EAAKI,GAE3BJ,EAAMhK,EAAOvD,WAIrBoO,YAAa,SAAS9d,EAAS+d,GAC9B/d,EAAQge,YACRhe,EAAQie,OAAOF,EAAO,GAAIA,EAAO,IACjC/d,EAAQke,OAAOH,EAAO,GAAIA,EAAO,IACjC/d,EAAQke,OAAOH,EAAO,GAAIA,EAAO,IACjC/d,EAAQme,aAGTjD,OAAQ,WAEP,GAAInc,GAAIzB,KAAK2V,QAAU6G,IAAa3Q,GAAQC,KAAO9L,KAAKge,aAAahe,KAAKH,QAAQ8V,OAclF,QAXK3V,KAAKua,UAAYva,KAAK2V,QAAmC,MAAzB3V,KAAK2V,OAAOvD,YAEhDpS,KAAKP,KAAKgB,MAAMkV,OAASlU,EAAEwU,QAG3BjW,KAAK8gB,UAIN9gB,KAAKqR,QAAQrL,OAAOhG,KAAKua,SAElBva,KAAK2V,QAGbmL,OAAQ,SAASnL,EAAQxS,GACxB,IAAInD,KAAKua,QAAW,MAAOva,KAE3B,IAOC0e,GAAO7N,EAAYnO,EACnB+d,EAAQM,EAAWC,EAAWC,EAAS5B,EARpClf,EAAWH,KAAKP,KAAKU,SACxBmd,EAAMtd,KAAKqR,QACX6P,EAAQ5D,EAAI6D,WACZthB,EAAUG,KAAKH,QACfuhB,EAAUphB,KAAKoK,KACfiX,EAAQxhB,EAAQwhB,MAChBpC,EAAQnV,KAAKmV,KAKVtJ,KAAUA,EAAS3V,KAAKP,KAAKgB,MAAMkV,QAAU3V,KAAK2V,QAGnD0L,IAAUzgB,EAASygB,EAAQ1L,GAI7B0L,EAAQ,GAAI5Y,GAAO4Y,GACnBA,EAAMxQ,WAAa8E,EAAO9E,WAEX,YAAZwQ,EAAM9N,EAAmB8N,EAAM9N,EAAIoC,EAAOpC,EACzB,YAAZ8N,EAAM7N,EAAmB6N,EAAM7N,EAAImC,EAAOnC,EAC1C6N,EAAM9N,IAAM8N,EAAM7N,IACzB6N,EAAO1L,EAAO9E,YAAe8E,EAAQA,EAAO9E,cAG9CA,EAAawQ,EAAMxQ,WAGhB8E,EAAO9E,aAAejG,EAAK5K,KAAK6d,kBAC5B7d,KAAK8d,mBAGZY,EAAQ1e,KAAK0e,MAAQ1e,KAAKue,cAAc5I,GAGrC+I,EAAM,KAAOpC,IAEf+C,EAASrf,KAAKqf,OAASrf,KAAKie,YAAYtI,EAAQA,EAAOA,EAAO9E,aAG3DhR,EAAQwf,QAAmB,EAATA,IAAe3C,GAAQlW,KAAKkY,EAAM,MAAOA,EAAM,GAAKA,EAAM,IAG/E1e,KAAKqf,OAASA,EAASxf,EAAQwf,SAAW9b,EAAO1D,EAAQwf,OAASA,GAI5Drf,KAAKqf,OAASA,EAAS,EAG9B4B,EAAUjhB,KAAKoK,KAAOpK,KAAK2e,eAAehJ,GAC1C2H,EAAI1T,KACHS,MAAO4W,EAAQ,GACf3W,OAAQ2W,EAAQ,GAChBK,WAAYL,EAAQ,GAAG,OAKvBD,EADErL,EAAO9E,aAAehG,GAEvBoU,EAAMoC,EAAM9N,IAAMtI,EAAOoU,EAASgC,EAAM9N,IAAMpI,EAAQ8V,EAAQ,GAAKG,EAAQ,GAAK/B,GAAU4B,EAAQ,GAAKG,EAAQ,IAAM,GACrHnC,EAAMoC,EAAM7N,IAAMxI,EAAMiW,EAAQ,GAAKG,EAAQ,GAAK,KAKlDnC,EAAMoC,EAAM9N,IAAMtI,EAAOgW,EAAQ,GAAKG,EAAQ,GAAK,GACnDnC,EAAMoC,EAAM7N,IAAMxI,EAAMqU,EAASgC,EAAM7N,IAAMtI,EAAS+V,EAAQ,GAAKG,EAAQ,GAAK/B,GAAU4B,EAAQ,GAAKG,EAAQ,IAAM,IAKpH5E,IAEF9Z,EAAUwe,EAAM,GAAGzE,WAAW,MAC9B/Z,EAAQ6e,UAAW7e,EAAQgb,OAC3Bhb,EAAQ8e,UAAU,EAAE,EAAE,IAAK,KAG3Bf,EAASzgB,KAAKuf,cAAc8B,EAAOD,EAASjE,IAC5C4D,EAAY/gB,KAAKuf,cAAc8B,EAAOrhB,KAAKoK,KAAM+S,IAGjD+D,EAAMnhB,KAAK+K,EAAOmW,EAAQ,GAAK9D,IAAOpd,KAAKgL,EAAQkW,EAAQ,GAAK9D,IAChE+D,EAAMtX,IAAIkB,EAAOmW,EAAQ,IAAIrX,IAAImB,EAAQkW,EAAQ,IAGjDjhB,KAAKwgB,YAAY9d,EAASqe,GAC1Bre,EAAQ+e,UAAY/C,EAAM,GAC1Bhc,EAAQgf,OAGRhf,EAAQse,UAAUA,EAAU,GAAK7D,GAAO6D,EAAU,GAAK7D,IACvDnd,KAAKwgB,YAAY9d,EAAS+d,GAC1B/d,EAAQ+e,UAAY/C,EAAM,GAC1Bhc,EAAQgf,SAMRjB,EAASzgB,KAAKuf,cAAc8B,GAG5BZ,EAAS,IAAMA,EAAO,GAAK,IAAMA,EAAO,GAAK,KAAOA,EAAO,GAC1D,IAAMA,EAAO,GAAK,IAAMA,EAAO,GAAK,IAAMA,EAAO,GAAK,MAGvDO,EAAU,GAAK3B,GAAU,UAAU7Y,KAAKmP,EAAO7E,UAC/B,IAAfjF,GAAQC,GAAW,EAAI,EAAI,EAG5BoV,EAAMtX,KACL+X,UAAYV,EAAQ,GAAG5B,EAAU,KAAO4B,EAAQ,GAAG5B,GACnDuC,UAAW,IAAIP,EAAMvQ,SAASwJ,QAAQlP,GAAU,IAChD2H,KAAMiO,EAAU,GAAMA,EAAU,GAAKa,OAAOhR,IAAejG,GAC3DoI,IAAKgO,EAAU,GAAMA,EAAU,GAAKa,OAAOhR,IAAehG,GAC1DR,MAAO4W,EAAQ,GAAK5B,EACpB/U,OAAQ2W,EAAQ,GAAK5B,IAErBzb,KAAK,SAASM,GACd,GAAI4d,GAAQpiB,EAAEM,KAGd8hB,GAAOA,EAAMzY,KAAO,OAAS,SAC5BsY,UAAYV,EAAQ,GAAG5B,EAAU,KAAO4B,EAAQ,GAAG5B,GACnD0C,KAAMtB,EACNuB,UAAWtD,EAAM,GACjBuD,SAAU/d,EACVge,SAAUhe,IAEV8B,UAAUqZ,IAAUnb,KAGpBA,GAAK4d,EAAMrQ,KAAM2L,GACjB,SAAU,WAAmB,EAAPiC,EAAU,cAAcX,EAAM,GAAG,6CAO1Dzf,EAAOkjB,OAAS1c,WAAW,WAC1BtF,EAASmd,IAAI1T,KACZ2H,QAAS,eACTC,WAAY,aAEX,GAGArO,IAAavC,GAASZ,KAAKoiB,UAAUzM,EAAQsL,IAGjDmB,UAAW,SAASzM,EAAQvL,GAC3B,IAAIpK,KAAKua,QAAW,MAAO3Z,EAE3B,IAMCiQ,GAAYwR,EANTxV,EAAO7M,KACVG,EAAWH,KAAKP,KAAKU,SACrBmd,EAAMtd,KAAKqR,QACXiR,EAAatiB,KAAKH,QAAQsK,OAE1BhH,GADWhD,EAASF,QAAQ4F,SAAS,gBAsCtC,OAjCA8P,GAASA,GAAU3V,KAAK2V,OACxB9E,EAAa8E,EAAO9E,WAGpBzG,EAAOA,GAAQpK,KAAK2e,eAAehJ,GAGnC0M,GAAY1M,EAAOpC,EAAGoC,EAAOnC,GAC1B3C,IAAejG,GAAKyX,EAAQ/C,UAG/B5f,EAAEkE,KAAKye,EAAS,SAASne,EAAGga,GAC3B,GAAIqE,GAAGtC,EAAIL,CAER1B;IAAS9S,GACXmX,EAAI1R,IAAehG,EAAII,EAAOD,EAC9B7H,EAAUof,GAAM,MAChBpf,EAAS+Y,GAAO,IAAMqG,IAAMzY,KAAKmV,MAAM7U,EAAMyG,IAAehG,EAAI,EAAI,GAAM,GAAKyX,IAG/EC,EAAI1V,EAAKoR,YAAYtI,EAAQuI,EAAM/d,EAASF,SAC5CggB,EAAKpT,EAAKoR,YAAYtI,EAAQuI,EAAM/d,EAAS6B,SAC7C4d,EAAK/S,EAAKuR,aAAazI,GAEvBxS,EAAU+a,GAASpU,KAAK0Y,KAAK3V,EAAKwS,OAAQnb,EAAI+b,EAAMqC,GAAc1C,EAAK2C,EAAI3C,GAAM2C,OAKnFpf,EAAUwS,EAAO9E,KAAiBzG,EAAMyG,IAAejG,EAAI,EAAI,GAG/D0S,EAAI1T,KAAM6Y,OAAQ,GAAIzP,IAAK,GAAI0P,OAAQ,GAAI3P,KAAM,GAAI4P,MAAO,KAAM/Y,IAAIzG,GAC/DA,GAGR6D,WAAY,SAAStG,EAAO4B,EAAKyS,GAYhC,QAAS6N,GAAUC,EAAWhS,EAAYiS,EAAW5E,EAAM6E,GAEvDF,IAAcvX,GAAS0X,EAAUnS,aAAeA,GAAc3D,EAAOgR,IAAS8E,EAAUF,KAAe1X,EACzG4X,EAAUnS,WAAamS,EAAUnS,aAAejG,EAAIC,EAAID,EAEjDiY,IAAcvX,GAAS4B,EAAOgR,KACrC8E,EAAUnS,GAAcmS,EAAUnS,KAAgBzF,EAChD8B,EAAOgR,GAAQ,EAAIA,EAAO6E,EAAaC,EAAUnS,KAAgBqN,EAAO6E,EAAW7E,GAIvF,QAAS+E,GAAUC,EAAIhF,EAAM6E,GACzBC,EAAUE,KAAQ9X,EACpBxB,EAAIsS,GAAO,IAAIgC,GAAQiF,EAAMD,GAAM/Y,EAAO+R,GAAO,IAAIgC,GAAQhR,EAAOgR,IAGpEzU,EAAQU,EAAO4Y,KAAc5jB,GAC1B+N,EAAOgR,IAAQ/T,EAAO+T,MAAahR,EAAOgR,GAAO/T,EAAO+T,KAEtDiF,EAAMD,GAAMpZ,KAAK0Y,IAAI/Y,EAAM,GAAIA,EAAM,KAAOA,EAAM,KACtDsL,EAAImJ,IAAShR,EAAOgR,GACpBiF,EAAMjF,GAAQtd,GAGfgJ,EAAKO,EAAO4Y,KAAc5jB,EAAY4jB,EAAW7E,GAASiF,EAAMD,IAnClE,GAAIljB,KAAKua,QAAT,CAEA,GAOCpQ,GAAkBV,EAPfhJ,EAAQ6B,EAAI7B,MACfuiB,EAAYhjB,KAAK2V,OAAOM,QACxB/I,EAAS6H,EAAIxC,SACbnL,EAAS9E,EAAIzC,QAAQsD,SAAS+J,OAAO9F,OAAO/C,MAAM,KAClD+e,EAAahc,EAAO,GACpBic,EAAWjc,EAAO,IAAMA,EAAO,GAC/B+b,GAAUpQ,KAAMnS,EAAOoS,IAAKpS,EAAO2S,EAAG,EAAGC,EAAG,GACpC5J,IA+BN5J,MAAK2V,OAAOpP,QAAUhD,IAExBqf,EAAUQ,EAAYxY,EAAGC,EAAGI,EAAME,GAClCyX,EAAUS,EAAUxY,EAAGD,EAAGI,EAAKE,IAG5B8X,EAAUlS,WAAarQ,EAAMkV,OAAO7E,UAAYrQ,EAAM6iB,YAAcpW,EAAO8F,KAAOvS,EAAM8iB,aAAerW,EAAO6F,OAChH/S,KAAK8gB,OAAOkC,EAAWpiB,IAKzBuJ,EAASnK,KAAKoiB,UAAUY,GAGrB7Y,EAAOwY,QAAUxjB,IAAagL,EAAO4I,MAAQ5I,EAAOwY,OACpDxY,EAAOuY,SAAWvjB,IAAagL,EAAO6I,KAAO7I,EAAOuY,QACvDvY,EAAOqZ,KAAOxjB,KAAKmK,QAGhBgZ,EAAMpQ,KAAQqQ,IAAe9X,KAAW4B,EAAO6F,OAASkQ,EAAUrY,EAAGK,EAAME,IAC3EgY,EAAMnQ,IAAOqQ,IAAa/X,KAAW4B,EAAO8F,MAAQiQ,EAAUpY,EAAGG,EAAKE,GAOzElL,KAAKqR,QAAQzH,IAAIA,GAAK5D,SAClBmd,EAAM5P,GAAK4P,EAAM3P,GAAOwP,EAAUzP,IAAMnI,GAAU+X,EAAM3P,GAAOwP,EAAUxP,IAAMpI,GAAU+X,EAAM5P,IAInGwB,EAAIhC,MAAQ5I,EAAO4I,KAAK9J,OAASkB,EAAOqZ,KACvCJ,IAAe9X,GAAS6X,EAAMnQ,MAAQmQ,EAAMpQ,OAASoQ,EAAMnQ,IAAM7I,EAAO4I,KAAO/S,KAAKqf,OAAS,EAC9FtK,EAAI/B,KAAO7I,EAAO6I,IAAI/J,OAASkB,EAAOqZ,KACrCH,IAAa/X,GAAS6X,EAAMpQ,OAASoQ,EAAMpQ,OAASoQ,EAAMnQ,IAAM7I,EAAO6I,IAAMhT,KAAKqf,OAAS,EAG5F5e,EAAM8iB,WAAarW,EAAO6F,KAAMtS,EAAM6iB,UAAYpW,EAAO8F,IACzDvS,EAAMkV,OAASqN,EAAU/M,UAG1B3H,QAAS,WAERtO,KAAKP,KAAKmZ,QAAQ5Y,KAAKP,KAAKQ,QAASD,KAAKkK,KAGvClK,KAAKP,KAAKU,SAASmd,KACrBtd,KAAKP,KAAKU,SAASmd,IAAI3O,KAAK,KAC1BC,SAASC,MAAMD,YAKpBqN,GAAMpY,EAAQyZ,IAAM,SAAShb,GAC5B,MAAO,IAAI2H,GAAI3H,EAAKA,EAAIzC,QAAQ6D,MAAM4Z,MAIvCrB,GAAI/N,WAAa,SAGjB+N,GAAInY,SAAW,SAASjE,GACvB,GAAGA,EAAQ6D,OAAS,OAAS7D,GAAQ6D,MAAO,CAC3C,GAAI3B,GAAOlC,EAAQ6D,MAAM4Z,GACN,iBAATvb,KAAqBA,EAAOlC,EAAQ6D,MAAM4Z,KAAQ3H,OAAQ5T,IAChE,kBAAoByE,WAAYzE,GAAK4T,UAAW5T,EAAK4T,OAASpS,KAKpEmH,EAAO4S,KACNmG,gDAAiD,WAEhDzjB,KAAK4d,SAGL5d,KAAKP,KAAKuH,cAEX0c,6BAA8B,SAASzf,GAEtCjE,KAAKoK,MAASnG,EAAIoG,MAAOpG,EAAIqG,QAC7BtK,KAAK8gB,SAGL9gB,KAAKP,KAAKuH,cAEX2c,yCAA0C,WACzC3jB,KAAK8gB,WAKPphB,EAAE+C,OAAOc,EAAM+D,EAAKc,UACnB1E,OACC4Z,KACC3H,OAAQpS,EACR8d,MAAOzgB,EACPyJ,MAAO,EACPC,OAAQ,EACR+U,OAAQ9b,EACR4G,OAAQ,KAIV,IAAIyZ,IAAOC,GACXC,GAAa,aACbC,GAAgB,IAAID,EAErBD,IAAU,WAST,QAASG,GAAU3S,GAElB,GAAG3R,EAAEukB,KAAK,KAAKD,UAAa,MAAOtkB,GAAEukB,KAAK,KAAKD,SAE/C,IAECE,GAAKC,EAAS5jB,EAFX6jB,GAAoB1P,MAAMhV,EAAEK,KAAKsR,EAAS,aAC7CgJ,EAAWhJ,EAAQgJ,UAAYhJ,EAAQgJ,SAAS1J,aAGjD,OAAG,SAAW0J,GACb6J,EAAM7S,EAAQgT,WACdF,EAAUD,EAAIlc,KACVqJ,EAAQiT,MAASH,GAA0C,QAA/BD,EAAI7J,SAAS1J,eAG7CpQ,EAAMb,EAAE,eAAiBykB,EAAU,KAAK,KAC/B5jB,GAAOA,EAAI+T,GAAG,cAHf,GAKD,sCAAsC9N,KAAM6T,IACjDhJ,EAAQ1Q,SACT,MAAQ0Z,EACPhJ,EAAQiT,MAAQF,EAChBA,EAKJ,QAASG,GAAYC,GAEjBC,EAAe9iB,OAAS,GAAK6iB,EAAU7iB,OAAU6iB,EAAUxN,IAAI,QAAQG,OAGnEsN,EAAeC,QAAQ7N,QAI/B,QAAS8N,GAAWjkB,GACnB,GAAIgH,EAAK4M,GAAG,YAAZ,CAEA,GAGCsQ,GAHGhlB,EAASF,EAAEgB,EAAMd,QACpBK,EAAU4kB,EAAQ5kB,QAClBoI,EAAYzI,EAAOwG,QAAQC,EAI5Bue,GAAcvc,EAAU1G,OAAS,EAAIf,EACnC8W,SAASrP,EAAU,GAAG3E,MAAMiU,OAAQ,IAAMD,SAASzX,EAAQ,GAAGyD,MAAMiU,OAAQ,IAK1EiN,GAAehlB,EAAOwG,QAAQC,GAAU,KAAOpG,EAAQ,IAC1DskB,EAAY3kB,GAIbklB,EAASpkB,EAAMd,SAAW6kB,EAAeA,EAAe9iB,OAAS,IA9DlE,GAECkjB,GAASC,EACTC,EAAWrd,EAHRmF,EAAO7M,KACVykB,IAgED/kB,GAAE+C,OAAOoK,GACRpF,KAAM,WA0BL,MAxBAC,GAAOmF,EAAKnF,KAAOhI,EAAE,WACpBI,GAAI,eACJ2R,KAAM,cACNuT,UAAW,WAAa,MAAOpkB,MAE/B6C,OAGD/D,EAAER,EAASmI,MAAMyP,KAAK,UAAUiN,GAAeY,GAG/CjlB,EAAER,GAAU4X,KAAK,UAAUiN,GAAe,SAASrjB,GAC/CmkB,GAAWA,EAAQhlB,QAAQyD,KAAK2hB,MAAMC,QAA4B,KAAlBxkB,EAAMykB,SACxDN,EAAQphB,KAAK/C,KAKfgH,EAAKoP,KAAK,QAAQiN,GAAe,SAASrjB,GACtCmkB,GAAWA,EAAQhlB,QAAQyD,KAAK2hB,MAAM9N,MACxC0N,EAAQphB,KAAK/C,KAIRmM,GAGRiU,OAAQ,SAASxe,GAEhBuiB,EAAUviB,EAITmiB,EADEniB,EAAIzC,QAAQyD,KAAK2hB,MAAMG,aAAexkB,EACvB0B,EAAIrC,QAAQ0O,KAAK,KAAKmJ,OAAO,WAC7C,MAAOkM,GAAUhkB,YAMpBgG,OAAQ,SAAS1D,EAAK4T,EAAO1Q,GAC5B,GACCvF,IADaP,EAAER,EAASmI,MACd/E,EAAIrC,SACdJ,EAAUyC,EAAIzC,QAAQyD,KAAK2hB,MAC3B5S,EAASxS,EAAQwS,OACjB9Q,EAAO2U,EAAQ,OAAQ,OACvBjD,EAAUvL,EAAK4M,GAAG,YAClB+Q,EAAgB3lB,EAAEqkB,IAAejM,OAAO,2BAA2Bd,IAAI/W,EAqBxE,OAjBA4M,GAAKiU,OAAOxe,GAIT4T,GAASrW,EAAQulB,aAAexkB,GAClC2jB,EAAa7kB,EAAE,WAIhBgI,EAAK+F,YAAY,QAAS5N,EAAQsX,MAG/BjB,GACFxO,EAAKgG,SAASxO,EAASmI,MAIpBK,EAAK4M,GAAG,cAAgBrB,IAAYiD,GAAS6O,IAAcnkB,IAAYsV,GAASmP,EAAc1jB,OAC1FkL,GAIRnF,EAAKgH,KAAKnL,EAAM3C,GAGblB,EAAEgC,WAAW2Q,GACfA,EAAO1M,KAAK+B,EAAMwO,GAIX7D,IAAWzR,EAClB8G,EAAMnG,KAKNmG,EAAK6P,OAAQG,SAASlS,EAAU,KAAO,GAAI0Q,EAAQ,EAAI,EAAG,WACrDA,GAASxO,EAAKjE,SAKhByS,GACHxO,EAAKiN,MAAM,SAASC,GACnBlN,EAAKkC,KAAMmJ,KAAM,GAAIC,IAAK,KACtBtT,EAAEqkB,IAAepiB,QAAU+F,EAAK4d,SACpC1Q,MAKFmQ,EAAY7O,EAGT2O,EAAQ7jB,YAAa6jB,EAAU3kB,GAE3B2M,MAITA,EAAKpF,QAENoc,GAAU,GAAIA,IASdnkB,EAAE+C,OAAO8H,EAAMiC,WACd/E,KAAM,SAAShI,GACd,GAAIQ,GAAUR,EAAKQ,OAGnB,OAAID,MAAKH,QAAQyY,IAGjB7Y,EAAKU,SAASolB,QAAU1B,GAAQnc,KAGhCzH,EAAQmQ,SAAS0T,IAAYla,IAAI,UAAWtC,EAAKke,aAAe9lB,EAAEqkB,IAAepiB,QAGjFlC,EAAK+Y,MAAMvY,GAAU,cAAe,eAAgB,SAASS,EAAO4B,EAAKkD,GACxE,GAAIigB,GAAS/kB,EAAMmY,aAGnB,IAAGnY,EAAMd,SAAWK,EAAQ,GAC3B,GAAGwlB,GAAyB,gBAAf/kB,EAAMa,MAA0B,qBAAqBiF,KAAKif,EAAOlkB,OAAS7B,EAAE+lB,EAAOvf,eAAeE,QAAQyd,GAAQnc,KAAK,IAAI/F,OACvI,IAAMjB,EAAM+F,iBAAoB,MAAME,UAE9B8e,GAAWA,GAA0B,gBAAhBA,EAAOlkB,OACpCvB,KAAKgG,OAAOtF,EAAsB,gBAAfA,EAAMa,KAAwBiE,IAGjDxF,KAAKkK,IAAKlK,MAGbP,EAAK+Y,MAAMvY,EAAS,eAAgB,SAASS,EAAO4B,GAEnD,IAAG5B,EAAMoY,sBAAwBpY,EAAMd,SAAWK,EAAQ,GAA1D,CAEA,GAAIuX,GAAQ9X,EAAEqkB,IAGdnM,EAAWtQ,EAAKke,aAAehO,EAAM7V,OACrC8V,EAAWC,SAASzX,EAAQ,GAAGyD,MAAMiU,OAAQ,GAG7CkM,IAAQnc,KAAK,GAAGhE,MAAMiU,OAASC,EAAW,EAG1CJ,EAAM5T,KAAK,WACP5D,KAAK0D,MAAMiU,OAASF,IACtBzX,KAAK0D,MAAMiU,QAAU,KAKvBH,EAAMM,OAAO,IAAMpM,GAAajM,KAAK,OAAQiB,EAAMmY,eAGnD5Y,EAAQmQ,SAAS1E,GAAa,GAAGhI,MAAMiU,OAASC,EAGhDiM,GAAQ/C,OAAOxe,EAGf,KAAM5B,EAAM+F,iBAAoB,MAAME,OACpC3G,KAAKkK,IAAKlK,UAGbP,GAAK+Y,MAAMvY,EAAS,cAAe,SAASS,GACxCA,EAAMd,SAAWK,EAAQ,IAC3BP,EAAEqkB,IAAejM,OAAO,YAAYd,IAAI/W,GAASylB,OAAOjmB,KAAK,QAASiB,IAErEV,KAAKkK,IAAKlK,OA9DiBA,MAiE/BgG,OAAQ,SAAStF,EAAOwV,EAAO1Q,GAE9B,MAAG9E,IAASA,EAAMoY,qBAA+B9Y,SAGjD6jB,IAAQ7d,OAAOhG,KAAKP,OAAQyW,EAAO1Q,IAGpC8I,QAAS,WAERtO,KAAKP,KAAKQ,QAAQkQ,YAAY2T,IAG9B9jB,KAAKP,KAAKmZ,QAAQ5Y,KAAKP,KAAKQ,QAASD,KAAKkK,KAG1C2Z,GAAQ7d,OAAOhG,KAAKP,KAAMmB,SACnBZ,MAAKP,KAAKU,SAASolB,WAK5B3B,GAAQ/f,EAAQohB,MAAQ,SAAS3iB,GAChC,MAAO,IAAIiI,GAAMjI,EAAKA,EAAIzC,QAAQyD,KAAK2hB,QAIxCrB,GAAM9f,SAAW,SAAS/B,GACtBA,EAAKuB,OACuB,gBAApBvB,GAAKuB,KAAK2hB,MAAsBljB,EAAKuB,KAAK2hB,OAAU3M,KAAMvW,EAAKuB,KAAK2hB,OACxC,mBAAvBljB,GAAKuB,KAAK2hB,MAAM3M,KAAsBvW,EAAKuB,KAAK2hB,MAAM3M,GAAK/U,KAK5E+D,EAAKke,aAAele,EAAKuQ,OAAS,IAGlC+L,GAAM1V,WAAa,SAGnBxD,EAAOua,OACNU,yBAA0B,WAEzB3lB,KAAKsO,UACLtO,KAAKyH,OAGLzH,KAAKP,KAAK+b,MAAM+J,QAAQvf,OACvBhG,KAAKP,KAAKQ,QAAQ,GAAG8G,YAAc,KAMtCrH,EAAE+C,OAAOc,EAAM+D,EAAKc,UACnB9E,MACC2hB,OACC3M,GAAI1X,EACJyR,OAAQ9O,EACR4T,KAAM5T,EACN6hB,WAAY7hB,EACZ2hB,OAAQ3hB,MAIVM,EAAQ0E,SAAW,SAASjG,EAAKa,EAAUwE,EAAYkL,EAAaC,EAAc8S,EAAWC,GAkC7F,QAASzD,GAAUlE,EAAM4H,EAAWvkB,EAAM2L,EAAQ6Y,EAAOC,EAAOC,EAAYC,EAAcC,GACzF,GAAIC,GAAajjB,EAAS4iB,GACzBM,EAASjjB,EAAG8a,GACZoI,EAASjjB,EAAG6a,GACZqI,EAAUhlB,IAAS+J,EACnBkb,EAAWH,IAAWN,EAAQI,EAAaE,IAAWL,GAASG,GAAcA,EAAa,EAC1FM,EAAWH,IAAWP,EAAQG,EAAeI,IAAWN,GAASE,GAAgBA,EAAe,EAChGQ,EAAaC,EAAeZ,GAASa,EAAeb,IAAUc,EAAkB,EAAIC,EAAgBf,IACpGgB,EAAYL,EAAaN,EACzBY,EAAYZ,EAAaD,GAAcF,IAAenb,EAAQmc,EAAgBC,GAAkBR,EAChGvc,EAASqc,GAAYpjB,EAAGyN,aAAeqN,GAAQmI,IAAWjjB,EAAG0iB,GAAaW,EAAW,IAAMH,IAAWlb,EAAS8a,EAAe,EAAI,EAgDnI,OA7CGK,IACFpc,GAAUkc,IAAWN,EAAQ,EAAI,IAAMS,EAGvCrjB,EAAS4iB,IAAUgB,EAAY,EAAIA,EAAYC,EAAY,GAAKA,EAAY,EAC5E7jB,EAAS4iB,GAASjc,KAAK0Y,KACrBsE,EAAgBf,GAASa,EAAeb,GACzCK,EAAajc,EACbL,KAAKqd,IACJrd,KAAK0Y,KACHsE,EAAgBf,GAASa,EAAeb,IAAUE,IAAenb,EAAQmc,EAAgBC,GAC1Fd,EAAajc,GAEdhH,EAAS4iB,GAGE,WAAXM,EAAsBD,EAAaI,EAAW,QAShDtZ,GAAW3L,IAAS8J,EAAa,EAAI,EAGlC0b,EAAY,IAAMV,IAAWN,GAASiB,EAAY,IACpD7jB,EAAS4iB,IAAU5b,EAAS+C,EAC5Bka,EAAMtR,OAAOoI,EAAM6H,IAIZiB,EAAY,IAAMX,IAAWL,GAASe,EAAY,KACzD5jB,EAAS4iB,KAAWM,IAAWjb,GAAUjB,EAASA,GAAU+C,EAC5Dka,EAAMtR,OAAOoI,EAAM8H,IAIjB7iB,EAAS4iB,GAASY,IAAmBxjB,EAAS4iB,GAASiB,IACzD7jB,EAAS4iB,GAASK,EAAYgB,EAAQhkB,EAAG6S,UAIpC9S,EAAS4iB,GAASK,EA1F1B,GAYC7f,GAAO6gB,EAAON,EAAiBD,EAC/BI,EAAeC,EAAgBP,EAAgBC,EAb5ChnB,EAAS+H,EAAW/H,OACvBK,EAAUqC,EAAInC,SAASF,QACvBmD,EAAKuE,EAAWvE,GAChBC,EAAKsE,EAAWtE,GAChB6J,EAASvF,EAAWuF,OACpB9F,EAAS8F,EAAO9F,OAAO/C,MAAM,KAC7BgjB,EAAUjgB,EAAO,GACjBkgB,EAAUlgB,EAAO,IAAMA,EAAO,GAC9BmB,EAAWZ,EAAWY,SACtBF,EAAYV,EAAWU,UAEvBkK,GADQjQ,EAAI7B,OACCsS,KAAM,EAAGC,IAAK,GAK5B,OAAIzK,GAAS3G,QAAUhC,EAAO,KAAOX,GAAUW,EAAO,KAAOV,EAASmI,MAA0B,SAAlB6F,EAAO9F,QAKrF0f,EAAkBze,EAAU8B,UAAYoI,EACxCsU,EAAgD,WAA9Bxe,EAAUuB,IAAI,YAGhCrD,EAAoC,UAA5BtG,EAAQ2J,IAAI,YACpBqd,EAAgB1e,EAAS,KAAOtJ,EAASsJ,EAAS8B,QAAU9B,EAASmK,WAAW9R,GAChFsmB,EAAiB3e,EAAS,KAAOtJ,EAASsJ,EAAS+B,SAAW/B,EAASqK,YAAYhS,GACnF+lB,GAAmB5T,KAAMxM,EAAQ,EAAIgC,EAAS0L,aAAcjB,IAAKzM,EAAQ,EAAIgC,EAAS4L,aACtFyS,EAAiBre,EAAS4B,UAAYoI,GAiEvB,UAAZ8U,GAAmC,UAAZC,KAAuBF,EAAQhkB,EAAG6S,SAG5D1D,GACCQ,KAAkB,SAAZsU,EAAqBjF,EAAWxX,EAAGC,EAAGwc,EAASna,EAAOqG,EAAGtI,EAAME,EAAOL,EAAO+H,EAAa+S,GAAc,EAC9G5S,IAAiB,SAAZsU,EAAqBlF,EAAWvX,EAAGD,EAAG0c,EAASpa,EAAOsG,EAAGxI,EAAKE,EAAQH,EAAQ+H,EAAc+S,GAAe,EAChHziB,GAAIgkB,IAnFG7U,GAwFR1O,EAAQ0jB,OAIRC,QAAS,SAASC,EAAY9R,GAC7B,GAQOf,GAIP8S,EAAUC,EAZN/W,GACHvG,MAAO,EAAGC,OAAQ,EAClBnH,UACC6P,IAAK,KAAM2P,MAAO,EAClBD,OAAQ,EAAG3P,KAAM,MAElB0B,WAAY7T,GAEbsD,EAAI,EACJuc,KACAmH,EAAW,EAAGC,EAAW,EACzBC,EAAQ,EAAGC,EAAQ,CAII,KAAvB7jB,EAAIujB,EAAW9lB,OAAcuC,KAC5B0Q,GAAS8C,SAAS+P,IAAavjB,GAAI,IAAKwT,SAAS+P,EAAWvjB,EAAE,GAAI,KAE/D0Q,EAAK,GAAKhE,EAAOzN,SAASwf,QAAQ/R,EAAOzN,SAASwf,MAAQ/N,EAAK,IAC/DA,EAAK,GAAKhE,EAAOzN,SAAS4P,OAAOnC,EAAOzN,SAAS4P,KAAO6B,EAAK,IAC7DA,EAAK,GAAKhE,EAAOzN,SAASuf,SAAS9R,EAAOzN,SAASuf,OAAS9N,EAAK,IACjEA,EAAK,GAAKhE,EAAOzN,SAAS6P,MAAMpC,EAAOzN,SAAS6P,IAAM4B,EAAK,IAE9D6L,EAAO1b,KAAK6P,EAQb,IAJA8S,EAAW9W,EAAOvG,MAAQP,KAAK8Q,IAAIhK,EAAOzN,SAASwf,MAAQ/R,EAAOzN,SAAS4P,MAC3E4U,EAAY/W,EAAOtG,OAASR,KAAK8Q,IAAIhK,EAAOzN,SAASuf,OAAS9R,EAAOzN,SAAS6P,KAGvD,MAApB2C,EAAOvD,SACTxB,EAAOzN,UACN4P,KAAMnC,EAAOzN,SAAS4P,KAAQnC,EAAOvG,MAAQ,EAC7C2I,IAAKpC,EAAOzN,SAAS6P,IAAOpC,EAAOtG,OAAS,OAGzC,CAEJ,KAAMod,EAAW,GAAKC,EAAY,GAAKC,EAAW,GAAKC,EAAW,GAa9C,IAXnBH,EAAW5d,KAAKke,MAAMN,EAAW,GACjCC,EAAY7d,KAAKke,MAAML,EAAY,GAEhChS,EAAOpC,IAAMtI,EAAO2c,EAAWF,EAC1B/R,EAAOpC,IAAMpI,EAAQyc,EAAWhX,EAAOvG,MAAQqd,EACjDE,GAAY9d,KAAKke,MAAMN,EAAW,GAErC/R,EAAOnC,IAAMxI,EAAM6c,EAAWF,EACzBhS,EAAOnC,IAAMtI,EAAS2c,EAAWjX,EAAOtG,OAASqd,EACnDE,GAAY/d,KAAKke,MAAML,EAAY,GAEzCzjB,EAAIuc,EAAO9e,OAAcuC,OAErBuc,EAAO9e,OAAS,IAEnBmmB,EAAQrH,EAAOvc,GAAG,GAAK0M,EAAOzN,SAAS4P,KACvCgV,EAAQtH,EAAOvc,GAAG,GAAK0M,EAAOzN,SAAS6P,KAEnC2C,EAAOpC,IAAMtI,GAAQ6c,GAASF,GACjCjS,EAAOpC,IAAMpI,GAAkByc,GAATE,GACtBnS,EAAOpC,IAAMnI,IAAmBwc,EAARE,GAAoBA,EAASlX,EAAOvG,MAAQud,IACpEjS,EAAOnC,IAAMxI,GAAO+c,GAASF,GAC7BlS,EAAOnC,IAAMtI,GAAmB2c,GAATE,GACvBpS,EAAOnC,IAAMpI,IAAmByc,EAARE,GAAoBA,EAASnX,EAAOtG,OAASud,KACrEpH,EAAOjH,OAAOtV,EAAG,EAIpB0M,GAAOzN,UAAa4P,KAAM0N,EAAO,GAAG,GAAIzN,IAAKyN,EAAO,GAAG,IAGxD,MAAO7P,IAGRqX,KAAM,SAASC,EAAIC,EAAIC,EAAIC,GAC1B,OACChe,MAAOP,KAAK8Q,IAAIwN,EAAKF,GACrB5d,OAAQR,KAAK8Q,IAAIyN,EAAKF,GACtBhlB,UACC4P,KAAMjJ,KAAKqd,IAAIe,EAAIE,GACnBpV,IAAKlJ,KAAKqd,IAAIgB,EAAIE,MAKrBC,SACCtI,GAAI,IAAOF,GAAI,EAAI,EAAGC,GAAI,EAAI,EAC9BE,GAAI,GAAOL,GAAI,IAAOC,GAAI,IAC1BK,GAAI,EAAGC,GAAI,EAAG1e,EAAG,GAElB8mB,QAAS,SAASC,EAAIC,EAAIC,EAAIC,EAAIhT,GACjC,GAAIlU,GAAIoC,EAAQ0jB,MAAMe,QAAS3S,EAAOvD,UACrCwW,EAAY,IAANnnB,EAAU,EAAIinB,EAAK5e,KAAK+e,IAAKpnB,EAAIqI,KAAKgf,IAC5CC,EAAMJ,EAAK7e,KAAKkf,IAAKvnB,EAAIqI,KAAKgf,GAE/B,QACCze,MAAa,EAALqe,EAAU5e,KAAK8Q,IAAIgO,GAC3Bte,OAAc,EAALqe,EAAU7e,KAAK8Q,IAAImO,GAC5B5lB,UACC4P,KAAMyV,EAAKI,EACX5V,IAAKyV,EAAKM,GAEXtU,WAAY7T,IAGdqoB,OAAQ,SAAST,EAAIC,EAAIS,EAAGvT,GAC3B,MAAO9R,GAAQ0jB,MAAMgB,QAAQC,EAAIC,EAAIS,EAAGA,EAAGvT,KAG5C9R,EAAQ0Q,IAAM,SAASjS,EAAKiS,EAAKoB,GAYjC,IAVA,GAKCwT,GAAaC,EAAKC,EAClBC,EAAK1U,EAAM1Q,EAAGqlB,EACd3Y,EAAQzN,EANRuE,GADShI,EAAER,GACJqV,EAAI,IACXiV,EAAO9pB,EAAEgI,EAAK8M,iBACdnB,EAAgB3L,EAAK2L,cACrBoW,GAAgB/R,SAASnD,EAAI3K,IAAI,gBAAiB,KAAO,GAAK,GAMxDlC,EAAKgiB,SAAWhiB,EAAOA,EAAK2c,UACnC,KAAI3c,EAAKgiB,UAAYhiB,EAAK2c,WAAc,MAAOzjB,EAG/C,QAAO8G,EAAK2S,UACX,IAAK,UACL,IAAK,SACJzJ,EAAS/M,EAAQ0jB,MAAMgB,QACtB7gB,EAAK8gB,GAAGmB,QAAQ1Y,MAChBvJ,EAAK+gB,GAAGkB,QAAQ1Y,OACfvJ,EAAKghB,IAAMhhB,EAAKwhB,GAAGS,QAAQ1Y,MAAQwY,GACnC/hB,EAAKihB,IAAMjhB,EAAKwhB,GAAGS,QAAQ1Y,MAAQwY,EACpC9T,EAEF,MAEA,KAAK,OACL,IAAK,UACL,IAAK,WAOJ,IALA4T,EAAS7hB,EAAK6hB,UACXhW,EAAG7L,EAAKkiB,GAAGD,QAAQ1Y,MAAOuC,EAAG9L,EAAKmiB,GAAGF,QAAQ1Y,QAC7CsC,EAAG7L,EAAKoiB,GAAGH,QAAQ1Y,MAAOuC,EAAG9L,EAAKqiB,GAAGJ,QAAQ1Y,QAG5CL,KAAa1M,EAAI,GAAIolB,EAAMC,EAAOS,eAAiBT,EAAO5nB,SAAUuC,EAAIolB,GAC3E1U,EAAO2U,EAAOU,QAAUV,EAAOU,QAAQ/lB,GAAKqlB,EAAOrlB,GACnD0M,EAAO7L,KAAKC,MAAM4L,GAASgE,EAAKrB,EAAGqB,EAAKpB,GAGzC5C,GAAS/M,EAAQ0jB,MAAMC,QAAQ5W,EAAQ+E,EACxC,MAGA,SACC/E,EAASlJ,EAAKgiB,UACd9Y,GACCvG,MAAOuG,EAAOvG,MACdC,OAAQsG,EAAOtG,OACfnH,UACC4P,KAAMnC,EAAO2C,EACbP,IAAKpC,EAAO4C,IAoChB,MA7BArQ,GAAWyN,EAAOzN,SAClBqmB,EAAOA,EAAK,GAGTA,EAAKU,iBACPd,EAAM1hB,EAAKyiB,eACXZ,EAASC,EAAKU,iBAEdX,EAAOhW,EAAIpQ,EAAS4P,KACpBwW,EAAO/V,EAAIrQ,EAAS6P,IACpBqW,EAAcE,EAAOa,gBAAiBhB,GACtCjmB,EAAS4P,KAAOsW,EAAY9V,EAC5BpQ,EAAS6P,IAAMqW,EAAY7V,GAIzBH,IAAkBnU,GAAoC,UAAxBoD,EAAIa,SAASvD,SAC7CupB,EAAczpB,GAAG2T,EAAcgX,aAAehX,EAAciX,cAAcC,cAAcpgB,SACrFgf,IACFhmB,EAAS4P,MAAQoW,EAAYpW,KAC7B5P,EAAS6P,KAAOmW,EAAYnW,MAK9BK,EAAgB3T,EAAE2T,GAClBlQ,EAAS4P,MAAQM,EAAcY,aAC/B9Q,EAAS6P,KAAOK,EAAcc,YAEvBvD,GAEP/M,EAAQwQ,SAAW,SAAS/R,EAAKkoB,EAAM7U,GAEnC6U,EAAK5oB,SAAU4oB,EAAO9qB,EAAE8qB,GAE5B,IAICC,GAAahK,EAAQvc,EAAS0M,EAAQ0Y,EAJnCoB,GAASF,EAAKzqB,KAAK,UAAY,QAAQ4Q,cAAcpE,QAAQ,OAAQ,WACxEoe,EAAQjrB,EAAE,gBAAgB8qB,EAAKlV,OAAO,OAAOvV,KAAK,QAAQ,MAC1D6qB,EAAelrB,EAAEoa,KAAK0Q,EAAKzqB,KAAK,WAChC8qB,EAAcD,EAAare,QAAQ,KAAM,IAAIlI,MAAM,IAIpD,KAAIsmB,EAAMhpB,OAAU,MAAOf,EAG3B,IAAa,YAAV8pB,EACF9Z,EAAS/M,EAAQ0jB,MAAMC,QAAQqD,EAAalV,OAIxC,CAAA,IAAG9R,EAAQ0jB,MAAMmD,GAWf,MAAO9pB,EAVb,KAAIsD,EAAI,GAAIolB,EAAMuB,EAAYlpB,OAAQ8e,OAAevc,EAAIolB,GACxD7I,EAAO1b,KAAM2S,SAASmT,EAAY3mB,GAAI,IAGvC0M,GAAS/M,EAAQ0jB,MAAMmD,GAAO1lB,MAC7BhF,KAAMygB,EAAOrb,OAAOuQ,IAgBtB,MARA8U,GAAcE,EAAMxgB,SACpBsgB,EAAY1X,MAAQjJ,KAAKC,MAAM4gB,EAAMjY,WAAW9R,GAAS+pB,EAAMtgB,SAAW,GAC1EogB,EAAYzX,KAAOlJ,KAAKC,MAAM4gB,EAAM/X,YAAYhS,GAAS+pB,EAAMrgB,UAAY,GAG3EsG,EAAOzN,SAAS4P,MAAQ0X,EAAY1X,KACpCnC,EAAOzN,SAAS6P,KAAOyX,EAAYzX,IAE5BpC,EAEP,IAAIka,IAMLC,GAAW,+OASXrrB,GAAE+C,OAAO+H,EAAIgC,WACZwe,QAAU,WACT,GAAIzF,GAAUvlB,KAAKP,KAAKU,SAASolB,OACjCA,KAAYA,EAAQ,GAAG7hB,MAAMsP,IAAMtT,EAAET,GAAQkV,YAAc,OAG5D1M,KAAM,SAAShI,GACd,GAAIQ,GAAUR,EAAKQ,OAIhBP,GAAE,kBAAkBiC,OAAS,IAC/B3B,KAAKirB,SAAWxrB,EAAKU,SAAS8qB,SAAWvrB,EAAEqrB,IAAUrd,SAASzN,GAG9DR,EAAK+Y,MAAMvY,EAAS,cAAeD,KAAKkrB,eAAgBlrB,KAAKkK,IAAKlK,OAInEA,KAAKmrB,gBAAkBzrB,EAAE,UAAYI,GAAIO,EAAU,gBACjDqN,SAASxO,EAASmI,MAGhB5H,EAAKU,SAASolB,SAAW9lB,EAAKU,SAASolB,QAAQnV,SAAS,sBAC3D3Q,EAAK+Y,MAAMvZ,GAAS,SAAU,UAAWe,KAAKgrB,QAAShrB,KAAKkK,IAAKlK,MACjEP,EAAK+Y,MAAMvY,GAAU,eAAgBD,KAAKgrB,QAAShrB,KAAKkK,IAAKlK,OAI9DA,KAAKorB,UAGNF,eAAgB,WACf,GAOCG,GAAWlhB,EAPRlK,EAAUD,KAAKP,KAAKQ,QACvBqrB,GACChhB,OAAQrK,EAAQ2S,YAAYhS,GAC5ByJ,MAAOpK,EAAQyS,WAAW9R,IAE3B2qB,EAASvrB,KAAKP,KAAKe,QAAQ8c,IAC3BA,EAAMtd,KAAKP,KAAKU,SAASmd,GAI1BnT,GAASuN,SAASzX,EAAQ2J,IAAI,mBAAoB,KAAO,EACzDO,GAAW4I,MAAO5I,EAAQ6I,KAAM7I,GAG7BohB,GAAUjO,IACZ+N,EAA0C,MAA7BE,EAAO5V,OAAO9E,YAAuB/F,EAAOG,IAASF,EAAQC,GAC1Eb,EAAQkhB,EAAU,KAAQ/N,EAAK+N,EAAU,OAI1CrrB,KAAKirB,SAASrhB,IAAIO,GAAQP,IAAI0hB,IAI/BF,OAAQ,WACP,GAAGprB,KAAKP,KAAKsB,SAAW,GAAKf,KAAKwrB,QAAW,MAAOxrB,KAEpD,IAGCyrB,GAAMphB,EAAOmY,EAAK2E,EAHflnB,EAAUD,KAAKP,KAAKQ,QACvByD,EAAQ1D,KAAKP,KAAKI,QAAQ6D,MAC1B2E,EAAYrI,KAAKP,KAAKI,QAAQsD,SAASkF,SAsCxC,OAlCArI,MAAKP,KAAK+rB,QAAU,EAGjB9nB,EAAM4G,QAAUrK,EAAQ2J,IAAImB,EAAQrH,EAAM4G,QAC1C5G,EAAM2G,MAASpK,EAAQ2J,IAAIkB,EAAOpH,EAAM2G,QAK1CpK,EAAQ2J,IAAIkB,EAAO,IAAI4C,SAAS1N,KAAKmrB,iBAGrC9gB,EAAQpK,EAAQoK,QACD,EAAZA,EAAQ,IAASA,GAAS,GAG7BmY,EAAMviB,EAAQ2J,IAAI,aAAe,GACjCud,EAAMlnB,EAAQ2J,IAAI,aAAe,GAGjC6hB,GAAQjJ,EAAM2E,GAAK7M,QAAQ,KAAO,GAAKjS,EAAUgC,QAAU,IAAM,EAClEmY,GAAQA,EAAIlI,QAAQ,KAAO,GAAKmR,EAAO,GAAK/T,SAAS8K,EAAK,KAAQnY,EACjE8c,GAAQA,EAAI7M,QAAQ,KAAO,GAAKmR,EAAO,GAAK/T,SAASyP,EAAK,KAAQ,EAGlE9c,EAAQmY,EAAM2E,EAAMrd,KAAKqd,IAAIrd,KAAK0Y,IAAInY,EAAO8c,GAAM3E,GAAOnY,EAG1DpK,EAAQ2J,IAAIkB,EAAOhB,KAAKmV,MAAM5U,IAAQqD,SAASrF,IAIhDrI,KAAKwrB,QAAU,EAERxrB,MAGRsO,QAAS,WAERtO,KAAKirB,UAAYjrB,KAAKirB,SAASrc,SAG/B5O,KAAKP,KAAKmZ,SAAS3Z,EAAQe,KAAKP,KAAKQ,SAAUD,KAAKkK,QAItD4gB,GAAMjnB,EAAQ6nB,IAAM,SAASppB,GAE5B,MAAsB,KAAfuJ,GAAQC,GAAW,GAAItB,GAAIlI,GAAO1B,GAG1CkqB,GAAI5c,WAAa,SAEjBxD,EAAOghB,KACNC,kBAAmB,WAClB3rB,KAAKorB,cAIJnsB,OAAQC"} \ No newline at end of file diff --git a/assets/js/notifications/admin-notifications.js b/assets/js/notifications/admin-notifications.js new file mode 100644 index 00000000..bc68cd56 --- /dev/null +++ b/assets/js/notifications/admin-notifications.js @@ -0,0 +1,196 @@ +/** + * Duplicator Admin Notifications. + * + * @since 1.6.0 + */ + +'use strict'; + +var DupAdminNotifications = window.DupAdminNotifications || (function (document, window, $) { + + /** + * Elements holder. + * + * @since 1.6.0 + * + * @type {object} + */ + var el = { + + $notifications: $('#dup-notifications'), + $nextButton: $('#dup-notifications .navigation .next'), + $prevButton: $('#dup-notifications .navigation .prev'), + $adminBarCounter: $('#wp-admin-bar-dup-menu .dup-menu-notification-counter'), + $adminBarMenuItem: $('#wp-admin-bar-dup-notifications'), + + }; + + /** + * Public functions and properties. + * + * @since 1.6.0 + * + * @type {object} + */ + var app = { + + /** + * Start the engine. + * + * @since 1.6.0 + */ + init: function () { + + $(app.ready); + }, + + /** + * Document ready. + * + * @since 1.6.0 + */ + ready: function () { + + app.updateNavigation(); + app.events(); + }, + + /** + * Register JS events. + * + * @since 1.6.0 + */ + events: function () { + + el.$notifications + .on('click', '.dismiss', app.dismiss) + .on('click', '.next', app.navNext) + .on('click', '.prev', app.navPrev); + }, + + /** + * Click on the Dismiss notification button. + * + * @since 1.6.0 + * + * @param {object} event Event object. + */ + dismiss: function (event) { + + if (el.$currentMessage.length === 0) { + return; + } + + // Update counter. + var count = parseInt(el.$adminBarCounter.text(), 10); + if (count > 1) { + --count; + el.$adminBarCounter.html(count); + } else { + el.$adminBarCounter.remove(); + el.$adminBarMenuItem.remove(); + } + + // Remove notification. + var $nextMessage = el.$nextMessage.length < 1 ? el.$prevMessage : el.$nextMessage, + messageId = el.$currentMessage.data('message-id'); + + if ($nextMessage.length === 0) { + el.$notifications.fadeOut(300); + } else { + el.$currentMessage.remove(); + $nextMessage.addClass('current'); + app.updateNavigation(); + } + + // AJAX call - update option. + var data = { + action: 'duplicator_notification_dismiss', + nonce: dup_admin_notifications.nonce, + id: messageId, + }; + + $.post(dup_admin_notifications.ajax_url, data, function (res) { + + if (!res.success) { + console.log(res); + } + }).fail(function (xhr, textStatus, e) { + + console.log(xhr.responseText); + }); + }, + + /** + * Click on the Next notification button. + * + * @since 1.6.0 + * + * @param {object} event Event object. + */ + navNext: function (event) { + + if (el.$nextButton.hasClass('disabled')) { + return; + } + + el.$currentMessage.removeClass('current'); + el.$nextMessage.addClass('current'); + + app.updateNavigation(); + }, + + /** + * Click on the Previous notification button. + * + * @since 1.6.0 + * + * @param {object} event Event object. + */ + navPrev: function (event) { + + if (el.$prevButton.hasClass('disabled')) { + return; + } + + el.$currentMessage.removeClass('current'); + el.$prevMessage.addClass('current'); + + app.updateNavigation(); + }, + + /** + * Update navigation buttons. + * + * @since 1.6.0 + */ + updateNavigation: function () { + + if (el.$notifications.find('.dup-notifications-message.current').length === 0) { + el.$notifications.find('.dup-notifications-message:first-child').addClass('current'); + } + + el.$currentMessage = el.$notifications.find('.dup-notifications-message.current'); + el.$nextMessage = el.$currentMessage.next('.dup-notifications-message'); + el.$prevMessage = el.$currentMessage.prev('.dup-notifications-message'); + + if (el.$nextMessage.length === 0) { + el.$nextButton.addClass('disabled'); + } else { + el.$nextButton.removeClass('disabled'); + } + + if (el.$prevMessage.length === 0) { + el.$prevButton.addClass('disabled'); + } else { + el.$prevButton.removeClass('disabled'); + } + }, + }; + + return app; + +}(document, window, jQuery)); + +// Initialize. +DupAdminNotifications.init(); diff --git a/assets/js/notifications/notices.js b/assets/js/notifications/notices.js new file mode 100644 index 00000000..d5b33c1c --- /dev/null +++ b/assets/js/notifications/notices.js @@ -0,0 +1,83 @@ +/** + * Duplicator Dismissible Notices. + * + */ + +'use strict'; + +var DupAdminNotices = window.DupAdminNotices || (function (document, window, $) { + + /** + * Public functions and properties. + */ + var app = { + + /** + * Start the engine. + */ + init: function () { + + $(app.ready); + }, + + /** + * Document ready. + */ + ready: function () { + + app.events(); + }, + + /** + * Dismissible notices events. + */ + events: function () { + $(document).on( + 'click', + '.dup-notice .notice-dismiss, .dup-notice .dup-notice-dismiss', + app.dismissNotice + ); + + $(document).on( + 'click', + '.dup-notice .dup-multi-notice a[data-step]', + function (e) { + e.preventDefault(); + var target = $(this).attr('data-step'); + console.log(target) + if (target) { + var notice = $(this).closest('.dup-multi-notice'); + var review_step = notice.find('.dup-multi-notice-step-' + target); + if (review_step.length > 0) { + notice.find('.dup-multi-notice-step:visible').fadeOut(function () { + review_step.fadeIn(); + }); + } + } + } + ); + }, + + /** + * Dismiss notice event handler. + * + * @param {object} e Event object. + * */ + dismissNotice: function (e) { + + $.post(dup_admin_notices.ajax_url, { + action: 'dup_notice_dismiss', + nonce: dup_admin_notices.nonce, + id: ($(this).closest('.dup-notice').attr('id') || '').replace('dup-notice-', ''), + }); + + $(this).closest('.dup-notice').fadeOut(); + } + }; + + return app; + +}(document, window, jQuery)); + +// Initialize. +DupAdminNotices.init(); diff --git a/assets/js/one-click-upgrade.js b/assets/js/one-click-upgrade.js new file mode 100644 index 00000000..51b60be3 --- /dev/null +++ b/assets/js/one-click-upgrade.js @@ -0,0 +1,66 @@ +var oneClickUpgradeRemoteEndpoint = "https://connect.duplicator.com/upgrade-free-to-pro"; + +jQuery(document).ready(function ($) { + if ($('#dup-settings-upgrade-license-key').length) { + function addErrorMessage(text) { + let msg = $('
' + + '

' + + text + + '

' + + '' + + '
' + ); + msg.insertAfter( ".dup-settings-pages > h1" ); + msg.find('.notice-dismiss').on('click', function (event) { + event.stopPropagation(); + msg.remove(); + }); + } + + // Client-side redirect to oneClickUpgradeRemoteEndpoint + function redirectToRemoteEndpoint(data) { + if (data["success"] != true) { + addErrorMessage(data["error_msg"]); + return; + } + + $("#redirect-to-remote-upgrade-endpoint").attr("action", oneClickUpgradeRemoteEndpoint); + $("#form-oth").attr("value", data["oth"]); + $("#form-key").attr("value", data["license_key"]); + $("#form-version").attr("value", data["version"]); + $("#form-redirect").attr("value", data["redirect"]); + $("#form-endpoint").attr("value", data["endpoint"]); + $("#form-siteurl").attr("value", data["siteurl"]); + $("#form-homeurl").attr("value", data["homeurl"]); + $("#form-file").attr("value", data["file"]); + $("#redirect-to-remote-upgrade-endpoint").submit(); + } + + $('#dup-settings-connect-btn').on('click', function (event) { + event.stopPropagation(); + var license_key = $('#dup-settings-upgrade-license-key').eq(0).val(); + jQuery.ajax({ + type: "POST", + url: dup_one_click_upgrade_script_data.ajaxurl, + dataType: "json", + data: { + action: 'duplicator_one_click_upgrade_prepare', + nonce: dup_one_click_upgrade_script_data.nonce_one_click_upgrade, + license_key: license_key + }, + success: function (result, textStatus, jqXHR) { + if (result.success) { + redirectToRemoteEndpoint(result.data.funcData); + } else { + addErrorMessage(result.data.message); + } + }, + error: function (result, textStatus, error) { + console.log(result); + } + }); + }); + } +}); diff --git a/assets/js/parsley-standalone.min.js b/assets/js/parsley-standalone.min.js deleted file mode 100644 index 052ab53e..00000000 --- a/assets/js/parsley-standalone.min.js +++ /dev/null @@ -1,85 +0,0 @@ -/* Parsley dist/parsley-standalone.min.js build version 1.1.18 http://parsleyjs.org */ -(function(b){String.prototype.trim===b&&(String.prototype.trim=function(){return this.replace(/^\s+/,"").replace(/\s+$/,"")});Array.prototype.reduce===b&&(Array.prototype.reduce=function(l){if(void 0===this||null===this)throw new TypeError;var r=Object(this),q=r.length>>>0,m=0,a;if("function"!=typeof l)throw new TypeError;if(0==q&&1==arguments.length)throw new TypeError;if(2<=arguments.length)a=arguments[1];else{do{if(m in r){a=r[m++];break}if(++m>=q)throw new TypeError;}while(1)}for(;m]*>/,N=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,I=/^(?:body|html)$/i,O="val css html text data width height offset".split(" "),F=p.createElement("table"),J=p.createElement("tr"), -K={tr:p.createElement("tbody"),tbody:F,thead:F,tfoot:F,td:J,th:J,"*":p.createElement("div")},P=/complete|loaded|interactive/,Q=/^\.([\w-]+)$/,R=/^#([\w-]*)$/,S=/^[\w-]+$/,M={}.toString,t={},G,E,L=p.createElement("div");t.matches=function(f,a){if(!f||1!==f.nodeType)return!1;var e=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.matchesSelector;if(e)return e.call(f,a);var b;b=f.parentNode;(e=!b)&&(b=L).appendChild(f);b=~t.qsa(b,a).indexOf(f);e&&L.removeChild(f);return b};G=function(f){return f.replace(/-+(.)?/g, -function(f,a){return a?a.toUpperCase():""})};E=function(f){return v.call(f,function(a,e){return f.indexOf(a)==e})};t.fragment=function(f,a,b){f.replace&&(f=f.replace(N,"<$1>"));a===n&&(a=H.test(f)&&RegExp.$1);a in K||(a="*");var c,d=K[a];d.innerHTML=""+f;f=e.each(u.call(d.childNodes),function(){d.removeChild(this)});r(b)&&(c=e(f),e.each(b,function(f,a){if(-1d.indexOf(a)&&c.push(a)})}return e(c)},has:function(a){return this.filter(function(){return l(a)? -e.contains(this,a):e(this).find(a).size()})},eq:function(a){return-1===a?this.slice(a):this.slice(a,+a+1)},first:function(){var a=this[0];return a&&!l(a)?a:e(a)},last:function(){var a=this[this.length-1];return a&&!l(a)?a:e(a)},find:function(a){return 1==this.length?e(t.qsa(this[0],a)):this.map(function(){return t.qsa(this,a)})},closest:function(a,b){for(var c=this[0];c&&!t.matches(c,a);)c=c!==b&&c!==p&&c.parentNode;return e(c)},parents:function(a){for(var b=[],c=this;0b.indexOf(a))return b.push(a),a});return j(b,a)},parent:function(a){return j(E(this.pluck("parentNode")),a)},children:function(a){return j(this.map(function(){return d(this)}),a)},contents:function(){return this.map(function(){return u.call(this.childNodes)})},siblings:function(a){return j(this.map(function(a,f){return v.call(d(f.parentNode),function(a){return a!==f})}),a)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(a){return e.map(this, -function(e){return e[a]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=null);if("none"==C(this,"").getPropertyValue("display")){var a=this.style,e=this.nodeName,b,c;h[e]||(b=p.createElement(e),p.body.appendChild(b),c=C(b,"").getPropertyValue("display"),b.parentNode.removeChild(b),"none"==c&&(c="block"),h[e]=c);a.display=h[e]}})},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){var c=b(a);if(this[0]&&!c)var d=e(a).get(0),p=d.parentNode|| -1arguments.length&&"string"==typeof b)return 0==this.length?n:this[0].style[G(b)]||C(this[0],"").getPropertyValue(b);var c="";for(s in b)!b[s]&&0!==b[s]?this.each(function(){this.style.removeProperty(a(s))}):c+=a(s)+":"+("number"==typeof b[s]&&!D[a(s)]?b[s]+"px":b[s])+";";"string"==typeof b&&(!e&& -0!==e?this.each(function(){this.style.removeProperty(a(b))}):c=a(b)+":"+("number"==typeof e&&!D[a(b)]?e+"px":e));return this.each(function(){this.style.cssText+=";"+c})},index:function(a){return a?this.indexOf(e(a)[0]):this.parent().children().indexOf(this[0])},hasClass:function(a){return 1>this.length?!1:c(a).test(w(this[0]))},addClass:function(a){return this.each(function(b){y=[];var c=w(this);k(this,a,b,c).split(/\s+/g).forEach(function(a){e(this).hasClass(a)||y.push(a)},this);y.length&&w(this, -c+(c?" ":"")+y.join(" "))})},removeClass:function(a){return this.each(function(b){if(a===n)return w(this,"");y=w(this);k(this,a,b,y).split(/\s+/g).forEach(function(a){y=y.replace(c(a)," ")});w(this,y.trim())})},toggleClass:function(a,b){return this.each(function(c){c=k(this,a,c,w(this));(b===n?!e(this).hasClass(c):b)?e(this).addClass(c):e(this).removeClass(c)})},scrollTop:function(){if(this.length)return"scrollTop"in this[0]?this[0].scrollTop:this[0].scrollY},position:function(){if(this.length){var a= -this[0],b=this.offsetParent(),c=this.offset(),d=I.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(e(a).css("margin-top"))||0;c.left-=parseFloat(e(a).css("margin-left"))||0;d.top+=parseFloat(e(b[0]).css("border-top-width"))||0;d.left+=parseFloat(e(b[0]).css("border-left-width"))||0;return{top:c.top-d.top,left:c.left-d.left}}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||p.body;a&&!I.test(a.nodeName)&&"static"==e(a).css("position");)a=a.offsetParent; -return a})}};["width","height"].forEach(function(a){e.fn[a]=function(b){var c,d=a.replace(/./,function(a){return a[0].toUpperCase()});return b===n?this[0]==window?window["inner"+d]:this[0]==p?p.documentElement["offset"+d]:(c=this.offset())&&c[a]:this.each(function(c){var d=e(this);d.css(a,k(this,b,c,d[a]()))})}});["after","prepend","before","append"].forEach(function(a,b){var c=b%2;e.fn[a]=function(){var a=e.map(arguments,function(a){return l(a)?a:t.fragment(a)}),d,f=1a.length? -this:this.each(function(p,h){d=c?h:h.parentNode;h=0==b?h.nextSibling:1==b?h.firstChild:2==b?h:null;a.forEach(function(a){if(f)a=a.cloneNode(!0);else if(!d)return e(a).remove();A(d.insertBefore(a,h),function(a){null!=a.nodeName&&("SCRIPT"===a.nodeName.toUpperCase()&&(!a.type||"text/javascript"===a.type)&&!a.src)&&window.eval.call(window,a.innerHTML)})})})};e.fn[c?a+"To":"insert"+(b?"Before":"After")]=function(b){e(b)[a](this);return this}});t.Z.prototype=e.fn;t.uniq=E;t.deserializeValue=x;e.zepto= -t;return e}();window.Zepto=Zepto;"$"in window||(window.$=Zepto); -(function(b){function l(a){return a._zid||(a._zid=j++)}function r(a,b,c,d){b=q(b);if(b.ns)var j=RegExp("(?:^| )"+b.ns.replace(" "," .* ?")+"(?: |$)");return(g[l(a)]||[]).filter(function(a){return a&&(!b.e||a.e==b.e)&&(!b.ns||j.test(a.ns))&&(!c||l(a.fn)===l(c))&&(!d||a.sel==d)})}function q(a){a=(""+a).split(".");return{e:a[0],ns:a.slice(1).sort().join(" ")}}function m(a,c,d){b.isObject(a)?b.each(a,d):a.split(/\s/).forEach(function(a){d(a,c)})}function a(a,c,d,j,n,p){var h=l(a),B=g[h]||(g[h]=[]);m(c, -d,function(c,d){var h=q(c);h.fn=d;h.sel=j;h.e in w&&(d=function(a){var c=a.relatedTarget;if(!c||c!==this&&!b.contains(this,c))return h.fn.apply(this,arguments)});h.del=n&&n(d,c);var g=h.del||d;h.proxy=function(b){var c=g.apply(a,[b].concat(b.data));!1===c&&(b.preventDefault(),b.stopPropagation());return c};h.i=B.length;B.push(h);a.addEventListener(w[h.e]||h.e,h.proxy,h.del&&("focus"==h.e||"blur"==h.e)||!!p)})}function c(a,b,c,d,j){var p=l(a);m(b||"",c,function(b,c){r(a,b,c,d).forEach(function(b){delete g[p][b.i]; -a.removeEventListener(w[b.e]||b.e,b.proxy,b.del&&("focus"==b.e||"blur"==b.e)||!!j)})})}function d(a){var c,d={originalEvent:a};for(c in a)!n.test(c)&&void 0!==a[c]&&(d[c]=a[c]);b.each(s,function(b,c){d[b]=function(){this[c]=x;return a[b].apply(a,arguments)};d[c]=A});return d}var g={},j=1,k={},w={mouseenter:"mouseover",mouseleave:"mouseout"};k.click=k.mousedown=k.mouseup=k.mousemove="MouseEvents";b.event={add:a,remove:c};b.proxy=function(a,c){if(b.isFunction(a)){var d=function(){return a.apply(c,arguments)}; -d._zid=l(a);return d}if("string"==typeof c)return b.proxy(a[c],a);throw new TypeError("expected function");};b.fn.bind=function(b,c){return this.each(function(){a(this,b,c)})};b.fn.unbind=function(a,b){return this.each(function(){c(this,a,b)})};b.fn.one=function(b,d){return this.each(function(g,j){a(this,b,d,null,function(a,b){return function(){var e=a.apply(j,arguments);c(j,b,a);return e}})})};var x=function(){return!0},A=function(){return!1},n=/^([A-Z]|layer[XY]$)/,s={preventDefault:"isDefaultPrevented", -stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};b.fn.delegate=function(c,g,j){return this.each(function(n,k){a(k,g,j,c,function(a){return function(h){var g,j=b(h.target).closest(c,k).get(0);if(j)return g=b.extend(d(h),{currentTarget:j,liveFired:k}),a.apply(j,[g].concat([].slice.call(arguments,1)))}})})};b.fn.undelegate=function(a,b,d){return this.each(function(){c(this,b,d,a)})};b.fn.live=function(a,c){b(document.body).delegate(this.selector,a,c);return this}; -b.fn.die=function(a,c){b(document.body).undelegate(this.selector,a,c);return this};b.fn.on=function(a,c,d){return!c||b.isFunction(c)?this.bind(a,c||d):this.delegate(c,a,d)};b.fn.off=function(a,c,d){return!c||b.isFunction(c)?this.unbind(a,c||d):this.undelegate(c,a,d)};b.fn.trigger=function(a,c){if("string"==typeof a||b.isPlainObject(a))a=b.Event(a);var d=a;if(!("defaultPrevented"in d)){d.defaultPrevented=!1;var g=d.preventDefault;d.preventDefault=function(){this.defaultPrevented=!0;g.call(this)}}a.data= -c;return this.each(function(){"dispatchEvent"in this&&this.dispatchEvent(a)})};b.fn.triggerHandler=function(a,c){var g,j;this.each(function(n,p){g=d("string"==typeof a?b.Event(a):a);g.data=c;g.target=p;b.each(r(p,a.type||a),function(a,b){j=b.proxy(g);if(g.isImmediatePropagationStopped())return!1})});return j};"focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(a){b.fn[a]= -function(b){return b?this.bind(a,b):this.trigger(a)}});["focus","blur"].forEach(function(a){b.fn[a]=function(b){b?this.bind(a,b):this.each(function(){try{this[a]()}catch(b){}});return this}});b.Event=function(a,b){"string"!=typeof a&&(b=a,a=b.type);var c=document.createEvent(k[a]||"Events"),d=!0;if(b)for(var g in b)"bubbles"==g?d=!!b[g]:c[g]=b[g];c.initEvent(a,d,!0,null,null,null,null,null,null,null,null,null,null,null,null);c.isDefaultPrevented=function(){return this.defaultPrevented};return c}})(Zepto); -(function(b,l){function r(a){return a.toLowerCase()}var q="",m,a=window.document.createElement("div"),c=/^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,d,g,j,k,w,x,A,n={};b.each({Webkit:"webkit",Moz:"",O:"o",ms:"MS"},function(b,c){if(a.style[b+"TransitionProperty"]!==l)return q="-"+r(b)+"-",m=c,!1});d=q+"transform";n[g=q+"transition-property"]=n[j=q+"transition-duration"]=n[k=q+"transition-timing-function"]=n[w=q+"animation-name"]=n[x=q+"animation-duration"]=n[A=q+"animation-timing-function"]= -"";b.fx={off:m===l&&a.style.transitionProperty===l,speeds:{_default:400,fast:200,slow:600},cssPrefix:q,transitionEnd:m?m+"TransitionEnd":r("TransitionEnd"),animationEnd:m?m+"AnimationEnd":r("AnimationEnd")};b.fn.animate=function(a,c,d,g){b.isObject(c)&&(d=c.easing,g=c.complete,c=c.duration);c&&(c=("number"==typeof c?c:b.fx.speeds[c]||b.fx.speeds._default)/1E3);return this.anim(a,c,d,g)};b.fn.anim=function(a,e,m,q){var u,v={},p,h="",B=this,C,D=b.fx.transitionEnd;e===l&&(e=0.4);b.fx.off&&(e=0);if("string"== -typeof a)v[w]=a,v[x]=e+"s",v[A]=m||"linear",D=b.fx.animationEnd;else{p=[];for(u in a)c.test(u)?h+=u+"("+a[u]+") ":(v[u]=a[u],p.push(r(u.replace(/([a-z])([A-Z])/,"$1-$2"))));h&&(v[d]=h,p.push(d));0=e&&setTimeout(function(){B.each(function(){C.call(this)})}, -0);return this};a=null})(Zepto); -(function(b){function l(a,c,d,e){if(a.global)return a=c||w,d=b.Event(d),b(a).trigger(d,e),!d.defaultPrevented}function r(a,b,c){var d=c.context;c.success.call(d,a,"success",b);l(c,d,"ajaxSuccess",[b,c,a]);m("success",b,c)}function q(a,b,c,d){var e=d.context;d.error.call(e,c,b,a);l(d,e,"ajaxError",[c,d,a]);m(b,c,d)}function m(a,c,d){var e=d.context;d.complete.call(e,c,a);l(d,e,"ajaxComplete",[c,d]);d.global&&!--b.active&&l(d,null,"ajaxStop")}function a(){}function c(a){return a&&(a==z?"html":a==y? -"json":s.test(a)?"script":e.test(a)&&"xml")||"text"}function d(a){a.processData&&k(a.data)&&(a.data=b.param(a.data,a.traditional));if(a.data&&(!a.type||"GET"==a.type.toUpperCase()))a.url=(a.url+"&"+a.data).replace(/[&?]{1,2}/,"?")}function g(a,c,d,e){var j=b.isArray(c);b.each(c,function(c,h){e&&(c=d?e:e+"["+(j?"":c)+"]");!e&&j?a.add(h.name,h.value):(d?b.isArray(h):k(h))?g(a,h,d,c):a.add(c,h)})}var j=0,k=b.isObject,w=window.document,x,A,n=/)<[^<]*)*<\/script>/gi,s=/^(?:text|application)\/javascript/i, -e=/^(?:text|application)\/xml/i,y="application/json",z="text/html",u=/^\s*$/;b.active=0;b.ajaxJSONP=function(c){if(!("type"in c))return b.ajax(c);var e="jsonp"+ ++j,g=w.createElement("script"),n={abort:function(){b(g).remove();e in window&&(window[e]=a);m("abort",n,c)}},k;c.error&&(g.onerror=function(){n.abort();c.error()});window[e]=function(a){clearTimeout(k);b(g).remove();delete window[e];r(a,n,c)};d(c);g.src=c.url.replace(/=\?/,"="+e);b("head").append(g);0k.status||304==k.status||0==k.status&&"file:"==n){g=g||c(k.getResponseHeader("content-type"));a=k.responseText;try{"script"==g?(0,eval)(a):"xml"==g?a=k.responseXML:"json"== -g&&(a=u.test(a)?null:b.parseJSON(a))}catch(e){d=e}d?q(d,"parsererror",k,h):r(a,k,h)}else q(null,"error",k,h)}};k.open(h.type,h.url,"async"in h?h.async:!0);for(A in h.headers)k.setRequestHeader(A,h.headers[A]);e=h.context;!1===h.beforeSend.call(e,k,h)||!1===l(h,e,"ajaxBeforeSend",[k,h])?e=!1:(l(h,e,"ajaxSend",[k,h]),e=void 0);if(!1===e)return k.abort(),!1;0").html(a.replace(n,"")).find(g):a);c&&c.apply(d,arguments)});return this};var v=encodeURIComponent;b.param= -function(a,c){var b=[];b.add=function(a,b){this.push(v(a)+"="+v(b))};g(b,a,c);return b.join("&").replace(/%20/g,"+")}})(Zepto); -(function(b){function l(d,g){var j=d[c],j=j&&q[j];if(void 0===g)return j||r(d);if(j){if(g in j)return j[g];var k=a(g);if(k in j)return j[k]}return m.call(b(d),g)}function r(d,g,j){var k=d[c]||(d[c]=++b.uuid),l;if(!(l=q[k])){l=q;var m={};b.each(d.attributes,function(c,d){0==d.name.indexOf("data-")&&(m[a(d.name.replace("data-",""))]=b.zepto.deserializeValue(d.value))});l=l[k]=m}d=l;void 0!==g&&(d[a(g)]=j);return d}var q={},m=b.fn.data,a=b.camelCase,c=b.expando="Zepto"+ +new Date;b.fn.data=function(a, -c){return void 0===c?b.isPlainObject(a)?this.each(function(c,g){b.each(a,function(a,c){r(g,a,c)})}):0==this.length?void 0:l(this[0],a):this.each(function(){r(this,a,c)})};b.fn.removeData=function(d){"string"==typeof d&&(d=d.split(/\s+/));return this.each(function(){var g=this[c],j=g&&q[g];j&&b.each(d,function(){delete j[a(this)]})})}})(Zepto); -(function(b,l){function r(a,c,j,k,m){"function"==typeof c&&!m&&(m=c,c=l);j={opacity:j};k&&(j.scale=k,a.css(b.fx.cssPrefix+"transform-origin","0 0"));return a.animate(j,c,null,m)}function q(c,g,j,k){return r(c,g,0,j,function(){a.call(b(this));k&&k.call(this)})}var m=b.fn.show,a=b.fn.hide,c=b.fn.toggle;b.fn.show=function(a,c){m.call(this);a===l?a=0:this.css("opacity",0);return r(this,a,1,"1,1",c)};b.fn.hide=function(c,b){return c===l?a.call(this):q(this,c,"0,0",b)};b.fn.toggle=function(a,g){return a=== -l||"boolean"==typeof a?c.call(this,a):this.each(function(){var c=b(this);c["none"==c.css("display")?"show":"hide"](a,g)})};b.fn.fadeTo=function(a,c,b){return r(this,a,c,null,b)};b.fn.fadeIn=function(a,c){var b=this.css("opacity");0=c},maxlength:function(a,c){return a.length<=c},rangelength:function(a,c){return this.minlength(a,c[0])&&this.maxlength(a,c[1])}, -min:function(a,c){return Number(a)>=c},max:function(a,c){return Number(a)<=c},range:function(a,c){return a>=c[0]&&a<=c[1]},equalto:function(a,c,d){d.options.validateIfUnchanged=!0;return a===b(c).val()},remote:function(a,c,d){var g={},j={};g[d.$element.attr("name")]=a;"undefined"!==typeof d.options.remoteDatatype&&(j={dataType:d.options.remoteDatatype});var k=function(a,c){"undefined"!==typeof c&&("undefined"!==typeof d.Validator.messages.remote&&c!==d.Validator.messages.remote)&&b(d.ulError+" .remote").remove(); -d.updtConstraint({name:"remote",valid:a},c);d.manageValidationResult()},m=function(a){if("object"===typeof a)return a;try{a=b.parseJSON(a)}catch(c){}return a},l=function(a){return"object"===typeof a&&null!==a?"undefined"!==typeof a.error?a.error:"undefined"!==typeof a.message?a.message:null:null};b.ajax(b.extend({},{url:c,data:g,type:d.options.remoteMethod||"GET",success:function(a){a=m(a);k(1===a||!0===a||"object"===typeof a&&null!==a&&"undefined"!==typeof a.success,l(a))},error:function(a){a=m(a); -k(!1,l(a))}},j));return null},mincheck:function(a,c){return this.minlength(a,c)},maxcheck:function(a,c){return this.maxlength(a,c)},rangecheck:function(a,c){return this.rangelength(a,c)}},init:function(a){var c=a.validators;a=a.messages;for(var b in c)this.addValidator(b,c[b]);for(b in a)this.addMessage(b,a[b])},formatMesssage:function(a,c){if("object"===typeof c){for(var b in c)a=this.formatMesssage(a,c[b]);return a}return"string"===typeof a?a.replace(/%s/i,c):""},addValidator:function(a,c){this.validators[a]= -c},addMessage:function(a,c,b){if("undefined"!==typeof b&&!0===b)this.messages.type[a]=c;else if("type"===a)for(var g in c)this.messages.type[g]=c[g];else this.messages[a]=c}};var r=function(a,c,b){this.options=c;this.Validator=new l(c);if("ParsleyFieldMultiple"===b)return this;this.init(a,b||"ParsleyField")};r.prototype={constructor:r,init:function(a,c){this.type=c;this.valid=!0;this.element=a;this.validatedOnce=!1;this.$element=b(a);this.val=this.$element.val();this.isRequired=!1;this.constraints= -{};"undefined"===typeof this.isRadioOrCheckbox&&(this.isRadioOrCheckbox=!1,this.hash=this.generateHash(),this.errorClassHandler=this.options.errors.classHandler(a,this.isRadioOrCheckbox)||this.$element);this.ulErrorManagement();this.bindHtml5Constraints();this.addConstraints();this.hasConstraints()&&this.bindValidationEvents()},setParent:function(a){this.$parent=b(a)},getParent:function(){return this.$parent},bindHtml5Constraints:function(){if(this.$element.hasClass("required")||this.$element.prop("required"))this.options.required= -!0;"undefined"!==typeof this.$element.attr("type")&&RegExp(this.$element.attr("type"),"i").test("email url number range")&&(this.options.type=this.$element.attr("type"),RegExp(this.options.type,"i").test("number range")&&(this.options.type="number","undefined"!==typeof this.$element.attr("min")&&this.$element.attr("min").length&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&this.$element.attr("max").length&&(this.options.max=this.$element.attr("max")))); -"string"===typeof this.$element.attr("pattern")&&this.$element.attr("pattern").length&&(this.options.regexp=this.$element.attr("pattern"))},addConstraints:function(){for(var a in this.options){var b={};b[a]=this.options[a];this.addConstraint(b,!0)}},addConstraint:function(a,b){for(var d in a)d=d.toLowerCase(),"function"===typeof this.Validator.validators[d]&&(this.constraints[d]={name:d,requirements:a[d],valid:null},"required"===d&&(this.isRequired=!0),this.addCustomConstraintMessage(d));"undefined"=== -typeof b&&this.bindValidationEvents()},updateConstraint:function(a,b){for(var d in a)this.updtConstraint({name:d,requirements:a[d],valid:null},b)},updtConstraint:function(a,c){this.constraints[a.name]=b.extend(!0,this.constraints[a.name],a);"string"===typeof c&&(this.Validator.messages[a.name]=c);this.bindValidationEvents()},removeConstraint:function(a){a=a.toLowerCase();delete this.constraints[a];"required"===a&&(this.isRequired=!1);this.hasConstraints()?this.bindValidationEvents():"ParsleyForm"=== -typeof this.getParent()?this.getParent().removeItem(this.$element):this.destroy()},addCustomConstraintMessage:function(a){var b=a+("type"===a&&"undefined"!==typeof this.options[a]?this.options[a].charAt(0).toUpperCase()+this.options[a].substr(1):"")+"Message";"undefined"!==typeof this.options[b]&&this.Validator.addMessage("type"===a?this.options[a]:a,this.options[b],"type"===a)},bindValidationEvents:function(){this.valid=null;this.$element.addClass("parsley-validated");this.$element.off("."+this.type); -this.options.remote&&!/change/i.test(this.options.trigger)&&(this.options.trigger=!this.options.trigger?"change":" change");var a=(!this.options.trigger?"":this.options.trigger)+(/key/i.test(this.options.trigger)?"":" keyup");this.$element.is("select")&&(a+=/change/i.test(a)?"":" change");a=a.replace(/^\s+/g,"").replace(/\s+$/g,"");this.$element.on((a+" ").split(" ").join("."+this.type+" "),!1,b.proxy(this.eventValidation,this))},generateHash:function(){return"parsley-"+(Math.random()+"").substring(2)}, -getHash:function(){return this.hash},getVal:function(){return this.$element.data("value")||this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"===a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||"change"===a.type&&!/change/i.test(this.options.trigger)&&!this.validatedOnce||!this.isRadioOrCheckbox&&this.getLength(b)",errorElem:"
  • "},listeners:{onFieldValidate:function(){return!1},onFormSubmit:function(){},onFieldError:function(){},onFieldSuccess:function(){}}}; -b(window).on("load",function(){b('[data-validate="parsley"]').each(function(){b(this).parsley()})})}(window.jQuery||window.Zepto); diff --git a/assets/js/parsley.min.js b/assets/js/parsley.min.js new file mode 100644 index 00000000..836699c6 --- /dev/null +++ b/assets/js/parsley.min.js @@ -0,0 +1,11 @@ +/*! +* Parsley.js +* Version 2.3.5 - built Sun, Feb 28th 2016, 6:25 am +* http://parsleyjs.org +* Guillaume Potier - +* Marc-Andre Lafortune - +* MIT Licensed +*/ +function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t1)throw Error("Second argument not supported");if("object"!=typeof t)throw TypeError("Argument must be an object");e.prototype=t;var i=new e;return e.prototype=null,i}}()},a=s,o={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,triggerAfterFailure:"input",errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(e){},errorsContainer:function(e){},errorsWrapper:'
      ',errorTemplate:"
    • "},l=function(){};l.prototype={asyncSupport:!0,actualizeOptions:function(){return a.attr(this.$element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(e){this.domOptions=a.objectCreate(this.parent.options),this.options=a.objectCreate(this.domOptions);for(var t in e)e.hasOwnProperty(t)&&(this.options[t]=e[t]);this.actualizeOptions()},_listeners:null,on:function(e,t){this._listeners=this._listeners||{};var i=this._listeners[e]=this._listeners[e]||[];return i.push(t),this},subscribe:function(t,i){e.listenTo(this,t.toLowerCase(),i)},off:function(e,t){var i=this._listeners&&this._listeners[e];if(i)if(t)for(var n=i.length;n--;)i[n]===t&&i.splice(n,1);else delete this._listeners[e];return this},unsubscribe:function(t,i){e.unsubscribeTo(this,t.toLowerCase())},trigger:function(e,t,i){t=t||this;var n,r=this._listeners&&this._listeners[e];if(r)for(var s=r.length;s--;)if(n=r[s].call(t,t,i),n===!1)return n;return this.parent?this.parent.trigger(e,t,i):!0},reset:function(){if("ParsleyForm"!==this.__class__)return this._resetUI(),this._trigger("reset");for(var e=0;e3&&(i=[].slice.call(arguments,1,-1)),this.fn.call(this,t,i);if(e.isArray(t)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}if(this.validateNumber)return isNaN(t)?!1:(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,i){if("string"!=typeof t)return e.isArray(t)?t:[t];var n=this.requirementType;if(e.isArray(n)){for(var r=d(t,n.length),s=0;s0},validateString:function(e){return/\S/.test(e)},priority:512},type:{validateString:function(e,t){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=i.step,r=void 0===n?"1":n,s=i.base,a=void 0===s?0:s,o=m[t];if(!o)throw new Error("validator type `"+t+"` is not supported");if(!o.test(e))return!1;if("number"===t&&!/^any$/i.test(r||"")){var l=Number(e),u=Math.max(g(r),g(a));if(g(l)>u)return!1;var d=function(e){return Math.round(e*Math.pow(10,u))};if((d(l)-d(a))%d(r)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(e,t){return t.test(e)},requirementType:"regexp",priority:64},minlength:{validateString:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxlength:{validateString:function(e,t){return e.length<=t},requirementType:"integer",priority:30},length:{validateString:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(e,t){return e.length<=t},requirementType:"integer",priority:30},check:{validateMultiple:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},min:{validateNumber:function(e,t){return e>=t},requirementType:"number",priority:30},max:{validateNumber:function(e,t){return t>=e},requirementType:"number",priority:30},range:{validateNumber:function(e,t,i){return e>=t&&i>=e},requirementType:["number","number"],priority:30},equalto:{validateString:function(t,i){var n=e(i);return n.length?t===n.val():t===i},priority:256}}};var y={},v=function T(e,t,i){for(var n=[],r=[],s=0;s0&&"undefined"==typeof t.options.noFocus&&(this._focusedField=t.$element,"first"===this.options.focus))break}return null===this._focusedField?null:this._focusedField.focus()},_destroyUI:function(){this.$element.off(".Parsley")}},y.Field={_reflowUI:function(){if(this._buildUI(),this._ui){var e=v(this.validationResult,this._ui.lastValidationResult);this._ui.lastValidationResult=this.validationResult,this._manageStatusClass(),this._manageErrorsMessages(e),this._actualizeTriggers(),!e.kept.length&&!e.added.length||this._failedOnce||(this._failedOnce=!0,this._actualizeTriggers())}},getErrorsMessages:function(){if(!0===this.validationResult)return[];for(var e=[],t=0;t0?this._errorClass():this._resetClass()},_manageErrorsMessages:function(t){if("undefined"==typeof this.options.errorsMessagesDisabled){if("undefined"!=typeof this.options.errorMessage)return t.added.length||t.kept.length?(this._insertErrorWrapper(),0===this._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&this._ui.$errorsWrapper.append(e(this.options.errorTemplate).addClass("parsley-custom-error-message")),this._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(this.options.errorMessage)):this._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var i=0;i').appendTo(this.$element)),i.attr({name:t.attr("name"),value:t.attr("value")})}this.$element.trigger(e.extend(e.Event("submit"),{parsley:!0}))}},validate:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1],s=i[2];t={group:n,force:r,event:s}}return w[this.whenValidate(t).state()]},whenValidate:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force,s=i.event;this.submitEvent=s,s&&(this.submitEvent=e.extend({},s,{preventDefault:function(){a.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),t.validationResult=!1}})),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var o=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValidate({force:r,group:n})})}),l=function(){var i=e.Deferred();return!1===t.validationResult&&i.reject(),i.resolve().promise()};return e.when.apply(e,_toConsumableArray(o)).done(function(){t._trigger("success")}).fail(function(){t.validationResult=!1,t.focus(),t._trigger("error")}).always(function(){t._trigger("validated")}).pipe(l,l)},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={group:n,force:r}}return w[this.whenValid(t).state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValid({group:n,force:r})})});return e.when.apply(e,_toConsumableArray(s))},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var t=this,i=this.fields;return this.fields=[],this.fieldsMappedById={},this._withoutReactualizingFormOptions(function(){t.$element.find(t.options.inputs).not(t.options.excluded).each(function(e,i){var n=new window.Parsley.Factory(i,{},t);"ParsleyField"!==n.__class__&&"ParsleyFieldMultiple"!==n.__class__||!0===n.options.excluded||"undefined"==typeof t.fieldsMappedById[n.__class__+"-"+n.__id__]&&(t.fieldsMappedById[n.__class__+"-"+n.__id__]=n,t.fields.push(n))}),e(i).not(t.fields).each(function(e,t){t._trigger("reset")})}),this},_withoutReactualizingFormOptions:function(e){var t=this.actualizeOptions;this.actualizeOptions=function(){return this};var i=e();return this.actualizeOptions=t,i},_trigger:function(e){return this.trigger("form:"+e)}};var b=function(t,i,n,r,s){if(!/ParsleyField/.test(t.__class__))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");var a=window.Parsley._validatorRegistry.validators[i],o=new f(a);e.extend(this,{validator:o,name:i,requirements:n,priority:r||t.options[i+"Priority"]||o.priority,isDomConstraint:!0===s}),this._parseRequirements(t.options)},F=function(e){var t=e[0].toUpperCase();return t+e.slice(1)};b.prototype={validate:function(e,t){var i=this.requirementList.slice(0);return i.unshift(e),i.push(t),this.validator.validate.apply(this.validator,i)},_parseRequirements:function(e){var t=this;this.requirementList=this.validator.parseRequirements(this.requirements,function(i){return e[t.name+F(i)]})}};var C=function(t,i,n,r){this.__class__="ParsleyField",this.__id__=a.generateID(),this.$element=e(t),"undefined"!=typeof r&&(this.parent=r),this.options=n,this.domOptions=i,this.constraints=[],this.constraintsByName={},this.validationResult=[],this._bindConstraints()},$={pending:null,resolved:!0,rejected:!1};C.prototype={validate:function(t){arguments.length>=1&&!e.isPlainObject(t)&&(a.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var i=this.whenValidate(t);if(!i)return!0;switch(i.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(){var e=this,t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],i=t.force,n=t.group;return this.refreshConstraints(),!n||this._isInGroup(n)?(this.value=this.getValue(),this._trigger("validate"),this.whenValid({force:i,value:this.value,_refreshed:!0}).always(function(){e._reflowUI()}).done(function(){e._trigger("success")}).fail(function(){e._trigger("error")}).always(function(){e._trigger("validated")})):void 0},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(e){return"undefined"==typeof e&&(e=this.getValue()),e.length||this._isRequired()||"undefined"!=typeof this.options.validateIfEmpty?!0:!1},_isInGroup:function(t){return e.isArray(this.options.group)?-1!==e.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={force:n,value:r}}var s=this.whenValid(t);return s?$[s.state()]:!0},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=void 0===n?!1:n,s=i.value,a=i.group,o=i._refreshed;if(o||this.refreshConstraints(),!a||this._isInGroup(a)){if(this.validationResult=!0,!this.hasConstraints())return e.when();if(("undefined"==typeof s||null===s)&&(s=this.getValue()),!this.needsValidation(s)&&!0!==r)return e.when();var l=this._getGroupedConstraints(),u=[];return e.each(l,function(i,n){var r=e.when.apply(e,_toConsumableArray(e.map(n,function(e){return t._validateConstraint(s,e)})));return u.push(r),"rejected"===r.state()?!1:void 0}),e.when.apply(e,u)}},_validateConstraint:function(t,i){var n=this,r=i.validate(t,this);return!1===r&&(r=e.Deferred().reject()),e.when(r).fail(function(e){!0===n.validationResult&&(n.validationResult=[]),n.validationResult.push({assert:i,errorMessage:"string"==typeof e&&e})})},getValue:function(){var e;return e="function"==typeof this.options.value?this.options.value(this):"undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof e||null===e?"":this._handleWhitespace(e)},refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},addConstraint:function(e,t,i,n){if(window.Parsley._validatorRegistry.validators[e]){var r=new b(this,e,t,i,n);"undefined"!==this.constraintsByName[r.name]&&this.removeConstraint(r.name),this.constraints.push(r),this.constraintsByName[r.name]=r}return this},removeConstraint:function(e){for(var t=0;t1){var i=[];return this.each(function(){i.push(e(this).parsley(t))}),i}return e(this).length?new E(this,t):void a.warn("You must bind Parsley on an existing element.")},"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),M.options=e.extend(a.objectCreate(o),window.ParsleyConfig),window.ParsleyConfig=M.options,window.Parsley=window.psly=M,window.ParsleyUtils=a;var O=window.Parsley._validatorRegistry=new c(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},e.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator".split(" "),function(t,i){window.Parsley[i]=e.proxy(O,i),window.ParsleyValidator[i]=function(){var e;return a.warnOnce("Accessing the method '"+i+"' through ParsleyValidator is deprecated. Simply call 'window.Parsley."+i+"(...)'"),(e=window.Parsley)[i].apply(e,arguments)}}),window.Parsley.UI=y,window.ParsleyUI={removeError:function(e,t,i){var n=!0!==i;return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e.removeError(t,{updateClass:n})},getErrorsMessages:function(e){return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly."),e.getErrorsMessages()}},e.each("addError updateError".split(" "),function(e,t){window.ParsleyUI[t]=function(e,i,n,r,s){var o=!0!==s;return a.warnOnce("Accessing ParsleyUI is deprecated. Call '"+t+"' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e[t](i,{message:n,assert:r,updateClass:o})}}),/firefox/i.test(navigator.userAgent)&&e(document).on("change","select",function(t){e(t.target).trigger("input")}),!1!==window.ParsleyConfig.autoBind&&e(function(){e("[data-parsley-validate]").length&&e("[data-parsley-validate]").parsley()});var A=e({}),R=function(){a.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")},D="parsley:";e.listen=function(e,n){var r;if(R(),"object"==typeof arguments[1]&&"function"==typeof arguments[2]&&(r=arguments[1],n=arguments[2]),"function"!=typeof n)throw new Error("Wrong parameters");window.Parsley.on(i(e),t(n,r))},e.listenTo=function(e,n,r){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");if("string"!=typeof n||"function"!=typeof r)throw new Error("Wrong parameters");e.on(i(n),t(r))},e.unsubscribe=function(e,t){if(R(),"string"!=typeof e||"function"!=typeof t)throw new Error("Wrong arguments");window.Parsley.off(i(e),t.parsleyAdaptedCallback)},e.unsubscribeTo=function(e,t){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");e.off(i(t))},e.unsubscribeAll=function(t){R(),window.Parsley.off(i(t)),e("form,input,textarea,select").each(function(){var n=e(this).data("Parsley");n&&n.off(i(t))})},e.emit=function(e,t){var n;R();var r=t instanceof x||t instanceof _,s=Array.prototype.slice.call(arguments,r?2:1);s.unshift(i(e)),r||(t=window.Parsley),(n=t).trigger.apply(n,_toConsumableArray(s))};e.extend(!0,M,{asyncValidators:{"default":{fn:function(e){return e.status>=200&&e.status<300},url:!1},reverse:{fn:function(e){return e.status<200||e.status>=300},url:!1}},addAsyncValidator:function(e,t,i,n){return M.asyncValidators[e]={fn:t,url:i||!1,options:n||{}},this}}),M.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,i,n,r){var s,a,o={},l=n.validator||(!0===n.reverse?"reverse":"default");if("undefined"==typeof M.asyncValidators[l])throw new Error("Calling an undefined async validator: `"+l+"`");i=M.asyncValidators[l].url||i,i.indexOf("{value}")>-1?i=i.replace("{value}",encodeURIComponent(t)):o[r.$element.attr("name")||r.$element.attr("id")]=t;var u=e.extend(!0,n.options||{},M.asyncValidators[l].options);s=e.extend(!0,{},{url:i,data:o,type:"GET"},u),r.trigger("field:ajaxoptions",r,s),a=e.param(s),"undefined"==typeof M._remoteCache&&(M._remoteCache={});var d=M._remoteCache[a]=M._remoteCache[a]||e.ajax(s),h=function(){var t=M.asyncValidators[l].fn.call(r,d,i,n);return t||(t=e.Deferred().reject()),e.when(t)};return d.then(h,h)},priority:-1}),M.on("form:submit",function(){M._remoteCache={}}),window.ParsleyExtend.addAsyncValidator=function(){return ParsleyUtils.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),M.addAsyncValidator.apply(M,arguments)},M.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),M.setLocale("en");var q=M;return q}); +//# sourceMappingURL=parsley.min.js.map \ No newline at end of file diff --git a/assets/js/parsley.min.js.map b/assets/js/parsley.min.js.map new file mode 100644 index 00000000..28ff9cb0 --- /dev/null +++ b/assets/js/parsley.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["parsley.min.js","/source/parsley.js","/source/src/parsley/pubsub.js","/source/src/parsley/utils.js","/source/src/parsley/defaults.js","/source/src/parsley/abstract.js","/source/src/parsley/validator.js","/source/src/parsley/validator_registry.js","/source/src/parsley/ui.js","/source/src/parsley/form.js","/source/src/parsley/factory/constraint.js","/source/src/parsley/field.js","/source/src/parsley/multiple.js","/source/src/parsley/factory.js","/source/src/parsley/main.js","/source/src/parsley/remote.js","/source/src/i18n/en.js","/source/src/parsley.js"],"names":["_toConsumableArray","arr","Array","isArray","i","arr2","length","from","_slice","prototype","slice","global","factory","exports","module","require","define","amd","parsley","jQuery","this","$","adapt","fn","context","parsleyAdaptedCallback","args","call","arguments","unshift","apply","o","eventName","name","lastIndexOf","eventPrefix","substr","globalID","pastWarnings","ParsleyUtils__ParsleyUtils","attr","$element","namespace","obj","attribute","attributes","regex","RegExp","hasOwnProperty","specified","test","camelize","deserializeValue","value","checkAttr","_checkAttr","is","setAttr","setAttribute","dasherize","String","generateID","num","isNaN","Number","parseJSON","e","str","replace","match","chr","toUpperCase","toLowerCase","warn","_window$console","window","console","warnOnce","msg","_resetWarnings","trimString","string","namespaceEvents","events","split","map","evt","join","objectCreate","Object","create","Error","TypeError","result","ParsleyUtils__default","ParsleyDefaults","inputs","excluded","priorityEnabled","multiple","group","uiEnabled","validationThreshold","focus","trigger","triggerAfterFailure","errorClass","successClass","classHandler","ParsleyField","errorsContainer","errorsWrapper","errorTemplate","ParsleyAbstract","asyncSupport","actualizeOptions","options","domOptions","parent","_resetOptions","initOptions","_listeners","on","queue","push","subscribe","listenTo","off","splice","unsubscribe","unsubscribeTo","target","extraArg","reset","__class__","_resetUI","_trigger","fields","destroy","_destroyUI","removeData","asyncIsValid","force","whenValid","_findRelated","find","requirementConverters","_string","integer","parseInt","number","parseFloat","reference","boolean","object","regexp","_regexp","flags","convertArrayRequirement","m","values","convertRequirement","requirementType","converter","convertExtraOptionRequirement","requirementSpec","extraOptionReader","main","extra","key","ParsleyValidator","spec","extend","validate","requirementFirstArg","validateMultiple","validateNumber","validateString","parseRequirements","requirements","type","isPlainObject","priority","ParsleyValidatorRegistry","validators","catalog","locale","init","typeRegexes","email","digits","alphanum","url","range","decimalPlaces","Math","max","addValidator","Parsley","setLocale","addCatalog","messages","set","addMessage","message","addMessages","nameMessageObject","arg1","arg2","_setValidator","updateValidator","removeValidator","validator","getErrorMessage","constraint","typeMessages","formatMessage","defaultMessage","en","parameters","notblank","required","_ref","undefined","_ref$step","step","_ref$base","base","nb","decimals","toInt","f","round","pow","pattern","minlength","requirement","maxlength","min","mincheck","maxcheck","check","equalto","refOrValue","$reference","val","ParsleyUI","diffResults","newResult","oldResult","deep","added","kept","found","j","assert","removed","Form","_actualizeTriggers","_this","onSubmitValidate","onSubmitButton","_focusedField","validationResult","field","noFocus","Field","_reflowUI","_buildUI","_ui","diff","lastValidationResult","_manageStatusClass","_manageErrorsMessages","_failedOnce","getErrorsMessages","errorMessage","_getErrorMessage","addError","_ref2","_ref2$updateClass","updateClass","_addError","_errorClass","updateError","_ref3","_ref3$updateClass","_updateError","removeError","_ref4","_ref4$updateClass","_removeError","hasConstraints","needsValidation","_successClass","_resetClass","errorsMessagesDisabled","_insertErrorWrapper","$errorsWrapper","append","addClass","html","removeClass","remove","_ref5","_ref6","customConstraintErrorMessage","__id__","$errorClassHandler","_manageClassHandler","errorsWrapperId","validationInformationVisible","$handler","$errorsContainer","$from","after","_this2","$toBind","event","_eventValidate","getValue","children","ParsleyForm","element","ParsleyForm__statusMapping","pending","resolved","rejected","_this3","$submitSource","_$submitSource","first","prop","promise","whenValidate","state","stopImmediatePropagation","preventDefault","done","_submit","$synthetic","appendTo","Event","_arguments","_this4","_ref7","submitEvent","_refreshFields","promises","_withoutReactualizingFormOptions","promiseBasedOnValidationResult","r","Deferred","reject","resolve","when","fail","always","pipe","isValid","_arguments2","_this5","_ref8","_bindFields","_this6","oldFields","fieldsMappedById","not","each","_","fieldInstance","Factory","oldActualizeOptions","ConstraintFactory","parsleyField","isDomConstraint","validatorSpec","_validatorRegistry","_parseRequirements","capitalize","cap","instance","requirementList","_this7","parsleyFormInstance","constraints","constraintsByName","_bindConstraints","parsley_field__statusMapping","_this8","_ref9","refreshConstraints","_isInGroup","_refreshed","_isRequired","validateIfEmpty","inArray","_arguments3","_this9","_ref10","_ref10$force","groupedConstraints","_getGroupedConstraints","_validateConstraint","_this10","_handleWhitespace","addConstraint","removeConstraint","updateConstraint","_bindHtml5Constraints","hasClass","trimValue","whitespace","index","p","sort","a","b","parsley_field","ParsleyMultiple","addElement","$elements","fieldConstraints","has","data","filter","_init","ParsleyFactory","savedparsleyFormInstance","__version__","bind","isMultiple","handleMultiple","parsleyMultipleInstance","_this11","input","$previouslyRelated","get","doNotStore","parsleyInstance","ParsleyExtend","vernums","jquery","forEach","document","version","psly","instances","ParsleyConfig","ParsleyUtils","registry","i18n","method","proxy","_window$Parsley","UI","doNotUpdateClass","navigator","userAgent","autoBind","deprecated","listen","callback","unsubscribeAll","emit","_instance","instanceGiven","asyncValidators","default","xhr","status","reverse","addAsyncValidator","ajaxOptions","csr","indexOf","encodeURIComponent","remoteOptions","param","_remoteCache","ajax","handleXhr","then"],"mappings":";;;;;;;;AAcA,QAASA,oBAAmBC,GAAO,GAAIC,MAAMC,QAAQF,GAAM,CAAE,IAAK,GAAIG,GAAI,EAAGC,EAAOH,MAAMD,EAAIK,QAASF,EAAIH,EAAIK,OAAQF,IAAKC,EAAKD,GAAKH,EAAIG,EAAI,OAAOC,GAAe,MAAOH,OAAMK,KAAKN,GCFtL,GAAAO,QAAAN,MAAAO,UAAAC,OAZA,SAAWC,EAAQC,GACE,gBAAZC,UAA0C,mBAAXC,QAAyBA,OAAOD,QAAUD,EAAQG,QAAQ,WAC9E,kBAAXC,SAAyBA,OAAOC,IAAMD,QAAQ,UAAWJ,GAChED,EAAOO,QAAUN,EAAQD,EAAOQ,SAChCC,KAAM,SAAUC,GAAK,YCOvB,SAASC,GAAMC,EAAIC,GASjB,MAPKD,GAAGE,yBACNF,EAAGE,uBAAyB,WAC1B,GAAIC,GAAOxB,MAAMO,UAAUC,MAAMiB,KAAKC,UAAW,EACjDF,GAAKG,QAAQT,MACbG,EAAGO,MAAMN,GAAWO,EAAGL,KAGpBH,EAAGE,uBAKZ,QAASO,GAAUC,GACjB,MAAyC,KAArCA,EAAKC,YAAYC,EAAa,GACzBF,EAAKG,OAAOD,EAAY7B,QAC1B2B,EC1BT,GAAII,GAAW,EACXC,KAHJC,GAQEC,KAAM,SAAUC,EAAUC,EAAWC,GACnC,GAAIvC,GACAwC,EACAC,EACAC,EAAQ,GAAIC,QAAO,IAAML,EAAW,IAExC,IAAI,mBAAuBC,GACzBA,SAGA,KAAKvC,IAAKuC,GACJA,EAAIK,eAAe5C,UACduC,GAAIvC,EAIjB,IAAI,mBAAuBqC,IAAY,mBAAuBA,GAAS,GACrE,MAAOE,EAGT,KADAE,EAAaJ,EAAS,GAAGI,WACpBzC,EAAIyC,EAAWvC,OAAQF,KAC1BwC,EAAYC,EAAWzC,GAEnBwC,GAAaA,EAAUK,WAAaH,EAAMI,KAAKN,EAAUX,QAC3DU,EAAIvB,KAAK+B,SAASP,EAAUX,KAAKvB,MAAMgC,EAAUpC,UAAYc,KAAKgC,iBAAiBR,EAAUS,OAIjG,OAAOV,IAGTW,UAAW,SAAUb,EAAUC,EAAWa,GACxC,MAAOd,GAASe,GAAG,IAAMd,EAAYa,EAAY,MAGnDE,QAAS,SAAUhB,EAAUC,EAAWF,EAAMa,GAC5CZ,EAAS,GAAGiB,aAAatC,KAAKuC,UAAUjB,EAAYF,GAAOoB,OAAOP,KAGpEQ,WAAY,WACV,MAAO,GAAKxB,KAKde,iBAAkB,SAAUC,GAC1B,GAAIS,EAEJ,KACE,MAAOT,GACI,QAATA,IACU,SAATA,GAAmB,EACX,QAATA,EAAkB,KACjBU,MAAMD,EAAME,OAAOX,IACpB,UAAUH,KAAKG,GAAShC,EAAE4C,UAAUZ,GACpCA,EAF8BS,GAG5BT,EACJ,MAAOa,GAAK,MAAOb,KAIvBF,SAAU,SAAUgB,GAClB,MAAOA,GAAIC,QAAQ,UAAW,SAAUC,EAAOC,GAC7C,MAAOA,GAAMA,EAAIC,cAAgB,MAKrCZ,UAAW,SAAUQ,GACnB,MAAOA,GAAIC,QAAQ,MAAO,KACvBA,QAAQ,wBAAyB,SACjCA,QAAQ,oBAAqB,SAC7BA,QAAQ,KAAM,KACdI,eAGLC,KAAM,WHOF,GAAIC,EGNFC,QAAOC,SAAW,kBAAsBD,QAAOC,QAAQH,OACzDC,EAAAC,OAAOC,SAAQH,KAAA3C,MAAA4C,EAAQ9C,YAG3BiD,SAAU,SAASC,GACZxC,EAAawC,KAChBxC,EAAawC,IAAO,EACpB1D,KAAKqD,KAAA3C,MAALV,KAAaQ,aAIjBmD,eAAgB,WACdzC,MAGF0C,WAAY,SAASC,GACnB,MAAOA,GAAOb,QAAQ,aAAc,KAGtCc,gBAAiB,SAASC,EAAQzC,GAEhC,MADAyC,GAAS/D,KAAK4D,WAAWG,GAAU,IAAIC,MAAM,OACxCD,EAAO,GAEL9D,EAAEgE,IAAIF,EAAQ,SAAAG,GAAS,MAAUA,GAAA,IAAO5C,IAAgB6C,KAAK,KAD3D,IAKXC,aAAcC,OAAOC,QAAU,WAC7B,GAAID,GAAS,YACb,OAAO,UAAUhF,GACf,GAAImB,UAAUtB,OAAS,EACrB,KAAMqF,OAAM,gCAEd,IAAwB,gBAAblF,GACT,KAAMmF,WAAU,6BAElBH,GAAOhF,UAAYA,CACnB,IAAIoF,GAAS,GAAIJ,EAEjB,OADAA,GAAOhF,UAAY,KACZoF,OA5HbC,EAAAvD,ECKIwD,GAIFrD,UAAW,gBAGXsD,OAAQ,0BAGRC,SAAU,gFAGVC,iBAAiB,EAKjBC,SAAU,KAGVC,MAAO,KAIPC,WAAW,EAGXC,oBAAqB,EAGrBC,MAAO,QAGPC,SAAS,EAGTC,oBAAqB,QAGrBC,WAAY,gBAGZC,aAAc,kBAIdC,aAAc,SAAUC,KAIxBC,gBAAiB,SAAUD,KAG3BE,cAAe,wCAGfC,cAAe,aC3DbC,EAAkB,YAEtBA,GAAgBxG,WACdyG,cAAc,EAEdC,iBAAkB,WAIhB,MAZJrB,GASiBtD,KAAKpB,KAAKqB,SAAUrB,KAAKgG,QAAQ1E,UAAWtB,KAAKiG,YAC1DjG,KAAKkG,QAAUlG,KAAKkG,OAAOH,kBAC7B/F,KAAKkG,OAAOH,mBACP/F,MAGTmG,cAAe,SAAUC,GACvBpG,KAAKiG,WAhBTvB,EAgBmCN,aAAapE,KAAKkG,OAAOF,SACxDhG,KAAKgG,QAjBTtB,EAiBgCN,aAAapE,KAAKiG,WAE9C,KAAK,GAAIjH,KAAKoH,GACRA,EAAYxE,eAAe5C,KAC7BgB,KAAKgG,QAAQhH,GAAKoH,EAAYpH,GAElCgB,MAAK+F,oBAGPM,WAAY,KAMZC,GAAI,SAAUzF,EAAMV,GAClBH,KAAKqG,WAAarG,KAAKqG,cACvB,IAAIE,GAAQvG,KAAKqG,WAAWxF,GAAQb,KAAKqG,WAAWxF,MAGpD,OAFA0F,GAAMC,KAAKrG,GAEJH,MAITyG,UAAW,SAAS5F,EAAMV,GACxBF,EAAEyG,SAAS1G,KAAMa,EAAKuC,cAAejD,IAIvCwG,IAAK,SAAU9F,EAAMV,GACnB,GAAIoG,GAAQvG,KAAKqG,YAAcrG,KAAKqG,WAAWxF,EAC/C,IAAI0F,EACF,GAAKpG,EAGH,IAAK,GAAInB,GAAIuH,EAAMrH,OAAQF,KACrBuH,EAAMvH,KAAOmB,GACfoG,EAAMK,OAAO5H,EAAG,cAJbgB,MAAKqG,WAAWxF,EAO3B,OAAOb,OAIT6G,YAAa,SAAShG,EAAMV,GAC1BF,EAAE6G,cAAc9G,KAAMa,EAAKuC,gBAM7BgC,QAAS,SAAUvE,EAAMkG,EAAQC,GAC/BD,EAASA,GAAU/G,IACnB,IACIyE,GADA8B,EAAQvG,KAAKqG,YAAcrG,KAAKqG,WAAWxF,EAG/C,IAAI0F,EACF,IAAK,GAAIvH,GAAIuH,EAAMrH,OAAQF,KAEzB,GADAyF,EAAS8B,EAAMvH,GAAGuB,KAAKwG,EAAQA,EAAQC,GACnCvC,KAAW,EAAO,MAAOA,EAGjC,OAAIzE,MAAKkG,OACAlG,KAAKkG,OAAOd,QAAQvE,EAAMkG,EAAQC,IAEpC,GAITC,MAAO,WAEL,GAAI,gBAAkBjH,KAAKkH,UAEzB,MADAlH,MAAKmH,WACEnH,KAAKoH,SAAS,QAIvB,KAAK,GAAIpI,GAAI,EAAGA,EAAIgB,KAAKqH,OAAOnI,OAAQF,IACtCgB,KAAKqH,OAAOrI,GAAGiI,OAEjBjH,MAAKoH,SAAS,UAIhBE,QAAS,WAGP,GADAtH,KAAKuH,aACD,gBAAkBvH,KAAKkH,UAKzB,MAJAlH,MAAKqB,SAASmG,WAAW,WACzBxH,KAAKqB,SAASmG,WAAW,4BACzBxH,MAAKoH,SAAS,UAMhB,KAAK,GAAIpI,GAAI,EAAGA,EAAIgB,KAAKqH,OAAOnI,OAAQF,IACtCgB,KAAKqH,OAAOrI,GAAGsI,SAEjBtH,MAAKqB,SAASmG,WAAW,WACzBxH,KAAKoH,SAAS,YAGhBK,aAAc,SAAUzC,EAAO0C,GAE7B,MA1HJhD,GAyHiBjB,SAAS,4DACfzD,KAAK2H,WAAW3C,MAAAA,EAAO0C,MAAAA,KAGhCE,aAAc,WACZ,MAAO5H,MAAKgG,QAAQjB,SAClB/E,KAAKkG,OAAO7E,SAASwG,KAAA,IAAS7H,KAAKgG,QAAQ1E,UAAA,aAAsBtB,KAAKgG,QAAQjB,SAAA,MAC9E/E,KAAKqB,UC7HX,IAAIyG,IACFjE,OAAQ,SAASkE,GACf,MAAOA,IAETC,QAAS,SAASnE,GAChB,GAAIlB,MAAMkB,GACR,KAAM,mCAAqCA,EAAS,GACtD,OAAOoE,UAASpE,EAAQ,KAE1BqE,OAAQ,SAASrE,GACf,GAAIlB,MAAMkB,GACR,KAAM,iCAAmCA,EAAS,GACpD,OAAOsE,YAAWtE,IAEpBuE,UAAW,SAASvE,GAClB,GAAIY,GAASxE,EAAE4D,EACf,IAAsB,IAAlBY,EAAOvF,OACT,KAAM,uBAAyB2E,EAAS,GAC1C,OAAOY,IAET4D,UAAS,SAASxE,GAChB,MAAkB,UAAXA,GAETyE,OAAQ,SAASzE,GACf,MA3BJa,GA2BwB1C,iBAAiB6B,IAEvC0E,OAAQ,SAASC,GACf,GAAIC,GAAQ,EAcZ,OAXI,sBAAsB3G,KAAK0G,IAG7BC,EAAQD,EAAOxF,QAAQ,iBAAkB,MAGzCwF,EAASA,EAAOxF,QAAQ,GAAIrB,QAAO,WAAa8G,EAAQ,KAAM,OAG9DD,EAAS,IAAMA,EAAS,IAEnB,GAAI7G,QAAO6G,EAAQC,KAI1BC,EAA0B,SAAS7E,EAAQ3E,GAC7C,GAAIyJ,GAAI9E,EAAOZ,MAAM,mBACrB,KAAK0F,EACH,KAAM,iCAAmC9E,EAAS,GACpD,IAAI+E,GAASD,EAAE,GAAG3E,MAAM,KAAKC,IApD/BS,EAoDgDd,WAC9C,IAAIgF,EAAO1J,SAAWA,EACpB,KAAM,mBAAqB0J,EAAO1J,OAAS,gBAAkBA,EAAS,aACxE,OAAO0J,IAGLC,EAAqB,SAASC,EAAiBjF,GACjD,GAAIkF,GAAYjB,EAAsBgB,GAAmB,SACzD,KAAKC,EACH,KAAM,uCAAyCD,EAAkB,GACnE,OAAOC,GAAUlF,IAGfmF,EAAgC,SAASC,EAAiBpF,EAAQqF,GACpE,GAAIC,GAAO,KACPC,IACJ,KAAK,GAAIC,KAAOJ,GACd,GAAII,EAAK,CACP,GAAIpH,GAAQiH,EAAkBG,EAC1B,iBAAoBpH,KACtBA,EAAQ4G,EAAmBI,EAAgBI,GAAMpH,IACnDmH,EAAMC,GAAOpH,MAEbkH,GAAON,EAAmBI,EAAgBI,GAAMxF,EAGpD,QAAQsF,EAAMC,IAKZE,EAAmB,SAASC,GAC9BtJ,EAAEuJ,QAAO,EAAMxJ,KAAMuJ,GAGvBD,GAAiBjK,WAEfoK,SAAU,SAASxH,EAAOyH,GACxB,GAAI1J,KAAKG,GAIP,MAFIK,WAAUtB,OAAS,IACrBwK,KAAyBpK,MAAMiB,KAAKC,UAAW,EAAG,KAC7CR,KAAKG,GAAGI,KAAKP,KAAMiC,EAAOyH,EAGnC,IAAIzJ,EAAElB,QAAQkD,GAAQ,CACpB,IAAKjC,KAAK2J,iBACR,KAAM,cAAgB3J,KAAKa,KAAO,mCACpC,OAAOb,MAAK2J,iBAAAjJ,MAALV,KAAyBQ,WAEhC,GAAIR,KAAK4J,eACP,MAAIjH,OAAMV,IACD,GACTzB,UAAU,GAAK2H,WAAW3H,UAAU,IAC7BR,KAAK4J,eAAAlJ,MAALV,KAAuBQ,WAEhC,IAAIR,KAAK6J,eACP,MAAO7J,MAAK6J,eAAAnJ,MAALV,KAAuBQ,UAEhC,MAAM,cAAgBR,KAAKa,KAAO,kCAMtCiJ,kBAAmB,SAASC,EAAcb,GACxC,GAAI,gBAAoBa,GAGtB,MAAO9J,GAAElB,QAAQgL,GAAgBA,GAAgBA,EAEnD,IAAIC,GAAOhK,KAAK8I,eAChB,IAAI7I,EAAElB,QAAQiL,GAAO,CAEnB,IAAK,GADDpB,GAASF,EAAwBqB,EAAcC,EAAK9K,QAC/CF,EAAI,EAAGA,EAAI4J,EAAO1J,OAAQF,IACjC4J,EAAO5J,GAAK6J,EAAmBmB,EAAKhL,GAAI4J,EAAO5J,GACjD,OAAO4J,GACF,MAAI3I,GAAEgK,cAAcD,GAClBhB,EAA8BgB,EAAMD,EAAcb,IAEjDL,EAAmBmB,EAAMD,KAIrCjB,gBAAiB,SAEjBoB,SAAU,ECrIZ,IAAIC,GAA2B,SAAUC,EAAYC,GACnDrK,KAAKkH,UAAY,2BAGjBlH,KAAKsK,OAAS,KAEdtK,KAAKuK,KAAKH,MAAkBC,QAG1BG,GACFC,MAAO,04BAGPvC,OAAQ,+BAERF,QAAS,UAET0C,OAAQ,QAERC,SAAU,SAEVC,IAAK,GAAIjJ,QACL,qWA+BK,KAGX6I,GAAYK,MAAQL,EAAYtC,MAGhC,IAAI4C,GAAgB,SAAApI,GAClB,GAAIO,IAAS,GAAKP,GAAKO,MAAM,mCAC7B,OAAKA,GACE8H,KAAKC,IACP,GAEC/H,EAAM,GAAKA,EAAM,GAAG/D,OAAS,IAE7B+D,EAAM,IAAMA,EAAM,GAAK,IANR,EASvBkH,GAAyB9K,WACvBkL,KAAM,SAAUH,EAAYC,GAC1BrK,KAAKqK,QAAUA,EAEfrK,KAAKoK,WAAanK,EAAEuJ,UAAWxJ,KAAKoK,WAEpC,KAAK,GAAIvJ,KAAQuJ,GACfpK,KAAKiL,aAAapK,EAAMuJ,EAAWvJ,GAAMV,GAAIiK,EAAWvJ,GAAMqJ,SAEhE3G,QAAO2H,QAAQ9F,QAAQ,2BAIzB+F,UAAW,SAAUb,GACnB,GAAI,mBAAuBtK,MAAKqK,QAAQC,GACtC,KAAM,IAAI/F,OAAM+F,EAAS,mCAI3B,OAFAtK,MAAKsK,OAASA,EAEPtK,MAIToL,WAAY,SAAUd,EAAQe,EAAUC,GAItC,MAHI,gBAAoBD,KACtBrL,KAAKqK,QAAQC,GAAUe,IAErB,IAASC,EACJtL,KAAKmL,UAAUb,GAEjBtK,MAITuL,WAAY,SAAUjB,EAAQzJ,EAAM2K,GAMlC,MALI,mBAAuBxL,MAAKqK,QAAQC,KACtCtK,KAAKqK,QAAQC,OAEftK,KAAKqK,QAAQC,GAAQzJ,GAAQ2K,EAEtBxL,MAITyL,YAAa,SAAUnB,EAAQoB,GAC7B,IAAK,GAAI7K,KAAQ6K,GACf1L,KAAKuL,WAAWjB,EAAQzJ,EAAM6K,EAAkB7K,GAElD,OAAOb,OAiBTiL,aAAc,SAAUpK,EAAM8K,EAAMC,GAClC,GAAI5L,KAAKoK,WAAWvJ,GA7IxB6D,EA8ImBrB,KAAK,cAAgBxC,EAAO,6BACtC,IAAI8D,EAAgB/C,eAAef,GAEtC,WAjJN6D,GAgJmBrB,KAAK,IAAMxC,EAAO,+DAGjC,OAAOb,MAAK6L,cAAAnL,MAALV,KAAsBQ,YAG/BsL,gBAAiB,SAAUjL,EAAM8K,EAAMC,GACrC,MAAK5L,MAAKoK,WAAWvJ,GAIdb,KAAK6L,cAAc7L,KAAMQ,YA3JpCkE,EAwJmBrB,KAAK,cAAgBxC,EAAO,6BAClCb,KAAKiL,aAAAvK,MAALV,KAAqBQ,aAKhCuL,gBAAiB,SAAUlL,GAMzB,MALKb,MAAKoK,WAAWvJ,IA/JzB6D,EAgKmBrB,KAAK,cAAgBxC,EAAO,2BAEpCb,MAAKoK,WAAWvJ,GAEhBb,MAGT6L,cAAe,SAAUhL,EAAMmL,EAAW9B,GACpC,gBAAoB8B,KAEtBA,GACE7L,GAAI6L,EACJ9B,SAAUA,IAGT8B,EAAUvC,WACbuC,EAAY,GAAI1C,GAAiB0C,IAEnChM,KAAKoK,WAAWvJ,GAAQmL,CAExB,KAAK,GAAI1B,KAAU0B,GAAUX,aAC3BrL,KAAKuL,WAAWjB,EAAQzJ,EAAMmL,EAAUX,SAASf,GAEnD,OAAOtK,OAGTiM,gBAAiB,SAAUC,GACzB,GAAIV,EAGJ,IAAI,SAAWU,EAAWrL,KAAM,CAC9B,GAAIsL,GAAenM,KAAKqK,QAAQrK,KAAKsK,QAAQ4B,EAAWrL,SACxD2K,GAAUW,EAAaD,EAAWnC,kBAElCyB,GAAUxL,KAAKoM,cAAcpM,KAAKqK,QAAQrK,KAAKsK,QAAQ4B,EAAWrL,MAAOqL,EAAWnC,aAEtF,OAAOyB,IAAWxL,KAAKqK,QAAQrK,KAAKsK,QAAQ+B,gBAAkBrM,KAAKqK,QAAQiC,GAAGD,gBAIhFD,cAAe,SAAUvI,EAAQ0I,GAC/B,GAAI,gBAAoBA,GAAY,CAClC,IAAK,GAAIvN,KAAKuN,GACZ1I,EAAS7D,KAAKoM,cAAcvI,EAAQ0I,EAAWvN,GAEjD,OAAO6E,GAGT,MAAO,gBAAoBA,GAASA,EAAOb,QAAQ,MAAOuJ,GAAc,IAU1EnC,YACEoC,UACE3C,eAAgB,SAAS5H,GACvB,MAAO,KAAKH,KAAKG,IAEnBiI,SAAU,GAEZuC,UACE9C,iBAAkB,SAASf,GACzB,MAAOA,GAAO1J,OAAS,GAEzB2K,eAAgB,SAAS5H,GACvB,MAAO,KAAKH,KAAKG,IAEnBiI,SAAU,KAEZF,MACEH,eAAgB,SAAS5H,EAAO+H,GPmb5B,GAAI0C,GAAOlM,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MOnbaA,UAAA,GPqbvDoM,EAAYF,EOrbmBG,KAAAA,EAAAF,SAAAC,EAAO,IAAAA,EPubtCE,EAAYJ,EOvb+BK,KAAAA,EAAAJ,SAAAG,EAAO,EAAAA,EACpDpL,EAAQ8I,EAAYR,EACxB,KAAKtI,EACH,KAAM,IAAI6C,OAAM,mBAAqByF,EAAO,qBAE9C,KAAKtI,EAAMI,KAAKG,GACd,OAAO,CACT,IAAI,WAAa+H,IACV,SAASlI,KAAK+K,GAAQ,IAAK,CAC9B,GAAIG,GAAKpK,OAAOX,GACZgL,EAAWlC,KAAKC,IAAIF,EAAc+B,GAAO/B,EAAciC,GAC3D,IAAIjC,EAAckC,GAAMC,EACtB,OAAO,CAET,IAAIC,GAAQ,SAAAC,GAAO,MAAOpC,MAAKqC,MAAMD,EAAIpC,KAAKsC,IAAI,GAAIJ,IACtD,KAAKC,EAAMF,GAAME,EAAMH,IAASG,EAAML,IAAS,EAC7C,OAAO,EAGb,OAAO,GAET/D,iBACE,GAAI,SACJ+D,KAAM,SACNE,KAAM,UAER7C,SAAU,KAEZoD,SACEzD,eAAgB,SAAS5H,EAAOsG,GAC9B,MAAOA,GAAOzG,KAAKG,IAErB6G,gBAAiB,SACjBoB,SAAU,IAEZqD,WACE1D,eAAgB,SAAU5H,EAAOuL,GAC/B,MAAOvL,GAAM/C,QAAUsO,GAEzB1E,gBAAiB,UACjBoB,SAAU,IAEZuD,WACE5D,eAAgB,SAAU5H,EAAOuL,GAC/B,MAAOvL,GAAM/C,QAAUsO,GAEzB1E,gBAAiB,UACjBoB,SAAU,IAEZhL,QACE2K,eAAgB,SAAU5H,EAAOyL,EAAK1C,GACpC,MAAO/I,GAAM/C,QAAUwO,GAAOzL,EAAM/C,QAAU8L,GAEhDlC,iBAAkB,UAAW,WAC7BoB,SAAU,IAEZyD,UACEhE,iBAAkB,SAAUf,EAAQ4E,GAClC,MAAO5E,GAAO1J,QAAUsO,GAE1B1E,gBAAiB,UACjBoB,SAAU,IAEZ0D,UACEjE,iBAAkB,SAAUf,EAAQ4E,GAClC,MAAO5E,GAAO1J,QAAUsO,GAE1B1E,gBAAiB,UACjBoB,SAAU,IAEZ2D,OACElE,iBAAkB,SAAUf,EAAQ8E,EAAK1C,GACvC,MAAOpC,GAAO1J,QAAUwO,GAAO9E,EAAO1J,QAAU8L,GAElDlC,iBAAkB,UAAW,WAC7BoB,SAAU,IAEZwD,KACE9D,eAAgB,SAAU3H,EAAOuL,GAC/B,MAAOvL,IAASuL,GAElB1E,gBAAiB,SACjBoB,SAAU,IAEZc,KACEpB,eAAgB,SAAU3H,EAAOuL,GAC/B,MAAgBA,IAATvL,GAET6G,gBAAiB,SACjBoB,SAAU,IAEZW,OACEjB,eAAgB,SAAU3H,EAAOyL,EAAK1C,GACpC,MAAO/I,IAASyL,GAAgB1C,GAAT/I,GAEzB6G,iBAAkB,SAAU,UAC5BoB,SAAU,IAEZ4D,SACEjE,eAAgB,SAAU5H,EAAO8L,GAC/B,GAAIC,GAAa/N,EAAE8N,EACnB,OAAIC,GAAW9O,OACN+C,IAAU+L,EAAWC,MAErBhM,IAAU8L,GAErB7D,SAAU,MClVhB,IAAIgE,MAEAC,EAAc,QAAdA,GAAwBC,EAAWC,EAAWC,GAIhD,IAAK,GAHDC,MACAC,KAEKxP,EAAI,EAAGA,EAAIoP,EAAUlP,OAAQF,IAAK,CAGzC,IAAK,GAFDyP,IAAQ,EAEHC,EAAI,EAAGA,EAAIL,EAAUnP,OAAQwP,IACpC,GAAIN,EAAUpP,GAAG2P,OAAO9N,OAASwN,EAAUK,GAAGC,OAAO9N,KAAM,CACzD4N,GAAQ,CACR,OAGAA,EACFD,EAAKhI,KAAK4H,EAAUpP,IAEpBuP,EAAM/H,KAAK4H,EAAUpP,IAGzB,OACEwP,KAAMA,EACND,MAAOA,EACPK,QAAUN,KAAOH,EAAYE,EAAWD,GAAW,GAAMG,OAI7DL,GAAUW,MAERC,mBAAoB,WR0wBhB,GAAIC,GAAQ/O,IQzwBdA,MAAKqB,SAASiF,GAAG,iBAAkB,SAAApC,GAAS6K,EAAKC,iBAAiB9K,KAClElE,KAAKqB,SAASiF,GAAG,gBAAiB,8CAA+C,SAAApC,GAAS6K,EAAKE,eAAe/K,MAG1G,IAAUlE,KAAKgG,QAAQf,WAG3BjF,KAAKqB,SAASD,KAAK,aAAc,KAGnC+D,MAAO,WAGL,GAFAnF,KAAKkP,cAAgB,MAEjB,IAASlP,KAAKmP,kBAAoB,SAAWnP,KAAKgG,QAAQb,MAC5D,MAAO,KAET,KAAK,GAAInG,GAAI,EAAGA,EAAIgB,KAAKqH,OAAOnI,OAAQF,IAAK,CAC3C,GAAIoQ,GAAQpP,KAAKqH,OAAOrI,EACxB,KAAI,IAASoQ,EAAMD,kBAAoBC,EAAMD,iBAAiBjQ,OAAS,GAAK,mBAAuBkQ,GAAMpJ,QAAQqJ,UAC/GrP,KAAKkP,cAAgBE,EAAM/N,SACvB,UAAYrB,KAAKgG,QAAQb,OAC3B,MAIN,MAAI,QAASnF,KAAKkP,cACT,KAEFlP,KAAKkP,cAAc/J,SAG5BoC,WAAY,WAEVvH,KAAKqB,SAASsF,IAAI,cAKtBuH,EAAUoB,OAERC,UAAW,WAIT,GAHAvP,KAAKwP,WAGAxP,KAAKyP,IAAV,CAIA,GAAIC,GAAOvB,EAAYnO,KAAKmP,iBAAkBnP,KAAKyP,IAAIE,qBAGvD3P,MAAKyP,IAAIE,qBAAuB3P,KAAKmP,iBAGrCnP,KAAK4P,qBAGL5P,KAAK6P,sBAAsBH,GAG3B1P,KAAK8O,sBAGAY,EAAKlB,KAAKtP,SAAUwQ,EAAKnB,MAAMrP,QAAYc,KAAK8P,cACnD9P,KAAK8P,aAAc,EACnB9P,KAAK8O,wBAKTiB,kBAAmB,WAEjB,IAAI,IAAS/P,KAAKmP,iBAChB,QAIF,KAAK,GAFD9D,MAEKrM,EAAI,EAAGA,EAAIgB,KAAKmP,iBAAiBjQ,OAAQF,IAChDqM,EAAS7E,KAAKxG,KAAKmP,iBAAiBnQ,GAAGgR,cACtChQ,KAAKiQ,iBAAiBjQ,KAAKmP,iBAAiBnQ,GAAG2P,QAElD,OAAOtD,IAIT6E,SAAU,SAAUrP,GRwwBhB,GAAIsP,GAAQ3P,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MQxwBeA,UAAA,GAAvCgL,EAAA2E,EAAA3E,QAASmD,EAAAwB,EAAAxB,OR4wB5ByB,EAAoBD,EQ5wBgBE,YAAAA,EAAA1D,SAAAyD,GAAc,EAAAA,CACxDpQ,MAAKwP,WACLxP,KAAKsQ,UAAUzP,GAAO2K,QAAAA,EAASmD,OAAAA,IAE3B0B,GACFrQ,KAAKuQ,eAITC,YAAa,SAAU3P,GR8wBnB,GAAI4P,GAAQjQ,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MQ9wBkBA,UAAA,GAAvCgL,EAAAiF,EAAAjF,QAASmD,EAAA8B,EAAA9B,ORkxB/B+B,EAAoBD,EQlxBmBJ,YAAAA,EAAA1D,SAAA+D,GAAc,EAAAA,CAC3D1Q,MAAKwP,WACLxP,KAAK2Q,aAAa9P,GAAO2K,QAAAA,EAASmD,OAAAA,IAE9B0B,GACFrQ,KAAKuQ,eAITK,YAAa,SAAU/P,GRoxBnB,GAAIgQ,GAAQrQ,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MQpxBCA,UAAA,GRsxB5CsQ,EAAoBD,EQtxBER,YAAAA,EAAA1D,SAAAmE,GAAc,EAAAA,CAC1C9Q,MAAKwP,WACLxP,KAAK+Q,aAAalQ,GAIdwP,GACFrQ,KAAK4P,sBAGTA,mBAAoB,WACd5P,KAAKgR,kBAAoBhR,KAAKiR,oBAAqB,IAASjR,KAAKmP,iBACnEnP,KAAKkR,gBACElR,KAAKmP,iBAAiBjQ,OAAS,EACtCc,KAAKuQ,cAELvQ,KAAKmR,eAGTtB,sBAAuB,SAAUH,GAC/B,GAAI,mBAAuB1P,MAAKgG,QAAQoL,uBAAxC,CAIA,GAAI,mBAAuBpR,MAAKgG,QAAQgK,aACtC,MAAKN,GAAKnB,MAAMrP,QAAUwQ,EAAKlB,KAAKtP,QAClCc,KAAKqR,sBAED,IAAMrR,KAAKyP,IAAI6B,eAAezJ,KAAK,iCAAiC3I,QACtEc,KAAKyP,IAAI6B,eACNC,OACCtR,EAAED,KAAKgG,QAAQJ,eACd4L,SAAS,iCAGTxR,KAAKyP,IAAI6B,eACbE,SAAS,UACT3J,KAAK,iCACL4J,KAAKzR,KAAKgG,QAAQgK,eAGhBhQ,KAAKyP,IAAI6B,eACbI,YAAY,UACZ7J,KAAK,iCACL8J,QAIL,KAAK,GAAI3S,GAAI,EAAGA,EAAI0Q,EAAKd,QAAQ1P,OAAQF,IACvCgB,KAAK+Q,aAAarB,EAAKd,QAAQ5P,GAAG2P,OAAO9N,KAE3C,KAAK7B,EAAI,EAAGA,EAAI0Q,EAAKnB,MAAMrP,OAAQF,IACjCgB,KAAKsQ,UAAUZ,EAAKnB,MAAMvP,GAAG2P,OAAO9N,MAAO2K,QAASkE,EAAKnB,MAAMvP,GAAGgR,aAAcrB,OAAQe,EAAKnB,MAAMvP,GAAG2P,QAExG,KAAK3P,EAAI,EAAGA,EAAI0Q,EAAKlB,KAAKtP,OAAQF,IAChCgB,KAAK2Q,aAAajB,EAAKlB,KAAKxP,GAAG2P,OAAO9N,MAAO2K,QAASkE,EAAKlB,KAAKxP,GAAGgR,aAAcrB,OAAQe,EAAKlB,KAAKxP,GAAG2P,WAI1G2B,UAAW,SAAUzP,EAAM+Q,GRmwBvB,GQnwBwBpG,GAADoG,EAACpG,QAASmD,EAAViD,EAAUjD,MACnC3O,MAAKqR,sBACLrR,KAAKyP,IAAI6B,eACNE,SAAS,UACTD,OACCtR,EAAED,KAAKgG,QAAQJ,eACd4L,SAAS,WAAa3Q,GACtB4Q,KAAKjG,GAAWxL,KAAKiQ,iBAAiBtB,MAI7CgC,aAAc,SAAU9P,EAAMgR,GRgwB1B,GQhwB2BrG,GAADqG,EAACrG,QAASmD,EAAVkD,EAAUlD,MACtC3O,MAAKyP,IAAI6B,eACNE,SAAS,UACT3J,KAAK,YAAchH,GACnB4Q,KAAKjG,GAAWxL,KAAKiQ,iBAAiBtB,KAG3CoC,aAAc,SAAUlQ,GACtBb,KAAKyP,IAAI6B,eACNI,YAAY,UACZ7J,KAAK,YAAchH,GACnB8Q,UAGL1B,iBAAkB,SAAU/D,GAC1B,GAAI4F,GAA+B5F,EAAWrL,KAAO,SAErD,OAAI,mBAAuBb,MAAKgG,QAAQ8L,GAC/BvO,OAAO2H,QAAQkB,cAAcpM,KAAKgG,QAAQ8L,GAA+B5F,EAAWnC,cAEtFxG,OAAO2H,QAAQe,gBAAgBC,IAGxCsD,SAAU,WAER,IAAIxP,KAAKyP,MAAO,IAAUzP,KAAKgG,QAAQf,UAAvC,CAGA,GAAIwK,KAGJzP,MAAKqB,SAASD,KAAKpB,KAAKgG,QAAQ1E,UAAY,KAAMtB,KAAK+R,QAIvDtC,EAAIuC,mBAAqBhS,KAAKiS,sBAG9BxC,EAAIyC,gBAAkB,eAAiBlS,KAAKgG,QAAQjB,SAAW,YAAc/E,KAAKgG,QAAQjB,SAAW/E,KAAK+R,QAC1GtC,EAAI6B,eAAiBrR,EAAED,KAAKgG,QAAQL,eAAevE,KAAK,KAAMqO,EAAIyC,iBAGlEzC,EAAIE,wBACJF,EAAI0C,8BAA+B,EAGnCnS,KAAKyP,IAAMA,IAIbwC,oBAAqB,WAEnB,GAAI,gBAAoBjS,MAAKgG,QAAQR,cAAgBvF,EAAED,KAAKgG,QAAQR,cAActG,OAChF,MAAOe,GAAED,KAAKgG,QAAQR,aAGxB,IAAI4M,GAAWpS,KAAKgG,QAAQR,aAAajF,KAAKP,KAAMA,KAGpD,OAAI,mBAAuBoS,IAAYA,EAASlT,OACvCkT,GAGJpS,KAAKgG,QAAQjB,UAAY/E,KAAKqB,SAASe,GAAG,UACtCpC,KAAKqB,SAGPrB,KAAKqB,SAAS6E,UAGvBmL,oBAAqB,WACnB,GAAIgB,EAGJ,IAAI,IAAMrS,KAAKyP,IAAI6B,eAAepL,SAAShH,OACzC,MAAOc,MAAKyP,IAAI6B,eAAepL,QAEjC,IAAI,gBAAoBlG,MAAKgG,QAAQN,gBAAiB,CACpD,GAAIzF,EAAED,KAAKgG,QAAQN,iBAAiBxG,OAClC,MAAOe,GAAED,KAAKgG,QAAQN,iBAAiB6L,OAAOvR,KAAKyP,IAAI6B,eA9R/D5M,GAgSqBrB,KAAK,yBAA2BrD,KAAKgG,QAAQN,gBAAkB,+BACrE,kBAAsB1F,MAAKgG,QAAQN,kBAC5C2M,EAAmBrS,KAAKgG,QAAQN,gBAAgBnF,KAAKP,KAAMA,MAE7D,IAAI,mBAAuBqS,IAAoBA,EAAiBnT,OAC9D,MAAOmT,GAAiBd,OAAOvR,KAAKyP,IAAI6B,eAE1C,IAAIgB,GAAQtS,KAAKqB,QAGjB,OAFIrB,MAAKgG,QAAQjB,WACfuN,EAAQA,EAAMpM,UACToM,EAAMC,MAAMvS,KAAKyP,IAAI6B,iBAG9BxC,mBAAoB,WRivBhB,GAAI0D,GAASxS,KQhvBXyS,EAAUzS,KAAK4H,cAGnB6K,GAAQ9L,IAAI,YACR3G,KAAK8P,YACP2C,EAAQnM,GAnTd5B,EAmT8BZ,gBAAgB9D,KAAKgG,QAAQX,oBAAqB,WAAY,WACpFmN,EAAK/I,aAGPgJ,EAAQnM,GAvTd5B,EAuT8BZ,gBAAgB9D,KAAKgG,QAAQZ,QAAS,WAAY,SAAAsN,GACxEF,EAAKG,eAAeD,MAK1BC,eAAgB,SAAUD,KAIpB,YAAY5Q,KAAK4Q,EAAM1I,OACnBhK,KAAKyP,KAAOzP,KAAKyP,IAAI0C,gCAAiCnS,KAAK4S,WAAW1T,QAAUc,KAAKgG,QAAQd,uBAGrGlF,KAAKyJ,YAGPtC,SAAU,WAERnH,KAAK8P,aAAc,EACnB9P,KAAK8O,qBAGD,mBAAuB9O,MAAKyP,MAIhCzP,KAAKyP,IAAI6B,eACNI,YAAY,UACZmB,WACAlB,SAGH3R,KAAKmR,cAGLnR,KAAKyP,IAAIE,wBACT3P,KAAKyP,IAAI0C,8BAA+B,IAG1C5K,WAAY,WACVvH,KAAKmH,WAED,mBAAuBnH,MAAKyP,KAC9BzP,KAAKyP,IAAI6B,eAAeK,eAEnB3R,MAAKyP,KAGdyB,cAAe,WACblR,KAAKyP,IAAI0C,8BAA+B,EACxCnS,KAAKyP,IAAIuC,mBAAmBN,YAAY1R,KAAKgG,QAAQV,YAAYkM,SAASxR,KAAKgG,QAAQT,eAEzFgL,YAAa,WACXvQ,KAAKyP,IAAI0C,8BAA+B,EACxCnS,KAAKyP,IAAIuC,mBAAmBN,YAAY1R,KAAKgG,QAAQT,cAAciM,SAASxR,KAAKgG,QAAQV,aAE3F6L,YAAa,WACXnR,KAAKyP,IAAIuC,mBAAmBN,YAAY1R,KAAKgG,QAAQT,cAAcmM,YAAY1R,KAAKgG,QAAQV,aC7WhG,IAAIwN,GAAc,SAAUC,EAAS9M,EAAYD,GAC/ChG,KAAKkH,UAAY,cACjBlH,KAAK+R,OANPrN,EAM6BjC,aAE3BzC,KAAKqB,SAAWpB,EAAE8S,GAClB/S,KAAKiG,WAAaA,EAClBjG,KAAKgG,QAAUA,EACfhG,KAAKkG,OAAS3C,OAAO2H,QAErBlL,KAAKqH,UACLrH,KAAKmP,iBAAmB,MAd1B6D,GAiBqBC,QAAS,KAAMC,UAAU,EAAMC,UAAU,EAE9DL,GAAYzT,WACV2P,iBAAkB,SAAU0D,GT2lCxB,GAAIU,GAASpT,ISzlCf,KAAI,IAAS0S,EAAM5S,QAAnB,CAIA,GAAIuT,GAAgBrT,KAAKsT,gBAAkBtT,KAAKqB,SAASwG,KAAK,+CAA+C0L,OAG7G,IAFAvT,KAAKsT,eAAiB,KACtBtT,KAAKqB,SAASwG,KAAK,oCAAoC2L,KAAK,YAAY,IACpEH,EAAcjR,GAAG,oBAArB,CAGA,GAAIqR,GAAUzT,KAAK0T,cAAchB,MAAAA,GAE7B,cAAee,EAAQE,UAAW,IAAU3T,KAAKoH,SAAS,YAK5DsL,EAAMkB,2BACNlB,EAAMmB,iBACF,YAAcJ,EAAQE,SACxBF,EAAQK,KAAK,WAAQV,EAAKW,QAAQV,SAIxCpE,eAAgB,SAASyD,GACvB1S,KAAKsT,eAAiBrT,EAAEyS,EAAM3L,SAKhCgN,QAAS,SAAUV,GACjB,IAAI,IAAUrT,KAAKoH,SAAS,UAA5B,CAGA,GAAIiM,EAAe,CACjB,GAAIW,GAAahU,KAAKqB,SAASwG,KAAK,oCAAoC2L,KAAK,YAAY,EACrF,KAAMQ,EAAW9U,SACnB8U,EAAa/T,EAAE,iEAAiEgU,SAASjU,KAAKqB,WAChG2S,EAAW5S,MACTP,KAAMwS,EAAcjS,KAAK,QACzBa,MAAOoR,EAAcjS,KAAK,WAI9BpB,KAAKqB,SAAS+D,QAAQnF,EAAEuJ,OAAOvJ,EAAEiU,MAAM,WAAYpU,SAAS,OAQ9D2J,SAAU,SAAUzD,GAClB,GAAIxF,UAAUtB,QAAU,IAAMe,EAAEgK,cAAcjE,GAAU,CA3E5DtB,EA4EmBjB,SAAS,2FT2lCpB,IAAI0Q,GAAa/U,OAAOmB,KS1lCEC,WAAvBwE,EAAAmP,EAAA,GAAOzM,EAAAyM,EAAA,GAAOzB,EAAAyB,EAAA,EACnBnO,IAAWhB,MAAAA,EAAO0C,MAAAA,EAAOgL,MAAAA,GAE3B,MAhFJM,GAgF0BhT,KAAK0T,aAAa1N,GAAS2N,UAGnDD,aAAc,WTgmCV,GAAIU,GAASpU,KAETqU,EAAQ7T,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MSlmCHA,UAAA,GAAvBwE,EAAAqP,EAAArP,MAAO0C,EAAA2M,EAAA3M,MAAOgL,EAAA2B,EAAA3B,KACrC1S,MAAKsU,YAAc5B,EACfA,IACF1S,KAAKsU,YAAcrU,EAAEuJ,UAAWkJ,GAAQmB,eAAgB,WAtF9DnP,EAuFqBjB,SAAS,0GACtB2Q,EAAKjF,kBAAmB,MAG5BnP,KAAKmP,kBAAmB,EAGxBnP,KAAKoH,SAAS,YAGdpH,KAAKuU,gBAEL,IAAIC,GAAWxU,KAAKyU,iCAAiC,WACnD,MAAOxU,GAAEgE,IAAImQ,EAAK/M,OAAQ,SAAA+H,GACxB,MAAOA,GAAMsE,cAAchM,MAAAA,EAAO1C,MAAAA,QAIlC0P,EAAiC,WACnC,GAAIC,GAAI1U,EAAE2U,UAGV,QAFI,IAAUR,EAAKjF,kBACjBwF,EAAEE,SACGF,EAAEG,UAAUrB,UAGrB,OAAOxT,GAAE8U,KAAArU,MAAFT,EAAArB,mBAAU4V,IACdV,KAAO,WAAQM,EAAKhN,SAAS,aAC7B4N,KAAO,WACNZ,EAAKjF,kBAAmB,EACxBiF,EAAKjP,QACLiP,EAAKhN,SAAS,WAEf6N,OAAO,WAAQb,EAAKhN,SAAS,eAC7B8N,KAAOR,EAAgCA,IAO5CS,QAAS,SAAUnP,GACjB,GAAIxF,UAAUtB,QAAU,IAAMe,EAAEgK,cAAcjE,GAAU,CAhI5DtB,EAiImBjB,SAAS,0FTwmCpB,IAAI2R,GAAchW,OAAOmB,KSvmCNC,WAAhBwE,EAAAoQ,EAAA,GAAO1N,EAAA0N,EAAA,EACZpP,IAAWhB,MAAAA,EAAO0C,MAAAA,GAEpB,MArIJsL,GAqI0BhT,KAAK2H,UAAU3B,GAAS2N,UAMhDhM,UAAW,WT4mCP,GAAI0N,GAASrV,KAETsV,EAAQ9U,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MS9mCbA,UAAA,GAAhBwE,EAAAsQ,EAAAtQ,MAAO0C,EAAA4N,EAAA5N,KAC3B1H,MAAKuU,gBAEL,IAAIC,GAAWxU,KAAKyU,iCAAiC,WACnD,MAAOxU,GAAEgE,IAAIoR,EAAKhO,OAAQ,SAAA+H,GACxB,MAAOA,GAAMzH,WAAW3C,MAAAA,EAAO0C,MAAAA,OAGnC,OAAOzH,GAAE8U,KAAArU,MAAFT,EAAArB,mBAAU4V,KAGnBD,eAAgB,WACd,MAAOvU,MAAK+F,mBAAmBwP,eAGjCA,YAAa,WTmnCT,GAAIC,GAASxV,KSlnCXyV,EAAYzV,KAAKqH,MAwBrB,OAtBArH,MAAKqH,UACLrH,KAAK0V,oBAEL1V,KAAKyU,iCAAiC,WACpCe,EAAKnU,SACJwG,KAAK2N,EAAKxP,QAAQpB,QAClB+Q,IAAIH,EAAKxP,QAAQnB,UACjB+Q,KAAK,SAACC,EAAG9C,GACR,GAAI+C,GAAgB,GAAIvS,QAAO2H,QAAQ6K,QAAQhD,KAASyC,EAGnD,kBAAmBM,EAAc5O,WAAa,yBAA2B4O,EAAc5O,YAAe,IAAS4O,EAAc9P,QAAQnB,UACpI,mBAAuB2Q,GAAKE,iBAAiBI,EAAc5O,UAAY,IAAM4O,EAAc/D,UAC7FyD,EAAKE,iBAAiBI,EAAc5O,UAAY,IAAM4O,EAAc/D,QAAU+D,EAC9EN,EAAKnO,OAAOb,KAAKsP,MAIvB7V,EAAEwV,GAAWE,IAAIH,EAAKnO,QAAQuO,KAAK,SAACC,EAAGzG,GACrCA,EAAMhI,SAAS,aAGZpH,MAUTyU,iCAAkC,SAAUtU,GAC1C,GAAI6V,GAAsBhW,KAAK+F,gBAC/B/F,MAAK+F,iBAAmB,WAAc,MAAO/F,MAC7C,IAAIyE,GAAStE,GAEb,OADAH,MAAK+F,iBAAmBiQ,EACjBvR,GAMT2C,SAAU,SAAUxG,GAClB,MAAOZ,MAAKoF,QAAQ,QAAUxE,ICpMlC,IAAIqV,GAAoB,SAAUC,EAAcrV,EAAMkJ,EAAcG,EAAUiM,GAC5E,IAAK,eAAerU,KAAKoU,EAAahP,WACpC,KAAM,IAAI3C,OAAM,yDAElB,IAAI6R,GAAgB7S,OAAO2H,QAAQmL,mBAAmBjM,WAAWvJ,GAC7DmL,EAAY,GAAI1C,GAAiB8M,EAErCnW,GAAEuJ,OAAOxJ,MACPgM,UAAWA,EACXnL,KAAMA,EACNkJ,aAAcA,EACdG,SAAUA,GAAYgM,EAAalQ,QAAQnF,EAAO,aAAemL,EAAU9B,SAC3EiM,iBAAiB,IAASA,IAE5BnW,KAAKsW,mBAAmBJ,EAAalQ,UAGnCuQ,EAAa,SAASxT,GACxB,GAAIyT,GAAMzT,EAAI,GAAGI,aACjB,OAAOqT,GAAMzT,EAAIzD,MAAM,GAGzB2W,GAAkB5W,WAChBoK,SAAU,SAASxH,EAAOwU,GACxB,GAAInW,GAAON,KAAK0W,gBAAgBpX,MAAM,EAGtC,OAFAgB,GAAKG,QAAQwB,GACb3B,EAAKkG,KAAKiQ,GACHzW,KAAKgM,UAAUvC,SAAS/I,MAAMV,KAAKgM,UAAW1L,IAGvDgW,mBAAoB,SAAStQ,GV2zCzB,GAAI2Q,GAAS3W,IU1zCfA,MAAK0W,gBAAkB1W,KAAKgM,UAAUlC,kBAAkB9J,KAAK+J,aAAc,SAAAV,GACzE,MAAOrD,GAAQ2Q,EAAK9V,KAAO0V,EAAWlN,OChC5C,IAAI5D,GAAe,SAAU2J,EAAOnJ,EAAYD,EAAS4Q,GACvD5W,KAAKkH,UAAY,eACjBlH,KAAK+R,OAPPrN,EAO6BjC,aAE3BzC,KAAKqB,SAAWpB,EAAEmP,GAGd,mBAAuBwH,KACzB5W,KAAKkG,OAAS0Q,GAGhB5W,KAAKgG,QAAUA,EACfhG,KAAKiG,WAAaA,EAGlBjG,KAAK6W,eACL7W,KAAK8W,qBACL9W,KAAKmP,oBAGLnP,KAAK+W,oBAzBPC,GA4BqB/D,QAAS,KAAMC,UAAU,EAAMC,UAAU,EAE9D1N,GAAapG,WAKXoK,SAAU,SAAUzD,GACdxF,UAAUtB,QAAU,IAAMe,EAAEgK,cAAcjE,KApClDtB,EAqCmBjB,SAAS,6FACtBuC,GAAWA,QAAAA,GAEb,IAAIyN,GAAUzT,KAAK0T,aAAa1N,EAChC,KAAKyN,EACH,OAAO,CACT,QAAQA,EAAQE,SACd,IAAK,UAAW,MAAO,KACvB,KAAK,WAAY,OAAO,CACxB,KAAK,WAAY,MAAO3T,MAAKmP,mBAOjCuE,aAAc,WXq2CV,GAAIuD,GAASjX,KAETkX,EAAQ1W,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MWv2CTA,UAAA,GAAjBkH,EAAAwP,EAAAxP,MAAO1C,EAAAkS,EAAAlS,KAG9B,OADAhF,MAAKmX,sBACDnS,GAAUhF,KAAKoX,WAAWpS,IAG9BhF,KAAKiC,MAAQjC,KAAK4S,WAGlB5S,KAAKoH,SAAS,YAEPpH,KAAK2H,WAAWD,MAAAA,EAAOzF,MAAOjC,KAAKiC,MAAOoV,YAAY,IAC1DpC,OAAO,WAAQgC,EAAK1H,cACpBuE,KAAK,WAAUmD,EAAK7P,SAAS,aAC7B4N,KAAK,WAAUiC,EAAK7P,SAAS,WAC7B6N,OAAO,WAAQgC,EAAK7P,SAAS,gBAZhC,QAeF4J,eAAgB,WACd,MAAO,KAAMhR,KAAK6W,YAAY3X,QAIhC+R,gBAAiB,SAAUhP,GAMzB,MALI,mBAAuBA,KACzBA,EAAQjC,KAAK4S,YAIV3Q,EAAM/C,QAAWc,KAAKsX,eAAiB,mBAAuBtX,MAAKgG,QAAQuR,iBAGzE,GAFE,GAKXH,WAAY,SAAUpS,GACpB,MAAI/E,GAAElB,QAAQiB,KAAKgG,QAAQhB,OAClB,KAAO/E,EAAEuX,QAAQxS,EAAOhF,KAAKgG,QAAQhB,OACvChF,KAAKgG,QAAQhB,QAAUA,GAOhCmQ,QAAS,SAAUnP,GACjB,GAAIxF,UAAUtB,QAAU,IAAMe,EAAEgK,cAAcjE,GAAU,CAnG5DtB,EAoGmBjB,SAAS,2FX62CpB,IAAIgU,GAAcrY,OAAOmB,KW52CNC,WAAhBkH,EAAA+P,EAAA,GAAOxV,EAAAwV,EAAA,EACZzR,IAAW0B,MAAAA,EAAOzF,MAAAA,GAEpB,GAAIwR,GAAUzT,KAAK2H,UAAU3B,EAC7B,OAAKyN,GAzGTuD,EA2GyBvD,EAAQE,UADpB,GASXhM,UAAW,WXi3CP,GAAI+P,GAAS1X,KAET2X,EAASnX,UAAUtB,QAAU,GAAsByN,SAAjBnM,UAAU,MWn3CaA,UAAA,GXq3CzDoX,EAAeD,EWr3CDjQ,MAAAA,EAAAiF,SAAAiL,GAAQ,EAAAA,EAAO3V,EAAA0V,EAAA1V,MAAO+C,EAAA2S,EAAA3S,MAAOqS,EAAAM,EAAAN,UAKjD,IAHKA,GACHrX,KAAKmX,sBAEHnS,GAAUhF,KAAKoX,WAAWpS,GAA9B,CAMA,GAHAhF,KAAKmP,kBAAmB,GAGnBnP,KAAKgR,iBACR,MAAO/Q,GAAE8U,MAMX,KAHI,mBAAuB9S,IAAS,OAASA,KAC3CA,EAAQjC,KAAK4S,aAEV5S,KAAKiR,gBAAgBhP,KAAU,IAASyF,EAC3C,MAAOzH,GAAE8U,MAEX,IAAI8C,GAAqB7X,KAAK8X,yBAC1BtD,IAWJ,OAVAvU,GAAE2V,KAAKiC,EAAoB,SAAChC,EAAGgB,GAG7B,GAAIpD,GAAUxT,EAAE8U,KAAArU,MAAFT,EAAArB,mBACTqB,EAAEgE,IAAI4S,EAAa,SAAA3K,GXq3CpB,MWr3CkCwL,GAAKK,oBAAoB9V,EAAOiK,MAGtE,OADAsI,GAAShO,KAAKiN,GACU,aAApBA,EAAQE,SACH,EADT,SAGK1T,EAAE8U,KAAKrU,MAAMT,EAAGuU,KAIzBuD,oBAAqB,SAAS9V,EAAOiK,GXq3CjC,GAAI8L,GAAUhY,KWp3CZyE,EAASyH,EAAWzC,SAASxH,EAAOjC,KAKxC,QAHI,IAAUyE,IACZA,EAASxE,EAAE2U,WAAWC,UAEjB5U,EAAE8U,KAAKtQ,GAAQuQ,KAAK,SAAAhF,IACrB,IAASgI,EAAK7I,mBAChB6I,EAAK7I,qBACP6I,EAAK7I,iBAAiB3I,MACpBmI,OAAQzC,EACR8D,aAAc,gBAAoBA,IAAgBA,OAMxD4C,SAAU,WACR,GAAI3Q,EAWJ,OAPEA,GADE,kBAAsBjC,MAAKgG,QAAQ/D,MAC7BjC,KAAKgG,QAAQ/D,MAAMjC,MACpB,mBAAuBA,MAAKgG,QAAQ/D,MACnCjC,KAAKgG,QAAQ/D,MAEbjC,KAAKqB,SAAS4M,MAGpB,mBAAuBhM,IAAS,OAASA,EACpC,GAEFjC,KAAKiY,kBAAkBhW,IAKhCkV,mBAAoB,WAClB,MAAOnX,MAAK+F,mBAAmBgR,oBAWjCmB,cAAe,SAAUrX,EAAMkJ,EAAcG,EAAUiM,GAErD,GAAI5S,OAAO2H,QAAQmL,mBAAmBjM,WAAWvJ,GAAO,CACtD,GAAIqL,GAAa,GAAI+J,GAAkBjW,KAAMa,EAAMkJ,EAAcG,EAAUiM,EAGvE,eAAgBnW,KAAK8W,kBAAkB5K,EAAWrL,OACpDb,KAAKmY,iBAAiBjM,EAAWrL,MAEnCb,KAAK6W,YAAYrQ,KAAK0F,GACtBlM,KAAK8W,kBAAkB5K,EAAWrL,MAAQqL,EAG5C,MAAOlM,OAITmY,iBAAkB,SAAUtX,GAC1B,IAAK,GAAI7B,GAAI,EAAGA,EAAIgB,KAAK6W,YAAY3X,OAAQF,IAC3C,GAAI6B,IAASb,KAAK6W,YAAY7X,GAAG6B,KAAM,CACrCb,KAAK6W,YAAYjQ,OAAO5H,EAAG,EAC3B,OAGJ,aADOgB,MAAK8W,kBAAkBjW,GACvBb,MAIToY,iBAAkB,SAAUvX,EAAM0L,EAAYrC,GAC5C,MAAOlK,MAAKmY,iBAAiBtX,GAC1BqX,cAAcrX,EAAM0L,EAAYrC,IAOrC6M,iBAAkB,WAKhB,IAAK,GAJDF,MACAC,KAGK9X,EAAI,EAAGA,EAAIgB,KAAK6W,YAAY3X,OAAQF,KACvC,IAAUgB,KAAK6W,YAAY7X,GAAGmX,kBAChCU,EAAYrQ,KAAKxG,KAAK6W,YAAY7X,IAClC8X,EAAkB9W,KAAK6W,YAAY7X,GAAG6B,MAAQb,KAAK6W,YAAY7X,GAGnEgB,MAAK6W,YAAcA,EACnB7W,KAAK8W,kBAAoBA,CAGzB,KAAK,GAAIjW,KAAQb,MAAKgG,QACpBhG,KAAKkY,cAAcrX,EAAMb,KAAKgG,QAAQnF,GAAO8L,QAAW,EAG1D,OAAO3M,MAAKqY,yBAKdA,sBAAuB,YAEjBrY,KAAKqB,SAASiX,SAAS,aAAetY,KAAKqB,SAASD,KAAK,cAC3DpB,KAAKkY,cAAc,YAAY,EAAMvL,QAAW,GAG9C,gBAAoB3M,MAAKqB,SAASD,KAAK,YACzCpB,KAAKkY,cAAc,UAAWlY,KAAKqB,SAASD,KAAK,WAAYuL,QAAW,GAGtE,mBAAuB3M,MAAKqB,SAASD,KAAK,QAAU,mBAAuBpB,MAAKqB,SAASD,KAAK,OAChGpB,KAAKkY,cAAc,SAAUlY,KAAKqB,SAASD,KAAK,OAAQpB,KAAKqB,SAASD,KAAK,QAASuL,QAAW,GAGxF,mBAAuB3M,MAAKqB,SAASD,KAAK,OACjDpB,KAAKkY,cAAc,MAAOlY,KAAKqB,SAASD,KAAK,OAAQuL,QAAW,GAGzD,mBAAuB3M,MAAKqB,SAASD,KAAK,QACjDpB,KAAKkY,cAAc,MAAOlY,KAAKqB,SAASD,KAAK,OAAQuL,QAAW,GAI9D,mBAAuB3M,MAAKqB,SAASD,KAAK,cAAgB,mBAAuBpB,MAAKqB,SAASD,KAAK,aACtGpB,KAAKkY,cAAc,UAAWlY,KAAKqB,SAASD,KAAK,aAAcpB,KAAKqB,SAASD,KAAK,cAAeuL,QAAW,GAGrG,mBAAuB3M,MAAKqB,SAASD,KAAK,aACjDpB,KAAKkY,cAAc,YAAalY,KAAKqB,SAASD,KAAK,aAAcuL,QAAW,GAGrE,mBAAuB3M,MAAKqB,SAASD,KAAK,cACjDpB,KAAKkY,cAAc,YAAalY,KAAKqB,SAASD,KAAK,aAAcuL,QAAW,EAI9E,IAAI3C,GAAOhK,KAAKqB,SAASD,KAAK,OAE9B,OAAI,mBAAuB4I,GAClBhK,KAGL,WAAagK,EACRhK,KAAKkY,cAAc,QAAS,UACjCrL,KAAM7M,KAAKqB,SAASD,KAAK,QACzB2L,KAAM/M,KAAKqB,SAASD,KAAK,QAAUpB,KAAKqB,SAASD,KAAK,WACpDuL,QAAW,GAEN,uBAAuB7K,KAAKkI,GAC9BhK,KAAKkY,cAAc,OAAQlO,EAAM2C,QAAW,GAE9C3M,MAKTsX,YAAa,WACX,MAAI,mBAAuBtX,MAAK8W,kBAAkBrK,UACzC,GAEF,IAAUzM,KAAK8W,kBAAkBrK,SAAS1C,cAKnD3C,SAAU,SAAUxG,GAClB,MAAOZ,MAAKoF,QAAQ,SAAWxE,IAOjCqX,kBAAmB,SAAUhW,GAU3B,OATI,IAASjC,KAAKgG,QAAQuS,WAhV9B7T,EAiVmBjB,SAAS,2FAEpB,WAAazD,KAAKgG,QAAQwS,aAC5BvW,EAAQA,EAAMe,QAAQ,UAAW,OAE/B,SAAYhD,KAAKgG,QAAQwS,YAAgB,WAAaxY,KAAKgG,QAAQwS,aAAgB,IAASxY,KAAKgG,QAAQuS,aAC3GtW,EAvVNyC,EAuV2Bd,WAAW3B,IAE3BA,GAMT6V,uBAAwB,WACtB,IAAI,IAAU9X,KAAKgG,QAAQlB,gBACzB,OAAQ9E,KAAK6W,YAMf,KAAK,GAJDgB,MACAY,KAGKzZ,EAAI,EAAGA,EAAIgB,KAAK6W,YAAY3X,OAAQF,IAAK,CAChD,GAAI0Z,GAAI1Y,KAAK6W,YAAY7X,GAAGkL,QACvBuO,GAAMC,IACTb,EAAmBrR,KAAKiS,EAAMC,OAChCD,EAAMC,GAAGlS,KAAKxG,KAAK6W,YAAY7X,IAKjC,MAFA6Y,GAAmBc,KAAK,SAAUC,EAAGC,GAAK,MAAOA,GAAE,GAAG3O,SAAW0O,EAAE,GAAG1O,WAE/D2N,GAhXX,IAAAiB,GAAArT,ECEIsT,EAAkB,WACpB/Y,KAAKkH,UAAY,uBAGnB6R,GAAgB1Z,WAEd2Z,WAAY,SAAU3X,GAGpB,MAFArB,MAAKiZ,UAAUzS,KAAKnF,GAEbrB,MAITmX,mBAAoB,WAClB,GAAI+B,EAKJ,IAHAlZ,KAAK6W,eAGD7W,KAAKqB,SAASe,GAAG,UAGnB,MAFApC,MAAK+F,mBAAmBgR,mBAEjB/W,IAIT,KAAK,GAAIhB,GAAI,EAAGA,EAAIgB,KAAKiZ,UAAU/Z,OAAQF,IAGzC,GAAKiB,EAAE,QAAQkZ,IAAInZ,KAAKiZ,UAAUja,IAAIE,OAAtC,CAKAga,EAAmBlZ,KAAKiZ,UAAUja,GAAGoa,KAAK,wBAAwBjC,qBAAqBN,WAEvF,KAAK,GAAInI,GAAI,EAAGA,EAAIwK,EAAiBha,OAAQwP,IAC3C1O,KAAKkY,cAAcgB,EAAiBxK,GAAG7N,KAAMqY,EAAiBxK,GAAG3E,aAAcmP,EAAiBxK,GAAGxE,SAAUgP,EAAiBxK,GAAGyH,qBAPjInW,MAAKiZ,UAAUrS,OAAO5H,EAAG,EAU7B,OAAOgB,OAIT4S,SAAU,WAER,GAAI,kBAAsB5S,MAAKgG,QAAQ/D,MACrCA,MAAQjC,KAAKgG,QAAQ/D,MAAMjC,UACxB,IAAI,mBAAuBA,MAAKgG,QAAQ/D,MAC3C,MAAOjC,MAAKgG,QAAQ/D,KAGtB,IAAIjC,KAAKqB,SAASe,GAAG,qBACnB,MAAOpC,MAAK4H,eAAeyR,OAAO,YAAYpL,OAAS,EAGzD,IAAIjO,KAAKqB,SAASe,GAAG,wBAAyB,CAC5C,GAAIwG,KAMJ,OAJA5I,MAAK4H,eAAeyR,OAAO,YAAYzD,KAAK,WAC1ChN,EAAOpC,KAAKvG,EAAED,MAAMiO,SAGfrF,EAIT,MAAI5I,MAAKqB,SAASe,GAAG,WAAa,OAASpC,KAAKqB,SAAS4M,SAIlDjO,KAAKqB,SAAS4M,OAGvBqL,MAAO,WAGL,MAFAtZ,MAAKiZ,WAAajZ,KAAKqB,UAEhBrB,MCxEX,IAAIuZ,GAAiB,SAAUxG,EAAS/M,EAAS4Q,GAC/C5W,KAAKqB,SAAWpB,EAAE8S,EAGlB,IAAIyG,GAA2BxZ,KAAKqB,SAAS+X,KAAK,UAClD,IAAII,EAQF,MALI,mBAAuB5C,IAAuB4C,EAAyBtT,SAAW3C,OAAO2H,UAC3FsO,EAAyBtT,OAAS0Q,EAClC4C,EAAyBrT,cAAcqT,EAAyBxT,UAG3DwT,CAIT,KAAKxZ,KAAKqB,SAASnC,OACjB,KAAM,IAAIqF,OAAM,gDAElB,IAAI,mBAAuBqS,IAAuB,gBAAkBA,EAAoB1P,UACtF,KAAM,IAAI3C,OAAM,iDAGlB,OADAvE,MAAKkG,OAAS0Q,GAAuBrT,OAAO2H,QACrClL,KAAKuK,KAAKvE,GAGnBuT,GAAela,WACbkL,KAAM,SAAUvE,GASd,MARAhG,MAAKkH,UAAY,UACjBlH,KAAKyZ,YAAc,QACnBzZ,KAAK+R,OAtCTrN,EAsC+BjC,aAG3BzC,KAAKmG,cAAcH,GAGfhG,KAAKqB,SAASe,GAAG,SA5CzBsC,EA4CkDxC,UAAUlC,KAAKqB,SAAUrB,KAAKgG,QAAQ1E,UAAW,cAAgBtB,KAAKqB,SAASe,GAAGpC,KAAKgG,QAAQpB,QACpI5E,KAAK0Z,KAAK,eAGZ1Z,KAAK2Z,aAAe3Z,KAAK4Z,iBAAmB5Z,KAAK0Z,KAAK,iBAG/DC,WAAY,WACV,MAAO3Z,MAAMqB,SAASe,GAAG,4CAAgDpC,KAAKqB,SAASe,GAAG,WAAa,mBAAuBpC,MAAKqB,SAASD,KAAK,aAKnJwY,eAAgB,WbmxDZ,GalxDE/Y,GAEAgZ,EbgxDEC,EAAU9Z,IarwDhB,IARIA,KAAKgG,QAAQjB,WAER,mBAAuB/E,MAAKqB,SAASD,KAAK,SAAWpB,KAAKqB,SAASD,KAAK,QAAQlC,OACvFc,KAAKgG,QAAQjB,SAAWlE,EAAOb,KAAKqB,SAASD,KAAK,QAC3C,mBAAuBpB,MAAKqB,SAASD,KAAK,OAASpB,KAAKqB,SAASD,KAAK,MAAMlC,SACnFc,KAAKgG,QAAQjB,SAAW/E,KAAKqB,SAASD,KAAK,QAGzCpB,KAAKqB,SAASe,GAAG,WAAa,mBAAuBpC,MAAKqB,SAASD,KAAK,YAE1E,MADApB,MAAKgG,QAAQjB,SAAW/E,KAAKgG,QAAQjB,UAAY/E,KAAK+R,OAC/C/R,KAAK0Z,KAAK,uBAGZ,KAAK1Z,KAAKgG,QAAQjB,SAEvB,MA9ENL,GA6EmBrB,KAAK,wHAAyHrD,KAAKqB,UACzIrB,IAITA,MAAKgG,QAAQjB,SAAW/E,KAAKgG,QAAQjB,SAAS/B,QAAQ,yBAA0B;AAG5E,mBAAuBnC,IACzBZ,EAAE,eAAiBY,EAAO,MAAM+U,KAAK,SAAC5W,EAAG+a,GACnC9Z,EAAE8Z,GAAO3X,GAAG,4CACdnC,EAAE8Z,GAAO3Y,KAAK0Y,EAAK9T,QAAQ1E,UAAY,WAAYwY,EAAK9T,QAAQjB,WAMtE,KAAK,GADDiV,GAAqBha,KAAK4H,eACrB5I,EAAI,EAAGA,EAAIgb,EAAmB9a,OAAQF,IAE7C,GADA6a,EAA0B5Z,EAAE+Z,EAAmBC,IAAIjb,IAAIoa,KAAK,WACxD,mBAAuBS,GAAyB,CAE7C7Z,KAAKqB,SAAS+X,KAAK,yBACtBS,EAAwBb,WAAWhZ,KAAKqB,SAG1C,OAQJ,MAFArB,MAAK0Z,KAAK,gBAAgB,GAEnBG,GAA2B7Z,KAAK0Z,KAAK,yBAI9CA,KAAM,SAAU1P,EAAMkQ,GACpB,GAAIC,EAEJ,QAAQnQ,GACN,IAAK,cACHmQ,EAAkBla,EAAEuJ,OAClB,GAAIsJ,GAAY9S,KAAKqB,SAAUrB,KAAKiG,WAAYjG,KAAKgG,SACrDzC,OAAO6W,eACP7E,aACF,MACF,KAAK,eACH4E,EAAkBla,EAAEuJ,OAClB,GA9HVsP,GA8H2B9Y,KAAKqB,SAAUrB,KAAKiG,WAAYjG,KAAKgG,QAAShG,KAAKkG,QACpE3C,OAAO6W,cAET,MACF,KAAK,uBACHD,EAAkBla,EAAEuJ,OAClB,GApIVsP,GAoI2B9Y,KAAKqB,SAAUrB,KAAKiG,WAAYjG,KAAKgG,QAAShG,KAAKkG,QACpE,GAAI6S,GACJxV,OAAO6W,eACPd,OACF,MACF,SACE,KAAM,IAAI/U,OAAMyF,EAAO,mCAM3B,MAHIhK,MAAKgG,QAAQjB,UA7IrBL,EA8ImBrC,QAAQrC,KAAKqB,SAAUrB,KAAKgG,QAAQ1E,UAAW,WAAYtB,KAAKgG,QAAQjB,UAEnF,mBAAuBmV,IACzBla,KAAKqB,SAAS+X,KAAK,uBAAwBe,GAEpCA,IAITna,KAAKqB,SAAS+X,KAAK,UAAWe,GAG9BA,EAAgBrL,qBAChBqL,EAAgB/S,SAAS,QAElB+S,IClJX,IAAIE,GAAUpa,EAAEE,GAAGma,OAAOtW,MAAM,IAChC,IAAIiE,SAASoS,EAAQ,KAAO,GAAKpS,SAASoS,EAAQ,IAAM,EACtD,KAAM,6EAEHA,GAAQE,SAfb7V,EAgBerB,KAAK,4FAGpB,IAAI6H,GAAUjL,EAAEuJ,OAAO,GAAI3D,IACvBxE,SAAUpB,EAAEua,UACZzU,iBAAkB,KAClBI,cAAe,KACf4P,QAASwD,EACTkB,QAAS,SAKbxa,GAAEuJ,OA7BFsP,EA6BsBzZ,UAAW6O,EAAUoB,MAAOzJ,EAAgBxG,WAClEY,EAAEuJ,OAAOsJ,EAAYzT,UAAW6O,EAAUW,KAAMhJ,EAAgBxG,WAEhEY,EAAEuJ,OAAO+P,EAAela,UAAWwG,EAAgBxG,WAInDY,EAAEE,GAAGL,QAAUG,EAAEE,GAAGua,KAAO,SAAU1U,GACnC,GAAIhG,KAAKd,OAAS,EAAG,CACnB,GAAIyb,KAMJ,OAJA3a,MAAK4V,KAAK,WACR+E,EAAUnU,KAAKvG,EAAED,MAAMF,QAAQkG,MAG1B2U,EAIT,MAAK1a,GAAED,MAAMd,OAMN,GAAIqa,GAAevZ,KAAMgG,OAtDlCtB,GAiDiBrB,KAAK,kDAUlB,mBAAuBE,QAAO6W,gBAChC7W,OAAO6W,kBAITlP,EAAQlF,QAAU/F,EAAEuJ,OAhEpB9E,EAgEwCN,aAAaO,GAAkBpB,OAAOqX,eAC9ErX,OAAOqX,cAAgB1P,EAAQlF,QAG/BzC,OAAO2H,QAAU3H,OAAOmX,KAAOxP,EAC/B3H,OAAOsX,aArEPnW,CAwEA,IAAIoW,GAAWvX,OAAO2H,QAAQmL,mBAAqB,GAAIlM,GAAyB5G,OAAOqX,cAAcxQ,WAAY7G,OAAOqX,cAAcG,KACtIxX,QAAO+F,oBACPrJ,EAAE2V,KAAK,yHAAyH5R,MAAM,KAAM,SAAUhF,EAAGgc,GACvJzX,OAAO2H,QAAQ8P,GAAU/a,EAAEgb,MAAMH,EAAUE,GAC3CzX,OAAO+F,iBAAiB0R,GAAU,Wd05D9B,GAAIE,Ecx5DN,OA9EJxW,GA6EiBjB,SAAA,yBAAkCuX,EAAA,yEAA+EA,EAAA,WACvHE,EAAA3X,OAAO2H,SAAQ8P,GAAAta,MAAAwa,EAAW1a,cAMrC+C,OAAO2H,QAAQiQ,GAAKjN,EACpB3K,OAAO2K,WACL0C,YAAa,SAAU6F,EAAU5V,EAAMua,GACrC,GAAI/K,IAAc,IAAS+K,CAE3B,OAzFJ1W,GAwFiBjB,SAAA,qJACNgT,EAAS7F,YAAY/P,GAAOwP,YAAAA,KAErCN,kBAAmB,SAAU0G,GAE3B,MA7FJ/R,GA4FiBjB,SAAA,yFACNgT,EAAS1G,sBAGpB9P,EAAE2V,KAAK,uBAAuB5R,MAAM,KAAM,SAAUhF,EAAGgc,GACrDzX,OAAO2K,UAAU8M,GAAU,SAAUvE,EAAU5V,EAAM2K,EAASmD,EAAQyM,GACpE,GAAI/K,IAAc,IAAS+K,CAE3B,OApGJ1W,GAmGiBjB,SAAA,4CAAqDuX,EAAA,iGAC3DvE,EAASuE,GAAQna,GAAO2K,QAAAA,EAASmD,OAAAA,EAAQ0B,YAAAA,OAMhD,WAAWvO,KAAKuZ,UAAUC,YAC5Brb,EAAEua,UAAUlU,GAAG,SAAU,SAAU,SAAApC,GACjCjE,EAAEiE,EAAI6C,QAAQ3B,QAAQ,YAMtB,IAAU7B,OAAOqX,cAAcW,UACjCtb,EAAE,WAEIA,EAAE,2BAA2Bf,QAC/Be,EAAE,2BAA2BH,WZjHnC,IAAIa,GAAIV,MACJub,EAAa,WANjB9W,EAOejB,SAAS,iHAgBpB1C,EAAc,UASlBd,GAAEwb,OAAS,SAAU5a,EAAM6a,GACzB,GAAItb,EAOJ,IANAob,IACI,gBAAoBhb,WAAU,IAAM,kBAAsBA,WAAU,KACtEJ,EAAUI,UAAU,GACpBkb,EAAWlb,UAAU,IAGnB,kBAAsBkb,GACxB,KAAM,IAAInX,OAAM,mBAElBhB,QAAO2H,QAAQ5E,GAAG1F,EAAUC,GAAOX,EAAMwb,EAAUtb,KAGrDH,EAAEyG,SAAW,SAAU+P,EAAU5V,EAAMV,GAErC,GADAqb,MACM/E,YAhDRqC,IAgD+CrC,YAAoB3D,IAC/D,KAAM,IAAIvO,OAAM,6BAElB,IAAI,gBAAoB1D,IAAQ,kBAAsBV,GACpD,KAAM,IAAIoE,OAAM,mBAElBkS,GAASnQ,GAAG1F,EAAUC,GAAOX,EAAMC,KAGrCF,EAAE4G,YAAc,SAAUhG,EAAMV,GAE9B,GADAqb,IACI,gBAAoB3a,IAAQ,kBAAsBV,GACpD,KAAM,IAAIoE,OAAM,kBAClBhB,QAAO2H,QAAQvE,IAAI/F,EAAUC,GAAOV,EAAGE,yBAGzCJ,EAAE6G,cAAgB,SAAU2P,EAAU5V,GAEpC,GADA2a,MACM/E,YAlERqC,IAkE+CrC,YAAoB3D,IAC/D,KAAM,IAAIvO,OAAM,6BAClBkS,GAAS9P,IAAI/F,EAAUC,KAGzBZ,EAAE0b,eAAiB,SAAU9a,GAC3B2a,IACAjY,OAAO2H,QAAQvE,IAAI/F,EAAUC,IAC7BZ,EAAE,8BAA8B2V,KAAK,WACnC,GAAIa,GAAWxW,EAAED,MAAMoZ,KAAK,UACxB3C,IACFA,EAAS9P,IAAI/F,EAAUC,OAM7BZ,EAAE2b,KAAO,SAAU/a,EAAM4V,GF0gErB,GAAIoF,EEzgENL,IACA,IAAIM,GAAiBrF,YArFvBqC,IAqF6DrC,YAAoB3D,GAC3ExS,EAAOxB,MAAMO,UAAUC,MAAMiB,KAAKC,UAAWsb,EAAgB,EAAI,EACrExb,GAAKG,QAAQG,EAAUC,IAClBib,IACHrF,EAAWlT,OAAO2H,UAEpB2Q,EAAApF,GAASrR,QAAA1E,MAAAmb,EAAAjd,mBAAW0B,IavFtBL,GAAEuJ,QAAO,EAAM0B,GACb6Q,iBACEC,WACE7b,GAAI,SAAU8b,GAKZ,MAAOA,GAAIC,QAAU,KAAOD,EAAIC,OAAS,KAE3CtR,KAAK,GAEPuR,SACEhc,GAAI,SAAU8b,GAEZ,MAAOA,GAAIC,OAAS,KAAOD,EAAIC,QAAU,KAE3CtR,KAAK,IAITwR,kBAAmB,SAAUvb,EAAMV,EAAIyK,EAAK5E,GAO1C,MANAkF,GAAQ6Q,gBAAgBlb,IACtBV,GAAIA,EACJyK,IAAKA,IAAO,EACZ5E,QAASA,OAGJhG,QAKXkL,EAAQD,aAAa,UACnBnC,iBACE,GAAI,SACJkD,UAAa,SACbmQ,QAAW,UACXnW,QAAW,UAGb6D,eAAgB,SAAU5H,EAAO2I,EAAK5E,EAASyQ,GAC7C,GACI4F,GACAC,EAFAlD,KAGApN,EAAYhG,EAAQgG,aAAc,IAAShG,EAAQmW,QAAU,UAAY,UAE7E,IAAI,mBAAuBjR,GAAQ6Q,gBAAgB/P,GACjD,KAAM,IAAIzH,OAAM,0CAA4CyH,EAAY,IAE1EpB,GAAMM,EAAQ6Q,gBAAgB/P,GAAWpB,KAAOA,EAG5CA,EAAI2R,QAAQ,WAAa,GAC3B3R,EAAMA,EAAI5H,QAAQ,UAAWwZ,mBAAmBva,IAEhDmX,EAAK3C,EAASpV,SAASD,KAAK,SAAWqV,EAASpV,SAASD,KAAK,OAASa,CAIzE,IAAIwa,GAAgBxc,EAAEuJ,QAAO,EAAMxD,EAAQA,YAAgBkF,EAAQ6Q,gBAAgB/P,GAAWhG,QAG9FqW,GAAcpc,EAAEuJ,QAAO,MACrBoB,IAAKA,EACLwO,KAAMA,EACNpP,KAAM,OACLyS,GAGHhG,EAASrR,QAAQ,oBAAqBqR,EAAU4F,GAEhDC,EAAMrc,EAAEyc,MAAML,GAGV,mBAAuBnR,GAAQyR,eACjCzR,EAAQyR,gBAGV,IAAIV,GAAM/Q,EAAQyR,aAAaL,GAAOpR,EAAQyR,aAAaL,IAAQrc,EAAE2c,KAAKP,GAEtEQ,EAAY,WACd,GAAIpY,GAASyG,EAAQ6Q,gBAAgB/P,GAAW7L,GAAGI,KAAKkW,EAAUwF,EAAKrR,EAAK5E,EAG5E,OAFKvB,KACHA,EAASxE,EAAE2U,WAAWC,UACjB5U,EAAE8U,KAAKtQ,GAGhB,OAAOwX,GAAIa,KAAKD,EAAWA,IAG7B3S,SAAU,KAGZgB,EAAQ5E,GAAG,cAAe,WACxB4E,EAAQyR,kBAGVpZ,OAAO6W,cAAcgC,kBAAoB,WAEvC,MADAvB,cAAapX,SAAS,4HACfyH,EAAQkR,kBAAA1b,MAARwK,EAA6B1K,YCpGtC0K,EAAQO,YAAY,MAClBY,eAAgB,kCAChBrC,MACES,MAAc,sCACdG,IAAc,oCACd1C,OAAc,uCACdF,QAAc,wCACd0C,OAAc,+BACdC,SAAc,sCAEhB6B,SAAgB,kCAChBC,SAAgB,0BAChBa,QAAgB,kCAChBI,IAAgB,oDAChB1C,IAAgB,kDAChBH,MAAgB,0CAChB0C,UAAgB,iEAChBE,UAAgB,iEAChBvO,OAAgB,gFAChByO,SAAgB,uCAChBC,SAAgB,uCAChBC,MAAgB,6CAChBC,QAAgB,mCAGlB5C,EAAQC,UAAU,KC7BlB,IAAArL,GAAAoL,ChBuzEE,OAAOpL","file":"parsley.min.js","sourcesContent":[null,"(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :\n typeof define === 'function' && define.amd ? define(['jquery'], factory) :\n global.parsley = factory(global.$)\n}(this, function ($) { 'use strict';\n\n var globalID = 1;\n var pastWarnings = {};\n\n var ParsleyUtils__ParsleyUtils = {\n // Parsley DOM-API\n // returns object from dom attributes and values\n attr: function ($element, namespace, obj) {\n var i;\n var attribute;\n var attributes;\n var regex = new RegExp('^' + namespace, 'i');\n\n if ('undefined' === typeof obj)\n obj = {};\n else {\n // Clear all own properties. This won't affect prototype's values\n for (i in obj) {\n if (obj.hasOwnProperty(i))\n delete obj[i];\n }\n }\n\n if ('undefined' === typeof $element || 'undefined' === typeof $element[0])\n return obj;\n\n attributes = $element[0].attributes;\n for (i = attributes.length; i--; ) {\n attribute = attributes[i];\n\n if (attribute && attribute.specified && regex.test(attribute.name)) {\n obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);\n }\n }\n\n return obj;\n },\n\n checkAttr: function ($element, namespace, checkAttr) {\n return $element.is('[' + namespace + checkAttr + ']');\n },\n\n setAttr: function ($element, namespace, attr, value) {\n $element[0].setAttribute(this.dasherize(namespace + attr), String(value));\n },\n\n generateID: function () {\n return '' + globalID++;\n },\n\n /** Third party functions **/\n // Zepto deserialize function\n deserializeValue: function (value) {\n var num;\n\n try {\n return value ?\n value == \"true\" ||\n (value == \"false\" ? false :\n value == \"null\" ? null :\n !isNaN(num = Number(value)) ? num :\n /^[\\[\\{]/.test(value) ? $.parseJSON(value) :\n value)\n : value;\n } catch (e) { return value; }\n },\n\n // Zepto camelize function\n camelize: function (str) {\n return str.replace(/-+(.)?/g, function (match, chr) {\n return chr ? chr.toUpperCase() : '';\n });\n },\n\n // Zepto dasherize function\n dasherize: function (str) {\n return str.replace(/::/g, '/')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/_/g, '-')\n .toLowerCase();\n },\n\n warn: function () {\n if (window.console && 'function' === typeof window.console.warn)\n window.console.warn(...arguments);\n },\n\n warnOnce: function(msg) {\n if (!pastWarnings[msg]) {\n pastWarnings[msg] = true;\n this.warn(...arguments);\n }\n },\n\n _resetWarnings: function () {\n pastWarnings = {};\n },\n\n trimString: function(string) {\n return string.replace(/^\\s+|\\s+$/g, '');\n },\n\n namespaceEvents: function(events, namespace) {\n events = this.trimString(events || '').split(/\\s+/);\n if (!events[0])\n return '';\n return $.map(events, evt => { return `${evt}.${namespace}`; }).join(' ');\n },\n\n // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill\n objectCreate: Object.create || (function () {\n var Object = function () {};\n return function (prototype) {\n if (arguments.length > 1) {\n throw Error('Second argument not supported');\n }\n if (typeof prototype != 'object') {\n throw TypeError('Argument must be an object');\n }\n Object.prototype = prototype;\n var result = new Object();\n Object.prototype = null;\n return result;\n };\n })()\n };\n\n var ParsleyUtils__default = ParsleyUtils__ParsleyUtils;\n\n // All these options could be overriden and specified directly in DOM using\n // `data-parsley-` default DOM-API\n // eg: `inputs` can be set in DOM using `data-parsley-inputs=\"input, textarea\"`\n // eg: `data-parsley-stop-on-first-failing-constraint=\"false\"`\n\n var ParsleyDefaults = {\n // ### General\n\n // Default data-namespace for DOM API\n namespace: 'data-parsley-',\n\n // Supported inputs by default\n inputs: 'input, textarea, select',\n\n // Excluded inputs by default\n excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',\n\n // Stop validating field on highest priority failing constraint\n priorityEnabled: true,\n\n // ### Field only\n\n // identifier used to group together inputs (e.g. radio buttons...)\n multiple: null,\n\n // identifier (or array of identifiers) used to validate only a select group of inputs\n group: null,\n\n // ### UI\n // Enable\\Disable error messages\n uiEnabled: true,\n\n // Key events threshold before validation\n validationThreshold: 3,\n\n // Focused field on form validation error. 'first'|'last'|'none'\n focus: 'first',\n\n // event(s) that will trigger validation before first failure. eg: `input`...\n trigger: false,\n\n // event(s) that will trigger validation after first failure.\n triggerAfterFailure: 'input',\n\n // Class that would be added on every failing validation Parsley field\n errorClass: 'parsley-error',\n\n // Same for success validation\n successClass: 'parsley-success',\n\n // Return the `$element` that will receive these above success or error classes\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n classHandler: function (ParsleyField) {},\n\n // Return the `$element` where errors will be appended\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n errorsContainer: function (ParsleyField) {},\n\n // ul elem that would receive errors' list\n errorsWrapper: '
        ',\n\n // li elem that would receive error message\n errorTemplate: '
      • '\n };\n\n var ParsleyAbstract = function () {};\n\n ParsleyAbstract.prototype = {\n asyncSupport: true, // Deprecated\n\n actualizeOptions: function () {\n ParsleyUtils__default.attr(this.$element, this.options.namespace, this.domOptions);\n if (this.parent && this.parent.actualizeOptions)\n this.parent.actualizeOptions();\n return this;\n },\n\n _resetOptions: function (initOptions) {\n this.domOptions = ParsleyUtils__default.objectCreate(this.parent.options);\n this.options = ParsleyUtils__default.objectCreate(this.domOptions);\n // Shallow copy of ownProperties of initOptions:\n for (var i in initOptions) {\n if (initOptions.hasOwnProperty(i))\n this.options[i] = initOptions[i];\n }\n this.actualizeOptions();\n },\n\n _listeners: null,\n\n // Register a callback for the given event name\n // Callback is called with context as the first argument and the `this`\n // The context is the current parsley instance, or window.Parsley if global\n // A return value of `false` will interrupt the calls\n on: function (name, fn) {\n this._listeners = this._listeners || {};\n var queue = this._listeners[name] = this._listeners[name] || [];\n queue.push(fn);\n\n return this;\n },\n\n // Deprecated. Use `on` instead\n subscribe: function(name, fn) {\n $.listenTo(this, name.toLowerCase(), fn);\n },\n\n // Unregister a callback (or all if none is given) for the given event name\n off: function (name, fn) {\n var queue = this._listeners && this._listeners[name];\n if (queue) {\n if (!fn) {\n delete this._listeners[name];\n } else {\n for (var i = queue.length; i--; )\n if (queue[i] === fn)\n queue.splice(i, 1);\n }\n }\n return this;\n },\n\n // Deprecated. Use `off`\n unsubscribe: function(name, fn) {\n $.unsubscribeTo(this, name.toLowerCase());\n },\n\n // Trigger an event of the given name\n // A return value of `false` interrupts the callback chain\n // Returns false if execution was interrupted\n trigger: function (name, target, extraArg) {\n target = target || this;\n var queue = this._listeners && this._listeners[name];\n var result;\n var parentResult;\n if (queue) {\n for (var i = queue.length; i--; ) {\n result = queue[i].call(target, target, extraArg);\n if (result === false) return result;\n }\n }\n if (this.parent) {\n return this.parent.trigger(name, target, extraArg);\n }\n return true;\n },\n\n // Reset UI\n reset: function () {\n // Field case: just emit a reset event for UI\n if ('ParsleyForm' !== this.__class__) {\n this._resetUI();\n return this._trigger('reset');\n }\n\n // Form case: emit a reset event for each field\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].reset();\n\n this._trigger('reset');\n },\n\n // Destroy Parsley instance (+ UI)\n destroy: function () {\n // Field case: emit destroy event to clean UI and then destroy stored instance\n this._destroyUI();\n if ('ParsleyForm' !== this.__class__) {\n this.$element.removeData('Parsley');\n this.$element.removeData('ParsleyFieldMultiple');\n this._trigger('destroy');\n\n return;\n }\n\n // Form case: destroy all its fields and then destroy stored instance\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].destroy();\n\n this.$element.removeData('Parsley');\n this._trigger('destroy');\n },\n\n asyncIsValid: function (group, force) {\n ParsleyUtils__default.warnOnce(\"asyncIsValid is deprecated; please use whenValid instead\");\n return this.whenValid({group, force});\n },\n\n _findRelated: function () {\n return this.options.multiple ?\n this.parent.$element.find(`[${this.options.namespace}multiple=\"${this.options.multiple}\"]`)\n : this.$element;\n }\n };\n\n var requirementConverters = {\n string: function(string) {\n return string;\n },\n integer: function(string) {\n if (isNaN(string))\n throw 'Requirement is not an integer: \"' + string + '\"';\n return parseInt(string, 10);\n },\n number: function(string) {\n if (isNaN(string))\n throw 'Requirement is not a number: \"' + string + '\"';\n return parseFloat(string);\n },\n reference: function(string) { // Unused for now\n var result = $(string);\n if (result.length === 0)\n throw 'No such reference: \"' + string + '\"';\n return result;\n },\n boolean: function(string) {\n return string !== 'false';\n },\n object: function(string) {\n return ParsleyUtils__default.deserializeValue(string);\n },\n regexp: function(regexp) {\n var flags = '';\n\n // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern\n if (/^\\/.*\\/(?:[gimy]*)$/.test(regexp)) {\n // Replace the regexp literal string with the first match group: ([gimy]*)\n // If no flag is present, this will be a blank string\n flags = regexp.replace(/.*\\/([gimy]*)$/, '$1');\n // Again, replace the regexp literal string with the first match group:\n // everything excluding the opening and closing slashes and the flags\n regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');\n } else {\n // Anchor regexp:\n regexp = '^' + regexp + '$';\n }\n return new RegExp(regexp, flags);\n }\n };\n\n var convertArrayRequirement = function(string, length) {\n var m = string.match(/^\\s*\\[(.*)\\]\\s*$/);\n if (!m)\n throw 'Requirement is not an array: \"' + string + '\"';\n var values = m[1].split(',').map(ParsleyUtils__default.trimString);\n if (values.length !== length)\n throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed';\n return values;\n };\n\n var convertRequirement = function(requirementType, string) {\n var converter = requirementConverters[requirementType || 'string'];\n if (!converter)\n throw 'Unknown requirement specification: \"' + requirementType + '\"';\n return converter(string);\n };\n\n var convertExtraOptionRequirement = function(requirementSpec, string, extraOptionReader) {\n var main = null;\n var extra = {};\n for (var key in requirementSpec) {\n if (key) {\n var value = extraOptionReader(key);\n if ('string' === typeof value)\n value = convertRequirement(requirementSpec[key], value);\n extra[key] = value;\n } else {\n main = convertRequirement(requirementSpec[key], string);\n }\n }\n return [main, extra];\n };\n\n // A Validator needs to implement the methods `validate` and `parseRequirements`\n\n var ParsleyValidator = function(spec) {\n $.extend(true, this, spec);\n };\n\n ParsleyValidator.prototype = {\n // Returns `true` iff the given `value` is valid according the given requirements.\n validate: function(value, requirementFirstArg) {\n if (this.fn) { // Legacy style validator\n\n if (arguments.length > 3) // If more args then value, requirement, instance...\n requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest\n return this.fn.call(this, value, requirementFirstArg);\n }\n\n if ($.isArray(value)) {\n if (!this.validateMultiple)\n throw 'Validator `' + this.name + '` does not handle multiple values';\n return this.validateMultiple(...arguments);\n } else {\n if (this.validateNumber) {\n if (isNaN(value))\n return false;\n arguments[0] = parseFloat(arguments[0]);\n return this.validateNumber(...arguments);\n }\n if (this.validateString) {\n return this.validateString(...arguments);\n }\n throw 'Validator `' + this.name + '` only handles multiple values';\n }\n },\n\n // Parses `requirements` into an array of arguments,\n // according to `this.requirementType`\n parseRequirements: function(requirements, extraOptionReader) {\n if ('string' !== typeof requirements) {\n // Assume requirement already parsed\n // but make sure we return an array\n return $.isArray(requirements) ? requirements : [requirements];\n }\n var type = this.requirementType;\n if ($.isArray(type)) {\n var values = convertArrayRequirement(requirements, type.length);\n for (var i = 0; i < values.length; i++)\n values[i] = convertRequirement(type[i], values[i]);\n return values;\n } else if ($.isPlainObject(type)) {\n return convertExtraOptionRequirement(type, requirements, extraOptionReader);\n } else {\n return [convertRequirement(type, requirements)];\n }\n },\n // Defaults:\n requirementType: 'string',\n\n priority: 2\n\n };\n\n var ParsleyValidatorRegistry = function (validators, catalog) {\n this.__class__ = 'ParsleyValidatorRegistry';\n\n // Default Parsley locale is en\n this.locale = 'en';\n\n this.init(validators || {}, catalog || {});\n };\n\n var typeRegexes = {\n email: /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$/i,\n\n // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers\n number: /^-?(\\d*\\.)?\\d+(e[-+]?\\d+)?$/i,\n\n integer: /^-?\\d+$/,\n\n digits: /^\\d+$/,\n\n alphanum: /^\\w+$/i,\n\n url: new RegExp(\n \"^\" +\n // protocol identifier\n \"(?:(?:https?|ftp)://)?\" + // ** mod: make scheme optional\n // user:pass authentication\n \"(?:\\\\S+(?::\\\\S*)?@)?\" +\n \"(?:\" +\n // IP address exclusion\n // private & local networks\n // \"(?!(?:10|127)(?:\\\\.\\\\d{1,3}){3})\" + // ** mod: allow local networks\n // \"(?!(?:169\\\\.254|192\\\\.168)(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // \"(?!172\\\\.(?:1[6-9]|2\\\\d|3[0-1])(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // IP address dotted notation octets\n // excludes loopback network 0.0.0.0\n // excludes reserved space >= 224.0.0.0\n // excludes network & broacast addresses\n // (first & last IP address of each class)\n \"(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])\" +\n \"(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}\" +\n \"(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))\" +\n \"|\" +\n // host name\n \"(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)\" +\n // domain name\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*\" +\n // TLD identifier\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))\" +\n \")\" +\n // port number\n \"(?::\\\\d{2,5})?\" +\n // resource path\n \"(?:/\\\\S*)?\" +\n \"$\", 'i'\n )\n };\n typeRegexes.range = typeRegexes.number;\n\n // See http://stackoverflow.com/a/10454560/8279\n var decimalPlaces = num => {\n var match = ('' + num).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n if (!match) { return 0; }\n return Math.max(\n 0,\n // Number of digits right of decimal point.\n (match[1] ? match[1].length : 0) -\n // Adjust for scientific notation.\n (match[2] ? +match[2] : 0));\n };\n\n ParsleyValidatorRegistry.prototype = {\n init: function (validators, catalog) {\n this.catalog = catalog;\n // Copy prototype's validators:\n this.validators = $.extend({}, this.validators);\n\n for (var name in validators)\n this.addValidator(name, validators[name].fn, validators[name].priority);\n\n window.Parsley.trigger('parsley:validator:init');\n },\n\n // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n\n setLocale: function (locale) {\n if ('undefined' === typeof this.catalog[locale])\n throw new Error(locale + ' is not available in the catalog');\n\n this.locale = locale;\n\n return this;\n },\n\n // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`\n addCatalog: function (locale, messages, set) {\n if ('object' === typeof messages)\n this.catalog[locale] = messages;\n\n if (true === set)\n return this.setLocale(locale);\n\n return this;\n },\n\n // Add a specific message for a given constraint in a given locale\n addMessage: function (locale, name, message) {\n if ('undefined' === typeof this.catalog[locale])\n this.catalog[locale] = {};\n\n this.catalog[locale][name] = message;\n\n return this;\n },\n\n // Add messages for a given locale\n addMessages: function (locale, nameMessageObject) {\n for (var name in nameMessageObject)\n this.addMessage(locale, name, nameMessageObject[name]);\n\n return this;\n },\n\n // Add a new validator\n //\n // addValidator('custom', {\n // requirementType: ['integer', 'integer'],\n // validateString: function(value, from, to) {},\n // priority: 22,\n // messages: {\n // en: \"Hey, that's no good\",\n // fr: \"Aye aye, pas bon du tout\",\n // }\n // })\n //\n // Old API was addValidator(name, function, priority)\n //\n addValidator: function (name, arg1, arg2) {\n if (this.validators[name])\n ParsleyUtils__default.warn('Validator \"' + name + '\" is already defined.');\n else if (ParsleyDefaults.hasOwnProperty(name)) {\n ParsleyUtils__default.warn('\"' + name + '\" is a restricted keyword and is not a valid validator name.');\n return;\n }\n return this._setValidator(...arguments);\n },\n\n updateValidator: function (name, arg1, arg2) {\n if (!this.validators[name]) {\n ParsleyUtils__default.warn('Validator \"' + name + '\" is not already defined.');\n return this.addValidator(...arguments);\n }\n return this._setValidator(this, arguments);\n },\n\n removeValidator: function (name) {\n if (!this.validators[name])\n ParsleyUtils__default.warn('Validator \"' + name + '\" is not defined.');\n\n delete this.validators[name];\n\n return this;\n },\n\n _setValidator: function (name, validator, priority) {\n if ('object' !== typeof validator) {\n // Old style validator, with `fn` and `priority`\n validator = {\n fn: validator,\n priority: priority\n };\n }\n if (!validator.validate) {\n validator = new ParsleyValidator(validator);\n }\n this.validators[name] = validator;\n\n for (var locale in validator.messages || {})\n this.addMessage(locale, name, validator.messages[locale]);\n\n return this;\n },\n\n getErrorMessage: function (constraint) {\n var message;\n\n // Type constraints are a bit different, we have to match their requirements too to find right error message\n if ('type' === constraint.name) {\n var typeMessages = this.catalog[this.locale][constraint.name] || {};\n message = typeMessages[constraint.requirements];\n } else\n message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);\n\n return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;\n },\n\n // Kind of light `sprintf()` implementation\n formatMessage: function (string, parameters) {\n if ('object' === typeof parameters) {\n for (var i in parameters)\n string = this.formatMessage(string, parameters[i]);\n\n return string;\n }\n\n return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';\n },\n\n // Here is the Parsley default validators list.\n // A validator is an object with the following key values:\n // - priority: an integer\n // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these\n // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise\n // Alternatively, a validator can be a function that returns such an object\n //\n validators: {\n notblank: {\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 2\n },\n required: {\n validateMultiple: function(values) {\n return values.length > 0;\n },\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 512\n },\n type: {\n validateString: function(value, type, {step = '1', base = 0} = {}) {\n var regex = typeRegexes[type];\n if (!regex) {\n throw new Error('validator type `' + type + '` is not supported');\n }\n if (!regex.test(value))\n return false;\n if ('number' === type) {\n if (!/^any$/i.test(step || '')) {\n var nb = Number(value);\n var decimals = Math.max(decimalPlaces(step), decimalPlaces(base));\n if (decimalPlaces(nb) > decimals) // Value can't have too many decimals\n return false;\n // Be careful of rounding errors by using integers.\n var toInt = f => { return Math.round(f * Math.pow(10, decimals)); };\n if ((toInt(nb) - toInt(base)) % toInt(step) != 0)\n return false;\n }\n }\n return true;\n },\n requirementType: {\n '': 'string',\n step: 'string',\n base: 'number'\n },\n priority: 256\n },\n pattern: {\n validateString: function(value, regexp) {\n return regexp.test(value);\n },\n requirementType: 'regexp',\n priority: 64\n },\n minlength: {\n validateString: function (value, requirement) {\n return value.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxlength: {\n validateString: function (value, requirement) {\n return value.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n length: {\n validateString: function (value, min, max) {\n return value.length >= min && value.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n mincheck: {\n validateMultiple: function (values, requirement) {\n return values.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxcheck: {\n validateMultiple: function (values, requirement) {\n return values.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n check: {\n validateMultiple: function (values, min, max) {\n return values.length >= min && values.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n min: {\n validateNumber: function (value, requirement) {\n return value >= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n max: {\n validateNumber: function (value, requirement) {\n return value <= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n range: {\n validateNumber: function (value, min, max) {\n return value >= min && value <= max;\n },\n requirementType: ['number', 'number'],\n priority: 30\n },\n equalto: {\n validateString: function (value, refOrValue) {\n var $reference = $(refOrValue);\n if ($reference.length)\n return value === $reference.val();\n else\n return value === refOrValue;\n },\n priority: 256\n }\n }\n };\n\n var ParsleyUI = {};\n\n var diffResults = function (newResult, oldResult, deep) {\n var added = [];\n var kept = [];\n\n for (var i = 0; i < newResult.length; i++) {\n var found = false;\n\n for (var j = 0; j < oldResult.length; j++)\n if (newResult[i].assert.name === oldResult[j].assert.name) {\n found = true;\n break;\n }\n\n if (found)\n kept.push(newResult[i]);\n else\n added.push(newResult[i]);\n }\n\n return {\n kept: kept,\n added: added,\n removed: !deep ? diffResults(oldResult, newResult, true).added : []\n };\n };\n\n ParsleyUI.Form = {\n\n _actualizeTriggers: function () {\n this.$element.on('submit.Parsley', evt => { this.onSubmitValidate(evt); });\n this.$element.on('click.Parsley', 'input[type=\"submit\"], button[type=\"submit\"]', evt => { this.onSubmitButton(evt); });\n\n // UI could be disabled\n if (false === this.options.uiEnabled)\n return;\n\n this.$element.attr('novalidate', '');\n },\n\n focus: function () {\n this._focusedField = null;\n\n if (true === this.validationResult || 'none' === this.options.focus)\n return null;\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i];\n if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) {\n this._focusedField = field.$element;\n if ('first' === this.options.focus)\n break;\n }\n }\n\n if (null === this._focusedField)\n return null;\n\n return this._focusedField.focus();\n },\n\n _destroyUI: function () {\n // Reset all event listeners\n this.$element.off('.Parsley');\n }\n\n };\n\n ParsleyUI.Field = {\n\n _reflowUI: function () {\n this._buildUI();\n\n // If this field doesn't have an active UI don't bother doing something\n if (!this._ui)\n return;\n\n // Diff between two validation results\n var diff = diffResults(this.validationResult, this._ui.lastValidationResult);\n\n // Then store current validation result for next reflow\n this._ui.lastValidationResult = this.validationResult;\n\n // Handle valid / invalid / none field class\n this._manageStatusClass();\n\n // Add, remove, updated errors messages\n this._manageErrorsMessages(diff);\n\n // Triggers impl\n this._actualizeTriggers();\n\n // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user\n if ((diff.kept.length || diff.added.length) && !this._failedOnce) {\n this._failedOnce = true;\n this._actualizeTriggers();\n }\n },\n\n // Returns an array of field's error message(s)\n getErrorsMessages: function () {\n // No error message, field is valid\n if (true === this.validationResult)\n return [];\n\n var messages = [];\n\n for (var i = 0; i < this.validationResult.length; i++)\n messages.push(this.validationResult[i].errorMessage ||\n this._getErrorMessage(this.validationResult[i].assert));\n\n return messages;\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n addError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._addError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n updateError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._updateError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n removeError: function (name, {updateClass = true} = {}) {\n this._buildUI();\n this._removeError(name);\n\n // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult\n // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.\n if (updateClass)\n this._manageStatusClass();\n },\n\n _manageStatusClass: function () {\n if (this.hasConstraints() && this.needsValidation() && true === this.validationResult)\n this._successClass();\n else if (this.validationResult.length > 0)\n this._errorClass();\n else\n this._resetClass();\n },\n\n _manageErrorsMessages: function (diff) {\n if ('undefined' !== typeof this.options.errorsMessagesDisabled)\n return;\n\n // Case where we have errorMessage option that configure an unique field error message, regardless failing validators\n if ('undefined' !== typeof this.options.errorMessage) {\n if ((diff.added.length || diff.kept.length)) {\n this._insertErrorWrapper();\n\n if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length)\n this._ui.$errorsWrapper\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-custom-error-message')\n );\n\n return this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-custom-error-message')\n .html(this.options.errorMessage);\n }\n\n return this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-custom-error-message')\n .remove();\n }\n\n // Show, hide, update failing constraints messages\n for (var i = 0; i < diff.removed.length; i++)\n this._removeError(diff.removed[i].assert.name);\n\n for (i = 0; i < diff.added.length; i++)\n this._addError(diff.added[i].assert.name, {message: diff.added[i].errorMessage, assert: diff.added[i].assert});\n\n for (i = 0; i < diff.kept.length; i++)\n this._updateError(diff.kept[i].assert.name, {message: diff.kept[i].errorMessage, assert: diff.kept[i].assert});\n },\n\n\n _addError: function (name, {message, assert}) {\n this._insertErrorWrapper();\n this._ui.$errorsWrapper\n .addClass('filled')\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-' + name)\n .html(message || this._getErrorMessage(assert))\n );\n },\n\n _updateError: function (name, {message, assert}) {\n this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-' + name)\n .html(message || this._getErrorMessage(assert));\n },\n\n _removeError: function (name) {\n this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-' + name)\n .remove();\n },\n\n _getErrorMessage: function (constraint) {\n var customConstraintErrorMessage = constraint.name + 'Message';\n\n if ('undefined' !== typeof this.options[customConstraintErrorMessage])\n return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements);\n\n return window.Parsley.getErrorMessage(constraint);\n },\n\n _buildUI: function () {\n // UI could be already built or disabled\n if (this._ui || false === this.options.uiEnabled)\n return;\n\n var _ui = {};\n\n // Give field its Parsley id in DOM\n this.$element.attr(this.options.namespace + 'id', this.__id__);\n\n /** Generate important UI elements and store them in this **/\n // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes\n _ui.$errorClassHandler = this._manageClassHandler();\n\n // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer\n _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__);\n _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId);\n\n // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly\n _ui.lastValidationResult = [];\n _ui.validationInformationVisible = false;\n\n // Store it in this for later\n this._ui = _ui;\n },\n\n // Determine which element will have `parsley-error` and `parsley-success` classes\n _manageClassHandler: function () {\n // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`\n if ('string' === typeof this.options.classHandler && $(this.options.classHandler).length)\n return $(this.options.classHandler);\n\n // Class handled could also be determined by function given in Parsley options\n var $handler = this.options.classHandler.call(this, this);\n\n // If this function returned a valid existing DOM element, go for it\n if ('undefined' !== typeof $handler && $handler.length)\n return $handler;\n\n // Otherwise, if simple element (input, texatrea, select...) it will perfectly host the classes\n if (!this.options.multiple || this.$element.is('select'))\n return this.$element;\n\n // But if multiple element (radio, checkbox), that would be their parent\n return this.$element.parent();\n },\n\n _insertErrorWrapper: function () {\n var $errorsContainer;\n\n // Nothing to do if already inserted\n if (0 !== this._ui.$errorsWrapper.parent().length)\n return this._ui.$errorsWrapper.parent();\n\n if ('string' === typeof this.options.errorsContainer) {\n if ($(this.options.errorsContainer).length)\n return $(this.options.errorsContainer).append(this._ui.$errorsWrapper);\n else\n ParsleyUtils__default.warn('The errors container `' + this.options.errorsContainer + '` does not exist in DOM');\n } else if ('function' === typeof this.options.errorsContainer)\n $errorsContainer = this.options.errorsContainer.call(this, this);\n\n if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)\n return $errorsContainer.append(this._ui.$errorsWrapper);\n\n var $from = this.$element;\n if (this.options.multiple)\n $from = $from.parent();\n return $from.after(this._ui.$errorsWrapper);\n },\n\n _actualizeTriggers: function () {\n var $toBind = this._findRelated();\n\n // Remove Parsley events already bound on this field\n $toBind.off('.Parsley');\n if (this._failedOnce)\n $toBind.on(ParsleyUtils__default.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), () => {\n this.validate();\n });\n else {\n $toBind.on(ParsleyUtils__default.namespaceEvents(this.options.trigger, 'Parsley'), event => {\n this._eventValidate(event);\n });\n }\n },\n\n _eventValidate: function (event) {\n // For keyup, keypress, keydown, input... events that could be a little bit obstrusive\n // do not validate if val length < min threshold on first validation. Once field have been validated once and info\n // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.\n if (/key|input/.test(event.type))\n if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold)\n return;\n\n this.validate();\n },\n\n _resetUI: function () {\n // Reset all event listeners\n this._failedOnce = false;\n this._actualizeTriggers();\n\n // Nothing to do if UI never initialized for this field\n if ('undefined' === typeof this._ui)\n return;\n\n // Reset all errors' li\n this._ui.$errorsWrapper\n .removeClass('filled')\n .children()\n .remove();\n\n // Reset validation class\n this._resetClass();\n\n // Reset validation flags and last validation result\n this._ui.lastValidationResult = [];\n this._ui.validationInformationVisible = false;\n },\n\n _destroyUI: function () {\n this._resetUI();\n\n if ('undefined' !== typeof this._ui)\n this._ui.$errorsWrapper.remove();\n\n delete this._ui;\n },\n\n _successClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass);\n },\n _errorClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass);\n },\n _resetClass: function () {\n this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass);\n }\n };\n\n var ParsleyForm = function (element, domOptions, options) {\n this.__class__ = 'ParsleyForm';\n this.__id__ = ParsleyUtils__default.generateID();\n\n this.$element = $(element);\n this.domOptions = domOptions;\n this.options = options;\n this.parent = window.Parsley;\n\n this.fields = [];\n this.validationResult = null;\n };\n\n var ParsleyForm__statusMapping = {pending: null, resolved: true, rejected: false};\n\n ParsleyForm.prototype = {\n onSubmitValidate: function (event) {\n // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior\n if (true === event.parsley)\n return;\n\n // If we didn't come here through a submit button, use the first one in the form\n var $submitSource = this._$submitSource || this.$element.find('input[type=\"submit\"], button[type=\"submit\"]').first();\n this._$submitSource = null;\n this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);\n if ($submitSource.is('[formnovalidate]'))\n return;\n\n var promise = this.whenValidate({event});\n\n if ('resolved' === promise.state() && false !== this._trigger('submit')) {\n // All good, let event go through. We make this distinction because browsers\n // differ in their handling of `submit` being called from inside a submit event [#1047]\n } else {\n // Rejected or pending: cancel this submit\n event.stopImmediatePropagation();\n event.preventDefault();\n if ('pending' === promise.state())\n promise.done(() => { this._submit($submitSource); });\n }\n },\n\n onSubmitButton: function(event) {\n this._$submitSource = $(event.target);\n },\n // internal\n // _submit submits the form, this time without going through the validations.\n // Care must be taken to \"fake\" the actual submit button being clicked.\n _submit: function ($submitSource) {\n if (false === this._trigger('submit'))\n return;\n // Add submit button's data\n if ($submitSource) {\n var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);\n if (0 === $synthetic.length)\n $synthetic = $('').appendTo(this.$element);\n $synthetic.attr({\n name: $submitSource.attr('name'),\n value: $submitSource.attr('value')\n });\n }\n\n this.$element.trigger($.extend($.Event('submit'), {parsley: true}));\n },\n\n // Performs validation on fields while triggering events.\n // @returns `true` if all validations succeeds, `false`\n // if a failure is immediately detected, or `null`\n // if dependant on a promise.\n // Consider using `whenValidate` instead.\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');\n var [group, force, event] = arguments;\n options = {group, force, event};\n }\n return ParsleyForm__statusMapping[ this.whenValidate(options).state() ];\n },\n\n whenValidate: function ({group, force, event} = {}) {\n this.submitEvent = event;\n if (event) {\n this.submitEvent = $.extend({}, event, {preventDefault: () => {\n ParsleyUtils__default.warnOnce(\"Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`\");\n this.validationResult = false;\n }});\n }\n this.validationResult = true;\n\n // fire validate event to eventually modify things before very validation\n this._trigger('validate');\n\n // Refresh form DOM options and form's fields that could have changed\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValidate({force, group});\n });\n });\n\n var promiseBasedOnValidationResult = () => {\n var r = $.Deferred();\n if (false === this.validationResult)\n r.reject();\n return r.resolve().promise();\n };\n\n return $.when(...promises)\n .done( () => { this._trigger('success'); })\n .fail( () => {\n this.validationResult = false;\n this.focus();\n this._trigger('error');\n })\n .always(() => { this._trigger('validated'); })\n .pipe( promiseBasedOnValidationResult, promiseBasedOnValidationResult);\n },\n\n // Iterate over refreshed fields, and stop on first failure.\n // Returns `true` if all fields are valid, `false` if a failure is detected\n // or `null` if the result depends on an unresolved promise.\n // Prefer using `whenValid` instead.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');\n var [group, force] = arguments;\n options = {group, force};\n }\n return ParsleyForm__statusMapping[ this.whenValid(options).state() ];\n },\n\n // Iterate over refreshed fields and validate them.\n // Returns a promise.\n // A validation that immediately fails will interrupt the validations.\n whenValid: function ({group, force} = {}) {\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValid({group, force});\n });\n });\n return $.when(...promises);\n },\n\n _refreshFields: function () {\n return this.actualizeOptions()._bindFields();\n },\n\n _bindFields: function () {\n var oldFields = this.fields;\n\n this.fields = [];\n this.fieldsMappedById = {};\n\n this._withoutReactualizingFormOptions(() => {\n this.$element\n .find(this.options.inputs)\n .not(this.options.excluded)\n .each((_, element) => {\n var fieldInstance = new window.Parsley.Factory(element, {}, this);\n\n // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children\n if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && (true !== fieldInstance.options.excluded))\n if ('undefined' === typeof this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {\n this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;\n this.fields.push(fieldInstance);\n }\n });\n\n $(oldFields).not(this.fields).each((_, field) => {\n field._trigger('reset');\n });\n });\n return this;\n },\n\n // Internal only.\n // Looping on a form's fields to do validation or similar\n // will trigger reactualizing options on all of them, which\n // in turn will reactualize the form's options.\n // To avoid calling actualizeOptions so many times on the form\n // for nothing, _withoutReactualizingFormOptions temporarily disables\n // the method actualizeOptions on this form while `fn` is called.\n _withoutReactualizingFormOptions: function (fn) {\n var oldActualizeOptions = this.actualizeOptions;\n this.actualizeOptions = function () { return this; };\n var result = fn();\n this.actualizeOptions = oldActualizeOptions;\n return result;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n // Returns true iff event is not interrupted and default not prevented.\n _trigger: function (eventName) {\n return this.trigger('form:' + eventName);\n }\n\n };\n\n var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {\n if (!/ParsleyField/.test(parsleyField.__class__))\n throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');\n\n var validatorSpec = window.Parsley._validatorRegistry.validators[name];\n var validator = new ParsleyValidator(validatorSpec);\n\n $.extend(this, {\n validator: validator,\n name: name,\n requirements: requirements,\n priority: priority || parsleyField.options[name + 'Priority'] || validator.priority,\n isDomConstraint: true === isDomConstraint\n });\n this._parseRequirements(parsleyField.options);\n };\n\n var capitalize = function(str) {\n var cap = str[0].toUpperCase();\n return cap + str.slice(1);\n };\n\n ConstraintFactory.prototype = {\n validate: function(value, instance) {\n var args = this.requirementList.slice(0); // Make copy\n args.unshift(value);\n args.push(instance);\n return this.validator.validate.apply(this.validator, args);\n },\n\n _parseRequirements: function(options) {\n this.requirementList = this.validator.parseRequirements(this.requirements, key => {\n return options[this.name + capitalize(key)];\n });\n }\n };\n\n var ParsleyField = function (field, domOptions, options, parsleyFormInstance) {\n this.__class__ = 'ParsleyField';\n this.__id__ = ParsleyUtils__default.generateID();\n\n this.$element = $(field);\n\n // Set parent if we have one\n if ('undefined' !== typeof parsleyFormInstance) {\n this.parent = parsleyFormInstance;\n }\n\n this.options = options;\n this.domOptions = domOptions;\n\n // Initialize some properties\n this.constraints = [];\n this.constraintsByName = {};\n this.validationResult = [];\n\n // Bind constraints\n this._bindConstraints();\n };\n\n var parsley_field__statusMapping = {pending: null, resolved: true, rejected: false};\n\n ParsleyField.prototype = {\n // # Public API\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns `true`, an array of the validators that failed, or\n // `null` if validation is not finished. Prefer using whenValidate\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.');\n options = {options};\n }\n var promise = this.whenValidate(options);\n if (!promise) // If excluded with `group` option\n return true;\n switch (promise.state()) {\n case 'pending': return null;\n case 'resolved': return true;\n case 'rejected': return this.validationResult;\n }\n },\n\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if field is not in the given `group`.\n whenValidate: function ({force, group} = {}) {\n // do not validate a field if not the same as given validation group\n this.refreshConstraints();\n if (group && !this._isInGroup(group))\n return;\n\n this.value = this.getValue();\n\n // Field Validate event. `this.value` could be altered for custom needs\n this._trigger('validate');\n\n return this.whenValid({force, value: this.value, _refreshed: true})\n .always(() => { this._reflowUI(); })\n .done(() => { this._trigger('success'); })\n .fail(() => { this._trigger('error'); })\n .always(() => { this._trigger('validated'); });\n },\n\n hasConstraints: function () {\n return 0 !== this.constraints.length;\n },\n\n // An empty optional field does not need validation\n needsValidation: function (value) {\n if ('undefined' === typeof value)\n value = this.getValue();\n\n // If a field is empty and not required, it is valid\n // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators\n if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty)\n return false;\n\n return true;\n },\n\n _isInGroup: function (group) {\n if ($.isArray(this.options.group))\n return -1 !== $.inArray(group, this.options.group);\n return this.options.group === group;\n },\n\n // Just validate field. Do not trigger any event.\n // Returns `true` iff all constraints pass, `false` if there are failures,\n // or `null` if the result can not be determined yet (depends on a promise)\n // See also `whenValid`.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.');\n var [force, value] = arguments;\n options = {force, value};\n }\n var promise = this.whenValid(options);\n if (!promise) // Excluded via `group`\n return true;\n return parsley_field__statusMapping[promise.state()];\n },\n\n // Just validate field. Do not trigger any event.\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if the field is not in the given `group`.\n // The argument `force` will force validation of empty fields.\n // If a `value` is given, it will be validated instead of the value of the input.\n whenValid: function ({force = false, value, group, _refreshed} = {}) {\n // Recompute options and rebind constraints to have latest changes\n if (!_refreshed)\n this.refreshConstraints();\n // do not validate a field if not the same as given validation group\n if (group && !this._isInGroup(group))\n return;\n\n this.validationResult = true;\n\n // A field without constraint is valid\n if (!this.hasConstraints())\n return $.when();\n\n // Value could be passed as argument, needed to add more power to 'parsley:field:validate'\n if ('undefined' === typeof value || null === value)\n value = this.getValue();\n\n if (!this.needsValidation(value) && true !== force)\n return $.when();\n\n var groupedConstraints = this._getGroupedConstraints();\n var promises = [];\n $.each(groupedConstraints, (_, constraints) => {\n // Process one group of constraints at a time, we validate the constraints\n // and combine the promises together.\n var promise = $.when(\n ...$.map(constraints, constraint => this._validateConstraint(value, constraint))\n );\n promises.push(promise);\n if (promise.state() === 'rejected')\n return false; // Interrupt processing if a group has already failed\n });\n return $.when.apply($, promises);\n },\n\n // @returns a promise\n _validateConstraint: function(value, constraint) {\n var result = constraint.validate(value, this);\n // Map false to a failed promise\n if (false === result)\n result = $.Deferred().reject();\n // Make sure we return a promise and that we record failures\n return $.when(result).fail(errorMessage => {\n if (true === this.validationResult)\n this.validationResult = [];\n this.validationResult.push({\n assert: constraint,\n errorMessage: 'string' === typeof errorMessage && errorMessage\n });\n });\n },\n\n // @returns Parsley field computed value that could be overrided or configured in DOM\n getValue: function () {\n var value;\n\n // Value could be overriden in DOM or with explicit options\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n value = this.options.value;\n else\n value = this.$element.val();\n\n // Handle wrong DOM or configurations\n if ('undefined' === typeof value || null === value)\n return '';\n\n return this._handleWhitespace(value);\n },\n\n // Actualize options that could have change since previous validation\n // Re-bind accordingly constraints (could be some new, removed or updated)\n refreshConstraints: function () {\n return this.actualizeOptions()._bindConstraints();\n },\n\n /**\n * Add a new constraint to a field\n *\n * @param {String} name\n * @param {Mixed} requirements optional\n * @param {Number} priority optional\n * @param {Boolean} isDomConstraint optional\n */\n addConstraint: function (name, requirements, priority, isDomConstraint) {\n\n if (window.Parsley._validatorRegistry.validators[name]) {\n var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);\n\n // if constraint already exist, delete it and push new version\n if ('undefined' !== this.constraintsByName[constraint.name])\n this.removeConstraint(constraint.name);\n\n this.constraints.push(constraint);\n this.constraintsByName[constraint.name] = constraint;\n }\n\n return this;\n },\n\n // Remove a constraint\n removeConstraint: function (name) {\n for (var i = 0; i < this.constraints.length; i++)\n if (name === this.constraints[i].name) {\n this.constraints.splice(i, 1);\n break;\n }\n delete this.constraintsByName[name];\n return this;\n },\n\n // Update a constraint (Remove + re-add)\n updateConstraint: function (name, parameters, priority) {\n return this.removeConstraint(name)\n .addConstraint(name, parameters, priority);\n },\n\n // # Internals\n\n // Internal only.\n // Bind constraints from config + options + DOM\n _bindConstraints: function () {\n var constraints = [];\n var constraintsByName = {};\n\n // clean all existing DOM constraints to only keep javascript user constraints\n for (var i = 0; i < this.constraints.length; i++)\n if (false === this.constraints[i].isDomConstraint) {\n constraints.push(this.constraints[i]);\n constraintsByName[this.constraints[i].name] = this.constraints[i];\n }\n\n this.constraints = constraints;\n this.constraintsByName = constraintsByName;\n\n // then re-add Parsley DOM-API constraints\n for (var name in this.options)\n this.addConstraint(name, this.options[name], undefined, true);\n\n // finally, bind special HTML5 constraints\n return this._bindHtml5Constraints();\n },\n\n // Internal only.\n // Bind specific HTML5 constraints to be HTML5 compliant\n _bindHtml5Constraints: function () {\n // html5 required\n if (this.$element.hasClass('required') || this.$element.attr('required'))\n this.addConstraint('required', true, undefined, true);\n\n // html5 pattern\n if ('string' === typeof this.$element.attr('pattern'))\n this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);\n\n // range\n if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);\n\n // HTML5 min\n else if ('undefined' !== typeof this.$element.attr('min'))\n this.addConstraint('min', this.$element.attr('min'), undefined, true);\n\n // HTML5 max\n else if ('undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('max', this.$element.attr('max'), undefined, true);\n\n\n // length\n if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);\n\n // HTML5 minlength\n else if ('undefined' !== typeof this.$element.attr('minlength'))\n this.addConstraint('minlength', this.$element.attr('minlength'), undefined, true);\n\n // HTML5 maxlength\n else if ('undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('maxlength', this.$element.attr('maxlength'), undefined, true);\n\n\n // html5 types\n var type = this.$element.attr('type');\n\n if ('undefined' === typeof type)\n return this;\n\n // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise\n if ('number' === type) {\n return this.addConstraint('type', ['number', {\n step: this.$element.attr('step'),\n base: this.$element.attr('min') || this.$element.attr('value')\n }], undefined, true);\n // Regular other HTML5 supported types\n } else if (/^(email|url|range)$/i.test(type)) {\n return this.addConstraint('type', type, undefined, true);\n }\n return this;\n },\n\n // Internal only.\n // Field is required if have required constraint without `false` value\n _isRequired: function () {\n if ('undefined' === typeof this.constraintsByName.required)\n return false;\n\n return false !== this.constraintsByName.required.requirements;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n _trigger: function (eventName) {\n return this.trigger('field:' + eventName);\n },\n\n // Internal only\n // Handles whitespace in a value\n // Use `data-parsley-whitespace=\"squish\"` to auto squish input value\n // Use `data-parsley-whitespace=\"trim\"` to auto trim input value\n _handleWhitespace: function (value) {\n if (true === this.options.trimValue)\n ParsleyUtils__default.warnOnce('data-parsley-trim-value=\"true\" is deprecated, please use data-parsley-whitespace=\"trim\"');\n\n if ('squish' === this.options.whitespace)\n value = value.replace(/\\s{2,}/g, ' ');\n\n if (('trim' === this.options.whitespace) || ('squish' === this.options.whitespace) || (true === this.options.trimValue))\n value = ParsleyUtils__default.trimString(value);\n\n return value;\n },\n\n // Internal only.\n // Returns the constraints, grouped by descending priority.\n // The result is thus an array of arrays of constraints.\n _getGroupedConstraints: function () {\n if (false === this.options.priorityEnabled)\n return [this.constraints];\n\n var groupedConstraints = [];\n var index = {};\n\n // Create array unique of priorities\n for (var i = 0; i < this.constraints.length; i++) {\n var p = this.constraints[i].priority;\n if (!index[p])\n groupedConstraints.push(index[p] = []);\n index[p].push(this.constraints[i]);\n }\n // Sort them by priority DESC\n groupedConstraints.sort(function (a, b) { return b[0].priority - a[0].priority; });\n\n return groupedConstraints;\n }\n\n };\n\n var parsley_field = ParsleyField;\n\n var ParsleyMultiple = function () {\n this.__class__ = 'ParsleyFieldMultiple';\n };\n\n ParsleyMultiple.prototype = {\n // Add new `$element` sibling for multiple field\n addElement: function ($element) {\n this.$elements.push($element);\n\n return this;\n },\n\n // See `ParsleyField.refreshConstraints()`\n refreshConstraints: function () {\n var fieldConstraints;\n\n this.constraints = [];\n\n // Select multiple special treatment\n if (this.$element.is('select')) {\n this.actualizeOptions()._bindConstraints();\n\n return this;\n }\n\n // Gather all constraints for each input in the multiple group\n for (var i = 0; i < this.$elements.length; i++) {\n\n // Check if element have not been dynamically removed since last binding\n if (!$('html').has(this.$elements[i]).length) {\n this.$elements.splice(i, 1);\n continue;\n }\n\n fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;\n\n for (var j = 0; j < fieldConstraints.length; j++)\n this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);\n }\n\n return this;\n },\n\n // See `ParsleyField.getValue()`\n getValue: function () {\n // Value could be overriden in DOM\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n return this.options.value;\n\n // Radio input case\n if (this.$element.is('input[type=radio]'))\n return this._findRelated().filter(':checked').val() || '';\n\n // checkbox input case\n if (this.$element.is('input[type=checkbox]')) {\n var values = [];\n\n this._findRelated().filter(':checked').each(function () {\n values.push($(this).val());\n });\n\n return values;\n }\n\n // Select multiple case\n if (this.$element.is('select') && null === this.$element.val())\n return [];\n\n // Default case that should never happen\n return this.$element.val();\n },\n\n _init: function () {\n this.$elements = [this.$element];\n\n return this;\n }\n };\n\n var ParsleyFactory = function (element, options, parsleyFormInstance) {\n this.$element = $(element);\n\n // If the element has already been bound, returns its saved Parsley instance\n var savedparsleyFormInstance = this.$element.data('Parsley');\n if (savedparsleyFormInstance) {\n\n // If the saved instance has been bound without a ParsleyForm parent and there is one given in this call, add it\n if ('undefined' !== typeof parsleyFormInstance && savedparsleyFormInstance.parent === window.Parsley) {\n savedparsleyFormInstance.parent = parsleyFormInstance;\n savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options);\n }\n\n return savedparsleyFormInstance;\n }\n\n // Parsley must be instantiated with a DOM element or jQuery $element\n if (!this.$element.length)\n throw new Error('You must bind Parsley on an existing element.');\n\n if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)\n throw new Error('Parent instance must be a ParsleyForm instance');\n\n this.parent = parsleyFormInstance || window.Parsley;\n return this.init(options);\n };\n\n ParsleyFactory.prototype = {\n init: function (options) {\n this.__class__ = 'Parsley';\n this.__version__ = '2.3.5';\n this.__id__ = ParsleyUtils__default.generateID();\n\n // Pre-compute options\n this._resetOptions(options);\n\n // A ParsleyForm instance is obviously a `
        ` element but also every node that is not an input and has the `data-parsley-validate` attribute\n if (this.$element.is('form') || (ParsleyUtils__default.checkAttr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))\n return this.bind('parsleyForm');\n\n // Every other element is bound as a `ParsleyField` or `ParsleyFieldMultiple`\n return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField');\n },\n\n isMultiple: function () {\n return (this.$element.is('input[type=radio], input[type=checkbox]')) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));\n },\n\n // Multiples fields are a real nightmare :(\n // Maybe some refactoring would be appreciated here...\n handleMultiple: function () {\n var name;\n var multiple;\n var parsleyMultipleInstance;\n\n // Handle multiple name\n if (this.options.multiple)\n ; // We already have our 'multiple' identifier\n else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)\n this.options.multiple = name = this.$element.attr('name');\n else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)\n this.options.multiple = this.$element.attr('id');\n\n // Special select multiple input\n if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {\n this.options.multiple = this.options.multiple || this.__id__;\n return this.bind('parsleyFieldMultiple');\n\n // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it\n } else if (!this.options.multiple) {\n ParsleyUtils__default.warn('To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);\n return this;\n }\n\n // Remove special chars\n this.options.multiple = this.options.multiple.replace(/(:|\\.|\\[|\\]|\\{|\\}|\\$)/g, '');\n\n // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name\n if ('undefined' !== typeof name) {\n $('input[name=\"' + name + '\"]').each((i, input) => {\n if ($(input).is('input[type=radio], input[type=checkbox]'))\n $(input).attr(this.options.namespace + 'multiple', this.options.multiple);\n });\n }\n\n // Check here if we don't already have a related multiple instance saved\n var $previouslyRelated = this._findRelated();\n for (var i = 0; i < $previouslyRelated.length; i++) {\n parsleyMultipleInstance = $($previouslyRelated.get(i)).data('Parsley');\n if ('undefined' !== typeof parsleyMultipleInstance) {\n\n if (!this.$element.data('ParsleyFieldMultiple')) {\n parsleyMultipleInstance.addElement(this.$element);\n }\n\n break;\n }\n }\n\n // Create a secret ParsleyField instance for every multiple field. It will be stored in `data('ParsleyFieldMultiple')`\n // And will be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance\n this.bind('parsleyField', true);\n\n return parsleyMultipleInstance || this.bind('parsleyFieldMultiple');\n },\n\n // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`\n bind: function (type, doNotStore) {\n var parsleyInstance;\n\n switch (type) {\n case 'parsleyForm':\n parsleyInstance = $.extend(\n new ParsleyForm(this.$element, this.domOptions, this.options),\n window.ParsleyExtend\n )._bindFields();\n break;\n case 'parsleyField':\n parsleyInstance = $.extend(\n new parsley_field(this.$element, this.domOptions, this.options, this.parent),\n window.ParsleyExtend\n );\n break;\n case 'parsleyFieldMultiple':\n parsleyInstance = $.extend(\n new parsley_field(this.$element, this.domOptions, this.options, this.parent),\n new ParsleyMultiple(),\n window.ParsleyExtend\n )._init();\n break;\n default:\n throw new Error(type + 'is not a supported Parsley type');\n }\n\n if (this.options.multiple)\n ParsleyUtils__default.setAttr(this.$element, this.options.namespace, 'multiple', this.options.multiple);\n\n if ('undefined' !== typeof doNotStore) {\n this.$element.data('ParsleyFieldMultiple', parsleyInstance);\n\n return parsleyInstance;\n }\n\n // Store the freshly bound instance in a DOM element for later access using jQuery `data()`\n this.$element.data('Parsley', parsleyInstance);\n\n // Tell the world we have a new ParsleyForm or ParsleyField instance!\n parsleyInstance._actualizeTriggers();\n parsleyInstance._trigger('init');\n\n return parsleyInstance;\n }\n };\n\n var vernums = $.fn.jquery.split('.');\n if (parseInt(vernums[0]) <= 1 && parseInt(vernums[1]) < 8) {\n throw \"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.\";\n }\n if (!vernums.forEach) {\n ParsleyUtils__default.warn('Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim');\n }\n // Inherit `on`, `off` & `trigger` to Parsley:\n var Parsley = $.extend(new ParsleyAbstract(), {\n $element: $(document),\n actualizeOptions: null,\n _resetOptions: null,\n Factory: ParsleyFactory,\n version: '2.3.5'\n });\n\n // Supplement ParsleyField and Form with ParsleyAbstract\n // This way, the constructors will have access to those methods\n $.extend(parsley_field.prototype, ParsleyUI.Field, ParsleyAbstract.prototype);\n $.extend(ParsleyForm.prototype, ParsleyUI.Form, ParsleyAbstract.prototype);\n // Inherit actualizeOptions and _resetOptions:\n $.extend(ParsleyFactory.prototype, ParsleyAbstract.prototype);\n\n // ### jQuery API\n // `$('.elem').parsley(options)` or `$('.elem').psly(options)`\n $.fn.parsley = $.fn.psly = function (options) {\n if (this.length > 1) {\n var instances = [];\n\n this.each(function () {\n instances.push($(this).parsley(options));\n });\n\n return instances;\n }\n\n // Return undefined if applied to non existing DOM element\n if (!$(this).length) {\n ParsleyUtils__default.warn('You must bind Parsley on an existing element.');\n\n return;\n }\n\n return new ParsleyFactory(this, options);\n };\n\n // ### ParsleyField and ParsleyForm extension\n // Ensure the extension is now defined if it wasn't previously\n if ('undefined' === typeof window.ParsleyExtend)\n window.ParsleyExtend = {};\n\n // ### Parsley config\n // Inherit from ParsleyDefault, and copy over any existing values\n Parsley.options = $.extend(ParsleyUtils__default.objectCreate(ParsleyDefaults), window.ParsleyConfig);\n window.ParsleyConfig = Parsley.options; // Old way of accessing global options\n\n // ### Globals\n window.Parsley = window.psly = Parsley;\n window.ParsleyUtils = ParsleyUtils__default;\n\n // ### Define methods that forward to the registry, and deprecate all access except through window.Parsley\n var registry = window.Parsley._validatorRegistry = new ParsleyValidatorRegistry(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);\n window.ParsleyValidator = {};\n $.each('setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator'.split(' '), function (i, method) {\n window.Parsley[method] = $.proxy(registry, method);\n window.ParsleyValidator[method] = function () {\n ParsleyUtils__default.warnOnce(`Accessing the method '${method}' through ParsleyValidator is deprecated. Simply call 'window.Parsley.${method}(...)'`);\n return window.Parsley[method](...arguments);\n };\n });\n\n // ### ParsleyUI\n // Deprecated global object\n window.Parsley.UI = ParsleyUI;\n window.ParsleyUI = {\n removeError: function (instance, name, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils__default.warnOnce(`Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance.removeError(name, {updateClass});\n },\n getErrorsMessages: function (instance) {\n ParsleyUtils__default.warnOnce(`Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly.`);\n return instance.getErrorsMessages();\n }\n };\n $.each('addError updateError'.split(' '), function (i, method) {\n window.ParsleyUI[method] = function (instance, name, message, assert, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils__default.warnOnce(`Accessing ParsleyUI is deprecated. Call '${method}' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance[method](name, {message, assert, updateClass});\n };\n });\n\n // Alleviate glaring Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1250521\n // See also https://github.com/guillaumepotier/Parsley.js/issues/1068\n if (/firefox/i.test(navigator.userAgent)) {\n $(document).on('change', 'select', evt => {\n $(evt.target).trigger('input');\n });\n }\n\n // ### PARSLEY auto-binding\n // Prevent it by setting `ParsleyConfig.autoBind` to `false`\n if (false !== window.ParsleyConfig.autoBind) {\n $(function () {\n // Works only on `data-parsley-validate`.\n if ($('[data-parsley-validate]').length)\n $('[data-parsley-validate]').parsley();\n });\n }\n\n var o = $({});\n var deprecated = function () {\n ParsleyUtils__default.warnOnce(\"Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley\");\n };\n\n // Returns an event handler that calls `fn` with the arguments it expects\n function adapt(fn, context) {\n // Store to allow unbinding\n if (!fn.parsleyAdaptedCallback) {\n fn.parsleyAdaptedCallback = function () {\n var args = Array.prototype.slice.call(arguments, 0);\n args.unshift(this);\n fn.apply(context || o, args);\n };\n }\n return fn.parsleyAdaptedCallback;\n }\n\n var eventPrefix = 'parsley:';\n // Converts 'parsley:form:validate' into 'form:validate'\n function eventName(name) {\n if (name.lastIndexOf(eventPrefix, 0) === 0)\n return name.substr(eventPrefix.length);\n return name;\n }\n\n // $.listen is deprecated. Use Parsley.on instead.\n $.listen = function (name, callback) {\n var context;\n deprecated();\n if ('object' === typeof arguments[1] && 'function' === typeof arguments[2]) {\n context = arguments[1];\n callback = arguments[2];\n }\n\n if ('function' !== typeof callback)\n throw new Error('Wrong parameters');\n\n window.Parsley.on(eventName(name), adapt(callback, context));\n };\n\n $.listenTo = function (instance, name, fn) {\n deprecated();\n if (!(instance instanceof parsley_field) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong parameters');\n\n instance.on(eventName(name), adapt(fn));\n };\n\n $.unsubscribe = function (name, fn) {\n deprecated();\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong arguments');\n window.Parsley.off(eventName(name), fn.parsleyAdaptedCallback);\n };\n\n $.unsubscribeTo = function (instance, name) {\n deprecated();\n if (!(instance instanceof parsley_field) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n instance.off(eventName(name));\n };\n\n $.unsubscribeAll = function (name) {\n deprecated();\n window.Parsley.off(eventName(name));\n $('form,input,textarea,select').each(function () {\n var instance = $(this).data('Parsley');\n if (instance) {\n instance.off(eventName(name));\n }\n });\n };\n\n // $.emit is deprecated. Use jQuery events instead.\n $.emit = function (name, instance) {\n deprecated();\n var instanceGiven = (instance instanceof parsley_field) || (instance instanceof ParsleyForm);\n var args = Array.prototype.slice.call(arguments, instanceGiven ? 2 : 1);\n args.unshift(eventName(name));\n if (!instanceGiven) {\n instance = window.Parsley;\n }\n instance.trigger(...args);\n };\n\n var pubsub = {};\n\n $.extend(true, Parsley, {\n asyncValidators: {\n 'default': {\n fn: function (xhr) {\n // By default, only status 2xx are deemed successful.\n // Note: we use status instead of state() because responses with status 200\n // but invalid messages (e.g. an empty body for content type set to JSON) will\n // result in state() === 'rejected'.\n return xhr.status >= 200 && xhr.status < 300;\n },\n url: false\n },\n reverse: {\n fn: function (xhr) {\n // If reverse option is set, a failing ajax request is considered successful\n return xhr.status < 200 || xhr.status >= 300;\n },\n url: false\n }\n },\n\n addAsyncValidator: function (name, fn, url, options) {\n Parsley.asyncValidators[name] = {\n fn: fn,\n url: url || false,\n options: options || {}\n };\n\n return this;\n }\n\n });\n\n Parsley.addValidator('remote', {\n requirementType: {\n '': 'string',\n 'validator': 'string',\n 'reverse': 'boolean',\n 'options': 'object'\n },\n\n validateString: function (value, url, options, instance) {\n var data = {};\n var ajaxOptions;\n var csr;\n var validator = options.validator || (true === options.reverse ? 'reverse' : 'default');\n\n if ('undefined' === typeof Parsley.asyncValidators[validator])\n throw new Error('Calling an undefined async validator: `' + validator + '`');\n\n url = Parsley.asyncValidators[validator].url || url;\n\n // Fill current value\n if (url.indexOf('{value}') > -1) {\n url = url.replace('{value}', encodeURIComponent(value));\n } else {\n data[instance.$element.attr('name') || instance.$element.attr('id')] = value;\n }\n\n // Merge options passed in from the function with the ones in the attribute\n var remoteOptions = $.extend(true, options.options || {} , Parsley.asyncValidators[validator].options);\n\n // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`\n ajaxOptions = $.extend(true, {}, {\n url: url,\n data: data,\n type: 'GET'\n }, remoteOptions);\n\n // Generate store key based on ajax options\n instance.trigger('field:ajaxoptions', instance, ajaxOptions);\n\n csr = $.param(ajaxOptions);\n\n // Initialise querry cache\n if ('undefined' === typeof Parsley._remoteCache)\n Parsley._remoteCache = {};\n\n // Try to retrieve stored xhr\n var xhr = Parsley._remoteCache[csr] = Parsley._remoteCache[csr] || $.ajax(ajaxOptions);\n\n var handleXhr = function () {\n var result = Parsley.asyncValidators[validator].fn.call(instance, xhr, url, options);\n if (!result) // Map falsy results to rejected promise\n result = $.Deferred().reject();\n return $.when(result);\n };\n\n return xhr.then(handleXhr, handleXhr);\n },\n\n priority: -1\n });\n\n Parsley.on('form:submit', function () {\n Parsley._remoteCache = {};\n });\n\n window.ParsleyExtend.addAsyncValidator = function () {\n ParsleyUtils.warnOnce('Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`');\n return Parsley.addAsyncValidator(...arguments);\n };\n\n // This is included with the Parsley library itself,\n // thus there is no use in adding it to your project.\n Parsley.addMessages('en', {\n defaultMessage: \"This value seems to be invalid.\",\n type: {\n email: \"This value should be a valid email.\",\n url: \"This value should be a valid url.\",\n number: \"This value should be a valid number.\",\n integer: \"This value should be a valid integer.\",\n digits: \"This value should be digits.\",\n alphanum: \"This value should be alphanumeric.\"\n },\n notblank: \"This value should not be blank.\",\n required: \"This value is required.\",\n pattern: \"This value seems to be invalid.\",\n min: \"This value should be greater than or equal to %s.\",\n max: \"This value should be lower than or equal to %s.\",\n range: \"This value should be between %s and %s.\",\n minlength: \"This value is too short. It should have %s characters or more.\",\n maxlength: \"This value is too long. It should have %s characters or fewer.\",\n length: \"This value length is invalid. It should be between %s and %s characters long.\",\n mincheck: \"You must select at least %s choices.\",\n maxcheck: \"You must select %s choices or fewer.\",\n check: \"You must select between %s and %s choices.\",\n equalto: \"This value should be the same.\"\n });\n\n Parsley.setLocale('en');\n\n var parsley = Parsley;\n\n return parsley;\n\n}));\n","import $ from 'jquery';\nimport ParsleyField from './field';\nimport ParsleyForm from './form';\nimport ParsleyUtils from './utils';\n\nvar o = $({});\nvar deprecated = function () {\n ParsleyUtils.warnOnce(\"Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley\");\n};\n\n// Returns an event handler that calls `fn` with the arguments it expects\nfunction adapt(fn, context) {\n // Store to allow unbinding\n if (!fn.parsleyAdaptedCallback) {\n fn.parsleyAdaptedCallback = function () {\n var args = Array.prototype.slice.call(arguments, 0);\n args.unshift(this);\n fn.apply(context || o, args);\n };\n }\n return fn.parsleyAdaptedCallback;\n}\n\nvar eventPrefix = 'parsley:';\n// Converts 'parsley:form:validate' into 'form:validate'\nfunction eventName(name) {\n if (name.lastIndexOf(eventPrefix, 0) === 0)\n return name.substr(eventPrefix.length);\n return name;\n}\n\n// $.listen is deprecated. Use Parsley.on instead.\n$.listen = function (name, callback) {\n var context;\n deprecated();\n if ('object' === typeof arguments[1] && 'function' === typeof arguments[2]) {\n context = arguments[1];\n callback = arguments[2];\n }\n\n if ('function' !== typeof callback)\n throw new Error('Wrong parameters');\n\n window.Parsley.on(eventName(name), adapt(callback, context));\n};\n\n$.listenTo = function (instance, name, fn) {\n deprecated();\n if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong parameters');\n\n instance.on(eventName(name), adapt(fn));\n};\n\n$.unsubscribe = function (name, fn) {\n deprecated();\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong arguments');\n window.Parsley.off(eventName(name), fn.parsleyAdaptedCallback);\n};\n\n$.unsubscribeTo = function (instance, name) {\n deprecated();\n if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n instance.off(eventName(name));\n};\n\n$.unsubscribeAll = function (name) {\n deprecated();\n window.Parsley.off(eventName(name));\n $('form,input,textarea,select').each(function () {\n var instance = $(this).data('Parsley');\n if (instance) {\n instance.off(eventName(name));\n }\n });\n};\n\n// $.emit is deprecated. Use jQuery events instead.\n$.emit = function (name, instance) {\n deprecated();\n var instanceGiven = (instance instanceof ParsleyField) || (instance instanceof ParsleyForm);\n var args = Array.prototype.slice.call(arguments, instanceGiven ? 2 : 1);\n args.unshift(eventName(name));\n if (!instanceGiven) {\n instance = window.Parsley;\n }\n instance.trigger(...args);\n};\n\nexport default {};\n","import $ from 'jquery';\n\nvar globalID = 1;\nvar pastWarnings = {};\n\nvar ParsleyUtils = {\n // Parsley DOM-API\n // returns object from dom attributes and values\n attr: function ($element, namespace, obj) {\n var i;\n var attribute;\n var attributes;\n var regex = new RegExp('^' + namespace, 'i');\n\n if ('undefined' === typeof obj)\n obj = {};\n else {\n // Clear all own properties. This won't affect prototype's values\n for (i in obj) {\n if (obj.hasOwnProperty(i))\n delete obj[i];\n }\n }\n\n if ('undefined' === typeof $element || 'undefined' === typeof $element[0])\n return obj;\n\n attributes = $element[0].attributes;\n for (i = attributes.length; i--; ) {\n attribute = attributes[i];\n\n if (attribute && attribute.specified && regex.test(attribute.name)) {\n obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);\n }\n }\n\n return obj;\n },\n\n checkAttr: function ($element, namespace, checkAttr) {\n return $element.is('[' + namespace + checkAttr + ']');\n },\n\n setAttr: function ($element, namespace, attr, value) {\n $element[0].setAttribute(this.dasherize(namespace + attr), String(value));\n },\n\n generateID: function () {\n return '' + globalID++;\n },\n\n /** Third party functions **/\n // Zepto deserialize function\n deserializeValue: function (value) {\n var num;\n\n try {\n return value ?\n value == \"true\" ||\n (value == \"false\" ? false :\n value == \"null\" ? null :\n !isNaN(num = Number(value)) ? num :\n /^[\\[\\{]/.test(value) ? $.parseJSON(value) :\n value)\n : value;\n } catch (e) { return value; }\n },\n\n // Zepto camelize function\n camelize: function (str) {\n return str.replace(/-+(.)?/g, function (match, chr) {\n return chr ? chr.toUpperCase() : '';\n });\n },\n\n // Zepto dasherize function\n dasherize: function (str) {\n return str.replace(/::/g, '/')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/_/g, '-')\n .toLowerCase();\n },\n\n warn: function () {\n if (window.console && 'function' === typeof window.console.warn)\n window.console.warn(...arguments);\n },\n\n warnOnce: function(msg) {\n if (!pastWarnings[msg]) {\n pastWarnings[msg] = true;\n this.warn(...arguments);\n }\n },\n\n _resetWarnings: function () {\n pastWarnings = {};\n },\n\n trimString: function(string) {\n return string.replace(/^\\s+|\\s+$/g, '');\n },\n\n namespaceEvents: function(events, namespace) {\n events = this.trimString(events || '').split(/\\s+/);\n if (!events[0])\n return '';\n return $.map(events, evt => { return `${evt}.${namespace}`; }).join(' ');\n },\n\n // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill\n objectCreate: Object.create || (function () {\n var Object = function () {};\n return function (prototype) {\n if (arguments.length > 1) {\n throw Error('Second argument not supported');\n }\n if (typeof prototype != 'object') {\n throw TypeError('Argument must be an object');\n }\n Object.prototype = prototype;\n var result = new Object();\n Object.prototype = null;\n return result;\n };\n })()\n};\n\nexport default ParsleyUtils;\n","// All these options could be overriden and specified directly in DOM using\n// `data-parsley-` default DOM-API\n// eg: `inputs` can be set in DOM using `data-parsley-inputs=\"input, textarea\"`\n// eg: `data-parsley-stop-on-first-failing-constraint=\"false\"`\n\nvar ParsleyDefaults = {\n // ### General\n\n // Default data-namespace for DOM API\n namespace: 'data-parsley-',\n\n // Supported inputs by default\n inputs: 'input, textarea, select',\n\n // Excluded inputs by default\n excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',\n\n // Stop validating field on highest priority failing constraint\n priorityEnabled: true,\n\n // ### Field only\n\n // identifier used to group together inputs (e.g. radio buttons...)\n multiple: null,\n\n // identifier (or array of identifiers) used to validate only a select group of inputs\n group: null,\n\n // ### UI\n // Enable\\Disable error messages\n uiEnabled: true,\n\n // Key events threshold before validation\n validationThreshold: 3,\n\n // Focused field on form validation error. 'first'|'last'|'none'\n focus: 'first',\n\n // event(s) that will trigger validation before first failure. eg: `input`...\n trigger: false,\n\n // event(s) that will trigger validation after first failure.\n triggerAfterFailure: 'input',\n\n // Class that would be added on every failing validation Parsley field\n errorClass: 'parsley-error',\n\n // Same for success validation\n successClass: 'parsley-success',\n\n // Return the `$element` that will receive these above success or error classes\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n classHandler: function (ParsleyField) {},\n\n // Return the `$element` where errors will be appended\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n errorsContainer: function (ParsleyField) {},\n\n // ul elem that would receive errors' list\n errorsWrapper: '
          ',\n\n // li elem that would receive error message\n errorTemplate: '
        • '\n};\n\nexport default ParsleyDefaults;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\n\nvar ParsleyAbstract = function () {};\n\nParsleyAbstract.prototype = {\n asyncSupport: true, // Deprecated\n\n actualizeOptions: function () {\n ParsleyUtils.attr(this.$element, this.options.namespace, this.domOptions);\n if (this.parent && this.parent.actualizeOptions)\n this.parent.actualizeOptions();\n return this;\n },\n\n _resetOptions: function (initOptions) {\n this.domOptions = ParsleyUtils.objectCreate(this.parent.options);\n this.options = ParsleyUtils.objectCreate(this.domOptions);\n // Shallow copy of ownProperties of initOptions:\n for (var i in initOptions) {\n if (initOptions.hasOwnProperty(i))\n this.options[i] = initOptions[i];\n }\n this.actualizeOptions();\n },\n\n _listeners: null,\n\n // Register a callback for the given event name\n // Callback is called with context as the first argument and the `this`\n // The context is the current parsley instance, or window.Parsley if global\n // A return value of `false` will interrupt the calls\n on: function (name, fn) {\n this._listeners = this._listeners || {};\n var queue = this._listeners[name] = this._listeners[name] || [];\n queue.push(fn);\n\n return this;\n },\n\n // Deprecated. Use `on` instead\n subscribe: function(name, fn) {\n $.listenTo(this, name.toLowerCase(), fn);\n },\n\n // Unregister a callback (or all if none is given) for the given event name\n off: function (name, fn) {\n var queue = this._listeners && this._listeners[name];\n if (queue) {\n if (!fn) {\n delete this._listeners[name];\n } else {\n for (var i = queue.length; i--; )\n if (queue[i] === fn)\n queue.splice(i, 1);\n }\n }\n return this;\n },\n\n // Deprecated. Use `off`\n unsubscribe: function(name, fn) {\n $.unsubscribeTo(this, name.toLowerCase());\n },\n\n // Trigger an event of the given name\n // A return value of `false` interrupts the callback chain\n // Returns false if execution was interrupted\n trigger: function (name, target, extraArg) {\n target = target || this;\n var queue = this._listeners && this._listeners[name];\n var result;\n var parentResult;\n if (queue) {\n for (var i = queue.length; i--; ) {\n result = queue[i].call(target, target, extraArg);\n if (result === false) return result;\n }\n }\n if (this.parent) {\n return this.parent.trigger(name, target, extraArg);\n }\n return true;\n },\n\n // Reset UI\n reset: function () {\n // Field case: just emit a reset event for UI\n if ('ParsleyForm' !== this.__class__) {\n this._resetUI();\n return this._trigger('reset');\n }\n\n // Form case: emit a reset event for each field\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].reset();\n\n this._trigger('reset');\n },\n\n // Destroy Parsley instance (+ UI)\n destroy: function () {\n // Field case: emit destroy event to clean UI and then destroy stored instance\n this._destroyUI();\n if ('ParsleyForm' !== this.__class__) {\n this.$element.removeData('Parsley');\n this.$element.removeData('ParsleyFieldMultiple');\n this._trigger('destroy');\n\n return;\n }\n\n // Form case: destroy all its fields and then destroy stored instance\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].destroy();\n\n this.$element.removeData('Parsley');\n this._trigger('destroy');\n },\n\n asyncIsValid: function (group, force) {\n ParsleyUtils.warnOnce(\"asyncIsValid is deprecated; please use whenValid instead\");\n return this.whenValid({group, force});\n },\n\n _findRelated: function () {\n return this.options.multiple ?\n this.parent.$element.find(`[${this.options.namespace}multiple=\"${this.options.multiple}\"]`)\n : this.$element;\n }\n};\n\nexport default ParsleyAbstract;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\n\nvar requirementConverters = {\n string: function(string) {\n return string;\n },\n integer: function(string) {\n if (isNaN(string))\n throw 'Requirement is not an integer: \"' + string + '\"';\n return parseInt(string, 10);\n },\n number: function(string) {\n if (isNaN(string))\n throw 'Requirement is not a number: \"' + string + '\"';\n return parseFloat(string);\n },\n reference: function(string) { // Unused for now\n var result = $(string);\n if (result.length === 0)\n throw 'No such reference: \"' + string + '\"';\n return result;\n },\n boolean: function(string) {\n return string !== 'false';\n },\n object: function(string) {\n return ParsleyUtils.deserializeValue(string);\n },\n regexp: function(regexp) {\n var flags = '';\n\n // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern\n if (/^\\/.*\\/(?:[gimy]*)$/.test(regexp)) {\n // Replace the regexp literal string with the first match group: ([gimy]*)\n // If no flag is present, this will be a blank string\n flags = regexp.replace(/.*\\/([gimy]*)$/, '$1');\n // Again, replace the regexp literal string with the first match group:\n // everything excluding the opening and closing slashes and the flags\n regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');\n } else {\n // Anchor regexp:\n regexp = '^' + regexp + '$';\n }\n return new RegExp(regexp, flags);\n }\n};\n\nvar convertArrayRequirement = function(string, length) {\n var m = string.match(/^\\s*\\[(.*)\\]\\s*$/);\n if (!m)\n throw 'Requirement is not an array: \"' + string + '\"';\n var values = m[1].split(',').map(ParsleyUtils.trimString);\n if (values.length !== length)\n throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed';\n return values;\n};\n\nvar convertRequirement = function(requirementType, string) {\n var converter = requirementConverters[requirementType || 'string'];\n if (!converter)\n throw 'Unknown requirement specification: \"' + requirementType + '\"';\n return converter(string);\n};\n\nvar convertExtraOptionRequirement = function(requirementSpec, string, extraOptionReader) {\n var main = null;\n var extra = {};\n for (var key in requirementSpec) {\n if (key) {\n var value = extraOptionReader(key);\n if ('string' === typeof value)\n value = convertRequirement(requirementSpec[key], value);\n extra[key] = value;\n } else {\n main = convertRequirement(requirementSpec[key], string);\n }\n }\n return [main, extra];\n};\n\n// A Validator needs to implement the methods `validate` and `parseRequirements`\n\nvar ParsleyValidator = function(spec) {\n $.extend(true, this, spec);\n};\n\nParsleyValidator.prototype = {\n // Returns `true` iff the given `value` is valid according the given requirements.\n validate: function(value, requirementFirstArg) {\n if (this.fn) { // Legacy style validator\n\n if (arguments.length > 3) // If more args then value, requirement, instance...\n requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest\n return this.fn.call(this, value, requirementFirstArg);\n }\n\n if ($.isArray(value)) {\n if (!this.validateMultiple)\n throw 'Validator `' + this.name + '` does not handle multiple values';\n return this.validateMultiple(...arguments);\n } else {\n if (this.validateNumber) {\n if (isNaN(value))\n return false;\n arguments[0] = parseFloat(arguments[0]);\n return this.validateNumber(...arguments);\n }\n if (this.validateString) {\n return this.validateString(...arguments);\n }\n throw 'Validator `' + this.name + '` only handles multiple values';\n }\n },\n\n // Parses `requirements` into an array of arguments,\n // according to `this.requirementType`\n parseRequirements: function(requirements, extraOptionReader) {\n if ('string' !== typeof requirements) {\n // Assume requirement already parsed\n // but make sure we return an array\n return $.isArray(requirements) ? requirements : [requirements];\n }\n var type = this.requirementType;\n if ($.isArray(type)) {\n var values = convertArrayRequirement(requirements, type.length);\n for (var i = 0; i < values.length; i++)\n values[i] = convertRequirement(type[i], values[i]);\n return values;\n } else if ($.isPlainObject(type)) {\n return convertExtraOptionRequirement(type, requirements, extraOptionReader);\n } else {\n return [convertRequirement(type, requirements)];\n }\n },\n // Defaults:\n requirementType: 'string',\n\n priority: 2\n\n};\n\nexport default ParsleyValidator;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\nimport ParsleyDefaults from './defaults';\nimport ParsleyValidator from './validator';\n\nvar ParsleyValidatorRegistry = function (validators, catalog) {\n this.__class__ = 'ParsleyValidatorRegistry';\n\n // Default Parsley locale is en\n this.locale = 'en';\n\n this.init(validators || {}, catalog || {});\n};\n\nvar typeRegexes = {\n email: /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$/i,\n\n // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers\n number: /^-?(\\d*\\.)?\\d+(e[-+]?\\d+)?$/i,\n\n integer: /^-?\\d+$/,\n\n digits: /^\\d+$/,\n\n alphanum: /^\\w+$/i,\n\n url: new RegExp(\n \"^\" +\n // protocol identifier\n \"(?:(?:https?|ftp)://)?\" + // ** mod: make scheme optional\n // user:pass authentication\n \"(?:\\\\S+(?::\\\\S*)?@)?\" +\n \"(?:\" +\n // IP address exclusion\n // private & local networks\n // \"(?!(?:10|127)(?:\\\\.\\\\d{1,3}){3})\" + // ** mod: allow local networks\n // \"(?!(?:169\\\\.254|192\\\\.168)(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // \"(?!172\\\\.(?:1[6-9]|2\\\\d|3[0-1])(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // IP address dotted notation octets\n // excludes loopback network 0.0.0.0\n // excludes reserved space >= 224.0.0.0\n // excludes network & broacast addresses\n // (first & last IP address of each class)\n \"(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])\" +\n \"(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}\" +\n \"(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))\" +\n \"|\" +\n // host name\n \"(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)\" +\n // domain name\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*\" +\n // TLD identifier\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))\" +\n \")\" +\n // port number\n \"(?::\\\\d{2,5})?\" +\n // resource path\n \"(?:/\\\\S*)?\" +\n \"$\", 'i'\n )\n};\ntypeRegexes.range = typeRegexes.number;\n\n// See http://stackoverflow.com/a/10454560/8279\nvar decimalPlaces = num => {\n var match = ('' + num).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n if (!match) { return 0; }\n return Math.max(\n 0,\n // Number of digits right of decimal point.\n (match[1] ? match[1].length : 0) -\n // Adjust for scientific notation.\n (match[2] ? +match[2] : 0));\n};\n\nParsleyValidatorRegistry.prototype = {\n init: function (validators, catalog) {\n this.catalog = catalog;\n // Copy prototype's validators:\n this.validators = $.extend({}, this.validators);\n\n for (var name in validators)\n this.addValidator(name, validators[name].fn, validators[name].priority);\n\n window.Parsley.trigger('parsley:validator:init');\n },\n\n // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n\n setLocale: function (locale) {\n if ('undefined' === typeof this.catalog[locale])\n throw new Error(locale + ' is not available in the catalog');\n\n this.locale = locale;\n\n return this;\n },\n\n // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`\n addCatalog: function (locale, messages, set) {\n if ('object' === typeof messages)\n this.catalog[locale] = messages;\n\n if (true === set)\n return this.setLocale(locale);\n\n return this;\n },\n\n // Add a specific message for a given constraint in a given locale\n addMessage: function (locale, name, message) {\n if ('undefined' === typeof this.catalog[locale])\n this.catalog[locale] = {};\n\n this.catalog[locale][name] = message;\n\n return this;\n },\n\n // Add messages for a given locale\n addMessages: function (locale, nameMessageObject) {\n for (var name in nameMessageObject)\n this.addMessage(locale, name, nameMessageObject[name]);\n\n return this;\n },\n\n // Add a new validator\n //\n // addValidator('custom', {\n // requirementType: ['integer', 'integer'],\n // validateString: function(value, from, to) {},\n // priority: 22,\n // messages: {\n // en: \"Hey, that's no good\",\n // fr: \"Aye aye, pas bon du tout\",\n // }\n // })\n //\n // Old API was addValidator(name, function, priority)\n //\n addValidator: function (name, arg1, arg2) {\n if (this.validators[name])\n ParsleyUtils.warn('Validator \"' + name + '\" is already defined.');\n else if (ParsleyDefaults.hasOwnProperty(name)) {\n ParsleyUtils.warn('\"' + name + '\" is a restricted keyword and is not a valid validator name.');\n return;\n }\n return this._setValidator(...arguments);\n },\n\n updateValidator: function (name, arg1, arg2) {\n if (!this.validators[name]) {\n ParsleyUtils.warn('Validator \"' + name + '\" is not already defined.');\n return this.addValidator(...arguments);\n }\n return this._setValidator(this, arguments);\n },\n\n removeValidator: function (name) {\n if (!this.validators[name])\n ParsleyUtils.warn('Validator \"' + name + '\" is not defined.');\n\n delete this.validators[name];\n\n return this;\n },\n\n _setValidator: function (name, validator, priority) {\n if ('object' !== typeof validator) {\n // Old style validator, with `fn` and `priority`\n validator = {\n fn: validator,\n priority: priority\n };\n }\n if (!validator.validate) {\n validator = new ParsleyValidator(validator);\n }\n this.validators[name] = validator;\n\n for (var locale in validator.messages || {})\n this.addMessage(locale, name, validator.messages[locale]);\n\n return this;\n },\n\n getErrorMessage: function (constraint) {\n var message;\n\n // Type constraints are a bit different, we have to match their requirements too to find right error message\n if ('type' === constraint.name) {\n var typeMessages = this.catalog[this.locale][constraint.name] || {};\n message = typeMessages[constraint.requirements];\n } else\n message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);\n\n return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;\n },\n\n // Kind of light `sprintf()` implementation\n formatMessage: function (string, parameters) {\n if ('object' === typeof parameters) {\n for (var i in parameters)\n string = this.formatMessage(string, parameters[i]);\n\n return string;\n }\n\n return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';\n },\n\n // Here is the Parsley default validators list.\n // A validator is an object with the following key values:\n // - priority: an integer\n // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these\n // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise\n // Alternatively, a validator can be a function that returns such an object\n //\n validators: {\n notblank: {\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 2\n },\n required: {\n validateMultiple: function(values) {\n return values.length > 0;\n },\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 512\n },\n type: {\n validateString: function(value, type, {step = '1', base = 0} = {}) {\n var regex = typeRegexes[type];\n if (!regex) {\n throw new Error('validator type `' + type + '` is not supported');\n }\n if (!regex.test(value))\n return false;\n if ('number' === type) {\n if (!/^any$/i.test(step || '')) {\n var nb = Number(value);\n var decimals = Math.max(decimalPlaces(step), decimalPlaces(base));\n if (decimalPlaces(nb) > decimals) // Value can't have too many decimals\n return false;\n // Be careful of rounding errors by using integers.\n var toInt = f => { return Math.round(f * Math.pow(10, decimals)); };\n if ((toInt(nb) - toInt(base)) % toInt(step) != 0)\n return false;\n }\n }\n return true;\n },\n requirementType: {\n '': 'string',\n step: 'string',\n base: 'number'\n },\n priority: 256\n },\n pattern: {\n validateString: function(value, regexp) {\n return regexp.test(value);\n },\n requirementType: 'regexp',\n priority: 64\n },\n minlength: {\n validateString: function (value, requirement) {\n return value.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxlength: {\n validateString: function (value, requirement) {\n return value.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n length: {\n validateString: function (value, min, max) {\n return value.length >= min && value.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n mincheck: {\n validateMultiple: function (values, requirement) {\n return values.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxcheck: {\n validateMultiple: function (values, requirement) {\n return values.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n check: {\n validateMultiple: function (values, min, max) {\n return values.length >= min && values.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n min: {\n validateNumber: function (value, requirement) {\n return value >= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n max: {\n validateNumber: function (value, requirement) {\n return value <= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n range: {\n validateNumber: function (value, min, max) {\n return value >= min && value <= max;\n },\n requirementType: ['number', 'number'],\n priority: 30\n },\n equalto: {\n validateString: function (value, refOrValue) {\n var $reference = $(refOrValue);\n if ($reference.length)\n return value === $reference.val();\n else\n return value === refOrValue;\n },\n priority: 256\n }\n }\n};\n\nexport default ParsleyValidatorRegistry;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\n\nvar ParsleyUI = {};\n\nvar diffResults = function (newResult, oldResult, deep) {\n var added = [];\n var kept = [];\n\n for (var i = 0; i < newResult.length; i++) {\n var found = false;\n\n for (var j = 0; j < oldResult.length; j++)\n if (newResult[i].assert.name === oldResult[j].assert.name) {\n found = true;\n break;\n }\n\n if (found)\n kept.push(newResult[i]);\n else\n added.push(newResult[i]);\n }\n\n return {\n kept: kept,\n added: added,\n removed: !deep ? diffResults(oldResult, newResult, true).added : []\n };\n};\n\nParsleyUI.Form = {\n\n _actualizeTriggers: function () {\n this.$element.on('submit.Parsley', evt => { this.onSubmitValidate(evt); });\n this.$element.on('click.Parsley', 'input[type=\"submit\"], button[type=\"submit\"]', evt => { this.onSubmitButton(evt); });\n\n // UI could be disabled\n if (false === this.options.uiEnabled)\n return;\n\n this.$element.attr('novalidate', '');\n },\n\n focus: function () {\n this._focusedField = null;\n\n if (true === this.validationResult || 'none' === this.options.focus)\n return null;\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i];\n if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) {\n this._focusedField = field.$element;\n if ('first' === this.options.focus)\n break;\n }\n }\n\n if (null === this._focusedField)\n return null;\n\n return this._focusedField.focus();\n },\n\n _destroyUI: function () {\n // Reset all event listeners\n this.$element.off('.Parsley');\n }\n\n};\n\nParsleyUI.Field = {\n\n _reflowUI: function () {\n this._buildUI();\n\n // If this field doesn't have an active UI don't bother doing something\n if (!this._ui)\n return;\n\n // Diff between two validation results\n var diff = diffResults(this.validationResult, this._ui.lastValidationResult);\n\n // Then store current validation result for next reflow\n this._ui.lastValidationResult = this.validationResult;\n\n // Handle valid / invalid / none field class\n this._manageStatusClass();\n\n // Add, remove, updated errors messages\n this._manageErrorsMessages(diff);\n\n // Triggers impl\n this._actualizeTriggers();\n\n // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user\n if ((diff.kept.length || diff.added.length) && !this._failedOnce) {\n this._failedOnce = true;\n this._actualizeTriggers();\n }\n },\n\n // Returns an array of field's error message(s)\n getErrorsMessages: function () {\n // No error message, field is valid\n if (true === this.validationResult)\n return [];\n\n var messages = [];\n\n for (var i = 0; i < this.validationResult.length; i++)\n messages.push(this.validationResult[i].errorMessage ||\n this._getErrorMessage(this.validationResult[i].assert));\n\n return messages;\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n addError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._addError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n updateError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._updateError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n removeError: function (name, {updateClass = true} = {}) {\n this._buildUI();\n this._removeError(name);\n\n // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult\n // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.\n if (updateClass)\n this._manageStatusClass();\n },\n\n _manageStatusClass: function () {\n if (this.hasConstraints() && this.needsValidation() && true === this.validationResult)\n this._successClass();\n else if (this.validationResult.length > 0)\n this._errorClass();\n else\n this._resetClass();\n },\n\n _manageErrorsMessages: function (diff) {\n if ('undefined' !== typeof this.options.errorsMessagesDisabled)\n return;\n\n // Case where we have errorMessage option that configure an unique field error message, regardless failing validators\n if ('undefined' !== typeof this.options.errorMessage) {\n if ((diff.added.length || diff.kept.length)) {\n this._insertErrorWrapper();\n\n if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length)\n this._ui.$errorsWrapper\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-custom-error-message')\n );\n\n return this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-custom-error-message')\n .html(this.options.errorMessage);\n }\n\n return this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-custom-error-message')\n .remove();\n }\n\n // Show, hide, update failing constraints messages\n for (var i = 0; i < diff.removed.length; i++)\n this._removeError(diff.removed[i].assert.name);\n\n for (i = 0; i < diff.added.length; i++)\n this._addError(diff.added[i].assert.name, {message: diff.added[i].errorMessage, assert: diff.added[i].assert});\n\n for (i = 0; i < diff.kept.length; i++)\n this._updateError(diff.kept[i].assert.name, {message: diff.kept[i].errorMessage, assert: diff.kept[i].assert});\n },\n\n\n _addError: function (name, {message, assert}) {\n this._insertErrorWrapper();\n this._ui.$errorsWrapper\n .addClass('filled')\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-' + name)\n .html(message || this._getErrorMessage(assert))\n );\n },\n\n _updateError: function (name, {message, assert}) {\n this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-' + name)\n .html(message || this._getErrorMessage(assert));\n },\n\n _removeError: function (name) {\n this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-' + name)\n .remove();\n },\n\n _getErrorMessage: function (constraint) {\n var customConstraintErrorMessage = constraint.name + 'Message';\n\n if ('undefined' !== typeof this.options[customConstraintErrorMessage])\n return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements);\n\n return window.Parsley.getErrorMessage(constraint);\n },\n\n _buildUI: function () {\n // UI could be already built or disabled\n if (this._ui || false === this.options.uiEnabled)\n return;\n\n var _ui = {};\n\n // Give field its Parsley id in DOM\n this.$element.attr(this.options.namespace + 'id', this.__id__);\n\n /** Generate important UI elements and store them in this **/\n // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes\n _ui.$errorClassHandler = this._manageClassHandler();\n\n // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer\n _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__);\n _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId);\n\n // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly\n _ui.lastValidationResult = [];\n _ui.validationInformationVisible = false;\n\n // Store it in this for later\n this._ui = _ui;\n },\n\n // Determine which element will have `parsley-error` and `parsley-success` classes\n _manageClassHandler: function () {\n // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`\n if ('string' === typeof this.options.classHandler && $(this.options.classHandler).length)\n return $(this.options.classHandler);\n\n // Class handled could also be determined by function given in Parsley options\n var $handler = this.options.classHandler.call(this, this);\n\n // If this function returned a valid existing DOM element, go for it\n if ('undefined' !== typeof $handler && $handler.length)\n return $handler;\n\n // Otherwise, if simple element (input, texatrea, select...) it will perfectly host the classes\n if (!this.options.multiple || this.$element.is('select'))\n return this.$element;\n\n // But if multiple element (radio, checkbox), that would be their parent\n return this.$element.parent();\n },\n\n _insertErrorWrapper: function () {\n var $errorsContainer;\n\n // Nothing to do if already inserted\n if (0 !== this._ui.$errorsWrapper.parent().length)\n return this._ui.$errorsWrapper.parent();\n\n if ('string' === typeof this.options.errorsContainer) {\n if ($(this.options.errorsContainer).length)\n return $(this.options.errorsContainer).append(this._ui.$errorsWrapper);\n else\n ParsleyUtils.warn('The errors container `' + this.options.errorsContainer + '` does not exist in DOM');\n } else if ('function' === typeof this.options.errorsContainer)\n $errorsContainer = this.options.errorsContainer.call(this, this);\n\n if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)\n return $errorsContainer.append(this._ui.$errorsWrapper);\n\n var $from = this.$element;\n if (this.options.multiple)\n $from = $from.parent();\n return $from.after(this._ui.$errorsWrapper);\n },\n\n _actualizeTriggers: function () {\n var $toBind = this._findRelated();\n\n // Remove Parsley events already bound on this field\n $toBind.off('.Parsley');\n if (this._failedOnce)\n $toBind.on(ParsleyUtils.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), () => {\n this.validate();\n });\n else {\n $toBind.on(ParsleyUtils.namespaceEvents(this.options.trigger, 'Parsley'), event => {\n this._eventValidate(event);\n });\n }\n },\n\n _eventValidate: function (event) {\n // For keyup, keypress, keydown, input... events that could be a little bit obstrusive\n // do not validate if val length < min threshold on first validation. Once field have been validated once and info\n // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.\n if (/key|input/.test(event.type))\n if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold)\n return;\n\n this.validate();\n },\n\n _resetUI: function () {\n // Reset all event listeners\n this._failedOnce = false;\n this._actualizeTriggers();\n\n // Nothing to do if UI never initialized for this field\n if ('undefined' === typeof this._ui)\n return;\n\n // Reset all errors' li\n this._ui.$errorsWrapper\n .removeClass('filled')\n .children()\n .remove();\n\n // Reset validation class\n this._resetClass();\n\n // Reset validation flags and last validation result\n this._ui.lastValidationResult = [];\n this._ui.validationInformationVisible = false;\n },\n\n _destroyUI: function () {\n this._resetUI();\n\n if ('undefined' !== typeof this._ui)\n this._ui.$errorsWrapper.remove();\n\n delete this._ui;\n },\n\n _successClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass);\n },\n _errorClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass);\n },\n _resetClass: function () {\n this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass);\n }\n};\n\nexport default ParsleyUI;\n","import $ from 'jquery';\nimport ParsleyAbstract from './abstract';\nimport ParsleyUtils from './utils';\n\nvar ParsleyForm = function (element, domOptions, options) {\n this.__class__ = 'ParsleyForm';\n this.__id__ = ParsleyUtils.generateID();\n\n this.$element = $(element);\n this.domOptions = domOptions;\n this.options = options;\n this.parent = window.Parsley;\n\n this.fields = [];\n this.validationResult = null;\n};\n\nvar statusMapping = {pending: null, resolved: true, rejected: false};\n\nParsleyForm.prototype = {\n onSubmitValidate: function (event) {\n // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior\n if (true === event.parsley)\n return;\n\n // If we didn't come here through a submit button, use the first one in the form\n var $submitSource = this._$submitSource || this.$element.find('input[type=\"submit\"], button[type=\"submit\"]').first();\n this._$submitSource = null;\n this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);\n if ($submitSource.is('[formnovalidate]'))\n return;\n\n var promise = this.whenValidate({event});\n\n if ('resolved' === promise.state() && false !== this._trigger('submit')) {\n // All good, let event go through. We make this distinction because browsers\n // differ in their handling of `submit` being called from inside a submit event [#1047]\n } else {\n // Rejected or pending: cancel this submit\n event.stopImmediatePropagation();\n event.preventDefault();\n if ('pending' === promise.state())\n promise.done(() => { this._submit($submitSource); });\n }\n },\n\n onSubmitButton: function(event) {\n this._$submitSource = $(event.target);\n },\n // internal\n // _submit submits the form, this time without going through the validations.\n // Care must be taken to \"fake\" the actual submit button being clicked.\n _submit: function ($submitSource) {\n if (false === this._trigger('submit'))\n return;\n // Add submit button's data\n if ($submitSource) {\n var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);\n if (0 === $synthetic.length)\n $synthetic = $('').appendTo(this.$element);\n $synthetic.attr({\n name: $submitSource.attr('name'),\n value: $submitSource.attr('value')\n });\n }\n\n this.$element.trigger($.extend($.Event('submit'), {parsley: true}));\n },\n\n // Performs validation on fields while triggering events.\n // @returns `true` if all validations succeeds, `false`\n // if a failure is immediately detected, or `null`\n // if dependant on a promise.\n // Consider using `whenValidate` instead.\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');\n var [group, force, event] = arguments;\n options = {group, force, event};\n }\n return statusMapping[ this.whenValidate(options).state() ];\n },\n\n whenValidate: function ({group, force, event} = {}) {\n this.submitEvent = event;\n if (event) {\n this.submitEvent = $.extend({}, event, {preventDefault: () => {\n ParsleyUtils.warnOnce(\"Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`\");\n this.validationResult = false;\n }});\n }\n this.validationResult = true;\n\n // fire validate event to eventually modify things before very validation\n this._trigger('validate');\n\n // Refresh form DOM options and form's fields that could have changed\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValidate({force, group});\n });\n });\n\n var promiseBasedOnValidationResult = () => {\n var r = $.Deferred();\n if (false === this.validationResult)\n r.reject();\n return r.resolve().promise();\n };\n\n return $.when(...promises)\n .done( () => { this._trigger('success'); })\n .fail( () => {\n this.validationResult = false;\n this.focus();\n this._trigger('error');\n })\n .always(() => { this._trigger('validated'); })\n .pipe( promiseBasedOnValidationResult, promiseBasedOnValidationResult);\n },\n\n // Iterate over refreshed fields, and stop on first failure.\n // Returns `true` if all fields are valid, `false` if a failure is detected\n // or `null` if the result depends on an unresolved promise.\n // Prefer using `whenValid` instead.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');\n var [group, force] = arguments;\n options = {group, force};\n }\n return statusMapping[ this.whenValid(options).state() ];\n },\n\n // Iterate over refreshed fields and validate them.\n // Returns a promise.\n // A validation that immediately fails will interrupt the validations.\n whenValid: function ({group, force} = {}) {\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValid({group, force});\n });\n });\n return $.when(...promises);\n },\n\n _refreshFields: function () {\n return this.actualizeOptions()._bindFields();\n },\n\n _bindFields: function () {\n var oldFields = this.fields;\n\n this.fields = [];\n this.fieldsMappedById = {};\n\n this._withoutReactualizingFormOptions(() => {\n this.$element\n .find(this.options.inputs)\n .not(this.options.excluded)\n .each((_, element) => {\n var fieldInstance = new window.Parsley.Factory(element, {}, this);\n\n // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children\n if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && (true !== fieldInstance.options.excluded))\n if ('undefined' === typeof this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {\n this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;\n this.fields.push(fieldInstance);\n }\n });\n\n $(oldFields).not(this.fields).each((_, field) => {\n field._trigger('reset');\n });\n });\n return this;\n },\n\n // Internal only.\n // Looping on a form's fields to do validation or similar\n // will trigger reactualizing options on all of them, which\n // in turn will reactualize the form's options.\n // To avoid calling actualizeOptions so many times on the form\n // for nothing, _withoutReactualizingFormOptions temporarily disables\n // the method actualizeOptions on this form while `fn` is called.\n _withoutReactualizingFormOptions: function (fn) {\n var oldActualizeOptions = this.actualizeOptions;\n this.actualizeOptions = function () { return this; };\n var result = fn();\n this.actualizeOptions = oldActualizeOptions;\n return result;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n // Returns true iff event is not interrupted and default not prevented.\n _trigger: function (eventName) {\n return this.trigger('form:' + eventName);\n }\n\n};\n\nexport default ParsleyForm;\n","import $ from 'jquery';\nimport ParsleyUtils from '../utils';\nimport ParsleyValidator from '../validator';\n\n\nvar ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {\n if (!/ParsleyField/.test(parsleyField.__class__))\n throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');\n\n var validatorSpec = window.Parsley._validatorRegistry.validators[name];\n var validator = new ParsleyValidator(validatorSpec);\n\n $.extend(this, {\n validator: validator,\n name: name,\n requirements: requirements,\n priority: priority || parsleyField.options[name + 'Priority'] || validator.priority,\n isDomConstraint: true === isDomConstraint\n });\n this._parseRequirements(parsleyField.options);\n};\n\nvar capitalize = function(str) {\n var cap = str[0].toUpperCase();\n return cap + str.slice(1);\n};\n\nConstraintFactory.prototype = {\n validate: function(value, instance) {\n var args = this.requirementList.slice(0); // Make copy\n args.unshift(value);\n args.push(instance);\n return this.validator.validate.apply(this.validator, args);\n },\n\n _parseRequirements: function(options) {\n this.requirementList = this.validator.parseRequirements(this.requirements, key => {\n return options[this.name + capitalize(key)];\n });\n }\n};\n\nexport default ConstraintFactory;\n\n","import $ from 'jquery';\nimport ConstraintFactory from './factory/constraint';\nimport ParsleyUI from './ui';\nimport ParsleyUtils from './utils';\n\nvar ParsleyField = function (field, domOptions, options, parsleyFormInstance) {\n this.__class__ = 'ParsleyField';\n this.__id__ = ParsleyUtils.generateID();\n\n this.$element = $(field);\n\n // Set parent if we have one\n if ('undefined' !== typeof parsleyFormInstance) {\n this.parent = parsleyFormInstance;\n }\n\n this.options = options;\n this.domOptions = domOptions;\n\n // Initialize some properties\n this.constraints = [];\n this.constraintsByName = {};\n this.validationResult = [];\n\n // Bind constraints\n this._bindConstraints();\n};\n\nvar statusMapping = {pending: null, resolved: true, rejected: false};\n\nParsleyField.prototype = {\n // # Public API\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns `true`, an array of the validators that failed, or\n // `null` if validation is not finished. Prefer using whenValidate\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.');\n options = {options};\n }\n var promise = this.whenValidate(options);\n if (!promise) // If excluded with `group` option\n return true;\n switch (promise.state()) {\n case 'pending': return null;\n case 'resolved': return true;\n case 'rejected': return this.validationResult;\n }\n },\n\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if field is not in the given `group`.\n whenValidate: function ({force, group} = {}) {\n // do not validate a field if not the same as given validation group\n this.refreshConstraints();\n if (group && !this._isInGroup(group))\n return;\n\n this.value = this.getValue();\n\n // Field Validate event. `this.value` could be altered for custom needs\n this._trigger('validate');\n\n return this.whenValid({force, value: this.value, _refreshed: true})\n .always(() => { this._reflowUI(); })\n .done(() => { this._trigger('success'); })\n .fail(() => { this._trigger('error'); })\n .always(() => { this._trigger('validated'); });\n },\n\n hasConstraints: function () {\n return 0 !== this.constraints.length;\n },\n\n // An empty optional field does not need validation\n needsValidation: function (value) {\n if ('undefined' === typeof value)\n value = this.getValue();\n\n // If a field is empty and not required, it is valid\n // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators\n if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty)\n return false;\n\n return true;\n },\n\n _isInGroup: function (group) {\n if ($.isArray(this.options.group))\n return -1 !== $.inArray(group, this.options.group);\n return this.options.group === group;\n },\n\n // Just validate field. Do not trigger any event.\n // Returns `true` iff all constraints pass, `false` if there are failures,\n // or `null` if the result can not be determined yet (depends on a promise)\n // See also `whenValid`.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.');\n var [force, value] = arguments;\n options = {force, value};\n }\n var promise = this.whenValid(options);\n if (!promise) // Excluded via `group`\n return true;\n return statusMapping[promise.state()];\n },\n\n // Just validate field. Do not trigger any event.\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if the field is not in the given `group`.\n // The argument `force` will force validation of empty fields.\n // If a `value` is given, it will be validated instead of the value of the input.\n whenValid: function ({force = false, value, group, _refreshed} = {}) {\n // Recompute options and rebind constraints to have latest changes\n if (!_refreshed)\n this.refreshConstraints();\n // do not validate a field if not the same as given validation group\n if (group && !this._isInGroup(group))\n return;\n\n this.validationResult = true;\n\n // A field without constraint is valid\n if (!this.hasConstraints())\n return $.when();\n\n // Value could be passed as argument, needed to add more power to 'parsley:field:validate'\n if ('undefined' === typeof value || null === value)\n value = this.getValue();\n\n if (!this.needsValidation(value) && true !== force)\n return $.when();\n\n var groupedConstraints = this._getGroupedConstraints();\n var promises = [];\n $.each(groupedConstraints, (_, constraints) => {\n // Process one group of constraints at a time, we validate the constraints\n // and combine the promises together.\n var promise = $.when(\n ...$.map(constraints, constraint => this._validateConstraint(value, constraint))\n );\n promises.push(promise);\n if (promise.state() === 'rejected')\n return false; // Interrupt processing if a group has already failed\n });\n return $.when.apply($, promises);\n },\n\n // @returns a promise\n _validateConstraint: function(value, constraint) {\n var result = constraint.validate(value, this);\n // Map false to a failed promise\n if (false === result)\n result = $.Deferred().reject();\n // Make sure we return a promise and that we record failures\n return $.when(result).fail(errorMessage => {\n if (true === this.validationResult)\n this.validationResult = [];\n this.validationResult.push({\n assert: constraint,\n errorMessage: 'string' === typeof errorMessage && errorMessage\n });\n });\n },\n\n // @returns Parsley field computed value that could be overrided or configured in DOM\n getValue: function () {\n var value;\n\n // Value could be overriden in DOM or with explicit options\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n value = this.options.value;\n else\n value = this.$element.val();\n\n // Handle wrong DOM or configurations\n if ('undefined' === typeof value || null === value)\n return '';\n\n return this._handleWhitespace(value);\n },\n\n // Actualize options that could have change since previous validation\n // Re-bind accordingly constraints (could be some new, removed or updated)\n refreshConstraints: function () {\n return this.actualizeOptions()._bindConstraints();\n },\n\n /**\n * Add a new constraint to a field\n *\n * @param {String} name\n * @param {Mixed} requirements optional\n * @param {Number} priority optional\n * @param {Boolean} isDomConstraint optional\n */\n addConstraint: function (name, requirements, priority, isDomConstraint) {\n\n if (window.Parsley._validatorRegistry.validators[name]) {\n var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);\n\n // if constraint already exist, delete it and push new version\n if ('undefined' !== this.constraintsByName[constraint.name])\n this.removeConstraint(constraint.name);\n\n this.constraints.push(constraint);\n this.constraintsByName[constraint.name] = constraint;\n }\n\n return this;\n },\n\n // Remove a constraint\n removeConstraint: function (name) {\n for (var i = 0; i < this.constraints.length; i++)\n if (name === this.constraints[i].name) {\n this.constraints.splice(i, 1);\n break;\n }\n delete this.constraintsByName[name];\n return this;\n },\n\n // Update a constraint (Remove + re-add)\n updateConstraint: function (name, parameters, priority) {\n return this.removeConstraint(name)\n .addConstraint(name, parameters, priority);\n },\n\n // # Internals\n\n // Internal only.\n // Bind constraints from config + options + DOM\n _bindConstraints: function () {\n var constraints = [];\n var constraintsByName = {};\n\n // clean all existing DOM constraints to only keep javascript user constraints\n for (var i = 0; i < this.constraints.length; i++)\n if (false === this.constraints[i].isDomConstraint) {\n constraints.push(this.constraints[i]);\n constraintsByName[this.constraints[i].name] = this.constraints[i];\n }\n\n this.constraints = constraints;\n this.constraintsByName = constraintsByName;\n\n // then re-add Parsley DOM-API constraints\n for (var name in this.options)\n this.addConstraint(name, this.options[name], undefined, true);\n\n // finally, bind special HTML5 constraints\n return this._bindHtml5Constraints();\n },\n\n // Internal only.\n // Bind specific HTML5 constraints to be HTML5 compliant\n _bindHtml5Constraints: function () {\n // html5 required\n if (this.$element.hasClass('required') || this.$element.attr('required'))\n this.addConstraint('required', true, undefined, true);\n\n // html5 pattern\n if ('string' === typeof this.$element.attr('pattern'))\n this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);\n\n // range\n if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);\n\n // HTML5 min\n else if ('undefined' !== typeof this.$element.attr('min'))\n this.addConstraint('min', this.$element.attr('min'), undefined, true);\n\n // HTML5 max\n else if ('undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('max', this.$element.attr('max'), undefined, true);\n\n\n // length\n if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);\n\n // HTML5 minlength\n else if ('undefined' !== typeof this.$element.attr('minlength'))\n this.addConstraint('minlength', this.$element.attr('minlength'), undefined, true);\n\n // HTML5 maxlength\n else if ('undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('maxlength', this.$element.attr('maxlength'), undefined, true);\n\n\n // html5 types\n var type = this.$element.attr('type');\n\n if ('undefined' === typeof type)\n return this;\n\n // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise\n if ('number' === type) {\n return this.addConstraint('type', ['number', {\n step: this.$element.attr('step'),\n base: this.$element.attr('min') || this.$element.attr('value')\n }], undefined, true);\n // Regular other HTML5 supported types\n } else if (/^(email|url|range)$/i.test(type)) {\n return this.addConstraint('type', type, undefined, true);\n }\n return this;\n },\n\n // Internal only.\n // Field is required if have required constraint without `false` value\n _isRequired: function () {\n if ('undefined' === typeof this.constraintsByName.required)\n return false;\n\n return false !== this.constraintsByName.required.requirements;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n _trigger: function (eventName) {\n return this.trigger('field:' + eventName);\n },\n\n // Internal only\n // Handles whitespace in a value\n // Use `data-parsley-whitespace=\"squish\"` to auto squish input value\n // Use `data-parsley-whitespace=\"trim\"` to auto trim input value\n _handleWhitespace: function (value) {\n if (true === this.options.trimValue)\n ParsleyUtils.warnOnce('data-parsley-trim-value=\"true\" is deprecated, please use data-parsley-whitespace=\"trim\"');\n\n if ('squish' === this.options.whitespace)\n value = value.replace(/\\s{2,}/g, ' ');\n\n if (('trim' === this.options.whitespace) || ('squish' === this.options.whitespace) || (true === this.options.trimValue))\n value = ParsleyUtils.trimString(value);\n\n return value;\n },\n\n // Internal only.\n // Returns the constraints, grouped by descending priority.\n // The result is thus an array of arrays of constraints.\n _getGroupedConstraints: function () {\n if (false === this.options.priorityEnabled)\n return [this.constraints];\n\n var groupedConstraints = [];\n var index = {};\n\n // Create array unique of priorities\n for (var i = 0; i < this.constraints.length; i++) {\n var p = this.constraints[i].priority;\n if (!index[p])\n groupedConstraints.push(index[p] = []);\n index[p].push(this.constraints[i]);\n }\n // Sort them by priority DESC\n groupedConstraints.sort(function (a, b) { return b[0].priority - a[0].priority; });\n\n return groupedConstraints;\n }\n\n};\n\nexport default ParsleyField;\n","import $ from 'jquery';\n\nvar ParsleyMultiple = function () {\n this.__class__ = 'ParsleyFieldMultiple';\n};\n\nParsleyMultiple.prototype = {\n // Add new `$element` sibling for multiple field\n addElement: function ($element) {\n this.$elements.push($element);\n\n return this;\n },\n\n // See `ParsleyField.refreshConstraints()`\n refreshConstraints: function () {\n var fieldConstraints;\n\n this.constraints = [];\n\n // Select multiple special treatment\n if (this.$element.is('select')) {\n this.actualizeOptions()._bindConstraints();\n\n return this;\n }\n\n // Gather all constraints for each input in the multiple group\n for (var i = 0; i < this.$elements.length; i++) {\n\n // Check if element have not been dynamically removed since last binding\n if (!$('html').has(this.$elements[i]).length) {\n this.$elements.splice(i, 1);\n continue;\n }\n\n fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;\n\n for (var j = 0; j < fieldConstraints.length; j++)\n this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);\n }\n\n return this;\n },\n\n // See `ParsleyField.getValue()`\n getValue: function () {\n // Value could be overriden in DOM\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n return this.options.value;\n\n // Radio input case\n if (this.$element.is('input[type=radio]'))\n return this._findRelated().filter(':checked').val() || '';\n\n // checkbox input case\n if (this.$element.is('input[type=checkbox]')) {\n var values = [];\n\n this._findRelated().filter(':checked').each(function () {\n values.push($(this).val());\n });\n\n return values;\n }\n\n // Select multiple case\n if (this.$element.is('select') && null === this.$element.val())\n return [];\n\n // Default case that should never happen\n return this.$element.val();\n },\n\n _init: function () {\n this.$elements = [this.$element];\n\n return this;\n }\n};\n\nexport default ParsleyMultiple;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\nimport ParsleyAbstract from './abstract';\nimport ParsleyForm from './form';\nimport ParsleyField from './field';\nimport ParsleyMultiple from './multiple';\n\nvar ParsleyFactory = function (element, options, parsleyFormInstance) {\n this.$element = $(element);\n\n // If the element has already been bound, returns its saved Parsley instance\n var savedparsleyFormInstance = this.$element.data('Parsley');\n if (savedparsleyFormInstance) {\n\n // If the saved instance has been bound without a ParsleyForm parent and there is one given in this call, add it\n if ('undefined' !== typeof parsleyFormInstance && savedparsleyFormInstance.parent === window.Parsley) {\n savedparsleyFormInstance.parent = parsleyFormInstance;\n savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options);\n }\n\n return savedparsleyFormInstance;\n }\n\n // Parsley must be instantiated with a DOM element or jQuery $element\n if (!this.$element.length)\n throw new Error('You must bind Parsley on an existing element.');\n\n if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)\n throw new Error('Parent instance must be a ParsleyForm instance');\n\n this.parent = parsleyFormInstance || window.Parsley;\n return this.init(options);\n};\n\nParsleyFactory.prototype = {\n init: function (options) {\n this.__class__ = 'Parsley';\n this.__version__ = '@@version';\n this.__id__ = ParsleyUtils.generateID();\n\n // Pre-compute options\n this._resetOptions(options);\n\n // A ParsleyForm instance is obviously a `` element but also every node that is not an input and has the `data-parsley-validate` attribute\n if (this.$element.is('form') || (ParsleyUtils.checkAttr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))\n return this.bind('parsleyForm');\n\n // Every other element is bound as a `ParsleyField` or `ParsleyFieldMultiple`\n return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField');\n },\n\n isMultiple: function () {\n return (this.$element.is('input[type=radio], input[type=checkbox]')) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));\n },\n\n // Multiples fields are a real nightmare :(\n // Maybe some refactoring would be appreciated here...\n handleMultiple: function () {\n var name;\n var multiple;\n var parsleyMultipleInstance;\n\n // Handle multiple name\n if (this.options.multiple)\n ; // We already have our 'multiple' identifier\n else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)\n this.options.multiple = name = this.$element.attr('name');\n else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)\n this.options.multiple = this.$element.attr('id');\n\n // Special select multiple input\n if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {\n this.options.multiple = this.options.multiple || this.__id__;\n return this.bind('parsleyFieldMultiple');\n\n // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it\n } else if (!this.options.multiple) {\n ParsleyUtils.warn('To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);\n return this;\n }\n\n // Remove special chars\n this.options.multiple = this.options.multiple.replace(/(:|\\.|\\[|\\]|\\{|\\}|\\$)/g, '');\n\n // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name\n if ('undefined' !== typeof name) {\n $('input[name=\"' + name + '\"]').each((i, input) => {\n if ($(input).is('input[type=radio], input[type=checkbox]'))\n $(input).attr(this.options.namespace + 'multiple', this.options.multiple);\n });\n }\n\n // Check here if we don't already have a related multiple instance saved\n var $previouslyRelated = this._findRelated();\n for (var i = 0; i < $previouslyRelated.length; i++) {\n parsleyMultipleInstance = $($previouslyRelated.get(i)).data('Parsley');\n if ('undefined' !== typeof parsleyMultipleInstance) {\n\n if (!this.$element.data('ParsleyFieldMultiple')) {\n parsleyMultipleInstance.addElement(this.$element);\n }\n\n break;\n }\n }\n\n // Create a secret ParsleyField instance for every multiple field. It will be stored in `data('ParsleyFieldMultiple')`\n // And will be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance\n this.bind('parsleyField', true);\n\n return parsleyMultipleInstance || this.bind('parsleyFieldMultiple');\n },\n\n // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`\n bind: function (type, doNotStore) {\n var parsleyInstance;\n\n switch (type) {\n case 'parsleyForm':\n parsleyInstance = $.extend(\n new ParsleyForm(this.$element, this.domOptions, this.options),\n window.ParsleyExtend\n )._bindFields();\n break;\n case 'parsleyField':\n parsleyInstance = $.extend(\n new ParsleyField(this.$element, this.domOptions, this.options, this.parent),\n window.ParsleyExtend\n );\n break;\n case 'parsleyFieldMultiple':\n parsleyInstance = $.extend(\n new ParsleyField(this.$element, this.domOptions, this.options, this.parent),\n new ParsleyMultiple(),\n window.ParsleyExtend\n )._init();\n break;\n default:\n throw new Error(type + 'is not a supported Parsley type');\n }\n\n if (this.options.multiple)\n ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', this.options.multiple);\n\n if ('undefined' !== typeof doNotStore) {\n this.$element.data('ParsleyFieldMultiple', parsleyInstance);\n\n return parsleyInstance;\n }\n\n // Store the freshly bound instance in a DOM element for later access using jQuery `data()`\n this.$element.data('Parsley', parsleyInstance);\n\n // Tell the world we have a new ParsleyForm or ParsleyField instance!\n parsleyInstance._actualizeTriggers();\n parsleyInstance._trigger('init');\n\n return parsleyInstance;\n }\n};\n\nexport default ParsleyFactory;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\nimport ParsleyDefaults from './defaults';\nimport ParsleyAbstract from './abstract';\nimport ParsleyValidatorRegistry from './validator_registry';\nimport ParsleyUI from './ui';\nimport ParsleyForm from './form';\nimport ParsleyField from './field';\nimport ParsleyMultiple from './multiple';\nimport ParsleyFactory from './factory';\n\nvar vernums = $.fn.jquery.split('.');\nif (parseInt(vernums[0]) <= 1 && parseInt(vernums[1]) < 8) {\n throw \"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.\";\n}\nif (!vernums.forEach) {\n ParsleyUtils.warn('Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim');\n}\n// Inherit `on`, `off` & `trigger` to Parsley:\nvar Parsley = $.extend(new ParsleyAbstract(), {\n $element: $(document),\n actualizeOptions: null,\n _resetOptions: null,\n Factory: ParsleyFactory,\n version: '@@version'\n });\n\n// Supplement ParsleyField and Form with ParsleyAbstract\n// This way, the constructors will have access to those methods\n$.extend(ParsleyField.prototype, ParsleyUI.Field, ParsleyAbstract.prototype);\n$.extend(ParsleyForm.prototype, ParsleyUI.Form, ParsleyAbstract.prototype);\n// Inherit actualizeOptions and _resetOptions:\n$.extend(ParsleyFactory.prototype, ParsleyAbstract.prototype);\n\n// ### jQuery API\n// `$('.elem').parsley(options)` or `$('.elem').psly(options)`\n$.fn.parsley = $.fn.psly = function (options) {\n if (this.length > 1) {\n var instances = [];\n\n this.each(function () {\n instances.push($(this).parsley(options));\n });\n\n return instances;\n }\n\n // Return undefined if applied to non existing DOM element\n if (!$(this).length) {\n ParsleyUtils.warn('You must bind Parsley on an existing element.');\n\n return;\n }\n\n return new ParsleyFactory(this, options);\n};\n\n// ### ParsleyField and ParsleyForm extension\n// Ensure the extension is now defined if it wasn't previously\nif ('undefined' === typeof window.ParsleyExtend)\n window.ParsleyExtend = {};\n\n// ### Parsley config\n// Inherit from ParsleyDefault, and copy over any existing values\nParsley.options = $.extend(ParsleyUtils.objectCreate(ParsleyDefaults), window.ParsleyConfig);\nwindow.ParsleyConfig = Parsley.options; // Old way of accessing global options\n\n// ### Globals\nwindow.Parsley = window.psly = Parsley;\nwindow.ParsleyUtils = ParsleyUtils;\n\n// ### Define methods that forward to the registry, and deprecate all access except through window.Parsley\nvar registry = window.Parsley._validatorRegistry = new ParsleyValidatorRegistry(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);\nwindow.ParsleyValidator = {};\n$.each('setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator'.split(' '), function (i, method) {\n window.Parsley[method] = $.proxy(registry, method);\n window.ParsleyValidator[method] = function () {\n ParsleyUtils.warnOnce(`Accessing the method '${method}' through ParsleyValidator is deprecated. Simply call 'window.Parsley.${method}(...)'`);\n return window.Parsley[method](...arguments);\n };\n});\n\n// ### ParsleyUI\n// Deprecated global object\nwindow.Parsley.UI = ParsleyUI;\nwindow.ParsleyUI = {\n removeError: function (instance, name, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils.warnOnce(`Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance.removeError(name, {updateClass});\n },\n getErrorsMessages: function (instance) {\n ParsleyUtils.warnOnce(`Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly.`);\n return instance.getErrorsMessages();\n }\n};\n$.each('addError updateError'.split(' '), function (i, method) {\n window.ParsleyUI[method] = function (instance, name, message, assert, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils.warnOnce(`Accessing ParsleyUI is deprecated. Call '${method}' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance[method](name, {message, assert, updateClass});\n };\n});\n\n// Alleviate glaring Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1250521\n// See also https://github.com/guillaumepotier/Parsley.js/issues/1068\nif (/firefox/i.test(navigator.userAgent)) {\n $(document).on('change', 'select', evt => {\n $(evt.target).trigger('input');\n });\n}\n\n// ### PARSLEY auto-binding\n// Prevent it by setting `ParsleyConfig.autoBind` to `false`\nif (false !== window.ParsleyConfig.autoBind) {\n $(function () {\n // Works only on `data-parsley-validate`.\n if ($('[data-parsley-validate]').length)\n $('[data-parsley-validate]').parsley();\n });\n}\n\nexport default Parsley;\n","import $ from 'jquery';\n\nimport Parsley from './main';\n\n$.extend(true, Parsley, {\n asyncValidators: {\n 'default': {\n fn: function (xhr) {\n // By default, only status 2xx are deemed successful.\n // Note: we use status instead of state() because responses with status 200\n // but invalid messages (e.g. an empty body for content type set to JSON) will\n // result in state() === 'rejected'.\n return xhr.status >= 200 && xhr.status < 300;\n },\n url: false\n },\n reverse: {\n fn: function (xhr) {\n // If reverse option is set, a failing ajax request is considered successful\n return xhr.status < 200 || xhr.status >= 300;\n },\n url: false\n }\n },\n\n addAsyncValidator: function (name, fn, url, options) {\n Parsley.asyncValidators[name] = {\n fn: fn,\n url: url || false,\n options: options || {}\n };\n\n return this;\n }\n\n});\n\nParsley.addValidator('remote', {\n requirementType: {\n '': 'string',\n 'validator': 'string',\n 'reverse': 'boolean',\n 'options': 'object'\n },\n\n validateString: function (value, url, options, instance) {\n var data = {};\n var ajaxOptions;\n var csr;\n var validator = options.validator || (true === options.reverse ? 'reverse' : 'default');\n\n if ('undefined' === typeof Parsley.asyncValidators[validator])\n throw new Error('Calling an undefined async validator: `' + validator + '`');\n\n url = Parsley.asyncValidators[validator].url || url;\n\n // Fill current value\n if (url.indexOf('{value}') > -1) {\n url = url.replace('{value}', encodeURIComponent(value));\n } else {\n data[instance.$element.attr('name') || instance.$element.attr('id')] = value;\n }\n\n // Merge options passed in from the function with the ones in the attribute\n var remoteOptions = $.extend(true, options.options || {} , Parsley.asyncValidators[validator].options);\n\n // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`\n ajaxOptions = $.extend(true, {}, {\n url: url,\n data: data,\n type: 'GET'\n }, remoteOptions);\n\n // Generate store key based on ajax options\n instance.trigger('field:ajaxoptions', instance, ajaxOptions);\n\n csr = $.param(ajaxOptions);\n\n // Initialise querry cache\n if ('undefined' === typeof Parsley._remoteCache)\n Parsley._remoteCache = {};\n\n // Try to retrieve stored xhr\n var xhr = Parsley._remoteCache[csr] = Parsley._remoteCache[csr] || $.ajax(ajaxOptions);\n\n var handleXhr = function () {\n var result = Parsley.asyncValidators[validator].fn.call(instance, xhr, url, options);\n if (!result) // Map falsy results to rejected promise\n result = $.Deferred().reject();\n return $.when(result);\n };\n\n return xhr.then(handleXhr, handleXhr);\n },\n\n priority: -1\n});\n\nParsley.on('form:submit', function () {\n Parsley._remoteCache = {};\n});\n\nwindow.ParsleyExtend.addAsyncValidator = function () {\n ParsleyUtils.warnOnce('Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`');\n return Parsley.addAsyncValidator(...arguments);\n};\n","// This is included with the Parsley library itself,\n// thus there is no use in adding it to your project.\nimport Parsley from '../parsley/main';\n\nParsley.addMessages('en', {\n defaultMessage: \"This value seems to be invalid.\",\n type: {\n email: \"This value should be a valid email.\",\n url: \"This value should be a valid url.\",\n number: \"This value should be a valid number.\",\n integer: \"This value should be a valid integer.\",\n digits: \"This value should be digits.\",\n alphanum: \"This value should be alphanumeric.\"\n },\n notblank: \"This value should not be blank.\",\n required: \"This value is required.\",\n pattern: \"This value seems to be invalid.\",\n min: \"This value should be greater than or equal to %s.\",\n max: \"This value should be lower than or equal to %s.\",\n range: \"This value should be between %s and %s.\",\n minlength: \"This value is too short. It should have %s characters or more.\",\n maxlength: \"This value is too long. It should have %s characters or fewer.\",\n length: \"This value length is invalid. It should be between %s and %s characters long.\",\n mincheck: \"You must select at least %s choices.\",\n maxcheck: \"You must select %s choices or fewer.\",\n check: \"You must select between %s and %s choices.\",\n equalto: \"This value should be the same.\"\n});\n\nParsley.setLocale('en');\n","import $ from 'jquery';\nimport Parsley from './parsley/main';\nimport './parsley/pubsub';\nimport './parsley/remote';\nimport './i18n/en';\n\nexport default Parsley;\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/assets/js/popper/popper.js b/assets/js/popper/popper.js new file mode 100644 index 00000000..a551fef5 --- /dev/null +++ b/assets/js/popper/popper.js @@ -0,0 +1,1961 @@ +/*! + * @popperjs/core v2.6.0 - MIT License + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = global || self, factory(global.Popper = {})); +}(this, (function (exports) { + 'use strict'; + + function getBoundingClientRect(element) + { + var rect = element.getBoundingClientRect(); + return { + width: rect.width, + height: rect.height, + top: rect.top, + right: rect.right, + bottom: rect.bottom, + left: rect.left, + x: rect.left, + y: rect.top + }; + } + + /*:: import type { Window } from '../types'; */ + + /*:: declare function getWindow(node: Node | Window): Window; */ + function getWindow(node) + { + if (node.toString() !== '[object Window]') { + var ownerDocument = node.ownerDocument; + return ownerDocument ? ownerDocument.defaultView || window : window; + } + + return node; + } + + function getWindowScroll(node) + { + var win = getWindow(node); + var scrollLeft = win.pageXOffset; + var scrollTop = win.pageYOffset; + return { + scrollLeft: scrollLeft, + scrollTop: scrollTop + }; + } + + /*:: declare function isElement(node: mixed): boolean %checks(node instanceof + Element); */ + + function isElement(node) + { + var OwnElement = getWindow(node).Element; + return node instanceof OwnElement || node instanceof Element; + } + /*:: declare function isHTMLElement(node: mixed): boolean %checks(node instanceof + HTMLElement); */ + + + function isHTMLElement(node) + { + var OwnElement = getWindow(node).HTMLElement; + return node instanceof OwnElement || node instanceof HTMLElement; + } + /*:: declare function isShadowRoot(node: mixed): boolean %checks(node instanceof + ShadowRoot); */ + + + function isShadowRoot(node) + { + var OwnElement = getWindow(node).ShadowRoot; + return node instanceof OwnElement || node instanceof ShadowRoot; + } + + function getHTMLElementScroll(element) + { + return { + scrollLeft: element.scrollLeft, + scrollTop: element.scrollTop + }; + } + + function getNodeScroll(node) + { + if (node === getWindow(node) || !isHTMLElement(node)) { + return getWindowScroll(node); + } else { + return getHTMLElementScroll(node); + } + } + + function getNodeName(element) + { + return element ? (element.nodeName || '').toLowerCase() : null; + } + + function getDocumentElement(element) + { + // $FlowFixMe[incompatible-return]: assume body is always available + return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing] + element.document) || window.document).documentElement; + } + + function getWindowScrollBarX(element) + { + // If has a CSS width greater than the viewport, then this will be + // incorrect for RTL. + // Popper 1 is broken in this case and never had a bug report so let's assume + // it's not an issue. I don't think anyone ever specifies width on + // anyway. + // Browsers where the left scrollbar doesn't cause an issue report `0` for + // this (e.g. Edge 2019, IE11, Safari) + return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft; + } + + function getComputedStyle(element) + { + return getWindow(element).getComputedStyle(element); + } + + function isScrollParent(element) + { + // Firefox wants us to check `-x` and `-y` variations as well + var _getComputedStyle = getComputedStyle(element), + overflow = _getComputedStyle.overflow, + overflowX = _getComputedStyle.overflowX, + overflowY = _getComputedStyle.overflowY; + + return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX); + } + + // Composite means it takes into account transforms as well as layout. + + function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) + { + if (isFixed === void 0) { + isFixed = false; + } + + var documentElement = getDocumentElement(offsetParent); + var rect = getBoundingClientRect(elementOrVirtualElement); + var isOffsetParentAnElement = isHTMLElement(offsetParent); + var scroll = { + scrollLeft: 0, + scrollTop: 0 + }; + var offsets = { + x: 0, + y: 0 + }; + + if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { + if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078 + isScrollParent(documentElement)) { + scroll = getNodeScroll(offsetParent); + } + + if (isHTMLElement(offsetParent)) { + offsets = getBoundingClientRect(offsetParent); + offsets.x += offsetParent.clientLeft; + offsets.y += offsetParent.clientTop; + } else if (documentElement) { + offsets.x = getWindowScrollBarX(documentElement); + } + } + + return { + x: rect.left + scroll.scrollLeft - offsets.x, + y: rect.top + scroll.scrollTop - offsets.y, + width: rect.width, + height: rect.height + }; + } + + // Returns the layout rect of an element relative to its offsetParent. Layout + // means it doesn't take into account transforms. + function getLayoutRect(element) + { + return { + x: element.offsetLeft, + y: element.offsetTop, + width: element.offsetWidth, + height: element.offsetHeight + }; + } + + function getParentNode(element) + { + if (getNodeName(element) === 'html') { + return element; + } + + return ( // this is a quicker (but less type safe) way to save quite some bytes from the bundle + // $FlowFixMe[incompatible-return] + // $FlowFixMe[prop-missing] + element.assignedSlot || // step into the shadow DOM of the parent of a slotted node + element.parentNode || // DOM Element detected + // $FlowFixMe[incompatible-return]: need a better way to handle this... + element.host || // ShadowRoot detected + // $FlowFixMe[incompatible-call]: HTMLElement is a Node + getDocumentElement(element) // fallback + + ); + } + + function getScrollParent(node) + { + if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) { + // $FlowFixMe[incompatible-return]: assume body is always available + return node.ownerDocument.body; + } + + if (isHTMLElement(node) && isScrollParent(node)) { + return node; + } + + return getScrollParent(getParentNode(node)); + } + + /* + given a DOM element, return the list of all scroll parents, up the list of ancesors + until we get to the top window object. This list is what we attach scroll listeners + to, because if any of these parent elements scroll, we'll need to re-calculate the + reference element's position. + */ + + function listScrollParents(element, list) + { + if (list === void 0) { + list = []; + } + + var scrollParent = getScrollParent(element); + var isBody = getNodeName(scrollParent) === 'body'; + var win = getWindow(scrollParent); + var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent; + var updatedList = list.concat(target); + return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here + updatedList.concat(listScrollParents(getParentNode(target))); + } + + function isTableElement(element) + { + return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0; + } + + function getTrueOffsetParent(element) + { + if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837 + getComputedStyle(element).position === 'fixed') { + return null; + } + + var offsetParent = element.offsetParent; + + if (offsetParent) { + var html = getDocumentElement(offsetParent); + + if (getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static' && getComputedStyle(html).position !== 'static') { + return html; + } + } + + return offsetParent; + } // `.offsetParent` reports `null` for fixed elements, while absolute elements + // return the containing block + + + function getContainingBlock(element) + { + var currentNode = getParentNode(element); + + while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) { + var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that + // create a containing block. + + if (css.transform !== 'none' || css.perspective !== 'none' || css.willChange && css.willChange !== 'auto') { + return currentNode; + } else { + currentNode = currentNode.parentNode; + } + } + + return null; + } // Gets the closest ancestor positioned element. Handles some edge cases, + // such as table ancestors and cross browser bugs. + + + function getOffsetParent(element) + { + var window = getWindow(element); + var offsetParent = getTrueOffsetParent(element); + + while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') { + offsetParent = getTrueOffsetParent(offsetParent); + } + + if (offsetParent && getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static') { + return window; + } + + return offsetParent || getContainingBlock(element) || window; + } + + var top = 'top'; + var bottom = 'bottom'; + var right = 'right'; + var left = 'left'; + var auto = 'auto'; + var basePlacements = [top, bottom, right, left]; + var start = 'start'; + var end = 'end'; + var clippingParents = 'clippingParents'; + var viewport = 'viewport'; + var popper = 'popper'; + var reference = 'reference'; + var variationPlacements = /*#__PURE__*/ basePlacements.reduce(function (acc, placement) { + return acc.concat([placement + "-" + start, placement + "-" + end]); + }, []); + var placements = /*#__PURE__*/ [].concat(basePlacements, [auto]).reduce(function (acc, placement) { + return acc.concat([placement, placement + "-" + start, placement + "-" + end]); + }, []); // modifiers that need to read the DOM + + var beforeRead = 'beforeRead'; + var read = 'read'; + var afterRead = 'afterRead'; // pure-logic modifiers + + var beforeMain = 'beforeMain'; + var main = 'main'; + var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state) + + var beforeWrite = 'beforeWrite'; + var write = 'write'; + var afterWrite = 'afterWrite'; + var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite]; + + function order(modifiers) + { + var map = new Map(); + var visited = new Set(); + var result = []; + modifiers.forEach(function (modifier) { + map.set(modifier.name, modifier); + }); // On visiting object, check for its dependencies and visit them recursively + + function sort(modifier) + { + visited.add(modifier.name); + var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []); + requires.forEach(function (dep) { + if (!visited.has(dep)) { + var depModifier = map.get(dep); + + if (depModifier) { + sort(depModifier); + } + } + }); + result.push(modifier); + } + + modifiers.forEach(function (modifier) { + if (!visited.has(modifier.name)) { + // check for visited object + sort(modifier); + } + }); + return result; + } + + function orderModifiers(modifiers) + { + // order based on dependencies + var orderedModifiers = order(modifiers); // order based on phase + + return modifierPhases.reduce(function (acc, phase) { + return acc.concat(orderedModifiers.filter(function (modifier) { + return modifier.phase === phase; + })); + }, []); + } + + function debounce(fn) + { + var pending; + return function () { + if (!pending) { + pending = new Promise(function (resolve) { + Promise.resolve().then(function () { + pending = undefined; + resolve(fn()); + }); + }); + } + + return pending; + }; + } + + function format(str) + { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + return [].concat(args).reduce(function (p, c) { + return p.replace(/%s/, c); + }, str); + } + + var INVALID_MODIFIER_ERROR = 'Popper: modifier "%s" provided an invalid %s property, expected %s but got %s'; + var MISSING_DEPENDENCY_ERROR = 'Popper: modifier "%s" requires "%s", but "%s" modifier is not available'; + var VALID_PROPERTIES = ['name', 'enabled', 'phase', 'fn', 'effect', 'requires', 'options']; + + function validateModifiers(modifiers) + { + modifiers.forEach(function (modifier) { + Object.keys(modifier).forEach(function (key) { + switch (key) { + case 'name': + if (typeof modifier.name !== 'string') { + console.error(format(INVALID_MODIFIER_ERROR, String(modifier.name), '"name"', '"string"', "\"" + String(modifier.name) + "\"")); + } + + break; + + case 'enabled': + if (typeof modifier.enabled !== 'boolean') { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"enabled"', '"boolean"', "\"" + String(modifier.enabled) + "\"")); + } + + case 'phase': + if (modifierPhases.indexOf(modifier.phase) < 0) { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"phase"', "either " + modifierPhases.join(', '), "\"" + String(modifier.phase) + "\"")); + } + + break; + + case 'fn': + if (typeof modifier.fn !== 'function') { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"fn"', '"function"', "\"" + String(modifier.fn) + "\"")); + } + + break; + + case 'effect': + if (typeof modifier.effect !== 'function') { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"effect"', '"function"', "\"" + String(modifier.fn) + "\"")); + } + + break; + + case 'requires': + if (!Array.isArray(modifier.requires)) { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"requires"', '"array"', "\"" + String(modifier.requires) + "\"")); + } + + break; + + case 'requiresIfExists': + if (!Array.isArray(modifier.requiresIfExists)) { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"requiresIfExists"', '"array"', "\"" + String(modifier.requiresIfExists) + "\"")); + } + + break; + + case 'options': + case 'data': + break; + + default: + console.error("PopperJS: an invalid property has been provided to the \"" + modifier.name + "\" modifier, valid properties are " + VALID_PROPERTIES.map(function (s) { + return "\"" + s + "\""; + }).join(', ') + "; but \"" + key + "\" was provided."); + } + + modifier.requires && modifier.requires.forEach(function (requirement) { + if (modifiers.find(function (mod) { + return mod.name === requirement; + }) == null) { + console.error(format(MISSING_DEPENDENCY_ERROR, String(modifier.name), requirement, requirement)); + } + }); + }); + }); + } + + function uniqueBy(arr, fn) + { + var identifiers = new Set(); + return arr.filter(function (item) { + var identifier = fn(item); + + if (!identifiers.has(identifier)) { + identifiers.add(identifier); + return true; + } + }); + } + + function getBasePlacement(placement) + { + return placement.split('-')[0]; + } + + function mergeByName(modifiers) + { + var merged = modifiers.reduce(function (merged, current) { + var existing = merged[current.name]; + merged[current.name] = existing ? Object.assign(Object.assign(Object.assign({}, existing), current), {}, { + options: Object.assign(Object.assign({}, existing.options), current.options), + data: Object.assign(Object.assign({}, existing.data), current.data) + }) : current; + return merged; + }, {}); // IE11 does not support Object.values + + return Object.keys(merged).map(function (key) { + return merged[key]; + }); + } + + function getViewportRect(element) + { + var win = getWindow(element); + var html = getDocumentElement(element); + var visualViewport = win.visualViewport; + var width = html.clientWidth; + var height = html.clientHeight; + var x = 0; + var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper + // can be obscured underneath it. + // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even + // if it isn't open, so if this isn't available, the popper will be detected + // to overflow the bottom of the screen too early. + + if (visualViewport) { + width = visualViewport.width; + height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently) + // In Chrome, it returns a value very close to 0 (+/-) but contains rounding + // errors due to floating point numbers, so we need to check precision. + // Safari returns a number <= 0, usually < -1 when pinch-zoomed + // Feature detection fails in mobile emulation mode in Chrome. + // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) < + // 0.001 + // Fallback here: "Not Safari" userAgent + + if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + x = visualViewport.offsetLeft; + y = visualViewport.offsetTop; + } + } + + return { + width: width, + height: height, + x: x + getWindowScrollBarX(element), + y: y + }; + } + + // of the `` and `` rect bounds if horizontally scrollable + + function getDocumentRect(element) + { + var html = getDocumentElement(element); + var winScroll = getWindowScroll(element); + var body = element.ownerDocument.body; + var width = Math.max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0); + var height = Math.max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0); + var x = -winScroll.scrollLeft + getWindowScrollBarX(element); + var y = -winScroll.scrollTop; + + if (getComputedStyle(body || html).direction === 'rtl') { + x += Math.max(html.clientWidth, body ? body.clientWidth : 0) - width; + } + + return { + width: width, + height: height, + x: x, + y: y + }; + } + + function contains(parent, child) + { + var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method + // then fallback to custom implementation with Shadow DOM support + if (parent.contains(child)) { + return true; + } else if (rootNode && isShadowRoot(rootNode)) { + var next = child; + + do { + if (next && parent.isSameNode(next)) { + return true; + } // $FlowFixMe[prop-missing]: need a better way to handle this... + + + next = next.parentNode || next.host; + } while (next); + } // Give up, the result is false + + + return false; + } + + function rectToClientRect(rect) + { + return Object.assign(Object.assign({}, rect), {}, { + left: rect.x, + top: rect.y, + right: rect.x + rect.width, + bottom: rect.y + rect.height + }); + } + + function getInnerBoundingClientRect(element) + { + var rect = getBoundingClientRect(element); + rect.top = rect.top + element.clientTop; + rect.left = rect.left + element.clientLeft; + rect.bottom = rect.top + element.clientHeight; + rect.right = rect.left + element.clientWidth; + rect.width = element.clientWidth; + rect.height = element.clientHeight; + rect.x = rect.left; + rect.y = rect.top; + return rect; + } + + function getClientRectFromMixedType(element, clippingParent) + { + return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element))); + } // A "clipping parent" is an overflowable container with the characteristic of + // clipping (or hiding) overflowing elements with a position different from + // `initial` + + + function getClippingParents(element) + { + var clippingParents = listScrollParents(getParentNode(element)); + var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0; + var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element; + + if (!isElement(clipperElement)) { + return []; + } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414 + + + return clippingParents.filter(function (clippingParent) { + return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body'; + }); + } // Gets the maximum area that the element is visible in due to any number of + // clipping parents + + + function getClippingRect(element, boundary, rootBoundary) + { + var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary); + var clippingParents = [].concat(mainClippingParents, [rootBoundary]); + var firstClippingParent = clippingParents[0]; + var clippingRect = clippingParents.reduce(function (accRect, clippingParent) { + var rect = getClientRectFromMixedType(element, clippingParent); + accRect.top = Math.max(rect.top, accRect.top); + accRect.right = Math.min(rect.right, accRect.right); + accRect.bottom = Math.min(rect.bottom, accRect.bottom); + accRect.left = Math.max(rect.left, accRect.left); + return accRect; + }, getClientRectFromMixedType(element, firstClippingParent)); + clippingRect.width = clippingRect.right - clippingRect.left; + clippingRect.height = clippingRect.bottom - clippingRect.top; + clippingRect.x = clippingRect.left; + clippingRect.y = clippingRect.top; + return clippingRect; + } + + function getVariation(placement) + { + return placement.split('-')[1]; + } + + function getMainAxisFromPlacement(placement) + { + return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y'; + } + + function computeOffsets(_ref) + { + var reference = _ref.reference, + element = _ref.element, + placement = _ref.placement; + var basePlacement = placement ? getBasePlacement(placement) : null; + var variation = placement ? getVariation(placement) : null; + var commonX = reference.x + reference.width / 2 - element.width / 2; + var commonY = reference.y + reference.height / 2 - element.height / 2; + var offsets; + + switch (basePlacement) { + case top: + offsets = { + x: commonX, + y: reference.y - element.height + }; + break; + + case bottom: + offsets = { + x: commonX, + y: reference.y + reference.height + }; + break; + + case right: + offsets = { + x: reference.x + reference.width, + y: commonY + }; + break; + + case left: + offsets = { + x: reference.x - element.width, + y: commonY + }; + break; + + default: + offsets = { + x: reference.x, + y: reference.y + }; + } + + var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null; + + if (mainAxis != null) { + var len = mainAxis === 'y' ? 'height' : 'width'; + + switch (variation) { + case start: + offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2); + break; + + case end: + offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2); + break; + } + } + + return offsets; + } + + function getFreshSideObject() + { + return { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + + function mergePaddingObject(paddingObject) + { + return Object.assign(Object.assign({}, getFreshSideObject()), paddingObject); + } + + function expandToHashMap(value, keys) + { + return keys.reduce(function (hashMap, key) { + hashMap[key] = value; + return hashMap; + }, {}); + } + + function detectOverflow(state, options) + { + if (options === void 0) { + options = {}; + } + + var _options = options, + _options$placement = _options.placement, + placement = _options$placement === void 0 ? state.placement : _options$placement, + _options$boundary = _options.boundary, + boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, + _options$rootBoundary = _options.rootBoundary, + rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, + _options$elementConte = _options.elementContext, + elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, + _options$altBoundary = _options.altBoundary, + altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary, + _options$padding = _options.padding, + padding = _options$padding === void 0 ? 0 : _options$padding; + var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); + var altContext = elementContext === popper ? reference : popper; + var referenceElement = state.elements.reference; + var popperRect = state.rects.popper; + var element = state.elements[altBoundary ? altContext : elementContext]; + var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary); + var referenceClientRect = getBoundingClientRect(referenceElement); + var popperOffsets = computeOffsets({ + reference: referenceClientRect, + element: popperRect, + strategy: 'absolute', + placement: placement + }); + var popperClientRect = rectToClientRect(Object.assign(Object.assign({}, popperRect), popperOffsets)); + var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect + // 0 or negative = within the clipping rect + + var overflowOffsets = { + top: clippingClientRect.top - elementClientRect.top + paddingObject.top, + bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom, + left: clippingClientRect.left - elementClientRect.left + paddingObject.left, + right: elementClientRect.right - clippingClientRect.right + paddingObject.right + }; + var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element + + if (elementContext === popper && offsetData) { + var offset = offsetData[placement]; + Object.keys(overflowOffsets).forEach(function (key) { + var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1; + var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x'; + overflowOffsets[key] += offset[axis] * multiply; + }); + } + + return overflowOffsets; + } + + var INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.'; + var INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.'; + var DEFAULT_OPTIONS = { + placement: 'bottom', + modifiers: [], + strategy: 'absolute' + }; + + function areValidElements() + { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return !args.some(function (element) { + return !(element && typeof element.getBoundingClientRect === 'function'); + }); + } + + function popperGenerator(generatorOptions) + { + if (generatorOptions === void 0) { + generatorOptions = {}; + } + + var _generatorOptions = generatorOptions, + _generatorOptions$def = _generatorOptions.defaultModifiers, + defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def, + _generatorOptions$def2 = _generatorOptions.defaultOptions, + defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2; + return function createPopper(reference, popper, options) + { + if (options === void 0) { + options = defaultOptions; + } + + var state = { + placement: 'bottom', + orderedModifiers: [], + options: Object.assign(Object.assign({}, DEFAULT_OPTIONS), defaultOptions), + modifiersData: {}, + elements: { + reference: reference, + popper: popper + }, + attributes: {}, + styles: {} + }; + var effectCleanupFns = []; + var isDestroyed = false; + var instance = { + state: state, + setOptions: function setOptions(options) + { + cleanupModifierEffects(); + state.options = Object.assign(Object.assign(Object.assign({}, defaultOptions), state.options), options); + state.scrollParents = { + reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [], + popper: listScrollParents(popper) + }; // Orders the modifiers based on their dependencies and `phase` + // properties + + var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers + + state.orderedModifiers = orderedModifiers.filter(function (m) { + return m.enabled; + }); // Validate the provided modifiers so that the consumer will get warned + // if one of the modifiers is invalid for any reason + + { + var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) { + var name = _ref.name; + return name; + }); + validateModifiers(modifiers); + + if (getBasePlacement(state.options.placement) === auto) { + var flipModifier = state.orderedModifiers.find(function (_ref2) { + var name = _ref2.name; + return name === 'flip'; + }); + + if (!flipModifier) { + console.error(['Popper: "auto" placements require the "flip" modifier be', 'present and enabled to work.'].join(' ')); + } + } + + var _getComputedStyle = getComputedStyle(popper), + marginTop = _getComputedStyle.marginTop, + marginRight = _getComputedStyle.marginRight, + marginBottom = _getComputedStyle.marginBottom, + marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can + // cause bugs with positioning, so we'll warn the consumer + + + if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) { + return parseFloat(margin); + })) { + console.warn(['Popper: CSS "margin" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' ')); + } + } + + runModifierEffects(); + return instance.update(); + }, + // Sync update – it will always be executed, even if not necessary. This + // is useful for low frequency updates where sync behavior simplifies the + // logic. + // For high frequency updates (e.g. `resize` and `scroll` events), always + // prefer the async Popper#update method + forceUpdate: function forceUpdate() + { + if (isDestroyed) { + return; + } + + var _state$elements = state.elements, + reference = _state$elements.reference, + popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements + // anymore + + if (!areValidElements(reference, popper)) { + { + console.error(INVALID_ELEMENT_ERROR); + } + + return; + } // Store the reference and popper rects to be read by modifiers + + + state.rects = { + reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'), + popper: getLayoutRect(popper) + }; // Modifiers have the ability to reset the current update cycle. The + // most common use case for this is the `flip` modifier changing the + // placement, which then needs to re-run all the modifiers, because the + // logic was previously ran for the previous placement and is therefore + // stale/incorrect + + state.reset = false; + state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier + // is filled with the initial data specified by the modifier. This means + // it doesn't persist and is fresh on each update. + // To ensure persistent data, use `${name}#persistent` + + state.orderedModifiers.forEach(function (modifier) { + return state.modifiersData[modifier.name] = Object.assign({}, modifier.data); + }); + var __debug_loops__ = 0; + + for (var index = 0; index < state.orderedModifiers.length; index++) { + { + __debug_loops__ += 1; + + if (__debug_loops__ > 100) { + console.error(INFINITE_LOOP_ERROR); + break; + } + } + + if (state.reset === true) { + state.reset = false; + index = -1; + continue; + } + + var _state$orderedModifie = state.orderedModifiers[index], + fn = _state$orderedModifie.fn, + _state$orderedModifie2 = _state$orderedModifie.options, + _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2, + name = _state$orderedModifie.name; + + if (typeof fn === 'function') { + state = fn({ + state: state, + options: _options, + name: name, + instance: instance + }) || state; + } + } + }, + // Async and optimistically optimized update – it will not be executed if + // not necessary (debounced to run at most once-per-tick) + update: debounce(function () { + return new Promise(function (resolve) { + instance.forceUpdate(); + resolve(state); + }); + }), + destroy: function destroy() + { + cleanupModifierEffects(); + isDestroyed = true; + } + }; + + if (!areValidElements(reference, popper)) { + { + console.error(INVALID_ELEMENT_ERROR); + } + + return instance; + } + + instance.setOptions(options).then(function (state) { + if (!isDestroyed && options.onFirstUpdate) { + options.onFirstUpdate(state); + } + }); // Modifiers have the ability to execute arbitrary code before the first + // update cycle runs. They will be executed in the same order as the update + // cycle. This is useful when a modifier adds some persistent data that + // other modifiers need to use, but the modifier is run after the dependent + // one. + + function runModifierEffects() + { + state.orderedModifiers.forEach(function (_ref3) { + var name = _ref3.name, + _ref3$options = _ref3.options, + options = _ref3$options === void 0 ? {} : _ref3$options, + effect = _ref3.effect; + + if (typeof effect === 'function') { + var cleanupFn = effect({ + state: state, + name: name, + instance: instance, + options: options + }); + + var noopFn = function noopFn() + {}; + + effectCleanupFns.push(cleanupFn || noopFn); + } + }); + } + + function cleanupModifierEffects() + { + effectCleanupFns.forEach(function (fn) { + return fn(); + }); + effectCleanupFns = []; + } + + return instance; + }; + } + + var passive = { + passive: true + }; + + function effect(_ref) + { + var state = _ref.state, + instance = _ref.instance, + options = _ref.options; + var _options$scroll = options.scroll, + scroll = _options$scroll === void 0 ? true : _options$scroll, + _options$resize = options.resize, + resize = _options$resize === void 0 ? true : _options$resize; + var window = getWindow(state.elements.popper); + var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper); + + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.addEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.addEventListener('resize', instance.update, passive); + } + + return function () { + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.removeEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.removeEventListener('resize', instance.update, passive); + } + }; + } // eslint-disable-next-line import/no-unused-modules + + + var eventListeners = { + name: 'eventListeners', + enabled: true, + phase: 'write', + fn: function fn() + {}, + effect: effect, + data: {} + }; + + function popperOffsets(_ref) + { + var state = _ref.state, + name = _ref.name; + // Offsets are the actual position the popper needs to have to be + // properly positioned near its reference element + // This is the most basic placement, and will be adjusted by + // the modifiers in the next step + state.modifiersData[name] = computeOffsets({ + reference: state.rects.reference, + element: state.rects.popper, + strategy: 'absolute', + placement: state.placement + }); + } // eslint-disable-next-line import/no-unused-modules + + + var popperOffsets$1 = { + name: 'popperOffsets', + enabled: true, + phase: 'read', + fn: popperOffsets, + data: {} + }; + + var unsetSides = { + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto' + }; // Round the offsets to the nearest suitable subpixel based on the DPR. + // Zooming can change the DPR, but it seems to report a value that will + // cleanly divide the values into the appropriate subpixels. + + function roundOffsetsByDPR(_ref) + { + var x = _ref.x, + y = _ref.y; + var win = window; + var dpr = win.devicePixelRatio || 1; + return { + x: Math.round(x * dpr) / dpr || 0, + y: Math.round(y * dpr) / dpr || 0 + }; + } + + function mapToStyles(_ref2) + { + var _Object$assign2; + + var popper = _ref2.popper, + popperRect = _ref2.popperRect, + placement = _ref2.placement, + offsets = _ref2.offsets, + position = _ref2.position, + gpuAcceleration = _ref2.gpuAcceleration, + adaptive = _ref2.adaptive, + roundOffsets = _ref2.roundOffsets; + + var _ref3 = roundOffsets ? roundOffsetsByDPR(offsets) : offsets, + _ref3$x = _ref3.x, + x = _ref3$x === void 0 ? 0 : _ref3$x, + _ref3$y = _ref3.y, + y = _ref3$y === void 0 ? 0 : _ref3$y; + + var hasX = offsets.hasOwnProperty('x'); + var hasY = offsets.hasOwnProperty('y'); + var sideX = left; + var sideY = top; + var win = window; + + if (adaptive) { + var offsetParent = getOffsetParent(popper); + + if (offsetParent === getWindow(popper)) { + offsetParent = getDocumentElement(popper); + } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it + + /*:: offsetParent = (offsetParent: Element); */ + + + if (placement === top) { + sideY = bottom; + y -= offsetParent.clientHeight - popperRect.height; + y *= gpuAcceleration ? 1 : -1; + } + + if (placement === left) { + sideX = right; + x -= offsetParent.clientWidth - popperRect.width; + x *= gpuAcceleration ? 1 : -1; + } + } + + var commonStyles = Object.assign({ + position: position + }, adaptive && unsetSides); + + if (gpuAcceleration) { + var _Object$assign; + + return Object.assign(Object.assign({}, commonStyles), {}, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign)); + } + + return Object.assign(Object.assign({}, commonStyles), {}, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2)); + } + + function computeStyles(_ref4) + { + var state = _ref4.state, + options = _ref4.options; + var _options$gpuAccelerat = options.gpuAcceleration, + gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat, + _options$adaptive = options.adaptive, + adaptive = _options$adaptive === void 0 ? true : _options$adaptive, + _options$roundOffsets = options.roundOffsets, + roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets; + + { + var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || ''; + + if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) { + return transitionProperty.indexOf(property) >= 0; + })) { + console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: "transform", "top", "right", "bottom", "left".', '\n\n', 'Disable the "computeStyles" modifier\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\n\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' ')); + } + } + + var commonStyles = { + placement: getBasePlacement(state.placement), + popper: state.elements.popper, + popperRect: state.rects.popper, + gpuAcceleration: gpuAcceleration + }; + + if (state.modifiersData.popperOffsets != null) { + state.styles.popper = Object.assign(Object.assign({}, state.styles.popper), mapToStyles(Object.assign(Object.assign({}, commonStyles), {}, { + offsets: state.modifiersData.popperOffsets, + position: state.options.strategy, + adaptive: adaptive, + roundOffsets: roundOffsets + }))); + } + + if (state.modifiersData.arrow != null) { + state.styles.arrow = Object.assign(Object.assign({}, state.styles.arrow), mapToStyles(Object.assign(Object.assign({}, commonStyles), {}, { + offsets: state.modifiersData.arrow, + position: 'absolute', + adaptive: false, + roundOffsets: roundOffsets + }))); + } + + state.attributes.popper = Object.assign(Object.assign({}, state.attributes.popper), {}, { + 'data-popper-placement': state.placement + }); + } // eslint-disable-next-line import/no-unused-modules + + + var computeStyles$1 = { + name: 'computeStyles', + enabled: true, + phase: 'beforeWrite', + fn: computeStyles, + data: {} + }; + + // and applies them to the HTMLElements such as popper and arrow + + function applyStyles(_ref) + { + var state = _ref.state; + Object.keys(state.elements).forEach(function (name) { + var style = state.styles[name] || {}; + var attributes = state.attributes[name] || {}; + var element = state.elements[name]; // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } // Flow doesn't support to extend this property, but it's the most + // effective way to apply styles to an HTMLElement + // $FlowFixMe[cannot-write] + + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (name) { + var value = attributes[name]; + + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value === true ? '' : value); + } + }); + }); + } + + function effect$1(_ref2) + { + var state = _ref2.state; + var initialStyles = { + popper: { + position: state.options.strategy, + left: '0', + top: '0', + margin: '0' + }, + arrow: { + position: 'absolute' + }, + reference: {} + }; + Object.assign(state.elements.popper.style, initialStyles.popper); + + if (state.elements.arrow) { + Object.assign(state.elements.arrow.style, initialStyles.arrow); + } + + return function () { + Object.keys(state.elements).forEach(function (name) { + var element = state.elements[name]; + var attributes = state.attributes[name] || {}; + var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them + + var style = styleProperties.reduce(function (style, property) { + style[property] = ''; + return style; + }, {}); // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (attribute) { + element.removeAttribute(attribute); + }); + }); + }; + } // eslint-disable-next-line import/no-unused-modules + + + var applyStyles$1 = { + name: 'applyStyles', + enabled: true, + phase: 'write', + fn: applyStyles, + effect: effect$1, + requires: ['computeStyles'] + }; + + function distanceAndSkiddingToXY(placement, rects, offset) + { + var basePlacement = getBasePlacement(placement); + var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1; + + var _ref = typeof offset === 'function' ? offset(Object.assign(Object.assign({}, rects), {}, { + placement: placement + })) : offset, + skidding = _ref[0], + distance = _ref[1]; + + skidding = skidding || 0; + distance = (distance || 0) * invertDistance; + return [left, right].indexOf(basePlacement) >= 0 ? { + x: distance, + y: skidding + } : { + x: skidding, + y: distance + }; + } + + function offset(_ref2) + { + var state = _ref2.state, + options = _ref2.options, + name = _ref2.name; + var _options$offset = options.offset, + offset = _options$offset === void 0 ? [0, 0] : _options$offset; + var data = placements.reduce(function (acc, placement) { + acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset); + return acc; + }, {}); + var _data$state$placement = data[state.placement], + x = _data$state$placement.x, + y = _data$state$placement.y; + + if (state.modifiersData.popperOffsets != null) { + state.modifiersData.popperOffsets.x += x; + state.modifiersData.popperOffsets.y += y; + } + + state.modifiersData[name] = data; + } // eslint-disable-next-line import/no-unused-modules + + + var offset$1 = { + name: 'offset', + enabled: true, + phase: 'main', + requires: ['popperOffsets'], + fn: offset + }; + + var hash = { + left: 'right', + right: 'left', + bottom: 'top', + top: 'bottom' + }; + + function getOppositePlacement(placement) + { + return placement.replace(/left|right|bottom|top/g, function (matched) { + return hash[matched]; + }); + } + + var hash$1 = { + start: 'end', + end: 'start' + }; + + function getOppositeVariationPlacement(placement) + { + return placement.replace(/start|end/g, function (matched) { + return hash$1[matched]; + }); + } + + /*:: type OverflowsMap = { [ComputedPlacement]: number }; */ + + /*;; type OverflowsMap = { [key in ComputedPlacement]: number }; */ + function computeAutoPlacement(state, options) + { + if (options === void 0) { + options = {}; + } + + var _options = options, + placement = _options.placement, + boundary = _options.boundary, + rootBoundary = _options.rootBoundary, + padding = _options.padding, + flipVariations = _options.flipVariations, + _options$allowedAutoP = _options.allowedAutoPlacements, + allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP; + var variation = getVariation(placement); + var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) { + return getVariation(placement) === variation; + }) : basePlacements; + var allowedPlacements = placements$1.filter(function (placement) { + return allowedAutoPlacements.indexOf(placement) >= 0; + }); + + if (allowedPlacements.length === 0) { + allowedPlacements = placements$1; + + { + console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, "auto" cannot be used to allow "bottom-start".', 'Use "auto-start" instead.'].join(' ')); + } + } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions... + + + var overflows = allowedPlacements.reduce(function (acc, placement) { + acc[placement] = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding + })[getBasePlacement(placement)]; + return acc; + }, {}); + return Object.keys(overflows).sort(function (a, b) { + return overflows[a] - overflows[b]; + }); + } + + function getExpandedFallbackPlacements(placement) + { + if (getBasePlacement(placement) === auto) { + return []; + } + + var oppositePlacement = getOppositePlacement(placement); + return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)]; + } + + function flip(_ref) + { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + + if (state.modifiersData[name]._skip) { + return; + } + + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis, + specifiedFallbackPlacements = options.fallbackPlacements, + padding = options.padding, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + _options$flipVariatio = options.flipVariations, + flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio, + allowedAutoPlacements = options.allowedAutoPlacements; + var preferredPlacement = state.options.placement; + var basePlacement = getBasePlacement(preferredPlacement); + var isBasePlacement = basePlacement === preferredPlacement; + var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement)); + var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) { + return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + flipVariations: flipVariations, + allowedAutoPlacements: allowedAutoPlacements + }) : placement); + }, []); + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var checksMap = new Map(); + var makeFallbackChecks = true; + var firstFittingPlacement = placements[0]; + + for (var i = 0; i < placements.length; i++) { + var placement = placements[i]; + + var _basePlacement = getBasePlacement(placement); + + var isStartVariation = getVariation(placement) === start; + var isVertical = [top, bottom].indexOf(_basePlacement) >= 0; + var len = isVertical ? 'width' : 'height'; + var overflow = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + altBoundary: altBoundary, + padding: padding + }); + var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top; + + if (referenceRect[len] > popperRect[len]) { + mainVariationSide = getOppositePlacement(mainVariationSide); + } + + var altVariationSide = getOppositePlacement(mainVariationSide); + var checks = []; + + if (checkMainAxis) { + checks.push(overflow[_basePlacement] <= 0); + } + + if (checkAltAxis) { + checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0); + } + + if (checks.every(function (check) { + return check; + })) { + firstFittingPlacement = placement; + makeFallbackChecks = false; + break; + } + + checksMap.set(placement, checks); + } + + if (makeFallbackChecks) { + // `2` may be desired in some cases – research later + var numberOfChecks = flipVariations ? 3 : 1; + + var _loop = function _loop(_i) + { + var fittingPlacement = placements.find(function (placement) { + var checks = checksMap.get(placement); + + if (checks) { + return checks.slice(0, _i).every(function (check) { + return check; + }); + } + }); + + if (fittingPlacement) { + firstFittingPlacement = fittingPlacement; + return "break"; + } + }; + + for (var _i = numberOfChecks; _i > 0; _i--) { + var _ret = _loop(_i); + + if (_ret === "break") { + break; + } + } + } + + if (state.placement !== firstFittingPlacement) { + state.modifiersData[name]._skip = true; + state.placement = firstFittingPlacement; + state.reset = true; + } + } // eslint-disable-next-line import/no-unused-modules + + + var flip$1 = { + name: 'flip', + enabled: true, + phase: 'main', + fn: flip, + requiresIfExists: ['offset'], + data: { + _skip: false + } + }; + + function getAltAxis(axis) + { + return axis === 'x' ? 'y' : 'x'; + } + + function within(min, value, max) + { + return Math.max(min, Math.min(value, max)); + } + + function preventOverflow(_ref) + { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + padding = options.padding, + _options$tether = options.tether, + tether = _options$tether === void 0 ? true : _options$tether, + _options$tetherOffset = options.tetherOffset, + tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset; + var overflow = detectOverflow(state, { + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + altBoundary: altBoundary + }); + var basePlacement = getBasePlacement(state.placement); + var variation = getVariation(state.placement); + var isBasePlacement = !variation; + var mainAxis = getMainAxisFromPlacement(basePlacement); + var altAxis = getAltAxis(mainAxis); + var popperOffsets = state.modifiersData.popperOffsets; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign(Object.assign({}, state.rects), {}, { + placement: state.placement + })) : tetherOffset; + var data = { + x: 0, + y: 0 + }; + + if (!popperOffsets) { + return; + } + + if (checkMainAxis) { + var mainSide = mainAxis === 'y' ? top : left; + var altSide = mainAxis === 'y' ? bottom : right; + var len = mainAxis === 'y' ? 'height' : 'width'; + var offset = popperOffsets[mainAxis]; + var min = popperOffsets[mainAxis] + overflow[mainSide]; + var max = popperOffsets[mainAxis] - overflow[altSide]; + var additive = tether ? -popperRect[len] / 2 : 0; + var minLen = variation === start ? referenceRect[len] : popperRect[len]; + var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go + // outside the reference bounds + + var arrowElement = state.elements.arrow; + var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : { + width: 0, + height: 0 + }; + var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject(); + var arrowPaddingMin = arrowPaddingObject[mainSide]; + var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want + // to include its full size in the calculation. If the reference is small + // and near the edge of a boundary, the popper can overflow even if the + // reference is not overflowing as well (e.g. virtual elements with no + // width or height) + + var arrowLen = within(0, referenceRect[len], arrowRect[len]); + var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue; + var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue; + var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow); + var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0; + var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0; + var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset; + var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue; + var preventedOffset = within(tether ? Math.min(min, tetherMin) : min, offset, tether ? Math.max(max, tetherMax) : max); + popperOffsets[mainAxis] = preventedOffset; + data[mainAxis] = preventedOffset - offset; + } + + if (checkAltAxis) { + var _mainSide = mainAxis === 'x' ? top : left; + + var _altSide = mainAxis === 'x' ? bottom : right; + + var _offset = popperOffsets[altAxis]; + + var _min = _offset + overflow[_mainSide]; + + var _max = _offset - overflow[_altSide]; + + var _preventedOffset = within(_min, _offset, _max); + + popperOffsets[altAxis] = _preventedOffset; + data[altAxis] = _preventedOffset - _offset; + } + + state.modifiersData[name] = data; + } // eslint-disable-next-line import/no-unused-modules + + + var preventOverflow$1 = { + name: 'preventOverflow', + enabled: true, + phase: 'main', + fn: preventOverflow, + requiresIfExists: ['offset'] + }; + + function arrow(_ref) + { + var _state$modifiersData$; + + var state = _ref.state, + name = _ref.name; + var arrowElement = state.elements.arrow; + var popperOffsets = state.modifiersData.popperOffsets; + var basePlacement = getBasePlacement(state.placement); + var axis = getMainAxisFromPlacement(basePlacement); + var isVertical = [left, right].indexOf(basePlacement) >= 0; + var len = isVertical ? 'height' : 'width'; + + if (!arrowElement || !popperOffsets) { + return; + } + + var paddingObject = state.modifiersData[name + "#persistent"].padding; + var arrowRect = getLayoutRect(arrowElement); + var minProp = axis === 'y' ? top : left; + var maxProp = axis === 'y' ? bottom : right; + var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len]; + var startDiff = popperOffsets[axis] - state.rects.reference[axis]; + var arrowOffsetParent = getOffsetParent(arrowElement); + var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0; + var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is + // outside of the popper bounds + + var min = paddingObject[minProp]; + var max = clientSize - arrowRect[len] - paddingObject[maxProp]; + var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference; + var offset = within(min, center, max); // Prevents breaking syntax highlighting... + + var axisProp = axis; + state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$); + } + + function effect$2(_ref2) + { + var state = _ref2.state, + options = _ref2.options, + name = _ref2.name; + var _options$element = options.element, + arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element, + _options$padding = options.padding, + padding = _options$padding === void 0 ? 0 : _options$padding; + + if (arrowElement == null) { + return; + } // CSS selector + + + if (typeof arrowElement === 'string') { + arrowElement = state.elements.popper.querySelector(arrowElement); + + if (!arrowElement) { + return; + } + } + + { + if (!isHTMLElement(arrowElement)) { + console.error(['Popper: "arrow" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' ')); + } + } + + if (!contains(state.elements.popper, arrowElement)) { + { + console.error(['Popper: "arrow" modifier\'s `element` must be a child of the popper', 'element.'].join(' ')); + } + + return; + } + + state.elements.arrow = arrowElement; + state.modifiersData[name + "#persistent"] = { + padding: mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)) + }; + } // eslint-disable-next-line import/no-unused-modules + + + var arrow$1 = { + name: 'arrow', + enabled: true, + phase: 'main', + fn: arrow, + effect: effect$2, + requires: ['popperOffsets'], + requiresIfExists: ['preventOverflow'] + }; + + function getSideOffsets(overflow, rect, preventedOffsets) + { + if (preventedOffsets === void 0) { + preventedOffsets = { + x: 0, + y: 0 + }; + } + + return { + top: overflow.top - rect.height - preventedOffsets.y, + right: overflow.right - rect.width + preventedOffsets.x, + bottom: overflow.bottom - rect.height + preventedOffsets.y, + left: overflow.left - rect.width - preventedOffsets.x + }; + } + + function isAnySideFullyClipped(overflow) + { + return [top, right, bottom, left].some(function (side) { + return overflow[side] >= 0; + }); + } + + function hide(_ref) + { + var state = _ref.state, + name = _ref.name; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var preventedOffsets = state.modifiersData.preventOverflow; + var referenceOverflow = detectOverflow(state, { + elementContext: 'reference' + }); + var popperAltOverflow = detectOverflow(state, { + altBoundary: true + }); + var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect); + var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets); + var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets); + var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets); + state.modifiersData[name] = { + referenceClippingOffsets: referenceClippingOffsets, + popperEscapeOffsets: popperEscapeOffsets, + isReferenceHidden: isReferenceHidden, + hasPopperEscaped: hasPopperEscaped + }; + state.attributes.popper = Object.assign(Object.assign({}, state.attributes.popper), {}, { + 'data-popper-reference-hidden': isReferenceHidden, + 'data-popper-escaped': hasPopperEscaped + }); + } // eslint-disable-next-line import/no-unused-modules + + + var hide$1 = { + name: 'hide', + enabled: true, + phase: 'main', + requiresIfExists: ['preventOverflow'], + fn: hide + }; + + var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1]; + var createPopper = /*#__PURE__*/ popperGenerator({ + defaultModifiers: defaultModifiers + }); // eslint-disable-next-line import/no-unused-modules + + var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1]; + var createPopper$1 = /*#__PURE__*/ popperGenerator({ + defaultModifiers: defaultModifiers$1 + }); // eslint-disable-next-line import/no-unused-modules + + exports.applyStyles = applyStyles$1; + exports.arrow = arrow$1; + exports.computeStyles = computeStyles$1; + exports.createPopper = createPopper$1; + exports.createPopperLite = createPopper; + exports.defaultModifiers = defaultModifiers$1; + exports.detectOverflow = detectOverflow; + exports.eventListeners = eventListeners; + exports.flip = flip$1; + exports.hide = hide$1; + exports.offset = offset$1; + exports.popperGenerator = popperGenerator; + exports.popperOffsets = popperOffsets$1; + exports.preventOverflow = preventOverflow$1; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); \ No newline at end of file diff --git a/assets/js/popper/popper.min.js b/assets/js/popper/popper.min.js new file mode 100644 index 00000000..91669bd0 --- /dev/null +++ b/assets/js/popper/popper.min.js @@ -0,0 +1,5 @@ +/*! + * @popperjs/core v2.6.0 - MIT License + */ + +"use strict";!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).Popper={})}(this,(function(e){function t(e){return{width:(e=e.getBoundingClientRect()).width,height:e.height,top:e.top,right:e.right,bottom:e.bottom,left:e.left,x:e.left,y:e.top}}function n(e){return"[object Window]"!==e.toString()?(e=e.ownerDocument)&&e.defaultView||window:e}function r(e){return{scrollLeft:(e=n(e)).pageXOffset,scrollTop:e.pageYOffset}}function o(e){return e instanceof n(e).Element||e instanceof Element}function i(e){return e instanceof n(e).HTMLElement||e instanceof HTMLElement}function a(e){return e?(e.nodeName||"").toLowerCase():null}function s(e){return((o(e)?e.ownerDocument:e.document)||window.document).documentElement}function f(e){return t(s(e)).left+r(e).scrollLeft}function c(e){return n(e).getComputedStyle(e)}function p(e){return e=c(e),/auto|scroll|overlay|hidden/.test(e.overflow+e.overflowY+e.overflowX)}function l(e,o,c){void 0===c&&(c=!1);var l=s(o);e=t(e);var u=i(o),d={scrollLeft:0,scrollTop:0},m={x:0,y:0};return(u||!u&&!c)&&(("body"!==a(o)||p(l))&&(d=o!==n(o)&&i(o)?{scrollLeft:o.scrollLeft,scrollTop:o.scrollTop}:r(o)),i(o)?((m=t(o)).x+=o.clientLeft,m.y+=o.clientTop):l&&(m.x=f(l))),{x:e.left+d.scrollLeft-m.x,y:e.top+d.scrollTop-m.y,width:e.width,height:e.height}}function u(e){return{x:e.offsetLeft,y:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight}}function d(e){return"html"===a(e)?e:e.assignedSlot||e.parentNode||e.host||s(e)}function m(e,t){void 0===t&&(t=[]);var r=function e(t){return 0<=["html","body","#document"].indexOf(a(t))?t.ownerDocument.body:i(t)&&p(t)?t:e(d(t))}(e);e="body"===a(r);var o=n(r);return r=e?[o].concat(o.visualViewport||[],p(r)?r:[]):r,t=t.concat(r),e?t:t.concat(m(d(r)))}function h(e){if(!i(e)||"fixed"===c(e).position)return null;if(e=e.offsetParent){var t=s(e);if("body"===a(e)&&"static"===c(e).position&&"static"!==c(t).position)return t}return e}function g(e){for(var t=n(e),r=h(e);r&&0<=["table","td","th"].indexOf(a(r))&&"static"===c(r).position;)r=h(r);if(r&&"body"===a(r)&&"static"===c(r).position)return t;if(!r)e:{for(e=d(e);i(e)&&0>["html","body"].indexOf(a(e));){if("none"!==(r=c(e)).transform||"none"!==r.perspective||r.willChange&&"auto"!==r.willChange){r=e;break e}e=e.parentNode}r=null}return r||t}function v(e){var t=new Map,n=new Set,r=[];return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||function e(o){n.add(o.name),[].concat(o.requires||[],o.requiresIfExists||[]).forEach((function(r){n.has(r)||(r=t.get(r))&&e(r)})),r.push(o)}(e)})),r}function b(e){var t;return function(){return t||(t=new Promise((function(n){Promise.resolve().then((function(){t=void 0,n(e())}))}))),t}}function y(e){return e.split("-")[0]}function O(e,t){var r,o=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if((r=o)&&(r=o instanceof(r=n(o).ShadowRoot)||o instanceof ShadowRoot),r)do{if(t&&e.isSameNode(t))return!0;t=t.parentNode||t.host}while(t);return!1}function w(e){return Object.assign(Object.assign({},e),{},{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function x(e,o){if("viewport"===o){o=n(e);var a=s(e);o=o.visualViewport;var p=a.clientWidth;a=a.clientHeight;var l=0,u=0;o&&(p=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(l=o.offsetLeft,u=o.offsetTop)),e=w(e={width:p,height:a,x:l+f(e),y:u})}else i(o)?((e=t(o)).top+=o.clientTop,e.left+=o.clientLeft,e.bottom=e.top+o.clientHeight,e.right=e.left+o.clientWidth,e.width=o.clientWidth,e.height=o.clientHeight,e.x=e.left,e.y=e.top):(u=s(e),e=s(u),l=r(u),o=u.ownerDocument.body,p=Math.max(e.scrollWidth,e.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),a=Math.max(e.scrollHeight,e.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),u=-l.scrollLeft+f(u),l=-l.scrollTop,"rtl"===c(o||e).direction&&(u+=Math.max(e.clientWidth,o?o.clientWidth:0)-p),e=w({width:p,height:a,x:u,y:l}));return e}function j(e,t,n){return t="clippingParents"===t?function(e){var t=m(d(e)),n=0<=["absolute","fixed"].indexOf(c(e).position)&&i(e)?g(e):e;return o(n)?t.filter((function(e){return o(e)&&O(e,n)&&"body"!==a(e)})):[]}(e):[].concat(t),(n=(n=[].concat(t,[n])).reduce((function(t,n){return n=x(e,n),t.top=Math.max(n.top,t.top),t.right=Math.min(n.right,t.right),t.bottom=Math.min(n.bottom,t.bottom),t.left=Math.max(n.left,t.left),t}),x(e,n[0]))).width=n.right-n.left,n.height=n.bottom-n.top,n.x=n.left,n.y=n.top,n}function M(e){return 0<=["top","bottom"].indexOf(e)?"x":"y"}function E(e){var t=e.reference,n=e.element,r=(e=e.placement)?y(e):null;e=e?e.split("-")[1]:null;var o=t.x+t.width/2-n.width/2,i=t.y+t.height/2-n.height/2;switch(r){case"top":o={x:o,y:t.y-n.height};break;case"bottom":o={x:o,y:t.y+t.height};break;case"right":o={x:t.x+t.width,y:i};break;case"left":o={x:t.x-n.width,y:i};break;default:o={x:t.x,y:t.y}}if(null!=(r=r?M(r):null))switch(i="y"===r?"height":"width",e){case"start":o[r]-=t[i]/2-n[i]/2;break;case"end":o[r]+=t[i]/2-n[i]/2}return o}function D(e){return Object.assign(Object.assign({},{top:0,right:0,bottom:0,left:0}),e)}function P(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function L(e,n){void 0===n&&(n={});var r=n;n=void 0===(n=r.placement)?e.placement:n;var i=r.boundary,a=void 0===i?"clippingParents":i,f=void 0===(i=r.rootBoundary)?"viewport":i;i=void 0===(i=r.elementContext)?"popper":i;var c=r.altBoundary,p=void 0!==c&&c;r=D("number"!=typeof(r=void 0===(r=r.padding)?0:r)?r:P(r,T));var l=e.elements.reference;c=e.rects.popper,a=j(o(p=e.elements[p?"popper"===i?"reference":"popper":i])?p:p.contextElement||s(e.elements.popper),a,f),p=E({reference:f=t(l),element:c,strategy:"absolute",placement:n}),c=w(Object.assign(Object.assign({},c),p)),f="popper"===i?c:f;var u={top:a.top-f.top+r.top,bottom:f.bottom-a.bottom+r.bottom,left:a.left-f.left+r.left,right:f.right-a.right+r.right};if(e=e.modifiersData.offset,"popper"===i&&e){var d=e[n];Object.keys(u).forEach((function(e){var t=0<=["right","bottom"].indexOf(e)?1:-1,n=0<=["top","bottom"].indexOf(e)?"y":"x";u[e]+=d[n]*t}))}return u}function k(){for(var e=arguments.length,t=Array(e),n=0;n(v.devicePixelRatio||1)?"translate("+e+"px, "+l+"px)":"translate3d("+e+"px, "+l+"px, 0)",d)):Object.assign(Object.assign({},r),{},((t={})[h]=a?l+"px":"",t[m]=u?e+"px":"",t.transform="",t))}function A(e){return e.replace(/left|right|bottom|top/g,(function(e){return G[e]}))}function H(e){return e.replace(/start|end/g,(function(e){return J[e]}))}function R(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function S(e){return["top","right","bottom","left"].some((function(t){return 0<=e[t]}))}var T=["top","bottom","right","left"],q=T.reduce((function(e,t){return e.concat([t+"-start",t+"-end"])}),[]),C=[].concat(T,["auto"]).reduce((function(e,t){return e.concat([t,t+"-start",t+"-end"])}),[]),N="beforeRead read afterRead beforeMain main afterMain beforeWrite write afterWrite".split(" "),V={placement:"bottom",modifiers:[],strategy:"absolute"},I={passive:!0},_={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(e){var t=e.state,r=e.instance,o=(e=e.options).scroll,i=void 0===o||o,a=void 0===(e=e.resize)||e,s=n(t.elements.popper),f=[].concat(t.scrollParents.reference,t.scrollParents.popper);return i&&f.forEach((function(e){e.addEventListener("scroll",r.update,I)})),a&&s.addEventListener("resize",r.update,I),function(){i&&f.forEach((function(e){e.removeEventListener("scroll",r.update,I)})),a&&s.removeEventListener("resize",r.update,I)}},data:{}},U={name:"popperOffsets",enabled:!0,phase:"read",fn:function(e){var t=e.state;t.modifiersData[e.name]=E({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})},data:{}},z={top:"auto",right:"auto",bottom:"auto",left:"auto"},F={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(e){var t=e.state,n=e.options;e=void 0===(e=n.gpuAcceleration)||e;var r=n.adaptive;r=void 0===r||r,n=void 0===(n=n.roundOffsets)||n,e={placement:y(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:e},null!=t.modifiersData.popperOffsets&&(t.styles.popper=Object.assign(Object.assign({},t.styles.popper),W(Object.assign(Object.assign({},e),{},{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:r,roundOffsets:n})))),null!=t.modifiersData.arrow&&(t.styles.arrow=Object.assign(Object.assign({},t.styles.arrow),W(Object.assign(Object.assign({},e),{},{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:n})))),t.attributes.popper=Object.assign(Object.assign({},t.attributes.popper),{},{"data-popper-placement":t.placement})},data:{}},X={name:"applyStyles",enabled:!0,phase:"write",fn:function(e){var t=e.state;Object.keys(t.elements).forEach((function(e){var n=t.styles[e]||{},r=t.attributes[e]||{},o=t.elements[e];i(o)&&a(o)&&(Object.assign(o.style,n),Object.keys(r).forEach((function(e){var t=r[e];!1===t?o.removeAttribute(e):o.setAttribute(e,!0===t?"":t)})))}))},effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach((function(e){var r=t.elements[e],o=t.attributes[e]||{};e=Object.keys(t.styles.hasOwnProperty(e)?t.styles[e]:n[e]).reduce((function(e,t){return e[t]="",e}),{}),i(r)&&a(r)&&(Object.assign(r.style,e),Object.keys(o).forEach((function(e){r.removeAttribute(e)})))}))}},requires:["computeStyles"]},Y={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(e){var t=e.state,n=e.name,r=void 0===(e=e.options.offset)?[0,0]:e,o=(e=C.reduce((function(e,n){var o=t.rects,i=y(n),a=0<=["left","top"].indexOf(i)?-1:1,s="function"==typeof r?r(Object.assign(Object.assign({},o),{},{placement:n})):r;return o=(o=s[0])||0,s=((s=s[1])||0)*a,i=0<=["left","right"].indexOf(i)?{x:s,y:o}:{x:o,y:s},e[n]=i,e}),{}))[t.placement],i=o.x;o=o.y,null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=i,t.modifiersData.popperOffsets.y+=o),t.modifiersData[n]=e}},G={left:"right",right:"left",bottom:"top",top:"bottom"},J={start:"end",end:"start"},K={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options;if(e=e.name,!t.modifiersData[e]._skip){var r=n.mainAxis;r=void 0===r||r;var o=n.altAxis;o=void 0===o||o;var i=n.fallbackPlacements,a=n.padding,s=n.boundary,f=n.rootBoundary,c=n.altBoundary,p=n.flipVariations,l=void 0===p||p,u=n.allowedAutoPlacements;p=y(n=t.options.placement),i=i||(p!==n&&l?function(e){if("auto"===y(e))return[];var t=A(e);return[H(e),t,H(t)]}(n):[A(n)]);var d=[n].concat(i).reduce((function(e,n){return e.concat("auto"===y(n)?function(e,t){void 0===t&&(t={});var n=t.boundary,r=t.rootBoundary,o=t.padding,i=t.flipVariations,a=t.allowedAutoPlacements,s=void 0===a?C:a,f=t.placement.split("-")[1];0===(i=(t=f?i?q:q.filter((function(e){return e.split("-")[1]===f})):T).filter((function(e){return 0<=s.indexOf(e)}))).length&&(i=t);var c=i.reduce((function(t,i){return t[i]=L(e,{placement:i,boundary:n,rootBoundary:r,padding:o})[y(i)],t}),{});return Object.keys(c).sort((function(e,t){return c[e]-c[t]}))}(t,{placement:n,boundary:s,rootBoundary:f,padding:a,flipVariations:l,allowedAutoPlacements:u}):n)}),[]);n=t.rects.reference,i=t.rects.popper;var m=new Map;p=!0;for(var h=d[0],g=0;gi[x]&&(O=A(O)),x=A(O),w=[],r&&w.push(0>=j[b]),o&&w.push(0>=j[O],0>=j[x]),w.every((function(e){return e}))){h=v,p=!1;break}m.set(v,w)}if(p)for(r=function(e){var t=d.find((function(t){if(t=m.get(t))return t.slice(0,e).every((function(e){return e}))}));if(t)return h=t,"break"},o=l?3:1;0.tippy-arrow::before { + bottom: -9px; +} + +.tippy-box[data-placement^='bottom']>.tippy-arrow::before { + top: -9px; +} + +.tippy-box[data-theme~='duplicator'], +.tippy-box[data-theme~='duplicator-filled'] { + border-color: #13659C; +} + +.tippy-box[data-theme~='duplicator'] h3, +.tippy-box[data-theme~='duplicato-filled'] h3 { + background-color: #13659C; + color: white; +} + +.tippy-box[data-theme~='duplicator-filled'] .tippy-content { + background-color: #13659C; + color: white; +} + +.tippy-box[data-theme~='duplicator'][data-placement^='top']>.tippy-arrow::before, +.tippy-box[data-theme~='duplicator-filled'][data-placement^='top']>.tippy-arrow::before { + border-top-color: #13659C; +} + +.tippy-box[data-theme~='duplicator'][data-placement^='bottom']>.tippy-arrow::before, +.tippy-box[data-theme~='duplicator-filled'][data-placement^='bottom']>.tippy-arrow::before { + border-bottom-color: #13659C; +} + +.tippy-box[data-theme~='duplicator'][data-placement^='left']>.tippy-arrow::before, +.tippy-box[data-theme~='duplicator-filled'][data-placement^='left']>.tippy-arrow::before { + border-left-color: #13659C; +} + +.tippy-box[data-theme~='duplicator'][data-placement^='right']>.tippy-arrow::before, +.tippy-box[data-theme~='duplicator-filled'][data-placement^='right']>.tippy-arrow::before { + border-right-color: #13659C; +} \ No newline at end of file diff --git a/assets/js/tippy/index.php b/assets/js/tippy/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/assets/js/tippy/index.php @@ -0,0 +1,3 @@ +.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:\"\";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}"; + + function injectCSS(css) + { + var style = document.createElement('style'); + style.textContent = css; + style.setAttribute('data-tippy-stylesheet', ''); + var head = document.head; + var firstStyleOrLinkTag = document.querySelector('head>style,head>link'); + + if (firstStyleOrLinkTag) { + head.insertBefore(style, firstStyleOrLinkTag); + } else { + head.appendChild(style); + } + } + + var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; + var ua = isBrowser ? navigator.userAgent : ''; + var isIE = /MSIE |Trident\//.test(ua); + + var ROUND_ARROW = ''; + var BOX_CLASS = "tippy-box"; + var CONTENT_CLASS = "tippy-content"; + var BACKDROP_CLASS = "tippy-backdrop"; + var ARROW_CLASS = "tippy-arrow"; + var SVG_ARROW_CLASS = "tippy-svg-arrow"; + var TOUCH_OPTIONS = { + passive: true, + capture: true + }; + + function hasOwnProperty(obj, key) + { + return {}.hasOwnProperty.call(obj, key); + } + function getValueAtIndexOrReturn(value, index, defaultValue) + { + if (Array.isArray(value)) { + var v = value[index]; + return v == null ? Array.isArray(defaultValue) ? defaultValue[index] : defaultValue : v; + } + + return value; + } + function isType(value, type) + { + var str = {}.toString.call(value); + return str.indexOf('[object') === 0 && str.indexOf(type + "]") > -1; + } + function invokeWithArgsOrReturn(value, args) + { + return typeof value === 'function' ? value.apply(void 0, args) : value; + } + function debounce(fn, ms) + { + // Avoid wrapping in `setTimeout` if ms is 0 anyway + if (ms === 0) { + return fn; + } + + var timeout; + return function (arg) { + clearTimeout(timeout); + timeout = setTimeout(function () { + fn(arg); + }, ms); + }; + } + function removeProperties(obj, keys) + { + var clone = Object.assign({}, obj); + keys.forEach(function (key) { + delete clone[key]; + }); + return clone; + } + function splitBySpaces(value) + { + return value.split(/\s+/).filter(Boolean); + } + function normalizeToArray(value) + { + return [].concat(value); + } + function pushIfUnique(arr, value) + { + if (arr.indexOf(value) === -1) { + arr.push(value); + } + } + function unique(arr) + { + return arr.filter(function (item, index) { + return arr.indexOf(item) === index; + }); + } + function getBasePlacement(placement) + { + return placement.split('-')[0]; + } + function arrayFrom(value) + { + return [].slice.call(value); + } + function removeUndefinedProps(obj) + { + return Object.keys(obj).reduce(function (acc, key) { + if (obj[key] !== undefined) { + acc[key] = obj[key]; + } + + return acc; + }, {}); + } + + function div() + { + return document.createElement('div'); + } + function isElement(value) + { + return ['Element', 'Fragment'].some(function (type) { + return isType(value, type); + }); + } + function isNodeList(value) + { + return isType(value, 'NodeList'); + } + function isMouseEvent(value) + { + return isType(value, 'MouseEvent'); + } + function isReferenceElement(value) + { + return !!(value && value._tippy && value._tippy.reference === value); + } + function getArrayOfElements(value) + { + if (isElement(value)) { + return [value]; + } + + if (isNodeList(value)) { + return arrayFrom(value); + } + + if (Array.isArray(value)) { + return value; + } + + return arrayFrom(document.querySelectorAll(value)); + } + function setTransitionDuration(els, value) + { + els.forEach(function (el) { + if (el) { + el.style.transitionDuration = value + "ms"; + } + }); + } + function setVisibilityState(els, state) + { + els.forEach(function (el) { + if (el) { + el.setAttribute('data-state', state); + } + }); + } + function getOwnerDocument(elementOrElements) + { + var _normalizeToArray = normalizeToArray(elementOrElements), + element = _normalizeToArray[0]; + + return element ? element.ownerDocument || document : document; + } + function isCursorOutsideInteractiveBorder(popperTreeData, event) + { + var clientX = event.clientX, + clientY = event.clientY; + return popperTreeData.every(function (_ref) { + var popperRect = _ref.popperRect, + popperState = _ref.popperState, + props = _ref.props; + var interactiveBorder = props.interactiveBorder; + var basePlacement = getBasePlacement(popperState.placement); + var offsetData = popperState.modifiersData.offset; + + if (!offsetData) { + return true; + } + + var topDistance = basePlacement === 'bottom' ? offsetData.top.y : 0; + var bottomDistance = basePlacement === 'top' ? offsetData.bottom.y : 0; + var leftDistance = basePlacement === 'right' ? offsetData.left.x : 0; + var rightDistance = basePlacement === 'left' ? offsetData.right.x : 0; + var exceedsTop = popperRect.top - clientY + topDistance > interactiveBorder; + var exceedsBottom = clientY - popperRect.bottom - bottomDistance > interactiveBorder; + var exceedsLeft = popperRect.left - clientX + leftDistance > interactiveBorder; + var exceedsRight = clientX - popperRect.right - rightDistance > interactiveBorder; + return exceedsTop || exceedsBottom || exceedsLeft || exceedsRight; + }); + } + function updateTransitionEndListener(box, action, listener) + { + var method = action + "EventListener"; // some browsers apparently support `transition` (unprefixed) but only fire + // `webkitTransitionEnd`... + + ['transitionend', 'webkitTransitionEnd'].forEach(function (event) { + box[method](event, listener); + }); + } + + var currentInput = { + isTouch: false + }; + var lastMouseMoveTime = 0; + /** + * When a `touchstart` event is fired, it's assumed the user is using touch + * input. We'll bind a `mousemove` event listener to listen for mouse input in + * the future. This way, the `isTouch` property is fully dynamic and will handle + * hybrid devices that use a mix of touch + mouse input. + */ + + function onDocumentTouchStart() + { + if (currentInput.isTouch) { + return; + } + + currentInput.isTouch = true; + + if (window.performance) { + document.addEventListener('mousemove', onDocumentMouseMove); + } + } + /** + * When two `mousemove` event are fired consecutively within 20ms, it's assumed + * the user is using mouse input again. `mousemove` can fire on touch devices as + * well, but very rarely that quickly. + */ + + function onDocumentMouseMove() + { + var now = performance.now(); + + if (now - lastMouseMoveTime < 20) { + currentInput.isTouch = false; + document.removeEventListener('mousemove', onDocumentMouseMove); + } + + lastMouseMoveTime = now; + } + /** + * When an element is in focus and has a tippy, leaving the tab/window and + * returning causes it to show again. For mouse users this is unexpected, but + * for keyboard use it makes sense. + * TODO: find a better technique to solve this problem + */ + + function onWindowBlur() + { + var activeElement = document.activeElement; + + if (isReferenceElement(activeElement)) { + var instance = activeElement._tippy; + + if (activeElement.blur && !instance.state.isVisible) { + activeElement.blur(); + } + } + } + function bindGlobalEventListeners() + { + document.addEventListener('touchstart', onDocumentTouchStart, TOUCH_OPTIONS); + window.addEventListener('blur', onWindowBlur); + } + + function createMemoryLeakWarning(method) + { + var txt = method === 'destroy' ? 'n already-' : ' '; + return [method + "() was called on a" + txt + "destroyed instance. This is a no-op but", 'indicates a potential memory leak.'].join(' '); + } + function clean(value) + { + var spacesAndTabs = /[ \t]{2,}/g; + var lineStartWithSpaces = /^[ \t]*/gm; + return value.replace(spacesAndTabs, ' ').replace(lineStartWithSpaces, '').trim(); + } + + function getDevMessage(message) + { + return clean("\n %ctippy.js\n\n %c" + clean(message) + "\n\n %c\uD83D\uDC77\u200D This is a development-only message. It will be removed in production.\n "); + } + + function getFormattedMessage(message) + { + return [getDevMessage(message), // title + 'color: #00C584; font-size: 1.3em; font-weight: bold;', // message + 'line-height: 1.5', // footer + 'color: #a6a095;']; + } // Assume warnings and errors never have the same message + + var visitedMessages; + + { + resetVisitedMessages(); + } + + function resetVisitedMessages() + { + visitedMessages = new Set(); + } + function warnWhen(condition, message) + { + if (condition && !visitedMessages.has(message)) { + var _console; + + visitedMessages.add(message); + + (_console = console).warn.apply(_console, getFormattedMessage(message)); + } + } + function errorWhen(condition, message) + { + if (condition && !visitedMessages.has(message)) { + var _console2; + + visitedMessages.add(message); + + (_console2 = console).error.apply(_console2, getFormattedMessage(message)); + } + } + function validateTargets(targets) + { + var didPassFalsyValue = !targets; + var didPassPlainObject = Object.prototype.toString.call(targets) === '[object Object]' && !targets.addEventListener; + errorWhen(didPassFalsyValue, ['tippy() was passed', '`' + String(targets) + '`', 'as its targets (first) argument. Valid types are: String, Element,', 'Element[], or NodeList.'].join(' ')); + errorWhen(didPassPlainObject, ['tippy() was passed a plain object which is not supported as an argument', 'for virtual positioning. Use props.getReferenceClientRect instead.'].join(' ')); + } + + var pluginProps = { + animateFill: false, + followCursor: false, + inlinePositioning: false, + sticky: false + }; + var renderProps = { + allowHTML: false, + animation: 'fade', + arrow: true, + content: '', + inertia: false, + maxWidth: 350, + role: 'tooltip', + theme: '', + zIndex: 9999 + }; + var defaultProps = Object.assign({ + appendTo: function appendTo() + { + return document.body; + }, + aria: { + content: 'auto', + expanded: 'auto' + }, + delay: 0, + duration: [300, 250], + getReferenceClientRect: null, + hideOnClick: true, + ignoreAttributes: false, + interactive: false, + interactiveBorder: 2, + interactiveDebounce: 0, + moveTransition: '', + offset: [0, 10], + onAfterUpdate: function onAfterUpdate() + {}, + onBeforeUpdate: function onBeforeUpdate() + {}, + onCreate: function onCreate() + {}, + onDestroy: function onDestroy() + {}, + onHidden: function onHidden() + {}, + onHide: function onHide() + {}, + onMount: function onMount() + {}, + onShow: function onShow() + {}, + onShown: function onShown() + {}, + onTrigger: function onTrigger() + {}, + onUntrigger: function onUntrigger() + {}, + onClickOutside: function onClickOutside() + {}, + placement: 'top', + plugins: [], + popperOptions: {}, + render: null, + showOnCreate: false, + touch: true, + trigger: 'mouseenter focus', + triggerTarget: null + }, pluginProps, {}, renderProps); + var defaultKeys = Object.keys(defaultProps); + var setDefaultProps = function setDefaultProps(partialProps) + { + /* istanbul ignore else */ + { + validateProps(partialProps, []); + } + + var keys = Object.keys(partialProps); + keys.forEach(function (key) { + defaultProps[key] = partialProps[key]; + }); + }; + function getExtendedPassedProps(passedProps) + { + var plugins = passedProps.plugins || []; + var pluginProps = plugins.reduce(function (acc, plugin) { + var name = plugin.name, + defaultValue = plugin.defaultValue; + + if (name) { + acc[name] = passedProps[name] !== undefined ? passedProps[name] : defaultValue; + } + + return acc; + }, {}); + return Object.assign({}, passedProps, {}, pluginProps); + } + function getDataAttributeProps(reference, plugins) + { + var propKeys = plugins ? Object.keys(getExtendedPassedProps(Object.assign({}, defaultProps, { + plugins: plugins + }))) : defaultKeys; + var props = propKeys.reduce(function (acc, key) { + var valueAsString = (reference.getAttribute("data-tippy-" + key) || '').trim(); + + if (!valueAsString) { + return acc; + } + + if (key === 'content') { + acc[key] = valueAsString; + } else { + try { + acc[key] = JSON.parse(valueAsString); + } catch (e) { + acc[key] = valueAsString; + } + } + + return acc; + }, {}); + return props; + } + function evaluateProps(reference, props) + { + var out = Object.assign({}, props, { + content: invokeWithArgsOrReturn(props.content, [reference]) + }, props.ignoreAttributes ? {} : getDataAttributeProps(reference, props.plugins)); + out.aria = Object.assign({}, defaultProps.aria, {}, out.aria); + out.aria = { + expanded: out.aria.expanded === 'auto' ? props.interactive : out.aria.expanded, + content: out.aria.content === 'auto' ? props.interactive ? null : 'describedby' : out.aria.content + }; + return out; + } + function validateProps(partialProps, plugins) + { + if (partialProps === void 0) { + partialProps = {}; + } + + if (plugins === void 0) { + plugins = []; + } + + var keys = Object.keys(partialProps); + keys.forEach(function (prop) { + var nonPluginProps = removeProperties(defaultProps, Object.keys(pluginProps)); + var didPassUnknownProp = !hasOwnProperty(nonPluginProps, prop); // Check if the prop exists in `plugins` + + if (didPassUnknownProp) { + didPassUnknownProp = plugins.filter(function (plugin) { + return plugin.name === prop; + }).length === 0; + } + + warnWhen(didPassUnknownProp, ["`" + prop + "`", "is not a valid prop. You may have spelled it incorrectly, or if it's", 'a plugin, forgot to pass it in an array as props.plugins.', '\n\n', 'All props: https://atomiks.github.io/tippyjs/v6/all-props/\n', 'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/'].join(' ')); + }); + } + + var innerHTML = function innerHTML() + { + return 'innerHTML'; + }; + + function dangerouslySetInnerHTML(element, html) + { + element[innerHTML()] = html; + } + + function createArrowElement(value) + { + var arrow = div(); + + if (value === true) { + arrow.className = ARROW_CLASS; + } else { + arrow.className = SVG_ARROW_CLASS; + + if (isElement(value)) { + arrow.appendChild(value); + } else { + dangerouslySetInnerHTML(arrow, value); + } + } + + return arrow; + } + + function setContent(content, props) + { + if (isElement(props.content)) { + dangerouslySetInnerHTML(content, ''); + content.appendChild(props.content); + } else if (typeof props.content !== 'function') { + if (props.allowHTML) { + dangerouslySetInnerHTML(content, props.content); + } else { + content.textContent = props.content; + } + } + } + function getChildren(popper) + { + var box = popper.firstElementChild; + var boxChildren = arrayFrom(box.children); + return { + box: box, + content: boxChildren.find(function (node) { + return node.classList.contains(CONTENT_CLASS); + }), + arrow: boxChildren.find(function (node) { + return node.classList.contains(ARROW_CLASS) || node.classList.contains(SVG_ARROW_CLASS); + }), + backdrop: boxChildren.find(function (node) { + return node.classList.contains(BACKDROP_CLASS); + }) + }; + } + function render(instance) + { + var popper = div(); + var box = div(); + box.className = BOX_CLASS; + box.setAttribute('data-state', 'hidden'); + box.setAttribute('tabindex', '-1'); + var content = div(); + content.className = CONTENT_CLASS; + content.setAttribute('data-state', 'hidden'); + setContent(content, instance.props); + popper.appendChild(box); + box.appendChild(content); + onUpdate(instance.props, instance.props); + + function onUpdate(prevProps, nextProps) + { + var _getChildren = getChildren(popper), + box = _getChildren.box, + content = _getChildren.content, + arrow = _getChildren.arrow; + + if (nextProps.theme) { + box.setAttribute('data-theme', nextProps.theme); + } else { + box.removeAttribute('data-theme'); + } + + if (typeof nextProps.animation === 'string') { + box.setAttribute('data-animation', nextProps.animation); + } else { + box.removeAttribute('data-animation'); + } + + if (nextProps.inertia) { + box.setAttribute('data-inertia', ''); + } else { + box.removeAttribute('data-inertia'); + } + + box.style.maxWidth = typeof nextProps.maxWidth === 'number' ? nextProps.maxWidth + "px" : nextProps.maxWidth; + + if (nextProps.role) { + box.setAttribute('role', nextProps.role); + } else { + box.removeAttribute('role'); + } + + if (prevProps.content !== nextProps.content || prevProps.allowHTML !== nextProps.allowHTML) { + setContent(content, instance.props); + } + + if (nextProps.arrow) { + if (!arrow) { + box.appendChild(createArrowElement(nextProps.arrow)); + } else if (prevProps.arrow !== nextProps.arrow) { + box.removeChild(arrow); + box.appendChild(createArrowElement(nextProps.arrow)); + } + } else if (arrow) { + box.removeChild(arrow); + } + } + + return { + popper: popper, + onUpdate: onUpdate + }; + } // Runtime check to identify if the render function is the default one; this + // way we can apply default CSS transitions logic and it can be tree-shaken away + + render.$$tippy = true; + + var idCounter = 1; + var mouseMoveListeners = []; // Used by `hideAll()` + + var mountedInstances = []; + function createTippy(reference, passedProps) + { + var props = evaluateProps(reference, Object.assign({}, defaultProps, {}, getExtendedPassedProps(removeUndefinedProps(passedProps)))); // =========================================================================== + // 🔒 Private members + // =========================================================================== + + var showTimeout; + var hideTimeout; + var scheduleHideAnimationFrame; + var isVisibleFromClick = false; + var didHideDueToDocumentMouseDown = false; + var didTouchMove = false; + var ignoreOnFirstUpdate = false; + var lastTriggerEvent; + var currentTransitionEndListener; + var onFirstUpdate; + var listeners = []; + var debouncedOnMouseMove = debounce(onMouseMove, props.interactiveDebounce); + var currentTarget; // =========================================================================== + // 🔑 Public members + // =========================================================================== + + var id = idCounter++; + var popperInstance = null; + var plugins = unique(props.plugins); + var state = { + // Is the instance currently enabled? + isEnabled: true, + // Is the tippy currently showing and not transitioning out? + isVisible: false, + // Has the instance been destroyed? + isDestroyed: false, + // Is the tippy currently mounted to the DOM? + isMounted: false, + // Has the tippy finished transitioning in? + isShown: false + }; + var instance = { + // properties + id: id, + reference: reference, + popper: div(), + popperInstance: popperInstance, + props: props, + state: state, + plugins: plugins, + // methods + clearDelayTimeouts: clearDelayTimeouts, + setProps: setProps, + setContent: setContent, + show: show, + hide: hide, + hideWithInteractivity: hideWithInteractivity, + enable: enable, + disable: disable, + unmount: unmount, + destroy: destroy + }; // TODO: Investigate why this early return causes a TDZ error in the tests — + // it doesn't seem to happen in the browser + + /* istanbul ignore if */ + + if (!props.render) { + { + errorWhen(true, 'render() function has not been supplied.'); + } + + return instance; + } // =========================================================================== + // Initial mutations + // =========================================================================== + + + var _props$render = props.render(instance), + popper = _props$render.popper, + onUpdate = _props$render.onUpdate; + + popper.setAttribute('data-tippy-root', ''); + popper.id = "tippy-" + instance.id; + instance.popper = popper; + reference._tippy = instance; + popper._tippy = instance; + var pluginsHooks = plugins.map(function (plugin) { + return plugin.fn(instance); + }); + var hasAriaExpanded = reference.hasAttribute('aria-expanded'); + addListeners(); + handleAriaExpandedAttribute(); + handleStyles(); + invokeHook('onCreate', [instance]); + + if (props.showOnCreate) { + scheduleShow(); + } // Prevent a tippy with a delay from hiding if the cursor left then returned + // before it started hiding + + + popper.addEventListener('mouseenter', function () { + if (instance.props.interactive && instance.state.isVisible) { + instance.clearDelayTimeouts(); + } + }); + popper.addEventListener('mouseleave', function (event) { + if (instance.props.interactive && instance.props.trigger.indexOf('mouseenter') >= 0) { + getDocument().addEventListener('mousemove', debouncedOnMouseMove); + debouncedOnMouseMove(event); + } + }); + return instance; // =========================================================================== + // 🔒 Private methods + // =========================================================================== + + function getNormalizedTouchSettings() + { + var touch = instance.props.touch; + return Array.isArray(touch) ? touch : [touch, 0]; + } + + function getIsCustomTouchBehavior() + { + return getNormalizedTouchSettings()[0] === 'hold'; + } + + function getIsDefaultRenderFn() + { + var _instance$props$rende; + + // @ts-ignore + return !!((_instance$props$rende = instance.props.render) == null ? void 0 : _instance$props$rende.$$tippy); + } + + function getCurrentTarget() + { + return currentTarget || reference; + } + + function getDocument() + { + var parent = getCurrentTarget().parentNode; + return parent ? getOwnerDocument(parent) : document; + } + + function getDefaultTemplateChildren() + { + return getChildren(popper); + } + + function getDelay(isShow) + { + // For touch or keyboard input, force `0` delay for UX reasons + // Also if the instance is mounted but not visible (transitioning out), + // ignore delay + if (instance.state.isMounted && !instance.state.isVisible || currentInput.isTouch || lastTriggerEvent && lastTriggerEvent.type === 'focus') { + return 0; + } + + return getValueAtIndexOrReturn(instance.props.delay, isShow ? 0 : 1, defaultProps.delay); + } + + function handleStyles() + { + popper.style.pointerEvents = instance.props.interactive && instance.state.isVisible ? '' : 'none'; + popper.style.zIndex = "" + instance.props.zIndex; + } + + function invokeHook(hook, args, shouldInvokePropsHook) + { + if (shouldInvokePropsHook === void 0) { + shouldInvokePropsHook = true; + } + + pluginsHooks.forEach(function (pluginHooks) { + if (pluginHooks[hook]) { + pluginHooks[hook].apply(void 0, args); + } + }); + + if (shouldInvokePropsHook) { + var _instance$props; + + (_instance$props = instance.props)[hook].apply(_instance$props, args); + } + } + + function handleAriaContentAttribute() + { + var aria = instance.props.aria; + + if (!aria.content) { + return; + } + + var attr = "aria-" + aria.content; + var id = popper.id; + var nodes = normalizeToArray(instance.props.triggerTarget || reference); + nodes.forEach(function (node) { + var currentValue = node.getAttribute(attr); + + if (instance.state.isVisible) { + node.setAttribute(attr, currentValue ? currentValue + " " + id : id); + } else { + var nextValue = currentValue && currentValue.replace(id, '').trim(); + + if (nextValue) { + node.setAttribute(attr, nextValue); + } else { + node.removeAttribute(attr); + } + } + }); + } + + function handleAriaExpandedAttribute() + { + if (hasAriaExpanded || !instance.props.aria.expanded) { + return; + } + + var nodes = normalizeToArray(instance.props.triggerTarget || reference); + nodes.forEach(function (node) { + if (instance.props.interactive) { + node.setAttribute('aria-expanded', instance.state.isVisible && node === getCurrentTarget() ? 'true' : 'false'); + } else { + node.removeAttribute('aria-expanded'); + } + }); + } + + function cleanupInteractiveMouseListeners() + { + getDocument().removeEventListener('mousemove', debouncedOnMouseMove); + mouseMoveListeners = mouseMoveListeners.filter(function (listener) { + return listener !== debouncedOnMouseMove; + }); + } + + function onDocumentPress(event) + { + // Moved finger to scroll instead of an intentional tap outside + if (currentInput.isTouch) { + if (didTouchMove || event.type === 'mousedown') { + return; + } + } // Clicked on interactive popper + + + if (instance.props.interactive && popper.contains(event.target)) { + return; + } // Clicked on the event listeners target + + + if (getCurrentTarget().contains(event.target)) { + if (currentInput.isTouch) { + return; + } + + if (instance.state.isVisible && instance.props.trigger.indexOf('click') >= 0) { + return; + } + } else { + invokeHook('onClickOutside', [instance, event]); + } + + if (instance.props.hideOnClick === true) { + instance.clearDelayTimeouts(); + instance.hide(); // `mousedown` event is fired right before `focus` if pressing the + // currentTarget. This lets a tippy with `focus` trigger know that it + // should not show + + didHideDueToDocumentMouseDown = true; + setTimeout(function () { + didHideDueToDocumentMouseDown = false; + }); // The listener gets added in `scheduleShow()`, but this may be hiding it + // before it shows, and hide()'s early bail-out behavior can prevent it + // from being cleaned up + + if (!instance.state.isMounted) { + removeDocumentPress(); + } + } + } + + function onTouchMove() + { + didTouchMove = true; + } + + function onTouchStart() + { + didTouchMove = false; + } + + function addDocumentPress() + { + var doc = getDocument(); + doc.addEventListener('mousedown', onDocumentPress, true); + doc.addEventListener('touchend', onDocumentPress, TOUCH_OPTIONS); + doc.addEventListener('touchstart', onTouchStart, TOUCH_OPTIONS); + doc.addEventListener('touchmove', onTouchMove, TOUCH_OPTIONS); + } + + function removeDocumentPress() + { + var doc = getDocument(); + doc.removeEventListener('mousedown', onDocumentPress, true); + doc.removeEventListener('touchend', onDocumentPress, TOUCH_OPTIONS); + doc.removeEventListener('touchstart', onTouchStart, TOUCH_OPTIONS); + doc.removeEventListener('touchmove', onTouchMove, TOUCH_OPTIONS); + } + + function onTransitionedOut(duration, callback) + { + onTransitionEnd(duration, function () { + if (!instance.state.isVisible && popper.parentNode && popper.parentNode.contains(popper)) { + callback(); + } + }); + } + + function onTransitionedIn(duration, callback) + { + onTransitionEnd(duration, callback); + } + + function onTransitionEnd(duration, callback) + { + var box = getDefaultTemplateChildren().box; + + function listener(event) + { + if (event.target === box) { + updateTransitionEndListener(box, 'remove', listener); + callback(); + } + } // Make callback synchronous if duration is 0 + // `transitionend` won't fire otherwise + + + if (duration === 0) { + return callback(); + } + + updateTransitionEndListener(box, 'remove', currentTransitionEndListener); + updateTransitionEndListener(box, 'add', listener); + currentTransitionEndListener = listener; + } + + function on(eventType, handler, options) + { + if (options === void 0) { + options = false; + } + + var nodes = normalizeToArray(instance.props.triggerTarget || reference); + nodes.forEach(function (node) { + node.addEventListener(eventType, handler, options); + listeners.push({ + node: node, + eventType: eventType, + handler: handler, + options: options + }); + }); + } + + function addListeners() + { + if (getIsCustomTouchBehavior()) { + on('touchstart', onTrigger, { + passive: true + }); + on('touchend', onMouseLeave, { + passive: true + }); + } + + splitBySpaces(instance.props.trigger).forEach(function (eventType) { + if (eventType === 'manual') { + return; + } + + on(eventType, onTrigger); + + switch (eventType) { + case 'mouseenter': + on('mouseleave', onMouseLeave); + break; + + case 'focus': + on(isIE ? 'focusout' : 'blur', onBlurOrFocusOut); + break; + + case 'focusin': + on('focusout', onBlurOrFocusOut); + break; + } + }); + } + + function removeListeners() + { + listeners.forEach(function (_ref) { + var node = _ref.node, + eventType = _ref.eventType, + handler = _ref.handler, + options = _ref.options; + node.removeEventListener(eventType, handler, options); + }); + listeners = []; + } + + function onTrigger(event) + { + var _lastTriggerEvent; + + var shouldScheduleClickHide = false; + + if (!instance.state.isEnabled || isEventListenerStopped(event) || didHideDueToDocumentMouseDown) { + return; + } + + var wasFocused = ((_lastTriggerEvent = lastTriggerEvent) == null ? void 0 : _lastTriggerEvent.type) === 'focus'; + lastTriggerEvent = event; + currentTarget = event.currentTarget; + handleAriaExpandedAttribute(); + + if (!instance.state.isVisible && isMouseEvent(event)) { + // If scrolling, `mouseenter` events can be fired if the cursor lands + // over a new target, but `mousemove` events don't get fired. This + // causes interactive tooltips to get stuck open until the cursor is + // moved + mouseMoveListeners.forEach(function (listener) { + return listener(event); + }); + } // Toggle show/hide when clicking click-triggered tooltips + + + if (event.type === 'click' && (instance.props.trigger.indexOf('mouseenter') < 0 || isVisibleFromClick) && instance.props.hideOnClick !== false && instance.state.isVisible) { + shouldScheduleClickHide = true; + } else { + scheduleShow(event); + } + + if (event.type === 'click') { + isVisibleFromClick = !shouldScheduleClickHide; + } + + if (shouldScheduleClickHide && !wasFocused) { + scheduleHide(event); + } + } + + function onMouseMove(event) + { + var target = event.target; + var isCursorOverReferenceOrPopper = getCurrentTarget().contains(target) || popper.contains(target); + + if (event.type === 'mousemove' && isCursorOverReferenceOrPopper) { + return; + } + + var popperTreeData = getNestedPopperTree().concat(popper).map(function (popper) { + var _instance$popperInsta; + + var instance = popper._tippy; + var state = (_instance$popperInsta = instance.popperInstance) == null ? void 0 : _instance$popperInsta.state; + + if (state) { + return { + popperRect: popper.getBoundingClientRect(), + popperState: state, + props: props + }; + } + + return null; + }).filter(Boolean); + + if (isCursorOutsideInteractiveBorder(popperTreeData, event)) { + cleanupInteractiveMouseListeners(); + scheduleHide(event); + } + } + + function onMouseLeave(event) + { + var shouldBail = isEventListenerStopped(event) || instance.props.trigger.indexOf('click') >= 0 && isVisibleFromClick; + + if (shouldBail) { + return; + } + + if (instance.props.interactive) { + instance.hideWithInteractivity(event); + return; + } + + scheduleHide(event); + } + + function onBlurOrFocusOut(event) + { + if (instance.props.trigger.indexOf('focusin') < 0 && event.target !== getCurrentTarget()) { + return; + } // If focus was moved to within the popper + + + if (instance.props.interactive && event.relatedTarget && popper.contains(event.relatedTarget)) { + return; + } + + scheduleHide(event); + } + + function isEventListenerStopped(event) + { + return currentInput.isTouch ? getIsCustomTouchBehavior() !== event.type.indexOf('touch') >= 0 : false; + } + + function createPopperInstance() + { + destroyPopperInstance(); + var _instance$props2 = instance.props, + popperOptions = _instance$props2.popperOptions, + placement = _instance$props2.placement, + offset = _instance$props2.offset, + getReferenceClientRect = _instance$props2.getReferenceClientRect, + moveTransition = _instance$props2.moveTransition; + var arrow = getIsDefaultRenderFn() ? getChildren(popper).arrow : null; + var computedReference = getReferenceClientRect ? { + getBoundingClientRect: getReferenceClientRect, + contextElement: getReferenceClientRect.contextElement || getCurrentTarget() + } : reference; + var tippyModifier = { + name: '$$tippy', + enabled: true, + phase: 'beforeWrite', + requires: ['computeStyles'], + fn: function fn(_ref2) + { + var state = _ref2.state; + + if (getIsDefaultRenderFn()) { + var _getDefaultTemplateCh = getDefaultTemplateChildren(), + box = _getDefaultTemplateCh.box; + + ['placement', 'reference-hidden', 'escaped'].forEach(function (attr) { + if (attr === 'placement') { + box.setAttribute('data-placement', state.placement); + } else { + if (state.attributes.popper["data-popper-" + attr]) { + box.setAttribute("data-" + attr, ''); + } else { + box.removeAttribute("data-" + attr); + } + } + }); + state.attributes.popper = {}; + } + } + }; + var modifiers = [{ + name: 'offset', + options: { + offset: offset + } + }, { + name: 'preventOverflow', + options: { + padding: { + top: 2, + bottom: 2, + left: 5, + right: 5 + } + } + }, { + name: 'flip', + options: { + padding: 5 + } + }, { + name: 'computeStyles', + options: { + adaptive: !moveTransition + } + }, tippyModifier]; + + if (getIsDefaultRenderFn() && arrow) { + modifiers.push({ + name: 'arrow', + options: { + element: arrow, + padding: 3 + } + }); + } + + modifiers.push.apply(modifiers, (popperOptions == null ? void 0 : popperOptions.modifiers) || []); + instance.popperInstance = core.createPopper(computedReference, popper, Object.assign({}, popperOptions, { + placement: placement, + onFirstUpdate: onFirstUpdate, + modifiers: modifiers + })); + } + + function destroyPopperInstance() + { + if (instance.popperInstance) { + instance.popperInstance.destroy(); + instance.popperInstance = null; + } + } + + function mount() + { + var appendTo = instance.props.appendTo; + var parentNode; // By default, we'll append the popper to the triggerTargets's parentNode so + // it's directly after the reference element so the elements inside the + // tippy can be tabbed to + // If there are clipping issues, the user can specify a different appendTo + // and ensure focus management is handled correctly manually + + var node = getCurrentTarget(); + + if (instance.props.interactive && appendTo === defaultProps.appendTo || appendTo === 'parent') { + parentNode = node.parentNode; + } else { + parentNode = invokeWithArgsOrReturn(appendTo, [node]); + } // The popper element needs to exist on the DOM before its position can be + // updated as Popper needs to read its dimensions + + + if (!parentNode.contains(popper)) { + parentNode.appendChild(popper); + } + + createPopperInstance(); + /* istanbul ignore else */ + + { + // Accessibility check + warnWhen(instance.props.interactive && appendTo === defaultProps.appendTo && node.nextElementSibling !== popper, ['Interactive tippy element may not be accessible via keyboard', 'navigation because it is not directly after the reference element', 'in the DOM source order.', '\n\n', 'Using a wrapper
          or tag around the reference element', 'solves this by creating a new parentNode context.', '\n\n', 'Specifying `appendTo: document.body` silences this warning, but it', 'assumes you are using a focus management solution to handle', 'keyboard navigation.', '\n\n', 'See: https://atomiks.github.io/tippyjs/v6/accessibility/#interactivity'].join(' ')); + } + } + + function getNestedPopperTree() + { + return arrayFrom(popper.querySelectorAll('[data-tippy-root]')); + } + + function scheduleShow(event) + { + instance.clearDelayTimeouts(); + + if (event) { + invokeHook('onTrigger', [instance, event]); + } + + addDocumentPress(); + var delay = getDelay(true); + + var _getNormalizedTouchSe = getNormalizedTouchSettings(), + touchValue = _getNormalizedTouchSe[0], + touchDelay = _getNormalizedTouchSe[1]; + + if (currentInput.isTouch && touchValue === 'hold' && touchDelay) { + delay = touchDelay; + } + + if (delay) { + showTimeout = setTimeout(function () { + instance.show(); + }, delay); + } else { + instance.show(); + } + } + + function scheduleHide(event) + { + instance.clearDelayTimeouts(); + invokeHook('onUntrigger', [instance, event]); + + if (!instance.state.isVisible) { + removeDocumentPress(); + return; + } // For interactive tippies, scheduleHide is added to a document.body handler + // from onMouseLeave so must intercept scheduled hides from mousemove/leave + // events when trigger contains mouseenter and click, and the tip is + // currently shown as a result of a click. + + + if (instance.props.trigger.indexOf('mouseenter') >= 0 && instance.props.trigger.indexOf('click') >= 0 && ['mouseleave', 'mousemove'].indexOf(event.type) >= 0 && isVisibleFromClick) { + return; + } + + var delay = getDelay(false); + + if (delay) { + hideTimeout = setTimeout(function () { + if (instance.state.isVisible) { + instance.hide(); + } + }, delay); + } else { + // Fixes a `transitionend` problem when it fires 1 frame too + // late sometimes, we don't want hide() to be called. + scheduleHideAnimationFrame = requestAnimationFrame(function () { + instance.hide(); + }); + } + } // =========================================================================== + // 🔑 Public methods + // =========================================================================== + + + function enable() + { + instance.state.isEnabled = true; + } + + function disable() + { + // Disabling the instance should also hide it + // https://github.com/atomiks/tippy.js-react/issues/106 + instance.hide(); + instance.state.isEnabled = false; + } + + function clearDelayTimeouts() + { + clearTimeout(showTimeout); + clearTimeout(hideTimeout); + cancelAnimationFrame(scheduleHideAnimationFrame); + } + + function setProps(partialProps) + { + /* istanbul ignore else */ + { + warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('setProps')); + } + + if (instance.state.isDestroyed) { + return; + } + + invokeHook('onBeforeUpdate', [instance, partialProps]); + removeListeners(); + var prevProps = instance.props; + var nextProps = evaluateProps(reference, Object.assign({}, instance.props, {}, partialProps, { + ignoreAttributes: true + })); + instance.props = nextProps; + addListeners(); + + if (prevProps.interactiveDebounce !== nextProps.interactiveDebounce) { + cleanupInteractiveMouseListeners(); + debouncedOnMouseMove = debounce(onMouseMove, nextProps.interactiveDebounce); + } // Ensure stale aria-expanded attributes are removed + + + if (prevProps.triggerTarget && !nextProps.triggerTarget) { + normalizeToArray(prevProps.triggerTarget).forEach(function (node) { + node.removeAttribute('aria-expanded'); + }); + } else if (nextProps.triggerTarget) { + reference.removeAttribute('aria-expanded'); + } + + handleAriaExpandedAttribute(); + handleStyles(); + + if (onUpdate) { + onUpdate(prevProps, nextProps); + } + + if (instance.popperInstance) { + createPopperInstance(); // Fixes an issue with nested tippies if they are all getting re-rendered, + // and the nested ones get re-rendered first. + // https://github.com/atomiks/tippyjs-react/issues/177 + // TODO: find a cleaner / more efficient solution(!) + + getNestedPopperTree().forEach(function (nestedPopper) { + // React (and other UI libs likely) requires a rAF wrapper as it flushes + // its work in one + requestAnimationFrame(nestedPopper._tippy.popperInstance.forceUpdate); + }); + } + + invokeHook('onAfterUpdate', [instance, partialProps]); + } + + function setContent(content) + { + instance.setProps({ + content: content + }); + } + + function show() + { + /* istanbul ignore else */ + { + warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('show')); + } // Early bail-out + + + var isAlreadyVisible = instance.state.isVisible; + var isDestroyed = instance.state.isDestroyed; + var isDisabled = !instance.state.isEnabled; + var isTouchAndTouchDisabled = currentInput.isTouch && !instance.props.touch; + var duration = getValueAtIndexOrReturn(instance.props.duration, 0, defaultProps.duration); + + if (isAlreadyVisible || isDestroyed || isDisabled || isTouchAndTouchDisabled) { + return; + } // Normalize `disabled` behavior across browsers. + // Firefox allows events on disabled elements, but Chrome doesn't. + // Using a wrapper element (i.e. ) is recommended. + + + if (getCurrentTarget().hasAttribute('disabled')) { + return; + } + + invokeHook('onShow', [instance], false); + + if (instance.props.onShow(instance) === false) { + return; + } + + instance.state.isVisible = true; + + if (getIsDefaultRenderFn()) { + popper.style.visibility = 'visible'; + } + + handleStyles(); + addDocumentPress(); + + if (!instance.state.isMounted) { + popper.style.transition = 'none'; + } // If flipping to the opposite side after hiding at least once, the + // animation will use the wrong placement without resetting the duration + + + if (getIsDefaultRenderFn()) { + var _getDefaultTemplateCh2 = getDefaultTemplateChildren(), + box = _getDefaultTemplateCh2.box, + content = _getDefaultTemplateCh2.content; + + setTransitionDuration([box, content], 0); + } + + onFirstUpdate = function onFirstUpdate() + { + if (!instance.state.isVisible || ignoreOnFirstUpdate) { + return; + } + + ignoreOnFirstUpdate = true; // reflow + + void popper.offsetHeight; + popper.style.transition = instance.props.moveTransition; + + if (getIsDefaultRenderFn() && instance.props.animation) { + var _getDefaultTemplateCh3 = getDefaultTemplateChildren(), + _box = _getDefaultTemplateCh3.box, + _content = _getDefaultTemplateCh3.content; + + setTransitionDuration([_box, _content], duration); + setVisibilityState([_box, _content], 'visible'); + } + + handleAriaContentAttribute(); + handleAriaExpandedAttribute(); + pushIfUnique(mountedInstances, instance); + instance.state.isMounted = true; + invokeHook('onMount', [instance]); + + if (instance.props.animation && getIsDefaultRenderFn()) { + onTransitionedIn(duration, function () { + instance.state.isShown = true; + invokeHook('onShown', [instance]); + }); + } + }; + + mount(); + } + + function hide() + { + /* istanbul ignore else */ + { + warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('hide')); + } // Early bail-out + + + var isAlreadyHidden = !instance.state.isVisible; + var isDestroyed = instance.state.isDestroyed; + var isDisabled = !instance.state.isEnabled; + var duration = getValueAtIndexOrReturn(instance.props.duration, 1, defaultProps.duration); + + if (isAlreadyHidden || isDestroyed || isDisabled) { + return; + } + + invokeHook('onHide', [instance], false); + + if (instance.props.onHide(instance) === false) { + return; + } + + instance.state.isVisible = false; + instance.state.isShown = false; + ignoreOnFirstUpdate = false; + isVisibleFromClick = false; + + if (getIsDefaultRenderFn()) { + popper.style.visibility = 'hidden'; + } + + cleanupInteractiveMouseListeners(); + removeDocumentPress(); + handleStyles(); + + if (getIsDefaultRenderFn()) { + var _getDefaultTemplateCh4 = getDefaultTemplateChildren(), + box = _getDefaultTemplateCh4.box, + content = _getDefaultTemplateCh4.content; + + if (instance.props.animation) { + setTransitionDuration([box, content], duration); + setVisibilityState([box, content], 'hidden'); + } + } + + handleAriaContentAttribute(); + handleAriaExpandedAttribute(); + + if (instance.props.animation) { + if (getIsDefaultRenderFn()) { + onTransitionedOut(duration, instance.unmount); + } + } else { + instance.unmount(); + } + } + + function hideWithInteractivity(event) + { + /* istanbul ignore else */ + { + warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('hideWithInteractivity')); + } + + getDocument().addEventListener('mousemove', debouncedOnMouseMove); + pushIfUnique(mouseMoveListeners, debouncedOnMouseMove); + debouncedOnMouseMove(event); + } + + function unmount() + { + /* istanbul ignore else */ + { + warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('unmount')); + } + + if (instance.state.isVisible) { + instance.hide(); + } + + if (!instance.state.isMounted) { + return; + } + + destroyPopperInstance(); // If a popper is not interactive, it will be appended outside the popper + // tree by default. This seems mainly for interactive tippies, but we should + // find a workaround if possible + + getNestedPopperTree().forEach(function (nestedPopper) { + nestedPopper._tippy.unmount(); + }); + + if (popper.parentNode) { + popper.parentNode.removeChild(popper); + } + + mountedInstances = mountedInstances.filter(function (i) { + return i !== instance; + }); + instance.state.isMounted = false; + invokeHook('onHidden', [instance]); + } + + function destroy() + { + /* istanbul ignore else */ + { + warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('destroy')); + } + + if (instance.state.isDestroyed) { + return; + } + + instance.clearDelayTimeouts(); + instance.unmount(); + removeListeners(); + delete reference._tippy; + instance.state.isDestroyed = true; + invokeHook('onDestroy', [instance]); + } + } + + function tippy(targets, optionalProps) + { + if (optionalProps === void 0) { + optionalProps = {}; + } + + var plugins = defaultProps.plugins.concat(optionalProps.plugins || []); + /* istanbul ignore else */ + + { + validateTargets(targets); + validateProps(optionalProps, plugins); + } + + bindGlobalEventListeners(); + var passedProps = Object.assign({}, optionalProps, { + plugins: plugins + }); + var elements = getArrayOfElements(targets); + /* istanbul ignore else */ + + { + var isSingleContentElement = isElement(passedProps.content); + var isMoreThanOneReferenceElement = elements.length > 1; + warnWhen(isSingleContentElement && isMoreThanOneReferenceElement, ['tippy() was passed an Element as the `content` prop, but more than', 'one tippy instance was created by this invocation. This means the', 'content element will only be appended to the last tippy instance.', '\n\n', 'Instead, pass the .innerHTML of the element, or use a function that', 'returns a cloned version of the element instead.', '\n\n', '1) content: element.innerHTML\n', '2) content: () => element.cloneNode(true)'].join(' ')); + } + + var instances = elements.reduce(function (acc, reference) { + var instance = reference && createTippy(reference, passedProps); + + if (instance) { + acc.push(instance); + } + + return acc; + }, []); + return isElement(targets) ? instances[0] : instances; + } + + tippy.defaultProps = defaultProps; + tippy.setDefaultProps = setDefaultProps; + tippy.currentInput = currentInput; + var hideAll = function hideAll(_temp) + { + var _ref = _temp === void 0 ? {} : _temp, + excludedReferenceOrInstance = _ref.exclude, + duration = _ref.duration; + + mountedInstances.forEach(function (instance) { + var isExcluded = false; + + if (excludedReferenceOrInstance) { + isExcluded = isReferenceElement(excludedReferenceOrInstance) ? instance.reference === excludedReferenceOrInstance : instance.popper === excludedReferenceOrInstance.popper; + } + + if (!isExcluded) { + var originalDuration = instance.props.duration; + instance.setProps({ + duration: duration + }); + instance.hide(); + + if (!instance.state.isDestroyed) { + instance.setProps({ + duration: originalDuration + }); + } + } + }); + }; + + var createSingleton = function createSingleton(tippyInstances, optionalProps) + { + if (optionalProps === void 0) { + optionalProps = {}; + } + + /* istanbul ignore else */ + { + errorWhen(!Array.isArray(tippyInstances), ['The first argument passed to createSingleton() must be an array of', 'tippy instances. The passed value was', String(tippyInstances)].join(' ')); + } + + var individualInstances = tippyInstances; + var references = []; + var currentTarget; + var overrides = optionalProps.overrides; + var interceptSetPropsCleanups = []; + + function setReferences() + { + references = individualInstances.map(function (instance) { + return instance.reference; + }); + } + + function enableInstances(isEnabled) + { + individualInstances.forEach(function (instance) { + if (isEnabled) { + instance.enable(); + } else { + instance.disable(); + } + }); + } + + function interceptSetProps(singleton) + { + return individualInstances.map(function (instance) { + var originalSetProps = instance.setProps; + + instance.setProps = function (props) { + originalSetProps(props); + + if (instance.reference === currentTarget) { + singleton.setProps(props); + } + }; + + return function () { + instance.setProps = originalSetProps; + }; + }); + } + + enableInstances(false); + setReferences(); + var plugin = { + fn: function fn() + { + return { + onDestroy: function onDestroy() + { + enableInstances(true); + }, + onTrigger: function onTrigger(instance, event) + { + var target = event.currentTarget; + var index = references.indexOf(target); // bail-out + + if (target === currentTarget) { + return; + } + + currentTarget = target; + var overrideProps = (overrides || []).concat('content').reduce(function (acc, prop) { + acc[prop] = individualInstances[index].props[prop]; + return acc; + }, {}); + instance.setProps(Object.assign({}, overrideProps, { + getReferenceClientRect: typeof overrideProps.getReferenceClientRect === 'function' ? overrideProps.getReferenceClientRect : function () { + return target.getBoundingClientRect(); + } + })); + } + }; + } + }; + var singleton = tippy(div(), Object.assign({}, removeProperties(optionalProps, ['overrides']), { + plugins: [plugin].concat(optionalProps.plugins || []), + triggerTarget: references + })); + var originalSetProps = singleton.setProps; + + singleton.setProps = function (props) { + overrides = props.overrides || overrides; + originalSetProps(props); + }; + + singleton.setInstances = function (nextInstances) { + enableInstances(true); + interceptSetPropsCleanups.forEach(function (fn) { + return fn(); + }); + individualInstances = nextInstances; + enableInstances(false); + setReferences(); + interceptSetProps(singleton); + singleton.setProps({ + triggerTarget: references + }); + }; + + interceptSetPropsCleanups = interceptSetProps(singleton); + return singleton; + }; + + var BUBBLING_EVENTS_MAP = { + mouseover: 'mouseenter', + focusin: 'focus', + click: 'click' + }; + /** + * Creates a delegate instance that controls the creation of tippy instances + * for child elements (`target` CSS selector). + */ + + function delegate(targets, props) + { + /* istanbul ignore else */ + { + errorWhen(!(props && props.target), ['You must specity a `target` prop indicating a CSS selector string matching', 'the target elements that should receive a tippy.'].join(' ')); + } + + var listeners = []; + var childTippyInstances = []; + var disabled = false; + var target = props.target; + var nativeProps = removeProperties(props, ['target']); + var parentProps = Object.assign({}, nativeProps, { + trigger: 'manual', + touch: false + }); + var childProps = Object.assign({}, nativeProps, { + showOnCreate: true + }); + var returnValue = tippy(targets, parentProps); + var normalizedReturnValue = normalizeToArray(returnValue); + + function onTrigger(event) + { + if (!event.target || disabled) { + return; + } + + var targetNode = event.target.closest(target); + + if (!targetNode) { + return; + } // Get relevant trigger with fallbacks: + // 1. Check `data-tippy-trigger` attribute on target node + // 2. Fallback to `trigger` passed to `delegate()` + // 3. Fallback to `defaultProps.trigger` + + + var trigger = targetNode.getAttribute('data-tippy-trigger') || props.trigger || defaultProps.trigger; // @ts-ignore + + if (targetNode._tippy) { + return; + } + + if (event.type === 'touchstart' && typeof childProps.touch === 'boolean') { + return; + } + + if (event.type !== 'touchstart' && trigger.indexOf(BUBBLING_EVENTS_MAP[event.type]) < 0) { + return; + } + + var instance = tippy(targetNode, childProps); + + if (instance) { + childTippyInstances = childTippyInstances.concat(instance); + } + } + + function on(node, eventType, handler, options) + { + if (options === void 0) { + options = false; + } + + node.addEventListener(eventType, handler, options); + listeners.push({ + node: node, + eventType: eventType, + handler: handler, + options: options + }); + } + + function addEventListeners(instance) + { + var reference = instance.reference; + on(reference, 'touchstart', onTrigger); + on(reference, 'mouseover', onTrigger); + on(reference, 'focusin', onTrigger); + on(reference, 'click', onTrigger); + } + + function removeEventListeners() + { + listeners.forEach(function (_ref) { + var node = _ref.node, + eventType = _ref.eventType, + handler = _ref.handler, + options = _ref.options; + node.removeEventListener(eventType, handler, options); + }); + listeners = []; + } + + function applyMutations(instance) + { + var originalDestroy = instance.destroy; + var originalEnable = instance.enable; + var originalDisable = instance.disable; + + instance.destroy = function (shouldDestroyChildInstances) { + if (shouldDestroyChildInstances === void 0) { + shouldDestroyChildInstances = true; + } + + if (shouldDestroyChildInstances) { + childTippyInstances.forEach(function (instance) { + instance.destroy(); + }); + } + + childTippyInstances = []; + removeEventListeners(); + originalDestroy(); + }; + + instance.enable = function () { + originalEnable(); + childTippyInstances.forEach(function (instance) { + return instance.enable(); + }); + disabled = false; + }; + + instance.disable = function () { + originalDisable(); + childTippyInstances.forEach(function (instance) { + return instance.disable(); + }); + disabled = true; + }; + + addEventListeners(instance); + } + + normalizedReturnValue.forEach(applyMutations); + return returnValue; + } + + var animateFill = { + name: 'animateFill', + defaultValue: false, + fn: function fn(instance) + { + var _instance$props$rende; + + // @ts-ignore + if (!((_instance$props$rende = instance.props.render) == null ? void 0 : _instance$props$rende.$$tippy)) { + { + errorWhen(instance.props.animateFill, 'The `animateFill` plugin requires the default render function.'); + } + + return {}; + } + + var _getChildren = getChildren(instance.popper), + box = _getChildren.box, + content = _getChildren.content; + + var backdrop = instance.props.animateFill ? createBackdropElement() : null; + return { + onCreate: function onCreate() + { + if (backdrop) { + box.insertBefore(backdrop, box.firstElementChild); + box.setAttribute('data-animatefill', ''); + box.style.overflow = 'hidden'; + instance.setProps({ + arrow: false, + animation: 'shift-away' + }); + } + }, + onMount: function onMount() + { + if (backdrop) { + var transitionDuration = box.style.transitionDuration; + var duration = Number(transitionDuration.replace('ms', '')); // The content should fade in after the backdrop has mostly filled the + // tooltip element. `clip-path` is the other alternative but is not + // well-supported and is buggy on some devices. + + content.style.transitionDelay = Math.round(duration / 10) + "ms"; + backdrop.style.transitionDuration = transitionDuration; + setVisibilityState([backdrop], 'visible'); + } + }, + onShow: function onShow() + { + if (backdrop) { + backdrop.style.transitionDuration = '0ms'; + } + }, + onHide: function onHide() + { + if (backdrop) { + setVisibilityState([backdrop], 'hidden'); + } + } + }; + } + }; + + function createBackdropElement() + { + var backdrop = div(); + backdrop.className = BACKDROP_CLASS; + setVisibilityState([backdrop], 'hidden'); + return backdrop; + } + + var mouseCoords = { + clientX: 0, + clientY: 0 + }; + var activeInstances = []; + + function storeMouseCoords(_ref) + { + var clientX = _ref.clientX, + clientY = _ref.clientY; + mouseCoords = { + clientX: clientX, + clientY: clientY + }; + } + + function addMouseCoordsListener(doc) + { + doc.addEventListener('mousemove', storeMouseCoords); + } + + function removeMouseCoordsListener(doc) + { + doc.removeEventListener('mousemove', storeMouseCoords); + } + + var followCursor = { + name: 'followCursor', + defaultValue: false, + fn: function fn(instance) + { + var reference = instance.reference; + var doc = getOwnerDocument(instance.props.triggerTarget || reference); + var isInternalUpdate = false; + var wasFocusEvent = false; + var isUnmounted = true; + var prevProps = instance.props; + + function getIsInitialBehavior() + { + return instance.props.followCursor === 'initial' && instance.state.isVisible; + } + + function addListener() + { + doc.addEventListener('mousemove', onMouseMove); + } + + function removeListener() + { + doc.removeEventListener('mousemove', onMouseMove); + } + + function unsetGetReferenceClientRect() + { + isInternalUpdate = true; + instance.setProps({ + getReferenceClientRect: null + }); + isInternalUpdate = false; + } + + function onMouseMove(event) + { + // If the instance is interactive, avoid updating the position unless it's + // over the reference element + var isCursorOverReference = event.target ? reference.contains(event.target) : true; + var followCursor = instance.props.followCursor; + var clientX = event.clientX, + clientY = event.clientY; + var rect = reference.getBoundingClientRect(); + var relativeX = clientX - rect.left; + var relativeY = clientY - rect.top; + + if (isCursorOverReference || !instance.props.interactive) { + instance.setProps({ + getReferenceClientRect: function getReferenceClientRect() + { + var rect = reference.getBoundingClientRect(); + var x = clientX; + var y = clientY; + + if (followCursor === 'initial') { + x = rect.left + relativeX; + y = rect.top + relativeY; + } + + var top = followCursor === 'horizontal' ? rect.top : y; + var right = followCursor === 'vertical' ? rect.right : x; + var bottom = followCursor === 'horizontal' ? rect.bottom : y; + var left = followCursor === 'vertical' ? rect.left : x; + return { + width: right - left, + height: bottom - top, + top: top, + right: right, + bottom: bottom, + left: left + }; + } + }); + } + } + + function create() + { + if (instance.props.followCursor) { + activeInstances.push({ + instance: instance, + doc: doc + }); + addMouseCoordsListener(doc); + } + } + + function destroy() + { + activeInstances = activeInstances.filter(function (data) { + return data.instance !== instance; + }); + + if (activeInstances.filter(function (data) { + return data.doc === doc; + }).length === 0) { + removeMouseCoordsListener(doc); + } + } + + return { + onCreate: create, + onDestroy: destroy, + onBeforeUpdate: function onBeforeUpdate() + { + prevProps = instance.props; + }, + onAfterUpdate: function onAfterUpdate(_, _ref2) + { + var followCursor = _ref2.followCursor; + + if (isInternalUpdate) { + return; + } + + if (followCursor !== undefined && prevProps.followCursor !== followCursor) { + destroy(); + + if (followCursor) { + create(); + + if (instance.state.isMounted && !wasFocusEvent && !getIsInitialBehavior()) { + addListener(); + } + } else { + removeListener(); + unsetGetReferenceClientRect(); + } + } + }, + onMount: function onMount() + { + if (instance.props.followCursor && !wasFocusEvent) { + if (isUnmounted) { + onMouseMove(mouseCoords); + isUnmounted = false; + } + + if (!getIsInitialBehavior()) { + addListener(); + } + } + }, + onTrigger: function onTrigger(_, event) + { + if (isMouseEvent(event)) { + mouseCoords = { + clientX: event.clientX, + clientY: event.clientY + }; + } + + wasFocusEvent = event.type === 'focus'; + }, + onHidden: function onHidden() + { + if (instance.props.followCursor) { + unsetGetReferenceClientRect(); + removeListener(); + isUnmounted = true; + } + } + }; + } + }; + + function getProps(props, modifier) + { + var _props$popperOptions; + + return { + popperOptions: Object.assign({}, props.popperOptions, { + modifiers: [].concat((((_props$popperOptions = props.popperOptions) == null ? void 0 : _props$popperOptions.modifiers) || []).filter(function (_ref) { + var name = _ref.name; + return name !== modifier.name; + }), [modifier]) + }) + }; + } + + var inlinePositioning = { + name: 'inlinePositioning', + defaultValue: false, + fn: function fn(instance) + { + var reference = instance.reference; + + function isEnabled() + { + return !!instance.props.inlinePositioning; + } + + var placement; + var cursorRectIndex = -1; + var isInternalUpdate = false; + var modifier = { + name: 'tippyInlinePositioning', + enabled: true, + phase: 'afterWrite', + fn: function fn(_ref2) + { + var state = _ref2.state; + + if (isEnabled()) { + if (placement !== state.placement) { + instance.setProps({ + getReferenceClientRect: function getReferenceClientRect() + { + return _getReferenceClientRect(state.placement); + } + }); + } + + placement = state.placement; + } + } + }; + + function _getReferenceClientRect(placement) + { + return getInlineBoundingClientRect(getBasePlacement(placement), reference.getBoundingClientRect(), arrayFrom(reference.getClientRects()), cursorRectIndex); + } + + function setInternalProps(partialProps) + { + isInternalUpdate = true; + instance.setProps(partialProps); + isInternalUpdate = false; + } + + function addModifier() + { + if (!isInternalUpdate) { + setInternalProps(getProps(instance.props, modifier)); + } + } + + return { + onCreate: addModifier, + onAfterUpdate: addModifier, + onTrigger: function onTrigger(_, event) + { + if (isMouseEvent(event)) { + var rects = arrayFrom(instance.reference.getClientRects()); + var cursorRect = rects.find(function (rect) { + return rect.left - 2 <= event.clientX && rect.right + 2 >= event.clientX && rect.top - 2 <= event.clientY && rect.bottom + 2 >= event.clientY; + }); + cursorRectIndex = rects.indexOf(cursorRect); + } + }, + onUntrigger: function onUntrigger() + { + cursorRectIndex = -1; + } + }; + } + }; + function getInlineBoundingClientRect(currentBasePlacement, boundingRect, clientRects, cursorRectIndex) + { + // Not an inline element, or placement is not yet known + if (clientRects.length < 2 || currentBasePlacement === null) { + return boundingRect; + } // There are two rects and they are disjoined + + + if (clientRects.length === 2 && cursorRectIndex >= 0 && clientRects[0].left > clientRects[1].right) { + return clientRects[cursorRectIndex] || boundingRect; + } + + switch (currentBasePlacement) { + case 'top': + case 'bottom': + { + var firstRect = clientRects[0]; + var lastRect = clientRects[clientRects.length - 1]; + var isTop = currentBasePlacement === 'top'; + var top = firstRect.top; + var bottom = lastRect.bottom; + var left = isTop ? firstRect.left : lastRect.left; + var right = isTop ? firstRect.right : lastRect.right; + var width = right - left; + var height = bottom - top; + return { + top: top, + bottom: bottom, + left: left, + right: right, + width: width, + height: height + }; + } + + case 'left': + case 'right': + { + var minLeft = Math.min.apply(Math, clientRects.map(function (rects) { + return rects.left; + })); + var maxRight = Math.max.apply(Math, clientRects.map(function (rects) { + return rects.right; + })); + var measureRects = clientRects.filter(function (rect) { + return currentBasePlacement === 'left' ? rect.left === minLeft : rect.right === maxRight; + }); + var _top = measureRects[0].top; + var _bottom = measureRects[measureRects.length - 1].bottom; + var _left = minLeft; + var _right = maxRight; + + var _width = _right - _left; + + var _height = _bottom - _top; + + return { + top: _top, + bottom: _bottom, + left: _left, + right: _right, + width: _width, + height: _height + }; + } + + default: + { + return boundingRect; + } + } + } + + var sticky = { + name: 'sticky', + defaultValue: false, + fn: function fn(instance) + { + var reference = instance.reference, + popper = instance.popper; + + function getReference() + { + return instance.popperInstance ? instance.popperInstance.state.elements.reference : reference; + } + + function shouldCheck(value) + { + return instance.props.sticky === true || instance.props.sticky === value; + } + + var prevRefRect = null; + var prevPopRect = null; + + function updatePosition() + { + var currentRefRect = shouldCheck('reference') ? getReference().getBoundingClientRect() : null; + var currentPopRect = shouldCheck('popper') ? popper.getBoundingClientRect() : null; + + if (currentRefRect && areRectsDifferent(prevRefRect, currentRefRect) || currentPopRect && areRectsDifferent(prevPopRect, currentPopRect)) { + if (instance.popperInstance) { + instance.popperInstance.update(); + } + } + + prevRefRect = currentRefRect; + prevPopRect = currentPopRect; + + if (instance.state.isMounted) { + requestAnimationFrame(updatePosition); + } + } + + return { + onMount: function onMount() + { + if (instance.props.sticky) { + updatePosition(); + } + } + }; + } + }; + + function areRectsDifferent(rectA, rectB) + { + if (rectA && rectB) { + return rectA.top !== rectB.top || rectA.right !== rectB.right || rectA.bottom !== rectB.bottom || rectA.left !== rectB.left; + } + + return true; + } + + if (isBrowser) { + injectCSS(css); + } + + tippy.setDefaultProps({ + plugins: [animateFill, followCursor, inlinePositioning, sticky], + render: render + }); + tippy.createSingleton = createSingleton; + tippy.delegate = delegate; + tippy.hideAll = hideAll; + tippy.roundArrow = ROUND_ARROW; + + return tippy; + +}))); diff --git a/assets/js/tippy/tippy-bundle.umd.min.js b/assets/js/tippy/tippy-bundle.umd.min.js new file mode 100644 index 00000000..09bc11d3 --- /dev/null +++ b/assets/js/tippy/tippy-bundle.umd.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t=t||self).tippy=e(t.Popper)}(this,(function(t){"use strict";var e="undefined"!=typeof window&&"undefined"!=typeof document,n=e?navigator.userAgent:"",r=/MSIE |Trident\//.test(n),i={passive:!0,capture:!0};function o(t,e,n){if(Array.isArray(t)){var r=t[e];return null==r?Array.isArray(n)?n[e]:n:r}return t}function a(t,e){var n={}.toString.call(t);return 0===n.indexOf("[object")&&n.indexOf(e+"]")>-1}function s(t,e){return"function"==typeof t?t.apply(void 0,e):t}function u(t,e){return 0===e?t:function(r){clearTimeout(n),n=setTimeout((function(){t(r)}),e)};var n}function c(t,e){var n=Object.assign({},t);return e.forEach((function(t){delete n[t]})),n}function p(t){return[].concat(t)}function f(t,e){-1===t.indexOf(e)&&t.push(e)}function l(t){return t.split("-")[0]}function d(t){return[].slice.call(t)}function v(){return document.createElement("div")}function m(t){return["Element","Fragment"].some((function(e){return a(t,e)}))}function g(t){return a(t,"MouseEvent")}function h(t){return!(!t||!t._tippy||t._tippy.reference!==t)}function b(t){return m(t)?[t]:function(t){return a(t,"NodeList")}(t)?d(t):Array.isArray(t)?t:d(document.querySelectorAll(t))}function y(t,e){t.forEach((function(t){t&&(t.style.transitionDuration=e+"ms")}))}function x(t,e){t.forEach((function(t){t&&t.setAttribute("data-state",e)}))}function w(t){var e=p(t)[0];return e&&e.ownerDocument||document}function E(t,e,n){var r=e+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(e){t[r](e,n)}))}var T={isTouch:!1},C=0;function A(){T.isTouch||(T.isTouch=!0,window.performance&&document.addEventListener("mousemove",O))}function O(){var t=performance.now();t-C<20&&(T.isTouch=!1,document.removeEventListener("mousemove",O)),C=t}function L(){var t=document.activeElement;if(h(t)){var e=t._tippy;t.blur&&!e.state.isVisible&&t.blur()}}var D=Object.assign({appendTo:function(){return document.body},aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(D);function R(t){var e=(t.plugins||[]).reduce((function(e,n){var r=n.name,i=n.defaultValue;return r&&(e[r]=void 0!==t[r]?t[r]:i),e}),{});return Object.assign({},t,{},e)}function M(t,e){var n=Object.assign({},e,{content:s(e.content,[t])},e.ignoreAttributes?{}:function(t,e){return(e?Object.keys(R(Object.assign({},D,{plugins:e}))):k).reduce((function(e,n){var r=(t.getAttribute("data-tippy-"+n)||"").trim();if(!r)return e;if("content"===n)e[n]=r;else try{e[n]=JSON.parse(r)}catch(t){e[n]=r}return e}),{})}(t,e.plugins));return n.aria=Object.assign({},D.aria,{},n.aria),n.aria={expanded:"auto"===n.aria.expanded?e.interactive:n.aria.expanded,content:"auto"===n.aria.content?e.interactive?null:"describedby":n.aria.content},n}function P(t,e){t.innerHTML=e}function V(t){var e=v();return!0===t?e.className="tippy-arrow":(e.className="tippy-svg-arrow",m(t)?e.appendChild(t):P(e,t)),e}function j(t,e){m(e.content)?(P(t,""),t.appendChild(e.content)):"function"!=typeof e.content&&(e.allowHTML?P(t,e.content):t.textContent=e.content)}function I(t){var e=t.firstElementChild,n=d(e.children);return{box:e,content:n.find((function(t){return t.classList.contains("tippy-content")})),arrow:n.find((function(t){return t.classList.contains("tippy-arrow")||t.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(t){return t.classList.contains("tippy-backdrop")}))}}function S(t){var e=v(),n=v();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=v();function i(n,r){var i=I(e),o=i.box,a=i.content,s=i.arrow;r.theme?o.setAttribute("data-theme",r.theme):o.removeAttribute("data-theme"),"string"==typeof r.animation?o.setAttribute("data-animation",r.animation):o.removeAttribute("data-animation"),r.inertia?o.setAttribute("data-inertia",""):o.removeAttribute("data-inertia"),o.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?o.setAttribute("role",r.role):o.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||j(a,t.props),r.arrow?s?n.arrow!==r.arrow&&(o.removeChild(s),o.appendChild(V(r.arrow))):o.appendChild(V(r.arrow)):s&&o.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),j(r,t.props),e.appendChild(n),n.appendChild(r),i(t.props,t.props),{popper:e,onUpdate:i}}S.$$tippy=!0;var B=1,H=[],N=[];function U(e,n){var a,c,m,h,b,C,A,O,L,k=M(e,Object.assign({},D,{},R((a=n,Object.keys(a).reduce((function(t,e){return void 0!==a[e]&&(t[e]=a[e]),t}),{}))))),P=!1,V=!1,j=!1,S=!1,U=[],_=u(bt,k.interactiveDebounce),z=B++,F=(L=k.plugins).filter((function(t,e){return L.indexOf(t)===e})),W={id:z,reference:e,popper:v(),popperInstance:null,props:k,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:F,clearDelayTimeouts:function(){clearTimeout(c),clearTimeout(m),cancelAnimationFrame(h)},setProps:function(t){if(W.state.isDestroyed)return;it("onBeforeUpdate",[W,t]),gt();var n=W.props,r=M(e,Object.assign({},W.props,{},t,{ignoreAttributes:!0}));W.props=r,mt(),n.interactiveDebounce!==r.interactiveDebounce&&(st(),_=u(bt,r.interactiveDebounce));n.triggerTarget&&!r.triggerTarget?p(n.triggerTarget).forEach((function(t){t.removeAttribute("aria-expanded")})):r.triggerTarget&&e.removeAttribute("aria-expanded");at(),rt(),q&&q(n,r);W.popperInstance&&(Et(),Ct().forEach((function(t){requestAnimationFrame(t._tippy.popperInstance.forceUpdate)})));it("onAfterUpdate",[W,t])},setContent:function(t){W.setProps({content:t})},show:function(){var t=W.state.isVisible,e=W.state.isDestroyed,n=!W.state.isEnabled,r=T.isTouch&&!W.props.touch,i=o(W.props.duration,0,D.duration);if(t||e||n||r)return;if(Z().hasAttribute("disabled"))return;if(it("onShow",[W],!1),!1===W.props.onShow(W))return;W.state.isVisible=!0,Q()&&(Y.style.visibility="visible");rt(),ft(),W.state.isMounted||(Y.style.transition="none");if(Q()){var a=et(),u=a.box,c=a.content;y([u,c],0)}A=function(){if(W.state.isVisible&&!S){if(S=!0,Y.offsetHeight,Y.style.transition=W.props.moveTransition,Q()&&W.props.animation){var t=et(),e=t.box,n=t.content;y([e,n],i),x([e,n],"visible")}ot(),at(),f(N,W),W.state.isMounted=!0,it("onMount",[W]),W.props.animation&&Q()&&function(t,e){dt(t,e)}(i,(function(){W.state.isShown=!0,it("onShown",[W])}))}},function(){var t,e=W.props.appendTo,n=Z();t=W.props.interactive&&e===D.appendTo||"parent"===e?n.parentNode:s(e,[n]);t.contains(Y)||t.appendChild(Y);Et()}()},hide:function(){var t=!W.state.isVisible,e=W.state.isDestroyed,n=!W.state.isEnabled,r=o(W.props.duration,1,D.duration);if(t||e||n)return;if(it("onHide",[W],!1),!1===W.props.onHide(W))return;W.state.isVisible=!1,W.state.isShown=!1,S=!1,P=!1,Q()&&(Y.style.visibility="hidden");if(st(),lt(),rt(),Q()){var i=et(),a=i.box,s=i.content;W.props.animation&&(y([a,s],r),x([a,s],"hidden"))}ot(),at(),W.props.animation?Q()&&function(t,e){dt(t,(function(){!W.state.isVisible&&Y.parentNode&&Y.parentNode.contains(Y)&&e()}))}(r,W.unmount):W.unmount()},hideWithInteractivity:function(t){tt().addEventListener("mousemove",_),f(H,_),_(t)},enable:function(){W.state.isEnabled=!0},disable:function(){W.hide(),W.state.isEnabled=!1},unmount:function(){W.state.isVisible&&W.hide();if(!W.state.isMounted)return;Tt(),Ct().forEach((function(t){t._tippy.unmount()})),Y.parentNode&&Y.parentNode.removeChild(Y);N=N.filter((function(t){return t!==W})),W.state.isMounted=!1,it("onHidden",[W])},destroy:function(){if(W.state.isDestroyed)return;W.clearDelayTimeouts(),W.unmount(),gt(),delete e._tippy,W.state.isDestroyed=!0,it("onDestroy",[W])}};if(!k.render)return W;var X=k.render(W),Y=X.popper,q=X.onUpdate;Y.setAttribute("data-tippy-root",""),Y.id="tippy-"+W.id,W.popper=Y,e._tippy=W,Y._tippy=W;var $=F.map((function(t){return t.fn(W)})),J=e.hasAttribute("aria-expanded");return mt(),at(),rt(),it("onCreate",[W]),k.showOnCreate&&At(),Y.addEventListener("mouseenter",(function(){W.props.interactive&&W.state.isVisible&&W.clearDelayTimeouts()})),Y.addEventListener("mouseleave",(function(t){W.props.interactive&&W.props.trigger.indexOf("mouseenter")>=0&&(tt().addEventListener("mousemove",_),_(t))})),W;function G(){var t=W.props.touch;return Array.isArray(t)?t:[t,0]}function K(){return"hold"===G()[0]}function Q(){var t;return!!(null==(t=W.props.render)?void 0:t.$$tippy)}function Z(){return O||e}function tt(){var t=Z().parentNode;return t?w(t):document}function et(){return I(Y)}function nt(t){return W.state.isMounted&&!W.state.isVisible||T.isTouch||b&&"focus"===b.type?0:o(W.props.delay,t?0:1,D.delay)}function rt(){Y.style.pointerEvents=W.props.interactive&&W.state.isVisible?"":"none",Y.style.zIndex=""+W.props.zIndex}function it(t,e,n){var r;(void 0===n&&(n=!0),$.forEach((function(n){n[t]&&n[t].apply(void 0,e)})),n)&&(r=W.props)[t].apply(r,e)}function ot(){var t=W.props.aria;if(t.content){var n="aria-"+t.content,r=Y.id;p(W.props.triggerTarget||e).forEach((function(t){var e=t.getAttribute(n);if(W.state.isVisible)t.setAttribute(n,e?e+" "+r:r);else{var i=e&&e.replace(r,"").trim();i?t.setAttribute(n,i):t.removeAttribute(n)}}))}}function at(){!J&&W.props.aria.expanded&&p(W.props.triggerTarget||e).forEach((function(t){W.props.interactive?t.setAttribute("aria-expanded",W.state.isVisible&&t===Z()?"true":"false"):t.removeAttribute("aria-expanded")}))}function st(){tt().removeEventListener("mousemove",_),H=H.filter((function(t){return t!==_}))}function ut(t){if(!(T.isTouch&&(j||"mousedown"===t.type)||W.props.interactive&&Y.contains(t.target))){if(Z().contains(t.target)){if(T.isTouch)return;if(W.state.isVisible&&W.props.trigger.indexOf("click")>=0)return}else it("onClickOutside",[W,t]);!0===W.props.hideOnClick&&(W.clearDelayTimeouts(),W.hide(),V=!0,setTimeout((function(){V=!1})),W.state.isMounted||lt())}}function ct(){j=!0}function pt(){j=!1}function ft(){var t=tt();t.addEventListener("mousedown",ut,!0),t.addEventListener("touchend",ut,i),t.addEventListener("touchstart",pt,i),t.addEventListener("touchmove",ct,i)}function lt(){var t=tt();t.removeEventListener("mousedown",ut,!0),t.removeEventListener("touchend",ut,i),t.removeEventListener("touchstart",pt,i),t.removeEventListener("touchmove",ct,i)}function dt(t,e){var n=et().box;function r(t){t.target===n&&(E(n,"remove",r),e())}if(0===t)return e();E(n,"remove",C),E(n,"add",r),C=r}function vt(t,n,r){void 0===r&&(r=!1),p(W.props.triggerTarget||e).forEach((function(e){e.addEventListener(t,n,r),U.push({node:e,eventType:t,handler:n,options:r})}))}function mt(){var t;K()&&(vt("touchstart",ht,{passive:!0}),vt("touchend",yt,{passive:!0})),(t=W.props.trigger,t.split(/\s+/).filter(Boolean)).forEach((function(t){if("manual"!==t)switch(vt(t,ht),t){case"mouseenter":vt("mouseleave",yt);break;case"focus":vt(r?"focusout":"blur",xt);break;case"focusin":vt("focusout",xt)}}))}function gt(){U.forEach((function(t){var e=t.node,n=t.eventType,r=t.handler,i=t.options;e.removeEventListener(n,r,i)})),U=[]}function ht(t){var e,n=!1;if(W.state.isEnabled&&!wt(t)&&!V){var r="focus"===(null==(e=b)?void 0:e.type);b=t,O=t.currentTarget,at(),!W.state.isVisible&&g(t)&&H.forEach((function(e){return e(t)})),"click"===t.type&&(W.props.trigger.indexOf("mouseenter")<0||P)&&!1!==W.props.hideOnClick&&W.state.isVisible?n=!0:At(t),"click"===t.type&&(P=!n),n&&!r&&Ot(t)}}function bt(t){var e=t.target,n=Z().contains(e)||Y.contains(e);"mousemove"===t.type&&n||function(t,e){var n=e.clientX,r=e.clientY;return t.every((function(t){var e=t.popperRect,i=t.popperState,o=t.props.interactiveBorder,a=l(i.placement),s=i.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,p="right"===a?s.left.x:0,f="left"===a?s.right.x:0,d=e.top-r+u>o,v=r-e.bottom-c>o,m=e.left-n+p>o,g=n-e.right-f>o;return d||v||m||g}))}(Ct().concat(Y).map((function(t){var e,n=null==(e=t._tippy.popperInstance)?void 0:e.state;return n?{popperRect:t.getBoundingClientRect(),popperState:n,props:k}:null})).filter(Boolean),t)&&(st(),Ot(t))}function yt(t){wt(t)||W.props.trigger.indexOf("click")>=0&&P||(W.props.interactive?W.hideWithInteractivity(t):Ot(t))}function xt(t){W.props.trigger.indexOf("focusin")<0&&t.target!==Z()||W.props.interactive&&t.relatedTarget&&Y.contains(t.relatedTarget)||Ot(t)}function wt(t){return!!T.isTouch&&K()!==t.type.indexOf("touch")>=0}function Et(){Tt();var n=W.props,r=n.popperOptions,i=n.placement,o=n.offset,a=n.getReferenceClientRect,s=n.moveTransition,u=Q()?I(Y).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||Z()}:e,p=[{name:"offset",options:{offset:o}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(t){var e=t.state;if(Q()){var n=et().box;["placement","reference-hidden","escaped"].forEach((function(t){"placement"===t?n.setAttribute("data-placement",e.placement):e.attributes.popper["data-popper-"+t]?n.setAttribute("data-"+t,""):n.removeAttribute("data-"+t)})),e.attributes.popper={}}}}];Q()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==r?void 0:r.modifiers)||[]),W.popperInstance=t.createPopper(c,Y,Object.assign({},r,{placement:i,onFirstUpdate:A,modifiers:p}))}function Tt(){W.popperInstance&&(W.popperInstance.destroy(),W.popperInstance=null)}function Ct(){return d(Y.querySelectorAll("[data-tippy-root]"))}function At(t){W.clearDelayTimeouts(),t&&it("onTrigger",[W,t]),ft();var e=nt(!0),n=G(),r=n[0],i=n[1];T.isTouch&&"hold"===r&&i&&(e=i),e?c=setTimeout((function(){W.show()}),e):W.show()}function Ot(t){if(W.clearDelayTimeouts(),it("onUntrigger",[W,t]),W.state.isVisible){if(!(W.props.trigger.indexOf("mouseenter")>=0&&W.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(t.type)>=0&&P)){var e=nt(!1);e?m=setTimeout((function(){W.state.isVisible&&W.hide()}),e):h=requestAnimationFrame((function(){W.hide()}))}}else lt()}}function _(t,e){void 0===e&&(e={});var n=D.plugins.concat(e.plugins||[]);document.addEventListener("touchstart",A,i),window.addEventListener("blur",L);var r=Object.assign({},e,{plugins:n}),o=b(t).reduce((function(t,e){var n=e&&U(e,r);return n&&t.push(n),t}),[]);return m(t)?o[0]:o}_.defaultProps=D,_.setDefaultProps=function(t){Object.keys(t).forEach((function(e){D[e]=t[e]}))},_.currentInput=T;var z={mouseover:"mouseenter",focusin:"focus",click:"click"};var F={name:"animateFill",defaultValue:!1,fn:function(t){var e;if(!(null==(e=t.props.render)?void 0:e.$$tippy))return{};var n=I(t.popper),r=n.box,i=n.content,o=t.props.animateFill?function(){var t=v();return t.className="tippy-backdrop",x([t],"hidden"),t}():null;return{onCreate:function(){o&&(r.insertBefore(o,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",t.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(o){var t=r.style.transitionDuration,e=Number(t.replace("ms",""));i.style.transitionDelay=Math.round(e/10)+"ms",o.style.transitionDuration=t,x([o],"visible")}},onShow:function(){o&&(o.style.transitionDuration="0ms")},onHide:function(){o&&x([o],"hidden")}}}};var W={clientX:0,clientY:0},X=[];function Y(t){var e=t.clientX,n=t.clientY;W={clientX:e,clientY:n}}var q={name:"followCursor",defaultValue:!1,fn:function(t){var e=t.reference,n=w(t.props.triggerTarget||e),r=!1,i=!1,o=!0,a=t.props;function s(){return"initial"===t.props.followCursor&&t.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,t.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||e.contains(n.target),i=t.props.followCursor,o=n.clientX,a=n.clientY,s=e.getBoundingClientRect(),u=o-s.left,c=a-s.top;!r&&t.props.interactive||t.setProps({getReferenceClientRect:function(){var t=e.getBoundingClientRect(),n=o,r=a;"initial"===i&&(n=t.left+u,r=t.top+c);var s="horizontal"===i?t.top:r,p="vertical"===i?t.right:n,f="horizontal"===i?t.bottom:r,l="vertical"===i?t.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){t.props.followCursor&&(X.push({instance:t,doc:n}),function(t){t.addEventListener("mousemove",Y)}(n))}function d(){0===(X=X.filter((function(e){return e.instance!==t}))).filter((function(t){return t.doc===n})).length&&function(t){t.removeEventListener("mousemove",Y)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=t.props},onAfterUpdate:function(e,n){var o=n.followCursor;r||void 0!==o&&a.followCursor!==o&&(d(),o?(l(),!t.state.isMounted||i||s()||u()):(c(),p()))},onMount:function(){t.props.followCursor&&!i&&(o&&(f(W),o=!1),s()||u())},onTrigger:function(t,e){g(e)&&(W={clientX:e.clientX,clientY:e.clientY}),i="focus"===e.type},onHidden:function(){t.props.followCursor&&(p(),c(),o=!0)}}}};var $={name:"inlinePositioning",defaultValue:!1,fn:function(t){var e,n=t.reference;var r=-1,i=!1,o={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(i){var o=i.state;t.props.inlinePositioning&&(e!==o.placement&&t.setProps({getReferenceClientRect:function(){return function(t){return function(t,e,n,r){if(n.length<2||null===t)return e;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||e;switch(t){case"top":case"bottom":var i=n[0],o=n[n.length-1],a="top"===t,s=i.top,u=o.bottom,c=a?i.left:o.left,p=a?i.right:o.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(t){return t.left}))),l=Math.max.apply(Math,n.map((function(t){return t.right}))),d=n.filter((function(e){return"left"===t?e.left===f:e.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return e}}(l(t),n.getBoundingClientRect(),d(n.getClientRects()),r)}(o.placement)}}),e=o.placement)}};function a(){var e;i||(e=function(t,e){var n;return{popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat(((null==(n=t.popperOptions)?void 0:n.modifiers)||[]).filter((function(t){return t.name!==e.name})),[e])})}}(t.props,o),i=!0,t.setProps(e),i=!1)}return{onCreate:a,onAfterUpdate:a,onTrigger:function(e,n){if(g(n)){var i=d(t.reference.getClientRects()),o=i.find((function(t){return t.left-2<=n.clientX&&t.right+2>=n.clientX&&t.top-2<=n.clientY&&t.bottom+2>=n.clientY}));r=i.indexOf(o)}},onUntrigger:function(){r=-1}}}};var J={name:"sticky",defaultValue:!1,fn:function(t){var e=t.reference,n=t.popper;function r(e){return!0===t.props.sticky||t.props.sticky===e}var i=null,o=null;function a(){var s=r("reference")?(t.popperInstance?t.popperInstance.state.elements.reference:e).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&G(i,s)||u&&G(o,u))&&t.popperInstance&&t.popperInstance.update(),i=s,o=u,t.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){t.props.sticky&&a()}}}};function G(t,e){return!t||!e||(t.top!==e.top||t.right!==e.right||t.bottom!==e.bottom||t.left!==e.left)}return e&&function(t){var e=document.createElement("style");e.textContent=t,e.setAttribute("data-tippy-stylesheet","");var n=document.head,r=document.querySelector("head>style,head>link");r?n.insertBefore(e,r):n.appendChild(e)}('.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}'),_.setDefaultProps({plugins:[F,q,$,J],render:S}),_.createSingleton=function(t,e){void 0===e&&(e={});var n,r=t,i=[],o=e.overrides,a=[];function s(){i=r.map((function(t){return t.reference}))}function u(t){r.forEach((function(e){t?e.enable():e.disable()}))}function p(t){return r.map((function(e){var r=e.setProps;return e.setProps=function(i){r(i),e.reference===n&&t.setProps(i)},function(){e.setProps=r}}))}u(!1),s();var f={fn:function(){return{onDestroy:function(){u(!0)},onTrigger:function(t,e){var a=e.currentTarget,s=i.indexOf(a);if(a!==n){n=a;var u=(o||[]).concat("content").reduce((function(t,e){return t[e]=r[s].props[e],t}),{});t.setProps(Object.assign({},u,{getReferenceClientRect:"function"==typeof u.getReferenceClientRect?u.getReferenceClientRect:function(){return a.getBoundingClientRect()}}))}}}}},l=_(v(),Object.assign({},c(e,["overrides"]),{plugins:[f].concat(e.plugins||[]),triggerTarget:i})),d=l.setProps;return l.setProps=function(t){o=t.overrides||o,d(t)},l.setInstances=function(t){u(!0),a.forEach((function(t){return t()})),r=t,u(!1),s(),p(l),l.setProps({triggerTarget:i})},a=p(l),l},_.delegate=function(t,e){var n=[],r=[],i=!1,o=e.target,a=c(e,["target"]),s=Object.assign({},a,{trigger:"manual",touch:!1}),u=Object.assign({},a,{showOnCreate:!0}),f=_(t,s);function l(t){if(t.target&&!i){var n=t.target.closest(o);if(n){var a=n.getAttribute("data-tippy-trigger")||e.trigger||D.trigger;if(!n._tippy&&!("touchstart"===t.type&&"boolean"==typeof u.touch||"touchstart"!==t.type&&a.indexOf(z[t.type])<0)){var s=_(n,u);s&&(r=r.concat(s))}}}}function d(t,e,r,i){void 0===i&&(i=!1),t.addEventListener(e,r,i),n.push({node:t,eventType:e,handler:r,options:i})}return p(f).forEach((function(t){var e=t.destroy,o=t.enable,a=t.disable;t.destroy=function(t){void 0===t&&(t=!0),t&&r.forEach((function(t){t.destroy()})),r=[],n.forEach((function(t){var e=t.node,n=t.eventType,r=t.handler,i=t.options;e.removeEventListener(n,r,i)})),n=[],e()},t.enable=function(){o(),r.forEach((function(t){return t.enable()})),i=!1},t.disable=function(){a(),r.forEach((function(t){return t.disable()})),i=!0},function(t){var e=t.reference;d(e,"touchstart",l),d(e,"mouseover",l),d(e,"focusin",l),d(e,"click",l)}(t)})),f},_.hideAll=function(t){var e=void 0===t?{}:t,n=e.exclude,r=e.duration;N.forEach((function(t){var e=!1;if(n&&(e=h(n)?t.reference===n:t.popper===n.popper),!e){var i=t.props.duration;t.setProps({duration:r}),t.hide(),t.state.isDestroyed||t.setProps({duration:i})}}))},_.roundArrow='',_})); \ No newline at end of file diff --git a/assets/js/tippy/tippy.css b/assets/js/tippy/tippy.css new file mode 100644 index 00000000..d1cd2e13 --- /dev/null +++ b/assets/js/tippy/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/assets/lib/lity/lity.min.css b/assets/lib/lity/lity.min.css new file mode 100644 index 00000000..02cb092c --- /dev/null +++ b/assets/lib/lity/lity.min.css @@ -0,0 +1,3 @@ +/*! Lity - v3.0.0-dev - 2018-07-09 +* http://sorgalla.com/lity/ +* Copyright (c) 2015-2018 Jan Sorgalla; Licensed MIT */.lity-active,.lity-active body{overflow:hidden}.lity{z-index:9990;position:fixed;top:0;right:0;bottom:0;left:0;white-space:nowrap;background:#0b0b0b;background:rgba(0,0,0,.9);outline:none!important;opacity:0;transition:opacity .3s ease}.lity.lity-opened{opacity:1}.lity.lity-closed{opacity:0}.lity *{box-sizing:border-box}.lity-wrap{z-index:9990;position:fixed;top:0;right:0;bottom:0;left:0;text-align:center;outline:none!important}.lity-wrap:before{content:"";display:inline-block;height:100%;vertical-align:middle;margin-right:-.25em}.lity-loader{z-index:9991;color:#fff;position:absolute;top:50%;margin-top:-.8em;width:100%;text-align:center;font-size:14px;font-family:Arial,Helvetica,sans-serif;opacity:0;transition:opacity .3s ease}.lity-loading .lity-loader{opacity:1}.lity-container{z-index:9992;position:relative;text-align:left;vertical-align:middle;display:inline-block;white-space:normal;max-width:100%;max-height:100%;outline:none!important}.lity-content{z-index:9993;width:100%;transform:scale(1);transition:transform .3s ease}.lity-closed .lity-content,.lity-loading .lity-content{transform:scale(.8)}.lity-content:after{content:"";position:absolute;left:0;top:0;bottom:0;display:block;right:0;width:auto;height:auto;z-index:-1;box-shadow:0 0 8px rgba(0,0,0,.6)}.lity-close,.lity-close:active,.lity-close:focus,.lity-close:hover,.lity-close:visited{z-index:9994;width:35px;height:35px;position:fixed;right:0;top:0;-webkit-appearance:none;cursor:pointer;text-decoration:none;text-align:center;padding:0;color:#fff;font-style:normal;font-size:35px;font-family:Arial,Baskerville,monospace;line-height:35px;text-shadow:0 1px 2px rgba(0,0,0,.6);border:0;background:none;box-shadow:none}.lity-close::-moz-focus-inner{border:0;padding:0}.lity-close:active{top:1px}.lity-image img{max-width:100%;display:block;line-height:0;border:0}.lity-iframe .lity-container{width:100%;max-width:964px}.lity-iframe-container{width:100%;height:0;padding-top:56.25%;overflow:auto;pointer-events:auto;transform:translateZ(0);-webkit-overflow-scrolling:touch}.lity-iframe-container iframe{position:absolute;display:block;top:0;left:0;width:100%;height:100%;box-shadow:0 0 8px rgba(0,0,0,.6);background:#000}.lity-hide{display:none} \ No newline at end of file diff --git a/assets/lib/lity/lity.min.js b/assets/lib/lity/lity.min.js new file mode 100644 index 00000000..2d9e23cb --- /dev/null +++ b/assets/lib/lity/lity.min.js @@ -0,0 +1,5 @@ +/*! Lity - v3.0.0-dev - 2019-08-07 +* http://sorgalla.com/lity/ +* Copyright (c) 2015-2019 Jan Sorgalla; Licensed MIT */ + +!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return b(a,c)}):"object"==typeof module&&"object"==typeof module.exports?module.exports=b(a,require("jquery")):a.lity=b(a,a.jQuery||a.Zepto)}("undefined"!=typeof window?window:this,function(a,b){"use strict";function c(a){var b=y();return G&&a.length?(a.one(G,b.resolve),setTimeout(b.resolve,500)):b.resolve(),b.promise()}function d(a,c,d){if(1===arguments.length)return b.extend({},a);if("string"==typeof c){if(void 0===d)return void 0===a[c]?null:a[c];a[c]=d}else b.extend(a,c);return this}function e(a){var b=a.indexOf("?");b>-1&&(a=a.substr(b+1));for(var c,d=decodeURI(a.split("#")[0]).split("&"),e={},f=0,g=d.length;f-1){var d=a.split("?");a=d.shift(),c=b.extend({},e(d[0]),c)}return a+"?"+b.param(c)}function g(a,b){var c=a.indexOf("#");return-1===c?b:(c>0&&(a=a.substr(c)),b+a)}function h(a,b,c,d){return b&&b.element().addClass("lity-iframe"),c&&(a=f(a,c)),d&&(a=g(d,a)),'
          '; + return DUPX_U_Html::getLigthBox($linkLabelHtml, $titleContent, $lightBoxContent, $echo, $afterContent); + } + + protected static function lightBoxCss() + { + ?> + + + + + + $atValue) { + $attrsHtml[] = $atName . '="' . DUPX_U::esc_attr($atValue) . '"'; + } + ?> + + /> + + + + + + + + > + > + + + + + 'help', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('help'), + 'basic' => '', + 'open_section' => $helpOpenSection + )); + } + + public static function helpLink($section, $linkLabel = 'Help', $echo = true) + { + ob_start(); + $help_url = self::getHelpLink($section); + DUPX_U_Html::getLightBoxIframe($linkLabel, 'HELP', $help_url); + if ($echo) { + ob_end_flush(); + } else { + return ob_get_clean(); + } + } + + public static function helpLockLink() + { + if (DUPX_ArchiveConfig::getInstance()->secure_on) { + self::helpLink('secure', ''); + } else { + self::helpLink('secure', ''); + } + } + + public static function helpIconLink($section) + { + self::helpLink($section, ''); + } + + /** + * Get badge class attr val from status + * + * @param string $status + * + * @return string html class attribute + */ + public static function getBadgeClassFromCheckStatus($status) + { + switch ($status) { + case 'Pass': + return 'status-badge.pass'; + case 'Fail': + return 'status-badge.fail'; + case 'Warn': + return 'status-badge.warn'; + default: + Log::error(sprintf("The arcCheck var has the illegal value %s in switch case", Log::v2str($status))); + } + } +} diff --git a/installer/dup-installer/ctrls/.htaccess b/installer/dup-installer/ctrls/.htaccess new file mode 100644 index 00000000..a58990b7 --- /dev/null +++ b/installer/dup-installer/ctrls/.htaccess @@ -0,0 +1,9 @@ + + Order Deny,Allow + Deny from all + + + + Order Allow,Deny + Allow from all + \ No newline at end of file diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.ajax.php b/installer/dup-installer/ctrls/classes/class.ctrl.ajax.php new file mode 100644 index 00000000..99e03460 --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.ajax.php @@ -0,0 +1,313 @@ + true, + 'message' => '', + "errorContent" => array( + 'pre' => '', + 'html' => '' + ), + 'trace' => '', + 'actionData' => null + ); + + Log::setThrowExceptionOnError(true); + + try { + DUPX_Template::getInstance()->setTemplate(PrmMng::getInstance()->getValue(PrmMng::PARAM_TEMPLATE)); + $jsonResult['actionData'] = self::actions($action); + } catch (Exception $e) { + Log::logException($e); + + if (SnapString::isHTML($e->getMessage())) { + $message = $e->getMessage(); + } else { + $message = DUPX_U::esc_html($e->getMessage()); + } + + $jsonResult = array( + 'success' => false, + 'message' => $message, + "errorContent" => array( + 'pre' => Log::getLogException($e), + 'html' => '' + ) + ); + } + + $invalidOutput = SnapUtil::obCleanAll(); + ob_end_clean(); + if (strlen($invalidOutput) > 0) { + Log::info('INVALID AJAX OUTPUT:' . "\n" . $invalidOutput . "\n---------------------------------"); + } + + if ($jsonResult['success']) { + Log::info('AJAX ACTION [' . $action . '] SUCCESS'); + } else { + Log::info('AJAX ACTION [' . $action . '] FAIL, MESSAGE: ' . $jsonResult['message']); + } + + Log::info('-------------------------' . "\n"); + + if (!headers_sent()) { + header('Content-Type: application/json'); + } + echo SnapJson::jsonEncode($jsonResult); + Log::close(); + // if is ajax always die; + die(); + } + + /** + * ajax actions + * + * @param string $action + * + * @return mixed + */ + protected static function actions($action) + { + $actionData = null; + + self::debugAjaxCallSleep(); + + switch ($action) { + case self::ACTION_PWD_CHECK: + $actionData = DUPX_Security::getInstance()->securityCheck(); + break; + case self::ACTION_EMAIL_SUBSCRIPTION: + $actionData = DUPX_Ctrl_Params::setParamEmail(); + break; + case self::ACTION_PROCEED_CONFIRM_DIALOG: + $vData = DUPX_Validation_database_service::getInstance(); + if (!$vData->getDbConnection()) { + throw new Exception('Connection DB data isn\'t valid'); + } + $actionData = dupxTplRender( + 'pages-parts/step1/proceed-confirm-dialog', + array( + 'tableCount' => $vData->getDBActionAffectedTablesCount() + ), + false + ); + break; + case self::ACTION_VALIDATE: + DUP_Extraction::resetData(); + $actionData = DUPX_Validation_manager::getInstance()->getValidateData(); + if ($actionData['mainLevel'] <= DUPX_Validation_abstract_item::LV_FAIL) { + sleep(self::PREVENT_BRUTE_FORCE_ATTACK_SLEEP); + } else { + DUPX_Ctrl_Params::setParamsAfterValidation(); + } + $actionData['nextStepMessagesHtml'] = DUPX_NOTICE_MANAGER::getInstance()->nextStepMessages(true, false); + + break; + case self::ACTION_SET_PARAMS_S1: + $valid = DUPX_Ctrl_Params::setParamsStep1(); + DUPX_NOTICE_MANAGER::getInstance()->nextStepLog(false); + $nexStepNotices = DUPX_NOTICE_MANAGER::getInstance()->nextStepMessages(true, false); + $actionData = array( + 'isValid' => $valid, + 'nextStepMessagesHtml' => $nexStepNotices + ); + break; + case self::ACTION_SET_PARAMS_S2: + $valid = DUPX_Ctrl_Params::setParamsStep2(); + DUPX_NOTICE_MANAGER::getInstance()->nextStepLog(false); + $nexStepNotices = DUPX_NOTICE_MANAGER::getInstance()->nextStepMessages(true, false); + $actionData = array( + 'isValid' => $valid, + 'nextStepMessagesHtml' => $nexStepNotices + ); + break; + case self::ACTION_SET_PARAMS_S3: + $valid = DUPX_Ctrl_Params::setParamsStep3(); + DUPX_NOTICE_MANAGER::getInstance()->nextStepLog(false); + $nexStepNotices = DUPX_NOTICE_MANAGER::getInstance()->nextStepMessages(true, false); + $actionData = array( + 'isValid' => $valid, + 'nextStepMessagesHtml' => $nexStepNotices + ); + break; + case self::ACTION_EXTRACTION: + $extractor = DUP_Extraction::getInstance(); + DUPX_U::maintenanceMode(true); + $extractor->runExtraction(); + $actionData = $extractor->finishExtraction(); + break; + case self::ACTION_DBINSTALL: + $dbInstall = DUPX_DBInstall::getInstance(); + $actionData = $dbInstall->deploy(); + DUPX_Plugins_Manager::getInstance()->preViewChecks(); + break; + case self::ACTION_WEBSITE_UPDATE: + $actionData = DUPX_S3_Funcs::getInstance()->updateWebsite(); + break; + case self::ACTION_FINAL_TESTS_PREPARE: + $actionData = TestsExecuter::preTestPrepare(); + break; + case self::ACTION_FINAL_TESTS_AFTER: + $actionData = TestsExecuter::afterTestClean(); + break; + case self::ACTION_SET_AUTO_CLEAN_FILES: + if (DUPX_Ctrl_Params::setParamAutoClean()) { + $valid = DUPX_S3_Funcs::getInstance()->duplicatorMigrationInfoSet(); + } else { + $valid = false; + } + DUPX_NOTICE_MANAGER::getInstance()->nextStepLog(false); + $nexStepNotices = DUPX_NOTICE_MANAGER::getInstance()->nextStepMessages(true, false); + $actionData = array( + 'isValid' => $valid, + 'nextStepMessagesHtml' => $nexStepNotices + ); + break; + default: + throw new Exception('Invalid ajax action'); + } + return $actionData; + } + + /** + * Check if current call is ajax + * + * @param string $action if is ajax $action is set with action string + * + * @return bool true if is ajax + */ + public static function isAjax(&$action = null) + { + static $isAjaxAction = null; + if (is_null($isAjaxAction)) { + $isAjaxAction = array( + 'isAjax' => false, + 'action' => false + ); + + $argsInput = SnapUtil::filterInputRequestArray(array( + PrmMng::PARAM_CTRL_ACTION => array( + 'filter' => FILTER_SANITIZE_SPECIAL_CHARS, + 'flags' => FILTER_REQUIRE_SCALAR | FILTER_FLAG_STRIP_HIGH, + 'options' => array('default' => '') + ), + self::ACTION_NAME => array( + 'filter' => FILTER_SANITIZE_SPECIAL_CHARS, + 'flags' => FILTER_REQUIRE_SCALAR | FILTER_FLAG_STRIP_HIGH, + 'options' => array('default' => false) + ) + )); + + if ($argsInput[PrmMng::PARAM_CTRL_ACTION] !== 'ajax' || $argsInput[self::ACTION_NAME] === false) { + $isAjaxAction['isAjax'] = false; + } else { + if (($isAjaxAction['isAjax'] = in_array($argsInput[self::ACTION_NAME], self::ajaxActions()))) { + $isAjaxAction['action'] = $argsInput[self::ACTION_NAME]; + } + } + } + + if ($isAjaxAction['isAjax']) { + $action = $isAjaxAction['action']; + } + return $isAjaxAction['isAjax']; + } + + public static function getTokenKeyByAction($action) + { + return self::ACTION_NAME . $action; + } + + public static function getTokenFromInput() + { + return SnapUtil::filterInputDefaultSanitizeString(INPUT_POST, self::TOKEN_NAME, false); + } + + public static function generateToken($action) + { + return DUPX_CSRF::generate(self::getTokenKeyByAction($action)); + } + + protected static function debugAjaxCallSleep() + { + if (self::DEBUG_AJAX_CALL_SLEEP > 0) { + sleep(self::DEBUG_AJAX_CALL_SLEEP); + } + } +} diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.dbinstall.php b/installer/dup-installer/ctrls/classes/class.ctrl.dbinstall.php new file mode 100644 index 00000000..6fd83489 --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.dbinstall.php @@ -0,0 +1,1332 @@ +initData(); + } + + /** + * inizialize extraction data + */ + protected function initData() + { + // if data file exists load saved data + if (file_exists(self::dbinstallDataFilePath())) { + Log::info('LOAD DBINSTALL DATA FROM JSON', Log::LV_DETAILED); + if ($this->loadData() == false) { + throw new Exception('Can\'t load dbinstall data'); + } + } else { + Log::info('INIT DB INSTALL DATA', Log::LV_DETAILED); + $this->constructData(); + $this->initLogDbInstall(); + $this->saveData(); + } + } + + protected function constructData() + { + $paramsManager = PrmMng::getInstance(); + $this->start_microtime = DUPX_U::getMicrotime(); + $this->sql_file_path = DUPX_Package::getSqlFilePath(); + $this->dbFileSize = DUPX_Package::getSqlFileSize(); + $this->profile_start = DUPX_U::getMicrotime(); + + $this->post = array( + 'view_mode' => $paramsManager->getValue(PrmMng::PARAM_DB_VIEW_MODE), + 'dbname' => $paramsManager->getValue(PrmMng::PARAM_DB_NAME), + 'dbuser' => $paramsManager->getValue(PrmMng::PARAM_DB_USER), + 'dbpass' => $paramsManager->getValue(PrmMng::PARAM_DB_PASS), + 'dbport' => parse_url($paramsManager->getValue(PrmMng::PARAM_DB_HOST), PHP_URL_PORT), + 'dbmysqlmode' => $paramsManager->getValue(PrmMng::PARAM_DB_MYSQL_MODE), + 'dbmysqlmode_opts' => $paramsManager->getValue(PrmMng::PARAM_DB_MYSQL_MODE_OPTS), + 'pos' => 0, + 'pass' => false, + 'first_chunk' => true, + 'dbchunk_retry' => 0, + 'continue_chunking' => $paramsManager->getValue(PrmMng::PARAM_DB_CHUNK), + 'progress' => 0, + 'delimiter' => ';', + 'is_error' => 0, + 'error_msg' => '' + ); + + $this->dbaction = $paramsManager->getValue(PrmMng::PARAM_DB_ACTION); + $this->dbcharset = $paramsManager->getValue(PrmMng::PARAM_DB_CHARSET); + $this->dbcollate = $paramsManager->getValue(PrmMng::PARAM_DB_COLLATE); + $this->dbsplit_creates = $paramsManager->getValue(PrmMng::PARAM_DB_SPLIT_CREATES); + + $this->dbUserMode = new DbUserMode(); + } + + protected function initLogDbInstall() + { + $paramsManager = PrmMng::getInstance(); + $labelPadSize = 20; + Log::info("\n\n\n********************************************************************************"); + Log::info('* DUPLICATOR LITE: INSTALL-LOG'); + Log::info('* STEP-2 START @ ' . @date('h:i:s')); + Log::info('* NOTICE: Do NOT post to public sites or forums!!'); + Log::info("********************************************************************************"); + Log::info("USER INPUTS"); + Log::info(str_pad('DB ENGINE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_ENGINE))); + Log::info(str_pad('VIEW MODE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_VIEW_MODE))); + Log::info(str_pad('DB ACTION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_ACTION))); + Log::info(str_pad('DB HOST', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str('**OBSCURED**')); + Log::info(str_pad('DB NAME', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str('**OBSCURED**')); + Log::info(str_pad('DB PASS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str('**OBSCURED**')); + Log::info(str_pad('DB PORT', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str('**OBSCURED**')); + Log::info(str_pad('USER MODE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_USERS_MODE))); + Log::info(str_pad('TABLE PREFIX', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX))); + Log::info(str_pad('MYSQL MODE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_MYSQL_MODE))); + Log::info(str_pad('MYSQL MODE OPTS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_MYSQL_MODE_OPTS))); + Log::info(str_pad('CHARSET', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_CHARSET))); + Log::info(str_pad('COLLATE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_COLLATE))); + Log::info(str_pad('CUNKING', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_CHUNK))); + Log::info(str_pad('VIEW CREATION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_VIEW_CREATION))); + Log::info(str_pad('STORED PROCEDURE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_PROC_CREATION))); + Log::info(str_pad('FUNCTIONS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_FUNC_CREATION))); + Log::info(str_pad('REMOVE DEFINER', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_REMOVE_DEFINER))); + Log::info(str_pad('SPLIT CREATES', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_DB_SPLIT_CREATES))); + + $tables = DUPX_DB_Tables::getInstance()->getTables(); + Log::info("--------------------------------------"); + Log::info('TABLES'); + Log::info("--------------------------------------"); + foreach ($tables as $tablesObj) { + Log::info('TABLE ' . str_pad(Log::v2str($tablesObj->getOriginalName()), 50, '_', STR_PAD_RIGHT) + . '[ROWS:' . str_pad($tablesObj->getRows(), 8, " ", STR_PAD_LEFT) . ']' + . ' [' . ($tablesObj->extract() ? 'EXTRACT' : 'NO EXTR') . '|' . ($tablesObj->replaceEngine() ? 'REPLACE' : 'NO REPL') . '] ' + . '[INST NAME: ' . $tablesObj->getNewName() . ']'); + } + Log::info("********************************************************************************\n"); + Log::flush(); + } + + public function deploy() + { + $paramsManager = PrmMng::getInstance(); + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + Log::setThrowExceptionOnError(true); + if ($this->firstOrNotChunking()) { + if ($this->post['dbchunk_retry'] > 0) { + Log::info("## >> Last DB Chunk installation was failed, so retrying from start point. Retrying count: " . $this->post['dbchunk_retry']); + } + + $this->prepareDB(); + + //Fatal Memory errors from file_get_contents is not catchable. + //Try to warn ahead of time with a check on buffer in memory difference + $current_php_mem = DUPX_U::returnBytes($GLOBALS['PHP_MEMORY_LIMIT']); + $current_php_mem = is_numeric($current_php_mem) ? $current_php_mem : null; + + if ($current_php_mem != null && $this->dbFileSize > $current_php_mem) { + $readable_size = DUPX_U::readableByteSize($this->dbFileSize); + $msg = "\nWARNING: The database script is '{$readable_size}' in size. The PHP memory allocation is set\n"; + $msg .= "at '{$GLOBALS['PHP_MEMORY_LIMIT']}'. There is a high possibility that the installer script will fail with\n"; + $msg .= "a memory allocation error when trying to load the database.sql file. It is\n"; + $msg .= "recommended to increase the 'memory_limit' setting in the php.ini config file.\n"; + $msg .= "see: " . DUPX_Constants::FAQ_URL . "how-to-manage-server-resources-cpu-memory-disk/ \n"; + Log::info($msg); + unset($msg); + } + + Log::info("--------------------------------------"); + Log::info("DATABASE RESULTS"); + Log::info("--------------------------------------"); + } + + switch ($paramsManager->getValue(PrmMng::PARAM_DB_ACTION)) { + case self::DBACTION_MANUAL: + Log::info("\n** SQL EXECUTION IS IN MANUAL MODE **"); + Log::info("- No SQL script has been executed -"); + $this->post['pass'] = 1; + $this->post['continue_chunking'] = false; + break; + case DUPX_DBInstall::DBACTION_ONLY_CONNECT: + case DUPX_DBInstall::DBACTION_CREATE: + case DUPX_DBInstall::DBACTION_EMPTY: + case DUPX_DBInstall::DBACTION_REMOVE_ONLY_TABLES: + case DUPX_DBInstall::DBACTION_RENAME: + if ($this->firstOrNotChunking()) { + $this->beforeInstallDatabaseActions(); + } + $this->insertDatabase(); + if (!$this->post['continue_chunking']) { + $this->afterInstallDatabaseActions(); + } + break; + default: + throw new Exception('Invalid db action'); + } + $this->post['first_chunk'] = false; + + $this->saveData(); + $nManager->saveNotices(); + + return $this->getResultData(); + } + + /** + * + * @throws Exception + */ + protected function insertDatabase() + { + $paramsManager = PrmMng::getInstance(); + $validation = false; + if ($paramsManager->getValue(PrmMng::PARAM_DB_CHUNK)) { + if ($this->post['continue_chunking'] == true) { + if ($this->deployDatabaseChunkMode() == false) { + throw new Exception('Error on db extraction'); + } + } elseif ($this->post['pass'] == 1) { + $validation = true; + } else { + throw new Exception('Error on db extraction'); + } + } else { + $this->deployDatabaseSingleMode(); + $validation = true; + } + + if ($validation) { + $rowCountMisMatchTables = $this->getRowCountMisMatchTables(); + $this->post['pass'] = 1; + if (!empty($rowCountMisMatchTables)) { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $errMsg = 'Database Table row count verification was failed for table(s): ' + . implode(', ', $rowCountMisMatchTables) . '.'; + Log::info($errMsg); + $nManager->addBothNextAndFinalReportNotice( + array( + 'shortMsg' => 'Database Table row count was validation failed', + 'level' => DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => $errMsg, + 'sections' => 'database' + ) + ); + } + } + } + + /** + * Actione executed before db install + * + * @return void + */ + protected function beforeInstallDatabaseActions() + { + $this->queryFixes = new QueryFixes(); + $this->queryFixes->logRules(); + DbUserMode::moveTargetUserTablesOnCurrentPrefix(); + $this->dbUserMode->removeAllUserMetaKeysOfCurrentPrefix(); + $this->dbUserMode->initTargetSiteUsersData(); + $this->saveData(); + } + + protected function afterInstallDatabaseActions() + { + $this->dbUserMode->generateImportReport(); + $profileEnd = DUPX_U::getMicrotime(); + $this->writeLog(); + + //FINAL RESULTS + $ajax1_sum = DUPX_U::elapsedTime($profileEnd, $this->start_microtime); + Log::info("\nINSERT DATA RUNTIME: " . DUPX_U::elapsedTime($profileEnd, $this->profile_start)); + Log::info('STEP-2 COMPLETE @ ' . @date('h:i:s') . " - RUNTIME: {$ajax1_sum}"); + self::resetData(); + } + + /** + * + * @return string + */ + protected static function dbinstallDataFilePath() + { + static $path = null; + if (is_null($path)) { + $path = DUPX_INIT . '/dup-installer-dbinstall__' . DUPX_Package::getPackageHash() . '.json'; + } + return $path; + } + + /** + * + * @staticvar string $path + * @return string + */ + protected static function seekTellFilePath() + { + static $path = null; + if (is_null($path)) { + $path = DUPX_INIT . "/dup-database-seek-tell-log__" . DUPX_ArchiveConfig::getInstance()->package_hash . ".txt"; + } + return $path; + } + + /** + * + * @return boolean + */ + protected function saveData() + { + if (($json = SnapJson::jsonEncodePPrint($this)) === false) { + Log::info('Can\'t encode json data'); + return false; + } + + if (file_put_contents(self::dbinstallDataFilePath(), $json) === false) { + throw new Exception('Can\'t save dbinstall data file'); + } + + return true; + } + + /** + * It can clean up the object and is supposed to return an array with the + * names of all variables of that object that should be serialized. + * + * @return string[] + */ + public function __sleep() + { + $props = array_keys(get_object_vars($this)); + return array_diff($props, array('dbh')); + } + + /** + * + * @return boolean + */ + protected function loadData() + { + if (!file_exists(self::dbinstallDataFilePath())) { + return false; + } + + if (($json = file_get_contents(self::dbinstallDataFilePath())) === false) { + throw new Exception('Can\'t load dbinstall data file'); + } + + JsonSerialize::unserializeToObj($json, $this); + + return true; + } + + /** + * + * @return boolean + */ + public static function resetData() + { + $result = true; + if (file_exists(self::dbinstallDataFilePath())) { + if (unlink(self::dbinstallDataFilePath()) === false) { + throw new Exception('Can\'t delete dbinstall data file'); + } + } + if (file_exists(self::seekTellFilePath())) { + if (unlink(self::seekTellFilePath()) === false) { + throw new Exception('Can\'t delete dbinstall chunk seek data file'); + } + } + return $result; + } + + /** + * execute a connection if db isn't connected + * + * @return resource + */ + protected function dbConnect($reconnect = false) + { + if ($reconnect) { + $this->dbClose(); + } + + $paramsManager = PrmMng::getInstance(); + + if (is_null($this->dbh)) { + switch ($this->dbaction) { + case self::DBACTION_EMPTY: + case self::DBACTION_REMOVE_ONLY_TABLES: + case self::DBACTION_RENAME: + case self::DBACTION_ONLY_CONNECT: + //ESTABLISH CONNECTION + if (($this->dbh = DUPX_DB_Functions::getInstance()->dbConnection()) == false) { + $this->dbh = null; + Log::error(ERR_DBCONNECT . mysqli_connect_error()); + } + + // EXEC ALWAYS A DB SELECT is required when chunking is activated + if (DUPX_DB::selectDB($this->dbh, $paramsManager->getValue(PrmMng::PARAM_DB_NAME)) == false) { + Log::error(sprintf(ERR_DBCREATE, $paramsManager->getValue(PrmMng::PARAM_DB_NAME))); + } + break; + case self::DBACTION_CREATE: + //ESTABLISH CONNECTION WITHOUT DATABASE NAME + $connParams = array( + 'dbhost' => $paramsManager->getValue(PrmMng::PARAM_DB_HOST), + 'dbname' => null, + 'dbuser' => $paramsManager->getValue(PrmMng::PARAM_DB_USER), + 'dbpass' => $paramsManager->getValue(PrmMng::PARAM_DB_PASS) + ); + + if (($this->dbh = DUPX_DB_Functions::getInstance()->dbConnection($connParams)) == false) { + $this->dbh = null; + Log::error(ERR_DBCONNECT . mysqli_connect_error()); + } + + // don't check for success because in the create new database option the database may not exist. + DUPX_DB::selectDB($this->dbh, $paramsManager->getValue(PrmMng::PARAM_DB_NAME)); + break; + case self::DBACTION_MANUAL: + Log::info('DB ACTION MANUAL'); + break; + default: + Log::error('Invalid dbaction: ' . Log::v2str($this->dbaction)); + break; + } + + try { + DUPX_DB::mysqli_query($this->dbh, "SET wait_timeout = " . mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME'])); + DUPX_DB::mysqli_query($this->dbh, "SET GLOBAL max_allowed_packet = " . mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']), Log::LV_DEBUG); + DUPX_DB::mysqli_query($this->dbh, "SET max_allowed_packet = " . mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']), Log::LV_DEBUG); + + $this->dbvar_maxtime = DUPX_DB::getVariable($this->dbh, 'wait_timeout', 300); + $this->dbvar_maxpacks = DUPX_DB::getVariable($this->dbh, 'max_allowed_packet', MB_IN_BYTES); + $this->dbvar_sqlmode = DUPX_DB::getVariable($this->dbh, 'sql_mode', 'NOT_SET'); + } catch (Exception $e) { + Log::logException($e, Log::LV_DEFAULT, 'EXCEPTION ON DB SET VARS [CONTINUE]'); + } + } + return $this->dbh; + } + + protected function dbClose() + { + if (!is_null($this->dbh)) { + mysqli_close($this->dbh); + $this->dbh = null; + } + } + + protected function pingAndReconnect() + { + if (!mysqli_ping($this->dbh)) { + $this->dbConnect(true); + } + } + + protected function prepareDB() + { + if ($this->dbaction === self::DBACTION_MANUAL) { + return; + } + + $this->dbConnect(); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + + DUPX_DB::setCharset($this->dbh, $this->dbcharset, $this->dbcollate); + $this->setSQLSessionMode(); + + //Set defaults incase the variable could not be read + $this->drop_tbl_log = 0; + $this->rename_tbl_log = 0; + $sql_file_size1 = DUPX_U::readableByteSize(DUPX_Package::getSqlFileSize()); + + Log::info("--------------------------------------"); + Log::info('DATABASE-ENVIRONMENT'); + Log::info("--------------------------------------"); + Log::info( + "MYSQL VERSION:\tThis Server: " . + DUPX_DB::getVersion($this->dbh) . + " -- Build Server: {$archiveConfig->version_db}" + ); + Log::info("FILE SIZE:\t" . basename(DUPX_Package::getSqlFilePath()) . " ({$sql_file_size1})"); + Log::info("TIMEOUT:\t{$this->dbvar_maxtime}"); + Log::info("MAXPACK:\t{$this->dbvar_maxpacks}"); + Log::info("SQLMODE-GLOBAL:\t{$this->dbvar_sqlmode}"); + Log::info("SQLMODE-SESSION:" . ($this->getSQLSessionMode())); + + switch ($this->dbaction) { + case self::DBACTION_CREATE: + $this->dbActionCreate(); + break; + case self::DBACTION_EMPTY: + $this->dbActionEmpty(); + break; + case self::DBACTION_REMOVE_ONLY_TABLES: + $this->dbActionRemoveOnlyTables(); + break; + case self::DBACTION_RENAME: + $this->dbActionRename(); + break; + case self::DBACTION_MANUAL: + case self::DBACTION_ONLY_CONNECT: + break; + default: + Log::error('DB ACTION INVALID'); + break; + } + } + + protected function dbActionCreate() + { + if ($this->post['view_mode'] == 'basic') { + DUPX_DB::mysqli_query($this->dbh, "CREATE DATABASE IF NOT EXISTS `" . mysqli_real_escape_string($this->dbh, $this->post['dbname']) . "`"); + } + + if (mysqli_select_db($this->dbh, mysqli_real_escape_string($this->dbh, $this->post['dbname'])) == false) { + Log::error(sprintf(ERR_DBCONNECT_CREATE, $this->post['dbname'])); + } + } + + protected function dbActionEmpty() + { + $excludeDropTable = DUPX_DB_Functions::getExcludedTables(); + + //Drop all tables, views and procs + $this->dropTables($excludeDropTable); + DbCleanup::dropViews(); + DbCleanup::dropProcs(); + DbCleanup::dropFuncs(); + } + + protected function dbActionRemoveOnlyTables() + { + $excludeDropTable = DUPX_DB_Functions::getExcludedTables(); + + $this->dropTables($excludeDropTable, DUPX_DB_Tables::getInstance()->getNewTablesNames()); + + DbCleanup::dropProcs(); + DbCleanup::dropFuncs(); + DbCleanup::dropViews(); + } + + protected function dbActionRename() + { + Log::info('TABLE RENAME TO BACKUP'); + + $copyTables = array(); + if (ParamDescUsers::getUsersMode() !== ParamDescUsers::USER_MODE_OVERWRITE) { + $paramsManager = PrmMng::getInstance(); + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + $copyTables = array( + DUPX_DB_Functions::getUserTableName($overwriteData['table_prefix']), + DUPX_DB_Functions::getUserMetaTableName($overwriteData['table_prefix']) + ); + } + + DUPX_DB_Functions::getInstance()->pregReplaceTableName('/^(.+)$/', $GLOBALS['DB_RENAME_PREFIX'] . '$1', array( + 'prefixFilter' => DUPX_Constants::BACKUP_RENAME_PREFIX, + 'regexTablesDropFkeys' => '^' . SnapDB::quoteRegex($GLOBALS['DB_RENAME_PREFIX']) . '.+', + 'copyTables' => $copyTables, + 'exclude' => array( + DUPX_DB_Functions::getUserTableName(self::TEMP_DB_PREFIX), + DUPX_DB_Functions::getUserMetaTableName(self::TEMP_DB_PREFIX) + ) + )); + } + + /** + * Return true if is delimiter query line and set new delimiter + * + * @param string $line query line + * + * @return boolean|string false if isn't delimiter or delimiter string + */ + protected static function isDelimiterLine($line) + { + $delimiterMatch = null; + + if (preg_match('/^\s*DELIMITER\s+([^\s]+)\s*$/i', $line, $delimiterMatch) === 1) { + $delimiter = $delimiterMatch[1]; + Log::info("SET DELIMITER " . $delimiter . " AND SKIP QUERY"); + return $delimiter; + } else { + return false; + } + } + + protected function deployDatabaseChunkMode() + { + Log::info("--------------------------------------"); + Log::info("** DATABASE CHUNK install start"); + Log::info("--------------------------------------"); + $this->dbConnect(); + + if (isset($this->post['dbchunk_retry']) && $this->post['dbchunk_retry'] > 0) { + Log::info("DATABASE CHUNK RETRY COUNT: " . Log::v2str($this->post['dbchunk_retry'])); + } + + $delimiter = $this->post['delimiter']; + + $handle = fopen($this->sql_file_path, 'rb'); + if ($handle === false) { + return false; + } + + Log::info("DATABASE CHUNK SEEK POSITION: " . Log::v2str($this->post['pos'])); + + if (-1 !== fseek($handle, $this->post['pos'])) { + DUPX_DB::setCharset($this->dbh, $this->dbcharset, $this->dbcollate); + + $this->setSQLSessionMode(); + + $this->thread_start_time = DUPX_U::getMicrotime(); + + Log::info('DATABASE CHUNK START POS:' . Log::v2str($this->post['pos']), Log::LV_DETAILED); + $this->pingAndReconnect(); + + if (@mysqli_autocommit($this->dbh, false)) { + Log::info('Auto Commit set to false successfully'); + } else { + Log::info('Failed to set Auto Commit to false'); + } + + Log::info("DATABASE CHUNK: Iterating query loop", Log::LV_DEBUG); + + if (!$this->post['first_chunk'] && !empty($this->setQueries)) { + Log::info("SET QUERIES FROM FIRST CHUNK", Log::LV_DETAILED); + foreach ($this->setQueries as $setQuery) { + Log::info("\tSET QUERY " . Log::v2str($setQuery), Log::LV_DEBUG); + $this->writeQueryInDB($setQuery); + } + } + + $query = ''; + $skipChunkTimeoutCheck = $this->dbsplit_creates && $this->post['first_chunk']; + + while (($line = fgets($handle)) !== false) { + if (($res = self::isDelimiterLine($line)) !== false) { + $query = ''; + $delimiter = $this->post['delimiter'] = $res; + continue; + } + + if ($this->post['first_chunk']) { + //Matches ordinary set queries e.g "SET @saved_cs_client = @@character_set_client;" + //and version dependent set queries e.g. "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;" + if (preg_match('/^[\s\t]*(?:\/\*!\d+)?[\s\t]*SET[\s\t]*@.+;/', $line)) { + $setQuery = trim($line); + if (!in_array($setQuery, $this->setQueries)) { + Log::info("FIRST CHUNK SET QUERY " . Log::v2str($setQuery), Log::LV_DEBUG); + $this->setQueries[] = $setQuery; + } + } + + if ($line === self::TABLE_CREATION_END_MARKER) { + Log::info("DATABASE CHUNK: CREATION TABLE MARKER FOUND"); + $skipChunkTimeoutCheck = false; + continue; + } + } + + $query .= $line; + if (preg_match('/' . preg_quote($delimiter, '/') . '\s*$/S', $line)) { + // Temp: Uncomment this to randomly kill the php db process to simulate real world hosts and verify system recovers properly + /* + $rand_no = rand(0, 500); + if (0 == $this->post['dbchunk_retry'] && 1 == $rand_no) { + Log::info("intentionally killing db chunk installation process"); + error_log('intentionally killing db chunk installation process'); + exit(1); + } + */ + + $this->writeQueryInDB($query); + $query = ''; + + $elapsed_time = (microtime(true) - $this->thread_start_time); + if (Log::isLevel(Log::LV_DEBUG)) { + Log::info("DATABASE CHUNK: Elapsed time: " . Log::v2str($elapsed_time), Log::LV_HARD_DEBUG); + if ($elapsed_time > DUPX_Constants::CHUNK_DBINSTALL_TIMEOUT_TIME) { + Log::info("DATABASE CHUNK: Breaking query loop.", Log::LV_DEBUG); + } else { + Log::info("DATABASE CHUNK: Not Breaking query loop", Log::LV_HARD_DEBUG); + } + } + + //Only stop first chunk if all CREATE queries have been run + if (!$skipChunkTimeoutCheck && $elapsed_time > DUPX_Constants::CHUNK_DBINSTALL_TIMEOUT_TIME) { + break; + } + } + } + + if (@mysqli_autocommit($this->dbh, true)) { + Log::info('Auto Commit set to true successfully'); + } else { + Log::info('Failed to set Auto Commit to true'); + } + + $query_offset = ftell($handle); + + $seek_tell_log_line = ( + file_exists(self::seekTellFilePath()) && + filesize(self::seekTellFilePath()) > 0 + ) ? ',' : ''; + + $seek_tell_log_line .= $this->post['pos'] . '-' . $query_offset; + file_put_contents(self::seekTellFilePath(), $seek_tell_log_line, FILE_APPEND); + + $this->post['progress'] = ceil($query_offset / $this->dbFileSize * 100); + $this->post['pos'] = $query_offset; + + if (feof($handle)) { + if ($this->seekIntegrityCheck()) { + Log::info('DATABASE CHUNK: DB install chunk process integrity check has been just passed successfully.', Log::LV_DETAILED); + $this->post['pass'] = 1; + $this->post['continue_chunking'] = false; + } else { + Log::info('DB install chunk process integrity check has been just failed.'); + $this->post['pass'] = 0; + $this->post['is_error'] = 1; + $this->post['error_msg'] = 'DB install chunk process integrity check has been just failed.'; + } + } else { + $this->post['pass'] = 0; + $this->post['continue_chunking'] = true; + } + } + Log::info("DATABASE CHUNK: End Query offset " . Log::v2str($query_offset), Log::LV_DETAILED); + + if ($this->post['pass']) { + Log::info('DATABASE CHUNK: This is last chunk', Log::LV_DETAILED); + } + + fclose($handle); + + Log::info("--------------------------------------"); + Log::info("** DATABASE CHUNK install end"); + Log::info("--------------------------------------"); + + ob_flush(); + flush(); + return true; + } + + protected function seekIntegrityCheck() + { + // ensure integrity + $seek_tell_log = file_get_contents(self::seekTellFilePath()); + $seek_tell_log_explodes = explode(',', $seek_tell_log); + $last_start = 0; + $last_end = 0; + foreach ($seek_tell_log_explodes as $seek_tell_log_explode) { + $temp_arr = explode('-', $seek_tell_log_explode); + if (is_array($temp_arr) && 2 == count($temp_arr)) { + $start = $temp_arr[0]; + $end = $temp_arr[1]; + if ($start != $last_end) { + return false; + } + if ($last_start > $end) { + return false; + } + + $last_start = $start; + $last_end = $end; + } else { + return false; + } + } + + if ($last_end != DUPX_Package::getSqlFileSize()) { + return false; + } + return true; + } + + /** + * Check if query should be skipped + * + * @param string $query query to check + * + * @return bool return true if query should be skipped + */ + protected static function skipQuery($query) + { + static $skipRegex = null; + + if (is_null($skipRegex)) { + $skipRegex = array(); + $skipTables = DUPX_DB_Tables::getInstance()->getTablesToSkip(); + $skipCreate = DUPX_DB_Tables::getInstance()->getTablesCreateSkip(); + + if (count($skipTables) > 0) { + $skipTables = array_map(function ($table) { + return preg_quote($table, '/'); + }, $skipTables); + + for ($i = 0; $i < ceil(count($skipTables) / self::TABLES_REGEX_CHUNK_SIZE); $i++) { + $subArray = array_slice($skipTables, $i * self::TABLES_REGEX_CHUNK_SIZE, self::TABLES_REGEX_CHUNK_SIZE); + + if (count($subArray) == 0) { + break; + } + + if (DUPX_ArchiveConfig::getInstance()->dbInfo->buildMode === self::BUILD_MODE_MYSQLDUMP) { + $skipRegex[] = '/^\s*(?:\/\*!\d+\s)?\s*(?:CREATE|INSERT|ALTER|LOCK)\s.*(?:TABLE|INTO).*[`\s](?-i)(' . + implode('|', $subArray) . ')(?i)[`\s]/im'; + } else { + $skipRegex[] = '/^\s*(?:CREATE|INSERT)\s.*(?:TABLE|INTO).*[`\s](?-i)(' . implode('|', $subArray) . ')(?i)[`\s]/im'; + } + } + } + + if (count($skipCreate) > 0) { + $skipCreate = array_map(function ($table) { + return preg_quote($table, '/'); + }, $skipCreate); + + for ($i = 0; $i < ceil(count($skipCreate) / self::TABLES_REGEX_CHUNK_SIZE); $i++) { + $subArray = array_slice($skipCreate, $i * self::TABLES_REGEX_CHUNK_SIZE, self::TABLES_REGEX_CHUNK_SIZE); + + if (count($subArray) == 0) { + break; + } + + $skipRegex[] = '/^\s*CREATE\s.*TABLE.*[`\s](?-i)(' . implode('|', $subArray) . ')(?i)[`\s]/im'; + } + } + + switch (count($skipRegex)) { + case 0: + $skipRegex = false; + Log::info('NO TABLE TO SKIP'); + break; + case 1: + $skipRegex = $skipRegex[0]; + // no break + default: + Log::info( + 'TABLES TO SKIP FOUND ' . Log::v2str( + array( + 'Extraction' => $skipTables, + 'Create only' => $skipCreate) + ) . "\n" + ); + Log::info('SKIP TABLE EXTRACTION REGEX ' . Log::v2str($skipRegex), Log::LV_DETAILED); + break; + } + } + + if (strlen($query) == 0) { + return true; + } elseif ($skipRegex === false) { + return false; + } elseif (is_array($skipRegex)) { + foreach ($skipRegex as $regex) { + if (preg_match($regex, $query) === 1) { + return true; + } + } + return false; + } else { + return (preg_match($skipRegex, $query) === 1); + } + } + + protected function getRowCountMisMatchTables() + { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + + $this->dbConnect(); + + if (is_null($this->dbh)) { + $errorMsg = "**ERROR** database DBH is null"; + $this->dbquery_errs++; + $nManager->addBothNextAndFinalReportNotice(array( + 'shortMsg' => $errorMsg, + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + 'sections' => 'database' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'query-dbh-null'); + Log::info($errorMsg); + $nManager->saveNotices(); + return false; + } + + $tablesList = $archiveConfig->dbInfo->tablesList; + $tablePrefix = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_TABLE_PREFIX); + $skipTables = array( + $tablePrefix . "duplicator_packages", + DUPX_DB_Functions::getOptionsTableName(), + DUPX_DB_Functions::getPackagesTableName() + ); + $misMatchTables = array(); + foreach ($tablesList as $table => $tableInfo) { + if ($tableInfo->insertedRows === false) { + // if it is false it means that no precise count is available to perform the validity test. + continue; + } + $table = $archiveConfig->getTableWithNewPrefix($table); + if (in_array($table, $skipTables)) { + continue; + } + $sql = "SELECT count(*) as cnt FROM `" . mysqli_real_escape_string($this->dbh, $table) . "`"; + $result = DUPX_DB::mysqli_query($this->dbh, $sql); + if (false !== $result) { + $row = mysqli_fetch_assoc($result); + if ($tableInfo->insertedRows != ($row['cnt'])) { + $errMsg = 'DATABASE: table ' . Log::v2str($table) . ' row count mismatch; expected ' . Log::v2str($tableInfo->insertedRows) . ' in database' . Log::v2str($row['cnt']); + Log::info($errMsg); + $nManager->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'Database Table row count validation was failed', + 'level' => DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => $errMsg . "\n", + 'sections' => 'database' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'row-count-mismatch'); + $misMatchTables[] = $table; + } + } + } + return $misMatchTables; + } + + protected function deployDatabaseSingleMode() + { + Log::info("--------------------------------------"); + Log::info("** DATABASE SNGLE MODE install start"); + Log::info("--------------------------------------"); + $this->dbConnect(); + + $handle = fopen($this->sql_file_path, 'rb'); + if ($handle === false) { + return false; + } + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + if (is_null($this->dbh)) { + $errorMsg = "**ERROR** database DBH is null"; + $this->dbquery_errs++; + $nManager->addNextStepNoticeMessage($errorMsg, DUPX_NOTICE_ITEM::CRITICAL, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'query-dbh-null'); + $nManager->addFinalReportNotice(array( + 'shortMsg' => $errorMsg, + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + 'sections' => 'database' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'query-dbh-null'); + Log::info($errorMsg); + $nManager->saveNotices(); + return; + } + + $query = ''; + $delimiter = ';'; + + while (($line = fgets($handle)) !== false) { + if (($res = self::isDelimiterLine($line)) !== false) { + $query = ''; + $delimiter = $this->post['delimiter'] = $res; + continue; + } + + $query .= $line; + + if (preg_match('/' . preg_quote($delimiter, '/') . '\s*$/S', $line)) { + $this->writeQueryInDB($query); + $query = ''; + } + } + + $nManager->saveNotices(); + } + + /** + * @param string $query + * + * @return boolean // false on failure + */ + protected function writeQueryInDB($query) + { + $query = trim($query); + if ($this->skipQuery($query)) { + return true; + } + + $return = false; + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + $query = $this->queryFixes->applyFixes($query); + $query = $this->dbUserMode->applyUsersFixes($query); + + if (strlen($query) == 0) { + return true; + } + + if (($queryLen = strlen($query)) > $this->dbvar_maxpacks) { + $errorMsg = "FAILED QUERY LIMIT [QLEN:" . $queryLen . "|MAX:{$this->dbvar_maxpacks}]\n\t[SQL=" . substr($query, 0, self::QUERY_ERROR_LOG_LEN) . "...]\n\n"; + $this->dbquery_errs++; + $nManager->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'Query size limit error (max limit ' . $this->dbvar_maxpacks . ')', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $errorMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE, + 'sections' => 'database', + 'faqLink' => array( + 'url' => LinkManager::getDocUrl( + 'how-to-fix-database-errors-or-general-warnings-on-the-install-report', + 'install', + 'DB error notice' + ), + 'label' => 'FAQ Link' + ) + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'query-size-limit-msg'); + Log::info($errorMsg); + $return = false; + } + + @mysqli_autocommit($this->dbh, false); + //Check to make sure the connection is alive + if (($query_res = DUPX_DB::mysqli_query($this->dbh, $query)) === false) { + $err = mysqli_error($this->dbh); + $errMsg = "DATABASE ERROR: '{$err}'\n\t[SQL=" . substr($query, 0, self::QUERY_ERROR_LOG_LEN) . "...]\n\n"; + $url = LinkManager::getDocUrl('how-to-fix-database-write-issues', 'install', 'DB error notice'); + + if (DUPX_U::contains($err, 'Unknown collation')) { + $nManager->addNextStepNotice(array( + 'shortMsg' => 'DATABASE ERROR: ' . $err, + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'longMsg' => 'Unknown collation
          RECOMMENDATION: Try resolutions found at ' . $url, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'faqLink' => array( + 'url' => $url, + 'label' => 'FAQ Link' + ) + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'query-collation-write-msg'); + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'DATABASE ERROR: ' . $err, + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'longMsg' => 'Unknown collation
          RECOMMENDATION: Try resolutions found at ' . $url . '
          ' . $errMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + 'faqLink' => array( + 'url' => $url, + 'label' => 'FAQ Link' + ) + )); + Log::info('RECOMMENDATION: Try resolutions found at ' . $url); + } elseif (!$this->skipErrorNotice($err, $query)) { + $nManager->addNextStepNotice(array( + 'shortMsg' => 'DATABASE ERROR: database error write', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $errMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'query-write-msg'); + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'DATABASE ERROR: ' . $err, + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $errMsg, + 'sections' => 'database' + )); + } + + $this->pingAndReconnect(); + $this->dbquery_errs++; + + //Buffer data to browser to keep connection open + $return = false; + } else { + if (!is_bool($query_res)) { + @mysqli_free_result($query_res); + } + $this->dbquery_rows++; + $return = true; + } + + @mysqli_commit($this->dbh); + @mysqli_autocommit($this->dbh, true); + return $return; + } + + private function getSQLSessionMode() + { + $this->dbConnect(); + $result = DUPX_DB::mysqli_query($this->dbh, "SELECT @@SESSION.sql_mode;"); + $row = mysqli_fetch_row($result); + $result->close(); + return is_array($row) ? $row[0] : ''; + } + + /** + * SQL MODE OVERVIEW: + * sql_mode can cause db create issues on some systems because the mode affects how data is inserted. + * Right now defaulting to NO_AUTO_VALUE_ON_ZERO (https://dev.mysql.com/doc/refman/5.5/en/sql-mode.html#sqlmode_no_auto_value_on_zero) + * has been the saftest option because the act of seting the sql_mode will nullify the MySQL Engine defaults which can be very problematic + * if the default is something such as STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_DATE. So the default behavior will be to always + * use NO_AUTO_VALUE_ON_ZERO. If the user insits on using the true system defaults they can use the Custom option. Note these values can + * be overriden by values set in the database.sql script such as: + * !40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' + * + * @throws Exception + */ + private function setSQLSessionMode() + { + $this->dbConnect(); + switch ($this->post['dbmysqlmode']) { + case 'DEFAULT': + $query = "SET SESSION sql_mode = 'NO_AUTO_VALUE_ON_ZERO'"; + break; + case 'DISABLE': + $query = "SET SESSION sql_mode = ''"; + break; + case 'CUSTOM': + $query = "SET SESSION sql_mode = '" . mysqli_real_escape_string($this->dbh, $this->post['dbmysqlmode_opts']) . "'"; + break; + default: + throw new Exception('Unknown dbmysqlmode option ' . $this->post['dbmysqlmode']); + } + + if (!$result = DUPX_DB::mysqli_query($this->dbh, $query)) { + $sql_error = mysqli_error($this->dbh); + $long = "WARNING: A custom sql_mode setting issue has been detected:\n{$sql_error}.
          "; + $long .= "The installation continue with the default MySQL Mode of the database.

          "; + $long .= "For more details visit:
          sql-mode documentation"; + DUPX_NOTICE_MANAGER::getInstance()->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'SET SQL MODE ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $long, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'drop-mysql-mode-set'); + } + } + + /** + * + * @param array $exclude tables to exclude + * @param bool|array $tables // if true drop all tables or table in list + * + * @return void + */ + private function dropTables($exclude = array(), $tables = true) + { + $logMsg = 'DROP' . ($tables === true ? ' ALL TABLES' : ' TABLES ' . Log::v2str($tables)); + if (count($exclude) > 0) { + $logMsg .= ' EXCEPT ' . Log::v2str($exclude); + } + Log::info($logMsg); + + $found_tables = array(); + + $sql = "SHOW FULL TABLES WHERE Table_Type != 'VIEW'"; + if (($result = DUPX_DB::mysqli_query($this->dbh, $sql)) === false) { + Log::error('QUERY ' . Log::v2str($sql) . 'ERROR: ' . mysqli_error($this->dbh)); + } + while ($row = mysqli_fetch_row($result)) { + if (in_array($row[0], $exclude)) { + continue; + } + + if (is_bool($tables) && $tables == false) { + continue; + } + + if (is_array($tables) && !in_array($row[0], $tables)) { + continue; + } + + $found_tables[] = $row[0]; + } + + if (!count($found_tables)) { + return; + } + + DUPX_DB::mysqli_query($this->dbh, "SET FOREIGN_KEY_CHECKS = 0;"); + foreach ($found_tables as $table_name) { + //Log::info('DROP TABLE ' . $table_name, Log::LV_DEBUG); + Log::info('DROP TABLE ' . $table_name); + $sql = "DROP TABLE `" . mysqli_real_escape_string($this->dbh, $this->post['dbname']) . "`.`" . mysqli_real_escape_string($this->dbh, $table_name) . "`"; + if (!$result = DUPX_DB::mysqli_query($this->dbh, $sql)) { + Log::error(sprintf(ERR_DROP_TABLE_TRYCLEAN, $table_name, $this->post['dbname'], mysqli_error($this->dbh))); + } + } + DUPX_DB::mysqli_query($this->dbh, "SET FOREIGN_KEY_CHECKS = 1;"); + + $this->drop_tbl_log = count($found_tables); + } + + protected function writeLog() + { + $this->dbConnect(); + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $paramsManager = PrmMng::getInstance(); + + Log::info("ERRORS FOUND:\t{$this->dbquery_errs}"); + Log::info("DROPPED TABLES:\t{$this->drop_tbl_log}"); + Log::info("RENAMED TABLES:\t{$this->rename_tbl_log}"); + Log::info("QUERIES RAN:\t{$this->dbquery_rows}\n"); + + $this->dbtable_rows = 1; + $this->dbtable_count = 0; + + Log::info("TABLES ROWS IN DATABASE AFTER EXTRACTION\n"); + if (($result = DUPX_DB::mysqli_query($this->dbh, "SHOW TABLES")) != false) { + while ($row = mysqli_fetch_array($result, MYSQLI_NUM)) { + $table_rows = DUPX_DB::countTableRows($this->dbh, $row[0]); + $this->dbtable_rows += $table_rows; + Log::info('TABLE ' . str_pad(Log::v2str($row[0]), 50, '_', STR_PAD_RIGHT) . '[ROWS:' . str_pad($table_rows, 6, " ", STR_PAD_LEFT) . ']'); + $this->dbtable_count++; + } + @mysqli_free_result($result); + } + + if ($this->dbtable_count == 0) { + $tablePrefix = $paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX); + $longMsg = "You may have to manually run the installer-data.sql to validate data input. " . + "Also check to make sure your installer file is correct and the table prefix '" . $tablePrefix . " is correct for this particular version of WordPress."; + $nManager->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'No table in database', + 'level' => DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => $longMsg, + 'sections' => 'database' + )); + Log::info("NOTICE: " . $longMsg . "\n"); + } + + $finalReport = $paramsManager->getValue(PrmMng::PARAM_FINAL_REPORT_DATA); + $finalReport['extraction']['table_count'] = $this->dbtable_count; + $finalReport['extraction']['table_rows'] = $this->dbtable_rows; + $finalReport['extraction']['query_errs'] = $this->dbquery_errs; + $paramsManager->setValue(PrmMng::PARAM_FINAL_REPORT_DATA, $finalReport); + + $paramsManager->save(); + $nManager->saveNotices(); + } + + public function getResultData() + { + $result = array(); + $result['pass'] = $this->post['pass']; + $result['continue_chunking'] = $this->post['continue_chunking']; + if ($result['continue_chunking'] == 0 && $result['pass']) { + $result['perc'] = '100%'; + $result['queryOffset'] = 'Bytes processed ' . number_format($this->dbFileSize) . ' of ' . number_format($this->dbFileSize); + } else { + $result['perc'] = round(($this->post['pos'] * 100 / $this->dbFileSize), 2) . '%'; + $result['queryOffset'] = 'Bytes processed ' . number_format($this->post['pos']) . ' of ' . number_format($this->dbFileSize); + } + $result['is_error'] = $this->post['is_error']; + $result['error_msg'] = $this->post['error_msg']; + $result['table_count'] = $this->dbtable_count; + $result['table_rows'] = $this->dbtable_rows; + $result['query_errs'] = $this->dbquery_errs; + + return $result; + } + + /** + * @param $err string Error message + * @param $query string the SQL query + * + * @return bool if true will skip front-end notice of error message + */ + private function skipErrorNotice($err, $query) + { + return false; + } + + protected function firstOrNotChunking() + { + return $this->post['first_chunk'] || !PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_CHUNK); + } + + public function __destruct() + { + $this->dbClose(); + } +} diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.extraction.php b/installer/dup-installer/ctrls/classes/class.ctrl.extraction.php new file mode 100644 index 00000000..0d5ebc31 --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.extraction.php @@ -0,0 +1,1196 @@ +initData(); + } + + /** + * Inizialize extraction data + * + * @return void + */ + public function initData() + { + // if data file exists load saved data + if (file_exists(self::extractionDataFilePath())) { + Log::info('LOAD EXTRACTION DATA FROM JSON', Log::LV_DETAILED); + if ($this->loadData() == false) { + throw new Exception('Can\'t load extraction data'); + } + } else { + Log::info('INIT EXTRACTION DATA', Log::LV_DETAILED); + $this->constructData(); + $this->saveData(); + $this->logStart(); + } + + if (strlen($relativeAbsPth = DUPX_ArchiveConfig::getInstance()->getRelativePathsInArchive('abs')) > 0) { + Log::info('SET RELATIVE ABSPATH: ' . Log::v2str($relativeAbsPth)); + SnapWP::setWpCoreRelativeAbsPath(DUPX_ArchiveConfig::getInstance()->getRelativePathsInArchive('abs')); + } + + $this->chunkStart = DUPX_U::getMicrotime(); + } + + /** + * Construct persistent data + * + * @return void + */ + private function constructData() + { + $paramsManager = PrmMng::getInstance(); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + + $this->extractonStart = DUPX_U::getMicrotime(); + $this->zip_filetime = $paramsManager->getValue(PrmMng::PARAM_FILE_TIME); + $this->archive_action = $paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ACTION); + $this->archive_engine = $paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ENGINE); + $this->root_path = SnapIO::trailingslashit($paramsManager->getValue(PrmMng::PARAM_PATH_NEW)); + $this->archive_path = DUPX_Security::getInstance()->getArchivePath(); + $this->dawn_status = null; + $this->archive_items_count = $archiveConfig->totalArchiveItemsCount(); + $this->ajax1_error_level = error_reporting(); + error_reporting(E_ERROR); + $this->max_size_extract_at_a_time = DUPX_U::get_default_chunk_size_in_byte(MB_IN_BYTES * 2); + + if (self::ENGINE_DUP == $this->archive_engine || $this->archive_engine == self::ENGINE_MANUAL) { + $this->sub_folder_archive = ''; + } elseif (($this->sub_folder_archive = DUPX_U::findDupInstallerFolder(DUPX_Security::getInstance()->getArchivePath())) === false) { + Log::info("findDupInstallerFolder error; set no subfolder"); + // if not found set not subfolder + $this->sub_folder_archive = ''; + } + + $this->filters = FilterMng::getExtractFilters($this->sub_folder_archive); + $this->removeFilters = FilterMng::getRemoveFilters($this->filters); + } + + /** + * + * @return string + */ + private static function extractionDataFilePath() + { + static $path = null; + if (is_null($path)) { + $path = DUPX_INIT . '/dup-installer-extraction__' . DUPX_Package::getPackageHash() . '.json'; + } + return $path; + } + + /** + * + * @return boolean + */ + public function saveData() + { + if (($json = SnapJson::jsonEncodePPrint($this)) === false) { + Log::info('Can\'t encode json data'); + return false; + } + + if (@file_put_contents(self::extractionDataFilePath(), $json) === false) { + Log::info('Can\'t save extraction data file'); + return false; + } + + return true; + } + + /** + * + * @return boolean + */ + private function loadData() + { + if (!file_exists(self::extractionDataFilePath())) { + return false; + } + + if (($json = @file_get_contents(self::extractionDataFilePath())) === false) { + throw new Exception('Can\'t load extraction data file'); + } + + JsonSerialize::unserializeToObj($json, $this); + return true; + } + + /** + * reset extraction data + * + * @return boolean + */ + public static function resetData() + { + $result = true; + if (file_exists(self::extractionDataFilePath())) { + if (@unlink(self::extractionDataFilePath()) === false) { + throw new Exception('Can\'t delete extraction data file'); + } + } + return $result; + } + + /** + * Preliminary actions before the extraction. + * + * @return void + */ + protected function beforeExtraction() + { + if (!$this->isFirst()) { + return; + } + + Log::info('BEFORE EXTRACION ACTIONS'); + + if (DUPX_ArchiveConfig::getInstance()->exportOnlyDB) { + Log::info('EXPORT DB ONLY CHECKS'); + $this->exportOnlyDB(); + } + + DUPX_ServerConfig::reset($this->root_path); + + $remover = new RemoveFiles($this->removeFilters); + $remover->remove(); + + //throw new Exception('FORCE FAIL'); + + DUPX_U::maintenanceMode(true); + + $this->createFoldersAndPermissionPrepare(); + + if (!empty($this->sub_folder_archive)) { + Log::info("ARCHIVE dup-installer SUBFOLDER:" . Log::v2str($this->sub_folder_archive)); + } else { + Log::info("ARCHIVE dup-installer SUBFOLDER:" . Log::v2str($this->sub_folder_archive), Log::LV_DETAILED); + } + } + + /** + * Shows next step and final report notice files are found WP core folders + * + * @return void + */ + protected function configFilesCheckNotice() + { + //Test if config files are present in main folders + $folderList = array( + PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . "/wp-admin", + PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . "/wp-includes", + PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) + ); + + $configFiles = array( + 'php.ini', + '.user.ini', + '.htaccess' + ); + + $foundConfigFiles = array(); + + foreach ($folderList as $dir) { + foreach ($configFiles as $file) { + if (file_exists($dir . '/' . $file)) { + $foundConfigFiles[] = DUPX_U::esc_html('- ' . $dir . '/' . $file); + Log::info("WARNING: Found " . $file . " config file in " . $dir, Log::LV_DETAILED); + } + } + } + + if (!empty($foundConfigFiles)) { + $noticeManager = DUPX_NOTICE_MANAGER::getInstance(); + $msg = "Config files in WordPress main folders may cause problems with accessing the site after the installation." . + " The following config files were found:

          " . implode("
          ", $foundConfigFiles) . + "

          Please consider removing those files in case you have problems with your site after the installation."; + + $noticeManager->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'One or multiple config files were found in main WordPress folders', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'longMsg' => $msg, + 'sections' => 'general' + )); + $noticeManager->saveNotices(); + } + } + + /** + * Execute extraction + * + * @throws Exception + * + * @return void + */ + public function runExtraction() + { + $this->beforeExtraction(); + + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + $this->runZipArchive(true); + break; + case self::ENGINE_ZIP: + $this->runZipArchive(false); + break; + case self::ENGINE_MANUAL: + break; + case self::ENGINE_ZIP_SHELL: + $this->runShellExec(); + break; + case self::ENGINE_DUP: + $this->runDupExtraction(); + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + } + + /** + * + * @return boolean + * + * @throws Exception + */ + protected function createFoldersAndPermissionPrepare() + { + Log::info("\n*** CREATE FOLDER AND PERMISSION PREPARE"); + + switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE)) { + case self::ENGINE_ZIP_CHUNK: + case self::ENGINE_ZIP: + case self::ENGINE_DUP: + $filters = $this->filters; + DUPX_Package::foreachDirCallback(function ($info) use ($filters) { + if ($filters->isFiltered($info->p)) { + return true; + } + + $destPath = DUPX_ArchiveConfig::getInstance()->destFileFromArchiveName($info->p); + + if (file_exists($destPath)) { + Log::info("PATH " . Log::v2str($destPath) . ' ALEADY EXISTS', Log::LV_DEBUG); + } else { + Log::info("PATH " . Log::v2str($destPath) . ' NOT EXISTS, CREATE IT', Log::LV_DEBUG); + if (SnapIO::mkdirP($destPath) === false) { + Log::info("ARCHIVE EXTRACION: can't create folder " . Log::v2str($destPath)); + } + } + + if (!SnapIO::dirAddFullPermsAndCheckResult($destPath)) { + Log::info("ARCHIVE EXTRACION: can't set writable " . Log::v2str($destPath)); + } + }); + break; + case self::ENGINE_ZIP_SHELL: + self::setPermsViaShell('u+rwx', 'u+rw'); + break; + case self::ENGINE_MANUAL: + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + + Log::info("FOLDER PREPARE DONE"); + return true; + } + + /** + * + * @return boolean + * @throws Exception + */ + public static function setFolderPermissionAfterExtraction() + { + $paramManager = PrmMng::getInstance(); + if (!$paramManager->getValue(PrmMng::PARAM_SET_DIR_PERMS)) { + Log::info('\n SKIP FOLDER PERMISSION AFTER EXTRACTION'); + return; + } + + Log::info("\n*** SET FOLDER PERMISSION AFTER EXTRACTION"); + + switch ($paramManager->getValue(PrmMng::PARAM_ARCHIVE_ENGINE)) { + case self::ENGINE_ZIP_CHUNK: + case self::ENGINE_ZIP: + case self::ENGINE_DUP: + DUPX_Package::foreachDirCallback(function ($info) { + $destPath = DUPX_ArchiveConfig::getInstance()->destFileFromArchiveName($info->p); + DUP_Extraction::setPermsFromParams($destPath); + }); + break; + case self::ENGINE_ZIP_SHELL: + $dirPerms = ( + $paramManager->getValue(PrmMng::PARAM_SET_DIR_PERMS) ? + $paramManager->getValue(PrmMng::PARAM_DIR_PERMS_VALUE) : + false); + $filePerms = ( + $paramManager->getValue(PrmMng::PARAM_SET_FILE_PERMS) ? + $paramManager->getValue(PrmMng::PARAM_FILE_PERMS_VALUE) : + false); + self::setPermsViaShell($dirPerms, $filePerms, true); + break; + case self::ENGINE_MANUAL: + break; + default: + throw new Exception('No valid engine '); + } + + Log::info("SET FOLDER PERMISSION DONE"); + return true; + } + + /** + * Extract package with duparchive + * + * @return void + */ + protected function runDupExtraction() + { + $paramsManager = PrmMng::getInstance(); + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + SnapLog::init(Log::getLogFilePath()); + SnapLog::$logHandle = Log::getFileHandle(); + + $params = array( + 'action' => $this->isFirst() ? 'start_expand' : 'expand', + 'archive_filepath' => DUPX_Security::getInstance()->getArchivePath(), + 'restore_directory' => $paramsManager->getValue(PrmMng::PARAM_PATH_NEW), + 'worker_time' => DUPX_Constants::CHUNK_EXTRACTION_TIMEOUT_TIME_ZIP, + 'filtered_directories' => $this->filters->getDirs(), + 'filtered_files' => $this->filters->getFiles(), + 'excludedDirWithoutChilds' => $this->filters->getDirsWithoutChilds(), + 'includeFiles' => array(), // ignore filtered + 'file_renames' => array(), + 'file_mode_override' => ( + $paramsManager->getValue(PrmMng::PARAM_SET_FILE_PERMS) ? + $paramsManager->getValue(PrmMng::PARAM_FILE_PERMS_VALUE) : + -1), + 'includedFiles' => array(), + 'dir_mode_override' => 'u+rwx', + 'keep_file_time' => ($paramsManager->getValue(PrmMng::PARAM_FILE_TIME) == 'original') ? true : false + ); + + $params['filtered_files'][] = DupArchive::INDEX_FILE_NAME; + if (!file_exists(DUPX_Package::getSqlFilePath())) { + Log::info('SQL FILE NOT FOUND SO ADD TO EXTRACTION'); + $params['includedFiles'][] = DUPX_Package::getSqlFilePathInArchive(); + $params['fileRenames'][DUPX_Package::getSqlFilePathInArchive()] = DUPX_Package::getSqlFilePath(); + } + + $offset = $this->isFirst() ? 0 : $this->dawn_status->archive_offset; + Log::info("ARCHIVE OFFSET " . $offset); + + $daws = new Daws(); + $daws->setFailureCallBack(function ($failure) { + DUP_Extraction::reportExtractionNotices($failure->subject, $failure->description); + }); + $dupResult = $daws->processRequest($params); + $this->dawn_status = $dupResult->status; + $nManager->saveNotices(); + } + + /** + * extract package with ziparchive + * + * @param bool $chunk false no chunk system + * + * @return void + * + * @throws Exception + */ + protected function runZipArchive($chunk = true) + { + if (!class_exists('ZipArchive')) { + Log::info("ERROR: Stopping install process. " . + "Trying to extract without ZipArchive module installed. " . + "Please use the 'Manual Archive Extraction' mode to extract zip file."); + Log::error(ERR_ZIPARCHIVE); + } + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + $dupInstallerZipPath = ltrim($this->sub_folder_archive . '/' . self::DUP_FOLDER_NAME, '/'); + + $zip = new ZipArchive(); + $time_over = false; + + Log::info("ARCHIVE OFFSET " . Log::v2str($this->archive_offset)); + Log::info('DUP INSTALLER ARCHIVE PATH:"' . $dupInstallerZipPath . '"', Log::LV_DETAILED); + + if ($zip->open($this->archive_path) !== true) { + $faqURL = LinkManager::getDocUrl('how-to-fix-installer-archive-extraction-issues', 'install'); + $zip_err_msg = ERR_ZIPOPEN; + $zip_err_msg .= '

          To resolve error see ' . + DUPX_Constants::FAQ_URL . "how-to-fix-installer-archive-extraction-issues/"; + Log::info($zip_err_msg); + throw new Exception("Couldn't open zip archive."); + } + + $this->num_files = $zip->numFiles; + $num_files_minus_1 = $this->num_files - 1; + + $extracted_size = 0; + + LogHandler::setMode(LogHandler::MODE_VAR, false, false); + + // Main chunk + do { + $extract_filename = null; + + $no_of_files_in_micro_chunk = 0; + $size_in_micro_chunk = 0; + do { + //rsr uncomment if debugging Log::info("c ao " . $this->archive_offset); + $stat_data = $zip->statIndex($this->archive_offset); + $filename = $stat_data['name']; + + if ($this->filters->isFiltered($filename)) { + if (Log::isLevel(Log::LV_DETAILED)) { + // optimization + Log::info("FILE EXTRACTION SKIP: " . Log::v2str($filename), Log::LV_DETAILED); + } + } else { + $extract_filename = $filename; + $size_in_micro_chunk += $stat_data['size']; + $no_of_files_in_micro_chunk++; + } + + $this->archive_offset++; + } while ( + $this->archive_offset < $num_files_minus_1 && + $no_of_files_in_micro_chunk < 1 && + $size_in_micro_chunk < $this->max_size_extract_at_a_time + ); + + if (!empty($extract_filename)) { + // skip dup-installer folder. Alrady extracted in bootstrap + if ( + (strpos($extract_filename, $dupInstallerZipPath) === 0) || + (strlen($this->sub_folder_archive) > 0 && strpos($extract_filename, $this->sub_folder_archive) !== 0) + ) { + Log::info("SKIPPING NOT IN ZIPATH:\"" . Log::v2str($extract_filename) . "\"", Log::LV_DETAILED); + } else { + $destFilePath = $archiveConfig->destFileFromArchiveName($extract_filename); + $this->extractFile($zip, $extract_filename, $destFilePath); + } + } + + $extracted_size += $size_in_micro_chunk; + if ($this->archive_offset == $this->num_files - 1) { + if (!empty($this->sub_folder_archive)) { + DUPX_U::moveUpfromSubFolder($this->root_path . $this->sub_folder_archive, true); + } + + Log::info("FILE EXTRACTION: done processing last file in list of {$this->num_files}"); + $this->chunkedExtractionCompleted = true; + break; + } + + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_ZIP_THROTTLING)) { + for ($i = 0; $i < self::ZIP_THROTTLING_ITERATIONS; $i++) { + usleep(self::ZIP_THROTTLING_SLEEP_TIME); + } + } + + if (($time_over = $chunk && (DUPX_U::getMicrotime() - $this->chunkStart) > DUPX_Constants::CHUNK_EXTRACTION_TIMEOUT_TIME_ZIP)) { + Log::info("TIME IS OVER - CHUNK", 2); + } + } while ($this->archive_offset < $num_files_minus_1 && !$time_over); + + // set handler as default + LogHandler::setMode(); + $zip->close(); + + $chunk_time = DUPX_U::getMicrotime() - $this->chunkStart; + + $chunk_extract_rate = $extracted_size / $chunk_time; + $this->zip_arc_chunks_extract_rates[] = $chunk_extract_rate; + $zip_arc_chunks_extract_rates = $this->zip_arc_chunks_extract_rates; + $average_extract_rate = array_sum($zip_arc_chunks_extract_rates) / count($zip_arc_chunks_extract_rates); + + $expected_extract_time = $average_extract_rate > 0 ? DUPX_Conf_Utils::archiveSize() / $average_extract_rate : 0; + + /* + Log::info("Expected total archive extract time: {$expected_extract_time}"); + Log::info("Total extraction elapsed time until now: {$expected_extract_time}"); + */ + + $elapsed_time = DUPX_U::getMicrotime() - $this->extractonStart; + $max_no_of_notices = count($GLOBALS['ZIP_ARC_CHUNK_EXTRACT_NOTICES']) - 1; + + $zip_arc_chunk_extract_disp_notice_after = $GLOBALS['ZIP_ARC_CHUNK_EXTRACT_DISP_NOTICE_AFTER']; + $zip_arc_chunk_extract_disp_notice_min_expected_extract_time = $GLOBALS['ZIP_ARC_CHUNK_EXTRACT_DISP_NOTICE_MIN_EXPECTED_EXTRACT_TIME']; + $zip_arc_chunk_extract_disp_next_notice_interval = $GLOBALS['ZIP_ARC_CHUNK_EXTRACT_DISP_NEXT_NOTICE_INTERVAL']; + + if ($this->zip_arc_chunk_notice_no < 0) { // -1 + if ( + ( + $elapsed_time > $zip_arc_chunk_extract_disp_notice_after && + $expected_extract_time > $zip_arc_chunk_extract_disp_notice_min_expected_extract_time + ) || + $elapsed_time > $zip_arc_chunk_extract_disp_notice_min_expected_extract_time + ) { + $this->zip_arc_chunk_notice_no++; + $this->zip_arc_chunk_notice_change_last_time = DUPX_U::getMicrotime(); + } + } elseif ($this->zip_arc_chunk_notice_no > 0 && $this->zip_arc_chunk_notice_no < $max_no_of_notices) { + $interval_after_last_notice = DUPX_U::getMicrotime() - $this->zip_arc_chunk_notice_change_last_time; + Log::info("Interval after last notice: {$interval_after_last_notice}"); + if ($interval_after_last_notice > $zip_arc_chunk_extract_disp_next_notice_interval) { + $this->zip_arc_chunk_notice_no++; + $this->zip_arc_chunk_notice_change_last_time = DUPX_U::getMicrotime(); + } + } + + $nManager->saveNotices(); + + //rsr todo uncomment when debugging Log::info("Zip archive chunk notice no.: {$this->zip_arc_chunk_notice_no}"); + } + + /** + * Set files permission + * + * @param string $path Path + * @param boolean $setDir Folders permissions + * @param boolean $setFile Files permissions + * + * @return boolean // false if fail, if file don't exists retur true + */ + public static function setPermsFromParams($path, $setDir = true, $setFile = true) + { + static $permsSettings = null; + + if (is_null($permsSettings)) { + $paramsManager = PrmMng::getInstance(); + + $permsSettings = array( + 'fileSet' => $paramsManager->getValue(PrmMng::PARAM_SET_FILE_PERMS), + 'fileVal' => $paramsManager->getValue(PrmMng::PARAM_FILE_PERMS_VALUE), + 'dirSet' => $paramsManager->getValue(PrmMng::PARAM_SET_DIR_PERMS), + 'dirVal' => $paramsManager->getValue(PrmMng::PARAM_DIR_PERMS_VALUE) + ); + } + + if (!file_exists($path)) { + return true; + } + + if (is_file($path) || is_link($path)) { + if ($setFile && $permsSettings['fileSet']) { + if (!SnapIO::chmod($path, $permsSettings['fileVal'])) { + Log::info('CHMOD FAIL: ' . $path . ' PERMS: ' . SnapIO::permsToString($permsSettings['fileVal'])); + return false; + } + } + } else { + if ($setDir && $permsSettings['dirSet']) { + if (!SnapIO::chmod($path, $permsSettings['dirVal'])) { + Log::info('CHMOD FAIL: ' . $path . ' PERMS: ' . SnapIO::permsToString($permsSettings['dirVal'])); + return false; + } + } + } + + return true; + } + + /** + * Extract file from zip archive + * + * @param ZipArchive $zipObj Zip archive object + * @param string $zipFilename File name + * @param string $newFilePath Path to extract + * + * @return void + */ + protected function extractFile(ZipArchive $zipObj, $zipFilename, $newFilePath) + { + try { + //rsr uncomment if debugging Log::info("Attempting to extract {$zipFilename}. Time:". time()); + $error = false; + + // IF EXIST SET READ WRITE PERMISSION + if (is_file($newFilePath) || is_link($newFilePath)) { + SnapIO::chmod($newFilePath, 'u+rw'); + } elseif (is_dir($newFilePath)) { + SnapIO::chmod($newFilePath, 'u+rwx'); + } + + if ($this->root_path . ltrim($zipFilename, '\\/') === $newFilePath) { + if (Log::isLevel(Log::LV_DEBUG)) { + Log::info('EXTRACT FILE [' . $zipFilename . '] TO [' . $newFilePath . ']', Log::LV_DEBUG); + } + if (!$zipObj->extractTo($this->root_path, $zipFilename)) { + $error = true; + } + } else { + if (Log::isLevel(Log::LV_DEBUG)) { + Log::info('CUSTOM EXTRACT FILE [' . $zipFilename . '] TO [' . $newFilePath . ']', Log::LV_DEBUG); + } + if (substr($zipFilename, -1) === '/') { + SnapIO::mkdirP(dirname($newFilePath)); + } else { + if (($destStream = fopen($newFilePath, 'w')) === false) { + if (!file_exists(dirname($newFilePath))) { + SnapIO::mkdirP(dirname($newFilePath)); + if (($destStream = fopen($newFilePath, 'w')) === false) { + $error = true; + } + } else { + $error = true; + } + } + + if ($error || ($sourceStream = $zipObj->getStream($zipFilename)) === false) { + $error = true; + } else { + while (!feof($sourceStream)) { + fwrite($destStream, fread($sourceStream, 1048576)); // 1M + } + + fclose($sourceStream); + fclose($destStream); + } + } + } + + if ($error) { + self::reportExtractionNotices($zipFilename, LogHandler::getVarLogClean()); + } else { + if (Log::isLevel(Log::LV_HARD_DEBUG)) { + Log::info("FILE EXTRACTION DONE: " . Log::v2str($zipFilename), Log::LV_HARD_DEBUG); + } + // SET ONLY FILES + self::setPermsFromParams($newFilePath, false); + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_FILE_TIME) == 'current') { + touch($newFilePath, time()); + } + } + } catch (Exception $ex) { + self::reportExtractionNotices($zipFilename, $ex->getMessage()); + } + } + + /** + * + * @param string $fileName package relative path + * @param string $errorMessage error message + * + * @return void + */ + protected static function reportExtractionNotices($fileName, $errorMessage) + { + if (DUPX_Custom_Host_Manager::getInstance()->skipWarningExtractionForManaged($fileName)) { + // @todo skip warning for managed hostiong (it's a temp solution) + return; + } + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + if (SnapWP::isWpCore($fileName, SnapWP::PATH_RELATIVE)) { + Log::info("FILE CORE EXTRACTION ERROR: {$fileName} | MSG:" . $errorMessage); + $shortMsg = 'Can\'t extract wp core files'; + $finalShortMsg = 'Wp core files not extracted'; + $errLevel = DUPX_NOTICE_ITEM::CRITICAL; + $idManager = 'wp-extract-error-file-core'; + } else { + Log::info("FILE EXTRACTION ERROR: {$fileName} | MSG:" . $errorMessage); + $shortMsg = 'Can\'t extract files'; + $finalShortMsg = 'Files not extracted'; + $errLevel = DUPX_NOTICE_ITEM::SOFT_WARNING; + $idManager = 'wp-extract-error-file-no-core'; + } + + $longMsg = 'FILE: ' . htmlspecialchars($fileName) . '
          Message: ' . htmlspecialchars($errorMessage) . '

          '; + + $nManager->addNextStepNotice(array( + 'shortMsg' => $shortMsg, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'level' => $errLevel + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager); + $nManager->addFinalReportNotice(array( + 'shortMsg' => $finalShortMsg, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'level' => $errLevel, + 'sections' => array('files'), + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager); + } + + /** + * Export db only + * + * @return void + */ + protected function exportOnlyDB() + { + if ($this->archive_engine == self::ENGINE_MANUAL || $this->archive_engine == self::ENGINE_DUP) { + $sql_file_path = DUPX_Package::getSqlFilePath(); + if (!file_exists(DUPX_Package::getWpconfigArkPath()) && !file_exists($sql_file_path)) { + Log::error(ERR_ZIPMANUAL); + } + } else { + if (!is_readable("{$this->archive_path}")) { + Log::error("archive file path:
          " . ERR_ZIPNOTFOUND); + } + } + } + + /** + * Write extraction log header + * + * @return void + */ + protected function logStart() + { + $paramsManager = PrmMng::getInstance(); + + Log::info("********************************************************************************"); + Log::info('* DUPLICATOR LITE: Install-Log'); + Log::info('* STEP-1 START @ ' . @date('h:i:s')); + Log::info('* NOTICE: Do NOT post to public sites or forums!!'); + Log::info("********************************************************************************"); + + $labelPadSize = 20; + Log::info("USER INPUTS"); + Log::info(str_pad('INSTALL TYPE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . DUPX_InstallerState::installTypeToString()); + Log::info(str_pad('BLOG NAME', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_BLOGNAME))); + + Log::info(str_pad('HOME URL NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_URL_NEW))); + Log::info(str_pad('SITE URL NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_SITE_URL))); + Log::info(str_pad('CONTENT URL NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_NEW))); + Log::info(str_pad('UPLOAD URL NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_URL_UPLOADS_NEW))); + Log::info(str_pad('PLUGINS URL NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_URL_PLUGINS_NEW))); + Log::info( + str_pad('MUPLUGINS URL NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_URL_MUPLUGINS_NEW)) + ); + + Log::info(str_pad('HOME PATH NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_NEW))); + Log::info(str_pad('SITE PATH NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW))); + Log::info(str_pad('CONTENT PATH NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW))); + Log::info(str_pad('UPLOAD PATH NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_UPLOADS_NEW))); + Log::info(str_pad('PLUGINS PATH NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_NEW))); + Log::info( + str_pad('MUPLUGINS PATH NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW)) + ); + + Log::info(str_pad('ARCHIVE ACTION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ACTION))); + Log::info( + str_pad( + 'SKIP WP FILES', + $labelPadSize, + '_', + STR_PAD_RIGHT + ) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES)) + ); + Log::info(str_pad('ARCHIVE ENGINE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ENGINE))); + Log::info(str_pad('SET DIR PERMS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_SET_DIR_PERMS))); + Log::info( + str_pad( + 'DIR PERMS VALUE', + $labelPadSize, + '_', + STR_PAD_RIGHT + ) . ': ' . SnapIO::permsToString($paramsManager->getValue(PrmMng::PARAM_DIR_PERMS_VALUE)) + ); + Log::info(str_pad('SET FILE PERMS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_SET_FILE_PERMS))); + Log::info( + str_pad( + 'FILE PERMS VALUE', + $labelPadSize, + '_', + STR_PAD_RIGHT + ) . ': ' . SnapIO::permsToString($paramsManager->getValue(PrmMng::PARAM_FILE_PERMS_VALUE)) + ); + Log::info(str_pad('SAFE MODE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_SAFE_MODE))); + Log::info(str_pad('LOGGING', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_LOGGING))); + Log::info(str_pad('ZIP THROTTLING', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_ZIP_THROTTLING))); + Log::info(str_pad('WP CONFIG', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_WP_CONFIG))); + Log::info(str_pad('HTACCESS CONFIG', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_HTACCESS_CONFIG))); + Log::info(str_pad('OTHER CONFIG', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_OTHER_CONFIG))); + Log::info(str_pad('FILE TIME', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_FILE_TIME))); + Log::info("********************************************************************************\n"); + Log::info('REMOVE FILTERS'); + Log::incIndent(); + foreach ($this->removeFilters->getDirs() as $path) { + Log::info('DIR : ' . Log::v2str($path)); + } + foreach ($this->removeFilters->getFiles() as $path) { + Log::info('FILE: ' . Log::v2str($path)); + } + foreach ($this->removeFilters->getDirsWithoutChilds() as $path) { + Log::info('DIRS WITHOUT CHILDS: ' . Log::v2str($path)); + } + Log::resetIndent(); + Log::info('EXTRACTION FILTERS'); + Log::incIndent(); + foreach ($this->filters->getDirs() as $path) { + Log::info('DIR : ' . Log::v2str($path)); + } + foreach ($this->filters->getFiles() as $path) { + Log::info('FILE: ' . Log::v2str($path)); + } + foreach ($this->filters->getDirsWithoutChilds() as $path) { + Log::info('DIR WITHOUT CHILDS: ' . Log::v2str($path)); + } + Log::resetIndent(); + Log::info("--------------------------------------\n"); + + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + Log::info("\nEXTRACTION: ZIP CHUNKING >>> START"); + break; + case self::ENGINE_ZIP: + Log::info("\nEXTRACTION: ZIP STANDARD >>> START"); + break; + case self::ENGINE_MANUAL: + Log::info("\nEXTRACTION: MANUAL MODE >>> START"); + break; + case self::ENGINE_ZIP_SHELL: + Log::info("\nEXTRACTION: ZIP SHELL >>> START"); + break; + case self::ENGINE_DUP: + Log::info("\nEXTRACTION: DUP ARCHIVE >>> START"); + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + } + + /** + * Write log extraction end + * + * @return void + */ + protected function logComplete() + { + + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + Log::info("\nEXTRACTION: ZIP CHUNKING >>> DONE"); + break; + case self::ENGINE_ZIP: + Log::info("\nEXTRACTION: ZIP STANDARD >>> DONE"); + break; + case self::ENGINE_MANUAL: + Log::info("\nEXTRACTION: MANUAL MODE >>> DONE"); + break; + case self::ENGINE_ZIP_SHELL: + Log::info("\nEXTRACTION: ZIP SHELL >>> DONE"); + break; + case self::ENGINE_DUP: + $criticalPresent = false; + if (count($this->dawn_status->failures) > 0) { + $log = ''; + foreach ($this->dawn_status->failures as $failure) { + if ($failure->isCritical) { + $log .= 'DUP EXTRACTION CRITICAL ERROR ' . $failure->description; + $criticalPresent = true; + } + } + if (!empty($log)) { + Log::info($log); + } + } + if ($criticalPresent) { + throw new Exception('Critical Errors present so stopping install.'); + } + + Log::info("\n\nEXTRACTION: DUP ARCHIVE >>> DONE"); + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + } + + /** + * Extract zip archive via shell + * + * @return void + */ + protected function runShellExec() + { + $command = escapeshellcmd(DUPX_Server::get_unzip_filepath()) . + " -o -qq " . escapeshellarg($this->archive_path) . " -d " . + escapeshellarg($this->root_path) . " 2>&1"; + if ($this->zip_filetime == 'original') { + Log::info("\nShell Exec Current does not support orginal file timestamp please use ZipArchive"); + } + + Log::info('SHELL COMMAND: ' . Log::v2str($command)); + $stderr = shell_exec($command); + if ($stderr != '') { + $faqUrl = LinkManager::getDocUrl('how-to-fix-installer-archive-extraction-issues', 'install', 'shell exec error'); + $zip_err_msg = ERR_SHELLEXEC_ZIPOPEN . ": $stderr"; + $zip_err_msg .= '

          To resolve error see ' + . DUPX_Constants::FAQ_URL . "how-to-fix-installer-archive-extraction-issues"; + Log::error($zip_err_msg); + } + } + + /** + * Set file permission via shell + * + * @param boolean|string $dirPerm folders permissions + * @param boolean|string $filePerm files permsission + * @param boolean $excludeDupInit if true dont set permsission on dup folder + * + * @return void + */ + protected static function setPermsViaShell($dirPerm = false, $filePerm = false, $excludeDupInit = false) + { + $rootPath = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW); + $exludeDupFolder = ($excludeDupInit ? "! -path " . escapeshellarg(DUPX_INIT . '*') . " " : ''); + + if ($filePerm !== false) { + $command = "find " . escapeshellarg($rootPath) . " -type d " . $exludeDupFolder . "-exec chmod " . SnapIO::permsToString($dirPerm) . " {} \;"; + Log::info('SHELL COMMAND: ' . Log::v2str($command)); + shell_exec($command); + } + + if ($dirPerm !== false) { + $command = "find " . escapeshellarg($rootPath) . " -type f " . $exludeDupFolder . "-exec chmod " . SnapIO::permsToString($filePerm) . " {} \;"; + Log::info('SHELL COMMAND: ' . Log::v2str($command)); + shell_exec($command); + } + } + + /** + * + * @return string + */ + public static function getInitialFileProcessedString() + { + return 'Files processed: 0 of ' . number_format(DUPX_ArchiveConfig::getInstance()->totalArchiveItemsCount()); + } + + /** + * Get extraction result + * + * @param boolean $complete true if extraction is complate false if chunk is complete + * + * @return array + */ + protected function getResultExtraction($complete = false) + { + $result = array( + 'pass' => 0, + 'processedFiles' => '', + 'perc' => '' + ); + + if ($complete) { + $result['pass'] = 1; + $result['perc'] = '100%'; + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + case self::ENGINE_ZIP: + case self::ENGINE_ZIP_SHELL: + case self::ENGINE_DUP: + $result['processedFiles'] = 'Files processed: ' . number_format($this->archive_items_count) . + ' of ' . number_format($this->archive_items_count); + break; + case self::ENGINE_MANUAL: + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + + $deltaTime = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $this->extractonStart); + Log::info("\nEXTRACTION COMPLETE @ " . @date('h:i:s') . " - RUNTIME: {$deltaTime} - " . $result['processedFiles']); + } else { + $result['pass'] = -1; + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + case self::ENGINE_ZIP: + case self::ENGINE_ZIP_SHELL: + $result['processedFiles'] = 'Files processed: ' . number_format(min($this->archive_offset, $this->archive_items_count)) . + ' of ' . number_format($this->archive_items_count); + $result['perc'] = min(100, round(($this->archive_offset * 100 / $this->archive_items_count), 2)) . '%'; + break; + case self::ENGINE_DUP: + $result['processedFiles'] = 'Files processed: ' . number_format(min($this->dawn_status->file_index, $this->archive_items_count)) . + ' of ' . number_format($this->archive_items_count); + $result['perc'] = min(100, round(($this->dawn_status->file_index * 100 / $this->archive_items_count), 2)) . '%'; + break; + case self::ENGINE_MANUAL: + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + + $deltaTime = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $this->chunkStart); + Log::info("CHUNK COMPLETE - RUNTIME: {$deltaTime} - " . $result['processedFiles']); + } + return $result; + } + + /** + * End extraction + * + * @return array + */ + protected function finishFullExtraction() + { + $this->configFilesCheckNotice(); + $this->logComplete(); + return $this->getResultExtraction(true); + } + + /** + * End chunked extraction + * + * @return array + */ + protected function finishChunkExtraction() + { + $this->saveData(); + return $this->getResultExtraction(false); + } + + /** + * Finish extraction process + * + * @return array + */ + public function finishExtraction() + { + $complete = false; + + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + $complete = $this->chunkedExtractionCompleted; + break; + case self::ENGINE_DUP: + $complete = $this->dawn_status->is_done; + break; + case self::ENGINE_ZIP: + case self::ENGINE_MANUAL: + case self::ENGINE_ZIP_SHELL: + $complete = true; + break; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + + if ($complete) { + return $this->finishFullExtraction(); + } else { + return $this->finishChunkExtraction(); + } + } + + /** + * + * @return bool + */ + protected function isFirst() + { + switch ($this->archive_engine) { + case self::ENGINE_ZIP_CHUNK: + return $this->archive_offset == 0 && $this->archive_engine == self::ENGINE_ZIP_CHUNK; + case self::ENGINE_DUP: + return is_null($this->dawn_status); + case self::ENGINE_ZIP: + case self::ENGINE_MANUAL: + case self::ENGINE_ZIP_SHELL: + return true; + default: + throw new Exception('No valid engine ' . $this->archive_engine); + } + } +} diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.params.php b/installer/dup-installer/ctrls/classes/class.ctrl.params.php new file mode 100644 index 00000000..8a5f5ef5 --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.params.php @@ -0,0 +1,442 @@ +setValueFromInput(PrmMng::PARAM_CTRL_ACTION, ParamForm::INPUT_REQUEST); + $paramsManager->setValueFromInput(PrmMng::PARAM_STEP_ACTION, ParamForm::INPUT_REQUEST); + return true; + } + + /** + * + * @return boolean + */ + public static function setParamsStep0() + { + Log::info('CTRL PARAMS S0', Log::LV_DETAILED); + Log::info('REQUEST: ' . Log::v2str($_REQUEST), Log::LV_HARD_DEBUG); + $paramsManager = PrmMng::getInstance(); + + DUPX_ArchiveConfig::getInstance()->setNewPathsAndUrlParamsByMainNew(); + DUPX_Custom_Host_Manager::getInstance()->setManagedHostParams(); + + $paramsManager->save(); + return self::$paramsValidated; + } + + /** + * Set param email + * + * @return bool + */ + public static function setParamEmail() + { + Log::info('CTRL PARAM EMAIL', Log::LV_DETAILED); + + PrmMng::getInstance()->setValueFromInput(PrmMng::PARAM_SUBSCRIBE_EMAIL, ParamForm::INPUT_REQUEST); + $resposne = DUPX_HTTP::post(DUPX_Constants::URL_SUBSCRIBE, array( + 'email' => PrmMng::getInstance()->getValue(PrmMng::PARAM_SUBSCRIBE_EMAIL) + )); + + Log::infoObject('response', $resposne); + + PrmMng::getInstance()->save(); + return true; + } + + /** + * + * @return boolean + */ + public static function setParamsStep1() + { + Log::info('CTRL PARAMS S1', Log::LV_DETAILED); + Log::info('REQUEST: ' . Log::v2str($_REQUEST), Log::LV_HARD_DEBUG); + $archive_config = DUPX_ArchiveConfig::getInstance(); + $paramsManager = PrmMng::getInstance(); + $paramsManager->setValueFromInput(PrmMng::PARAM_LOGGING, ParamForm::INPUT_POST); + Log::setLogLevel(); + + $readParamsList = array( + PrmMng::PARAM_INST_TYPE, + PrmMng::PARAM_PATH_NEW, + PrmMng::PARAM_URL_NEW, + PrmMng::PARAM_PATH_WP_CORE_NEW, + PrmMng::PARAM_SITE_URL, + PrmMng::PARAM_PATH_CONTENT_NEW, + PrmMng::PARAM_URL_CONTENT_NEW, + PrmMng::PARAM_PATH_UPLOADS_NEW, + PrmMng::PARAM_URL_UPLOADS_NEW, + PrmMng::PARAM_PATH_PLUGINS_NEW, + PrmMng::PARAM_URL_PLUGINS_NEW, + PrmMng::PARAM_PATH_MUPLUGINS_NEW, + PrmMng::PARAM_URL_MUPLUGINS_NEW, + PrmMng::PARAM_ARCHIVE_ACTION, + PrmMng::PARAM_ARCHIVE_ENGINE, + PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES, + PrmMng::PARAM_DB_ENGINE, + PrmMng::PARAM_REPLACE_ENGINE, + PrmMng::PARAM_USERS_MODE, + PrmMng::PARAM_SET_FILE_PERMS, + PrmMng::PARAM_SET_DIR_PERMS, + PrmMng::PARAM_FILE_PERMS_VALUE, + PrmMng::PARAM_DIR_PERMS_VALUE, + PrmMng::PARAM_SAFE_MODE, + PrmMng::PARAM_WP_CONFIG, + PrmMng::PARAM_HTACCESS_CONFIG, + PrmMng::PARAM_OTHER_CONFIG, + PrmMng::PARAM_FILE_TIME, + PrmMng::PARAM_REMOVE_RENDUNDANT, + PrmMng::PARAM_BLOGNAME, + PrmMng::PARAM_ACCEPT_TERM_COND, + PrmMng::PARAM_ZIP_THROTTLING + ); + + foreach ($readParamsList as $cParam) { + if ($paramsManager->setValueFromInput($cParam, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + } + + $paramsManager->setValue(PrmMng::PARAM_REPLACE_ENGINE, ParamDescEngines::getReplaceEngineModeFromParams()); + $paramsManager->setValue(PrmMng::PARAM_DB_CHUNK, ParamDescEngines::getDbChunkFromParams()); + + self::setParamsDatabase(); + + if (self::$paramsValidated) { + self::resetUrlAndPathsFromOverwriteData(); + + Log::info('UPDATE PARAMS FROM SUBSITE ID', Log::LV_DEBUG); + Log::info('NETWORK INSTALL: false', Log::LV_DEBUG); + + // UPDATE ACTIVE PARAMS BY SUBSITE ID + $activePlugins = DUPX_Plugins_Manager::getInstance()->getDefaultActivePluginsList(); + $paramsManager->setValue(PrmMng::PARAM_PLUGINS, $activePlugins); + + // IF SAFE MODE DISABLE ALL PLUGINS + if ($paramsManager->getValue(PrmMng::PARAM_SAFE_MODE) > 0) { + $forceDisable = DUPX_Plugins_Manager::getInstance()->getAllPluginsSlugs(); + + // EXCLUDE DUPLICATOR PRO + if (($key = array_search(DUPX_Plugins_Manager::SLUG_DUPLICATOR_PRO, $forceDisable)) !== false) { + unset($forceDisable[$key]); + } + + $paramsManager->setValue(PrmMng::PARAM_FORCE_DIABLE_PLUGINS, $forceDisable); + } + } + + // reload state after new path and new url + DUPX_InstallerState::getInstance()->checkState(false, false); + $paramsManager->save(); + return self::$paramsValidated; + } + + /** + * + * @return boolean + */ + public static function setParamsAfterValidation() + { + Log::info("\nCTRL PARAMS AFTER VALIDATION"); + $paramsManager = PrmMng::getInstance(); + + $paramsManager->setValue(PrmMng::PARAM_WP_ADDON_SITES_PATHS, DUPX_Validation_test_addon_sites::getAddonsListsFolders()); + ParamDescDatabase::updateCharsetAndCollateByDatabaseSettings(); + + $configsChecks = DUPX_Validation_test_iswritable_configs::configsWritableChecks(); + + if ($configsChecks['wpconfig'] === false) { + Log::info("WP-CONFIG ISN\'T READABLE SO SET noting ON " . PrmMng::PARAM_WP_CONFIG . ' PARAM'); + $paramsManager->setValue(PrmMng::PARAM_WP_CONFIG, 'nothing'); + $paramsManager->setFormStatus(PrmMng::PARAM_WP_CONFIG, ParamForm::STATUS_INFO_ONLY); + + Log::info('SET AND DISABLE ALL DB PARAMS'); + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + $paramsManager->setValue(PrmMng::PARAM_DB_HOST, $overwriteData['dbhost']); + $paramsManager->setFormStatus(PrmMng::PARAM_DB_HOST, ParamForm::STATUS_INFO_ONLY); + $paramsManager->setValue(PrmMng::PARAM_DB_NAME, $overwriteData['dbname']); + $paramsManager->setFormStatus(PrmMng::PARAM_DB_NAME, ParamForm::STATUS_INFO_ONLY); + $paramsManager->setValue(PrmMng::PARAM_DB_USER, $overwriteData['dbuser']); + $paramsManager->setFormStatus(PrmMng::PARAM_DB_USER, ParamForm::STATUS_INFO_ONLY); + $paramsManager->setValue(PrmMng::PARAM_DB_PASS, $overwriteData['dbpass']); + $paramsManager->setFormStatus(PrmMng::PARAM_DB_PASS, ParamForm::STATUS_INFO_ONLY); + $paramsManager->setValue(PrmMng::PARAM_DB_TABLE_PREFIX, $overwriteData['table_prefix']); + $paramsManager->setFormStatus(PrmMng::PARAM_DB_TABLE_PREFIX, ParamForm::STATUS_INFO_ONLY); + } + + if ($configsChecks['htaccess'] === false) { + Log::info("HTACCESS ISN\'T READABLE SO SET noting ON " . PrmMng::PARAM_HTACCESS_CONFIG . ' PARAM'); + $paramsManager->setValue(PrmMng::PARAM_HTACCESS_CONFIG, 'nothing'); + $paramsManager->setFormStatus(PrmMng::PARAM_HTACCESS_CONFIG, ParamForm::STATUS_INFO_ONLY); + } + + if ($configsChecks['other'] === false) { + Log::info("OTHER CONFIGS ISN\'T READABLE SO SET noting ON " . PrmMng::PARAM_OTHER_CONFIG . ' PARAM'); + $paramsManager->setValue(PrmMng::PARAM_OTHER_CONFIG, 'nothing'); + $paramsManager->setFormStatus(PrmMng::PARAM_OTHER_CONFIG, ParamForm::STATUS_INFO_ONLY); + } + + $paramsManager->save(); + + return self::$paramsValidated; + } + + /** + * + * @return bool + */ + protected static function setParamsDatabase() + { + $paramsManager = PrmMng::getInstance(); + + $paramsManager->setValueFromInput(PrmMng::PARAM_DB_VIEW_MODE, ParamForm::INPUT_POST); + + switch ($paramsManager->getValue(PrmMng::PARAM_DB_VIEW_MODE)) { + case 'basic': + case 'cpnl': + $readParamsList = array( + PrmMng::PARAM_DB_ACTION, + PrmMng::PARAM_DB_HOST, + PrmMng::PARAM_DB_NAME, + PrmMng::PARAM_DB_USER, + PrmMng::PARAM_DB_PASS + ); + foreach ($readParamsList as $cParam) { + if ($paramsManager->setValueFromInput($cParam, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + } + break; + } + + $readParamsList = array( + PrmMng::PARAM_DB_TABLE_PREFIX, + PrmMng::PARAM_DB_VIEW_CREATION, + PrmMng::PARAM_DB_PROC_CREATION, + PrmMng::PARAM_DB_FUNC_CREATION, + PrmMng::PARAM_DB_REMOVE_DEFINER, + PrmMng::PARAM_DB_SPLIT_CREATES, + PrmMng::PARAM_DB_MYSQL_MODE, + PrmMng::PARAM_DB_MYSQL_MODE_OPTS + ); + + foreach ($readParamsList as $cParam) { + if ($paramsManager->setValueFromInput($cParam, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + } + + if ( + DUPX_Validation_database_service::getInstance()->caseSensitiveTablesValue() !== 0 + && ($redundantTables = DUPX_ArchiveConfig::getInstance()->getRedundantDuplicateTableNames()) !== array() + ) { + $defaultTables = DUPX_DB_Tables::getInstance()->getFilteredParamValue($redundantTables); + } else { + $defaultTables = DUPX_DB_Tables::getInstance()->getDefaultParamValue(); + } + + if ($paramsManager->setValue(PrmMng::PARAM_DB_TABLES, $defaultTables) === false) { + self::$paramsValidated = false; + } + + return self::$paramsValidated; + } + + /** + * resets the original values in case of D&G import + * + * @return void + */ + protected static function resetUrlAndPathsFromOverwriteData() + { + if (!DUPX_InstallerState::isImportFromBackendMode()) { + return; + } + + $paramsManager = PrmMng::getInstance(); + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + + if (!isset($overwriteData['urls']['home']) || !isset($overwriteData['paths']['home'])) { + return; + } + + $paramsManager->setValue(PrmMng::PARAM_URL_NEW, $overwriteData['urls']['home']); + $paramsManager->setValue(PrmMng::PARAM_PATH_NEW, $overwriteData['paths']['home']); + + $paramsManager->setValue(PrmMng::PARAM_SITE_URL, $overwriteData['urls']['abs']); + $paramsManager->setValue(PrmMng::PARAM_PATH_WP_CORE_NEW, $overwriteData['paths']['abs']); + + $paramsManager->setValue(PrmMng::PARAM_URL_UPLOADS_NEW, $overwriteData['urls']['uploads']); + $paramsManager->setValue(PrmMng::PARAM_PATH_UPLOADS_NEW, $overwriteData['paths']['uploads']); + } + + /** + * + * @return boolean + */ + public static function setParamsStep2() + { + Log::info('CTRL PARAMS S2', Log::LV_DETAILED); + Log::info('REQUEST: ' . Log::v2str($_REQUEST), Log::LV_HARD_DEBUG); + $paramsManager = PrmMng::getInstance(); + + $readParamsList = array( + PrmMng::PARAM_DB_CHARSET, + PrmMng::PARAM_DB_COLLATE, + PrmMng::PARAM_DB_TABLES + ); + + foreach ($readParamsList as $cParam) { + if ($paramsManager->setValueFromInput($cParam, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + } + + $paramsManager->save(); + return self::$paramsValidated; + } + + /** + * + * @return boolean + */ + public static function setParamsStep3() + { + Log::info('CTRL PARAMS S3', Log::LV_DETAILED); + Log::info('REQUEST: ' . Log::v2str($_REQUEST), Log::LV_HARD_DEBUG); + + $paramsManager = PrmMng::getInstance(); + + $readParamsList = array( + PrmMng::PARAM_EMAIL_REPLACE, + PrmMng::PARAM_FULL_SEARCH, + PrmMng::PARAM_SKIP_PATH_REPLACE, + PrmMng::PARAM_POSTGUID, + PrmMng::PARAM_MAX_SERIALIZE_CHECK, + PrmMng::PARAM_PLUGINS, + PrmMng::PARAM_WP_CONF_DISALLOW_FILE_EDIT, + PrmMng::PARAM_WP_CONF_DISALLOW_FILE_MODS, + PrmMng::PARAM_WP_CONF_AUTOSAVE_INTERVAL, + PrmMng::PARAM_WP_CONF_WP_POST_REVISIONS, + PrmMng::PARAM_WP_CONF_FORCE_SSL_ADMIN, + PrmMng::PARAM_WP_CONF_IMAGE_EDIT_OVERWRITE, + PrmMng::PARAM_GEN_WP_AUTH_KEY, + PrmMng::PARAM_WP_CONF_AUTOMATIC_UPDATER_DISABLED, + PrmMng::PARAM_WP_CONF_WP_AUTO_UPDATE_CORE, + PrmMng::PARAM_WP_CONF_WP_CACHE, + PrmMng::PARAM_WP_CONF_WPCACHEHOME, + PrmMng::PARAM_WP_CONF_WP_DEBUG, + PrmMng::PARAM_WP_CONF_WP_DEBUG_LOG, + PrmMng::PARAM_WP_CONF_WP_DISABLE_FATAL_ERROR_HANDLER, + PrmMng::PARAM_WP_CONF_WP_DEBUG_DISPLAY, + PrmMng::PARAM_WP_CONF_SCRIPT_DEBUG, + PrmMng::PARAM_WP_CONF_CONCATENATE_SCRIPTS, + PrmMng::PARAM_WP_CONF_SAVEQUERIES, + PrmMng::PARAM_WP_CONF_ALTERNATE_WP_CRON, + PrmMng::PARAM_WP_CONF_DISABLE_WP_CRON, + PrmMng::PARAM_WP_CONF_WP_CRON_LOCK_TIMEOUT, + PrmMng::PARAM_WP_CONF_EMPTY_TRASH_DAYS, + PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN, + PrmMng::PARAM_WP_CONF_WP_MEMORY_LIMIT, + PrmMng::PARAM_WP_CONF_WP_MAX_MEMORY_LIMIT, + PrmMng::PARAM_WP_CONF_WP_TEMP_DIR, + PrmMng::PARAM_WP_CONF_MYSQL_CLIENT_FLAGS, + PrmMng::PARAM_USERS_PWD_RESET, + PrmMng::PARAM_WP_ADMIN_CREATE_NEW + ); + + foreach ($readParamsList as $cParam) { + if ($paramsManager->setValueFromInput($cParam, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + } + + if ($paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_CREATE_NEW)) { + $readParamsList = array( + PrmMng::PARAM_WP_ADMIN_NAME, + PrmMng::PARAM_WP_ADMIN_PASSWORD, + PrmMng::PARAM_WP_ADMIN_MAIL, + PrmMng::PARAM_WP_ADMIN_NICKNAME, + PrmMng::PARAM_WP_ADMIN_FIRST_NAME, + PrmMng::PARAM_WP_ADMIN_LAST_NAME + ); + + foreach ($readParamsList as $cParam) { + if ($paramsManager->setValueFromInput($cParam, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + } + + if (DUPX_DB_Functions::getInstance()->checkIfUserNameExists($paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_NAME))) { + self::$paramsValidated = false; + DUPX_NOTICE_MANAGER::getInstance()->addNextStepNotice(array( + 'shortMsg' => 'The user ' . $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_NAME) . ' can\'t be created, already exists', + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + 'longMsg' => 'Please insert another new user login name', + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML + )); + } + } + + $paramsManager->save(); + return self::$paramsValidated; + } + + /** + * + * @return boolean + */ + public static function setParamAutoClean() + { + $paramsManager = PrmMng::getInstance(); + if ($paramsManager->setValueFromInput(PrmMng::PARAM_AUTO_CLEAN_INSTALLER_FILES, ParamForm::INPUT_POST, false, true) === false) { + self::$paramsValidated = false; + } + $paramsManager->save(); + return self::$paramsValidated; + } +} diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.s0.php b/installer/dup-installer/ctrls/classes/class.ctrl.s0.php new file mode 100644 index 00000000..eb2f6b87 --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.s0.php @@ -0,0 +1,95 @@ +getArchivePath(); + $paramsManager = PrmMng::getInstance(); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + $labelPadSize = 20; + + Log::info("INSTALLER INFO\n"); + Log::info(str_pad('TEMPLATE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_TEMPLATE))); + Log::info(str_pad('SECURE MODE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str(DUPX_Security::getInstance()->getSecurityType())); + Log::info(str_pad('URL PLUGINS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('pluginsUrl')); + Log::info(str_pad('VALIDATE ON START', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_VALIDATION_ACTION_ON_START))); + Log::info(str_pad('PATH_NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_PATH_NEW))); + Log::info(str_pad('URL_NEW', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_URL_NEW))); + Log::info("********************************************************************************"); + + if (DUPX_InstallerState::isImportFromBackendMode()) { + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + Log::info("IMPORTER INFO\n"); + Log::info(str_pad('WP VERSION ', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . (isset($overwriteData['wpVersion']) ? $overwriteData['wpVersion'] : 'unknown')); + Log::info(str_pad('DUP VERSION ', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . (isset($overwriteData['dupVersion']) ? $overwriteData['dupVersion'] : 'unknown')); + Log::info(str_pad('LICENSE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . 'Free version'); + Log::info("********************************************************************************"); + } + + $log = ''; + $log .= "ARCHIVE INFO\n\n"; + $log .= str_pad('ARCHIVE NAME', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($archive_path) . "\n"; + $log .= str_pad('ARCHIVE SIZE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . DUPX_U::readableByteSize(DUPX_Conf_Utils::archiveSize()) . "\n"; + $log .= str_pad('CREATED', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->created . "\n"; + $log .= str_pad('WP VERSION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->version_wp . "\n"; + $log .= str_pad('DUP VERSION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->version_dup . "\n"; + $log .= str_pad('LICENSE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . 'Free version' . "\n"; + $log .= str_pad('DB VERSION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->version_db . "\n"; + $log .= str_pad('DB FILE SIZE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . DUPX_U::readableByteSize($archiveConfig->dbInfo->tablesSizeOnDisk) . "\n"; + $log .= str_pad('DB TABLES', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->dbInfo->tablesFinalCount . "\n"; + $log .= str_pad('DB ROWS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->dbInfo->tablesRowCount . "\n"; + $log .= str_pad('URL HOME', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('homeUrl') . "\n"; + $log .= str_pad('URL CORE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('siteUrl') . "\n"; + $log .= str_pad('URL CONTENT', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('contentUrl') . "\n"; + $log .= str_pad('URL UPLOAD', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('uploadBaseUrl') . "\n"; + $log .= str_pad('URL PLUGINS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('pluginsUrl') . "\n"; + $log .= str_pad('URL MU PLUGINS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('mupluginsUrl') . "\n"; + $log .= str_pad('URL THEMES', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->getRealValue('themesUrl') . "\n"; + + + $paths = (array) $archiveConfig->getRealValue('archivePaths'); + foreach ($paths as $key => $value) { + $log .= str_pad('PATH ' . strtoupper($key), $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $value . "\n"; + } + + if (count($archiveConfig->subsites) > 0) { + $log .= "\nSUBSITES\n"; + foreach ($archiveConfig->subsites as $subsite) { + $log .= 'SUBSITE [ID:' . str_pad($subsite->id, 4, ' ', STR_PAD_LEFT) . '] ' . Log::v2str($subsite->domain . $subsite->path) . "\n"; + } + } + + $plugins = (array) $archiveConfig->wpInfo->plugins; + $log .= "\nPLUGINS\n"; + foreach ($plugins as $plugin) { + $log .= 'PLUGIN [SLUG:' . str_pad($plugin->slug, 50, ' ', STR_PAD_RIGHT) . ']'; + + if (is_array($plugin->active)) { + $log .= '[ON:' . str_pad(implode(',', $plugin->active), 5, ' ', STR_PAD_RIGHT) . ']'; + } else { + $log .= '[ON:' . str_pad(Log::v2str($plugin->active), 5, ' ', STR_PAD_RIGHT) . ']'; + } + + $log .= ' ' . $plugin->name . "\n"; + } + Log::info($log, Log::LV_DEFAULT); + Log::info("********************************************************************************"); + Log::flush(); + } +} diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.s3.funcs.php b/installer/dup-installer/ctrls/classes/class.ctrl.s3.funcs.php new file mode 100644 index 00000000..923d34ae --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.s3.funcs.php @@ -0,0 +1,1405 @@ +initData(); + $this->timeStart = DUPX_U::getMicrotime(); + } + + public function updateWebsite() + { + Log::setThrowExceptionOnError(true); + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + switch ($this->getEngineMode()) { + case DUPX_S3_Funcs::MODE_CHUNK: + /* START CHUNK MANAGER */ + $maxIteration = 0; // max iteration before stop. If 0 have no limit + // auto set prevent timeout + $inimaxExecutionTime = ini_get('max_execution_time'); + $maxExecutionTime = (int) (empty($inimaxExecutionTime) ? DUPX_Constants::CHUNK_MAX_TIMEOUT_TIME : $inimaxExecutionTime); + $timeOut = max(5, $maxExecutionTime - 2) * 1000; // timeout in milliseconds before stop exectution + $throttling = 2; // sleep in milliseconds every iteration + $GLOBALS['DATABASE_PAGE_SIZE'] = 1000; // database pagination size for engine update queries + + /* TEST INIT SINGLE FUNC + $maxIteration = 1; // max iteration before stop. If 0 have no limit + $timeOut = 0; // timeout in milliseconds before stop exectution + $throttling = 0; // sleep in milliseconds every iteration + $GLOBALS['DATABASE_PAGE_SIZE'] = 1000000; // database pagination size for engine update queries + */ + + $chunkmManager = new DUPX_chunkS3Manager($maxIteration, $timeOut, $throttling); + if ($chunkmManager->start() === false) { + /* Stop executions */ + $this->chunkStop($chunkmManager->getProgressPerc(), $chunkmManager->getLastPosition()); + } else { + /* step 3 completed */ + $this->complete(); + } + break; + case DUPX_S3_Funcs::MODE_SKIP: + $this->initLog(); + DbCleanup::cleanupOptions(); + DbCleanup::cleanupExtra(); + DbCleanup::cleanupPackages(); + $this->removeMaintenanceMode(); + $this->configFilesUpdate(); + $this->forceLogoutOfAllUsers(); + $this->duplicatorMigrationInfoSet(); + $this->checkForIndexHtml(); + $this->noticeTest(); + $this->cleanupTmpFiles(); + $this->setFilePermsission(); + $this->finalReportNotices(); + $this->complete(); + break; + case DUPX_S3_Funcs::MODE_NORMAL: + default: + $chunkmManager = new DUPX_chunkS3Manager(); + if ($chunkmManager->start() === false) { + throw new Exception('No chunk in normal mode'); + } + $this->complete(); + } + + $nManager->saveNotices(); + return $this->getJsonReport(); + } + + /** + * + * @return self + */ + public static function getInstance() + { + if (is_null(self::$instance)) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * inizialize 3sFunc data + */ + public function initData() + { + // if data file exists load saved data + if (file_exists(self::getS3dataFilePath())) { + Log::info('LOAD S3 DATA FROM JSON', Log::LV_DETAILED); + if ($this->loadData() == false) { + throw new Exception('Can\'t load s3 data'); + } + } else { + Log::info('INIT S3 DATA', Log::LV_DETAILED); + // else init data from $_POST + $this->setReplaceList(); + $this->initReport(); + } + } + + /** + * + * @return string + */ + private static function getS3dataFilePath() + { + static $path = null; + if (is_null($path)) { + $path = DUPX_INIT . '/dup-installer-s3data__' . DUPX_Package::getPackageHash() . '.json'; + } + return $path; + } + + /** + * + * @return boolean + */ + public function saveData() + { + $data = array( + 'report' => $this->report, + 'cTableParams' => $this->cTableParams, + 'replaceData' => DUPX_S_R_MANAGER::getInstance()->getArrayData() + ); + + if (($json = SnapJson::jsonEncodePPrint($data)) === false) { + Log::info('Can\'t encode json data'); + return false; + } + + if (@file_put_contents(self::getS3dataFilePath(), $json) === false) { + Log::info('Can\'t save s3 data file'); + return false; + } + + return true; + } + + /** + * + * @return boolean + */ + private function loadData() + { + if (!file_exists(self::getS3dataFilePath())) { + return false; + } + + if (($json = @file_get_contents(self::getS3dataFilePath())) === false) { + Log::info('Can\'t load s3 data file'); + return false; + } + + $data = json_decode($json, true); + + if (!is_array($data)) { + Log::info('Can\'t decode json data'); + return false; + } + + if (array_key_exists('cTableParams', $data)) { + $this->cTableParams = $data['cTableParams']; + } else { + Log::info('S3 data not well formed: cTableParams not found.'); + return false; + } + + if (array_key_exists('replaceData', $data)) { + DUPX_S_R_MANAGER::getInstance()->setFromArrayData($data['replaceData']); + } else { + Log::info('S3 data not well formed: replace not found.'); + return false; + } + + if (array_key_exists('report', $data)) { + $this->report = $data['report']; + } else { + Log::info('S3 data not well formed: report not found.'); + return false; + } + + return true; + } + + /** + * + * @return boolean + */ + public static function resetData() + { + $result = true; + if (file_exists(self::getS3dataFilePath())) { + if (@unlink(self::getS3dataFilePath()) === false) { + Log::info('Can\'t delete s3 data file'); + $result = false; + } + } + + if (file_exists($GLOBALS["CHUNK_DATA_FILE_PATH"])) { + if (@unlink($GLOBALS["CHUNK_DATA_FILE_PATH"]) === false) { + Log::info('Can\'t delete s3 chunk file'); + $result = false; + } + } + return $result; + } + + private function initReport() + { + $this->report = array( + 'pass' => 0, + 'chunk' => 0, + 'chunkPos' => array(), + 'progress_perc' => 0, + 'scan_tables' => 0, + 'scan_rows' => 0, + 'scan_cells' => 0, + 'updt_tables' => 0, + 'updt_rows' => 0, + 'updt_cells' => 0, + 'errsql' => array(), + 'errser' => array(), + 'errkey' => array(), + 'errsql_sum' => 0, + 'errser_sum' => 0, + 'errkey_sum' => 0, + 'profile_start' => '', + 'profile_end' => '', + 'time' => '', + 'err_all' => 0, + 'warn_all' => 0, + 'warnlist' => array() + ); + } + + public function getJsonReport() + { + $this->report['warn_all'] = empty($this->report['warnlist']) ? 0 : count($this->report['warnlist']); + + return array( + 'step3' => $this->report + ); + } + + private static function logSectionHeader($title, $func, $line) + { + $log = "\n" . '====================================' . "\n" . + $title; + + if (Log::isLevel(Log::LV_DETAILED)) { + $log .= ' [FUNC: ' . $func . ' L:' . $line . ']'; + } + $log .= "\n" . + '===================================='; + Log::info($log); + } + + /** + * open db connection if is closed + * + * @return database connection handle + */ + private function dbConnection() + { + if (is_null($this->dbh)) { + $this->dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + } + return $this->dbh; + } + + /** + * @return database|mysqli connection handle + */ + public function getDbConnection() + { + return $this->dbConnection(); + } + + /** + * close db connection if is open + */ + public function closeDbConnection() + { + DUPX_DB_Functions::getInstance()->closeDbConnection(); + $this->dbh = null; + } + + public function initLog() + { + $paramsManager = PrmMng::getInstance(); + $labelPadSize = 22; + + // make sure dbConnection is initialized + $this->dbConnection(); + + $charsetServer = @mysqli_character_set_name($this->dbh); + $charsetClient = @mysqli_character_set_name($this->dbh); + + //LOGGING + $date = @date('h:i:s'); + $log = "\n\n" . + "********************************************************************************\n" . + "DUPLICATOR LITE: INSTALL-LOG\n" . + "STEP-3 START @ " . $date . "\n" . + "NOTICE: Do NOT post to public sites or forums\n" . + "********************************************************************************\n" . + "CHARSET SERVER:\t" . Log::v2str($charsetServer) . "\n" . + "CHARSET CLIENT:\t" . Log::v2str($charsetClient) . "\n" . + "********************************************************************************\n" . + "OPTIONS:\n"; + + $log .= str_pad('SKIP PATH REPLACE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($paramsManager->getValue(PrmMng::PARAM_SKIP_PATH_REPLACE)) . "\n"; + + $wpConfigsKeys = array( + PrmMng::PARAM_WP_CONF_DISALLOW_FILE_EDIT, + PrmMng::PARAM_WP_CONF_DISALLOW_FILE_MODS, + PrmMng::PARAM_WP_CONF_AUTOSAVE_INTERVAL, + PrmMng::PARAM_WP_CONF_WP_POST_REVISIONS, + PrmMng::PARAM_WP_CONF_FORCE_SSL_ADMIN, + PrmMng::PARAM_WP_CONF_WP_AUTO_UPDATE_CORE, + PrmMng::PARAM_WP_CONF_WP_CACHE, + PrmMng::PARAM_WP_CONF_WPCACHEHOME, + PrmMng::PARAM_WP_CONF_WP_DEBUG, + PrmMng::PARAM_WP_CONF_WP_DEBUG_LOG, + PrmMng::PARAM_WP_CONF_WP_DEBUG_DISPLAY, + PrmMng::PARAM_WP_CONF_WP_DISABLE_FATAL_ERROR_HANDLER, + PrmMng::PARAM_WP_CONF_SCRIPT_DEBUG, + PrmMng::PARAM_WP_CONF_CONCATENATE_SCRIPTS, + PrmMng::PARAM_WP_CONF_SAVEQUERIES, + PrmMng::PARAM_WP_CONF_ALTERNATE_WP_CRON, + PrmMng::PARAM_WP_CONF_DISABLE_WP_CRON, + PrmMng::PARAM_WP_CONF_WP_CRON_LOCK_TIMEOUT, + PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN, + PrmMng::PARAM_WP_CONF_WP_MEMORY_LIMIT, + PrmMng::PARAM_WP_CONF_WP_MAX_MEMORY_LIMIT, + PrmMng::PARAM_WP_CONF_WP_TEMP_DIR + ); + foreach ($wpConfigsKeys as $key) { + $label = $paramsManager->getLabel($key); + $value = SnapString::implodeKeyVals(', ', $paramsManager->getValue($key), '[%s = %s]'); + $log .= str_pad($label, $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $value . "\n"; + } + $log .= "********************************************************************************\n"; + + Log::info($log); + + $log .= "--------------------------------------\n"; + $log .= "KEEP PLUGINS ACTIVE\n"; + $log .= "--------------------------------------\n"; + $plugins = $paramsManager->getValue(PrmMng::PARAM_PLUGINS); + $log .= (count($plugins) > 0 ? Log::v2str($plugins) : 'No plugins selected for activation'); + Log::info($log, Log::LV_DETAILED); + Log::flush(); + } + + public function initChunkLog($maxIteration, $timeOut, $throttling, $rowsPerPage) + { + $log = "********************************************************************************\n" . + "CHUNK PARAMS:\n"; + $log .= str_pad('maxIteration', 22, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($maxIteration) . "\n"; + $log .= str_pad('timeOut', 22, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($timeOut) . "\n"; + $log .= str_pad('throttling', 22, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($throttling) . "\n"; + $log .= str_pad('rowsPerPage', 22, '_', STR_PAD_RIGHT) . ': ' . Log::v2str($rowsPerPage) . "\n"; + $log .= "********************************************************************************\n"; + Log::info($log); + } + + /** + * set replace list + * + * Auto inizialize function + */ + public function setReplaceList() + { + if ($this->getEngineMode() === self::MODE_SKIP) { + return; + } + + self::logSectionHeader('SET SEARCH AND REPLACE LIST INSTALL TYPE ' . DUPX_InstallerState::installTypeToString(), __FUNCTION__, __LINE__); + + $dbReplace = new DbReplace(); + $dbReplace->setSearchReplace(); + } + + /** + * + * @return int MODE_NORAML|MODE_CHUNK|MODE_SKIP + */ + public function getEngineMode() + { + return PrmMng::getInstance()->getValue(PrmMng::PARAM_REPLACE_ENGINE); + } + + /** + * + * @return bool + */ + public function isChunk() + { + return PrmMng::getInstance()->getValue(PrmMng::PARAM_REPLACE_ENGINE) === self::MODE_CHUNK; + } + + public function runSearchAndReplace() + { + self::logSectionHeader('RUN SEARCH AND REPLACE', __FUNCTION__, __LINE__); + + $tables = DUPX_DB_Tables::getInstance()->getReplaceTablesNames(); + + DUPX_UpdateEngine::load($tables); + DUPX_UpdateEngine::logStats(); + DUPX_UpdateEngine::logErrors(); + } + + public function removeMaintenanceMode() + { + self::logSectionHeader('REMOVE MAINTENANCE MODE', __FUNCTION__, __LINE__); + DUPX_U::maintenanceMode(false); + } + + protected function resetUsersPasswords() + { + self::logSectionHeader('RESET USERS PASSWORD', __FUNCTION__, __LINE__); + + $usersLoginsName = DUPX_ArchiveConfig::getInstance()->getUsersLists(); + foreach (PrmMng::getInstance()->getValue(PrmMng::PARAM_USERS_PWD_RESET) as $userId => $newPassword) { + if (strlen($newPassword) > 0) { + Log::info('RESET USER ID ' . $userId . ' NAME ' . $usersLoginsName[$userId] . ' PASSWORD'); + DUPX_DB_Functions::getInstance()->userPwdReset($userId, $newPassword); + } + } + } + + public function forceLogoutOfAllUsers() + { + Log::info('RESET ALL USERS SESSION TOKENS'); + $escapedTablePrefix = mysqli_real_escape_string($this->dbh, PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)); + + try { + DUPX_DB::chunksDelete($this->dbh, $escapedTablePrefix . 'usermeta', "meta_key='session_tokens'"); + } catch (Exception $e) { + Log::info('RESET USER SESSION TOKENS EXCEPTION: ' . $e->getMessage()); + } + } + + public function createNewAdminUser() + { + $this->resetUsersPasswords(); + + if (!PrmMng::getInstance()->getValue(PrmMng::PARAM_WP_ADMIN_CREATE_NEW)) { + return; + } + + self::logSectionHeader('CREATE NEW ADMIN USER', __FUNCTION__, __LINE__); + // make sure dbConnection is initialized + $this->dbConnection(); + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $escapedTablePrefix = mysqli_real_escape_string($this->dbh, PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + $paramsManager = PrmMng::getInstance(); + + $wpUserName = $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_NAME); + $wpUserNameEscaped = mysqli_real_escape_string($this->dbh, $wpUserName); + + $newuser_check = DUPX_DB::mysqli_query( + $this->dbh, + "SELECT COUNT(*) AS count FROM `" . $escapedTablePrefix . "users` WHERE user_login = '{$wpUserNameEscaped}' " + ); + $newuser_row = mysqli_fetch_row($newuser_check); + $newuser_count = is_null($newuser_row) ? 0 : $newuser_row[0]; + + if ($newuser_count == 0) { + $newuser_datetime = @date("Y-m-d H:i:s"); + $newuser_datetime = mysqli_real_escape_string($this->dbh, $newuser_datetime); + $newuser_security = mysqli_real_escape_string($this->dbh, DUPX_WPConfig::ADMIN_SERIALIZED_SECURITY_STRING); + + $post_wp_password = $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_PASSWORD); + $post_wp_mail = $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_MAIL); + $post_wp_nickname = $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_NICKNAME); + if (empty($post_wp_nickname)) { + $post_wp_nickname = $wpUserName; + } + $post_wp_first_name = $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_FIRST_NAME); + $post_wp_last_name = $paramsManager->getValue(PrmMng::PARAM_WP_ADMIN_LAST_NAME); + + $wp_password = mysqli_real_escape_string($this->dbh, $post_wp_password); + $wp_mail = mysqli_real_escape_string($this->dbh, $post_wp_mail); + $wp_nickname = mysqli_real_escape_string($this->dbh, $post_wp_nickname); + $wp_first_name = mysqli_real_escape_string($this->dbh, $post_wp_first_name); + $wp_last_name = mysqli_real_escape_string($this->dbh, $post_wp_last_name); + + $usermeta_table = $escapedTablePrefix . 'usermeta'; + + $newuser1 = DUPX_DB::mysqli_query( + $this->dbh, + "INSERT INTO `" . $escapedTablePrefix . "users` + (`user_login`, `user_pass`, `user_nicename`, `user_email`, `user_registered`, `user_activation_key`, `user_status`, `display_name`) + VALUES ('{$wpUserNameEscaped}', MD5('{$wp_password}'), '{$wpUserNameEscaped}', '{$wp_mail}', '{$newuser_datetime}', '', '0', '{$wpUserNameEscaped}')" + ); + + $newuser1_insert_id = intval(mysqli_insert_id($this->dbh)); + + $newuser2 = DUPX_DB::mysqli_query( + $this->dbh, + "INSERT INTO `" . $usermeta_table . "` + (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', '" . $escapedTablePrefix . "capabilities', '{$newuser_security}')" + ); + + $newuser3 = DUPX_DB::mysqli_query( + $this->dbh, + "INSERT INTO `" . $usermeta_table . "` + (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', '" . $escapedTablePrefix . "user_level', '10')" + ); + + //Misc Meta-Data Settings: + DUPX_DB::mysqli_query($this->dbh, "INSERT INTO `" . $usermeta_table . "` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'rich_editing', 'true')"); + DUPX_DB::mysqli_query($this->dbh, "INSERT INTO `" . $usermeta_table . "` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'admin_color', 'fresh')"); + DUPX_DB::mysqli_query($this->dbh, "INSERT INTO `" . $usermeta_table . "` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'nickname', '{$wp_nickname}')"); + DUPX_DB::mysqli_query($this->dbh, "INSERT INTO `" . $usermeta_table . "` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'first_name', '{$wp_first_name}')"); + DUPX_DB::mysqli_query($this->dbh, "INSERT INTO `" . $usermeta_table . "` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser1_insert_id}', 'last_name', '{$wp_last_name}')"); + + Log::info("\nNEW WP-ADMIN USER:"); + if ($newuser1 && $newuser2 && $newuser3) { + Log::info("- New username '{$wpUserName}' was created successfully allong with MU usermeta."); + } elseif ($newuser1) { + Log::info("- New username '{$wpUserName}' was created successfully."); + } else { + $newuser_warnmsg = "- Failed to create the user '{$wpUserName}' \n "; + $this->report['warnlist'][] = $newuser_warnmsg; + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'New admin user create error', + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'longMsg' => $newuser_warnmsg, + 'sections' => 'general' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'new-user-create-error'); + + Log::info($newuser_warnmsg); + } + } else { + $newuser_warnmsg = "\nNEW WP-ADMIN USER:\n - Username '{$wpUserName}' already exists in the database. Unable to create new account.\n"; + $this->report['warnlist'][] = $newuser_warnmsg; + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'New admin user create error', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $newuser_warnmsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE, + 'sections' => 'general' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'new-user-create-error'); + + Log::info($newuser_warnmsg); + } + } + + /** + * update all config files + */ + public function configFilesUpdate() + { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + // SET FILES + DUPX_ServerConfig::setFiles(PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW)); + $wpConfigFile = DUPX_WPConfig::getWpConfigPath(); + + // UPDATE FILES + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_WP_CONFIG) == 'nothing') { + Log::info('SKIP WP CONFIG UPDATE'); + } elseif (file_exists(($wpConfigFile))) { + if (SnapIO::chmod($wpConfigFile, 'u+rw') === false) { + $err_log = "\nWARNING: Unable to update file permissions and write to wp-config.php. "; + $err_log .= "Check that the wp-config.php is in the archive.zip and check with your host or administrator to enable PHP to write to the wp-config.php file. "; + $err_log .= "If performing a 'Manual Extraction' please be sure to select the 'Manual Archive Extraction' option on step 1 under options."; + Log::error("{$err_log}"); + } + $configTransformer = new WPConfigTransformer($wpConfigFile); + $this->wpConfigUpdate($configTransformer); + DUP_Extraction::setPermsFromParams($wpConfigFile); + } else { + $msg = "WP-CONFIG NOTICE: wp-config.php not found.

          "; + $msg .= "No action on the wp-config was possible.
          "; + $msg .= "Be sure to insert a properly modified wp-config for correct wordpress operation."; + + $nManager->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'wp-config.php file not found', + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'longMsg' => $msg, + 'sections' => 'general' + )); + } + + $this->htaccessUpdate(); + $this->indexPhpUpdate(); + DUPX_NOTICE_MANAGER::getInstance()->saveNotices(); + } + + /** + * update index.php file with right wp-blog-header include related to installation ABSPATH + * + * @return boolean + */ + protected function indexPhpUpdate() + { + $paramsManager = PrmMng::getInstance(); + + if ( + DUPX_InstallerState::isRestoreBackup() + ) { + return; + } + + self::logSectionHeader('INDEX.PHP UPDATE', __FUNCTION__, __LINE__); + + $pathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_NEW); + $indexPath = $pathNew . '/index.php'; + + if (!is_writable($indexPath)) { + Log::info('index.php isn\'t writable'); + return false; + } + + if (($relativeAbsPath = SnapIO::getRelativePath($paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW), $pathNew)) === false) { + $blogHeaderValue = "'" . $paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW) . "/wp-blog-header.php'"; + } else { + $relativeAbsPath = strlen($relativeAbsPath) ? '/' . $relativeAbsPath : ''; + $blogHeaderValue = "dirname(__FILE__) . '" . $relativeAbsPath . "/wp-blog-header.php'"; + } + + if (($indexContent = file_get_contents($indexPath)) === false) { + Log::info('Can\'t read index.php content'); + return false; + } + $indexContent = preg_replace('/(require\s*\(.*wp-blog-header.php[\'"]\s*\))/m', 'require(' . $blogHeaderValue . ')', $indexContent); + + if (file_put_contents($indexPath, $indexContent) === false) { + Log::info('Can\'t update index.php content'); + return false; + } + + Log::info('INDEX.PHP updated with new blog header ' . Log::v2str($blogHeaderValue) . "\n"); + return true; + } + + /** + * + * @param WPConfigTransformer $confTransformer + * + * @return void + */ + protected function wpConfigUpdate(WPConfigTransformer $confTransformer) + { + self::logSectionHeader('CONFIGURATION FILE UPDATES', __FUNCTION__, __LINE__); + Log::incIndent(); + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $paramsManager = PrmMng::getInstance(); + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + + try { + $this->configurationMultisiteUpdate($confTransformer); + $this->configurationUrlsAndPaths($confTransformer); + + $dbhost = DUPX_U::getEscapedGenericString($paramsManager->getValue(PrmMng::PARAM_DB_HOST)); + $dbname = DUPX_U::getEscapedGenericString($paramsManager->getValue(PrmMng::PARAM_DB_NAME)); + $dbuser = DUPX_U::getEscapedGenericString($paramsManager->getValue(PrmMng::PARAM_DB_USER)); + $dbpass = DUPX_U::getEscapedGenericString($paramsManager->getValue(PrmMng::PARAM_DB_PASS)); + $dbcharset = $paramsManager->getValue(PrmMng::PARAM_DB_CHARSET); + $dbcollate = $paramsManager->getValue(PrmMng::PARAM_DB_COLLATE); + + $confTransformer->update('constant', 'DB_NAME', $dbname, array('raw' => true)); + Log::info('UPDATE DB_NAME ' . Log::v2str($dbname)); + + $confTransformer->update('constant', 'DB_USER', $dbuser, array('raw' => true)); + Log::info('UPDATE DB_USER ' . Log::v2str('** OBSCURED **')); + + $confTransformer->update('constant', 'DB_PASSWORD', $dbpass, array('raw' => true)); + Log::info('UPDATE DB_PASSWORD ' . Log::v2str('** OBSCURED **')); + + $confTransformer->update('constant', 'DB_HOST', $dbhost, array('raw' => true)); + Log::info('UPDATE DB_HOST ' . Log::v2str($dbhost)); + + $confTransformer->update('constant', 'DB_CHARSET', $dbcharset); + Log::info('UPDATE DB_CHARSET ' . Log::v2str($dbcharset)); + + $confTransformer->update('constant', 'DB_COLLATE', $dbcollate); + Log::info('UPDATE DB_COLLATE ' . Log::v2str($dbcollate)); + + if (DUPX_InstallerState::isRestoreBackup()) { + Log::info("\nRESTORE BACKUP MODE: SKIP OTHER WP-CONFIGS UPDATE ***"); + Log::resetIndent(); + return; + } + + $auth_keys = array( + 'AUTH_KEY', + 'SECURE_AUTH_KEY', + 'LOGGED_IN_KEY', + 'NONCE_KEY', + 'AUTH_SALT', + 'SECURE_AUTH_SALT', + 'LOGGED_IN_SALT', + 'NONCE_SALT', + ); + + foreach ($auth_keys as $const_key) { + $confTransformer->update('constant', $const_key, $archiveConfig->getDefineValue($const_key)); + } + + $confTransformer->update('variable', 'table_prefix', $paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)); + + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'DISALLOW_FILE_EDIT', PrmMng::PARAM_WP_CONF_DISALLOW_FILE_EDIT); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'DISALLOW_FILE_MODS', PrmMng::PARAM_WP_CONF_DISALLOW_FILE_MODS); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'FORCE_SSL_ADMIN', PrmMng::PARAM_WP_CONF_FORCE_SSL_ADMIN); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'IMAGE_EDIT_OVERWRITE', PrmMng::PARAM_WP_CONF_IMAGE_EDIT_OVERWRITE); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_CACHE', PrmMng::PARAM_WP_CONF_WP_CACHE); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WPCACHEHOME', PrmMng::PARAM_WP_CONF_WPCACHEHOME); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'COOKIE_DOMAIN', PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'AUTOSAVE_INTERVAL', PrmMng::PARAM_WP_CONF_AUTOSAVE_INTERVAL); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_POST_REVISIONS', PrmMng::PARAM_WP_CONF_WP_POST_REVISIONS); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_DEBUG', PrmMng::PARAM_WP_CONF_WP_DEBUG); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_DEBUG_LOG', PrmMng::PARAM_WP_CONF_WP_DEBUG_LOG); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_DISABLE_FATAL_ERROR_HANDLER', PrmMng::PARAM_WP_CONF_WP_DISABLE_FATAL_ERROR_HANDLER); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_DEBUG_DISPLAY', PrmMng::PARAM_WP_CONF_WP_DEBUG_DISPLAY); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'SCRIPT_DEBUG', PrmMng::PARAM_WP_CONF_SCRIPT_DEBUG); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'CONCATENATE_SCRIPTS', PrmMng::PARAM_WP_CONF_CONCATENATE_SCRIPTS); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'SAVEQUERIES', PrmMng::PARAM_WP_CONF_SAVEQUERIES); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'ALTERNATE_WP_CRON', PrmMng::PARAM_WP_CONF_ALTERNATE_WP_CRON); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'DISABLE_WP_CRON', PrmMng::PARAM_WP_CONF_DISABLE_WP_CRON); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_CRON_LOCK_TIMEOUT', PrmMng::PARAM_WP_CONF_WP_CRON_LOCK_TIMEOUT); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'EMPTY_TRASH_DAYS', PrmMng::PARAM_WP_CONF_EMPTY_TRASH_DAYS); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_MEMORY_LIMIT', PrmMng::PARAM_WP_CONF_WP_MEMORY_LIMIT); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_MAX_MEMORY_LIMIT', PrmMng::PARAM_WP_CONF_WP_MAX_MEMORY_LIMIT); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'WP_TEMP_DIR', PrmMng::PARAM_WP_CONF_WP_TEMP_DIR); + DUPX_ArchiveConfig::updateWpConfigByParam($confTransformer, 'AUTOMATIC_UPDATER_DISABLED', PrmMng::PARAM_WP_CONF_AUTOMATIC_UPDATER_DISABLED); + + $wpConfigValue = $paramsManager->getValue(PrmMng::PARAM_WP_CONF_WP_AUTO_UPDATE_CORE); + switch ($wpConfigValue['value']) { + case 'false': + $wpConfigValue['value'] = false; + break; + case 'true': + $wpConfigValue['value'] = true; + break; + case 'minor': + default: + $wpConfigValue['value'] = 'minor'; + break; + } + DUPX_ArchiveConfig::updateWpConfigByValue($confTransformer, 'WP_AUTO_UPDATE_CORE', $wpConfigValue); + + $wpConfigValue = $paramsManager->getValue(PrmMng::PARAM_WP_CONF_MYSQL_CLIENT_FLAGS); + $constantValue = implode(' | ', SnapDB::getMysqlConnectFlagsList(true, $wpConfigValue['value'])); + DUPX_ArchiveConfig::updateWpConfigByValue($confTransformer, 'MYSQL_CLIENT_FLAGS', $wpConfigValue, $constantValue); + + Log::info("\n*** UPDATED WP CONFIG FILE ***"); + } catch (Exception $e) { + $shortMsg = 'wp-config.php transformer:' . $e->getMessage(); + $longMsg = << +The installation is finished but check the wp-config.php file and manually update the incorrect values. +LONGMSG; + /* $nManager->addNextStepNotice(array( + 'shortMsg' => $shortMsg, + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'wp-config-transformer-exception'); */ + $nManager->addFinalReportNotice(array( + 'shortMsg' => $shortMsg, + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'general' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'wp-config-transformer-exception'); + + Log::info("WP-CONFIG TRANSFORMER EXCEPTION\n" . $e->getTraceAsString()); + } + Log::resetIndent(); + } + + /** + * + * @param WPConfigTransformer $confTransformer + */ + protected function configurationMultisiteUpdate(WPConfigTransformer $confTransformer) + { + $muDefines = array( + 'WP_ALLOW_MULTISITE', + 'ALLOW_MULTISITE', + 'MULTISITE', + 'DOMAIN_CURRENT_SITE', + 'PATH_CURRENT_SITE', + 'SITE_ID_CURRENT_SITE', + 'BLOG_ID_CURRENT_SITE', + 'NOBLOGREDIRECT', + 'SUBDOMAIN_INSTALL', + 'VHOST', + 'SUNRISE', + 'COOKIEPATH', + 'SITECOOKIEPATH', + 'ADMIN_COOKIE_PATH', + 'PLUGINS_COOKIE_PATH' + ); + + // Clean all mu site define + foreach ($muDefines as $key) { + if ($confTransformer->exists('constant', $key)) { + $confTransformer->remove('constant', $key); + Log::info('TRANSFORMER[no wpmu]: ' . $key . ' constant removed from WP config file'); + } + } + } + + /** + * + * @param WPConfigTransformer $confTransformer + */ + protected function configurationUrlsAndPaths(WPConfigTransformer $confTransformer) + { + $paramsManager = PrmMng::getInstance(); + + $urlNew = $paramsManager->getValue(PrmMng::PARAM_URL_NEW); + $pathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_NEW); + + $mu_newDomain = parse_url($urlNew); + $mu_newDomainHost = $mu_newDomain['host']; + $mu_newUrlPath = parse_url($urlNew, PHP_URL_PATH); + + if (empty($mu_newUrlPath) || ($mu_newUrlPath == '/')) { + $mu_newUrlPath = '/'; + } else { + $mu_newUrlPath = rtrim($mu_newUrlPath, '/') . '/'; + } + + if ($confTransformer->exists('constant', 'ABSPATH')) { + if (($relativeAbsPath = SnapIO::getRelativePath($paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW), $pathNew)) === false) { + $absPathValue = "'" . $paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW) . "'"; + } else { + $absPathValue = "dirname(__FILE__) . '/" . $relativeAbsPath . "'"; + } + $confTransformer->update('constant', 'ABSPATH', $absPathValue, array('raw' => true)); + Log::info('UPDATE ABSPATH ' . Log::v2str($absPathValue)); + } + + if ($confTransformer->exists('constant', 'WP_HOME')) { + $confTransformer->update('constant', 'WP_HOME', $urlNew, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WP_HOME ' . Log::v2str($urlNew)); + } + + $newSiteUrl = $paramsManager->getValue(PrmMng::PARAM_SITE_URL); + if ($confTransformer->exists('constant', 'WP_SITEURL') || $urlNew != $newSiteUrl) { + $confTransformer->update('constant', 'WP_SITEURL', $newSiteUrl, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WP_SITEURL ' . Log::v2str($newSiteUrl)); + } + + if ($confTransformer->exists('constant', 'DOMAIN_CURRENT_SITE')) { + $confTransformer->update('constant', 'DOMAIN_CURRENT_SITE', $mu_newDomainHost, array('normalize' => true, 'add' => true)); + Log::info('UPDATE DOMAIN_CURRENT_SITE ' . Log::v2str($mu_newDomainHost)); + } + if ($confTransformer->exists('constant', 'PATH_CURRENT_SITE')) { + $confTransformer->update('constant', 'PATH_CURRENT_SITE', $mu_newUrlPath, array('normalize' => true, 'add' => true)); + Log::info('UPDATE PATH_CURRENT_SITE ' . Log::v2str($mu_newUrlPath)); + } + + $pathContent = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW); + if ($confTransformer->exists('constant', 'WP_CONTENT_DIR') || $pathNew . '/wp-content' != $pathContent) { + $confTransformer->update('constant', 'WP_CONTENT_DIR', $pathContent, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WP_CONTENT_DIR ' . Log::v2str($pathContent)); + } + + $urlContent = $paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_NEW); + if ($confTransformer->exists('constant', 'WP_CONTENT_URL') || $urlNew . '/wp-content' != $urlContent) { + $confTransformer->update('constant', 'WP_CONTENT_URL', $urlContent, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WP_CONTENT_URL ' . Log::v2str($urlContent)); + } + + $pathPlugins = $paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_NEW); + if ($confTransformer->exists('constant', 'WP_PLUGIN_DIR') || $pathNew . '/wp-content/plugins' != $pathPlugins) { + $confTransformer->update('constant', 'WP_PLUGIN_DIR', $pathPlugins, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WP_PLUGIN_DIR ' . Log::v2str($pathPlugins)); + } + + $urlPlugins = $paramsManager->getValue(PrmMng::PARAM_URL_PLUGINS_NEW); + if ($confTransformer->exists('constant', 'WP_PLUGIN_URL') || $urlNew . '/wp-content/plugins' != $urlPlugins) { + $confTransformer->update('constant', 'WP_PLUGIN_URL', $urlPlugins, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WP_PLUGIN_URL ' . Log::v2str($urlPlugins)); + } + + $pathMuPlugins = $paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW); + if ($confTransformer->exists('constant', 'WPMU_PLUGIN_DIR') || $pathNew . '/wp-content/mu-plugins' != $pathMuPlugins) { + $confTransformer->update('constant', 'WPMU_PLUGIN_DIR', $pathMuPlugins, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WPMU_PLUGIN_DIR ' . Log::v2str($pathMuPlugins)); + } + + $urlMuPlugins = $paramsManager->getValue(PrmMng::PARAM_URL_MUPLUGINS_NEW); + if ($confTransformer->exists('constant', 'WPMU_PLUGIN_URL') || $urlNew . '/wp-content/mu-plugins' != $urlMuPlugins) { + $confTransformer->update('constant', 'WPMU_PLUGIN_URL', $urlMuPlugins, array('normalize' => true, 'add' => true)); + Log::info('UPDATE WPMU_PLUGIN_URL ' . Log::v2str($urlMuPlugins)); + } + } + + protected function htaccessUpdate() + { + self::logSectionHeader('HTACCESS UPDATE', __FUNCTION__, __LINE__); + // make sure dbConnection is initialized + $this->dbConnection(); + + DUPX_ServerConfig::setup($this->dbh, PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW)); + } + + protected function updateBlogName() + { + $paramsManager = PrmMng::getInstance(); + + $escapedOptionTable = mysqli_real_escape_string($this->dbh, DUPX_DB_Functions::getOptionsTableName()); + $escapedBlogName = htmlspecialchars($paramsManager->getValue(PrmMng::PARAM_BLOGNAME), ENT_QUOTES); + $escapedBlogName = mysqli_real_escape_string($this->dbh, $escapedBlogName); + + Log::info('UPATE BLOG NAME ' . Log::v2str($escapedBlogName), Log::LV_DETAILED); + DUPX_DB::mysqli_query( + $this->dbh, + "UPDATE `" . $escapedOptionTable . + "` SET option_value = '" . mysqli_real_escape_string($this->dbh, $escapedBlogName) . + "' WHERE option_name = 'blogname' " + ); + } + + /** + * Update options URLs + * + * @param string $table + * @param string $urlNew + * @param string $siteUrl + * + * @return void + */ + protected function updateOptionsUrls($table, $urlNew, $siteUrl) + { + $paramsManager = PrmMng::getInstance(); + $escapedOptionTable = mysqli_real_escape_string($this->dbh, $table); + + Log::info('UPATE URL NEW ' . Log::v2str($urlNew), Log::LV_DETAILED); + DUPX_DB::mysqli_query( + $this->dbh, + "UPDATE `" . $escapedOptionTable . "` " . + "SET option_value = '" . mysqli_real_escape_string($this->dbh, $urlNew) . "' WHERE option_name = 'home' " + ); + Log::info('UPATE SITE URL ' . Log::v2str($siteUrl), Log::LV_DETAILED); + DUPX_DB::mysqli_query( + $this->dbh, + "UPDATE `" . $escapedOptionTable . "` " . + "SET option_value = '" . mysqli_real_escape_string($this->dbh, $siteUrl) . "' WHERE option_name = 'siteurl' " + ); + + $safeModeVal = mysqli_real_escape_string($this->dbh, $paramsManager->getValue(PrmMng::PARAM_SAFE_MODE)); + DUPX_DB::mysqli_query($this->dbh, "INSERT INTO `" . $escapedOptionTable . "` (option_value, option_name) " + . "VALUES('" . $safeModeVal . "','duplicator_pro_exe_safe_mode')" + . "ON DUPLICATE KEY UPDATE option_value = '" . $safeModeVal . "'"); + } + + /** + * Update post GUID + * + * @param string $table + * @param string $urlNew + * + * @return void + */ + protected function updatePostsGuid($table, $urlNew) + { + $paramsManager = PrmMng::getInstance(); + + //Reset the postguid data + if (!$paramsManager->getValue(PrmMng::PARAM_POSTGUID)) { + return; + } + $escapedPostsTable = mysqli_real_escape_string($this->dbh, $table); + + Log::info('UPATE postguid'); + DUPX_DB::mysqli_query( + $this->dbh, + "UPDATE `" . $escapedPostsTable . "` SET guid = REPLACE(guid, '" . mysqli_real_escape_string($this->dbh, $urlNew) . "', '" . mysqli_real_escape_string( + $this->dbh, + $paramsManager->getValue(PrmMng::PARAM_URL_OLD) + ) . "')" + ); + $update_guid = @mysqli_affected_rows($this->dbh) or 0; + Log::info("Reverted '{$update_guid}' post guid columns back to '" . $paramsManager->getValue(PrmMng::PARAM_URL_OLD) . "'"); + } + + public function generalUpdate() + { + self::logSectionHeader('GENERAL UPDATES', __FUNCTION__, __LINE__); + // make sure dbConnection is initialized + $this->dbConnection(); + + $this->updateBlogName(); + + $paramsManager = PrmMng::getInstance(); + $urlNew = $paramsManager->getValue(PrmMng::PARAM_URL_NEW); + $siteUrl = $paramsManager->getValue(PrmMng::PARAM_SITE_URL); + + $this->updateOptionsUrls( + DUPX_DB_Functions::getOptionsTableName(), + $urlNew, + $siteUrl + ); + $this->updatePostsGuid( + DUPX_DB_Functions::getPostsTableName(), + $urlNew + ); + + $this->managePlugins(); + } + + /** + * + * @return boolean + */ + public function duplicatorMigrationInfoSet() + { + Log::info('MIGRATION INFO SET'); + // make sure dbConnection is initialized + $this->dbConnection(); + + // on main options tables in all installation + $optionTable = mysqli_real_escape_string($this->dbh, DUPX_DB_Functions::getOptionsTableName()); + $migrationData = DUPX_InstallerState::getMigrationData(); + + $query = "REPLACE INTO `" . $optionTable . "` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES " . + "(NULL, '" . self::FIRST_LOGIN_OPTION . "', '1', 'no'), " . + "(NULL, '" . self::MIGRATION_DATA_OPTION . "', '" . mysqli_real_escape_string($this->dbh, SnapJson::jsonEncodePPrint($migrationData)) . "', 'no');"; + + if (DUPX_DB::mysqli_query($this->dbh, $query) === false) { + $errMsg = "DATABASE ERROR \"" . mysqli_error($this->dbh) . "\"
          [sql=" . substr($query, 0, DUPX_DBInstall::QUERY_ERROR_LOG_LEN) . "...]"; + DUPX_NOTICE_MANAGER::getInstance()->addBothNextAndFinalReportNotice(array( + 'shortMsg' => 'UPDATE MIRATION INFO ISSUE', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $errMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database' + )); + + return false; + } else { + return true; + } + } + + public function generalCleanup() + { + self::logSectionHeader('GENERAL CLEANUP', __FUNCTION__, __LINE__); + // make sure dbConnection is initialized + $this->dbConnection(); + $paramsManager = PrmMng::getInstance(); + + if (!DUPX_UpdateEngine::updateTablePrefixKeys()) { + // @todo display erorr on notice manager + } + } + + /** + * activate and deactivate plugins + * + * @return void + */ + protected function managePlugins() + { + self::logSectionHeader("MANAGE PLUGINS", __FUNCTION__, __LINE__); + $paramsManager = PrmMng::getInstance(); + + try { + $pluginsManager = DUPX_Plugins_Manager::getInstance(); + $pluginsManager->setActions($paramsManager->getValue(PrmMng::PARAM_PLUGINS)); + $pluginsManager->executeActions($this->dbConnection()); + } catch (Exception $e) { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'Plugins settings error ' . $e->getMessage(), + 'level' => DUPX_NOTICE_ITEM::CRITICAL, + 'longMsg' => $e->getTraceAsString(), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE, + 'sections' => 'general' + )); + + Log::info("PLUGIN MANAGER EXCEPTIOMN\n" . $e->getTraceAsString()); + } + } + + /** + * checks for index.html in root, and if found, issues a soft warning + * + * @return void + */ + public function checkForIndexHtml() + { + self::logSectionHeader('CHECK FOR INDEX.HTML', __FUNCTION__, __LINE__); + + //scan for index.html + if (file_exists(PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . '/index.html')) { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $nManager->addFinalReportNotice( + array( + 'shortMsg' => 'An index.html was found.', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => 'An index.html was found in the existing site. You may need to manually remove it for the new site to work.', + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT, + 'sections' => 'general' + ) + ); + + Log::info("AN INDEX.HTML WAS FOUND IN THE ROOT OF THE INSTALLATION."); + } else { + Log::info("NO INDEX.HTML WAS FOUND"); + } + } + + public function noticeTest() + { + self::logSectionHeader('NOTICES TEST', __FUNCTION__, __LINE__); + // make sure dbConnection is initialized + $this->dbConnection(); + $optonsTable = mysqli_real_escape_string($this->dbh, DUPX_DB_Functions::getOptionsTableName()); + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + //Database + $result = DUPX_DB::mysqli_query( + $this->dbh, + "SELECT option_value FROM `" . $optonsTable . "` WHERE option_name IN ('upload_url_path','uploadPath')" + ); + if ($result) { + while ($row = mysqli_fetch_row($result)) { + if (strlen($row[0])) { + $msg = "MEDIA SETTINGS NOTICE: The table '" . $optonsTable . "' has at least one the following values ['upload_url_path','uploadPath'] \n"; + $msg .= "set please validate settings. These settings can be changed in the wp-admin by going to /wp-admin/options.php'"; + + $this->report['warnlist'][] = $msg; + Log::info($msg); + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'Media settings notice', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $msg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE, + 'sections' => 'general' + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_UPDATE, 'media-settings-notice'); + + break; + } + } + } + + if (empty($this->report['warnlist'])) { + Log::info("No General Notices Found\n"); + } + } + + public function cleanupTmpFiles() + { + self::logSectionHeader('CLEANUP TMP FILES', __FUNCTION__, __LINE__); + + //Cleanup any tmp files a developer may have forgotten about + //Lets be proactive for the developer just in case + $pathNew = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW); + $wpconfig_path_bak = $pathNew . "/wp-config.bak"; + $wpconfig_path_old = $pathNew . "/wp-config.old"; + $wpconfig_path_org = $pathNew . "/wp-config.org"; + $wpconfig_path_orig = $pathNew . "/wp-config.orig"; + $wpconfig_safe_check = array($wpconfig_path_bak, $wpconfig_path_old, $wpconfig_path_org, $wpconfig_path_orig); + foreach ($wpconfig_safe_check as $file) { + if (file_exists($file)) { + $tmp_newfile = $file . uniqid('_'); + if (rename($file, $tmp_newfile) === false) { + Log::info("WARNING: Unable to rename '{$file}' to '{$tmp_newfile}'"); + } + } + } + } + + public function setFilePermsission() + { + self::logSectionHeader('SET PARAMS PERMISSION', __FUNCTION__, __LINE__); + DUP_Extraction::setFolderPermissionAfterExtraction(); + } + + public function finalReportNotices() + { + self::logSectionHeader('FINAL REPORT NOTICES', __FUNCTION__, __LINE__); + + $this->wpConfigFinalReport(); + $this->htaccessFinalReport(); + } + + private function htaccessFinalReport() + { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + $origHtaccessPath = DUPX_Orig_File_Manager::getInstance()->getEntryStoredPath(DUPX_ServerConfig::CONFIG_ORIG_FILE_HTACCESS_ID); + if ($origHtaccessPath === false || ($orig = file_get_contents($origHtaccessPath)) === false) { + $orig = 'Original .htaccess file doesn\'t exist'; + } + + $targetHtaccessPath = DUPX_ServerConfig::getHtaccessTargetPath(); + if (!file_exists($targetHtaccessPath) || ($new = file_get_contents($targetHtaccessPath)) === false) { + $new = 'New .htaccess file doesn\'t exist'; + } + + $lightBoxContent = '
          ' . + '
          Original .htaccess
          ' . htmlspecialchars($orig) . '
          ' . + '
          New .htaccess
          ' . htmlspecialchars($new) . '
          ' . + '
          '; + $longMsg = DUPX_U_Html::getLigthBox('.htaccess changes', 'HTACCESS COMPARE', $lightBoxContent, false); + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'htaccess changes', + 'level' => DUPX_NOTICE_ITEM::INFO, + 'longMsg' => $longMsg, + 'sections' => 'changes', + 'open' => true, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'htaccess-changes'); + } + + private function wpConfigFinalReport() + { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $wpConfigPath = DUPX_Orig_File_Manager::getInstance()->getEntryStoredPath(DUPX_ServerConfig::CONFIG_ORIG_FILE_WPCONFIG_ID); + + if ($wpConfigPath === false || ($orig = file_get_contents($wpConfigPath)) === false) { + $orig = 'Can\'t read origin wp-config.php file'; + } else { + $orig = $this->obscureWpConfig($orig); + } + + $wpConfigFile = DUPX_WPConfig::getWpConfigPath(); + if (!is_readable($wpConfigFile)) { + $new = 'Can read wp-config.php file'; + } elseif (($new = file_get_contents($wpConfigFile)) === false) { + $new = 'Can read wp-config.php file'; + } else { + $new = $this->obscureWpConfig($new); + } + + $lightBoxContent = '
          ' . + '
          Original wp-config.php
          ' . htmlspecialchars($orig) . '
          ' . + '
          New wp-config.php
          ' . htmlspecialchars($new) . '
          ' . + '
          '; + $longMsg = DUPX_U_Html::getLigthBox('wp-config.php changes', 'WP-CONFIG.PHP COMPARE', $lightBoxContent, false); + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'wp-config.php changes', + 'level' => DUPX_NOTICE_ITEM::INFO, + 'longMsg' => $longMsg, + 'sections' => 'changes', + 'open' => true, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'wp-config-changes'); + } + + private function obscureWpConfig($src) + { + $transformer = new WPConfigTransformerSrc($src); + $obsKeys = array( + 'DB_NAME', + 'DB_USER', + 'DB_HOST', + 'DB_PASSWORD', + 'AUTH_KEY', + 'SECURE_AUTH_KEY', + 'LOGGED_IN_KEY', + 'NONCE_KEY', + 'AUTH_SALT', + 'SECURE_AUTH_SALT', + 'LOGGED_IN_SALT', + 'NONCE_SALT' + ); + + foreach ($obsKeys as $key) { + if ($transformer->exists('constant', $key)) { + $transformer->update('constant', $key, '**OBSCURED**'); + } + } + + return $transformer->getSrc(); + } + + public function chunkStop($progressPerc, $position) + { + $this->closeDbConnection(); + + $ajax3_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $this->timeStart); + Log::info("\nSTEP-3 CHUNK STOP @ " . @date('h:i:s') . " - RUNTIME: {$ajax3_sum} \n\n"); + + $this->report['chunk'] = 1; + $this->report['chunkPos'] = $position; + $this->report['pass'] = 0; + $this->report['progress_perc'] = $progressPerc; + } + + public function complete() + { + $this->closeDbConnection(); + + $paramsManager = PrmMng::getInstance(); + + $ajax3_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $this->timeStart); + Log::info("\nSTEP-3 COMPLETE @ " . @date('h:i:s') . " - RUNTIME: {$ajax3_sum} \n\n"); + + $finalReport = $paramsManager->getValue(PrmMng::PARAM_FINAL_REPORT_DATA); + + $finalReport['replace']['scan_tables'] = $this->report['scan_tables']; + $finalReport['replace']['scan_rows'] = $this->report['scan_rows']; + $finalReport['replace']['scan_cells'] = $this->report['scan_cells']; + $finalReport['replace']['updt_tables'] = $this->report['updt_tables']; + $finalReport['replace']['updt_rows'] = $this->report['updt_rows']; + $finalReport['replace']['updt_cells'] = $this->report['updt_cells']; + $finalReport['replace']['errsql'] = $this->report['errsql']; + $finalReport['replace']['errser'] = $this->report['errser']; + $finalReport['replace']['errkey'] = $this->report['errkey']; + $finalReport['replace']['errsql_sum'] = $this->report['errsql_sum']; + $finalReport['replace']['errser_sum'] = $this->report['errser_sum']; + $finalReport['replace']['errkey_sum'] = $this->report['errkey_sum']; + $finalReport['replace']['err_all'] = $this->report['err_all']; + $finalReport['replace']['warn_all'] = $this->report['warn_all']; + $finalReport['replace']['warnlist'] = $this->report['warnlist']; + + $paramsManager->setValue(PrmMng::PARAM_FINAL_REPORT_DATA, $finalReport); + $paramsManager->save(); + + $this->report['pass'] = 1; + $this->report['chunk'] = 0; + $this->report['chunkPos'] = null; + $this->report['progress_perc'] = 100; + // error_reporting($ajax3_error_level); + } +} diff --git a/installer/dup-installer/ctrls/classes/class.ctrl.s4.php b/installer/dup-installer/ctrls/classes/class.ctrl.s4.php new file mode 100644 index 00000000..3a9d418f --- /dev/null +++ b/installer/dup-installer/ctrls/classes/class.ctrl.s4.php @@ -0,0 +1,140 @@ +sortFinalReport(); + } + + public static function getNoticesCount() + { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + return array( + 'general' => $nManager->countFinalReportNotices('general', DUPX_NOTICE_ITEM::NOTICE, '>='), + 'files' => $nManager->countFinalReportNotices('files', DUPX_NOTICE_ITEM::NOTICE, '>='), + 'database' => $nManager->countFinalReportNotices('database', DUPX_NOTICE_ITEM::NOTICE, '>'), + 'search_replace' => $nManager->countFinalReportNotices('search_replace', DUPX_NOTICE_ITEM::NOTICE, '>='), + 'plugins' => $nManager->countFinalReportNotices('plugins', DUPX_NOTICE_ITEM::NOTICE, '>=') + ); + } + + protected static function finalReportDatabase() + { + $paramsManager = PrmMng::getInstance(); + $finalReportData = $paramsManager->getValue(PrmMng::PARAM_FINAL_REPORT_DATA); + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $logLink = DUPX_View_Funcs::installerLogLink(false); + $faqUrl = LinkManager::getDocUrl('how-to-fix-database-write-issues', 'final-report', 'How to Fix Database Write Issues'); + + if ($finalReportData['extraction']['query_errs'] > 0) { + $longMsg = <<
          + +COMMON FIXES: + +LONGMSG; + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'DB EXTRACTION - INSTALL NOTICES (' . $finalReportData['extraction']['query_errs'] . ')', + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => array('database'), + 'priority' => 5, + 'open' => true + )); + } + + if ($finalReportData['replace']['errsql_sum'] > 0) { + $longMsg = <<addFinalReportNotice(array( + 'shortMsg' => 'STEP 3 - UPDATE NOTICES (' . $finalReportData['replace']['errsql_sum'] . ')', + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'longMsg' => $longMsg, + 'sections' => array('database'), + 'priority' => 5, + 'open' => true + )); + } + + if ($finalReportData['replace']['errkey_sum'] > 0) { + $longMsg = <<
          + + Advanced Searching:
          + Use the following query to locate the table that was not updated:
          + SELECT @row := @row + 1 as row, t.* FROM some_table t, (SELECT @row := 0) r +
          +LONGMSG; + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'TABLE KEY NOTICES (' . $finalReportData['replace']['errkey_sum'] . ')', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => array('database'), + 'priority' => 5, + 'open' => true + )); + } + } + + protected static function finalReportSearchReplace() + { + $paramsManager = PrmMng::getInstance(); + $finalReportData = $paramsManager->getValue(PrmMng::PARAM_FINAL_REPORT_DATA); + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + if ($finalReportData['replace']['errser_sum'] > 0) { + $longMsg = <<addFinalReportNotice(array( + 'shortMsg' => 'SERIALIZATION NOTICES (' . $finalReportData['replace']['errser_sum'] . ')', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => $longMsg, + 'sections' => array('search_replace'), + 'priority' => 5, + 'open' => true + )); + } + } +} diff --git a/installer/dup-installer/ctrls/ctrl.base.php b/installer/dup-installer/ctrls/ctrl.base.php new file mode 100644 index 00000000..e08abb04 --- /dev/null +++ b/installer/dup-installer/ctrls/ctrl.base.php @@ -0,0 +1,237 @@ +report = new DUPX_CTRL_Report(); + $this->payload = null; + $this->startProcessTime(); + } + + public function startProcessTime() + { + $this->timeStart = $this->microtimeFloat(); + } + + public function getProcessTime() + { + $this->timeEnd = $this->microtimeFloat(); + $this->report->runTime = $this->timeEnd - $this->timeStart; + return $this->report->runTime; + } + + private function microtimeFloat() + { + list($usec, $sec) = explode(" ", microtime()); + return ((float) $usec + (float) $sec); + } +} + +class DUPX_CTRL +{ + const ACTION_STEP_INIZIALIZED = 'initialized'; + const ACTION_STEP_ON_VALIDATE = 'on-validate'; + const ACTION_STEP_SET_TEMPLATE = 'settpm'; +/** + * + * @var self + */ + protected static $instance = null; +/** + * + * @var bool|string + */ + protected $pageView = false; +/** + * + * @var array + */ + protected $extraParamsPage = array(); +/** + * + * @return self + */ + public static function getInstance() + { + if (is_null(self::$instance)) { + self::$instance = new self(); + } + return self::$instance; + } + + private function __construct() + { + } + + public function mainController() + { + $paramsManager = PrmMng::getInstance(); + $ctrlAction = $paramsManager->getValue(PrmMng::PARAM_CTRL_ACTION); + $stepAction = $paramsManager->getValue(PrmMng::PARAM_STEP_ACTION); + Log::info("\n" . '---------------', Log::LV_DETAILED); + Log::info('CONTROLLER ACTION: ' . Log::v2str($ctrlAction), Log::LV_DETAILED); + if (!empty($stepAction)) { + Log::info('STEP ACTION: ' . Log::v2str($stepAction)); + } + Log::info('---------------' . "\n", Log::LV_DETAILED); + DUPX_Template::getInstance()->setTemplate(PrmMng::getInstance()->getValue(PrmMng::PARAM_TEMPLATE)); + if (Bootstrap::isInit()) { + if (!DUPX_Ctrl_Params::setParamsStep0()) { + Log::info('PARAMS AREN\'T VALID', Log::LV_DETAILED); + Log::error('PARAMS AREN\'T VALID'); + } + DUPX_Ctrl_S0::stepHeaderLog(); + } + + if ( + $ctrlAction !== 'help' && + DUPX_Security::getInstance()->getSecurityType() != DUPX_Security::SECURITY_NONE + ) { + Log::info('SECURE CHECK -> GO TO SECURE PAGE'); + $this->pageView = 'secure'; + return; + } + + switch ($ctrlAction) { + case "ctrl-step1": + if ($stepAction === DUPX_CTRL::ACTION_STEP_SET_TEMPLATE) { + $paramsManager->setValueFromInput(PrmMng::PARAM_TEMPLATE); + Log::info('NEW TEMPLATE:' . $paramsManager->getValue(PrmMng::PARAM_TEMPLATE)); + $paramsManager->save(); + DUPX_Template::getInstance()->setTemplate($paramsManager->getValue(PrmMng::PARAM_TEMPLATE)); + } + $this->pageView = 'step1'; + break; + case "ctrl-step2": + $this->pageView = 'step2'; + break; + case "ctrl-step3": + $this->pageView = 'step3'; + break; + case "ctrl-step4": + DUPX_Ctrl_S4::updateFinalReport(); + $this->pageView = 'step4'; + break; + case "help": + $this->pageView = 'help'; + break; + default: + Log::error('No valid action request ' . $ctrlAction); + } + } + + public function setExceptionPage(Exception $e) + { + Log::info("--------------------------------------"); + Log::info('EXCEPTION: ' . $e->getMessage()); + Log::info('TRACE:'); + Log::info($e->getTraceAsString()); + Log::info("--------------------------------------"); + $this->extraParamsPage['exception'] = $e; + $this->pageView = 'exception'; + } + + public function renderPage() + { + Log::logTime('RENDER PAGE ' . Log::v2str($this->pageView), Log::LV_DETAILED); + $echo = false; + $paramsManager = PrmMng::getInstance(); + $this->extraParamsPage['bodyClasses'] = 'template_' . $paramsManager->getValue(PrmMng::PARAM_TEMPLATE); + if ($paramsManager->getValue(PrmMng::PARAM_DEBUG_PARAMS)) { + $this->extraParamsPage['bodyClasses'] .= ' debug-params'; + } + + switch ($this->pageView) { + case 'secure': + $result = dupxTplRender('page-secure', $this->extraParamsPage, $echo); + break; + case 'step1': + $result = dupxTplRender('page-step1', $this->extraParamsPage, $echo); + break; + case 'step2': + $result = dupxTplRender('page-step2', $this->extraParamsPage, $echo); + break; + case 'step3': + $result = dupxTplRender('page-step3', $this->extraParamsPage, $echo); + break; + case 'step4': + $result = dupxTplRender('page-step4', $this->extraParamsPage, $echo); + DUPX_NOTICE_MANAGER::getInstance()->finalReportLog( + array('general', 'files', 'database', 'search_replace', 'plugins') + ); + break; + case 'exception': + $result = dupxTplRender('page-exception', $this->extraParamsPage, $echo); + break; + case 'help': + $result = dupxTplRender('page-help', $this->extraParamsPage, $echo); + break; + case false: + // no page + break; + default: + Log::error('No valid render page ' . Log::v2str($this->pageView)); + } + Log::logTime('END RENDER PAGE'); + return self::renderPostProcessings($result); + } + + public static function renderPostProcessings($string) + { + return str_replace(array( + DUPX_Package::getArchiveFileHash(), + DUPX_Package::getPackageHash()), '[HASH]', $string); + } +} diff --git a/installer/dup-installer/ctrls/index.php b/installer/dup-installer/ctrls/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/installer/dup-installer/ctrls/index.php @@ -0,0 +1,3 @@ + + + + + + #ffc40d + + + diff --git a/installer/dup-installer/favicon/pro01_android-chrome-192x192.png b/installer/dup-installer/favicon/pro01_android-chrome-192x192.png new file mode 100644 index 00000000..5a53ec64 Binary files /dev/null and b/installer/dup-installer/favicon/pro01_android-chrome-192x192.png differ diff --git a/installer/dup-installer/favicon/pro01_android-chrome-256x256.png b/installer/dup-installer/favicon/pro01_android-chrome-256x256.png new file mode 100644 index 00000000..890596da Binary files /dev/null and b/installer/dup-installer/favicon/pro01_android-chrome-256x256.png differ diff --git a/installer/dup-installer/favicon/pro01_apple-touch-icon.png b/installer/dup-installer/favicon/pro01_apple-touch-icon.png new file mode 100644 index 00000000..1d675060 Binary files /dev/null and b/installer/dup-installer/favicon/pro01_apple-touch-icon.png differ diff --git a/installer/dup-installer/favicon/pro01_favicon-16x16.png b/installer/dup-installer/favicon/pro01_favicon-16x16.png new file mode 100644 index 00000000..45951823 Binary files /dev/null and b/installer/dup-installer/favicon/pro01_favicon-16x16.png differ diff --git a/installer/dup-installer/favicon/pro01_favicon-32x32.png b/installer/dup-installer/favicon/pro01_favicon-32x32.png new file mode 100644 index 00000000..f5d420fd Binary files /dev/null and b/installer/dup-installer/favicon/pro01_favicon-32x32.png differ diff --git a/installer/dup-installer/favicon/pro01_favicon.ico b/installer/dup-installer/favicon/pro01_favicon.ico new file mode 100644 index 00000000..4575c3c7 Binary files /dev/null and b/installer/dup-installer/favicon/pro01_favicon.ico differ diff --git a/installer/dup-installer/favicon/pro01_mstile-150x150.png b/installer/dup-installer/favicon/pro01_mstile-150x150.png new file mode 100644 index 00000000..f12abe14 Binary files /dev/null and b/installer/dup-installer/favicon/pro01_mstile-150x150.png differ diff --git a/installer/dup-installer/favicon/pro01_safari-pinned-tab.svg b/installer/dup-installer/favicon/pro01_safari-pinned-tab.svg new file mode 100644 index 00000000..c8967554 --- /dev/null +++ b/installer/dup-installer/favicon/pro01_safari-pinned-tab.svg @@ -0,0 +1,40 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + + diff --git a/installer/dup-installer/favicon/site.webmanifest b/installer/dup-installer/favicon/site.webmanifest new file mode 100644 index 00000000..b73d6e26 --- /dev/null +++ b/installer/dup-installer/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/dup-installer/favicon/pro01_android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/dup-installer/favicon/pro01_android-chrome-256x256.png", + "sizes": "256x256", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/installer/dup-installer/index.php b/installer/dup-installer/index.php new file mode 100644 index 00000000..674e2371 --- /dev/null +++ b/installer/dup-installer/index.php @@ -0,0 +1,4 @@ + $ex->getMessage(), + 'trace' => $ex->getTraceAsString() + )); + die(); +} + +ob_start(); +try { + $controller = DUPX_CTRL::getInstance(); + $exceptionError = false; + // Log::error thotw an exception + Log::setThrowExceptionOnError(true); + Log::logTime('CONTROLLER START', Log::LV_DETAILED); + + $controller->mainController(); +} catch (Exception $e) { + SnapUtil::obCleanAll(false); + $controller->setExceptionPage($e); +} + +/** + * clean output + */ +$unespectOutput = trim(ob_get_clean()); +ob_end_clean(); +if (!empty($unespectOutput)) { + Log::info('ERROR: Unespect output ' . Log::v2str($unespectOutput)); + $exceptionError = new Exception('Unespected output ' . Log::v2str($unespectOutput)); + $controller->setExceptionPage($exceptionError); +} + +ob_start(); +try { + echo $controller->renderPage(); +} catch (Exception $e) { + SnapUtil::obCleanAll(false); + ob_end_clean(); + $controller->setExceptionPage($e); + echo $controller->renderPage(); +} diff --git a/installer/dup-installer/src/.htaccess b/installer/dup-installer/src/.htaccess new file mode 100644 index 00000000..a58990b7 --- /dev/null +++ b/installer/dup-installer/src/.htaccess @@ -0,0 +1,9 @@ + + Order Deny,Allow + Deny from all + + + + Order Allow,Deny + Allow from all + \ No newline at end of file diff --git a/installer/dup-installer/src/Core/Addons/InstAbstractAddonCore.php b/installer/dup-installer/src/Core/Addons/InstAbstractAddonCore.php new file mode 100644 index 00000000..dc7da0c5 --- /dev/null +++ b/installer/dup-installer/src/Core/Addons/InstAbstractAddonCore.php @@ -0,0 +1,254 @@ +addonData = self::getInitAddonData($reflect->getShortName()); + } + + /** + * Function called on addon init only if is avaiable + * + * @return void + */ + abstract public function init(); + + /** + * Get main addon file path + * + * @return string + */ + public static function getAddonFile() + { + // To prevent the warning about static abstract functions that appears in PHP 5.4/5.6 I use this trick. + throw new \Exception('this function have to overwritte on child class'); + } + + /** + * Get main addon folder + * + * @return string + */ + public static function getAddonPath() + { + // To prevent the warning about static abstract functions that appears in PHP 5.4/5.6 I use this trick. + throw new \Exception('this function have to overwritte on child class'); + } + + /** + * Get slug of current addon + * + * @return string + */ + public function getSlug() + { + return $this->addonData['slug']; + } + + /** + * True if current addon is avaiable + * + * @return boolean + */ + public function canEnable() + { + if (version_compare(PHP_VERSION, $this->addonData['requiresPHP'], '<')) { + return false; + } + + if (version_compare(DUPX_VERSION, $this->addonData['requiresDuplcator'], '<')) { + return false; + } + + return true; + } + + /** + * True if addon has dependencies + * + * @return boolean + */ + public function hasDependencies() + { + $avaliableAddons = InstAddonsManager::getInstance()->getAvaiableAddons(); + return !array_diff($this->addonData['requiresAddons'], $avaliableAddons); + } + + /** + * Get addon data from header addon file + * + * @param string $class addon class + * + * @return array + */ + protected static function getInitAddonData($class) + { + $data = self::getFileFata(static::getAddonFile(), self::getDefaltHeaders()); + $getDefaultVal = self::getDefaultHeadersValues(); + + foreach ($data as $key => $val) { + if (strlen($val) === 0) { + $data[$key] = $getDefaultVal[$key]; + } + } + + if (!is_array($data['requiresAddons'])) { + $data['requiresAddons'] = explode(',', $data['requiresAddons']); + } + $data['requiresAddons'] = array_map('trim', $data['requiresAddons']); + + $data['slug'] = $class; + if (strlen($data['name']) === 0) { + $data['name'] = $data['slug']; + } + return $data; + } + + /** + * Retur default addon date headers + * + * @return array + */ + protected static function getDefaultHeadersValues() + { + static $defaultHeaders = null; + if (is_null($defaultHeaders)) { + $defaultHeaders = array( + 'name' => '', + 'addonURI' => '', + 'version' => '0', + 'description' => '', + 'author' => '', + 'authorURI' => '', + 'requiresWP' => '4.0', + 'requiresPHP' => '5.3', + 'requiresDuplcator' => '4.0.2', + 'requiresAddons' => array() + ); + } + return $defaultHeaders; + } + + /** + * Return headers list keys + * + * @return array + */ + protected static function getDefaltHeaders() + { + return array( + 'name' => 'Name', + 'addonURI' => 'Addon URI', + 'version' => 'Version', + 'description' => 'Description', + 'author' => 'Author', + 'authorURI' => 'Author URI', + 'requiresWP' => 'Requires WordPress min version', + 'requiresPHP' => 'Requires PHP', + 'requiresDuplcator' => 'Requires Duplicator min version', + 'requiresAddons' => 'Requires addons' + ); + } + + /** + * Retrieve metadata from a file. + * + * Searches for metadata in the first 8 KB of a file, such as a plugin or theme. + * Each piece of metadata must be on its own line. Fields can not span multiple + * lines, the value will get cut at the end of the first line. + * + * If the file data is not within that first 8 KB, then the author should correct + * their plugin file and move the data headers to the top. + * + * from wordpress get_file_data function + * + * @param string $file Absolute path to the file. + * @param array $defaultHeaders List of headers, in the format `array( 'HeaderKey' => 'Header Name' )`. + * + * @return array Array of file headers in `HeaderKey => Header Value` format. + */ + protected static function getFileFata($file, $defaultHeaders) + { + // We don't need to write to the file, so just open for reading. + $fp = fopen($file, 'r'); + + // Pull only the first 8 KB of the file in. + $file_data = fread($fp, 8 * KB_IN_BYTES); + + // PHP will close file handle, but we are good citizens. + fclose($fp); + + // Make sure we catch CR-only line endings. + $file_data = str_replace("\r", "\n", $file_data); + $all_headers = $defaultHeaders; + + foreach ($all_headers as $field => $regex) { + if (preg_match('/^[ \t\/*#@]*' . preg_quote($regex, '/') . ':(.*)$/mi', $file_data, $match) && $match[1]) { + $all_headers[$field] = self::cleanupHeaderComment($match[1]); + } else { + $all_headers[$field] = ''; + } + } + + return $all_headers; + } + + /** + * Strip close comment and close php tags from file headers used by WP. + * + * From wordpress _cleanup_header_comment + * + * @param string $str Header comment to clean up. + * + * @return string + */ + protected static function cleanupHeaderComment($str) + { + return trim(preg_replace('/\s*(?:\*\/|\?>).*/', '', $str)); + } +} diff --git a/installer/dup-installer/src/Core/Addons/InstAddonsManager.php b/installer/dup-installer/src/Core/Addons/InstAddonsManager.php new file mode 100644 index 00000000..e37638c7 --- /dev/null +++ b/installer/dup-installer/src/Core/Addons/InstAddonsManager.php @@ -0,0 +1,178 @@ +addons = self::getAddonListFromFolder(); + } + + /** + * inizialize all abaiblae addons + * + * @return void + */ + public function inizializeAddons() + { + foreach ($this->addons as $addon) { + if ($addon->canEnable() && $addon->hasDependencies()) { + $this->addonsEnabled[] = $addon->getSlug(); + $addon->init(); + Log::info('ADDON ' . $addon->getAddonFile() . ' ENABLED', Log::LV_DETAILED); + } else { + Log::info('CAN\'T ENABLE ADDON ' . $addon->getSlug()); + } + } + HooksMng::getInstance()->doAction('duplicator_addons_loaded'); + } + + /** + * + * @return InstAbstractAddonCore[] + */ + public function getAvaiableAddons() + { + $result = array(); + foreach ($this->addons as $addon) { + $result[] = $addon->getSlug(); + } + + return $result; + } + + /** + * + * @return InstAbstractAddonCore[] + */ + public function getEnabledAddons() + { + return $this->enabledAddons; + } + + /** + * return addons folder + * + * @return string + */ + public static function getAddonsPath() + { + return DUPX_INIT . '/addons'; + } + + /** + * + * @return InstAbstractAddonCore[] + */ + private static function getAddonListFromFolder() + { + $addonList = array(); + + $checkDir = SnapIO::trailingslashit(self::getAddonsPath()); + + if (!is_dir($checkDir)) { + return array(); + } + + if (($dh = opendir($checkDir)) == false) { + return array(); + } + + while (($elem = readdir($dh)) !== false) { + if ($elem === '.' || $elem === '..') { + continue; + } + + $fullPath = $checkDir . $elem; + $addonMainFile = false; + + if (!is_dir($fullPath)) { + continue; + } + + if (($addonDh = opendir($fullPath)) == false) { + continue; + } + + while (($addonElem = readdir($addonDh)) !== false) { + if ($addonElem === '.' || $addonElem === '..') { + continue; + } + $info = pathinfo($fullPath . '/' . $addonElem); + + if (strcasecmp($elem, $info['filename']) === 0) { + $addonMainFile = $checkDir . $elem . '/' . $addonElem; + $addonMainClass = 'Duplicator\\Installer\\Addons\\' . $info['filename'] . '\\' . $info['filename']; + break; + } + } + + if (empty($addonMainFile)) { + continue; + } + + try { + if (!is_subclass_of($addonMainClass, 'Duplicator\\Installer\\Core\\Addons\\InstAbstractAddonCore')) { + continue; + } + } catch (\Exception $e) { + Log::info('Addon file ' . $addonMainFile . ' exists but not countain addon main core class, Exception: ' . $e->getMessage()); + continue; + } catch (\Error $e) { + Log::info('Addon file ' . $addonMainFile . ' exists but generate an error, Exception: ' . $e->getMessage()); + continue; + } + + $addonObj = $addonMainClass::getInstance(); + $addonList[$addonObj->getSlug()] = $addonObj; + } + closedir($dh); + + return $addonList; + } +} diff --git a/installer/dup-installer/src/Core/Bootstrap.php b/installer/dup-installer/src/Core/Bootstrap.php new file mode 100644 index 00000000..f20928d7 --- /dev/null +++ b/installer/dup-installer/src/Core/Bootstrap.php @@ -0,0 +1,539 @@ +inizializeAddons(); + // init templates + self::templatesInit(); + // SECURITY CHECK + \DUPX_Security::getInstance()->check(); + // init error handler after constant + LogHandler::initErrorHandler(); + + // init params + PrmMng::getInstance()->initParams(); + + // read params from request and init global value + self::initInstallerFiles(); + + // check custom hosts + \DUPX_Custom_Host_Manager::getInstance()->init(); + + $pathInfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ''; + Log::info("\n\n" + . "==============================================\n" + . "= BOOT INIT OK [" . $pathInfo . "]\n" + . "==============================================\n", Log::LV_DETAILED); + + if (Log::isLevel(Log::LV_DEBUG)) { + Log::info('-------------------'); + Log::info('PARAMS'); + Log::info(PrmMng::getInstance()->getParamsToText()); + Log::info('-------------------'); + } + + \DUPX_DB_Tables::getInstance(); + } + + /** + * Init ini_set and default constants + * + * @return void + */ + public static function phpIni() + { + /* Absolute path to the Installer directory. - necessary for php protection */ + if (!defined('KB_IN_BYTES')) { + define('KB_IN_BYTES', 1024); + } + if (!defined('MB_IN_BYTES')) { + define('MB_IN_BYTES', 1024 * KB_IN_BYTES); + } + if (!defined('GB_IN_BYTES')) { + define('GB_IN_BYTES', 1024 * MB_IN_BYTES); + } + if (!defined('DUPLICATOR_PHP_MAX_MEMORY')) { + define('DUPLICATOR_PHP_MAX_MEMORY', 4096 * MB_IN_BYTES); + } + + date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here. + @ignore_user_abort(true); + + @set_time_limit(3600); + + $defaultCharset = ini_get("default_charset"); + if (empty($defaultCharset) && SnapUtil::isIniValChangeable('default_charset')) { + @ini_set("default_charset", 'utf-8'); + } + if (SnapUtil::isIniValChangeable('memory_limit')) { + @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY); + } + if (SnapUtil::isIniValChangeable('max_input_time')) { + @ini_set('max_input_time', '-1'); + } + if (SnapUtil::isIniValChangeable('pcre.backtrack_limit')) { + @ini_set('pcre.backtrack_limit', PHP_INT_MAX); + } + + //PHP INI SETUP: all time in seconds + if (!isset($GLOBALS['DUPX_ENFORCE_PHP_INI']) || !$GLOBALS['DUPX_ENFORCE_PHP_INI']) { + if (SnapUtil::isIniValChangeable('mysql.connect_timeout')) { + @ini_set('mysql.connect_timeout', '5000'); + } + if (SnapUtil::isIniValChangeable('max_execution_time')) { + @ini_set("max_execution_time", '5000'); + } + if (SnapUtil::isIniValChangeable('max_input_time')) { + @ini_set("max_input_time", '5000'); + } + if (SnapUtil::isIniValChangeable('default_socket_timeout')) { + @ini_set('default_socket_timeout', '5000'); + } + @set_time_limit(0); + } + } + + /** + * Include default utils files and constants + * + * @return void + */ + public static function includes() + { + require_once(DUPX_INIT . '/vendor/requests/library/Requests.php'); + \Requests::register_autoloader(); + + require_once(DUPX_INIT . '/classes/config/class.conf.wp.php'); + require_once(DUPX_INIT . '/classes/utilities/class.u.exceptions.php'); + require_once(DUPX_INIT . '/classes/utilities/class.u.php'); + require_once(DUPX_INIT . '/classes/utilities/class.u.notices.manager.php'); + require_once(DUPX_INIT . '/classes/utilities/template/class.u.template.manager.php'); + require_once(DUPX_INIT . '/classes/utilities/class.u.orig.files.manager.php'); + require_once(DUPX_INIT . '/classes/validation/class.validation.manager.php'); + require_once(DUPX_INIT . '/classes/config/class.security.php'); + require_once(DUPX_INIT . '/classes/plugins/class.plugins.manager.php'); + require_once(DUPX_INIT . '/classes/class.password.php'); + require_once(DUPX_INIT . '/classes/database/class.db.php'); + require_once(DUPX_INIT . '/classes/database/class.db.functions.php'); + require_once(DUPX_INIT . '/classes/database/class.db.tables.php'); + require_once(DUPX_INIT . '/classes/database/class.db.table.item.php'); + require_once(DUPX_INIT . '/classes/class.http.php'); + require_once(DUPX_INIT . '/classes/class.crypt.php'); + require_once(DUPX_INIT . '/classes/class.csrf.php'); + require_once(DUPX_INIT . '/classes/class.package.php'); + require_once(DUPX_INIT . '/classes/class.server.php'); + require_once(DUPX_INIT . '/classes/rest/class.rest.php'); + require_once(DUPX_INIT . '/classes/rest/class.rest.auth.php'); + require_once(DUPX_INIT . '/classes/config/class.archive.config.php'); + require_once(DUPX_INIT . '/classes/config/class.constants.php'); + require_once(DUPX_INIT . '/classes/config/class.conf.utils.php'); + require_once(DUPX_INIT . '/classes/class.installer.state.php'); + require_once(DUPX_INIT . '/ctrls/classes/class.ctrl.ajax.php'); + require_once(DUPX_INIT . '/ctrls/classes/class.ctrl.params.php'); + require_once(DUPX_INIT . '/ctrls/ctrl.base.php'); + require_once(DUPX_INIT . '/ctrls/classes/class.ctrl.extraction.php'); + require_once(DUPX_INIT . '/ctrls/classes/class.ctrl.dbinstall.php'); + require_once(DUPX_INIT . '/ctrls/classes/class.ctrl.s3.funcs.php'); + require_once(DUPX_INIT . '/classes/view-helpers/class.u.html.php'); + require_once(DUPX_INIT . '/classes/view-helpers/class.view.php'); + require_once(DUPX_INIT . '/classes/host/class.custom.host.manager.php'); + require_once(DUPX_INIT . '/classes/config/class.conf.srv.php'); + require_once(DUPX_INIT . '/classes/class.engine.php'); + } + + /** + * This function moves the error_log.php into the dup-installer directory. + * It is called before including any other file so it uses only native PHP functions. + * + * !!! Don't use any Duplicator function within this function. !!! + * + * @param bool $reset if true reset log file + * + * @return boolean + */ + public static function initPhpErrorLog($reset = false) + { + if (!function_exists('ini_set')) { + return false; + } + + $logFile = DUPX_INIT . '/php_error__' . self::getPackageHash() . '.log'; + + if (file_exists($logFile)) { + if (!is_writable($logFile)) { + return false; + } elseif ($reset && function_exists('unlink')) { + @unlink($logFile); + } + } + + if (function_exists('error_reporting')) { + error_reporting(E_ALL | E_STRICT); // E_STRICT for PHP 5.3 + } + + @ini_set("log_errors", 1); + if (@ini_set("error_log", $logFile) === false) { + return false; + } + + if (!file_exists($logFile)) { + error_log("PHP ERROR LOG INIT"); + } + + return true; + } + + /** + * It is called before including any other file so it uses only native PHP functions. + * + * !!! Don't use any Duplicator function within this function. !!! + * + * @return bool|string package hash or false if fail + */ + public static function getPackageHash() + { + static $packageHash = null; + if (is_null($packageHash)) { + $searchStr = DUPX_INIT . '/' . self::ARCHIVE_PREFIX . '*' . self::ARCHIVE_EXTENSION; + $config_files = glob($searchStr); + if (empty($config_files)) { + $packageHash = false; + } else { + $config_file_absolute_path = array_pop($config_files); + $config_file_name = basename($config_file_absolute_path, self::ARCHIVE_EXTENSION); + $packageHash = substr($config_file_name, strlen(self::ARCHIVE_PREFIX)); + } + } + return $packageHash; + } + + /** + * This function init all params before read from request + * + * @return void + */ + protected static function initParamsBase() + { + // GET PARAMS FROM REQUEST + \DUPX_Ctrl_Params::setParamsBase(); + + // set log level from params + Log::setLogLevel(); + Log::setPostProcessCallback(array('DUPX_CTRL', 'renderPostProcessings')); + Log::setAfterFatalErrorCallback(function () { + if (\DUPX_InstallerState::getInstance()->getMode() === \DUPX_InstallerState::MODE_OVR_INSTALL) { + \DUPX_U::maintenanceMode(false); + } + }); + + $paramsManager = PrmMng::getInstance(); + $GLOBALS['DUPX_DEBUG'] = $paramsManager->getValue(PrmMng::PARAM_DEBUG); + } + + /** + * Makes sure no caching mechanism is used during install + * + * @return void + */ + protected static function setHTTPHeaders() + { + header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } + + /** + * Init log header + * + * @return void + */ + protected static function initLogs() + { + if (!chdir(DUPX_INIT)) { + // RSR TODO: Can't change directories + throw new \Exception("Can't change to directory " . DUPX_INIT); + } + + //Restart log if user starts from step 0 + if (self::isInit()) { + self::initPhpErrorLog(true); + Log::clearLog(); + Log::info("********************************************************************************"); + Log::info('* DUPLICATOR LITE: Install-Log'); + Log::info('* STEP-0 START @ ' . @date('h:i:s')); + Log::info('* NOTICE: Do NOT post to public sites or forums!!'); + Log::info("********************************************************************************"); + } + } + + /** + * Init all installer files + * + * @return void + */ + protected static function initInstallerFiles() + { + if (!chdir(DUPX_INIT)) { + // RSR TODO: Can't change directories + throw new \Exception("Can't change to directory " . DUPX_INIT); + } + + //Restart log if user starts from step 0 + if (self::isInit()) { + self::logHeader(); + \DUPX_NOTICE_MANAGER::getInstance()->resetNotices(); + + // LOAD PARAMS AFTER LOG RESET + $paramManager = PrmMng::getInstance(); + $paramManager->load(true); + \DUPX_Orig_File_Manager::getInstance()->init(false); + try { + \DUPX_Orig_File_Manager::getInstance()->restoreAll(array( + \DUPX_ServerConfig::CONFIG_ORIG_FILE_USERINI_ID, + \DUPX_ServerConfig::CONFIG_ORIG_FILE_PHPINI_ID, + \DUPX_ServerConfig::CONFIG_ORIG_FILE_WEBCONFIG_ID, + \DUPX_ServerConfig::CONFIG_ORIG_FILE_HTACCESS_ID, + \DUPX_ServerConfig::CONFIG_ORIG_FILE_WPCONFIG_ID + )); + } catch (\Exception $e) { + Log::logException($e, 'CANT RESTORE CONFIG FILES FORM PREVISION INSTALLATION'); + \DUPX_NOTICE_MANAGER::getInstance()->addNextStepNotice(array( + 'shortMsg' => 'The installer cannot restore files from a previous installation. ', + 'longMsg' => 'This problem does not affect the current installation so you can continue.
          ' + . 'This can happen if the root folder does not have write permissions.', + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'level' => \DUPX_NOTICE_ITEM::NOTICE + )); + } + + self::initParamsBase(); + + \DUP_Extraction::resetData(); + \DUPX_DBInstall::resetData(); + \DUPX_S3_Funcs::resetData(); + + // update state only if isn't set by param overwrite + \DUPX_InstallerState::getInstance()->checkState(true, false); + // On init remove maintenance mode + \DUPX_U::maintenanceMode(false); + } else { + // INIT PARAMS + $paramManager = PrmMng::getInstance(); + $paramManager->load(); + \DUPX_Orig_File_Manager::getInstance()->init(false); + + self::initParamsBase(); + } + + $paramManager->save(); + } + + /** + * Write log header + * + * @return void + */ + protected static function logHeader() + { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + $colSize = 60; + $labelPadSize = 20; + $os = defined('PHP_OS') ? PHP_OS : 'unknown'; + + $log = ''; + $log .= str_pad( + str_pad('PACKAGE INFO', $labelPadSize, '_', STR_PAD_RIGHT) . ' ' . 'ORIGINAL SERVER', + $colSize, + ' ', + STR_PAD_RIGHT + ) . '|' . 'CURRENT SERVER' . "\n"; + $log .= str_pad( + str_pad('OS', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->version_os, + $colSize, + ' ', + STR_PAD_RIGHT + ) . '|' . $os . "\n"; + $log .= str_pad( + str_pad('PHP VERSION', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $archiveConfig->version_php, + $colSize, + ' ', + STR_PAD_RIGHT + ) . '|' . phpversion() . "\n"; + $log .= "********************************************************************************"; + Log::info($log, Log::LV_DEFAULT); + + Log::info("CURRENT SERVER INFO"); + Log::info(str_pad('PHP', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . phpversion() . ' | SAPI: ' . php_sapi_name()); + Log::info(str_pad('PHP MEMORY', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $GLOBALS['PHP_MEMORY_LIMIT'] . ' | SUHOSIN: ' . $GLOBALS['PHP_SUHOSIN_ON']); + Log::info(str_pad('ARCHITECTURE', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . SnapUtil::getArchitectureString()); + Log::info(str_pad('SERVER', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . $_SERVER['SERVER_SOFTWARE']); + Log::info(str_pad('DOC ROOT', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str(DUPX_ROOT)); + Log::info(str_pad('REQUEST URL', $labelPadSize, '_', STR_PAD_RIGHT) . ': ' . Log::v2str(DUPX_ROOT_URL)); + Log::info("********************************************************************************"); + } + + /** + * return true if is the first installer call from installer.php + * + * @return bool + */ + public static function isInit() + { + // don't use param manager because isn't initialized + $isFirstStep = isset($_REQUEST[PrmMng::PARAM_CTRL_ACTION]) && $_REQUEST[PrmMng::PARAM_CTRL_ACTION] === "ctrl-step1"; + $isInitialized = isset($_REQUEST[PrmMng::PARAM_STEP_ACTION]) && !empty($_REQUEST[PrmMng::PARAM_STEP_ACTION]); + return $isFirstStep && !$isInitialized; + } + + /** + * This function disables the shutdown function defined in the boot class + * + * @return void + */ + public static function disableBootShutdownFunction() + { + self::$shutdownFunctionEnaled = false; + } + + /** + * This function sets the shutdown function before the installer is initialized. + * Prevents blank pages. + * + * After the plugin is initialized it will be set as a shudwon ​​function LogHandler::shutdown + * + * !!! Don't use any Duplicator function within this function. !!! + * + * @return void + */ + public static function bootShutdown() + { + if (!self::$shutdownFunctionEnaled) { + return; + } + + if (($error = error_get_last())) { + ?> +

          BOOT SHUTDOWN FATAL ERROR

          +
          + =')) { + return true; + } + $match = null; + if (preg_match("#^\d+(\.\d+)*#", PHP_VERSION, $match)) { + $phpVersion = $match[0]; + } else { + $phpVersion = PHP_VERSION; + } + // no html + echo 'This server is running PHP: ' . $phpVersion . '. A minimum of PHP ' . self::MINIMUM_PHP_VERSION . ' is required to run the installer.' + . ' Contact your hosting provider or server administrator and let them know you would like to upgrade your PHP version.'; + die(); + } + + /** + * Init templates + * + * @return void + */ + protected static function templatesInit() + { + $tpl = \DUPX_Template::getInstance(); + + $tpl->addTemplate(\DUPX_Template::TEMPLATE_BASE, DUPX_INIT . '/templates/base', \DUPX_Template::TEMPLATE_ADVANCED); + $tpl->addTemplate(\DUPX_Template::TEMPLATE_IMPORT_ADVANCED, DUPX_INIT . '/templates/import-advanced', \DUPX_Template::TEMPLATE_ADVANCED); + $tpl->addTemplate(\DUPX_Template::TEMPLATE_IMPORT_BASE, DUPX_INIT . '/templates/import-base', \DUPX_Template::TEMPLATE_IMPORT_ADVANCED); + + $tpl->setTemplate(\DUPX_Template::TEMPLATE_ADVANCED); + } +} diff --git a/installer/dup-installer/src/Core/Deploy/Database/DbCleanup.php b/installer/dup-installer/src/Core/Deploy/Database/DbCleanup.php new file mode 100644 index 00000000..3c5096fa --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/Database/DbCleanup.php @@ -0,0 +1,334 @@ +getValue(PrmMng::PARAM_DB_VIEW_CREATION)) { + self::dropViews(); + Log::info("\t- VIEWS DROPPED"); + } else { + Log::info("\t- SKIP DROP VIEWS"); + } + + if (!$paramsManager->getValue(PrmMng::PARAM_DB_PROC_CREATION)) { + self::dropProcs(); + Log::info("\t- PROCS DROPPED"); + } else { + Log::info("\t- SKIP DROP PROCS"); + } + + if (!$paramsManager->getValue(PrmMng::PARAM_DB_FUNC_CREATION)) { + self::dropFuncs(); + Log::info("\t- FUNCS DROPPED"); + } else { + Log::info("\t- SKIP DROP FUNCS"); + } + } + + /** + * Cleanup packages + * + * @return void + */ + public static function cleanupPackages() + { + if (DUPX_InstallerState::isRestoreBackup()) { + Log::info("REMOVE CURRENT PACKAGE IN BACKUP"); + self::deletePackageInBackup(); + } else { + Log::info("EMPTY PACKAGES TABLE"); + self::emptyDuplicatorPackages(); + } + } + + /** + * Cleanup options tables (remove transientes ..) + * + * @return int return number of items deleted + */ + public static function cleanupOptions() + { + if (DUPX_InstallerState::isRestoreBackup()) { + return; + } + + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + $optionsTableList = array(); + $deleteOptionConds = array(); + + $optionsTableList[] = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getOptionsTableName()); + $deleteOptionConds[] = '`option_name` = "duplicator_plugin_data_stats"'; + $deleteOptionConds[] = '`option_name` LIKE "\_transient%"'; + $deleteOptionConds[] = '`option_name` LIKE "\_site\_transient%"'; + + $opts_delete = array(); + foreach ($archiveConfig->opts_delete as $value) { + $opts_delete[] = '"' . mysqli_real_escape_string($dbh, $value) . '"'; + } + if (count($opts_delete) > 0) { + $deleteOptionConds[] = '`option_name` IN (' . implode(',', $opts_delete) . ')'; + } + + $count = 0; + foreach ($optionsTableList as $optionsTable) { + $log = "CLEAN OPTIONS [" . $optionsTable . "]"; + foreach ($deleteOptionConds as $cond) { + $log .= "\n\t" . $cond; + } + Log::info($log); + $count += DUPX_DB::chunksDelete($dbh, $optionsTable, implode(' OR ', $deleteOptionConds)); + Log::info(sprintf('DATABASE OPTIONS DELETED [ROWS:%6d]', $count)); + } + return $count; + } + + /** + * Delete current package in backup + * + * @return void + */ + protected static function deletePackageInBackup() + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $packageId = DUPX_ArchiveConfig::getInstance()->packInfo->packageId; + Log::info("CLEANUP CURRENT PACKAGE STATUS ID " . $packageId); + + $packagesTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getPackagesTableName()); + $optionsTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getOptionsTableName()); + DUPX_DB::mysqli_query($dbh, 'DELETE FROM `' . $packagesTable . '` WHERE `id` = ' . $packageId); + DUPX_DB::mysqli_query($dbh, "DELETE FROM `" . $optionsTable . "` WHERE `option_name` = 'duplicator_package_active'"); + } + + /** + * Empty duplicator packages table + * + * @return int return number of packages deleted + */ + protected static function emptyDuplicatorPackages() + { + Log::info("CLEAN PACKAGES"); + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $packagesTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getPackagesTableName()); + $count = DUPX_DB::chunksDelete($dbh, $packagesTable, '1 = 1'); + Log::info('DATABASE PACKAGE DELETED [ROWS:' . str_pad($count, 6, " ", STR_PAD_LEFT) . ']'); + return$count; + } + + + /** + * Drop db procedures + * + * @return void + */ + public static function dropProcs() + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME); + + $sql = "SHOW PROCEDURE STATUS WHERE db='{$dbName}'"; + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + if (!($result = DUPX_DB::mysqli_query($dbh, $sql))) { + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'PROCEDURE CLEAN ERROR: ' . mysqli_error($dbh), + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to get list of PROCEDURES from database "%s".', $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + )); + + Log::info("PROCEDURE CLEAN ERROR: Could not get list of PROCEDURES to drop them."); + return; + } + + if ($result->num_rows === 0) { + return; + } + + while ($row = mysqli_fetch_row($result)) { + $proc_name = $row[1]; + $sql = "DROP PROCEDURE IF EXISTS `" . mysqli_real_escape_string($dbh, $dbName) . "`.`" . mysqli_real_escape_string($dbh, $proc_name) . "`"; + if (!DUPX_DB::mysqli_query($dbh, $sql)) { + $err = mysqli_error($dbh); + $nManager->addNextStepNotice(array( + 'shortMsg' => 'PROCEDURE CLEAN ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to remove PROCEDURE "%s" from database "%s".
          ', $proc_name, $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-proc-fail-msg'); + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'PROCEDURE CLEAN ERROR: ' . $err, + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to remove PROCEDURE "%s" from database "%s".', $proc_name, $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + )); + + Log::info("PROCEDURE CLEAN ERROR: '{$err}'\n\t[SQL=" . substr($sql, 0, DUPX_DBInstall::QUERY_ERROR_LOG_LEN) . "...]\n\n"); + } + } + + $nManager->addNextStepNotice(array( + 'shortMsg' => 'PROCEDURE CLEAN ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf(ERR_DROP_PROCEDURE_TRYCLEAN, mysqli_error($dbh)), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-proc-fail-msg'); + } + + /** + * Drop db functions + * + * @return void + */ + public static function dropFuncs() + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME); + + $sql = "SHOW FUNCTION STATUS WHERE db='{$dbName}'"; + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + if (!($result = DUPX_DB::mysqli_query($dbh, $sql))) { + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'FUNCTION CLEAN ERROR: ' . mysqli_error($dbh), + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to get list of FUNCTIONS from database "%s".', $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + )); + + Log::info("FUNCTION CLEAN ERROR: Could not get list of FUNCTIONS to drop them."); + return; + } + + if ($result->num_rows === 0) { + return; + } + + while ($row = mysqli_fetch_row($result)) { + $func_name = $row[1]; + $sql = "DROP FUNCTION IF EXISTS `" . mysqli_real_escape_string($dbh, $dbName) . "`.`" . mysqli_real_escape_string($dbh, $func_name) . "`"; + if (!DUPX_DB::mysqli_query($dbh, $sql)) { + $err = mysqli_error($dbh); + $nManager->addNextStepNotice(array( + 'shortMsg' => 'FUNCTION CLEAN ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to remove FUNCTION "%s" from database "%s".
          ', $func_name, $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-func-fail-msg'); + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'FUNCTION CLEAN ERROR: ' . $err, + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to remove FUNCTION "%s" from database "%s".', $func_name, $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + )); + + Log::info("FUNCTION CLEAN ERROR: '{$err}'\n\t[SQL=" . substr($sql, 0, DUPX_DBInstall::QUERY_ERROR_LOG_LEN) . "...]\n\n"); + } + } + + $nManager->addNextStepNotice(array( + 'shortMsg' => 'FUNCTION CLEAN ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf(ERR_DROP_FUNCTION_TRYCLEAN, mysqli_error($dbh)), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-func-fail-msg'); + } + + /** + * Drop db views + * + * @return void + */ + public static function dropViews() + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME); + + $sql = "SHOW FULL TABLES WHERE Table_Type = 'VIEW'"; + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + if (!($result = DUPX_DB::mysqli_query($dbh, $sql))) { + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'VIEW CLEAN ERROR: ' . mysqli_error($dbh), + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to get list of VIEWS from database "%s"', $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + )); + + Log::info("VIEW CLEAN ERROR: Could not get list of VIEWS to drop them."); + return; + } + + if ($result->num_rows === 0) { + return; + } + + while ($row = mysqli_fetch_row($result)) { + $view_name = $row[0]; + $sql = "DROP VIEW `" . mysqli_real_escape_string($dbh, $dbName) . "`.`" . mysqli_real_escape_string($dbh, $view_name) . "`"; + if (!DUPX_DB::mysqli_query($dbh, $sql)) { + $err = mysqli_error($dbh); + + $nManager->addNextStepNotice(array( + 'shortMsg' => 'VIEW CLEAN ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to remove VIEW "%s" from database "%s".
          ', $view_name, $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-view-fail-msg'); + + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'VIEW CLEAN ERROR: ' . $err, + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf('Unable to remove VIEW "%s" from database "%s"', $view_name, $dbName), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'database', + )); + + Log::info("VIEW CLEAN ERROR: '{$err}'\n\t[SQL=" . substr($sql, 0, DUPX_DBInstall::QUERY_ERROR_LOG_LEN) . "...]\n\n"); + } + } + + $nManager->addNextStepNotice(array( + 'shortMsg' => 'VIEW CLEAN ERROR', + 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => sprintf(ERR_DROP_VIEW_TRYCLEAN, mysqli_error($dbh)), + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-view-fail-msg'); + } +} diff --git a/installer/dup-installer/src/Core/Deploy/Database/DbReplace.php b/installer/dup-installer/src/Core/Deploy/Database/DbReplace.php new file mode 100644 index 00000000..723d278c --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/Database/DbReplace.php @@ -0,0 +1,250 @@ +mainUrlOld = $prmMng->getValue(PrmMng::PARAM_URL_OLD); + $this->mainUrlNew = $prmMng->getValue(PrmMng::PARAM_URL_NEW); + } + + /** + * Set search and replace strings + * + * @return bool + */ + public function setSearchReplace() + { + switch (DUPX_InstallerState::getInstType()) { + case DUPX_InstallerState::INSTALL_SINGLE_SITE: + $this->setGlobalSearchAndReplaceList(); + break; + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN: + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER: + throw new Exception('mode not avaiable'); + case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE: + throw new Exception('Replace engine isn\'t avaiable for restore backup mode'); + case DUPX_InstallerState::INSTALL_NOT_SET: + default: + throw new Exception('Invalid installer mode'); + } + + return true; + } + + /** + * Set global search replace + * + * @return void + */ + private function setGlobalSearchAndReplaceList() + { + $srManager = DUPX_S_R_MANAGER::getInstance(); + $paramsManager = PrmMng::getInstance(); + + // DIRS PATHS + $this->addReplaceEnginePaths($srManager); + + Log::info('GLOBAL SEARCH REPLACE ', Log::LV_DETAILED); + + if ( + !DUPX_InstallerState::isInstallerCreatedInThisLocation() + ) { + $uploadUrlOld = $paramsManager->getValue(PrmMng::PARAM_URL_UPLOADS_OLD); + $uploadUrlNew = $paramsManager->getValue(PrmMng::PARAM_URL_UPLOADS_NEW); + + if (self::checkRelativeAndAbsoluteDiff($this->mainUrlOld, $this->mainUrlNew, $uploadUrlOld, $uploadUrlNew)) { + $srManager->addItem($uploadUrlOld, $uploadUrlNew, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + + $siteUrlOld = $paramsManager->getValue(PrmMng::PARAM_SITE_URL_OLD); + $siteUrlNew = $paramsManager->getValue(PrmMng::PARAM_SITE_URL); + if (self::checkRelativeAndAbsoluteDiff($this->mainUrlOld, $this->mainUrlNew, $siteUrlOld, $siteUrlNew)) { + $srManager->addItem($siteUrlOld, $siteUrlNew, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P3); + } + + $srManager->addItem($this->mainUrlOld, $this->mainUrlNew, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P3); + } + + $pluginsUrlOld = $paramsManager->getValue(PrmMng::PARAM_URL_PLUGINS_OLD); + $pluginsUrlNew = $paramsManager->getValue(PrmMng::PARAM_URL_PLUGINS_NEW); + if ( + $this->forceReplaceSiteSubfolders || + self::checkRelativeAndAbsoluteDiff($this->mainUrlOld, $this->mainUrlNew, $pluginsUrlOld, $pluginsUrlNew) + ) { + $srManager->addItem($pluginsUrlOld, $pluginsUrlNew, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + + $mupluginsUrlOld = $paramsManager->getValue(PrmMng::PARAM_URL_MUPLUGINS_OLD); + $mupluginsUrlNew = $paramsManager->getValue(PrmMng::PARAM_URL_MUPLUGINS_NEW); + if ( + $this->forceReplaceSiteSubfolders || + self::checkRelativeAndAbsoluteDiff($this->mainUrlOld, $this->mainUrlNew, $mupluginsUrlOld, $mupluginsUrlNew) + ) { + $srManager->addItem($mupluginsUrlOld, $mupluginsUrlNew, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + + $contentUrlOld = $paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_OLD); + $contentUrlNew = $paramsManager->getValue(PrmMng::PARAM_URL_CONTENT_NEW); + if ( + $this->forceReplaceSiteSubfolders || + self::checkRelativeAndAbsoluteDiff($this->mainUrlOld, $this->mainUrlNew, $contentUrlOld, $contentUrlNew) + ) { + $srManager->addItem($contentUrlOld, $contentUrlNew, DUPX_S_R_ITEM::TYPE_URL_NORMALIZE_DOMAIN, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P2); + } + + // Replace email address (xyz@oldomain.com to xyz@newdomain.com). + if ($paramsManager->getValue(PrmMng::PARAM_EMAIL_REPLACE)) { + $at_old_domain = '@' . DUPX_U::getDomain($this->mainUrlOld); + $at_new_domain = '@' . DUPX_U::getDomain($this->mainUrlNew); + $srManager->addItem($at_old_domain, $at_new_domain, DUPX_S_R_ITEM::TYPE_STRING, DUPX_UpdateEngine::SR_PRORITY_LOW); + } + } + + /** + * add paths to replace on sear/replace engine + * + * @return void + */ + private function addReplaceEnginePaths() + { + $srManager = DUPX_S_R_MANAGER::getInstance(); + $paramsManager = PrmMng::getInstance(); + if ($paramsManager->getValue(PrmMng::PARAM_SKIP_PATH_REPLACE)) { + return; + } + + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + $originalPaths = $archiveConfig->getRealValue('originalPaths'); + $mainPathOld = $paramsManager->getValue(PrmMng::PARAM_PATH_OLD); + $mainPathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_NEW); + + if ( + !DUPX_InstallerState::isInstallerCreatedInThisLocation() + ) { + $uploadPathOld = $paramsManager->getValue(PrmMng::PARAM_PATH_UPLOADS_OLD); + $uploadPathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_UPLOADS_NEW); + if (self::checkRelativeAndAbsoluteDiff($mainPathOld, $mainPathNew, $uploadPathOld, $uploadPathNew)) { + $srManager->addItem($uploadPathOld, $uploadPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + if ( + $originalPaths->uploads != $uploadPathOld && + self::checkRelativeAndAbsoluteDiff($originalPaths->home, $mainPathNew, $originalPaths->uploads, $uploadPathNew) + ) { + $srManager->addItem($originalPaths->uploads, $uploadPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + + $corePathOld = $paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_OLD); + $corePathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW); + if (self::checkRelativeAndAbsoluteDiff($mainPathOld, $mainPathNew, $corePathOld, $corePathNew)) { + $srManager->addItem($corePathOld, $corePathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P3); + } + if ( + $originalPaths->abs != $corePathOld && + self::checkRelativeAndAbsoluteDiff($originalPaths->home, $mainPathNew, $originalPaths->abs, $corePathNew) + ) { + $srManager->addItem($originalPaths->abs, $corePathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P3); + } + + $srManager->addItem($mainPathOld, $mainPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P3); + if ($originalPaths->home != $mainPathOld) { + $srManager->addItem($originalPaths->home, $mainPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P3); + } + } + + $pluginsPathOld = $paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_OLD); + $pluginsPathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_NEW); + if (self::checkRelativeAndAbsoluteDiff($mainPathOld, $mainPathNew, $pluginsPathOld, $pluginsPathNew)) { + $srManager->addItem($pluginsPathOld, $pluginsPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + if ( + $originalPaths->plugins != $pluginsPathOld && + self::checkRelativeAndAbsoluteDiff($originalPaths->home, $mainPathNew, $originalPaths->plugins, $pluginsPathNew) + ) { + $srManager->addItem($originalPaths->plugins, $pluginsPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + + $mupluginsPathOld = $paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_OLD); + $mupluginsPathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW); + if (self::checkRelativeAndAbsoluteDiff($mainPathOld, $mainPathNew, $mupluginsPathOld, $mupluginsPathNew)) { + $srManager->addItem($mupluginsPathOld, $mupluginsPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + if ( + $originalPaths->muplugins != $mupluginsPathOld && + self::checkRelativeAndAbsoluteDiff($originalPaths->home, $mainPathNew, $originalPaths->muplugins, $mupluginsPathNew) + ) { + $srManager->addItem($originalPaths->muplugins, $mupluginsPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P1); + } + + $contentPathOld = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_OLD); + $contentPathNew = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW); + if (self::checkRelativeAndAbsoluteDiff($mainPathOld, $mainPathNew, $contentPathOld, $contentPathNew)) { + $srManager->addItem($contentPathOld, $contentPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P2); + } + if ( + $originalPaths->wpcontent != $contentPathOld && + self::checkRelativeAndAbsoluteDiff($originalPaths->home, $mainPathNew, $originalPaths->wpcontent, $contentPathNew) + ) { + $srManager->addItem($originalPaths->wpcontent, $contentPathNew, DUPX_S_R_ITEM::TYPE_PATH, DUPX_UpdateEngine::SR_PRORITY_GENERIC_SUBST_P2); + } + } + + /** + * Check if sub path if different + * + * @param string $mainOld main old path + * @param string $mainNew main new path + * @param string $old old sub path + * @param string $new new sub path + * + * @return bool + */ + private static function checkRelativeAndAbsoluteDiff($mainOld, $mainNew, $old, $new) + { + $mainOld = SnapIO::safePath($mainOld); + $mainNew = SnapIO::safePath($mainNew); + $old = SnapIO::safePath($old); + $new = SnapIO::safePath($new); + + $log = "CHECK REL AND ABS DIF\n" . + "\tMAIN OLD: " . Log::v2str($mainOld) . "\n" . + "\tMAIN NEW: " . Log::v2str($mainNew) . "\n" . + "\tOLD: " . Log::v2str($old) . "\n" . + "\tNEW: " . Log::v2str($new); + Log::info($log, Log::LV_DEBUG); + + $isRelativePathDifferent = substr($old, strlen($mainOld)) !== substr($new, strlen($mainNew)); + + if (strpos($old, $mainOld) !== 0 || strpos($new, $mainNew) !== 0 || $isRelativePathDifferent) { + Log::info("\t*** RESULT: TRUE", Log::LV_DEBUG); + return true; + } else { + Log::info("\t*** RESULT: FALSE", Log::LV_DEBUG); + return false; + } + } +} diff --git a/installer/dup-installer/src/Core/Deploy/Database/DbUserMode.php b/installer/dup-installer/src/Core/Deploy/Database/DbUserMode.php new file mode 100644 index 00000000..d2a66aaf --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/Database/DbUserMode.php @@ -0,0 +1,618 @@ +userMode = ParamDescUsers::getUsersMode(); + $this->prefixMetaRegexCheck = '/^' . preg_quote(DUPX_ArchiveConfig::getInstance()->wp_tableprefix, '/') . '(?:(\d+)_)?(.*)$/'; + + switch (DUPX_InstallerState::getInstType()) { + case DUPX_InstallerState::INSTALL_SINGLE_SITE: + $this->addPrefixMetaMapping( + 0, + $prmMng->getValue(PrmMng::PARAM_DB_TABLE_PREFIX) + ); + break; + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN: + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER: + throw new Exception('Invalid mode'); + case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE: + break; + case DUPX_InstallerState::INSTALL_NOT_SET: + throw new Exception('Cannot change setup with current installation type [' . DUPX_InstallerState::getInstType() . ']'); + default: + throw new Exception('Unknown mode'); + } + } + + /** + * Add meta prefix meta mapping + * + * @param int $subsiteId subsite id + * @param string $prefix replace value + * + * @return void + */ + protected function addPrefixMetaMapping($subsiteId, $prefix) + { + Log::info('ADD PREFIX META MAP ID ' . $subsiteId . ' ' . $prefix); + $key = ($subsiteId == 1 ? 0 : $subsiteId); + $this->prefixMetaMapping[$key] = $prefix; + } + + /** + * This function renames the user tables of the target site, also updates the user meta keys + * + * @return void + */ + public static function moveTargetUserTablesOnCurrentPrefix() + { + $paramsManager = PrmMng::getInstance(); + if (ParamDescUsers::getUsersMode() === ParamDescUsers::USER_MODE_OVERWRITE) { + return; + } + + Log::info("\nKEEP TARGET SITE USERS TABLES - USER MODE " . ParamDescUsers::getUsersMode()); + + $dbFunc = DUPX_DB_Functions::getInstance(); + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + + if ($overwriteData['table_prefix'] == $paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)) { + Log::info('TABLE NAMES ARE THE SAME, SO SKIP USERS TABLES RENAME'); + return; + } + + $targetUserTable = DUPX_DB_Functions::getUserTableName($overwriteData['table_prefix']); + $targetUserMetaTable = DUPX_DB_Functions::getUserMetaTableName($overwriteData['table_prefix']); + $currentUserTableName = DUPX_DB_Functions::getUserTableName(); + $currentUserMetaTableName = DUPX_DB_Functions::getUserMetaTableName(); + + $dbFunc->renameTable($targetUserTable, $currentUserTableName, true); + $dbFunc->renameTable($targetUserMetaTable, $currentUserMetaTableName, true); + + // Update table prefix on meta key + DUPX_UpdateEngine::updateTablePrefix( + $dbFunc->dbConnection(), + $currentUserMetaTableName, + 'meta_key', + $overwriteData['table_prefix'], + $paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX) + ); + Log::info("USER TABLES RENAMED"); + } + + /** + * This function removes all meta keys of the current prefix in the usermeta table. + * This is needed to replace them with the meta keys that will be imported + * + * @return void + */ + public function removeAllUserMetaKeysOfCurrentPrefix() + { + $paramsManager = PrmMng::getInstance(); + if ( + ParamDescUsers::getUsersMode() !== ParamDescUsers::USER_MODE_IMPORT_USERS + ) { + return; + } + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + + $loggedInUserId = (int) $overwriteData['loggedUser']['id']; + + foreach ($this->prefixMetaMapping as $overwriteId => $prefix) { + $where = 'user_id != ' . $loggedInUserId; + $escPergPrefix = mysqli_real_escape_string($dbh, SnapDB::quoteRegex($prefix)); + + if ($prefix == $overwriteData['table_prefix']) { + Log::info("\nREMOVE EXISTING USER META KEY WITH PREFIX " . $prefix . ' EXCEPT ' . $prefix . '[0-9]+_'); + // SELECT * FROM `prefix_usermeta` WHERE user_id != 2 AND meta_key REGEXP "^prefix_" AND meta_key NOT REGEXP "^prefix_[0-9]+_" + $where .= ' AND meta_key REGEXP "^' . $escPergPrefix . '" AND meta_key NOT REGEXP "^' . $escPergPrefix . '[0-9]+_"'; + } else { + Log::info("\nREMOVE EXISTING USER META KEY WITH PREFIX " . $prefix); + // SELECT * FROM `prefix_usermeta` WHERE user_id != 2 AND meta_key REGEXP "^prefix_2_" + $where .= ' AND meta_key REGEXP "^' . $escPergPrefix . '"'; + } + + DUPX_DB::chunksDelete($dbh, DUPX_DB_Functions::getUserMetaTableName(), $where); + } + } + + /** + * Filter props on json encode + * + * @return strng[] + */ + public function __sleep() + { + $props = array_keys(get_object_vars($this)); + return array_diff($props, array('targetUsersByMail', 'targetUsersByLogin')); + } + + /** + * Called after json decode + * + * @return void + */ + public function __wakeup() + { + foreach ($this->targetUsersById as $user) { + $this->targetUsersByMail[$user->getMail()] = $user; + $this->targetUsersByLogin[$user->getLogin()] = $user; + } + } + + /** + * Return the list of columns that contain user id to remap in an array( table => numberColumn) + * + * @return int[] + */ + protected static function getTableColIdsToRemap() + { + static $remapTables = null; + if (is_null($remapTables)) { + $remapTables = array(); + + foreach (DUPX_DB_Tables::getInstance()->getTablesByNameWithoutPrefix('posts') as $table) { + $remapTables[$table] = 1; + } + + Log::info('REMAP USERS TABLES/COLUMN ' . Log::v2str($remapTables)); + } + return $remapTables; + } + + /** + * Load from users table the user list + * + * @return void + */ + public function initTargetSiteUsersData() + { + if ($this->userMode !== ParamDescUsers::USER_MODE_IMPORT_USERS) { + return; + } + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + Log::info('INIT IMPORT TARGET USER TABLE DATA'); + + $dbName = mysqli_real_escape_string($dbh, PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME)); + $userTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserTableName()); + + // count num cols of user table, can be different from source to target + $query = 'SELECT count(*) AS num_cols FROM information_schema.columns WHERE table_schema = "' . $dbName . '" AND table_name = "' . $userTable . '"'; + if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) { + $err = mysqli_error($dbh); + throw new Exception('Query error: ' . $err); + } + $row = $queryRes->fetch_array(); + $this->userTableNumCols = (int) $row[0]; + Log::info('USER TABLE COLUMNS COUNT ' . $this->userTableNumCols, Log::LV_DETAILED); + + $query = 'SELECT `ID`,`user_login`,`user_email` FROM `' . $userTable . '`'; + if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) { + $err = mysqli_error($dbh); + throw new Exception('Query error: ' . $err); + } + + $this->usersAutoIncrement = -1; + while ($row = $queryRes->fetch_assoc()) { + $rowId = (int) $row['ID']; + $user = new ImportUser($rowId, $row['user_login'], $row['user_email']); + + $this->targetUsersById[$user->getId()] = $user; + $this->targetUsersByMail[$user->getMail()] = $user; + $this->targetUsersByLogin[$user->getLogin()] = $user; + + if ($rowId > $this->usersAutoIncrement) { + $this->usersAutoIncrement = $rowId; + } + } + $this->usersAutoIncrement ++; + $queryRes->free_result(); + Log::info('EXISTING USERS COUNT ' . count($this->targetUsersById), Log::LV_DETAILED); + Log::info('USERS TABLE AUTOINCREMENT VALUE ' . $this->usersAutoIncrement, Log::LV_DETAILED); + + $this->initTargetSiteUserMetaData(); + } + + /** + * For each existing meta key, a list of IDs is associated with each user who has that key or true if all users have the key + * + * @return void + */ + protected function initTargetSiteUserMetaData() + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + Log::info('INIT IMPORT TARGET USERMETA TABLE DATA'); + + $userTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserTableName()); + $userMetaTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserMetaTableName()); + + $query = 'SELECT max(umeta_id) AS maxId FROM `' . $userMetaTable . '`'; + if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) { + $err = mysqli_error($dbh); + throw new Exception('Query error: ' . $err); + } + $row = $queryRes->fetch_assoc(); + $this->usersMetaAutoIncrement = ((int) $row['maxId']) + 1; + $queryRes->free_result(); + Log::info('USERMETA TABLE AUTOINCREMENT VALUE ' . $this->usersAutoIncrement, Log::LV_DETAILED); + + $query = 'SELECT COUNT(*) FROM `' . $userTable . '`'; + if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) { + $err = mysqli_error($dbh); + throw new Exception('Query error: ' . $err); + } + $row = $queryRes->fetch_array(); + $maxNumIds = $row[0]; + + $query = 'SELECT `meta_key`, IF(COUNT(`user_id`) >= ' . $maxNumIds . ', "ALL", GROUP_CONCAT(`user_id` ORDER BY `user_id` ASC)) AS IDS ' . + 'FROM `' . $userMetaTable . '`' . + 'WHERE `user_id` IN (SELECT `ID` FROM `' . $userTable . '`) GROUP BY meta_key'; + if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) { + $err = mysqli_error($dbh); + throw new Exception('Query error: ' . $err); + } + + while ($row = $queryRes->fetch_assoc()) { + $this->existingsMetaIsd[$row['meta_key']] = ( + ($row['IDS'] === 'ALL') ? + true : + array_map('intval', explode(',', $row['IDS'])) + ); + } + Log::info('NUM META KEYS READ ' . count($this->existingsMetaIsd), Log::LV_DETAILED); + $queryRes->free_result(); + } + + /** + * Apply inser query user fixes + * + * @param string $query query string + * + * @return string if the string is empty no query must be executed + */ + public function applyUsersFixes(&$query) + { + if ($this->userMode == ParamDescUsers::USER_MODE_OVERWRITE) { + return $query; + } + + $matches = array(); + if (preg_match('/^\s*(?:\/\*.*\*\/|#.*\n|--.*\n)?\s*INSERT\s+INTO\s+`?([^\s`]*?)`?\s+VALUES/s', $query, $matches) !== 1) { + return $query; + } + + $tableName = SnapDB::parsedQueryValueToString($matches[1]); + + if ($this->userMode == ParamDescUsers::USER_MODE_IMPORT_USERS) { + if ($tableName == DUPX_DB_Functions::getUserTableName()) { + return $this->getUserTableQueryFix(SnapDB::getValuesFromQueryInsert($query)); + } elseif ($tableName == DUPX_DB_Functions::getUserMetaTableName()) { + return $this->getUserMetaTableQueryFix(SnapDB::getValuesFromQueryInsert($query)); + } + } + + $tablesColRemap = self::getTableColIdsToRemap(); + if (in_array($tableName, array_keys($tablesColRemap))) { + return $this->getTableUserRemapQueryFix( + $tableName, + $tablesColRemap[$tableName], + SnapDB::getValuesFromQueryInsert($query) + ); + } + return $query; + } + + /** + * Generate import final report + * + * @return void + */ + public function generateImportReport() + { + if ($this->userMode !== ParamDescUsers::USER_MODE_IMPORT_USERS) { + return; + } + + $numAdded = 0; + $numChanged = 0; + + if (($fp = fopen(DUPX_INIT . '/' . self::getCsvReportName(), 'w')) === false) { + Log::info('Can\'t open report file ' . DUPX_INIT . '/' . self::getCsvReportName()); + } else { + fputcsv($fp, ImportUser::getArrayReportTitles()); + } + + foreach ($this->targetUsersById as $user) { + if ($user->isAdded()) { + $numAdded++; + } elseif ($user->isChanged()) { + $numChanged++; + } else { + continue; + } + if ($fp != false) { + fputcsv($fp, $user->getArrayReport()); + } + } + + if ($fp != false) { + fclose($fp); + $csvUrl = DUPX_INIT_URL . '/' . self::getCsvReportName(); + } else { + $csvUrl = false; + } + + $longMsg = dupxTplRender( + 'parts/reports/import_report', + array( + 'numAdded' => $numAdded, + 'numChanged' => $numChanged, + 'csvUrl' => $csvUrl + ), + false + ); + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $nManager->addFinalReportNotice( + array( + 'shortMsg' => 'User import report', + 'level' => DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'sections' => 'general' + ) + ); + $nManager->saveNotices(); + } + + /** + * Return csv report file name + * + * @return string + */ + protected static function getCsvReportName() + { + return 'dup-installer-import-report__' . DUPX_Security::getInstance()->getSecondaryPackageHash() . '.csv'; + } + + /** + * Apply query fix for user table + * + * @param array $queryValues two dimensional array where each item is a row containing the list of values + * + * @return string + */ + protected function getUserTableQueryFix($queryValues) + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $resultValues = array(); + $numColsQueryVals = isset($queryValues[0]) ? count($queryValues[0]) : 0; + $colsDeltaDiff = $this->userTableNumCols - $numColsQueryVals; + + foreach ($queryValues as $rowVals) { + $rowId = SnapDB::parsedQueryValueToInt($rowVals[0]); + $rowLogin = SnapDB::parsedQueryValueToString($rowVals[1]); + $rowMail = SnapDB::parsedQueryValueToString($rowVals[4]); + + if (isset($this->targetUsersByMail[$rowMail])) { + $targetUser = $this->targetUsersByMail[$rowMail]; + $targetId = $targetUser->getId(); + $targetLogin = $targetUser->getLogin(); + + if ($rowId != $targetId) { + $targetUser->setOldId($rowId); + $this->mappingIds[$rowId] = $targetId; + } + + if ($rowLogin != $targetLogin) { + $targetUser->setOldLogin($rowLogin); + } + } else { + $rowVals[0] = $targetId = $this->usersAutoIncrement; + $this->usersAutoIncrement ++; + + if ($rowId != $targetId) { + $this->mappingIds[$rowId] = $targetId; + } + + $newLogin = $rowLogin; + $postfixIndex = 0; + while (isset($this->targetUsersByLogin[$newLogin])) { + $postfixIndex++; + $newLogin = $rowLogin . $postfixIndex; + } + if ($rowLogin != $newLogin) { + $rowVals[1] = '"' . mysqli_real_escape_string($dbh, $newLogin) . '"'; + + $niceName = SnapDB::parsedQueryValueToString($rowVals[3]); + $rowVals[3] = '"' . mysqli_real_escape_string($dbh, $niceName) . $postfixIndex . '"'; + + $displayName = SnapDB::parsedQueryValueToString($rowVals[9]); + if ($rowLogin == $displayName) { + $rowVals[9] = '"' . mysqli_real_escape_string($dbh, $newLogin) . '"'; + } + } + + $user = new ImportUser($targetId, $newLogin, $rowMail, $rowId, $rowLogin, true); + $this->targetUsersById[$user->getId()] = $user; + $this->targetUsersByMail[$user->getMail()] = $user; + $this->targetUsersByLogin[$user->getLogin()] = $user; + $this->addedUsers[$user->getOldId()] = true; + + if ($colsDeltaDiff == 0) { + $resultValues[] = $rowVals; + } elseif ($colsDeltaDiff < 0) { + $resultValues[] = array_slice($rowVals, 0, $this->userTableNumCols); + } else { + for ($i = 0; $i < $colsDeltaDiff; $i++) { + $rowVals[] = '"0"'; + } + $resultValues[] = $rowVals; + } + } + } + + if (empty($resultValues)) { + return ''; + } + + return 'INSERT INTO `' . mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserTableName()) . '` ' . + 'VALUES ' . SnapDB::getQueryInsertValuesFromArray($resultValues) . ';'; + } + + /** + * Apply query fix for usermeta table + * + * @param array $queryValues two dimensional array where each item is a row containing the list of values + * + * @return string + */ + protected function getUserMetaTableQueryFix($queryValues) + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + $resultValues = array(); + + // reset value + $user = new ImportUser(-1, '', ''); + + $prefixMatches = null; + foreach ($queryValues as $rowVals) { + try { + $rowUserId = SnapDB::parsedQueryValueToInt($rowVals[1]); + $rowMetakey = SnapDB::parsedQueryValueToString($rowVals[2]); + + if ($user->getId() != $rowUserId) { + $userId = isset($this->mappingIds[$rowUserId]) ? $this->mappingIds[$rowUserId] : $rowUserId; + if (isset($this->targetUsersById[$userId])) { + $user = $this->targetUsersById[$userId]; + } else { + // This happens if there is a meta key that has a user id that does not belong to any user, it is an anomalous thing so it is skipped. + continue; + } + } + + if (preg_match($this->prefixMetaRegexCheck, $rowMetakey, $prefixMatches) === 1) { + $currentId = (int)$prefixMatches[1]; + if (!isset($this->prefixMetaMapping[$currentId])) { + // if the attribute is not of the selected sub-site then it is not inserted in the import + continue; + } + + $rowMetakey = $this->prefixMetaMapping[$currentId] . $prefixMatches[2]; + $rowVals[2] = '"' . mysqli_real_escape_string($dbh, $rowMetakey) . '"'; + } + + if ( + $user->isAdded() || + !isset($this->existingsMetaIsd[$rowMetakey]) || + ( + $this->existingsMetaIsd[$rowMetakey] !== true && + SnapUtil::binarySearch($this->existingsMetaIsd[$rowMetakey], $user->getId()) == false + ) + ) { + $rowVals[0] = $this->usersMetaAutoIncrement; + $this->usersMetaAutoIncrement ++; + $rowVals[1] = $user->getId(); + + if ($rowMetakey == 'nickname') { + // update nickname + $rowMetaValue = SnapDB::parsedQueryValueToString($rowVals[3]); + if ($rowMetaValue == $user->getOldLogin()) { + $rowVals[3] = '"' . mysqli_real_escape_string($dbh, $user->getLogin()) . '"'; + } + } + + $resultValues[] = $rowVals; + } + } catch (Exception $e) { + Log::logException($e, 'Error on parse user meta row'); + } catch (Error $e) { + Log::logException($e, 'Error on parse user meta row'); + } + } + + if (empty($resultValues)) { + return ''; + } + + return 'INSERT INTO `' . mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserMetaTableName()) . + '` VALUES ' . SnapDB::getQueryInsertValuesFromArray($resultValues) . ';'; + } + + /** + * Apply query fix for table/colum user id + * + * @param string $tableName table name + * @param string $colNum column index, 0 is first + * @param array $queryValues two dimensional array where each item is a row containing the list of values + * + * @return void + */ + protected function getTableUserRemapQueryFix($tableName, $colNum, $queryValues) + { + $dbh = DUPX_DB_Functions::getInstance()->dbConnection(); + + for ($i = 0; $i < count($queryValues); $i++) { + $rowUserId = SnapDB::parsedQueryValueToInt($queryValues[$i][$colNum]); + if (isset($this->mappingIds[$rowUserId])) { + $queryValues[$i][$colNum] = $this->mappingIds[$rowUserId]; + } + } + + return 'INSERT INTO `' . mysqli_real_escape_string($dbh, $tableName) . + '` VALUES ' . SnapDB::getQueryInsertValuesFromArray($queryValues) . ';'; + } +} diff --git a/installer/dup-installer/src/Core/Deploy/Database/QueryFixes.php b/installer/dup-installer/src/Core/Deploy/Database/QueryFixes.php new file mode 100644 index 00000000..00a84e24 --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/Database/QueryFixes.php @@ -0,0 +1,302 @@ + array(), + 'replace' => array() + ); + /** @var array */ + protected $tablesPrefixRules = array(); + /** @var string */ + protected $generatorLog = ''; + + /** + * Class constructor + */ + public function __construct() + { + $this->rulesProcAndViews(); + $this->rulesMySQLEngine(); + $this->legacyCharsetAndCollation(); + $this->rulesTableNames(); + } + + /** + * Filter props on json encode + * + * @return string[] + */ + public function __sleep() + { + $props = array_keys(get_object_vars($this)); + return array_diff($props, array('generatorLog')); + } + + /** + * Write rules in log + * + * @return void + */ + public function logRules() + { + if (strlen($this->generatorLog) == 0) { + Log::info('NO GENERAL QUERY FIXES'); + } else { + Log::info('QUERY FIXES'); + Log::info($this->generatorLog); + } + + if (count($this->globalRules['search']) > 0) { + Log::info('QUERY FIXES GLOBAL RULES'); + Log::incIndent(); + foreach ($this->globalRules['search'] as $index => $search) { + Log::info('SEARCH => ' . $search); + Log::info('REPLACE => ' . $this->globalRules['replace'][$index] . "\n"); + } + Log::resetIndent(); + } + + if (count($this->tablesPrefixRules) > 0) { + Log::info('QUERY FIXES TABLES RULES'); + Log::incIndent(); + foreach ($this->tablesPrefixRules as $indexRulesSet => $ruleSet) { + Log::info('RULESET ' . ($indexRulesSet + 1)); + Log::incIndent(); + foreach ($ruleSet['search'] as $index => $search) { + Log::info('SEARCH => ' . $search); + Log::info('REPLACE => ' . $ruleSet['replace'][$index] . "\n"); + } + Log::decIndent(); + } + Log::resetIndent(); + } + } + + /** + * @param string $query query to fix + * + * @return string The query with appropriate substitutions done + */ + public function applyFixes($query) + { + $query = preg_replace($this->globalRules['search'], $this->globalRules['replace'], $query); + + foreach ($this->tablesPrefixRules as $ruleSet) { + $query = preg_replace($ruleSet['search'], $ruleSet['replace'], $query); + } + return $query; + } + + /** + * Set search and replace rules + * + * @return void + */ + protected function rulesProcAndViews() + { + if (DUPX_InstallerState::isRestoreBackup()) { + return; + } + + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_REMOVE_DEFINER)) { + $this->globalRules['search'][] = self::USER_DEFINER_REMOVE_PATTERN; + $this->globalRules['replace'][] = self::USER_DEFINER_REMOVE_REPLACE; + } else { + $this->globalRules['search'][] = self::USER_DEFINER_REPLACE_PATTERN; + + $dbHost = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_HOST); + $dbUser = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_USER); + + $definerHost = (($dbHost == "localhost" || $dbHost == "127.0.0.1") ? $dbHost : '%'); + $this->globalRules['replace'][] = '$1' . addcslashes("`" . $dbUser . "`@`" . $definerHost . "`", '\\$') . '$3'; + } + + $this->globalRules['search'][] = self::SQL_SECURITY_INVOKER_PATTERN; + $this->globalRules['replace'][] = self::SQL_SECURITY_INVOKER_REPLACE; + + $this->generatorLog .= "GLOBAL RULES ADDED: PROC AND VIEWS\n"; + } + + /** + * Check invalid SQL engines + * + * @return void + */ + protected function rulesMySQLEngine() + { + $invalidEngines = array_map(function ($engine) { + return preg_quote($engine, '/'); + }, DUPX_ArchiveConfig::getInstance()->invalidEngines()); + + if (empty($invalidEngines)) { + return; + } + $this->globalRules['search'][] = '/^(\s*(?:\/\*!\d+\s)?\s*CREATE.+ENGINE=)(' . implode('|', $invalidEngines) . ')(.*)$/ms'; + $this->globalRules['replace'][] = '$1' . DUPX_DB_Functions::getInstance()->getDefaultEngine() . '$3'; + + $this->generatorLog .= "GLOBAL RULES ADDED: MYSQL ENGINES\n"; + } + + /** + * Set legacy charset adn collation rules + * + * regex managed examples + * - `meta_value` longtext CHARACTER SET utf16 COLLATE utf16_slovak_ci DEFAULT NULL, + * - `comment_author` tinytext COLLATE utf8mb4_unicode_ci NOT NULL, + * - ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci_test; + * - ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4; + * + * accept ['"`]charset['"`] + * + * @return void + */ + public function legacyCharsetAndCollation() + { + $invalidCharsets = DUPX_ArchiveConfig::getInstance()->invalidCharsets(); + $invalidCollations = DUPX_ArchiveConfig::getInstance()->invalidCollations(); + $defCharsetRegex = addcslashes(DUPX_DB_Functions::getInstance()->getRealCharsetByParam(), '\\$'); + $defCollateRegex = addcslashes(DUPX_DB_Functions::getInstance()->getRealCollateByParam(), '\\$'); + + if (count($invalidCharsets) > 0) { + $invalidChrRegex = '(?:' . implode('|', array_map(function ($val) { + return preg_quote($val, '/'); + }, $invalidCharsets)) . ')'; + + $this->globalRules['search'][] = '/(^.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)(' . + $invalidChrRegex . ')([`\'"]?\s.*COLLATE\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?.*$)/m'; + $this->globalRules['replace'][] = '$1' . $defCharsetRegex . '$3' . $defCollateRegex . '$5'; + $this->globalRules['search'][] = '/(^.*COLLATE\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?\s.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)(' . + $invalidChrRegex . ')([`\'"]?[\s;,].*$)/m'; + $this->globalRules['replace'][] = '$1' . $defCollateRegex . '$3' . $defCharsetRegex . '$5'; + $this->globalRules['search'][] = '/(^.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)(' . $invalidChrRegex . ')([`\'"]?[\s;,].*$)/m'; + $this->globalRules['replace'][] = '$1' . $defCharsetRegex . '$3'; + + $this->generatorLog .= "GLOBAL RULES ADDED: INVALID CHARSETS\n"; + } + + if (count($invalidCollations) > 0) { + $invalidColRegex = '(?:' . implode('|', array_map(function ($val) { + return preg_quote($val, '/'); + }, $invalidCollations)) . ')'; + + $this->globalRules['search'][] = '/(^.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?\s.*COLLATE\s*[\s=]\s*[`\'"]?)(' . + $invalidColRegex . ')([`\'"]?[\s;,].*$)/m'; + $this->globalRules['replace'][] = '$1' . $defCharsetRegex . '$3' . $defCollateRegex . '$5'; + $this->globalRules['search'][] = '/(^.*COLLATE\s*[\s=]\s*[`\'"]?)(' . + $invalidColRegex . ')([`\'"]?\s.*(?:CHARSET|CHARACTER SET)\s*[\s=]\s*[`\'"]?)([^`\'"\s;,]+)([`\'"]?.*$)/m'; + $this->globalRules['replace'][] = '$1' . $defCollateRegex . '$3' . $defCharsetRegex . '$5'; + $this->globalRules['search'][] = '/(^.*COLLATE\s*[\s=]\s*[`\'"]?)(' . $invalidColRegex . ')([`\'"]?[\s;,].*$)/m'; + $this->globalRules['replace'][] = '$1' . $defCollateRegex . '$3'; + + $this->generatorLog .= "GLOBAL RULES ADDED: INVALID COLLATIONS\n"; + } + } + + /** + * Set search and replace table prefix rules + * + * @return void + */ + protected function rulesTableNames() + { + $mapping = DUPX_DB_Tables::getInstance()->getRenameTablesMapping(); + + $oldPrefixes = array_keys($mapping); + $newPrefixes = array(); + foreach ($mapping as $oldPrefix => $newMapping) { + $newPrefixes = array_merge($newPrefixes, array_keys($newMapping)); + } + $newPrefixes = array_unique($newPrefixes); + + // Prevent double transformation with temp prefix + $doublePrefixes = array_intersect($oldPrefixes, $newPrefixes); + if (count($doublePrefixes) > 0) { + $this->generatorLog .= 'DOUBLE PREFIXES ' . Log::v2str($doublePrefixes); + } + + foreach ($mapping as $oldPrefix => $newMapping) { + $rulesSet = array( + 'search' => array(), + 'replace' => array() + ); + + $quoteOldPrefix = preg_quote($oldPrefix, '/'); + + foreach ($newMapping as $newPrefix => $commons) { + $this->generatorLog .= "TABLES RULES ADDED: CHANGE TABLES PREFIX " . $oldPrefix . " TO " . $newPrefix ; + if (in_array($newPrefix, $doublePrefixes)) { + $this->generatorLog .= " [USE TMP PREFIX]\n"; + $newPrefix = $newPrefix . self::TEMP_POSTFIX; + } else { + $this->generatorLog .= "\n"; + } + $this->generatorLog .= "\tFOR TABLES " . implode(',', $commons) . "\n"; + + $quoteNewPrefix = addcslashes($newPrefix, '\\$'); + $quoteCommons = array_map( + function ($val) { + return preg_quote($val, '/'); + }, + $commons + ); + + for ($i = 0; $i < ceil(count($quoteCommons) / DUPX_DBInstall::TABLES_REGEX_CHUNK_SIZE); $i++) { + $subArray = array_slice($quoteCommons, $i * DUPX_DBInstall::TABLES_REGEX_CHUNK_SIZE, DUPX_DBInstall::TABLES_REGEX_CHUNK_SIZE); + + if (count($subArray) == 0) { + break; + } + + $rulesSet['search'][] = '/' . $quoteOldPrefix . '(' . implode('|', $subArray) . ')/m'; + $rulesSet['replace'][] = $quoteNewPrefix . '$1'; + } + + $rulesSet['search'][] = '/(CONSTRAINT[\s\t]+[`\'"]?.+)(?-i)' . $quoteOldPrefix . '(?i)(.+[`\'"]?[\s\t]+FOREIGN[\s\t]+KEY)/mi'; + $rulesSet['replace'][] = '$1' . $quoteNewPrefix . '$2'; + } + + if (count($rulesSet['search']) > 0) { + $this->tablesPrefixRules[] = $rulesSet; + } + } + + if (count($doublePrefixes)) { + // REMOVE TEMP PREFIXES + $rulesSet = array( + 'search' => array(), + 'replace' => array() + ); + + foreach ($doublePrefixes as $prefix) { + $quoteTempPrefix = preg_quote($prefix . self::TEMP_POSTFIX, '/'); + $quotePrefix = addcslashes($prefix, '\\$'); + + $rulesSet['search'][] = '/' . $quoteTempPrefix . '/m'; + $rulesSet['replace'][] = $quotePrefix . '$1'; + } + + $this->tablesPrefixRules[] = $rulesSet; + } + } +} diff --git a/installer/dup-installer/src/Core/Deploy/DupArchive/Daws.php b/installer/dup-installer/src/Core/Deploy/DupArchive/Daws.php new file mode 100644 index 00000000..f92b3975 --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/DupArchive/Daws.php @@ -0,0 +1,196 @@ +lockFile = DUPX_INIT . '/dup-installer-dawslock__' . DUPX_Package::getPackageHash() . '.bin'; + $this->cancelFile = DUPX_INIT . '/dup-installer-dawscancel__' . DUPX_Package::getPackageHash() . '.bin'; + } + + /** + * Failure callback + * + * @param callable $callback callback + * + * @return void + */ + public function setFailureCallBack($callback) + { + if (is_callable($callback)) { + $this->failureCallback = $callback; + } + } + + /** + * Extract dup archvie + * + * @param array $params dup archvie params + * + * @return stdClass + */ + public function processRequest($params) + { + $retVal = new stdClass(); + + $retVal->pass = false; + + $action = $params['action']; + + $initializeState = false; + + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + if (!DupArchiveFileProcessor::setNewFilePathCallback(array($archiveConfig, 'destFileFromArchiveName'))) { + Log::info('ERROR: CAN\'T SET THE PATH SE CALLBACK FUNCTION'); + } else { + Log::info('PATH SE CALLBACK FUNCTION OK ', Log::LV_DEBUG); + } + + $throttleDelayInMs = SnapUtil::getArrayValue($params, 'throttle_delay', false, 0); + + if ($action == 'start_expand') { + Log::info('DAWN START EXPAND'); + + $initializeState = true; + + DawsExpandState::purgeStatefile(); + SnapIO::rm($this->cancelFile); + $archiveFilepath = SnapUtil::getArrayValue($params, 'archive_filepath'); + $restoreDirectory = SnapUtil::getArrayValue($params, 'restore_directory'); + $workerTime = SnapUtil::getArrayValue($params, 'worker_time', false, self::DEFAULT_WORKER_TIME); + $filteredDirectories = SnapUtil::getArrayValue($params, 'filtered_directories', false, array()); + $excludedDirWithoutChilds = SnapUtil::getArrayValue($params, 'excludedDirWithoutChilds', false, array()); + $filteredFiles = SnapUtil::getArrayValue($params, 'filtered_files', false, array()); + $fileRenames = SnapUtil::getArrayValue($params, 'fileRenames', false, array()); + $fileModeOverride = SnapUtil::getArrayValue($params, 'file_mode_override', false, 0644); + $includedFiles = SnapUtil::getArrayValue($params, 'includedFiles', false, array()); + $directoryModeOverride = SnapUtil::getArrayValue($params, 'dir_mode_override', false, 0755); + $keepFileTime = SnapUtil::getArrayValue($params, 'keep_file_time', false, false); + + $action = 'expand'; + } else { + Log::info('DAWN CONTINUE EXPAND'); + } + + if ($action == 'expand') { + $expandState = DawsExpandState::getInstance($initializeState); + + $this->lock_handle = SnapIO::fopen($this->lockFile, 'c+'); + SnapIO::flock($this->lock_handle, LOCK_EX); + + if ($initializeState || $expandState->working) { + if ($initializeState) { + $expandState->archivePath = $archiveFilepath; + $expandState->working = true; + $expandState->timeSliceInSecs = $workerTime; + $expandState->basePath = $restoreDirectory; + $expandState->filteredDirectories = $filteredDirectories; + $expandState->excludedDirWithoutChilds = $excludedDirWithoutChilds; + $expandState->includedFiles = $includedFiles; + $expandState->filteredFiles = $filteredFiles; + $expandState->fileRenames = $fileRenames; + $expandState->fileModeOverride = $fileModeOverride; + $expandState->directoryModeOverride = $directoryModeOverride; + $expandState->keepFileTime = $keepFileTime; + + $expandState->save(); + } + $expandState->throttleDelayInUs = 1000 * $throttleDelayInMs; + DupArchiveEngine::expandArchive($expandState); + } + + if (!$expandState->working) { + $deltaTime = time() - $expandState->startTimestamp; + Log::info("DAWN EXPAND DONE, SECONDS: " . $deltaTime, Log::LV_DETAILED); + + if (count($expandState->failures) > 0) { + Log::info('DAWN EXPAND ERRORS DETECTED'); + + foreach ($expandState->failures as $failure) { + Log::info("{$failure->subject}:{$failure->description}"); + if (is_callable($this->failureCallback)) { + call_user_func($this->failureCallback, $failure); + } + } + } + } else { + Log::info("DAWN EXPAND CONTINUE", Log::LV_DETAILED); + } + + + SnapIO::flock($this->lock_handle, LOCK_UN); + + $retVal->pass = true; + $retVal->status = $this->getStatus($expandState); + } elseif ($action == 'get_status') { + /* @var $expandState DawsExpandState */ + $expandState = DawsExpandState::getInstance($initializeState); + + $retVal->pass = true; + $retVal->status = $this->getStatus($expandState); + } elseif ($action == 'cancel') { + if (!SnapIO::touch($this->cancelFile)) { + throw new Exception("Couldn't update time on " . $this->cancelFile); + } + $retVal->pass = true; + } else { + throw new Exception('Unknown command.'); + } + session_write_close(); + + return $retVal; + } + + /** + * Get dup archive status + * + * @param DupArchiveStateBase $state dup archive state + * + * @return stdClass + */ + private function getStatus(DawsExpandState $state) + { + $ret_val = new stdClass(); + $ret_val->archive_offset = $state->archiveOffset; + $ret_val->archive_size = @filesize($state->archivePath); + $ret_val->failures = $state->failures; + $ret_val->file_index = $state->fileWriteCount; + $ret_val->is_done = !$state->working; + $ret_val->timestamp = time(); + + return $ret_val; + } +} diff --git a/installer/dup-installer/src/Core/Deploy/DupArchive/DawsExpandState.php b/installer/dup-installer/src/Core/Deploy/DupArchive/DawsExpandState.php new file mode 100644 index 00000000..4d61f059 --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/DupArchive/DawsExpandState.php @@ -0,0 +1,161 @@ +initMembers(); + } + + /** + * Remove state file + * + * @return bool + */ + public static function purgeStatefile() + { + $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; + if (!file_exists($stateFilepath)) { + return true; + } + return SnapIO::rm($stateFilepath, false); + } + + /** + * + * @param boolean $reset reset state + * + * @return self + */ + public static function getInstance($reset = false) + { + if ((self::$instance == null) && (!$reset)) { + $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; + + self::$instance = new self(); + + if (file_exists($stateFilepath)) { + $stateHandle = SnapIO::fopen($stateFilepath, 'rb'); + + // RSR we shouldn't need read locks and it seems to screw up on some boxes anyway.. SnapIO::flock($stateHandle, LOCK_EX); + $stateString = fread($stateHandle, filesize($stateFilepath)); + $data = json_decode($stateString, false); + self::$instance->setFromData($data); + self::$instance->fileRenames = (array) (self::$instance->fileRenames); + + // SnapIO::flock($stateHandle, LOCK_UN); + SnapIO::fclose($stateHandle); + } else { + $reset = true; + } + } + + if ($reset) { + self::$instance = new self(); + self::$instance->reset(); + } + + return self::$instance; + } + + /** + * Init state from data + * + * @param stdClass $data data + * + * @return void + */ + private function setFromData($data) + { + foreach ($data as $key => $val) { + if (!property_exists($this, $key)) { + continue; + } + $this->{$key} = $val; + } + } + + /** + * Reset state + * + * @return void + */ + public function reset() + { + $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; + $stateHandle = SnapIO::fopen($stateFilepath, 'w'); + SnapIO::flock($stateHandle, LOCK_EX); + + $this->initMembers(); + SnapIO::fwrite($stateHandle, json_encode($this)); + SnapIO::flock($stateHandle, LOCK_UN); + SnapIO::fclose($stateHandle); + } + + /** + * Save state + * + * @return void + */ + public function save() + { + $stateFilepath = dirname(__FILE__) . '/' . self::STATE_FILE; + $stateHandle = SnapIO::fopen($stateFilepath, 'w'); + SnapIO::flock($stateHandle, LOCK_EX); + + DupArchiveUtil::tlog("saving state"); + SnapIO::fwrite($stateHandle, json_encode($this)); + SnapIO::flock($stateHandle, LOCK_UN); + SnapIO::fclose($stateHandle); + } + + /** + * Init props + * + * @return void + */ + private function initMembers() + { + $this->currentFileHeader = null; + $this->archiveOffset = 0; + $this->archiveHeader = 0; + $this->archivePath = null; + $this->basePath = null; + $this->currentFileOffset = 0; + $this->failures = array(); + $this->isCompressed = false; + $this->startTimestamp = time(); + $this->timeSliceInSecs = -1; + $this->working = false; + $this->validateOnly = false; + $this->filteredDirectories = array(); + $this->filteredFiles = array(); + $this->fileRenames = array(); + $this->directoryModeOverride = -1; + $this->fileModeOverride = -1; + $this->lastHeaderOffset = -1; + $this->throttleDelayInUs = 0; + $this->timerEnabled = true; + } +} diff --git a/installer/dup-installer/src/Core/Deploy/DupArchive/DawsLogger.php b/installer/dup-installer/src/Core/Deploy/DupArchive/DawsLogger.php new file mode 100644 index 00000000..cd9683e9 --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/DupArchive/DawsLogger.php @@ -0,0 +1,63 @@ +addFile($archiveConfig->installer_backup_name); + $result->addDir(ltrim($subFolderArchive . '/' . DUP_Extraction::DUP_FOLDER_NAME, '/')); + + if (self::filterWpCoreFiles()) { + $relAbsPath = $archiveConfig->getRelativePathsInArchive('abs'); + $relAbsPath .= (strlen($relAbsPath) > 0 ? '/' : ''); + $rootWpCoreItems = SnapWP::getWpCoreFilesListInFolder(); + foreach ($rootWpCoreItems['dirs'] as $name) { + $result->addDir($relAbsPath . $name); + } + + foreach ($rootWpCoreItems['files'] as $name) { + $result->addFile($relAbsPath . $name); + } + } + + if (self::filterAllExceptPlugingThemesMedia()) { + Log::info('FILTER ALL EXCEPT MEDIA'); + $filterFilesChildOfFolders[] = $archiveConfig->getRelativePathsInArchive('home'); + $filterFilesChildOfFolders[] = $archiveConfig->getRelativePathsInArchive('wpcontent'); + + $acceptFolderOfFilterChilds[] = $archiveConfig->getRelativePathsInArchive('uploads'); + $acceptFolderOfFilterChilds[] = $archiveConfig->getRelativePathsInArchive('wpcontent') . '/blogs.dir'; + $acceptFolderOfFilterChilds[] = $archiveConfig->getRelativePathsInArchive('plugins'); + $acceptFolderOfFilterChilds[] = $archiveConfig->getRelativePathsInArchive('muplugins'); + $acceptFolderOfFilterChilds[] = $archiveConfig->getRelativePathsInArchive('themes'); + } + + if (self::filterExistsPlugins()) { + $newPluginDir = $paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_NEW); + if (is_dir($newPluginDir)) { + $relPlugPath = $archiveConfig->getRelativePathsInArchive('plugins'); + $relPlugPath .= (strlen($relPlugPath) > 0 ? '/' : ''); + + SnapIO::regexGlobCallback($newPluginDir, function ($item) use ($relPlugPath, &$result) { + if (is_dir($item)) { + $result->addDir($relPlugPath . pathinfo($item, PATHINFO_BASENAME)); + } else { + $result->addFile($relPlugPath . pathinfo($item, PATHINFO_BASENAME)); + } + }, array()); + } + + $newMuPluginDir = $paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW); + if (is_dir($newMuPluginDir)) { + $relMuPlugPath = $archiveConfig->getRelativePathsInArchive('muplugins'); + $relMuPlugPath .= (strlen($relMuPlugPath) > 0 ? '/' : ''); + + SnapIO::regexGlobCallback($newMuPluginDir, function ($item) use ($relMuPlugPath, &$result) { + if (is_dir($item)) { + $result->addDir($relMuPlugPath . pathinfo($item, PATHINFO_BASENAME)); + } else { + $result->addFile($relMuPlugPath . pathinfo($item, PATHINFO_BASENAME)); + } + }, array()); + } + + $newWpContentDir = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/'; + if (is_dir($newWpContentDir)) { + $relContentPath = $archiveConfig->getRelativePathsInArchive('wpcontent'); + $relContentPath .= (strlen($relContentPath) > 0 ? '/' : ''); + foreach (SnapWP::getDropinsPluginsNames() as $dropinsPlugin) { + if (file_exists($newWpContentDir . $dropinsPlugin)) { + $result->addFile($relContentPath . $dropinsPlugin); + } + } + } + } + + if (self::filterExistsThemes()) { + $newThemesDir = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/themes'; + if (is_dir($newThemesDir)) { + $relThemesPath = $archiveConfig->getRelativePathsInArchive('themes'); + $relThemesPath .= (strlen($relContentPath) > 0 ? '/' : ''); + + SnapIO::regexGlobCallback($newThemesDir, function ($item) use ($relThemesPath, &$result) { + if (is_dir($item)) { + $result->addDir($relThemesPath . pathinfo($item, PATHINFO_BASENAME)); + } else { + $result->addFile($relThemesPath . pathinfo($item, PATHINFO_BASENAME)); + } + }, array()); + } + } + + self::filterAllChildsOfPathExcept($result, $filterFilesChildOfFolders, $acceptFolderOfFilterChilds); + $result->optmizeFilters(); + + return $result; + } + + /** + * Create filters for remove files + * + * @param Filters|null $baseFilters base extraction filters + * + * @return Filters + */ + public static function getRemoveFilters(Filters $baseFilters = null) + { + $archiveConfig = DUPX_ArchiveConfig::getInstance(); + $security = DUPX_Security::getInstance(); + + $result = new Filters(); + if (!is_null($baseFilters)) { + // convert all relative path from archive to absolute destination path + foreach ($baseFilters->getDirs() as $dir) { + $result->addDir($archiveConfig->destFileFromArchiveName($dir)); + } + foreach ($baseFilters->getDirsWithoutChilds() as $dir) { + $result->addDir($archiveConfig->destFileFromArchiveName($dir), true); + } + foreach ($baseFilters->getFiles() as $file) { + $result->addFile($archiveConfig->destFileFromArchiveName($file)); + } + } + + $result->addFile($security->getArchivePath()); + $result->addFile($security->getBootFilePath()); + $result->addFile($security->getBootLogFile()); + + $result->addDir(DUPX_INIT); + foreach (DUPX_Server::getWpAddonsSiteLists() as $addonPath) { + $result->addDir($addonPath); + } + + $result->optmizeFilters(); + + return $result; + } + + /** + * This function update filters from $filterFilesChildOfFolders and $acceptFolders values + * + * @param Filters $filters Filters + * @param string[] $filterFilesChildOfFolders Filter contents of these paths + * @param string[] $acceptFolders Folders not to filtered + * + * @return void + */ + private static function filterAllChildsOfPathExcept(Filters $filters, $filterFilesChildOfFolders, $acceptFolders = array()) + { + //No sense adding filters if not folders specified + if (!is_array($filterFilesChildOfFolders) || count($filterFilesChildOfFolders) == 0) { + return; + } + + $acceptFolders = array_unique($acceptFolders); + $filterFilesChildOfFolders = array_unique($filterFilesChildOfFolders); + + Log::info('ACCEPT FOLDERS ' . Log::v2str($acceptFolders), Log::LV_DETAILED); + Log::info('CHILDS FOLDERS ' . Log::v2str($filterFilesChildOfFolders), Log::LV_DETAILED); + + DUPX_Package::foreachDirCallback(function ($info) use ($acceptFolders, $filterFilesChildOfFolders, &$filters) { + if (in_array($info->p, $filterFilesChildOfFolders)) { + return; + } + + foreach ($acceptFolders as $acceptFolder) { + if (SnapIO::isChildPath($info->p, $acceptFolder, true)) { + return; + } + } + + $parentFolder = SnapIO::getRelativeDirname($info->p); + + if (in_array($parentFolder, $filterFilesChildOfFolders)) { + $filters->addDir($info->p); + } + }); + + DUPX_Package::foreachFileCallback(function ($info) use ($filterFilesChildOfFolders, &$filters) { + $parentFolder = SnapIO::getRelativeDirname($info->p); + if (in_array($parentFolder, $filterFilesChildOfFolders)) { + $filters->addFile($info->p); + } + }); + + Log::info('FILTERS RESULT ' . Log::v2str($filters), log::LV_DETAILED); + } + + /** + * + * @return boolean + * @throws Exception + */ + public static function filterWpCoreFiles() + { + switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES)) { + case DUP_Extraction::FILTER_NONE: + return false; + case DUP_Extraction::FILTER_SKIP_WP_CORE: + case DUP_Extraction::FILTER_SKIP_CORE_PLUG_THEMES: + case DUP_Extraction::FILTER_ONLY_MEDIA_PLUG_THEMES: + return true; + default: + throw new Exception('Unknown filter type'); + } + } + + /** + * + * @return boolean + * @throws Exception + */ + protected static function filterExistsPlugins() + { + switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES)) { + case DUP_Extraction::FILTER_NONE: + case DUP_Extraction::FILTER_SKIP_WP_CORE: + return false; + case DUP_Extraction::FILTER_SKIP_CORE_PLUG_THEMES: + case DUP_Extraction::FILTER_ONLY_MEDIA_PLUG_THEMES: + return true; + default: + throw new Exception('Unknown filter type'); + } + } + + /** + * + * @return boolean + * @throws Exception + */ + protected static function filterExistsThemes() + { + switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES)) { + case DUP_Extraction::FILTER_NONE: + case DUP_Extraction::FILTER_SKIP_WP_CORE: + return false; + case DUP_Extraction::FILTER_SKIP_CORE_PLUG_THEMES: + case DUP_Extraction::FILTER_ONLY_MEDIA_PLUG_THEMES: + return true; + default: + throw new Exception('Unknown filter type'); + } + } + + /** + * + * @return boolean + * @throws Exception + */ + protected static function filterAllExceptPlugingThemesMedia() + { + switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES)) { + case DUP_Extraction::FILTER_NONE: + case DUP_Extraction::FILTER_SKIP_WP_CORE: + case DUP_Extraction::FILTER_SKIP_CORE_PLUG_THEMES: + return false; + case DUP_Extraction::FILTER_ONLY_MEDIA_PLUG_THEMES: + return true; + default: + throw new Exception('Unknown filter type'); + } + } +} diff --git a/installer/dup-installer/src/Core/Deploy/Files/Filters.php b/installer/dup-installer/src/Core/Deploy/Files/Filters.php new file mode 100644 index 00000000..096e7b92 --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/Files/Filters.php @@ -0,0 +1,166 @@ +files = (array) $files; + $this->dirs = (array) $dirs; + $this->dirsWithoutChilds = (array) $dirsWithoutChilds; + } + + /** + * Check if passe path is filterd + * + * @param string $path path to check + * + * @return bool + */ + public function isFiltered($path) + { + if (in_array($path, $this->dirsWithoutChilds)) { + return true; + } + + foreach ($this->dirs as $dirFilter) { + if (SnapIO::isChildPath($path, $dirFilter)) { + return true; + } + } + + return in_array($path, $this->files); + } + + /** + * Add dir filter + * + * @param string $dir dir path + * @param bool $withoutChild if true add dir filter without childs + * + * @return void + */ + public function addDir($dir, $withoutChild = false) + { + if ($withoutChild) { + $this->dirsWithoutChilds[] = (string) $dir; + } else { + $this->dirs[] = (string) $dir; + } + } + + /** + * Add file fo filters + * + * @param string $file file path + * + * @return void + */ + public function addFile($file) + { + $this->files[] = (string) $file; + } + + /** + * Optimize and sort filters + * + * @return bool + */ + public function optmizeFilters() + { + $this->files = array_values(array_unique($this->files)); + $this->dirsWithoutChilds = array_values(array_unique($this->dirsWithoutChilds)); + $this->dirs = array_values(array_unique($this->dirs)); + + $optimizedDirs = array(); + $optimizedFiles = array(); + + for ($i = 0; $i < count($this->dirs); $i++) { + $exclude = false; + for ($j = 0; $j < count($this->dirs); $j++) { + if ($i === $j) { + continue; + } + if (SnapIO::isChildPath($this->dirs[$i], $this->dirs[$j])) { + $exclude = true; + break; + } + } + if (!$exclude) { + $optimizedDirs[] = $this->dirs[$i]; + } + } + + $optimizedDirs = SnapIO::sortBySubfoldersCount($optimizedDirs); + + foreach ($this->files as $file) { + $exclude = false; + foreach ($optimizedDirs as $cDir) { + if (SnapIO::isChildPath($file, $cDir)) { + $exclude = true; + break; + } + } + + if (!$exclude) { + $optimizedFiles[] = $file; + } + } + + $this->files = $optimizedFiles; + $this->dirs = $optimizedDirs; + + return true; + } + + /** + * Get the value of files + * + * @return string[] + */ + public function getFiles() + { + return $this->files; + } + + /** + * Get the value of dirs + * + * @return string[] + */ + public function getDirs() + { + return $this->dirs; + } + + /** + * Get the value of dirsWithoutChilds + * + * @return string[] + */ + public function getDirsWithoutChilds() + { + return $this->dirsWithoutChilds; + } +} diff --git a/installer/dup-installer/src/Core/Deploy/Files/RemoveFiles.php b/installer/dup-installer/src/Core/Deploy/Files/RemoveFiles.php new file mode 100644 index 00000000..1b2e2a2c --- /dev/null +++ b/installer/dup-installer/src/Core/Deploy/Files/RemoveFiles.php @@ -0,0 +1,256 @@ +removeFilters = $filters; + } + + /** + * Remove file if action is enableds + * + * @return void + */ + public function remove() + { + $paramsManager = PrmMng::getInstance(); + + switch ($paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ACTION)) { + case DUP_Extraction::ACTION_REMOVE_ALL_FILES: + $this->removeAllFiles(); + break; + case DUP_Extraction::ACTION_REMOVE_WP_FILES: + $this->removeWpFiles(); + break; + case DUP_Extraction::ACTION_REMOVE_UPLOADS: + $this->removeUploads(); + break; + case DUP_Extraction::ACTION_DO_NOTHING: + break; + default: + throw new Exception('Invalid engine action ' . $paramsManager->getValue(PrmMng::PARAM_ARCHIVE_ACTION)); + } + } + + /** + * This function remove files before extraction + * + * @param string[] $folders Folders lists + * + * @return void + */ + protected function removeFiles($folders = array()) + { + Log::info('REMOVE FILES'); + + $excludeFiles = array_map(function ($value) { + return '/^' . preg_quote($value, '/') . '$/'; + }, $this->removeFilters->getFiles()); + + $excludeFolders = array_map(function ($value) { + return '/^' . preg_quote($value, '/') . '(?:\/.*)?$/'; + }, $this->removeFilters->getDirs()); + $excludeFolders[] = '/.+\/backups-dup-(lite|pro)$/'; + + $excludeDirsWithoutChilds = $this->removeFilters->getDirsWithoutChilds(); + + foreach ($folders as $folder) { + Log::info('REMOVE FOLDER ' . Log::v2str($folder)); + SnapIO::regexGlobCallback($folder, function ($path) use ($excludeDirsWithoutChilds) { + foreach ($excludeDirsWithoutChilds as $excludePath) { + if (SnapIO::isChildPath($excludePath, $path)) { + return; + } + } + + $result = (is_dir($path) ? rmdir($path) : unlink($path)); + if ($result == false) { + $lastError = error_get_last(); + $message = (isset($lastError['message']) ? $lastError['message'] : 'Couldn\'t remove file'); + RemoveFiles::reportRemoveNotices($path, $message); + } + }, array( + 'regexFile' => $excludeFiles, + 'regexFolder' => $excludeFolders, + 'checkFullPath' => true, + 'recursive' => true, + 'invert' => true, + 'childFirst' => true + )); + } + } + + /** + * Remove worpdress core files + * + * @return void + */ + protected function removeWpFiles() + { + try { + Log::info('REMOVE WP FILES'); + Log::resetTime(Log::LV_DEFAULT, false); + + $paramsManager = PrmMng::getInstance(); + $absDir = SnapIO::safePathTrailingslashit($paramsManager->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW)); + if (!is_dir($absDir) || !is_readable($absDir)) { + return false; + } + + $removeFolders = array(); + + if (!FilterMng::filterWpCoreFiles() && ($dh = opendir($absDir))) { + while (($elem = readdir($dh)) !== false) { + if ($elem === '.' || $elem === '..') { + continue; + } + + if (SnapWP::isWpCore($elem, SnapWP::PATH_RELATIVE)) { + $fullPath = $absDir . $elem; + if (is_dir($fullPath)) { + $removeFolders[] = $fullPath; + } else { + if (is_writable($fullPath)) { + unlink($fullPath); + } + } + } + } + closedir($dh); + } + + $removeFolders[] = $paramsManager->getValue(PrmMng::PARAM_PATH_CONTENT_NEW); + $removeFolders[] = $paramsManager->getValue(PrmMng::PARAM_PATH_UPLOADS_NEW); + $removeFolders[] = $paramsManager->getValue(PrmMng::PARAM_PATH_PLUGINS_NEW); + $removeFolders[] = $paramsManager->getValue(PrmMng::PARAM_PATH_MUPLUGINS_NEW); + + $this->removeFiles(array_unique($removeFolders)); + Log::logTime('FOLDERS REMOVED', Log::LV_DEFAULT, false); + } catch (Exception $e) { + Log::logException($e); + } catch (Error $e) { + Log::logException($e); + } + } + + /** + * Remove ony uploads files + * + * @return void + */ + protected function removeUploads() + { + try { + Log::info('REMOVE UPLOADS FILES'); + Log::resetTime(Log::LV_DEFAULT, false); + + $paramsManager = PrmMng::getInstance(); + + $removeFolders = array(); + $removeFolders[] = $paramsManager->getValue(PrmMng::PARAM_PATH_UPLOADS_NEW); + + $this->removeFiles(array_unique($removeFolders)); + Log::logTime('FOLDERS REMOVED', Log::LV_DEFAULT, false); + } catch (Exception $e) { + Log::logException($e); + } catch (Error $e) { + Log::logException($e); + } + } + + /** + * Remove all files before extraction + * + * @return void + */ + protected function removeAllFiles() + { + try { + Log::info('REMOVE ALL FILES'); + Log::resetTime(Log::LV_DEFAULT, false); + $pathsMapping = DUPX_ArchiveConfig::getInstance()->getPathsMapping(); + $folders = is_string($pathsMapping) ? array($pathsMapping) : array_values($pathsMapping); + + $this->removeFiles($folders); + Log::logTime('FOLDERS REMOVED', Log::LV_DEFAULT, false); + } catch (Exception $e) { + Log::logException($e); + } catch (Error $e) { + Log::logException($e); + } + } + + + /** + * + * @param string $fileName package relative path + * @param string $errorMessage error message + * + * @return void + */ + public static function reportRemoveNotices($fileName, $errorMessage) + { + if (DUPX_Custom_Host_Manager::getInstance()->skipWarningExtractionForManaged($fileName)) { + // @todo skip warning for managed hostiong (it's a temp solution) + return; + } + + Log::info('Remove ' . $fileName . ' error message: ' . $errorMessage); + if (is_dir($fileName)) { + // Skip warning message for folders + return; + } + + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + + if (SnapWP::isWpCore($fileName, SnapWP::PATH_RELATIVE)) { + Log::info("FILE CORE REMOVE ERROR: {$fileName} | MSG:" . $errorMessage); + $shortMsg = 'Can\'t remove wp core files'; + $errLevel = DUPX_NOTICE_ITEM::CRITICAL; + $idManager = 'wp-remove-error-file-core'; + } else { + Log::info("FILE REMOVE ERROR: {$fileName} | MSG:" . $errorMessage); + $shortMsg = 'Can\'t remove files'; + $errLevel = DUPX_NOTICE_ITEM::HARD_WARNING; + $idManager = 'wp-remove-error-file-no-core'; + } + + $longMsg = 'FILE: ' . htmlspecialchars($fileName) . '
          Message: ' . htmlspecialchars($errorMessage) . '

          '; + + $nManager->addBothNextAndFinalReportNotice( + array( + 'shortMsg' => $shortMsg, + 'longMsg' => $longMsg, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML, + 'level' => $errLevel, + 'sections' => array('files') + ), + DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, + $idManager + ); + } +} diff --git a/installer/dup-installer/src/Core/Hooks/Hook.php b/installer/dup-installer/src/Core/Hooks/Hook.php new file mode 100644 index 00000000..9b98d4aa --- /dev/null +++ b/installer/dup-installer/src/Core/Hooks/Hook.php @@ -0,0 +1,593 @@ +callbacks[$priority]); + + $this->callbacks[$priority][$idx] = array( + 'function' => $function_to_add, + 'accepted_args' => $accepted_args, + ); + + // If we're adding a new priority to the list, put them back in sorted order. + if (!$priority_existed && count($this->callbacks) > 1) { + ksort($this->callbacks, SORT_NUMERIC); + } + + if ($this->nestingLevel > 0) { + $this->resortActiveIterations($priority, $priority_existed); + } + } + + /** + * Handles resetting callback priority keys mid-iteration. + * + * @param false|int $new_priority Optional. The priority of the new filter being added. Default false, + * for no priority being added. + * @param bool $priority_existed Optional. Flag for whether the priority already existed before the new + * filter was added. Default false. + * + * @return void + */ + private function resortActiveIterations($new_priority = false, $priority_existed = false) + { + $new_priorities = array_keys($this->callbacks); + + // If there are no remaining hooks, clear out all running iterations. + if (!$new_priorities) { + foreach ($this->iterations as $index => $iteration) { + $this->iterations[$index] = $new_priorities; + } + return; + } + + $min = min($new_priorities); + foreach ($this->iterations as $index => &$iteration) { + $current = current($iteration); + // If we're already at the end of this iteration, just leave the array pointer where it is. + if (false === $current) { + continue; + } + + $iteration = $new_priorities; + + if ($current < $min) { + array_unshift($iteration, $current); + continue; + } + + while (current($iteration) < $current) { + if (false === next($iteration)) { + break; + } + } + + // If we have a new priority that didn't exist, but ::applyFilters() or ::doAction() thinks it's the current priority... + if ($new_priority === $this->currentPriority[$index] && !$priority_existed) { + /* + * ...and the new priority is the same as what $this->iterations thinks is the previous + * priority, we need to move back to it. + */ + + if (false === current($iteration)) { + // If we've already moved off the end of the array, go back to the last element. + $prev = end($iteration); + } else { + // Otherwise, just go back to the previous element. + $prev = prev($iteration); + } + if (false === $prev) { + // Start of the array. Reset, and go about our day. + reset($iteration); + } elseif ($new_priority !== $prev) { + // Previous wasn't the same. Move forward again. + next($iteration); + } + } + } + unset($iteration); + } + + /** + * Unhooks a function or method from a specific filter action. + * + * @param string $tag The filter hook to which the function to be removed is hooked. + * @param callable $function_to_remove The callback to be removed from running when the filter is applied. + * @param int $priority The exact priority used when adding the original filter callback. + * + * @return bool Whether the callback existed before it was removed. + */ + public function removeFilter($tag, $function_to_remove, $priority) + { + $function_key = self::wpFilterBuildUniqueId($tag, $function_to_remove, $priority); + + $exists = isset($this->callbacks[$priority][$function_key]); + if ($exists) { + unset($this->callbacks[$priority][$function_key]); + if (!$this->callbacks[$priority]) { + unset($this->callbacks[$priority]); + if ($this->nestingLevel > 0) { + $this->resortActiveIterations(); + } + } + } + return $exists; + } + + /** + * Checks if a specific action has been registered for this hook. + * + * When using the `$function_to_check` argument, this function may return a non-boolean value + * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. + * + * @param string $tag Optional. The name of the filter hook. Default empty. + * @param callable|false $function_to_check Optional. The callback to check for. Default false. + * + * @return bool|int If `$function_to_check` is omitted, returns boolean for whether the hook has + * anything registered. When checking a specific function, the priority of that + * hook is returned, or false if the function is not attached. + */ + public function hasFilter($tag = '', $function_to_check = false) + { + if (false === $function_to_check) { + return $this->hasFilters(); + } + + $function_key = self::wpFilterBuildUniqueId($tag, $function_to_check, false); + if (!$function_key) { + return false; + } + + foreach ($this->callbacks as $priority => $callbacks) { + if (isset($callbacks[$function_key])) { + return $priority; + } + } + + return false; + } + + /** + * Checks if any callbacks have been registered for this hook. + * + * @return bool True if callbacks have been registered for the current hook, otherwise false. + */ + public function hasFilters() + { + foreach ($this->callbacks as $callbacks) { + if ($callbacks) { + return true; + } + } + return false; + } + + /** + * Removes all callbacks from the current filter. + * + * @param int|false $priority Optional. The priority number to remove. Default false. + * + * @return void + */ + public function removeAllFilters($priority = false) + { + if (!$this->callbacks) { + return; + } + + if (false === $priority) { + $this->callbacks = array(); + } elseif (isset($this->callbacks[$priority])) { + unset($this->callbacks[$priority]); + } + + if ($this->nestingLevel > 0) { + $this->resortActiveIterations(); + } + } + + /** + * Calls the callback functions that have been added to a filter hook. + * + * @param mixed $value The value to filter. + * @param array $args Additional parameters to pass to the callback functions. + * This array is expected to include $value at index 0. + * + * @return mixed The filtered value after all hooked functions are applied to it. + */ + public function applyFilters($value, $args) + { + if (!$this->callbacks) { + return $value; + } + + $nestingLevel = $this->nestingLevel++; + + $this->iterations[$nestingLevel] = array_keys($this->callbacks); + $num_args = count($args); + + do { + $this->currentPriority[$nestingLevel] = current($this->iterations[$nestingLevel]); + $priority = $this->currentPriority[$nestingLevel]; + + foreach ($this->callbacks[$priority] as $the_) { + if (!$this->doingAction) { + $args[0] = $value; + } + + // Avoid the array_slice() if possible. + if (0 == $the_['accepted_args']) { + $value = call_user_func($the_['function']); + } elseif ($the_['accepted_args'] >= $num_args) { + $value = call_user_func_array($the_['function'], $args); + } else { + $value = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); + } + } + } while (false !== next($this->iterations[$nestingLevel])); + + unset($this->iterations[$nestingLevel]); + unset($this->currentPriority[$nestingLevel]); + + $this->nestingLevel--; + + return $value; + } + + /** + * Calls the callback functions that have been added to an action hook. + * + * @param array $args Parameters to pass to the callback functions. + * + * @return void + */ + public function doAction($args) + { + $this->doingAction = true; + $this->applyFilters('', $args); + + // If there are recursive calls to the current action, we haven't finished it until we get to the last one. + if (!$this->nestingLevel) { + $this->doingAction = false; + } + } + + /** + * Processes the functions hooked into the 'all' hook. + * + * @param array $args Arguments to pass to the hook callbacks. Passed by reference. + * + * @return void + */ + public function doAllHook(&$args) + { + $nestingLevel = $this->nestingLevel++; + $this->iterations[$nestingLevel] = array_keys($this->callbacks); + + do { + $priority = current($this->iterations[$nestingLevel]); + foreach ($this->callbacks[$priority] as $the_) { + call_user_func_array($the_['function'], $args); + } + } while (false !== next($this->iterations[$nestingLevel])); + + unset($this->iterations[$nestingLevel]); + $this->nestingLevel--; + } + + /** + * Return the current priority level of the currently running iteration of the hook. + * + * @return int|false If the hook is running, return the current priority level. If it isn't running, return false. + */ + public function currentPriority() + { + if (false === current($this->iterations)) { + return false; + } + + return current(current($this->iterations)); + } + + /** + * Normalizes filters set up before WordPress has initialized to Hook objects. + * + * The `$filters` parameter should be an array keyed by hook name, with values + * containing either: + * + * - A `Hook` instance + * - An array of callbacks keyed by their priorities + * + * Examples: + * + * $filters = array( + * 'wp_fatal_error_handler_enabled' => array( + * 10 => array( + * array( + * 'accepted_args' => 0, + * 'function' => function() { + * return false; + * }, + * ), + * ), + * ), + * ); + * + * @param array $filters Filters to normalize. See documentation above for details. + * + * @return WP_Hook[] Array of normalized filters. + */ + public static function buildPreinitializedHooks($filters) + { + /** @var WP_Hook[] $normalized */ + $normalized = array(); + + foreach ($filters as $tag => $callback_groups) { + if (is_object($callback_groups) && $callback_groups instanceof self) { + $normalized[$tag] = $callback_groups; + continue; + } + $hook = new self(); + + // Loop through callback groups. + foreach ($callback_groups as $priority => $callbacks) { + // Loop through callbacks. + foreach ($callbacks as $cb) { + $hook->addFilter($tag, $cb['function'], $priority, $cb['accepted_args']); + } + } + $normalized[$tag] = $hook; + } + return $normalized; + } + + /** + * Determines whether an offset value exists. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetexists.php + * + * @param mixed $offset An offset to check for. + * + * @return bool True if the offset exists, false otherwise. + */ + #[\ReturnTypeWillChange] + public function offsetExists($offset) + { + return isset($this->callbacks[$offset]); + } + + /** + * Retrieves a value at a specified offset. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetget.php + * + * @param mixed $offset The offset to retrieve. + * + * @return mixed If set, the value at the specified offset, null otherwise. + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return isset($this->callbacks[$offset]) ? $this->callbacks[$offset] : null; + } + + /** + * Sets a value at a specified offset. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetset.php + * + * @param mixed $offset The offset to assign the value to. + * @param mixed $value The value to set. + * + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + if (is_null($offset)) { + $this->callbacks[] = $value; + } else { + $this->callbacks[$offset] = $value; + } + } + + /** + * Unsets a specified offset. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetunset.php + * + * @param mixed $offset The offset to unset. + * + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + unset($this->callbacks[$offset]); + } + + /** + * Returns the current element. + * + * @link https://www.php.net/manual/en/iterator.current.php + * + * @return array Of callbacks at current priority. + */ + #[\ReturnTypeWillChange] + public function current() + { + return current($this->callbacks); + } + + /** + * Moves forward to the next element. + * + * @link https://www.php.net/manual/en/iterator.next.php + * + * @return array Of callbacks at next priority. + */ + #[\ReturnTypeWillChange] + public function next() + { + return next($this->callbacks); + } + + /** + * Returns the key of the current element. + * + * @link https://www.php.net/manual/en/iterator.key.php + * + * @return mixed Returns current priority on success, or NULL on failure + */ + #[\ReturnTypeWillChange] + public function key() + { + return key($this->callbacks); + } + + /** + * Checks if current position is valid. + * + * @link https://www.php.net/manual/en/iterator.valid.php + * + * @return bool Whether the current position is valid. + */ + #[\ReturnTypeWillChange] + public function valid() + { + return key($this->callbacks) !== null; + } + + /** + * Rewinds the Iterator to the first element. + * + * @link https://www.php.net/manual/en/iterator.rewind.php + * + * @return void + */ + #[\ReturnTypeWillChange] + public function rewind() + { + reset($this->callbacks); + } + + /** + * Build Unique ID for storage and retrieval. + * + * The old way to serialize the callback caused issues and this function is the + * solution. It works by checking for objects and creating a new property in + * the class to keep track of the object and new objects of the same class that + * need to be added. + * + * It also allows for the removal of actions and filters for objects after they + * change class properties. It is possible to include the property $wp_filter_id + * in your class and set it to "null" or a number to bypass the workaround. + * However this will prevent you from adding new classes and any new classes + * will overwrite the previous hook by the same class. + * + * Functions and static method callbacks are just returned as strings and + * shouldn't have any speed penalty. + * + * @link https://core.trac.wordpress.org/ticket/3875 + * + * @since 2.2.3 + * @since 5.3.0 Removed workarounds for spl_object_hash(). + * `$tag` and `$priority` are no longer used, + * and the function always returns a string. + * @access private + * + * @param string $tag Unused. The name of the filter to build ID for. + * @param callable $function The function to generate ID for. + * @param int $priority Unused. The order in which the functions + * associated with a particular action are executed. + * + * @return string Unique function ID for usage as array key. + */ + protected static function wpFilterBuildUniqueId($tag, $function, $priority) + { + if (is_string($function)) { + return $function; + } + + if (is_object($function)) { + // Closures are currently implemented as objects. + $function = array($function, ''); + } else { + $function = (array) $function; + } + + if (is_object($function[0])) { + // Object class calling. + return spl_object_hash($function[0]) . $function[1]; + } elseif (is_string($function[0])) { + // Static calling. + return $function[0] . '::' . $function[1]; + } + } +} diff --git a/installer/dup-installer/src/Core/Hooks/HooksMng.php b/installer/dup-installer/src/Core/Hooks/HooksMng.php new file mode 100644 index 00000000..6ad7c691 --- /dev/null +++ b/installer/dup-installer/src/Core/Hooks/HooksMng.php @@ -0,0 +1,451 @@ +filters[$tag])) { + $this->filters[$tag] = new Hook(); + } + $this->filters[$tag]->addFilter($tag, $function_to_add, $priority, $accepted_args); + return true; + } + + /** + * Checks if any filter has been registered for a hook. + * + * When using the `$function_to_check` argument, this function may return a non-boolean value + * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. + * + * @param string $tag The name of the filter hook. + * @param callable|false $function_to_check Optional. The callback to check for. Default false. + * + * @return bool|int If `$function_to_check` is omitted, returns boolean for whether the hook has + * anything registered. When checking a specific function, the priority of that + * hook is returned, or false if the function is not attached. + */ + public function hasFilter($tag, $function_to_check = false) + { + if (!isset($this->filters[$tag])) { + return false; + } + + return $this->filters[$tag]->hasFilter($tag, $function_to_check); + } + + /** + * Calls the callback functions that have been added to a filter hook. + * + * The callback functions attached to the filter hook are invoked by calling + * this function. This function can be used to create a new filter hook by + * simply calling this function with the name of the new hook specified using + * the `$tag` parameter. + * + * The function also allows for multiple additional arguments to be passed to hooks. + * + * Example usage: + * + * // The filter callback function. + * function example_callback( $string, $arg1, $arg2 ) { + * // (maybe) modify $string. + * return $string; + * } + * add_filter( 'example_filter', 'example_callback', 10, 3 ); + * + * /* + * * Apply the filters by calling the 'example_callback()' function + * * that's hooked onto `example_filter` above. + * * + * * - 'example_filter' is the filter hook. + * * - 'filter me' is the value being filtered. + * * - $arg1 and $arg2 are the additional arguments passed to the callback. + * $value = applyFilters( 'example_filter', 'filter me', $arg1, $arg2 ); + * + * @param string $tag The name of the filter hook. + * @param mixed $value The value to filter. + * ... $args Additional parameters to pass to the callback functions. + * + * @return mixed The filtered value after all hooked functions are applied to it. + */ + public function applyFilters($tag, $value) + { + $args = func_get_args(); + + // Do 'all' actions first. + if (isset($this->filters['all'])) { + $this->currentFilter[] = $tag; + $this->callAllHook($args); + } + + if (!isset($this->filters[$tag])) { + if (isset($this->filters['all'])) { + array_pop($this->currentFilter); + } + return $value; + } + + if (!isset($this->filters['all'])) { + $this->currentFilter[] = $tag; + } + + // Don't pass the tag name to Hook. + array_shift($args); + + $filtered = $this->filters[$tag]->applyFilters($value, $args); + + array_pop($this->currentFilter); + + return $filtered; + } + + /** + * Removes a function from a specified filter hook. + * + * This function removes a function attached to a specified filter hook. This + * method can be used to remove default functions attached to a specific filter + * hook and possibly replace them with a substitute. + * + * To remove a hook, the $function_to_remove and $priority arguments must match + * when the hook was added. This goes for both filters and actions. No warning + * will be given on removal failure. + * + * @param string $tag The filter hook to which the function to be removed is hooked. + * @param callable $function_to_remove The name of the function which should be removed. + * @param int $priority Optional. The priority of the function. Default 10. + * + * @return bool Whether the function existed before it was removed. + */ + public function removeFilter($tag, $function_to_remove, $priority = 10) + { + $r = false; + if (isset($this->filters[$tag])) { + $r = $this->filters[$tag]->removeFilter($tag, $function_to_remove, $priority); + if (!$this->filters[$tag]->callbacks) { + unset($this->filters[$tag]); + } + } + + return $r; + } + + /** + * Remove all of the hooks from a filter. + * + * @param string $tag The filter to remove hooks from. + * @param int|false $priority Optional. The priority number to remove. Default false. + * + * @return true True when finished. + */ + public function removeAllFilters($tag, $priority = false) + { + if (isset($this->filters[$tag])) { + $this->filters[$tag]->removeAllFilters($priority); + if (!$this->filters[$tag]->hasFilters()) { + unset($this->filters[$tag]); + } + } + + return true; + } + + /** + * Hooks a function on to a specific action. + * + * Actions are the hooks that the WordPress core launches at specific points + * during execution, or when specific events occur. Plugins can specify that + * one or more of its PHP functions are executed at these points, using the + * Action API. + * + * @param string $tag The name of the action to which the $function_to_add is hooked. + * @param callable $function_to_add The name of the function you wish to be called. + * @param int $priority Optional. Used to specify the order in which the functions + * associated with a particular action are executed. Default 10. + * Lower numbers correspond with earlier execution, + * and functions with the same priority are executed + * in the order in which they were added to the action. + * @param int $accepted_args Optional. The number of arguments the function accepts. Default 1. + * + * @return true Will always return true. + */ + public function addAction($tag, $function_to_add, $priority = 10, $accepted_args = 1) + { + return $this->addFilter($tag, $function_to_add, $priority, $accepted_args); + } + + /** + * Execute functions hooked on a specific action hook. + * + * This function invokes all functions attached to action hook `$tag`. It is + * possible to create new action hooks by simply calling this function, + * specifying the name of the new hook using the `$tag` parameter. + * + * You can pass extra arguments to the hooks, much like you can with `applyFilters()`. + * + * Example usage: + * + * // The action callback function. + * function example_callback( $arg1, $arg2 ) { + * // (maybe) do something with the args. + * } + * add_action( 'example_action', 'example_callback', 10, 2 ); + * + * /* + * * Trigger the actions by calling the 'example_callback()' function + * * that's hooked onto `example_action` above. + * * + * * - 'example_action' is the action hook. + * * - $arg1 and $arg2 are the additional arguments passed to the callback. + * $value = do_action( 'example_action', $arg1, $arg2 ); + * + * @global Hook[] $this->filters Stores all of the filters and actions. + * @global string[] $this->currentFilter Stores the list of current filters with the current one last. + * + * @param string $tag The name of the action to be executed. + * ...$arg Optional. Additional arguments which are passed on to the + * functions hooked to the action. Default empty. + * + * @return void + */ + public function doAction($tag) + { + $arg = $all_args = func_get_args(); + array_shift($arg); // remove tag action + + // Do 'all' actions first. + if (isset($this->filters['all'])) { + $this->currentFilter[] = $tag; + $this->callAllHook($all_args); + } + + if (!isset($this->filters[$tag])) { + if (isset($this->filters['all'])) { + array_pop($this->currentFilter); + } + return; + } + + if (!isset($this->filters['all'])) { + $this->currentFilter[] = $tag; + } + + if (empty($arg)) { + $arg[] = ''; + } elseif (is_array($arg[0]) && 1 === count($arg[0]) && isset($arg[0][0]) && is_object($arg[0][0])) { + // Backward compatibility for PHP4-style passing of `array( &$this )` as action `$arg`. + $arg[0] = $arg[0][0]; + } + + $this->filters[$tag]->doAction($arg); + + array_pop($this->currentFilter); + } + + /** + * Checks if any action has been registered for a hook. + * + * When using the `$function_to_check` argument, this function may return a non-boolean value + * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. + * + * @see hasFilter() has_action() is an alias of hasFilter(). + * + * @param string $tag The name of the action hook. + * @param callable|false $function_to_check Optional. The callback to check for. Default false. + * + * @return bool|int If `$function_to_check` is omitted, returns boolean for whether the hook has + * anything registered. When checking a specific function, the priority of that + * hook is returned, or false if the function is not attached. + */ + public function hasAction($tag, $function_to_check = false) + { + return $this->hasFilter($tag, $function_to_check); + } + + /** + * Removes a function from a specified action hook. + * + * This function removes a function attached to a specified action hook. This + * method can be used to remove default functions attached to a specific filter + * hook and possibly replace them with a substitute. + * + * @param string $tag The action hook to which the function to be removed is hooked. + * @param callable $function_to_remove The name of the function which should be removed. + * @param int $priority Optional. The priority of the function. Default 10. + * + * @return bool Whether the function is removed. + */ + public function removeAction($tag, $function_to_remove, $priority = 10) + { + return $this->removeFilter($tag, $function_to_remove, $priority); + } + + /** + * Remove all of the hooks from an action. + * + * @param string $tag The action to remove hooks from. + * @param int|false $priority The priority number to remove them from. Default false. + * + * @return true True when finished. + */ + public function removeAllActions($tag, $priority = false) + { + return $this->removeAllFilters($tag, $priority); + } + + /** + * Retrieve the name of the current filter or action. + * + * @global string[] $wp_current_filter Stores the list of current filters with the current one last + * + * @return string Hook name of the current filter or action. + */ + public function currentFilter() + { + return end($this->currentFilter); + } + + /** + * Retrieve the name of the current action. + * + * @return string Hook name of the current action. + */ + public function currentAction() + { + return $this->currentFilter(); + } + + /** + * Call the 'all' hook, which will process the functions hooked into it. + * + * The 'all' hook passes all of the arguments or parameters that were used for + * the hook, which this function was called for. + * + * This function is used internally for apply_filters(), do_action(), and + * do_action_ref_array() and is not meant to be used from outside those + * functions. This function does not check for the existence of the all hook, so + * it will fail unless the all hook exists prior to this function call. + * + * @global Hook[] $this->filters Stores all of the filters and actions. + * + * @param array $args The collected parameters from the hook that was called. + * + * @return void + */ + private function callAllHook($args) + { + $this->filters['all']->doAllHook($args); + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/DescriptorInterface.php b/installer/dup-installer/src/Core/Params/Descriptors/DescriptorInterface.php new file mode 100644 index 00000000..ac03f70d --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/DescriptorInterface.php @@ -0,0 +1,36 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamOption; +use Duplicator\Installer\Utils\Log\Log; +use DUPX_InstallerState; +use DUPX_Template; +use DUPX_TemplateItem; +use Exception; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescConfigs implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_INST_TYPE] = new ParamForm( + PrmMng::PARAM_INST_TYPE, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_RADIO, + array( + 'default' => DUPX_InstallerState::INSTALL_NOT_SET, + 'acceptValues' => array(__CLASS__, 'getInstallTypesAcceptValues') + ), + array( + 'status' => ParamForm::STATUS_ENABLED, + 'label' => 'Install Type:', + 'wrapperClasses' => array('group-block', 'revalidate-on-change'), + 'options' => self::getInstallTypeOptions(), + // Temporarly diabled for inital release 1.5 + // 'proFlagTitle' => 'Upgrade Features', + // 'proFlag' => 'Improve the install experiance with support for these popular install modes:' + // . '
            ' . + // '
          • Full Multisite Support
          • ' . + // '
          • Install from Remote Server
          • ' . + // '
          • Restore from Recovery Point
          • ' . + // '
          ' + ) + ); + + $params[PrmMng::PARAM_WP_CONFIG] = new ParamForm( + PrmMng::PARAM_WP_CONFIG, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => 'modify', + 'acceptValues' => array( + 'modify', + 'nothing', + 'new' + ) + ), + array( + 'label' => 'WordPress:', + 'wrapperClasses' => 'medium', + 'status' => function (ParamItem $paramObj) { + if ( + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array( + new ParamOption('nothing', 'Do nothing'), + new ParamOption('modify', 'Modify original'), + new ParamOption('new', 'Create new from wp-config sample') + ), + 'subNote' => 'wp-config.php' + ) + ); + + $params[PrmMng::PARAM_HTACCESS_CONFIG] = new ParamForm( + PrmMng::PARAM_HTACCESS_CONFIG, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => 'new', + 'acceptValues' => array( + 'new', + 'original', + 'nothing' + ) + ), + array( + 'label' => 'Apache:', + 'wrapperClasses' => 'medium', + 'status' => function (ParamItem $paramObj) { + if ( + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array( + new ParamOption('nothing', 'Do nothing'), + new ParamOption('original', 'Retain original from Archive.zip/daf'), + new ParamOption('new', 'Create new (recommended)') + ), + 'subNote' => '.htaccess' + ) + ); + + $params[PrmMng::PARAM_OTHER_CONFIG] = new ParamForm( + PrmMng::PARAM_OTHER_CONFIG, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => 'new', + 'acceptValues' => array( + 'new', + 'original', + 'nothing' + ) + ), + array( + 'label' => 'General:', + 'wrapperClasses' => 'medium', + 'status' => function (ParamItem $paramObj) { + if ( + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array( + new ParamOption('nothing', 'Do nothing'), + new ParamOption('original', 'Retain original from Archive.zip/daf'), + new ParamOption('new', 'Reset') + ), + 'subNote' => 'includes: php.ini, .user.ini, web.config' + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + $installType = $params[PrmMng::PARAM_INST_TYPE]->getValue(); + if ($installType == DUPX_InstallerState::INSTALL_NOT_SET) { + $acceptValues = $params[PrmMng::PARAM_INST_TYPE]->getAcceptValues(); + $params[PrmMng::PARAM_INST_TYPE]->setValue(self::getInstTypeByPriority($acceptValues)); + } + + $installType = $params[PrmMng::PARAM_INST_TYPE]->getValue(); + if (DUPX_InstallerState::isRestoreBackup($installType)) { + if (\DUPX_Custom_Host_Manager::getInstance()->isManaged()) { + $params[PrmMng::PARAM_WP_CONFIG]->setValue('nothing'); + $params[PrmMng::PARAM_HTACCESS_CONFIG]->setValue('nothing'); + $params[PrmMng::PARAM_OTHER_CONFIG]->setValue('nothing'); + } else { + $params[PrmMng::PARAM_WP_CONFIG]->setValue('modify'); + $params[PrmMng::PARAM_HTACCESS_CONFIG]->setValue('original'); + $params[PrmMng::PARAM_OTHER_CONFIG]->setValue('original'); + } + } + } + + /** + * Return default install type from install types enabled + * + * @param int[] $acceptValues install types enabled + * + * @return int + */ + protected static function getInstTypeByPriority($acceptValues) + { + $defaultPriority = array( + DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE, + DUPX_InstallerState::INSTALL_SINGLE_SITE + ); + + foreach ($defaultPriority as $current) { + if (in_array($current, $acceptValues)) { + return $current; + } + } + + throw new Exception('No default value found on proprity list'); + } + + /** + * + * @return ParamOption[] + */ + protected static function getInstallTypeOptions() + { + $result = array(); + + $option = new ParamOption( + DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE, + 'Restore single site', + array(__CLASS__, 'typeOptionsVisibility') + ); + $result[] = $option; + + $option = new ParamOption( + DUPX_InstallerState::INSTALL_SINGLE_SITE, + 'Full install single site', + array(__CLASS__, 'typeOptionsVisibility') + ); + $result[] = $option; + + $option = new ParamOption( + DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN, + 'Import single site into multisite network', + array(__CLASS__, 'typeOptionsVisibility') + ); + $result[] = $option; + + $option = new ParamOption( + DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER, + 'Import single site into multisite network', + array(__CLASS__, 'typeOptionsVisibility') + ); + $result[] = $option; + + return $result; + } + + /** + * Return option type status + * + * @param ParamOption $option install type option + * + * @return string option status + */ + public static function typeOptionsVisibility(ParamOption $option) + { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + $overwriteData = PrmMng::getInstance()->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + $isOwrMode = PrmMng::getInstance()->getValue(PrmMng::PARAM_INSTALLER_MODE) === DUPX_InstallerState::MODE_OVR_INSTALL; + + switch ($option->value) { + case DUPX_InstallerState::INSTALL_SINGLE_SITE: + if ($archiveConfig->mu_mode != 0) { + return ParamOption::OPT_HIDDEN; + } + break; + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN: + if (!$isOwrMode || !$overwriteData['isMultisite'] || !$overwriteData['subdomain']) { + return ParamOption::OPT_HIDDEN; + } + break; + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER: + if (!$isOwrMode || !$overwriteData['isMultisite'] || $overwriteData['subdomain']) { + return ParamOption::OPT_HIDDEN; + } + break; + case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE: + if ($archiveConfig->mu_mode != 0 || !DUPX_InstallerState::isInstallerCreatedInThisLocation()) { + return ParamOption::OPT_HIDDEN; + } + break; + case DUPX_InstallerState::INSTALL_NOT_SET: + default: + throw new Exception('Install type not valid ' . $option->value); + } + + $acceptValues = self::getInstallTypesAcceptValues(); + return in_array($option->value, $acceptValues) ? ParamOption::OPT_ENABLED : ParamOption::OPT_DISABLED; + } + + /** + * + * @return int[] + */ + public static function getInstallTypesAcceptValues() + { + $acceptValues = array(); + $isSameLocation = DUPX_InstallerState::isInstallerCreatedInThisLocation(); + + $acceptValues[] = DUPX_InstallerState::INSTALL_SINGLE_SITE; + if ($isSameLocation) { + $acceptValues[] = DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE; + } + + return $acceptValues; + } + + /** + * Return install type option note + * + * @param ParamOption $option install type option + * + * @return string + */ + public static function getInstallTypesNotes(ParamOption $option) + { + switch ($option->value) { + case DUPX_InstallerState::INSTALL_SINGLE_SITE: + return ''; + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN: + case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER: + return ''; + case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE: + case DUPX_InstallerState::INSTALL_NOT_SET: + default: + throw new Exception('Install type not valid ' . $option->value); + } + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescController.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescController.php new file mode 100644 index 00000000..5f912038 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescController.php @@ -0,0 +1,184 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescController implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_FINAL_REPORT_DATA] = new ParamItem( + PrmMng::PARAM_FINAL_REPORT_DATA, + ParamItem::TYPE_ARRAY_MIXED, + array( + 'default' => array( + 'extraction' => array( + 'table_count' => 0, + 'table_rows' => 0, + 'query_errs' => 0, + ), + 'replace' => array( + 'scan_tables' => 0, + 'scan_rows' => 0, + 'scan_cells' => 0, + 'updt_tables' => 0, + 'updt_rows' => 0, + 'updt_cells' => 0, + 'errsql' => 0, + 'errser' => 0, + 'errkey' => 0, + 'errsql_sum' => 0, + 'errser_sum' => 0, + 'errkey_sum' => 0, + 'err_all' => 0, + 'warn_all' => 0, + 'warnlist' => array() + ) + ) + ) + ); + + $params[PrmMng::PARAM_INSTALLER_MODE] = new ParamItem( + PrmMng::PARAM_INSTALLER_MODE, + ParamItem::TYPE_INT, + array( + 'default' => \DUPX_InstallerState::MODE_UNKNOWN, + 'acceptValues' => array( + \DUPX_InstallerState::MODE_UNKNOWN, + \DUPX_InstallerState::MODE_STD_INSTALL, + \DUPX_InstallerState::MODE_OVR_INSTALL + ) + ) + ); + + $params[PrmMng::PARAM_OVERWRITE_SITE_DATA] = new ParamItem( + PrmMng::PARAM_OVERWRITE_SITE_DATA, + ParamItem::TYPE_ARRAY_MIXED, + array( + 'default' => DUPX_InstallerState::overwriteDataDefault() + ) + ); + + + $params[PrmMng::PARAM_DEBUG] = new ParamItem( + PrmMng::PARAM_DEBUG, + ParamItem::TYPE_BOOL, + array( + 'persistence' => true, + 'default' => false + ) + ); + + $params[PrmMng::PARAM_DEBUG_PARAMS] = new ParamItem( + PrmMng::PARAM_DEBUG_PARAMS, + ParamItem::TYPE_BOOL, + array( + 'persistence' => true, + 'default' => false + ) + ); + + $params[PrmMng::PARAM_CTRL_ACTION] = new ParamItem( + PrmMng::PARAM_CTRL_ACTION, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_HIDDEN, + array( + 'persistence' => false, + 'default' => '', + 'acceptValues' => array( + '', + 'ajax', + 'secure', + 'ctrl-step1', + 'ctrl-step2', + 'ctrl-step3', + 'ctrl-step4', + 'help' + )) + ); + + $params[PrmMng::PARAM_STEP_ACTION] = new ParamItem( + PrmMng::PARAM_STEP_ACTION, + ParamForm::TYPE_STRING, + array( + 'persistence' => false, + 'default' => '', + 'acceptValues' => array( + '', + \DUPX_CTRL::ACTION_STEP_INIZIALIZED, + \DUPX_CTRL::ACTION_STEP_ON_VALIDATE, + \DUPX_CTRL::ACTION_STEP_SET_TEMPLATE + )) + ); + + $params[\DUPX_Security::CTRL_TOKEN] = new ParamItem( + \DUPX_Security::CTRL_TOKEN, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_HIDDEN, + array( + 'persistence' => false, + 'default' => null, + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline') + ) + ); + + $params[PrmMng::PARAM_ROUTER_ACTION] = new ParamItem( + PrmMng::PARAM_ROUTER_ACTION, + ParamItem::TYPE_STRING, + array( + 'persistence' => false, + 'default' => 'router', + 'acceptValues' => array( + 'router' + )) + ); + + $params[PrmMng::PARAM_TEMPLATE] = new ParamItem( + PrmMng::PARAM_TEMPLATE, + ParamForm::TYPE_STRING, + array( + 'default' => \DUPX_Template::TEMPLATE_BASE, + 'acceptValues' => array( + \DUPX_Template::TEMPLATE_BASE, + \DUPX_Template::TEMPLATE_ADVANCED, + \DUPX_Template::TEMPLATE_IMPORT_BASE, + \DUPX_Template::TEMPLATE_IMPORT_ADVANCED + )) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescDatabase.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescDatabase.php new file mode 100644 index 00000000..6a2afeb9 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescDatabase.php @@ -0,0 +1,506 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Descriptors\ParamsDescriptors; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamOption; +use Duplicator\Installer\Core\Params\Items\ParamFormTables; +use Duplicator\Installer\Core\Params\Items\ParamFormPass; +use Duplicator\Installer\Utils\Log\Log; +use Duplicator\Libs\Snap\SnapJson; +use Duplicator\Libs\Snap\SnapUtil; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescDatabase implements DescriptorInterface +{ + const INVALID_EMPTY = 'can\'t be empty'; + const EMPTY_COLLATION_LABEL = ' --- DEFAULT --- '; + const DEFAULT_CHARSET_POSTFIX = ' (Default)'; + const DEFAULT_COLLATE_POSTFIX = ' (Default)'; + const SPLIT_CREATE_MAX_VALUE_TO_DEFAULT = 200; + + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + + $params[PrmMng::PARAM_DB_DISPLAY_OVERWIRE_WARNING] = new ParamItem( + PrmMng::PARAM_DB_DISPLAY_OVERWIRE_WARNING, + ParamItem::TYPE_BOOL, + array( + 'default' => true + ) + ); + + $params[PrmMng::PARAM_DB_VIEW_MODE] = new ParamForm( + PrmMng::PARAM_DB_VIEW_MODE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_BGROUP, + array( + 'default' => 'basic', + 'acceptValues' => array( + 'basic', + 'cpnl' + ) + ), + array( + 'label' => 'Database view mode', + 'renderLabel' => false, + 'options' => array( + new ParamOption('basic', 'Default'), + new ParamOption('cpnl', 'cPanel') + ), + 'wrapperClasses' => array('revalidate-on-change', 'align-right'), + 'inputContainerClasses' => array('small') + ) + ); + + $params[PrmMng::PARAM_DB_HOST] = new ParamForm( + PrmMng::PARAM_DB_HOST, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'persistence' => true, + 'default' => 'localhost', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline'), + 'validateCallback' => array(__CLASS__, 'validateNoEmptyIfBasic'), + 'invalidMessage' => self::INVALID_EMPTY + ), + array( + 'label' => 'Host:', + 'wrapperClasses' => array('revalidate-on-change'), + 'attr' => array( + 'required' => 'required', + 'placeholder' => 'localhost' + ) + ) + ); + + $params[PrmMng::PARAM_DB_NAME] = new ParamForm( + PrmMng::PARAM_DB_NAME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'persistence' => true, + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline'), + 'validateCallback' => array(__CLASS__, 'validateNoEmptyIfBasic'), + 'invalidMessage' => self::INVALID_EMPTY + ), + array( + 'label' => 'Database:', + 'wrapperClasses' => array('revalidate-on-change'), + 'attr' => array( + 'required' => 'required', + 'placeholder' => 'new or existing database name' + ), + 'subNote' => dupxTplRender('parts/params/db-name-notes', array(), false) + ) + ); + + $params[PrmMng::PARAM_DB_USER] = new ParamForm( + PrmMng::PARAM_DB_USER, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'persistence' => true, + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline'), + 'validateCallback' => array(__CLASS__, 'validateNoEmptyIfBasic'), + 'invalidMessage' => self::INVALID_EMPTY + ), + array( + 'label' => 'User:', + 'wrapperClasses' => array('revalidate-on-change'), + 'attr' => array( + 'placeholder' => 'valid database username', + // Can be written field wise + // Ref. https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion + 'autocomplete' => "off" + ) + ) + ); + + $params[PrmMng::PARAM_DB_PASS] = new ParamFormPass( + PrmMng::PARAM_DB_PASS, + ParamFormPass::TYPE_STRING, + ParamFormPass::FORM_TYPE_PWD_TOGGLE, + array( + 'persistence' => true, + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline') + ), + array( + 'label' => 'Password:', + 'wrapperClasses' => array('revalidate-on-change'), + 'attr' => array( + 'placeholder' => 'valid database user password', + // Can be written field wise + // Ref. https://devBasicBasiceloper.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion + 'autocomplete' => "off" + ) + ) + ); + + $params[PrmMng::PARAM_DB_FLAG] = new ParamItem( + PrmMng::PARAM_DB_FLAG, + ParamForm::TYPE_INT, + array( + 'default' => \DUPX_DB::DB_CONNECTION_FLAG_NOT_SET, + 'acceptValues' => function (ParamItem $param) { + $result = array( + \DUPX_DB::MYSQLI_CLIENT_NO_FLAGS, + MYSQLI_CLIENT_SSL, + ); + if (defined("MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT")) { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.mysqli_client_ssl_dont_verify_server_certFound + $result[] = MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; + } + return $result; + } + ) + ); + + $params[PrmMng::PARAM_DB_CHARSET] = new ParamForm( + PrmMng::PARAM_DB_CHARSET, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => $archiveConfig->getWpConfigDefineValue('DB_CHARSET', ''), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateRegex' => ParamForm::VALIDATE_REGEX_AZ_NUMBER_SEP_EMPTY + ), + array( + 'label' => 'Charset:', + 'status' => function (ParamForm $param) { + if (DUPX_InstallerState::isRestoreBackup()) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array(__CLASS__, 'getCharsetSelectOptions') + ) + ); + + $params[PrmMng::PARAM_DB_COLLATE] = new ParamForm( + PrmMng::PARAM_DB_COLLATE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => $archiveConfig->getWpConfigDefineValue('DB_COLLATE', ''), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateRegex' => ParamForm::VALIDATE_REGEX_AZ_NUMBER_SEP_EMPTY + ), + array( + 'label' => 'Collation:', + 'status' => function () { + if (DUPX_InstallerState::isRestoreBackup()) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array(__CLASS__, 'getCollationSelectOptions') + ) + ); + + $params[PrmMng::PARAM_DB_TABLE_PREFIX] = new ParamForm( + PrmMng::PARAM_DB_TABLE_PREFIX, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => \DUPX_ArchiveConfig::getInstance()->wp_tableprefix, + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateRegex' => ParamForm::VALIDATE_REGEX_AZ_NUMBER_SEP + ), + array( + 'status' => function () { + return ParamForm::STATUS_DISABLED; + }, + 'label' => 'Table Prefix:', + 'proFlagTitle' => 'Upgrade Features', + 'proFlag' => '

          Enhance the install experiance by changing the table prefix to a new name during installation.

          ' + ) + ); + + $params[PrmMng::PARAM_DB_VIEW_CREATION] = new ParamForm( + PrmMng::PARAM_DB_VIEW_CREATION, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => true + ), + array( + 'label' => 'Objects:', + 'checkboxLabel' => 'Enable View Creation' + ) + ); + + $params[PrmMng::PARAM_DB_PROC_CREATION] = new ParamForm( + PrmMng::PARAM_DB_PROC_CREATION, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => true + ), + array( + 'label' => ' ', + 'checkboxLabel' => 'Enable Stored Procedure Creation' + ) + ); + + $params[PrmMng::PARAM_DB_FUNC_CREATION] = new ParamForm( + PrmMng::PARAM_DB_FUNC_CREATION, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => true + ), + array( + 'label' => ' ', + 'checkboxLabel' => 'Enable Function Creation' + ) + ); + + $params[PrmMng::PARAM_DB_REMOVE_DEFINER] = new ParamForm( + PrmMng::PARAM_DB_REMOVE_DEFINER, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => ' ', + 'checkboxLabel' => 'Remove security DEFINER declarations' + ) + ); + + $numTables = count((array) \DUPX_ArchiveConfig::getInstance()->dbInfo->tablesList); + $params[PrmMng::PARAM_DB_SPLIT_CREATES] = new ParamForm( + PrmMng::PARAM_DB_SPLIT_CREATES, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => ($numTables > self::SPLIT_CREATE_MAX_VALUE_TO_DEFAULT ? false : true) + ), + array( + 'label' => 'Create:', + 'checkboxLabel' => 'Run all CREATE SQL statements at once' + ) + ); + + $newObj = new ParamForm( + PrmMng::PARAM_DB_MYSQL_MODE_OPTS, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'validateRegex' => '/^[A-Za-z0-9_\-,]*$/', // db options with , and can be empty + 'sanitizeCallback' => function ($value) { + $value = SnapUtil::sanitizeNSCharsNewlineTrim($value); + return str_replace(' ', '', $value); + }, + ), + array( + 'label' => ' ', // for aligment at PARAM_DB_MYSQL_MODE + 'wrapperClasses' => 'no-display', + 'subNote' => 'Separate additional ' . \DUPX_View_Funcs::helpLink('step2', 'sql modes', false) . ' with commas & no spaces.
          ' + . 'Example: NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,....' + ) + ); + $params[PrmMng::PARAM_DB_MYSQL_MODE_OPTS] = $newObj; + $modeOptsWrapper = $newObj->getFormWrapperId(); + + $params[PrmMng::PARAM_DB_MYSQL_MODE] = new ParamForm( + PrmMng::PARAM_DB_MYSQL_MODE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_RADIO, + array( + 'default' => 'DEFAULT', + 'acceptValues' => array( + 'DEFAULT', + 'DISABLE', + 'CUSTOM' + ) + ), + array( + 'label' => 'Mode:', + 'options' => array( + new ParamOption('DEFAULT', 'Default', ParamOption::OPT_ENABLED, array( + 'onchange' => "if ($(this).is(':checked')) { " + . "jQuery('#" . $modeOptsWrapper . "').addClass('no-display');" + . "}" + )), + new ParamOption('DISABLE', 'Disable', ParamOption::OPT_ENABLED, array( + 'onchange' => "if ($(this).is(':checked')) { " + . "jQuery('#" . $modeOptsWrapper . "').addClass('no-display');" + . "}" + )), + new ParamOption('CUSTOM', 'Custom', ParamOption::OPT_ENABLED, array( + 'onchange' => "if ($(this).is(':checked')) { " + . "jQuery('#" . $modeOptsWrapper . "').removeClass('no-display');" + . "}")), + )) + ); + + $params[PrmMng::PARAM_DB_TABLES] = new ParamFormTables( + PrmMng::PARAM_DB_TABLES, + ParamFormTables::TYPE_ARRAY_TABLES, + ParamFormTables::FORM_TYPE_TABLES_SELECT, + array(// ITEM ATTRIBUTES + 'default' => array() + ), + array(// FORM ATTRIBUTES + 'label' => 'Tables', + 'renderLabel' => false, + 'status' => function (ParamForm $paramObj) { + if (DUPX_InstallerState::isRestoreBackup()) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + } + ) + ); + } + + /** + * Validate function for database params + * + * @param mixed $value input value + * @param ParamItem $paramObj current param object + * + * @return boolean + */ + public static function validateNoEmptyIfBasic($value, ParamItem $paramObj) + { + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_VIEW_MODE) !== 'basic') { + return true; + } + + return ParamsDescriptors::validateNotEmpty($value, $paramObj); + } + + /** + * Get charset options list + * + * @return ParamOption[] + */ + public static function getCharsetSelectOptions() + { + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_VALIDATION_LEVEL) < \DUPX_Validation_manager::MIN_LEVEL_VALID) { + return array(); + } + + $data = \DUPX_DB_Functions::getInstance()->getCharsetAndCollationData(); + $charsetDef = \DUPX_DB_Functions::getInstance()->getDefaultCharset(); + + $options = array(); + + foreach ($data as $charset => $charsetInfo) { + $label = $charset . ($charset == $charsetDef ? self::DEFAULT_CHARSET_POSTFIX : ''); + $options[] = new ParamOption($charset, $label, ParamOption::OPT_ENABLED, array( + 'data-collations' => json_encode($charsetInfo['collations']), + 'data-collation-default' => $charsetInfo['defCollation'] + )); + } + + return $options; + } + + /** + * Get collation options list + * + * @return ParamOption[] + */ + public static function getCollationSelectOptions() + { + $options = array( + new ParamOption('', self::EMPTY_COLLATION_LABEL) + ); + + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_VALIDATION_LEVEL) < \DUPX_Validation_manager::MIN_LEVEL_VALID) { + return $options; + } + + $data = \DUPX_DB_Functions::getInstance()->getCharsetAndCollationData(); + $currentCharset = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_CHARSET); + + if (!isset($data[$currentCharset])) { + return $options; + } + + $defaultCollation = \DUPX_DB_Functions::getInstance()->getDefaultCollateOfCharset($currentCharset); + // if charset exists update default + $options = array( + new ParamOption('', self::EMPTY_COLLATION_LABEL . ' [' . $defaultCollation . ']') + ); + + foreach ($data[$currentCharset]['collations'] as $collation) { + $label = $collation . ($collation == $data[$currentCharset]['defCollation'] ? self::DEFAULT_COLLATE_POSTFIX : ''); + $options[] = new ParamOption($collation, $label); + } + + return $options; + } + + /** + * Update Charset and collate param by database settings + * + * @return void + */ + public static function updateCharsetAndCollateByDatabaseSettings() + { + $paramsManager = PrmMng::getInstance(); + $data = \DUPX_DB_Functions::getInstance()->getCharsetAndCollationData(); + $charsetDef = \DUPX_DB_Functions::getInstance()->getDefaultCharset(); + + $currentCharset = $paramsManager->getValue(PrmMng::PARAM_DB_CHARSET); + $currentCollate = $paramsManager->getValue(PrmMng::PARAM_DB_COLLATE); + + if (!array_key_exists($currentCharset, $data)) { + $paramsManager->setValue(PrmMng::PARAM_DB_CHARSET, $charsetDef); + $paramsManager->setValue(PrmMng::PARAM_DB_COLLATE, ''); + Log::info('DEFAULT DB_CHARSET [' . $currentCharset . '] isn\'t valid, update DB_CHARSET to ' . $charsetDef . ' and DB_COLLATE set empty'); + } elseif (strlen($currentCollate) > 0 && !in_array($currentCollate, $data[$currentCharset]['collations'])) { + $paramsManager->setValue(PrmMng::PARAM_DB_COLLATE, ''); + Log::info('DEFAULT DB_COLLATE [' . $currentCollate . '] isn\'t valid, DB_COLLATE set empty'); + } + $paramsManager->save(); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + $params[PrmMng::PARAM_DB_TABLES]->setValue(\DUPX_DB_Tables::getInstance()->getDefaultParamValue()); + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescEngines.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescEngines.php new file mode 100644 index 00000000..2a5462bb --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescEngines.php @@ -0,0 +1,446 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use DUP_Extraction; +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamOption; +use DUPX_InstallerState; +use DUPX_ArchiveConfig; +use Duplicator\Installer\Utils\LinkManager; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescEngines implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + + $params[PrmMng::PARAM_ARCHIVE_ACTION] = new ParamForm( + PrmMng::PARAM_ARCHIVE_ACTION, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => DUP_Extraction::ACTION_DO_NOTHING, + 'acceptValues' => array( + DUP_Extraction::ACTION_DO_NOTHING, + DUP_Extraction::ACTION_REMOVE_WP_FILES, + DUP_Extraction::ACTION_REMOVE_ALL_FILES + ) + ), + array( + 'label' => 'Archive Action:', + 'status' => function ($paramObj) { + if (DUPX_InstallerState::isRestoreBackup()) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array( + new ParamOption(DUP_Extraction::ACTION_DO_NOTHING, 'Extract files over current files'), + new ParamOption(DUP_Extraction::ACTION_REMOVE_WP_FILES, 'Remove WordPress core and content and extract (Pro)', ParamOption::OPT_DISABLED), + new ParamOption(DUP_Extraction::ACTION_REMOVE_ALL_FILES, 'Remove all files except addon sites and extract (Pro)', ParamOption::OPT_DISABLED), + new ParamOption(DUP_Extraction::ACTION_REMOVE_UPLOADS, 'Empty only uploads folder (Pro)', ParamOption::OPT_DISABLED) + ), + 'wrapperClasses' => array('revalidate-on-change'), + 'subNote' => function ($param) { + return dupxTplRender('parts/params/archive-action-notes', array( + 'currentAction' => $param->getValue() + ), false); + }, + // Temporarly diabled for inital release 1.5 + // 'proFlagTitle' => 'Upgrade Features', + // 'proFlag' => 'Enhance the install experience with custom extraction modes. + // When performing an overwrite install process users can ' + // . 'automate and customize that files they need to be installed.' + ) + ); + + $params[PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES] = new ParamForm( + PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => DUP_Extraction::FILTER_NONE, + 'acceptValues' => array(DUP_Extraction::FILTER_NONE) + ), + array( + 'label' => 'Skip Files:', + 'status' => ParamForm::STATUS_ENABLED, + 'options' => array( + new ParamOption(DUP_Extraction::FILTER_NONE, 'Extract all files'), + new ParamOption(DUP_Extraction::FILTER_SKIP_WP_CORE, 'Skip extraction of WordPress core files (Pro)', ParamOption::OPT_DISABLED), + new ParamOption( + DUP_Extraction::FILTER_SKIP_CORE_PLUG_THEMES, + 'Skip extraction of WordPress core files and plugins/themes existing on host (Pro)', + ParamOption::OPT_DISABLED + ), + new ParamOption( + DUP_Extraction::FILTER_ONLY_MEDIA_PLUG_THEMES, + 'Extract only media files and new plugins/themes (Pro)', + ParamOption::OPT_DISABLED + ) + ), + 'wrapperClasses' => array('revalidate-on-change'), + 'subNote' => dupxTplRender('parts/params/extract-skip-notes', array( + 'currentSkipMode' => DUP_Extraction::FILTER_NONE + ), false), + // Temporarly diabled for inital release 1.5 + // 'proFlagTitle' => 'Upgrade Features', + // 'proFlag' => 'Exclude plugins and themes from extraction so as not to overwrite existing ones' . + // '
            ' . + // '
          • Skip extraction of WP core files
          • ' . + // '
          • Skip extraction of WP core files & plugins/themes existing on the host
          • ' . + // '
          • Extract only media files & new plugins/themes
          • ' . + // '
          ' + ) + ); + + $engineOptions = self::getArchiveEngineOptions(); + + $params[PrmMng::PARAM_ARCHIVE_ENGINE] = new ParamForm( + PrmMng::PARAM_ARCHIVE_ENGINE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => $engineOptions['default'], + 'acceptValues' => $engineOptions['acceptValues'], + 'sanitizeCallback' => function ($value) { + if ( + PrmMng::getInstance()->getValue( + PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES + ) !== DUP_Extraction::FILTER_NONE && $value === DUP_Extraction::ENGINE_ZIP_SHELL + ) { + return DUP_Extraction::ENGINE_ZIP_CHUNK; + } + return $value; + } + ), + array( + 'label' => 'Extraction Mode:', + 'options' => $engineOptions['options'], + 'size' => 0, + 'subNote' => $engineOptions['subNote'], + 'attr' => array( + 'onchange' => 'DUPX.onSafeModeSwitch();' + ) + ) + ); + + $params[PrmMng::PARAM_ZIP_THROTTLING] = new ParamForm( + PrmMng::PARAM_ZIP_THROTTLING, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Server Throttling:', + 'checkboxLabel' => 'Enable archive extraction throttling', + 'status' => function () { + if ( + PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE) === DUP_Extraction::ENGINE_ZIP + || PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE) === DUP_Extraction::ENGINE_ZIP_CHUNK + ) { + return ParamForm::STATUS_ENABLED; + } else { + return ParamForm::STATUS_DISABLED; + } + }, + 'subNote' => '* This option is only available with Zip Formats' + ) + ); + + $params[PrmMng::PARAM_DB_ACTION] = new ParamForm( + PrmMng::PARAM_DB_ACTION, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => 'empty', + 'acceptValues' => array( + \DUPX_DBInstall::DBACTION_CREATE, + \DUPX_DBInstall::DBACTION_EMPTY, + \DUPX_DBInstall::DBACTION_REMOVE_ONLY_TABLES, + \DUPX_DBInstall::DBACTION_RENAME, + \DUPX_DBInstall::DBACTION_MANUAL, + \DUPX_DBInstall::DBACTION_ONLY_CONNECT + ) + ), + array( + 'label' => 'Action:', + 'status' => function ($paramObj) { + if ( + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'wrapperClasses' => array('revalidate-on-change'), + 'options' => array( + new ParamOption(\DUPX_DBInstall::DBACTION_EMPTY, 'Empty Database'), + new ParamOption(\DUPX_DBInstall::DBACTION_RENAME, 'Backup Existing Tables'), + new ParamOption(\DUPX_DBInstall::DBACTION_ONLY_CONNECT, 'Do Nothing (Advanced)', ParamOption::OPT_HIDDEN), + new ParamOption(\DUPX_DBInstall::DBACTION_MANUAL, 'Skip Database Extraction'), + new ParamOption(\DUPX_DBInstall::DBACTION_CREATE, 'Create New Database'), + new ParamOption(\DUPX_DBInstall::DBACTION_REMOVE_ONLY_TABLES, 'Overwrite Existing Tables (Pro)', ParamOption::OPT_DISABLED), + ), + // Temporarly diabled for inital release 1.5 + // 'proFlagTitle' => 'Upgrade Features', + // 'proFlag' => + // 'Duplicator Pro offers these additional actions on the database for greater flexibility.' + // . '
            ' . + // '
          • Create New Database
          • ' . + // '
          • Overwrite Existing Tables
          • ' . + // '
          ' . + // 'Users can create a new database on supported servers or act only on installation-specific tables without touching ' + // . 'others tables. This process is useful if you want to install multiple instances of worpdress in the same database.' + ) + ); + + $params[PrmMng::PARAM_DB_ENGINE] = new ParamForm( + PrmMng::PARAM_DB_ENGINE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => \DUPX_DBInstall::ENGINE_CHUNK, + 'acceptValues' => array( + \DUPX_DBInstall::ENGINE_CHUNK, + \DUPX_DBInstall::ENGINE_NORMAL + )), + array( + 'label' => 'Processing:', + 'size' => 0, + 'options' => array( + new ParamOption(\DUPX_DBInstall::ENGINE_CHUNK, 'Chunking mode'), + new ParamOption(\DUPX_DBInstall::ENGINE_NORMAL, 'Single step') + )) + ); + + $params[PrmMng::PARAM_DB_CHUNK] = new ParamItem( + PrmMng::PARAM_DB_CHUNK, + ParamForm::TYPE_BOOL, + array( + 'default' => ($params[PrmMng::PARAM_DB_ENGINE]->getValue() === \DUPX_DBInstall::ENGINE_CHUNK) + ) + ); + + $params[PrmMng::PARAM_REPLACE_ENGINE] = new ParamItem( + PrmMng::PARAM_REPLACE_ENGINE, + ParamForm::TYPE_INT, + array( + 'default' => \DUPX_S3_Funcs::MODE_CHUNK, + 'acceptValues' => array( + \DUPX_S3_Funcs::MODE_NORMAL, + \DUPX_S3_Funcs::MODE_CHUNK, + \DUPX_S3_Funcs::MODE_SKIP, + )) + ); + + $oldHomePath = DUPX_ArchiveConfig::getInstance()->getRealValue('archivePaths')->home; + $params[PrmMng::PARAM_SKIP_PATH_REPLACE] = new ParamForm( + PrmMng::PARAM_SKIP_PATH_REPLACE, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => in_array($oldHomePath, array('', '/html')) + ), + array( + 'label' => 'Skip Path Replace:', + 'checkboxLabel' => 'Skips the replacement of the source path', + 'status' => function (ParamForm $paramObj) { + $sourcePath = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_OLD); + if (strlen($sourcePath) == 0) { + return ParamForm::STATUS_DISABLED; + } else { + return ParamForm::STATUS_ENABLED; + } + } + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + if ( + $params[PrmMng::PARAM_ARCHIVE_ACTION]->getStatus() !== ParamItem::STATUS_OVERWRITE && + DUPX_InstallerState::isRestoreBackup($params[PrmMng::PARAM_INST_TYPE]->getValue()) + ) { + $params[PrmMng::PARAM_ARCHIVE_ACTION]->setValue(DUP_Extraction::ACTION_REMOVE_WP_FILES); + } + + if (DUPX_InstallerState::isRestoreBackup($params[PrmMng::PARAM_INST_TYPE]->getValue())) { + $default = \DUPX_S3_Funcs::MODE_SKIP; + } elseif ($params[PrmMng::PARAM_DB_ENGINE]->getValue() === \DUPX_DBInstall::ENGINE_CHUNK) { + $default = \DUPX_S3_Funcs::MODE_CHUNK; + } else { + $default = \DUPX_S3_Funcs::MODE_NORMAL; + } + $params[PrmMng::PARAM_REPLACE_ENGINE]->setValue($default); + + if ( + ($params[PrmMng::PARAM_ARCHIVE_ENGINE]->getValue() === DUP_Extraction::ENGINE_ZIP + || $params[PrmMng::PARAM_ARCHIVE_ENGINE]->getValue() === DUP_Extraction::ENGINE_ZIP_CHUNK) + && \DUPX_Custom_Host_Manager::getInstance()->isHosting(\DUPX_Custom_Host_Manager::HOST_SITEGROUND) + ) { + $params[PrmMng::PARAM_ZIP_THROTTLING]->setValue(true); + } + } + + /** + * Get db chunk engine value + * + * @return boolean + */ + public static function getDbChunkFromParams() + { + return PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_ENGINE) === \DUPX_DBInstall::ENGINE_CHUNK; + } + + /** + * Get replace engine mode + * + * @return integer + */ + public static function getReplaceEngineModeFromParams() + { + $paramsManager = PrmMng::getInstance(); + if (DUPX_InstallerState::isRestoreBackup()) { + return \DUPX_S3_Funcs::MODE_SKIP; + } elseif ($paramsManager->getValue(PrmMng::PARAM_DB_ENGINE) === \DUPX_DBInstall::ENGINE_CHUNK) { + return \DUPX_S3_Funcs::MODE_CHUNK; + } else { + return \DUPX_S3_Funcs::MODE_NORMAL; + } + } + + + /** + * Get archive engine options + * + * @return array + */ + private static function getArchiveEngineOptions() + { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + + $acceptValues = array(); + $subNote = null; + if (($manualEnable = \DUPX_Conf_Utils::isManualExtractFilePresent()) === true) { + $acceptValues[] = DUP_Extraction::ENGINE_MANUAL; + } else { + $faqUrl = LinkManager::getDocUrl('how-to-handle-various-install-scenarios', 'install', 'archive engine subnote'); + $subNote = <<[more info] +SUBNOTEHTML; + } + if (($zipEnable = ($archiveConfig->isZipArchive() && \DUPX_Conf_Utils::archiveExists() && \DUPX_Conf_Utils::classZipArchiveEnable())) === true) { + $acceptValues[] = DUP_Extraction::ENGINE_ZIP; + $acceptValues[] = DUP_Extraction::ENGINE_ZIP_CHUNK; + } + if (($shellZipEnable = ($archiveConfig->isZipArchive() && \DUPX_Conf_Utils::archiveExists() && \DUPX_Conf_Utils::shellExecUnzipEnable())) === true) { + $acceptValues[] = DUP_Extraction::ENGINE_ZIP_SHELL; + } + if (($dupEnable = (!$archiveConfig->isZipArchive() && \DUPX_Conf_Utils::archiveExists())) === true) { + $acceptValues[] = DUP_Extraction::ENGINE_DUP; + } + + $options = array(); + $options[] = new ParamOption( + DUP_Extraction::ENGINE_MANUAL, + 'Manual Archive Extraction', + $manualEnable ? ParamOption::OPT_ENABLED : ParamOption::OPT_DISABLED + ); + + if ($archiveConfig->isZipArchive()) { + //ZIP-ARCHIVE + $options[] = new ParamOption( + DUP_Extraction::ENGINE_ZIP, + 'PHP ZipArchive', + $zipEnable ? ParamOption::OPT_ENABLED : ParamOption::OPT_DISABLED + ); + + $options[] = new ParamOption( + DUP_Extraction::ENGINE_ZIP_CHUNK, + 'PHP ZipArchive Chunking', + $zipEnable ? ParamOption::OPT_ENABLED : ParamOption::OPT_DISABLED + ); + + $options[] = new ParamOption( + DUP_Extraction::ENGINE_ZIP_SHELL, + 'Shell Exec Unzip', + function () { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + $pathsMapping = $archiveConfig->getPathsMapping(); + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES) !== DUP_Extraction::FILTER_NONE) { + return ParamOption::OPT_DISABLED; + } + if (is_array($pathsMapping) && count($pathsMapping) > 1) { + return ParamOption::OPT_DISABLED; + } + if ($archiveConfig->isZipArchive() && \DUPX_Conf_Utils::archiveExists() && \DUPX_Conf_Utils::shellExecUnzipEnable()) { + return ParamOption::OPT_ENABLED; + } + return ParamOption::OPT_DISABLED; + } + ); + } else { + // DUPARCHIVE + $options[] = new ParamOption( + DUP_Extraction::ENGINE_DUP, + 'DupArchive', + $dupEnable ? ParamOption::OPT_ENABLED : ParamOption::OPT_DISABLED + ); + } + + if ($manualEnable) { + $default = DUP_Extraction::ENGINE_MANUAL; + } elseif ($zipEnable) { + $default = DUP_Extraction::ENGINE_ZIP_CHUNK; + } elseif ($shellZipEnable) { + $default = DUP_Extraction::ENGINE_ZIP_SHELL; + } elseif ($dupEnable) { + $default = DUP_Extraction::ENGINE_DUP; + } else { + $default = null; + } + + return array( + 'options' => $options, + 'acceptValues' => $acceptValues, + 'default' => $default, + 'subNote' => $subNote + ); + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescGeneric.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescGeneric.php new file mode 100644 index 00000000..468229e0 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescGeneric.php @@ -0,0 +1,299 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamOption; +use Duplicator\Installer\Core\Params\Items\ParamFormPass; +use Duplicator\Installer\Utils\Log\Log; +use Duplicator\Libs\Snap\SnapOS; +use DUPX_ArchiveConfig; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescGeneric implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $newObj = new ParamForm( + PrmMng::PARAM_FILE_PERMS_VALUE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '644', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateRegex' => '/^[ugorwx,\s\+\-0-7]+$/' // octal + ugo rwx, + ), + array( + 'label' => 'File permissions', + 'renderLabel' => false, + 'status' => SnapOS::isWindows() ? ParamForm::STATUS_SKIP : ParamForm::STATUS_ENABLED, + 'wrapperClasses' => array('display-inline-block') + ) + ); + + $params[PrmMng::PARAM_FILE_PERMS_VALUE] = $newObj; + $permItemId = $newObj->getFormItemId(); + $params[PrmMng::PARAM_SET_FILE_PERMS] = new ParamForm( + PrmMng::PARAM_SET_FILE_PERMS, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_SWITCH, + array( + 'default' => !SnapOS::isWindows() + ), + array( + 'status' => SnapOS::isWindows() ? ParamForm::STATUS_SKIP : ParamForm::STATUS_ENABLED, + 'label' => 'File permissions:', + 'checkboxLabel' => 'All files', + 'wrapperClasses' => array('display-inline-block'), + 'attr' => array( + 'onclick' => "jQuery('#" . $permItemId . "').prop('disabled', !jQuery(this).is(':checked'));" + ) + ) + ); + + $newObj = new ParamForm( + PrmMng::PARAM_DIR_PERMS_VALUE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '755', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateRegex' => '/^[ugorwx,\s\+\-0-7]+$/' // octal + ugo rwx + ), + array( + 'label' => 'Folder permissions', + 'renderLabel' => false, + 'status' => SnapOS::isWindows() ? ParamForm::STATUS_SKIP : ParamForm::STATUS_ENABLED, + 'wrapperClasses' => array('display-inline-block') + ) + ); + + $params[PrmMng::PARAM_DIR_PERMS_VALUE] = $newObj; + $permItemId = $newObj->getFormItemId(); + $params[PrmMng::PARAM_SET_DIR_PERMS] = new ParamForm( + PrmMng::PARAM_SET_DIR_PERMS, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_SWITCH, + array( + 'default' => !SnapOS::isWindows() + ), + array( + 'status' => SnapOS::isWindows() ? ParamForm::STATUS_SKIP : ParamForm::STATUS_ENABLED, + 'label' => 'Dir permissions:', + 'checkboxLabel' => 'All Directories', + 'wrapperClasses' => array('display-inline-block'), + 'attr' => array( + 'onclick' => "jQuery('#" . $permItemId . "').prop('disabled', !jQuery(this).is(':checked'));" + ) + ) + ); + + $params[PrmMng::PARAM_SAFE_MODE] = new ParamForm( + PrmMng::PARAM_SAFE_MODE, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => 0, + 'acceptValues' => array(0, 1, 2) + ), + array( + 'label' => 'Safe Mode:', + 'status' => function (ParamItem $paramObj) { + if (DUPX_InstallerState::isRestoreBackup()) { + return ParamForm::STATUS_DISABLED; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'options' => array( + new ParamOption(0, 'Disabled'), + new ParamOption(1, 'Enabled') + ), + 'attr' => array( + 'onchange' => 'DUPX.onSafeModeSwitch();' + ) + ) + ); + + $params[PrmMng::PARAM_FILE_TIME] = new ParamForm( + PrmMng::PARAM_FILE_TIME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_RADIO, + array( + 'default' => 'current', + 'acceptValues' => array( + 'current', + 'original' + ) + ), + array( + 'label' => 'File Times:', + 'status' => ParamForm::STATUS_ENABLED, + 'options' => array( + new ParamOption('current', 'Current', ParamOption::OPT_ENABLED, array('title' => 'Set the files current date time to now')), + new ParamOption('original', 'Original', ParamOption::OPT_ENABLED, array('title' => 'Keep the files date time the same')) + ), + 'subNote' => 'This option is not supported for extraction mode Shell Exec Unzip' + ) + ); + + $params[PrmMng::PARAM_LOGGING] = new ParamForm( + PrmMng::PARAM_LOGGING, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_RADIO, + array( + 'default' => Log::LV_DEFAULT, + 'acceptValues' => array( + Log::LV_DEFAULT, + Log::LV_DETAILED, + Log::LV_DEBUG, + Log::LV_HARD_DEBUG, + ) + ), + array( + 'label' => 'Logging:', + 'options' => array( + new ParamOption(Log::LV_DEFAULT, 'Light'), + new ParamOption(Log::LV_DETAILED, 'Detailed'), + new ParamOption(Log::LV_DEBUG, 'Debug'), + // enabled only with overwrite params + new ParamOption(Log::LV_HARD_DEBUG, 'Hard debug', ParamOption::OPT_HIDDEN) + ) + ) + ); + + $params[PrmMng::PARAM_REMOVE_RENDUNDANT] = new ParamForm( + PrmMng::PARAM_REMOVE_RENDUNDANT, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Cleanup:', + 'checkboxLabel' => 'Remove disabled plugins/themes (Pro)', + 'status' => ParamForm::STATUS_DISABLED, + 'proFlagTitle' => 'Upgrade Features', + 'proFlag' => '

          Improve the install cleanup and automation of additional tasks with these cleanup options that are available ' + . 'in Duplicator Pro.

          ' + ) + ); + + $params[PrmMng::PARAM_REMOVE_USERS_WITHOUT_PERMISSIONS] = new ParamForm( + PrmMng::PARAM_REMOVE_USERS_WITHOUT_PERMISSIONS, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => ' ', + 'checkboxLabel' => 'Remove users without permissions (Pro)', + 'status' => ParamForm::STATUS_DISABLED + ) + ); + + $params[PrmMng::PARAM_RECOVERY_LINK] = new ParamItem( + PrmMng::PARAM_RECOVERY_LINK, + ParamFormPass::TYPE_STRING, + array( + 'default' => '' + ) + ); + + $params[PrmMng::PARAM_FROM_SITE_IMPORT_INFO] = new ParamItem( + PrmMng::PARAM_FROM_SITE_IMPORT_INFO, + ParamFormPass::TYPE_ARRAY_MIXED, + array( + 'default' => array() + ) + ); + + $params[PrmMng::PARAM_AUTO_CLEAN_INSTALLER_FILES] = new ParamForm( + PrmMng::PARAM_AUTO_CLEAN_INSTALLER_FILES, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => true + ), + array( + 'label' => 'CLean installation files', + 'renderLabel' => false, + 'checkboxLabel' => 'Auto delete installer files after login to secure site (recommended!)' + ) + ); + + $params[PrmMng::PARAM_SUBSCRIBE_EMAIL] = new ParamForm( + PrmMng::PARAM_SUBSCRIBE_EMAIL, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'validateCallback' => function ($value, ParamItem $paramObj) { + if (strlen($value) < 4) { + $paramObj->setInvalidMessage('Email name must have 4 or more characters'); + return false; + } + + if (filter_var($value, FILTER_VALIDATE_EMAIL) == false) { + $paramObj->setInvalidMessage('Email "' . $value . '" isn\'t valid'); + return false; + } + + return true; + } + ), + array(// FORM ATTRIBUTES + 'label' => 'Subscribe to our newsletter:', + 'renderLabel' => false, + 'wrapperClasses' => array('subscribe-form'), + 'attr' => array( + 'placeholder' => 'Email Address' + ), + 'subNote' => 'Get tips and product updates straight to your inbox.', + 'status' => function ($paramObj) { + if ($paramObj->getValue() !== '') { + return ParamForm::STATUS_SKIP; + } + + return ParamForm::STATUS_ENABLED; + }, + 'postfix' => array('type' => 'button', 'label' => 'Subscribe', 'btnAction' => 'DUPX.submitEmail(this);') + + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescNewAdmin.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescNewAdmin.php new file mode 100644 index 00000000..2c4d544c --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescNewAdmin.php @@ -0,0 +1,233 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamFormPass; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescNewAdmin implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_WP_ADMIN_CREATE_NEW] = new ParamForm( + PrmMng::PARAM_WP_ADMIN_CREATE_NEW, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_SWITCH, + array( + 'default' => false + ), + array( + 'label' => 'Create New User:', + 'status' => function ($paramObj) { + if (ParamDescUsers::getUsersMode() != ParamDescUsers::USER_MODE_OVERWRITE) { + return ParamForm::STATUS_DISABLED; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'checkboxLabel' => '' + ) + ); + + $params[PrmMng::PARAM_WP_ADMIN_NAME] = new ParamForm( + PrmMng::PARAM_WP_ADMIN_NAME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateCallback' => function ($value, ParamItem $paramObj) { + if (!PrmMng::getInstance()->getValue(PrmMng::PARAM_WP_ADMIN_CREATE_NEW)) { + return true; + } + + if (strlen($value) < 4) { + $paramObj->setInvalidMessage('Must have 4 or more characters'); + return false; + } + + return true; + } + ), + array( + 'status' => array(__CLASS__, 'getStatuOfNewAdminParams'), + 'label' => 'Username:', + 'classes' => 'new-admin-field', + 'attr' => array( + 'title' => '4 characters minimum', + 'placeholder' => "(4 or more characters)" + ) + ) + ); + + $params[PrmMng::PARAM_WP_ADMIN_PASSWORD] = new ParamFormPass( + PrmMng::PARAM_WP_ADMIN_PASSWORD, + ParamFormPass::TYPE_STRING, + ParamFormPass::FORM_TYPE_PWD_TOGGLE, + array( + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateCallback' => function ($value, ParamItem $paramObj) { + if (!PrmMng::getInstance()->getValue(PrmMng::PARAM_WP_ADMIN_CREATE_NEW)) { + return true; + } + + if (strlen($value) < \DUPX_Constants::MIN_NEW_PASSWORD_LEN) { + $paramObj->setInvalidMessage('Must have ' . \DUPX_Constants::MIN_NEW_PASSWORD_LEN . ' or more characters'); + return false; + } + + return true; + } + ), + array( + 'status' => array(__CLASS__, 'getStatuOfNewAdminParams'), + 'label' => 'Password:', + 'classes' => array('strength-pwd-check', 'new-admin-field'), + 'attr' => array( + 'placeholder' => '(' . \DUPX_Constants::MIN_NEW_PASSWORD_LEN . ' or more characters)', + 'title' => \DUPX_Constants::MIN_NEW_PASSWORD_LEN . ' characters minimum' + ) + ) + ); + + $params[PrmMng::PARAM_WP_ADMIN_MAIL] = new ParamForm( + PrmMng::PARAM_WP_ADMIN_MAIL, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateCallback' => function ($value, ParamItem $paramObj) { + if (!PrmMng::getInstance()->getValue(PrmMng::PARAM_WP_ADMIN_CREATE_NEW)) { + return true; + } + + if (strlen($value) < 4) { + $paramObj->setInvalidMessage('Email name must have 4 or more characters'); + return false; + } + + if (filter_var($value, FILTER_VALIDATE_EMAIL) == false) { + $paramObj->setInvalidMessage('Email "' . $value . '" isn\'t valid'); + return false; + } + + return true; + } + ), + array( + 'status' => array(__CLASS__, 'getStatuOfNewAdminParams'), + 'label' => 'Email:', + 'classes' => 'new-admin-field', + 'attr' => array( + 'title' => '4 characters minimum', + 'placeholder' => "(4 or more characters)" + ) + ) + ); + + $params[PrmMng::PARAM_WP_ADMIN_NICKNAME] = new ParamForm( + PrmMng::PARAM_WP_ADMIN_NICKNAME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim') + ), + array( + 'status' => array(__CLASS__, 'getStatuOfNewAdminParams'), + 'label' => 'Nickname:', + 'classes' => 'new-admin-field', + 'attr' => array( + 'title' => 'if username is empty', + 'placeholder' => "(if username is empty)" + ) + ) + ); + + $params[PrmMng::PARAM_WP_ADMIN_FIRST_NAME] = new ParamForm( + PrmMng::PARAM_WP_ADMIN_FIRST_NAME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim') + ), + array( + 'status' => array(__CLASS__, 'getStatuOfNewAdminParams'), + 'label' => 'First Name:', + 'classes' => 'new-admin-field', + 'attr' => array( + 'title' => 'optional', + 'placeholder' => "(optional)" + ) + ) + ); + + $params[PrmMng::PARAM_WP_ADMIN_LAST_NAME] = new ParamForm( + PrmMng::PARAM_WP_ADMIN_LAST_NAME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim') + ), + array( + 'status' => array(__CLASS__, 'getStatuOfNewAdminParams'), + 'label' => 'Last Name:', + 'classes' => 'new-admin-field', + 'attr' => array( + 'title' => 'optional', + 'placeholder' => "(optional)" + ) + ) + ); + } + + /** + * + * @return string + */ + public static function getStatuOfNewAdminParams() + { + if (PrmMng::getInstance()->getValue(PrmMng::PARAM_WP_ADMIN_CREATE_NEW)) { + return ParamForm::STATUS_ENABLED; + } else { + return ParamForm::STATUS_DISABLED; + } + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescPlugins.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescPlugins.php new file mode 100644 index 00000000..a77fd02a --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescPlugins.php @@ -0,0 +1,88 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamFormPlugins; +use Duplicator\Libs\Snap\SnapUtil; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescPlugins implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_PLUGINS] = new ParamFormPlugins( + PrmMng::PARAM_PLUGINS, + ParamFormPlugins::TYPE_ARRAY_STRING, + ParamFormPlugins::FORM_TYPE_PLUGINS_SELECT, + array( + 'default' => array(), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline') + ), + array( + 'label' => 'Plugins', + 'renderLabel' => false, + 'status' => function ($paramObj) { + if ( + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_DISABLED; + } else { + return ParamForm::STATUS_ENABLED; + } + } + ) + ); + + $params[PrmMng::PARAM_IGNORE_PLUGINS] = new ParamItem( + PrmMng::PARAM_IGNORE_PLUGINS, + ParamItem::TYPE_ARRAY_STRING, + array( + 'default' => array(), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline'), + ) + ); + + $params[PrmMng::PARAM_FORCE_DIABLE_PLUGINS] = new ParamItem( + PrmMng::PARAM_FORCE_DIABLE_PLUGINS, + ParamItem::TYPE_ARRAY_STRING, + array( + 'default' => array(), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline'), + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescReplace.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescReplace.php new file mode 100644 index 00000000..3984da2b --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescReplace.php @@ -0,0 +1,128 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Libs\Snap\SnapUtil; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescReplace implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_BLOGNAME] = new ParamForm( + PrmMng::PARAM_BLOGNAME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'default' => '', + 'sanitizeCallback' => function ($value) { + $value = SnapUtil::sanitizeNSCharsNewline($value); + return htmlspecialchars_decode((empty($value) ? 'No Blog Title Set' : $value), ENT_QUOTES); + } + ), + array( + 'label' => 'Site Title:', + 'status' => function ($paramObj) { + if (DUPX_InstallerState::isRestoreBackup()) { + return ParamForm::STATUS_DISABLED; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'wrapperClasses' => array('revalidate-on-change'), + ) + ); + + $params[PrmMng::PARAM_EMAIL_REPLACE] = new ParamForm( + PrmMng::PARAM_EMAIL_REPLACE, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Email Domains:', + 'checkboxLabel' => 'Update' + ) + ); + + $params[PrmMng::PARAM_FULL_SEARCH] = new ParamForm( + PrmMng::PARAM_FULL_SEARCH, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Database Search:', + 'checkboxLabel' => 'Full Search Mode' + ) + ); + + $params[PrmMng::PARAM_POSTGUID] = new ParamForm( + PrmMng::PARAM_POSTGUID, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Post GUID:', + 'checkboxLabel' => 'Keep Unchanged' + ) + ); + + $params[PrmMng::PARAM_MAX_SERIALIZE_CHECK] = new ParamForm( + PrmMng::PARAM_MAX_SERIALIZE_CHECK, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_NUMBER, + array( + 'default' => \DUPX_Constants::DEFAULT_MAX_STRLEN_SERIALIZED_CHECK_IN_M + ), + array( + 'min' => 0, + 'max' => 99, + 'step' => 1, + 'wrapperClasses' => array('small'), + 'label' => 'Serialized Max Size:', + 'postfix' => array('type' => 'label', 'label' => 'MB'), + 'subNote' => 'If the serialized object stored in the database exceeds this size, it will not be parsed for replacement.' + . '
          Too large a size in low memory installations can generate a fatal error.' + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescSecurity.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescSecurity.php new file mode 100644 index 00000000..6e516e28 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescSecurity.php @@ -0,0 +1,110 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamFormPass; +use DUPX_ArchiveConfig; +use DUPX_InstallerState; +use DUPX_Security; +use DUPX_View_Funcs; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescSecurity implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_SECURE_PASS] = new ParamFormPass( + PrmMng::PARAM_SECURE_PASS, + ParamFormPass::TYPE_STRING, + ParamFormPass::FORM_TYPE_PWD_TOGGLE, + array( + 'persistence' => false, + 'default' => null, + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewline') + ), + array( + 'label' => 'Password:', + 'status' => function (ParamForm $param) { + if (DUPX_Security::getInstance()->getSecurityType() == DUPX_Security::SECURITY_PASSWORD) { + return ParamForm::STATUS_ENABLED; + } else { + return ParamForm::STATUS_DISABLED; + } + }, + 'wrapperClasses' => 'margin-bottom-1', + 'attr' => array( + 'placeholder' => (DUPX_ArchiveConfig::getInstance()->secure_on ? '' : 'Password not enabled') + ) + ) + ); + + $params[PrmMng::PARAM_SECURE_ARCHIVE_HASH] = new ParamForm( + PrmMng::PARAM_SECURE_ARCHIVE_HASH, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( + 'persistence' => false, + 'default' => null, + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim') + ), + array( + 'label' => 'Archive File Name:', + 'status' => function (ParamForm $param) { + if (!DUPX_InstallerState::isOverwrite()) { + return ParamForm::STATUS_SKIP; + } elseif (DUPX_Security::getInstance()->getSecurityType() == DUPX_Security::SECURITY_ARCHIVE) { + return ParamForm::STATUS_ENABLED; + } else { + return ParamForm::STATUS_DISABLED; + } + }, + 'wrapperClasses' => 'margin-bottom-4', + 'attr' => array( + 'placeholder' => 'example: [full-unique-name]_archive.zip' + ), + 'subNote' => DUPX_View_Funcs::helpLink('secure', 'How to get archive file name?', false) + ) + ); + + $params[PrmMng::PARAM_SECURE_OK] = new ParamItem( + PrmMng::PARAM_SECURE_OK, + ParamForm::TYPE_BOOL, + array( + 'default' => false + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescUrlsPaths.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescUrlsPaths.php new file mode 100644 index 00000000..24ac458e --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescUrlsPaths.php @@ -0,0 +1,498 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Libs\Snap\SnapIO; +use Duplicator\Libs\Snap\SnapJson; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescUrlsPaths implements DescriptorInterface +{ + const INVALID_PATH_EMPTY = 'can\'t be empty'; + const INVALID_URL_EMPTY = 'can\'t be empty'; + + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $archive_config = \DUPX_ArchiveConfig::getInstance(); + $paths = $archive_config->getRealValue('archivePaths'); + + $oldMainPath = $paths->home; + $newMainPath = DUPX_ROOT; + + $oldHomeUrl = rtrim($archive_config->getRealValue('homeUrl'), '/'); + $newHomeUrl = rtrim(DUPX_ROOT_URL, '/'); + + $oldSiteUrl = rtrim($archive_config->getRealValue('siteUrl'), '/'); + $oldContentUrl = rtrim($archive_config->getRealValue('contentUrl'), '/'); + $oldUploadUrl = rtrim($archive_config->getRealValue('uploadBaseUrl'), '/'); + $oldPluginsUrl = rtrim($archive_config->getRealValue('pluginsUrl'), '/'); + $oldMuPluginsUrl = rtrim($archive_config->getRealValue('mupluginsUrl'), '/'); + + $oldWpAbsPath = $paths->abs; + $oldContentPath = $paths->wpcontent; + $oldUploadsBasePath = $paths->uploads; + $oldPluginsPath = $paths->plugins; + $oldMuPluginsPath = $paths->muplugins; + + $defValEdit = "This default value is automatically generated.\n" + . "Change it only if you're sure you know what you're doing!"; + + $params[PrmMng::PARAM_URL_OLD] = new ParamItem( + PrmMng::PARAM_URL_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldHomeUrl + ) + ); + + $params[PrmMng::PARAM_WP_ADDON_SITES_PATHS] = new ParamItem( + PrmMng::PARAM_WP_ADDON_SITES_PATHS, + ParamForm::TYPE_ARRAY_STRING, + array( + 'default' => array() + ) + ); + + $newObj = new ParamForm( + PrmMng::PARAM_URL_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => $newHomeUrl, + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizeUrl'), + 'validateCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'validateUrlWithScheme') + ), + array(// FORM ATTRIBUTES + 'label' => 'New Site URL:', + 'status' => function (ParamForm $param) { + if ( + PrmMng::getInstance()->getValue(PrmMng::PARAM_TEMPLATE) !== \DUPX_Template::TEMPLATE_ADVANCED || + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'wrapperClasses' => array('revalidate-on-change', 'cant-be-empty'), + 'subNote' => function (ParamForm $param) { + $archive_config = \DUPX_ArchiveConfig::getInstance(); + $oldHomeUrl = rtrim($archive_config->getRealValue('homeUrl'), '/'); + return 'Old value: ' . \DUPX_U::esc_html($oldHomeUrl) . ''; + }, + 'postfix' => array('type' => 'button', 'label' => 'get', 'btnAction' => 'DUPX.getNewUrlByDomObj(this);') + ) + ); + $params[PrmMng::PARAM_URL_NEW] = $newObj; + $urlNewInputId = $newObj->getFormItemId(); + + $params[PrmMng::PARAM_PATH_OLD] = new ParamItem( + PrmMng::PARAM_PATH_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldMainPath + ) + ); + + $newObj = new ParamForm( + PrmMng::PARAM_PATH_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => $newMainPath, + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath'), + 'validateCallback' => function ($value, ParamItem $paramObj) { + if (strlen($value) == 0) { + $paramObj->setInvalidMessage('The new path can\'t be empty.'); + return false; + } + + // if home path is root path is necessary do a trailingslashit + $realPath = SnapIO::safePathTrailingslashit($value); + if (!is_dir($realPath)) { + $paramObj->setInvalidMessage( + 'The new path must be an existing folder on the server.
          ' . + 'It is not possible to continue the installation without first creating the folder
          ' . + '' . $value . '' + ); + return false; + } + + // don't check the return of chmod, if fail the installer must continue + SnapIO::chmod($realPath, 'u+rwx'); + return true; + } + ), + array(// FORM ATTRIBUTES + 'label' => 'New Path:', + 'status' => function (ParamForm $param) { + if ( + PrmMng::getInstance()->getValue(PrmMng::PARAM_TEMPLATE) !== \DUPX_Template::TEMPLATE_ADVANCED || + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_INFO_ONLY; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldMainPath) . '', + 'wrapperClasses' => array('revalidate-on-change', 'cant-be-empty') + ) + ); + + $params[PrmMng::PARAM_PATH_NEW] = $newObj; + $pathNewInputId = $newObj->getFormItemId(); + + $params[PrmMng::PARAM_SITE_URL_OLD] = new ParamItem( + PrmMng::PARAM_SITE_URL_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldSiteUrl + ) + ); + + $wrapClasses = array('revalidate-on-change', 'cant-be-empty', 'auto-updatable', 'autoupdate-enabled'); + $postfixElement = array( + 'type' => 'button', + 'label' => 'Auto', + 'btnAction' => 'DUPX.autoUpdateToggle(this, ' . SnapJson::jsonEncode($defValEdit) . ');' + ); + + $params[PrmMng::PARAM_SITE_URL] = new ParamForm( + PrmMng::PARAM_SITE_URL, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizeUrl'), + 'validateCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'validateUrlWithScheme') + ), + array(// FORM ATTRIBUTES + 'label' => 'WP core URL:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldSiteUrl) . '', + ) + ); + + $params[PrmMng::PARAM_PATH_CONTENT_OLD] = new ParamItem( + PrmMng::PARAM_PATH_CONTENT_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldContentPath + ) + ); + + $params[PrmMng::PARAM_PATH_CONTENT_NEW] = new ParamForm( + PrmMng::PARAM_PATH_CONTENT_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath') + ), + array(// FORM ATTRIBUTES + 'label' => 'WP-content path:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldContentPath) . '' + ) + ); + + $params[PrmMng::PARAM_PATH_WP_CORE_OLD] = new ParamItem( + PrmMng::PARAM_PATH_WP_CORE_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldWpAbsPath + ) + ); + + $params[PrmMng::PARAM_PATH_WP_CORE_NEW] = new ParamForm( + PrmMng::PARAM_PATH_WP_CORE_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath'), + ), + array(// FORM ATTRIBUTES + 'label' => 'WP core path:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldWpAbsPath) . '' + ) + ); + + $params[PrmMng::PARAM_PATH_UPLOADS_OLD] = new ParamItem( + PrmMng::PARAM_PATH_UPLOADS_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldUploadsBasePath + ) + ); + + $params[PrmMng::PARAM_PATH_UPLOADS_NEW] = new ParamForm( + PrmMng::PARAM_PATH_UPLOADS_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath') + ), + array(// FORM ATTRIBUTES + 'label' => 'Uploads path:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldUploadsBasePath) . '' + ) + ); + + $params[PrmMng::PARAM_URL_CONTENT_OLD] = new ParamItem( + PrmMng::PARAM_URL_CONTENT_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldContentUrl + ) + ); + + $params[PrmMng::PARAM_URL_CONTENT_NEW] = new ParamForm( + PrmMng::PARAM_URL_CONTENT_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizeUrl'), + 'validateCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'validateUrlWithScheme') + ), + array(// FORM ATTRIBUTES + 'label' => 'WP-content URL:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldContentUrl) . '' + ) + ); + + $params[PrmMng::PARAM_URL_UPLOADS_OLD] = new ParamItem( + PrmMng::PARAM_URL_UPLOADS_OLD, + ParamForm::TYPE_STRING, + array(// ITEM ATTRIBUTES + 'default' => $oldUploadUrl + ) + ); + + $params[PrmMng::PARAM_URL_UPLOADS_NEW] = new ParamForm( + PrmMng::PARAM_URL_UPLOADS_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizeUrl'), + 'validateCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'validateUrlWithScheme') + ), + array(// FORM ATTRIBUTES + 'label' => 'Uploads URL:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldUploadUrl) . '' + ) + ); + + $params[PrmMng::PARAM_URL_PLUGINS_OLD] = new ParamItem( + PrmMng::PARAM_URL_PLUGINS_OLD, + ParamForm::TYPE_STRING, + array(// ITEM ATTRIBUTES + 'default' => $oldPluginsUrl + ) + ); + + $params[PrmMng::PARAM_URL_PLUGINS_NEW] = new ParamForm( + PrmMng::PARAM_URL_PLUGINS_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizeUrl'), + 'validateCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'validateUrlWithScheme') + ), + array(// FORM ATTRIBUTES + 'label' => 'Plugins URL:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldPluginsUrl) . '' + ) + ); + + $params[PrmMng::PARAM_PATH_PLUGINS_OLD] = new ParamItem( + PrmMng::PARAM_PATH_PLUGINS_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldPluginsPath + ) + ); + + $params[PrmMng::PARAM_PATH_PLUGINS_NEW] = new ParamForm( + PrmMng::PARAM_PATH_PLUGINS_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath') + ), + array(// FORM ATTRIBUTES + 'label' => 'Plugins path:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldPluginsPath) . '' + ) + ); + + $params[PrmMng::PARAM_URL_MUPLUGINS_OLD] = new ParamItem( + PrmMng::PARAM_URL_MUPLUGINS_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldMuPluginsUrl + ) + ); + + $params[PrmMng::PARAM_URL_MUPLUGINS_NEW] = new ParamForm( + PrmMng::PARAM_URL_MUPLUGINS_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizeUrl'), + 'validateCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'validateUrlWithScheme') + ), + array(// FORM ATTRIBUTES + 'label' => 'MU-plugins URL:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'subNote' => 'Old value: ' . \DUPX_U::esc_html($oldMuPluginsUrl) . '' + ) + ); + + $params[PrmMng::PARAM_PATH_MUPLUGINS_OLD] = new ParamItem( + PrmMng::PARAM_PATH_MUPLUGINS_OLD, + ParamForm::TYPE_STRING, + array( + 'default' => $oldMuPluginsPath + ) + ); + + $params[PrmMng::PARAM_PATH_MUPLUGINS_NEW] = new ParamForm( + PrmMng::PARAM_PATH_MUPLUGINS_NEW, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array(// ITEM ATTRIBUTES + 'default' => '', + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath') + ), + array(// FORM ATTRIBUTES + 'label' => 'MU-plugins path:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'postfix' => $postfixElement + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + PrmMng::getInstance(); + + $archive_config = \DUPX_ArchiveConfig::getInstance(); + $paths = $archive_config->getRealValue('archivePaths'); + + $oldMainPath = $paths->home; + $newMainPath = $params[PrmMng::PARAM_PATH_NEW]->getValue(); + + $oldHomeUrl = rtrim($archive_config->getRealValue('homeUrl'), '/'); + $newHomeUrl = $params[PrmMng::PARAM_URL_NEW]->getValue(); + + $oldSiteUrl = rtrim($archive_config->getRealValue('siteUrl'), '/'); + $oldContentUrl = rtrim($archive_config->getRealValue('contentUrl'), '/'); + $oldUploadUrl = rtrim($archive_config->getRealValue('uploadBaseUrl'), '/'); + $oldPluginsUrl = rtrim($archive_config->getRealValue('pluginsUrl'), '/'); + $oldMuPluginsUrl = rtrim($archive_config->getRealValue('mupluginsUrl'), '/'); + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_PATH_WP_CORE_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubString($oldMainPath, $newMainPath, $paths->abs); + $params[PrmMng::PARAM_PATH_WP_CORE_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_PATH_CONTENT_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubString($oldMainPath, $newMainPath, $paths->wpcontent); + $params[PrmMng::PARAM_PATH_CONTENT_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_PATH_UPLOADS_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubString($oldMainPath, $newMainPath, $paths->uploads); + $params[PrmMng::PARAM_PATH_UPLOADS_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_PATH_PLUGINS_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubString($oldMainPath, $newMainPath, $paths->plugins); + $params[PrmMng::PARAM_PATH_PLUGINS_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_PATH_MUPLUGINS_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubString($oldMainPath, $newMainPath, $paths->muplugins); + $params[PrmMng::PARAM_PATH_MUPLUGINS_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_SITE_URL]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubUrl($oldHomeUrl, $newHomeUrl, $oldSiteUrl); + $params[PrmMng::PARAM_SITE_URL]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_URL_CONTENT_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubUrl($oldHomeUrl, $newHomeUrl, $oldContentUrl); + $params[PrmMng::PARAM_URL_CONTENT_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_URL_UPLOADS_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubUrl($oldHomeUrl, $newHomeUrl, $oldUploadUrl); + $params[PrmMng::PARAM_URL_UPLOADS_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_URL_PLUGINS_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubUrl($oldHomeUrl, $newHomeUrl, $oldPluginsUrl); + $params[PrmMng::PARAM_URL_PLUGINS_NEW]->setValue($newVal); + } + + // if empty value isn't overwritten + if (strlen($params[PrmMng::PARAM_URL_MUPLUGINS_NEW]->getValue()) == 0) { + $newVal = \DUPX_ArchiveConfig::getNewSubUrl($oldHomeUrl, $newHomeUrl, $oldMuPluginsUrl); + $params[PrmMng::PARAM_URL_MUPLUGINS_NEW]->setValue($newVal); + } + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescUsers.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescUsers.php new file mode 100644 index 00000000..cac25e9f --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescUsers.php @@ -0,0 +1,166 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamOption; +use Duplicator\Installer\Core\Params\Items\ParamFormUsersReset; +use DUPX_DBInstall; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescUsers implements DescriptorInterface +{ + const USER_MODE_OVERWRITE = 'overwrite'; + const USER_MODE_IMPORT_USERS = 'import_users'; + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_USERS_MODE] = new ParamForm( + PrmMng::PARAM_USERS_MODE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_RADIO, + array( + 'default' => self::USER_MODE_OVERWRITE, + 'sanitizeCallback' => function ($value) { + if ( + DUPX_InstallerState::getInstance()->getMode() !== DUPX_InstallerState::MODE_OVR_INSTALL || + DUPX_InstallerState::isRestoreBackup() + ) { + // if is restore backup user mode must be overwrite + return ParamDescUsers::USER_MODE_OVERWRITE; + } + + $overwriteData = PrmMng::getInstance()->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + if ($overwriteData['isMultisite']) { + return ParamDescUsers::USER_MODE_OVERWRITE; + } + + // disable keep users for some db actions + switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_ACTION)) { + case DUPX_DBInstall::DBACTION_CREATE: + case DUPX_DBInstall::DBACTION_MANUAL: + case DUPX_DBInstall::DBACTION_ONLY_CONNECT: + return ParamDescUsers::USER_MODE_OVERWRITE; + case DUPX_DBInstall::DBACTION_EMPTY: + case DUPX_DBInstall::DBACTION_REMOVE_ONLY_TABLES: + case DUPX_DBInstall::DBACTION_RENAME: + return $value; + } + }, + 'acceptValues' => array( + self::USER_MODE_OVERWRITE, + self::USER_MODE_IMPORT_USERS + ) + ), + array( + 'status' => function () { + /* Hide user mode instandalone migration for now */ + return ParamForm::STATUS_SKIP; + if (DUPX_InstallerState::getInstance()->getMode() !== DUPX_InstallerState::MODE_OVR_INSTALL) { + return ParamForm::STATUS_DISABLED; + } + + $overwriteData = PrmMng::getInstance()->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + + if ( + $overwriteData['isMultisite'] || + DUPX_InstallerState::isRestoreBackup() + ) { + return ParamForm::STATUS_DISABLED; + } + return ParamForm::STATUS_ENABLED; + }, + 'label' => 'Users:', + 'options' => function ($item) { + $result = array(); + $result[] = new ParamOption(ParamDescUsers::USER_MODE_OVERWRITE, 'Overwrite'); + $result[] = new ParamOption(ParamDescUsers::USER_MODE_IMPORT_USERS, 'Merge'); + return $result; + }, + 'inlineHelp' => dupxTplRender('parts/params/inline_helps/user_mode', array(), false), + 'wrapperClasses' => array('revalidate-on-change') + ) + ); + + $params[PrmMng::PARAM_USERS_PWD_RESET] = new ParamFormUsersReset( + PrmMng::PARAM_USERS_PWD_RESET, + ParamFormUsersReset::TYPE_ARRAY_STRING, + ParamFormUsersReset::FORM_TYPE_USERS_PWD_RESET, + array( // ITEM ATTRIBUTES + 'default' => array_map(function ($value) { + return ''; + }, \DUPX_ArchiveConfig::getInstance()->getUsersLists()), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateCallback' => function ($value) { + return strlen($value) == 0 || strlen($value) >= \DUPX_Constants::MIN_NEW_PASSWORD_LEN; + }, + 'validateCallback' => function ($value, ParamItem $paramObj) { + if (strlen($value) > 0 && strlen($value) < \DUPX_Constants::MIN_NEW_PASSWORD_LEN) { + $paramObj->setInvalidMessage('New password must have ' . \DUPX_Constants::MIN_NEW_PASSWORD_LEN . ' or more characters'); + return false; + } + + return true; + } + ), + array( // FORM ATTRIBUTES + 'status' => function ($paramObj) { + if (ParamDescUsers::getUsersMode() != ParamDescUsers::USER_MODE_OVERWRITE) { + return ParamForm::STATUS_DISABLED; + } else { + return ParamForm::STATUS_ENABLED; + } + }, + 'label' => 'Existing user reset password:', + 'classes' => 'strength-pwd-check', + 'attr' => array( + 'title' => \DUPX_Constants::MIN_NEW_PASSWORD_LEN . ' characters minimum', + 'placeholder' => "Reset user password" + ) + ) + ); + } + + /** + * Return import users mode + * + * @return string + */ + public static function getUsersMode() + { + $paramsManager = PrmMng::getInstance(); + return $paramsManager->getValue(PrmMng::PARAM_USERS_MODE); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescValidation.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescValidation.php new file mode 100644 index 00000000..d98f7a68 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescValidation.php @@ -0,0 +1,102 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescValidation implements DescriptorInterface +{ + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $params[PrmMng::PARAM_VALIDATION_LEVEL] = new ParamItem( + PrmMng::PARAM_VALIDATION_LEVEL, + ParamItem::TYPE_INT, + array( + 'default' => \DUPX_Validation_abstract_item::LV_FAIL, + 'acceptValues' => array( + \DUPX_Validation_abstract_item::LV_FAIL, + \DUPX_Validation_abstract_item::LV_HARD_WARNING, + \DUPX_Validation_abstract_item::LV_SOFT_WARNING, + \DUPX_Validation_abstract_item::LV_GOOD, + \DUPX_Validation_abstract_item::LV_PASS + ) + ) + ); + + $params[PrmMng::PARAM_VALIDATION_ACTION_ON_START] = new ParamItem( + PrmMng::PARAM_VALIDATION_ACTION_ON_START, + ParamForm::TYPE_STRING, + array( + 'default' => \DUPX_Validation_manager::ACTION_ON_START_NORMAL, + 'acceptValues' => array( + \DUPX_Validation_manager::ACTION_ON_START_NORMAL, + \DUPX_Validation_manager::ACTION_ON_START_AUTO + ) + ) + ); + + $params[PrmMng::PARAM_VALIDATION_SHOW_ALL] = new ParamForm( + PrmMng::PARAM_VALIDATION_SHOW_ALL, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_SWITCH, + array( + 'default' => false + ), + array( + 'label' => 'Show all', + 'wrapperClasses' => 'align-right' + ) + ); + + $params[PrmMng::PARAM_ACCEPT_TERM_COND] = new ParamForm( + PrmMng::PARAM_ACCEPT_TERM_COND, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Accept term and conditions', + 'renderLabel' => false, + 'checkboxLabel' => 'I have read and accept all terms & notices*', + 'subNote' => '
          * required to continue
          ', + 'attr' => array( + 'onclick' => 'DUPX.acceptWarning();' + ) + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamDescWpConfig.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescWpConfig.php new file mode 100644 index 00000000..64d5685d --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamDescWpConfig.php @@ -0,0 +1,749 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Params\PrmMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Core\Params\Items\ParamForm; +use Duplicator\Installer\Core\Params\Items\ParamOption; +use Duplicator\Installer\Core\Params\Items\ParamFormWpConfig; +use Duplicator\Libs\Snap\SnapUtil; +use Duplicator\Libs\Snap\SnapIO; +use Duplicator\Libs\Snap\SnapDB; +use DUPX_ArchiveConfig; +use DUPX_InstallerState; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamDescWpConfig implements DescriptorInterface +{ + const NOTICE_ID_WP_CONF_PARAM_PATHS_EMPTY = 'wp_conf_param_paths_empty_to_validate'; + const NOTICE_ID_WP_CONF_FORCE_SSL_ADMIN = 'wp_conf_disabled_force_ssl_admin'; + const NOTICE_ID_WP_CONF_PARAM_DOMAINS_MODIFIED = 'wp_conf_param_domains_empty_to_validate'; + + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function init(&$params) + { + $archiveConfig = \DUPX_ArchiveConfig::getInstance(); + + $params[PrmMng::PARAM_GEN_WP_AUTH_KEY] = new ParamForm( + PrmMng::PARAM_GEN_WP_AUTH_KEY, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => false + ), + array( + 'label' => 'Auth Keys:', + 'checkboxLabel' => 'Generate New Unique Authentication Keys and Salts', + 'status' => ParamForm::STATUS_INFO_ONLY + ) + ); + + $params[PrmMng::PARAM_WP_CONF_DISALLOW_FILE_EDIT] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_DISALLOW_FILE_EDIT, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue( + 'DISALLOW_FILE_EDIT' + ) + ), + array( + 'label' => 'DISALLOW_FILE_EDIT:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Disable the Plugin/Theme Editor' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_DISALLOW_FILE_MODS] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_DISALLOW_FILE_MODS, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue( + 'DISALLOW_FILE_MODS', + array( + 'value' => false, + 'inWpConfig' => false + ) + ) + ), + array( + 'label' => 'DISALLOW_FILE_MODS:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'This will block users being able to use the plugin and theme installation/update ' . + 'functionality from the WordPress admin area' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_AUTOSAVE_INTERVAL] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_AUTOSAVE_INTERVAL, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_NUMBER, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue( + 'AUTOSAVE_INTERVAL', + array( + 'value' => 60, + 'inWpConfig' => false + ) + ) + ), + array( // FORM ATTRIBUTES + 'label' => 'AUTOSAVE_INTERVAL:', + 'status' => ParamForm::STATUS_INFO_ONLY, + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_POST_REVISIONS] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_POST_REVISIONS, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_NUMBER, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue( + 'WP_POST_REVISIONS', + array( + 'value' => true, + 'inWpConfig' => false + ) + ), + ), + array( // FORM ATTRIBUTES + 'label' => 'WP_POST_REVISIONS:', + 'status' => ParamForm::STATUS_INFO_ONLY, + ) + ); + + $params[PrmMng::PARAM_WP_CONF_FORCE_SSL_ADMIN] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_FORCE_SSL_ADMIN, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => self::getDefaultForceSSLAdminConfig(), + ), + array( + 'label' => 'FORCE_SSL_ADMIN:', + 'checkboxLabel' => 'Enforce Admin SSL' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_AUTOMATIC_UPDATER_DISABLED] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_AUTOMATIC_UPDATER_DISABLED, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue( + 'AUTOMATIC_UPDATER_DISABLED', + array( + 'value' => false, + 'inWpConfig' => false + ) + ) + ), + array( + 'label' => 'AUTOMATIC_UPDATER_DISABLED:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Disable automatic updater' + ) + ); + + $autoUpdateValue = $archiveConfig->getWpConfigDefineValue('WP_AUTO_UPDATE_CORE'); + if (is_bool($autoUpdateValue)) { + $autoUpdateValue = ($autoUpdateValue ? 'true' : 'false'); + } + $params[PrmMng::PARAM_WP_CONF_WP_AUTO_UPDATE_CORE] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_AUTO_UPDATE_CORE, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_SELECT, + array( + 'default' => array( + 'value' => $autoUpdateValue, + 'inWpConfig' => $archiveConfig->inWpConfigDefine('WP_AUTO_UPDATE_CORE') + ), + 'acceptValues' => array('', 'false', 'true', 'minor') + ), + array( + 'label' => 'WP_AUTO_UPDATE_CORE:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'options' => array( + new ParamOption('minor', 'Enable only core minor updates - Default'), + new ParamOption('false', 'Disable all core updates'), + new ParamOption('true', 'Enable all core updates') + ) + ) + ); + + $params[PrmMng::PARAM_WP_CONF_IMAGE_EDIT_OVERWRITE] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_IMAGE_EDIT_OVERWRITE, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue( + 'IMAGE_EDIT_OVERWRITE', + array( + 'value' => true, + 'inWpConfig' => false + ) + ) + ), + array( + 'label' => 'IMAGE_EDIT_OVERWRITE:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Create only one set of image edits' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_CACHE] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_CACHE, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('WP_CACHE') + ), + array( + 'label' => 'WP_CACHE:', + 'checkboxLabel' => 'Keep Enabled' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WPCACHEHOME] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WPCACHEHOME, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue("WPCACHEHOME"), + 'sanitizeCallback' => function ($value) { + $result = SnapUtil::sanitizeNSCharsNewlineTrim($value); + // WPCACHEHOME want final slash + return SnapIO::safePathTrailingslashit($result); + } + ), + array( // FORM ATTRIBUTES + 'label' => 'WPCACHEHOME:', + 'subNote' => 'This define is not part of the WordPress core but is a define used by WP Super Cache.' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_TEMP_DIR] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_TEMP_DIR, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue("WP_TEMP_DIR"), + 'sanitizeCallback' => array('Duplicator\\Installer\\Core\\Params\\Descriptors\\ParamsDescriptors', 'sanitizePath') + ), + array( // FORM ATTRIBUTES + 'label' => 'WP_TEMP_DIR:', + //'wrapperClasses' => array('small'), + //'subNote' => 'Wordpress admin maximum memory limit (default:256M)' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_DEBUG] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_DEBUG, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('WP_DEBUG') + ), + array( + 'label' => 'WP_DEBUG:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Display errors and warnings' + ) + ); + + $debugLogValue = $archiveConfig->getWpConfigDefineValue('WP_DEBUG_LOG'); + if (is_string($debugLogValue)) { + $debugLogValue = empty($debugLogValue) ? false : true; + } + $params[PrmMng::PARAM_WP_CONF_WP_DEBUG_LOG] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_DEBUG_LOG, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => array( + 'value' => $debugLogValue, + 'inWpConfig' => $archiveConfig->inWpConfigDefine('WP_DEBUG_LOG') + ) + ), + array( + 'label' => 'WP_DEBUG_LOG:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Log errors and warnings', + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_DISABLE_FATAL_ERROR_HANDLER] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_DISABLE_FATAL_ERROR_HANDLER, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('WP_DISABLE_FATAL_ERROR_HANDLER') + ), + array( + 'label' => 'WP_DISABLE_FATAL_ERROR_HANDLER:', + 'checkboxLabel' => 'Disable fatal error handler', + 'status' => ParamForm::STATUS_INFO_ONLY + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_DEBUG_DISPLAY] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_DEBUG_DISPLAY, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('WP_DEBUG_DISPLAY') + ), + array( + 'label' => 'WP_DEBUG_DISPLAY:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Display errors and warnings' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_SCRIPT_DEBUG] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_SCRIPT_DEBUG, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('SCRIPT_DEBUG') + ), + array( + 'label' => 'SCRIPT_DEBUG:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'JavaScript or CSS errors' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_CONCATENATE_SCRIPTS] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_CONCATENATE_SCRIPTS, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('CONCATENATE_SCRIPTS', array( + 'value' => false, + 'inWpConfig' => false + )) + ), + array( + 'label' => 'CONCATENATE_SCRIPTS:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Concatenate all JavaScript files into one URL' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_SAVEQUERIES] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_SAVEQUERIES, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('SAVEQUERIES') + ), + array( + 'label' => 'SAVEQUERIES:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Save database queries in an array ($wpdb->queries)' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_ALTERNATE_WP_CRON] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_ALTERNATE_WP_CRON, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('ALTERNATE_WP_CRON', array( + 'value' => false, + 'inWpConfig' => false + )) + ), + array( + 'label' => 'ALTERNATE_WP_CRON:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Use an alternative Cron with WP' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_DISABLE_WP_CRON] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_DISABLE_WP_CRON, + ParamForm::TYPE_BOOL, + ParamForm::FORM_TYPE_CHECKBOX, + array( + 'default' => $archiveConfig->getDefineArrayValue('DISABLE_WP_CRON', array( + 'value' => false, + 'inWpConfig' => false + )) + ), + array( + 'label' => 'DISABLE_WP_CRON:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'checkboxLabel' => 'Disable cron entirely' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_CRON_LOCK_TIMEOUT] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_CRON_LOCK_TIMEOUT, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_NUMBER, + array( + 'default' => $archiveConfig->getDefineArrayValue('WP_CRON_LOCK_TIMEOUT', array( + 'value' => 60, + 'inWpConfig' => false + )), + 'min_range' => 1 + ), + array( + 'label' => 'WP_CRON_LOCK_TIMEOUT:', + 'status' => ParamForm::STATUS_INFO_ONLY + ) + ); + + $params[PrmMng::PARAM_WP_CONF_EMPTY_TRASH_DAYS] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_EMPTY_TRASH_DAYS, + ParamForm::TYPE_INT, + ParamForm::FORM_TYPE_NUMBER, + array( + 'default' => $archiveConfig->getDefineArrayValue('EMPTY_TRASH_DAYS', array( + 'value' => 30, + 'inWpConfig' => false + )), + 'min_range' => 0 + ), + array( + 'label' => 'EMPTY_TRASH_DAYS:', + 'status' => ParamForm::STATUS_INFO_ONLY + ) + ); + + $params[PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue("COOKIE_DOMAIN"), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim') + ), + array( // FORM ATTRIBUTES + 'label' => 'COOKIE_DOMAIN:', + 'subNote' => 'Set ' . + 'different domain for cookies.subdomain.example.com' + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_MEMORY_LIMIT] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_MEMORY_LIMIT, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue('WP_MEMORY_LIMIT'), + 'sanitizeCallback' => array('Duplicator\\Libs\\Snap\\SnapUtil', 'sanitizeNSCharsNewlineTrim'), + 'validateRegex' => ParamItem::VALIDATE_REGEX_AZ_NUMBER + ), + array( // FORM ATTRIBUTES + 'label' => 'WP_MEMORY_LIMIT:', + 'status' => ParamForm::STATUS_INFO_ONLY + ) + ); + + $params[PrmMng::PARAM_WP_CONF_WP_MAX_MEMORY_LIMIT] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_WP_MAX_MEMORY_LIMIT, + ParamForm::TYPE_STRING, + ParamForm::FORM_TYPE_TEXT, + array( // ITEM ATTRIBUTES + 'default' => $archiveConfig->getDefineArrayValue('WP_MAX_MEMORY_LIMIT') + ), + array( // FORM ATTRIBUTES + 'label' => 'WP_MAX_MEMORY_LIMIT:', + 'status' => ParamForm::STATUS_INFO_ONLY + ) + ); + + $params[PrmMng::PARAM_WP_CONF_MYSQL_CLIENT_FLAGS] = new ParamFormWpConfig( + PrmMng::PARAM_WP_CONF_MYSQL_CLIENT_FLAGS, + ParamForm::TYPE_ARRAY_INT, + ParamForm::FORM_TYPE_SELECT, + array( // ITEM ATTRIBUTES + 'default' => self::getMysqlClientFlagsDefaultVals(), + ), + array( // FORM ATTRIBUTES + 'label' => 'MYSQL_CLIENT_FLAGS:', + 'status' => ParamForm::STATUS_INFO_ONLY, + 'options' => self::getMysqlClientFlagsOptions(), + 'multiple' => true + ) + ); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + //UPDATE PATHS AUTOMATICALLY + self::setDefaultWpConfigPathValue($params, PrmMng::PARAM_WP_CONF_WP_TEMP_DIR, 'WP_TEMP_DIR'); + self::setDefaultWpConfigPathValue($params, PrmMng::PARAM_WP_CONF_WPCACHEHOME, 'WPCACHEHOME'); + self::wpConfigPathsNotices(); + + //UPDATE DOMAINS AUTOMATICALLY + self::setDefaultWpConfigDomainValue($params, PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN, "COOKIE_DOMAIN"); + self::wpConfigDomainNotices(); + } + + /** + * Returns wp counfi default value + * + * @return array + */ + protected static function getMysqlClientFlagsDefaultVals() + { + $result = DUPX_ArchiveConfig::getInstance()->getDefineArrayValue( + 'MYSQL_CLIENT_FLAGS', + array( + 'value' => array(), + 'inWpConfig' => false + ) + ); + + $result['value'] = array_intersect($result['value'], SnapDB::getMysqlConnectFlagsList(false)); + return $result; + } + + /** + * Returns the list of options of the mysql real connect flags + * + * @return int[] + */ + protected static function getMysqlClientFlagsOptions() + { + $result = array(); + foreach (SnapDB::getMysqlConnectFlagsList() as $flag) { + $result[] = new ParamOption(constant($flag), $flag); + } + return $result; + } + + /** + * Tries to replace the old path with the new path for the given wp config define. + * If that's not possible returns a notice to the user. + * + * @param ParamItem[] $params params list + * @param string $paramKey param key + * @param string $wpConfigKey wp config key + * + * @return void + */ + protected static function setDefaultWpConfigPathValue(&$params, $paramKey, $wpConfigKey) + { + if (!self::wpConfigNeedsUpdate($params, $paramKey, $wpConfigKey)) { + return; + } + + $oldMainPath = $params[PrmMng::PARAM_PATH_OLD]->getValue(); + $newMainPath = $params[PrmMng::PARAM_PATH_NEW]->getValue(); + $wpConfigVal = \DUPX_ArchiveConfig::getInstance()->getDefineArrayValue($wpConfigKey); + + // TRY TO CHANGE THE VALUE OR RESET + if (($wpConfigVal['value'] = \DUPX_ArchiveConfig::getNewSubString($oldMainPath, $newMainPath, $wpConfigVal['value'])) === false) { + $wpConfigVal['inWpConfig'] = false; + $wpConfigVal['value'] = ''; + + \DUPX_NOTICE_MANAGER::getInstance()->addNextStepNotice(array( + 'shortMsg' => 'WP CONFIG custom paths disabled.', + 'level' => \DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => "The " . $params[$paramKey]->getLabel() . " path could not be set programmatically and has been disabled
          \n", + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, self::NOTICE_ID_WP_CONF_PARAM_PATHS_EMPTY); + } + + $params[$paramKey]->setValue($wpConfigVal); + } + + /** + * Tries to replace the old domain with the new domain for the given wp config define. + * If that's not possible returns a notice to the user. + * + * @param ParamItem[] $params params list + * @param string $paramKey param key + * @param string $wpConfigKey wp config key + * + * @return void + */ + protected static function setDefaultWpConfigDomainValue(&$params, $paramKey, $wpConfigKey) + { + if (!self::wpConfigNeedsUpdate($params, $paramKey, $wpConfigKey)) { + return; + } + + $wpConfigVal = \DUPX_ArchiveConfig::getInstance()->getDefineArrayValue($wpConfigKey); + $parsedUrlNew = parse_url(PrmMng::getInstance()->getValue(PrmMng::PARAM_URL_NEW)); + $parsedUrlOld = parse_url(PrmMng::getInstance()->getValue(PrmMng::PARAM_URL_OLD)); + + if ($wpConfigVal['value'] == $parsedUrlOld['host']) { + $wpConfigVal['value'] = $parsedUrlNew['host']; + } else { + $wpConfigVal['inWpConfig'] = false; + $wpConfigVal['value'] = ''; + + \DUPX_NOTICE_MANAGER::getInstance()->addNextStepNotice(array( + 'shortMsg' => 'WP CONFIG domains disabled.', + 'level' => \DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => "The " . $params[$paramKey]->getLabel() . " domain could not be set programmatically and has been disabled
          \n", + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, self::NOTICE_ID_WP_CONF_PARAM_DOMAINS_MODIFIED); + } + + $params[$paramKey]->setValue($wpConfigVal); + } + + /** + * Return true if wp config key need update + * + * @param ParamItem[] $params params list + * @param string $paramKey param key + * @param string $wpConfigKey wp config key + * + * @return bool + */ + protected static function wpConfigNeedsUpdate(&$params, $paramKey, $wpConfigKey) + { + if ( + DUPX_InstallerState::isRestoreBackup($params[PrmMng::PARAM_INST_TYPE]->getValue()) + ) { + return false; + } + + // SKIP IF PARAM IS OVERWRITTEN + if ($params[$paramKey]->getStatus() === ParamItem::STATUS_OVERWRITE) { + return false; + } + + // SKIP IF EMPTY + $wpConfigVal = \DUPX_ArchiveConfig::getInstance()->getDefineArrayValue($wpConfigKey); + if (strlen($wpConfigVal['value']) === 0) { + return false; + } + + // EMPTY IF DISABLED + if ($wpConfigVal['inWpConfig'] == false) { + $wpConfigVal['value'] = ''; + $params[$paramKey]->setValue($wpConfigVal); + return false; + } + + return true; + } + + /** + * Set wp config paths notices + * + * @return void + */ + protected static function wpConfigPathsNotices() + { + $noticeManager = \DUPX_NOTICE_MANAGER::getInstance(); + + /* PREPEND IF EXISTS */ + $noticeManager->addNextStepNotice(array( + 'shortMsg' => '', + 'level' => \DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => "It was found that the following config paths were outside of the source site's home path (" . + \DUPX_ArchiveConfig::getInstance()->getRealValue("originalPaths")->home . "):

          \n", + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, self::NOTICE_ID_WP_CONF_PARAM_PATHS_EMPTY); + + /* APPEND IF EXISTS */ + $msg = '
          Keeping config paths that are outside of the home path may cause malfunctions, so these settings have been disabled by default,'; + $msg .= ' but you can set them manually if necessary by switching the install mode '; + $msg .= 'to "Advanced" and at Step 3 navigating to "Options" > "WP-Config File"'; + + $noticeManager->addNextStepNotice(array( + 'shortMsg' => '', + 'level' => \DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => $msg, + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND_IF_EXISTS, self::NOTICE_ID_WP_CONF_PARAM_PATHS_EMPTY); + + $noticeManager->saveNotices(); + } + + /** + * Set wp config domain notices + * + * @return void + */ + protected static function wpConfigDomainNotices() + { + $noticeManager = \DUPX_NOTICE_MANAGER::getInstance(); + + /* PREPEND IF EXISTS */ + $noticeManager->addNextStepNotice(array( + 'shortMsg' => '', + 'level' => \DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => "The following config domains were disabled:

          \n", + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, self::NOTICE_ID_WP_CONF_PARAM_DOMAINS_MODIFIED); + + /* APPEND IF EXISTS */ + $msg = '
          The plugin was unable to automatically replace the domain, so the setting has been disabled by default.'; + $msg .= ' Please review them by switching the install mode to "Advanced" and at Step 3 navigating to "Options" > "WP-Config File"'; + + $noticeManager->addNextStepNotice(array( + 'shortMsg' => '', + 'level' => \DUPX_NOTICE_ITEM::NOTICE, + 'longMsg' => $msg, + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND_IF_EXISTS, self::NOTICE_ID_WP_CONF_PARAM_DOMAINS_MODIFIED); + + $noticeManager->saveNotices(); + } + + /** + * Returns default config value for FORCE_SSL_ADMIN depending on current site's settings + * + * @return array + * @throws \Exception + */ + protected static function getDefaultForceSSLAdminConfig() + { + $forceAdminSSLConfig = \DUPX_ArchiveConfig::getInstance()->getDefineArrayValue('FORCE_SSL_ADMIN'); + if (!\DUPX_U::is_ssl() && $forceAdminSSLConfig['inWpConfig'] === true) { + $noticeMng = \DUPX_NOTICE_MANAGER::getInstance(); + $noticeMng->addFinalReportNotice( + array( + 'shortMsg' => "FORCE_SSL_ADMIN was enabled on none SSL", + 'level' => \DUPX_NOTICE_ITEM::SOFT_WARNING, + 'longMsg' => 'It was found that FORCE_SSL_ADMIN is enabled and you are installing on a site without SSL, ' . + 'so that config has been disabled.', + 'sections' => 'general' + ), + \DUPX_NOTICE_MANAGER::ADD_UNIQUE, + self::NOTICE_ID_WP_CONF_FORCE_SSL_ADMIN + ); + $noticeMng->saveNotices(); + $forceAdminSSLConfig['value'] = false; + } + return $forceAdminSSLConfig; + } +} diff --git a/installer/dup-installer/src/Core/Params/Descriptors/ParamsDescriptors.php b/installer/dup-installer/src/Core/Params/Descriptors/ParamsDescriptors.php new file mode 100644 index 00000000..d65b096c --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Descriptors/ParamsDescriptors.php @@ -0,0 +1,183 @@ + + * @copyright 2011-2021 Snapcreek LLC + * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3 + */ + +namespace Duplicator\Installer\Core\Params\Descriptors; + +use Duplicator\Installer\Core\Hooks\HooksMng; +use Duplicator\Installer\Core\Params\Items\ParamItem; +use Duplicator\Installer\Utils\Log\Log; +use Duplicator\Libs\Snap\SnapUtil; +use Duplicator\Libs\Snap\SnapIO; + +/** + * class where all parameters are initialized. Used by the param manager + */ +final class ParamsDescriptors +{ + /** + * Params init + * + * @return void + */ + public static function init() + { + HooksMng::getInstance()->addAction('after_params_overwrite', array(__CLASS__, 'updateParamsAfterOverwrite')); + } + + /** + * Init params + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function initParams(&$params) + { + ParamDescUrlsPaths::init($params); + ParamDescController::init($params); + ParamDescSecurity::init($params); + ParamDescGeneric::init($params); + ParamDescConfigs::init($params); + ParamDescEngines::init($params); + ParamDescValidation::init($params); + ParamDescDatabase::init($params); + ParamDescReplace::init($params); + ParamDescPlugins::init($params); + ParamDescUsers::init($params); + ParamDescNewAdmin::init($params); + ParamDescWpConfig::init($params); + } + + /** + * Update params after overwrite logic + * + * @param ParamItem[]|ParamForm[] $params params list + * + * @return void + */ + public static function updateParamsAfterOverwrite($params) + { + Log::info('UPDATE PARAMS AFTER OVERWRITE', Log::LV_DETAILED); + ParamDescUrlsPaths::updateParamsAfterOverwrite($params); + ParamDescController::updateParamsAfterOverwrite($params); + ParamDescSecurity::updateParamsAfterOverwrite($params); + ParamDescGeneric::updateParamsAfterOverwrite($params); + ParamDescConfigs::updateParamsAfterOverwrite($params); + ParamDescEngines::updateParamsAfterOverwrite($params); + ParamDescValidation::updateParamsAfterOverwrite($params); + ParamDescDatabase::updateParamsAfterOverwrite($params); + ParamDescReplace::updateParamsAfterOverwrite($params); + ParamDescPlugins::updateParamsAfterOverwrite($params); + ParamDescUsers::updateParamsAfterOverwrite($params); + ParamDescNewAdmin::updateParamsAfterOverwrite($params); + ParamDescWpConfig::updateParamsAfterOverwrite($params); + } + + /** + * Validate function, return true if value isn't empty + * + * @param mixed $value input value + * @param ParamItem $paramObj current param object + * + * @return boolean + */ + public static function validateNotEmpty($value, ParamItem $paramObj) + { + if (is_string($value)) { + $result = strlen($value) > 0; + } else { + $result = !empty($value); + } + + if ($result == false) { + $paramObj->setInvalidMessage('Can\'t be empty'); + } + + return true; + } + + /** + * Sanitize path + * + * @param string $value input value + * + * @return string + */ + public static function sanitizePath($value) + { + $result = SnapUtil::sanitizeNSCharsNewlineTrim($value); + return SnapIO::safePathUntrailingslashit($result); + } + + /** + * The path can't be empty + * + * @param string $value input value + * @param ParamItem $paramObj current param object + * + * @return bool + */ + public static function validatePath($value, ParamItem $paramObj) + { + if (strlen($value) > 1) { + return true; + } else { + $paramObj->setInvalidMessage('Path can\'t empty'); + return false; + } + } + + /** + * Sanitize URL + * + * @param string $value input value + * + * @return string + */ + public static function sanitizeUrl($value) + { + $result = SnapUtil::sanitizeNSCharsNewlineTrim($value); + if (empty($value)) { + return ''; + } + // if scheme not set add http by default + if (!preg_match('/^[a-zA-Z]+\:\/\//', $result)) { + $result = 'http://' . ltrim($result, '/'); + } + return rtrim($result, '/\\'); + } + + /** + * The URL can't be empty + * + * @param string $value input value + * @param ParamItem $paramObj current param object + * + * @return bool + */ + public static function validateUrlWithScheme($value, ParamItem $paramObj) + { + if (strlen($value) == 0) { + $paramObj->setInvalidMessage('URL can\'t be empty'); + return false; + } + if (($parsed = parse_url($value)) === false) { + $paramObj->setInvalidMessage('URL isn\'t valid'); + return false; + } + if (!isset($parsed['host']) || empty($parsed['host'])) { + $paramObj->setInvalidMessage('URL must be a valid host'); + return false; + } + return true; + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamForm.php b/installer/dup-installer/src/Core/Params/Items/ParamForm.php new file mode 100644 index 00000000..d13773ea --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamForm.php @@ -0,0 +1,1312 @@ +formAttr = array_merge($defaultAttr, (array) $formAttr); + + if (isset($formAttr['classes'])) { + $this->formAttr['classes'] = array_merge($defaultAttr['classes'], (array) $formAttr['classes']); + } + + if (isset($formAttr['labelClasses'])) { + $this->formAttr['labelClasses'] = array_merge($defaultAttr['labelClasses'], (array) $formAttr['labelClasses']); + } + + if (isset($formAttr['wrapperClasses'])) { + $this->formAttr['wrapperClasses'] = array_merge($defaultAttr['wrapperClasses'], (array) $formAttr['wrapperClasses']); + } + + if (isset($formAttr['inputContainerClasses'])) { + $this->formAttr['inputContainerClasses'] = array_merge($defaultAttr['inputContainerClasses'], (array) $formAttr['inputContainerClasses']); + } + + if (strlen($this->formAttr['label']) == 0) { + throw new Exception('Param ' . $name . ' must have label (user renderLabel to hide it)'); + } + + if ($this->formAttr['renderLabel']) { + $this->formAttr['wrapperClasses'][] = 'has-main-label'; + } + + $this->formType = $formType; + + if (empty($this->formAttr['id'])) { + $this->formAttr['id'] = 'param_item_' . $name; + } + + if (empty($this->formAttr['wrapperId'])) { + $this->formAttr['wrapperId'] = 'wrapper_item_' . $name; + } + + //Log::infoObject('PARAM INIZIALIZED ['.$this->name.']', $this, Log::LV_DEFAULT); + } + + /** + * Return param label + * + * @return string + */ + public function getLabel() + { + if (!empty($this->formAttr['label'])) { + return $this->formAttr['label']; + } else { + return parent::getLabel(); + } + } + + /** + * get the input id (input, select ... ) + * normally it depends on the name of the object but can be perosnalizzato through formAttrs + * + * @return string + */ + public function getFormItemId() + { + return $this->formAttr['id']; + } + + /** + * return the input wrapper id if isn't empty or false + * normally it depends on the name of the object but can be perosnalizzato through formAttrs + * + * @return string + */ + /** + * return the input wrapper id if isn't empty or false + * normally it depends on the name of the object but can be perosnalizzato through formAttrs + * + * @return string + */ + public function getFormWrapperId() + { + return empty($this->formAttr['wrapperId']) ? false : $this->formAttr['wrapperId']; + } + + /** + * return current form status + * + * @return string // STATUS_ENABLED | STATUS_READONLY ... + */ + public function getFormStatus() + { + if (is_callable($this->formAttr['status'])) { + return call_user_func($this->formAttr['status'], $this); + } else { + return $this->formAttr['status']; + } + } + + /** + * Add html class at param wrapper container + * + * @param string $class class string + * + * @return void + */ + public function addWrapperClass($class) + { + if (!in_array($class, $this->formAttr['wrapperClasses'])) { + $this->formAttr['wrapperClasses'][] = $class; + } + } + + /** + * Remove html class at param wrapper container + * + * @param string $class class string + * + * @return void + */ + public function removeWrapperClass($class) + { + if (in_array($class, $this->formAttr['wrapperClasses'])) { + unset($this->formAttr['wrapperClasses'][$class]); + } + } + + /** + * This function can be extended in child classes + * + * @return string + */ + protected function getAttrName() + { + return $this->name; + } + + /** + * this function renturn a hidden name for support checkbox input + * + * @return string + */ + protected function getAttrHiddenName() + { + return $this->getAttrName() . '_is_input'; + } + + /** + * this function can be extended in child classes + * + * @return mixed + */ + protected function getInputValue() + { + return $this->value; + } + + /** + * Return a copy of this object with a new name ad overwrite attr + * + * @param string $newName new param name + * @param array $attr param attributes + * @param array $formAttr form attributes + * + * @return self + */ + public function getCopyWithNewName($newName, $attr = array(), $formAttr = array()) + { + $copy = parent::getCopyWithNewName($newName, $attr); + + $reflect = new \ReflectionObject($copy); + + $formAttrProp = $reflect->getProperty('formAttr'); + $formAttrProp->setAccessible(true); + + $newAttr = $formAttrProp->getValue($copy); + $newAttr['id'] = 'param_item_' . $newName; + $newAttr['wrapperId'] = 'wrapper_item_' . $newName; + $newAttr = array_merge($newAttr, $formAttr); + + if (isset($newAttr['options']) && is_array($newAttr['options'])) { + $options = $newAttr['options']; + $newAttr['options'] = array(); + foreach ($options as $key => $option) { + if (is_object($option)) { + $newAttr['options'][$key] = clone $option; + } else { + $newAttr['options'][$key] = $option; + } + } + } + + $formAttrProp->setValue($copy, $newAttr); + + return $copy; + } + + /** + * + * @return bool + */ + public function isEnabled() + { + return $this->getFormStatus() == self::STATUS_ENABLED; + } + + /** + * + * @return bool + */ + public function isSkip() + { + return $this->getFormStatus() == self::STATUS_SKIP; + } + + /** + * + * @return bool + */ + public function isDisabled() + { + return $this->getFormStatus() == self::STATUS_DISABLED; + } + + /** + * + * @return bool + */ + public function isReadonly() + { + return $this->getFormStatus() == self::STATUS_READONLY; + } + + /** + * Return true if the passed value is in current value if type is array or equal if is scalar + * + * @param mixed $value value to check + * @param mixed $inputValue current selected value/s + * + * @return bool + */ + protected static function isValueInValue($value, $inputValue) + { + if (is_null($inputValue) || is_scalar($inputValue)) { + return $value == $inputValue; + } else { + return in_array($value, $inputValue); + } + } + + /** + * Display the html input of current item + * + * @return void + */ + protected function htmlItem() + { + switch ($this->formType) { + case self::FORM_TYPE_HIDDEN: + $this->hiddenHtml(); + break; + case self::FORM_TYPE_TEXT: + $this->inputHtml('text'); + break; + case self::FORM_TYPE_NUMBER: + $this->inputHtml('number'); + break; + case self::FORM_TYPE_SELECT: + $this->selectHtml(); + break; + case self::FORM_TYPE_CHECKBOX: + $this->checkBoxHtml(false); + break; + case self::FORM_TYPE_SWITCH: + $this->checkBoxHtml(true); + break; + case self::FORM_TYPE_M_CHECKBOX: + $this->mCheckBoxHtml(); + break; + case self::FORM_TYPE_RADIO: + $this->radioHtml(); + break; + case self::FORM_TYPE_BGROUP: + $this->bgroupHtml(); + break; + default: + throw new \Exception('ITEM ERROR ' . $this->name . ' Invalid form type ' . $this->formType); + } + } + + /** + * Return form attribute + * + * @param string $key form attribute key + * + * @return mixed + */ + public function getFormAttr($key) + { + return $this->formAttr[$key]; + } + + /** + * Set form attribute + * + * @param string $key form attribute key + * @param mixed $value value + * + * @return void + */ + public function setFormAttr($key, $value) + { + $this->formAttr[$key] = $value; + } + + /** + * Get param options + * + * @return ParamOption[] + */ + protected function getOptions() + { + if (!isset($this->formAttr['options'])) { + return array(); + } elseif (is_callable($this->formAttr['options'])) { + return call_user_func($this->formAttr['options'], $this); + } else { + return $this->formAttr['options']; + } + } + + /** + * Update option status + * + * @param int $index option index + * @param string $status option status + * + * @return void + */ + public function setOptionStatus($index, $status) + { + if (is_array($this->formAttr['options']) && isset($this->formAttr['options'][$index])) { + $this->formAttr['options'][$index]->setStatus($status); + } + } + + /** + * Html of current item if the status if info only + * + * @return void + */ + protected function infoOnlyHtml() + { + $attrs = array( + 'id' => $this->formAttr['id'] + ); + $classes = array_merge(array('input-info-only'), $this->formAttr['classes']); + $attrs['class'] = implode(' ', $classes); + ?> + > + valueToInfo()); ?> + + formType) { + case self::FORM_TYPE_SELECT: + case self::FORM_TYPE_M_CHECKBOX: + $optionsLabels = array(); + foreach ($this->getOptions() as $option) { + if (self::isValueInValue($option->value, $this->getInputValue())) { + $optionsLabels[] = $option->label; + } + } + return implode(', ', $optionsLabels); + case self::FORM_TYPE_CHECKBOX: + $result = ''; + if (self::isValueInValue($this->formAttr['checkedValue'], $this->getInputValue())) { + $result = '[enabled]'; + } else { + $result = '[disabled]'; + } + return $result . ' ' . $this->formAttr['checkboxLabel']; + case self::FORM_TYPE_RADIO: + case self::FORM_TYPE_BGROUP: + $optionsLabels = array(); + foreach ($this->getOptions() as $option) { + if (self::isValueInValue($option->value, $this->getInputValue())) { + return $option->label; + } + } + return '[disabled]'; + case self::FORM_TYPE_HIDDEN: + case self::FORM_TYPE_TEXT: + case self::FORM_TYPE_NUMBER: + default: + if (is_null($this->getInputValue()) || is_scalar($this->getInputValue())) { + return \DUPX_U::esc_html($this->getInputValue()); + } else { + return \DUPX_U::esc_html(implode(',', $this->getInputValue())); + } + } + } + + /** + * Get html form option of current item + * + * @param bool $echo if true echo html + * + * @return string + */ + public function getHtml($echo = true) + { + if ($this->isSkip() === true) { + return ''; + } + ob_start(); + + try { + $this->htmlItemBefore(); + if ($this->getFormStatus() == self::STATUS_INFO_ONLY) { + $this->infoOnlyHtml(); + } else { + $this->htmlItem(); + } + $this->htmlItemAfter(); + } catch (\Exception $e) { + ob_end_flush(); + throw $e; + } + + + if ($echo) { + ob_end_flush(); + return ''; + } else { + return ob_get_clean(); + } + } + + /** + * Input item before (wrapper input and label) + * + * @return void + */ + protected function htmlItemBefore() + { + if (!empty($this->formAttr['wrapperTag'])) { + $wrapperAttrs = array(); + if (!empty($this->formAttr['wrapperId'])) { + $wrapperAttrs['id'] = $this->formAttr['wrapperId']; + } + + $tmpWrapperClasses = $this->formAttr['wrapperClasses']; + if ($this->isDisabled()) { + $tmpWrapperClasses[] = 'param-wrapper-disabled'; + } + + if ($this->isReadonly()) { + $tmpWrapperClasses[] = 'param-wrapper-readonly'; + } + + if ($this->isEnabled()) { + $tmpWrapperClasses[] = 'param-wrapper-enabled'; + } + + if (!empty($tmpWrapperClasses)) { + $wrapperAttrs['class'] = implode(' ', $tmpWrapperClasses); + } + + foreach ($this->formAttr['wrapperAttr'] as $attrName => $attrVal) { + $wrapperAttrs[$attrName] = $attrVal; + } + + echo '<' . $this->formAttr['wrapperTag'] . ' ' . \DUPX_U_Html::arrayAttrToHtml($wrapperAttrs) . ' >'; + + if (!empty($this->formAttr['wrapperContainerTag'])) { + echo '<' . $this->formAttr['wrapperContainerTag'] . ' class="container" >'; + } + } + + $this->getLabelHtml(); + $this->htmlInputContBefore(); + if (!empty($this->formAttr['inputContainerTag'])) { + echo ''; + } + } + + /** + * function called between label and input container + * used on extended classes + * + * @return void + */ + protected function htmlInputContBefore() + { + } + + /** + * function calle after input container + * used on extended classes + * + * @return void + */ + protected function htmlInputContAfter() + { + } + + /** + * input item after (close wrapper) + * + * @return void + */ + protected function htmlItemAfter() + { + if (!empty($this->formAttr['inputContainerTag'])) { + echo ''; + } + + $this->htmlInputContAfter(); + if (!empty($this->formAttr['wrapperTag'])) { + if (!empty($this->formAttr['wrapperContainerTag'])) { + echo 'formAttr['wrapperContainerTag'] . '>'; + } + echo $this->getSubNote(); + echo 'formAttr['wrapperTag'] . '>'; + } else { + echo $this->getSubNote(); + } + } + + /** + * + * @return string + */ + protected function getSubNote() + { + + if (is_callable($this->formAttr['subNote'])) { + $subNote = call_user_func($this->formAttr['subNote'], $this); + } else { + $subNote = $this->formAttr['subNote']; + } + + return empty($subNote) ? '' : '
          ' . $subNote . '
          '; + } + + /** + * Return postfix element data + * + * @param array $data postix element data + * + * @return array + */ + protected function prefixPostfixElem($data) + { + $default = array( + 'type' => 'none', + 'label' => null, + 'id' => null, + 'btnAction' => null, + 'attrs' => array() + ); + + if (is_callable($data)) { + $element = call_user_func($data, $this); + } else { + $element = $data; + } + + if (is_array($element)) { + return array_merge($default, $element); + } else { + return $default; + } + } + + /** + * Return prefix element data + * + * @return array + */ + protected function getPrefix() + { + return $this->prefixPostfixElem($this->formAttr['prefix']); + } + + /** + * Return postifx element data + * + * @return array + */ + protected function getPostfix() + { + return $this->prefixPostfixElem($this->formAttr['postfix']); + } + + /** + * html if type is hidden + * + * @return void + */ + protected function hiddenHtml() + { + $attrs = array( + 'id' => $this->formAttr['id'], + 'name' => $this->getAttrName(), + 'value' => $this->getInputValue() + ); + + if ($this->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', $this->formAttr['classes']); + } + + $attrs = array_merge($attrs, $this->formAttr['attr']); + ?> + > + $type, + 'id' => $this->formAttr['id'], + 'name' => $this->getAttrName(), + 'value' => $this->getInputValue() + ); + + if ($this->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if (!is_null($this->formAttr['maxLength'])) { + $attrs['maxLength'] = $this->formAttr['maxLength']; + } + + if (!is_null($this->formAttr['size'])) { + $attrs['size'] = $this->formAttr['size']; + } + + if (isset($this->formAttr['min']) && !is_null($this->formAttr['min'])) { + $attrs['min'] = $this->formAttr['min']; + } + + if (isset($this->formAttr['max']) && !is_null($this->formAttr['max'])) { + $attrs['max'] = $this->formAttr['max']; + } + + if (isset($this->formAttr['step']) && !is_null($this->formAttr['step'])) { + $attrs['step'] = $this->formAttr['step']; + } + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', $this->formAttr['classes']); + } + + $prefixHtml = self::getPrefixPostfixHtml($this->getPrefix(), 'prefix'); + $postfixHtml = self::getPrefixPostfixHtml($this->getPostfix(), 'postfix'); + $isPrePostFix = (strlen($prefixHtml) > 0 || strlen($postfixHtml) > 0); + + $attrs = array_merge($attrs, $this->formAttr['attr']); + if ($isPrePostFix) { + ?> + + + > + + + $class); + switch ($element['type']) { + case 'button': + $tag = 'button'; + $attrs['type'] = 'button'; + if (!empty($element['btnAction'])) { + $attrs['onclick'] = $element['btnAction']; + } + break; + case 'label': + default: + $tag = 'span'; + break; + } + if (!empty($element['id'])) { + $attrs['id'] = $element['id']; + } + $attrs = array_merge($attrs, $element['attrs']); + return '<' . $tag . ' ' . \DUPX_U_Html::arrayAttrToHtml($attrs) . '>' . $element['label'] . ''; + } + + /** + * HTML if type is select + * + * @return void + */ + protected function selectHtml() + { + $attrs = array( + 'id' => $this->formAttr['id'], + 'name' => $this->getAttrName() . ($this->formAttr['multiple'] ? '[]' : ''), + ); + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', $this->formAttr['classes']); + } + + if ($this->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if ($this->formAttr['multiple']) { + $attrs['multiple'] = ''; + } + + $attrs['size'] = $this->formAttr['size'] == 0 ? count($this->getOptions()) : $this->formAttr['size']; + + $attrs = array_merge($attrs, $this->formAttr['attr']); + ?> + + isHidden()) { + continue; + } + + if ($lastOptGroup !== $option->getOptGroup()) { + if (strlen($lastOptGroup) > 0) { + ?>getOptGroup()) > 0) { + ?>getOptGroup(); + } + + $optAttr = array( + 'value' => $option->value + ); + + if ($option->isDisabled()) { + $optAttr['disabled'] = 'disabled'; + } elseif ( + self::isValueInValue($option->value, $inputValue) || + $autoSelectFirst + ) { + // can't be selected if is disabled + $optAttr['selected'] = 'selected'; + } + + $optAttr = array_merge($optAttr, (array) $option->attrs); + ?> + + 0) { + ?> $this->formAttr['id'], + 'name' => $this->getAttrName(), + 'value' => $this->formAttr['checkedValue'] + ); + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', $this->formAttr['classes']); + } + + if ($this->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if (self::isValueInValue($this->formAttr['checkedValue'], $this->getInputValue())) { + $attrs['checked'] = 'checked'; + } + + $attrs = array_merge($attrs, $this->formAttr['attr']); + + $hiddenAttrs = array( + 'name' => $this->getAttrHiddenName(), + 'value' => true + ); + + if ($switch) { + \DUPX_U_Html::checkboxSwitch($attrs); + } else { + ?> + > + + formAttr['checkboxLabel']; ?> + > + formAttr['attr']); + */ + foreach ($this->getOptions() as $index => $option) { + $attrs = array( + 'id' => $this->formAttr['id'] . '_' . $index, + 'name' => $this->getAttrName() . '[]', + 'value' => $option->value + ); + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', $this->formAttr['classes']); + } + + if (self::isValueInValue($option->value, $this->getInputValue())) { + $attrs['checked'] = 'checked'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if ($this->isDisabled() || $option->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + $attrs = array_merge($attrs, $option->attrs); + if (!empty($attrs['title'])) { + $labelTtile = ' title="' . \DUPX_U::esc_attr($attrs['title']) . '"'; + unset($attrs['title']); + } else { + $labelTtile = ''; + } + ?> + + formAttr['attr']); + */ + foreach ($this->getOptions() as $index => $option) { + if ($option->isHidden()) { + continue; + } + + $attrs = array( + 'id' => $this->formAttr['id'] . '_' . $index, + 'name' => $this->getAttrName(), + 'value' => $option->value + ); + + $optionGroupClasses = 'option-group'; + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', $this->formAttr['classes']); + } + + if (self::isValueInValue($option->value, $this->getInputValue())) { + $attrs['checked'] = 'checked'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if ($this->isDisabled() || $option->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if ($option->isDisabled()) { + $optionGroupClasses .= ' option-disabled'; + } + + $attrs = array_merge($attrs, $option->attrs); + if (!empty($attrs['title'])) { + $labelTtile = ' title="' . \DUPX_U::esc_attr($attrs['title']) . '"'; + unset($attrs['title']); + } else { + $labelTtile = ''; + } + ?> + + formAttr['attr']); + */ + $this->hiddenHtml(); + foreach ($this->getOptions() as $index => $option) { + if ($option->isHidden()) { + continue; + } + + $attrs = array( + 'id' => $this->formAttr['id'] . '_' . $index, + 'value' => $option->value, + 'class' => $this->formAttr['id'] . '_button ' . implode(' ', $this->formAttr['classes']) + ); + + if (self::isValueInValue($option->value, $this->getInputValue())) { + $attrs['class'] .= ' active'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if ($this->isDisabled() || $option->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + $attrs = array_merge($attrs, $option->attrs); + if (!empty($attrs['title'])) { + $labelTtile = ' title="' . \DUPX_U::esc_attr($attrs['title']) . '"'; + unset($attrs['title']); + } else { + $labelTtile = ''; + } + ?> + + formAttr['renderLabel'] == false) { + return ''; + } + + $attrs = array(); + if (!empty($this->formAttr['labelClasses'])) { + $attrs['class'] = implode(' ', $this->formAttr['labelClasses']); + } + ob_start(); + ?> + > + formAttr['label']) == 0 ? ' ' : \DUPX_U::esc_html($this->formAttr['label'])); + if (strlen($this->formAttr['inlineHelp']) > 0) { + $helpTitle = (strlen($this->formAttr['inlineHelpTitle']) ? $this->formAttr['inlineHelpTitle'] : rtrim($this->formAttr['label'], ':')); + ?> + + formAttr['proFlag']) > 0) { + $flagTitle = (strlen($this->formAttr['proFlagTitle']) ? $this->formAttr['proFlagTitle'] : rtrim($this->formAttr['label'], ':')); + ?>* + + + formAttr['status'] = $data['formStatus']; + } + return $result; + } + + /** + * return array dato to store in json array data + * + * @return array + */ + public function toArrayData() + { + $result = parent::toArrayData(); + if (!is_callable($this->formAttr['status'])) { + $result['formStatus'] = $this->getFormStatus(); + } + return $result; + } + + /** + * update the value from input if exists ot set the default + * sanitation and validation are performed + * skip set value if current status is disabled, info only or skip + * + * @param string $method query string method (POST, GET) + * + * @return boolean false if value isn't validated + */ + public function setValueFromInput($method = self::INPUT_POST) + { + // if input is disabled don't reads from input. + if ( + $this->getFormStatus() == self::STATUS_INFO_ONLY || + $this->getFormStatus() == self::STATUS_SKIP + ) { + return true; + } + + // prevent overwrite by default if item is disable and isn't enable in client by js + $superObject = self::getSuperObjectByMethod($method); + if ($this->getFormStatus() == self::STATUS_DISABLED && !$this->isValueInInput($superObject)) { + return true; + } + + // prevent overwrite by default if checkbox isn't in form + if (($this->formType === self::FORM_TYPE_CHECKBOX || $this->formType === self::FORM_TYPE_SWITCH) && !isset($superObject[$this->getAttrName()])) { + if (!isset($superObject[$this->getAttrHiddenName()]) || !$superObject[$this->getAttrHiddenName()]) { + return true; + } + } elseif (!isset($superObject[$this->name])) { + return true; + } + + return parent::setValueFromInput($method); + } + + /** + * this function return the default formAttr for each type. + * in the constructor an array merge is made between the result of this function and the parameters passed. + * In this way the values ​​in $ this -> ['attr'] are always consistent. + * + * @param string $formType form type + * + * @return array + */ + protected static function getDefaultAttrForFormType($formType) + { + $attrs = array( + 'label' => null, // input main label, + 'renderLabel' => true, // if false don\'t render label + 'labelClasses' => array('label', 'main-label'), // label classes (the label html is label + 'id' => null, // input id , if null the default is 'param_item_'.$name + 'classes' => array('input-item'), // input classes + 'status' => self::STATUS_ENABLED, // form status + 'title' => null, // input title + 'attr' => array(), // custom input attributes key="VALUE" + 'inlineHelpTitle' => '', + 'inlineHelp' => '', + 'proFlagTitle' => '', + 'proFlag' => '', + 'subNote' => null, // sub note container (html string), + 'wrapperTag' => 'div', // if null the input haven't the wrapper tag. + // input tag wrapper, wrapper html is + // ~ + 'wrapperId' => null, // input wrapper id, if null the default is 'wrapper_item_'.$name + 'wrapperClasses' => array(// wrapper classes, param-wrapper generic class plus 'param-form-type-'.$formType type class + 'param-wrapper', + 'param-form-type-' . $formType), + 'wrapperAttr' => array(), // custom wrapper attributes key="VALUE" + 'wrapperContainerTag' => 'label', + 'inputContainerTag' => 'span', + 'inputContainerClasses' => array('input-container'), + ); + + switch ($formType) { + case self::FORM_TYPE_HIDDEN: + $attrs['wrapperTag'] = null; // disable wrapper for hidden inputs + $attrs['wrapperContainerTag'] = null; + $attrs['inputContainerTag'] = null; + break; + case self::FORM_TYPE_NUMBER: + $attrs['min'] = null; // attr min + $attrs['max'] = null; // attr max + $attrs['step'] = null; // attr step + // continue form type text + case self::FORM_TYPE_TEXT: + $attrs['maxLength'] = null; // if null have no limit + $attrs['size'] = null; + $attrs['prefix'] = array( + 'type' => 'none', // none | button | label + 'label' => null, + 'id' => null, + 'btnAction' => null, + 'attrs' => array() + ); + $attrs['postfix'] = array( + 'type' => 'none', // none | button | label + 'label' => null, + 'id' => null, + 'btnAction' => null, + 'attrs' => array() + ); + break; + case self::FORM_TYPE_SELECT: + $attrs['classes'][] = 'js-select'; + $attrs['multiple'] = false; + $attrs['options'] = array(); // ParamOption[] | callback + $attrs['size'] = 1; // select size if 0 get num options + break; + case self::FORM_TYPE_CHECKBOX: + case self::FORM_TYPE_SWITCH: + $attrs['checkboxLabel'] = null; + $attrs['checkedValue'] = true; + break; + case self::FORM_TYPE_M_CHECKBOX: + $attrs['options'] = array(); // ParamOption[] | callback + $attrs['wrapperContainerTag'] = 'div'; + break; + case self::FORM_TYPE_RADIO: + $attrs['options'] = array(); // ParamOption[] | callback + $attrs['wrapperContainerTag'] = 'div'; + break; + case self::FORM_TYPE_BGROUP: + $attrs['options'] = array(); // ParamOption[] | callback + $attrs['wrapperContainerTag'] = 'span'; + $attrs['inputContainerClasses'] = array('input-container', 'btn-group'); + break; + default: + // accepts unknown values ​​because this class can be extended + } + + return $attrs; + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamFormPass.php b/installer/dup-installer/src/Core/Params/Items/ParamFormPass.php new file mode 100644 index 00000000..662fd972 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamFormPass.php @@ -0,0 +1,94 @@ +formType == self::FORM_TYPE_PWD_TOGGLE) { + $this->pwdToggleHtml(); + } else { + parent::htmlItem(); + } + } + + /** + * return the text of current object for info only status + * + * @return string + */ + protected function valueToInfo() + { + return '**********'; + } + + /** + * Render PWD toggle element + * + * @return void + */ + protected function pwdToggleHtml() + { + $attrs = array( + 'value' => $this->getInputValue(), + ); + + if ($this->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + if (!is_null($this->formAttr['maxLength'])) { + $attrs['maxLength'] = $this->formAttr['maxLength']; + } + + if (!is_null($this->formAttr['size'])) { + $attrs['size'] = $this->formAttr['size']; + } + + $attrs = array_merge($attrs, $this->formAttr['attr']); + + \DUPX_U_Html::inputPasswordToggle($this->getAttrName(), $this->formAttr['id'], $this->formAttr['classes'], $attrs, true); + } + + /** + * Get default form attributes + * + * @param string $formType form type + * + * @return array + */ + protected static function getDefaultAttrForFormType($formType) + { + $attrs = parent::getDefaultAttrForFormType($formType); + if ($formType == self::FORM_TYPE_PWD_TOGGLE) { + $attrs['maxLength'] = null; // if null have no limit + $attrs['size'] = null; + } + return $attrs; + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamFormPlugins.php b/installer/dup-installer/src/Core/Params/Items/ParamFormPlugins.php new file mode 100644 index 00000000..eb8f88f3 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamFormPlugins.php @@ -0,0 +1,318 @@ +formType == self::FORM_TYPE_PLUGINS_SELECT) { + $this->pluginSelectHtml(); + } else { + parent::htmlItem(); + } + } + + /** + * Render plugin selector HTML + * + * @return void + */ + protected function pluginSelectHtml() + { + $pluginsManager = \DUPX_Plugins_Manager::getInstance(); + $plugns_list = $pluginsManager->getPlugins(); + + $attrs = array( + 'id' => $this->formAttr['id'], + 'name' => $this->getAttrName() . '[]', + 'multiple' => '' + ); + $this->formAttr['classes'][] = 'no-display'; + + if (!empty($this->formAttr['classes'])) { + $attrs['class'] = implode(' ', array_unique($this->formAttr['classes'])); + } + + if ($this->isDisabled()) { + $attrs['disabled'] = 'disabled'; + } + + if ($this->isReadonly()) { + $attrs['readonly'] = 'readonly'; + } + + $attrs = array_merge($attrs, $this->formAttr['attr']); + ?> + + getSubNote(); + $this->pluginsSelector(); + } + + /** + * Render plugin selector + * + * @return void + */ + protected function pluginsSelector() + { + $pluginsManager = \DUPX_Plugins_Manager::getInstance(); + $plugns_list = $pluginsManager->getPlugins(); + $paramsManager = PrmMng::getInstance(); + $safe_mode = $paramsManager->getValue(PrmMng::PARAM_SAFE_MODE); + ?> +
          + isDisabled()) { ?> + 0) { + echo + '
          ' + . ' Safe Mode Enabled: Only Duplicator will be enabled during install.' + . '
          '; + } + ?> +
          + +
          +
            +
          • + + All () + +
          • + getStatusCounts() as $status => $count) { + if ($count) { + ?> +
          • + + () + +
          • + +
          + + + + + + + + + + + + isIgnore() || $pluginObj->isForceDisabled()) { + continue; + } + $this->pluginHtmlItem($pluginObj); + } + ?> + +
          NameDetailsOriginal
          Status
          + pluginTableSelectorJs(); + } + + /** + * Render plugin item + * + * @param \DUPX_Plugin_item $pluginObj plugin object + * @param int $subsiteId selected subsite id + * + * @return void + */ + protected function pluginHtmlItem($pluginObj, $subsiteId = -1) + { + $itemClasses = array( + 'table-item', + ); + $orgiStats = $pluginObj->getOrgiStatus($subsiteId); + $itemClasses[] = 'orig-' . $orgiStats; + $itemClasses[] = self::isValueInValue($pluginObj->slug, $this->getInputValue()) ? 'active' : 'inactive'; + + //$authorURI = $pluginObj->authorURI; + if (empty($pluginObj->authorURI)) { + $author = \DUPX_U::esc_html($pluginObj->author); + } else { + $author = '' . \DUPX_U::esc_html($pluginObj->author) . ''; + } + ?> + + + isReadonly() ? 'readonly' : ''; ?> isDisabled() ? 'disabled' : ''; ?>> + + name); ?> + + Version: version); ?>
          + URL: + pluginURI); ?> +
          + Author:
          + + getStatusLabel($orgiStats)); ?> + + + + formType == self::FORM_TYPE_TABLES_SELECT) { + $this->tablesSelectHtml(); + } else { + parent::htmlItem(); + } + } + + /** + * Render tables selector HTML + * + * @return void + */ + protected function tablesSelectHtml() + { + $tables = \DUPX_DB_Tables::getInstance(); + $value = $this->getInputValue(); + ?> + + + + + + + + + + + + + + + + + $tableVals) { + $this->tableHtmlItem($tableVals, $tables->getTableObjByName($name), $index); + $index++; + } + ?> + + + + + + + + + +
          + Toggle All + + + + + + + + + + +
          Original NameNew NameImportUpdate
          Original NameNew NameImportUpdate
          + getFormItemId() . self::TABLE_ITEM_POSTFIX + ); + $hiddenNameAttrs = array( + 'id' => $this->getFormItemId() . self::TABLE_NAME_POSTFIX_TNAME . '_' . $index, + 'type' => 'hidden', + 'name' => $this->getName() . '[]', + 'class' => $this->getFormItemId() . self::TABLE_NAME_POSTFIX_TNAME, + 'value' => $tableOjb->getOriginalName() + ); + $extractCheckboxAttrs = array( + 'id' => $this->getFormItemId() . self::TABLE_NAME_POSTFIX_EXTRACT . '_' . $index, + 'name' => $this->getName() . self::TABLE_NAME_POSTFIX_EXTRACT . '[]', + 'class' => $this->getFormItemId() . self::TABLE_NAME_POSTFIX_EXTRACT, + 'value' => 1 + ); + $replaceCheckboxAttrs = array( + 'id' => $this->getFormItemId() . self::TABLE_NAME_POSTFIX_REPLACE . '_' . $index, + 'name' => $this->getName() . self::TABLE_NAME_POSTFIX_REPLACE . '[]', + 'class' => $this->getFormItemId() . self::TABLE_NAME_POSTFIX_REPLACE, + 'value' => 1 + ); + + if ($tableOjb->canBeExctracted()) { + if ($vals['extract']) { + $extractCheckboxAttrs['checked'] = ''; + } + + if ($vals['replace']) { + $replaceCheckboxAttrs['checked'] = ''; + } + } else { + $itemClasses[] = 'no-display'; + $extractCheckboxAttrs['disabled'] = ''; + $replaceCheckboxAttrs['disabled'] = ''; + } + + if ($this->isDisabled() || $this->isReadonly()) { + $extractCheckboxAttrs['disabled'] = ''; + $replaceCheckboxAttrs['disabled'] = ''; + + $skipSendValue = true; + } else { + $skipSendValue = false; + } + ?> + + + getOriginalName()); ?>
          + Rows: getRows(); ?> Size: getSize(true); ?> + + + getNewName()); ?>
          +   + + + + > + 'Extract in database' + ) + ); + ?> + + + 'Apply replace engine at URLs and paths in database' + ) + ); + ?> + + + getTablesNames(); + $validateTables = array_keys($validateValue); + + // all tables in list have to exist in avaiable tables + foreach ($validateValue as $table => $tableValues) { + if (!in_array($table, $avaiableTables)) { + Log::info('INVALID ' . $table . ' ISN\'T IN AVAIBLE LIST: ' . Log::v2str($avaiableTables)); + return false; + } + } + + // all tables abaliable have to exists in list + foreach ($avaiableTables as $avaibleTable) { + if (!in_array($avaibleTable, $validateTables)) { + Log::info('AVAIABLE ' . $avaibleTable . ' ISN\'T IN PARAM LIST TABLE'); + return false; + } + } + + return true; + } + + /** + * Appli filter to value input + * + * @param array $superObject query string values + * + * @return array + */ + public function getValueFilter($superObject) + { + $result = array(); + + if (($tables = json_decode($superObject[$this->getName()])) == false) { + throw new \Exception('Invalid json string'); + } + + foreach ($tables as $table) { + $table = (array) $table; + if ($table['extract'] == false) { + // replace can't be true if extract if false + $table['replace'] = false; + } + $result[$table['name']] = $table; + } + + return $result; + } + + /** + * Return sanitized value + * + * @param mixed $value value input + * + * @return array + */ + public function getSanitizeValue($value) + { + $newValues = (array) $value; + $sanitizeValues = array(); + + foreach ($newValues as $key => $newValue) { + $sanitizedKey = SnapUtil::sanitizeNSCharsNewlineTrim($key); + $newValue = (array) $newValue; + + $sanitizedNewValue = self::getParamItemValueFromData(); + $sanitizedNewValue['name'] = isset($newValue['name']) ? SnapUtil::sanitizeNSCharsNewlineTrim($newValue['name']) : ''; + $sanitizedNewValue['extract'] = isset($newValue['extract']) ? filter_var($newValue['extract'], FILTER_VALIDATE_BOOLEAN) : false; + $sanitizedNewValue['replace'] = isset($newValue['replace']) ? filter_var($newValue['replace'], FILTER_VALIDATE_BOOLEAN) : false; + + $sanitizeValues[$sanitizedKey] = $sanitizedNewValue; + } + return $sanitizeValues; + } + + /** + * Get default type attributes + * + * @param string $type param type + * + * @return array + */ + protected static function getDefaultAttrForType($type) + { + $attrs = parent::getDefaultAttrForType($type); + if ($type == self::TYPE_ARRAY_TABLES) { + $attrs['default'] = array(); + } + + return $attrs; + } + + /** + * Get default form attributes + * + * @param string $formType form type + * + * @return array + */ + protected static function getDefaultAttrForFormType($formType) + { + $attrs = parent::getDefaultAttrForFormType($formType); + if ($formType == self::FORM_TYPE_TABLES_SELECT) { + $attrs['wrapperContainerTag'] = 'div'; + $attrs['inputContainerTag'] = 'div'; + } + return $attrs; + } + + /** + * Return param item from data + * + * @param string $name table name + * @param bool $extract extract + * @param bool $replace replace + * + * @return array + */ + public static function getParamItemValueFromData($name = '', $extract = false, $replace = false) + { + return array( + 'name' => $name, + 'extract' => $extract, + 'replace' => $replace + ); + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamFormUsersReset.php b/installer/dup-installer/src/Core/Params/Items/ParamFormUsersReset.php new file mode 100644 index 00000000..45c53cf4 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamFormUsersReset.php @@ -0,0 +1,105 @@ +formType == self::FORM_TYPE_USERS_PWD_RESET) { + $result = ''; + $users = \DUPX_ArchiveConfig::getInstance()->getUsersLists(); + + $mainInputId = $this->formAttr['id']; + foreach ($users as $userId => $login) { + $this->currentUserId = $userId; + $this->formAttr['id'] = $mainInputId . '_' . $this->currentUserId; + $this->formAttr['label'] = $login; + $result .= parent::getHtml($echo); + } + $this->currentUserId = -1; + $this->formAttr['id'] = $mainInputId; + return $result; + } else { + return parent::getHtml($echo); + } + } + + /** + * Display the html input of current item + * + * @return void + */ + protected function htmlItem() + { + if ($this->formType == self::FORM_TYPE_USERS_PWD_RESET) { + $this->pwdToggleHtml(); + } else { + parent::htmlItem(); + } + } + + /** + * Return attribute name + * + * @return string + */ + protected function getAttrName() + { + return $this->name . '[' . $this->currentUserId . ']'; + } + + /** + * Return input value + * + * @return mixed + */ + protected function getInputValue() + { + return isset($this->value[$this->currentUserId]) ? $this->value[$this->currentUserId] : ''; + } + + /** + * Get default form attributes + * + * @param string $formType form type + * + * @return array + */ + protected static function getDefaultAttrForFormType($formType) + { + $attrs = parent::getDefaultAttrForFormType($formType); + if ($formType == self::FORM_TYPE_USERS_PWD_RESET) { + $attrs['maxLength'] = null; // if null have no limit + $attrs['size'] = null; + } + return $attrs; + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamFormWpConfig.php b/installer/dup-installer/src/Core/Params/Items/ParamFormWpConfig.php new file mode 100644 index 00000000..8a89ceaa --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamFormWpConfig.php @@ -0,0 +1,221 @@ +attr['defaultFromInput'] = $this->attr['default']; + $this->attr['defaultFromInput']['inWpConfig'] = false; + + if ($type === self::TYPE_BOOL) { + $this->attr['defaultFromInput']['value'] = false; + } + } + + /** + * this function is calle before sanitization. + * Is use in extendend classs and transform value before the sanitization and validation process + * + * @param array $superObject query string super object + * + * @return mixed + */ + protected function getValueFilter($superObject) + { + $result = array( + 'value' => parent::getValueFilter($superObject), + 'inWpConfig' => filter_var($superObject[$this->name . self::IN_WP_CONF_POSTFIX], FILTER_VALIDATE_BOOLEAN) + ); + + if (!parent::isValueInInput($superObject)) { + $result['value'] = $this->attr['defaultFromInput']['value']; + } + + return $result; + } + + /** + * Return sanitized value + * + * @param mixed $value input value + * + * @return mixed + */ + public function getSanitizeValue($value) + { + $result = (array) $value; + $result['value'] = parent::getSanitizeValue($result['value']); + return $result; + } + + /** + * Get value info from value + * + * @return string + */ + protected function valueToInfo() + { + if ($this->value['inWpConfig']) { + return 'Set in wp config with value ' . parent::valueToInfo(); + } else { + return 'Not set in wp config'; + } + } + + /** + * Return input value + * + * @return mixed + */ + protected function getInputValue() + { + return $this->value['value']; + } + + /** + * Return true if value is in input method + * + * @param array $superObject query string super object + * + * @return bool + */ + protected function isValueInInput($superObject) + { + return parent::isValueInInput($superObject) || isset($superObject[$this->name . self::IN_WP_CONF_POSTFIX]); + } + + /** + * Check if input value is valid + * + * @param mixed $value input value + * @param mixed $validateValue variable passed by reference. Updated to validated value in the case, the value is a valid value. + * + * @return bool true if is a valid value for this object + */ + public function isValid($value, &$validateValue = null) + { + if (!is_array($value) || !isset($value['value']) || !isset($value['inWpConfig'])) { + Log::info('WP CONFIG INVALID ARRAY VAL:' . Log::v2str($value)); + return false; + } + + // IF isn't in wp config the value isn't validate + if ($value['inWpConfig'] === false) { + $validateValue = $value; + return true; + } else { + $confValidValue = $value['value']; + if (parent::isValid($value['value'], $confValidValue) === false) { + Log::info('WP CONFIG INVALID VALUE:' . Log::v2str($confValidValue)); + return false; + } else { + $validateValue = $value; + $validateValue['value'] = $confValidValue; + return true; + } + } + } + + /** + * Render HTML input before content + * + * @return void + */ + protected function htmlInputContBefore() + { + if ($this->getFormStatus() == self::STATUS_INFO_ONLY) { + return; + } + + if (!$this->value['inWpConfig']) { + $this->formAttr['inputContainerClasses'][] = 'no-display'; + if ($this->formAttr['status'] == self::STATUS_ENABLED) { + $this->formAttr['status'] = self::STATUS_DISABLED; + } + } + + $inputAttrs = array( + 'name' => $this->name . self::IN_WP_CONF_POSTFIX, + 'value' => 1 + ); + if ($this->value['inWpConfig']) { + $inputAttrs['checked'] = 'checked'; + } + echo ''; + \DUPX_U_Html::checkboxSwitch( + $inputAttrs, + array( + 'title' => 'Add in wp config' + ) + ); + echo ''; + } + + /** + * This function return the default attr for each type. + * in the constructor an array merge is made between the result of this function and the parameters passed. + * In this way the values ​​in $ this -> ['attr'] are always consistent. + * + * @param string $type param value type + * + * @return array + */ + protected static function getDefaultAttrForType($type) + { + $attrs = parent::getDefaultAttrForType($type); + $valFromInput = $attrs['defaultFromInput']; + + $attrs['defaultFromInput'] = array( + 'value' => $valFromInput, + 'inWpConfig' => false + ); + return $attrs; + } + + /** + * this function return the default formAttr for each type. + * in the constructor an array merge is made between the result of this function and the parameters passed. + * In this way the values ​​in $ this -> ['attr'] are always consistent. + * + * @param string $formType form type + * + * @return array + */ + protected static function getDefaultAttrForFormType($formType) + { + $attrs = parent::getDefaultAttrForFormType($formType); + + $attrs['wrapperClasses'][] = 'wp-config-item'; + $attrs['wrapperContainerTag'] = 'div'; + return $attrs; + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamItem.php b/installer/dup-installer/src/Core/Params/Items/ParamItem.php new file mode 100644 index 00000000..1d126852 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamItem.php @@ -0,0 +1,656 @@ +\0]+$/'; + const VALIDATE_REGEX_FILE_PATH = '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/'; + + protected $name = null; + protected $type = null; + protected $attr = array(); + protected $value = null; + protected $status = self::STATUS_INIT; + + /** + * Class constructor + * + * @param string $name param identifier + * @param string $type TYPE_STRING | TYPE_ARRAY_STRING | ... + * @param array $attr list of attributes + */ + public function __construct($name, $type, $attr = null) + { + if (empty($name) || strlen($name) < 4) { + throw new \Exception('the name can\'t be empty or len can\'t be minor of 4'); + } + $this->type = $type; + $this->attr = array_merge(static::getDefaultAttrForType($type), (array) $attr); + if ($type == self::TYPE_ARRAY_STRING || $type == self::TYPE_ARRAY_INT || $type == self::TYPE_ARRAY_MIXED) { + $this->attr['default'] = (array) $this->attr['default']; + } + $this->name = $name; + $this->value = $this->getSanitizeValue($this->attr['default']); + + if (is_null($this->attr['defaultFromInput'])) { + $this->attr['defaultFromInput'] = $this->attr['default']; + } else { + if ($type == self::TYPE_ARRAY_STRING || $type == self::TYPE_ARRAY_INT || $type == self::TYPE_ARRAY_MIXED) { + $this->attr['defaultFromInput'] = (array) $this->attr['defaultFromInput']; + } + } + } + + /** + * this funtion return the discursive label + * + * @return string + */ + public function getLabel() + { + return $this->name; + } + + /** + * get current item identifier + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * get current item value + * + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * + * @return string // STATUS_INIT | STATUS_OVERWRITE | STATUS_UPD_FROM_INPUT + */ + public function getStatus() + { + return $this->status; + } + + /** + * Set item status with overwrite value + * + * @return void + */ + public function setOveriteStatus() + { + $this->status = self::STATUS_OVERWRITE; + } + + /** + * if it is true, this object is defined as persistent and will be saved in the parameter persistence file otherwise the param manager + * will not save this value and at each call of the script the parameter will assume the default value. + * + * @return bool + */ + public function isPersistent() + { + return $this->attr['persistence']; + } + + /** + * return the invalid param message or empty string + * + * @return string + */ + public function getInvalidMessage() + { + if (is_callable($this->attr['invalidMessage'])) { + return call_user_func($this->attr['invalidMessage'], $this); + } else { + return (string) $this->attr['invalidMessage']; + } + } + + /** + * Set the invalid param message + * + * @param $message invalid message + * + * @return string + */ + public function setInvalidMessage($message) + { + $this->attr['invalidMessage'] = (string) $message; + } + + /** + * Update item attribute + * + * @param string $key attribute key + * @param mixed $value value + * + * @return void + */ + public function setAttr($key, $value) + { + $this->attr[$key] = $value; + } + + /** + * Set param value + * + * @param mixed $value value to set + * + * @return boolean false if value isn't validated + */ + public function setValue($value) + { + $validateValue = null; + if (!$this->isValid($value, $validateValue)) { + return false; + } + + $this->value = $validateValue; + return true; + } + + /** + * Get super object from method + * + * @param string $method query string method + * + * @return array return the reference + */ + protected static function getSuperObjectByMethod($method) + { + $superObject = array(); + switch ($method) { + case self::INPUT_GET: + $superObject = &$_GET; + break; + case self::INPUT_POST: + $superObject = &$_POST; + break; + case self::INPUT_REQUEST: + $superObject = &$_REQUEST; + break; + case self::INPUT_COOKIE: + $superObject = &$_COOKIE; + break; + case self::INPUT_SERVER: + $superObject = &$_SERVER; + break; + case self::INPUT_ENV: + $superObject = &$_ENV; + break; + default: + throw new \Exception('INVALID SUPER OBJECT METHOD ' . Log::v2str($method)); + } + return $superObject; + } + + /** + * Return true if value is in input method + * + * @param array $superObject query string super object + * + * @return bool + */ + protected function isValueInInput($superObject) + { + return isset($superObject[$this->name]); + } + + /** + * update the value from input if exists ot set the default + * sanitation and validation are performed + * + * @param string $method query string method + * + * @return boolean false if value isn't validated + */ + public function setValueFromInput($method = self::INPUT_POST) + { + $superObject = self::getSuperObjectByMethod($method); + + Log::info( + 'SET VALUE FROM INPUT KEY [' . $this->name . '] VALUE[' . + Log::v2str(isset($superObject[$this->name]) ? $superObject[$this->name] : '') . + ']', + Log::LV_DEBUG + ); + + if (!$this->isValueInInput($superObject)) { + $inputValue = $this->attr['defaultFromInput']; + } else { + // get value from input + $inputValue = $this->getValueFilter($superObject); + // sanitize value + $inputValue = $this->getSanitizeValue($inputValue); + } + + if (($result = $this->setValue($inputValue)) === false) { + $msg = 'PARAM [' . $this->name . '] ERROR: Invalid value ' . Log::v2str($inputValue); + Log::info($msg); + return false; + } else { + $this->status = self::STATUS_UPD_FROM_INPUT; + } + + return $result; + } + + /** + * Check if input value is valid + * + * @param mixed $value input value + * @param mixed $validateValue variable passed by reference. Updated to validated value in the case, the value is a valid value. + * + * @return bool true if is a valid value for this object + */ + public function isValid($value, &$validateValue = null) + { + switch ($this->type) { + case self::TYPE_STRING: + case self::TYPE_BOOL: + case self::TYPE_INT: + return $this->isValidScalar($value, $validateValue); + case self::TYPE_ARRAY_STRING: + case self::TYPE_ARRAY_INT: + case self::TYPE_ARRAY_MIXED: + return $this->isValidArray($value, $validateValue); + default: + throw new \Exception('ITEM ERROR invalid type ' . $this->type); + } + } + + /** + * Validate function for scalar value + * + * @param mixed $value input value + * @param mixed $validateValue variable passed by reference. Updated to validated value in the case, the value is a valid value. + * + * @return boolean false if value isn't a valid value + */ + protected function isValidScalar($value, &$validateValue = null) + { + if (!is_null($value) && !is_scalar($value)) { + return false; + } + + $result = true; + switch ($this->type) { + case self::TYPE_STRING: + case self::TYPE_ARRAY_STRING: + $validateValue = (string) $value; + if (strlen($validateValue) < $this->attr['min_len']) { + $this->setInvalidMessage('Must have ' . $this->attr['min_len'] . ' or more characters'); + $result = false; + } + + if ($this->attr['max_len'] > 0 && strlen($validateValue) > $this->attr['max_len']) { + $this->setInvalidMessage('Must have max ' . $this->attr['mimax_lenn_len'] . ' characters'); + $result = false; + } + + if (!empty($this->attr['validateRegex']) && preg_match($this->attr['validateRegex'], $validateValue) !== 1) { + $this->setInvalidMessage('String isn\'t valid'); + $result = false; + } + break; + case self::TYPE_INT: + case self::TYPE_ARRAY_INT: + $validateValue = filter_var($value, FILTER_VALIDATE_INT, array( + 'options' => array( + 'default' => false, // value to return if the filter fails + 'min_range' => $this->attr['min_range'], + 'max_range' => $this->attr['max_range'], + ) + )); + + if ($validateValue === false) { + $this->setInvalidMessage('Isn\'t a valid number'); + $result = false; + } + break; + case self::TYPE_BOOL: + $validateValue = is_bool($value) ? $value : filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + if (($result = !is_null($validateValue)) === false) { + $this->setInvalidMessage('Isn\'t a valid value'); + } + break; + default: + throw new \Exception('ITEM ERROR ' . $this->name . ' Invalid type ' . $this->type); + } + + if ($result == true) { + $acceptValues = $this->getAcceptValues(); + if (empty($acceptValues)) { + $result = $this->callValidateCallback($validateValue); + } else { + if (in_array($validateValue, $acceptValues)) { + $result = true; + } else { + $this->setInvalidMessage('Isn\'t a accepted value'); + $result = false; + } + } + } + + if ($result === false) { + $validateValue = null; + } + + return $result; + } + + /** + * Validate function for array value + * + * @param mixed $value input value + * @param mixed $validateValue variable passed by reference. Updated to validated value in the case, the value is a valid value. + * + * @return boolean false if value isn't a valid value + */ + protected function isValidArray($value, &$validateValue = null) + { + $newValues = (array) $value; + $validateValue = array(); + $validValue = null; + + if ($this->type == self::TYPE_ARRAY_MIXED) { + $validateValue = $newValues; + return $this->callValidateCallback($newValues); + } else { + foreach ($newValues as $key => $newValue) { + if (!$this->isValidScalar($newValue, $validValue)) { + return false; + } + $validateValue[$key] = $validValue; + } + } + return true; + } + + /** + * Call attribute validate callback + * + * @param mixed $value input value + * + * @return mixed + */ + protected function callValidateCallback($value) + { + if (is_callable($this->attr['validateCallback'])) { + return call_user_func($this->attr['validateCallback'], $value, $this); + } elseif (!is_null($this->attr['validateCallback'])) { + throw new \Exception('PARAM ' . $this->name . ' validateCallback isn\'t null and isn\'t callable'); + } else { + return true; + } + } + + /** + * this function is calle before sanitization. + * Is use in extendend classs and transform value before the sanitization and validation process + * + * @param array $superObject query string super object + * + * @return mixed + */ + protected function getValueFilter($superObject) + { + if (isset($superObject[$this->name])) { + return $superObject[$this->name]; + } else { + return null; + } + } + + /** + * Return sanitized value + * + * @param mixed $value input value + * + * @return mixed + */ + public function getSanitizeValue($value) + { + switch ($this->type) { + case self::TYPE_STRING: + case self::TYPE_BOOL: + case self::TYPE_INT: + return $this->getSanitizeValueScalar($value); + case self::TYPE_ARRAY_STRING: + case self::TYPE_ARRAY_INT: + return $this->getSanitizeValueArray($value); + case self::TYPE_ARRAY_MIXED: + // global sanitize for mixed + return $this->getSanitizeValueScalar($value); + default: + throw new \Exception('ITEM ERROR invalid type ' . $this->type); + } + } + + /** + * If sanitizeCallback is apply sanitizeCallback at current value else return value. + * + * @param mixed $value input value + * + * @return mixed + */ + protected function getSanitizeValueScalar($value) + { + if (is_callable($this->attr['sanitizeCallback'])) { + return call_user_func($this->attr['sanitizeCallback'], $value); + } elseif (!is_null($this->attr['sanitizeCallback'])) { + throw new \Exception('PARAM ' . $this->name . ' sanitizeCallback isn\'t null and isn\'t callable'); + } else { + return $value; + } + } + + /** + * If sanitizeCallback is apply sanitizeCallback at each value of array. + * + * @param mixed $value input value + * + * @return array + */ + protected function getSanitizeValueArray($value) + { + $newValues = (array) $value; + $sanitizeValues = array(); + + foreach ($newValues as $key => $newValue) { + $sanitizeValues[$key] = $this->getSanitizeValueScalar($newValue); + } + + return $sanitizeValues; + } + + /** + * get accept values + * + * @return array + */ + public function getAcceptValues() + { + if (is_callable($this->attr['acceptValues'])) { + return call_user_func($this->attr['acceptValues'], $this); + } else { + return $this->attr['acceptValues']; + } + } + + /** + * Set value from array. This function is used to set data from json array + * + * @param array $data param data + * + * @return boolean + */ + public function fromArrayData($data) + { + $data = (array) $data; + if (isset($data['status'])) { + $this->status = $data['status']; + } + + // only if value is different from current value + if (isset($data['value']) && $data['value'] !== $this->value) { + $sanitizedVal = $this->getSanitizeValue($data['value']); + return $this->setValue($sanitizedVal); + } else { + return true; + } + } + + /** + * return array dato to store in json array data + * + * @return array + */ + public function toArrayData() + { + return array( + 'value' => $this->value, + 'status' => $this->status + ); + } + + /** + * Return a copy of this object with a new name ad overwrite attr + * + * @param string $newName new name + * @param array $attr overwrite attributes + * + * @return self + */ + public function getCopyWithNewName($newName, $attr = array()) + { + $copy = clone $this; + $reflect = new \ReflectionObject($copy); + + $nameProp = $reflect->getProperty('name'); + $nameProp->setAccessible(true); + $nameProp->setValue($copy, $newName); + + $attrProp = $reflect->getProperty('attr'); + $attrProp->setAccessible(true); + $newAttr = array_merge($attrProp->getValue($copy), $attr); + $attrProp->setValue($copy, $newAttr); + + $valueProp = $reflect->getProperty('value'); + $valueProp->setAccessible(true); + $valueProp->setValue($copy, $newAttr['default']); + + return $copy; + } + + /** + * This function return the default attr for each type. + * in the constructor an array merge is made between the result of this function and the parameters passed. + * In this way the values ​​in $ this -> ['attr'] are always consistent. + * + * @param string $type param value type + * + * @return array + */ + protected static function getDefaultAttrForType($type) + { + $attrs = array( + 'default' => null, // the default value on init + 'defaultFromInput' => null, // if value isn't set in query form when setValueFromInput is called set this valus. + // (normally defaultFromInput is equal to default) + 'acceptValues' => array(), // if not empty accept only values in list | callback + 'sanitizeCallback' => null, // function (ParamItem $obj, $inputValue) + 'validateCallback' => null, // function (ParamItem $obj, $validateValue, $originalValue) + 'persistence' => true, // if false don't store value in persistence file + 'invalidMessage' => '' //this message is added at next step validation error message if not empty + ); + + switch ($type) { + case self::TYPE_STRING: // value type is a string + $attrs['min_len'] = 0; // min string len. used in validation + $attrs['max_len'] = 0; // max string len. used in validation + $attrs['default'] = ''; // set default at empty string + $attrs['validateRegex'] = null; // if isn;t null this regex is called to pass for validation. + //Can be combined with validateCallback. If both are active, the validation must pass both. + break; + case self::TYPE_ARRAY_STRING: // value type is array of string + $attrs['min_len'] = 0; // min string len. used in validation + $attrs['max_len'] = 0; // max string len. used in validation + $attrs['default'] = array(); // set default at empty array + $attrs['validateRegex'] = null; // if isn;t null this regex is called to pass for validation. + // Can be combined with validateCallback. If both are active, the validation must pass both. + break; + case self::TYPE_INT: // value type is a int + $attrs['min_range'] = PHP_INT_MAX * -1; + $attrs['max_range'] = PHP_INT_MAX; + $attrs['default'] = 0; // set default at 0 + break; + case self::TYPE_ARRAY_INT: // value type is an array of int + $attrs['min_range'] = PHP_INT_MAX * -1; + $attrs['max_range'] = PHP_INT_MAX; + $attrs['default'] = array(); // set default at empty array + break; + case self::TYPE_BOOL: + $attrs['default'] = false; // set default fals + $attrs['defaultFromInput'] = false; // if value isn't set in input the default must be false for bool values + break; + case self::TYPE_ARRAY_MIXED: + break; + default: + // accepts unknown values ​​because this class can be extended + } + return $attrs; + } +} diff --git a/installer/dup-installer/src/Core/Params/Items/ParamOption.php b/installer/dup-installer/src/Core/Params/Items/ParamOption.php new file mode 100644 index 00000000..5da17dc0 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/Items/ParamOption.php @@ -0,0 +1,149 @@ +value = $value; + $this->label = $label; + $this->optStatus = $optStatus; + $this->attrs = (array) $attrs; + } + + /** + * get current statis. + * + * @return string + */ + public function getStatus() + { + if (is_callable($this->optStatus)) { + return call_user_func($this->optStatus, $this); + } else { + return $this->optStatus; + } + } + + /** + * Set options status + * + * @param string|callable $optStatus option status. can be a fixed status or a callback + * + * @return void + */ + public function setStatus($optStatus) + { + $this->optStatus = $optStatus; + } + + /** + * Set option note + * + * @param string|callable $note option note + * + * @return void + */ + public function setNote($note) + { + $this->note = is_callable($note) ? $note : ((string) $note); + } + + /** + * + * @return string + */ + public function getNote() + { + $note = ''; + if (is_callable($this->note)) { + $note = call_user_func($this->note, $this); + } else { + $note = $this->note; + } + + return (empty($note) ? '' : '
          ' . $note . '
          '); + } + + /** + * Set option group, used on select + * + * @param string $label optiongroup label is empty reset option + * + * @return void + */ + public function setOptGroup($label) + { + $this->groupLabel = (string) $label; + } + + /** + * Return option group label, empty if not set + * + * @return string + */ + public function getOptGroup() + { + return $this->groupLabel; + } + + /** + * + * @return bool + */ + public function isEnable() + { + return $this->getStatus() == self::OPT_ENABLED; + } + + /** + * + * @return bool + */ + public function isDisabled() + { + return $this->getStatus() == self::OPT_DISABLED; + } + + /** + * + * @return bool + */ + public function isHidden() + { + return $this->getStatus() == self::OPT_HIDDEN; + } +} diff --git a/installer/dup-installer/src/Core/Params/PrmMng.php b/installer/dup-installer/src/Core/Params/PrmMng.php new file mode 100644 index 00000000..12b76cc4 --- /dev/null +++ b/installer/dup-installer/src/Core/Params/PrmMng.php @@ -0,0 +1,863 @@ +params); + $this->params = HooksMng::getInstance()->applyFilters('installer_get_init_params', $this->params); + + $this->paramsHtmlInfo[] = '***** INIT PARAMS WITH STD VALUlES'; + + return true; + } + + /** + * get value of param key. + * thorw execption if key don't exists + * + * @param string $key param key + * + * @return mixed + * + * @throws \Exception + */ + public function getValue($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + return $this->params[$key]->getValue(); + } + + /** + * Get param status + * + * @param string $key param key + * + * @return string // STATUS_INIT | STATUS_OVERWRITE | STATUS_UPD_FROM_INPUT + * + * @throws \Exception + */ + public function getInitStatus($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'does not exists'); + } + return $this->params[$key]->getStatus(); + } + + /** + * get the label of param key. + * thorw execption if key don't exists + * + * @param string $key param key + * + * @return string + * + * @throws \Exception + */ + public function getLabel($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + return rtrim($this->params[$key]->getLabel(), ": \n\t"); + } + + /** + * Set param value + * + * @param string $key param key + * @param mixed $value value + * + * @return boolean // return false if params isn't valid + * + * @throws \Exception // if key don't exists + */ + public function setValue($key, $value) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + return $this->params[$key]->setValue($value); + } + + /** + * this cungion set value get from input method. + * + * @param string $key param key + * @param string $method input method (GET, POST ... ) + * @param boolean $thowException if true throw exception if value isn't valid. + * @param boolean $nextStepErrorMessage if true and param isn't valid add next step message + * + * @return boolean + */ + public function setValueFromInput($key, $method = ParamForm::INPUT_POST, $thowException = true, $nextStepErrorMessage = false) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (($result = $this->params[$key]->setValueFromInput($method)) === false) { + $this->paramsHtmlInfo[] = 'INVALID VALUE INPUT ' . $key . ''; + + if ($nextStepErrorMessage) { + $this->addParamValidationFaliedNotice($key); + } + if ($thowException) { + $errorMessage = 'Parameter "' . $this->getLabel($key) . '" have invalid value'; + throw new \Exception('PARAM ERROR: ' . $errorMessage); + } + } else { + $this->paramsHtmlInfo[] = 'SET FROM INPUT ' . $key . ' VALUE: ' . Log::v2str($this->params[$key]->getValue()); + } + return $result; + } + + /** + * Add next step validation failed notice + * + * @param string $key param key + * + * @return void + */ + public function addParamValidationFaliedNotice($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + $longMessage = '' . $this->getLabel($key) . ' ' . $this->params[$key]->getInvalidMessage() . "
          \n"; + \DUPX_NOTICE_MANAGER::getInstance()->addNextStepNotice(array( + 'shortMsg' => 'Parameter validation failed', + 'level' => \DUPX_NOTICE_ITEM::CRITICAL, + 'longMsg' => $longMessage, + 'longMsgMode' => \DUPX_NOTICE_ITEM::MSG_MODE_HTML + ), \DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'params_validation_fail'); + } + + /** + * Return the form param wrapper id + * + * @param string $key param key + * + * @return boolean|string return false if the item key isn't a instance of ParamForm + */ + public function getFormWrapperId($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'getFormWrapperId')) { + return $this->params[$key]->getFormWrapperId(); + } else { + return false; + } + } + + /** + * Return form item id + * + * @param string $key param key + * + * @return boolean|string return false if the item key isn't a instance of ParamForm + */ + public function getFormItemId($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'getFormItemId')) { + return $this->params[$key]->getFormItemId(); + } else { + return false; + } + } + + /** + * Get param form status + * + * @param string $key param key + * + * @return boolean|string return false if the item key isn't a instance of ParamForm + */ + public function getFormStatus($key) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'getFormStatus')) { + return $this->params[$key]->getFormStatus(); + } else { + return false; + } + } + + /** + * Set form param status + * + * @param string $key param key + * @param string|callable $status STATUS_ENABLED , STATUS_READONLY or callable function + * + * @return boolean|string return false if the item key isn't a instance of ParamForm + */ + public function setFormStatus($key, $status) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'setFormAttr')) { + return $this->params[$key]->setFormAttr('status', $status); + } else { + return false; + } + } + + /** + * Set form wrapper class + * + * @param string $key param key + * @param string $class wrapper class + * + * @return boolean|string return false if the item key isn't a instance of ParamForm + */ + public function addFormWrapperClass($key, $class) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'addWrapperClass')) { + return $this->params[$key]->addWrapperClass($class); + } else { + return false; + } + } + + /** + * Remove form wrapper class + * + * @param string $key param key + * @param string $class wrapper class + * + * @return boolean|string return false if the item key isn't a instance of ParamForm + */ + public function removeFormWrapperClass($key, $class) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'removeWrapperClass')) { + return $this->params[$key]->removeWrapperClass($class); + } else { + return false; + } + } + + /** + * This tunction add o remove note on the param form + * + * @param string $key param key + * @param string $htmlString true if is html + * + * @return boolean + */ + public function setFormNote($key, $htmlString) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (method_exists($this->params[$key], 'setFormAttr')) { + $this->params[$key]->setFormAttr('subNote', $htmlString); + return true; + } else { + return false; + } + } + + /** + * return true if the input exists in html form + * false if isn't ParamForm object or status is STATUS_INFO_ONLY or STATUS_SKIP + * + * @param string $key param key + * + * @return boolean + */ + public function isHtmlInput($key) + { + $status = $this->getFormStatus($key); + switch ($status) { + case ParamForm::STATUS_ENABLED: + case ParamForm::STATUS_READONLY: + case ParamForm::STATUS_DISABLED: + return true; + case ParamForm::STATUS_INFO_ONLY: + case ParamForm::STATUS_SKIP: + default: + return false; + } + } + + /** + * get the input form html + * + * @param string $key the param identifier + * @param mixed $overwriteValue if not null set overwriteValue begore get html + * (IMPORTANT: the stored param value don't change. To change it use setValue.) + * @param bool $echo true echo else return string + * + * @return bool|string return false if the item kay isn't a instance of ParamForm + */ + public function getHtmlFormParam($key, $overwriteValue = null, $echo = true) + { + if (!isset($this->params[$key])) { + throw new \Exception('Param key ' . Log::v2str($key) . 'don\' exists'); + } + + if (!($this->params[$key] instanceof ParamForm)) { + return false; + } + + if (is_null($overwriteValue)) { + return $this->params[$key]->getHtml($echo); + } else { + $tmpParam = clone $this->params[$key]; + if ($tmpParam->setValue($overwriteValue) === false) { + throw new \Exception('Can\'t set overwriteValue ' . Log::v2str($overwriteValue) . ' in param:' . $tmpParam->getName()); + } + + return $tmpParam->getHtml($echo); + } + } + + /** + * Load params from persistance files + * + * @param boolean $reset if true reset params + * + * @return boolean + */ + public function load($reset = false) + { + if ($reset) { + $this->resetParams(); + $this->initParamsOverwrite(); + return true; + } else { + if (!file_exists(self::getPersistanceFilePath())) { + return false; + } + $this->paramsHtmlInfo[] = '***** LOAD PARAMS FROM PERSISTENCE FILE'; + + if (($json = file_get_contents(self::getPersistanceFilePath())) === false) { + throw new \Exception('Can\'t read param persistence file ' . Log::v2str(self::getPersistanceFilePath())); + } + + $arrayData = json_decode($json, true); + if ($this->setParamsValues($arrayData) === false) { + throw new \Exception('Can\'t set params from persistence file ' . Log::v2str(self::getPersistanceFilePath())); + } + return true; + } + } + + /** + * Remove persistance file and all params and reinit all + * + * @return boolean + */ + protected function resetParams() + { + $this->paramsHtmlInfo[] = '***** RESET PARAMS'; + SnapIO::rm(self::getPersistanceFilePath()); + $this->params = array(); + self::$initialized = false; + return $this->initParams(); + } + + /** + * Ovrewrite params from sources + * + * @return boolean + */ + public function initParamsOverwrite() + { + Log::info('OVERWRITE PARAMS'); + $this->paramsHtmlInfo[] = '***** LOAD OVERWRITE INFO'; + /** + * @todo temp disabled require major study + * if (isset($_ENV[self::ENV_PARAMS_KEY])) { + * $this->paramsHtmlInfo[] = 'LOAD FROM ENV VARS'; + $arrayData = json_decode($_ENV[self::ENV_PARAMS_KEY]); + $this->setParamsValues($arrayData, true); + } */ + // LOAD PARAMS FROM PACKAGE OVERWRITE + $arrayData = (array) \DUPX_ArchiveConfig::getInstance()->overwriteInstallerParams; + if (!empty($arrayData)) { + $this->paramsHtmlInfo[] = '***** LOAD FROM PACKAGE OVERWRITE'; + Log::info(' *** FROM PACKAGE'); + if ($this->setParamsValues($arrayData, true, Log::LV_DEFAULT) === false) { + throw new \Exception('Can\'t set params from package overwrite '); + } + } + + // LOAD PARAMS FROM LOCAL OVERWRITE + $localOverwritePath = DUPX_ROOT . '/' . self::LOCAL_OVERWRITE_PARAMS . self::LOCAL_OVERWRITE_PARAMS_EXTENSION; + if (is_readable($localOverwritePath)) { + // json file is set in $localOverwritePath php file + $json = null; + include($localOverwritePath); + if (empty($json)) { + Log::info('LOCAL OVERWRITE PARAMS FILE ISN\'T WELL FORMED'); + } else { + $arrayData = json_decode($json, true); + if (!empty($arrayData)) { + $this->paramsHtmlInfo[] = '***** LOAD FROM LOCAL OVERWRITE'; + Log::info(' *** FROM LOCAL FILE'); + if ($this->setParamsValues($arrayData, true, Log::LV_DEFAULT) === false) { + throw new \Exception('Can\'t set params from local overwrite '); + } + } + } + } + + // LOAD PARAMS FROM LOCAL OVERWRITE PACKAGE_HASH + $localOverwritePath = DUPX_ROOT . '/' . self::LOCAL_OVERWRITE_PARAMS . '_' . Bootstrap::getPackageHash() . '.json'; + if (is_readable($localOverwritePath)) { + if (($json = file_get_contents($localOverwritePath)) === false) { + Log::info('CAN\'T READ LOCAL OVERWRITE PARAM HASH FILE'); + } else { + $arrayData = json_decode($json, true); + if (!empty($arrayData)) { + $this->paramsHtmlInfo[] = '***** LOAD FROM LOCAL OVERWRITE HASH'; + Log::info(' *** FROM LOCAL FILE'); + if ($this->setParamsValues($arrayData, true, Log::LV_DEFAULT) === false) { + throw new \Exception('Can\'t set params from local overwrite '); + } + } + } + } + + HooksMng::getInstance()->doAction('after_params_overwrite', $this->params); + + Log::info("********************************************************************************"); + return true; + } + + /** + * Update params values from arrayData + * + * @param array $arrayData params data + * @param boolean $overwrite if true overwrite status + * @param integer $logginLevelSet log level + * + * @return bool returns false if a parameter has not been set + */ + protected function setParamsValues($arrayData, $overwrite = false, $logginLevelSet = Log::LV_DEBUG) + { + + if (!is_array($arrayData)) { + throw new \Exception('Invalid data params '); + } + $result = true; + + foreach ($arrayData as $key => $arrayValues) { + if (isset($this->params[$key])) { + $arrayValues = (array) $arrayValues; + $arrayValValToStr = array_map(array('Duplicator\\Installer\\Utils\\Log\\Log', 'v2str'), $arrayValues); + + $this->paramsHtmlInfo[] = 'SET PARAM ' . $key . ' ARRAY DATA: ' . + SnapString::implodeKeyVals(', ', $arrayValValToStr, '[%s = %s]'); + if ($this->params[$key]->fromArrayData($arrayValues) === false) { + Log::info('PARAM ISSUE SET KEY[' . $key . '] VALUE: ' . SnapString::implodeKeyVals(', ', $arrayValValToStr, '[%s = %s]')); + Log::info(Log::traceToString(debug_backtrace())); + // $result = false; + } else { + $log = 'PARAM SET KEY[' . $key . ']'; + $log .= (Log::isLevel(Log::LV_DEBUG) ? (' VALUE: ' . SnapString::implodeKeyVals(', ', $arrayValValToStr, '[%s = %s]')) : ''); + Log::info($log, $logginLevelSet); + if ($overwrite) { + $this->params[$key]->setOveriteStatus(); + } + } + } + } + return $result; + } + + /** + * update persistance file + * + * @return bool\int // This function returns the number of bytes that were written to the file, or FALSE on failure. + */ + public function save() + { + Log::info("SAVE PARAMS\n" . Log::traceToString(debug_backtrace()), Log::LV_DEBUG); + + $arrayData = array(); + foreach ($this->params as $param) { + if ($param->isPersistent()) { + $arrayData[$param->getName()] = $param->toArrayData(); + } + } + $json = SnapJson::jsonEncodePPrint($arrayData); + if (($result = file_put_contents(self::getPersistanceFilePath(), $json, LOCK_EX)) === false) { + Log::info('PRAMS: can\'t save persistence file'); + } + return $result; + } + + /** + * + * @staticvar string $path + * @return string + */ + protected static function getPersistanceFilePath() + { + static $path = null; + + if (is_null($path)) { + $path = DUPX_INIT . '/' . 'dup-params__' . \DUPX_Package::getPackageHash() . '.json'; + } + + return $path; + } + + /** + * html params info for debug params + * + * @return void + */ + public function getParamsHtmlInfo() + { + if (!$this->getValue(self::PARAM_DEBUG_PARAMS)) { + return; + } + ?> +
          +

          CURRENT VALUES

          +
            + params as $param) { ?> +
          • + PARAM getName(); ?> VALUE: getValue())); ?> +
          • + +
          +

          LOAD SEQUENCE

          +
            + paramsHtmlInfo as $info) { ?> +
          • + +
          • + +
          +

          ARCHIVE PARAM DATA

          +
          +
          + params as $param) { + if (method_exists($param, 'getFormStatus')) { + $line = 'PARAM FORM ' . $param->getName() . ' VALUE: ' . Log::v2str($param->getValue()) . ' STATUS: ' . $param->getFormStatus(); + } else { + $line = 'PARAM ITEM ' . $param->getName() . ' VALUE: ' . Log::v2str($param->getValue()); + } + + $result[] = $line; + } + + return implode("\n", $result); + } + + /** + * Prevent clone object + * + * @return void + */ + private function __clone() + { + } +} diff --git a/installer/dup-installer/src/Models/ImportUser.php b/installer/dup-installer/src/Models/ImportUser.php new file mode 100644 index 00000000..0f8e851a --- /dev/null +++ b/installer/dup-installer/src/Models/ImportUser.php @@ -0,0 +1,183 @@ +id = (int) $id; + $this->login = $login; + $this->mail = $mail; + $this->oldId = (int) $oldId; + $this->oldLogin = $oldLogin; + $this->isAdded = $isAdded; + + if ($this->id == $this->oldId) { + $this->oldId = 0; + } + if ($this->login == $this->oldLogin) { + $this->oldLogin = ''; + } + } + + /** + * Return CSV report columns title + * + * @return string[] + */ + public static function getArrayReportTitles() + { + return array( + 'e-mail', + 'original login', + 'new login', + 'original id', + 'new id' + ); + } + + /** + * Return array for CSV report + * + * @return array + */ + public function getArrayReport() + { + $result = array($this->mail); + if (strlen($this->oldLogin) == 0) { + $result[] = $this->login; + $result[] = ''; + } else { + $result[] = $this->oldLogin; + $result[] = $this->login; + } + + if ($this->oldId == 0) { + $result[] = $this->id; + $result[] = ''; + } else { + $result[] = $this->oldId; + $result[] = $this->id; + } + + return $result; + } + + /** + * Get the value of id + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the value of login + * + * @return string + */ + public function getLogin() + { + return $this->login; + } + + /** + * Get the value of mail + * + * @return string + */ + public function getMail() + { + return $this->mail; + } + + /** + * Get the value of oldId + * + * @return int + */ + public function getOldId() + { + return ($this->oldId == 0 ? $this->id : $this->oldId); + } + + /** + * Set the value of oldId + * + * @param int $oldId old mapped id + * + * @return void + */ + public function setOldId($oldId) + { + $this->oldId = (int) ($this->id == $oldId ? 0 : $oldId); + } + + /** + * Get the value of oldLogin + * + * @return string + */ + public function getOldLogin() + { + return (strlen($this->oldLogin) == 0 ? $this->login : $this->oldLogin); + } + + /** + * Set the value of oldLogin + * + * @param string $oldLogin old login + * + * @return void + */ + public function setOldLogin($oldLogin) + { + $this->oldLogin = ($this->login == $oldLogin ? '' : $oldLogin); + } + + /** + * True if current user have changed values (login or id) + * + * @return boolean + */ + public function isChanged() + { + return ($this->oldId > 0 || strlen($this->oldLogin) > 0); + } + + /** + * True if current user is added + * + * @return bool + */ + public function isAdded() + { + return $this->isAdded; + } +} diff --git a/installer/dup-installer/src/Models/ScanInfo.php b/installer/dup-installer/src/Models/ScanInfo.php new file mode 100644 index 00000000..2c262393 --- /dev/null +++ b/installer/dup-installer/src/Models/ScanInfo.php @@ -0,0 +1,75 @@ +data = json_decode($contents, true)) === null) { + throw new Exception("Can\'t decode archive json"); + } + } + + /** + * Get uncompressed size, -1 unknown + * + * @return int + */ + public function getUSize() + { + return isset($this->data['ARC']['Usize']) ? $this->data['ARC']['Usize'] : -1; + } + + /** + * Return true if package has filtered core folders + * + * @return bool + */ + public function hasFilteredCoreFolders() + { + return $this->data['ARC']['Status']['HasFilteredCoreFolders']; + } +} diff --git a/installer/dup-installer/src/Utils/Autoloader.php b/installer/dup-installer/src/Utils/Autoloader.php new file mode 100644 index 00000000..58e21e85 --- /dev/null +++ b/installer/dup-installer/src/Utils/Autoloader.php @@ -0,0 +1,126 @@ + $mappedPath) { + if (strpos($className, $namespace) !== 0) { + continue; + } + + $filepath = $mappedPath . str_replace('\\', '/', substr($className, strlen($namespace))) . '.php'; + if (file_exists($filepath)) { + include_once($filepath); + return true; + } + } + } else { + if (file_exists($filepath)) { + include_once($filepath); + return true; + } + } + + return false; + } + + /** + * + * @param string $class class name + * + * @return boolean|string + */ + protected static function getAddonFile($class) + { + $matches = null; + if (preg_match('/^\\\\?Duplicator\\\\Installer\\\\Addons\\\\(.+?)\\\\(.+)$/', $class, $matches) !== 1) { + return false; + } + + $addonName = $matches[1]; + $subClass = $matches[2]; + $basePath = DUPX_INIT . '/addons/' . strtolower($addonName) . '/'; + + if (self::endsWith($class, $addonName) === false) { + $basePath .= 'src/'; + } + + return $basePath . str_replace('\\', '/', $subClass) . '.php'; + } + + /** + * + * @staticvar [string] $mapping + * @return [string] + */ + protected static function getNamespacesMapping() + { + // the order is important, it is necessary to insert the longest namespaces first + return array( + self::ROOT_ADDON_INSTALLER_NAMESPACE => DUPX_INIT . '/addons/', + self::ROOT_INSTALLER_NAMESPACE => DUPX_INIT . '/src/', + self::ROOT_LIBS_NAMESPACE => DUPX_INIT . '/libs/' + ); + } + + /** + * Returns true if the $haystack string end with the $needle, only for internal use + * + * @param string $haystack The full string to search in + * @param string $needle The string to for + * + * @return bool Returns true if the $haystack string starts with the $needle + */ + protected static function endsWith($haystack, $needle) + { + $length = strlen($needle); + if ($length == 0) { + return true; + } + + return (substr($haystack, -$length) === $needle); + } +} diff --git a/installer/dup-installer/src/Utils/InstallerUpsell.php b/installer/dup-installer/src/Utils/InstallerUpsell.php new file mode 100644 index 00000000..10aefda5 --- /dev/null +++ b/installer/dup-installer/src/Utils/InstallerUpsell.php @@ -0,0 +1,119 @@ + $medium, + 'utm_content' => $content, + 'utm_source' => 'WordPress', + 'utm_campaign' => 'liteplugin' + ); + + return 'https://duplicator.com/lite-upgrade/?' . http_build_query($utmData); + } + + /** + * getCampainUrlHtml + * Get upgrade campaign HTML for tooltips + * + * @param string[] $utmData utm_content flag + * + * @return string + */ + public static function getCampaignTooltipHTML($utmData) + { + $url = self::getCampaignUrl($utmData); + if (function_exists('esc_url')) { + $url = esc_url($url); + } else { + $url = \DUPX_U::esc_url($url); + } + + ob_start(); + ?> + + 'WordPress', + 'utm_campaign' => 'liteplugin' + ); + + if ($medium !== '') { + $utmData['utm_medium'] = $medium; + } + + if ($content !== '') { + $utmData['utm_content'] = $content; + } + + if (is_array($paths)) { + $paths = implode('/', $paths); + } + $paths = trim($paths, '/') . '/'; + + return self::DUPLICATOR_URL . $paths . '?' . http_build_query($utmData); + } +} diff --git a/installer/dup-installer/src/Utils/Log/Log.php b/installer/dup-installer/src/Utils/Log/Log.php new file mode 100644 index 00000000..88a3b637 --- /dev/null +++ b/installer/dup-installer/src/Utils/Log/Log.php @@ -0,0 +1,483 @@ +getValue(PrmMng::PARAM_LOGGING); + } + + /** + * Used to write debug info to the text log file + * + * @param string $msg Any text data + * @param int $logging Log level + * @param bool $flush if true flush file log + * + * @return void + */ + public static function info($msg, $logging = self::LV_DEFAULT, $flush = false) + { + if ($logging > self::$logLevel) { + return; + } + + $preLog = ''; + if (self::$indentation) { + $preLog .= str_repeat("\t", self::$indentation); + } + if (self::$logLevel >= self::LV_DETAILED) { + $preLog .= sprintf('[DELTA:%10.5f] ', microtime(true) - self::$microtimeStart); + } + if (is_callable(self::$postprocessCallback)) { + $msg = call_user_func(self::$postprocessCallback, $msg); + } + + @fwrite(self::getFileHandle(), $preLog . $msg . "\n", self::MAX_LENGTH_FWRITE); + + if ($flush) { + self::flush(); + } + } + + /** + * + * @return bool

          Returns true on success or false on failure.

          + */ + public static function clearLog() + { + self::close(); + if (file_exists(self::getLogFilePath())) { + return unlink(self::getLogFilePath()); + } else { + return true; + } + } + + /** + * + * @return string + */ + protected static function getLogFileName() + { + return 'dup-installer-log__' . \DUPX_Security::getInstance()->getSecondaryPackageHash() . '.txt'; + } + + /** + * + * @return string + */ + public static function getLogFilePath() + { + return DUPX_INIT . '/' . self::getLogFileName(); + } + + /** + * + * @return string + */ + public static function getLogFileUrl() + { + return DUPX_INIT_URL . '/' . self::getLogFileName() . '?now=' . $GLOBALS['NOW_TIME']; + } + + /** + * Get trace string + * + * @param array $callers result of debug_backtrace + * @param int $fromLevel level to start + * + * @return string + */ + public static function traceToString($callers, $fromLevel = 0) + { + $result = ''; + for ($i = $fromLevel; $i < count($callers); $i++) { + $trace = $callers[$i]; + if (!empty($trace['class'])) { + $result .= str_pad('TRACE[' . $i . '] CLASS___: ' . $trace['class'] . $trace['type'] . $trace['function'], 45, ' '); + } else { + $result .= str_pad('TRACE[' . $i . '] FUNCTION: ' . $trace['function'], 45, ' '); + } + if (isset($trace['file'])) { + $result .= ' FILE: ' . $trace['file'] . '[' . $trace['line'] . ']'; + } else { + $result .= ' NO FILE'; + } + $result .= "\n"; + } + return $result; + } + + /** + * Set post process callback + * + * @param callable $callback callback function + * + * @return void + */ + public static function setPostProcessCallback($callback) + { + self::$postprocessCallback = is_callable($callback) ? $callback : null; + } + + /** + * Set after fatal error callback + * + * @param callable $callback callback function + * + * @return void + */ + public static function setAfterFatalErrorCallback($callback) + { + self::$afterFatalErrorCallback = is_callable($callback) ? $callback : null; + } + + /** + * Reset time counter + * + * @param int $logging log level + * @param boolean $fileInfo Log file info (file, line) + * + * @return void + */ + public static function resetTime($logging = self::LV_DEFAULT, $fileInfo = true) + { + self::$microtimeStart = microtime(true); + if ($logging > self::$logLevel) { + return; + } + $callers = debug_backtrace(); + $file = $callers[0]['file']; + $line = $callers[0]['line']; + Log::info('LOG-TIME' . ($fileInfo ? '[' . $file . ':' . $line . ']' : '') . ' RESET TIME', $logging); + } + + /** + * Log time delta from last resetTime call + * + * @param string $msg message + * @param int $logging log level + * @param bool $fileInfo if strue write file info (file, line) + * + * @return void + */ + public static function logTime($msg = '', $logging = self::LV_DEFAULT, $fileInfo = true) + { + if ($logging > self::$logLevel) { + return; + } + $callers = debug_backtrace(); + $file = $callers[0]['file']; + $line = $callers[0]['line']; + + if ($fileInfo) { + Log::info( + sprintf('LOG-TIME[%s:%s][DELTA:%10.5f] ', $file, $line, microtime(true) - self::$microtimeStart) . (empty($msg) ? '' : ' MESSAGE:' . $msg), + $logging + ); + } else { + Log::info(sprintf('LOG-TIME[DELTA:%10.5f] ', microtime(true) - self::$microtimeStart) . (empty($msg) ? '' : ' MESSAGE:' . $msg), $logging); + } + } + + /** + * Increment indentation + * + * @return void + */ + public static function incIndent() + { + self::$indentation++; + } + + /** + * Decrease indentation + * + * @return void + */ + public static function decIndent() + { + if (self::$indentation > 0) { + self::$indentation--; + } + } + + /** + * Reset indentation + * + * @return void + */ + public static function resetIndent() + { + self::$indentation = 0; + } + + /** + * Return true if log level is >= of loggin level + * + * @param int $logging log level + * + * @return boolean + */ + public static function isLevel($logging) + { + return $logging <= self::$logLevel; + } + + /** + * Log passed object + * + * @param string $msg log message + * @param mixed $object object to log + * @param int $logging log level + * + * @return void + */ + public static function infoObject($msg, &$object, $logging = self::LV_DEFAULT) + { + $msg = $msg . "\n" . print_r($object, true); + self::info($msg, $logging); + } + + /** + * Flush log file + * + * @return void + */ + public static function flush() + { + if (is_resource(self::$logHandle)) { + fflush(self::$logHandle); + } + } + + /** + * Close log file + * + * @return void + */ + public static function close() + { + if (is_null(self::$logHandle)) { + return true; + } + + if (is_resource(self::$logHandle)) { + fclose(self::$logHandle); + } + self::$logHandle = null; + return true; + } + + /** + * Get log file stream + * + * @return resource + */ + public static function getFileHandle() + { + if (is_resource(self::$logHandle)) { + return self::$logHandle; + } + + if (!is_writable(dirname(self::getLogFilePath()))) { + throw new \Exception('Can\'t write in dup-installer folder, please check the dup-installer permission folder'); + } + + if (file_exists(self::getLogFilePath())) { + SnapIO::chmod(self::getLogFilePath(), 'u+rw'); + } + + if ((self::$logHandle = fopen(self::getLogFilePath(), "a+")) === false) { + self::$logHandle = null; + throw new \Exception('Can\'t open the log file, please check the dup-installer permission folder'); + } + + SnapIO::chmod(self::getLogFilePath(), 'u+rw'); + + return self::$logHandle; + } + + /** + * Log error and die or thore exception if self::$thowExceptionOnError is true + * + * @param string $errorMessage error message + * + * @return void + */ + public static function error($errorMessage) + { + $breaks = array("
          ", "
          ", "
          "); + $spaces = array(" "); + $log_msg = str_ireplace($breaks, "\r\n", $errorMessage); + $log_msg = str_ireplace($spaces, " ", $log_msg); + $log_msg = strip_tags($log_msg); + + self::info("\nINSTALLER ERROR:\n{$log_msg}\n"); + + if (is_callable(self::$afterFatalErrorCallback)) { + call_user_func(self::$afterFatalErrorCallback); + } + + if (self::$thowExceptionOnError) { + throw new \Exception($errorMessage); + } else { + self::close(); + die("

          INSTALL ERROR!
          {$errorMessage}
          "); + } + } + + /** + * Get log exception string + * + * @param Exception $e exception object + * @param string $title log message + * + * @return string + */ + public static function getLogException($e, $title = 'EXCEPTION ERROR: ') + { + return $title . ' ' . $e->getMessage() . "\n" . + "\tFILE:" . $e->getFile() . '[' . $e->getLIne() . "]\n" . + "\tTRACE:\n" . $e->getTraceAsString(); + } + + /** + * Log exception + * + * @param Exception $e exception object + * @param int $logging log level + * @param string $title log message + * + * @return void + */ + public static function logException($e, $logging = self::LV_DEFAULT, $title = 'EXCEPTION ERROR: ') + { + if ($logging <= self::$logLevel) { + Log::info("\n" . self::getLogException($e, $title) . "\n"); + } + } + + /** + * If set true error function thorw exception instead die + * + * @param boolean $set enable/disable thorw exception + * + * @return void + */ + public static function setThrowExceptionOnError($set) + { + self::$thowExceptionOnError = (bool) $set; + } + + /** + * Get string from generic value + * + * @param mixed $var value + * @param bool $checkCallable if true check if var is callable and display it + * + * @return string + */ + public static function v2str($var, $checkCallable = false) + { + if ($checkCallable && is_callable($var)) { + return '(callable) ' . print_r($var, true); + } + switch (gettype($var)) { + case "boolean": + return $var ? 'true' : 'false'; + case "integer": + case "double": + return (string) $var; + case "string": + return '"' . $var . '"'; + case "array": + case "object": + return print_r($var, true); + case "resource": + case "resource (closed)": + case "NULL": + case "unknown type": + default: + return gettype($var); + } + } +} diff --git a/installer/dup-installer/src/Utils/Log/LogHandler.php b/installer/dup-installer/src/Utils/Log/LogHandler.php new file mode 100644 index 00000000..f11b128e --- /dev/null +++ b/installer/dup-installer/src/Utils/Log/LogHandler.php @@ -0,0 +1,261 @@ + 'timeout' + ); + + /** + * + * @var int + */ + private static $handlerMode = self::MODE_LOG; + + /** + * + * @var bool // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100] + */ + private static $codeReference = true; + + /** + * + * @var bool // print prefix in php error line [PHP ERR][WARN] MSG: ..... + */ + private static $errPrefix = true; + + /** + * + * @var string // php errors in MODE_VAR + */ + private static $varModeLog = ''; + + /** + * Error handler + * + * @param integer $errno Error level + * @param string $errstr Error message + * @param string $errfile Error file + * @param integer $errline Error line + * + * @return void + */ + public static function error($errno, $errstr, $errfile, $errline) + { + switch (self::$handlerMode) { + case self::MODE_OFF: + if ($errno == E_ERROR) { + $log_message = self::getMessage($errno, $errstr, $errfile, $errline); + Log::error($log_message); + } + break; + case self::MODE_VAR: + self::$varModeLog .= self::getMessage($errno, $errstr, $errfile, $errline) . "\n"; + break; + case self::MODE_LOG: + default: + switch ($errno) { + case E_ERROR: + $log_message = self::getMessage($errno, $errstr, $errfile, $errline); + Log::error($log_message); + break; + case E_NOTICE: + case E_WARNING: + default: + $log_message = self::getMessage($errno, $errstr, $errfile, $errline); + Log::info($log_message); + break; + } + } + } + + /** + * Get error message from erro data + * + * @param int $errno error code + * @param string $errstr error message + * @param string $errfile file + * @param int $errline line + * + * @return string + */ + private static function getMessage($errno, $errstr, $errfile, $errline) + { + $result = ''; + + if (self::$errPrefix) { + $result = '[PHP ERR]' . '[' . self::errnoToString($errno) . '] MSG:'; + } + + $result .= $errstr; + + if (self::$codeReference) { + $result .= ' [CODE:' . $errno . '|FILE:' . $errfile . '|LINE:' . $errline . ']'; + if (Log::isLevel(Log::LV_DEBUG)) { + Log::info(Log::traceToString(debug_backtrace(), 1)); + } + } + + return $result; + } + + /** + * Errno code to string + * + * @param int $errno error code + * + * @return string + */ + public static function errnoToString($errno) + { + switch ($errno) { + case E_PARSE: + return 'E_PARSE'; + case E_ERROR: + return 'E_ERROR'; + case E_CORE_ERROR: + return 'E_CORE_ERROR'; + case E_COMPILE_ERROR: + return 'E_COMPILE_ERROR'; + case E_USER_ERROR: + return 'E_USER_ERROR'; + case E_WARNING: + return 'E_WARNING'; + case E_USER_WARNING: + return 'E_USER_WARNING'; + case E_COMPILE_WARNING: + return 'E_COMPILE_WARNING'; + case E_NOTICE: + return 'E_NOTICE'; + case E_USER_NOTICE: + return 'E_USER_NOTICE'; + case self::ERRNO_EXCEPTION: + return 'EXCEPTION'; + default: + break; + } + if (defined('E_STRICT') && $errno === E_STRICT) { + return 'E_STRICT'; + } + if (defined('E_RECOVERABLE_ERROR') && $errno === E_RECOVERABLE_ERROR) { + return 'E_RECOVERABLE_ERROR'; + } + if (defined('E_DEPRECATED') && $errno === E_DEPRECATED) { + return 'E_DEPRECATED'; + } + if (defined('E_USER_DEPRECATED') && $errno === E_USER_DEPRECATED) { + return 'E_USER_DEPRECATED'; + } + return 'E_UNKNOWN CODE: ' . $errno; + } + + /** + * if setMode is called without params set as default + * + * @param int $mode log mode + * @param bool $errPrefix print prefix in php error line [PHP ERR][WARN] MSG: ..... + * @param bool $codeReference print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100] + * + * @return void + */ + public static function setMode($mode = self::MODE_LOG, $errPrefix = true, $codeReference = true) + { + switch ($mode) { + case self::MODE_OFF: + case self::MODE_VAR: + self::$handlerMode = $mode; + break; + case self::MODE_LOG: + default: + self::$handlerMode = self::MODE_LOG; + } + + self::$varModeLog = ''; + self::$errPrefix = $errPrefix; + self::$codeReference = $codeReference; + } + + /** + * + * @return string // return var log string in MODE_VAR + */ + public static function getVarLog() + { + return self::$varModeLog; + } + + /** + * + * @return string // return var log string in MODE_VAR and clean var + */ + public static function getVarLogClean() + { + $result = self::$varModeLog; + self::$varModeLog = ''; + return $result; + } + + /** + * Set shutdown print string + * + * @param string $status status type + * @param string $str string to print if is shouddown status + * + * @return void + */ + public static function setShutdownReturn($status, $str) + { + self::$shutdownReturns[$status] = $str; + } + + /** + * Shutdown handler + * + * @return void + */ + public static function shutdown() + { + if (($error = error_get_last())) { + if (preg_match('/^Maximum execution time (?:.+) exceeded$/i', $error['message'])) { + echo self::$shutdownReturns[self::SHUTDOWN_TIMEOUT]; + } + self::error($error['type'], $error['message'], $error['file'], $error['line']); + } + } +} diff --git a/installer/dup-installer/src/Utils/Tests/MessageCustomizer.php b/installer/dup-installer/src/Utils/Tests/MessageCustomizer.php new file mode 100644 index 00000000..f1d8739a --- /dev/null +++ b/installer/dup-installer/src/Utils/Tests/MessageCustomizer.php @@ -0,0 +1,201 @@ +conditionSatisfied($longMessage)) { + $shortMessage = $item->apply($shortMessage, self::CONTEXT_SHORT_MESSAGE); + $longMessage = $item->apply($longMessage, self::CONTEXT_LONG_MESSAGE); + $noticeId = $item->apply($noticeId, self::CONTEXT_NOTICE_ID); + return true; + } + } + + return false; + } + + /** + * Get customization to apply at error messages + * + * @return MessageCustomizerItem[] customizations list + * @throws \Exception + */ + protected static function getCustomizationItems() + { + $items = array(); + $items[] = new MessageCustomizerItem( + function ($string) { + if (MessageCustomizer::getArchiveConfigData() == false) { + return false; + } + return preg_match("/undefined.*create_function/", $string) && + version_compare(phpversion(), "8") >= 0 && + version_compare(MessageCustomizer::getArchiveConfigData()->version_php, "8") < 0; + }, + function ($string, $context) { + if (MessageCustomizer::getArchiveConfigData() == false) { + return $string; + } + $phpVersionNew = MessageCustomizer::getTwoLevelVersion(phpversion()); + $phpVersionOld = MessageCustomizer::getTwoLevelVersion(MessageCustomizer::getArchiveConfigData()->version_php); + $longMsgPrefix = "There is code in this site that is not compatible with PHP " . $phpVersionNew . ". " . + "To make the install work you will either have to\ninstall on PHP " . + $phpVersionOld . " or "; + + switch ($context) { + case MessageCustomizer::CONTEXT_SHORT_MESSAGE: + return "Source site or plugins are incompatible with PHP " . $phpVersionNew; + case MessageCustomizer::CONTEXT_LONG_MESSAGE: + if (($plugin = MessageCustomizer::getProblematicPluginFromError($string)) !== false) { + return $longMsgPrefix . "disable the plugin '{$plugin->name}' (slug: $plugin->slug) using a " . + "file manager of your choice.\nSee full error message below: \n\n" . $string; + } elseif (($theme = MessageCustomizer::getProblematicThemeFromError($string)) !== false) { + return $longMsgPrefix . "disable the theme '{$theme->themeName}' (slug: $theme->slug) using a " . + "file manager of your choice.\nSee full error message below: \n\n" . $string; + } else { + return $longMsgPrefix . "manually modify the affected files mentioned in the error trace below: \n\n" . + $string; + } + case MessageCustomizer::CONTEXT_NOTICE_ID: + return $string . '_php8'; + } + } + ); + + return $items; + } + + /** + * Return the plugin that is causing the error message if present + * + * @param string $longMessage the long error message containing the error trace + * + * @return false|object object containing plugin info or false on failure + */ + protected static function getProblematicPluginFromError($longMessage) + { + if (($archiveConfig = self::getArchiveConfigData()) === false) { + return false; + } + $oldMain = $archiveConfig->wpInfo->targetRoot; + $oldMuPlugins = $archiveConfig->wpInfo->configs->realValues->originalPaths->muplugins; + $oldPlugins = $archiveConfig->wpInfo->configs->realValues->originalPaths->plugins; + $relativeMuPlugins = str_replace($oldMain, "", $oldMuPlugins); + $relativePlugins = str_replace($oldMain, "", $oldPlugins); + $regex = "/(?:" . preg_quote($relativePlugins, "/") . "\/|" . preg_quote($relativeMuPlugins, "/") . "\/)(.*?)(\/|\.php).*$/m"; + if (!preg_match($regex, $longMessage, $matches)) { + return false; + } + + //matches the first part of the slug related to the plugin directory + $slug = $matches[1]; + foreach ($archiveConfig->wpInfo->plugins as $plugin) { + if (strpos($plugin->slug, $slug) === 0) { + return $plugin; + } + } + + return false; + } + + /** + * Returns the theme that is causing the error message if present + * + * @param string $longMessage the long error message containing the error trace + * + * @return false|object object containing theme info or false + */ + protected static function getProblematicThemeFromError($longMessage) + { + $archiveConfig = self::getArchiveConfigData(); + $oldMain = $archiveConfig->wpInfo->targetRoot; + $oldThemes = $archiveConfig->wpInfo->configs->realValues->originalPaths->themes; + $relativeThemes = str_replace($oldMain, "", $oldThemes); + + file_put_contents( + DUPX_INIT . "/my_log.txt", + "OLD THEMES: {$oldThemes} \n" . + "Relative themes: {$relativeThemes} \n" . + "regex: " . "/(" . preg_quote($relativeThemes, "/") . "\/)(.*?)(\/|\.php).*$/m" + ); + + if (!preg_match("/(?:" . preg_quote($relativeThemes, "/") . "\/)(.*?)(?:\/|\.php).*$/m", $longMessage, $matches)) { + return false; + } + + $slug = $matches[1]; + foreach ($archiveConfig->wpInfo->themes as $theme) { + if ($theme->slug == $slug) { + return $theme; + } + } + + return false; + } + + /** + * Get package config data + * + * @return false|object package config data or false on failure + */ + protected static function getArchiveConfigData() + { + static $archiveConfig = null; + if (is_null($archiveConfig)) { + if ( + ($path = glob(DUPX_INIT . "/dup-archive__*.txt")) === false || + count($path) !== 1 + ) { + return $archiveConfig = false; + } + + if (($json = file_get_contents($path[0])) === false) { + return $archiveConfig = false; + } + + $archiveConfig = json_decode($json); + if (!is_object($archiveConfig)) { + $archiveConfig = false; + } + } + return $archiveConfig; + } + + /** + * @param string $version a version number + * + * @return string returns only the first 2 levels of the version numbers + */ + private static function getTwoLevelVersion($version) + { + $arr = explode(".", $version); + return $arr[0] . "." . $arr[1]; + } +} diff --git a/installer/dup-installer/src/Utils/Tests/MessageCustomizerItem.php b/installer/dup-installer/src/Utils/Tests/MessageCustomizerItem.php new file mode 100644 index 00000000..9640aada --- /dev/null +++ b/installer/dup-installer/src/Utils/Tests/MessageCustomizerItem.php @@ -0,0 +1,47 @@ +checkCallback = $checkCallback; + + if (!is_callable($applyCallback)) { + throw new \Exception("customization callback must be callable"); + } + $this->applyCallback = $applyCallback; + } + + /** + * @param mixed $input necessary input to check condition + * + * @return bool + */ + public function conditionSatisfied($input) + { + return (is_bool($this->checkCallback) && $this->checkCallback) || call_user_func($this->checkCallback, $input); + } + + /** + * @param string $string string to be customized + * @param mixed $context context about what to apply + * + * @return false|mixed + */ + public function apply($string, $context) + { + return call_user_func($this->applyCallback, $string, $context); + } +} diff --git a/installer/dup-installer/src/Utils/Tests/TestInterface.php b/installer/dup-installer/src/Utils/Tests/TestInterface.php new file mode 100644 index 00000000..61e91eee --- /dev/null +++ b/installer/dup-installer/src/Utils/Tests/TestInterface.php @@ -0,0 +1,16 @@ + self::getErrorCategoryFromErrno($errno), + 'errno' => $errno, + 'errno_str' => self::errnoToString($errno), + 'errstr' => $errstr, + 'errfile' => $errfile, + 'errline' => $errline, + 'trace' => array_map(array(__CLASS__, 'normalizeTraceElement'), $trace) + ); + + self::$errors[] = $newError; + + if (function_exists('error_clear_last')) { + error_clear_last(); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.error_clear_lastFound + } + } + + /** + * @param array $error the error array + * + * @return string human-readable error message with trace + */ + public static function errorToString($error) + { + $result = $error['errno_str'] . ' ' . $error['errstr'] . "\n"; + $result .= "\t" . 'FILE: ' . $error['errfile'] . '[' . $error['errline'] . ']' . "\n"; + $result .= "\t--- TRACE ---\n"; + foreach ($error['trace'] as $trace) { + $result .= "\t"; + if (!empty($trace['class'])) { + $result .= str_pad('CLASS___: ' . $trace['class'] . $trace['type'] . $trace['function'], 40, ' '); + } else { + $result .= str_pad('FUNCTION: ' . $trace['function'], 40, ' '); + } + $result .= 'FILE: ' . $trace['file'] . '[' . $trace['line'] . ']' . "\n"; + } + + return $result; + } + + /** + * Error handler + * + * @param integer $errno Error level + * @param string $errstr Error message + * @param string $errfile Error file + * @param integer $errline Error line + * + * @return void + */ + public static function error($errno, $errstr, $errfile, $errline) + { + $trace = debug_backtrace(); + array_shift($trace); + self::adderror($errno, $errstr, $errfile, $errline, $trace); + } + + /** + * Exception handler + * + * @param Exception|Error $e // Throwable in php 7 + * + * @return void + */ + public static function exception($e) + { + self::adderror(self::ERRNO_EXCEPTION, $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace()); + } + + /** + * Shutdown handler + * + * @return void + */ + public static function shutdown() + { + self::obCleanAll(); + + if (($error = error_get_last())) { + self::error($error['type'], $error['message'], $error['file'], $error['line']); + } + ob_end_clean(); + + if (is_callable(self::$shutdownCallback)) { + call_user_func(self::$shutdownCallback, self::$errors); + } else { + echo json_encode(self::$errors); + } + + // prevent other shutdown functions + exit(); + } + + /** + * Close all buffers and return content + * + * @param bool $getContent If true it returns buffer content, otherwise it is discarded + * + * @return string + */ + protected static function obCleanAll($getContent = true) + { + $result = ''; + for ($i = 0; $i < ob_get_level(); $i++) { + if ($getContent) { + $result .= ob_get_contents(); + } + ob_clean(); + } + return $result; + } + + /** + * @param array $elem normalize error element + * + * @return array + */ + public static function normalizeTraceElement($elem) + { + if (!is_array($elem)) { + $elem = array(); + } + + unset($elem['args']); + unset($elem['object']); + + return array_merge(array( + 'file' => '', + 'line' => -1, + 'function' => '', + 'class' => '', + 'type' => ''), $elem); + } + + /** + * + * @param int $errno error number + * + * @return string + */ + public static function getErrorCategoryFromErrno($errno) + { + switch ($errno) { + case E_PARSE: + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + case self::ERRNO_EXCEPTION: + return self::ERR_TYPE_ERROR; + case E_WARNING: + case E_USER_WARNING: + case E_COMPILE_WARNING: + return self::ERR_TYPE_WARNING; + case E_NOTICE: + case E_USER_NOTICE: + return self::ERR_TYPE_NOTICE; + default: + break; + } + if (defined('E_STRICT') && $errno === E_STRICT) { + return self::ERR_TYPE_WARNING; + } + if (defined('E_RECOVERABLE_ERROR') && $errno === E_RECOVERABLE_ERROR) { + return self::ERR_TYPE_WARNING; + } + if (defined('E_DEPRECATED') && $errno === E_DEPRECATED) { + return self::ERR_TYPE_DEPRECATED; + } + if (defined('E_USER_DEPRECATED') && $errno === E_USER_DEPRECATED) { + return self::ERR_TYPE_DEPRECATED; + } + return self::ERR_TYPE_WARNING; + } + + /** + * + * @param int $errno error number + * + * @return string + */ + public static function errnoToString($errno) + { + switch ($errno) { + case E_PARSE: + return 'E_PARSE'; + case E_ERROR: + return 'E_ERROR'; + case E_CORE_ERROR: + return 'E_CORE_ERROR'; + case E_COMPILE_ERROR: + return 'E_COMPILE_ERROR'; + case E_USER_ERROR: + return 'E_USER_ERROR'; + case E_WARNING: + return 'E_WARNING'; + case E_USER_WARNING: + return 'E_USER_WARNING'; + case E_COMPILE_WARNING: + return 'E_COMPILE_WARNING'; + case E_NOTICE: + return 'E_NOTICE'; + case E_USER_NOTICE: + return 'E_USER_NOTICE'; + case self::ERRNO_EXCEPTION: + return 'EXCEPTION'; + default: + break; + } + if (defined('E_STRICT') && $errno === E_STRICT) { + return 'E_STRICT'; + } + if (defined('E_RECOVERABLE_ERROR') && $errno === E_RECOVERABLE_ERROR) { + return 'E_RECOVERABLE_ERROR'; + } + if (defined('E_DEPRECATED') && $errno === E_DEPRECATED) { + return 'E_DEPRECATED'; + } + if (defined('E_USER_DEPRECATED') && $errno === E_USER_DEPRECATED) { + return 'E_USER_DEPRECATED'; + } + return 'E_UNKNOWN CODE: ' . $errno; + } +} diff --git a/installer/dup-installer/src/Utils/Tests/WP/TestsExecuter.php b/installer/dup-installer/src/Utils/Tests/WP/TestsExecuter.php new file mode 100644 index 00000000..8d8c610c --- /dev/null +++ b/installer/dup-installer/src/Utils/Tests/WP/TestsExecuter.php @@ -0,0 +1,149 @@ +addFinalReportNotice(array( + 'shortMsg' => 'Can\'t create final text script file', + 'longMsg' => 'Can\'t create file ' . $scriptFilePath, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT, + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'sections' => array('general'), + )); + + return false; + } + + return true; + } + + /** + * @return bool true on success + * @throws \Exception + */ + public static function afterTestClean() + { + $nManager = DUPX_NOTICE_MANAGER::getInstance(); + $scriptFilePath = self::getScriptTestPath(); + Log::info('DELETE FILE AFTER TEST: ' . $scriptFilePath, Log::LV_DETAILED); + if (file_exists($scriptFilePath)) { + if (unlink($scriptFilePath) == false) { + $nManager->addFinalReportNotice(array( + 'shortMsg' => 'Can\'t deleta final text script file', + 'longMsg' => 'Can\'t delete file ' . $scriptFilePath . '. Remove it manually', + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT, + 'level' => DUPX_NOTICE_ITEM::HARD_WARNING, + 'sections' => array('general'), + )); + } + } + + return true; + } + + /** + * @return string url of WP front-end + * @throws \Exception + */ + public static function getFrontendUrl() + { + $indexPath = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_NEW) . '/index.php'; + $data = array( + self::SCRIPT_NAME_HTTP_PARAM => $indexPath + ); + + return self::getScriptTestUrl() . '?' . http_build_query($data); + } + + /** + * @return string url of WP back-end + * @throws \Exception + */ + public static function getBackendUrl() + { + $indexPath = PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW) . '/wp-login.php'; + $data = array( + self::SCRIPT_NAME_HTTP_PARAM => $indexPath + ); + + return self::getScriptTestUrl() . '?' . http_build_query($data); + } + + /** + * @return string test script name + */ + protected static function getScriptTestName() + { + return 'wp_test_script_' . DUPX_Security::getInstance()->getSecondaryPackageHash() . '.php'; + } + + /** + * @return string test script path + * @throws \Exception + */ + public static function getScriptTestPath() + { + // use wp-content path and not root path + return PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_CONTENT_NEW) . '/' . self::getScriptTestName(); + } + + /** + * @return string test script url + * @throws \Exception + */ + public static function getScriptTestUrl() + { + // use wp-content path and not root path + return PrmMng::getInstance()->getValue(PrmMng::PARAM_URL_CONTENT_NEW) . '/' . self::getScriptTestName(); + } + + /** + * @return string contents to be added to the test script file + */ + public static function getExecFileContent() + { + $result = file_get_contents(dirname(__FILE__) . '/tests_template.php'); + $result = preg_replace('/^.*\[REMOVE LINE BY SCRIPT].*\n/m', '', $result); // remove first line with die + return str_replace( + array( + '$_$_NOTICES_FILE_PATH_$_$', + '$_$_DUPX_INIT_$_$' + ), + array( + $GLOBALS["NOTICES_FILE_PATH"], + DUPX_INIT + ), + $result + ); + } +} diff --git a/installer/dup-installer/src/Utils/Tests/WP/tests_template.php b/installer/dup-installer/src/Utils/Tests/WP/tests_template.php new file mode 100644 index 00000000..da5246a3 --- /dev/null +++ b/installer/dup-installer/src/Utils/Tests/WP/tests_template.php @@ -0,0 +1,121 @@ + $shortMessage, + 'level' => $errorLevel, + 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE, + 'longMsg' => $longMessage, + 'sections' => 'general' + ); + if ($errorLevel == DUPX_NOTICE_ITEM::FATAL) { + $nManager->addBothNextAndFinalReportNotice($data, DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $noticeId); + } else { + $nManager->addFinalReportNotice($data, DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $noticeId); + } + } + + if ($nManager->saveNotices()) { + echo json_encode(true); + } else { + echo json_encode(false); + } +}); + +$_SERVER['REQUEST_URI'] = '/'; +if (file_exists($GLOBALS["TEST_SCRIPT"])) { + require_once($GLOBALS["TEST_SCRIPT"]); +} else { + throw new Exception('test script file ' . $GLOBALS["TEST_SCRIPT"] . ' doesn\'t exist'); +} diff --git a/installer/dup-installer/templates/.htaccess b/installer/dup-installer/templates/.htaccess new file mode 100644 index 00000000..a58990b7 --- /dev/null +++ b/installer/dup-installer/templates/.htaccess @@ -0,0 +1,9 @@ + + Order Deny,Allow + Deny from all + + + + Order Allow,Deny + Allow from all + \ No newline at end of file diff --git a/installer/dup-installer/templates/base/pages-parts/step1/actions/switch-template.php b/installer/dup-installer/templates/base/pages-parts/step1/actions/switch-template.php new file mode 100644 index 00000000..1b6c8dae --- /dev/null +++ b/installer/dup-installer/templates/base/pages-parts/step1/actions/switch-template.php @@ -0,0 +1,25 @@ + +
          + + + + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/base/pages-parts/step1/continue-block.php b/installer/dup-installer/templates/base/pages-parts/step1/continue-block.php new file mode 100644 index 00000000..3f178ed0 --- /dev/null +++ b/installer/dup-installer/templates/base/pages-parts/step1/continue-block.php @@ -0,0 +1,31 @@ + +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/base/pages-parts/step1/options.php b/installer/dup-installer/templates/base/pages-parts/step1/options.php new file mode 100644 index 00000000..63817679 --- /dev/null +++ b/installer/dup-installer/templates/base/pages-parts/step1/options.php @@ -0,0 +1,8 @@ + 'Step 1 of 2: Deployment ' . + '
          This step will extract the archive file, install & update the database.
          ', + 'showInstallerMode' => true, + 'showSwitchView' => true, + 'showInstallerLog' => false +)); diff --git a/installer/dup-installer/templates/base/pages-parts/step4/step-title.php b/installer/dup-installer/templates/base/pages-parts/step4/step-title.php new file mode 100644 index 00000000..90bd42f2 --- /dev/null +++ b/installer/dup-installer/templates/base/pages-parts/step4/step-title.php @@ -0,0 +1,12 @@ + 'Step 2 of 2: Test Site' +)); diff --git a/installer/dup-installer/templates/base/scripts/step1-deploy.php b/installer/dup-installer/templates/base/scripts/step1-deploy.php new file mode 100644 index 00000000..36c030bb --- /dev/null +++ b/installer/dup-installer/templates/base/scripts/step1-deploy.php @@ -0,0 +1,22 @@ + 'ctrl-step4', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('ctrl-step4') +); +?> + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/page-boot-error.php b/installer/dup-installer/templates/default/page-boot-error.php new file mode 100644 index 00000000..b5fb6568 --- /dev/null +++ b/installer/dup-installer/templates/default/page-boot-error.php @@ -0,0 +1,23 @@ + + + + + +
          +

          DUPLICATOR: ISSUE

          + Problem on duplicator init.
          + Message: +
          +
          + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/page-exception.php b/installer/dup-installer/templates/default/page-exception.php new file mode 100644 index 00000000..92b611cf --- /dev/null +++ b/installer/dup-installer/templates/default/page-exception.php @@ -0,0 +1,32 @@ + 'exception', + 'bodyId' => 'page-exception', + 'bodyClasses' => $bodyClasses +)); +?> +
          + 'Exception error' + )); + ?> +
          + $exception + )); + ?> +
          +
          + + 'help', + 'bodyId' => 'page-help', + 'bodyClasses' => $bodyClasses +)); +?> +
          +
          + +
          +
          + 'secure', + 'bodyId' => 'page-secure', + 'bodyClasses' => $bodyClasses, + 'skipTopMessages' => true +)); +?> +
          + 'Installer Security' + )); + ?> +
          + +
          +
          + + + + + +
          +

          DUPLICATOR: SECURITY CHECK

          + An invalid request was made.
          + Message:
          +
          + In order to protect this request from unauthorized access please restart this install process.
          + Reopen your browser and browse to the http(s)://yoursite.com/[hash]_installer.php file again. +
          + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/page-step1.php b/installer/dup-installer/templates/default/page-step1.php new file mode 100644 index 00000000..85d0346c --- /dev/null +++ b/installer/dup-installer/templates/default/page-step1.php @@ -0,0 +1,30 @@ + 'step1', + 'bodyId' => 'page-step1', + 'bodyClasses' => $bodyClasses +)); +?> +
          + +
          + +
          + DUPX_Validation_manager::validateOnLoad() + )); + ?> +
          + 'step2', + 'bodyId' => 'page-step2', + 'bodyClasses' => $bodyClasses +)); +?> +
          + +
          + +
          + +
          + 'step3', + 'bodyId' => 'page-step3', + 'bodyClasses' => $bodyClasses +)); +?> +
          + +
          + +
          + +
          + 'step4', + 'bodyId' => 'page-step4', + 'bodyClasses' => $bodyClasses +)); +?> +
          + +
          + +
          + +
          + + diff --git a/installer/dup-installer/templates/default/pages-parts/boot-error/header.php b/installer/dup-installer/templates/default/pages-parts/boot-error/header.php new file mode 100644 index 00000000..6cec1a37 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/boot-error/header.php @@ -0,0 +1,23 @@ + + + + + Duplicator - issue + + + + + + + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/exception/main.php b/installer/dup-installer/templates/default/pages-parts/exception/main.php new file mode 100644 index 00000000..8a3821dc --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/exception/main.php @@ -0,0 +1,57 @@ +getValue(PrmMng::PARAM_RECOVERY_LINK); +if (SnapString::isHTML($exception->getMessage())) { + $message = $exception->getMessage(); +} else { + $message = '' . DUPX_U::esc_html($exception->getMessage()) . ''; +} +?> +
          + INSTALL ERROR! +

          + Message:
          + Please see the file for more details. + haveFaqLink()) { + ?> +
          + See FAQ: getFaqLinkLabel(); ?> + getLongMsg())) { + echo '

          ' . $longMsg; + } + } + ?> +

          +
          + Trace: +
          getTraceAsString();
          +    ?>
          +
          + + +

          + + Restore Recovery Point + +

          + + +
          + + See online help for more details at duplicator.com +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/head/css-scripts.php b/installer/dup-installer/templates/default/pages-parts/head/css-scripts.php new file mode 100644 index 00000000..b95f23cd --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/head/css-scripts.php @@ -0,0 +1,47 @@ +version_dup; + +$cssList = array( + 'assets/normalize.css', + 'assets/font-awesome/css/all.min.css', + 'assets/fonts/dots/dots-font.css', + 'assets/js/password-strength/password.css', + 'assets/js/tippy/dup-pro-tippy.css', + 'vendor/select2/css/select2.css' +); + +$jsList = array( + 'assets/inc.libs.js', + 'assets/js/popper/popper.min.js', + 'assets/js/tippy/tippy-bundle.umd.min.js', + 'assets/js/duplicator-tooltip.js', + 'vendor/select2/js/select2.js' +); + +/* CSS */ +foreach ($cssList as $css) { + ?> + + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/head/css-template-custom.php b/installer/dup-installer/templates/default/pages-parts/head/css-template-custom.php new file mode 100644 index 00000000..63817679 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/head/css-template-custom.php @@ -0,0 +1,8 @@ + +
          +
          + +
          +
          + +
          + getHtmlModeHeader(); ?> +
          + +
          + +
          + +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/head/meta.php b/installer/dup-installer/templates/default/pages-parts/head/meta.php new file mode 100644 index 00000000..bb28e8ce --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/head/meta.php @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/head/server-details.php b/installer/dup-installer/templates/default/pages-parts/head/server-details.php new file mode 100644 index 00000000..6dc167c8 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/head/server-details.php @@ -0,0 +1,50 @@ + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/help/addtional-help.php b/installer/dup-installer/templates/default/pages-parts/help/addtional-help.php new file mode 100644 index 00000000..053188d8 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/addtional-help.php @@ -0,0 +1,13 @@ + +
          + For additional help please visit + + Duplicator Migration and Backup Online Help + +
          diff --git a/installer/dup-installer/templates/default/pages-parts/help/main.php b/installer/dup-installer/templates/default/pages-parts/help/main.php new file mode 100644 index 00000000..140eda3e --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/main.php @@ -0,0 +1,57 @@ + + +
          +

          + For complete help visit
          + Duplicator Migration and Backup Online Help
          + The Pro tag indicates the feature is only available in Duplicator Pro +
          + + $open_section, + ); + dupxTplRender('pages-parts/help/steps/security', $step_pass_data); + dupxTplRender('pages-parts/help/steps/step-1', $step_pass_data); + dupxTplRender('pages-parts/help/steps/step-2', $step_pass_data); + dupxTplRender('pages-parts/help/steps/step-3', $step_pass_data); + dupxTplRender('pages-parts/help/steps/step-4', $step_pass_data); + dupxTplRender('pages-parts/help/addtional-help'); + ?> +
          + + + diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/security.php b/installer/dup-installer/templates/default/pages-parts/help/steps/security.php new file mode 100644 index 00000000..d80c07ad --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/security.php @@ -0,0 +1,132 @@ + + + + + diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step-1.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step-1.php new file mode 100644 index 00000000..dbc59d51 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step-1.php @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step-2.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step-2.php new file mode 100644 index 00000000..eea7df5d --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step-2.php @@ -0,0 +1,87 @@ + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step-3.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step-3.php new file mode 100644 index 00000000..f69653db --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step-3.php @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step-4.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step-4.php new file mode 100644 index 00000000..0eec491c --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step-4.php @@ -0,0 +1,42 @@ + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/advanced-step1-options.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/advanced-step1-options.php new file mode 100644 index 00000000..6da1b97b --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/advanced-step1-options.php @@ -0,0 +1,432 @@ + +

          + Options + Advanced mode +

          +The advanced options are only shown when the installer mode is set to "Advanced." This section allows users to change or set advanced options, +configure additional database settings and set other configuration options in the wp-config.php file. +

          + + +

          + + Advanced Tab +

          +These are the advanced options for advanced users. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          OptionDetails
          + Processing +
          Extraction
          Mode
          + Manual Archive Extraction
          + Set the Extraction value to "Manual Archive Extraction" when the archive file has already been manually extracted on the server. This can be + done through your host's control panel such as cPanel or by your host directly. This setting can be helpful if you have a large archive file + or are having issues with the installer extracting the file due to timeout issues. +

          + + PHP ZipArchive
          + This extraction method will use the PHP ZipArchive code to extract the + archive zip file. +

          + + PHP ZipArchive Chunking
          + This extraction method will use the PHP ZipArchive code with multiple + execution threads to extract the archive zip file. +

          + + Shell-Exec Unzip
          + This extraction method will use the PHP shell_exec + to call the system unzip command on the server. This is the default mode that is used if it's available on the server. +

          + + DupArchive
          + This extraction method will use the DupArchive extractor code to extract the daf-based archive file. +
          Server
          Throttling
          + If the current host is a budget host that monitors CPU usage, then users might want to consider checking this box to help slow down the + process and not kick off any high-usage monitors. +
          +
          + Extraction Flow +
          Archive Action + Extract files over current files
          + The existing site files will be overwritten with the contents of the archive.zip/daf. +

          + + Pro + Remove WordPress core and content and extract
          + The existing WordPress core files and WordPress content directory will be removed, and then the archive will be extracted. +

          + + Pro + Remove all files except add-on sites and extract
          + All files except an add-on site will be removed, and then the archive will be extracted. An add-on site is a site/domain that is stored in a + directory off of your main site that has been "added on" to your main hosting account. For instance, when you purchased a hosting account it + could be for a.com. Then after that, you decided to add b.com and c.com to the same hosting account. The structure of this setup is often the + following although it can vary some: + +
            +
          • /public_html - contains files for a.com
          • +
          • /public_html/b.com - contains files for b.com
          • +
          • /public_html/c.com - contains files for c.com
          • +
          + + The directories /public_html/b.com and c.com contain the files for the add-on sites b.com and c.com (so the option above means that b.com and c.com + would be preserved and not deleted when you installed to a.com) +
          Skip Files + Extract all files
          + Extract all files from the package archive. This option is selected by default. +

          + + Pro + Skip extraction of WordPress core files
          + Extract all files except WordPress core files. Choose this option to extract only the wp-content folder and other non-core WordPress + files and directories. +

          + + Pro + Skip extraction of WordPress core files and plugins/themes existing on host
          + Extract all files except WordPress core files and existing plugins/themes on the current host. +

          + + Pro + Extract only media files and new plugins and themes
          + Extract all media files, new plugins, and new themes. The installer will not extract plugins and themes that already exist on the destination site. +
          File Times + When the archive is extracted it should show the current date-time or keep the original time it had when it was built. + This setting will be applied to all files and directories. + Note: Setting the Original time is currently only supported when using the ZipArchive Format. +
          File
          Permissions
          + Switch on and set permissions in either octal or symbolic values to assign permissions to files. This option is not available on Windows machines. +
          Directory
          Permissions
          + Switch on and set permissions in either octal or symbolic values to assign permissions to directories. This option is not available on + Windows machines. +
          + Configuration Files +
          + WordPress
          + wp-config +
          + Do nothing
          + This option simply does nothing. The wp-config file does not get backed up, renamed, or created. This advanced option assumes you already + know how it should behave in the new environment. This option is for advanced technical persons. +

          + + Modify original
          + This is the default recommended option which will modify the original wp-config file. +

          + + Create new from wp-config sample
          + This option creates a new wp-config file by modifying the wp-config-sample.php file. + The new wp-config.php file will behave as if it was created in a fresh, default WordPress installation. +

          +
          + Apache
          + .htaccess +
          + Do nothing
          + This option simply does nothing. The .htaccess is not backed up, renamed, or created. This advanced option assumes you already have your + .htaccess file set up and know how it should behave in the new environment. When the package is built it will always create an .htaccess file + at this location: + + /dup-installer/original_files_[HASH]/.htaccess + + Since the file is already in the archive file it will show up when the archive is extracted. +

          + + Retain original from Archive.zip/daf
          + This option simply copies the /dup-installer/original_files_[HASH]/.htaccess file to the .htaccess file. Please note this option will cause issues + with the install process if the .htaccess is not properly set up to handle the new server environment. This is an advanced option and should + only be used if you know how to properly configure your .htaccess configuration. +

          + + Create New
          + This is the default recommended option which will create a new .htaccess file. The new .htaccess file is streamlined to help + guarantee no conflicts are created during install. +

          + + + Notes: Inside the archive.zip or archive.daf will be a copy of the original .htaccess (Apache) file that was set up with your + packaged site. The .htaccess file is copied to /dup-installer/original_files_[HASH]/source_site_htaccess. When using either "Create New" + or "Retain original from Archive.zip/daf" an existing .htaccess file will be backed up to a + /wp-content/backups-dup-lite/installer/original_files_[HASH]/source_site_htaccess. + This change will not made until the final step is completed, to avoid any issues the .htaccess might cause during the install + +
          + General
          + php.ini, .user.ini,
          web.config
          +
          + OVERVIEW
          + When the archive is built it will always create an original backup of the php.ini, .user.ini, and web.config files ("Config Files") if they exist. + The backups will be in the following location within the archive file without an extension. + + Original File Backups
          + archive.zip|daf/dup-installer/original_files_[HASH]/[location]_phpini
          + archive.zip|daf/dup-installer/original_files_[HASH]/[location]_userini
          + archive.zip|daf/dup-installer/original_files_[HASH]/[location]_webconfig +
          + If there are "Config Files" on the new server, backups may also optionally be created. Backup [location] is defined by the following: +
            +
          • source_site Backup of original file when the archive was created on the source host
          • +
          • installer_host Backup of original file before the installer starts on active host
          • +

          + + + ACTIONS
          + Do nothing
          + This option performs no actions and assumes you already have your configuration files set up properly; either on the server or in the archive. + If the same "Config Files" exist in both the deploy directory and the archive, then the archive files will overwrite any configuration files + that exist at the same location in the archive. +


          + + Retain original from Archive.zip/daf +
            +
          1. + Moves any existing "Config Files" on the new host to the following location: + + /dup-installer/original_files_[HASH]/installer_host_[CONFIG-TYPE]
            + An existing "Config File" resides on the server before the archive is extracted or step 1 is ran. +
            +
          2. +
          3. + The installer last step copies all "Config Files" from the archive backups to the correct location on the new host. + They are copied from this location:
            + + /dup-installer/original_files_[HASH]/source_site_[CONFIG-TYPE] + +
          4. +

          + + Reset +
            +
          1. + Moves any existing "Config Files" on the new host to the following location: + + /dup-installer/original_files_[HASH]/installer_host_[CONFIG-TYPE]
            + An existing "Config File" resides on the server before the archive is extracted or step 1 is ran. +
            +
          2. +
          3. + If any "Config Files" already exist in the archive they will be deployed "as is" to the location that matches the + archive file structure. +
          4. +
          +
          + General +
          Logging + The level of detail that will be sent to the log file (installer-log.txt). The recommended setting for most installs should be "Light." + Note if you use Debug the amount of data written can be very large. Debug is only recommended for support. +
          Cleanup + Pro + Remove disabled plugins/themes
          + Remove all inactive plugins and themes when installing site. Inactive users will also be removed during subsite to standalone migrations. +

          + + Pro + Remove users without permissions
          + Removes users that currently do not have any permissions associated with their accounts. +
          Safe Mode + Safe mode is designed to configure the site with specific options at install time to help overcome issues that may happen during the install + where the site is having issues. These options should only be used if you run into issues after you have tried to run an install. +

          + + Disabled
          + This is the default. This option will not apply any additional settings at install time. +

          + + Enabled
          + When enabled the safe mode option will disable all the plugins at install time. + Note: When this option is set you will need to manually re-enable the plugins that need to be enabled after the install from the + WordPress admin plugins page. +
          +

          + + + +

          + + Database Tab +

          +These are the advanced options for database configuration. + + + + + + + + + + + + + + + + + + + + + + + + + +
          OptionDetails
          Table Prefix + Pro + This option allows changing the table prefix to other than the package creation site's table prefix. The table prefix is the value placed in the + front of your database tables. It is possible to have multiple installations in one database if you give each WordPress site a unique prefix. +
          Mode + Modes affect the SQL syntax MySQL supports (and others such as MariaDB) . This setting performs various data validation checks. This makes + it easier to use MySQL in different environments and to use MySQL together with other database servers. It is very useful when running into + conversion issues. The following options are supported: +
            +
          • Default: This is the recommended setting to use. It will use the current Database mode setting.
          • +
          • Disable: This will prevent the database engine from running in any mode.
          • +
          • Custom: This option will allow you to enter a custom set of mode commands. See the documentation link below for options.
          • +
          + + For a full overview please see the MySQL mode and + MariaDB mode specific to your version. To add a custom setting enable the + Custom radio button and enter in the mode(s) that needs to be applied. +
          Processing + Chunking mode
          + Split the work of inserting data across several requests. If your host throttles requests or you're on a shared server that is being heavily + utilized by other sites then you should choose this option. This is the default option. +

          + + Single step
          + Perform data insertion in a single request. This is typically a bit faster than chunking, however it is more susceptible to problems when the + database is large or the host is constrained. +
          Create + Run all CREATE SQL statements at once. This option should be checked when source database tables have foreign key relationships. + When choosing this option there might be a chance of a timeout error. Uncheck this option to split CREATE queries in chunks. + This option is checked by default. +
          Objects + Allow or Ignore objects for "Views," "Stored Procedures," "Functions" and "DEFINER" statements. Typically the defaults + for these settings should be used. In the event you see an error such as "'Access denied; you need (at least one of) + the SUPER privilege(s) for this operation" then changing the value for each operation should be considered. +
          +

          + + +

          + + URLs & Paths Tab + Pro +

          +In the tab "URLs & Paths," you can read the current path of all the various path configurations for the WordPress site. These are advanced options +that should only be edited if you know the correct path. These options are editable in the Pro version. +
            +
          • + WordPress core path +
          • +
          • + WordPress core URL +
          • +
          • + WP-content path +
          • +
          • + WP-content URL +
          • +
          • + Uploads path +
          • +
          • + Uploads URL +
          • +
          • + Plugins path +
          • +
          • + Plugins URL +
          • +
          • + MU-plugins path +
          • +
          • + MU-plugins URL +
          • +
          + +These paths and URLs are set automatically by the package installer. You can set these paths and URLs manually. If you are changing it, +please make sure you are putting the right path or URL. +


          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/basic-step1-setup.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/basic-step1-setup.php new file mode 100644 index 00000000..d75d1209 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/basic-step1-setup.php @@ -0,0 +1,354 @@ + + +If no passwords were set on the installer or archive file then users will initially see step one of the installer. The installer has two operating views +that can be toggled via the Basic and Advanced buttons in the right-hand corner of the application. These installer views can only be chosen on step 1. +An overview of each view is explained below. +

          + + Views: +
            +
          • + Basic: + This is a simple two-step mode with all options set to the defaults. This is the default mode. The Basic view is the easiest and fastest and + covers most setup types. This is the recommended view for most installs. +
          • +
          • + Advanced: + This four-step mode allows for higher levels of customization with various detail settings. The Advanced view allows users to implement and apply + additional settings/features to the install process.
            + This is the only mode that Duplicator supported before version 1.5 +
          • +
          + + +

          Overview

          +The overview section allows users to identify the status, mode and select from the install type based on the user's install status. Additionally there are +other details about the archive file. Below is an overview of the various status, mode and install types.
          + + + Note: Duplicator Lite supports only single WordPress sites, while + " target="_blank"> + Duplicator Pro + supports single and multisite websites. + +

          + +

          + + Installation Tab +

          +This section will give an overview of the various install modes, methods and types that are currently being used. +

          + + Status: +
            +
          • + Install - Single Site
            + This will perform the installation of a single WordPress site based on the associated method. +
          • +
          • + Pro + Install - Multisite-Subdomain:
            + This is a full Multisite installation subdomain (i.e. subdomain.mysite.com) install. All sites in the network will be extracted and installed. +
          • +
          • + Pro + Install - Multisite-Subfolder:
            + This is a full Multisite installation via sub-folders install. All sites in the network will be extracted and installed. +
          • +
          • + Pro + Install - Standalone Site:
            + This installation converts the selected subsite into a standalone website. +
          • +
          • + Pro + Install - Archive Single Site into Subdomain/Subfolder Multisite:
            + This installation will insert the package site into the current multisite subdomain/subfolder setup. +
          • +
          • + Pro + Install - Selected Subsite in Subdomain/Subfolder Multisite:
            + This installation will insert the selected subsite of the package into the current subdomain/subfolder multisite installation. +
          • +
          • + Pro + Recovery - [Site Type]:
            + This status is enabled when the installer detects recovery mode installer was launched. This process will overwrite this site from the recovery + point made on a specific date. The site type will represent the type of site being recovered. +
          • +
          • + Pro + Restore Site Backup:
            + This method is enabled when the installer detects an archive is imported that matches the current setup. The restore backup status restores the + original site by not performing any processing on the database or tables to ensure an exact copy of the original site exists. Restore has the + following status types: Restore: Single Site Backup, Restore - Multisite-Subdomain Backup, Restore - Multisite-Subfolder Backup +
          • +
          + + + Mode: +
            +
          • + Standard Install +
              +
            • Includes both files and tables in the archive file.
            • +
            • The files and tables are determined by filters enabled during the archive build process.
            • +
            • Method is enabled when there is no existing WordPress site present in the current install directory.
            • +
            +
          • +
          • + Standard Install - Database Only +
              +
            • Includes only database tables in the archive file.
            • +
            • The tables are determined by filters enabled during the archive build process.
            • +
            • + Method is enabled when the archive only contains the database and there is no existing WordPress site present in the + current install directory. +
            • +
            +
          • +
          • + Overwrite Install
            +
              +
            • Includes both files and tables in the archive file.
            • +
            • The files and tables are determined by filters enabled during the archive build process.
            • +
            • Method is enabled when the installer detects an existing WordPress site is present.
            • +
            +
          • +
          • + Overwrite Install - Database Only
            +
              +
            • Includes only database tables in the archive file.
            • +
            • The tables are determined by filters enabled during the archive build process.
            • +
            • Method is enabled when the installer detects an existing WordPress site is present.
            • +
            +
          • +
          • + Pro + Custom Install
            +
              +
            • When the mode is custom this indicates the install is specifically driven by the status type.
            • +
            • See the status type of the install for all exact install details.
            • +
            +
          • +
          + + Install Type: +
            +
          • Full/Restore: This is the default install type.
          • +
          • Pro Convert: This is a Multisite feature used to convert a network subsite to a standalone site.
          • +
          • Pro Import: This is a Multisite feature used to import a subsite into a Multisite network.
          • +
          +* The Restore, Convert and Import types are only visible when the installer detects that it can perform the action. +

          + +

          + + Archive Tab +

          +The archive tab shows various details about the archive file and site details related to the site that was archived. With Duplicator the following +install modes are currently supported: +
            +
          • + Classic Install: + With this mode users can install to an empty directory like a new WordPress install does. +
          • +
          • + Overwrite Install: + This mode allows users to quickly overwrite an existing WordPress site in a few clicks. +
          • +
          • + Pro + Import Install: + Drag and drop or use a URL for super-fast installs. This Pro-only feature will import both Pro and Lite archives. +
              +
            • Import File: Drag and drop an existing Duplicator Lite or Pro archive and quickly replace the existing WordPress site
            • +
            • Import Link: Provide a link to an existing Duplicator Lite or Pro archive and quickly replace the existing WordPress site.
            • +
            +
          • +
          +


          + + +

          Setup

          +

          + + Database Tab +

          +The database connection inputs allow you to connect to an existing database or create a new database along with the other actions below. There are currently +two options you can use to perform the database setup: +
            +
          1. + Default: This option requires knowledge about the existing server, and requires the database be created ahead of time on most hosts. +
          2. +
          3. + Pro + cPanel: + The cPanel option is for hosts that support cPanel software. This option will automatically show you the existing + databases and users in your cPanel server and allow you to create new databases directly from the installer. +
          4. +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          OptionDetails
          + Default +
          Action + Empty Database
          + DELETE all tables in the database you are connecting to. Please make sure you have backups of all your data before using this part of the + installer, as this option WILL remove all data. +

          + + Backup Existing Tables
          + Create a backup of all existing tables by performing a RENAME of all tables in the database with a prefix of + "". This makes room for the new tables to be created. +

          + + Skip Database Extraction
          + This option requires that you manually run your own SQL import to an existing database before running the installer. + When this action is selected the + dup-database__[hash].sql file found inside the dup-installer folder of the archive.zip file will NOT be processed. The database you're connecting to + should already be a valid WordPress installed database. This option is viable when you need to perform custom SQL work or advanced installs. +

          + + Create New Database
          + Will attempt to create a new database if it does not exist. This option will not work on most hosting providers (due to host restrictions) but + will work on most local systems. If the database does not exist then you will need to log in to your host's database management system and create + the database. If your host supports cPanel then you can use this option to create a new database after logging in via your cPanel account. +

          + + Pro + Overwrite Existing Tables
          + Overwrite only the tables that are extracted. This option is useful if you want to install WordPress in a database containing other WordPress + installations or applications. Note: When performing an install alongside another installation be sure to change the prefix since only those + tables with the same prefix will be overwritten while tables of a different prefix will be retained. +

          +
          HostThe name of the host server that the database resides on. + Most times this will be "localhost," however each hosting provider will have its own naming + convention so please check with your server administrator or host to determine the proper host name. + To add a port number, just append it to the host i.e. "localhost:3306."
          Database + The name of the database to which this installation will connect and install the new tables and data into. + Some hosts will require a prefix while others do not. + Be sure to know exactly how your host requires the database name to be entered. +
          User + The name of MySQL/MariaDB database server user. + This is a special account that has privileges to access a database and can read from or write to that database. + This is not the WordPress administrator account. +
          PasswordThe password of the MySQL/MariaDB database server user.
          + cPanel Pro +
          HostPro + This should be the primary domain account URL that is associated with your host. Most hosts will require you to register a primary domain name. + This should be the URL that you place in the host field. For example if your primary domain name is "mysite.com" then you would enter in + "https://mysite.com:2083." The port 2083 is the common port number that cPanel works on. If you do not know your primary domain name please + contact your hosting provider or server administrator. +
          Username + Pro + The cPanel username used to login to your cPanel account. This is not the same thing as your WordPress administrator account. + If you're unsure of this name please contact your hosting provider or server administrator. +
          Password + Pro + The password of the cPanel user. +
          Troubleshoot + Pro + Common cPanel Connection Issues:
          + - Your host does not use cPanel software.
          + - Your host has disabled cPanel API access.
          + - Your host has configured cPanel to work differently (please contact your host).
          + + - View a list of valid cPanel Supported Hosts. +
          +

          + + +

          + + Settings Tab +

          +The settings options allow users to change the "Site Title," "Site URL" and "Site Path". By default and in most cases the "Site URL" and "Site Path" +should not need to be changed. In Basic mode these values are read-only. In order to edit them switch to the "Advanced" mode found in the upper right +corner of the installer wizard. + + + + + + + + + + + + + + + + + +
          OptionDetails
          Site Title + The name of the WordPress website. On most websites this value will be the name used to bookmark the site or the name of the browser tab + used to view the page. +
          Site URL + The New Site URL input field is auto-filled with the installation site URL. By default you have no need to change it. For details see WordPress + Site URL & + Alternate Directory. + This value should only be changed if you know what you want the value to be. The old URL value is listed as a read-only and will show the URL + of the site when the package was created. These values should not be changed, unless you know the underlying reasons. +
          Site Path + This is the physical server path where your WordPress site resides. For hosted server check with your hosting provider for the correct + path location. These values should not be changed, unless you know the underlying reasons. +
          +


          diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/validation-step1.php b/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/validation-step1.php new file mode 100644 index 00000000..e7b708d5 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/step1-parts/validation-step1.php @@ -0,0 +1,27 @@ + + + + +

          Validation

          +The system validation checks help to make sure the system is ready for install. During installation the website will be in maintenance mode and not +accessible to users. The series of checks will alert if there are any items that need attention. An overview of the different status codes can all +be found online in the FAQ titled + + How to fix installer validation checks? + +

          + +The validation process requires a connection to the database before starting. Enter in all the Database Connection fields and click the "Validate" button +to start the validation process. If the database connection is not successful, details about how to solve the issue will be provided. If the database +connection is successful then additional system checks will be performed to help users identify any potential issues that might arise during the install +process. + diff --git a/installer/dup-installer/templates/default/pages-parts/help/steps/troubleshoot.php b/installer/dup-installer/templates/default/pages-parts/help/steps/troubleshoot.php new file mode 100644 index 00000000..66e072b9 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/help/steps/troubleshoot.php @@ -0,0 +1,76 @@ + + + + diff --git a/installer/dup-installer/templates/default/pages-parts/page-footer.php b/installer/dup-installer/templates/default/pages-parts/page-footer.php new file mode 100644 index 00000000..063b39c9 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/page-footer.php @@ -0,0 +1,24 @@ + InstallerUpsell::getProFeatureList() +)); +?> +
          +getParamsHtmlInfo(); +?> + + + diff --git a/installer/dup-installer/templates/default/pages-parts/page-header.php b/installer/dup-installer/templates/default/pages-parts/page-header.php new file mode 100644 index 00000000..cacea4f8 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/page-header.php @@ -0,0 +1,37 @@ + + + + + Duplicator + + + + $bodyId, + 'bodyClasses' => $bodyClasses + )); + ?> +
          + $paramView + )); + if (!isset($skipTopMessages) || $skipTopMessages !== true) { + dupxTplRender('parts/top-messages.php'); + } diff --git a/installer/dup-installer/templates/default/pages-parts/secure/main.php b/installer/dup-installer/templates/default/pages-parts/secure/main.php new file mode 100644 index 00000000..f9abff46 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/secure/main.php @@ -0,0 +1,81 @@ +getSecurityType()) { + case DUPX_Security::SECURITY_PASSWORD: + $errorMsg = 'Invalid Password! Please try again...'; + break; + case DUPX_Security::SECURITY_ARCHIVE: + $errorMsg = 'Invalid Archive name! Please try again...'; + break; + case DUPX_Security::SECURITY_NONE: + default: + $errorMsg = ''; + break; +} +?> + +
          +

          + +

          +
          + +
          +
          + + Why do I see this screen? + +
          +
          + This screen will show under the following conditions: +

          + + Password: + If the installer was password protected when created then the password input below should be enabled.
          + If the input is disabled then no password was set during the build process. +

          + + Secure-File: + If the archive file is on a public server under these conditions: +
            +
          • Running a basic installer name (installer.php) with no installer password.
          • +
          • Running with the "Overwrite Install" method active and no installer password.
          • +
          + Validate the 'Archive File Name' input with the secure-file name it was created with ([name]_[hash]_[time]_archive.zip).
          + If the archive file name input is disabled or hidden then it can be ignored. +
          +
          + +
          + getHtmlFormParam(PrmMng::PARAM_SECURE_PASS); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_SECURE_ARCHIVE_HASH); + ?> +
          + + + + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/actions-part.php b/installer/dup-installer/templates/default/pages-parts/step1/actions-part.php new file mode 100644 index 00000000..fdc9ba3f --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/actions-part.php @@ -0,0 +1,12 @@ + +
          +
          + + This installation will not be able to proceed until the archive and validation sections both pass. + Please adjust your servers settings click validate buttom or contact your server administrator, + hosting provider or visit the resources below for additional help. + + +
          +
          diff --git a/installer/dup-installer/templates/default/pages-parts/step1/actions/hwarn-accept.php b/installer/dup-installer/templates/default/pages-parts/step1/actions/hwarn-accept.php new file mode 100644 index 00000000..aca52931 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/actions/hwarn-accept.php @@ -0,0 +1,15 @@ + +
          +

          + It is not recommended but possible to continue with the installation before
          + the problems indicated in the validation have been solved. +

          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/actions/next.php b/installer/dup-installer/templates/default/pages-parts/step1/actions/next.php new file mode 100644 index 00000000..462c50cf --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/actions/next.php @@ -0,0 +1,31 @@ + +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/actions/switch-template.php b/installer/dup-installer/templates/default/pages-parts/step1/actions/switch-template.php new file mode 100644 index 00000000..6e983ed5 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/actions/switch-template.php @@ -0,0 +1,25 @@ + +
          + + + + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/actions/validate.php b/installer/dup-installer/templates/default/pages-parts/step1/actions/validate.php new file mode 100644 index 00000000..111c899b --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/actions/validate.php @@ -0,0 +1,20 @@ + +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/base-setup.php b/installer/dup-installer/templates/default/pages-parts/step1/base-setup.php new file mode 100644 index 00000000..8b3fadc8 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/base-setup.php @@ -0,0 +1,61 @@ +getValue(PrmMng::PARAM_DB_VIEW_MODE) === 'cpnl') { + $cpnlDisplay = ''; + $basicDisplay = 'no-display'; +} +?> +
          + Setup +
          +
          +
          +
          + +
          + getHtmlFormParam(PrmMng::PARAM_DB_VIEW_MODE); + } + ?> +
          + +
          + + +
          + +
          + + +
          +
          + +
          +
          +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/continue-block.php b/installer/dup-installer/templates/default/pages-parts/step1/continue-block.php new file mode 100644 index 00000000..3f178ed0 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/continue-block.php @@ -0,0 +1,31 @@ + +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/basic-db-connection.php b/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/basic-db-connection.php new file mode 100644 index 00000000..b4911eb3 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/basic-db-connection.php @@ -0,0 +1,56 @@ +getMode() === DUPX_InstallerState::MODE_OVR_INSTALL && $paramsManager->getValue(PrmMng::PARAM_DB_DISPLAY_OVERWIRE_WARNING)) { + $displayOverwrite = true; +} else { + $displayOverwrite = false; +} +?> +
          +
          + Database Connection +
          + +
          + Ready to connect to existing sites database?
          +
          + The existing site's database settings are ready to be applied below. + If you want to connect to this database and replace all its data then + click the 'Apply button' to set the placeholder values. + To use different database settings click the 'Reset button' to clear and set new values. +

          + + + + Warning: Please note that reusing an existing site's database will overwrite all of its data. If you're not 100% sure about + using these database settings, then create a new database and use the new credentials instead. + +
          + +
          + + +
          +
          + getHtmlFormParam(PrmMng::PARAM_DB_ACTION); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_HOST); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_NAME); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_USER); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_PASS); + ?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/cpanel-panel.php b/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/cpanel-panel.php new file mode 100644 index 00000000..c83d7e08 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/cpanel-panel.php @@ -0,0 +1,64 @@ + +
          cPanel Connection
          + +
          +

          + cPanel Connectivity +

          + + + + + +
          + This server does not appear to support cPanel!
          + Consider upgrading to a host that does.
          + cPanel support is available only in Duplicator Pro with participating hosts. +
          + + + Duplicator Pro cPanel connectivity allows the following + without leaving this installer: + +
            +
          • Directly login to cPanel
          • +
          • Instantly create new databases & users
          • +
          • Preview and select existing databases & users
          • +
          + + + Note: Hosts that support cPanel provide remote access to server resources, allowing operations such as direct database and user creation. + Duplicator Pro + supports cPanel API access, which can help improve and speed up your workflow. + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/db-options.php b/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/db-options.php new file mode 100644 index 00000000..cdb024f8 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/database-tabs/db-options.php @@ -0,0 +1,39 @@ + +
          Extraction Settings
          +
          + +
          +isManaged()) { + $paramsManager->setFormNote(PrmMng::PARAM_DB_TABLE_PREFIX, 'The table prefix must be set according to the managed hosting where you install the site.'); +} +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_TABLE_PREFIX); +?> +
          + getHtmlFormParam(PrmMng::PARAM_DB_MYSQL_MODE); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_MYSQL_MODE_OPTS); + ?> +
          +getHtmlFormParam(PrmMng::PARAM_DB_ENGINE); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_SPLIT_CREATES); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_VIEW_CREATION); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_PROC_CREATION); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_FUNC_CREATION); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_REMOVE_DEFINER); diff --git a/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/archive.php b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/archive.php new file mode 100644 index 00000000..68c38042 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/archive.php @@ -0,0 +1,58 @@ + +
          + + + + + + + + + + + + + + + + +
          Archive File
          Created:created; ?>
          Size:
          Archive:package_name; ?>
          + + + + + + + + + + + + + + + + + + + exportOnlyDB) : ?> + + + + + +
          Site Details
          Site:blogname); ?>
          URL:getRealValue('siteUrl'), '/')); ?>
          Notes:package_notes) ? "{$archiveConfig->package_notes}" : " - no notes - "; ?>
          Mode:Archive only database was enabled during package package creation.
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/general.php b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/general.php new file mode 100644 index 00000000..a0bc7526 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/general.php @@ -0,0 +1,21 @@ + +
          + +
          + getHtmlFormParam(PrmMng::PARAM_INST_TYPE); + ?> +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overview-description.php b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overview-description.php new file mode 100644 index 00000000..e2ebf6d7 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overview-description.php @@ -0,0 +1,31 @@ +getMode() === DUPX_InstallerState::MODE_OVR_INSTALL); +?> +
          + isManaged()) !== false) { + $hostObj = $hostManager->getHosting($identifier); + ?> +
          +

          + getLabel(); ?> managed hosting detected +

          +

          + The installation is occurring on a WordPress managed host. + Managed hosts are more restrictive than standard shared hosts so some installer settings cannot be changed. + These settings include new path, new URL, database connection data, and wp-config settings. +

          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overviews/restore-backup.php b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overviews/restore-backup.php new file mode 100644 index 00000000..cb1409c8 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overviews/restore-backup.php @@ -0,0 +1,59 @@ +getMode() === DUPX_InstallerState::MODE_OVR_INSTALL); +$display = DUPX_InstallerState::getInstance()->isInstType( + array( + DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE + ) +); +?> +
          +
          +
          + '); ?> +
          + + + + + + + + + + + + + +
          Views: + Try + Basic + new or + Advanced views + +
          Status:Restore Single Site Backup
          Mode: +  ' : ''; + echo DUPX_InstallerState::getInstance()->getHtmlModeHeader(); + if ($overwriteMode) { + echo '
          + This will clear all site data and the current archive will be installed. This process cannot be undone! +
          '; + } + ?> +
          +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overviews/type-single-site.php b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overviews/type-single-site.php new file mode 100644 index 00000000..5aa24b92 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/info-tabs/overviews/type-single-site.php @@ -0,0 +1,54 @@ +getMode() === DUPX_InstallerState::MODE_OVR_INSTALL); +$display = DUPX_InstallerState::getInstance()->isInstType(DUPX_InstallerState::INSTALL_SINGLE_SITE); +?> +
          +
          +
          + '); ?> +
          + + + + + + + + + + + + + +
          View: + Try + Basic + new or + Advanced views +
          Status:Standard Single Site Setup
          Mode: +  ' : ''; + echo DUPX_InstallerState::getInstance()->getHtmlModeHeader(); + if ($overwriteMode) { + echo '
          + This will clear all site data and the current archive will be installed. This process cannot be undone! +
          '; + } + ?> +
          +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/info.php b/installer/dup-installer/templates/default/pages-parts/step1/info.php new file mode 100644 index 00000000..41f70649 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/info.php @@ -0,0 +1,28 @@ + + +
          +
          + + +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/main.php b/installer/dup-installer/templates/default/pages-parts/step1/main.php new file mode 100644 index 00000000..e6a49a4a --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/main.php @@ -0,0 +1,20 @@ + +
          +
          + +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/advanced.php b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/advanced.php new file mode 100644 index 00000000..ad9980d9 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/advanced.php @@ -0,0 +1,63 @@ + +
          + +
          + +
          Processing
          +getHtmlFormParam(PrmMng::PARAM_ARCHIVE_ENGINE); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_ZIP_THROTTLING); +?> + +
          Extraction Flow
          +getHtmlFormParam(PrmMng::PARAM_ARCHIVE_ACTION); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_FILE_TIME); +if (!SnapOS::isWindows()) { + ?> +
          + getHtmlFormParam(PrmMng::PARAM_SET_FILE_PERMS); ?> +   + getHtmlFormParam(PrmMng::PARAM_FILE_PERMS_VALUE); ?> +
          +
          + getHtmlFormParam(PrmMng::PARAM_SET_DIR_PERMS); ?> +   + getHtmlFormParam(PrmMng::PARAM_DIR_PERMS_VALUE); ?> +
          + + +
          Configuration Files
          +getHtmlFormParam(PrmMng::PARAM_WP_CONFIG); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_HTACCESS_CONFIG); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_OTHER_CONFIG); +?> + +
          General
          +getHtmlFormParam(PrmMng::PARAM_USERS_MODE); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_LOGGING); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_REMOVE_RENDUNDANT); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_REMOVE_USERS_WITHOUT_PERMISSIONS); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_SAFE_MODE); + + + diff --git a/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/engine-settings.php b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/engine-settings.php new file mode 100644 index 00000000..74da4807 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/engine-settings.php @@ -0,0 +1,19 @@ + +
          Engine Settings
          +getHtmlFormParam(PrmMng::PARAM_ARCHIVE_ENGINE); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_ARCHIVE_ENGINE_SKIP_WP_FILES); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_ENGINE); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_ZIP_THROTTLING); diff --git a/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/other-urls-path.php b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/other-urls-path.php new file mode 100644 index 00000000..882f1560 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/other-urls-path.php @@ -0,0 +1,41 @@ + +
          + Secondary URLs and paths + ">* + +
          + +
          + *All of these options are configurable with Duplicator Pro. + getHtmlFormParam(PrmMng::PARAM_PATH_WP_CORE_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_SITE_URL); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_PATH_CONTENT_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_URL_CONTENT_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_PATH_UPLOADS_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_URL_UPLOADS_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_PATH_PLUGINS_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_URL_PLUGINS_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_PATH_MUPLUGINS_NEW); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_URL_MUPLUGINS_NEW); + ?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/settings.php b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/settings.php new file mode 100644 index 00000000..24c399de --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/options-tabs/settings.php @@ -0,0 +1,20 @@ + +
          General
          +getHtmlFormParam(PrmMng::PARAM_BLOGNAME); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_URL_NEW); +$paramsManager->getHtmlFormParam(PrmMng::PARAM_PATH_NEW); + + diff --git a/installer/dup-installer/templates/default/pages-parts/step1/options.php b/installer/dup-installer/templates/default/pages-parts/step1/options.php new file mode 100644 index 00000000..66d6f0bb --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/options.php @@ -0,0 +1,34 @@ + +
          + Options +
          +
          +
          + +
          + +
          +
          + +
          +
          + +
          +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/proceed-confirm-dialog.php b/installer/dup-installer/templates/default/pages-parts/step1/proceed-confirm-dialog.php new file mode 100644 index 00000000..d52433d0 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/proceed-confirm-dialog.php @@ -0,0 +1,85 @@ +getValue(PrmMng::PARAM_RECOVERY_LINK); +$txtTable = $tableCount . ' table' . ($tableCount == 1 ? '' : 's'); +?> + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step1/step-title.php b/installer/dup-installer/templates/default/pages-parts/step1/step-title.php new file mode 100644 index 00000000..8af6687b --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/step-title.php @@ -0,0 +1,15 @@ + 'Step 1 of 4: Deployment
          This step will extract the archive file contents.
          ', + 'showInstallerMode' => true, + 'showSwitchView' => true, + 'showInstallerLog' => false +)); diff --git a/installer/dup-installer/templates/default/pages-parts/step1/terms-and-conditions.php b/installer/dup-installer/templates/default/pages-parts/step1/terms-and-conditions.php new file mode 100644 index 00000000..d82f1de4 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step1/terms-and-conditions.php @@ -0,0 +1,97 @@ + + + + diff --git a/installer/dup-installer/templates/default/pages-parts/step2/main.php b/installer/dup-installer/templates/default/pages-parts/step2/main.php new file mode 100644 index 00000000..7ae5c6bb --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step2/main.php @@ -0,0 +1,49 @@ + + +
          +
          + +
          +
          + +
          + +
          +
          + +
          +
          +
          +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step2/options-tabs/general.php b/installer/dup-installer/templates/default/pages-parts/step2/options-tabs/general.php new file mode 100644 index 00000000..ef5c1e4f --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step2/options-tabs/general.php @@ -0,0 +1,31 @@ + +
          + +
          +
          + +
          + Charset & Collation +
          + getHtmlFormParam(PrmMng::PARAM_DB_CHARSET); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_DB_COLLATE); + } + ?> +
          diff --git a/installer/dup-installer/templates/default/pages-parts/step2/options-tabs/tables.php b/installer/dup-installer/templates/default/pages-parts/step2/options-tabs/tables.php new file mode 100644 index 00000000..abee7244 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step2/options-tabs/tables.php @@ -0,0 +1,32 @@ + +
          + +
          +
          + +
          + Import and Update +
          + + To exclude a table from install click the "Import" checkbox. To prevent a table from being updated with the new site data click the "Update" checkbox. +
          + getHtmlFormParam(PrmMng::PARAM_DB_TABLES); + }?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step2/step-title.php b/installer/dup-installer/templates/default/pages-parts/step2/step-title.php new file mode 100644 index 00000000..b42a0991 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step2/step-title.php @@ -0,0 +1,12 @@ + 'Step 2 of 4: Install Database
          This step will install the database from the archive.
          ' +)); diff --git a/installer/dup-installer/templates/default/pages-parts/step3/main.php b/installer/dup-installer/templates/default/pages-parts/step3/main.php new file mode 100644 index 00000000..6841b45f --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/main.php @@ -0,0 +1,28 @@ + + + +
          +
          + +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/plugins.php b/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/plugins.php new file mode 100644 index 00000000..23e316a3 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/plugins.php @@ -0,0 +1,23 @@ + +
          + +
          +
          Activate Plugins Settings
          +getHtmlFormParam(PrmMng::PARAM_PLUGINS); diff --git a/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/search-rules.php b/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/search-rules.php new file mode 100644 index 00000000..51e33ba6 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/search-rules.php @@ -0,0 +1,54 @@ + +
          Search & replace settings
          + +
          + +
          + +
          + Custom Search and Replace + ">* + +
          +

          + Add additional search and replace URLs to replace additional data.
          + This option is available in Duplicator Pro. +

          + +
          Database Scan Options
          +
          + getHtmlFormParam(PrmMng::PARAM_SKIP_PATH_REPLACE); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_EMAIL_REPLACE); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_FULL_SEARCH); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_POSTGUID); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_MAX_SERIALIZE_CHECK); + ?> +
          + + + + diff --git a/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/users.php b/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/users.php new file mode 100644 index 00000000..f764b381 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/options-tabs/users.php @@ -0,0 +1,26 @@ + +
          + +
          + +
          User settings
          + +
          + +
          +
          + WP-Config File Setup + " + aria-expanded="false">* + +
          +
          + + + + See the WordPress documentation + for more information and specifications. All items are fully editable in Duplicator Pro. + + +
          CONTENT Posts/Pages
          + getHtmlFormParam(PrmMng::PARAM_WP_CONF_DISALLOW_FILE_EDIT); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_DISALLOW_FILE_MODS); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_AUTOSAVE_INTERVAL); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_POST_REVISIONS); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_EMPTY_TRASH_DAYS); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_IMAGE_EDIT_OVERWRITE); + ?> +
          SECURITY
          + getHtmlFormParam(PrmMng::PARAM_WP_CONF_FORCE_SSL_ADMIN); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_AUTOMATIC_UPDATER_DISABLED); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_AUTO_UPDATE_CORE); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_GEN_WP_AUTH_KEY); + ?> +
          CRON
          + getHtmlFormParam(PrmMng::PARAM_WP_CONF_ALTERNATE_WP_CRON); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_DISABLE_WP_CRON); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_CRON_LOCK_TIMEOUT); + ?> +
          DEBUG
          + getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_DEBUG); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_DEBUG_LOG); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_DEBUG_DISPLAY); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_SCRIPT_DEBUG); + ?> +
          SYSTEM
          + getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_CACHE); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WPCACHEHOME); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_MEMORY_LIMIT); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_MAX_MEMORY_LIMIT); + ?> +
          GENERAL
          + getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_DISABLE_FATAL_ERROR_HANDLER); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_MYSQL_CLIENT_FLAGS); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_CONCATENATE_SCRIPTS); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_SAVEQUERIES); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_COOKIE_DOMAIN); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_CONF_WP_TEMP_DIR); + } + ?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step3/options.php b/installer/dup-installer/templates/default/pages-parts/step3/options.php new file mode 100644 index 00000000..6bb3bc63 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/options.php @@ -0,0 +1,58 @@ +getValue(PrmMng::PARAM_WP_CONFIG); +$skipWpConfig = ($wpConfig == 'nothing' || $wpConfig == 'original'); +?> + +
          + Options +
          + +
          +
          + + + +
          + +
          + + +
          + +
          + + +
          + +
          + + +
          + +
          + +
          +
          diff --git a/installer/dup-installer/templates/default/pages-parts/step3/step-title.php b/installer/dup-installer/templates/default/pages-parts/step3/step-title.php new file mode 100644 index 00000000..bb7f0621 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/step-title.php @@ -0,0 +1,13 @@ + 'Step 3 of 4: ' . + 'Update Data
          This step will update the database and config files to match your new sites values.
          ' +)); diff --git a/installer/dup-installer/templates/default/pages-parts/step3/usersParts/newAdminUser.php b/installer/dup-installer/templates/default/pages-parts/step3/usersParts/newAdminUser.php new file mode 100644 index 00000000..5f4b4369 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/usersParts/newAdminUser.php @@ -0,0 +1,32 @@ + +
          New Admin Account
          +

          + + This feature is optional. If the username already exists the account will NOT be created or updated. + +

          +
          + getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_CREATE_NEW); ?> +
          + getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_NAME); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_PASSWORD); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_MAIL); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_NICKNAME); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_FIRST_NAME); + $paramsManager->getHtmlFormParam(PrmMng::PARAM_WP_ADMIN_LAST_NAME); + ?> +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step3/usersParts/usersPwdReset.php b/installer/dup-installer/templates/default/pages-parts/step3/usersParts/usersPwdReset.php new file mode 100644 index 00000000..28212586 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step3/usersParts/usersPwdReset.php @@ -0,0 +1,19 @@ + +
          Admin Password Reset
          +
          + getHtmlFormParam(PrmMng::PARAM_USERS_PWD_RESET); + ?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step4/actions/admin-login-button.php b/installer/dup-installer/templates/default/pages-parts/step4/actions/admin-login-button.php new file mode 100644 index 00000000..76e29aab --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step4/actions/admin-login-button.php @@ -0,0 +1,35 @@ +getValue(PrmMng::PARAM_SAFE_MODE); +?> +
          + +
          + Click the Admin Login button to login and finalize this install.
          + getHtmlFormParam(PrmMng::PARAM_AUTO_CLEAN_INSTALLER_FILES); ?> +
          +
          + + +
          + SAFE MODE: + Safe mode has deactivated all plugins. Please be sure to enable your plugins after logging in. + + If you notice that problems arise when activating + the plugins then active them one-by-one to isolate the plugin that could be causing the issue. + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step4/final-review-actions.php b/installer/dup-installer/templates/default/pages-parts/step4/final-review-actions.php new file mode 100644 index 00000000..a3c68c49 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step4/final-review-actions.php @@ -0,0 +1,40 @@ + + +
          + Review +
          +
            +
          • + Review this site's front-end + +
          • +
          • + getFinalReporNoticeById('wp-config-changes'); + $htaccessNorice = $nManager->getFinalReporNoticeById('htaccess-changes'); + ?> + Review the longMsg; ?> and longMsg; ?> +
          • +
          • + For additional help visit the online FAQs +
          • +
          diff --git a/installer/dup-installer/templates/default/pages-parts/step4/full-report.php b/installer/dup-installer/templates/default/pages-parts/step4/full-report.php new file mode 100644 index 00000000..c225de28 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step4/full-report.php @@ -0,0 +1,56 @@ +getValue(PrmMng::PARAM_FINAL_REPORT_DATA); +?> +
          +
          + displayFinalRepostSectionHtml('general', 'General Notices Report'); + $nManager->displayFinalRepostSectionHtml('files', 'Files Notices Report'); + $nManager->displayFinalRepostSectionHtml('database', 'Database Notices Report'); + $nManager->displayFinalRepostSectionHtml('search_replace', 'Search and Replace Notices Report'); + $nManager->displayFinalRepostSectionHtml('plugins', 'Plugins Actions Report'); + ?> +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          Database Report
          TablesRowsCells
          Createdn/a
          Scanned
          Updated
          +
          diff --git a/installer/dup-installer/templates/default/pages-parts/step4/important-final-notice.php b/installer/dup-installer/templates/default/pages-parts/step4/important-final-notice.php new file mode 100644 index 00000000..225a17b1 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step4/important-final-notice.php @@ -0,0 +1,15 @@ + +
          + FINAL STEPS: + Login into the WordPress Admin to remove all and finalize the install process. + This install is NOT complete until all installer files have been completely removed. Leaving installer files on this server can + lead to security issues. +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step4/installer-result-summary.php b/installer/dup-installer/templates/default/pages-parts/step4/installer-result-summary.php new file mode 100644 index 00000000..0ecbb735 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step4/installer-result-summary.php @@ -0,0 +1,45 @@ + + +
          + Install Result +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          General Notices()getSectionErrLevelHtml('general'); ?>
          Files Status() getSectionErrLevelHtml('files'); ?>
          Database Status()getSectionErrLevelHtml('database'); ?>
          Search and Replace Status() getSectionErrLevelHtml('search_replace'); ?>
          Plugins Status() getSectionErrLevelHtml('plugins'); ?>
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/pages-parts/step4/main.php b/installer/dup-installer/templates/default/pages-parts/step4/main.php new file mode 100644 index 00000000..d0955cc6 --- /dev/null +++ b/installer/dup-installer/templates/default/pages-parts/step4/main.php @@ -0,0 +1,14 @@ + 'Step 4 of 4: Test Site' +)); diff --git a/installer/dup-installer/templates/default/parts/ajax-error.php b/installer/dup-installer/templates/default/parts/ajax-error.php new file mode 100644 index 00000000..1896a444 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/ajax-error.php @@ -0,0 +1,42 @@ +getValue(PrmMng::PARAM_RECOVERY_LINK); +?> +
          +

          + ERROR:

          + Please try again an issue has occurred. +

          +
          Please see the file for more details.
          +
          +
          +
          
          +
          +

          + Additional Resources:
          + » '>Help Resources
          + » '>Technical FAQ +

          +

          + + + + Restore Recovery Point + + +

          +

          + + See online help for more details at duplicator.com +

          +
          diff --git a/installer/dup-installer/templates/default/parts/education/did-you-know-blurb.php b/installer/dup-installer/templates/default/parts/education/did-you-know-blurb.php new file mode 100644 index 00000000..e740ec64 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/education/did-you-know-blurb.php @@ -0,0 +1,27 @@ + +
          + Did you know Duplicator Pro has: ? + + Upgrade To Pro + + getHtmlFormParam(PrmMng::PARAM_SUBSCRIBE_EMAIL); ?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/education/footer-cta.php b/installer/dup-installer/templates/default/parts/education/footer-cta.php new file mode 100644 index 00000000..700cb227 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/education/footer-cta.php @@ -0,0 +1,57 @@ + +
          +
          Get Duplicator Pro and Unlock all the Powerful Features
          +

          + Thanks for being a loyal Duplicator Lite user. Upgrade to Duplicator Pro to unlock all the awesome features and + experience why Duplicator is consistently rated the best WordPress migration plugin. +

          +

          + ', 5) + ); + ?> +

          +
          Pro Features:
          +
            + +
          • + + + +
          • + +
          +

          + + Get Duplicator Pro Today and Unlock all the Powerful Features » + +

          +

          + Bonus: Duplicator Lite users get % off regular price, + automatically applied at checkout. +

          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/params/archive-action-notes.php b/installer/dup-installer/templates/default/parts/params/archive-action-notes.php new file mode 100644 index 00000000..cf40fec1 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/params/archive-action-notes.php @@ -0,0 +1,43 @@ + +
          + Note: Files are extracted over existing files. + After install, the destination folder will contain a combination of the old site files and the files extracted from the archive. + This option is the most conservative option for those who want to make sure they do not want to lose data. +
          +
          + Note: Before extracting the package files, all files and folders in the installation folder will be removed + except for folders that contain WordPress installations or Duplicator backup folders
          + This option is recommended for those who want to delete all files related to old installations or external applications. +
          +
          + Note: Before extracting the package files, all current media files will be removed (wp-content/uploads)
          + This option is for those who want to avoid having old site media mixed with new but have other files/folders + in the home path that they don't want to delete. +
          +
          + Note: Before extracting the package files, all current WordPress core and content files and folders will be removed (wp-include, wp-content ... )
          + This option is for those who want to avoid having old site media mixed with new but have other files/folders + in the home path that they don't want to delete. +
          diff --git a/installer/dup-installer/templates/default/parts/params/db-name-notes.php b/installer/dup-installer/templates/default/parts/params/db-name-notes.php new file mode 100644 index 00000000..669e0e87 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/params/db-name-notes.php @@ -0,0 +1,21 @@ + + + Warning: The selected 'Action' above will remove all data from this database! + + + Notice: The selected 'Action' will rename all existing tables from the database name above with a prefix + The prefix is only applied to existing tables and not the new tables that will be installed. + + + Notice: The 'Skip Database Extraction' action will prevent the SQL script (dup-database__[HASH].sql) in the archive from being executed. + The database above should already be pre-populated with the data for the site. The updates routines for updating the site URL and paths will be the + only SQL database commands applied to the database. + diff --git a/installer/dup-installer/templates/default/parts/params/extract-skip-notes.php b/installer/dup-installer/templates/default/parts/params/extract-skip-notes.php new file mode 100644 index 00000000..72efd276 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/params/extract-skip-notes.php @@ -0,0 +1,36 @@ + +
          + All Files in the archive are going to be extracted. +
          +
          + When this option is chosen the wordpress core files, if any, are not modified. They are not deleted and/or extracted. +
          +
          + When this option is chosen the wordpress core files, if any, are not modified. They are not deleted and/or extracted.
          + Also, if a plugin (theme) exists on BOTH the host and and the archive, the contents of the host plugin (theme) are going to be kept. +
          +
          + When this option is chosen only the "uploads" folder and plugins (themes) that don't exist on the host are going to be extracted. +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/params/inline_helps/subsite_user_mode.php b/installer/dup-installer/templates/default/parts/params/inline_helps/subsite_user_mode.php new file mode 100644 index 00000000..db1ccde2 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/params/inline_helps/subsite_user_mode.php @@ -0,0 +1,17 @@ + +

          + Import: Adds all users from the source site to the target site. Does not remove or alter existing target users. +

          +

          + Ignore: Don't import users from the source site. + All content on the source site will be assigned to the content author selected user. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/params/inline_helps/user_mode.php b/installer/dup-installer/templates/default/parts/params/inline_helps/user_mode.php new file mode 100644 index 00000000..e785dc0c --- /dev/null +++ b/installer/dup-installer/templates/default/parts/params/inline_helps/user_mode.php @@ -0,0 +1,21 @@ + +

          + Overwrite: Overwrites users is the classic mode, users from the source site will be installed and those from the target site will be discarded. +

          +

          + Keep: Keeps all users of the target site by discarding users of the source site. + All content on the source site will be assigned to the content author selected user. +

          +

          + Merge: Merges users from the target site with users from the source site. + The target site users will be unchanged and the source site users will be added by remapping ids and logins if duplicated. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/progress-bar.php b/installer/dup-installer/templates/default/parts/progress-bar.php new file mode 100644 index 00000000..8426e95b --- /dev/null +++ b/installer/dup-installer/templates/default/parts/progress-bar.php @@ -0,0 +1,24 @@ +
          +
          +
          +
          +
          +
          +

          Please Wait...



          +
          +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/reports/import_report.php b/installer/dup-installer/templates/default/parts/reports/import_report.php new file mode 100644 index 00000000..58310073 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/reports/import_report.php @@ -0,0 +1,33 @@ + +

          + users have been added
          + users were already present and therefore have been modified +

          + +

          + No users have been imported and/or modified, all users from the source site are in the target site. +

          + + A CSV report has been generated with the list of all the users added/modified and the mapping of the modifications
          + + Download import CSV report +
          + Note: This report does not contain users who were already at the target site. + +

          + Csv report rile can't be generated +

          + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/restore-backup-mode-notice.php b/installer/dup-installer/templates/default/parts/restore-backup-mode-notice.php new file mode 100644 index 00000000..549815c2 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/restore-backup-mode-notice.php @@ -0,0 +1,13 @@ + +

          + Restore backup mode is enabled so most options are disabled.
          + If you want to activate these options to change the migration website you need to restart the installer and deactivate the Restore backup mode option +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/top-header-help.php b/installer/dup-installer/templates/default/parts/top-header-help.php new file mode 100644 index 00000000..9f76b1cb --- /dev/null +++ b/installer/dup-installer/templates/default/parts/top-header-help.php @@ -0,0 +1,21 @@ + + + + + +
          +
          + Duplicator help +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/top-header.php b/installer/dup-installer/templates/default/parts/top-header.php new file mode 100644 index 00000000..b844108c --- /dev/null +++ b/installer/dup-installer/templates/default/parts/top-header.php @@ -0,0 +1,43 @@ + + + + + + +
          +
          + + applyFilters('dupx_main_header', 'Duplicator'); ?> +
          +
          + version:version_dup; ?> + +
          + +  | '; + DUPX_View_Funcs::helpLink($paramView, 'Help'); + ?> + +   + +
          +
          + +
          + nextStepLog(); +// display and remove next step notices + DUPX_NOTICE_MANAGER::getInstance()->displayStepMessages(); + ?> +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-affected-tables.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-affected-tables.php new file mode 100644 index 00000000..a5b3ff51 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-affected-tables.php @@ -0,0 +1,47 @@ + +
          STATUS
          + + + +

          + Adding a new subsite into WordPress does not require removing or renaming any tables. +

          + +

          + The chosen Database Action does not affect any tables in the selected database. +

          + + +

          + The chosen Database Action will result in the modification of + table(s). +

          + +
          DETAILS
          +

          + +
          +
            + +
          • + +
          +
          + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-case-sensitive-duplicates.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-case-sensitive-duplicates.php new file mode 100644 index 00000000..4497cf2b --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-case-sensitive-duplicates.php @@ -0,0 +1,49 @@ + $duplicateTableNames + * @var string[] $reduntantTableNames + */ + +?> +
          STATUS
          +

          + The following tables have the same name but different casing. Underlined tables are going to be excluded from the database extraction. +

          +
            + $tableNames) { ?> +
          • + $name) { + if (in_array($name, $reduntantTableNames)) { ?> + + +
          • + +
          + +
          DETAILS
          +

          + The database setting lower_case_table_names is set to [] which doesn't allow case sensitive table names. + This will cause issues trying to create tables with the same case insensitive table name. To change the filtered tables switch to "Advanced" and + mode and choose the tables to extract in Step 2. +

          diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-case-sensitive-tables.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-case-sensitive-tables.php new file mode 100644 index 00000000..69b16250 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-case-sensitive-tables.php @@ -0,0 +1,65 @@ + +
          STATUS
          +

          + + No table casing issues detected. This servers variable setting for lower_case_table_names is [] + + An upper case table name was found in the database SQL script and the server variable lower_case_table_names is set to + []. + When both of these conditions are met it can lead to issues with creating tables with upper case characters.
          + Options:
          + - On this server have the host company set the lower_case_table_names value to 1 or 2 in the my.cnf file.
          + - On the build server set the lower_case_table_names value to 2 restart server and build package.
          + - Optionally continue the install with data creation issues on upper case tables names.
          + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks if any tables have upper case characters as part of the name. + On some systems creating tables with upper case can cause issues if the server + setting for + lower_case_table_names + is set to zero and upper case + table names exist. +

          + +
          TROUBLESHOOT
          + + + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-cleanup.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-cleanup.php new file mode 100644 index 00000000..04f59ce9 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-cleanup.php @@ -0,0 +1,76 @@ + +
          STATUS
          +

          + + Successfully removed database [] + + The database [] was successfully created. + However removing the database was not successful with the following response:
          + To continue refresh the page, change the setup action and continue with the install + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks if the database can be removed by the database user . + The test will attempt drop the database name provided as part of the overall test. +

          + +
          TROUBLESHOOT
          + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-connection.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-connection.php new file mode 100644 index 00000000..ff4186a5 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-connection.php @@ -0,0 +1,95 @@ + +
          STATUS
          +

          + + The user [] successfully connected to the database server on host + []. + + Unable to connect the user [] to the host + [].
          + + The server error response was: ' + + Please contact your hosting provider or server administrator. + + +

          + +
          DETAILS
          +

          + This test checks that the database user is allowed to connect to the database server. + It validates on the user name, password and host values. + The check does not take into account the database name or the user permissions. A database user must first exist and have access to the host + database server before any additional checks can be made. +

          + + + + + + + + + + + + + + +
          Host:
          User:
          Password:

          + +
          TROUBLESHOOT
          + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-create.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-create.php new file mode 100644 index 00000000..5823a302 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-create.php @@ -0,0 +1,82 @@ + +
          STATUS
          +

          + + Successfully created database [] + + DATABASE CREATION FAILURE: A database named [] already exists.

          + Please continue with the following options:
          + - Choose a different database name or remove this one.
          + - Change the action drop-down to an option like "Connect and Remove All Data".
          + + Error creating database []. + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks if the database can be created by the database user . + The test will attempt to create and drop the database name provided as part of the overall test. +

          + +
          TROUBLESHOOT
          + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-gtid-mode.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-gtid-mode.php new file mode 100644 index 00000000..62bb1b90 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-gtid-mode.php @@ -0,0 +1,48 @@ + +
          STATUS
          +

          + + The installer have not detected GTID mode. + + Your database server have GTID mode is on, It might make a trouble in Database installation.
          + Details: You might face the error something like Statement violates GTID consistency. + You should ask hosting provider to make off GTID off. + You can make off GTID mode as decribed in the + + https://dev.mysql.com/doc/refman/5.7/en/replication-mode-change-online-disable-gtids.html + + + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks to make sure the database server should not have GTID mode enabled. +

          +
          TROUBLESHOOT
          + + + + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-host-name.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-host-name.php new file mode 100644 index 00000000..b13299c5 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-host-name.php @@ -0,0 +1,29 @@ + +

          + Database host: + + [] is valid. + + [] is not a valid. Try using [] instead. + + +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-manual-tables-count.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-manual-tables-count.php new file mode 100644 index 00000000..0988f172 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-manual-tables-count.php @@ -0,0 +1,42 @@ + +
          STATUS
          +

          + + This test passes. A WordPress database looks to be setup. + + The database [] has tables. This does not look to be a valid WordPress database. + The base WordPress install has 12 tables. Please validate that this database is indeed pre-populated with a valid WordPress database. + The "Skip Database Extraction" mode requires that you have a valid WordPress database already installed. + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks if the database looks to represents a base WordPress install. Since this option is advanced it is left upto the user to + have the correct database tables installed. +

          + + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-multiple-wp-installs.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-multiple-wp-installs.php new file mode 100644 index 00000000..36a6a46c --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-multiple-wp-installs.php @@ -0,0 +1,45 @@ + +
          STATUS
          + + +

          + The selected database action does not affect other WordPress installations. +

          + +

          + The selected database action affects WordPress installations. +

          + + +
          DETAILS
          +

          + This test makes sure that the selected database action affects at most one WordPress installation. Please make sure that the + chosen database action will not cause unwanted consequences for tables of other sites residing on the same database. In case + you want to avoid removing the tables of the second WordPress installation we recommend switching the Database action to + "Overwrite Existing Tables". +

          + 0) : ?> +

          WordPress tables with the following table prefixes will be affected by the chosen database action:

          +
            + +
          • + +
          + + + + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-prefix-too-long.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-prefix-too-long.php new file mode 100644 index 00000000..12def112 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-prefix-too-long.php @@ -0,0 +1,54 @@ + +
          STATUS
          +

          + + There are no table names whose length exceeds limit of 64 characters after adding prefix. + + Some table names exceed limit of 64 characters after adding prefix. + +

          + +

          + Error detail: +

          + + + +
          DETAILS
          +

          + This test checks if there are any table names that would be too long after adding prefix to them. + MySQL accepts length of table names with maximum of 64 characters + (see length limits). + With a too long prefix, tables can exceed this limit. +

          + + + List of database tables that are too long after adding prefix
          +
          +
            + +
          • + +
          +
          + + +
          TROUBLESHOOT
          +
            +
          • Choose a shorter prefix in Options ❯ Database Settings ❯ Table Prefix.
          • +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-show-variables.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-show-variables.php new file mode 100644 index 00000000..04836c90 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-show-variables.php @@ -0,0 +1,38 @@ + +
          STATUS
          + +

          + Successfully read database variables. +

          + +

          + Error reading database variables. +

          + +
          DETAILS
          +

          + Query executed: SHOW VARIABLES like 'version'

          + The "SHOW VARIABLES" query statement is required to obtain + necessary information about the database and safely execute the installation process. There is not a single setting that will make this query work + for all hosting providers. Please contact your hosting provider or server admin with + this link and ask for them to provide support for the + "SHOW VARIABLES" when called from PHP.

          + + Additional FAQ resources for this issue can be found here:
          + + Digital Ocean -- digitalocean.com + +

          diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-charset.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-charset.php new file mode 100644 index 00000000..73aeab1e --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-charset.php @@ -0,0 +1,138 @@ + DUPX_Validation_abstract_item::LV_SOFT_WARNING ? 'green' : 'red'; + +$dupDatabase = basename(DUPX_Package::getSqlFilePath()); +$dupDatabaseDupFolder = basename(DUPX_INIT) . '/' . $dupDatabase; +$invalidCheckboxTitle = ''; +$subTitle = ''; + +?> +
          STATUS
          +

          + + It is impossible to verify the list of charsets in the database. + + isn't supported on current database. + will be replaced with default values.
          + + Character set and Collate test passed! This database supports the required table character sets and collations. + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks to make sure this database can support the character set and collations found in the + script. +

          + + + + + + + + + + + + + + + + + + + + + + +
          + Character set list +
          + + + + +
          + Collations list +
          + + +
          + +

          + The database where the package was created has a that is not supported on this server. + This issue happens when a site is moved from an newer version of MySQL to a older version of MySQL. + The recommended fix is to update MySQL on this server to support the character set that is failing below. + If this is not an option for your host, then you can continue the installation. Invalid values will be replaced with the default values. + For more details about this issue and other details regarding this issue see the FAQ link below. +

          + +

          + Default charset and setting in current installation
          + DB_CHARSET =
          + DB_COLLATE = +

          + +

          TROUBLESHOOT
          + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-default-charset.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-default-charset.php new file mode 100644 index 00000000..77957605 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-default-charset.php @@ -0,0 +1,55 @@ + +
          STATUS
          +

          + + It is not possible to read the list of available charsets in the database.
          + Message: + + This server's database does not support the source site's character set [], + so the installer is going to use default character []. + + This server's database does not support the source site's collate [], + so the installer is going to use default collate of current charset []. + + The current server supports the source site's charset [] + and Collate [] + (set in the wp-config file).
          + +

          + +
          DETAILS
          +

          + Settings used in the current installation
          + DB_CHARSET =
          + DB_COLLATE = +

          +

          + DB_CHARSET and DB_COLLATE are set in wp-config.php + (see: Editing wp-config.php ).
          + When the charset or collate of the source site is not supported in the database of the target site, the default is automatically set. +

          + +
          TROUBLESHOOT
          +
            +
          • In case the default charset/collates are not the desired ones you can change the setting in the advanced installation mode.
          • +
          diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-engine.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-engine.php new file mode 100644 index 00000000..ee21924c --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-supported-engine.php @@ -0,0 +1,79 @@ + DUPX_Validation_abstract_item::LV_SOFT_WARNING ? 'green' : 'red'; + +$dupDatabase = basename(DUPX_Package::getSqlFilePath()); +$dupDatabaseDupFolder = basename(DUPX_INIT) . '/' . $dupDatabase; +$invalidCheckboxTitle = ''; +$subTitle = ''; + +?> +
          STATUS
          +

          + + The Duplicator Installer is currently unable to verify the list of engines in the database. + + Some of the MySQL engines used in the source site are not supported on the current database. + + Database engine for MySQL compatibility passed! This database supports the required MySQL engine types. + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks to make sure this database can support the MySQL engines found in the + script. +

          + + +

          + The following MySQL Engine(s) were found to not be supported by the current database: +

          +
            + +
          • + +
          + and are going to be replaced by the default MySQL Engine []. + + +
          TROUBLESHOOT
          +
            +
          • + In case some of the MySQL engines of the source site are not supported and replacing them with the default engine + is not desired, please try getting in touch with your hosting provider and asking them to enable the engine. +
          • +
          + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-triggers.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-triggers.php new file mode 100644 index 00000000..ad4a0090 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-triggers.php @@ -0,0 +1,46 @@ + +
          STATUS
          +

          + + The source database did not contain any triggers. + + The source database contained TRIGGERS which will have to be manually imported. + +

          + +
          DETAILS
          +

          + TRIGGERS are not being imported along side the rest of the database, because their presence might cause unintended + behavior. You can copy the CREATE queries by clicking the button below and manually add triggers via PHPMyAdmin, if necessary. +

          + +
          + + +
          diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-cleanup.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-cleanup.php new file mode 100644 index 00000000..f746595a --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-cleanup.php @@ -0,0 +1,50 @@ + +
          STATUS
          +

          + + Successfully removed database user [] with cPanel API. + + The database user [] was successfully created. + However removing the user was not successful via the cPanel API with the following response:
          + To continue refresh the page, uncheck the 'Create New Database User' checkbox and select the user from the drop-down. + +

          + +

          + Error detail: +

          + + +
          DETAILS
          +

          + This test checks that the cPanl API is allowed to remove database user crated before. +

          + + + + + + +
          User:

          + +
          TROUBLESHOOT
          +
            +
          • Contact your host to make sure they support the cPanel API.
          • +
          • Check with your host to make sure the user name provided meets the cPanel requirements.
          • +
          + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-perms.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-perms.php new file mode 100644 index 00000000..51786af3 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-perms.php @@ -0,0 +1,147 @@ + +
          STATUS
          +

          + + The user [] has the correct privileges on the database []. + + The user [] is missing privileges on the database [] + + The user [] is missing privileges on the database []
          + You can continue with the installation but some features may not be restored correctly. + +

          + +

          + Error detail:
          + +
          + +

          + + +
          DETAILS
          +

          + This test checks the privileges of the current database user. In order to successfully use Duplicator all of the privileges should pass. + In the event the checks below fail, contact your hosting provider to make sure the database user has the correct permissions listed below. +

          + + + Note: In some cases "Create Views, Procedures, Functions and Triggers" will not pass, but continuing with the install will still work. + It is however recommended that a green pass on all permissions is set when possible. Please work with your hosting provider to get all + values to pass. + +


          + +
          TABLE PRIVILEGES ON []
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          Create
          Select
          Insert
          Update
          Delete
          Drop
          Create Views
          Procedures (Create & Alter)
          Functions (Create & Alter)
          Trigger

          + +
          TROUBLESHOOT
          + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-resources.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-resources.php new file mode 100644 index 00000000..c6bf0449 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-user-resources.php @@ -0,0 +1,48 @@ + +
          STATUS
          + +

          + No restrictions on the current DB user's resources were detected. +

          + +

          + Restrictions on the current DB user's resources were detected. +

          + + +
          DETAILS
          +

          + Some server's put in place restrictions on the resources available to a user, which may cause errors during + the installation process since a significant number of connections are made and queries are run. +

          + + 0) : ?> +
          USER RESOURCES
          +
            + $limit) : ?> +
          • + : 0 ? $limit : 'unlimited'; ?> +
          • + +
          + +
          TROUBLESHOOT
          +

          + We suggest asking your hosting provider to undo the restrictions in case they are present or if you have root access to the mysql server + you can use the methods described in the official documentation + to remove the restrictions. +

          + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-version-swarn.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-version-swarn.php new file mode 100644 index 00000000..9882a3c3 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-version-swarn.php @@ -0,0 +1,64 @@ + +
          STATUS
          +

          + + + The current database engine is [] while the host database engine was + []. + + + + The current database version is [] which is below the source database version of + []. + + + In some cases this might cause problems with the migration. +

          + +
          DETAILS
          +

          + + Some versions of different database engines are not compatible with each other, which might cause problems with the database import. + We suggest continuing the install as usual. + In case there are problems with the database install please consult the links in the + troubleshoot section to find out which features are not compatible. + + The source site used a newer version of , + which may result in problems during the installation if there were changes + made which are not backward-compatible. We suggest continuing with the install as usual. + In case of problems with the database try contacting your hosting provider and asking for a database version upgrade. + +

          + +
          TROUBLESHOOT
          + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-version.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-version.php new file mode 100644 index 00000000..002f9fcb --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-version.php @@ -0,0 +1,52 @@ + +
          STATUS
          +

          + + + This test passes with a current database version of [] + + + + The current database version is [] which is below the required version of 5.0.0. + Please work with your server admin or hosting provider to update the database server. + + +

          + +
          DETAILS
          +

          + The minimum supported database server is MySQL Server 5.0 or the + MariaDB equivalent. + Versions prior to MySQL 5.0 are over 10 years old and will not be compatible with Duplicator. + If your host is using a legacy version, please ask them + to upgrade the MySQL database engine to a more recent version. +

          + +
          TROUBLESHOOT
          + + diff --git a/installer/dup-installer/templates/default/parts/validation/database-tests/db-visibility.php b/installer/dup-installer/templates/default/parts/validation/database-tests/db-visibility.php new file mode 100644 index 00000000..596e0eb6 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/database-tests/db-visibility.php @@ -0,0 +1,96 @@ + +
          STATUS
          +

          + + The database user [] has visible access to see the database named + [] + + The user [] is unable to see the database named + [].
          + Be sure the database name already exists. + If you want to create a new database choose the action 'Create New Database'.
          + +

          + +

          + Error detail: +

          + + + +
          DETAILS
          +

          + This test checks if the database user is allowed to connect or view the database. + This test will not be ran if the 'Create New Database' action is selected. +

          + + + Databases visible to user []
          +
            + +
          • + +
          • + +
          • + No databases are viewable +
          • + +
          + + +
          TROUBLESHOOT
          + diff --git a/installer/dup-installer/templates/default/parts/validation/tests/addon-sites.php b/installer/dup-installer/templates/default/parts/validation/tests/addon-sites.php new file mode 100644 index 00000000..fee5dc10 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/addon-sites.php @@ -0,0 +1,58 @@ + DUPX_Validation_abstract_item::LV_SOFT_WARNING ? 'green' : 'red' ); +?> +
          STATUS
          +

          + + No addon site detected. + + Detected addon sites, see the details section for the list of sites.
          + DUPX_Validation_abstract_item::LV_SOFT_WARNING) { ?> + Normal installation generally does not interfere with these sites. + + These sites are not deleted even if you have selected an action that removes the files before extracting them. + If there are other folders outside the home path that are necessary for the addon site to work, it will be removed + so pay attention in the event there are addon custom installations. + +

          + +
          DETAILS
          +

          + An addon site is a WordPress installation in a subfolder of the current home path. +

          + 0) { ?> +

          + Addons Site Paths +

          +
            + +
          • + +
          • + +
          + +
          TROUBLESHOOT
          +
            +
          • + The installer doesn't modify addon sites so their presence doesn't cause problems + but if you want to be sure you don't lose data it might be useful to make a backup of the addon site. +
          • +
          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/archive-check.php b/installer/dup-installer/templates/default/parts/validation/tests/archive-check.php new file mode 100644 index 00000000..4761fbc7 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/archive-check.php @@ -0,0 +1,43 @@ + + Archive file successfully detected. + + + The archive file named above must be the exact name of the archive file placed in the root path (character for character). + But you can proceed with choosing Manual Archive Extraction. + + + + The archive file named above must be the exact name of the archive file placed in the root path (character for character). + When downloading the package files make sure both files are from the same package line.

          + + If the contents of the archive were manually transferred to this location without the archive file then simply create a temp file named with + the exact name shown above and place the file in the same directory as the installer.php file. The temp file will not need to contain any data. + Afterward, refresh this page and continue with the install process. +
          + + Invalid test result value DUPX_Validation_abstract_item::LV_SOFT_WARNING ? 'green' : 'red' ); +?> +
          STATUS
          +

          + DUPX_Validation_abstract_item::LV_SOFT_WARNING) { ?> + All configuration files are editable. + + One or more configuration files cannot be edited, the list is in the details section + +

          + +
          DETAILS
          +

          + This test verifies that the configuration files are editable. + Otherwise it is possible to continue with the installation but some settings will be disabled and + it will not be possible to modify the configuration file without write permissions. +

          + + + + + + + + + + + + + + + +
          + wp-config.php + + + +
          + .htaccess + + + +
          + Other configs
          + [ web.config, php.ini, .user.ini ] +
          + + +
          + +
          TROUBLESHOOT
          +
            +
          • If possible, via FTP or file manager, manually change the permissions of the conditioner files.
          • +
          • In case the home path does not have write or run permissions, add them manually.
          • +
          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/dbonly-iswordpress.php b/installer/dup-installer/templates/default/parts/validation/tests/dbonly-iswordpress.php new file mode 100644 index 00000000..38126f2b --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/dbonly-iswordpress.php @@ -0,0 +1,30 @@ +Deployment Path: getValue(PrmMng::PARAM_PATH_NEW)); ?> +

          + +The installer has detected that a WordPress site does not exist at the deployment path above. +This installer is currently in 'Database Only' mode because that is how the archive was created. +If core WordPress site files do not exist at the path above then they will need to be placed there in order for a WordPress site +to properly work. To continue choose one of these options: + +
            +
          1. Place this installer and archive at a path where core WordPress files already exist to hide this message.
          2. +
          3. Create a new package that includes both the database and the core WordPress files.
          4. +
          5. Ignore this message and install only the database (for advanced users only).
          6. +
          + + + Note: This test simply looks for the directories and a wp-config.php file. + If they are not found in the deployment path above then this notice is shown. + diff --git a/installer/dup-installer/templates/default/parts/validation/tests/diskspace.php b/installer/dup-installer/templates/default/parts/validation/tests/diskspace.php new file mode 100644 index 00000000..c620b351 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/diskspace.php @@ -0,0 +1,34 @@ + +
          STATUS
          +

          + + You have sufficient disk space on your machine to extract the archive. + + You don’t have sufficient disk space on your machine to extract the archive. + +

          + +
          DETAILS
          +

          + Duplicator needs at least enough disk space to be able to host the package file and the extracted files.
          + The available free disk space is , the required disk space should at least be . +

          + +
          TROUBLESHOOT
          +
            +
          • Ask your host to increase your disk space.
          • +
          • Back-up and remove all unnecessary files you have in the install directory to free up space.
          • +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/importable-package.php b/installer/dup-installer/templates/default/parts/validation/tests/importable-package.php new file mode 100644 index 00000000..05dc9b5f --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/importable-package.php @@ -0,0 +1,41 @@ + DUPX_Validation_abstract_item::LV_SOFT_WARNING ? 'green' : 'red' ); +?> +
          STATUS
          +

          + DUPX_Validation_abstract_item::LV_SOFT_WARNING) { ?> + The package has all the elements to be imported. + + The package can't be imported. + +

          + + 0) { ?> +
          DETAILS
          +

          + +

          + + +
          TROUBLESHOOT
          +
            +
          • + A package with filtered elements cannot be imported to avoid a malfunction of the current site.
            + Create a new package in the site you want to import deactivating the filters on tables and/or files. +
          • +
          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/importer-version.php b/installer/dup-installer/templates/default/parts/validation/tests/importer-version.php new file mode 100644 index 00000000..57ab75ea --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/importer-version.php @@ -0,0 +1,43 @@ + DUPX_Validation_abstract_item::LV_SOFT_WARNING ? 'green' : 'red' ); +?> +
          STATUS
          +

          + DUPX_Validation_abstract_item::LV_SOFT_WARNING) { ?> + The version of Duplicator importer is compatible with the current package. + + Version of Duplicator importer is old compared to version of current package. + +

          + +
          DETAILS
          +

          + Importer version:
          + Package version: +

          + +
          TROUBLESHOOT
          +
            +
          • + The version of Duplicator in the importer site must be equal to or greater than the version with which the package was created.
            + Please update Duplicator to the latest version and restart the installation. +
          • +
          • + In case it is not possible to update the plugin, it is possible to perform a classic installation by starting the installer directly +
          • +
          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/managed-supported.php b/installer/dup-installer/templates/default/parts/validation/tests/managed-supported.php new file mode 100644 index 00000000..69efd923 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/managed-supported.php @@ -0,0 +1,22 @@ +

          + Managed hosting detected.
          + This managed hosting is supported. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/managed-tprefix.php b/installer/dup-installer/templates/default/parts/validation/tests/managed-tprefix.php new file mode 100644 index 00000000..e27f285a --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/managed-tprefix.php @@ -0,0 +1,26 @@ + +

          + + The prefix of the existing WordPress configuration table is equal of the prefix of the table of the source site where the package was created. + + The prefix of the existing WordPress configuration table does not match the prefix of the table of the source site where the package was created, + so the prefix will be changed to the managed hosting prefix. + +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/manual-extraction.php b/installer/dup-installer/templates/default/parts/validation/tests/manual-extraction.php new file mode 100644 index 00000000..b7429226 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/manual-extraction.php @@ -0,0 +1,35 @@ +

          + Deployment Path: getValue(PrmMng::PARAM_PATH_NEW)); ?> +

          +The installer has detected that the archive file has been extracted to the deployment path above. + +

          + The installer has detected that the archive file has been extracted to the deployment path above. The installer is going + to skip the extraction process by default. If you want to re-extract the archive file, switch to "Advanced" mode, and + under "Options" > "Extraction Mode" choose the preferred extraction mode. +

          + + + Note: This test looks for a file named dup-manual-extract__[HASH] in the directory. + If the file exists then this notice is shown. + The dup-manual-extract__[HASH] file is created with every archive and removed once the install is complete. For more details on this process see the + + manual extraction FAQ + . + diff --git a/installer/dup-installer/templates/default/parts/validation/tests/memory-limit.php b/installer/dup-installer/templates/default/parts/validation/tests/memory-limit.php new file mode 100644 index 00000000..3380400e --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/memory-limit.php @@ -0,0 +1,49 @@ + +

          +

          STATUS
          +

          + + + The memory_limit has a value of [] which is higher or equal to the suggested minimum of + []. + + + + The memory_limit has a value of [] + which is lower than the suggested minimum of []. + + +

          + +
          DETAILS
          +

          + +

          +The 'memory_limit' configuration in php.ini sets how much memory a script can use during its runtime. +When this value is lower than the suggested minimum of + the installer might run into issues. + +
          TROUBLESHOOT
          + diff --git a/installer/dup-installer/templates/default/parts/validation/tests/mysql-connect.php b/installer/dup-installer/templates/default/parts/validation/tests/mysql-connect.php new file mode 100644 index 00000000..29402893 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/mysql-connect.php @@ -0,0 +1,13 @@ +

          + Support for the PHP mysqli extension is required. + Please contact your hosting provider or server administrator to enable the mysqli extension. The detection for this call uses + the function_exists('mysqli_connect') call. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/open-basedir.php b/installer/dup-installer/templates/default/parts/validation/tests/open-basedir.php new file mode 100644 index 00000000..669f6eac --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/open-basedir.php @@ -0,0 +1,44 @@ + +

          + Open BaseDir: + DisabledEnabledEnabled +

          + + + The open_basedir configuration is disabled. + + All required archive paths were found in the open_basedir path list. + + If open_basedir is enabled and you're + having issues getting your site to install properly please work with your host and follow these steps to prevent issues: +
            +
          1. Disable the open_basedir setting in the php.ini file
          2. +
          3. If the host will not disable, then add the paths below to the open_basedir setting in the php.ini
            + + ""
            + +
          4. +
          5. Save the settings and restart the web server
          6. +
          + diff --git a/installer/dup-installer/templates/default/parts/validation/tests/overwrite-install.php b/installer/dup-installer/templates/default/parts/validation/tests/overwrite-install.php new file mode 100644 index 00000000..92a05942 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/overwrite-install.php @@ -0,0 +1,35 @@ +Deployment Path: getValue(PrmMng::PARAM_PATH_NEW)); ?> +

          + +Duplicator is in "Overwrite Install" mode because it has detected an existing WordPress site at the deployment path above. This mode allows for the installer +to be dropped directly into an existing WordPress site and overwrite its contents. Any content inside of the archive file +will overwrite the contents from the deployment path. To continue choose one of these options: + +
            +
          1. Ignore this notice and continue with the install if you want to overwrite this sites files.
          2. +
          3. Move this installer and archive to another empty directory path to keep this sites files.
          4. +
          + + + Notice: Existing content such as plugin/themes/images will still show-up after the install is complete if they did not already exist in + the archive file. For example if you have an SEO plugin in the current site but that same SEO plugin does not exist in the archive file + then that plugin will display as a disabled plugin after the install is completed. The same concept with themes and images applies. This will + not impact the sites operation, and the behavior is expected. + +

          + + Recommendation: It is recommended you only overwrite WordPress sites that have a minimal setup (plugins/themes). Typically a fresh install or a + cPanel 'one click' install is the best baseline to work from when using this mode but is not required. + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/package-age.php b/installer/dup-installer/templates/default/parts/validation/tests/package-age.php new file mode 100644 index 00000000..52cd40e6 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/package-age.php @@ -0,0 +1,17 @@ +

          + This package is day(s) old. + Packages older than days might be considered stale. It is recommended to build a new + package unless your aware of the content and its data. This is message is simply a recommendation. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/package-size.php b/installer/dup-installer/templates/default/parts/validation/tests/package-size.php new file mode 100644 index 00000000..21b38bc6 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/package-size.php @@ -0,0 +1,28 @@ + +

          + This package is . + You might run into issues installing packages bigger than MB with Duplicator Lite. + Duplicator Pro has support for larger sites. Confirmed migration of sites up to 100GB! +

          +

          + + Upgrade Now + +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/php-extensions.php b/installer/dup-installer/templates/default/parts/validation/tests/php-extensions.php new file mode 100644 index 00000000..3ffb5bbb --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/php-extensions.php @@ -0,0 +1,51 @@ + +
          DETAILS
          +

          + PHP extensions are compiled libraries which enable specific functions to be used in your PHP code. + This test checks if some of the most widely used extensions are + installed on your server. Extensions with an asterisk (*) are required for the installer to work. +

          + +
            + $extensionTest) : ?> +
          • + + + + * + : + + + Enabled + + Disabled + +
          • + +
          + +
          TROUBLESHOOT
          +

          + In case this test failed you have to install the required extension on your server or ask your hosting provider to + install it for you. +

          + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/php-version.php b/installer/dup-installer/templates/default/parts/validation/tests/php-version.php new file mode 100644 index 00000000..7c679637 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/php-version.php @@ -0,0 +1,46 @@ + +
          STATUS
          +

          + You are migrating site from PHP to PHP +

          + +
          DETAILS
          +

          + If the PHP version of your website is different than the PHP version of your package it may cause problems with the + functioning of your website. +

          + +

          + In case you are migrating your website from an older version of PHP to + PHP 8.x there is a relatively high probability + that some plugins or themes will not be compatible and may cause the overall website to not work. +

          + +
          TROUBLESHOOT
          +
            +
          • + We suggest proceeding in the "Advanced" mode and at Step 3 of the installation process under the "Plugins" tab + uncheck all plugins. In this way all plugins will be deactivated after the migration and you can then activate them + one-by-one to make sure everything works properly and be able to isolate offending plugins. +
          • +
          • + In case you are still experiencing issues after applying the fix above, the most likely cause of that is that + the active theme is not compatible with the new version of PHP. In this case too, it is suggested to + deactivate the theme to debug the issue. +
          • +
          + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/recovery.php b/installer/dup-installer/templates/default/parts/validation/tests/recovery.php new file mode 100644 index 00000000..3a24b77e --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/recovery.php @@ -0,0 +1,60 @@ + + Recovery URL: is valid. + + The Recovery Point is set but was created hours ago. +

          + In case of an error and subsequent restore all changes created after the restore point will be lost. +

          + + The Recovery Point is not set! + +

          You can continue but in the event you run into an install issue/error you will not be able to restore the current site. In some cases + this might be desirable. For example: +

          +
            +
          • This is a completely blank WordPress site and getting it back is simple.
          • +
          • Losing access to this site is no big deal and you know how to restore things on your own.
          • +
          + + +
          DETAILS
          +

          + Package age: hours +

          +

          + You can + + go back + + go back + + and set a new Recovery Point. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/replace-paths.php b/installer/dup-installer/templates/default/parts/validation/tests/replace-paths.php new file mode 100644 index 00000000..c5522261 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/replace-paths.php @@ -0,0 +1,33 @@ + +

          + The installer will not perform replacements on database PATHs but only on URLs. +

          + +
          DETAILS
          + + +

          + +

          + + +

          + Usually the database does not contain significant references to paths, so you can continue with the installation, + but some plugins may write absolute paths in the database and there may be some malfunctions. +

          + +
          TROUBLESHOOT
          +

          + If you experience any issues after the install you will have to manually replace paths in the database using phpMyAdmin or similar tools. +

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/rest-api.php b/installer/dup-installer/templates/default/parts/validation/tests/rest-api.php new file mode 100644 index 00000000..5fa84fec --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/rest-api.php @@ -0,0 +1,64 @@ + +
          STATUS
          + +

          + Successfully did a test REST API call to the WordPress backend. +

          + +

          + REST API call failed with the following message: +

          + + + +
          DETAILS
          +

          + This test makes sure the + WordPress REST API works properly, which is necessary to create new subsites. + +

          + +
          TROUBLESHOOT
          +

          + Some of the possible reasons why the WordPress REST API test might fail are the following: +

          + +
            +
          • + The rest API is disabled on WordPress. + To test whether the REST API works properly please visit the + following address + + and make sure you get a valid JSON output. + In case you don't get a JSON output, please make sure that you have permalinks enabled. Under "Settings" > "Permalinks" the + setting should not be set to "Plain". +
          • +
          • + SSL certificates are expired or invalid. + If this is the case please get in touch with your hosting provider to get everything working and up-to-date. +
          • +
          • + Basic Auth Authentication is enabled. If you have basic auth enabled, please go to + Duplicator ❯ Settings ❯ Packages ❯ Advanced Settings and + set the "Basic Auth" option to enabled and enter the username and password. After saving the settings restart the import process. +
          • +
          • + For more information on the topic please check out the + + REST API FAQ + . +
          • +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/siteground.php b/installer/dup-installer/templates/default/parts/validation/tests/siteground.php new file mode 100644 index 00000000..44280572 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/siteground.php @@ -0,0 +1,34 @@ + +
          STATUS
          +

          + You are installing on a SiteGround server. +

          + +
          DETAILS
          +

          + To overcome errors while extracting ZipArchive on SiteGround Server throttling has been automatically enabled. +

          + +
          TROUBLESHOOT
          +
            +
          • + In case you still get errors during the extraction please try switching the "Extraction Mode" to + "Shell Exec Zip" in Advanced mode under the "Options" section. +
          • +
          • + If the above doesn't work either, please consider creating a new package on the source using the DAF archive format. +
          • +
          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/timeout.php b/installer/dup-installer/templates/default/parts/validation/tests/timeout.php new file mode 100644 index 00000000..4bc2350b --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/timeout.php @@ -0,0 +1,44 @@ +

          + Archive Size: (detection limit is set at )
          + PHP max_execution_time: (zero means not limit)
          + PHP set_time_limit: SuccessFailed +

          +

          + The PHP max_execution_time + setting is used to determine how long a PHP process is allowed to run. + If the setting is too small and the archive file size is too large then PHP may not have enough + time to finish running before the process is killed causing a timeout. +

          +

          + Duplicator attempts to turn off the timeout by using the + set_time_limit setting. + If this notice shows as a warning then it is still safe to continue with the install. + However, if a timeout occurs then you will need to consider working with the max_execution_time setting or extracting the + archive file using the 'Manual Archive Extraction' method.   + + [Additional FAQ Help] + +

          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/tokenizer.php b/installer/dup-installer/templates/default/parts/validation/tests/tokenizer.php new file mode 100644 index 00000000..9aa42020 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/tokenizer.php @@ -0,0 +1,46 @@ + +
          STATUS
          + +

          + The function [token_get_all] exists on your server and can be used. +

          + +

          + The function [token_get_all] is disabled or not present on your server. +

          + + +
          DETAILS
          + +

          + The function [token_get_all] + is part of the tokenizer module + and is required for parsing the contents of the wp-config.php file. + To avoid problems during the installation the handling of the wp-config.php file has been disabled (the setting 'WordPress wp-config.php' + under Advanced Mode > Options > Advanced > Configuration files has been set to 'Do nothing'.) +

          + +
          TROUBLESHOOT
          + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/wordfence/wordfence-detected.php b/installer/dup-installer/templates/default/parts/validation/tests/wordfence/wordfence-detected.php new file mode 100644 index 00000000..91951502 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/wordfence/wordfence-detected.php @@ -0,0 +1,29 @@ + +
          STATUS
          +

          A Wordfence firewall instance was detected at .

          + +
          DETAILS
          +

          + The Wordfence Web Application Firewall is a PHP based, application level firewall that filters out malicious + requests to your site. Sometimes Wordfence returns false positives on requests done during the installation process, + because of which it might fail. +

          + +
          TROUBLESHOOT
          +

          + We recommend turning off the Wordfence firewall of the WordPress instance located at "" + during the installation process and reactivate it after the migration is completed. To deactivate the firewall follow these steps: +

          +
            +
          1. Go to WordPress Admin Dashboard ❯ Wordfence ❯ Firewall and click on the "Manage WAF".
          2. +
          3. Choose Web Application Firewall Status to the "Disabled" option.
          4. +
          5. Click on the "SAVE CHANGES" button and save the changed settings.
          6. +
          7. Wait for the changes to take place
          8. +
          diff --git a/installer/dup-installer/templates/default/parts/validation/tests/wordfence/wordfence-not-detected.php b/installer/dup-installer/templates/default/parts/validation/tests/wordfence/wordfence-not-detected.php new file mode 100644 index 00000000..ae77dbae --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/wordfence/wordfence-not-detected.php @@ -0,0 +1,11 @@ + +
          STATUS
          +

          Having Wordfence in a parent site can interfere with the install, however no such condition was detected.

          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/tests/writeable-checks.php b/installer/dup-installer/templates/default/parts/validation/tests/writeable-checks.php new file mode 100644 index 00000000..3b0dd1b7 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/tests/writeable-checks.php @@ -0,0 +1,134 @@ + +
          STATUS
          + +

          + Some folders do not have write permission, see details for more information. +

          + +

          + Write permissions granted for WordPress core directories. +

          + + +
          DETAILS
          + + + + + + + + + + + + + + + + + + + + + + +
          + Deployment Path: + + getValue(PrmMng::PARAM_PATH_NEW)); ?> +
          + Check folders permission: + + All existing folders have write permissionsSome folders do not have write permissions +
          + PHP files extraction on : + + + Pass + + + +
          + Suhosin Extension: + + DisabledEnabled +
          + PHP Safe Mode: + + DisabledEnabled +
          + + 0) { ?> +

          + Overwrite fails for these folders (change permissions or remove then restart): +

          +
          +
          +
          + + +
          TROUBLESHOOT
          + diff --git a/installer/dup-installer/templates/default/parts/validation/validate-area.php b/installer/dup-installer/templates/default/parts/validation/validate-area.php new file mode 100644 index 00000000..aacfe3a8 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/validate-area.php @@ -0,0 +1,25 @@ + + +
          +
          + +
          +
          + The system validation checks help to make sure the system is ready for install.
          + During installation the website will be in maintenance mode and not accessible to users. +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/validate-noresult.php b/installer/dup-installer/templates/default/parts/validation/validate-noresult.php new file mode 100644 index 00000000..7b9a3118 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/validate-noresult.php @@ -0,0 +1,14 @@ + +
          + + Pending setup validation!
          + Click the validate button to continue... +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/validation-category.php b/installer/dup-installer/templates/default/parts/validation/validation-category.php new file mode 100644 index 00000000..e12ed1f1 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/validation-category.php @@ -0,0 +1,31 @@ +getTestsCategory($category); +?> +
          +
          +
          + + +
          +
          +
          + $test)); + } + ?> +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/parts/validation/validation-result.php b/installer/dup-installer/templates/default/parts/validation/validation-result.php new file mode 100644 index 00000000..1d4b62d4 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/validation-result.php @@ -0,0 +1,30 @@ + +
          + getHtmlFormParam(PrmMng::PARAM_VALIDATION_SHOW_ALL); ?> +
          + 'General', + 'category' => DUPX_Validation_manager::CAT_GENERAL)); +dupxTplRender('parts/validation/validation-category', array( + 'title' => 'File System', + 'category' => DUPX_Validation_manager::CAT_FILESYSTEM)); +dupxTplRender('parts/validation/validation-category', array( + 'title' => 'PHP config', + 'category' => DUPX_Validation_manager::CAT_PHP)); +dupxTplRender('parts/validation/validation-category', array( + 'title' => 'Database', + 'category' => DUPX_Validation_manager::CAT_DATABASE)); diff --git a/installer/dup-installer/templates/default/parts/validation/validation-test.php b/installer/dup-installer/templates/default/parts/validation/validation-test.php new file mode 100644 index 00000000..a7e90891 --- /dev/null +++ b/installer/dup-installer/templates/default/parts/validation/validation-test.php @@ -0,0 +1,31 @@ +display()) { + return; +} + +$validationLevel = PrmMng::getInstance()->getValue(PrmMng::PARAM_VALIDATION_LEVEL); +$open = ($test->test() <= DUPX_Validation_abstract_item::LV_HARD_WARNING && $test->test() <= $validationLevel); +$icon = $open ? 'fa-caret-down' : 'fa-caret-right'; +?> +
          +
          + getTitle()); ?> + +
          +
          + getContent(); ?> +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/dupx-functions.php b/installer/dup-installer/templates/default/scripts/dupx-functions.php new file mode 100644 index 00000000..cac0ead2 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/dupx-functions.php @@ -0,0 +1,23 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/confirm-dialog.php b/installer/dup-installer/templates/default/scripts/modules/confirm-dialog.php new file mode 100644 index 00000000..ac7a39b7 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/confirm-dialog.php @@ -0,0 +1,74 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/db-charset.php b/installer/dup-installer/templates/default/scripts/modules/db-charset.php new file mode 100644 index 00000000..7f7786c0 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/db-charset.php @@ -0,0 +1,43 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/db-install.php b/installer/dup-installer/templates/default/scripts/modules/db-install.php new file mode 100644 index 00000000..b4f43def --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/db-install.php @@ -0,0 +1,120 @@ + + diff --git a/installer/dup-installer/templates/default/scripts/modules/db-test.php b/installer/dup-installer/templates/default/scripts/modules/db-test.php new file mode 100644 index 00000000..4c84f5a2 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/db-test.php @@ -0,0 +1,109 @@ +getMode() === DUPX_InstallerState::MODE_OVR_INSTALL) { + $overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA); + $ovr_dbhost = $overwriteData['dbhost']; + $ovr_dbname = $overwriteData['dbname']; + $ovr_dbuser = $overwriteData['dbuser']; + $ovr_dbpass = $overwriteData['dbpass']; +} else { + $ovr_dbhost = ''; + $ovr_dbname = ''; + $ovr_dbuser = ''; + $ovr_dbpass = ''; +} +?> + diff --git a/installer/dup-installer/templates/default/scripts/modules/extraction-module.php b/installer/dup-installer/templates/default/scripts/modules/extraction-module.php new file mode 100644 index 00000000..b2c27cb1 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/extraction-module.php @@ -0,0 +1,169 @@ + + diff --git a/installer/dup-installer/templates/default/scripts/modules/final-tests.php b/installer/dup-installer/templates/default/scripts/modules/final-tests.php new file mode 100644 index 00000000..72f6e0a7 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/final-tests.php @@ -0,0 +1,116 @@ + + diff --git a/installer/dup-installer/templates/default/scripts/modules/new-admin-user.php b/installer/dup-installer/templates/default/scripts/modules/new-admin-user.php new file mode 100644 index 00000000..7003c07c --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/new-admin-user.php @@ -0,0 +1,30 @@ + + + diff --git a/installer/dup-installer/templates/default/scripts/modules/package-deploy.php b/installer/dup-installer/templates/default/scripts/modules/package-deploy.php new file mode 100644 index 00000000..296e075c --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/package-deploy.php @@ -0,0 +1,36 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/page-components.php b/installer/dup-installer/templates/default/scripts/modules/page-components.php new file mode 100644 index 00000000..91749b83 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/page-components.php @@ -0,0 +1,44 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/params-module.php b/installer/dup-installer/templates/default/scripts/modules/params-module.php new file mode 100644 index 00000000..431b5c5a --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/params-module.php @@ -0,0 +1,331 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/progress-bar.php b/installer/dup-installer/templates/default/scripts/modules/progress-bar.php new file mode 100644 index 00000000..7363310b --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/progress-bar.php @@ -0,0 +1,119 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/site-replace-and-update.php b/installer/dup-installer/templates/default/scripts/modules/site-replace-and-update.php new file mode 100644 index 00000000..5ede059f --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/site-replace-and-update.php @@ -0,0 +1,97 @@ + + diff --git a/installer/dup-installer/templates/default/scripts/modules/system-validation-module.php b/installer/dup-installer/templates/default/scripts/modules/system-validation-module.php new file mode 100644 index 00000000..fc1edea6 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/system-validation-module.php @@ -0,0 +1,60 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/modules/top-page-messages.php b/installer/dup-installer/templates/default/scripts/modules/top-page-messages.php new file mode 100644 index 00000000..5aa27785 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/modules/top-page-messages.php @@ -0,0 +1,24 @@ + + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/secure-init.php b/installer/dup-installer/templates/default/scripts/secure-init.php new file mode 100644 index 00000000..4e4f712a --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/secure-init.php @@ -0,0 +1,55 @@ + 'ctrl-step1', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('ctrl-step1'), + PrmMng::PARAM_STEP_ACTION => DUPX_CTRL::ACTION_STEP_INIZIALIZED +); +?> + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/step1-deploy.php b/installer/dup-installer/templates/default/scripts/step1-deploy.php new file mode 100644 index 00000000..500fb869 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/step1-deploy.php @@ -0,0 +1,22 @@ + 'ctrl-step2', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('ctrl-step2') +); +?> + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/step1-init.php b/installer/dup-installer/templates/default/scripts/step1-init.php new file mode 100644 index 00000000..78971126 --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/step1-init.php @@ -0,0 +1,339 @@ + + + 'ctrl-step3', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('ctrl-step3') +); +?> diff --git a/installer/dup-installer/templates/default/scripts/step3-init.php b/installer/dup-installer/templates/default/scripts/step3-init.php new file mode 100644 index 00000000..b89dc08a --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/step3-init.php @@ -0,0 +1,114 @@ + 'ctrl-step4', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('ctrl-step4') +); + +dupxTplRender('scripts/modules/new-admin-user'); +?> + \ No newline at end of file diff --git a/installer/dup-installer/templates/default/scripts/step4-init.php b/installer/dup-installer/templates/default/scripts/step4-init.php new file mode 100644 index 00000000..ed48668d --- /dev/null +++ b/installer/dup-installer/templates/default/scripts/step4-init.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/body/body-tag.php b/installer/dup-installer/templates/import-advanced/pages-parts/body/body-tag.php new file mode 100644 index 00000000..321c33e9 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/body/body-tag.php @@ -0,0 +1,11 @@ + + diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/head/css-template-custom.php b/installer/dup-installer/templates/import-advanced/pages-parts/head/css-template-custom.php new file mode 100644 index 00000000..36ebec64 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/head/css-template-custom.php @@ -0,0 +1,158 @@ +getValue(PrmMng::PARAM_FROM_SITE_IMPORT_INFO); + +if (isset($importSiteInfo['color-scheme'])) { + $colorScheme = $importSiteInfo['color-scheme']; +} else { + $colorScheme = array(); + $colorScheme['colors'] = array('#222', '#333', '#0073aa', '#00a0d2'); +} +$colorPrimaryButton = isset($importSiteInfo['color-primary-button']) ? $importSiteInfo['color-primary-button'] : $colorScheme->colors[2]; +?> + \ No newline at end of file diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step1/actions/next.php b/installer/dup-installer/templates/import-advanced/pages-parts/step1/actions/next.php new file mode 100644 index 00000000..a15c9dee --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step1/actions/next.php @@ -0,0 +1,35 @@ +getValue(PrmMng::PARAM_FROM_SITE_IMPORT_INFO); +$importPage = isset($importSiteInfo['import_page']) ? $importSiteInfo['import_page'] : false; + +?> +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step1/actions/switch-template.php b/installer/dup-installer/templates/import-advanced/pages-parts/step1/actions/switch-template.php new file mode 100644 index 00000000..44a8b688 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step1/actions/switch-template.php @@ -0,0 +1,25 @@ + +
          + + + + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step1/info-tabs/restore-backup.php b/installer/dup-installer/templates/import-advanced/pages-parts/step1/info-tabs/restore-backup.php new file mode 100644 index 00000000..69856c82 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step1/info-tabs/restore-backup.php @@ -0,0 +1,19 @@ + +
          +

          + Site Overwrite Notice +

          +

          + This process will overwrite the entire site you're currently logged into. + All plugins, themes, content and data will be replaced with the content found in the archive file. + The database credentials of the imported site will be used for the database overwrite by default. +

          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step1/step-title.php b/installer/dup-installer/templates/import-advanced/pages-parts/step1/step-title.php new file mode 100644 index 00000000..85b399a3 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step1/step-title.php @@ -0,0 +1,15 @@ + 'Step 1 of 4: Extract Uploaded Package
          This step will extract package.
          ', + 'showInstallerMode' => false, + 'showSwitchView' => true, + 'showInstallerLog' => true +)); diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step2/step-title.php b/installer/dup-installer/templates/import-advanced/pages-parts/step2/step-title.php new file mode 100644 index 00000000..68acc0eb --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step2/step-title.php @@ -0,0 +1,16 @@ + 'Step 2 of 4: ' . + 'Install Database
          This step will install the database from the archive.
          ', + 'showInstallerMode' => false, + 'showSwitchView' => false, + 'showInstallerLog' => true +)); diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step3/step-title.php b/installer/dup-installer/templates/import-advanced/pages-parts/step3/step-title.php new file mode 100644 index 00000000..9fe9756b --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step3/step-title.php @@ -0,0 +1,16 @@ + 'Step 3 of 4: ' . + 'Update Data
          This step will update the database and config files to match your new sites values.
          ', + 'showInstallerMode' => false, + 'showSwitchView' => false, + 'showInstallerLog' => true +)); diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step4/actions/recovery-point-button.php b/installer/dup-installer/templates/import-advanced/pages-parts/step4/actions/recovery-point-button.php new file mode 100644 index 00000000..1e765bb8 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step4/actions/recovery-point-button.php @@ -0,0 +1,35 @@ +getValue(PrmMng::PARAM_RECOVERY_LINK); + +if (empty($recoveryLink)) { + return; +} +?> +
          +
          +
          Restore Options
          +
          + +
          + The new import has finished. + Optionally this site can be restored to its previous recovery point by running the recovery wizard. + If no recovery is needed then this option can be ignored. +
          +
          +
          +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/import-advanced/pages-parts/step4/main.php b/installer/dup-installer/templates/import-advanced/pages-parts/step4/main.php new file mode 100644 index 00000000..0c78b4b4 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/pages-parts/step4/main.php @@ -0,0 +1,15 @@ + 'Step 4 of 4: Import Finished', + 'showInstallerMode' => false, + 'showSwitchView' => false, + 'showInstallerLog' => true +)); diff --git a/installer/dup-installer/templates/import-advanced/parts/top-header.php b/installer/dup-installer/templates/import-advanced/parts/top-header.php new file mode 100644 index 00000000..63817679 --- /dev/null +++ b/installer/dup-installer/templates/import-advanced/parts/top-header.php @@ -0,0 +1,8 @@ + +
          STATUS
          +

          A Wordfence firewall instance was detected at .

          + +
          DETAILS
          +

          + The Wordfence Web Application Firewall is a PHP based, application level firewall that filters out malicious + requests to your site. Sometimes Wordfence returns false positives on requests done during the import, because of which + the import might fail. +

          + +
          TROUBLESHOOT
          +

          + If you have Wordfence installed on the current WordPress instance (or the current WordPress instance is located in a + subdirectory of another WordPress instance which has Wordfence installed) we recommend turning it off during the import + and reactivating it after the import is completed. To deactivate the firewall follow these steps: +

          +
            +
          1. Go to WordPress Admin Dashboard ❯ Wordfence ❯ Firewall and click on the "Manage WAF".
          2. +
          3. Choose Web Application Firewall Status to the "Disabled" option.
          4. +
          5. Click on the "SAVE CHANGES" button and save the changed settings.
          6. +
          7. Wait for the changes to take place
          8. +
          diff --git a/installer/dup-installer/templates/import-base/pages-parts/step1/actions/switch-template.php b/installer/dup-installer/templates/import-base/pages-parts/step1/actions/switch-template.php new file mode 100644 index 00000000..8a5ae08c --- /dev/null +++ b/installer/dup-installer/templates/import-base/pages-parts/step1/actions/switch-template.php @@ -0,0 +1,30 @@ + +
          + + + + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/import-base/pages-parts/step1/base-setup.php b/installer/dup-installer/templates/import-base/pages-parts/step1/base-setup.php new file mode 100644 index 00000000..f7ed7324 --- /dev/null +++ b/installer/dup-installer/templates/import-base/pages-parts/step1/base-setup.php @@ -0,0 +1,15 @@ + +
          + Setup +
          +
          + +
          \ No newline at end of file diff --git a/installer/dup-installer/templates/import-base/pages-parts/step1/options.php b/installer/dup-installer/templates/import-base/pages-parts/step1/options.php new file mode 100644 index 00000000..63817679 --- /dev/null +++ b/installer/dup-installer/templates/import-base/pages-parts/step1/options.php @@ -0,0 +1,8 @@ + 'Step 1 of 2: ' . + 'Deploy Uploaded Package
          This step will extract the archive file, install & update the database.
          ', + 'showInstallerMode' => false, + 'showSwitchView' => true, + 'showInstallerLog' => true +)); diff --git a/installer/dup-installer/templates/import-base/pages-parts/step4/step-title.php b/installer/dup-installer/templates/import-base/pages-parts/step4/step-title.php new file mode 100644 index 00000000..852e84ab --- /dev/null +++ b/installer/dup-installer/templates/import-base/pages-parts/step4/step-title.php @@ -0,0 +1,15 @@ + 'Step 2 of 2: Import Finished', + 'showInstallerMode' => false, + 'showSwitchView' => false, + 'showInstallerLog' => true +)); diff --git a/installer/dup-installer/templates/import-base/parts/top-header.php b/installer/dup-installer/templates/import-base/parts/top-header.php new file mode 100644 index 00000000..63817679 --- /dev/null +++ b/installer/dup-installer/templates/import-base/parts/top-header.php @@ -0,0 +1,8 @@ + +
          STATUS
          +

          A Wordfence firewall instance was detected at .

          + +
          DETAILS
          +

          + The Wordfence Web Application Firewall is a PHP based, application level firewall that filters out malicious + requests to your site. Sometimes Wordfence returns false positives on requests done during the import, because of which + the import might fail. +

          + +
          TROUBLESHOOT
          +

          + If you have Wordfence installed on the current WordPress instance (or the current WordPress instance is located in a + subdirectory of another WordPress instance which has Wordfence installed) we recommend turning it off during the import + and reactivating it after the import is completed. To deactivate the firewall follow these steps: +

          +
            +
          1. Go to WordPress Admin Dashboard ❯ Wordfence ❯ Firewall and click on the "Manage WAF".
          2. +
          3. Choose Web Application Firewall Status to the "Disabled" option.
          4. +
          5. Click on the "SAVE CHANGES" button and save the changed settings.
          6. +
          7. Wait for the changes to take place
          8. +
          diff --git a/installer/dup-installer/templates/import-base/scripts/step1-deploy.php b/installer/dup-installer/templates/import-base/scripts/step1-deploy.php new file mode 100644 index 00000000..36c030bb --- /dev/null +++ b/installer/dup-installer/templates/import-base/scripts/step1-deploy.php @@ -0,0 +1,22 @@ + 'ctrl-step4', + DUPX_Security::CTRL_TOKEN => DUPX_CSRF::generate('ctrl-step4') +); +?> + \ No newline at end of file diff --git a/installer/dup-installer/vendor/.htaccess b/installer/dup-installer/vendor/.htaccess new file mode 100644 index 00000000..a58990b7 --- /dev/null +++ b/installer/dup-installer/vendor/.htaccess @@ -0,0 +1,9 @@ + + Order Deny,Allow + Deny from all + + + + Order Allow,Deny + Allow from all + \ No newline at end of file diff --git a/installer/dup-installer/vendor/index.php b/installer/dup-installer/vendor/index.php new file mode 100644 index 00000000..bcebfd76 --- /dev/null +++ b/installer/dup-installer/vendor/index.php @@ -0,0 +1,3 @@ + .select2-results__options { + max-height: 200px; + overflow-y: auto; } + +.select2-container--default .select2-results__option[role=group] { + padding: 0; } + +.select2-container--default .select2-results__option[aria-disabled=true] { + color: #999; } + +.select2-container--default .select2-results__option[aria-selected=true] { + background-color: #ddd; } + +.select2-container--default .select2-results__option .select2-results__option { + padding-left: 1em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; } + +.select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: #5897fb; + color: white; } + +.select2-container--default .select2-results__group { + cursor: default; + display: block; + padding: 6px; } + +.select2-container--classic .select2-selection--single { + background-color: #f7f7f7; + border: 1px solid #aaa; + border-radius: 4px; + outline: 0; + background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%); + background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%); + background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); } + .select2-container--classic .select2-selection--single:focus { + border: 1px solid #5897fb; } + .select2-container--classic .select2-selection--single .select2-selection__rendered { + color: #444; + line-height: 28px; } + .select2-container--classic .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin-right: 10px; } + .select2-container--classic .select2-selection--single .select2-selection__placeholder { + color: #999; } + .select2-container--classic .select2-selection--single .select2-selection__arrow { + background-color: #ddd; + border: none; + border-left: 1px solid #aaa; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; + background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%); + background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%); + background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); } + .select2-container--classic .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; } + +.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; } + +.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow { + border: none; + border-right: 1px solid #aaa; + border-radius: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + left: 1px; + right: auto; } + +.select2-container--classic.select2-container--open .select2-selection--single { + border: 1px solid #5897fb; } + .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow { + background: transparent; + border: none; } + .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; } + +.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; + background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); } + +.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%); + background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%); + background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); } + +.select2-container--classic .select2-selection--multiple { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + cursor: text; + outline: 0; } + .select2-container--classic .select2-selection--multiple:focus { + border: 1px solid #5897fb; } + .select2-container--classic .select2-selection--multiple .select2-selection__rendered { + list-style: none; + margin: 0; + padding: 0 5px; } + .select2-container--classic .select2-selection--multiple .select2-selection__clear { + display: none; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice { + background-color: #e4e4e4; + border: 1px solid #aaa; + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove { + color: #888; + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover { + color: #555; } + +.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + float: right; + margin-left: 5px; + margin-right: auto; } + +.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; } + +.select2-container--classic.select2-container--open .select2-selection--multiple { + border: 1px solid #5897fb; } + +.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--classic .select2-search--dropdown .select2-search__field { + border: 1px solid #aaa; + outline: 0; } + +.select2-container--classic .select2-search--inline .select2-search__field { + outline: 0; + box-shadow: none; } + +.select2-container--classic .select2-dropdown { + background-color: white; + border: 1px solid transparent; } + +.select2-container--classic .select2-dropdown--above { + border-bottom: none; } + +.select2-container--classic .select2-dropdown--below { + border-top: none; } + +.select2-container--classic .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; } + +.select2-container--classic .select2-results__option[role=group] { + padding: 0; } + +.select2-container--classic .select2-results__option[aria-disabled=true] { + color: grey; } + +.select2-container--classic .select2-results__option--highlighted[aria-selected] { + background-color: #3875d7; + color: white; } + +.select2-container--classic .select2-results__group { + cursor: default; + display: block; + padding: 6px; } + +.select2-container--classic.select2-container--open .select2-dropdown { + border-color: #5897fb; } diff --git a/installer/dup-installer/vendor/select2/css/select2.min.css b/installer/dup-installer/vendor/select2/css/select2.min.css new file mode 100644 index 00000000..7c18ad59 --- /dev/null +++ b/installer/dup-installer/vendor/select2/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/installer/dup-installer/vendor/select2/js/i18n/af.js b/installer/dup-installer/vendor/select2/js/i18n/af.js new file mode 100644 index 00000000..32e5ac7d --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/af.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Verwyders asseblief "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Voer asseblief "+(e.minimum-e.input.length)+" of meer karakters"},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var n="Kies asseblief net "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"},removeAllItems:function(){return"Verwyder alle items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ar.js b/installer/dup-installer/vendor/select2/js/i18n/ar.js new file mode 100644 index 00000000..64e1caad --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ar.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(n){return"الرجاء حذف "+(n.input.length-n.maximum)+" عناصر"},inputTooShort:function(n){return"الرجاء إضافة "+(n.minimum-n.input.length)+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(n){return"تستطيع إختيار "+n.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"},removeAllItems:function(){return"قم بإزالة كل العناصر"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/az.js b/installer/dup-installer/vendor/select2/js/i18n/az.js new file mode 100644 index 00000000..1d52c260 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/az.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/az",[],function(){return{inputTooLong:function(n){return n.input.length-n.maximum+" simvol silin"},inputTooShort:function(n){return n.minimum-n.input.length+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(n){return"Sadəcə "+n.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"},removeAllItems:function(){return"Bütün elementləri sil"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/bg.js b/installer/dup-installer/vendor/select2/js/i18n/bg.js new file mode 100644 index 00000000..73b730a7 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/bg.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bg",[],function(){return{inputTooLong:function(n){var e=n.input.length-n.maximum,u="Моля въведете с "+e+" по-малко символ";return e>1&&(u+="a"),u},inputTooShort:function(n){var e=n.minimum-n.input.length,u="Моля въведете още "+e+" символ";return e>1&&(u+="a"),u},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(n){var e="Можете да направите до "+n.maximum+" ";return n.maximum>1?e+="избора":e+="избор",e},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"},removeAllItems:function(){return"Премахнете всички елементи"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/bn.js b/installer/dup-installer/vendor/select2/js/i18n/bn.js new file mode 100644 index 00000000..2d17b9d8 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/bn.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bn",[],function(){return{errorLoading:function(){return"ফলাফলগুলি লোড করা যায়নি।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।";return 1!=e&&(u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।"),u},inputTooShort:function(n){return n.minimum-n.input.length+" টি অক্ষর অথবা অধিক অক্ষর লিখুন।"},loadingMore:function(){return"আরো ফলাফল লোড হচ্ছে ..."},maximumSelected:function(n){var e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।";return 1!=n.maximum&&(e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।"),e},noResults:function(){return"কোন ফলাফল পাওয়া যায়নি।"},searching:function(){return"অনুসন্ধান করা হচ্ছে ..."}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/bs.js b/installer/dup-installer/vendor/select2/js/i18n/bs.js new file mode 100644 index 00000000..46b084d7 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/bs.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/bs",[],function(){function e(e,n,r,t){return e%10==1&&e%100!=11?n:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(n){var r=n.input.length-n.maximum,t="Obrišite "+r+" simbol";return t+=e(r,"","a","a")},inputTooShort:function(n){var r=n.minimum-n.input.length,t="Ukucajte bar još "+r+" simbol";return t+=e(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(n){var r="Možete izabrati samo "+n.maximum+" stavk";return r+=e(n.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Uklonite sve stavke"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ca.js b/installer/dup-installer/vendor/select2/js/i18n/ca.js new file mode 100644 index 00000000..82dbbb7a --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ca.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Si us plau, elimina "+n+" car";return r+=1==n?"àcter":"àcters"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Si us plau, introdueix "+n+" car";return r+=1==n?"àcter":"àcters"},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var n="Només es pot seleccionar "+e.maximum+" element";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"},removeAllItems:function(){return"Treu tots els elements"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/cs.js b/installer/dup-installer/vendor/select2/js/i18n/cs.js new file mode 100644 index 00000000..7116d6c1 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/cs.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/cs",[],function(){function e(e,n){switch(e){case 2:return n?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadejte o jeden znak méně.":t<=4?"Prosím, zadejte o "+e(t,!0)+" znaky méně.":"Prosím, zadejte o "+t+" znaků méně."},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadejte ještě jeden znak.":t<=4?"Prosím, zadejte ještě další "+e(t,!0)+" znaky.":"Prosím, zadejte ještě dalších "+t+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(n){var t=n.maximum;return 1==t?"Můžete zvolit jen jednu položku.":t<=4?"Můžete zvolit maximálně "+e(t,!1)+" položky.":"Můžete zvolit maximálně "+t+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"},removeAllItems:function(){return"Odstraňte všechny položky"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/da.js b/installer/dup-installer/vendor/select2/js/i18n/da.js new file mode 100644 index 00000000..cda32c34 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/da.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){return"Angiv venligst "+(e.input.length-e.maximum)+" tegn mindre"},inputTooShort:function(e){return"Angiv venligst "+(e.minimum-e.input.length)+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var n="Du kan kun vælge "+e.maximum+" emne";return 1!=e.maximum&&(n+="r"),n},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/de.js b/installer/dup-installer/vendor/select2/js/i18n/de.js new file mode 100644 index 00000000..c2e61e58 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/de.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){return"Bitte "+(e.input.length-e.maximum)+" Zeichen weniger eingeben"},inputTooShort:function(e){return"Bitte "+(e.minimum-e.input.length)+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var n="Sie können nur "+e.maximum+" Element";return 1!=e.maximum&&(n+="e"),n+=" auswählen"},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"},removeAllItems:function(){return"Entferne alle Elemente"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/dsb.js b/installer/dup-installer/vendor/select2/js/i18n/dsb.js new file mode 100644 index 00000000..02f283ab --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/dsb.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/dsb",[],function(){var n=["znamuško","znamušce","znamuška","znamuškow"],e=["zapisk","zapiska","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Pšosym lašuj "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Pšosym zapódaj nanejmjenjej "+a+" "+u(a,n)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(n){return"Móžoš jano "+n.maximum+" "+u(n.maximum,e)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/el.js b/installer/dup-installer/vendor/select2/js/i18n/el.js new file mode 100644 index 00000000..d4922a1d --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/el.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(n){var e=n.input.length-n.maximum,u="Παρακαλώ διαγράψτε "+e+" χαρακτήρ";return 1==e&&(u+="α"),1!=e&&(u+="ες"),u},inputTooShort:function(n){return"Παρακαλώ συμπληρώστε "+(n.minimum-n.input.length)+" ή περισσότερους χαρακτήρες"},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(n){var e="Μπορείτε να επιλέξετε μόνο "+n.maximum+" επιλογ";return 1==n.maximum&&(e+="ή"),1!=n.maximum&&(e+="ές"),e},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"},removeAllItems:function(){return"Καταργήστε όλα τα στοιχεία"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/en.js b/installer/dup-installer/vendor/select2/js/i18n/en.js new file mode 100644 index 00000000..3b192857 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/en.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Please delete "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Please enter "+(e.minimum-e.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var n="You can only select "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No results found"},searching:function(){return"Searching…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/es.js b/installer/dup-installer/vendor/select2/js/i18n/es.js new file mode 100644 index 00000000..68afd6d2 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/es.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Por favor, elimine "+n+" car";return r+=1==n?"ácter":"acteres"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Por favor, introduzca "+n+" car";return r+=1==n?"ácter":"acteres"},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var n="Sólo puede seleccionar "+e.maximum+" elemento";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Eliminar todos los elementos"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/et.js b/installer/dup-installer/vendor/select2/js/i18n/et.js new file mode 100644 index 00000000..070b61a2 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/et.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var n=e.input.length-e.maximum,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" vähem"},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" rohkem"},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var n="Saad vaid "+e.maximum+" tulemus";return 1==e.maximum?n+="e":n+="t",n+=" valida"},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"},removeAllItems:function(){return"Eemalda kõik esemed"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/eu.js b/installer/dup-installer/vendor/select2/js/i18n/eu.js new file mode 100644 index 00000000..90d5e73f --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/eu.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gutxiago"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gehiago"},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return 1===e.maximum?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"},removeAllItems:function(){return"Kendu elementu guztiak"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/fa.js b/installer/dup-installer/vendor/select2/js/i18n/fa.js new file mode 100644 index 00000000..e1ffdbed --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/fa.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(n){return"لطفاً "+(n.input.length-n.maximum)+" کاراکتر را حذف نمایید"},inputTooShort:function(n){return"لطفاً تعداد "+(n.minimum-n.input.length)+" کاراکتر یا بیشتر وارد نمایید"},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(n){return"شما تنها می‌توانید "+n.maximum+" آیتم را انتخاب نمایید"},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."},removeAllItems:function(){return"همه موارد را حذف کنید"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/fi.js b/installer/dup-installer/vendor/select2/js/i18n/fi.js new file mode 100644 index 00000000..ffed1247 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/fi.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(n){return"Ole hyvä ja anna "+(n.input.length-n.maximum)+" merkkiä vähemmän"},inputTooShort:function(n){return"Ole hyvä ja anna "+(n.minimum-n.input.length)+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(n){return"Voit valita ainoastaan "+n.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"},removeAllItems:function(){return"Poista kaikki kohteet"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/fr.js b/installer/dup-installer/vendor/select2/js/i18n/fr.js new file mode 100644 index 00000000..dd02f973 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/fr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var n=e.input.length-e.maximum;return"Supprimez "+n+" caractère"+(n>1?"s":"")},inputTooShort:function(e){var n=e.minimum-e.input.length;return"Saisissez au moins "+n+" caractère"+(n>1?"s":"")},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1?"s":"")},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"},removeAllItems:function(){return"Supprimer tous les éléments"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/gl.js b/installer/dup-installer/vendor/select2/js/i18n/gl.js new file mode 100644 index 00000000..208a0057 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/gl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var n=e.input.length-e.maximum;return 1===n?"Elimine un carácter":"Elimine "+n+" caracteres"},inputTooShort:function(e){var n=e.minimum-e.input.length;return 1===n?"Engada un carácter":"Engada "+n+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return 1===e.maximum?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Elimina todos os elementos"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/he.js b/installer/dup-installer/vendor/select2/js/i18n/he.js new file mode 100644 index 00000000..25a8805a --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/he.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="נא למחוק ";return r+=1===e?"תו אחד":e+" תווים"},inputTooShort:function(n){var e=n.minimum-n.input.length,r="נא להכניס ";return r+=1===e?"תו אחד":e+" תווים",r+=" או יותר"},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(n){var e="באפשרותך לבחור עד ";return 1===n.maximum?e+="פריט אחד":e+=n.maximum+" פריטים",e},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"},removeAllItems:function(){return"הסר את כל הפריטים"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/hi.js b/installer/dup-installer/vendor/select2/js/i18n/hi.js new file mode 100644 index 00000000..f3ed7984 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/hi.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(n){var e=n.input.length-n.maximum,r=e+" अक्षर को हटा दें";return e>1&&(r=e+" अक्षरों को हटा दें "),r},inputTooShort:function(n){return"कृपया "+(n.minimum-n.input.length)+" या अधिक अक्षर दर्ज करें"},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(n){return"आप केवल "+n.maximum+" आइटम का चयन कर सकते हैं"},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."},removeAllItems:function(){return"सभी वस्तुओं को हटा दें"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/hr.js b/installer/dup-installer/vendor/select2/js/i18n/hr.js new file mode 100644 index 00000000..cb3268db --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/hr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hr",[],function(){function n(n){var e=" "+n+" znak";return n%10<5&&n%10>0&&(n%100<5||n%100>19)?n%10>1&&(e+="a"):e+="ova",e}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(e){return"Unesite "+n(e.input.length-e.maximum)},inputTooShort:function(e){return"Unesite još "+n(e.minimum-e.input.length)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(n){return"Maksimalan broj odabranih stavki je "+n.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Ukloni sve stavke"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/hsb.js b/installer/dup-installer/vendor/select2/js/i18n/hsb.js new file mode 100644 index 00000000..3d5bf09d --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/hsb.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hsb",[],function(){var n=["znamješko","znamješce","znamješka","znamješkow"],e=["zapisk","zapiskaj","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Prošu zhašej "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Prošu zapodaj znajmjeńša "+a+" "+u(a,n)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(n){return"Móžeš jenož "+n.maximum+" "+u(n.maximum,e)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/hu.js b/installer/dup-installer/vendor/select2/js/i18n/hu.js new file mode 100644 index 00000000..4893aa2f --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/hu.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){return"Túl hosszú. "+(e.input.length-e.maximum)+" karakterrel több, mint kellene."},inputTooShort:function(e){return"Túl rövid. Még "+(e.minimum-e.input.length)+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"},removeAllItems:function(){return"Távolítson el minden elemet"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/hy.js b/installer/dup-installer/vendor/select2/js/i18n/hy.js new file mode 100644 index 00000000..82300071 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/hy.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(n){return"Խնդրում ենք հեռացնել "+(n.input.length-n.maximum)+" նշան"},inputTooShort:function(n){return"Խնդրում ենք մուտքագրել "+(n.minimum-n.input.length)+" կամ ավել նշաններ"},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(n){return"Դուք կարող եք ընտրել առավելագույնը "+n.maximum+" կետ"},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"},removeAllItems:function(){return"Հեռացնել բոլոր տարրերը"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/id.js b/installer/dup-installer/vendor/select2/js/i18n/id.js new file mode 100644 index 00000000..4a0b3bf0 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/id.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(n){return"Hapuskan "+(n.input.length-n.maximum)+" huruf"},inputTooShort:function(n){return"Masukkan "+(n.minimum-n.input.length)+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(n){return"Anda hanya dapat memilih "+n.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Hapus semua item"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/is.js b/installer/dup-installer/vendor/select2/js/i18n/is.js new file mode 100644 index 00000000..cca5bbec --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/is.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/is",[],function(){return{inputTooLong:function(n){var t=n.input.length-n.maximum,e="Vinsamlegast styttið texta um "+t+" staf";return t<=1?e:e+"i"},inputTooShort:function(n){var t=n.minimum-n.input.length,e="Vinsamlegast skrifið "+t+" staf";return t>1&&(e+="i"),e+=" í viðbót"},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(n){return"Þú getur aðeins valið "+n.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"},removeAllItems:function(){return"Fjarlægðu öll atriði"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/it.js b/installer/dup-installer/vendor/select2/js/i18n/it.js new file mode 100644 index 00000000..507c7d9f --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/it.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Per favore cancella "+n+" caratter";return t+=1!==n?"i":"e"},inputTooShort:function(e){return"Per favore inserisci "+(e.minimum-e.input.length)+" o più caratteri"},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var n="Puoi selezionare solo "+e.maximum+" element";return 1!==e.maximum?n+="i":n+="o",n},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"},removeAllItems:function(){return"Rimuovi tutti gli oggetti"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ja.js b/installer/dup-installer/vendor/select2/js/i18n/ja.js new file mode 100644 index 00000000..451025e2 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ja.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(n){return n.input.length-n.maximum+" 文字を削除してください"},inputTooShort:function(n){return"少なくとも "+(n.minimum-n.input.length)+" 文字を入力してください"},loadingMore:function(){return"読み込み中…"},maximumSelected:function(n){return n.maximum+" 件しか選択できません"},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"},removeAllItems:function(){return"すべてのアイテムを削除"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ka.js b/installer/dup-installer/vendor/select2/js/i18n/ka.js new file mode 100644 index 00000000..60c593b7 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ka.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ka",[],function(){return{errorLoading:function(){return"მონაცემების ჩატვირთვა შეუძლებელია."},inputTooLong:function(n){return"გთხოვთ აკრიფეთ "+(n.input.length-n.maximum)+" სიმბოლოთი ნაკლები"},inputTooShort:function(n){return"გთხოვთ აკრიფეთ "+(n.minimum-n.input.length)+" სიმბოლო ან მეტი"},loadingMore:function(){return"მონაცემების ჩატვირთვა…"},maximumSelected:function(n){return"თქვენ შეგიძლიათ აირჩიოთ არაუმეტეს "+n.maximum+" ელემენტი"},noResults:function(){return"რეზულტატი არ მოიძებნა"},searching:function(){return"ძიება…"},removeAllItems:function(){return"ამოიღე ყველა ელემენტი"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/km.js b/installer/dup-installer/vendor/select2/js/i18n/km.js new file mode 100644 index 00000000..4dca94f4 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/km.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(n){return"សូមលុបចេញ "+(n.input.length-n.maximum)+" អក្សរ"},inputTooShort:function(n){return"សូមបញ្ចូល"+(n.minimum-n.input.length)+" អក្សរ រឺ ច្រើនជាងនេះ"},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(n){return"អ្នកអាចជ្រើសរើសបានតែ "+n.maximum+" ជម្រើសប៉ុណ្ណោះ"},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."},removeAllItems:function(){return"លុបធាតុទាំងអស់"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ko.js b/installer/dup-installer/vendor/select2/js/i18n/ko.js new file mode 100644 index 00000000..f2880fb0 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ko.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/lt.js b/installer/dup-installer/vendor/select2/js/i18n/lt.js new file mode 100644 index 00000000..f6a42155 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/lt.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/lt",[],function(){function n(n,e,i,t){return n%10==1&&(n%100<11||n%100>19)?e:n%10>=2&&n%10<=9&&(n%100<11||n%100>19)?i:t}return{inputTooLong:function(e){var i=e.input.length-e.maximum,t="Pašalinkite "+i+" simbol";return t+=n(i,"į","ius","ių")},inputTooShort:function(e){var i=e.minimum-e.input.length,t="Įrašykite dar "+i+" simbol";return t+=n(i,"į","ius","ių")},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(e){var i="Jūs galite pasirinkti tik "+e.maximum+" element";return i+=n(e.maximum,"ą","us","ų")},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"},removeAllItems:function(){return"Pašalinti visus elementus"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/lv.js b/installer/dup-installer/vendor/select2/js/i18n/lv.js new file mode 100644 index 00000000..806dc5c4 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/lv.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/lv",[],function(){function e(e,n,u,i){return 11===e?n:e%10==1?u:i}return{inputTooLong:function(n){var u=n.input.length-n.maximum,i="Lūdzu ievadiet par "+u;return(i+=" simbol"+e(u,"iem","u","iem"))+" mazāk"},inputTooShort:function(n){var u=n.minimum-n.input.length,i="Lūdzu ievadiet vēl "+u;return i+=" simbol"+e(u,"us","u","us")},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(n){var u="Jūs varat izvēlēties ne vairāk kā "+n.maximum;return u+=" element"+e(n.maximum,"us","u","us")},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"},removeAllItems:function(){return"Noņemt visus vienumus"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/mk.js b/installer/dup-installer/vendor/select2/js/i18n/mk.js new file mode 100644 index 00000000..cb7b84a2 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/mk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/mk",[],function(){return{inputTooLong:function(n){var e=(n.input.length,n.maximum,"Ве молиме внесете "+n.maximum+" помалку карактер");return 1!==n.maximum&&(e+="и"),e},inputTooShort:function(n){var e=(n.minimum,n.input.length,"Ве молиме внесете уште "+n.maximum+" карактер");return 1!==n.maximum&&(e+="и"),e},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(n){var e="Можете да изберете само "+n.maximum+" ставк";return 1===n.maximum?e+="а":e+="и",e},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"},removeAllItems:function(){return"Отстрани ги сите предмети"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ms.js b/installer/dup-installer/vendor/select2/js/i18n/ms.js new file mode 100644 index 00000000..6bd7eaa3 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ms.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(n){return"Sila hapuskan "+(n.input.length-n.maximum)+" aksara"},inputTooShort:function(n){return"Sila masukkan "+(n.minimum-n.input.length)+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(n){return"Anda hanya boleh memilih "+n.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Keluarkan semua item"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/nb.js b/installer/dup-installer/vendor/select2/js/i18n/nb.js new file mode 100644 index 00000000..25d89c68 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/nb.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){return"Vennligst fjern "+(e.input.length-e.maximum)+" tegn"},inputTooShort:function(e){return"Vennligst skriv inn "+(e.minimum-e.input.length)+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ne.js b/installer/dup-installer/vendor/select2/js/i18n/ne.js new file mode 100644 index 00000000..1c39f672 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ne.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ne",[],function(){return{errorLoading:function(){return"नतिजाहरु देखाउन सकिएन।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="कृपया "+e+" अक्षर मेटाउनुहोस्।";return 1!=e&&(u+="कृपया "+e+" अक्षरहरु मेटाउनुहोस्।"),u},inputTooShort:function(n){return"कृपया बाँकी रहेका "+(n.minimum-n.input.length)+" वा अरु धेरै अक्षरहरु भर्नुहोस्।"},loadingMore:function(){return"अरु नतिजाहरु भरिँदैछन् …"},maximumSelected:function(n){var e="तँपाई "+n.maximum+" वस्तु मात्र छान्न पाउँनुहुन्छ।";return 1!=n.maximum&&(e="तँपाई "+n.maximum+" वस्तुहरु मात्र छान्न पाउँनुहुन्छ।"),e},noResults:function(){return"कुनै पनि नतिजा भेटिएन।"},searching:function(){return"खोजि हुँदैछ…"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/nl.js b/installer/dup-installer/vendor/select2/js/i18n/nl.js new file mode 100644 index 00000000..2b74058d --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/nl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){return"Gelieve "+(e.input.length-e.maximum)+" karakters te verwijderen"},inputTooShort:function(e){return"Gelieve "+(e.minimum-e.input.length)+" of meer karakters in te voeren"},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var n=1==e.maximum?"kan":"kunnen",r="Er "+n+" maar "+e.maximum+" item";return 1!=e.maximum&&(r+="s"),r+=" worden geselecteerd"},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"},removeAllItems:function(){return"Verwijder alle items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/pl.js b/installer/dup-installer/vendor/select2/js/i18n/pl.js new file mode 100644 index 00000000..4ca5748c --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/pl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/pl",[],function(){var n=["znak","znaki","znaków"],e=["element","elementy","elementów"],r=function(n,e){return 1===n?e[0]:n>1&&n<=4?e[1]:n>=5?e[2]:void 0};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Usuń "+t+" "+r(t,n)},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Podaj przynajmniej "+t+" "+r(t,n)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(n){return"Możesz zaznaczyć tylko "+n.maximum+" "+r(n.maximum,e)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"},removeAllItems:function(){return"Usuń wszystkie przedmioty"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ps.js b/installer/dup-installer/vendor/select2/js/i18n/ps.js new file mode 100644 index 00000000..9b008e4c --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ps.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="د مهربانۍ لمخي "+e+" توری ړنګ کړئ";return 1!=e&&(r=r.replace("توری","توري")),r},inputTooShort:function(n){return"لږ تر لږه "+(n.minimum-n.input.length)+" يا ډېر توري وليکئ"},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(n){var e="تاسو يوازي "+n.maximum+" قلم په نښه کولای سی";return 1!=n.maximum&&(e=e.replace("قلم","قلمونه")),e},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."},removeAllItems:function(){return"ټول توکي لرې کړئ"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/pt-BR.js b/installer/dup-installer/vendor/select2/js/i18n/pt-BR.js new file mode 100644 index 00000000..c991e255 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/pt-BR.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Apague "+n+" caracter";return 1!=n&&(r+="es"),r},inputTooShort:function(e){return"Digite "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var n="Você só pode selecionar "+e.maximum+" ite";return 1==e.maximum?n+="m":n+="ns",n},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/pt.js b/installer/dup-installer/vendor/select2/js/i18n/pt.js new file mode 100644 index 00000000..b5da1a6b --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/pt.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var r=e.input.length-e.maximum,n="Por favor apague "+r+" ";return n+=1!=r?"caracteres":"caractere"},inputTooShort:function(e){return"Introduza "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var r="Apenas pode seleccionar "+e.maximum+" ";return r+=1!=e.maximum?"itens":"item"},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ro.js b/installer/dup-installer/vendor/select2/js/i18n/ro.js new file mode 100644 index 00000000..1ba7b40b --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ro.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return 1!==t&&(n+="e"),n},inputTooShort:function(e){return"Vă rugăm să introduceți "+(e.minimum-e.input.length)+" sau mai multe caractere"},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",1!==e.maximum&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"},removeAllItems:function(){return"Eliminați toate elementele"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/ru.js b/installer/dup-installer/vendor/select2/js/i18n/ru.js new file mode 100644 index 00000000..63a7d66c --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/ru.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ru",[],function(){function n(n,e,r,u){return n%10<5&&n%10>0&&n%100<5||n%100>20?n%10>1?r:e:u}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Пожалуйста, введите на "+r+" символ";return u+=n(r,"","a","ов"),u+=" меньше"},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Пожалуйста, введите ещё хотя бы "+r+" символ";return u+=n(r,"","a","ов")},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(e){var r="Вы можете выбрать не более "+e.maximum+" элемент";return r+=n(e.maximum,"","a","ов")},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"},removeAllItems:function(){return"Удалить все элементы"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/sk.js b/installer/dup-installer/vendor/select2/js/i18n/sk.js new file mode 100644 index 00000000..5049528a --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/sk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadajte o jeden znak menej":t>=2&&t<=4?"Prosím, zadajte o "+e[t](!0)+" znaky menej":"Prosím, zadajte o "+t+" znakov menej"},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadajte ešte jeden znak":t<=4?"Prosím, zadajte ešte ďalšie "+e[t](!0)+" znaky":"Prosím, zadajte ešte ďalších "+t+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(n){return 1==n.maximum?"Môžete zvoliť len jednu položku":n.maximum>=2&&n.maximum<=4?"Môžete zvoliť najviac "+e[n.maximum](!1)+" položky":"Môžete zvoliť najviac "+n.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"},removeAllItems:function(){return"Odstráňte všetky položky"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/sl.js b/installer/dup-installer/vendor/select2/js/i18n/sl.js new file mode 100644 index 00000000..4d0b7d3e --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/sl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Prosim zbrišite "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Prosim vpišite še "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var n="Označite lahko največ "+e.maximum+" predmet";return 2==e.maximum?n+="a":1!=e.maximum&&(n+="e"),n},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"},removeAllItems:function(){return"Odstranite vse elemente"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/sq.js b/installer/dup-installer/vendor/select2/js/i18n/sq.js new file mode 100644 index 00000000..59162024 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/sq.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sq",[],function(){return{errorLoading:function(){return"Rezultatet nuk mund të ngarkoheshin."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Të lutem fshi "+n+" karakter";return 1!=n&&(t+="e"),t},inputTooShort:function(e){return"Të lutem shkruaj "+(e.minimum-e.input.length)+" ose më shumë karaktere"},loadingMore:function(){return"Duke ngarkuar më shumë rezultate…"},maximumSelected:function(e){var n="Mund të zgjedhësh vetëm "+e.maximum+" element";return 1!=e.maximum&&(n+="e"),n},noResults:function(){return"Nuk u gjet asnjë rezultat"},searching:function(){return"Duke kërkuar…"},removeAllItems:function(){return"Hiq të gjitha sendet"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/sr-Cyrl.js b/installer/dup-installer/vendor/select2/js/i18n/sr-Cyrl.js new file mode 100644 index 00000000..ce13ce8f --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/sr-Cyrl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr-Cyrl",[],function(){function n(n,e,r,u){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:u}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Обришите "+r+" симбол";return u+=n(r,"","а","а")},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Укуцајте бар још "+r+" симбол";return u+=n(r,"","а","а")},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(e){var r="Можете изабрати само "+e.maximum+" ставк";return r+=n(e.maximum,"у","е","и")},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/sr.js b/installer/dup-installer/vendor/select2/js/i18n/sr.js new file mode 100644 index 00000000..dd407a06 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/sr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr",[],function(){function n(n,e,r,t){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(e){var r=e.input.length-e.maximum,t="Obrišite "+r+" simbol";return t+=n(r,"","a","a")},inputTooShort:function(e){var r=e.minimum-e.input.length,t="Ukucajte bar još "+r+" simbol";return t+=n(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(e){var r="Možete izabrati samo "+e.maximum+" stavk";return r+=n(e.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/sv.js b/installer/dup-installer/vendor/select2/js/i18n/sv.js new file mode 100644 index 00000000..1bc8724a --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/sv.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(n){return"Vänligen sudda ut "+(n.input.length-n.maximum)+" tecken"},inputTooShort:function(n){return"Vänligen skriv in "+(n.minimum-n.input.length)+" eller fler tecken"},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(n){return"Du kan max välja "+n.maximum+" element"},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"},removeAllItems:function(){return"Ta bort alla objekt"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/th.js b/installer/dup-installer/vendor/select2/js/i18n/th.js new file mode 100644 index 00000000..63eab711 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/th.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(n){return"โปรดลบออก "+(n.input.length-n.maximum)+" ตัวอักษร"},inputTooShort:function(n){return"โปรดพิมพ์เพิ่มอีก "+(n.minimum-n.input.length)+" ตัวอักษร"},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(n){return"คุณสามารถเลือกได้ไม่เกิน "+n.maximum+" รายการ"},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"},removeAllItems:function(){return"ลบรายการทั้งหมด"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/tk.js b/installer/dup-installer/vendor/select2/js/i18n/tk.js new file mode 100644 index 00000000..30255ff3 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/tk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/tk",[],function(){return{errorLoading:function(){return"Netije ýüklenmedi."},inputTooLong:function(e){return e.input.length-e.maximum+" harp bozuň."},inputTooShort:function(e){return"Ýene-de iň az "+(e.minimum-e.input.length)+" harp ýazyň."},loadingMore:function(){return"Köpräk netije görkezilýär…"},maximumSelected:function(e){return"Diňe "+e.maximum+" sanysyny saýlaň."},noResults:function(){return"Netije tapylmady."},searching:function(){return"Gözlenýär…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/tr.js b/installer/dup-installer/vendor/select2/js/i18n/tr.js new file mode 100644 index 00000000..fc4c0bf0 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/tr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(n){return n.input.length-n.maximum+" karakter daha girmelisiniz"},inputTooShort:function(n){return"En az "+(n.minimum-n.input.length)+" karakter daha girmelisiniz"},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(n){return"Sadece "+n.maximum+" seçim yapabilirsiniz"},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tüm öğeleri kaldır"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/uk.js b/installer/dup-installer/vendor/select2/js/i18n/uk.js new file mode 100644 index 00000000..63697e38 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/uk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/uk",[],function(){function n(n,e,u,r){return n%100>10&&n%100<15?r:n%10==1?e:n%10>1&&n%10<5?u:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(e){return"Будь ласка, видаліть "+(e.input.length-e.maximum)+" "+n(e.maximum,"літеру","літери","літер")},inputTooShort:function(n){return"Будь ласка, введіть "+(n.minimum-n.input.length)+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(e){return"Ви можете вибрати лише "+e.maximum+" "+n(e.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"},removeAllItems:function(){return"Видалити всі елементи"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/vi.js b/installer/dup-installer/vendor/select2/js/i18n/vi.js new file mode 100644 index 00000000..24f3bc2d --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/vi.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/vi",[],function(){return{inputTooLong:function(n){return"Vui lòng xóa bớt "+(n.input.length-n.maximum)+" ký tự"},inputTooShort:function(n){return"Vui lòng nhập thêm từ "+(n.minimum-n.input.length)+" ký tự trở lên"},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(n){return"Chỉ có thể chọn được "+n.maximum+" lựa chọn"},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"},removeAllItems:function(){return"Xóa tất cả các mục"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/zh-CN.js b/installer/dup-installer/vendor/select2/js/i18n/zh-CN.js new file mode 100644 index 00000000..2c5649d3 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/zh-CN.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/i18n/zh-TW.js b/installer/dup-installer/vendor/select2/js/i18n/zh-TW.js new file mode 100644 index 00000000..570a5669 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/i18n/zh-TW.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(n){return"請刪掉"+(n.input.length-n.maximum)+"個字元"},inputTooShort:function(n){return"請再輸入"+(n.minimum-n.input.length)+"個字元"},loadingMore:function(){return"載入中…"},maximumSelected:function(n){return"你只能選擇最多"+n.maximum+"項"},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"},removeAllItems:function(){return"刪除所有項目"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/installer/dup-installer/vendor/select2/js/select2.full.js b/installer/dup-installer/vendor/select2/js/select2.full.js new file mode 100644 index 00000000..358572a6 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/select2.full.js @@ -0,0 +1,6820 @@ +/*! + * Select2 4.0.13 + * https://select2.github.io + * + * Released under the MIT license + * https://github.com/select2/select2/blob/master/LICENSE.md + */ +;(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function (root, jQuery) { + if (jQuery === undefined) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if (typeof window !== 'undefined') { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + factory(jQuery); + return jQuery; + }; + } else { + // Browser globals + factory(jQuery); + } +} (function (jQuery) { + // This is needed so we can catch the AMD loader configuration and use it + // The inner file should be wrapped (by `banner.start.js`) in a function that + // returns the AMD loader references. + var S2 =(function () { + // Restore the Select2 AMD loader so it can be used + // Needed mostly in the language files, where the loader is not inserted + if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) { + var S2 = jQuery.fn.select2.amd; + } +var S2;(function () { if (!S2 || !S2.requirejs) { +if (!S2) { S2 = {}; } else { require = S2; } +/** + * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. + * Released under MIT license, http://github.com/requirejs/almond/LICENSE + */ +//Going sloppy to avoid 'use strict' string cost, but strict practices should +//be followed. +/*global setTimeout: false */ + +var requirejs, require, define; +(function (undef) { + var main, req, makeMap, handlers, + defined = {}, + waiting = {}, + config = {}, + defining = {}, + hasOwn = Object.prototype.hasOwnProperty, + aps = [].slice, + jsSuffixRegExp = /\.js$/; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var nameParts, nameSegment, mapValue, foundMap, lastIndex, + foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, + baseParts = baseName && baseName.split("/"), + map = config.map, + starMap = (map && map['*']) || {}; + + //Adjust any relative paths. + if (name) { + name = name.split('/'); + lastIndex = name.length - 1; + + // If wanting node ID compatibility, strip .js from end + // of IDs. Have to do this here, and not in nameToUrl + // because node allows either .js or non .js to map + // to same file. + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + // Starts with a '.' so need the baseName + if (name[0].charAt(0) === '.' && baseParts) { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + name = normalizedBaseParts.concat(name); + } + + //start trimDots + for (i = 0; i < name.length; i++) { + part = name[i]; + if (part === '.') { + name.splice(i, 1); + i -= 1; + } else if (part === '..') { + // If at the start, or previous value is still .., + // keep them so that when converted to a path it may + // still work when converted to a path, even though + // as an ID it is less than ideal. In larger point + // releases, may be better to just kick out an error. + if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') { + continue; + } else if (i > 0) { + name.splice(i - 1, 2); + i -= 2; + } + } + } + //end trimDots + + name = name.join('/'); + } + + //Apply map config if available. + if ((baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join("/"); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function makeRequire(relName, forceSync) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + var args = aps.call(arguments, 0); + + //If first arg is not require('string'), and there is only + //one arg, it is the array form without a callback. Insert + //a null so that the following concat is correct. + if (typeof args[0] !== 'string' && args.length === 1) { + args.push(null); + } + return req.apply(undef, args.concat([relName, forceSync])); + }; + } + + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(depName) { + return function (value) { + defined[depName] = value; + }; + } + + function callDep(name) { + if (hasProp(waiting, name)) { + var args = waiting[name]; + delete waiting[name]; + defining[name] = true; + main.apply(undef, args); + } + + if (!hasProp(defined, name) && !hasProp(defining, name)) { + throw new Error('No ' + name); + } + return defined[name]; + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + //Creates a parts array for a relName where first part is plugin ID, + //second part is resource ID. Assumes relName has already been normalized. + function makeRelParts(relName) { + return relName ? splitPrefix(relName) : []; + } + + /** + * Makes a name map, normalizing the name, and using a plugin + * for normalization if necessary. Grabs a ref to plugin + * too, as an optimization. + */ + makeMap = function (name, relParts) { + var plugin, + parts = splitPrefix(name), + prefix = parts[0], + relResourceName = relParts[1]; + + name = parts[1]; + + if (prefix) { + prefix = normalize(prefix, relResourceName); + plugin = callDep(prefix); + } + + //Normalize according + if (prefix) { + if (plugin && plugin.normalize) { + name = plugin.normalize(name, makeNormalize(relResourceName)); + } else { + name = normalize(name, relResourceName); + } + } else { + name = normalize(name, relResourceName); + parts = splitPrefix(name); + prefix = parts[0]; + name = parts[1]; + if (prefix) { + plugin = callDep(prefix); + } + } + + //Using ridiculous property names for space reasons + return { + f: prefix ? prefix + '!' + name : name, //fullName + n: name, + pr: prefix, + p: plugin + }; + }; + + function makeConfig(name) { + return function () { + return (config && config.config && config.config[name]) || {}; + }; + } + + handlers = { + require: function (name) { + return makeRequire(name); + }, + exports: function (name) { + var e = defined[name]; + if (typeof e !== 'undefined') { + return e; + } else { + return (defined[name] = {}); + } + }, + module: function (name) { + return { + id: name, + uri: '', + exports: defined[name], + config: makeConfig(name) + }; + } + }; + + main = function (name, deps, callback, relName) { + var cjsModule, depName, ret, map, i, relParts, + args = [], + callbackType = typeof callback, + usingExports; + + //Use name if no relName + relName = relName || name; + relParts = makeRelParts(relName); + + //Call the callback to define the module, if necessary. + if (callbackType === 'undefined' || callbackType === 'function') { + //Pull out the defined dependencies and pass the ordered + //values to the callback. + //Default to [require, exports, module] if no deps + deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; + for (i = 0; i < deps.length; i += 1) { + map = makeMap(deps[i], relParts); + depName = map.f; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + args[i] = handlers.require(name); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + args[i] = handlers.exports(name); + usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + cjsModule = args[i] = handlers.module(name); + } else if (hasProp(defined, depName) || + hasProp(waiting, depName) || + hasProp(defining, depName)) { + args[i] = callDep(depName); + } else if (map.p) { + map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); + args[i] = defined[depName]; + } else { + throw new Error(name + ' missing ' + depName); + } + } + + ret = callback ? callback.apply(defined[name], args) : undefined; + + if (name) { + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (cjsModule && cjsModule.exports !== undef && + cjsModule.exports !== defined[name]) { + defined[name] = cjsModule.exports; + } else if (ret !== undef || !usingExports) { + //Use the return value from the function. + defined[name] = ret; + } + } + } else if (name) { + //May just be an object definition for the module. Only + //worry about defining if have a module name. + defined[name] = callback; + } + }; + + requirejs = require = req = function (deps, callback, relName, forceSync, alt) { + if (typeof deps === "string") { + if (handlers[deps]) { + //callback in this case is really relName + return handlers[deps](callback); + } + //Just return the module wanted. In this scenario, the + //deps arg is the module name, and second arg (if passed) + //is just the relName. + //Normalize module name, if it contains . or .. + return callDep(makeMap(deps, makeRelParts(callback)).f); + } else if (!deps.splice) { + //deps is a config object, not an array. + config = deps; + if (config.deps) { + req(config.deps, config.callback); + } + if (!callback) { + return; + } + + if (callback.splice) { + //callback is an array, which means it is a dependency list. + //Adjust args if there are dependencies + deps = callback; + callback = relName; + relName = null; + } else { + deps = undef; + } + } + + //Support require(['a']) + callback = callback || function () {}; + + //If relName is a function, it is an errback handler, + //so remove it. + if (typeof relName === 'function') { + relName = forceSync; + forceSync = alt; + } + + //Simulate async callback; + if (forceSync) { + main(undef, deps, callback, relName); + } else { + //Using a non-zero value because of concern for what old browsers + //do, and latest browsers "upgrade" to 4 if lower value is used: + //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: + //If want a value immediately, use require('id') instead -- something + //that works in almond on the global level, but not guaranteed and + //unlikely to work in other AMD implementations. + setTimeout(function () { + main(undef, deps, callback, relName); + }, 4); + } + + return req; + }; + + /** + * Just drops the config on the floor, but returns req in case + * the config return value is used. + */ + req.config = function (cfg) { + return req(cfg); + }; + + /** + * Expose module registry for debugging and tooling + */ + requirejs._defined = defined; + + define = function (name, deps, callback) { + if (typeof name !== 'string') { + throw new Error('See almond README: incorrect module build, no module name'); + } + + //This module may not have dependencies + if (!deps.splice) { + //deps is not an array, so probably means + //an object literal or factory function for + //the value. Adjust args. + callback = deps; + deps = []; + } + + if (!hasProp(defined, name) && !hasProp(waiting, name)) { + waiting[name] = [name, deps, callback]; + } + }; + + define.amd = { + jQuery: true + }; +}()); + +S2.requirejs = requirejs;S2.require = require;S2.define = define; +} +}()); +S2.define("almond", function(){}); + +/* global jQuery:false, $:false */ +S2.define('jquery',[],function () { + var _$ = jQuery || $; + + if (_$ == null && console && console.error) { + console.error( + 'Select2: An instance of jQuery or a jQuery-compatible library was not ' + + 'found. Make sure that you are including jQuery before Select2 on your ' + + 'web page.' + ); + } + + return _$; +}); + +S2.define('select2/utils',[ + 'jquery' +], function ($) { + var Utils = {}; + + Utils.Extend = function (ChildClass, SuperClass) { + var __hasProp = {}.hasOwnProperty; + + function BaseConstructor () { + this.constructor = ChildClass; + } + + for (var key in SuperClass) { + if (__hasProp.call(SuperClass, key)) { + ChildClass[key] = SuperClass[key]; + } + } + + BaseConstructor.prototype = SuperClass.prototype; + ChildClass.prototype = new BaseConstructor(); + ChildClass.__super__ = SuperClass.prototype; + + return ChildClass; + }; + + function getMethods (theClass) { + var proto = theClass.prototype; + + var methods = []; + + for (var methodName in proto) { + var m = proto[methodName]; + + if (typeof m !== 'function') { + continue; + } + + if (methodName === 'constructor') { + continue; + } + + methods.push(methodName); + } + + return methods; + } + + Utils.Decorate = function (SuperClass, DecoratorClass) { + var decoratedMethods = getMethods(DecoratorClass); + var superMethods = getMethods(SuperClass); + + function DecoratedClass () { + var unshift = Array.prototype.unshift; + + var argCount = DecoratorClass.prototype.constructor.length; + + var calledConstructor = SuperClass.prototype.constructor; + + if (argCount > 0) { + unshift.call(arguments, SuperClass.prototype.constructor); + + calledConstructor = DecoratorClass.prototype.constructor; + } + + calledConstructor.apply(this, arguments); + } + + DecoratorClass.displayName = SuperClass.displayName; + + function ctr () { + this.constructor = DecoratedClass; + } + + DecoratedClass.prototype = new ctr(); + + for (var m = 0; m < superMethods.length; m++) { + var superMethod = superMethods[m]; + + DecoratedClass.prototype[superMethod] = + SuperClass.prototype[superMethod]; + } + + var calledMethod = function (methodName) { + // Stub out the original method if it's not decorating an actual method + var originalMethod = function () {}; + + if (methodName in DecoratedClass.prototype) { + originalMethod = DecoratedClass.prototype[methodName]; + } + + var decoratedMethod = DecoratorClass.prototype[methodName]; + + return function () { + var unshift = Array.prototype.unshift; + + unshift.call(arguments, originalMethod); + + return decoratedMethod.apply(this, arguments); + }; + }; + + for (var d = 0; d < decoratedMethods.length; d++) { + var decoratedMethod = decoratedMethods[d]; + + DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod); + } + + return DecoratedClass; + }; + + var Observable = function () { + this.listeners = {}; + }; + + Observable.prototype.on = function (event, callback) { + this.listeners = this.listeners || {}; + + if (event in this.listeners) { + this.listeners[event].push(callback); + } else { + this.listeners[event] = [callback]; + } + }; + + Observable.prototype.trigger = function (event) { + var slice = Array.prototype.slice; + var params = slice.call(arguments, 1); + + this.listeners = this.listeners || {}; + + // Params should always come in as an array + if (params == null) { + params = []; + } + + // If there are no arguments to the event, use a temporary object + if (params.length === 0) { + params.push({}); + } + + // Set the `_type` of the first object to the event + params[0]._type = event; + + if (event in this.listeners) { + this.invoke(this.listeners[event], slice.call(arguments, 1)); + } + + if ('*' in this.listeners) { + this.invoke(this.listeners['*'], arguments); + } + }; + + Observable.prototype.invoke = function (listeners, params) { + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i].apply(this, params); + } + }; + + Utils.Observable = Observable; + + Utils.generateChars = function (length) { + var chars = ''; + + for (var i = 0; i < length; i++) { + var randomChar = Math.floor(Math.random() * 36); + chars += randomChar.toString(36); + } + + return chars; + }; + + Utils.bind = function (func, context) { + return function () { + func.apply(context, arguments); + }; + }; + + Utils._convertData = function (data) { + for (var originalKey in data) { + var keys = originalKey.split('-'); + + var dataLevel = data; + + if (keys.length === 1) { + continue; + } + + for (var k = 0; k < keys.length; k++) { + var key = keys[k]; + + // Lowercase the first letter + // By default, dash-separated becomes camelCase + key = key.substring(0, 1).toLowerCase() + key.substring(1); + + if (!(key in dataLevel)) { + dataLevel[key] = {}; + } + + if (k == keys.length - 1) { + dataLevel[key] = data[originalKey]; + } + + dataLevel = dataLevel[key]; + } + + delete data[originalKey]; + } + + return data; + }; + + Utils.hasScroll = function (index, el) { + // Adapted from the function created by @ShadowScripter + // and adapted by @BillBarry on the Stack Exchange Code Review website. + // The original code can be found at + // http://codereview.stackexchange.com/q/13338 + // and was designed to be used with the Sizzle selector engine. + + var $el = $(el); + var overflowX = el.style.overflowX; + var overflowY = el.style.overflowY; + + //Check both x and y declarations + if (overflowX === overflowY && + (overflowY === 'hidden' || overflowY === 'visible')) { + return false; + } + + if (overflowX === 'scroll' || overflowY === 'scroll') { + return true; + } + + return ($el.innerHeight() < el.scrollHeight || + $el.innerWidth() < el.scrollWidth); + }; + + Utils.escapeMarkup = function (markup) { + var replaceMap = { + '\\': '\', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '/': '/' + }; + + // Do not try to escape the markup if it's not a string + if (typeof markup !== 'string') { + return markup; + } + + return String(markup).replace(/[&<>"'\/\\]/g, function (match) { + return replaceMap[match]; + }); + }; + + // Append an array of jQuery nodes to a given element. + Utils.appendMany = function ($element, $nodes) { + // jQuery 1.7.x does not support $.fn.append() with an array + // Fall back to a jQuery object collection using $.fn.add() + if ($.fn.jquery.substr(0, 3) === '1.7') { + var $jqNodes = $(); + + $.map($nodes, function (node) { + $jqNodes = $jqNodes.add(node); + }); + + $nodes = $jqNodes; + } + + $element.append($nodes); + }; + + // Cache objects in Utils.__cache instead of $.data (see #4346) + Utils.__cache = {}; + + var id = 0; + Utils.GetUniqueElementId = function (element) { + // Get a unique element Id. If element has no id, + // creates a new unique number, stores it in the id + // attribute and returns the new id. + // If an id already exists, it simply returns it. + + var select2Id = element.getAttribute('data-select2-id'); + if (select2Id == null) { + // If element has id, use it. + if (element.id) { + select2Id = element.id; + element.setAttribute('data-select2-id', select2Id); + } else { + element.setAttribute('data-select2-id', ++id); + select2Id = id.toString(); + } + } + return select2Id; + }; + + Utils.StoreData = function (element, name, value) { + // Stores an item in the cache for a specified element. + // name is the cache key. + var id = Utils.GetUniqueElementId(element); + if (!Utils.__cache[id]) { + Utils.__cache[id] = {}; + } + + Utils.__cache[id][name] = value; + }; + + Utils.GetData = function (element, name) { + // Retrieves a value from the cache by its key (name) + // name is optional. If no name specified, return + // all cache items for the specified element. + // and for a specified element. + var id = Utils.GetUniqueElementId(element); + if (name) { + if (Utils.__cache[id]) { + if (Utils.__cache[id][name] != null) { + return Utils.__cache[id][name]; + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } else { + return Utils.__cache[id]; + } + }; + + Utils.RemoveData = function (element) { + // Removes all cached items for a specified element. + var id = Utils.GetUniqueElementId(element); + if (Utils.__cache[id] != null) { + delete Utils.__cache[id]; + } + + element.removeAttribute('data-select2-id'); + }; + + return Utils; +}); + +S2.define('select2/results',[ + 'jquery', + './utils' +], function ($, Utils) { + function Results ($element, options, dataAdapter) { + this.$element = $element; + this.data = dataAdapter; + this.options = options; + + Results.__super__.constructor.call(this); + } + + Utils.Extend(Results, Utils.Observable); + + Results.prototype.render = function () { + var $results = $( + '
            ' + ); + + if (this.options.get('multiple')) { + $results.attr('aria-multiselectable', 'true'); + } + + this.$results = $results; + + return $results; + }; + + Results.prototype.clear = function () { + this.$results.empty(); + }; + + Results.prototype.displayMessage = function (params) { + var escapeMarkup = this.options.get('escapeMarkup'); + + this.clear(); + this.hideLoading(); + + var $message = $( + '' + ); + + var message = this.options.get('translations').get(params.message); + + $message.append( + escapeMarkup( + message(params.args) + ) + ); + + $message[0].className += ' select2-results__message'; + + this.$results.append($message); + }; + + Results.prototype.hideMessages = function () { + this.$results.find('.select2-results__message').remove(); + }; + + Results.prototype.append = function (data) { + this.hideLoading(); + + var $options = []; + + if (data.results == null || data.results.length === 0) { + if (this.$results.children().length === 0) { + this.trigger('results:message', { + message: 'noResults' + }); + } + + return; + } + + data.results = this.sort(data.results); + + for (var d = 0; d < data.results.length; d++) { + var item = data.results[d]; + + var $option = this.option(item); + + $options.push($option); + } + + this.$results.append($options); + }; + + Results.prototype.position = function ($results, $dropdown) { + var $resultsContainer = $dropdown.find('.select2-results'); + $resultsContainer.append($results); + }; + + Results.prototype.sort = function (data) { + var sorter = this.options.get('sorter'); + + return sorter(data); + }; + + Results.prototype.highlightFirstItem = function () { + var $options = this.$results + .find('.select2-results__option[aria-selected]'); + + var $selected = $options.filter('[aria-selected=true]'); + + // Check if there are any selected options + if ($selected.length > 0) { + // If there are selected options, highlight the first + $selected.first().trigger('mouseenter'); + } else { + // If there are no selected options, highlight the first option + // in the dropdown + $options.first().trigger('mouseenter'); + } + + this.ensureHighlightVisible(); + }; + + Results.prototype.setClasses = function () { + var self = this; + + this.data.current(function (selected) { + var selectedIds = $.map(selected, function (s) { + return s.id.toString(); + }); + + var $options = self.$results + .find('.select2-results__option[aria-selected]'); + + $options.each(function () { + var $option = $(this); + + var item = Utils.GetData(this, 'data'); + + // id needs to be converted to a string when comparing + var id = '' + item.id; + + if ((item.element != null && item.element.selected) || + (item.element == null && $.inArray(id, selectedIds) > -1)) { + $option.attr('aria-selected', 'true'); + } else { + $option.attr('aria-selected', 'false'); + } + }); + + }); + }; + + Results.prototype.showLoading = function (params) { + this.hideLoading(); + + var loadingMore = this.options.get('translations').get('searching'); + + var loading = { + disabled: true, + loading: true, + text: loadingMore(params) + }; + var $loading = this.option(loading); + $loading.className += ' loading-results'; + + this.$results.prepend($loading); + }; + + Results.prototype.hideLoading = function () { + this.$results.find('.loading-results').remove(); + }; + + Results.prototype.option = function (data) { + var option = document.createElement('li'); + option.className = 'select2-results__option'; + + var attrs = { + 'role': 'option', + 'aria-selected': 'false' + }; + + var matches = window.Element.prototype.matches || + window.Element.prototype.msMatchesSelector || + window.Element.prototype.webkitMatchesSelector; + + if ((data.element != null && matches.call(data.element, ':disabled')) || + (data.element == null && data.disabled)) { + delete attrs['aria-selected']; + attrs['aria-disabled'] = 'true'; + } + + if (data.id == null) { + delete attrs['aria-selected']; + } + + if (data._resultId != null) { + option.id = data._resultId; + } + + if (data.title) { + option.title = data.title; + } + + if (data.children) { + attrs.role = 'group'; + attrs['aria-label'] = data.text; + delete attrs['aria-selected']; + } + + for (var attr in attrs) { + var val = attrs[attr]; + + option.setAttribute(attr, val); + } + + if (data.children) { + var $option = $(option); + + var label = document.createElement('strong'); + label.className = 'select2-results__group'; + + var $label = $(label); + this.template(data, label); + + var $children = []; + + for (var c = 0; c < data.children.length; c++) { + var child = data.children[c]; + + var $child = this.option(child); + + $children.push($child); + } + + var $childrenContainer = $('
              ', { + 'class': 'select2-results__options select2-results__options--nested' + }); + + $childrenContainer.append($children); + + $option.append(label); + $option.append($childrenContainer); + } else { + this.template(data, option); + } + + Utils.StoreData(option, 'data', data); + + return option; + }; + + Results.prototype.bind = function (container, $container) { + var self = this; + + var id = container.id + '-results'; + + this.$results.attr('id', id); + + container.on('results:all', function (params) { + self.clear(); + self.append(params.data); + + if (container.isOpen()) { + self.setClasses(); + self.highlightFirstItem(); + } + }); + + container.on('results:append', function (params) { + self.append(params.data); + + if (container.isOpen()) { + self.setClasses(); + } + }); + + container.on('query', function (params) { + self.hideMessages(); + self.showLoading(params); + }); + + container.on('select', function () { + if (!container.isOpen()) { + return; + } + + self.setClasses(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } + }); + + container.on('unselect', function () { + if (!container.isOpen()) { + return; + } + + self.setClasses(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } + }); + + container.on('open', function () { + // When the dropdown is open, aria-expended="true" + self.$results.attr('aria-expanded', 'true'); + self.$results.attr('aria-hidden', 'false'); + + self.setClasses(); + self.ensureHighlightVisible(); + }); + + container.on('close', function () { + // When the dropdown is closed, aria-expended="false" + self.$results.attr('aria-expanded', 'false'); + self.$results.attr('aria-hidden', 'true'); + self.$results.removeAttr('aria-activedescendant'); + }); + + container.on('results:toggle', function () { + var $highlighted = self.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + $highlighted.trigger('mouseup'); + }); + + container.on('results:select', function () { + var $highlighted = self.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + var data = Utils.GetData($highlighted[0], 'data'); + + if ($highlighted.attr('aria-selected') == 'true') { + self.trigger('close', {}); + } else { + self.trigger('select', { + data: data + }); + } + }); + + container.on('results:previous', function () { + var $highlighted = self.getHighlightedResults(); + + var $options = self.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + // If we are already at the top, don't move further + // If no options, currentIndex will be -1 + if (currentIndex <= 0) { + return; + } + + var nextIndex = currentIndex - 1; + + // If none are highlighted, highlight the first + if ($highlighted.length === 0) { + nextIndex = 0; + } + + var $next = $options.eq(nextIndex); + + $next.trigger('mouseenter'); + + var currentOffset = self.$results.offset().top; + var nextTop = $next.offset().top; + var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset); + + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextTop - currentOffset < 0) { + self.$results.scrollTop(nextOffset); + } + }); + + container.on('results:next', function () { + var $highlighted = self.getHighlightedResults(); + + var $options = self.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + var nextIndex = currentIndex + 1; + + // If we are at the last option, stay there + if (nextIndex >= $options.length) { + return; + } + + var $next = $options.eq(nextIndex); + + $next.trigger('mouseenter'); + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var nextBottom = $next.offset().top + $next.outerHeight(false); + var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset; + + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextBottom > currentOffset) { + self.$results.scrollTop(nextOffset); + } + }); + + container.on('results:focus', function (params) { + params.element.addClass('select2-results__option--highlighted'); + }); + + container.on('results:message', function (params) { + self.displayMessage(params); + }); + + if ($.fn.mousewheel) { + this.$results.on('mousewheel', function (e) { + var top = self.$results.scrollTop(); + + var bottom = self.$results.get(0).scrollHeight - top + e.deltaY; + + var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0; + var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height(); + + if (isAtTop) { + self.$results.scrollTop(0); + + e.preventDefault(); + e.stopPropagation(); + } else if (isAtBottom) { + self.$results.scrollTop( + self.$results.get(0).scrollHeight - self.$results.height() + ); + + e.preventDefault(); + e.stopPropagation(); + } + }); + } + + this.$results.on('mouseup', '.select2-results__option[aria-selected]', + function (evt) { + var $this = $(this); + + var data = Utils.GetData(this, 'data'); + + if ($this.attr('aria-selected') === 'true') { + if (self.options.get('multiple')) { + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } else { + self.trigger('close', {}); + } + + return; + } + + self.trigger('select', { + originalEvent: evt, + data: data + }); + }); + + this.$results.on('mouseenter', '.select2-results__option[aria-selected]', + function (evt) { + var data = Utils.GetData(this, 'data'); + + self.getHighlightedResults() + .removeClass('select2-results__option--highlighted'); + + self.trigger('results:focus', { + data: data, + element: $(this) + }); + }); + }; + + Results.prototype.getHighlightedResults = function () { + var $highlighted = this.$results + .find('.select2-results__option--highlighted'); + + return $highlighted; + }; + + Results.prototype.destroy = function () { + this.$results.remove(); + }; + + Results.prototype.ensureHighlightVisible = function () { + var $highlighted = this.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + var $options = this.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + var currentOffset = this.$results.offset().top; + var nextTop = $highlighted.offset().top; + var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset); + + var offsetDelta = nextTop - currentOffset; + nextOffset -= $highlighted.outerHeight(false) * 2; + + if (currentIndex <= 2) { + this.$results.scrollTop(0); + } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) { + this.$results.scrollTop(nextOffset); + } + }; + + Results.prototype.template = function (result, container) { + var template = this.options.get('templateResult'); + var escapeMarkup = this.options.get('escapeMarkup'); + + var content = template(result, container); + + if (content == null) { + container.style.display = 'none'; + } else if (typeof content === 'string') { + container.innerHTML = escapeMarkup(content); + } else { + $(container).append(content); + } + }; + + return Results; +}); + +S2.define('select2/keys',[ + +], function () { + var KEYS = { + BACKSPACE: 8, + TAB: 9, + ENTER: 13, + SHIFT: 16, + CTRL: 17, + ALT: 18, + ESC: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46 + }; + + return KEYS; +}); + +S2.define('select2/selection/base',[ + 'jquery', + '../utils', + '../keys' +], function ($, Utils, KEYS) { + function BaseSelection ($element, options) { + this.$element = $element; + this.options = options; + + BaseSelection.__super__.constructor.call(this); + } + + Utils.Extend(BaseSelection, Utils.Observable); + + BaseSelection.prototype.render = function () { + var $selection = $( + '' + ); + + this._tabindex = 0; + + if (Utils.GetData(this.$element[0], 'old-tabindex') != null) { + this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex'); + } else if (this.$element.attr('tabindex') != null) { + this._tabindex = this.$element.attr('tabindex'); + } + + $selection.attr('title', this.$element.attr('title')); + $selection.attr('tabindex', this._tabindex); + $selection.attr('aria-disabled', 'false'); + + this.$selection = $selection; + + return $selection; + }; + + BaseSelection.prototype.bind = function (container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + this.container = container; + + this.$selection.on('focus', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('blur', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', function (evt) { + self.trigger('keypress', evt); + + if (evt.which === KEYS.SPACE) { + evt.preventDefault(); + } + }); + + container.on('results:focus', function (params) { + self.$selection.attr('aria-activedescendant', params.data._resultId); + }); + + container.on('selection:update', function (params) { + self.update(params.data); + }); + + container.on('open', function () { + // When the dropdown is open, aria-expanded="true" + self.$selection.attr('aria-expanded', 'true'); + self.$selection.attr('aria-owns', resultsId); + + self._attachCloseHandler(container); + }); + + container.on('close', function () { + // When the dropdown is closed, aria-expanded="false" + self.$selection.attr('aria-expanded', 'false'); + self.$selection.removeAttr('aria-activedescendant'); + self.$selection.removeAttr('aria-owns'); + + self.$selection.trigger('focus'); + + self._detachCloseHandler(container); + }); + + container.on('enable', function () { + self.$selection.attr('tabindex', self._tabindex); + self.$selection.attr('aria-disabled', 'false'); + }); + + container.on('disable', function () { + self.$selection.attr('tabindex', '-1'); + self.$selection.attr('aria-disabled', 'true'); + }); + }; + + BaseSelection.prototype._handleBlur = function (evt) { + var self = this; + + // This needs to be delayed as the active element is the body when the tab + // key is pressed, possibly along with others. + window.setTimeout(function () { + // Don't trigger `blur` if the focus is still in the selection + if ( + (document.activeElement == self.$selection[0]) || + ($.contains(self.$selection[0], document.activeElement)) + ) { + return; + } + + self.trigger('blur', evt); + }, 1); + }; + + BaseSelection.prototype._attachCloseHandler = function (container) { + + $(document.body).on('mousedown.select2.' + container.id, function (e) { + var $target = $(e.target); + + var $select = $target.closest('.select2'); + + var $all = $('.select2.select2-container--open'); + + $all.each(function () { + if (this == $select[0]) { + return; + } + + var $element = Utils.GetData(this, 'element'); + + $element.select2('close'); + }); + }); + }; + + BaseSelection.prototype._detachCloseHandler = function (container) { + $(document.body).off('mousedown.select2.' + container.id); + }; + + BaseSelection.prototype.position = function ($selection, $container) { + var $selectionContainer = $container.find('.selection'); + $selectionContainer.append($selection); + }; + + BaseSelection.prototype.destroy = function () { + this._detachCloseHandler(this.container); + }; + + BaseSelection.prototype.update = function (data) { + throw new Error('The `update` method must be defined in child classes.'); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + BaseSelection.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + BaseSelection.prototype.isDisabled = function () { + return this.options.get('disabled'); + }; + + return BaseSelection; +}); + +S2.define('select2/selection/single',[ + 'jquery', + './base', + '../utils', + '../keys' +], function ($, BaseSelection, Utils, KEYS) { + function SingleSelection () { + SingleSelection.__super__.constructor.apply(this, arguments); + } + + Utils.Extend(SingleSelection, BaseSelection); + + SingleSelection.prototype.render = function () { + var $selection = SingleSelection.__super__.render.call(this); + + $selection.addClass('select2-selection--single'); + + $selection.html( + '' + + '' + + '' + + '' + ); + + return $selection; + }; + + SingleSelection.prototype.bind = function (container, $container) { + var self = this; + + SingleSelection.__super__.bind.apply(this, arguments); + + var id = container.id + '-container'; + + this.$selection.find('.select2-selection__rendered') + .attr('id', id) + .attr('role', 'textbox') + .attr('aria-readonly', 'true'); + this.$selection.attr('aria-labelledby', id); + + this.$selection.on('mousedown', function (evt) { + // Only respond to left clicks + if (evt.which !== 1) { + return; + } + + self.trigger('toggle', { + originalEvent: evt + }); + }); + + this.$selection.on('focus', function (evt) { + // User focuses on the container + }); + + this.$selection.on('blur', function (evt) { + // User exits the container + }); + + container.on('focus', function (evt) { + if (!container.isOpen()) { + self.$selection.trigger('focus'); + } + }); + }; + + SingleSelection.prototype.clear = function () { + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); // clear tooltip on empty + }; + + SingleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); + + return escapeMarkup(template(data, container)); + }; + + SingleSelection.prototype.selectionContainer = function () { + return $(''); + }; + + SingleSelection.prototype.update = function (data) { + if (data.length === 0) { + this.clear(); + return; + } + + var selection = data[0]; + + var $rendered = this.$selection.find('.select2-selection__rendered'); + var formatted = this.display(selection, $rendered); + + $rendered.empty().append(formatted); + + var title = selection.title || selection.text; + + if (title) { + $rendered.attr('title', title); + } else { + $rendered.removeAttr('title'); + } + }; + + return SingleSelection; +}); + +S2.define('select2/selection/multiple',[ + 'jquery', + './base', + '../utils' +], function ($, BaseSelection, Utils) { + function MultipleSelection ($element, options) { + MultipleSelection.__super__.constructor.apply(this, arguments); + } + + Utils.Extend(MultipleSelection, BaseSelection); + + MultipleSelection.prototype.render = function () { + var $selection = MultipleSelection.__super__.render.call(this); + + $selection.addClass('select2-selection--multiple'); + + $selection.html( + '
                ' + ); + + return $selection; + }; + + MultipleSelection.prototype.bind = function (container, $container) { + var self = this; + + MultipleSelection.__super__.bind.apply(this, arguments); + + this.$selection.on('click', function (evt) { + self.trigger('toggle', { + originalEvent: evt + }); + }); + + this.$selection.on( + 'click', + '.select2-selection__choice__remove', + function (evt) { + // Ignore the event if it is disabled + if (self.isDisabled()) { + return; + } + + var $remove = $(this); + var $selection = $remove.parent(); + + var data = Utils.GetData($selection[0], 'data'); + + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } + ); + }; + + MultipleSelection.prototype.clear = function () { + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); + }; + + MultipleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); + + return escapeMarkup(template(data, container)); + }; + + MultipleSelection.prototype.selectionContainer = function () { + var $container = $( + '
              • ' + + '' + + '×' + + '' + + '
              • ' + ); + + return $container; + }; + + MultipleSelection.prototype.update = function (data) { + this.clear(); + + if (data.length === 0) { + return; + } + + var $selections = []; + + for (var d = 0; d < data.length; d++) { + var selection = data[d]; + + var $selection = this.selectionContainer(); + var formatted = this.display(selection, $selection); + + $selection.append(formatted); + + var title = selection.title || selection.text; + + if (title) { + $selection.attr('title', title); + } + + Utils.StoreData($selection[0], 'data', selection); + + $selections.push($selection); + } + + var $rendered = this.$selection.find('.select2-selection__rendered'); + + Utils.appendMany($rendered, $selections); + }; + + return MultipleSelection; +}); + +S2.define('select2/selection/placeholder',[ + '../utils' +], function (Utils) { + function Placeholder (decorated, $element, options) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options); + } + + Placeholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + Placeholder.prototype.createPlaceholder = function (decorated, placeholder) { + var $placeholder = this.selectionContainer(); + + $placeholder.html(this.display(placeholder)); + $placeholder.addClass('select2-selection__placeholder') + .removeClass('select2-selection__choice'); + + return $placeholder; + }; + + Placeholder.prototype.update = function (decorated, data) { + var singlePlaceholder = ( + data.length == 1 && data[0].id != this.placeholder.id + ); + var multipleSelections = data.length > 1; + + if (multipleSelections || singlePlaceholder) { + return decorated.call(this, data); + } + + this.clear(); + + var $placeholder = this.createPlaceholder(this.placeholder); + + this.$selection.find('.select2-selection__rendered').append($placeholder); + }; + + return Placeholder; +}); + +S2.define('select2/selection/allowClear',[ + 'jquery', + '../keys', + '../utils' +], function ($, KEYS, Utils) { + function AllowClear () { } + + AllowClear.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + if (this.placeholder == null) { + if (this.options.get('debug') && window.console && console.error) { + console.error( + 'Select2: The `allowClear` option should be used in combination ' + + 'with the `placeholder` option.' + ); + } + } + + this.$selection.on('mousedown', '.select2-selection__clear', + function (evt) { + self._handleClear(evt); + }); + + container.on('keypress', function (evt) { + self._handleKeyboardClear(evt, container); + }); + }; + + AllowClear.prototype._handleClear = function (_, evt) { + // Ignore the event if it is disabled + if (this.isDisabled()) { + return; + } + + var $clear = this.$selection.find('.select2-selection__clear'); + + // Ignore the event if nothing has been selected + if ($clear.length === 0) { + return; + } + + evt.stopPropagation(); + + var data = Utils.GetData($clear[0], 'data'); + + var previousVal = this.$element.val(); + this.$element.val(this.placeholder.id); + + var unselectData = { + data: data + }; + this.trigger('clear', unselectData); + if (unselectData.prevented) { + this.$element.val(previousVal); + return; + } + + for (var d = 0; d < data.length; d++) { + unselectData = { + data: data[d] + }; + + // Trigger the `unselect` event, so people can prevent it from being + // cleared. + this.trigger('unselect', unselectData); + + // If the event was prevented, don't clear it out. + if (unselectData.prevented) { + this.$element.val(previousVal); + return; + } + } + + this.$element.trigger('input').trigger('change'); + + this.trigger('toggle', {}); + }; + + AllowClear.prototype._handleKeyboardClear = function (_, evt, container) { + if (container.isOpen()) { + return; + } + + if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) { + this._handleClear(evt); + } + }; + + AllowClear.prototype.update = function (decorated, data) { + decorated.call(this, data); + + if (this.$selection.find('.select2-selection__placeholder').length > 0 || + data.length === 0) { + return; + } + + var removeAll = this.options.get('translations').get('removeAllItems'); + + var $remove = $( + '' + + '×' + + '' + ); + Utils.StoreData($remove[0], 'data', data); + + this.$selection.find('.select2-selection__rendered').prepend($remove); + }; + + return AllowClear; +}); + +S2.define('select2/selection/search',[ + 'jquery', + '../utils', + '../keys' +], function ($, Utils, KEYS) { + function Search (decorated, $element, options) { + decorated.call(this, $element, options); + } + + Search.prototype.render = function (decorated) { + var $search = $( + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + var $rendered = decorated.call(this); + + this._transferTabIndex(); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + decorated.call(this, container, $container); + + container.on('open', function () { + self.$search.attr('aria-controls', resultsId); + self.$search.trigger('focus'); + }); + + container.on('close', function () { + self.$search.val(''); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); + self.$search.trigger('focus'); + }); + + container.on('enable', function () { + self.$search.prop('disabled', false); + + self._transferTabIndex(); + }); + + container.on('disable', function () { + self.$search.prop('disabled', true); + }); + + container.on('focus', function (evt) { + self.$search.trigger('focus'); + }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); + + this.$selection.on('focusin', '.select2-search--inline', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('focusout', '.select2-search--inline', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', '.select2-search--inline', function (evt) { + evt.stopPropagation(); + + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + + var key = evt.which; + + if (key === KEYS.BACKSPACE && self.$search.val() === '') { + var $previousChoice = self.$searchContainer + .prev('.select2-selection__choice'); + + if ($previousChoice.length > 0) { + var item = Utils.GetData($previousChoice[0], 'data'); + + self.searchRemoveChoice(item); + + evt.preventDefault(); + } + } + }); + + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + + // Try to detect the IE version should the `documentMode` property that + // is stored on the document. This is only implemented in IE and is + // slightly cleaner than doing a user agent check. + // This property is not available in Edge, but Edge also doesn't have + // this bug. + var msie = document.documentMode; + var disableInputEvents = msie && msie <= 11; + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$selection.on( + 'input.searchcheck', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents) { + self.$selection.off('input.search input.searchcheck'); + return; + } + + // Unbind the duplicated `keyup` event + self.$selection.off('keyup.search'); + } + ); + + this.$selection.on( + 'keyup.search input.search', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents && evt.type === 'input') { + self.$selection.off('input.search input.searchcheck'); + return; + } + + var key = evt.which; + + // We can freely ignore events from modifier keys + if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + return; + } + + // Tabbing will be handled during the `keydown` phase + if (key == KEYS.TAB) { + return; + } + + self.handleSearch(evt); + } + ); + }; + + /** + * This method will transfer the tabindex attribute from the rendered + * selection to the search box. This allows for the search box to be used as + * the primary focus instead of the selection container. + * + * @private + */ + Search.prototype._transferTabIndex = function (decorated) { + this.$search.attr('tabindex', this.$selection.attr('tabindex')); + this.$selection.attr('tabindex', '-1'); + }; + + Search.prototype.createPlaceholder = function (decorated, placeholder) { + this.$search.attr('placeholder', placeholder.text); + }; + + Search.prototype.update = function (decorated, data) { + var searchHadFocus = this.$search[0] == document.activeElement; + + this.$search.attr('placeholder', ''); + + decorated.call(this, data); + + this.$selection.find('.select2-selection__rendered') + .append(this.$searchContainer); + + this.resizeSearch(); + if (searchHadFocus) { + this.$search.trigger('focus'); + } + }; + + Search.prototype.handleSearch = function () { + this.resizeSearch(); + + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.searchRemoveChoice = function (decorated, item) { + this.trigger('unselect', { + data: item + }); + + this.$search.val(item.text); + this.handleSearch(); + }; + + Search.prototype.resizeSearch = function () { + this.$search.css('width', '25px'); + + var width = ''; + + if (this.$search.attr('placeholder') !== '') { + width = this.$selection.find('.select2-selection__rendered').width(); + } else { + var minimumWidth = this.$search.val().length + 1; + + width = (minimumWidth * 0.75) + 'em'; + } + + this.$search.css('width', width); + }; + + return Search; +}); + +S2.define('select2/selection/eventRelay',[ + 'jquery' +], function ($) { + function EventRelay () { } + + EventRelay.prototype.bind = function (decorated, container, $container) { + var self = this; + var relayEvents = [ + 'open', 'opening', + 'close', 'closing', + 'select', 'selecting', + 'unselect', 'unselecting', + 'clear', 'clearing' + ]; + + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; + + decorated.call(this, container, $container); + + container.on('*', function (name, params) { + // Ignore events that should not be relayed + if ($.inArray(name, relayEvents) === -1) { + return; + } + + // The parameters should always be an object + params = params || {}; + + // Generate the jQuery event for the Select2 event + var evt = $.Event('select2:' + name, { + params: params + }); + + self.$element.trigger(evt); + + // Only handle preventable events if it was one + if ($.inArray(name, preventableEvents) === -1) { + return; + } + + params.prevented = evt.isDefaultPrevented(); + }); + }; + + return EventRelay; +}); + +S2.define('select2/translation',[ + 'jquery', + 'require' +], function ($, require) { + function Translation (dict) { + this.dict = dict || {}; + } + + Translation.prototype.all = function () { + return this.dict; + }; + + Translation.prototype.get = function (key) { + return this.dict[key]; + }; + + Translation.prototype.extend = function (translation) { + this.dict = $.extend({}, translation.all(), this.dict); + }; + + // Static functions + + Translation._cache = {}; + + Translation.loadPath = function (path) { + if (!(path in Translation._cache)) { + var translations = require(path); + + Translation._cache[path] = translations; + } + + return new Translation(Translation._cache[path]); + }; + + return Translation; +}); + +S2.define('select2/diacritics',[ + +], function () { + var diacritics = { + '\u24B6': 'A', + '\uFF21': 'A', + '\u00C0': 'A', + '\u00C1': 'A', + '\u00C2': 'A', + '\u1EA6': 'A', + '\u1EA4': 'A', + '\u1EAA': 'A', + '\u1EA8': 'A', + '\u00C3': 'A', + '\u0100': 'A', + '\u0102': 'A', + '\u1EB0': 'A', + '\u1EAE': 'A', + '\u1EB4': 'A', + '\u1EB2': 'A', + '\u0226': 'A', + '\u01E0': 'A', + '\u00C4': 'A', + '\u01DE': 'A', + '\u1EA2': 'A', + '\u00C5': 'A', + '\u01FA': 'A', + '\u01CD': 'A', + '\u0200': 'A', + '\u0202': 'A', + '\u1EA0': 'A', + '\u1EAC': 'A', + '\u1EB6': 'A', + '\u1E00': 'A', + '\u0104': 'A', + '\u023A': 'A', + '\u2C6F': 'A', + '\uA732': 'AA', + '\u00C6': 'AE', + '\u01FC': 'AE', + '\u01E2': 'AE', + '\uA734': 'AO', + '\uA736': 'AU', + '\uA738': 'AV', + '\uA73A': 'AV', + '\uA73C': 'AY', + '\u24B7': 'B', + '\uFF22': 'B', + '\u1E02': 'B', + '\u1E04': 'B', + '\u1E06': 'B', + '\u0243': 'B', + '\u0182': 'B', + '\u0181': 'B', + '\u24B8': 'C', + '\uFF23': 'C', + '\u0106': 'C', + '\u0108': 'C', + '\u010A': 'C', + '\u010C': 'C', + '\u00C7': 'C', + '\u1E08': 'C', + '\u0187': 'C', + '\u023B': 'C', + '\uA73E': 'C', + '\u24B9': 'D', + '\uFF24': 'D', + '\u1E0A': 'D', + '\u010E': 'D', + '\u1E0C': 'D', + '\u1E10': 'D', + '\u1E12': 'D', + '\u1E0E': 'D', + '\u0110': 'D', + '\u018B': 'D', + '\u018A': 'D', + '\u0189': 'D', + '\uA779': 'D', + '\u01F1': 'DZ', + '\u01C4': 'DZ', + '\u01F2': 'Dz', + '\u01C5': 'Dz', + '\u24BA': 'E', + '\uFF25': 'E', + '\u00C8': 'E', + '\u00C9': 'E', + '\u00CA': 'E', + '\u1EC0': 'E', + '\u1EBE': 'E', + '\u1EC4': 'E', + '\u1EC2': 'E', + '\u1EBC': 'E', + '\u0112': 'E', + '\u1E14': 'E', + '\u1E16': 'E', + '\u0114': 'E', + '\u0116': 'E', + '\u00CB': 'E', + '\u1EBA': 'E', + '\u011A': 'E', + '\u0204': 'E', + '\u0206': 'E', + '\u1EB8': 'E', + '\u1EC6': 'E', + '\u0228': 'E', + '\u1E1C': 'E', + '\u0118': 'E', + '\u1E18': 'E', + '\u1E1A': 'E', + '\u0190': 'E', + '\u018E': 'E', + '\u24BB': 'F', + '\uFF26': 'F', + '\u1E1E': 'F', + '\u0191': 'F', + '\uA77B': 'F', + '\u24BC': 'G', + '\uFF27': 'G', + '\u01F4': 'G', + '\u011C': 'G', + '\u1E20': 'G', + '\u011E': 'G', + '\u0120': 'G', + '\u01E6': 'G', + '\u0122': 'G', + '\u01E4': 'G', + '\u0193': 'G', + '\uA7A0': 'G', + '\uA77D': 'G', + '\uA77E': 'G', + '\u24BD': 'H', + '\uFF28': 'H', + '\u0124': 'H', + '\u1E22': 'H', + '\u1E26': 'H', + '\u021E': 'H', + '\u1E24': 'H', + '\u1E28': 'H', + '\u1E2A': 'H', + '\u0126': 'H', + '\u2C67': 'H', + '\u2C75': 'H', + '\uA78D': 'H', + '\u24BE': 'I', + '\uFF29': 'I', + '\u00CC': 'I', + '\u00CD': 'I', + '\u00CE': 'I', + '\u0128': 'I', + '\u012A': 'I', + '\u012C': 'I', + '\u0130': 'I', + '\u00CF': 'I', + '\u1E2E': 'I', + '\u1EC8': 'I', + '\u01CF': 'I', + '\u0208': 'I', + '\u020A': 'I', + '\u1ECA': 'I', + '\u012E': 'I', + '\u1E2C': 'I', + '\u0197': 'I', + '\u24BF': 'J', + '\uFF2A': 'J', + '\u0134': 'J', + '\u0248': 'J', + '\u24C0': 'K', + '\uFF2B': 'K', + '\u1E30': 'K', + '\u01E8': 'K', + '\u1E32': 'K', + '\u0136': 'K', + '\u1E34': 'K', + '\u0198': 'K', + '\u2C69': 'K', + '\uA740': 'K', + '\uA742': 'K', + '\uA744': 'K', + '\uA7A2': 'K', + '\u24C1': 'L', + '\uFF2C': 'L', + '\u013F': 'L', + '\u0139': 'L', + '\u013D': 'L', + '\u1E36': 'L', + '\u1E38': 'L', + '\u013B': 'L', + '\u1E3C': 'L', + '\u1E3A': 'L', + '\u0141': 'L', + '\u023D': 'L', + '\u2C62': 'L', + '\u2C60': 'L', + '\uA748': 'L', + '\uA746': 'L', + '\uA780': 'L', + '\u01C7': 'LJ', + '\u01C8': 'Lj', + '\u24C2': 'M', + '\uFF2D': 'M', + '\u1E3E': 'M', + '\u1E40': 'M', + '\u1E42': 'M', + '\u2C6E': 'M', + '\u019C': 'M', + '\u24C3': 'N', + '\uFF2E': 'N', + '\u01F8': 'N', + '\u0143': 'N', + '\u00D1': 'N', + '\u1E44': 'N', + '\u0147': 'N', + '\u1E46': 'N', + '\u0145': 'N', + '\u1E4A': 'N', + '\u1E48': 'N', + '\u0220': 'N', + '\u019D': 'N', + '\uA790': 'N', + '\uA7A4': 'N', + '\u01CA': 'NJ', + '\u01CB': 'Nj', + '\u24C4': 'O', + '\uFF2F': 'O', + '\u00D2': 'O', + '\u00D3': 'O', + '\u00D4': 'O', + '\u1ED2': 'O', + '\u1ED0': 'O', + '\u1ED6': 'O', + '\u1ED4': 'O', + '\u00D5': 'O', + '\u1E4C': 'O', + '\u022C': 'O', + '\u1E4E': 'O', + '\u014C': 'O', + '\u1E50': 'O', + '\u1E52': 'O', + '\u014E': 'O', + '\u022E': 'O', + '\u0230': 'O', + '\u00D6': 'O', + '\u022A': 'O', + '\u1ECE': 'O', + '\u0150': 'O', + '\u01D1': 'O', + '\u020C': 'O', + '\u020E': 'O', + '\u01A0': 'O', + '\u1EDC': 'O', + '\u1EDA': 'O', + '\u1EE0': 'O', + '\u1EDE': 'O', + '\u1EE2': 'O', + '\u1ECC': 'O', + '\u1ED8': 'O', + '\u01EA': 'O', + '\u01EC': 'O', + '\u00D8': 'O', + '\u01FE': 'O', + '\u0186': 'O', + '\u019F': 'O', + '\uA74A': 'O', + '\uA74C': 'O', + '\u0152': 'OE', + '\u01A2': 'OI', + '\uA74E': 'OO', + '\u0222': 'OU', + '\u24C5': 'P', + '\uFF30': 'P', + '\u1E54': 'P', + '\u1E56': 'P', + '\u01A4': 'P', + '\u2C63': 'P', + '\uA750': 'P', + '\uA752': 'P', + '\uA754': 'P', + '\u24C6': 'Q', + '\uFF31': 'Q', + '\uA756': 'Q', + '\uA758': 'Q', + '\u024A': 'Q', + '\u24C7': 'R', + '\uFF32': 'R', + '\u0154': 'R', + '\u1E58': 'R', + '\u0158': 'R', + '\u0210': 'R', + '\u0212': 'R', + '\u1E5A': 'R', + '\u1E5C': 'R', + '\u0156': 'R', + '\u1E5E': 'R', + '\u024C': 'R', + '\u2C64': 'R', + '\uA75A': 'R', + '\uA7A6': 'R', + '\uA782': 'R', + '\u24C8': 'S', + '\uFF33': 'S', + '\u1E9E': 'S', + '\u015A': 'S', + '\u1E64': 'S', + '\u015C': 'S', + '\u1E60': 'S', + '\u0160': 'S', + '\u1E66': 'S', + '\u1E62': 'S', + '\u1E68': 'S', + '\u0218': 'S', + '\u015E': 'S', + '\u2C7E': 'S', + '\uA7A8': 'S', + '\uA784': 'S', + '\u24C9': 'T', + '\uFF34': 'T', + '\u1E6A': 'T', + '\u0164': 'T', + '\u1E6C': 'T', + '\u021A': 'T', + '\u0162': 'T', + '\u1E70': 'T', + '\u1E6E': 'T', + '\u0166': 'T', + '\u01AC': 'T', + '\u01AE': 'T', + '\u023E': 'T', + '\uA786': 'T', + '\uA728': 'TZ', + '\u24CA': 'U', + '\uFF35': 'U', + '\u00D9': 'U', + '\u00DA': 'U', + '\u00DB': 'U', + '\u0168': 'U', + '\u1E78': 'U', + '\u016A': 'U', + '\u1E7A': 'U', + '\u016C': 'U', + '\u00DC': 'U', + '\u01DB': 'U', + '\u01D7': 'U', + '\u01D5': 'U', + '\u01D9': 'U', + '\u1EE6': 'U', + '\u016E': 'U', + '\u0170': 'U', + '\u01D3': 'U', + '\u0214': 'U', + '\u0216': 'U', + '\u01AF': 'U', + '\u1EEA': 'U', + '\u1EE8': 'U', + '\u1EEE': 'U', + '\u1EEC': 'U', + '\u1EF0': 'U', + '\u1EE4': 'U', + '\u1E72': 'U', + '\u0172': 'U', + '\u1E76': 'U', + '\u1E74': 'U', + '\u0244': 'U', + '\u24CB': 'V', + '\uFF36': 'V', + '\u1E7C': 'V', + '\u1E7E': 'V', + '\u01B2': 'V', + '\uA75E': 'V', + '\u0245': 'V', + '\uA760': 'VY', + '\u24CC': 'W', + '\uFF37': 'W', + '\u1E80': 'W', + '\u1E82': 'W', + '\u0174': 'W', + '\u1E86': 'W', + '\u1E84': 'W', + '\u1E88': 'W', + '\u2C72': 'W', + '\u24CD': 'X', + '\uFF38': 'X', + '\u1E8A': 'X', + '\u1E8C': 'X', + '\u24CE': 'Y', + '\uFF39': 'Y', + '\u1EF2': 'Y', + '\u00DD': 'Y', + '\u0176': 'Y', + '\u1EF8': 'Y', + '\u0232': 'Y', + '\u1E8E': 'Y', + '\u0178': 'Y', + '\u1EF6': 'Y', + '\u1EF4': 'Y', + '\u01B3': 'Y', + '\u024E': 'Y', + '\u1EFE': 'Y', + '\u24CF': 'Z', + '\uFF3A': 'Z', + '\u0179': 'Z', + '\u1E90': 'Z', + '\u017B': 'Z', + '\u017D': 'Z', + '\u1E92': 'Z', + '\u1E94': 'Z', + '\u01B5': 'Z', + '\u0224': 'Z', + '\u2C7F': 'Z', + '\u2C6B': 'Z', + '\uA762': 'Z', + '\u24D0': 'a', + '\uFF41': 'a', + '\u1E9A': 'a', + '\u00E0': 'a', + '\u00E1': 'a', + '\u00E2': 'a', + '\u1EA7': 'a', + '\u1EA5': 'a', + '\u1EAB': 'a', + '\u1EA9': 'a', + '\u00E3': 'a', + '\u0101': 'a', + '\u0103': 'a', + '\u1EB1': 'a', + '\u1EAF': 'a', + '\u1EB5': 'a', + '\u1EB3': 'a', + '\u0227': 'a', + '\u01E1': 'a', + '\u00E4': 'a', + '\u01DF': 'a', + '\u1EA3': 'a', + '\u00E5': 'a', + '\u01FB': 'a', + '\u01CE': 'a', + '\u0201': 'a', + '\u0203': 'a', + '\u1EA1': 'a', + '\u1EAD': 'a', + '\u1EB7': 'a', + '\u1E01': 'a', + '\u0105': 'a', + '\u2C65': 'a', + '\u0250': 'a', + '\uA733': 'aa', + '\u00E6': 'ae', + '\u01FD': 'ae', + '\u01E3': 'ae', + '\uA735': 'ao', + '\uA737': 'au', + '\uA739': 'av', + '\uA73B': 'av', + '\uA73D': 'ay', + '\u24D1': 'b', + '\uFF42': 'b', + '\u1E03': 'b', + '\u1E05': 'b', + '\u1E07': 'b', + '\u0180': 'b', + '\u0183': 'b', + '\u0253': 'b', + '\u24D2': 'c', + '\uFF43': 'c', + '\u0107': 'c', + '\u0109': 'c', + '\u010B': 'c', + '\u010D': 'c', + '\u00E7': 'c', + '\u1E09': 'c', + '\u0188': 'c', + '\u023C': 'c', + '\uA73F': 'c', + '\u2184': 'c', + '\u24D3': 'd', + '\uFF44': 'd', + '\u1E0B': 'd', + '\u010F': 'd', + '\u1E0D': 'd', + '\u1E11': 'd', + '\u1E13': 'd', + '\u1E0F': 'd', + '\u0111': 'd', + '\u018C': 'd', + '\u0256': 'd', + '\u0257': 'd', + '\uA77A': 'd', + '\u01F3': 'dz', + '\u01C6': 'dz', + '\u24D4': 'e', + '\uFF45': 'e', + '\u00E8': 'e', + '\u00E9': 'e', + '\u00EA': 'e', + '\u1EC1': 'e', + '\u1EBF': 'e', + '\u1EC5': 'e', + '\u1EC3': 'e', + '\u1EBD': 'e', + '\u0113': 'e', + '\u1E15': 'e', + '\u1E17': 'e', + '\u0115': 'e', + '\u0117': 'e', + '\u00EB': 'e', + '\u1EBB': 'e', + '\u011B': 'e', + '\u0205': 'e', + '\u0207': 'e', + '\u1EB9': 'e', + '\u1EC7': 'e', + '\u0229': 'e', + '\u1E1D': 'e', + '\u0119': 'e', + '\u1E19': 'e', + '\u1E1B': 'e', + '\u0247': 'e', + '\u025B': 'e', + '\u01DD': 'e', + '\u24D5': 'f', + '\uFF46': 'f', + '\u1E1F': 'f', + '\u0192': 'f', + '\uA77C': 'f', + '\u24D6': 'g', + '\uFF47': 'g', + '\u01F5': 'g', + '\u011D': 'g', + '\u1E21': 'g', + '\u011F': 'g', + '\u0121': 'g', + '\u01E7': 'g', + '\u0123': 'g', + '\u01E5': 'g', + '\u0260': 'g', + '\uA7A1': 'g', + '\u1D79': 'g', + '\uA77F': 'g', + '\u24D7': 'h', + '\uFF48': 'h', + '\u0125': 'h', + '\u1E23': 'h', + '\u1E27': 'h', + '\u021F': 'h', + '\u1E25': 'h', + '\u1E29': 'h', + '\u1E2B': 'h', + '\u1E96': 'h', + '\u0127': 'h', + '\u2C68': 'h', + '\u2C76': 'h', + '\u0265': 'h', + '\u0195': 'hv', + '\u24D8': 'i', + '\uFF49': 'i', + '\u00EC': 'i', + '\u00ED': 'i', + '\u00EE': 'i', + '\u0129': 'i', + '\u012B': 'i', + '\u012D': 'i', + '\u00EF': 'i', + '\u1E2F': 'i', + '\u1EC9': 'i', + '\u01D0': 'i', + '\u0209': 'i', + '\u020B': 'i', + '\u1ECB': 'i', + '\u012F': 'i', + '\u1E2D': 'i', + '\u0268': 'i', + '\u0131': 'i', + '\u24D9': 'j', + '\uFF4A': 'j', + '\u0135': 'j', + '\u01F0': 'j', + '\u0249': 'j', + '\u24DA': 'k', + '\uFF4B': 'k', + '\u1E31': 'k', + '\u01E9': 'k', + '\u1E33': 'k', + '\u0137': 'k', + '\u1E35': 'k', + '\u0199': 'k', + '\u2C6A': 'k', + '\uA741': 'k', + '\uA743': 'k', + '\uA745': 'k', + '\uA7A3': 'k', + '\u24DB': 'l', + '\uFF4C': 'l', + '\u0140': 'l', + '\u013A': 'l', + '\u013E': 'l', + '\u1E37': 'l', + '\u1E39': 'l', + '\u013C': 'l', + '\u1E3D': 'l', + '\u1E3B': 'l', + '\u017F': 'l', + '\u0142': 'l', + '\u019A': 'l', + '\u026B': 'l', + '\u2C61': 'l', + '\uA749': 'l', + '\uA781': 'l', + '\uA747': 'l', + '\u01C9': 'lj', + '\u24DC': 'm', + '\uFF4D': 'm', + '\u1E3F': 'm', + '\u1E41': 'm', + '\u1E43': 'm', + '\u0271': 'm', + '\u026F': 'm', + '\u24DD': 'n', + '\uFF4E': 'n', + '\u01F9': 'n', + '\u0144': 'n', + '\u00F1': 'n', + '\u1E45': 'n', + '\u0148': 'n', + '\u1E47': 'n', + '\u0146': 'n', + '\u1E4B': 'n', + '\u1E49': 'n', + '\u019E': 'n', + '\u0272': 'n', + '\u0149': 'n', + '\uA791': 'n', + '\uA7A5': 'n', + '\u01CC': 'nj', + '\u24DE': 'o', + '\uFF4F': 'o', + '\u00F2': 'o', + '\u00F3': 'o', + '\u00F4': 'o', + '\u1ED3': 'o', + '\u1ED1': 'o', + '\u1ED7': 'o', + '\u1ED5': 'o', + '\u00F5': 'o', + '\u1E4D': 'o', + '\u022D': 'o', + '\u1E4F': 'o', + '\u014D': 'o', + '\u1E51': 'o', + '\u1E53': 'o', + '\u014F': 'o', + '\u022F': 'o', + '\u0231': 'o', + '\u00F6': 'o', + '\u022B': 'o', + '\u1ECF': 'o', + '\u0151': 'o', + '\u01D2': 'o', + '\u020D': 'o', + '\u020F': 'o', + '\u01A1': 'o', + '\u1EDD': 'o', + '\u1EDB': 'o', + '\u1EE1': 'o', + '\u1EDF': 'o', + '\u1EE3': 'o', + '\u1ECD': 'o', + '\u1ED9': 'o', + '\u01EB': 'o', + '\u01ED': 'o', + '\u00F8': 'o', + '\u01FF': 'o', + '\u0254': 'o', + '\uA74B': 'o', + '\uA74D': 'o', + '\u0275': 'o', + '\u0153': 'oe', + '\u01A3': 'oi', + '\u0223': 'ou', + '\uA74F': 'oo', + '\u24DF': 'p', + '\uFF50': 'p', + '\u1E55': 'p', + '\u1E57': 'p', + '\u01A5': 'p', + '\u1D7D': 'p', + '\uA751': 'p', + '\uA753': 'p', + '\uA755': 'p', + '\u24E0': 'q', + '\uFF51': 'q', + '\u024B': 'q', + '\uA757': 'q', + '\uA759': 'q', + '\u24E1': 'r', + '\uFF52': 'r', + '\u0155': 'r', + '\u1E59': 'r', + '\u0159': 'r', + '\u0211': 'r', + '\u0213': 'r', + '\u1E5B': 'r', + '\u1E5D': 'r', + '\u0157': 'r', + '\u1E5F': 'r', + '\u024D': 'r', + '\u027D': 'r', + '\uA75B': 'r', + '\uA7A7': 'r', + '\uA783': 'r', + '\u24E2': 's', + '\uFF53': 's', + '\u00DF': 's', + '\u015B': 's', + '\u1E65': 's', + '\u015D': 's', + '\u1E61': 's', + '\u0161': 's', + '\u1E67': 's', + '\u1E63': 's', + '\u1E69': 's', + '\u0219': 's', + '\u015F': 's', + '\u023F': 's', + '\uA7A9': 's', + '\uA785': 's', + '\u1E9B': 's', + '\u24E3': 't', + '\uFF54': 't', + '\u1E6B': 't', + '\u1E97': 't', + '\u0165': 't', + '\u1E6D': 't', + '\u021B': 't', + '\u0163': 't', + '\u1E71': 't', + '\u1E6F': 't', + '\u0167': 't', + '\u01AD': 't', + '\u0288': 't', + '\u2C66': 't', + '\uA787': 't', + '\uA729': 'tz', + '\u24E4': 'u', + '\uFF55': 'u', + '\u00F9': 'u', + '\u00FA': 'u', + '\u00FB': 'u', + '\u0169': 'u', + '\u1E79': 'u', + '\u016B': 'u', + '\u1E7B': 'u', + '\u016D': 'u', + '\u00FC': 'u', + '\u01DC': 'u', + '\u01D8': 'u', + '\u01D6': 'u', + '\u01DA': 'u', + '\u1EE7': 'u', + '\u016F': 'u', + '\u0171': 'u', + '\u01D4': 'u', + '\u0215': 'u', + '\u0217': 'u', + '\u01B0': 'u', + '\u1EEB': 'u', + '\u1EE9': 'u', + '\u1EEF': 'u', + '\u1EED': 'u', + '\u1EF1': 'u', + '\u1EE5': 'u', + '\u1E73': 'u', + '\u0173': 'u', + '\u1E77': 'u', + '\u1E75': 'u', + '\u0289': 'u', + '\u24E5': 'v', + '\uFF56': 'v', + '\u1E7D': 'v', + '\u1E7F': 'v', + '\u028B': 'v', + '\uA75F': 'v', + '\u028C': 'v', + '\uA761': 'vy', + '\u24E6': 'w', + '\uFF57': 'w', + '\u1E81': 'w', + '\u1E83': 'w', + '\u0175': 'w', + '\u1E87': 'w', + '\u1E85': 'w', + '\u1E98': 'w', + '\u1E89': 'w', + '\u2C73': 'w', + '\u24E7': 'x', + '\uFF58': 'x', + '\u1E8B': 'x', + '\u1E8D': 'x', + '\u24E8': 'y', + '\uFF59': 'y', + '\u1EF3': 'y', + '\u00FD': 'y', + '\u0177': 'y', + '\u1EF9': 'y', + '\u0233': 'y', + '\u1E8F': 'y', + '\u00FF': 'y', + '\u1EF7': 'y', + '\u1E99': 'y', + '\u1EF5': 'y', + '\u01B4': 'y', + '\u024F': 'y', + '\u1EFF': 'y', + '\u24E9': 'z', + '\uFF5A': 'z', + '\u017A': 'z', + '\u1E91': 'z', + '\u017C': 'z', + '\u017E': 'z', + '\u1E93': 'z', + '\u1E95': 'z', + '\u01B6': 'z', + '\u0225': 'z', + '\u0240': 'z', + '\u2C6C': 'z', + '\uA763': 'z', + '\u0386': '\u0391', + '\u0388': '\u0395', + '\u0389': '\u0397', + '\u038A': '\u0399', + '\u03AA': '\u0399', + '\u038C': '\u039F', + '\u038E': '\u03A5', + '\u03AB': '\u03A5', + '\u038F': '\u03A9', + '\u03AC': '\u03B1', + '\u03AD': '\u03B5', + '\u03AE': '\u03B7', + '\u03AF': '\u03B9', + '\u03CA': '\u03B9', + '\u0390': '\u03B9', + '\u03CC': '\u03BF', + '\u03CD': '\u03C5', + '\u03CB': '\u03C5', + '\u03B0': '\u03C5', + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' + }; + + return diacritics; +}); + +S2.define('select2/data/base',[ + '../utils' +], function (Utils) { + function BaseAdapter ($element, options) { + BaseAdapter.__super__.constructor.call(this); + } + + Utils.Extend(BaseAdapter, Utils.Observable); + + BaseAdapter.prototype.current = function (callback) { + throw new Error('The `current` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.query = function (params, callback) { + throw new Error('The `query` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.bind = function (container, $container) { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.destroy = function () { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.generateResultId = function (container, data) { + var id = container.id + '-result-'; + + id += Utils.generateChars(4); + + if (data.id != null) { + id += '-' + data.id.toString(); + } else { + id += '-' + Utils.generateChars(4); + } + return id; + }; + + return BaseAdapter; +}); + +S2.define('select2/data/select',[ + './base', + '../utils', + 'jquery' +], function (BaseAdapter, Utils, $) { + function SelectAdapter ($element, options) { + this.$element = $element; + this.options = options; + + SelectAdapter.__super__.constructor.call(this); + } + + Utils.Extend(SelectAdapter, BaseAdapter); + + SelectAdapter.prototype.current = function (callback) { + var data = []; + var self = this; + + this.$element.find(':selected').each(function () { + var $option = $(this); + + var option = self.item($option); + + data.push(option); + }); + + callback(data); + }; + + SelectAdapter.prototype.select = function (data) { + var self = this; + + data.selected = true; + + // If data.element is a DOM node, use it instead + if ($(data.element).is('option')) { + data.element.selected = true; + + this.$element.trigger('input').trigger('change'); + + return; + } + + if (this.$element.prop('multiple')) { + this.current(function (currentData) { + var val = []; + + data = [data]; + data.push.apply(data, currentData); + + for (var d = 0; d < data.length; d++) { + var id = data[d].id; + + if ($.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + self.$element.trigger('input').trigger('change'); + }); + } else { + var val = data.id; + + this.$element.val(val); + this.$element.trigger('input').trigger('change'); + } + }; + + SelectAdapter.prototype.unselect = function (data) { + var self = this; + + if (!this.$element.prop('multiple')) { + return; + } + + data.selected = false; + + if ($(data.element).is('option')) { + data.element.selected = false; + + this.$element.trigger('input').trigger('change'); + + return; + } + + this.current(function (currentData) { + var val = []; + + for (var d = 0; d < currentData.length; d++) { + var id = currentData[d].id; + + if (id !== data.id && $.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + + self.$element.trigger('input').trigger('change'); + }); + }; + + SelectAdapter.prototype.bind = function (container, $container) { + var self = this; + + this.container = container; + + container.on('select', function (params) { + self.select(params.data); + }); + + container.on('unselect', function (params) { + self.unselect(params.data); + }); + }; + + SelectAdapter.prototype.destroy = function () { + // Remove anything added to child elements + this.$element.find('*').each(function () { + // Remove any custom data set by Select2 + Utils.RemoveData(this); + }); + }; + + SelectAdapter.prototype.query = function (params, callback) { + var data = []; + var self = this; + + var $options = this.$element.children(); + + $options.each(function () { + var $option = $(this); + + if (!$option.is('option') && !$option.is('optgroup')) { + return; + } + + var option = self.item($option); + + var matches = self.matches(params, option); + + if (matches !== null) { + data.push(matches); + } + }); + + callback({ + results: data + }); + }; + + SelectAdapter.prototype.addOptions = function ($options) { + Utils.appendMany(this.$element, $options); + }; + + SelectAdapter.prototype.option = function (data) { + var option; + + if (data.children) { + option = document.createElement('optgroup'); + option.label = data.text; + } else { + option = document.createElement('option'); + + if (option.textContent !== undefined) { + option.textContent = data.text; + } else { + option.innerText = data.text; + } + } + + if (data.id !== undefined) { + option.value = data.id; + } + + if (data.disabled) { + option.disabled = true; + } + + if (data.selected) { + option.selected = true; + } + + if (data.title) { + option.title = data.title; + } + + var $option = $(option); + + var normalizedData = this._normalizeItem(data); + normalizedData.element = option; + + // Override the option's data with the combined data + Utils.StoreData(option, 'data', normalizedData); + + return $option; + }; + + SelectAdapter.prototype.item = function ($option) { + var data = {}; + + data = Utils.GetData($option[0], 'data'); + + if (data != null) { + return data; + } + + if ($option.is('option')) { + data = { + id: $option.val(), + text: $option.text(), + disabled: $option.prop('disabled'), + selected: $option.prop('selected'), + title: $option.prop('title') + }; + } else if ($option.is('optgroup')) { + data = { + text: $option.prop('label'), + children: [], + title: $option.prop('title') + }; + + var $children = $option.children('option'); + var children = []; + + for (var c = 0; c < $children.length; c++) { + var $child = $($children[c]); + + var child = this.item($child); + + children.push(child); + } + + data.children = children; + } + + data = this._normalizeItem(data); + data.element = $option[0]; + + Utils.StoreData($option[0], 'data', data); + + return data; + }; + + SelectAdapter.prototype._normalizeItem = function (item) { + if (item !== Object(item)) { + item = { + id: item, + text: item + }; + } + + item = $.extend({}, { + text: '' + }, item); + + var defaults = { + selected: false, + disabled: false + }; + + if (item.id != null) { + item.id = item.id.toString(); + } + + if (item.text != null) { + item.text = item.text.toString(); + } + + if (item._resultId == null && item.id && this.container != null) { + item._resultId = this.generateResultId(this.container, item); + } + + return $.extend({}, defaults, item); + }; + + SelectAdapter.prototype.matches = function (params, data) { + var matcher = this.options.get('matcher'); + + return matcher(params, data); + }; + + return SelectAdapter; +}); + +S2.define('select2/data/array',[ + './select', + '../utils', + 'jquery' +], function (SelectAdapter, Utils, $) { + function ArrayAdapter ($element, options) { + this._dataToConvert = options.get('data') || []; + + ArrayAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(ArrayAdapter, SelectAdapter); + + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + + ArrayAdapter.prototype.select = function (data) { + var $option = this.$element.find('option').filter(function (i, elm) { + return elm.value == data.id.toString(); + }); + + if ($option.length === 0) { + $option = this.option(data); + + this.addOptions($option); + } + + ArrayAdapter.__super__.select.call(this, data); + }; + + ArrayAdapter.prototype.convertToOptions = function (data) { + var self = this; + + var $existing = this.$element.find('option'); + var existingIds = $existing.map(function () { + return self.item($(this)).id; + }).get(); + + var $options = []; + + // Filter out all items except for the one passed in the argument + function onlyItem (item) { + return function () { + return $(this).val() == item.id; + }; + } + + for (var d = 0; d < data.length; d++) { + var item = this._normalizeItem(data[d]); + + // Skip items which were pre-loaded, only merge the data + if ($.inArray(item.id, existingIds) >= 0) { + var $existingOption = $existing.filter(onlyItem(item)); + + var existingData = this.item($existingOption); + var newData = $.extend(true, {}, item, existingData); + + var $newOption = this.option(newData); + + $existingOption.replaceWith($newOption); + + continue; + } + + var $option = this.option(item); + + if (item.children) { + var $children = this.convertToOptions(item.children); + + Utils.appendMany($option, $children); + } + + $options.push($option); + } + + return $options; + }; + + return ArrayAdapter; +}); + +S2.define('select2/data/ajax',[ + './array', + '../utils', + 'jquery' +], function (ArrayAdapter, Utils, $) { + function AjaxAdapter ($element, options) { + this.ajaxOptions = this._applyDefaults(options.get('ajax')); + + if (this.ajaxOptions.processResults != null) { + this.processResults = this.ajaxOptions.processResults; + } + + AjaxAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(AjaxAdapter, ArrayAdapter); + + AjaxAdapter.prototype._applyDefaults = function (options) { + var defaults = { + data: function (params) { + return $.extend({}, params, { + q: params.term + }); + }, + transport: function (params, success, failure) { + var $request = $.ajax(params); + + $request.then(success); + $request.fail(failure); + + return $request; + } + }; + + return $.extend({}, defaults, options, true); + }; + + AjaxAdapter.prototype.processResults = function (results) { + return results; + }; + + AjaxAdapter.prototype.query = function (params, callback) { + var matches = []; + var self = this; + + if (this._request != null) { + // JSONP requests cannot always be aborted + if ($.isFunction(this._request.abort)) { + this._request.abort(); + } + + this._request = null; + } + + var options = $.extend({ + type: 'GET' + }, this.ajaxOptions); + + if (typeof options.url === 'function') { + options.url = options.url.call(this.$element, params); + } + + if (typeof options.data === 'function') { + options.data = options.data.call(this.$element, params); + } + + function request () { + var $request = options.transport(options, function (data) { + var results = self.processResults(data, params); + + if (self.options.get('debug') && window.console && console.error) { + // Check to make sure that the response included a `results` key. + if (!results || !results.results || !$.isArray(results.results)) { + console.error( + 'Select2: The AJAX results did not return an array in the ' + + '`results` key of the response.' + ); + } + } + + callback(results); + }, function () { + // Attempt to detect if a request was aborted + // Only works if the transport exposes a status property + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { + return; + } + + self.trigger('results:message', { + message: 'errorLoading' + }); + }); + + self._request = $request; + } + + if (this.ajaxOptions.delay && params.term != null) { + if (this._queryTimeout) { + window.clearTimeout(this._queryTimeout); + } + + this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); + } else { + request(); + } + }; + + return AjaxAdapter; +}); + +S2.define('select2/data/tags',[ + 'jquery' +], function ($) { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + var createTag = options.get('createTag'); + + if (createTag !== undefined) { + this.createTag = createTag; + } + + var insertTag = options.get('insertTag'); + + if (insertTag !== undefined) { + this.insertTag = insertTag; + } + + decorated.call(this, $element, options); + + if ($.isArray(tags)) { + for (var t = 0; t < tags.length; t++) { + var tag = tags[t]; + var item = this._normalizeItem(tag); + + var $option = this.option(item); + + this.$element.append($option); + } + } + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + this._removeOldTags(); + + if (params.term == null || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (obj, child) { + var data = obj.results; + + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && + !wrapper({ + results: option.children + }, true) + ); + + var optionText = (option.text || '').toUpperCase(); + var paramsTerm = (params.term || '').toUpperCase(); + + var checkText = optionText === paramsTerm; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + obj.data = data; + callback(obj); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + + if (tag != null) { + var $option = self.option(tag); + $option.attr('data-select2-tag', true); + + self.addOptions([$option]); + + self.insertTag(data, tag); + } + + obj.results = data; + + callback(obj); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + var term = $.trim(params.term); + + if (term === '') { + return null; + } + + return { + id: term, + text: term + }; + }; + + Tags.prototype.insertTag = function (_, data, tag) { + data.unshift(tag); + }; + + Tags.prototype._removeOldTags = function (_) { + var $options = this.$element.find('option[data-select2-tag]'); + + $options.each(function () { + if (this.selected) { + return; + } + + $(this).remove(); + }); + }; + + return Tags; +}); + +S2.define('select2/data/tokenizer',[ + 'jquery' +], function ($) { + function Tokenizer (decorated, $element, options) { + var tokenizer = options.get('tokenizer'); + + if (tokenizer !== undefined) { + this.tokenizer = tokenizer; + } + + decorated.call(this, $element, options); + } + + Tokenizer.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + this.$search = container.dropdown.$search || container.selection.$search || + $container.find('.select2-search__field'); + }; + + Tokenizer.prototype.query = function (decorated, params, callback) { + var self = this; + + function createAndSelect (data) { + // Normalize the data object so we can use it for checks + var item = self._normalizeItem(data); + + // Check if the data object already exists as a tag + // Select it if it doesn't + var $existingOptions = self.$element.find('option').filter(function () { + return $(this).val() === item.id; + }); + + // If an existing option wasn't found for it, create the option + if (!$existingOptions.length) { + var $option = self.option(item); + $option.attr('data-select2-tag', true); + + self._removeOldTags(); + self.addOptions([$option]); + } + + // Select the item, now that we know there is an option for it + select(item); + } + + function select (data) { + self.trigger('select', { + data: data + }); + } + + params.term = params.term || ''; + + var tokenData = this.tokenizer(params, this.options, createAndSelect); + + if (tokenData.term !== params.term) { + // Replace the search term if we have the search box + if (this.$search.length) { + this.$search.val(tokenData.term); + this.$search.trigger('focus'); + } + + params.term = tokenData.term; + } + + decorated.call(this, params, callback); + }; + + Tokenizer.prototype.tokenizer = function (_, params, options, callback) { + var separators = options.get('tokenSeparators') || []; + var term = params.term; + var i = 0; + + var createTag = this.createTag || function (params) { + return { + id: params.term, + text: params.term + }; + }; + + while (i < term.length) { + var termChar = term[i]; + + if ($.inArray(termChar, separators) === -1) { + i++; + + continue; + } + + var part = term.substr(0, i); + var partParams = $.extend({}, params, { + term: part + }); + + var data = createTag(partParams); + + if (data == null) { + i++; + continue; + } + + callback(data); + + // Reset the term to not include the tokenized portion + term = term.substr(i + 1) || ''; + i = 0; + } + + return { + term: term + }; + }; + + return Tokenizer; +}); + +S2.define('select2/data/minimumInputLength',[ + +], function () { + function MinimumInputLength (decorated, $e, options) { + this.minimumInputLength = options.get('minimumInputLength'); + + decorated.call(this, $e, options); + } + + MinimumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (params.term.length < this.minimumInputLength) { + this.trigger('results:message', { + message: 'inputTooShort', + args: { + minimum: this.minimumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MinimumInputLength; +}); + +S2.define('select2/data/maximumInputLength',[ + +], function () { + function MaximumInputLength (decorated, $e, options) { + this.maximumInputLength = options.get('maximumInputLength'); + + decorated.call(this, $e, options); + } + + MaximumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (this.maximumInputLength > 0 && + params.term.length > this.maximumInputLength) { + this.trigger('results:message', { + message: 'inputTooLong', + args: { + maximum: this.maximumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MaximumInputLength; +}); + +S2.define('select2/data/maximumSelectionLength',[ + +], function (){ + function MaximumSelectionLength (decorated, $e, options) { + this.maximumSelectionLength = options.get('maximumSelectionLength'); + + decorated.call(this, $e, options); + } + + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + + MaximumSelectionLength.prototype.query = + function (decorated, params, callback) { + var self = this; + + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + + this.current(function (currentData) { + var count = currentData != null ? currentData.length : 0; + if (self.maximumSelectionLength > 0 && + count >= self.maximumSelectionLength) { + self.trigger('results:message', { + message: 'maximumSelected', + args: { + maximum: self.maximumSelectionLength + } + }); + return; + } + + if (successCallback) { + successCallback(); + } + }); + }; + + return MaximumSelectionLength; +}); + +S2.define('select2/dropdown',[ + 'jquery', + './utils' +], function ($, Utils) { + function Dropdown ($element, options) { + this.$element = $element; + this.options = options; + + Dropdown.__super__.constructor.call(this); + } + + Utils.Extend(Dropdown, Utils.Observable); + + Dropdown.prototype.render = function () { + var $dropdown = $( + '' + + '' + + '' + ); + + $dropdown.attr('dir', this.options.get('dir')); + + this.$dropdown = $dropdown; + + return $dropdown; + }; + + Dropdown.prototype.bind = function () { + // Should be implemented in subclasses + }; + + Dropdown.prototype.position = function ($dropdown, $container) { + // Should be implemented in subclasses + }; + + Dropdown.prototype.destroy = function () { + // Remove the dropdown from the DOM + this.$dropdown.remove(); + }; + + return Dropdown; +}); + +S2.define('select2/dropdown/search',[ + 'jquery', + '../utils' +], function ($, Utils) { + function Search () { } + + Search.prototype.render = function (decorated) { + var $rendered = decorated.call(this); + + var $search = $( + '' + + '' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + $rendered.prepend($search); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + decorated.call(this, container, $container); + + this.$search.on('keydown', function (evt) { + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + }); + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$search.on('input', function (evt) { + // Unbind the duplicated `keyup` event + $(this).off('keyup'); + }); + + this.$search.on('keyup input', function (evt) { + self.handleSearch(evt); + }); + + container.on('open', function () { + self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); + + self.$search.trigger('focus'); + + window.setTimeout(function () { + self.$search.trigger('focus'); + }, 0); + }); + + container.on('close', function () { + self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); + + self.$search.val(''); + self.$search.trigger('blur'); + }); + + container.on('focus', function () { + if (!container.isOpen()) { + self.$search.trigger('focus'); + } + }); + + container.on('results:all', function (params) { + if (params.query.term == null || params.query.term === '') { + var showSearch = self.showSearch(params); + + if (showSearch) { + self.$searchContainer.removeClass('select2-search--hide'); + } else { + self.$searchContainer.addClass('select2-search--hide'); + } + } + }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); + }; + + Search.prototype.handleSearch = function (evt) { + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.showSearch = function (_, params) { + return true; + }; + + return Search; +}); + +S2.define('select2/dropdown/hidePlaceholder',[ + +], function () { + function HidePlaceholder (decorated, $element, options, dataAdapter) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options, dataAdapter); + } + + HidePlaceholder.prototype.append = function (decorated, data) { + data.results = this.removePlaceholder(data.results); + + decorated.call(this, data); + }; + + HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + HidePlaceholder.prototype.removePlaceholder = function (_, data) { + var modifiedData = data.slice(0); + + for (var d = data.length - 1; d >= 0; d--) { + var item = data[d]; + + if (this.placeholder.id === item.id) { + modifiedData.splice(d, 1); + } + } + + return modifiedData; + }; + + return HidePlaceholder; +}); + +S2.define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + this.loading = false; + + decorated.call(this, data); + + if (this.showLoadingMore(data)) { + this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); + } + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; + + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); + + if (this.loading || !isLoadMoreVisible) { + return; + } + + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.showLoadingMore = function (_, data) { + return data.pagination && data.pagination.more; + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
              • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + +S2.define('select2/dropdown/attachBody',[ + 'jquery', + '../utils' +], function ($, Utils) { + function AttachBody (decorated, $element, options) { + this.$dropdownParent = $(options.get('dropdownParent') || document.body); + + decorated.call(this, $element, options); + } + + AttachBody.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('open', function () { + self._showDropdown(); + self._attachPositioningHandler(container); + + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); + }); + + container.on('close', function () { + self._hideDropdown(); + self._detachPositioningHandler(container); + }); + + this.$dropdownContainer.on('mousedown', function (evt) { + evt.stopPropagation(); + }); + }; + + AttachBody.prototype.destroy = function (decorated) { + decorated.call(this); + + this.$dropdownContainer.remove(); + }; + + AttachBody.prototype.position = function (decorated, $dropdown, $container) { + // Clone all of the container classes + $dropdown.attr('class', $container.attr('class')); + + $dropdown.removeClass('select2'); + $dropdown.addClass('select2-container--open'); + + $dropdown.css({ + position: 'absolute', + top: -999999 + }); + + this.$container = $container; + }; + + AttachBody.prototype.render = function (decorated) { + var $container = $(''); + + var $dropdown = decorated.call(this); + $container.append($dropdown); + + this.$dropdownContainer = $container; + + return $container; + }; + + AttachBody.prototype._hideDropdown = function (decorated) { + this.$dropdownContainer.detach(); + }; + + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + + AttachBody.prototype._attachPositioningHandler = + function (decorated, container) { + var self = this; + + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.each(function () { + Utils.StoreData(this, 'select2-scroll-position', { + x: $(this).scrollLeft(), + y: $(this).scrollTop() + }); + }); + + $watchers.on(scrollEvent, function (ev) { + var position = Utils.GetData(this, 'select2-scroll-position'); + $(this).scrollTop(position.y); + }); + + $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, + function (e) { + self._positionDropdown(); + self._resizeDropdown(); + }); + }; + + AttachBody.prototype._detachPositioningHandler = + function (decorated, container) { + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.off(scrollEvent); + + $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); + }; + + AttachBody.prototype._positionDropdown = function () { + var $window = $(window); + + var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); + var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); + + var newDirection = null; + + var offset = this.$container.offset(); + + offset.bottom = offset.top + this.$container.outerHeight(false); + + var container = { + height: this.$container.outerHeight(false) + }; + + container.top = offset.top; + container.bottom = offset.top + container.height; + + var dropdown = { + height: this.$dropdown.outerHeight(false) + }; + + var viewport = { + top: $window.scrollTop(), + bottom: $window.scrollTop() + $window.height() + }; + + var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); + var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); + + var css = { + left: offset.left, + top: container.bottom + }; + + // Determine what the parent element is to use for calculating the offset + var $offsetParent = this.$dropdownParent; + + // For statically positioned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); + } + + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } + + css.top -= parentOffset.top; + css.left -= parentOffset.left; + + if (!isCurrentlyAbove && !isCurrentlyBelow) { + newDirection = 'below'; + } + + if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { + newDirection = 'above'; + } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { + newDirection = 'below'; + } + + if (newDirection == 'above' || + (isCurrentlyAbove && newDirection !== 'below')) { + css.top = container.top - parentOffset.top - dropdown.height; + } + + if (newDirection != null) { + this.$dropdown + .removeClass('select2-dropdown--below select2-dropdown--above') + .addClass('select2-dropdown--' + newDirection); + this.$container + .removeClass('select2-container--below select2-container--above') + .addClass('select2-container--' + newDirection); + } + + this.$dropdownContainer.css(css); + }; + + AttachBody.prototype._resizeDropdown = function () { + var css = { + width: this.$container.outerWidth(false) + 'px' + }; + + if (this.options.get('dropdownAutoWidth')) { + css.minWidth = css.width; + css.position = 'relative'; + css.width = 'auto'; + } + + this.$dropdown.css(css); + }; + + AttachBody.prototype._showDropdown = function (decorated) { + this.$dropdownContainer.appendTo(this.$dropdownParent); + + this._positionDropdown(); + this._resizeDropdown(); + }; + + return AttachBody; +}); + +S2.define('select2/dropdown/minimumResultsForSearch',[ + +], function () { + function countResults (data) { + var count = 0; + + for (var d = 0; d < data.length; d++) { + var item = data[d]; + + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + } + + return count; + } + + function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { + this.minimumResultsForSearch = options.get('minimumResultsForSearch'); + + if (this.minimumResultsForSearch < 0) { + this.minimumResultsForSearch = Infinity; + } + + decorated.call(this, $element, options, dataAdapter); + } + + MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { + if (countResults(params.data.results) < this.minimumResultsForSearch) { + return false; + } + + return decorated.call(this, params); + }; + + return MinimumResultsForSearch; +}); + +S2.define('select2/dropdown/selectOnClose',[ + '../utils' +], function (Utils) { + function SelectOnClose () { } + + SelectOnClose.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('close', function (params) { + self._handleSelectOnClose(params); + }); + }; + + SelectOnClose.prototype._handleSelectOnClose = function (_, params) { + if (params && params.originalSelect2Event != null) { + var event = params.originalSelect2Event; + + // Don't select an item if the close event was triggered from a select or + // unselect event + if (event._type === 'select' || event._type === 'unselect') { + return; + } + } + + var $highlightedResults = this.getHighlightedResults(); + + // Only select highlighted results + if ($highlightedResults.length < 1) { + return; + } + + var data = Utils.GetData($highlightedResults[0], 'data'); + + // Don't re-select already selected resulte + if ( + (data.element != null && data.element.selected) || + (data.element == null && data.selected) + ) { + return; + } + + this.trigger('select', { + data: data + }); + }; + + return SelectOnClose; +}); + +S2.define('select2/dropdown/closeOnSelect',[ + +], function () { + function CloseOnSelect () { } + + CloseOnSelect.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function (evt) { + self._selectTriggered(evt); + }); + + container.on('unselect', function (evt) { + self._selectTriggered(evt); + }); + }; + + CloseOnSelect.prototype._selectTriggered = function (_, evt) { + var originalEvent = evt.originalEvent; + + // Don't close if the control key is being held + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { + return; + } + + this.trigger('close', { + originalEvent: originalEvent, + originalSelect2Event: evt + }); + }; + + return CloseOnSelect; +}); + +S2.define('select2/i18n/en',[],function () { + // English + return { + errorLoading: function () { + return 'The results could not be loaded.'; + }, + inputTooLong: function (args) { + var overChars = args.input.length - args.maximum; + + var message = 'Please delete ' + overChars + ' character'; + + if (overChars != 1) { + message += 's'; + } + + return message; + }, + inputTooShort: function (args) { + var remainingChars = args.minimum - args.input.length; + + var message = 'Please enter ' + remainingChars + ' or more characters'; + + return message; + }, + loadingMore: function () { + return 'Loading more results…'; + }, + maximumSelected: function (args) { + var message = 'You can only select ' + args.maximum + ' item'; + + if (args.maximum != 1) { + message += 's'; + } + + return message; + }, + noResults: function () { + return 'No results found'; + }, + searching: function () { + return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; + } + }; +}); + +S2.define('select2/defaults',[ + 'jquery', + 'require', + + './results', + + './selection/single', + './selection/multiple', + './selection/placeholder', + './selection/allowClear', + './selection/search', + './selection/eventRelay', + + './utils', + './translation', + './diacritics', + + './data/select', + './data/array', + './data/ajax', + './data/tags', + './data/tokenizer', + './data/minimumInputLength', + './data/maximumInputLength', + './data/maximumSelectionLength', + + './dropdown', + './dropdown/search', + './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', + './dropdown/attachBody', + './dropdown/minimumResultsForSearch', + './dropdown/selectOnClose', + './dropdown/closeOnSelect', + + './i18n/en' +], function ($, require, + + ResultsList, + + SingleSelection, MultipleSelection, Placeholder, AllowClear, + SelectionSearch, EventRelay, + + Utils, Translation, DIACRITICS, + + SelectData, ArrayData, AjaxData, Tags, Tokenizer, + MinimumInputLength, MaximumInputLength, MaximumSelectionLength, + + Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, + AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, + + EnglishTranslation) { + function Defaults () { + this.reset(); + } + + Defaults.prototype.apply = function (options) { + options = $.extend(true, {}, this.defaults, options); + + if (options.dataAdapter == null) { + if (options.ajax != null) { + options.dataAdapter = AjaxData; + } else if (options.data != null) { + options.dataAdapter = ArrayData; + } else { + options.dataAdapter = SelectData; + } + + if (options.minimumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MinimumInputLength + ); + } + + if (options.maximumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumInputLength + ); + } + + if (options.maximumSelectionLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumSelectionLength + ); + } + + if (options.tags) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + + if (options.tokenSeparators != null || options.tokenizer != null) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Tokenizer + ); + } + + if (options.query != null) { + var Query = require(options.amdBase + 'compat/query'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Query + ); + } + + if (options.initSelection != null) { + var InitSelection = require(options.amdBase + 'compat/initSelection'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + InitSelection + ); + } + } + + if (options.resultsAdapter == null) { + options.resultsAdapter = ResultsList; + + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + + if (options.placeholder != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + HidePlaceholder + ); + } + + if (options.selectOnClose) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + SelectOnClose + ); + } + } + + if (options.dropdownAdapter == null) { + if (options.multiple) { + options.dropdownAdapter = Dropdown; + } else { + var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + + options.dropdownAdapter = SearchableDropdown; + } + + if (options.minimumResultsForSearch !== 0) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + MinimumResultsForSearch + ); + } + + if (options.closeOnSelect) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + CloseOnSelect + ); + } + + if ( + options.dropdownCssClass != null || + options.dropdownCss != null || + options.adaptDropdownCssClass != null + ) { + var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + DropdownCSS + ); + } + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + AttachBody + ); + } + + if (options.selectionAdapter == null) { + if (options.multiple) { + options.selectionAdapter = MultipleSelection; + } else { + options.selectionAdapter = SingleSelection; + } + + // Add the placeholder mixin if a placeholder was specified + if (options.placeholder != null) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + Placeholder + ); + } + + if (options.allowClear) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + AllowClear + ); + } + + if (options.multiple) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + SelectionSearch + ); + } + + if ( + options.containerCssClass != null || + options.containerCss != null || + options.adaptContainerCssClass != null + ) { + var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + ContainerCSS + ); + } + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + EventRelay + ); + } + + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); + + // Always fall back to English since it will always be complete + options.language.push('en'); + + var uniqueLanguages = []; + + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; + + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); + } + } + + options.language = uniqueLanguages; + + options.translations = this._processTranslations( + options.language, + options.debug + ); + + return options; + }; + + Defaults.prototype.reset = function () { + function stripDiacritics (text) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } + + return text.replace(/[^\u0000-\u007E]/g, match); + } + + function matcher (params, data) { + // Always return the object if there is nothing to compare + if ($.trim(params.term) === '') { + return data; + } + + // Do a recursive check for options with children + if (data.children && data.children.length > 0) { + // Clone the data object if there are children + // This is required as we modify the object to remove any non-matches + var match = $.extend(true, {}, data); + + // Check each child of the option + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; + + var matches = matcher(params, child); + + // If there wasn't a match, remove the object in the array + if (matches == null) { + match.children.splice(c, 1); + } + } + + // If any children matched, return the new object + if (match.children.length > 0) { + return match; + } + + // If there were no matching children, check just the plain object + return matcher(params, match); + } + + var original = stripDiacritics(data.text).toUpperCase(); + var term = stripDiacritics(params.term).toUpperCase(); + + // Check if the text contains the term + if (original.indexOf(term) > -1) { + return data; + } + + // If it doesn't contain the term, don't return anything + return null; + } + + this.defaults = { + amdBase: './', + amdLanguageBase: './i18n/', + closeOnSelect: true, + debug: false, + dropdownAutoWidth: false, + escapeMarkup: Utils.escapeMarkup, + language: {}, + matcher: matcher, + minimumInputLength: 0, + maximumInputLength: 0, + maximumSelectionLength: 0, + minimumResultsForSearch: 0, + selectOnClose: false, + scrollAfterSelect: false, + sorter: function (data) { + return data; + }, + templateResult: function (result) { + return result.text; + }, + templateSelection: function (selection) { + return selection.text; + }, + theme: 'default', + width: 'resolve' + }; + }; + + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + + Defaults.prototype.set = function (key, value) { + var camelKey = $.camelCase(key); + + var data = {}; + data[camelKey] = value; + + var convertedData = Utils._convertData(data); + + $.extend(true, this.defaults, convertedData); + }; + + var defaults = new Defaults(); + + return defaults; +}); + +S2.define('select2/options',[ + 'require', + 'jquery', + './defaults', + './utils' +], function (require, $, Defaults, Utils) { + function Options (options, $element) { + this.options = options; + + if ($element != null) { + this.fromElement($element); + } + + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + + this.options = Defaults.apply(this.options); + + if ($element && $element.is('input')) { + var InputCompat = require(this.get('amdBase') + 'compat/inputData'); + + this.options.dataAdapter = Utils.Decorate( + this.options.dataAdapter, + InputCompat + ); + } + } + + Options.prototype.fromElement = function ($e) { + var excludedData = ['select2']; + + if (this.options.multiple == null) { + this.options.multiple = $e.prop('multiple'); + } + + if (this.options.disabled == null) { + this.options.disabled = $e.prop('disabled'); + } + + if (this.options.dir == null) { + if ($e.prop('dir')) { + this.options.dir = $e.prop('dir'); + } else if ($e.closest('[dir]').prop('dir')) { + this.options.dir = $e.closest('[dir]').prop('dir'); + } else { + this.options.dir = 'ltr'; + } + } + + $e.prop('disabled', this.options.disabled); + $e.prop('multiple', this.options.multiple); + + if (Utils.GetData($e[0], 'select2Tags')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-select2-tags` attribute has been changed to ' + + 'use the `data-data` and `data-tags="true"` attributes and will be ' + + 'removed in future versions of Select2.' + ); + } + + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); + } + + if (Utils.GetData($e[0], 'ajaxUrl')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-ajax-url` attribute has been changed to ' + + '`data-ajax--url` and support for the old attribute will be removed' + + ' in future versions of Select2.' + ); + } + + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); + } + + var dataset = {}; + + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + + // Prefer the element's `dataset` attribute if it exists + // jQuery 1.x does not correctly handle data attributes with multiple dashes + if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { + dataset = $.extend(true, {}, $e[0].dataset, dataset); + } + + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); + + data = Utils._convertData(data); + + for (var key in data) { + if ($.inArray(key, excludedData) > -1) { + continue; + } + + if ($.isPlainObject(this.options[key])) { + $.extend(this.options[key], data[key]); + } else { + this.options[key] = data[key]; + } + } + + return this; + }; + + Options.prototype.get = function (key) { + return this.options[key]; + }; + + Options.prototype.set = function (key, val) { + this.options[key] = val; + }; + + return Options; +}); + +S2.define('select2/core',[ + 'jquery', + './options', + './utils', + './keys' +], function ($, Options, Utils, KEYS) { + var Select2 = function ($element, options) { + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); + } + + this.$element = $element; + + this.id = this._generateId($element); + + options = options || {}; + + this.options = new Options(options, $element); + + Select2.__super__.constructor.call(this); + + // Set up the tabindex + + var tabindex = $element.attr('tabindex') || 0; + Utils.StoreData($element[0], 'old-tabindex', tabindex); + $element.attr('tabindex', '-1'); + + // Set up containers and adapters + + var DataAdapter = this.options.get('dataAdapter'); + this.dataAdapter = new DataAdapter($element, this.options); + + var $container = this.render(); + + this._placeContainer($container); + + var SelectionAdapter = this.options.get('selectionAdapter'); + this.selection = new SelectionAdapter($element, this.options); + this.$selection = this.selection.render(); + + this.selection.position(this.$selection, $container); + + var DropdownAdapter = this.options.get('dropdownAdapter'); + this.dropdown = new DropdownAdapter($element, this.options); + this.$dropdown = this.dropdown.render(); + + this.dropdown.position(this.$dropdown, $container); + + var ResultsAdapter = this.options.get('resultsAdapter'); + this.results = new ResultsAdapter($element, this.options, this.dataAdapter); + this.$results = this.results.render(); + + this.results.position(this.$results, this.$dropdown); + + // Bind events + + var self = this; + + // Bind the container to all of the adapters + this._bindAdapters(); + + // Register any DOM event handlers + this._registerDomEvents(); + + // Register any internal event handlers + this._registerDataEvents(); + this._registerSelectionEvents(); + this._registerDropdownEvents(); + this._registerResultsEvents(); + this._registerEvents(); + + // Set the initial state + this.dataAdapter.current(function (initialData) { + self.trigger('selection:update', { + data: initialData + }); + }); + + // Hide the original select + $element.addClass('select2-hidden-accessible'); + $element.attr('aria-hidden', 'true'); + + // Synchronize any monitored attributes + this._syncAttributes(); + + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). + $element.data('select2', this); + }; + + Utils.Extend(Select2, Utils.Observable); + + Select2.prototype._generateId = function ($element) { + var id = ''; + + if ($element.attr('id') != null) { + id = $element.attr('id'); + } else if ($element.attr('name') != null) { + id = $element.attr('name') + '-' + Utils.generateChars(2); + } else { + id = Utils.generateChars(4); + } + + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = 'select2-' + id; + + return id; + }; + + Select2.prototype._placeContainer = function ($container) { + $container.insertAfter(this.$element); + + var width = this._resolveWidth(this.$element, this.options.get('width')); + + if (width != null) { + $container.css('width', width); + } + }; + + Select2.prototype._resolveWidth = function ($element, method) { + var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; + + if (method == 'resolve') { + var styleWidth = this._resolveWidth($element, 'style'); + + if (styleWidth != null) { + return styleWidth; + } + + return this._resolveWidth($element, 'element'); + } + + if (method == 'element') { + var elementWidth = $element.outerWidth(false); + + if (elementWidth <= 0) { + return 'auto'; + } + + return elementWidth + 'px'; + } + + if (method == 'style') { + var style = $element.attr('style'); + + if (typeof(style) !== 'string') { + return null; + } + + var attrs = style.split(';'); + + for (var i = 0, l = attrs.length; i < l; i = i + 1) { + var attr = attrs[i].replace(/\s/g, ''); + var matches = attr.match(WIDTH); + + if (matches !== null && matches.length >= 1) { + return matches[1]; + } + } + + return null; + } + + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + + return method; + }; + + Select2.prototype._bindAdapters = function () { + this.dataAdapter.bind(this, this.$container); + this.selection.bind(this, this.$container); + + this.dropdown.bind(this, this.$container); + this.results.bind(this, this.$container); + }; + + Select2.prototype._registerDomEvents = function () { + var self = this; + + this.$element.on('change.select2', function () { + self.dataAdapter.current(function (data) { + self.trigger('selection:update', { + data: data + }); + }); + }); + + this.$element.on('focus.select2', function (evt) { + self.trigger('focus', evt); + }); + + this._syncA = Utils.bind(this._syncAttributes, this); + this._syncS = Utils.bind(this._syncSubtree, this); + + if (this.$element[0].attachEvent) { + this.$element[0].attachEvent('onpropertychange', this._syncA); + } + + var observer = window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver + ; + + if (observer != null) { + this._observer = new observer(function (mutations) { + self._syncA(); + self._syncS(null, mutations); + }); + this._observer.observe(this.$element[0], { + attributes: true, + childList: true, + subtree: false + }); + } else if (this.$element[0].addEventListener) { + this.$element[0].addEventListener( + 'DOMAttrModified', + self._syncA, + false + ); + this.$element[0].addEventListener( + 'DOMNodeInserted', + self._syncS, + false + ); + this.$element[0].addEventListener( + 'DOMNodeRemoved', + self._syncS, + false + ); + } + }; + + Select2.prototype._registerDataEvents = function () { + var self = this; + + this.dataAdapter.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerSelectionEvents = function () { + var self = this; + var nonRelayEvents = ['toggle', 'focus']; + + this.selection.on('toggle', function () { + self.toggleDropdown(); + }); + + this.selection.on('focus', function (params) { + self.focus(params); + }); + + this.selection.on('*', function (name, params) { + if ($.inArray(name, nonRelayEvents) !== -1) { + return; + } + + self.trigger(name, params); + }); + }; + + Select2.prototype._registerDropdownEvents = function () { + var self = this; + + this.dropdown.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerResultsEvents = function () { + var self = this; + + this.results.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerEvents = function () { + var self = this; + + this.on('open', function () { + self.$container.addClass('select2-container--open'); + }); + + this.on('close', function () { + self.$container.removeClass('select2-container--open'); + }); + + this.on('enable', function () { + self.$container.removeClass('select2-container--disabled'); + }); + + this.on('disable', function () { + self.$container.addClass('select2-container--disabled'); + }); + + this.on('blur', function () { + self.$container.removeClass('select2-container--focus'); + }); + + this.on('query', function (params) { + if (!self.isOpen()) { + self.trigger('open', {}); + } + + this.dataAdapter.query(params, function (data) { + self.trigger('results:all', { + data: data, + query: params + }); + }); + }); + + this.on('query:append', function (params) { + this.dataAdapter.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + + this.on('keypress', function (evt) { + var key = evt.which; + + if (self.isOpen()) { + if (key === KEYS.ESC || key === KEYS.TAB || + (key === KEYS.UP && evt.altKey)) { + self.close(evt); + + evt.preventDefault(); + } else if (key === KEYS.ENTER) { + self.trigger('results:select', {}); + + evt.preventDefault(); + } else if ((key === KEYS.SPACE && evt.ctrlKey)) { + self.trigger('results:toggle', {}); + + evt.preventDefault(); + } else if (key === KEYS.UP) { + self.trigger('results:previous', {}); + + evt.preventDefault(); + } else if (key === KEYS.DOWN) { + self.trigger('results:next', {}); + + evt.preventDefault(); + } + } else { + if (key === KEYS.ENTER || key === KEYS.SPACE || + (key === KEYS.DOWN && evt.altKey)) { + self.open(); + + evt.preventDefault(); + } + } + }); + }; + + Select2.prototype._syncAttributes = function () { + this.options.set('disabled', this.$element.prop('disabled')); + + if (this.isDisabled()) { + if (this.isOpen()) { + this.close(); + } + + this.trigger('disable', {}); + } else { + this.trigger('enable', {}); + } + }; + + Select2.prototype._isChangeMutation = function (evt, mutations) { + var changed = false; + var self = this; + + // Ignore any mutation events raised for elements that aren't options or + // optgroups. This handles the case when the select element is destroyed + if ( + evt && evt.target && ( + evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP' + ) + ) { + return; + } + + if (!mutations) { + // If mutation events aren't supported, then we can only assume that the + // change affected the selections + changed = true; + } else if (mutations.addedNodes && mutations.addedNodes.length > 0) { + for (var n = 0; n < mutations.addedNodes.length; n++) { + var node = mutations.addedNodes[n]; + + if (node.selected) { + changed = true; + } + } + } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { + changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); + } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; + + // Only re-pull the data if we think there is a change + if (changed) { + this.dataAdapter.current(function (currentData) { + self.trigger('selection:update', { + data: currentData + }); + }); + } + }; + + /** + * Override the trigger method to automatically trigger pre-events when + * there are events that can be prevented. + */ + Select2.prototype.trigger = function (name, args) { + var actualTrigger = Select2.__super__.trigger; + var preTriggerMap = { + 'open': 'opening', + 'close': 'closing', + 'select': 'selecting', + 'unselect': 'unselecting', + 'clear': 'clearing' + }; + + if (args === undefined) { + args = {}; + } + + if (name in preTriggerMap) { + var preTriggerName = preTriggerMap[name]; + var preTriggerArgs = { + prevented: false, + name: name, + args: args + }; + + actualTrigger.call(this, preTriggerName, preTriggerArgs); + + if (preTriggerArgs.prevented) { + args.prevented = true; + + return; + } + } + + actualTrigger.call(this, name, args); + }; + + Select2.prototype.toggleDropdown = function () { + if (this.isDisabled()) { + return; + } + + if (this.isOpen()) { + this.close(); + } else { + this.open(); + } + }; + + Select2.prototype.open = function () { + if (this.isOpen()) { + return; + } + + if (this.isDisabled()) { + return; + } + + this.trigger('query', {}); + }; + + Select2.prototype.close = function (evt) { + if (!this.isOpen()) { + return; + } + + this.trigger('close', { originalEvent : evt }); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + Select2.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + Select2.prototype.isDisabled = function () { + return this.options.get('disabled'); + }; + + Select2.prototype.isOpen = function () { + return this.$container.hasClass('select2-container--open'); + }; + + Select2.prototype.hasFocus = function () { + return this.$container.hasClass('select2-container--focus'); + }; + + Select2.prototype.focus = function (data) { + // No need to re-trigger focus events if we are already focused + if (this.hasFocus()) { + return; + } + + this.$container.addClass('select2-container--focus'); + this.trigger('focus', {}); + }; + + Select2.prototype.enable = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("enable")` method has been deprecated and will' + + ' be removed in later Select2 versions. Use $element.prop("disabled")' + + ' instead.' + ); + } + + if (args == null || args.length === 0) { + args = [true]; + } + + var disabled = !args[0]; + + this.$element.prop('disabled', disabled); + }; + + Select2.prototype.data = function () { + if (this.options.get('debug') && + arguments.length > 0 && window.console && console.warn) { + console.warn( + 'Select2: Data can no longer be set using `select2("data")`. You ' + + 'should consider setting the value instead using `$element.val()`.' + ); + } + + var data = []; + + this.dataAdapter.current(function (currentData) { + data = currentData; + }); + + return data; + }; + + Select2.prototype.val = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("val")` method has been deprecated and will be' + + ' removed in later Select2 versions. Use $element.val() instead.' + ); + } + + if (args == null || args.length === 0) { + return this.$element.val(); + } + + var newVal = args[0]; + + if ($.isArray(newVal)) { + newVal = $.map(newVal, function (obj) { + return obj.toString(); + }); + } + + this.$element.val(newVal).trigger('input').trigger('change'); + }; + + Select2.prototype.destroy = function () { + this.$container.remove(); + + if (this.$element[0].detachEvent) { + this.$element[0].detachEvent('onpropertychange', this._syncA); + } + + if (this._observer != null) { + this._observer.disconnect(); + this._observer = null; + } else if (this.$element[0].removeEventListener) { + this.$element[0] + .removeEventListener('DOMAttrModified', this._syncA, false); + this.$element[0] + .removeEventListener('DOMNodeInserted', this._syncS, false); + this.$element[0] + .removeEventListener('DOMNodeRemoved', this._syncS, false); + } + + this._syncA = null; + this._syncS = null; + + this.$element.off('.select2'); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); + + this.$element.removeClass('select2-hidden-accessible'); + this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); + this.$element.removeData('select2'); + + this.dataAdapter.destroy(); + this.selection.destroy(); + this.dropdown.destroy(); + this.results.destroy(); + + this.dataAdapter = null; + this.selection = null; + this.dropdown = null; + this.results = null; + }; + + Select2.prototype.render = function () { + var $container = $( + '' + + '' + + '' + + '' + ); + + $container.attr('dir', this.options.get('dir')); + + this.$container = $container; + + this.$container.addClass('select2-container--' + this.options.get('theme')); + + Utils.StoreData($container[0], 'element', this.$element); + + return $container; + }; + + return Select2; +}); + +S2.define('select2/compat/utils',[ + 'jquery' +], function ($) { + function syncCssClasses ($dest, $src, adapter) { + var classes, replacements = [], adapted; + + classes = $.trim($dest.attr('class')); + + if (classes) { + classes = '' + classes; // for IE which returns object + + $(classes.split(/\s+/)).each(function () { + // Save all Select2 classes + if (this.indexOf('select2-') === 0) { + replacements.push(this); + } + }); + } + + classes = $.trim($src.attr('class')); + + if (classes) { + classes = '' + classes; // for IE which returns object + + $(classes.split(/\s+/)).each(function () { + // Only adapt non-Select2 classes + if (this.indexOf('select2-') !== 0) { + adapted = adapter(this); + + if (adapted != null) { + replacements.push(adapted); + } + } + }); + } + + $dest.attr('class', replacements.join(' ')); + } + + return { + syncCssClasses: syncCssClasses + }; +}); + +S2.define('select2/compat/containerCss',[ + 'jquery', + './utils' +], function ($, CompatUtils) { + // No-op CSS adapter that discards all classes by default + function _containerAdapter (clazz) { + return null; + } + + function ContainerCSS () { } + + ContainerCSS.prototype.render = function (decorated) { + var $container = decorated.call(this); + + var containerCssClass = this.options.get('containerCssClass') || ''; + + if ($.isFunction(containerCssClass)) { + containerCssClass = containerCssClass(this.$element); + } + + var containerCssAdapter = this.options.get('adaptContainerCssClass'); + containerCssAdapter = containerCssAdapter || _containerAdapter; + + if (containerCssClass.indexOf(':all:') !== -1) { + containerCssClass = containerCssClass.replace(':all:', ''); + + var _cssAdapter = containerCssAdapter; + + containerCssAdapter = function (clazz) { + var adapted = _cssAdapter(clazz); + + if (adapted != null) { + // Append the old one along with the adapted one + return adapted + ' ' + clazz; + } + + return clazz; + }; + } + + var containerCss = this.options.get('containerCss') || {}; + + if ($.isFunction(containerCss)) { + containerCss = containerCss(this.$element); + } + + CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter); + + $container.css(containerCss); + $container.addClass(containerCssClass); + + return $container; + }; + + return ContainerCSS; +}); + +S2.define('select2/compat/dropdownCss',[ + 'jquery', + './utils' +], function ($, CompatUtils) { + // No-op CSS adapter that discards all classes by default + function _dropdownAdapter (clazz) { + return null; + } + + function DropdownCSS () { } + + DropdownCSS.prototype.render = function (decorated) { + var $dropdown = decorated.call(this); + + var dropdownCssClass = this.options.get('dropdownCssClass') || ''; + + if ($.isFunction(dropdownCssClass)) { + dropdownCssClass = dropdownCssClass(this.$element); + } + + var dropdownCssAdapter = this.options.get('adaptDropdownCssClass'); + dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter; + + if (dropdownCssClass.indexOf(':all:') !== -1) { + dropdownCssClass = dropdownCssClass.replace(':all:', ''); + + var _cssAdapter = dropdownCssAdapter; + + dropdownCssAdapter = function (clazz) { + var adapted = _cssAdapter(clazz); + + if (adapted != null) { + // Append the old one along with the adapted one + return adapted + ' ' + clazz; + } + + return clazz; + }; + } + + var dropdownCss = this.options.get('dropdownCss') || {}; + + if ($.isFunction(dropdownCss)) { + dropdownCss = dropdownCss(this.$element); + } + + CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter); + + $dropdown.css(dropdownCss); + $dropdown.addClass(dropdownCssClass); + + return $dropdown; + }; + + return DropdownCSS; +}); + +S2.define('select2/compat/initSelection',[ + 'jquery' +], function ($) { + function InitSelection (decorated, $element, options) { + if (options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `initSelection` option has been deprecated in favor' + + ' of a custom data adapter that overrides the `current` method. ' + + 'This method is now called multiple times instead of a single ' + + 'time when the instance is initialized. Support will be removed ' + + 'for the `initSelection` option in future versions of Select2' + ); + } + + this.initSelection = options.get('initSelection'); + this._isInitialized = false; + + decorated.call(this, $element, options); + } + + InitSelection.prototype.current = function (decorated, callback) { + var self = this; + + if (this._isInitialized) { + decorated.call(this, callback); + + return; + } + + this.initSelection.call(null, this.$element, function (data) { + self._isInitialized = true; + + if (!$.isArray(data)) { + data = [data]; + } + + callback(data); + }); + }; + + return InitSelection; +}); + +S2.define('select2/compat/inputData',[ + 'jquery', + '../utils' +], function ($, Utils) { + function InputData (decorated, $element, options) { + this._currentData = []; + this._valueSeparator = options.get('valueSeparator') || ','; + + if ($element.prop('type') === 'hidden') { + if (options.get('debug') && console && console.warn) { + console.warn( + 'Select2: Using a hidden input with Select2 is no longer ' + + 'supported and may stop working in the future. It is recommended ' + + 'to use a `');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),t.on("open",function(){i.$search.attr("aria-controls",r),i.$search.trigger("focus")}),t.on("close",function(){i.$search.val(""),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.trigger("focus")}),t.on("enable",function(){i.$search.prop("disabled",!1),i._transferTabIndex()}),t.on("disable",function(){i.$search.prop("disabled",!0)}),t.on("focus",function(e){i.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){i.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){i._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===i.$search.val()){var t=i.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("select",function(){i._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var i=this;this._checkIfMaximumSelected(function(){e.call(i,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var i=this;this.current(function(e){var t=null!=e?e.length:0;0=i.maximumSelectionLength?i.trigger("results:message",{message:"maximumSelected",args:{maximum:i.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){i.handleSearch(e)}),t.on("open",function(){i.$search.attr("tabindex",0),i.$search.attr("aria-controls",r),i.$search.trigger("focus"),window.setTimeout(function(){i.$search.trigger("focus")},0)}),t.on("close",function(){i.$search.attr("tabindex",-1),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.val(""),i.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||i.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(i.showSearch(e)?i.$searchContainer.removeClass("select2-search--hide"):i.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,i){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,i)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),i=t.length-1;0<=i;i--){var r=t[i];this.placeholder.id===r.id&&n.splice(i,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,i){this.lastParams={},e.call(this,t,n,i),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("query",function(e){i.lastParams=e,i.loading=!0}),t.on("query:append",function(e){i.lastParams=e,i.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
              • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("open",function(){i._showDropdown(),i._attachPositioningHandler(t),i._bindContainerResultHandlers(t)}),t.on("close",function(){i._hideDropdown(),i._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,i="scroll.select2."+t.id,r="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(i,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(i+" "+r+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+i+" "+r)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),i=null,r=this.$container.offset();r.bottom=r.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=r.top,o.bottom=r.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ar.bottom+s,d={left:r.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(i="below"),u||!c||t?!c&&u&&t&&(i="below"):i="above",("above"==i||t&&"below"!==i)&&(d.top=o.top-h.top-s),null!=i&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+i),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+i)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,i){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,i)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,i=0;i');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("select2/compat/utils",["jquery"],function(s){return{syncCssClasses:function(e,t,n){var i,r,o=[];(i=s.trim(e.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0===this.indexOf("select2-")&&o.push(this)}),(i=s.trim(t.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&null!=(r=n(this))&&o.push(r)}),e.attr("class",o.join(" "))}}}),e.define("select2/compat/containerCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("containerCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptContainerCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("containerCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/dropdownCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("dropdownCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptDropdownCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("dropdownCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/initSelection",["jquery"],function(i){function e(e,t,n){n.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=n.get("initSelection"),this._isInitialized=!1,e.call(this,t,n)}return e.prototype.current=function(e,t){var n=this;this._isInitialized?e.call(this,t):this.initSelection.call(null,this.$element,function(e){n._isInitialized=!0,i.isArray(e)||(e=[e]),t(e)})},e}),e.define("select2/compat/inputData",["jquery","../utils"],function(s,i){function e(e,t,n){this._currentData=[],this._valueSeparator=n.get("valueSeparator")||",","hidden"===t.prop("type")&&n.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + var $rendered = decorated.call(this); + + this._transferTabIndex(); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + decorated.call(this, container, $container); + + container.on('open', function () { + self.$search.attr('aria-controls', resultsId); + self.$search.trigger('focus'); + }); + + container.on('close', function () { + self.$search.val(''); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); + self.$search.trigger('focus'); + }); + + container.on('enable', function () { + self.$search.prop('disabled', false); + + self._transferTabIndex(); + }); + + container.on('disable', function () { + self.$search.prop('disabled', true); + }); + + container.on('focus', function (evt) { + self.$search.trigger('focus'); + }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); + + this.$selection.on('focusin', '.select2-search--inline', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('focusout', '.select2-search--inline', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', '.select2-search--inline', function (evt) { + evt.stopPropagation(); + + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + + var key = evt.which; + + if (key === KEYS.BACKSPACE && self.$search.val() === '') { + var $previousChoice = self.$searchContainer + .prev('.select2-selection__choice'); + + if ($previousChoice.length > 0) { + var item = Utils.GetData($previousChoice[0], 'data'); + + self.searchRemoveChoice(item); + + evt.preventDefault(); + } + } + }); + + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + + // Try to detect the IE version should the `documentMode` property that + // is stored on the document. This is only implemented in IE and is + // slightly cleaner than doing a user agent check. + // This property is not available in Edge, but Edge also doesn't have + // this bug. + var msie = document.documentMode; + var disableInputEvents = msie && msie <= 11; + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$selection.on( + 'input.searchcheck', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents) { + self.$selection.off('input.search input.searchcheck'); + return; + } + + // Unbind the duplicated `keyup` event + self.$selection.off('keyup.search'); + } + ); + + this.$selection.on( + 'keyup.search input.search', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents && evt.type === 'input') { + self.$selection.off('input.search input.searchcheck'); + return; + } + + var key = evt.which; + + // We can freely ignore events from modifier keys + if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + return; + } + + // Tabbing will be handled during the `keydown` phase + if (key == KEYS.TAB) { + return; + } + + self.handleSearch(evt); + } + ); + }; + + /** + * This method will transfer the tabindex attribute from the rendered + * selection to the search box. This allows for the search box to be used as + * the primary focus instead of the selection container. + * + * @private + */ + Search.prototype._transferTabIndex = function (decorated) { + this.$search.attr('tabindex', this.$selection.attr('tabindex')); + this.$selection.attr('tabindex', '-1'); + }; + + Search.prototype.createPlaceholder = function (decorated, placeholder) { + this.$search.attr('placeholder', placeholder.text); + }; + + Search.prototype.update = function (decorated, data) { + var searchHadFocus = this.$search[0] == document.activeElement; + + this.$search.attr('placeholder', ''); + + decorated.call(this, data); + + this.$selection.find('.select2-selection__rendered') + .append(this.$searchContainer); + + this.resizeSearch(); + if (searchHadFocus) { + this.$search.trigger('focus'); + } + }; + + Search.prototype.handleSearch = function () { + this.resizeSearch(); + + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.searchRemoveChoice = function (decorated, item) { + this.trigger('unselect', { + data: item + }); + + this.$search.val(item.text); + this.handleSearch(); + }; + + Search.prototype.resizeSearch = function () { + this.$search.css('width', '25px'); + + var width = ''; + + if (this.$search.attr('placeholder') !== '') { + width = this.$selection.find('.select2-selection__rendered').width(); + } else { + var minimumWidth = this.$search.val().length + 1; + + width = (minimumWidth * 0.75) + 'em'; + } + + this.$search.css('width', width); + }; + + return Search; +}); + +S2.define('select2/selection/eventRelay',[ + 'jquery' +], function ($) { + function EventRelay () { } + + EventRelay.prototype.bind = function (decorated, container, $container) { + var self = this; + var relayEvents = [ + 'open', 'opening', + 'close', 'closing', + 'select', 'selecting', + 'unselect', 'unselecting', + 'clear', 'clearing' + ]; + + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; + + decorated.call(this, container, $container); + + container.on('*', function (name, params) { + // Ignore events that should not be relayed + if ($.inArray(name, relayEvents) === -1) { + return; + } + + // The parameters should always be an object + params = params || {}; + + // Generate the jQuery event for the Select2 event + var evt = $.Event('select2:' + name, { + params: params + }); + + self.$element.trigger(evt); + + // Only handle preventable events if it was one + if ($.inArray(name, preventableEvents) === -1) { + return; + } + + params.prevented = evt.isDefaultPrevented(); + }); + }; + + return EventRelay; +}); + +S2.define('select2/translation',[ + 'jquery', + 'require' +], function ($, require) { + function Translation (dict) { + this.dict = dict || {}; + } + + Translation.prototype.all = function () { + return this.dict; + }; + + Translation.prototype.get = function (key) { + return this.dict[key]; + }; + + Translation.prototype.extend = function (translation) { + this.dict = $.extend({}, translation.all(), this.dict); + }; + + // Static functions + + Translation._cache = {}; + + Translation.loadPath = function (path) { + if (!(path in Translation._cache)) { + var translations = require(path); + + Translation._cache[path] = translations; + } + + return new Translation(Translation._cache[path]); + }; + + return Translation; +}); + +S2.define('select2/diacritics',[ + +], function () { + var diacritics = { + '\u24B6': 'A', + '\uFF21': 'A', + '\u00C0': 'A', + '\u00C1': 'A', + '\u00C2': 'A', + '\u1EA6': 'A', + '\u1EA4': 'A', + '\u1EAA': 'A', + '\u1EA8': 'A', + '\u00C3': 'A', + '\u0100': 'A', + '\u0102': 'A', + '\u1EB0': 'A', + '\u1EAE': 'A', + '\u1EB4': 'A', + '\u1EB2': 'A', + '\u0226': 'A', + '\u01E0': 'A', + '\u00C4': 'A', + '\u01DE': 'A', + '\u1EA2': 'A', + '\u00C5': 'A', + '\u01FA': 'A', + '\u01CD': 'A', + '\u0200': 'A', + '\u0202': 'A', + '\u1EA0': 'A', + '\u1EAC': 'A', + '\u1EB6': 'A', + '\u1E00': 'A', + '\u0104': 'A', + '\u023A': 'A', + '\u2C6F': 'A', + '\uA732': 'AA', + '\u00C6': 'AE', + '\u01FC': 'AE', + '\u01E2': 'AE', + '\uA734': 'AO', + '\uA736': 'AU', + '\uA738': 'AV', + '\uA73A': 'AV', + '\uA73C': 'AY', + '\u24B7': 'B', + '\uFF22': 'B', + '\u1E02': 'B', + '\u1E04': 'B', + '\u1E06': 'B', + '\u0243': 'B', + '\u0182': 'B', + '\u0181': 'B', + '\u24B8': 'C', + '\uFF23': 'C', + '\u0106': 'C', + '\u0108': 'C', + '\u010A': 'C', + '\u010C': 'C', + '\u00C7': 'C', + '\u1E08': 'C', + '\u0187': 'C', + '\u023B': 'C', + '\uA73E': 'C', + '\u24B9': 'D', + '\uFF24': 'D', + '\u1E0A': 'D', + '\u010E': 'D', + '\u1E0C': 'D', + '\u1E10': 'D', + '\u1E12': 'D', + '\u1E0E': 'D', + '\u0110': 'D', + '\u018B': 'D', + '\u018A': 'D', + '\u0189': 'D', + '\uA779': 'D', + '\u01F1': 'DZ', + '\u01C4': 'DZ', + '\u01F2': 'Dz', + '\u01C5': 'Dz', + '\u24BA': 'E', + '\uFF25': 'E', + '\u00C8': 'E', + '\u00C9': 'E', + '\u00CA': 'E', + '\u1EC0': 'E', + '\u1EBE': 'E', + '\u1EC4': 'E', + '\u1EC2': 'E', + '\u1EBC': 'E', + '\u0112': 'E', + '\u1E14': 'E', + '\u1E16': 'E', + '\u0114': 'E', + '\u0116': 'E', + '\u00CB': 'E', + '\u1EBA': 'E', + '\u011A': 'E', + '\u0204': 'E', + '\u0206': 'E', + '\u1EB8': 'E', + '\u1EC6': 'E', + '\u0228': 'E', + '\u1E1C': 'E', + '\u0118': 'E', + '\u1E18': 'E', + '\u1E1A': 'E', + '\u0190': 'E', + '\u018E': 'E', + '\u24BB': 'F', + '\uFF26': 'F', + '\u1E1E': 'F', + '\u0191': 'F', + '\uA77B': 'F', + '\u24BC': 'G', + '\uFF27': 'G', + '\u01F4': 'G', + '\u011C': 'G', + '\u1E20': 'G', + '\u011E': 'G', + '\u0120': 'G', + '\u01E6': 'G', + '\u0122': 'G', + '\u01E4': 'G', + '\u0193': 'G', + '\uA7A0': 'G', + '\uA77D': 'G', + '\uA77E': 'G', + '\u24BD': 'H', + '\uFF28': 'H', + '\u0124': 'H', + '\u1E22': 'H', + '\u1E26': 'H', + '\u021E': 'H', + '\u1E24': 'H', + '\u1E28': 'H', + '\u1E2A': 'H', + '\u0126': 'H', + '\u2C67': 'H', + '\u2C75': 'H', + '\uA78D': 'H', + '\u24BE': 'I', + '\uFF29': 'I', + '\u00CC': 'I', + '\u00CD': 'I', + '\u00CE': 'I', + '\u0128': 'I', + '\u012A': 'I', + '\u012C': 'I', + '\u0130': 'I', + '\u00CF': 'I', + '\u1E2E': 'I', + '\u1EC8': 'I', + '\u01CF': 'I', + '\u0208': 'I', + '\u020A': 'I', + '\u1ECA': 'I', + '\u012E': 'I', + '\u1E2C': 'I', + '\u0197': 'I', + '\u24BF': 'J', + '\uFF2A': 'J', + '\u0134': 'J', + '\u0248': 'J', + '\u24C0': 'K', + '\uFF2B': 'K', + '\u1E30': 'K', + '\u01E8': 'K', + '\u1E32': 'K', + '\u0136': 'K', + '\u1E34': 'K', + '\u0198': 'K', + '\u2C69': 'K', + '\uA740': 'K', + '\uA742': 'K', + '\uA744': 'K', + '\uA7A2': 'K', + '\u24C1': 'L', + '\uFF2C': 'L', + '\u013F': 'L', + '\u0139': 'L', + '\u013D': 'L', + '\u1E36': 'L', + '\u1E38': 'L', + '\u013B': 'L', + '\u1E3C': 'L', + '\u1E3A': 'L', + '\u0141': 'L', + '\u023D': 'L', + '\u2C62': 'L', + '\u2C60': 'L', + '\uA748': 'L', + '\uA746': 'L', + '\uA780': 'L', + '\u01C7': 'LJ', + '\u01C8': 'Lj', + '\u24C2': 'M', + '\uFF2D': 'M', + '\u1E3E': 'M', + '\u1E40': 'M', + '\u1E42': 'M', + '\u2C6E': 'M', + '\u019C': 'M', + '\u24C3': 'N', + '\uFF2E': 'N', + '\u01F8': 'N', + '\u0143': 'N', + '\u00D1': 'N', + '\u1E44': 'N', + '\u0147': 'N', + '\u1E46': 'N', + '\u0145': 'N', + '\u1E4A': 'N', + '\u1E48': 'N', + '\u0220': 'N', + '\u019D': 'N', + '\uA790': 'N', + '\uA7A4': 'N', + '\u01CA': 'NJ', + '\u01CB': 'Nj', + '\u24C4': 'O', + '\uFF2F': 'O', + '\u00D2': 'O', + '\u00D3': 'O', + '\u00D4': 'O', + '\u1ED2': 'O', + '\u1ED0': 'O', + '\u1ED6': 'O', + '\u1ED4': 'O', + '\u00D5': 'O', + '\u1E4C': 'O', + '\u022C': 'O', + '\u1E4E': 'O', + '\u014C': 'O', + '\u1E50': 'O', + '\u1E52': 'O', + '\u014E': 'O', + '\u022E': 'O', + '\u0230': 'O', + '\u00D6': 'O', + '\u022A': 'O', + '\u1ECE': 'O', + '\u0150': 'O', + '\u01D1': 'O', + '\u020C': 'O', + '\u020E': 'O', + '\u01A0': 'O', + '\u1EDC': 'O', + '\u1EDA': 'O', + '\u1EE0': 'O', + '\u1EDE': 'O', + '\u1EE2': 'O', + '\u1ECC': 'O', + '\u1ED8': 'O', + '\u01EA': 'O', + '\u01EC': 'O', + '\u00D8': 'O', + '\u01FE': 'O', + '\u0186': 'O', + '\u019F': 'O', + '\uA74A': 'O', + '\uA74C': 'O', + '\u0152': 'OE', + '\u01A2': 'OI', + '\uA74E': 'OO', + '\u0222': 'OU', + '\u24C5': 'P', + '\uFF30': 'P', + '\u1E54': 'P', + '\u1E56': 'P', + '\u01A4': 'P', + '\u2C63': 'P', + '\uA750': 'P', + '\uA752': 'P', + '\uA754': 'P', + '\u24C6': 'Q', + '\uFF31': 'Q', + '\uA756': 'Q', + '\uA758': 'Q', + '\u024A': 'Q', + '\u24C7': 'R', + '\uFF32': 'R', + '\u0154': 'R', + '\u1E58': 'R', + '\u0158': 'R', + '\u0210': 'R', + '\u0212': 'R', + '\u1E5A': 'R', + '\u1E5C': 'R', + '\u0156': 'R', + '\u1E5E': 'R', + '\u024C': 'R', + '\u2C64': 'R', + '\uA75A': 'R', + '\uA7A6': 'R', + '\uA782': 'R', + '\u24C8': 'S', + '\uFF33': 'S', + '\u1E9E': 'S', + '\u015A': 'S', + '\u1E64': 'S', + '\u015C': 'S', + '\u1E60': 'S', + '\u0160': 'S', + '\u1E66': 'S', + '\u1E62': 'S', + '\u1E68': 'S', + '\u0218': 'S', + '\u015E': 'S', + '\u2C7E': 'S', + '\uA7A8': 'S', + '\uA784': 'S', + '\u24C9': 'T', + '\uFF34': 'T', + '\u1E6A': 'T', + '\u0164': 'T', + '\u1E6C': 'T', + '\u021A': 'T', + '\u0162': 'T', + '\u1E70': 'T', + '\u1E6E': 'T', + '\u0166': 'T', + '\u01AC': 'T', + '\u01AE': 'T', + '\u023E': 'T', + '\uA786': 'T', + '\uA728': 'TZ', + '\u24CA': 'U', + '\uFF35': 'U', + '\u00D9': 'U', + '\u00DA': 'U', + '\u00DB': 'U', + '\u0168': 'U', + '\u1E78': 'U', + '\u016A': 'U', + '\u1E7A': 'U', + '\u016C': 'U', + '\u00DC': 'U', + '\u01DB': 'U', + '\u01D7': 'U', + '\u01D5': 'U', + '\u01D9': 'U', + '\u1EE6': 'U', + '\u016E': 'U', + '\u0170': 'U', + '\u01D3': 'U', + '\u0214': 'U', + '\u0216': 'U', + '\u01AF': 'U', + '\u1EEA': 'U', + '\u1EE8': 'U', + '\u1EEE': 'U', + '\u1EEC': 'U', + '\u1EF0': 'U', + '\u1EE4': 'U', + '\u1E72': 'U', + '\u0172': 'U', + '\u1E76': 'U', + '\u1E74': 'U', + '\u0244': 'U', + '\u24CB': 'V', + '\uFF36': 'V', + '\u1E7C': 'V', + '\u1E7E': 'V', + '\u01B2': 'V', + '\uA75E': 'V', + '\u0245': 'V', + '\uA760': 'VY', + '\u24CC': 'W', + '\uFF37': 'W', + '\u1E80': 'W', + '\u1E82': 'W', + '\u0174': 'W', + '\u1E86': 'W', + '\u1E84': 'W', + '\u1E88': 'W', + '\u2C72': 'W', + '\u24CD': 'X', + '\uFF38': 'X', + '\u1E8A': 'X', + '\u1E8C': 'X', + '\u24CE': 'Y', + '\uFF39': 'Y', + '\u1EF2': 'Y', + '\u00DD': 'Y', + '\u0176': 'Y', + '\u1EF8': 'Y', + '\u0232': 'Y', + '\u1E8E': 'Y', + '\u0178': 'Y', + '\u1EF6': 'Y', + '\u1EF4': 'Y', + '\u01B3': 'Y', + '\u024E': 'Y', + '\u1EFE': 'Y', + '\u24CF': 'Z', + '\uFF3A': 'Z', + '\u0179': 'Z', + '\u1E90': 'Z', + '\u017B': 'Z', + '\u017D': 'Z', + '\u1E92': 'Z', + '\u1E94': 'Z', + '\u01B5': 'Z', + '\u0224': 'Z', + '\u2C7F': 'Z', + '\u2C6B': 'Z', + '\uA762': 'Z', + '\u24D0': 'a', + '\uFF41': 'a', + '\u1E9A': 'a', + '\u00E0': 'a', + '\u00E1': 'a', + '\u00E2': 'a', + '\u1EA7': 'a', + '\u1EA5': 'a', + '\u1EAB': 'a', + '\u1EA9': 'a', + '\u00E3': 'a', + '\u0101': 'a', + '\u0103': 'a', + '\u1EB1': 'a', + '\u1EAF': 'a', + '\u1EB5': 'a', + '\u1EB3': 'a', + '\u0227': 'a', + '\u01E1': 'a', + '\u00E4': 'a', + '\u01DF': 'a', + '\u1EA3': 'a', + '\u00E5': 'a', + '\u01FB': 'a', + '\u01CE': 'a', + '\u0201': 'a', + '\u0203': 'a', + '\u1EA1': 'a', + '\u1EAD': 'a', + '\u1EB7': 'a', + '\u1E01': 'a', + '\u0105': 'a', + '\u2C65': 'a', + '\u0250': 'a', + '\uA733': 'aa', + '\u00E6': 'ae', + '\u01FD': 'ae', + '\u01E3': 'ae', + '\uA735': 'ao', + '\uA737': 'au', + '\uA739': 'av', + '\uA73B': 'av', + '\uA73D': 'ay', + '\u24D1': 'b', + '\uFF42': 'b', + '\u1E03': 'b', + '\u1E05': 'b', + '\u1E07': 'b', + '\u0180': 'b', + '\u0183': 'b', + '\u0253': 'b', + '\u24D2': 'c', + '\uFF43': 'c', + '\u0107': 'c', + '\u0109': 'c', + '\u010B': 'c', + '\u010D': 'c', + '\u00E7': 'c', + '\u1E09': 'c', + '\u0188': 'c', + '\u023C': 'c', + '\uA73F': 'c', + '\u2184': 'c', + '\u24D3': 'd', + '\uFF44': 'd', + '\u1E0B': 'd', + '\u010F': 'd', + '\u1E0D': 'd', + '\u1E11': 'd', + '\u1E13': 'd', + '\u1E0F': 'd', + '\u0111': 'd', + '\u018C': 'd', + '\u0256': 'd', + '\u0257': 'd', + '\uA77A': 'd', + '\u01F3': 'dz', + '\u01C6': 'dz', + '\u24D4': 'e', + '\uFF45': 'e', + '\u00E8': 'e', + '\u00E9': 'e', + '\u00EA': 'e', + '\u1EC1': 'e', + '\u1EBF': 'e', + '\u1EC5': 'e', + '\u1EC3': 'e', + '\u1EBD': 'e', + '\u0113': 'e', + '\u1E15': 'e', + '\u1E17': 'e', + '\u0115': 'e', + '\u0117': 'e', + '\u00EB': 'e', + '\u1EBB': 'e', + '\u011B': 'e', + '\u0205': 'e', + '\u0207': 'e', + '\u1EB9': 'e', + '\u1EC7': 'e', + '\u0229': 'e', + '\u1E1D': 'e', + '\u0119': 'e', + '\u1E19': 'e', + '\u1E1B': 'e', + '\u0247': 'e', + '\u025B': 'e', + '\u01DD': 'e', + '\u24D5': 'f', + '\uFF46': 'f', + '\u1E1F': 'f', + '\u0192': 'f', + '\uA77C': 'f', + '\u24D6': 'g', + '\uFF47': 'g', + '\u01F5': 'g', + '\u011D': 'g', + '\u1E21': 'g', + '\u011F': 'g', + '\u0121': 'g', + '\u01E7': 'g', + '\u0123': 'g', + '\u01E5': 'g', + '\u0260': 'g', + '\uA7A1': 'g', + '\u1D79': 'g', + '\uA77F': 'g', + '\u24D7': 'h', + '\uFF48': 'h', + '\u0125': 'h', + '\u1E23': 'h', + '\u1E27': 'h', + '\u021F': 'h', + '\u1E25': 'h', + '\u1E29': 'h', + '\u1E2B': 'h', + '\u1E96': 'h', + '\u0127': 'h', + '\u2C68': 'h', + '\u2C76': 'h', + '\u0265': 'h', + '\u0195': 'hv', + '\u24D8': 'i', + '\uFF49': 'i', + '\u00EC': 'i', + '\u00ED': 'i', + '\u00EE': 'i', + '\u0129': 'i', + '\u012B': 'i', + '\u012D': 'i', + '\u00EF': 'i', + '\u1E2F': 'i', + '\u1EC9': 'i', + '\u01D0': 'i', + '\u0209': 'i', + '\u020B': 'i', + '\u1ECB': 'i', + '\u012F': 'i', + '\u1E2D': 'i', + '\u0268': 'i', + '\u0131': 'i', + '\u24D9': 'j', + '\uFF4A': 'j', + '\u0135': 'j', + '\u01F0': 'j', + '\u0249': 'j', + '\u24DA': 'k', + '\uFF4B': 'k', + '\u1E31': 'k', + '\u01E9': 'k', + '\u1E33': 'k', + '\u0137': 'k', + '\u1E35': 'k', + '\u0199': 'k', + '\u2C6A': 'k', + '\uA741': 'k', + '\uA743': 'k', + '\uA745': 'k', + '\uA7A3': 'k', + '\u24DB': 'l', + '\uFF4C': 'l', + '\u0140': 'l', + '\u013A': 'l', + '\u013E': 'l', + '\u1E37': 'l', + '\u1E39': 'l', + '\u013C': 'l', + '\u1E3D': 'l', + '\u1E3B': 'l', + '\u017F': 'l', + '\u0142': 'l', + '\u019A': 'l', + '\u026B': 'l', + '\u2C61': 'l', + '\uA749': 'l', + '\uA781': 'l', + '\uA747': 'l', + '\u01C9': 'lj', + '\u24DC': 'm', + '\uFF4D': 'm', + '\u1E3F': 'm', + '\u1E41': 'm', + '\u1E43': 'm', + '\u0271': 'm', + '\u026F': 'm', + '\u24DD': 'n', + '\uFF4E': 'n', + '\u01F9': 'n', + '\u0144': 'n', + '\u00F1': 'n', + '\u1E45': 'n', + '\u0148': 'n', + '\u1E47': 'n', + '\u0146': 'n', + '\u1E4B': 'n', + '\u1E49': 'n', + '\u019E': 'n', + '\u0272': 'n', + '\u0149': 'n', + '\uA791': 'n', + '\uA7A5': 'n', + '\u01CC': 'nj', + '\u24DE': 'o', + '\uFF4F': 'o', + '\u00F2': 'o', + '\u00F3': 'o', + '\u00F4': 'o', + '\u1ED3': 'o', + '\u1ED1': 'o', + '\u1ED7': 'o', + '\u1ED5': 'o', + '\u00F5': 'o', + '\u1E4D': 'o', + '\u022D': 'o', + '\u1E4F': 'o', + '\u014D': 'o', + '\u1E51': 'o', + '\u1E53': 'o', + '\u014F': 'o', + '\u022F': 'o', + '\u0231': 'o', + '\u00F6': 'o', + '\u022B': 'o', + '\u1ECF': 'o', + '\u0151': 'o', + '\u01D2': 'o', + '\u020D': 'o', + '\u020F': 'o', + '\u01A1': 'o', + '\u1EDD': 'o', + '\u1EDB': 'o', + '\u1EE1': 'o', + '\u1EDF': 'o', + '\u1EE3': 'o', + '\u1ECD': 'o', + '\u1ED9': 'o', + '\u01EB': 'o', + '\u01ED': 'o', + '\u00F8': 'o', + '\u01FF': 'o', + '\u0254': 'o', + '\uA74B': 'o', + '\uA74D': 'o', + '\u0275': 'o', + '\u0153': 'oe', + '\u01A3': 'oi', + '\u0223': 'ou', + '\uA74F': 'oo', + '\u24DF': 'p', + '\uFF50': 'p', + '\u1E55': 'p', + '\u1E57': 'p', + '\u01A5': 'p', + '\u1D7D': 'p', + '\uA751': 'p', + '\uA753': 'p', + '\uA755': 'p', + '\u24E0': 'q', + '\uFF51': 'q', + '\u024B': 'q', + '\uA757': 'q', + '\uA759': 'q', + '\u24E1': 'r', + '\uFF52': 'r', + '\u0155': 'r', + '\u1E59': 'r', + '\u0159': 'r', + '\u0211': 'r', + '\u0213': 'r', + '\u1E5B': 'r', + '\u1E5D': 'r', + '\u0157': 'r', + '\u1E5F': 'r', + '\u024D': 'r', + '\u027D': 'r', + '\uA75B': 'r', + '\uA7A7': 'r', + '\uA783': 'r', + '\u24E2': 's', + '\uFF53': 's', + '\u00DF': 's', + '\u015B': 's', + '\u1E65': 's', + '\u015D': 's', + '\u1E61': 's', + '\u0161': 's', + '\u1E67': 's', + '\u1E63': 's', + '\u1E69': 's', + '\u0219': 's', + '\u015F': 's', + '\u023F': 's', + '\uA7A9': 's', + '\uA785': 's', + '\u1E9B': 's', + '\u24E3': 't', + '\uFF54': 't', + '\u1E6B': 't', + '\u1E97': 't', + '\u0165': 't', + '\u1E6D': 't', + '\u021B': 't', + '\u0163': 't', + '\u1E71': 't', + '\u1E6F': 't', + '\u0167': 't', + '\u01AD': 't', + '\u0288': 't', + '\u2C66': 't', + '\uA787': 't', + '\uA729': 'tz', + '\u24E4': 'u', + '\uFF55': 'u', + '\u00F9': 'u', + '\u00FA': 'u', + '\u00FB': 'u', + '\u0169': 'u', + '\u1E79': 'u', + '\u016B': 'u', + '\u1E7B': 'u', + '\u016D': 'u', + '\u00FC': 'u', + '\u01DC': 'u', + '\u01D8': 'u', + '\u01D6': 'u', + '\u01DA': 'u', + '\u1EE7': 'u', + '\u016F': 'u', + '\u0171': 'u', + '\u01D4': 'u', + '\u0215': 'u', + '\u0217': 'u', + '\u01B0': 'u', + '\u1EEB': 'u', + '\u1EE9': 'u', + '\u1EEF': 'u', + '\u1EED': 'u', + '\u1EF1': 'u', + '\u1EE5': 'u', + '\u1E73': 'u', + '\u0173': 'u', + '\u1E77': 'u', + '\u1E75': 'u', + '\u0289': 'u', + '\u24E5': 'v', + '\uFF56': 'v', + '\u1E7D': 'v', + '\u1E7F': 'v', + '\u028B': 'v', + '\uA75F': 'v', + '\u028C': 'v', + '\uA761': 'vy', + '\u24E6': 'w', + '\uFF57': 'w', + '\u1E81': 'w', + '\u1E83': 'w', + '\u0175': 'w', + '\u1E87': 'w', + '\u1E85': 'w', + '\u1E98': 'w', + '\u1E89': 'w', + '\u2C73': 'w', + '\u24E7': 'x', + '\uFF58': 'x', + '\u1E8B': 'x', + '\u1E8D': 'x', + '\u24E8': 'y', + '\uFF59': 'y', + '\u1EF3': 'y', + '\u00FD': 'y', + '\u0177': 'y', + '\u1EF9': 'y', + '\u0233': 'y', + '\u1E8F': 'y', + '\u00FF': 'y', + '\u1EF7': 'y', + '\u1E99': 'y', + '\u1EF5': 'y', + '\u01B4': 'y', + '\u024F': 'y', + '\u1EFF': 'y', + '\u24E9': 'z', + '\uFF5A': 'z', + '\u017A': 'z', + '\u1E91': 'z', + '\u017C': 'z', + '\u017E': 'z', + '\u1E93': 'z', + '\u1E95': 'z', + '\u01B6': 'z', + '\u0225': 'z', + '\u0240': 'z', + '\u2C6C': 'z', + '\uA763': 'z', + '\u0386': '\u0391', + '\u0388': '\u0395', + '\u0389': '\u0397', + '\u038A': '\u0399', + '\u03AA': '\u0399', + '\u038C': '\u039F', + '\u038E': '\u03A5', + '\u03AB': '\u03A5', + '\u038F': '\u03A9', + '\u03AC': '\u03B1', + '\u03AD': '\u03B5', + '\u03AE': '\u03B7', + '\u03AF': '\u03B9', + '\u03CA': '\u03B9', + '\u0390': '\u03B9', + '\u03CC': '\u03BF', + '\u03CD': '\u03C5', + '\u03CB': '\u03C5', + '\u03B0': '\u03C5', + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' + }; + + return diacritics; +}); + +S2.define('select2/data/base',[ + '../utils' +], function (Utils) { + function BaseAdapter ($element, options) { + BaseAdapter.__super__.constructor.call(this); + } + + Utils.Extend(BaseAdapter, Utils.Observable); + + BaseAdapter.prototype.current = function (callback) { + throw new Error('The `current` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.query = function (params, callback) { + throw new Error('The `query` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.bind = function (container, $container) { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.destroy = function () { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.generateResultId = function (container, data) { + var id = container.id + '-result-'; + + id += Utils.generateChars(4); + + if (data.id != null) { + id += '-' + data.id.toString(); + } else { + id += '-' + Utils.generateChars(4); + } + return id; + }; + + return BaseAdapter; +}); + +S2.define('select2/data/select',[ + './base', + '../utils', + 'jquery' +], function (BaseAdapter, Utils, $) { + function SelectAdapter ($element, options) { + this.$element = $element; + this.options = options; + + SelectAdapter.__super__.constructor.call(this); + } + + Utils.Extend(SelectAdapter, BaseAdapter); + + SelectAdapter.prototype.current = function (callback) { + var data = []; + var self = this; + + this.$element.find(':selected').each(function () { + var $option = $(this); + + var option = self.item($option); + + data.push(option); + }); + + callback(data); + }; + + SelectAdapter.prototype.select = function (data) { + var self = this; + + data.selected = true; + + // If data.element is a DOM node, use it instead + if ($(data.element).is('option')) { + data.element.selected = true; + + this.$element.trigger('input').trigger('change'); + + return; + } + + if (this.$element.prop('multiple')) { + this.current(function (currentData) { + var val = []; + + data = [data]; + data.push.apply(data, currentData); + + for (var d = 0; d < data.length; d++) { + var id = data[d].id; + + if ($.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + self.$element.trigger('input').trigger('change'); + }); + } else { + var val = data.id; + + this.$element.val(val); + this.$element.trigger('input').trigger('change'); + } + }; + + SelectAdapter.prototype.unselect = function (data) { + var self = this; + + if (!this.$element.prop('multiple')) { + return; + } + + data.selected = false; + + if ($(data.element).is('option')) { + data.element.selected = false; + + this.$element.trigger('input').trigger('change'); + + return; + } + + this.current(function (currentData) { + var val = []; + + for (var d = 0; d < currentData.length; d++) { + var id = currentData[d].id; + + if (id !== data.id && $.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + + self.$element.trigger('input').trigger('change'); + }); + }; + + SelectAdapter.prototype.bind = function (container, $container) { + var self = this; + + this.container = container; + + container.on('select', function (params) { + self.select(params.data); + }); + + container.on('unselect', function (params) { + self.unselect(params.data); + }); + }; + + SelectAdapter.prototype.destroy = function () { + // Remove anything added to child elements + this.$element.find('*').each(function () { + // Remove any custom data set by Select2 + Utils.RemoveData(this); + }); + }; + + SelectAdapter.prototype.query = function (params, callback) { + var data = []; + var self = this; + + var $options = this.$element.children(); + + $options.each(function () { + var $option = $(this); + + if (!$option.is('option') && !$option.is('optgroup')) { + return; + } + + var option = self.item($option); + + var matches = self.matches(params, option); + + if (matches !== null) { + data.push(matches); + } + }); + + callback({ + results: data + }); + }; + + SelectAdapter.prototype.addOptions = function ($options) { + Utils.appendMany(this.$element, $options); + }; + + SelectAdapter.prototype.option = function (data) { + var option; + + if (data.children) { + option = document.createElement('optgroup'); + option.label = data.text; + } else { + option = document.createElement('option'); + + if (option.textContent !== undefined) { + option.textContent = data.text; + } else { + option.innerText = data.text; + } + } + + if (data.id !== undefined) { + option.value = data.id; + } + + if (data.disabled) { + option.disabled = true; + } + + if (data.selected) { + option.selected = true; + } + + if (data.title) { + option.title = data.title; + } + + var $option = $(option); + + var normalizedData = this._normalizeItem(data); + normalizedData.element = option; + + // Override the option's data with the combined data + Utils.StoreData(option, 'data', normalizedData); + + return $option; + }; + + SelectAdapter.prototype.item = function ($option) { + var data = {}; + + data = Utils.GetData($option[0], 'data'); + + if (data != null) { + return data; + } + + if ($option.is('option')) { + data = { + id: $option.val(), + text: $option.text(), + disabled: $option.prop('disabled'), + selected: $option.prop('selected'), + title: $option.prop('title') + }; + } else if ($option.is('optgroup')) { + data = { + text: $option.prop('label'), + children: [], + title: $option.prop('title') + }; + + var $children = $option.children('option'); + var children = []; + + for (var c = 0; c < $children.length; c++) { + var $child = $($children[c]); + + var child = this.item($child); + + children.push(child); + } + + data.children = children; + } + + data = this._normalizeItem(data); + data.element = $option[0]; + + Utils.StoreData($option[0], 'data', data); + + return data; + }; + + SelectAdapter.prototype._normalizeItem = function (item) { + if (item !== Object(item)) { + item = { + id: item, + text: item + }; + } + + item = $.extend({}, { + text: '' + }, item); + + var defaults = { + selected: false, + disabled: false + }; + + if (item.id != null) { + item.id = item.id.toString(); + } + + if (item.text != null) { + item.text = item.text.toString(); + } + + if (item._resultId == null && item.id && this.container != null) { + item._resultId = this.generateResultId(this.container, item); + } + + return $.extend({}, defaults, item); + }; + + SelectAdapter.prototype.matches = function (params, data) { + var matcher = this.options.get('matcher'); + + return matcher(params, data); + }; + + return SelectAdapter; +}); + +S2.define('select2/data/array',[ + './select', + '../utils', + 'jquery' +], function (SelectAdapter, Utils, $) { + function ArrayAdapter ($element, options) { + this._dataToConvert = options.get('data') || []; + + ArrayAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(ArrayAdapter, SelectAdapter); + + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + + ArrayAdapter.prototype.select = function (data) { + var $option = this.$element.find('option').filter(function (i, elm) { + return elm.value == data.id.toString(); + }); + + if ($option.length === 0) { + $option = this.option(data); + + this.addOptions($option); + } + + ArrayAdapter.__super__.select.call(this, data); + }; + + ArrayAdapter.prototype.convertToOptions = function (data) { + var self = this; + + var $existing = this.$element.find('option'); + var existingIds = $existing.map(function () { + return self.item($(this)).id; + }).get(); + + var $options = []; + + // Filter out all items except for the one passed in the argument + function onlyItem (item) { + return function () { + return $(this).val() == item.id; + }; + } + + for (var d = 0; d < data.length; d++) { + var item = this._normalizeItem(data[d]); + + // Skip items which were pre-loaded, only merge the data + if ($.inArray(item.id, existingIds) >= 0) { + var $existingOption = $existing.filter(onlyItem(item)); + + var existingData = this.item($existingOption); + var newData = $.extend(true, {}, item, existingData); + + var $newOption = this.option(newData); + + $existingOption.replaceWith($newOption); + + continue; + } + + var $option = this.option(item); + + if (item.children) { + var $children = this.convertToOptions(item.children); + + Utils.appendMany($option, $children); + } + + $options.push($option); + } + + return $options; + }; + + return ArrayAdapter; +}); + +S2.define('select2/data/ajax',[ + './array', + '../utils', + 'jquery' +], function (ArrayAdapter, Utils, $) { + function AjaxAdapter ($element, options) { + this.ajaxOptions = this._applyDefaults(options.get('ajax')); + + if (this.ajaxOptions.processResults != null) { + this.processResults = this.ajaxOptions.processResults; + } + + AjaxAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(AjaxAdapter, ArrayAdapter); + + AjaxAdapter.prototype._applyDefaults = function (options) { + var defaults = { + data: function (params) { + return $.extend({}, params, { + q: params.term + }); + }, + transport: function (params, success, failure) { + var $request = $.ajax(params); + + $request.then(success); + $request.fail(failure); + + return $request; + } + }; + + return $.extend({}, defaults, options, true); + }; + + AjaxAdapter.prototype.processResults = function (results) { + return results; + }; + + AjaxAdapter.prototype.query = function (params, callback) { + var matches = []; + var self = this; + + if (this._request != null) { + // JSONP requests cannot always be aborted + if ($.isFunction(this._request.abort)) { + this._request.abort(); + } + + this._request = null; + } + + var options = $.extend({ + type: 'GET' + }, this.ajaxOptions); + + if (typeof options.url === 'function') { + options.url = options.url.call(this.$element, params); + } + + if (typeof options.data === 'function') { + options.data = options.data.call(this.$element, params); + } + + function request () { + var $request = options.transport(options, function (data) { + var results = self.processResults(data, params); + + if (self.options.get('debug') && window.console && console.error) { + // Check to make sure that the response included a `results` key. + if (!results || !results.results || !$.isArray(results.results)) { + console.error( + 'Select2: The AJAX results did not return an array in the ' + + '`results` key of the response.' + ); + } + } + + callback(results); + }, function () { + // Attempt to detect if a request was aborted + // Only works if the transport exposes a status property + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { + return; + } + + self.trigger('results:message', { + message: 'errorLoading' + }); + }); + + self._request = $request; + } + + if (this.ajaxOptions.delay && params.term != null) { + if (this._queryTimeout) { + window.clearTimeout(this._queryTimeout); + } + + this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); + } else { + request(); + } + }; + + return AjaxAdapter; +}); + +S2.define('select2/data/tags',[ + 'jquery' +], function ($) { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + var createTag = options.get('createTag'); + + if (createTag !== undefined) { + this.createTag = createTag; + } + + var insertTag = options.get('insertTag'); + + if (insertTag !== undefined) { + this.insertTag = insertTag; + } + + decorated.call(this, $element, options); + + if ($.isArray(tags)) { + for (var t = 0; t < tags.length; t++) { + var tag = tags[t]; + var item = this._normalizeItem(tag); + + var $option = this.option(item); + + this.$element.append($option); + } + } + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + this._removeOldTags(); + + if (params.term == null || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (obj, child) { + var data = obj.results; + + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && + !wrapper({ + results: option.children + }, true) + ); + + var optionText = (option.text || '').toUpperCase(); + var paramsTerm = (params.term || '').toUpperCase(); + + var checkText = optionText === paramsTerm; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + obj.data = data; + callback(obj); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + + if (tag != null) { + var $option = self.option(tag); + $option.attr('data-select2-tag', true); + + self.addOptions([$option]); + + self.insertTag(data, tag); + } + + obj.results = data; + + callback(obj); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + var term = $.trim(params.term); + + if (term === '') { + return null; + } + + return { + id: term, + text: term + }; + }; + + Tags.prototype.insertTag = function (_, data, tag) { + data.unshift(tag); + }; + + Tags.prototype._removeOldTags = function (_) { + var $options = this.$element.find('option[data-select2-tag]'); + + $options.each(function () { + if (this.selected) { + return; + } + + $(this).remove(); + }); + }; + + return Tags; +}); + +S2.define('select2/data/tokenizer',[ + 'jquery' +], function ($) { + function Tokenizer (decorated, $element, options) { + var tokenizer = options.get('tokenizer'); + + if (tokenizer !== undefined) { + this.tokenizer = tokenizer; + } + + decorated.call(this, $element, options); + } + + Tokenizer.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + this.$search = container.dropdown.$search || container.selection.$search || + $container.find('.select2-search__field'); + }; + + Tokenizer.prototype.query = function (decorated, params, callback) { + var self = this; + + function createAndSelect (data) { + // Normalize the data object so we can use it for checks + var item = self._normalizeItem(data); + + // Check if the data object already exists as a tag + // Select it if it doesn't + var $existingOptions = self.$element.find('option').filter(function () { + return $(this).val() === item.id; + }); + + // If an existing option wasn't found for it, create the option + if (!$existingOptions.length) { + var $option = self.option(item); + $option.attr('data-select2-tag', true); + + self._removeOldTags(); + self.addOptions([$option]); + } + + // Select the item, now that we know there is an option for it + select(item); + } + + function select (data) { + self.trigger('select', { + data: data + }); + } + + params.term = params.term || ''; + + var tokenData = this.tokenizer(params, this.options, createAndSelect); + + if (tokenData.term !== params.term) { + // Replace the search term if we have the search box + if (this.$search.length) { + this.$search.val(tokenData.term); + this.$search.trigger('focus'); + } + + params.term = tokenData.term; + } + + decorated.call(this, params, callback); + }; + + Tokenizer.prototype.tokenizer = function (_, params, options, callback) { + var separators = options.get('tokenSeparators') || []; + var term = params.term; + var i = 0; + + var createTag = this.createTag || function (params) { + return { + id: params.term, + text: params.term + }; + }; + + while (i < term.length) { + var termChar = term[i]; + + if ($.inArray(termChar, separators) === -1) { + i++; + + continue; + } + + var part = term.substr(0, i); + var partParams = $.extend({}, params, { + term: part + }); + + var data = createTag(partParams); + + if (data == null) { + i++; + continue; + } + + callback(data); + + // Reset the term to not include the tokenized portion + term = term.substr(i + 1) || ''; + i = 0; + } + + return { + term: term + }; + }; + + return Tokenizer; +}); + +S2.define('select2/data/minimumInputLength',[ + +], function () { + function MinimumInputLength (decorated, $e, options) { + this.minimumInputLength = options.get('minimumInputLength'); + + decorated.call(this, $e, options); + } + + MinimumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (params.term.length < this.minimumInputLength) { + this.trigger('results:message', { + message: 'inputTooShort', + args: { + minimum: this.minimumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MinimumInputLength; +}); + +S2.define('select2/data/maximumInputLength',[ + +], function () { + function MaximumInputLength (decorated, $e, options) { + this.maximumInputLength = options.get('maximumInputLength'); + + decorated.call(this, $e, options); + } + + MaximumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (this.maximumInputLength > 0 && + params.term.length > this.maximumInputLength) { + this.trigger('results:message', { + message: 'inputTooLong', + args: { + maximum: this.maximumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MaximumInputLength; +}); + +S2.define('select2/data/maximumSelectionLength',[ + +], function (){ + function MaximumSelectionLength (decorated, $e, options) { + this.maximumSelectionLength = options.get('maximumSelectionLength'); + + decorated.call(this, $e, options); + } + + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + + MaximumSelectionLength.prototype.query = + function (decorated, params, callback) { + var self = this; + + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + + this.current(function (currentData) { + var count = currentData != null ? currentData.length : 0; + if (self.maximumSelectionLength > 0 && + count >= self.maximumSelectionLength) { + self.trigger('results:message', { + message: 'maximumSelected', + args: { + maximum: self.maximumSelectionLength + } + }); + return; + } + + if (successCallback) { + successCallback(); + } + }); + }; + + return MaximumSelectionLength; +}); + +S2.define('select2/dropdown',[ + 'jquery', + './utils' +], function ($, Utils) { + function Dropdown ($element, options) { + this.$element = $element; + this.options = options; + + Dropdown.__super__.constructor.call(this); + } + + Utils.Extend(Dropdown, Utils.Observable); + + Dropdown.prototype.render = function () { + var $dropdown = $( + '' + + '' + + '' + ); + + $dropdown.attr('dir', this.options.get('dir')); + + this.$dropdown = $dropdown; + + return $dropdown; + }; + + Dropdown.prototype.bind = function () { + // Should be implemented in subclasses + }; + + Dropdown.prototype.position = function ($dropdown, $container) { + // Should be implemented in subclasses + }; + + Dropdown.prototype.destroy = function () { + // Remove the dropdown from the DOM + this.$dropdown.remove(); + }; + + return Dropdown; +}); + +S2.define('select2/dropdown/search',[ + 'jquery', + '../utils' +], function ($, Utils) { + function Search () { } + + Search.prototype.render = function (decorated) { + var $rendered = decorated.call(this); + + var $search = $( + '' + + '' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + $rendered.prepend($search); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + decorated.call(this, container, $container); + + this.$search.on('keydown', function (evt) { + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + }); + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$search.on('input', function (evt) { + // Unbind the duplicated `keyup` event + $(this).off('keyup'); + }); + + this.$search.on('keyup input', function (evt) { + self.handleSearch(evt); + }); + + container.on('open', function () { + self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); + + self.$search.trigger('focus'); + + window.setTimeout(function () { + self.$search.trigger('focus'); + }, 0); + }); + + container.on('close', function () { + self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); + + self.$search.val(''); + self.$search.trigger('blur'); + }); + + container.on('focus', function () { + if (!container.isOpen()) { + self.$search.trigger('focus'); + } + }); + + container.on('results:all', function (params) { + if (params.query.term == null || params.query.term === '') { + var showSearch = self.showSearch(params); + + if (showSearch) { + self.$searchContainer.removeClass('select2-search--hide'); + } else { + self.$searchContainer.addClass('select2-search--hide'); + } + } + }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); + }; + + Search.prototype.handleSearch = function (evt) { + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.showSearch = function (_, params) { + return true; + }; + + return Search; +}); + +S2.define('select2/dropdown/hidePlaceholder',[ + +], function () { + function HidePlaceholder (decorated, $element, options, dataAdapter) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options, dataAdapter); + } + + HidePlaceholder.prototype.append = function (decorated, data) { + data.results = this.removePlaceholder(data.results); + + decorated.call(this, data); + }; + + HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + HidePlaceholder.prototype.removePlaceholder = function (_, data) { + var modifiedData = data.slice(0); + + for (var d = data.length - 1; d >= 0; d--) { + var item = data[d]; + + if (this.placeholder.id === item.id) { + modifiedData.splice(d, 1); + } + } + + return modifiedData; + }; + + return HidePlaceholder; +}); + +S2.define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + this.loading = false; + + decorated.call(this, data); + + if (this.showLoadingMore(data)) { + this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); + } + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; + + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); + + if (this.loading || !isLoadMoreVisible) { + return; + } + + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.showLoadingMore = function (_, data) { + return data.pagination && data.pagination.more; + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
              • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + +S2.define('select2/dropdown/attachBody',[ + 'jquery', + '../utils' +], function ($, Utils) { + function AttachBody (decorated, $element, options) { + this.$dropdownParent = $(options.get('dropdownParent') || document.body); + + decorated.call(this, $element, options); + } + + AttachBody.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('open', function () { + self._showDropdown(); + self._attachPositioningHandler(container); + + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); + }); + + container.on('close', function () { + self._hideDropdown(); + self._detachPositioningHandler(container); + }); + + this.$dropdownContainer.on('mousedown', function (evt) { + evt.stopPropagation(); + }); + }; + + AttachBody.prototype.destroy = function (decorated) { + decorated.call(this); + + this.$dropdownContainer.remove(); + }; + + AttachBody.prototype.position = function (decorated, $dropdown, $container) { + // Clone all of the container classes + $dropdown.attr('class', $container.attr('class')); + + $dropdown.removeClass('select2'); + $dropdown.addClass('select2-container--open'); + + $dropdown.css({ + position: 'absolute', + top: -999999 + }); + + this.$container = $container; + }; + + AttachBody.prototype.render = function (decorated) { + var $container = $(''); + + var $dropdown = decorated.call(this); + $container.append($dropdown); + + this.$dropdownContainer = $container; + + return $container; + }; + + AttachBody.prototype._hideDropdown = function (decorated) { + this.$dropdownContainer.detach(); + }; + + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + + AttachBody.prototype._attachPositioningHandler = + function (decorated, container) { + var self = this; + + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.each(function () { + Utils.StoreData(this, 'select2-scroll-position', { + x: $(this).scrollLeft(), + y: $(this).scrollTop() + }); + }); + + $watchers.on(scrollEvent, function (ev) { + var position = Utils.GetData(this, 'select2-scroll-position'); + $(this).scrollTop(position.y); + }); + + $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, + function (e) { + self._positionDropdown(); + self._resizeDropdown(); + }); + }; + + AttachBody.prototype._detachPositioningHandler = + function (decorated, container) { + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.off(scrollEvent); + + $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); + }; + + AttachBody.prototype._positionDropdown = function () { + var $window = $(window); + + var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); + var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); + + var newDirection = null; + + var offset = this.$container.offset(); + + offset.bottom = offset.top + this.$container.outerHeight(false); + + var container = { + height: this.$container.outerHeight(false) + }; + + container.top = offset.top; + container.bottom = offset.top + container.height; + + var dropdown = { + height: this.$dropdown.outerHeight(false) + }; + + var viewport = { + top: $window.scrollTop(), + bottom: $window.scrollTop() + $window.height() + }; + + var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); + var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); + + var css = { + left: offset.left, + top: container.bottom + }; + + // Determine what the parent element is to use for calculating the offset + var $offsetParent = this.$dropdownParent; + + // For statically positioned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); + } + + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } + + css.top -= parentOffset.top; + css.left -= parentOffset.left; + + if (!isCurrentlyAbove && !isCurrentlyBelow) { + newDirection = 'below'; + } + + if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { + newDirection = 'above'; + } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { + newDirection = 'below'; + } + + if (newDirection == 'above' || + (isCurrentlyAbove && newDirection !== 'below')) { + css.top = container.top - parentOffset.top - dropdown.height; + } + + if (newDirection != null) { + this.$dropdown + .removeClass('select2-dropdown--below select2-dropdown--above') + .addClass('select2-dropdown--' + newDirection); + this.$container + .removeClass('select2-container--below select2-container--above') + .addClass('select2-container--' + newDirection); + } + + this.$dropdownContainer.css(css); + }; + + AttachBody.prototype._resizeDropdown = function () { + var css = { + width: this.$container.outerWidth(false) + 'px' + }; + + if (this.options.get('dropdownAutoWidth')) { + css.minWidth = css.width; + css.position = 'relative'; + css.width = 'auto'; + } + + this.$dropdown.css(css); + }; + + AttachBody.prototype._showDropdown = function (decorated) { + this.$dropdownContainer.appendTo(this.$dropdownParent); + + this._positionDropdown(); + this._resizeDropdown(); + }; + + return AttachBody; +}); + +S2.define('select2/dropdown/minimumResultsForSearch',[ + +], function () { + function countResults (data) { + var count = 0; + + for (var d = 0; d < data.length; d++) { + var item = data[d]; + + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + } + + return count; + } + + function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { + this.minimumResultsForSearch = options.get('minimumResultsForSearch'); + + if (this.minimumResultsForSearch < 0) { + this.minimumResultsForSearch = Infinity; + } + + decorated.call(this, $element, options, dataAdapter); + } + + MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { + if (countResults(params.data.results) < this.minimumResultsForSearch) { + return false; + } + + return decorated.call(this, params); + }; + + return MinimumResultsForSearch; +}); + +S2.define('select2/dropdown/selectOnClose',[ + '../utils' +], function (Utils) { + function SelectOnClose () { } + + SelectOnClose.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('close', function (params) { + self._handleSelectOnClose(params); + }); + }; + + SelectOnClose.prototype._handleSelectOnClose = function (_, params) { + if (params && params.originalSelect2Event != null) { + var event = params.originalSelect2Event; + + // Don't select an item if the close event was triggered from a select or + // unselect event + if (event._type === 'select' || event._type === 'unselect') { + return; + } + } + + var $highlightedResults = this.getHighlightedResults(); + + // Only select highlighted results + if ($highlightedResults.length < 1) { + return; + } + + var data = Utils.GetData($highlightedResults[0], 'data'); + + // Don't re-select already selected resulte + if ( + (data.element != null && data.element.selected) || + (data.element == null && data.selected) + ) { + return; + } + + this.trigger('select', { + data: data + }); + }; + + return SelectOnClose; +}); + +S2.define('select2/dropdown/closeOnSelect',[ + +], function () { + function CloseOnSelect () { } + + CloseOnSelect.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function (evt) { + self._selectTriggered(evt); + }); + + container.on('unselect', function (evt) { + self._selectTriggered(evt); + }); + }; + + CloseOnSelect.prototype._selectTriggered = function (_, evt) { + var originalEvent = evt.originalEvent; + + // Don't close if the control key is being held + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { + return; + } + + this.trigger('close', { + originalEvent: originalEvent, + originalSelect2Event: evt + }); + }; + + return CloseOnSelect; +}); + +S2.define('select2/i18n/en',[],function () { + // English + return { + errorLoading: function () { + return 'The results could not be loaded.'; + }, + inputTooLong: function (args) { + var overChars = args.input.length - args.maximum; + + var message = 'Please delete ' + overChars + ' character'; + + if (overChars != 1) { + message += 's'; + } + + return message; + }, + inputTooShort: function (args) { + var remainingChars = args.minimum - args.input.length; + + var message = 'Please enter ' + remainingChars + ' or more characters'; + + return message; + }, + loadingMore: function () { + return 'Loading more results…'; + }, + maximumSelected: function (args) { + var message = 'You can only select ' + args.maximum + ' item'; + + if (args.maximum != 1) { + message += 's'; + } + + return message; + }, + noResults: function () { + return 'No results found'; + }, + searching: function () { + return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; + } + }; +}); + +S2.define('select2/defaults',[ + 'jquery', + 'require', + + './results', + + './selection/single', + './selection/multiple', + './selection/placeholder', + './selection/allowClear', + './selection/search', + './selection/eventRelay', + + './utils', + './translation', + './diacritics', + + './data/select', + './data/array', + './data/ajax', + './data/tags', + './data/tokenizer', + './data/minimumInputLength', + './data/maximumInputLength', + './data/maximumSelectionLength', + + './dropdown', + './dropdown/search', + './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', + './dropdown/attachBody', + './dropdown/minimumResultsForSearch', + './dropdown/selectOnClose', + './dropdown/closeOnSelect', + + './i18n/en' +], function ($, require, + + ResultsList, + + SingleSelection, MultipleSelection, Placeholder, AllowClear, + SelectionSearch, EventRelay, + + Utils, Translation, DIACRITICS, + + SelectData, ArrayData, AjaxData, Tags, Tokenizer, + MinimumInputLength, MaximumInputLength, MaximumSelectionLength, + + Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, + AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, + + EnglishTranslation) { + function Defaults () { + this.reset(); + } + + Defaults.prototype.apply = function (options) { + options = $.extend(true, {}, this.defaults, options); + + if (options.dataAdapter == null) { + if (options.ajax != null) { + options.dataAdapter = AjaxData; + } else if (options.data != null) { + options.dataAdapter = ArrayData; + } else { + options.dataAdapter = SelectData; + } + + if (options.minimumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MinimumInputLength + ); + } + + if (options.maximumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumInputLength + ); + } + + if (options.maximumSelectionLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumSelectionLength + ); + } + + if (options.tags) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + + if (options.tokenSeparators != null || options.tokenizer != null) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Tokenizer + ); + } + + if (options.query != null) { + var Query = require(options.amdBase + 'compat/query'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Query + ); + } + + if (options.initSelection != null) { + var InitSelection = require(options.amdBase + 'compat/initSelection'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + InitSelection + ); + } + } + + if (options.resultsAdapter == null) { + options.resultsAdapter = ResultsList; + + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + + if (options.placeholder != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + HidePlaceholder + ); + } + + if (options.selectOnClose) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + SelectOnClose + ); + } + } + + if (options.dropdownAdapter == null) { + if (options.multiple) { + options.dropdownAdapter = Dropdown; + } else { + var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + + options.dropdownAdapter = SearchableDropdown; + } + + if (options.minimumResultsForSearch !== 0) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + MinimumResultsForSearch + ); + } + + if (options.closeOnSelect) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + CloseOnSelect + ); + } + + if ( + options.dropdownCssClass != null || + options.dropdownCss != null || + options.adaptDropdownCssClass != null + ) { + var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + DropdownCSS + ); + } + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + AttachBody + ); + } + + if (options.selectionAdapter == null) { + if (options.multiple) { + options.selectionAdapter = MultipleSelection; + } else { + options.selectionAdapter = SingleSelection; + } + + // Add the placeholder mixin if a placeholder was specified + if (options.placeholder != null) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + Placeholder + ); + } + + if (options.allowClear) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + AllowClear + ); + } + + if (options.multiple) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + SelectionSearch + ); + } + + if ( + options.containerCssClass != null || + options.containerCss != null || + options.adaptContainerCssClass != null + ) { + var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + ContainerCSS + ); + } + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + EventRelay + ); + } + + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); + + // Always fall back to English since it will always be complete + options.language.push('en'); + + var uniqueLanguages = []; + + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; + + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); + } + } + + options.language = uniqueLanguages; + + options.translations = this._processTranslations( + options.language, + options.debug + ); + + return options; + }; + + Defaults.prototype.reset = function () { + function stripDiacritics (text) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } + + return text.replace(/[^\u0000-\u007E]/g, match); + } + + function matcher (params, data) { + // Always return the object if there is nothing to compare + if ($.trim(params.term) === '') { + return data; + } + + // Do a recursive check for options with children + if (data.children && data.children.length > 0) { + // Clone the data object if there are children + // This is required as we modify the object to remove any non-matches + var match = $.extend(true, {}, data); + + // Check each child of the option + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; + + var matches = matcher(params, child); + + // If there wasn't a match, remove the object in the array + if (matches == null) { + match.children.splice(c, 1); + } + } + + // If any children matched, return the new object + if (match.children.length > 0) { + return match; + } + + // If there were no matching children, check just the plain object + return matcher(params, match); + } + + var original = stripDiacritics(data.text).toUpperCase(); + var term = stripDiacritics(params.term).toUpperCase(); + + // Check if the text contains the term + if (original.indexOf(term) > -1) { + return data; + } + + // If it doesn't contain the term, don't return anything + return null; + } + + this.defaults = { + amdBase: './', + amdLanguageBase: './i18n/', + closeOnSelect: true, + debug: false, + dropdownAutoWidth: false, + escapeMarkup: Utils.escapeMarkup, + language: {}, + matcher: matcher, + minimumInputLength: 0, + maximumInputLength: 0, + maximumSelectionLength: 0, + minimumResultsForSearch: 0, + selectOnClose: false, + scrollAfterSelect: false, + sorter: function (data) { + return data; + }, + templateResult: function (result) { + return result.text; + }, + templateSelection: function (selection) { + return selection.text; + }, + theme: 'default', + width: 'resolve' + }; + }; + + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + + Defaults.prototype.set = function (key, value) { + var camelKey = $.camelCase(key); + + var data = {}; + data[camelKey] = value; + + var convertedData = Utils._convertData(data); + + $.extend(true, this.defaults, convertedData); + }; + + var defaults = new Defaults(); + + return defaults; +}); + +S2.define('select2/options',[ + 'require', + 'jquery', + './defaults', + './utils' +], function (require, $, Defaults, Utils) { + function Options (options, $element) { + this.options = options; + + if ($element != null) { + this.fromElement($element); + } + + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + + this.options = Defaults.apply(this.options); + + if ($element && $element.is('input')) { + var InputCompat = require(this.get('amdBase') + 'compat/inputData'); + + this.options.dataAdapter = Utils.Decorate( + this.options.dataAdapter, + InputCompat + ); + } + } + + Options.prototype.fromElement = function ($e) { + var excludedData = ['select2']; + + if (this.options.multiple == null) { + this.options.multiple = $e.prop('multiple'); + } + + if (this.options.disabled == null) { + this.options.disabled = $e.prop('disabled'); + } + + if (this.options.dir == null) { + if ($e.prop('dir')) { + this.options.dir = $e.prop('dir'); + } else if ($e.closest('[dir]').prop('dir')) { + this.options.dir = $e.closest('[dir]').prop('dir'); + } else { + this.options.dir = 'ltr'; + } + } + + $e.prop('disabled', this.options.disabled); + $e.prop('multiple', this.options.multiple); + + if (Utils.GetData($e[0], 'select2Tags')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-select2-tags` attribute has been changed to ' + + 'use the `data-data` and `data-tags="true"` attributes and will be ' + + 'removed in future versions of Select2.' + ); + } + + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); + } + + if (Utils.GetData($e[0], 'ajaxUrl')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-ajax-url` attribute has been changed to ' + + '`data-ajax--url` and support for the old attribute will be removed' + + ' in future versions of Select2.' + ); + } + + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); + } + + var dataset = {}; + + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + + // Prefer the element's `dataset` attribute if it exists + // jQuery 1.x does not correctly handle data attributes with multiple dashes + if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { + dataset = $.extend(true, {}, $e[0].dataset, dataset); + } + + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); + + data = Utils._convertData(data); + + for (var key in data) { + if ($.inArray(key, excludedData) > -1) { + continue; + } + + if ($.isPlainObject(this.options[key])) { + $.extend(this.options[key], data[key]); + } else { + this.options[key] = data[key]; + } + } + + return this; + }; + + Options.prototype.get = function (key) { + return this.options[key]; + }; + + Options.prototype.set = function (key, val) { + this.options[key] = val; + }; + + return Options; +}); + +S2.define('select2/core',[ + 'jquery', + './options', + './utils', + './keys' +], function ($, Options, Utils, KEYS) { + var Select2 = function ($element, options) { + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); + } + + this.$element = $element; + + this.id = this._generateId($element); + + options = options || {}; + + this.options = new Options(options, $element); + + Select2.__super__.constructor.call(this); + + // Set up the tabindex + + var tabindex = $element.attr('tabindex') || 0; + Utils.StoreData($element[0], 'old-tabindex', tabindex); + $element.attr('tabindex', '-1'); + + // Set up containers and adapters + + var DataAdapter = this.options.get('dataAdapter'); + this.dataAdapter = new DataAdapter($element, this.options); + + var $container = this.render(); + + this._placeContainer($container); + + var SelectionAdapter = this.options.get('selectionAdapter'); + this.selection = new SelectionAdapter($element, this.options); + this.$selection = this.selection.render(); + + this.selection.position(this.$selection, $container); + + var DropdownAdapter = this.options.get('dropdownAdapter'); + this.dropdown = new DropdownAdapter($element, this.options); + this.$dropdown = this.dropdown.render(); + + this.dropdown.position(this.$dropdown, $container); + + var ResultsAdapter = this.options.get('resultsAdapter'); + this.results = new ResultsAdapter($element, this.options, this.dataAdapter); + this.$results = this.results.render(); + + this.results.position(this.$results, this.$dropdown); + + // Bind events + + var self = this; + + // Bind the container to all of the adapters + this._bindAdapters(); + + // Register any DOM event handlers + this._registerDomEvents(); + + // Register any internal event handlers + this._registerDataEvents(); + this._registerSelectionEvents(); + this._registerDropdownEvents(); + this._registerResultsEvents(); + this._registerEvents(); + + // Set the initial state + this.dataAdapter.current(function (initialData) { + self.trigger('selection:update', { + data: initialData + }); + }); + + // Hide the original select + $element.addClass('select2-hidden-accessible'); + $element.attr('aria-hidden', 'true'); + + // Synchronize any monitored attributes + this._syncAttributes(); + + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). + $element.data('select2', this); + }; + + Utils.Extend(Select2, Utils.Observable); + + Select2.prototype._generateId = function ($element) { + var id = ''; + + if ($element.attr('id') != null) { + id = $element.attr('id'); + } else if ($element.attr('name') != null) { + id = $element.attr('name') + '-' + Utils.generateChars(2); + } else { + id = Utils.generateChars(4); + } + + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = 'select2-' + id; + + return id; + }; + + Select2.prototype._placeContainer = function ($container) { + $container.insertAfter(this.$element); + + var width = this._resolveWidth(this.$element, this.options.get('width')); + + if (width != null) { + $container.css('width', width); + } + }; + + Select2.prototype._resolveWidth = function ($element, method) { + var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; + + if (method == 'resolve') { + var styleWidth = this._resolveWidth($element, 'style'); + + if (styleWidth != null) { + return styleWidth; + } + + return this._resolveWidth($element, 'element'); + } + + if (method == 'element') { + var elementWidth = $element.outerWidth(false); + + if (elementWidth <= 0) { + return 'auto'; + } + + return elementWidth + 'px'; + } + + if (method == 'style') { + var style = $element.attr('style'); + + if (typeof(style) !== 'string') { + return null; + } + + var attrs = style.split(';'); + + for (var i = 0, l = attrs.length; i < l; i = i + 1) { + var attr = attrs[i].replace(/\s/g, ''); + var matches = attr.match(WIDTH); + + if (matches !== null && matches.length >= 1) { + return matches[1]; + } + } + + return null; + } + + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + + return method; + }; + + Select2.prototype._bindAdapters = function () { + this.dataAdapter.bind(this, this.$container); + this.selection.bind(this, this.$container); + + this.dropdown.bind(this, this.$container); + this.results.bind(this, this.$container); + }; + + Select2.prototype._registerDomEvents = function () { + var self = this; + + this.$element.on('change.select2', function () { + self.dataAdapter.current(function (data) { + self.trigger('selection:update', { + data: data + }); + }); + }); + + this.$element.on('focus.select2', function (evt) { + self.trigger('focus', evt); + }); + + this._syncA = Utils.bind(this._syncAttributes, this); + this._syncS = Utils.bind(this._syncSubtree, this); + + if (this.$element[0].attachEvent) { + this.$element[0].attachEvent('onpropertychange', this._syncA); + } + + var observer = window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver + ; + + if (observer != null) { + this._observer = new observer(function (mutations) { + self._syncA(); + self._syncS(null, mutations); + }); + this._observer.observe(this.$element[0], { + attributes: true, + childList: true, + subtree: false + }); + } else if (this.$element[0].addEventListener) { + this.$element[0].addEventListener( + 'DOMAttrModified', + self._syncA, + false + ); + this.$element[0].addEventListener( + 'DOMNodeInserted', + self._syncS, + false + ); + this.$element[0].addEventListener( + 'DOMNodeRemoved', + self._syncS, + false + ); + } + }; + + Select2.prototype._registerDataEvents = function () { + var self = this; + + this.dataAdapter.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerSelectionEvents = function () { + var self = this; + var nonRelayEvents = ['toggle', 'focus']; + + this.selection.on('toggle', function () { + self.toggleDropdown(); + }); + + this.selection.on('focus', function (params) { + self.focus(params); + }); + + this.selection.on('*', function (name, params) { + if ($.inArray(name, nonRelayEvents) !== -1) { + return; + } + + self.trigger(name, params); + }); + }; + + Select2.prototype._registerDropdownEvents = function () { + var self = this; + + this.dropdown.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerResultsEvents = function () { + var self = this; + + this.results.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerEvents = function () { + var self = this; + + this.on('open', function () { + self.$container.addClass('select2-container--open'); + }); + + this.on('close', function () { + self.$container.removeClass('select2-container--open'); + }); + + this.on('enable', function () { + self.$container.removeClass('select2-container--disabled'); + }); + + this.on('disable', function () { + self.$container.addClass('select2-container--disabled'); + }); + + this.on('blur', function () { + self.$container.removeClass('select2-container--focus'); + }); + + this.on('query', function (params) { + if (!self.isOpen()) { + self.trigger('open', {}); + } + + this.dataAdapter.query(params, function (data) { + self.trigger('results:all', { + data: data, + query: params + }); + }); + }); + + this.on('query:append', function (params) { + this.dataAdapter.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + + this.on('keypress', function (evt) { + var key = evt.which; + + if (self.isOpen()) { + if (key === KEYS.ESC || key === KEYS.TAB || + (key === KEYS.UP && evt.altKey)) { + self.close(evt); + + evt.preventDefault(); + } else if (key === KEYS.ENTER) { + self.trigger('results:select', {}); + + evt.preventDefault(); + } else if ((key === KEYS.SPACE && evt.ctrlKey)) { + self.trigger('results:toggle', {}); + + evt.preventDefault(); + } else if (key === KEYS.UP) { + self.trigger('results:previous', {}); + + evt.preventDefault(); + } else if (key === KEYS.DOWN) { + self.trigger('results:next', {}); + + evt.preventDefault(); + } + } else { + if (key === KEYS.ENTER || key === KEYS.SPACE || + (key === KEYS.DOWN && evt.altKey)) { + self.open(); + + evt.preventDefault(); + } + } + }); + }; + + Select2.prototype._syncAttributes = function () { + this.options.set('disabled', this.$element.prop('disabled')); + + if (this.isDisabled()) { + if (this.isOpen()) { + this.close(); + } + + this.trigger('disable', {}); + } else { + this.trigger('enable', {}); + } + }; + + Select2.prototype._isChangeMutation = function (evt, mutations) { + var changed = false; + var self = this; + + // Ignore any mutation events raised for elements that aren't options or + // optgroups. This handles the case when the select element is destroyed + if ( + evt && evt.target && ( + evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP' + ) + ) { + return; + } + + if (!mutations) { + // If mutation events aren't supported, then we can only assume that the + // change affected the selections + changed = true; + } else if (mutations.addedNodes && mutations.addedNodes.length > 0) { + for (var n = 0; n < mutations.addedNodes.length; n++) { + var node = mutations.addedNodes[n]; + + if (node.selected) { + changed = true; + } + } + } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { + changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); + } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; + + // Only re-pull the data if we think there is a change + if (changed) { + this.dataAdapter.current(function (currentData) { + self.trigger('selection:update', { + data: currentData + }); + }); + } + }; + + /** + * Override the trigger method to automatically trigger pre-events when + * there are events that can be prevented. + */ + Select2.prototype.trigger = function (name, args) { + var actualTrigger = Select2.__super__.trigger; + var preTriggerMap = { + 'open': 'opening', + 'close': 'closing', + 'select': 'selecting', + 'unselect': 'unselecting', + 'clear': 'clearing' + }; + + if (args === undefined) { + args = {}; + } + + if (name in preTriggerMap) { + var preTriggerName = preTriggerMap[name]; + var preTriggerArgs = { + prevented: false, + name: name, + args: args + }; + + actualTrigger.call(this, preTriggerName, preTriggerArgs); + + if (preTriggerArgs.prevented) { + args.prevented = true; + + return; + } + } + + actualTrigger.call(this, name, args); + }; + + Select2.prototype.toggleDropdown = function () { + if (this.isDisabled()) { + return; + } + + if (this.isOpen()) { + this.close(); + } else { + this.open(); + } + }; + + Select2.prototype.open = function () { + if (this.isOpen()) { + return; + } + + if (this.isDisabled()) { + return; + } + + this.trigger('query', {}); + }; + + Select2.prototype.close = function (evt) { + if (!this.isOpen()) { + return; + } + + this.trigger('close', { originalEvent : evt }); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + Select2.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + Select2.prototype.isDisabled = function () { + return this.options.get('disabled'); + }; + + Select2.prototype.isOpen = function () { + return this.$container.hasClass('select2-container--open'); + }; + + Select2.prototype.hasFocus = function () { + return this.$container.hasClass('select2-container--focus'); + }; + + Select2.prototype.focus = function (data) { + // No need to re-trigger focus events if we are already focused + if (this.hasFocus()) { + return; + } + + this.$container.addClass('select2-container--focus'); + this.trigger('focus', {}); + }; + + Select2.prototype.enable = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("enable")` method has been deprecated and will' + + ' be removed in later Select2 versions. Use $element.prop("disabled")' + + ' instead.' + ); + } + + if (args == null || args.length === 0) { + args = [true]; + } + + var disabled = !args[0]; + + this.$element.prop('disabled', disabled); + }; + + Select2.prototype.data = function () { + if (this.options.get('debug') && + arguments.length > 0 && window.console && console.warn) { + console.warn( + 'Select2: Data can no longer be set using `select2("data")`. You ' + + 'should consider setting the value instead using `$element.val()`.' + ); + } + + var data = []; + + this.dataAdapter.current(function (currentData) { + data = currentData; + }); + + return data; + }; + + Select2.prototype.val = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("val")` method has been deprecated and will be' + + ' removed in later Select2 versions. Use $element.val() instead.' + ); + } + + if (args == null || args.length === 0) { + return this.$element.val(); + } + + var newVal = args[0]; + + if ($.isArray(newVal)) { + newVal = $.map(newVal, function (obj) { + return obj.toString(); + }); + } + + this.$element.val(newVal).trigger('input').trigger('change'); + }; + + Select2.prototype.destroy = function () { + this.$container.remove(); + + if (this.$element[0].detachEvent) { + this.$element[0].detachEvent('onpropertychange', this._syncA); + } + + if (this._observer != null) { + this._observer.disconnect(); + this._observer = null; + } else if (this.$element[0].removeEventListener) { + this.$element[0] + .removeEventListener('DOMAttrModified', this._syncA, false); + this.$element[0] + .removeEventListener('DOMNodeInserted', this._syncS, false); + this.$element[0] + .removeEventListener('DOMNodeRemoved', this._syncS, false); + } + + this._syncA = null; + this._syncS = null; + + this.$element.off('.select2'); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); + + this.$element.removeClass('select2-hidden-accessible'); + this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); + this.$element.removeData('select2'); + + this.dataAdapter.destroy(); + this.selection.destroy(); + this.dropdown.destroy(); + this.results.destroy(); + + this.dataAdapter = null; + this.selection = null; + this.dropdown = null; + this.results = null; + }; + + Select2.prototype.render = function () { + var $container = $( + '' + + '' + + '' + + '' + ); + + $container.attr('dir', this.options.get('dir')); + + this.$container = $container; + + this.$container.addClass('select2-container--' + this.options.get('theme')); + + Utils.StoreData($container[0], 'element', this.$element); + + return $container; + }; + + return Select2; +}); + +S2.define('jquery-mousewheel',[ + 'jquery' +], function ($) { + // Used to shim jQuery.mousewheel for non-full builds. + return $; +}); + +S2.define('jquery.select2',[ + 'jquery', + 'jquery-mousewheel', + + './select2/core', + './select2/defaults', + './select2/utils' +], function ($, _, Select2, Defaults, Utils) { + if ($.fn.select2 == null) { + // All methods that should return the element + var thisMethods = ['open', 'close', 'destroy']; + + $.fn.select2 = function (options) { + options = options || {}; + + if (typeof options === 'object') { + this.each(function () { + var instanceOptions = $.extend(true, {}, options); + + var instance = new Select2($(this), instanceOptions); + }); + + return this; + } else if (typeof options === 'string') { + var ret; + var args = Array.prototype.slice.call(arguments, 1); + + this.each(function () { + var instance = Utils.GetData(this, 'select2'); + + if (instance == null && window.console && console.error) { + console.error( + 'The select2(\'' + options + '\') method was called on an ' + + 'element that is not using Select2.' + ); + } + + ret = instance[options].apply(instance, args); + }); + + // Check if we should be returning `this` + if ($.inArray(options, thisMethods) > -1) { + return this; + } + + return ret; + } else { + throw new Error('Invalid arguments for Select2: ' + options); + } + }; + } + + if ($.fn.select2.defaults == null) { + $.fn.select2.defaults = Defaults; + } + + return Select2; +}); + + // Return the AMD loader configuration so it can be used outside of this file + return { + define: S2.define, + require: S2.require + }; +}()); + + // Autoload the jQuery bindings + // We know that all of the modules exist above this, so we're safe + var select2 = S2.require('jquery.select2'); + + // Hold the AMD module references on the jQuery function that was just loaded + // This allows Select2 to use the internal loader outside of this file, such + // as in the language files. + jQuery.fn.select2.amd = S2; + + // Return the Select2 instance for anyone who is importing it. + return select2; +})); diff --git a/installer/dup-installer/vendor/select2/js/select2.min.js b/installer/dup-installer/vendor/select2/js/select2.min.js new file mode 100644 index 00000000..e4214264 --- /dev/null +++ b/installer/dup-installer/vendor/select2/js/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(u){var e=function(){if(u&&u.fn&&u.fn.select2&&u.fn.select2.amd)var e=u.fn.select2.amd;var t,n,r,h,o,s,f,g,m,v,y,_,i,a,b;function w(e,t){return i.call(e,t)}function l(e,t){var n,r,i,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&b.test(e[s])&&(e[s]=e[s].replace(b,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},i.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},i.__cache={};var n=0;return i.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},i.StoreData=function(e,t,n){var r=i.GetUniqueElementId(e);i.__cache[r]||(i.__cache[r]={}),i.__cache[r][t]=n},i.GetData=function(e,t){var n=i.GetUniqueElementId(e);return t?i.__cache[n]&&null!=i.__cache[n][t]?i.__cache[n][t]:o(e).data(t):i.__cache[n]},i.RemoveData=function(e){var t=i.GetUniqueElementId(e);null!=i.__cache[t]&&delete i.__cache[t],e.removeAttribute("data-select2-id")},i}),e.define("select2/results",["jquery","./utils"],function(h,f){function r(e,t,n){this.$element=e,this.data=n,this.options=t,r.__super__.constructor.call(this)}return f.Extend(r,f.Observable),r.prototype.render=function(){var e=h('
                  ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},r.prototype.clear=function(){this.$results.empty()},r.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h(''),r=this.options.get("translations").get(e.message);n.append(t(r(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},r.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},r.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},r.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var r=n-1;0===e.length&&(r=0);var i=t.eq(r);i.trigger("mouseenter");var o=l.$results.offset().top,s=i.offset().top,a=l.$results.scrollTop()+(s-o);0===r?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var r=t.eq(n);r.trigger("mouseenter");var i=l.$results.offset().top+l.$results.outerHeight(!1),o=r.offset().top+r.outerHeight(!1),s=l.$results.scrollTop()+o-i;0===n?l.$results.scrollTop(0):ithis.$results.outerHeight()||o<0)&&this.$results.scrollTop(i)}},r.prototype.template=function(e,t){var n=this.options.get("templateResult"),r=this.options.get("escapeMarkup"),i=n(e,t);null==i?t.style.display="none":"string"==typeof i?t.innerHTML=r(i):h(t).append(i)},r}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,r,i){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return r.Extend(o,r.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=r.GetData(this.$element[0],"old-tabindex")?this._tabindex=r.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,r=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",r),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&r.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,r){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var r=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",r).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",r),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),r=this.display(t,n);n.empty().append(r);var i=t.title||t.text;i?n.attr("title",i):n.removeAttr("title")}else this.clear()},i}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
                    '),e},n.prototype.bind=function(e,t){var r=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){r.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!r.isDisabled()){var t=i(this).parent(),n=l.GetData(t[0],"data");r.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return i('
                  • ×
                  • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×');a.StoreData(r[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(r)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(r,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=r('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),t.on("open",function(){r.$search.attr("aria-controls",i),r.$search.trigger("focus")}),t.on("close",function(){r.$search.val(""),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.trigger("focus")}),t.on("enable",function(){r.$search.prop("disabled",!1),r._transferTabIndex()}),t.on("disable",function(){r.$search.prop("disabled",!0)}),t.on("focus",function(e){r.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){r.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){r._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===r.$search.val()){var t=r.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("select",function(){r._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var r=this;this._checkIfMaximumSelected(function(){e.call(r,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var r=this;this.current(function(e){var t=null!=e?e.length:0;0=r.maximumSelectionLength?r.trigger("results:message",{message:"maximumSelected",args:{maximum:r.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){r.handleSearch(e)}),t.on("open",function(){r.$search.attr("tabindex",0),r.$search.attr("aria-controls",i),r.$search.trigger("focus"),window.setTimeout(function(){r.$search.trigger("focus")},0)}),t.on("close",function(){r.$search.attr("tabindex",-1),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.val(""),r.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||r.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(r.showSearch(e)?r.$searchContainer.removeClass("select2-search--hide"):r.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,r){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,r)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),r=t.length-1;0<=r;r--){var i=t[r];this.placeholder.id===i.id&&n.splice(r,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,r){this.lastParams={},e.call(this,t,n,r),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("query",function(e){r.lastParams=e,r.loading=!0}),t.on("query:append",function(e){r.lastParams=e,r.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
                  • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("open",function(){r._showDropdown(),r._attachPositioningHandler(t),r._bindContainerResultHandlers(t)}),t.on("close",function(){r._hideDropdown(),r._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,r="scroll.select2."+t.id,i="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(r,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(r+" "+i+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,r="resize.select2."+t.id,i="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+r+" "+i)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),r=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=i.top,o.bottom=i.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+s,d={left:i.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(r="below"),u||!c||t?!c&&u&&t&&(r="below"):r="above",("above"==r||t&&"below"!==r)&&(d.top=o.top-h.top-s),null!=r&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+r),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+r)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,r){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,r)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,r=0;r');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("jquery-mousewheel",["jquery"],function(e){return e}),e.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,o,t,s){if(null==i.fn.select2){var a=["open","close","destroy"];i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new o(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,r=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=s.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,r)}),-1setHTTPHeaders(); + $this->targetRoot = self::setSafePath(dirname(__FILE__)); + // clean log file + $this->log('', true); + + $archive_filepath = $this->getArchiveFilePath(); + $this->origDupInstFolder = self::INSTALLER_DIR_NAME; + $this->targetDupInstFolder = filter_input(INPUT_GET, 'dup_folder', FILTER_SANITIZE_SPECIAL_CHARS, array( + "options" => array( + "default" => self::INSTALLER_DIR_NAME, + ), + 'flags' => FILTER_FLAG_STRIP_HIGH)); + + $this->isCustomDupFolder = $this->origDupInstFolder !== $this->targetDupInstFolder; + $this->targetDupInst = $this->targetRoot . '/' . $this->targetDupInstFolder; + $this->manualExtractFileName = 'dup-manual-extract__' . self::PACKAGE_HASH; + + if ($this->isCustomDupFolder) { + $this->extractionTmpFolder = $this->getTempDir($this->targetRoot); + } else { + $this->extractionTmpFolder = $this->targetRoot; + } + + DUPX_CSRF::init($this->targetDupInst, self::PACKAGE_HASH); + + //ARCHIVE_SIZE will be blank with a root filter so we can estimate + //the default size of the package around 17.5MB (18088000) + $archiveActualSize = @file_exists($archive_filepath) ? @filesize($archive_filepath) : false; + $archiveActualSize = ($archiveActualSize !== false) ? $archiveActualSize : 0; + $this->hasZipArchive = class_exists('ZipArchive'); + $this->hasShellExecUnzip = $this->getUnzipFilePath() != null ? true : false; + $this->archiveExpectedSize = strlen(self::ARCHIVE_SIZE) ? self::ARCHIVE_SIZE : 0; + $this->archiveActualSize = $archiveActualSize; + + if ($this->archiveExpectedSize > 0) { + $this->archiveRatio = (((1.0) * $this->archiveActualSize) / $this->archiveExpectedSize) * 100; + } else { + $this->archiveRatio = 100; + } + } + + /** + * + * @return self + */ + public static function getInstance() + { + if (is_null(self::$instance)) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Makes sure no caching mechanism is used during install + * + * @return void + */ + private function setHTTPHeaders() + { + header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } + + /** + * Return temp dir + * + * @param string $path path string + * + * @return boolean|string + */ + private function getTempDir($path) + { + $tempfile = tempnam($path, 'dup-installer_tmp_'); + if (file_exists($tempfile)) { + unlink($tempfile); + mkdir($tempfile); + if (is_dir($tempfile)) { + return $tempfile; + } + } + return false; + } + + /** + * Check php version + * + * @return void + */ + public static function phpVersionCheck() + { + if (version_compare(PHP_VERSION, self::MINIMUM_PHP_VERSION, '>=')) { + return true; + } + + $match = null; + if (preg_match("#^\d+(\.\d+)*#", PHP_VERSION, $match)) { + $phpVersion = $match[0]; + } else { + $phpVersion = PHP_VERSION; + } + ?> + + + + + Duplicator - issue + + +
                    +

                    DUPLICATOR ISSUE: PHP REQUIRED

                    +

                    + This server is running PHP: . A minimum of PHP + is required.

                    + Contact your hosting provider or server administrator and let them know you would like to upgrade your PHP version. +

                    +
                    + + + log('==DUPLICATOR INSTALLER BOOTSTRAP v' . self::VERSION . '=='); + $this->log('----------------------------------------------------'); + $this->log('Installer bootstrap start'); + + $archive_filepath = $this->getArchiveFilePath(); + $archive_filename = self::ARCHIVE_FILENAME; + + $error = null; + + $is_installer_file_valid = true; + if (preg_match('/_([a-z0-9]{7})[a-z0-9]+_[0-9]{6}([0-9]{8})_archive.(?:zip|daf)$/', $archive_filename, $matches)) { + $expected_package_hash = $matches[1] . '-' . $matches[2]; + if (self::PACKAGE_HASH != $expected_package_hash) { + $is_installer_file_valid = false; + $this->log("[ERROR] Installer and archive mismatch detected."); + } + } else { + $this->log("[ERROR] Invalid archive file name."); + $is_installer_file_valid = false; + } + + if (false === $is_installer_file_valid) { + $error = "Installer and archive mismatch detected. + Ensure uncorrupted installer and matching archive are present."; + return $error; + } + + $extract_installer = true; + $extract_success = false; + $archiveExpectedEasy = $this->readableByteSize($this->archiveExpectedSize); + $archiveActualEasy = $this->readableByteSize($this->archiveActualSize); + + //$archive_extension = strtolower(pathinfo($archive_filepath)['extension']); + $archive_extension = strtolower(pathinfo($archive_filepath, PATHINFO_EXTENSION)); + $installer_dir_found = ( + file_exists($this->targetDupInst) && + file_exists($this->targetDupInst . "/main.installer.php") && + file_exists($this->targetDupInst . "/dup-archive__" . self::PACKAGE_HASH . ".txt") + ); + + $manual_extract_found = ( + $installer_dir_found && + file_exists($this->targetDupInst . "/" . $this->manualExtractFileName) + ); + + $isZip = ($archive_extension == 'zip'); + + //MANUAL EXTRACTION NOT FOUND + if (!$manual_extract_found) { + //MISSING ARCHIVE FILE + if (!file_exists($archive_filepath)) { + $this->log("[ERROR] Archive file not found!"); + $archive_candidates = ($isZip) ? $this->getFilesWithExtension('zip') : $this->getFilesWithExtension('daf'); + $candidate_count = count($archive_candidates); + $candidate_html = "- No {$archive_extension} files found -"; + + if ($candidate_count >= 1) { + $candidate_html = "
                      "; + foreach ($archive_candidates as $archive_candidate) { + $candidate_html .= '
                    1. ' . $this->compareStrings($archive_filename, $archive_candidate) . '
                    2. '; + } + $candidate_html .= "
                    "; + } + + $error = "" + . "Archive not found! The required archive file must be present in the 'Extraction Path' below. " + . "When the archive file name was created it was named with a secure file name. This file name must be " + . "the exact same name as when it was created character for character. Each archive file has a unique installer associated " + . "with it and must be used together. See the list below for more options:
                    " + . ""; + + return $error; + } + + $archive_size = self::ARCHIVE_SIZE; + + // Sometimes the self::ARCHIVE_SIZE is ''. + if (!empty($archive_size) && !self::checkInputValidInt(self::ARCHIVE_SIZE)) { + $no_of_bits = PHP_INT_SIZE * 8; + $error = 'Current is a ' . $no_of_bits . '-bit SO. This archive is too large for ' . $no_of_bits . '-bit PHP.' . '
                    '; + $this->log('[ERROR] ' . $error); + $error .= 'Possibibles solutions:
                    '; + $error .= '- Use the file filters to get your package lower to support this server or try the package on a Linux server.' . '
                    '; + $error .= '- Perform a ' . + 'Manual Extract Install' . '
                    '; + + switch ($no_of_bits == 32) { + case 32: + $error .= '- Ask your host to upgrade the server to 64-bit PHP or install on another system has 64-bit PHP' . '
                    '; + break; + case 64: + $error .= '- Ask your host to upgrade the server to 128-bit PHP or install on another system has 128-bit PHP' . '
                    '; + break; + } + + if (self::isWindows()) { + $error .= '- ' . + 'Windows DupArchive extractor to extract all files from the archive.' . '
                    '; + } + + return $error; + } + + //SIZE CHECK ERROR + if (($this->archiveRatio < 90) && ($this->archiveActualSize > 0) && ($this->archiveExpectedSize > 0)) { + $this->log( + "ERROR: The expected archive size should be around [{$archiveExpectedEasy}]. " . + "The actual size is currently [{$archiveActualEasy}]." + ); + $this->log("ERROR: The archive file may not have fully been downloaded to the server"); + $percent = round($this->archiveRatio); + + $autochecked = isset($_POST['auto-fresh']) ? "checked='true'" : ''; + $error = "Archive file size warning.
                    The expected archive size is [{$archiveExpectedEasy}]. " + . "Currently the archive size is [{$archiveActualEasy}].
                    " + . "The archive file may have not fully been uploaded to the server." + . "
                      " + . "
                    • Download the whole archive from the source website (open WordPress Admin > Duplicator > Packages) " + . "and validate that the file size is close to the expected size.
                    • " + . "
                    • Make sure to upload the whole archive file to the destination server.
                    • " + . "
                    • If the archive file is still uploading then please refresh this page to get an update on the currently uploaded file size.
                    • " + . "
                    "; + return $error; + } + } + + if ($installer_dir_found) { + // INSTALL DIRECTORY: Check if its setup correctly AND we are not in overwrite mode + if (($extract_installer = filter_input(INPUT_GET, 'force-extract-installer', FILTER_VALIDATE_BOOLEAN))) { + $this->log("Manual extract found with force extract installer get parametr"); + } else { + $this->log("Manual extract found so not going to extract " . $this->targetDupInstFolder . " dir"); + } + } else { + $extract_installer = true; + } + + // if ($extract_installer && file_exists($this->targetDupInst)) { + if (file_exists($this->targetDupInst)) { + $this->log("EXTRACT " . $this->targetDupInstFolder . " dir"); + $hash_pattern = '[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'; + $file_patterns_with_hash_file = array( + // file pattern => hash file + 'dup-archive__' . $hash_pattern . '.txt' => 'dup-archive__' . self::PACKAGE_HASH . '.txt', + 'dup-database__' . $hash_pattern . '.sql' => 'dup-database__' . self::PACKAGE_HASH . '.sql', + 'dup-installer-data__' . $hash_pattern . '.sql' => 'dup-installer-data__' . self::PACKAGE_HASH . '.sql', + 'dup-installer-log__' . $hash_pattern . '.txt' => 'dup-installer-log__' . self::PACKAGE_HASH . '.txt', + 'dup-scan__' . $hash_pattern . '.json' => 'dup-scan__' . self::PACKAGE_HASH . '.json', + 'dup-scanned-dirs__' . $hash_pattern . '.txt' => 'dup-scanned-dirs__' . self::PACKAGE_HASH . '.txt', + 'dup-scanned-files__' . $hash_pattern . '.txt' => 'dup-scanned-files__' . self::PACKAGE_HASH . '.txt', + ); + foreach ($file_patterns_with_hash_file as $file_pattern => $hash_file) { + $globs = glob($this->targetDupInst . '/' . $file_pattern); + if (!empty($globs)) { + foreach ($globs as $glob) { + $file = basename($glob); + if ($file != $hash_file) { + if (unlink($glob)) { + $this->log('Successfully deleted the file ' . $glob); + } else { + $error .= '[ERROR] Error deleting the file ' . $glob . ' Please manually delete it and try again.'; + $this->log($error); + } + } + } + } + } + } + + //ATTEMPT EXTRACTION: + //ZipArchive and Shell Exec + if ($extract_installer) { + $this->log("Ready to extract the installer"); + + $this->log("Checking permission of destination folder"); + $destination = $this->targetRoot; + if (!is_writable($destination)) { + $this->log("destination folder for extraction is not writable"); + if (self::chmod($destination, 'u+rwx')) { + $this->log("Permission of destination folder changed to u+rwx"); + } else { + $this->log("[ERROR] Permission of destination folder failed to change to u+rwx"); + } + } + + if (!is_writable($destination)) { + $this->log("WARNING: The {$destination} directory is not writable."); + $error = "NOTICE: The {$destination} directory is not writable on this server please talk to your host or server admin about making "; + $error .= "" . + "writable {$destination} directory on this server.
                    "; + return $error; + } + + if ($isZip) { + $zip_mode = $this->getZipMode(); + + if (($zip_mode == self::ZIP_MODE_AUTO) || ($zip_mode == self::ZIP_MODE_ARCHIVE) && class_exists('ZipArchive')) { + if ($this->hasZipArchive) { + $this->log("ZipArchive exists so using that"); + $extract_success = $this->extractInstallerZipArchive($archive_filepath, $this->origDupInstFolder, $this->extractionTmpFolder); + + if ($extract_success) { + $this->log('Successfully extracted with ZipArchive'); + } else { + if (0 == $this->installer_files_found) { + $error = "[ERROR] This archive is not properly formatted and does not contain a " . $this->origDupInstFolder . + " directory. Please make sure you are attempting to install " . + "the original archive and not one that has been reconstructed."; + $this->log($error); + return $error; + } else { + $error = '[ERROR] Error extracting with ZipArchive. '; + $this->log($error); + } + } + } else { + $this->log("WARNING: ZipArchive is not enabled."); + $error = "NOTICE: ZipArchive is not enabled on this server please talk to your host or server admin about enabling "; + $error .= "" . + "ZipArchive on this server.
                    "; + } + } + + if (!$extract_success) { + if (($zip_mode == self::ZIP_MODE_AUTO) || ($zip_mode == self::ZIP_MODE_SHELL)) { + $unzip_filepath = $this->getUnzipFilePath(); + if ($unzip_filepath != null) { + $extract_success = $this->extractInstallerShellexec($archive_filepath, $this->origDupInstFolder, $this->extractionTmpFolder); + $this->log("Resetting perms of items in folder {$this->targetDupInstFolder}"); + self::setPermsToDefaultR($this->targetDupInstFolder); + if ($extract_success) { + $this->log('Successfully extracted with Shell Exec'); + $error = null; + } else { + $error .= '[ERROR] Error extracting with Shell Exec. ' . + 'Please manually extract archive then choose Advanced > Manual Extract in installer.'; + $this->log($error); + } + } else { + $this->log('WARNING: Shell Exec Zip is not available'); + $error .= "NOTICE: Shell Exec is not enabled on this server please talk to your host or server admin about enabling "; + $error .= "Shell Exec " . + "on this server or manually extract archive then choose Advanced > Manual Extract in installer."; + } + } + } + + // If both ZipArchive and ShellZip are not available, Error message should be combined for both + if (!$extract_success && $zip_mode == self::ZIP_MODE_AUTO) { + $unzip_filepath = $this->getUnzipFilePath(); + if (!class_exists('ZipArchive') && empty($unzip_filepath)) { + $this->log("WARNING: ZipArchive and Shell Exec are not enabled on this server."); + $error = "NOTICE: ZipArchive and Shell Exec are not enabled on this server please " . + "talk to your host or server admin about enabling "; + $error .= "ZipArchive " . + "or Shell Exec " . + "on this server or manually extract archive then choose Advanced > Manual Extract in installer."; + } + } + } else { + try { + DupArchiveExpandBasicEngine::setCallbacks( + array($this, 'log'), + array($this, 'chmod'), + array($this, 'mkdir') + ); + $offset = DupArchiveExpandBasicEngine::getExtraOffset($archive_filepath); + $this->log('Expand directory from offset ' . $offset); + DupArchiveExpandBasicEngine::expandDirectory( + $archive_filepath, + $this->origDupInstFolder, + $this->extractionTmpFolder, + false, + $offset + ); + //In case of DupArchive just remove the manual extract check file + @unlink($this->extractionTmpFolder . "/" . $this->origDupInstFolder . "/" . $this->manualExtractFileName); + } catch (Exception $ex) { + $this->log("[ERROR] Error expanding installer subdirectory:" . $ex->getMessage()); + throw $ex; + } + } + + if ($this->isCustomDupFolder) { + $this->log("Move dup-installer folder to custom folder:" . $this->targetDupInst); + if (file_exists($this->targetDupInst)) { + $this->log('Custom folder already exists so delete it'); + if (self::rrmdir($this->targetDupInst) == false) { + throw new Exception('Can\'t remove custom target folder'); + } + } + if (rename($this->extractionTmpFolder . '/' . $this->origDupInstFolder, $this->targetDupInst) === false) { + throw new Exception('Can\'t rename the tmp dup-installer folder'); + } + } + + $htaccessToRemove = $this->targetDupInst.'/.htaccess'; + if (is_file($htaccessToRemove) && is_writable($htaccessToRemove)) { + $this->log("Remove Htaccess in dup-installer folder"); + @unlink($htaccessToRemove); + } + + $is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false); + $is_nginx = (strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false); + + $sapi_type = php_sapi_name(); + $php_ini_data = array( + 'max_execution_time' => 3600, + 'max_input_time' => -1, + 'ignore_user_abort' => 'On', + 'post_max_size' => '4096M', + 'upload_max_filesize' => '4096M', + 'memory_limit' => DUPLICATOR_PHP_MAX_MEMORY, + 'default_socket_timeout' => 3600, + 'pcre.backtrack_limit' => 99999999999, + ); + $sapi_type_first_three_chars = substr($sapi_type, 0, 3); + if ('fpm' === $sapi_type_first_three_chars) { + $this->log("SAPI: FPM"); + if ($is_apache) { + $this->log('Server: Apache'); + } elseif ($is_nginx) { + $this->log('Server: Nginx'); + } + + if (($is_apache && function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) || $is_nginx) { + $htaccess_data = array(); + foreach ($php_ini_data as $php_ini_key => $php_ini_val) { + if ($is_apache) { + $htaccess_data[] = 'SetEnv PHP_VALUE "' . $php_ini_key . ' = ' . $php_ini_val . '"'; + } elseif ($is_nginx) { + if ('On' == $php_ini_val || 'Off' == $php_ini_val) { + $htaccess_data[] = 'php_flag ' . $php_ini_key . ' ' . $php_ini_val; + } else { + $htaccess_data[] = 'php_value ' . $php_ini_key . ' ' . $php_ini_val; + } + } + } + + $htaccess_text = implode("\n", $htaccess_data); + $htaccess_file_path = $this->targetDupInst . '/.htaccess'; + $this->log("creating {$htaccess_file_path} with the content:"); + $this->log($htaccess_text); + @file_put_contents($htaccess_file_path, $htaccess_text); + } + } elseif ('cgi' === $sapi_type_first_three_chars || 'litespeed' === $sapi_type) { + if ('cgi' === $sapi_type_first_three_chars) { + $this->log("SAPI: CGI"); + } else { + $this->log("SAPI: litespeed"); + } + if (version_compare(phpversion(), 5.5) >= 0 && (!$is_apache || 'litespeed' === $sapi_type)) { + $ini_data = array(); + foreach ($php_ini_data as $php_ini_key => $php_ini_val) { + $ini_data[] = $php_ini_key . ' = ' . $php_ini_val; + } + $ini_text = implode("\n", $ini_data); + $ini_file_path = $this->targetDupInst . '/.user.ini'; + $this->log("creating {$ini_file_path} with the content:"); + $this->log($ini_text); + @file_put_contents($ini_file_path, $ini_text); + } else { + $this->log("No need to create " . $this->targetDupInstFolder . "/.htaccess or " . $this->targetDupInstFolder . "/.user.ini"); + } + } elseif ("apache2handler" === $sapi_type) { + $this->log("No need to create " . $this->targetDupInstFolder . "/.htaccess or " . $this->targetDupInstFolder . "/.user.ini"); + $this->log("SAPI: apache2handler"); + } + else { + $this->log("No need to create " . $this->targetDupInstFolder . "/.htaccess or " . $this->targetDupInstFolder . "/.user.ini"); + $this->log("ERROR: SAPI: Unrecognized"); + } + } else { + $this->log("NOTICE: Didn't need to extract the installer."); + } + + if (empty($error)) { + if ($this->isCustomDupFolder && file_exists($this->extractionTmpFolder)) { + rmdir($this->extractionTmpFolder); + } + + $config_files = glob($this->targetDupInst . '/dup-archive__*.txt'); + $config_file_absolute_path = array_pop($config_files); + if (!file_exists($config_file_absolute_path)) { + $error = 'Archive config file not found in ' . $this->targetDupInstFolder . ' folder.

                    '; + return $error; + } + } + + $uri_start = self::getCurrentUrl(false, false, 1); + if ($error === null) { + if (!file_exists($this->targetDupInst)) { + $error = 'Can\'t extract installer directory. ' . + 'See this FAQ item' . + ' for details on how to resolve.'; + } + + if ($error == null) { + $bootloader_name = basename(__FILE__); + $this->mainInstallerURL = $uri_start . '/' . $this->targetDupInstFolder . '/main.installer.php'; + + $this->archive = $archive_filepath; + $this->bootloader = $bootloader_name; + + $this->fixInstallerPerms($this->mainInstallerURL); + // $this->mainInstallerURL = $this->mainInstallerURL . "?archive=$encoded_archive_path&bootloader=$bootloader_name&ctrl_action=ctrl-step1"; + /* + if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) { + $this->mainInstallerURL .= '?'.$_SERVER['QUERY_STRING']; + }*/ + + $this->log("DONE: No detected errors so redirecting to the main installer. Main Installer URI = {$this->mainInstallerURL}"); + } + } + + return $error; + } + + /** + * Get current url + * + * @param bool $queryString If true the query string will also be returned. + * @param bool $requestUri if true check request uri + * @param int $getParentDirLevel if 0 get current script name or parent folder, if 1 parent folder if 2 parent of parent folder ... + * + * @return void + */ + public static function getCurrentUrl($queryString = true, $requestUri = false, $getParentDirLevel = 0) + { + // *** HOST + if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) { + $host = $_SERVER['HTTP_X_ORIGINAL_HOST']; + } else { + $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; //WAS SERVER_NAME and caused problems on some boxes + } + + // *** PROTOCOL + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER ['HTTPS'] = 'on'; + } + if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'https') { + $_SERVER ['HTTPS'] = 'on'; + } + if (isset($_SERVER['HTTP_CF_VISITOR'])) { + $visitor = json_decode($_SERVER['HTTP_CF_VISITOR']); + if ($visitor->scheme == 'https') { + $_SERVER ['HTTPS'] = 'on'; + } + } + $protocol = 'http' . ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') ? 's' : ''); + + if ($requestUri) { + $serverUrlSelf = preg_replace('/\?.*$/', '', $_SERVER['REQUEST_URI']); + } else { + // *** SCRIPT NAME + $serverUrlSelf = $_SERVER['SCRIPT_NAME']; + for ($i = 0; $i < $getParentDirLevel; $i++) { + $serverUrlSelf = preg_match('/^[\\\\\/]?$/', dirname($serverUrlSelf)) ? '' : dirname($serverUrlSelf); + } + } + + // *** QUERY STRING + $query = ($queryString && isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0 ) ? '?' . $_SERVER['QUERY_STRING'] : ''; + + return $protocol . '://' . $host . $serverUrlSelf . $query; + } + + /** + * Attempts to set the 'dup-installer' directory permissions + * + * @return null + */ + private function fixInstallerPerms() + { + $file_perms = 'u+rw'; + $dir_perms = 'u+rwx'; + + $installer_dir_path = $this->targetDupInstFolder; + + $this->setPerms($installer_dir_path, $dir_perms, false); + $this->setPerms($installer_dir_path, $file_perms, true); + } + + /** + * Set the permissions of a given directory and optionally all files + * + * @param string $directory The full path to the directory where perms will be set + * @param string $perms The given permission sets to use such as '0755' or 'u+rw' + * @param string $do_files Also set the permissions of all the files in the directory + * + * @return null + */ + private function setPerms($directory, $perms, $do_files) + { + if (!$do_files) { + // If setting a directory hiearchy be sure to include the base directory + $this->setPermsOnItem($directory, $perms); + } + + $item_names = array_diff(scandir($directory), array('.', '..')); + + foreach ($item_names as $item_name) { + $path = "$directory/$item_name"; + if (($do_files && is_file($path)) || (!$do_files && !is_file($path))) { + $this->setPermsOnItem($path, $perms); + } + } + } + + /** + * Set the permissions of a single directory or file + * + * @param string $path The full path to the directory or file where perms will be set + * @param string $perms The given permission sets to use such as '0755' or 'u+rw' + * + * @return bool Returns true if the permission was properly set + */ + private function setPermsOnItem($path, $perms) + { + if (($result = self::chmod($path, $perms)) === false) { + $this->log("ERROR: Couldn't set permissions of $path
                    "); + } else { + $this->log("Set permissions of $path
                    "); + } + return $result; + } + + /** + * Compare two strings and return html text which represts diff + * + * @param string $oldString old string + * @param string $newString new string + * + * @return string Returns html text + */ + private function compareStrings($oldString, $newString) + { + $ret = ''; + for ($i = 0; isset($oldString[$i]) || isset($newString[$i]); $i++) { + if (!isset($oldString[$i])) { + $ret .= '' . $newString[$i] . ''; + continue; + } + for ($char = 0; isset($oldString[$i][$char]) || isset($newString[$i][$char]); $char++) { + if (!isset($oldString[$i][$char])) { + $ret .= '' . substr($newString[$i], $char) . ''; + break; + } elseif (!isset($newString[$i][$char])) { + break; + } + + if (ord($oldString[$i][$char]) != ord($newString[$i][$char])) { + $ret .= '' . $newString[$i][$char] . ''; + } else { + $ret .= $newString[$i][$char]; + } + } + } + return $ret; + } + + /** + * Logs a string to the dup-installer-bootlog__[HASH].txt file + * + * @param string $s The string to log to the log file + * @param bool $deleteOld if true delete old file + * + * @return boog|int This function returns the number of bytes that were written to the file, or FALSE on failure. + */ + public function log($s, $deleteOld = false) + { + static $logfile = null; + if (is_null($logfile)) { + $logfile = $this->getBootLogFilePath(); + } + if ($deleteOld && file_exists($logfile)) { + @unlink($logfile); + } + $timestamp = date('M j H:i:s'); + return @file_put_contents($logfile, '[' . $timestamp . '] ' . self::postprocessLog($s) . "\n", FILE_APPEND); + } + + /** + * get boot log file name the dup-installer-bootlog__[HASH].txt file + * + * @return string + */ + public function getBootLogFilePath() + { + return $this->targetRoot . '/dup-installer-bootlog__' . self::SECONDARY_PACKAGE_HASH . '.txt'; + } + + /** + * Post process log and remove hash string + * + * @param string $str string + * + * @return string + */ + protected static function postprocessLog($str) + { + return str_replace(array( + self::getArchiveFileHash(), + self::PACKAGE_HASH, + self::SECONDARY_PACKAGE_HASH + ), '[HASH]', $str); + } + + /** + * Return archive file hash + * + * @return string + */ + public static function getArchiveFileHash() + { + static $fileHash = null; + if (is_null($fileHash)) { + $fileHash = preg_replace('/^.+_([a-z0-9]+)_[0-9]{14}_archive\.(?:daf|zip)$/', '$1', self::ARCHIVE_FILENAME); + } + return $fileHash; + } + + /** + * Extraxt installer + * + * @param string $archive_filepath The path to the archive file. + * @param string $origDupInstFolder relative folder in archive + * @param string $destination destination folder + * @param bool $checkSubFolder check if is in subfolder + * + * @return bool Returns true if the data was properly extracted + */ + private function extractInstallerZipArchive($archive_filepath, $origDupInstFolder, $destination, $checkSubFolder = false) + { + $success = true; + $zipArchive = new ZipArchive(); + $subFolderArchiveList = array(); + + if (($zipOpenRes = $zipArchive->open($archive_filepath)) === true) { + $this->log("Successfully opened archive file."); + $folder_prefix = $origDupInstFolder . '/'; + $this->log("Extracting all files from archive within " . $origDupInstFolder); + + $installer_files_found = 0; + + for ($i = 0; $i < $zipArchive->numFiles; $i++) { + $stat = $zipArchive->statIndex($i); + if ($checkSubFolder == false) { + $filenameCheck = $stat['name']; + $filename = $stat['name']; + $tmpSubFolder = null; + } else { + $safePath = rtrim(self::setSafePath($stat['name']), '/'); + $tmpArray = explode('/', $safePath); + + if (count($tmpArray) < 2) { + continue; + } + + $tmpSubFolder = $tmpArray[0]; + array_shift($tmpArray); + $filenameCheck = implode('/', $tmpArray); + $filename = $stat['name']; + } + + + if ($this->startsWith($filenameCheck, $folder_prefix)) { + $installer_files_found++; + + if (!empty($tmpSubFolder) && !in_array($tmpSubFolder, $subFolderArchiveList)) { + $subFolderArchiveList[] = $tmpSubFolder; + } + + if (basename($filename) === $this->manualExtractFileName) { + $this->log("Skipping manual extract file: {$filename}"); + continue; + } + + if ($zipArchive->extractTo($destination, $filename) === true) { + $this->log("Success: {$filename} >>> {$destination}"); + } else { + $this->log("[ERROR] Error extracting {$filename} from archive archive file"); + $success = false; + break; + } + } + } + + if ($checkSubFolder && count($subFolderArchiveList) !== 1) { + $this->log("Error: Multiple dup subfolder archive"); + $success = false; + } else { + if ($checkSubFolder) { + $this->moveUpfromSubFolder($destination . '/' . $subFolderArchiveList[0], true); + } + + $lib_directory = $destination . '/' . $origDupInstFolder . '/lib'; + $snaplib_directory = $lib_directory . '/snaplib'; + + // If snaplib files aren't present attempt to extract and copy those + if (!file_exists($snaplib_directory)) { + $folder_prefix = 'snaplib/'; + $destination = $lib_directory; + + for ($i = 0; $i < $zipArchive->numFiles; $i++) { + $stat = $zipArchive->statIndex($i); + $filename = $stat['name']; + + if ($this->startsWith($filename, $folder_prefix)) { + $installer_files_found++; + + if ($zipArchive->extractTo($destination, $filename) === true) { + $this->log("Success: {$filename} >>> {$destination}"); + } else { + $this->log("[ERROR] Error extracting {$filename} from archive archive file"); + $success = false; + break; + } + } + } + } + } + + if ($zipArchive->close() === true) { + $this->log("Successfully closed archive file"); + } else { + $this->log("[ERROR] Problem closing archive file"); + $success = false; + } + + if ($success != false && $installer_files_found < 10) { + if ($checkSubFolder) { + $this->log("[ERROR] Couldn't find the installer directory in the archive!"); + $success = false; + } else { + $this->log("[ERROR] Couldn't find the installer directory in archive root! Check subfolder"); + $this->extractInstallerZipArchive($archive_filepath, $origDupInstFolder, $destination, true); + } + } + } else { + $this->log("[ERROR] Couldn't open archive archive file with ZipArchive CODE[" . $zipOpenRes . "]"); + $success = false; + } + + return $success; + } + + /** + * return true if current SO is windows + * + * @staticvar bool $isWindows + * @return bool + */ + public static function isWindows() + { + static $isWindows = null; + if (is_null($isWindows)) { + $isWindows = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + } + return $isWindows; + } + + /** + * return current SO path path len + * @staticvar int $maxPath + * @return int + */ + public static function maxPathLen() + { + static $maxPath = null; + if (is_null($maxPath)) { + if (defined('PHP_MAXPATHLEN')) { + $maxPath = PHP_MAXPATHLEN; + } else { + // for PHP < 5.3.0 + $maxPath = self::isWindows() ? 260 : 4096; + } + } + return $maxPath; + } + + /** + * @param string $directory Path for folder to set perms + * + * @return void + */ + public static function setPermsToDefaultR($directory) + { + $dir = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS); + $iterator = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST); + // Default permissions + $defaultFilePermission = 0666 & ~umask(); + $defaultDirPermission = 0777 & ~umask(); + + foreach ($iterator as $item) { + if ($item->isFile()) { + self::chmod($item->getPathname(), $defaultFilePermission); + } + + if ($item->isDir()) { + self::chmod($item->getPathname(), $defaultDirPermission); + } + } + } + + /** + * this function make a chmod only if the are different from perms input and if chmod function is enabled + * + * this function handles the variable MODE in a way similar to the chmod of lunux + * So the MODE variable can be + * 1) an octal number (0755) + * 2) a string that defines an octal number ("644") + * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+ + * + * examples + * u+rw add read and write at the user + * u+rw,uo-wx add read and write ad the user and remove wx at groupd and other + * a=rw is equal at 666 + * u=rwx,go-rwx is equal at 700 + * + * @param string $file file path + * @param int|string $mode mode + * + * @return boolean + */ + public static function chmod($file, $mode) + { + if (!file_exists($file)) { + return false; + } + + $octalMode = 0; + + if (is_int($mode)) { + $octalMode = $mode; + } elseif (is_string($mode)) { + $mode = trim($mode); + if (preg_match('/([0-7]{1,3})/', $mode)) { + $octalMode = intval(('0' . $mode), 8); + } elseif (preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) { + if (!function_exists('fileperms')) { + return false; + } + + // start by file permission + $octalMode = (fileperms($file) & 0777); + + foreach ($gMatch as $matches) { + // [ugo] or a = ugo + $group = $matches[1]; + if ($group === 'a') { + $group = 'ugo'; + } + // can be + - = + $action = $matches[2]; + // [rwx] + $gPerms = $matches[3]; + + // reset octal group perms + $octalGroupMode = 0; + + // Init sub perms + $subPerm = 0; + $subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001 + $subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010 + $subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100 + + $ugoLen = strlen($group); + + if ($action === '=') { + // generate octal group permsissions and ugo mask invert + $ugoMaskInvert = 0777; + for ($i = 0; $i < $ugoLen; $i++) { + switch ($group[$i]) { + case 'u': + $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000 + $ugoMaskInvert = $ugoMaskInvert & 077; + break; + case 'g': + $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000 + $ugoMaskInvert = $ugoMaskInvert & 0707; + break; + case 'o': + $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx + $ugoMaskInvert = $ugoMaskInvert & 0770; + break; + } + } + // apply = action + $octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode); + } else { + // generate octal group permsissions + for ($i = 0; $i < $ugoLen; $i++) { + switch ($group[$i]) { + case 'u': + $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000 + break; + case 'g': + $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000 + break; + case 'o': + $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx + break; + } + } + // apply + or - action + switch ($action) { + case '+': + $octalMode = $octalMode | $octalGroupMode; + break; + case '-': + $octalMode = $octalMode & ~$octalGroupMode; + break; + } + } + } + } + } + + // if input permissions are equal at file permissions return true without performing chmod + if (function_exists('fileperms') && $octalMode === (fileperms($file) & 0777)) { + return true; + } + + if (!function_exists('chmod')) { + return false; + } + + return @chmod($file, $octalMode); + } + + /** + * Check if input is valid int + * + * @param mixed $input input string or number + * + * @return bool + */ + public static function checkInputValidInt($input) + { + return (filter_var($input, FILTER_VALIDATE_INT) === 0 || filter_var($input, FILTER_VALIDATE_INT)); + } + + /** + * this function creates a folder if it does not exist and performs a chmod. + * it is different from the normal mkdir function to which an umask is applied to the input permissions. + * + * this function handles the variable MODE in a way similar to the chmod of lunux + * So the MODE variable can be + * 1) an octal number (0755) + * 2) a string that defines an octal number ("644") + * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+ + * + * @param string $path folder path + * @param int|string $mode mode permissions + * @param bool $recursive Allows the creation of nested directories specified in the pathname. Default to false. + * @param resource $context not used for windows bug + * + * @return boolean bool TRUE on success or FALSE on failure. + * + * @todo check recursive true and multiple chmod + */ + public static function mkdir($path, $mode = 0777, $recursive = false, $context = null) + { + if (strlen($path) > self::maxPathLen()) { + throw new Exception('Skipping a file that exceeds allowed max path length [' . self::maxPathLen() . ']. File: ' . $filepath); + } + + if (!file_exists($path)) { + if (!function_exists('mkdir')) { + return false; + } + if (!@mkdir($path, 0777, $recursive)) { + return false; + } + } + + return self::chmod($path, $mode); + } + + /** + * move all folder content up to parent + * + * @param string $subFolderName full path + * @param boolean $deleteSubFolder if true delete subFolder after moved all + * + * @return boolean + */ + private function moveUpfromSubFolder($subFolderName, $deleteSubFolder = false) + { + if (!is_dir($subFolderName)) { + return false; + } + + $parentFolder = dirname($subFolderName); + if (!is_writable($parentFolder)) { + return false; + } + + $success = true; + if (($subList = glob(rtrim($subFolderName, '/') . '/*', GLOB_NOSORT)) === false) { + $this->log("[ERROR] Problem glob folder " . $subFolderName); + return false; + } else { + foreach ($subList as $cName) { + $destination = $parentFolder . '/' . basename($cName); + if (file_exists($destination)) { + $success = self::rrmdir($destination); + } + + if ($success) { + $success = rename($cName, $destination); + } else { + break; + } + } + + if ($success && $deleteSubFolder) { + $success = self::rrmdir($subFolderName, true); + } + } + + if (!$success) { + $this->log("[ERROR] Problem om moveUpfromSubFolder subFolder:" . $subFolderName); + } + + return $success; + } + + /** + * Extracts only the 'dup-installer' files using Shell-Exec Unzip + * + * @param string $archive_filepath The path to the archive file. + * @param string $origDupInstFolder dup-installer folder + * @param string $destination destination folder + * + * @return bool + */ + private function extractInstallerShellexec($archive_filepath, $origDupInstFolder, $destination) + { + $success = false; + $this->log("Attempting to use Shell Exec"); + $unzip_filepath = $this->getUnzipFilePath(); + + if ($unzip_filepath != null) { + $unzip_command = "$unzip_filepath -q $archive_filepath " . + $origDupInstFolder . '/* -d ' . $destination . ' -x ' . + $origDupInstFolder . '/' . $this->manualExtractFileName . ' 2>&1'; + $this->log("Executing $unzip_command"); + $stderr = shell_exec($unzip_command); + + $lib_directory = $destination . '/' . $origDupInstFolder . '/lib'; + $snaplib_directory = $lib_directory . '/snaplib'; + + // If snaplib files aren't present attempt to extract and copy those + if (!file_exists($snaplib_directory)) { + $local_lib_directory = $destination . '/snaplib'; + $unzip_command = "$unzip_filepath -q $archive_filepath snaplib/* -d '.$destination.' 2>&1"; + + $this->log("Executing unzip command"); + $stderr .= shell_exec($unzip_command); + self::mkdir($lib_directory, 'u+rwx'); + rename($local_lib_directory, $snaplib_directory); + } + + if ($stderr == '') { + $this->log("Shell exec unzip succeeded"); + $success = true; + } else { + $this->log("[ERROR] Shell exec unzip failed. Output={$stderr}"); + } + } + + return $success; + } + + /** + * Attempts to get the archive file path + * + * @return string The full path to the archive file + */ + private function getArchiveFilePath() + { + if (($archive_filepath = filter_input(INPUT_GET, 'archive', FILTER_SANITIZE_SPECIAL_CHARS)) != false) { + if (is_dir($archive_filepath) && file_exists($archive_filepath . '/' . self::ARCHIVE_FILENAME)) { + $archive_filepath = $archive_filepath . '/' . self::ARCHIVE_FILENAME; + } else { + $archive_filepath = $archive_filepath; + } + } else { + $archive_filepath = $this->targetRoot . '/' . self::ARCHIVE_FILENAME; + } + + if (($realPath = realpath($archive_filepath)) !== false) { + return $realPath; + } else { + return $archive_filepath; + } + } + + /** + * Gets the enum type that should be used + * + * @return int Returns the current zip mode enum + */ + private function getZipMode() + { + $zip_mode = self::ZIP_MODE_AUTO; + + if (isset($_GET['zipmode'])) { + $zipmode_string = $_GET['zipmode']; + $this->log("Unzip mode specified in querystring: $zipmode_string"); + + switch ($zipmode_string) { + case 'autounzip': + $zip_mode = self::ZIP_MODE_AUTO; + break; + case 'ziparchive': + $zip_mode = self::ZIP_MODE_ARCHIVE; + break; + case 'shellexec': + $zip_mode = self::ZIP_MODE_SHELL; + break; + } + } + + return $zip_mode; + } + + /** + * Checks to see if a string starts with specific characters + * + * @param string $haystack haystack + * @param string $needle needle + * + * @return bool + */ + private function startsWith($haystack, $needle) + { + return $needle === "" || strrpos($haystack, $needle, - strlen($haystack)) !== false; + } + + /** + * Checks to see if the server supports issuing commands to shell_exex + * + * @return bool Returns true shell_exec can be ran on this server + */ + public function hasShellExec() + { + $cmds = array('shell_exec', 'escapeshellarg', 'escapeshellcmd', 'extension_loaded'); + + //Function disabled at server level + if (array_intersect($cmds, array_map('trim', explode(',', @ini_get('disable_functions'))))) { + return false; + } + + //Suhosin: http://www.hardened-php.net/suhosin/ + //Will cause PHP to silently fail + if (extension_loaded('suhosin')) { + $suhosin_ini = @ini_get("suhosin.executor.func.blacklist"); + if (array_intersect($cmds, array_map('trim', explode(',', $suhosin_ini)))) { + return false; + } + } + + if (! function_exists('shell_exec')) { + return false; + } + + // Can we issue a simple echo command? + if (!@shell_exec('echo duplicator')) { + return false; + } + + return true; + } + + /** + * Gets the possible system commands for unzip on Linux + * + * @return string Returns unzip file path that can execute the unzip command + */ + public function getUnzipFilePath() + { + $filepath = null; + + if ($this->hasShellExec()) { + if (shell_exec('hash unzip 2>&1') == null) { + $filepath = 'unzip'; + } else { + $possible_paths = array( + '/usr/bin/unzip', + '/opt/local/bin/unzip', + '/bin/unzip', + '/usr/local/bin/unzip', + '/usr/sfw/bin/unzip', + '/usr/xdg4/bin/unzip', + '/opt/bin/unzip', + // RSR TODO put back in when we support shellexec on windows, + ); + + foreach ($possible_paths as $path) { + if (file_exists($path)) { + $filepath = $path; + break; + } + } + } + } + + return $filepath; + } + + /** + * Display human readable byte sizes such as 150MB + * + * @param int $size The size in bytes + * + * @return string A readable byte size format such as 100MB + */ + public function readableByteSize($size) + { + try { + $units = array('B', 'KB', 'MB', 'GB', 'TB'); + for ($i = 0; $size >= 1024 && $i < 4; $i++) { + $size /= 1024; + } + return round($size, 2) . $units[$i]; + } catch (Exception $e) { + return "n/a"; + } + } + + /** + * Returns an array of zip files found in the current executing directory + * + * @param string $extension extenstion file + * + * @return array of zip files + */ + public function getFilesWithExtension($extension) + { + $files = array(); + foreach (glob("*.{$extension}") as $name) { + if (file_exists($name)) { + $files[] = $name; + } + } + if (count($files) > 0) { + return $files; + } + //FALL BACK: Windows XP has bug with glob, + //add secondary check for PHP lameness + if (($dh = opendir($this->targetRoot))) { + while (false !== ($name = readdir($dh))) { + $ext = substr($name, strrpos($name, '.') + 1); + if (in_array($ext, array($extension))) { + $files[] = $name; + } + } + closedir($dh); + } + + return $files; + } + + /** + * Safely remove a directory and recursively files and directory upto multiple sublevels + * + * @param string $path The full path to the directory to remove + * + * @return bool Returns true if all content was removed + */ + public static function rrmdir($path) + { + if (is_dir($path)) { + if (($dh = opendir($path)) === false) { + return false; + } + while (($object = readdir($dh)) !== false) { + if ($object == "." || $object == "..") { + continue; + } + if (!self::rrmdir($path . "/" . $object)) { + closedir($dh); + return false; + } + } + closedir($dh); + return @rmdir($path); + } else { + if (is_writable($path)) { + return @unlink($path); + } else { + return false; + } + } + } + + /** + * Makes path safe for any OS for PHP + * + * Paths should ALWAYS READ be "/" + * uni: /home/path/file.txt + * win: D:/home/path/file.txt + * + * @param string $path TThe path to make safe + * + * @return string The original $path with a with all slashes facing '/'. + */ + public static function setSafePath($path) + { + return str_replace("\\", "/", $path); + } + } + + class LogHandler + { + + /** @var bool */ + private static $initialized = false; + + /** + * This function only initializes the error handler the first time it is called + * + * @return void + */ + public static function init_error_handler() + { + if (!self::$initialized) { + @set_error_handler(array(__CLASS__, 'error')); + @register_shutdown_function(array(__CLASS__, 'shutdown')); + self::$initialized = true; + } + } + + /** + * Error handler + * + * @param integer $errno Error level + * @param string $errstr Error message + * @param string $errfile Error file + * @param integer $errline Error line + * @return void + */ + public static function error($errno, $errstr, $errfile, $errline) + { + switch ($errno) { + case E_ERROR: + $log_message = self::getMessage($errno, $errstr, $errfile, $errline); + if (DUPX_Bootstrap::getInstance()->log($log_message) === false) { + $log_message = "Can\'t wrinte logfile\n\n" . $log_message; + } + die('
                    ' . htmlspecialchars($log_message) . '
                    '); + break; + case E_NOTICE: + case E_WARNING: + default: + $log_message = self::getMessage($errno, $errstr, $errfile, $errline); + DUPX_Bootstrap::getInstance()->log($log_message); + break; + } + } + + /** + * Get message from error + * + * @param int $errno errno + * @param string $errstr message + * @param string $errfile file + * @param int $errline line + * + * @return string + */ + private static function getMessage($errno, $errstr, $errfile, $errline) + { + $result = '[PHP ERR]'; + switch ($errno) { + case E_ERROR: + $result .= '[FATAL]'; + break; + case E_WARNING: + $result .= '[WARN]'; + break; + case E_NOTICE: + $result .= '[NOTICE]'; + break; + default: + $result .= '[ISSUE]'; + break; + } + $result .= ' MSG:'; + $result .= $errstr; + $result .= ' [CODE:' . $errno . '|FILE:' . $errfile . '|LINE:' . $errline . ']'; + return $result; + } + + /** + * Shutdown handler + * + * @return void + */ + public static function shutdown() + { + if (($error = error_get_last())) { + LogHandler::error($error['type'], $error['message'], $error['file'], $error['line']); + } + } + } + + class DUPX_CSRF + { + + private static $packagHash = null; + private static $mainFolder = null; + + /** + * Session var name prefix + * @var string + */ + public static $prefix = '_DUPX_CSRF'; + + /** + * Stores all CSRF values: Key as CSRF name and Val as CRF value + * @var array + */ + private static $CSRFVars = null; + + /** + * Init CSRF + * + * @param string $mainFolderm main folder + * @param string $packageHash hash + * + * @return void + */ + public static function init($mainFolderm, $packageHash) + { + self::$mainFolder = $mainFolderm; + self::$packagHash = $packageHash; + self::$CSRFVars = null; + } + + /** + * Set new CSRF + * + * @param string $key CSRF Key + * @param string $val CSRF Val + * + * @return Void + */ + public static function setKeyVal($key, $val) + { + $CSRFVars = self::getCSRFVars(); + $CSRFVars[$key] = $val; + self::saveCSRFVars($CSRFVars); + self::$CSRFVars = null; + } + + /** + * Get CSRF value by passing CSRF key + * + * @param string $key CSRF key + * + * @return string|boolean If CSRF value set for give n Key, It returns CRF value otherise returns false + */ + public static function getVal($key) + { + $CSRFVars = self::getCSRFVars(); + if (isset($CSRFVars[$key])) { + return $CSRFVars[$key]; + } else { + return false; + } + } + + /** + * Generate DUPX_CSRF value for form + * + * @param string $form Form name as session key + * + * @return string token + */ + public static function generate($form = null) + { + $keyName = self::getKeyName($form); + + $existingToken = self::getVal($keyName); + if (false !== $existingToken) { + $token = $existingToken; + } else { + $token = DUPX_CSRF::token() . DUPX_CSRF::fingerprint(); + } + + self::setKeyVal($keyName, $token); + return $token; + } + + /** + * Check DUPX_CSRF value of form + * + * @param string $token Token + * @param string $form Form name as session key + * + * @return boolean + */ + public static function check($token, $form = null) + { + if (empty($form)) { + return false; + } + + $keyName = self::getKeyName($form); + $CSRFVars = self::getCSRFVars(); + if (isset($CSRFVars[$keyName]) && $CSRFVars[$keyName] == $token) { // token OK + return true; + } + return false; + } + + /** Generate token + * + * @return string + */ + protected static function token() + { + $microtime = (int) (microtime(true) * 10000); + mt_srand($microtime); + $charid = strtoupper(md5(uniqid(rand(), true))); + return substr($charid, 0, 8) . substr($charid, 8, 4) . substr($charid, 12, 4) . substr($charid, 16, 4) . substr($charid, 20, 12); + } + + /** Returns "digital fingerprint" of user + * + * @return string - MD5 hashed data + */ + protected static function fingerprint() + { + return strtoupper(md5(implode('|', array($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT'])))); + } + + /** + * Generate CSRF Key name + * + * @param string $form the form name for which CSRF key need to generate + * @return string CSRF key + */ + private static function getKeyName($form) + { + return DUPX_CSRF::$prefix . '_' . $form; + } + + /** + * Get Package hash + * + * @return string Package hash + */ + private static function getPackageHash() + { + if (is_null(self::$packagHash)) { + throw new Exception('Not init CSFR CLASS'); + } + return self::$packagHash; + } + + /** + * Get file path where CSRF tokens are stored in JSON encoded format + * + * @return string file path where CSRF token stored + */ + private static function getFilePath() + { + if (is_null(self::$mainFolder)) { + throw new Exception('Not init CSFR CLASS'); + } + $dupInstallerfolderPath = self::$mainFolder; + $packageHash = self::getPackageHash(); + $fileName = 'dup-installer-csrf__' . $packageHash . '.txt'; + $filePath = $dupInstallerfolderPath . '/' . $fileName; + return $filePath; + } + + /** + * Get all CSRF vars in array format + * + * @return array Key as CSRF name and value as CSRF value + */ + private static function getCSRFVars() + { + if (is_null(self::$CSRFVars)) { + $filePath = self::getFilePath(); + if (file_exists($filePath)) { + $contents = file_get_contents($filePath); + if (empty($contents)) { + self::$CSRFVars = array(); + } else { + $CSRFobjs = json_decode($contents); + foreach ($CSRFobjs as $key => $value) { + self::$CSRFVars[$key] = $value; + } + } + } else { + self::$CSRFVars = array(); + } + } + return self::$CSRFVars; + } + + /** + * Stores all CSRF vars + * + * @param array $CSRFVars holds all CSRF key val + * @return void + */ + private static function saveCSRFVars($CSRFVars) + { + $contents = json_encode($CSRFVars); + $filePath = self::getFilePath(); + file_put_contents($filePath, $contents); + } + } + /* * * CLASS DEFINITION END ** */ + $auto_refresh = isset($_POST['auto-fresh']) ? true : false; + DUPX_Bootstrap::phpVersionCheck(); + + try { + $boot = DUPX_Bootstrap::getInstance(); + $boot_error = $boot->run(); + } catch (Exception $e) { + $boot_error = $e->getMessage(); + } + + if ($boot_error == null) { + $secure_csrf_token = DUPX_CSRF::generate('secure'); + $ctrl_csrf_token = DUPX_CSRF::generate('ctrl-step1'); + DUPX_CSRF::setKeyVal('installerOrigCall', DUPX_Bootstrap::getCurrentUrl()); + DUPX_CSRF::setKeyVal('installerOrigPath', __FILE__); + DUPX_CSRF::setKeyVal('archive', $boot->archive); + DUPX_CSRF::setKeyVal('bootloader', $boot->bootloader); + DUPX_CSRF::setKeyVal('booturl', '//' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); + DUPX_CSRF::setKeyVal('bootLogFile', $boot->getBootLogFilePath()); + DUPX_CSRF::setKeyVal('package_hash', DUPX_Bootstrap::PACKAGE_HASH); + DUPX_CSRF::setKeyVal('secondaryHash', DUPX_Bootstrap::SECONDARY_PACKAGE_HASH); + } + ?> + + + + + + Duplicator Installer + + + +
                    + Initializing Installer. Please wait... +
                    + mainInstallerURL}' />\n"; + $data = array( + 'ctrl_action' => 'ctrl-step1', + 'ctrl_csrf_token' => $ctrl_csrf_token, + 'step_action' => 'init' + ); + foreach ($data as $name => $value) { + if ('csrf_token' != $name) { + $_SESSION[$name] = $value; + } + $html .= "\n"; + } + $html .= "\n"; + $html .= ""; + echo $html; + ?> + + + + + + + +
                    + + + + + +
                      Duplicator - Bootloader + + version:
                    + » + + dup-installer-bootlog__[HASH].txt + +
                    + +
                    +
                    +

                    Setup Notice

                    +
                    + An error has occurred. In order to load the full installer please resolve the issue below. +
                    +
                    + +
                    +

                    + +

                    Server Settings

                    + + + + + + + + + + + + + + + + + + + + + + + + + +
                    ZipArchive:hasZipArchive ? 'Enabled' : 'Disabled'; ?>
                    Shell Unzip:hasShellExecUnzip ? 'Enabled' : 'Disabled'; ?>
                    Extraction Path:targetRoot; ?>
                    Installer Path:targetDupInstFolder; ?>
                    Archive Size: + Expected Size: readableByteSize($boot->archiveExpectedSize); ?>   + Actual Size: readableByteSize($boot->archiveActualSize); ?> +
                    Boot Log + + dup-installer-bootlog__[HASH].txt + +
                    +

                    + +
                    + Note: For archive.zip files either ZipArchive or Shell Exec will need to be enabled for the installer to run automatically + otherwise a manual extraction will need to be performed. In order to run the installer manually follow the instructions to + manually extract before + running the installer. +
                    +

                    + +
                    +
                    + +
                    + + + + + + + + \n" -"Language-Team: \n" -"Language: de_DE\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.8.2\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" -"X-Poedit-Basepath: ..\n" -"X-Poedit-WPHeader: duplicator.php\n" -"X-Textdomain-Support: yes\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPathExcluded-0: assets\n" - -# @ wpduplicator -#: classes/ui.php:111 -msgid "" -"Reserved Duplicator install file(s) still exists in the root directory. " -"Please delete these file(s) to avoid possible security issues." -msgstr "" -"Reservierte Duplicator Installationsdatei(en) sind noch im Root-Verzeichnis " -"vorhanden. Bitte lösche diese Datei (en), um mögliche Sicherheitsprobleme zu " -"vermeiden." - -# @ wpduplicator -#: classes/ui.php:112 -msgid "Remove file(s) now" -msgstr "Entferne die Datei(en) jetzt" - -# @ wpduplicator -#: classes/ui.php:113 -msgid "Dismiss this notice" -msgstr "Verwerfe diese Notiz" - -# @ wpduplicator -#: classes/utility.php:249 -msgid "You do not have sufficient permissions to access this page." -msgstr "" -"Du verfügst nicht über ausreichende Rechte, um diese Seite zu betreten." - -# @ wpduplicator -#: duplicator.php:102 -msgid "Get Help" -msgstr "Hilfe bekommen" - -# @ wpduplicator -#: duplicator.php:102 duplicator.php:191 views/help/help.php:29 -msgid "Help" -msgstr "Hilfe" - -# @ wpduplicator -#: duplicator.php:103 -msgid "Support the Plugin" -msgstr "Unterstütze das Plugin" - -# @ wpduplicator -#: duplicator.php:103 duplicator.php:195 views/help/about.php:41 -msgid "About" -msgstr "Über" - -# @ wpduplicator -#: duplicator.php:179 views/packages/controller.php:76 -#: views/packages/list.base.php:235 -msgid "Packages" -msgstr "Archive" - -# @ wpduplicator -#: duplicator.php:183 views/settings/controller.php:19 -msgid "Settings" -msgstr "Einstellungen" - -# @ wpduplicator -#: duplicator.php:187 views/tools/controller.php:13 -msgid "Tools" -msgstr "Werkzeuge" - -# @ wpduplicator -#: duplicator.php:246 -msgid "Manage" -msgstr "Verwalten" - -# @ wpduplicator -#: views/help/about.php:54 -msgid "" -"Created for Admins, Developers and Designers the Duplicator can streamline " -"your workflows and help you quickly clone a WordPress application. " -"Migrating a WordPress site manually can be very time consuming. The " -"Duplicator was made to help you speed up the migration process. Please help " -"us to continue the development effort of this plugin." -msgstr "" -"Erstellt für Admins, Entwickler und Designer, die mit dem Duplicator Ihre " -"Arbeitsabläufe optimieren und eine Wordpress-Anwendung schnell klonen " -"können. Die manuell Migration eines Wordpress-Seite kann sehr zeitaufwendig " -"sein. Der Duplicator wurde entwickelt, um den Migrationsprozess zu " -"beschleunigen. Bitte unterstütze uns, um die Entwicklung des Plugins weiter " -"zu führen." - -# @ wpduplicator -#: views/help/about.php:64 -msgid "Support Duplicator" -msgstr "Unterstützung Duplicator" - -# @ wpduplicator -#: views/help/about.php:71 -msgid "Partner with Us" -msgstr "Unsere Partner" - -# @ wpduplicator -#: views/help/about.php:83 -msgid "Keep Active and Online" -msgstr "Bitte unterstütze den Duplicator mit einer Spende" - -# @ wpduplicator -#: views/help/about.php:90 -msgid "Leave 5 Stars" -msgstr "Vergebe 5 Sterne" - -# @ wpduplicator -#: views/help/about.php:107 -msgid "Spread the Word" -msgstr "Verbreitung des Inhaltes" - -# @ wpduplicator -#: views/help/about.php:113 -msgid "Duplicate Your WordPress" -msgstr "Duplizieren dein WordPress" - -# @ wpduplicator -#: views/help/about.php:114 -msgid "Rapid WordPress Duplication by LifeInTheGrid.com" -msgstr "Schnelle WordPress-Vervielfältigung von LifeInTheGrid.com" - -# @ wpduplicator -#: views/help/about.php:131 -msgid "Get More Great Tools" -msgstr "Hole Dir weitere großartige Anwendungen" - -# @ wpduplicator -#: views/help/gopro.php:37 -msgid "Go Pro!" -msgstr "Zur Pro-Version wechseln!" - -# @ wpduplicator -#: views/help/gopro.php:46 -msgid "Duplicator Pro Has Arrived!" -msgstr "Duplicator Pro ist da!" - -# @ wpduplicator -#: views/help/gopro.php:49 -msgid "The simplicity of Duplicator" -msgstr "Die Einfachheit des Duplicators" - -# @ wpduplicator -#: views/help/gopro.php:50 -msgid "with the power the professional requires." -msgstr "mit der professionellen Unterstützung." - -# @ wpduplicator -#: views/help/gopro.php:57 -msgid "Duplicator Free" -msgstr "Duplicator Free" - -# @ wpduplicator -#: views/help/gopro.php:60 views/help/gopro.php:88 -msgid "Backup Files & Database" -msgstr "Backup Dateien & Datenbank" - -# @ wpduplicator -#: views/help/gopro.php:61 views/help/gopro.php:89 -msgid "" -"Compresses all your WordPress files and database into a compressed snapshot " -"archive file." -msgstr "" -"Komprimiert alle Wordpress-Dateien und die Datenbank in eine Snapshot-" -"Archivdatei." - -# @ wpduplicator -#: views/help/gopro.php:64 views/help/gopro.php:92 -msgid "Directory Filters" -msgstr "Verzeichnisfilter" - -# @ wpduplicator -#: views/help/gopro.php:65 views/help/gopro.php:93 -msgid "" -"Filter out the directories and file extensions you want to include/exclude " -"in your in your archive file." -msgstr "" -"Filtern der Verzeichnisse und Dateierweiterungen, welche in die Archivdatei " -"eingeschlossen/ausgeschlossen werden." - -# @ wpduplicator -#: views/help/gopro.php:68 views/help/gopro.php:96 -msgid "Database Table Filters" -msgstr "Datenbanktabellen-Filter" - -# @ wpduplicator -#: views/help/gopro.php:69 views/help/gopro.php:97 -msgid "" -"Filter out only the database tables you want to include/exclude in your " -"database creation script." -msgstr "" -"Nur eingeschlossene / ausgeschlossene Datenbanktabellen zur Erstellung des " -"Datenbankscripts verwenden." - -# @ wpduplicator -#: views/help/gopro.php:72 views/help/gopro.php:100 -msgid "Migration Wizard" -msgstr "Migrations-Assistent" - -# @ wpduplicator -#: views/help/gopro.php:73 views/help/gopro.php:101 -msgid "" -"With just two files (archive & installer.php) move your site to a new " -"location." -msgstr "" -"Mit nur zwei Dateien (Archiv und installer.php) installiere die Website auf " -"eine neue Position." - -# @ wpduplicator -#: views/help/gopro.php:85 views/packages/new1.inc.form.php:50 -msgid "Duplicator Pro" -msgstr "Duplicator Pro" - -# @ wpduplicator -#: views/help/gopro.php:104 -msgid "Scheduled Backups" -msgstr "Geplante Sicherungen" - -# @ wpduplicator -#: views/help/gopro.php:105 -msgid "" -"Automate the creation of your packages to run at various scheduled intervals." -msgstr "" -"Die Erstellung der Pakete kann automatisiert an verschiedenen geplanten " -"Intervallen ausgeführt werden." - -# @ wpduplicator -#: views/help/gopro.php:108 -msgid "Dropbox Support" -msgstr "Dropbox-Unterstützung" - -# @ wpduplicator -#: views/help/gopro.php:109 -msgid "Backup up your entire site to Dropbox." -msgstr "Sichern der gesamten Website in die Dropbox." - -# @ wpduplicator -#: views/help/gopro.php:112 -msgid "FTP Support" -msgstr "FTP-Unterstützung" - -# @ wpduplicator -#: views/help/gopro.php:113 -msgid "Backup up your entire site to an FTP server." -msgstr "Sichern der gesamten Website auf einen FTP-Server." - -# @ wpduplicator -#: views/help/gopro.php:116 -msgid "Customer Support" -msgstr "Benutzer-Unterstützung" - -# @ wpduplicator -#: views/help/gopro.php:117 -msgid "" -"Server setups can be quite complex, with pro you get prompt help to get your " -"site backed up and moved." -msgstr "" -"Server-Setups können recht komplex sein. Mit der Pro-Version gibt es " -"schnelle Hilfe, um die Website zu sichern bzw. zu verschieben." - -# @ wpduplicator -#: views/help/gopro.php:124 -msgid "Check It Out!" -msgstr "Probiere es aus!" - -# @ wpduplicator -#: views/help/help.php:38 -msgid "" -"Migrating WordPress is a complex process and the logic to make all the magic " -"happen smoothly may not work quickly with every site. With over 30,000 " -"plugins and a very complex server eco-system some migrations may run into " -"issues. This is why the Duplicator includes a detailed knowledgebase that " -"can help with many common issues. Resources to additional support, approved " -"hosting, and alternatives to fit your needs can be found below." -msgstr "" -"Die Migration von Wordpress ist ein komplexer Prozess. Mit über 30.000 " -"installierbaren Plugins kann es zu Problemen kommen. Deshalb enthält der " -"Duplicator eine detaillierte Wissensdatenbank, in welcher zahlreiche Fehler " -"beschrieben sind. Weitere Unterstützung, Hosting und Alternativen sind unten " -"zu finden." - -# @ wpduplicator -#: views/help/help.php:50 -msgid "Knowledgebase" -msgstr "Wissens-Datenbank" - -# @ wpduplicator -#: views/help/help.php:53 -msgid "Complete Online Documentation" -msgstr "Vollständige Online-Dokumentation" - -# @ wpduplicator -#: views/help/help.php:55 -msgid "Choose A Section" -msgstr "Wähle eine Rubrik" - -# @ wpduplicator -#: views/help/help.php:56 -msgid "Quick Start" -msgstr "Schnell-Start" - -# @ wpduplicator -#: views/help/help.php:57 -msgid "User Guide" -msgstr "Benutzerhandbuch" - -# @ wpduplicator -#: views/help/help.php:58 -msgid "FAQs" -msgstr "Häufig gestellte Fragen" - -# @ wpduplicator -#: views/help/help.php:59 -msgid "Change Log" -msgstr "Liste der Änderungen" - -# @ wpduplicator -#: views/help/help.php:60 -msgid "Product Page" -msgstr "Produkt-Seite" - -# @ wpduplicator -#: views/help/help.php:69 -msgid "Online Support" -msgstr "Online Support" - -# @ wpduplicator -#: views/help/help.php:72 -msgid "Get Help From IT Professionals" -msgstr "Erhalte Hilfe von IT-Spezialisten" - -# @ wpduplicator -#: views/help/help.php:76 -msgid "Get Support!" -msgstr "Unterstützung bekommen!" - -# @ wpduplicator -#: views/help/help.php:88 -msgid "Approved Hosting" -msgstr "Empfohlene Hosting-Provider" - -# @ wpduplicator -#: views/help/help.php:91 -msgid "Servers That Work With Duplicator" -msgstr "Server, welche mit dem Duplicator problemlos zusammenarbeiten" - -# @ wpduplicator -#: views/help/help.php:94 -msgid "Trusted Providers!" -msgstr "Vertrauenswürdige Provider!" - -# @ wpduplicator -#: views/help/help.php:104 -msgid "Alternatives" -msgstr "Alternativen" - -# @ wpduplicator -#: views/help/help.php:107 -msgid "Other Commercial Resources" -msgstr "Andere kommerzielle Angebote" - -# @ wpduplicator -#: views/help/help.php:110 -msgid "Pro Solutions!" -msgstr "Pro-Version!" - -# @ wpduplicator -#: views/packages/list-nodata.php:7 -msgid "No Packages Found." -msgstr "Keine Archive gefunden." - -# @ wpduplicator -#: views/packages/list-nodata.php:8 -msgid "Click the 'Create New' button to build a package." -msgstr "Zum Erstellen eines Pakets auf \"Neu erzeugen\" klicken." - -# @ wpduplicator -#: views/packages/list-nodata.php:13 -msgid "Please visit the" -msgstr "Bitte besuche die" - -# @ wpduplicator -#: views/packages/list-nodata.php:14 views/packages/list-nodata.php:28 -#: views/packages/new1.base.php:234 -msgid "help page" -msgstr "Hilfe-Seiten" - -# @ wpduplicator -#: views/packages/list-nodata.php:15 -msgid "for additional support" -msgstr "für weitere Unterstützung" - -# @ wpduplicator -#: views/packages/list-nodata.php:24 -msgid "Older packages prior to 0.5.0 are no longer supported in this version." -msgstr "" -"Ältere Archive (vor 0.5.0) werden in dieser Version nicht mehr unterstützt." - -# @ wpduplicator -#: views/packages/list-nodata.php:27 -msgid "To get an older package please visit the" -msgstr "Bei älteren Archiven besuche bitte die" - -# @ wpduplicator -#: views/packages/list-nodata.php:29 -msgid "and look for the Change Log link for additional instructions." -msgstr "und suche im Änderungsprotokoll nach weiteren Anweisungen." - -# @ wpduplicator -#: views/packages/list-nodata.php:33 -msgid "Hide this message" -msgstr "Diese Nachricht ausblenden" - -# @ wpduplicator -#: views/packages/list.base.php:39 -msgid "Help Support Duplicator" -msgstr "Duplicator-Hilfe" - -# @ wpduplicator -#: views/packages/list.base.php:50 -msgid "Bulk Actions" -msgstr "Auswahl" - -# @ wpduplicator -#: views/packages/list.base.php:51 -msgid "Delete selected package(s)" -msgstr "Ausgewählte Archive löschen" - -# @ wpduplicator -#: views/packages/list.base.php:51 -msgid "Delete" -msgstr "Löschen" - -# @ wpduplicator -#: views/packages/list.base.php:53 -msgid "Apply" -msgstr "Anwenden" - -# @ wpduplicator -#: views/packages/list.base.php:58 -msgid "Package Logs" -msgstr "Archiv Logs" - -# @ wpduplicator -#: views/packages/list.base.php:61 views/packages/new1.base.php:96 -#: views/packages/new2.base.php:69 views/packages/new3.base.php:43 -#: views/packages/new3.base.php:89 -msgid "All Packages" -msgstr "Alle Archive" - -# @ wpduplicator -#: views/packages/list.base.php:62 views/packages/new1.base.php:97 -#: views/packages/new2.base.php:70 views/packages/new3.base.php:44 -msgid "Create New" -msgstr "Neu erzeugen" - -# @ wpduplicator -#: views/packages/list.base.php:87 -msgid "Select all packages" -msgstr "Alle Archive auswählen" - -# @ wpduplicator -#: views/packages/list.base.php:88 views/packages/new3.base.php:108 -msgid "Details" -msgstr "Details" - -# @ wpduplicator -#: views/packages/list.base.php:89 -msgid "Created" -msgstr "Erstellt" - -# @ wpduplicator -#: views/packages/list.base.php:90 views/packages/new2.base.php:222 -#: views/packages/new2.base.php:334 -msgid "Size" -msgstr "Größe" - -# @ wpduplicator -#: views/packages/list.base.php:91 views/packages/new1.inc.form.php:6 -#: views/packages/new1.inc.form.php:31 views/packages/new3.base.php:74 -msgid "Name" -msgstr "Name" - -# @ wpduplicator -#: views/packages/list.base.php:93 views/settings/general.php:110 -msgid "Package" -msgstr "Archiv" - -# @ wpduplicator -#: views/packages/list.base.php:124 -msgid "(No Notes Taken)" -msgstr "(Keine Notizen erstellt)" - -# @ wpduplicator -#: views/packages/list.base.php:142 views/packages/list.base.php:187 -msgid "View" -msgstr "Ansicht" - -# @ wpduplicator -#: views/packages/list.base.php:147 views/packages/new1.inc.form.php:176 -#: views/packages/new3.base.php:79 -msgid "Installer" -msgstr "Installer" - -# @ wpduplicator -#: views/packages/list.base.php:150 views/packages/new1.inc.form.php:65 -#: views/packages/new2.base.php:195 views/packages/new3.base.php:83 -msgid "Archive" -msgstr "Archive" - -# @ wpduplicator -#: views/packages/list.base.php:155 views/packages/list.base.php:200 -#: views/settings/general.php:79 views/tools/diagnostics.php:141 -#: views/tools/diagnostics.php:160 views/tools/diagnostics.php:200 -msgid "Version" -msgstr "Version" - -# @ wpduplicator -#: views/packages/list.base.php:156 views/packages/list.base.php:201 -#: views/packages/new1.inc.form.php:199 views/tools/diagnostics.php:168 -msgid "User" -msgstr "Benutzer" - -# @ wpduplicator -#: views/packages/list.base.php:157 views/packages/list.base.php:202 -msgid "Hash" -msgstr "Hash" - -# @ wpduplicator -#: views/packages/list.base.php:158 views/packages/list.base.php:207 -#: views/packages/new1.inc.form.php:8 views/packages/new1.inc.form.php:13 -msgid "Notes" -msgstr "Anmerkungen" - -# @ wpduplicator -#: views/packages/list.base.php:160 -msgid "Links" -msgstr "Links" - -# @ wpduplicator -#: views/packages/list.base.php:161 -msgid "SQL" -msgstr "SQL" - -# @ wpduplicator -#: views/packages/list.base.php:162 -msgid "Log" -msgstr "Log" - -# @ wpduplicator -#: views/packages/list.base.php:165 -msgid "Open Scan Report" -msgstr "Scan-Bericht öffnen" - -# @ wpduplicator -#: views/packages/list.base.php:166 -msgid "View Package Object" -msgstr "Paket ansehen" - -# @ wpduplicator -#: views/packages/list.base.php:193 -msgid "View Error Details" -msgstr "Fehler-Details ansehen" - -# @ wpduplicator -#: views/packages/list.base.php:205 -msgid "Unrecoverable Error! Please remove this package." -msgstr "Nicht behebbarer Fehler! Bitte lösche das Paket." - -# @ wpduplicator -#: views/packages/list.base.php:210 -msgid "" -"This package has encountered errors. Click 'View Log' for more details. " -"For additional support see the " -msgstr "" -"Es sind Fehler aufgetreten. Klicke auf 'Log ansehen' für weitere Details. " -"Zusätzliche Unterstützung findest du in der " - -# @ wpduplicator -#: views/packages/list.base.php:211 -msgid "online knowledgebase" -msgstr "Online-Wissensdatenbank" - -# @ wpduplicator -#: views/packages/list.base.php:213 -msgid "View Log" -msgstr "Log ansehen" - -# @ wpduplicator -#: views/packages/list.base.php:236 views/packages/new2.base.php:219 -#: views/packages/new2.base.php:328 -msgid "Total Size" -msgstr "Gesamte Größe" - -# @ wpduplicator -#: views/packages/list.base.php:255 -msgid "Download Links" -msgstr "Download Links" - -# @ wpduplicator -#: views/packages/list.base.php:258 -msgid "The following links contain sensitive data. Please share with caution!" -msgstr "" -"Die folgenden Links enthalten sensible Daten. Bitte verwende sie mit " -"Vorsicht!" - -# @ wpduplicator -#: views/packages/list.base.php:264 -msgid "" -"The database SQL script is a quick link to your database backup script. An " -"exact copy is also stored in the package." -msgstr "" -"Das Datenbank-SQL-Skript ist ein direkter Link zum Datenbank-Backup-Skript. " -"Eine exakte Kopie ist auch im Archiv gespeichert." - -# @ wpduplicator -#: views/packages/list.base.php:287 -msgid "" -"Please select an action from the bulk action drop down menu to perform a " -"specific action." -msgstr "Bitte wähle eine Aktion aus dem Dropdown-Menü aus." - -# @ wpduplicator -#: views/packages/list.base.php:295 -msgid "Please select at least one package to delete." -msgstr "Bitte wähle mindestens ein Archiv zum Löschen." - -# @ wpduplicator -#: views/packages/list.base.php:299 -msgid "Are you sure, you want to delete the selected package(s)?" -msgstr "Ausgewählte Archive wirklich löschen?" - -# @ wpduplicator -#: views/packages/list.base.php:333 -msgid "Package File Links" -msgstr "Archiv-Datei Links" - -# @ wpduplicator -#: views/packages/list.base.php:336 -msgid "DATABASE" -msgstr "Datenbank" - -# @ wpduplicator -#: views/packages/list.base.php:337 -msgid "PACKAGE" -msgstr "Archive" - -# @ wpduplicator -#: views/packages/list.base.php:338 -msgid "INSTALLER" -msgstr "INSTALLER" - -# @ wpduplicator -#: views/packages/list.base.php:339 -msgid "LOG" -msgstr "Log" - -# @ wpduplicator -#: views/packages/list.base.php:340 -msgid "REPORT" -msgstr "Bericht" - -# @ wpduplicator -#: views/packages/new1.base.php:13 -msgid "Package settings have been reset." -msgstr "Archiveinstellungen wurden zurückgesetzt." - -# @ wpduplicator -#: views/packages/new1.base.php:86 views/packages/new2.base.php:59 -#: views/packages/new3.base.php:33 -msgid "Setup" -msgstr "Setup" - -# @ wpduplicator -#: views/packages/new1.base.php:87 views/packages/new2.base.php:60 -#: views/packages/new3.base.php:34 -msgid "Scan" -msgstr "Scan" - -# @ wpduplicator -#: views/packages/new1.base.php:88 views/packages/new2.base.php:61 -#: views/packages/new2.base.php:388 views/packages/new3.base.php:35 -msgid "Build" -msgstr "Erstellen" - -# @ wpduplicator -#: views/packages/new1.base.php:91 -msgid "Step 1: Package Setup" -msgstr "Schritt 1: Archiv-Setup" - -# @ wpduplicator -#: views/packages/new1.base.php:115 -msgid "Requirements:" -msgstr "Anforderungen:" - -# @ wpduplicator -#: views/packages/new1.base.php:124 -msgid "" -"System requirements must pass for the Duplicator to work properly. Click " -"each link for details." -msgstr "" -"Damit der Duplicator richtig funktioniert, müssen die Systemanforderungen " -"erfüllt sein. Klicken auf jeden beliebigen Link für weitere Details." - -# @ wpduplicator -#: views/packages/new1.base.php:130 -msgid "PHP Support" -msgstr "PHP-Unterstützung" - -# @ wpduplicator -#: views/packages/new1.base.php:136 -msgid "PHP Version" -msgstr "PHP-Version" - -# @ wpduplicator -#: views/packages/new1.base.php:140 -msgid "Zip Archive Enabled" -msgstr "Zip-Archiv aktiviert" - -# @ wpduplicator -#: views/packages/new1.base.php:144 -msgid "Safe Mode Off" -msgstr "Safe Mode Off" - -# @ wpduplicator -#: views/packages/new1.base.php:148 views/packages/new1.base.php:152 -#: views/packages/new1.base.php:156 -msgid "Function" -msgstr "Funktion" - -# @ wpduplicator -#: views/packages/new1.base.php:161 -msgid "" -"PHP versions 5.2.17+ or higher is required. Please note that in versioning " -"logic a value such as 5.2.9 is less than 5.2.17. For compression to work the " -"ZipArchive extension for PHP is required. Safe Mode should be set to 'Off' " -"in you php.ini file and is deprecated as of PHP 5.3.0. For any issues in " -"this section please contact your hosting provider or server administrator. " -"For additional information see our online documentation." -msgstr "" -"PHP-Versionen 5.2.17+ oder höher ist erforderlich. Bitte beachte, dass in " -"der Versionslogik ein Wert wie 5.2.9 weniger ist als 5.2.17. Für die " -"Kompression ist die ZipArchive-Erweiterung für PHP ist erforderlich. Der " -"Safe Mode sollte auf 'Aus' in dir php.ini-Datei eingestellt werden (veraltet " -"ab PHP 5.3.0). Für weitere Fragen in diesem Abschnitt wende dich an deinen " -"Hosting-Provider oder Serveradministrator. Weitere Informationen befinden " -"sich auf unserer Online-Dokumentation." - -# @ wpduplicator -#: views/packages/new1.base.php:169 -msgid "Permissions" -msgstr "Berechtigungen" - -# @ wpduplicator -#: views/packages/new1.base.php:172 -msgid "Required Paths" -msgstr "Erforderliche Pfade" - -# @ wpduplicator -#: views/packages/new1.base.php:183 -msgid "" -"Permissions can be difficult to resolve on some systems. If the plugin can " -"not read the above paths here are a few things to try. 1) Set the above " -"paths to have permissions of 755 for directories and 644 for files. You can " -"temporarily try 777 however, be sure you don’t leave them this way. 2) Check " -"the owner/group settings for both files and directories. The PHP script " -"owner and the process owner are different. The script owner owns the PHP " -"script but the process owner is the user the script is running as, thus " -"determining its capabilities/privileges in the file system. For more details " -"contact your host or server administrator or visit the 'Help' menu under " -"Duplicator for additional online resources." -msgstr "" -"Berechtigungen sind auf einigen Systemen nur schwer zu ändern. Wenn das " -"Plugin die oben genannten Pfade nicht lesen kann, versuche folgendes. 1) " -"Setze die Berechtigungen für Verzeichnisse auf 755 und für Dateien auf 644. " -"Versuche es ggf. vorübergehend mit 777. 2) Prüfe den Eigentümer / " -"Gruppeneinstellungen für Dateien und Verzeichnissen. Das PHP-Skript und ein " -"FTP-Benutzer erfordern unterschiedliche Eigentümer. Der Skript Eigentümer " -"besitzt das PHP-Skript, aber der Prozess-Besitzer ist der Benutzer, welcher " -"das Skript ausführt. Für weitere Informationen wende dich Host- oder Server-" -"Administrator oder besuche das \\\"Hilfe\\\"-Menü unter Duplicator für " -"zusätzliche Online-Ressourcen." - -# @ wpduplicator -#: views/packages/new1.base.php:191 -msgid "Server Support" -msgstr "Server-Support" - -# @ wpduplicator -#: views/packages/new1.base.php:197 -msgid "MySQL Version" -msgstr "MySQL-Version" - -# @ wpduplicator -#: views/packages/new1.base.php:201 -msgid "MySQLi Support" -msgstr "MySQLi-Support" - -# @ wpduplicator -#: views/packages/new1.base.php:207 -msgid "" -"MySQL version 5.0+ or better is required and the PHP MySQLi extension (note " -"the trailing 'i') is also required. Contact your server administrator and " -"request that mysqli extension and MySQL Server 5.0+ be installed. Please " -"note in future versions support for other databases and extensions will be " -"added." -msgstr "" -"MySQL-Version 5.0 oder höher und die PHP MySQLi-Erweiterung (beachte das " -"ergänzende \\\"i\\\") ist ebenfalls erforderlich. Kontaktiere deinen Server-" -"Administrator und verlange, dass mysqli-Erweiterung und MySQL Server 5.0 und " -"höher installiert werden. Bitte beachte, dass in zukünftigen Versionen " -"Unterstützung für andere Datenbanken und Erweiterungen hinzugefügt werden." - -# @ wpduplicator -#: views/packages/new1.base.php:208 -msgid "more info" -msgstr "mehr Informationen" - -# @ wpduplicator -#: views/packages/new1.base.php:217 -msgid "Reserved Files" -msgstr "Reservierte Dateien" - -# @ wpduplicator -#: views/packages/new1.base.php:221 -msgid "" -"None of the reserved files (installer.php, installer-data.sql and installer-" -"log.txt) where found from a previous install. This means you are clear to " -"create a new package." -msgstr "" -"Es wurden keine reservierte Dateien (installer.php, installer-data.sql und " -"installer-log.txt) von einer früheren Installation gefunden. Ein neues Paket " -"kann nun erstellt werden." - -# @ wpduplicator -#: views/packages/new1.base.php:224 -msgid "" -"A reserved file(s) was found in the WordPress root directory. Reserved file " -"names are installer.php, installer-data.sql and installer-log.txt. To " -"archive your data correctly please remove any of these files from your " -"WordPress root directory. Then try creating your package again." -msgstr "" -"Es wurden reservierte Datei (en) im WordPress Stammverzeichnis gefunden. " -"Reservierte Dateinamen sind installer.php, installer-data.sql und installer-" -"log.txt. Zum korrekten Archivieren deiner Dateien entferne bitte diese " -"Dateien aus dem WordPress-Stammverzeichnis. Dann versuche erneut, das Archiv " -"zu erstellen." - -# @ wpduplicator -#: views/packages/new1.base.php:225 -msgid "Remove Files Now" -msgstr "Dateien werden entfernt" - -# @ wpduplicator -#: views/packages/new1.base.php:234 -msgid "For additional help please see the " -msgstr "Weitere Hilfe befindet sich in der " - -# @ wpduplicator -#: views/packages/new1.inc.form.php:10 -msgid "Create a new default name" -msgstr "Erstelle einen neuen Standardnamen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:23 views/settings/general.php:94 -msgid "Storage" -msgstr "Speicher" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:32 -msgid "Type" -msgstr "Typ" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:33 -msgid "Location" -msgstr "Ort" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:38 -msgid "Default" -msgstr "Vorgabe" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:39 -msgid "Local" -msgstr "Lokal" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:45 -msgid "" -"All packages including the archive, installer and SQL script are stored in " -"the location above. " -msgstr "" -"Alle Dateien einschließlich des Archivs, Installer und SQL-Skript sind im " -"Ordner oberhalb gespeichert. " - -# @ wpduplicator -#: views/packages/new1.inc.form.php:48 -msgid "Dropbox, FTP and other multiple storage options available in " -msgstr "Dropbox, FTP und weitere Speicheroptionen sind verfügbar in " - -# @ wpduplicator -#: views/packages/new1.inc.form.php:67 -msgid "File filter enabled" -msgstr "Datei-Filter aktiviert" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:68 -msgid "Database filter enabled" -msgstr "Datenbank-Filter aktiviert" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:77 views/packages/new2.base.php:203 -msgid "Files" -msgstr "Dateien" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:78 views/packages/new1.inc.form.php:195 -#: views/packages/new2.base.php:312 -msgid "Database" -msgstr "Datenbank" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:90 -msgid "Enable File Filters" -msgstr "Dateifilter aktivieren" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:94 views/packages/new1.inc.form.php:102 -msgid "Separate all filters by semicolon" -msgstr "Trenne alle Filter durch ein Semikolon" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:94 views/packages/new2.base.php:278 -msgid "Directories" -msgstr "Verzeichnisse" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:96 -msgid "root path" -msgstr "Root-Pfad" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:97 -msgid "wp-uploads" -msgstr "uploads" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:98 -msgid "cache" -msgstr "Cache" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:99 views/packages/new1.inc.form.php:106 -msgid "(clear)" -msgstr "(Löschen)" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:102 -msgid "File extensions" -msgstr "Datei-Erweiterungen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:104 -msgid "media" -msgstr "Medien" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:105 -msgid "archive" -msgstr "Archive" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:111 -msgid "" -"The directory paths and extensions above will be be excluded from the " -"archive file if enabled is checked." -msgstr "" -"Diese Verzeichnispfade und Erweiterungen werden aus der Archivdatei " -"ausgeschlossen." - -# @ wpduplicator -#: views/packages/new1.inc.form.php:112 -msgid "Use the full path for directories and semicolons to separate all items." -msgstr "" -"Verwende den vollständigen Pfad für Verzeichnisse und Semikolons, um alle " -"Elemente zu trennen." - -# @ wpduplicator -#: views/packages/new1.inc.form.php:123 -msgid "Enable Table Filters" -msgstr "Tabellen-Filter aktivieren" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:124 -msgid "checked tables are excluded" -msgstr "Markierte Tabellen sind ausgeschlossen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:129 -msgid "Include All" -msgstr "Alle einschliessen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:130 -msgid "Exclude All" -msgstr "Alle ausschliessen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:163 -msgid "" -"Checked tables will not be added to the database script. Excluding certain " -"tables can possibly cause your site or plugins to not work correctly after " -"install!" -msgstr "" -"Ausgewählte Tabellen werden dem Archiv nicht hinzugefügt. Ohne diese " -"Tabellen funktionieren möglicherweise die Website oder Plugins nach der " -"Installation nicht korrekt!" - -# @ default -#: views/packages/new1.inc.form.php:181 -msgid "STEP 1 - INPUTS" -msgstr "Schritt 1 – Eingaben" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:184 -msgid "MySQL Server" -msgstr "MySQL-Server" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:187 -msgid "Host" -msgstr "Host" - -#: views/packages/new1.inc.form.php:191 -msgid "Host Port" -msgstr "Host-Port" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:203 -msgid "Advanced Options" -msgstr "Erweiterte Optionen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:209 -msgid "SSL" -msgstr "SSL" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:212 -msgid "Enforce on Admin" -msgstr "Admin erzwingen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:216 -msgid "Enforce on Logins" -msgstr "Logins erzwingen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:220 -msgid "Cache" -msgstr "Cache" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:223 -msgid "Keep Enabled" -msgstr "Aktiviert halten" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:227 -msgid "Keep Home Path" -msgstr "Startseite Pfad belassen" - -# @ default -#: views/packages/new1.inc.form.php:235 -msgid "STEP 2 - INPUTS" -msgstr "Schritt 2 – Eingaben" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:239 -msgid "New URL" -msgstr "Neue URL" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:245 -msgid "The installer can have these fields pre-filled at install time." -msgstr "" -"Das Installationsprogramm kann diese Felder bereits vor der Installation " -"ausgefüllt haben." - -# @ wpduplicator -#: views/packages/new1.inc.form.php:245 -msgid "All values are optional." -msgstr "Alle Werte sind optional." - -# @ wpduplicator -#: views/packages/new1.inc.form.php:254 -msgid "Reset" -msgstr "Zurücksetzen" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:255 -msgid "Next" -msgstr "Weiter" - -# @ wpduplicator -#: views/packages/new1.inc.form.php:267 -msgid "" -"This will reset all of the current package settings. Would you like to " -"continue?" -msgstr "" -"Dies wird alle aktuellen Archiveinstellungen zurückzusetzen. Möchtest Du " -"fortfahren?" - -# @ wpduplicator -#: views/packages/new2.base.php:64 -msgid "Step 2: System Scan" -msgstr "Schritt 2: System Scan" - -# @ wpduplicator -#: views/packages/new2.base.php:81 -msgid "Scanning Site" -msgstr "Scan Seite" - -# @ wpduplicator -#: views/packages/new2.base.php:83 views/packages/new3.base.php:57 -msgid "Please Wait..." -msgstr "Bitte warten..." - -# @ wpduplicator -#: views/packages/new2.base.php:89 -msgid "Scan Complete" -msgstr "Scan vollständig" - -# @ wpduplicator -#: views/packages/new2.base.php:91 -msgid "" -"Scan checks are not required to pass, however they could cause issues on " -"some systems." -msgstr "" -"Scan-Checks sind nicht unbedingt erforderlich, können jedoch auf einigen " -"Systemen Probleme verursachen." - -# @ wpduplicator -#: views/packages/new2.base.php:92 -msgid "Process Time:" -msgstr "Verarbeitungs-Dauer" - -# @ wpduplicator -#: views/packages/new2.base.php:101 -msgid "Server" -msgstr "Server" - -# @ wpduplicator -#: views/packages/new2.base.php:103 views/tools/controller.php:17 -msgid "Diagnostics" -msgstr "Diagnose" - -# @ wpduplicator -#: views/packages/new2.base.php:112 views/packages/new2.base.php:117 -#: views/tools/diagnostics.php:106 -msgid "Web Server" -msgstr "Webserver" - -#: views/packages/new2.base.php:119 -msgid "Supported web servers:" -msgstr "Unterstützte Webserver:" - -#: views/packages/new2.base.php:129 -msgid "PHP Setup" -msgstr "PHP-Setup" - -# @ wpduplicator -#: views/packages/new2.base.php:135 -msgid "Open Base Dir" -msgstr "Open Base Dir" - -#: views/packages/new2.base.php:137 -msgid "" -"Issues might occur when [open_basedir] is enabled. Work with your server " -"admin to disable this value in the php.ini file if you’re having issues " -"building a package." -msgstr "" -"Es können Probleme auftreten falls [open_basedir] aktiviert ist. Für den " -"Fall, dass Du Probleme hast ein Archiv zu erstellen, kontaktiere Deinen " -"Administrator damit dieser den Wert in der php.ini Datei deaktiviert." - -#: views/packages/new2.base.php:138 views/packages/new2.base.php:148 -#: views/packages/new2.base.php:155 -msgid "details" -msgstr "Details" - -# @ wpduplicator -#: views/packages/new2.base.php:143 views/tools/diagnostics.php:189 -msgid "Max Execution Time" -msgstr "Maximale Ausführungs-Zeit" - -#: views/packages/new2.base.php:145 -#, php-format -msgid "" -"Issues might occur for larger packages when the [max_execution_time] value " -"in the php.ini is too low. The minimum recommended timeout is \"%1$s\" " -"seconds or higher. An attempt is made to override this value if the server " -"allows it. A value of 0 (recommended) indicates that PHP has no time limits." -msgstr "" -"Es können Probleme bei größeren Archiven auftreten falls der Wert für die " -"[max_execution_time] in der php.ini zu niedrig gesetzt ist. Der kleinste " -"empfohlene Timeout-Wert liegt bei \"%1$s\" Sekunden oder mehr. Es wird ein " -"Versuch unternommen diesen Wert zu übergehen falls der Server dies erlaubt. " -"Ein Wert von 0 (empfohlen) zeigt an, dass PHP kein Zeitlimit hat." - -# @ wpduplicator -#: views/packages/new2.base.php:147 -msgid "" -"Note: Timeouts can also be set at the web server layer, so if the PHP max " -"timeout passes and you still see a build interrupt messages, then your web " -"server could be killing the process. If you are limited on processing " -"time, consider using the database or file filters to shrink the size of your " -"overall package. However use caution as excluding the wrong resources can " -"cause your install to not work properly." -msgstr "" -"Hinweis: Timeouts können auch am Web-Server eingestellt werden, so dass bei " -"PHP-Timeout der Prozess abgebrochen wird. Wenn die Verarbeitungszeit " -"begrenzt ist, nutze Datenbank-oder Dateifilter, um die Größe des " -"Gesamtpakets schrumpfen. Bitte beachte, dass falsche Einstellungen dazu " -"führen können, dass die Anwendung nicht mehr richtig funktioniert." - -#: views/packages/new2.base.php:152 -msgid "MySQLi" -msgstr "MySQLi" - -#: views/packages/new2.base.php:154 -msgid "" -"Creating the package does not require the mysqli module. However the " -"installer.php file requires that the PHP module mysqli be installed on the " -"server it is deployed on." -msgstr "" -"Für das Erstellen eines Archivs benötigst Du nicht das MySQLi-Modul. Jedoch " -"benötigt die installer.php Datei das installierte MySQLi-Modul auf dem " -"Server auf dem das Archiv erstellt wird." - -#: views/packages/new2.base.php:164 -msgid "WordPress" -msgstr "WordPress" - -# @ wpduplicator -#: views/packages/new2.base.php:169 -msgid "WordPress Version" -msgstr "WordPress-Version" - -#: views/packages/new2.base.php:171 -#, php-format -msgid "" -"It is recommended to have a version of WordPress that is greater than %1$s" -msgstr "" -"Es wird empfohlen eine Version von WordPress installiert zu haben die größer " -"%1$s ist" - -# @ wpduplicator -#: views/packages/new2.base.php:175 -msgid "Core Files" -msgstr "Core-Dateien" - -# @ wpduplicator -#: views/packages/new2.base.php:177 -msgid "" -"If the scanner is unable to locate the wp-config.php file in the root " -"directory, then you will need to manually copy it to its new location." -msgstr "" -"Wenn der Scanner die Datei wp-config.php im Root-Verzeichnis nicht findet, " -"muss sie manuell an die neue Position manuell kopiert werden." - -# @ wpduplicator -#: views/packages/new2.base.php:183 -msgid "Cache Path" -msgstr "Cache-Pfad" - -#: views/packages/new2.base.php:185 -msgid "" -"Cached data will lead to issues at install time and increases your archive " -"size. It is recommended to empty your cache directory at build time. Use " -"caution when removing data from the cache directory. If you have a cache " -"plugin review the documentation for how to empty it; simply removing files " -"might cause errors on your site. The cache size minimum threshold is " -"currently set at " -msgstr "" -"Gecachte Daten führen zu Problemen bei der Installation und zu einer " -"erhöhten Archiv-Größe. Es wird empfohlen das Cache-Verzeichnis vor der " -"Erstellung des Archives zu leeren. Lasse Vorsicht walten bevor Du Daten aus " -"dem Cache-Verzeichnis entfernst. Für den Fall dass Du ein Cache-Plugin " -"verwendest lies in der Anleitung nach wie Du dessen Cache sicher leerst; das " -"direkte Entfernen von Dateien kann zu Problemen mit Deiner Webseite führen. " -"Der untere Grenzwert für die Cache-Größe liegt aktuell bei " - -# @ wpduplicator -#: views/packages/new2.base.php:208 views/packages/new2.base.php:317 -msgid "Enabled" -msgstr "Aktiviert" - -# @ wpduplicator -#: views/packages/new2.base.php:223 -msgid "File Count" -msgstr "Dateianzahl" - -# @ wpduplicator -#: views/packages/new2.base.php:224 -msgid "Directory Count" -msgstr "Verzeichnisanzahl" - -# @ wpduplicator -#: views/packages/new2.base.php:227 -#, php-format -msgid "" -"Total size represents all files minus any filters that have been setup. The " -"current thresholds that trigger warnings are %1$s for the entire site and " -"%2$s for large files." -msgstr "" -"Die Gesamtgröße entspricht allen Dateien abzüglich der im Filter " -"festgelegten Elemente. Die aktuellen Grenzwerte, die Warnungen auslösen, " -"sind %1$s für die gesamte Site und %2$s für große Dateien." - -#: views/packages/new2.base.php:239 -msgid "Name Checks" -msgstr "Namenüberprüfung" - -#: views/packages/new2.base.php:244 -msgid "" -"File or directory names may cause issues when working across different " -"environments and servers. Names that are over 250 characters, contain " -"special characters (such as * ? > < : / \\ |) or are unicode might cause " -"issues in a remote enviroment. It is recommended to remove or filter these " -"files before building the archive if you have issues at install time." -msgstr "" -"Datei- oder Verzeichnis-Namen können zu Problemen führen wenn in " -"unterschiedlichen Umgebungen und Servern gearbeitet wird. Namen die mehr als " -"250 Zeichen lang sind, Sonderzeichen wie z.B. * ? > < : / \\ | enthalten " -"oder aber Unicode sind können zu Problemen in entfernten Umgebungen führen. " -"Es wird empfohlen diese Dateien vor der Erstellung des Archivs zu entfernen " -"oder zu filtern, sollte es zu Problemen bei der Installation im Anschluss " -"kommen." - -# @ wpduplicator -#: views/packages/new2.base.php:247 views/packages/new2.base.php:265 -msgid "Show Paths" -msgstr "Zeige Pfade" - -# @ wpduplicator -#: views/packages/new2.base.php:256 -msgid "Large Files" -msgstr "Große Dateien" - -# @ wpduplicator -#: views/packages/new2.base.php:261 -#, php-format -msgid "" -"Large files such as movies or other backuped data can cause issues with " -"timeouts. The current check for large files is %1$s per file. If your " -"having issues creating a package consider excluding these files with the " -"files filter and manually moving them to your new location." -msgstr "" -"Große Dateien wie Filme oder andere Archiv-Daten können zu Problemen mit " -"Timeouts führen. Die aktuelle Prüfung für große Dateien ist %1$s pro Datei. " -"Wenn es zu Problemen beim Erstellen des Archives kommt, bitte diese Dateien " -"mit dem Filter ausschließen und manuell auf die neue Position verschieben." - -# @ wpduplicator -#: views/packages/new2.base.php:275 -msgid "View Filters" -msgstr "Filter anzeigen" - -# @ wpduplicator -#: views/packages/new2.base.php:283 -msgid "No directory filters have been set." -msgstr "Es sind keine Verzeichnisfilter eingestellt." - -# @ wpduplicator -#: views/packages/new2.base.php:288 -msgid "File Extensions" -msgstr "Datei-Erweiterungen" - -# @ wpduplicator -#: views/packages/new2.base.php:293 -msgid "No file extension filters have been set." -msgstr "Keine Dateierweiterungs-Filter gesetzt." - -#: views/packages/new2.base.php:297 -msgid "" -"The lists above are the directories and file extension that will be excluded " -"from the archive." -msgstr "" -"Die Listen darüber sind die Verzeichnisse und Dateiendungen die aus dem " -"Archiv ausgeschlossen werden." - -# @ wpduplicator -#: views/packages/new2.base.php:332 -msgid "Tables" -msgstr "Tabellen" - -# @ wpduplicator -#: views/packages/new2.base.php:333 -msgid "Records" -msgstr "Aufzeichnungen" - -# @ wpduplicator -#: views/packages/new2.base.php:336 -msgid "repair and optimization" -msgstr "Reparatur und Optimierung" - -# @ wpduplicator -#: views/packages/new2.base.php:337 -#, php-format -msgid "" -"Total size and row count for all database tables are approximate values. " -"The thresholds that trigger warnings are %1$s and %2$s records. Large " -"databases take time to process and can cause issues with server timeout and " -"memory settings. Running a %3$s on your database can also help improve the " -"overall size and performance. If your server supports shell_exec and " -"mysqldump you can try to enable this option from the settings menu." -msgstr "" -"Gesamtgröße und Zeilenanzahl für alle Datenbank-Tabellen sind Richtwerte. " -"Die Schwellenwerte, die Warnungen auslösen, sind %1$s und %2$s Datensätze. " -"Große Datenbanken benötigen mehr Zeit bei der Verarbeitung und können zu " -"Problemen mit Server-Timeout und Speichereinstellungen führen. Ausführen " -"einer %3$s auf der Datenbank können auch dazu beitragen, die Gesamtgröße und " -"Leistung zu verbessern. Wenn der Server shell_exec und mysqldump " -"unterstützt, kannst du versuchen, diese Option aus dem Menü Einstellungen zu " -"aktivieren." - -# @ wpduplicator -#: views/packages/new2.base.php:349 -msgid "Table Details" -msgstr "Tabellen-Details" - -# @ wpduplicator -#: views/packages/new2.base.php:360 -msgid "Name:" -msgstr "Name:" - -# @ wpduplicator -#: views/packages/new2.base.php:361 -msgid "Host:" -msgstr "Host:" - -# @ wpduplicator -#: views/packages/new2.base.php:362 -msgid "Build Mode:" -msgstr "Erstellungs-Modus:" - -# @ wpduplicator -#: views/packages/new2.base.php:373 -msgid "Scan Error" -msgstr "Scan Fehler" - -# @ wpduplicator -#: views/packages/new2.base.php:374 -msgid "Please try again!" -msgstr "Bitte nochmals versuchen!" - -# @ wpduplicator -#: views/packages/new2.base.php:376 views/packages/new3.base.php:111 -msgid "Server Status:" -msgstr "Server Status:" - -# @ wpduplicator -#: views/packages/new2.base.php:379 views/packages/new3.base.php:115 -msgid "Error Message:" -msgstr "Fehler-Meldung:" - -# @ wpduplicator -#: views/packages/new2.base.php:386 -msgid "Back" -msgstr "Zurück" - -# @ wpduplicator -#: views/packages/new2.base.php:387 -msgid "Rescan" -msgstr "Erneuter Scan" - -# @ wpduplicator -#: views/packages/new2.base.php:486 -msgid "Unable to report on any tables" -msgstr "Kein Bericht über die Tabellen" - -# @ wpduplicator -#: views/packages/new2.base.php:495 -msgid "Unable to report on database stats" -msgstr "Kein Bericht zum Datenbank-Status" - -#: views/packages/new2.base.php:514 -msgid "DIR" -msgstr "DIR" - -# @ wpduplicator -#: views/packages/new2.base.php:520 views/packages/new2.base.php:533 -msgid "FILE" -msgstr "Datei" - -#: views/packages/new2.base.php:523 -msgid "No name warning issues found." -msgstr "Es sind keine Probleme bei der Namensüberprüfung aufgetreten." - -# @ wpduplicator -#: views/packages/new2.base.php:529 -msgid "No large files found." -msgstr "Keine großen Dateien gefunden." - -# @ wpduplicator -#: views/packages/new3.base.php:38 -msgid "Step 3: Build Package" -msgstr "Schritt 3: Archiv erstellen" - -# @ wpduplicator -#: views/packages/new3.base.php:55 -msgid "Building Package" -msgstr "Archiv erstellen" - -# @ wpduplicator -#: views/packages/new3.base.php:58 -msgid "Keep this window open during the build process." -msgstr "Lass dieses Fenster während der Archiv-Erstellung geöffnet." - -# @ wpduplicator -#: views/packages/new3.base.php:59 -msgid "This may take several minutes." -msgstr "Dies kann einige Minuten dauern." - -# @ wpduplicator -#: views/packages/new3.base.php:63 -msgid "Build Status" -msgstr "Erstellungs-Status" - -# @ wpduplicator -#: views/packages/new3.base.php:70 -msgid "Package Completed" -msgstr "Archiv komplett" - -# @ wpduplicator -#: views/packages/new3.base.php:75 -msgid "Process Time" -msgstr "Verarbeitungszeit" - -# @ wpduplicator -#: views/packages/new3.base.php:100 -msgid "Build Interrupt" -msgstr "Erstellung unterbrochen" - -# @ wpduplicator -#: views/packages/new3.base.php:101 -msgid "The current build has experienced an issue." -msgstr "Die aktuelle Version hat ein Problem." - -# @ wpduplicator -#: views/packages/new3.base.php:103 -msgid "Please try the process again." -msgstr "Bitte versuche den Vorgang erneut." - -# @ wpduplicator -#: views/packages/new3.base.php:105 -msgid "Diagnose" -msgstr "Diagnose" - -# @ wpduplicator -#: views/packages/new3.base.php:106 -msgid "Try Again" -msgstr "Nochmals versuchen" - -# @ wpduplicator -#: views/packages/new3.base.php:122 -msgid "Notice" -msgstr "Anmerkung" - -# @ default -#: views/packages/new3.base.php:125 -msgid "Build Folder:" -msgstr "Erstellungs-Verzeichnis:" - -# @ wpduplicator -#: views/packages/new3.base.php:127 -msgid "" -"Some servers close connections quickly; yet the build can continue to run in " -"the background. To validate if a build is still running; open the 'tmp' " -"folder above and see if the archive file is growing in size. If it is not " -"then your server has strict timeout constraints. Please visit the support " -"page for additional resources." -msgstr "" -"Einige Server schließen die Verbindungen schnell, doch die Erstellung kann " -"auch weiterhin im Hintergrund laufen. Um zu prüfen ob derProzess noch läuft, " -"öffnen den 'tmp'-Ordner um zu sehen, ob die Archivdatei in der Größe wächst. " -"Wenn nicht, hat der Server strenge Beschränkungen im Timeout. Bitte besuche " -"die Support-Seite für weitere Lösungen." - -# @ wpduplicator -#: views/packages/new3.base.php:136 -msgid "Package Log" -msgstr "Archiv Log" - -# @ wpduplicator -#: views/settings/controller.php:22 views/tools/diagnostics.php:87 -msgid "General" -msgstr "Allgemein" - -# @ wpduplicator -#: views/settings/general.php:6 -msgid "Settings Saved" -msgstr "Einstellungen gespeichert" - -# @ wpduplicator -#: views/settings/general.php:75 -msgid "Plugin" -msgstr "Plugin" - -# @ wpduplicator -#: views/settings/general.php:83 -msgid "Uninstall" -msgstr "Deinstallieren" - -# @ wpduplicator -#: views/settings/general.php:86 -msgid "Delete Plugin Settings" -msgstr "Plugin-Einstellungen löschen" - -# @ wpduplicator -#: views/settings/general.php:89 -msgid "Delete Entire Storage Directory" -msgstr "Speicher-Verzeichnisse vollständig löschen" - -# @ wpduplicator -#: views/settings/general.php:96 -msgid "Full Path" -msgstr "Vollständiger Pfad" - -# @ wpduplicator -#: views/settings/general.php:99 -msgid "Disable .htaccess File In Storage Directory" -msgstr ".htaccess-Datei im Speicher-Verzeichnis deaktivieren" - -# @ wpduplicator -#: views/settings/general.php:101 -msgid "Disable if issues occur when downloading installer/archive files." -msgstr "" -"Deaktivieren, wenn beim Download von Installer / Archivdateien Probleme " -"auftreten." - -# @ wpduplicator -#: views/settings/general.php:114 -msgid "Archive Flush" -msgstr "Archiv erstellen" - -# @ wpduplicator -#: views/settings/general.php:117 -msgid "Attempt Network Keep Alive" -msgstr "" -"Dadurch wird versucht, eine Netzwerkverbindung für große Archive zu " -"etablieren" - -# @ wpduplicator -#: views/settings/general.php:118 -msgid "recommended only for large archives" -msgstr "nur empfohlen für große Archive" - -# @ wpduplicator -#: views/settings/general.php:120 -msgid "" -"This will attempt to keep a network connection established for large " -"archives." -msgstr "" -"Dadurch wird versucht, eine Netzwerkverbindung für große Archive zu " -"etablieren." - -# @ wpduplicator -#: views/settings/general.php:125 -msgid "Database Build" -msgstr "Datenbank erstellen" - -# @ wpduplicator -#: views/settings/general.php:128 -msgid "Use PHP" -msgstr "Benutze PHP" - -# @ wpduplicator -#: views/settings/general.php:131 -msgid "Query Limit Size" -msgstr "Abfragelimit-Größe" - -# @ wpduplicator -#: views/settings/general.php:140 -msgid "higher values speed up build times but uses more memory" -msgstr "" -"Höhere Werte beschleunigen die Erstellung, aber sie benötigen mehr Speicher" - -# @ wpduplicator -#: views/settings/general.php:147 -msgid "This server does not have shell_exec configured to run." -msgstr "Dieser Server ist nicht zur Ausführung von shell_exec konfiguriert." - -# @ wpduplicator -#: views/settings/general.php:149 -msgid "Please contact the server administrator to enable this feature." -msgstr "" -"Bitte kontaktiere den Server-Administrator, um diese Funktion zu aktivieren." - -# @ wpduplicator -#: views/settings/general.php:154 -msgid "Use mysqldump" -msgstr "Benutze mysqldump" - -# @ wpduplicator -#: views/settings/general.php:155 -msgid "recommended for large databases" -msgstr "für große Datenbanken empfohlen" - -# @ wpduplicator -#: views/settings/general.php:160 -msgid "Working Path:" -msgstr "Arbeits-Pfad" - -# @ wpduplicator -#: views/settings/general.php:166 -msgid "" -"Mysqldump was not found at its default location or the location provided. " -"Please enter a path to a valid location where mysqldump can run. If the " -"problem persist contact your server administrator." -msgstr "" -"Mysqldump wurde nicht an der Standardposition gefunden. Bitte gib den Pfad " -"zu einem gültigen Ort ein, an dem mysqldump ausgeführt werden kann. Sollte " -"das Problem bestehen bleiben, kontaktiere den Server-Administrator." - -# @ wpduplicator -#: views/settings/general.php:171 -msgid "Add Custom Path:" -msgstr "Benutzer-Pfad hinzufügen" - -# @ wpduplicator -#: views/settings/general.php:175 -msgid "This is the path to your mysqldump program." -msgstr "Das ist der Pfad zu deinem mysqldump-Programm." - -# @ wpduplicator -#: views/settings/general.php:184 -msgid "Package Debug" -msgstr "Fehlerbeseitigung Archiv" - -# @ wpduplicator -#: views/settings/general.php:187 -msgid "Show Package Debug Status in Packages Screen" -msgstr "Zeige Fehlerstatus des Archives in der Anzeige" - -# @ wpduplicator -#: views/settings/general.php:195 -msgid "Roles & Capabilities" -msgstr "Rollen & Funktionen" - -# @ wpduplicator -#: views/settings/general.php:200 -msgid "Custom Roles" -msgstr "Benutzerdefinierte Rollen" - -# @ wpduplicator -#: views/settings/general.php:203 -msgid "Enable User Role Editor Plugin Integration" -msgstr "Ermöglicht User Role Editor Plugin Integration" - -# @ wpduplicator -#: views/settings/general.php:210 -msgid "The User Role Editor Plugin" -msgstr "Das User Role Editor Plugin" - -# @ wpduplicator -#: views/settings/general.php:211 -msgid "Free" -msgstr "Free" - -# @ wpduplicator -#: views/settings/general.php:212 -msgid "or" -msgstr "oder" - -# @ wpduplicator -#: views/settings/general.php:213 -msgid "Professional" -msgstr "Professional" - -# @ wpduplicator -#: views/settings/general.php:214 -msgid "must be installed to use" -msgstr "muss installiert werden zur Benutzung" - -# @ wpduplicator -#: views/settings/general.php:215 -msgid "this feature." -msgstr "dieser Option." - -# @ wpduplicator -#: views/settings/general.php:227 -msgid "Save Settings" -msgstr "Einstellungen speichern" - -# @ wpduplicator -#: views/tools/cleanup.php:8 -msgid "Installer File Cleanup Ran." -msgstr "Installations-Dateien gelöscht." - -# @ wpduplicator -#: views/tools/cleanup.php:12 views/tools/diagnostics.php:44 -msgid "Legacy data removed." -msgstr "Daten entfernt." - -# @ wpduplicator -#: views/tools/cleanup.php:16 -msgid "Build cache removed." -msgstr "Cache-Dateien entfernt" - -# @ wpduplicator -#: views/tools/cleanup.php:73 -msgid "" -"If the installer files did not successfully get removed, then you WILL need " -"to remove them manually" -msgstr "" -"Wenn die Installationsdateien nicht vollständig erfolgreich entfernt wurden, " -"dann müssen sie manuell gelöscht werden" - -# @ wpduplicator -#: views/tools/cleanup.php:74 -msgid "" -"Please remove all installer files to avoid leaving open security issues on " -"your server" -msgstr "" -"Bitte entferne alle Installationsdateien aus Sicherheitsgründen von deinem " -"Server" - -# @ wpduplicator -#: views/tools/cleanup.php:82 -msgid "Data Cleanup" -msgstr "Daten gelöscht" - -# @ wpduplicator -#: views/tools/cleanup.php:85 -msgid "Delete Reserved Files" -msgstr "Lösche reservierte Dateien" - -# @ wpduplicator -#: views/tools/cleanup.php:86 -msgid "Removes all installer files from a previous install" -msgstr "Entferne alle Installations-Dateien der früheren Installation." - -# @ wpduplicator -#: views/tools/cleanup.php:89 -msgid "Delete Legacy Data" -msgstr "Lösche übernommene Daten" - -# @ wpduplicator -#: views/tools/cleanup.php:90 -msgid "Removes all legacy data and settings prior to version" -msgstr "Entfernt alle übernommenen Daten und Einstellungen vor Version" - -# @ wpduplicator -#: views/tools/cleanup.php:93 -msgid "Clear Build Cache" -msgstr "Cache löschen" - -# @ wpduplicator -#: views/tools/cleanup.php:94 -msgid "Removes all build data from:" -msgstr "Entferne alle Daten von:" - -# @ wpduplicator -#: views/tools/cleanup.php:107 -#, php-format -msgid "This action will remove all legacy settings prior to version %1$s. " -msgstr "" -"Diese Aktion wird alle alten Einstellungen vor Version %1$s entfernen. " - -# @ wpduplicator -#: views/tools/cleanup.php:108 -msgid "" -"Legacy settings are only needed if you plan to migrate back to an older " -"version of this plugin." -msgstr "" -"Frühere Einstellungen werden nur benötigt, wenn du zu einer älteren Version " -"des Plugins zurückgehst." - -# @ wpduplicator -#: views/tools/cleanup.php:120 -msgid "" -"This process will remove all build cache files. Be sure no packages are " -"currently building or else they will be cancelled." -msgstr "" -"Dieser Vorgang wird alle erstellten Cache-Dateien entfernen. Bitte stelle " -"sicher, dass derzeit keine neuen Cache-Dateien erstellt werden." - -# @ wpduplicator -#: views/tools/controller.php:16 -msgid "Logging" -msgstr "Logging" - -# @ wpduplicator -#: views/tools/controller.php:18 -msgid "Cleanup" -msgstr "Löschen" - -# @ wpduplicator -#: views/tools/diagnostics.php:18 views/tools/diagnostics.php:19 -msgid "unknow" -msgstr "unbekannt" - -# @ wpduplicator -#: views/tools/diagnostics.php:39 -msgid "Plugin settings reset." -msgstr "Plugin-Einstellungen zurücksetzen." - -# @ wpduplicator -#: views/tools/diagnostics.php:40 -msgid "View state settings reset." -msgstr "Statuseinstellungen zurücksetzen." - -# @ wpduplicator -#: views/tools/diagnostics.php:41 -msgid "Active package settings reset." -msgstr "Aktive Archiv-Einstellungen zurücksetzen." - -# @ wpduplicator -#: views/tools/diagnostics.php:81 -msgid "Server Settings" -msgstr "Server-Einstellungen" - -# @ wpduplicator -#: views/tools/diagnostics.php:90 -msgid "Duplicator Version" -msgstr "Duplicator-Version" - -# @ wpduplicator -#: views/tools/diagnostics.php:94 -msgid "Operating System" -msgstr "Betriebs-System" - -# @ wpduplicator -#: views/tools/diagnostics.php:98 -msgid "Timezone" -msgstr "Zeitzone" - -# @ wpduplicator -#: views/tools/diagnostics.php:102 -msgid "Server Time" -msgstr "Serverzeit" - -# @ wpduplicator -#: views/tools/diagnostics.php:110 -msgid "APC Enabled" -msgstr "APC Aktiviert" - -# @ wpduplicator -#: views/tools/diagnostics.php:114 -msgid "Root Path" -msgstr "Root-Pfad" - -# @ wpduplicator -#: views/tools/diagnostics.php:118 -msgid "ABSPATH" -msgstr "ABSPATH" - -# @ wpduplicator -#: views/tools/diagnostics.php:122 -msgid "Plugins Path" -msgstr "Plugin-Pfad" - -# @ wpduplicator -#: views/tools/diagnostics.php:126 -msgid "Loaded PHP INI" -msgstr "Geladene PHP-INI" - -# @ wpduplicator -#: views/tools/diagnostics.php:130 -msgid "Server IP" -msgstr "Server-IP" - -# @ wpduplicator -#: views/tools/diagnostics.php:134 -msgid "Client IP" -msgstr "Client-IP" - -# @ wpduplicator -#: views/tools/diagnostics.php:145 -msgid "Langugage" -msgstr "Sprache" - -# @ wpduplicator -#: views/tools/diagnostics.php:149 views/tools/diagnostics.php:204 -msgid "Charset" -msgstr "Zeichensatz" - -# @ wpduplicator -#: views/tools/diagnostics.php:153 -msgid "Memory Limit " -msgstr "Speicher-Limit " - -# @ wpduplicator -#: views/tools/diagnostics.php:154 -msgid "Max" -msgstr "Max" - -# @ wpduplicator -#: views/tools/diagnostics.php:172 -msgid "Safe Mode" -msgstr "Safe Mode" - -# @ wpduplicator -#: views/tools/diagnostics.php:176 -msgid "On" -msgstr "An" - -# @ wpduplicator -#: views/tools/diagnostics.php:176 -msgid "Off" -msgstr "Aus" - -# @ wpduplicator -#: views/tools/diagnostics.php:181 -msgid "Memory Limit" -msgstr "Speicher-Limit" - -# @ wpduplicator -#: views/tools/diagnostics.php:185 -msgid "Memory In Use" -msgstr "Verwendeter Arbeitsspeicher" - -# @ wpduplicator -#: views/tools/diagnostics.php:193 -msgid "Shell Exec" -msgstr "Shell Exec" - -# @ wpduplicator -#: views/tools/diagnostics.php:194 -msgid "Is Supported" -msgstr "Wird unterstützt" - -# @ wpduplicator -#: views/tools/diagnostics.php:194 -msgid "Not Supported" -msgstr "Nicht unterstützt" - -# @ wpduplicator -#: views/tools/diagnostics.php:208 -msgid "Wait Timeout" -msgstr "Wartezeitsperre" - -# @ wpduplicator -#: views/tools/diagnostics.php:212 -msgid "Max Allowed Packets" -msgstr "Maximal erlaubte Pakete" - -# @ wpduplicator -#: views/tools/diagnostics.php:216 -msgid "msyqldump Path" -msgstr "msyqldump Pfad" - -# @ wpduplicator -#: views/tools/diagnostics.php:220 -msgid "Server Disk" -msgstr "Server-Festplatte" - -# @ hyper-cache -#: views/tools/diagnostics.php:223 -msgid "Free space" -msgstr "Freier Speicherplatz" - -# @ wpduplicator -#: views/tools/diagnostics.php:226 -msgid "Note: This value is the physical servers hard-drive allocation." -msgstr "Hinweis: Dieser Wert ist die physische Server-Festplatte-Verteilung." - -# @ wpduplicator -#: views/tools/diagnostics.php:227 -msgid "" -"On shared hosts check your control panel for the 'TRUE' disk space quota " -"value." -msgstr "" -"Überprüfe auf freigegebenen Hosts deines Control Panels für den 'TRUE' Disk " -"Space Quote Wert." - -# @ wpduplicator -#: views/tools/diagnostics.php:243 -msgid "Stored Data" -msgstr "Gespeicherte Daten" - -# @ wpduplicator -#: views/tools/diagnostics.php:248 -msgid "Options Values" -msgstr "Options Werte" - -# @ wpduplicator -#: views/tools/diagnostics.php:281 -msgid "PHP Information" -msgstr "PHP-Information" - -# @ wpduplicator -#: views/tools/diagnostics.php:300 -msgid "Delete this option value" -msgstr "Lösche den optionalen Wert" - -# @ wpduplicator -#: views/tools/logging.php:140 -msgid "Log file not found or unreadable" -msgstr "Log-Datei nicht gefunden oder nicht lesbar" - -# @ wpduplicator -#: views/tools/logging.php:142 -msgid "" -"Try to create a package, since no log files were found in the snapshots " -"directory with the extension *.log" -msgstr "" -"Versuche ein Archiv zu erstellen, da keine Log-Dateien im Snapshots-" -"Verzeichnis mit der Endung *. Log gefunden wurden" - -# @ wpduplicator -#: views/tools/logging.php:144 -msgid "Reasons for log file not showing" -msgstr "Die Gründe für die Log-Datei werden nicht angezeigt" - -# @ wpduplicator -#: views/tools/logging.php:145 -msgid "The web server does not support returning .log file extentions" -msgstr "Der Webserver unterstützt keine .log-Datei-Erweiterungen" - -# @ wpduplicator -#: views/tools/logging.php:146 -msgid "" -"The snapshots directory does not have the correct permissions to write " -"files. Try setting the permissions to 755" -msgstr "" -"In das Verzeichnis wp-snapshots kann nicht geschrieben werden. Bitte setze " -"die Berechtigung auf 755" - -# @ wpduplicator -#: views/tools/logging.php:147 -msgid "" -"The process that PHP runs under does not have enough permissions to create " -"files. Please contact your hosting provider for more details" -msgstr "" -"Der Prozess hat nicht genügend Berechtigungen, um Dateien zu erstellen. " -"Bitte kontaktiere deinen Hosting-Provider für weitere Informationen" - -# @ wpduplicator -#: views/tools/logging.php:156 views/tools/logging.php:161 -msgid "Options" -msgstr "Optionen" - -# @ wpduplicator -#: views/tools/logging.php:163 -msgid "Refresh" -msgstr "Neu laden" - -# @ wpduplicator -#: views/tools/logging.php:168 -msgid "Auto Refresh" -msgstr "Automatisch neu laden" - -# @ wpduplicator -#: views/tools/logging.php:174 -msgid "Last 20 Logs" -msgstr "Letzte 20 Logs" - -#. Plugin Name of the plugin/theme -msgid "Duplicator" -msgstr "Duplicator" - -#. Plugin URI of the plugin/theme -msgid "http://www.lifeinthegrid.com/duplicator/" -msgstr "http://www.lifeinthegrid.com/duplicator/" - -#. Description of the plugin/theme -msgid "" -"Create a backup of your WordPress files and database. Duplicate and move an " -"entire site from one location to another in a few steps. Create a full " -"snapshot of your site at any point in time." -msgstr "" -"Erstelle eine Sicherungskopie Deiner WordPress-Dateien und der Datenbank. " -"Dupliziere und verschiebe in nur wenigen Schritten eine komplette Webseite " -"von einem Ort an einen Anderen. Erstelle einen vollständigen Snapshot Deiner " -"Webseite zu jedem beliebigen Zeitpunkt." - -#. Author of the plugin/theme -msgid "LifeInTheGrid" -msgstr "LifeInTheGrid" - -#. Author URI of the plugin/theme -msgid "http://www.lifeinthegrid.com" -msgstr "http://www.lifeinthegrid.com" - -# @ wpduplicator -#~ msgid "Invalid Names" -#~ msgstr "Ungültige Namen" - -# @ wpduplicator -#~ msgid "" -#~ "Invalid file or folder names can cause issues when extracting an archive " -#~ "across different environments. Invalid file names consist of lengths " -#~ "over 250 characters and illegal characters that may not work on all " -#~ "operating systems such as * ? > < : / \\ | . It is recommended to " -#~ "remove or filter these files before building the archive or else you " -#~ "might have issues at install time." -#~ msgstr "" -#~ "Ungültige Datei-oder Ordnernamen können bei einigen Umgebungen zu " -#~ "Problemen führen. Ungültige Dateinamen bestehen aus Längen über 250 " -#~ "Zeichen und illegalen Zeichen, die nicht auf allen Betriebssystemen wie " -#~ "* ? > < : / \\ | arbeiten können. Es wird empfohlen, diese Dateien vor " -#~ "dem Erstellen des Archivs zu entfernen oder durch Filtereinstellungen " -#~ "auszublenden." - -# @ wpduplicator -#~ msgid "No name length issues." -#~ msgstr "Keine lange oder ungültige Namen." - -# @ wpduplicator -#~ msgid "PHP Settings" -#~ msgstr "PHP-Einstellungen" - -# @ wpduplicator -#~ msgid "" -#~ "The Duplicator may have issues when [open_basedir] is enabled. Please " -#~ "work with your server administrator to disable this value in the php.ini " -#~ "file if you’re having issues building a package." -#~ msgstr "" -#~ "Der Duplicator kann Probleme haben, wenn [open_basedir] aktiviert ist. " -#~ "Bitte frage den Server-Administrator, ob dieser Wert in der php.ini-Datei " -#~ "deaktiviert werden kann." - -# @ wpduplicator -#~ msgid "" -#~ "The Duplicator will have issues when the [max_execution_time] value in " -#~ "the php.ini is low. Timeouts effect how long a process is allowed to " -#~ "run. The recommended timeout is \"%1$s\" seconds. An attempt is made to " -#~ "override this value if the server allows it. Please work with your " -#~ "server administrator to make sure there are no restrictions for how long " -#~ "a PHP process is allowed to run." -#~ msgstr "" -#~ "Der Duplicator wird Probleme haben, wenn der Wert [max_execution_time] in " -#~ "der php.ini ist gering. Der Timeout-Wert gibt an, wie lange ein Prozess " -#~ "ausgeführt werden darf. Die empfohlene Timeout ist \"%1$s\" Sekunden. Es " -#~ "wird versucht, diesen Wert zu überschreiben, wenn es der Server erlaubt. " -#~ "Bitte frage den Server-Administrator nach den Einschränkungen für den PHP-" -#~ "Prozess." - -# @ wpduplicator -#~ msgid "The Duplicator currently works with these web servers:" -#~ msgstr "Der Duplicator arbeitet derzeit mit diesen Web-Servern:" - -# @ wpduplicator -#~ msgid "WordPress Settings" -#~ msgstr "WordPress-Einstellungen" - -# @ wpduplicator -#~ msgid "" -#~ "It is recommended to have a version of WordPress that is greater that " -#~ msgstr "Es wird empfohlen, eine höhere Version von Wordpress zu nutzen: " - -# @ wpduplicator -#~ msgid "Found" -#~ msgstr "Gefunden" - -# @ wpduplicator -#~ msgid "Missing" -#~ msgstr "Vermisst" - -# @ wpduplicator -#~ msgid "" -#~ "Cached data will lead to issues at install time and increases your " -#~ "archive size. It is recommended to empty your cache directory at build " -#~ "time. Use caution when removing data from the cache directory. If you " -#~ "have a cache plugin review the documentation for how to empty it; simply " -#~ "removing files might cause errors on your site." -#~ msgstr "" -#~ "Cache-Daten werden zu Probleme bei der Installation führen und erhöhen " -#~ "die Archivgröße. Es wird empfohlen, das Cache-Verzeichnis bei der " -#~ "Erstellung zu leeren. Vorsicht beim Entfernen von Daten aus dem Cache-" -#~ "Verzeichnis. Beachte die Dokumentation des Cache-Plugins zum entleeren. " -#~ "Das einfache Entfernen von Dateien kann möglicherweise zu Fehlern auf der " -#~ "Website führen. " - -# @ wpduplicator -#~ msgid "The cache size minimum threshold is currently set at " -#~ msgstr "Die minimale Cache-Schwelle ist derzeit festgelegt auf " - -# @ wpduplicator -#~ msgid "" -#~ "Below is a list of the directories and file extension that will be " -#~ "excluded from the archive." -#~ msgstr "" -#~ "Unten ist eine Liste der Verzeichnisse und Dateierweiterung, die aus dem " -#~ "Archiv ausgeschlossen werden." diff --git a/lang/wpduplicator-fa_IR.mo b/lang/wpduplicator-fa_IR.mo deleted file mode 100644 index 31d89aff..00000000 Binary files a/lang/wpduplicator-fa_IR.mo and /dev/null differ diff --git a/lang/wpduplicator-fa_IR.po b/lang/wpduplicator-fa_IR.po deleted file mode 100644 index f2ea7a91..00000000 --- a/lang/wpduplicator-fa_IR.po +++ /dev/null @@ -1,1808 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: WPDuplicator v0.5.23\n" -"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/duplicator\n" -"POT-Creation-Date: 2015-07-26 23:54+0200\n" -"PO-Revision-Date: 2015-07-26 23:54+0200\n" -"Last-Translator: Ralf Koller \n" -"Language-Team: Amoozesh98.com \n" -"Language: fa_IR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.2\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" -"X-Poedit-Basepath: ..\n" -"X-Poedit-WPHeader: duplicator.php\n" -"X-Textdomain-Support: yes\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPathExcluded-0: assets\n" - -#: classes/ui.php:111 -msgid "" -"Reserved Duplicator install file(s) still exists in the root directory. " -"Please delete these file(s) to avoid possible security issues." -msgstr "" - -#: classes/ui.php:112 -msgid "Remove file(s) now" -msgstr "پاک کردن پرونده" - -#: classes/ui.php:113 -msgid "Dismiss this notice" -msgstr "نمایش ندادن این پیام" - -#: classes/utility.php:249 -msgid "You do not have sufficient permissions to access this page." -msgstr "" - -#: duplicator.php:102 -msgid "Get Help" -msgstr "رفتن به راهنما" - -#: duplicator.php:102 duplicator.php:191 views/help/help.php:29 -msgid "Help" -msgstr "راهنما" - -#: duplicator.php:103 -msgid "Support the Plugin" -msgstr "پشتیبان افزونه" - -#: duplicator.php:103 duplicator.php:195 views/help/about.php:41 -msgid "About" -msgstr "درباره" - -#: duplicator.php:179 views/packages/controller.php:76 -#: views/packages/list.base.php:235 -msgid "Packages" -msgstr "بسته های نصبی" - -#: duplicator.php:183 views/settings/controller.php:19 -msgid "Settings" -msgstr "تنظیمات" - -#: duplicator.php:187 views/tools/controller.php:13 -msgid "Tools" -msgstr "ابزارها" - -#: duplicator.php:246 -msgid "Manage" -msgstr "مدیریت" - -#: views/help/about.php:54 -msgid "" -"Created for Admins, Developers and Designers the Duplicator can streamline " -"your workflows and help you quickly clone a WordPress application. " -"Migrating a WordPress site manually can be very time consuming. The " -"Duplicator was made to help you speed up the migration process. Please help " -"us to continue the development effort of this plugin." -msgstr "" -"برای مدیران و توسعه دهندگان و طراحان ایجاد تکثیر گردش کار و کمک شما به سرعت " -"کلون برنامه وردپرس ساده می تواند. انتقال سایت وردپرس به صورت دستی می تواند " -"بسیار وقت گیر است. تکثیر شده است برای کمک به شما سرعت بخشیدن به فرایند " -"انتقال. لطفا کمک به ما برای ادامه تلاش توسعه این پلاگین." - -#: views/help/about.php:64 -msgid "Support Duplicator" -msgstr "پشتیبان ایجاد کننده بسته نصبی" - -#: views/help/about.php:71 -msgid "Partner with Us" -msgstr "همکاری با ما" - -#: views/help/about.php:83 -msgid "Keep Active and Online" -msgstr "نگه دارید فعال و آنلاین" - -#: views/help/about.php:90 -msgid "Leave 5 Stars" -msgstr "" - -#: views/help/about.php:107 -msgid "Spread the Word" -msgstr "ارتقا دهید (لطفا!)" - -#: views/help/about.php:113 -msgid "Duplicate Your WordPress" -msgstr "تولید بسته آسان نصبی وردپرس" - -#: views/help/about.php:114 -msgid "Rapid WordPress Duplication by LifeInTheGrid.com" -msgstr "" - -#: views/help/about.php:131 -msgid "Get More Great Tools" -msgstr "دریافت ابزارهای بیشتر" - -#: views/help/gopro.php:37 -msgid "Go Pro!" -msgstr "نسخه تجاری!" - -#: views/help/gopro.php:46 -msgid "Duplicator Pro Has Arrived!" -msgstr "" - -#: views/help/gopro.php:49 -msgid "The simplicity of Duplicator" -msgstr "" - -#: views/help/gopro.php:50 -msgid "with the power the professional requires." -msgstr "" - -#: views/help/gopro.php:57 -msgid "Duplicator Free" -msgstr "ایجاد کننده بسته نصبی رایگان" - -#: views/help/gopro.php:60 views/help/gopro.php:88 -msgid "Backup Files & Database" -msgstr "فایل های پشتیبان و پایگاه داده" - -#: views/help/gopro.php:61 views/help/gopro.php:89 -msgid "" -"Compresses all your WordPress files and database into a compressed snapshot " -"archive file." -msgstr "" - -#: views/help/gopro.php:64 views/help/gopro.php:92 -msgid "Directory Filters" -msgstr "فیلتر های پوشه" - -#: views/help/gopro.php:65 views/help/gopro.php:93 -msgid "" -"Filter out the directories and file extensions you want to include/exclude " -"in your in your archive file." -msgstr "" - -#: views/help/gopro.php:68 views/help/gopro.php:96 -msgid "Database Table Filters" -msgstr "فعال کردن فیلتر های جدول" - -#: views/help/gopro.php:69 views/help/gopro.php:97 -msgid "" -"Filter out only the database tables you want to include/exclude in your " -"database creation script." -msgstr "" - -#: views/help/gopro.php:72 views/help/gopro.php:100 -msgid "Migration Wizard" -msgstr "برنامه جادویی انتقال" - -#: views/help/gopro.php:73 views/help/gopro.php:101 -msgid "" -"With just two files (archive & installer.php) move your site to a new " -"location." -msgstr "" - -#: views/help/gopro.php:85 views/packages/new1.inc.form.php:50 -msgid "Duplicator Pro" -msgstr "ایجاد کننده بسته نصبی تجاری یا همان پولی" - -#: views/help/gopro.php:104 -msgid "Scheduled Backups" -msgstr "" - -#: views/help/gopro.php:105 -msgid "" -"Automate the creation of your packages to run at various scheduled intervals." -msgstr "" - -#: views/help/gopro.php:108 -msgid "Dropbox Support" -msgstr "" - -#: views/help/gopro.php:109 -msgid "Backup up your entire site to Dropbox." -msgstr "" - -#: views/help/gopro.php:112 -msgid "FTP Support" -msgstr "" - -#: views/help/gopro.php:113 -msgid "Backup up your entire site to an FTP server." -msgstr "" - -#: views/help/gopro.php:116 -msgid "Customer Support" -msgstr "پشتیبانی 24 ساعته" - -#: views/help/gopro.php:117 -msgid "" -"Server setups can be quite complex, with pro you get prompt help to get your " -"site backed up and moved." -msgstr "" - -#: views/help/gopro.php:124 -msgid "Check It Out!" -msgstr "بررسی" - -#: views/help/help.php:38 -msgid "" -"Migrating WordPress is a complex process and the logic to make all the magic " -"happen smoothly may not work quickly with every site. With over 30,000 " -"plugins and a very complex server eco-system some migrations may run into " -"issues. This is why the Duplicator includes a detailed knowledgebase that " -"can help with many common issues. Resources to additional support, approved " -"hosting, and alternatives to fit your needs can be found below." -msgstr "" -"مهاجرت وردپرس، یک فرآیند پیچیده و منطق را به همه سحر و جادو اتفاق می افتد " -"هموار ممکن است به سرعت با هر سایت کار نمی کند. با بیش از 30000 پلاگین ها و " -"سرور اکو سیستم بسیار پیچیده برخی از مهاجرت ممکن است به مسائل اجرا شود. به " -"همین دلیل است نسخه برداری شامل یک مرکز آموزش دقیق است که می تواند با بسیاری " -"از مسائل مشترک کمک کند. منابع برای حمایت از اضافی، میزبانی تایید، و جایگزین " -"های مناسب نیازهای شما می تواند زیر آمده است." - -#: views/help/help.php:50 -msgid "Knowledgebase" -msgstr "مرکز آموزش" - -#: views/help/help.php:53 -msgid "Complete Online Documentation" -msgstr "مستندات کامل آنلاین" - -#: views/help/help.php:55 -msgid "Choose A Section" -msgstr "یک بخش را انتخاب کنید" - -#: views/help/help.php:56 -msgid "Quick Start" -msgstr "شروع سریع" - -#: views/help/help.php:57 -msgid "User Guide" -msgstr "راهنمای کاربر" - -#: views/help/help.php:58 -msgid "FAQs" -msgstr "پرسش و پاسخ" - -#: views/help/help.php:59 -msgid "Change Log" -msgstr "تغییر گزارشات" - -#: views/help/help.php:60 -msgid "Product Page" -msgstr "صفحه محصولات" - -#: views/help/help.php:69 -msgid "Online Support" -msgstr "پشتیبانی آنلاین" - -#: views/help/help.php:72 -msgid "Get Help From IT Professionals" -msgstr "کمک گرفتن از حرفه ای های IT" - -#: views/help/help.php:76 -msgid "Get Support!" -msgstr "گرفتن پشتیبانی" - -#: views/help/help.php:88 -msgid "Approved Hosting" -msgstr "هاستینگ های تایید شده" - -#: views/help/help.php:91 -msgid "Servers That Work With Duplicator" -msgstr "سرور های هاستینگی که از افزونه ایجاد کننده بسته نصبی پشتیبانی می کنند" - -#: views/help/help.php:94 -msgid "Trusted Providers!" -msgstr "ارائه دهندگان خدمات قابل اعتماد!" - -#: views/help/help.php:104 -msgid "Alternatives" -msgstr "جایگزین" - -#: views/help/help.php:107 -msgid "Other Commercial Resources" -msgstr "سایر منابع تجاری" - -#: views/help/help.php:110 -msgid "Pro Solutions!" -msgstr "راه حل های حرفه ای!" - -#: views/packages/list-nodata.php:7 -msgid "No Packages Found." -msgstr "هیچ بسته آسان نصبی وجود ندارد." - -#: views/packages/list-nodata.php:8 -msgid "Click the 'Create New' button to build a package." -msgstr "" -"برای ایجاد بسته آسان نصبی از دکمه بالای صفحه یعنی ( ایجاد بسته آسان نصبی " -"جدید ) استفاده نمایید." - -#: views/packages/list-nodata.php:13 -msgid "Please visit the" -msgstr "در صورت نیاز لطفا از " - -#: views/packages/list-nodata.php:14 views/packages/list-nodata.php:28 -#: views/packages/new1.base.php:234 -msgid "help page" -msgstr "صفحه راهنما" - -#: views/packages/list-nodata.php:15 -msgid "for additional support" -msgstr "" -"برای پیشتیبانی بیشتر استفاده کنید.

                    برای رفتن به صفحه راهنما از منو های " -"داخل افزونه کپی کننده به گزینه راهنما مراجعه نمایید!

                    " - -#: views/packages/list-nodata.php:24 -msgid "Older packages prior to 0.5.0 are no longer supported in this version." -msgstr "" - -#: views/packages/list-nodata.php:27 -msgid "To get an older package please visit the" -msgstr "" - -#: views/packages/list-nodata.php:29 -msgid "and look for the Change Log link for additional instructions." -msgstr "" - -#: views/packages/list-nodata.php:33 -msgid "Hide this message" -msgstr "این پیغام را ببند" - -#: views/packages/list.base.php:39 -msgid "Help Support Duplicator" -msgstr "پشتیبان ایجاد کننده بسته نصبی" - -#: views/packages/list.base.php:50 -msgid "Bulk Actions" -msgstr "انجام عملیات کلی" - -#: views/packages/list.base.php:51 -msgid "Delete selected package(s)" -msgstr "حذف بسته های نصبی انتخاب شده(s)" - -#: views/packages/list.base.php:51 -msgid "Delete" -msgstr "حذف" - -#: views/packages/list.base.php:53 -msgid "Apply" -msgstr "اعمال" - -#: views/packages/list.base.php:58 -msgid "Package Logs" -msgstr "گزارش بسته نصبی" - -#: views/packages/list.base.php:61 views/packages/new1.base.php:96 -#: views/packages/new2.base.php:69 views/packages/new3.base.php:43 -#: views/packages/new3.base.php:89 -msgid "All Packages" -msgstr "تمام بسته های نصبی" - -#: views/packages/list.base.php:62 views/packages/new1.base.php:97 -#: views/packages/new2.base.php:70 views/packages/new3.base.php:44 -msgid "Create New" -msgstr "ایجاد بسته نصبی جدید" - -#: views/packages/list.base.php:87 -msgid "Select all packages" -msgstr "انتخاب همه بسته" - -#: views/packages/list.base.php:88 views/packages/new3.base.php:108 -msgid "Details" -msgstr "جزئیات" - -#: views/packages/list.base.php:89 -msgid "Created" -msgstr "زمان ایجاد" - -#: views/packages/list.base.php:90 views/packages/new2.base.php:222 -#: views/packages/new2.base.php:334 -msgid "Size" -msgstr "حجم" - -#: views/packages/list.base.php:91 views/packages/new1.inc.form.php:6 -#: views/packages/new1.inc.form.php:31 views/packages/new3.base.php:74 -msgid "Name" -msgstr "نام بسته " - -#: views/packages/list.base.php:93 views/settings/general.php:110 -msgid "Package" -msgstr "بسته" - -#: views/packages/list.base.php:124 -msgid "(No Notes Taken)" -msgstr "(بدون یادداشت ها گرفته شده)" - -#: views/packages/list.base.php:142 views/packages/list.base.php:187 -msgid "View" -msgstr "مشاهده شده" - -#: views/packages/list.base.php:147 views/packages/new1.inc.form.php:176 -#: views/packages/new3.base.php:79 -msgid "Installer" -msgstr "نصب کننده" - -#: views/packages/list.base.php:150 views/packages/new1.inc.form.php:65 -#: views/packages/new2.base.php:195 views/packages/new3.base.php:83 -msgid "Archive" -msgstr "آرشیو بسته نصبی" - -#: views/packages/list.base.php:155 views/packages/list.base.php:200 -#: views/settings/general.php:79 views/tools/diagnostics.php:141 -#: views/tools/diagnostics.php:160 views/tools/diagnostics.php:200 -msgid "Version" -msgstr "نسخه" - -#: views/packages/list.base.php:156 views/packages/list.base.php:201 -#: views/packages/new1.inc.form.php:199 views/tools/diagnostics.php:168 -msgid "User" -msgstr "کاربر دیتابیس" - -#: views/packages/list.base.php:157 views/packages/list.base.php:202 -msgid "Hash" -msgstr "Hash" - -#: views/packages/list.base.php:158 views/packages/list.base.php:207 -#: views/packages/new1.inc.form.php:8 views/packages/new1.inc.form.php:13 -msgid "Notes" -msgstr "توضیحات" - -#: views/packages/list.base.php:160 -msgid "Links" -msgstr "لینک‌ها" - -#: views/packages/list.base.php:161 -msgid "SQL" -msgstr "اس‌کیوال" - -#: views/packages/list.base.php:162 -msgid "Log" -msgstr "گزارش" - -#: views/packages/list.base.php:165 -msgid "Open Scan Report" -msgstr "گزارش اسکن باز" - -#: views/packages/list.base.php:166 -msgid "View Package Object" -msgstr "مشاهده بسته شی" - -#: views/packages/list.base.php:193 -msgid "View Error Details" -msgstr "مشاهده جزئیات خطا" - -#: views/packages/list.base.php:205 -msgid "Unrecoverable Error! Please remove this package." -msgstr "" - -#: views/packages/list.base.php:210 -msgid "" -"This package has encountered errors. Click 'View Log' for more details. " -"For additional support see the " -msgstr "" - -#: views/packages/list.base.php:211 -msgid "online knowledgebase" -msgstr "" - -#: views/packages/list.base.php:213 -msgid "View Log" -msgstr "نمایش گزارش" - -#: views/packages/list.base.php:236 views/packages/new2.base.php:219 -#: views/packages/new2.base.php:328 -msgid "Total Size" -msgstr "اندازه کل" - -#: views/packages/list.base.php:255 -msgid "Download Links" -msgstr "لینک دانلود" - -#: views/packages/list.base.php:258 -msgid "The following links contain sensitive data. Please share with caution!" -msgstr "" - -#: views/packages/list.base.php:264 -msgid "" -"The database SQL script is a quick link to your database backup script. An " -"exact copy is also stored in the package." -msgstr "" - -#: views/packages/list.base.php:287 -msgid "" -"Please select an action from the bulk action drop down menu to perform a " -"specific action." -msgstr "" - -#: views/packages/list.base.php:295 -msgid "Please select at least one package to delete." -msgstr "" - -#: views/packages/list.base.php:299 -msgid "Are you sure, you want to delete the selected package(s)?" -msgstr "آیا مطمئنید که مایلید package(s) منتخب را حذف کنید؟" - -#: views/packages/list.base.php:333 -msgid "Package File Links" -msgstr "لینک فایل های بسته" - -#: views/packages/list.base.php:336 -msgid "DATABASE" -msgstr "پایگاه داده" - -#: views/packages/list.base.php:337 -msgid "PACKAGE" -msgstr "بسته" - -#: views/packages/list.base.php:338 -msgid "INSTALLER" -msgstr "نصب کننده" - -#: views/packages/list.base.php:339 -msgid "LOG" -msgstr "گزارش" - -#: views/packages/list.base.php:340 -msgid "REPORT" -msgstr "گزارش" - -#: views/packages/new1.base.php:13 -msgid "Package settings have been reset." -msgstr "" - -#: views/packages/new1.base.php:86 views/packages/new2.base.php:59 -#: views/packages/new3.base.php:33 -msgid "Setup" -msgstr "نصب" - -#: views/packages/new1.base.php:87 views/packages/new2.base.php:60 -#: views/packages/new3.base.php:34 -msgid "Scan" -msgstr "آنالیز ( اسکن )" - -#: views/packages/new1.base.php:88 views/packages/new2.base.php:61 -#: views/packages/new2.base.php:388 views/packages/new3.base.php:35 -msgid "Build" -msgstr "ایجاد بسته" - -#: views/packages/new1.base.php:91 -msgid "Step 1: Package Setup" -msgstr "بخش 1 : تنظیمات بسته " - -#: views/packages/new1.base.php:115 -msgid "Requirements:" -msgstr "موارد مورد نیاز:" - -#: views/packages/new1.base.php:124 -msgid "" -"System requirements must pass for the Duplicator to work properly. Click " -"each link for details." -msgstr "" - -#: views/packages/new1.base.php:130 -msgid "PHP Support" -msgstr "پشتیبان پی اچ پی" - -#: views/packages/new1.base.php:136 -msgid "PHP Version" -msgstr "نسخه پی اچ پی" - -#: views/packages/new1.base.php:140 -msgid "Zip Archive Enabled" -msgstr "" - -#: views/packages/new1.base.php:144 -msgid "Safe Mode Off" -msgstr "" - -#: views/packages/new1.base.php:148 views/packages/new1.base.php:152 -#: views/packages/new1.base.php:156 -msgid "Function" -msgstr "تابع" - -#: views/packages/new1.base.php:161 -msgid "" -"PHP versions 5.2.17+ or higher is required. Please note that in versioning " -"logic a value such as 5.2.9 is less than 5.2.17. For compression to work the " -"ZipArchive extension for PHP is required. Safe Mode should be set to 'Off' " -"in you php.ini file and is deprecated as of PHP 5.3.0. For any issues in " -"this section please contact your hosting provider or server administrator. " -"For additional information see our online documentation." -msgstr "" - -#: views/packages/new1.base.php:169 -msgid "Permissions" -msgstr "دسترسی‌ها" - -#: views/packages/new1.base.php:172 -msgid "Required Paths" -msgstr "مسیرهای مورد نیاز" - -#: views/packages/new1.base.php:183 -msgid "" -"Permissions can be difficult to resolve on some systems. If the plugin can " -"not read the above paths here are a few things to try. 1) Set the above " -"paths to have permissions of 755 for directories and 644 for files. You can " -"temporarily try 777 however, be sure you don’t leave them this way. 2) Check " -"the owner/group settings for both files and directories. The PHP script " -"owner and the process owner are different. The script owner owns the PHP " -"script but the process owner is the user the script is running as, thus " -"determining its capabilities/privileges in the file system. For more details " -"contact your host or server administrator or visit the 'Help' menu under " -"Duplicator for additional online resources." -msgstr "" - -#: views/packages/new1.base.php:191 -msgid "Server Support" -msgstr "پشتیبانی سرور" - -#: views/packages/new1.base.php:197 -msgid "MySQL Version" -msgstr "نسخه MySQL" - -#: views/packages/new1.base.php:201 -msgid "MySQLi Support" -msgstr "پشتیبانی از MySQLi" - -#: views/packages/new1.base.php:207 -msgid "" -"MySQL version 5.0+ or better is required and the PHP MySQLi extension (note " -"the trailing 'i') is also required. Contact your server administrator and " -"request that mysqli extension and MySQL Server 5.0+ be installed. Please " -"note in future versions support for other databases and extensions will be " -"added." -msgstr "" - -#: views/packages/new1.base.php:208 -msgid "more info" -msgstr "اطلاعات بیشتر" - -#: views/packages/new1.base.php:217 -msgid "Reserved Files" -msgstr "فایل محافظت شده" - -#: views/packages/new1.base.php:221 -msgid "" -"None of the reserved files (installer.php, installer-data.sql and installer-" -"log.txt) where found from a previous install. This means you are clear to " -"create a new package." -msgstr "" - -#: views/packages/new1.base.php:224 -msgid "" -"A reserved file(s) was found in the WordPress root directory. Reserved file " -"names are installer.php, installer-data.sql and installer-log.txt. To " -"archive your data correctly please remove any of these files from your " -"WordPress root directory. Then try creating your package again." -msgstr "" - -#: views/packages/new1.base.php:225 -msgid "Remove Files Now" -msgstr "حذف فایل های حال حاضر" - -#: views/packages/new1.base.php:234 -msgid "For additional help please see the " -msgstr "" - -#: views/packages/new1.inc.form.php:10 -msgid "Create a new default name" -msgstr "ایجاد یک نام پیشفرض" - -#: views/packages/new1.inc.form.php:23 views/settings/general.php:94 -msgid "Storage" -msgstr "ذخیره سازی" - -#: views/packages/new1.inc.form.php:32 -msgid "Type" -msgstr "" - -#: views/packages/new1.inc.form.php:33 -msgid "Location" -msgstr "" - -#: views/packages/new1.inc.form.php:38 -msgid "Default" -msgstr "" - -#: views/packages/new1.inc.form.php:39 -msgid "Local" -msgstr "" - -#: views/packages/new1.inc.form.php:45 -msgid "" -"All packages including the archive, installer and SQL script are stored in " -"the location above. " -msgstr "" - -#: views/packages/new1.inc.form.php:48 -msgid "Dropbox, FTP and other multiple storage options available in " -msgstr "" - -#: views/packages/new1.inc.form.php:67 -msgid "File filter enabled" -msgstr "" - -#: views/packages/new1.inc.form.php:68 -msgid "Database filter enabled" -msgstr "بانک اطلاعات فیلتر فعال" - -#: views/packages/new1.inc.form.php:77 views/packages/new2.base.php:203 -msgid "Files" -msgstr "فایل ها" - -#: views/packages/new1.inc.form.php:78 views/packages/new1.inc.form.php:195 -#: views/packages/new2.base.php:312 -msgid "Database" -msgstr "پایگاه داده" - -#: views/packages/new1.inc.form.php:90 -msgid "Enable File Filters" -msgstr "فعال کردن فیلتر های پرونده" - -#: views/packages/new1.inc.form.php:94 views/packages/new1.inc.form.php:102 -msgid "Separate all filters by semicolon" -msgstr "" - -#: views/packages/new1.inc.form.php:94 views/packages/new2.base.php:278 -msgid "Directories" -msgstr "پوشه ها" - -#: views/packages/new1.inc.form.php:96 -msgid "root path" -msgstr "مسیر ریشه" - -#: views/packages/new1.inc.form.php:97 -msgid "wp-uploads" -msgstr "" - -#: views/packages/new1.inc.form.php:98 -msgid "cache" -msgstr "کش" - -#: views/packages/new1.inc.form.php:99 views/packages/new1.inc.form.php:106 -msgid "(clear)" -msgstr "" - -#: views/packages/new1.inc.form.php:102 -msgid "File extensions" -msgstr "پسوند فایل ها" - -#: views/packages/new1.inc.form.php:104 -msgid "media" -msgstr "فیلم یا آهنگ" - -#: views/packages/new1.inc.form.php:105 -msgid "archive" -msgstr "بسته فشرده" - -#: views/packages/new1.inc.form.php:111 -msgid "" -"The directory paths and extensions above will be be excluded from the " -"archive file if enabled is checked." -msgstr "" -"مسیر دایرکتوری و پسوند بالا خواهد شد می شود محروم از آرشیو فایل اگر فعال " -"بررسی می شود." - -#: views/packages/new1.inc.form.php:112 -msgid "Use the full path for directories and semicolons to separate all items." -msgstr "مسیر کامل دایرکتوری و ویرگول برای جدا کردن همه موارد استفاده کنید." - -#: views/packages/new1.inc.form.php:123 -msgid "Enable Table Filters" -msgstr "فعال کردن فیلتر های جدول" - -#: views/packages/new1.inc.form.php:124 -msgid "checked tables are excluded" -msgstr "انتخاب جداول محروم شده" - -#: views/packages/new1.inc.form.php:129 -msgid "Include All" -msgstr "حذف همه" - -#: views/packages/new1.inc.form.php:130 -msgid "Exclude All" -msgstr "انتخاب همه" - -#: views/packages/new1.inc.form.php:163 -msgid "" -"Checked tables will not be added to the database script. Excluding certain " -"tables can possibly cause your site or plugins to not work correctly after " -"install!" -msgstr "" -"بررسی جداول به اسکریپت بانک اطلاعاتی اضافه خواهد شد. جداول خاصی به جز " -"احتمالا سایت یا افزونه هنوز کار درست پس از نصب می تواند باعث شود!" - -#: views/packages/new1.inc.form.php:181 -msgid "STEP 1 - INPUTS" -msgstr "بخش 1 - ورودی ها" - -#: views/packages/new1.inc.form.php:184 -msgid "MySQL Server" -msgstr "سرور مای اسکیوال" - -#: views/packages/new1.inc.form.php:187 -msgid "Host" -msgstr "میزبان" - -#: views/packages/new1.inc.form.php:191 -msgid "Host Port" -msgstr "" - -#: views/packages/new1.inc.form.php:203 -msgid "Advanced Options" -msgstr "تنظیمات بیشتر" - -#: views/packages/new1.inc.form.php:209 -msgid "SSL" -msgstr "گواهینامه SSL" - -#: views/packages/new1.inc.form.php:212 -msgid "Enforce on Admin" -msgstr "اجرا توسط مدیر" - -#: views/packages/new1.inc.form.php:216 -msgid "Enforce on Logins" -msgstr "اجرا بعد از ورود" - -#: views/packages/new1.inc.form.php:220 -msgid "Cache" -msgstr "کش" - -#: views/packages/new1.inc.form.php:223 -msgid "Keep Enabled" -msgstr "فعال نگه داشتن" - -#: views/packages/new1.inc.form.php:227 -msgid "Keep Home Path" -msgstr "نگه داشتن مسیر خانه" - -#: views/packages/new1.inc.form.php:235 -msgid "STEP 2 - INPUTS" -msgstr "بخش 2 - ورودی ها" - -#: views/packages/new1.inc.form.php:239 -msgid "New URL" -msgstr "آدرس جدید" - -#: views/packages/new1.inc.form.php:245 -msgid "The installer can have these fields pre-filled at install time." -msgstr "نصب می توانید این زمینه ها در زمان نصب از پیش پر شده است." - -#: views/packages/new1.inc.form.php:245 -msgid "All values are optional." -msgstr "همه مقادیر اختیاری هستند." - -#: views/packages/new1.inc.form.php:254 -msgid "Reset" -msgstr "بازگشت به تنظیمات اولیه" - -#: views/packages/new1.inc.form.php:255 -msgid "Next" -msgstr "ادامه" - -#: views/packages/new1.inc.form.php:267 -msgid "" -"This will reset all of the current package settings. Would you like to " -"continue?" -msgstr "" - -#: views/packages/new2.base.php:64 -msgid "Step 2: System Scan" -msgstr "بخش 2 : آنالیز سیستم" - -#: views/packages/new2.base.php:81 -msgid "Scanning Site" -msgstr "آنالیز ( اسکن ) در سایت" - -#: views/packages/new2.base.php:83 views/packages/new3.base.php:57 -msgid "Please Wait..." -msgstr "لطفا منتظر بمانید ...." - -#: views/packages/new2.base.php:89 -msgid "Scan Complete" -msgstr "آنالیز ( اسکن ) کامل شده" - -#: views/packages/new2.base.php:91 -msgid "" -"Scan checks are not required to pass, however they could cause issues on " -"some systems." -msgstr "" -"آنالیز ( اسکن ) انجام شد تمام موارد مورد تایید می باشد با این حال بسته به " -"سیستم های مختلف می تواند موارد تغییر کند." - -#: views/packages/new2.base.php:92 -msgid "Process Time:" -msgstr "زمان اجرا:" - -#: views/packages/new2.base.php:101 -msgid "Server" -msgstr "سرور" - -#: views/packages/new2.base.php:103 views/tools/controller.php:17 -msgid "Diagnostics" -msgstr "تشخیص" - -#: views/packages/new2.base.php:112 views/packages/new2.base.php:117 -#: views/tools/diagnostics.php:106 -msgid "Web Server" -msgstr "سرور وب" - -#: views/packages/new2.base.php:119 -msgid "Supported web servers:" -msgstr "" - -#: views/packages/new2.base.php:129 -msgid "PHP Setup" -msgstr "" - -#: views/packages/new2.base.php:135 -msgid "Open Base Dir" -msgstr "" - -#: views/packages/new2.base.php:137 -msgid "" -"Issues might occur when [open_basedir] is enabled. Work with your server " -"admin to disable this value in the php.ini file if you’re having issues " -"building a package." -msgstr "" - -#: views/packages/new2.base.php:138 views/packages/new2.base.php:148 -#: views/packages/new2.base.php:155 -msgid "details" -msgstr "" - -#: views/packages/new2.base.php:143 views/tools/diagnostics.php:189 -msgid "Max Execution Time" -msgstr "حداکثر زمان اجرا" - -#: views/packages/new2.base.php:145 -#, php-format -msgid "" -"Issues might occur for larger packages when the [max_execution_time] value " -"in the php.ini is too low. The minimum recommended timeout is \"%1$s\" " -"seconds or higher. An attempt is made to override this value if the server " -"allows it. A value of 0 (recommended) indicates that PHP has no time limits." -msgstr "" - -#: views/packages/new2.base.php:147 -msgid "" -"Note: Timeouts can also be set at the web server layer, so if the PHP max " -"timeout passes and you still see a build interrupt messages, then your web " -"server could be killing the process. If you are limited on processing " -"time, consider using the database or file filters to shrink the size of your " -"overall package. However use caution as excluding the wrong resources can " -"cause your install to not work properly." -msgstr "" - -#: views/packages/new2.base.php:152 -msgid "MySQLi" -msgstr "" - -#: views/packages/new2.base.php:154 -msgid "" -"Creating the package does not require the mysqli module. However the " -"installer.php file requires that the PHP module mysqli be installed on the " -"server it is deployed on." -msgstr "" - -#: views/packages/new2.base.php:164 -msgid "WordPress" -msgstr "وردپرس" - -#: views/packages/new2.base.php:169 -msgid "WordPress Version" -msgstr "ورژن وردپرس" - -#: views/packages/new2.base.php:171 -#, php-format -msgid "" -"It is recommended to have a version of WordPress that is greater than %1$s" -msgstr "" - -#: views/packages/new2.base.php:175 -msgid "Core Files" -msgstr "فایل های هسته ای" - -#: views/packages/new2.base.php:177 -msgid "" -"If the scanner is unable to locate the wp-config.php file in the root " -"directory, then you will need to manually copy it to its new location." -msgstr "" - -#: views/packages/new2.base.php:183 -msgid "Cache Path" -msgstr "" - -#: views/packages/new2.base.php:185 -msgid "" -"Cached data will lead to issues at install time and increases your archive " -"size. It is recommended to empty your cache directory at build time. Use " -"caution when removing data from the cache directory. If you have a cache " -"plugin review the documentation for how to empty it; simply removing files " -"might cause errors on your site. The cache size minimum threshold is " -"currently set at " -msgstr "" - -#: views/packages/new2.base.php:208 views/packages/new2.base.php:317 -msgid "Enabled" -msgstr "فعال" - -#: views/packages/new2.base.php:223 -msgid "File Count" -msgstr "تعداد پرونده" - -#: views/packages/new2.base.php:224 -msgid "Directory Count" -msgstr "تعداد دایرکتوری" - -#: views/packages/new2.base.php:227 -#, php-format -msgid "" -"Total size represents all files minus any filters that have been setup. The " -"current thresholds that trigger warnings are %1$s for the entire site and " -"%2$s for large files." -msgstr "" - -#: views/packages/new2.base.php:239 -msgid "Name Checks" -msgstr "" - -#: views/packages/new2.base.php:244 -msgid "" -"File or directory names may cause issues when working across different " -"environments and servers. Names that are over 250 characters, contain " -"special characters (such as * ? > < : / \\ |) or are unicode might cause " -"issues in a remote enviroment. It is recommended to remove or filter these " -"files before building the archive if you have issues at install time." -msgstr "" - -#: views/packages/new2.base.php:247 views/packages/new2.base.php:265 -msgid "Show Paths" -msgstr "نشان دادن مسیر" - -#: views/packages/new2.base.php:256 -msgid "Large Files" -msgstr "فایل های بزرگ" - -#: views/packages/new2.base.php:261 -#, php-format -msgid "" -"Large files such as movies or other backuped data can cause issues with " -"timeouts. The current check for large files is %1$s per file. If your " -"having issues creating a package consider excluding these files with the " -"files filter and manually moving them to your new location." -msgstr "" - -#: views/packages/new2.base.php:275 -msgid "View Filters" -msgstr "مشاهده فیلتر ها" - -#: views/packages/new2.base.php:283 -msgid "No directory filters have been set." -msgstr "" - -#: views/packages/new2.base.php:288 -msgid "File Extensions" -msgstr "پسوند فایل ها" - -#: views/packages/new2.base.php:293 -msgid "No file extension filters have been set." -msgstr "" - -#: views/packages/new2.base.php:297 -msgid "" -"The lists above are the directories and file extension that will be excluded " -"from the archive." -msgstr "" - -#: views/packages/new2.base.php:332 -msgid "Tables" -msgstr "جدول" - -#: views/packages/new2.base.php:333 -msgid "Records" -msgstr "رکورد" - -#: views/packages/new2.base.php:336 -msgid "repair and optimization" -msgstr "تعمیر و بهینه سازی" - -#: views/packages/new2.base.php:337 -#, php-format -msgid "" -"Total size and row count for all database tables are approximate values. " -"The thresholds that trigger warnings are %1$s and %2$s records. Large " -"databases take time to process and can cause issues with server timeout and " -"memory settings. Running a %3$s on your database can also help improve the " -"overall size and performance. If your server supports shell_exec and " -"mysqldump you can try to enable this option from the settings menu." -msgstr "" - -#: views/packages/new2.base.php:349 -msgid "Table Details" -msgstr "جدول جزئیات" - -#: views/packages/new2.base.php:360 -msgid "Name:" -msgstr "نام:" - -#: views/packages/new2.base.php:361 -msgid "Host:" -msgstr "میزبان:" - -#: views/packages/new2.base.php:362 -msgid "Build Mode:" -msgstr "نحوه ساخت:" - -#: views/packages/new2.base.php:373 -msgid "Scan Error" -msgstr "خطا در آنالیز ( اسکن )" - -#: views/packages/new2.base.php:374 -msgid "Please try again!" -msgstr "لطفا دوباره سعی کنید" - -#: views/packages/new2.base.php:376 views/packages/new3.base.php:111 -msgid "Server Status:" -msgstr "وضعیت سرور:" - -#: views/packages/new2.base.php:379 views/packages/new3.base.php:115 -msgid "Error Message:" -msgstr "پیام خطا:" - -#: views/packages/new2.base.php:386 -msgid "Back" -msgstr "بازگشت" - -#: views/packages/new2.base.php:387 -msgid "Rescan" -msgstr "آنالیز یا ( اسکن ) مجدد" - -#: views/packages/new2.base.php:486 -msgid "Unable to report on any tables" -msgstr "قادر به گزارش هیچ کدام از جداول نمی باشم" - -#: views/packages/new2.base.php:495 -msgid "Unable to report on database stats" -msgstr "قادر به گزارش آمار پایگاه داده نمی باشم" - -#: views/packages/new2.base.php:514 -msgid "DIR" -msgstr "" - -#: views/packages/new2.base.php:520 views/packages/new2.base.php:533 -msgid "FILE" -msgstr "پرونده" - -#: views/packages/new2.base.php:523 -msgid "No name warning issues found." -msgstr "" - -#: views/packages/new2.base.php:529 -msgid "No large files found." -msgstr "هیچ فایلی یافت یا انتخاب نشد" - -#: views/packages/new3.base.php:38 -msgid "Step 3: Build Package" -msgstr "بخش 3 : ساخت بسته آسان نصبی" - -#: views/packages/new3.base.php:55 -msgid "Building Package" -msgstr "در حال ساخت بسته آسان نصبی" - -#: views/packages/new3.base.php:58 -msgid "Keep this window open during the build process." -msgstr "این پنجره را در طول فرایند ساخت هرگز نبندید." - -#: views/packages/new3.base.php:59 -msgid "This may take several minutes." -msgstr "این ممکن است چند دقیقه طول بکشد." - -#: views/packages/new3.base.php:63 -msgid "Build Status" -msgstr "وضعیت ساخت بسته آسان نصبی" - -#: views/packages/new3.base.php:70 -msgid "Package Completed" -msgstr "بسته آسان نصبی با موفقییت تولید شد" - -#: views/packages/new3.base.php:75 -msgid "Process Time" -msgstr "فرایند تولید بسته" - -#: views/packages/new3.base.php:100 -msgid "Build Interrupt" -msgstr "ایجاد وقفه" - -#: views/packages/new3.base.php:101 -msgid "The current build has experienced an issue." -msgstr "" - -#: views/packages/new3.base.php:103 -msgid "Please try the process again." -msgstr "لطفا این فرآیند را دوباره امتحان کنید." - -#: views/packages/new3.base.php:105 -msgid "Diagnose" -msgstr "" - -#: views/packages/new3.base.php:106 -msgid "Try Again" -msgstr "دوباره امتحان کردن" - -#: views/packages/new3.base.php:122 -msgid "Notice" -msgstr "هشدار" - -#: views/packages/new3.base.php:125 -msgid "Build Folder:" -msgstr "پوشه ایجاد:" - -#: views/packages/new3.base.php:127 -msgid "" -"Some servers close connections quickly; yet the build can continue to run in " -"the background. To validate if a build is still running; open the 'tmp' " -"folder above and see if the archive file is growing in size. If it is not " -"then your server has strict timeout constraints. Please visit the support " -"page for additional resources." -msgstr "" - -#: views/packages/new3.base.php:136 -msgid "Package Log" -msgstr "گزارش بسته نصبی" - -#: views/settings/controller.php:22 views/tools/diagnostics.php:87 -msgid "General" -msgstr "عمومی" - -#: views/settings/general.php:6 -msgid "Settings Saved" -msgstr "تنظیمات ذخیره شد" - -#: views/settings/general.php:75 -msgid "Plugin" -msgstr "افزونه" - -#: views/settings/general.php:83 -msgid "Uninstall" -msgstr "پاک کردن افزونه" - -#: views/settings/general.php:86 -msgid "Delete Plugin Settings" -msgstr "حذف تنظیمات افزونه" - -#: views/settings/general.php:89 -msgid "Delete Entire Storage Directory" -msgstr "حذف دایرکتوری ذخیره سازی کل" - -#: views/settings/general.php:96 -msgid "Full Path" -msgstr "مسیر کامل" - -#: views/settings/general.php:99 -msgid "Disable .htaccess File In Storage Directory" -msgstr "غیر فعال کردن فایل htaccess در دایرکتوری ذخیره سازی" - -#: views/settings/general.php:101 -msgid "Disable if issues occur when downloading installer/archive files." -msgstr "اگر مسائل را رخ می دهد که دانلود نصب و آرشیو فایل ها را غیر فعال کنید." - -#: views/settings/general.php:114 -msgid "Archive Flush" -msgstr "آرشیو بسته نصبی" - -#: views/settings/general.php:117 -msgid "Attempt Network Keep Alive" -msgstr "زنده نگه داشتن شبکه تلاش" - -#: views/settings/general.php:118 -msgid "recommended only for large archives" -msgstr "توصیه می شود تنها برای آرشیو بزرگ" - -#: views/settings/general.php:120 -msgid "" -"This will attempt to keep a network connection established for large " -"archives." -msgstr "این تلاش برای حفظ یک اتصال شبکه برای آرشیو بزرگ است." - -#: views/settings/general.php:125 -msgid "Database Build" -msgstr "ساخت پایگاه داده" - -#: views/settings/general.php:128 -msgid "Use PHP" -msgstr "استفاده از پی اچ پی" - -#: views/settings/general.php:131 -msgid "Query Limit Size" -msgstr "پرس و جو حد اندازه" - -#: views/settings/general.php:140 -msgid "higher values speed up build times but uses more memory" -msgstr "مقادیر بالاتر سرعت بار ساخت اما با استفاده از حافظه بیشتر" - -#: views/settings/general.php:147 -msgid "This server does not have shell_exec configured to run." -msgstr "" - -#: views/settings/general.php:149 -msgid "Please contact the server administrator to enable this feature." -msgstr "" - -#: views/settings/general.php:154 -msgid "Use mysqldump" -msgstr "استفاده از mysqldump" - -#: views/settings/general.php:155 -msgid "recommended for large databases" -msgstr "توصیه می شود برای پایگاه های داده بزرگ" - -#: views/settings/general.php:160 -msgid "Working Path:" -msgstr "مسیر در حال کار:" - -#: views/settings/general.php:166 -msgid "" -"Mysqldump was not found at its default location or the location provided. " -"Please enter a path to a valid location where mysqldump can run. If the " -"problem persist contact your server administrator." -msgstr "" - -#: views/settings/general.php:171 -msgid "Add Custom Path:" -msgstr "مسیر سفارشی اضافه کنید:" - -#: views/settings/general.php:175 -msgid "This is the path to your mysqldump program." -msgstr "این مسیر برای برنامه mysqldump شما است." - -#: views/settings/general.php:184 -msgid "Package Debug" -msgstr "اشکال زدایی بسته" - -#: views/settings/general.php:187 -msgid "Show Package Debug Status in Packages Screen" -msgstr "نمایش وضعیت اشکال زدایی بسته در صفحه نمایش بسته" - -#: views/settings/general.php:195 -msgid "Roles & Capabilities" -msgstr "نقش ها و قابلیت ها" - -#: views/settings/general.php:200 -msgid "Custom Roles" -msgstr "نقش های سفارشی" - -#: views/settings/general.php:203 -msgid "Enable User Role Editor Plugin Integration" -msgstr "فعال کردن قابلیت هماهنگ سازی با پلاگین User Role Editor" - -#: views/settings/general.php:210 -msgid "The User Role Editor Plugin" -msgstr "پلاگین ویرایش نقش کاربران" - -#: views/settings/general.php:211 -msgid "Free" -msgstr "رایگان" - -#: views/settings/general.php:212 -msgid "or" -msgstr "یا" - -#: views/settings/general.php:213 -msgid "Professional" -msgstr "تجاری" - -#: views/settings/general.php:214 -msgid "must be installed to use" -msgstr "باید نصب کنید برای استفاده از" - -#: views/settings/general.php:215 -msgid "this feature." -msgstr "این ویژگی" - -#: views/settings/general.php:227 -msgid "Save Settings" -msgstr "ذخیره تغییرات" - -#: views/tools/cleanup.php:8 -msgid "Installer File Cleanup Ran." -msgstr "نصب فایل پاک کردن ران." - -#: views/tools/cleanup.php:12 views/tools/diagnostics.php:44 -msgid "Legacy data removed." -msgstr "حذف داده های میراث." - -#: views/tools/cleanup.php:16 -msgid "Build cache removed." -msgstr "پاک کردن کش" - -#: views/tools/cleanup.php:73 -msgid "" -"If the installer files did not successfully get removed, then you WILL need " -"to remove them manually" -msgstr "" - -#: views/tools/cleanup.php:74 -msgid "" -"Please remove all installer files to avoid leaving open security issues on " -"your server" -msgstr "" - -#: views/tools/cleanup.php:82 -msgid "Data Cleanup" -msgstr "پاک کردن داده ها" - -#: views/tools/cleanup.php:85 -msgid "Delete Reserved Files" -msgstr "حذف فایلها و پوشه های محافظت شده" - -#: views/tools/cleanup.php:86 -msgid "Removes all installer files from a previous install" -msgstr "تمام فایل های نصب را از یک نصب قبلی حذف می کند" - -#: views/tools/cleanup.php:89 -msgid "Delete Legacy Data" -msgstr "حذف داده های میراث" - -#: views/tools/cleanup.php:90 -msgid "Removes all legacy data and settings prior to version" -msgstr "حذف همه داده های میراث و تنظیمات قبل از نسخه" - -#: views/tools/cleanup.php:93 -msgid "Clear Build Cache" -msgstr "پاک کردن کش" - -#: views/tools/cleanup.php:94 -msgid "Removes all build data from:" -msgstr "حذف همه داده ها از ساخت:" - -#: views/tools/cleanup.php:107 -#, php-format -msgid "This action will remove all legacy settings prior to version %1$s. " -msgstr "" - -#: views/tools/cleanup.php:108 -msgid "" -"Legacy settings are only needed if you plan to migrate back to an older " -"version of this plugin." -msgstr "" - -#: views/tools/cleanup.php:120 -msgid "" -"This process will remove all build cache files. Be sure no packages are " -"currently building or else they will be cancelled." -msgstr "" - -#: views/tools/controller.php:16 -msgid "Logging" -msgstr "گزارشات" - -#: views/tools/controller.php:18 -msgid "Cleanup" -msgstr "گزارش های پاکسازی" - -#: views/tools/diagnostics.php:18 views/tools/diagnostics.php:19 -msgid "unknow" -msgstr "" - -#: views/tools/diagnostics.php:39 -msgid "Plugin settings reset." -msgstr "بازگشت به تنظیمات اولیه" - -#: views/tools/diagnostics.php:40 -msgid "View state settings reset." -msgstr "تنظیمات بازنشانی شد" - -#: views/tools/diagnostics.php:41 -msgid "Active package settings reset." -msgstr "تنظیم مجدد تنظیمات فعال بسته." - -#: views/tools/diagnostics.php:81 -msgid "Server Settings" -msgstr "تنظیمات سرور" - -#: views/tools/diagnostics.php:90 -msgid "Duplicator Version" -msgstr "نسخه ایجاد کننده بسته نصبی" - -#: views/tools/diagnostics.php:94 -msgid "Operating System" -msgstr "سیستم عامل" - -#: views/tools/diagnostics.php:98 -msgid "Timezone" -msgstr "منطقه زمانی" - -#: views/tools/diagnostics.php:102 -msgid "Server Time" -msgstr "زمان سرور" - -#: views/tools/diagnostics.php:110 -msgid "APC Enabled" -msgstr "APC فعال" - -#: views/tools/diagnostics.php:114 -msgid "Root Path" -msgstr "مسیر ریشه" - -#: views/tools/diagnostics.php:118 -msgid "ABSPATH" -msgstr "مسیر کامل دایرکتوری وردپرس" - -#: views/tools/diagnostics.php:122 -msgid "Plugins Path" -msgstr "مسیر پلاگین ها" - -#: views/tools/diagnostics.php:126 -msgid "Loaded PHP INI" -msgstr "مسیر php.ini" - -#: views/tools/diagnostics.php:130 -msgid "Server IP" -msgstr "آی پی سرور" - -#: views/tools/diagnostics.php:134 -msgid "Client IP" -msgstr "آی پی کاربر" - -#: views/tools/diagnostics.php:145 -msgid "Langugage" -msgstr "زبان" - -#: views/tools/diagnostics.php:149 views/tools/diagnostics.php:204 -msgid "Charset" -msgstr "انکودینگ" - -#: views/tools/diagnostics.php:153 -msgid "Memory Limit " -msgstr "محدوديت حافظه وردپرس" - -#: views/tools/diagnostics.php:154 -msgid "Max" -msgstr "بیشترین" - -#: views/tools/diagnostics.php:172 -msgid "Safe Mode" -msgstr "" - -#: views/tools/diagnostics.php:176 -msgid "On" -msgstr "روشن" - -#: views/tools/diagnostics.php:176 -msgid "Off" -msgstr "خاموش" - -#: views/tools/diagnostics.php:181 -msgid "Memory Limit" -msgstr "محدوديت حافظه" - -#: views/tools/diagnostics.php:185 -msgid "Memory In Use" -msgstr "حافظه در حال استفاده" - -#: views/tools/diagnostics.php:193 -msgid "Shell Exec" -msgstr "" - -#: views/tools/diagnostics.php:194 -msgid "Is Supported" -msgstr "پشتیبانی می شود" - -#: views/tools/diagnostics.php:194 -msgid "Not Supported" -msgstr "پشتیبانی نمی شود" - -#: views/tools/diagnostics.php:208 -msgid "Wait Timeout" -msgstr "زمان تمام شدن" - -#: views/tools/diagnostics.php:212 -msgid "Max Allowed Packets" -msgstr "حداکثر مجاز بسته" - -#: views/tools/diagnostics.php:216 -msgid "msyqldump Path" -msgstr "مسیر msyqldump" - -#: views/tools/diagnostics.php:220 -msgid "Server Disk" -msgstr "دیسک سرویس دهنده" - -#: views/tools/diagnostics.php:223 -msgid "Free space" -msgstr "فضای خالی" - -#: views/tools/diagnostics.php:226 -msgid "Note: This value is the physical servers hard-drive allocation." -msgstr "توجه: این مقدار تخصیص هارد دیسک سرور فیزیکی است." - -#: views/tools/diagnostics.php:227 -msgid "" -"On shared hosts check your control panel for the 'TRUE' disk space quota " -"value." -msgstr "" -"در میزبان مشترک کنترل پنل خود را برای ارزش ظرفیت فضای دیسک 'واقعی' را بررسی " -"کنید." - -#: views/tools/diagnostics.php:243 -msgid "Stored Data" -msgstr "داده های ذخیره شده" - -#: views/tools/diagnostics.php:248 -msgid "Options Values" -msgstr "تنظیمات" - -#: views/tools/diagnostics.php:281 -msgid "PHP Information" -msgstr "اطلاعات مربوط به پی اچ پی" - -#: views/tools/diagnostics.php:300 -msgid "Delete this option value" -msgstr "حذف مقادیر این تنظیمات" - -#: views/tools/logging.php:140 -msgid "Log file not found or unreadable" -msgstr "" -"فایل گزارشات یافت نشد یا قابل خواندن نیست و احتمال می رود که مشکلی در حال " -"حاظر وجود نداشته که گزارش شود." - -#: views/tools/logging.php:142 -msgid "" -"Try to create a package, since no log files were found in the snapshots " -"directory with the extension *.log" -msgstr "" -"سعی کنید به ایجاد یک بسته، بدون ورود به سیستم فایل در دایرکتوری فوری با فرمت " -"*.log یافت شد" - -#: views/tools/logging.php:144 -msgid "Reasons for log file not showing" -msgstr "دلایلی برای نمایش ندادن فایل گزارشات" - -#: views/tools/logging.php:145 -msgid "The web server does not support returning .log file extentions" -msgstr "" -"سرور وب شما از پسوند .log پشتیبانی نمی کند. بنا بر این می توانید به سرور خود " -"اطلاع دهید تا مشکل را بررسی و رفع نمایند" - -#: views/tools/logging.php:146 -msgid "" -"The snapshots directory does not have the correct permissions to write " -"files. Try setting the permissions to 755" -msgstr "" -"احتمالا دایکرکتوری wp-snapshots سطح دسترسی لازم را ندارد برای نوشتن را " -"ندارد. بنا بر این به هاست خود بروید و سطح دسترسی این پوشه را روی 755 تنظیم " -"کنید" - -#: views/tools/logging.php:147 -msgid "" -"The process that PHP runs under does not have enough permissions to create " -"files. Please contact your hosting provider for more details" -msgstr "" -"پی اچی پی امکان اجرای دستورات لازم را ندارد بنا بر این با هاستینگ خود تماس " -"بگیرید و مشکل را جهت رفع آن ارجاع دهید" - -#: views/tools/logging.php:156 views/tools/logging.php:161 -msgid "Options" -msgstr "تنظیمات" - -#: views/tools/logging.php:163 -msgid "Refresh" -msgstr "بازسازی" - -#: views/tools/logging.php:168 -msgid "Auto Refresh" -msgstr "بازسازی اتوماتیک" - -#: views/tools/logging.php:174 -msgid "Last 20 Logs" -msgstr "20 گزارش اخیر" - -#. Plugin Name of the plugin/theme -msgid "Duplicator" -msgstr "ایجاد کننده بسته نصبی" - -#. Plugin URI of the plugin/theme -msgid "http://www.lifeinthegrid.com/duplicator/" -msgstr "" - -#. Description of the plugin/theme -msgid "" -"Create a backup of your WordPress files and database. Duplicate and move an " -"entire site from one location to another in a few steps. Create a full " -"snapshot of your site at any point in time." -msgstr "" - -#. Author of the plugin/theme -msgid "LifeInTheGrid" -msgstr "" - -#. Author URI of the plugin/theme -msgid "http://www.lifeinthegrid.com" -msgstr "" - -#~ msgid "PHP Version:" -#~ msgstr "نسخه پی اچ پی" - -#~ msgid "Backup and Move Made Easy!" -#~ msgstr "پشتیبان گیری و حرکت آسان ساخته شده!" - -#~ msgid "The top-rated Duplicator plugin is going professional!" -#~ msgstr "دارای امتیاز بالا تکثیر پلاگین حرفه ای می گذرد!" - -#~ msgid "Schedules" -#~ msgstr "زمان‌بندی" - -#~ msgid "Custom Templates" -#~ msgstr "قالب های سفارشی" - -#~ msgid "Cloud Storage" -#~ msgstr "ذخیره سازی ابری" - -#~ msgid "Queued Processing" -#~ msgstr "صف پردازش" - -#~ msgid "Pass" -#~ msgstr "همه چیز مورد تایید می باشد" - -#~ msgid "Fail" -#~ msgstr "مواردی مورد تایید نمی باشد" - -#~ msgid "Format" -#~ msgstr "نوع" - -#~ msgid "localhost" -#~ msgstr "" -#~ "سرور محلی مثال ( localhost یا 127.0.0.1 یا آی پی که هاستینگ برای لوکال " -#~ "هاست به شما داده )" - -#~ msgid "mydatabaseName" -#~ msgstr "نام پایگاه داده" - -#~ msgid "databaseUserName" -#~ msgstr "نام کاربری پایگاه داده" - -#~ msgid "http://mynewsite.com" -#~ msgstr "https://www.amoozesh98.com" - -#~ msgid "PHP Settings" -#~ msgstr "تنظیمات پی اچ پی" - -#~ msgid "WordPress Settings" -#~ msgstr "تنظیمات وردپرس" - -#~ msgid "Missing" -#~ msgstr "گم" - -#~ msgid "Invalid Names" -#~ msgstr "نامهای بی اعتبار" - -#~ msgid "No name length issues." -#~ msgstr "بدون مسائل طول نام." - -#~ msgid "Support" -#~ msgstr "پشتیبانی" - -#~ msgid "Yes" -#~ msgstr "بله" - -#~ msgid "No" -#~ msgstr "نه" - -#~ msgid "PHP" -#~ msgstr "پی اچ پی" - -#~ msgid "MySQL" -#~ msgstr "مای اس کیوال" - -#~ msgid "Good" -#~ msgstr "خوب" - -#~ msgid "Warn" -#~ msgstr "" -#~ "اخطار ( البته به این معنی نمی باشد که مشکل در ایجاد بسته نصبی وجود خواهد " -#~ "داشت )" - -#~ msgid "unable to read" -#~ msgstr "قادر به خواندن نمی باشم" - -#~ msgid "Goods" -#~ msgstr "خوب" diff --git a/lang/wpduplicator-fr_FR.mo b/lang/wpduplicator-fr_FR.mo deleted file mode 100644 index 43d7c311..00000000 Binary files a/lang/wpduplicator-fr_FR.mo and /dev/null differ diff --git a/lang/wpduplicator-fr_FR.po b/lang/wpduplicator-fr_FR.po deleted file mode 100644 index e8b1aa90..00000000 --- a/lang/wpduplicator-fr_FR.po +++ /dev/null @@ -1,2608 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: WPDuplicator v0.5.23\n" -"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/duplicator\n" -"POT-Creation-Date: 2015-07-26 23:57+0200\n" -"PO-Revision-Date: 2015-07-26 23:57+0200\n" -"Last-Translator: Ralf Koller \n" -"Language-Team: Nicolas Richer \n" -"Language: fr_FR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 1.8.2\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" -"X-Poedit-Basepath: ..\n" -"X-Poedit-WPHeader: duplicator.php\n" -"X-Textdomain-Support: yes\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPathExcluded-0: assets\n" - -#: classes/ui.php:111 -msgid "" -"Reserved Duplicator install file(s) still exists in the root directory. " -"Please delete these file(s) to avoid possible security issues." -msgstr "" -"Les fichiers d'installation de Duplicator sont toujours présents à la " -"racine de votre serveur. Merci de supprimer ces fichiers pour éviter toute " -"faille de sécurité." - -#: classes/ui.php:112 -msgid "Remove file(s) now" -msgstr "Supprimer les fichiers maintenant" - -#: classes/ui.php:113 -msgid "Dismiss this notice" -msgstr "Masquer ce message" - -#: classes/utility.php:249 -msgid "You do not have sufficient permissions to access this page." -msgstr "Vous n'avez pas les droits suffisants pour accéder à cette page" - -#: duplicator.php:102 -msgid "Get Help" -msgstr "Contactez le support" - -#: duplicator.php:102 duplicator.php:191 views/help/help.php:29 -msgid "Help" -msgstr "Support" - -#: duplicator.php:103 -msgid "Support the Plugin" -msgstr "Aidez le plugin" - -#: duplicator.php:103 duplicator.php:195 views/help/about.php:41 -msgid "About" -msgstr "A propos" - -#: duplicator.php:179 views/packages/controller.php:76 -#: views/packages/list.base.php:235 -msgid "Packages" -msgstr "Paquets" - -#: duplicator.php:183 views/settings/controller.php:19 -msgid "Settings" -msgstr "Paramètres" - -#: duplicator.php:187 views/tools/controller.php:13 -msgid "Tools" -msgstr "Outils" - -#: duplicator.php:246 -msgid "Manage" -msgstr "Gérer" - -#: views/help/about.php:54 -msgid "" -"Created for Admins, Developers and Designers the Duplicator can streamline " -"your workflows and help you quickly clone a WordPress application. " -"Migrating a WordPress site manually can be very time consuming. The " -"Duplicator was made to help you speed up the migration process. Please help " -"us to continue the development effort of this plugin." -msgstr "" -"Créé pour les webmasters, développeurs et designers, Duplicator va accélérer " -"votre travail en vous permettant de cloner rapidement une installation " -"WordPress. Faire une migration manuelle peut vite devenir très long, c'" -"est pourquoi Duplicator vient l'automatiser. Merci de nous aider pour " -"continuer les efforts de développement du plugin." - -#: views/help/about.php:64 -msgid "Support Duplicator" -msgstr "Aide de Duplicator" - -#: views/help/about.php:71 -msgid "Partner with Us" -msgstr "Soutenez-nous" - -#: views/help/about.php:83 -msgid "Keep Active and Online" -msgstr "Pour que Duplicator soit activement développé" - -#: views/help/about.php:90 -msgid "Leave 5 Stars" -msgstr "Nous donner 5 Étoiles" - -#: views/help/about.php:107 -msgid "Spread the Word" -msgstr "Faites passer le mot" - -#: views/help/about.php:113 -msgid "Duplicate Your WordPress" -msgstr "Dupliquer votre WordPress" - -#: views/help/about.php:114 -msgid "Rapid WordPress Duplication by LifeInTheGrid.com" -msgstr "Duplication Rapide WordPress par LifeInTheGrid.com" - -#: views/help/about.php:131 -msgid "Get More Great Tools" -msgstr "Obtenez d'autres Super Outils" - -#: views/help/gopro.php:37 -msgid "Go Pro!" -msgstr "Version Premium" - -#: views/help/gopro.php:46 -msgid "Duplicator Pro Has Arrived!" -msgstr "Duplicator Pro est arrivé !" - -#: views/help/gopro.php:49 -msgid "The simplicity of Duplicator" -msgstr "La simplicité de Duplicator" - -#: views/help/gopro.php:50 -msgid "with the power the professional requires." -msgstr "avec la puissance dont les pros ont besoin." - -#: views/help/gopro.php:57 -msgid "Duplicator Free" -msgstr "Duplicator Gratuit" - -#: views/help/gopro.php:60 views/help/gopro.php:88 -msgid "Backup Files & Database" -msgstr "Sauvegarde des Fichiers & de la Base de Données" - -#: views/help/gopro.php:61 views/help/gopro.php:89 -msgid "" -"Compresses all your WordPress files and database into a compressed snapshot " -"archive file." -msgstr "" -"Compresse les fichiers WordPress ainsi que la base de données dans un " -"instantané" - -#: views/help/gopro.php:64 views/help/gopro.php:92 -msgid "Directory Filters" -msgstr "Filtres de Répertoire" - -#: views/help/gopro.php:65 views/help/gopro.php:93 -msgid "" -"Filter out the directories and file extensions you want to include/exclude " -"in your in your archive file." -msgstr "" -"Filtrez les répertoires et les extensions de fichiers que vous souhaitez " -"inclure ou exclure de votre instantané." - -#: views/help/gopro.php:68 views/help/gopro.php:96 -msgid "Database Table Filters" -msgstr "Filtres des Tables de la Base de Données" - -#: views/help/gopro.php:69 views/help/gopro.php:97 -msgid "" -"Filter out only the database tables you want to include/exclude in your " -"database creation script." -msgstr "" -"Filtrez les tables de la base de données que vous souhaitez inclure/exclure " -"de votre instantané." - -#: views/help/gopro.php:72 views/help/gopro.php:100 -msgid "Migration Wizard" -msgstr "Assistant de Migration" - -#: views/help/gopro.php:73 views/help/gopro.php:101 -msgid "" -"With just two files (archive & installer.php) move your site to a new " -"location." -msgstr "" -"Avec seulement deux fichiers (archive & installer.php) vous pourrez " -"déplacer votre site à un autre emplacement." - -#: views/help/gopro.php:85 views/packages/new1.inc.form.php:50 -msgid "Duplicator Pro" -msgstr "Duplicator Pro" - -#: views/help/gopro.php:104 -msgid "Scheduled Backups" -msgstr "Sauvegardes Planifiées" - -#: views/help/gopro.php:105 -msgid "" -"Automate the creation of your packages to run at various scheduled intervals." -msgstr "Automatisez la création de vos paquets à intervalles réguliers" - -#: views/help/gopro.php:108 -msgid "Dropbox Support" -msgstr "Compatibilité avec Dropbox" - -#: views/help/gopro.php:109 -msgid "Backup up your entire site to Dropbox." -msgstr "Sauvegardez votre site sur Dropbox." - -#: views/help/gopro.php:112 -msgid "FTP Support" -msgstr "Compatibilité FTP" - -#: views/help/gopro.php:113 -msgid "Backup up your entire site to an FTP server." -msgstr "Sauvegardez votre site sur un serveur FTP externe." - -#: views/help/gopro.php:116 -msgid "Customer Support" -msgstr "Support Client" - -#: views/help/gopro.php:117 -msgid "" -"Server setups can be quite complex, with pro you get prompt help to get your " -"site backed up and moved." -msgstr "" -"La configuration de serveurs peut être complexe. Avec la version Pro vous " -"obtenez une assistance pour vous aider à sauvegarder et déplacer votre site." - -#: views/help/gopro.php:124 -msgid "Check It Out!" -msgstr "Jetez-y un oeil !" - -#: views/help/help.php:38 -msgid "" -"Migrating WordPress is a complex process and the logic to make all the magic " -"happen smoothly may not work quickly with every site. With over 30,000 " -"plugins and a very complex server eco-system some migrations may run into " -"issues. This is why the Duplicator includes a detailed knowledgebase that " -"can help with many common issues. Resources to additional support, approved " -"hosting, and alternatives to fit your needs can be found below." -msgstr "" -"Migrer un site WordPress est un processus complexe et il n'est pas " -"facile de rendre cette opération rapide à 100%. Avec plus de 30 000 plugins " -"et un écosystème serveur complexe, il est courant que tout ne fonctionne pas " -"comme prévu. C'est pourquoi Duplicator contient une documentation " -"détaillée (en anglais seulement) pour vous aider à résoudre les problèmes " -"les plus fréquents. Les liens pour du support additionnel (en anglais), les " -"hébergeurs \"approuvés\" et les solutions alternatives se trouvent ci-" -"dessous." - -#: views/help/help.php:50 -msgid "Knowledgebase" -msgstr "Base de connaissances" - -#: views/help/help.php:53 -msgid "Complete Online Documentation" -msgstr "Documentation en ligne" - -#: views/help/help.php:55 -msgid "Choose A Section" -msgstr "Choisissez une section" - -#: views/help/help.php:56 -msgid "Quick Start" -msgstr "Démarrage Rapide" - -#: views/help/help.php:57 -msgid "User Guide" -msgstr "Guide Utilisateur" - -#: views/help/help.php:58 -msgid "FAQs" -msgstr "FAQs" - -#: views/help/help.php:59 -msgid "Change Log" -msgstr "Notes de Version" - -#: views/help/help.php:60 -msgid "Product Page" -msgstr "Page Produit" - -#: views/help/help.php:69 -msgid "Online Support" -msgstr "Aide en Ligne" - -#: views/help/help.php:72 -msgid "Get Help From IT Professionals" -msgstr "Obtenez l'aide de professionnels" - -#: views/help/help.php:76 -msgid "Get Support!" -msgstr "Demandez de l'aide !" - -#: views/help/help.php:88 -msgid "Approved Hosting" -msgstr "Hébergeur Approuvés" - -#: views/help/help.php:91 -msgid "Servers That Work With Duplicator" -msgstr "Les serveurs qui fonctionnent avec Duplicator" - -#: views/help/help.php:94 -msgid "Trusted Providers!" -msgstr "Hébergeurs approuvés" - -#: views/help/help.php:104 -msgid "Alternatives" -msgstr "Alternatives" - -#: views/help/help.php:107 -msgid "Other Commercial Resources" -msgstr "Autres ressources (commerciales)" - -#: views/help/help.php:110 -msgid "Pro Solutions!" -msgstr "Solutions Pro !" - -#: views/packages/list-nodata.php:7 -msgid "No Packages Found." -msgstr "Aucun paquet trouvé." - -#: views/packages/list-nodata.php:8 -msgid "Click the 'Create New' button to build a package." -msgstr "Cliquez sur l'onglet "Créer Paquet" pour en générer un." - -#: views/packages/list-nodata.php:13 -msgid "Please visit the" -msgstr "Allez donc sur" - -#: views/packages/list-nodata.php:14 views/packages/list-nodata.php:28 -#: views/packages/new1.base.php:234 -msgid "help page" -msgstr "la page de support" - -#: views/packages/list-nodata.php:15 -msgid "for additional support" -msgstr "pour une aide supplémentaire" - -#: views/packages/list-nodata.php:24 -msgid "Older packages prior to 0.5.0 are no longer supported in this version." -msgstr "" -"Les paquets antérieurs à la version 0.5.0 ne sont plus compatibles avec " -"cette version." - -#: views/packages/list-nodata.php:27 -msgid "To get an older package please visit the" -msgstr "Pour obtenir une version antérieure, allez donc sur " - -#: views/packages/list-nodata.php:29 -msgid "and look for the Change Log link for additional instructions." -msgstr "" -"et cherchez dans le Journal des Changements (Change Log) pour des " -"instructions additionnelles." - -#: views/packages/list-nodata.php:33 -msgid "Hide this message" -msgstr "Cacher ce message" - -#: views/packages/list.base.php:39 -msgid "Help Support Duplicator" -msgstr "Centre d'Aide de Duplicator" - -#: views/packages/list.base.php:50 -msgid "Bulk Actions" -msgstr "Actions par lots" - -#: views/packages/list.base.php:51 -msgid "Delete selected package(s)" -msgstr "Effacer le(s) paquet(s) sélectionné(s)" - -#: views/packages/list.base.php:51 -msgid "Delete" -msgstr "Effacer" - -#: views/packages/list.base.php:53 -msgid "Apply" -msgstr "Appliquer" - -#: views/packages/list.base.php:58 -msgid "Package Logs" -msgstr "Journaux des Paquets" - -#: views/packages/list.base.php:61 views/packages/new1.base.php:96 -#: views/packages/new2.base.php:69 views/packages/new3.base.php:43 -#: views/packages/new3.base.php:89 -msgid "All Packages" -msgstr "Tous les Paquets" - -#: views/packages/list.base.php:62 views/packages/new1.base.php:97 -#: views/packages/new2.base.php:70 views/packages/new3.base.php:44 -msgid "Create New" -msgstr "Créer Paquet" - -#: views/packages/list.base.php:87 -msgid "Select all packages" -msgstr "Sélectionner tous les paquets" - -#: views/packages/list.base.php:88 views/packages/new3.base.php:108 -msgid "Details" -msgstr "Détails" - -#: views/packages/list.base.php:89 -msgid "Created" -msgstr "Créé" - -#: views/packages/list.base.php:90 views/packages/new2.base.php:222 -#: views/packages/new2.base.php:334 -msgid "Size" -msgstr "Taille" - -#: views/packages/list.base.php:91 views/packages/new1.inc.form.php:6 -#: views/packages/new1.inc.form.php:31 views/packages/new3.base.php:74 -msgid "Name" -msgstr "Nom" - -#: views/packages/list.base.php:93 views/settings/general.php:110 -msgid "Package" -msgstr "Paquet" - -#: views/packages/list.base.php:124 -msgid "(No Notes Taken)" -msgstr "(Aucun note générée)" - -#: views/packages/list.base.php:142 views/packages/list.base.php:187 -msgid "View" -msgstr "Voir" - -#: views/packages/list.base.php:147 views/packages/new1.inc.form.php:176 -#: views/packages/new3.base.php:79 -msgid "Installer" -msgstr "Installeur" - -#: views/packages/list.base.php:150 views/packages/new1.inc.form.php:65 -#: views/packages/new2.base.php:195 views/packages/new3.base.php:83 -msgid "Archive" -msgstr "Archive" - -#: views/packages/list.base.php:155 views/packages/list.base.php:200 -#: views/settings/general.php:79 views/tools/diagnostics.php:141 -#: views/tools/diagnostics.php:160 views/tools/diagnostics.php:200 -msgid "Version" -msgstr "Version" - -#: views/packages/list.base.php:156 views/packages/list.base.php:201 -#: views/packages/new1.inc.form.php:199 views/tools/diagnostics.php:168 -msgid "User" -msgstr "Utilisateur" - -#: views/packages/list.base.php:157 views/packages/list.base.php:202 -msgid "Hash" -msgstr "Découpage" - -#: views/packages/list.base.php:158 views/packages/list.base.php:207 -#: views/packages/new1.inc.form.php:8 views/packages/new1.inc.form.php:13 -msgid "Notes" -msgstr "Notes" - -#: views/packages/list.base.php:160 -msgid "Links" -msgstr "Liens" - -#: views/packages/list.base.php:161 -msgid "SQL" -msgstr "SQL" - -#: views/packages/list.base.php:162 -msgid "Log" -msgstr "Journal" - -#: views/packages/list.base.php:165 -msgid "Open Scan Report" -msgstr "Ouvrir le Rapport de Scan" - -#: views/packages/list.base.php:166 -msgid "View Package Object" -msgstr "Voir l'objet du Paquet" - -#: views/packages/list.base.php:193 -msgid "View Error Details" -msgstr "Voir le détail des Erreurs" - -#: views/packages/list.base.php:205 -msgid "Unrecoverable Error! Please remove this package." -msgstr "Erreur : contenu non récupérable ! Merci de supprimer ce paquet." - -#: views/packages/list.base.php:210 -msgid "" -"This package has encountered errors. Click 'View Log' for more details. " -"For additional support see the " -msgstr "" -"Ce paquet a généré des erreurs. Cliquez sur "Voir les Journaux" pour " -"plus de détails. Pour une aide supplémentaire allez donc sur" - -#: views/packages/list.base.php:211 -msgid "online knowledgebase" -msgstr "notre base de connaissances en ligne" - -#: views/packages/list.base.php:213 -msgid "View Log" -msgstr "Voir les Journaux" - -#: views/packages/list.base.php:236 views/packages/new2.base.php:219 -#: views/packages/new2.base.php:328 -msgid "Total Size" -msgstr "Taille Totale" - -#: views/packages/list.base.php:255 -msgid "Download Links" -msgstr "Liens de Téléchargement" - -#: views/packages/list.base.php:258 -msgid "The following links contain sensitive data. Please share with caution!" -msgstr "" -"Les liens suivants contiennent des informations sensibles. Partagez-les avec " -"parcimonie !" - -#: views/packages/list.base.php:264 -msgid "" -"The database SQL script is a quick link to your database backup script. An " -"exact copy is also stored in the package." -msgstr "" -"Le script de base de données SQL est un lien rapide vers votre script de " -"sauvegarde de base de données. Une copie exacte est également dans le paquet." - -#: views/packages/list.base.php:287 -msgid "" -"Please select an action from the bulk action drop down menu to perform a " -"specific action." -msgstr "Merci de sélectionner une action de la liste des actions par lot" - -#: views/packages/list.base.php:295 -msgid "Please select at least one package to delete." -msgstr "Merci de sélectionner au moins un paquet à effacer." - -#: views/packages/list.base.php:299 -msgid "Are you sure, you want to delete the selected package(s)?" -msgstr "Êtes-vous sûr de vouloir effacer le paquet sélectionné ?" - -#: views/packages/list.base.php:333 -msgid "Package File Links" -msgstr "Liens vers les Fichiers du Paquet" - -#: views/packages/list.base.php:336 -msgid "DATABASE" -msgstr "BASE DE DONNEES" - -#: views/packages/list.base.php:337 -msgid "PACKAGE" -msgstr "PAQUET" - -#: views/packages/list.base.php:338 -msgid "INSTALLER" -msgstr "INSTALLEUR" - -#: views/packages/list.base.php:339 -msgid "LOG" -msgstr "JOURNAL" - -#: views/packages/list.base.php:340 -msgid "REPORT" -msgstr "RAPPORT" - -#: views/packages/new1.base.php:13 -msgid "Package settings have been reset." -msgstr "Les paramètres du paquet ont été remis à zéro." - -#: views/packages/new1.base.php:86 views/packages/new2.base.php:59 -#: views/packages/new3.base.php:33 -msgid "Setup" -msgstr "Configuration" - -#: views/packages/new1.base.php:87 views/packages/new2.base.php:60 -#: views/packages/new3.base.php:34 -msgid "Scan" -msgstr "Scan" - -#: views/packages/new1.base.php:88 views/packages/new2.base.php:61 -#: views/packages/new2.base.php:388 views/packages/new3.base.php:35 -msgid "Build" -msgstr "Création" - -#: views/packages/new1.base.php:91 -msgid "Step 1: Package Setup" -msgstr "Étape 1 : Configurer un Paquet" - -#: views/packages/new1.base.php:115 -msgid "Requirements:" -msgstr "Exigences :" - -#: views/packages/new1.base.php:124 -msgid "" -"System requirements must pass for the Duplicator to work properly. Click " -"each link for details." -msgstr "" -"Les exigences système doivent être validées pour que Duplicator fonctionne " -"convenablement. Cliquez sur chaque lien pour en voir les détails." - -#: views/packages/new1.base.php:130 -msgid "PHP Support" -msgstr "Support de PHP" - -#: views/packages/new1.base.php:136 -msgid "PHP Version" -msgstr "Version de PHP" - -#: views/packages/new1.base.php:140 -msgid "Zip Archive Enabled" -msgstr "Archivage Zip Activé" - -#: views/packages/new1.base.php:144 -msgid "Safe Mode Off" -msgstr "Mode Sécurité Désactivé" - -#: views/packages/new1.base.php:148 views/packages/new1.base.php:152 -#: views/packages/new1.base.php:156 -msgid "Function" -msgstr "Fonction" - -#: views/packages/new1.base.php:161 -msgid "" -"PHP versions 5.2.17+ or higher is required. Please note that in versioning " -"logic a value such as 5.2.9 is less than 5.2.17. For compression to work the " -"ZipArchive extension for PHP is required. Safe Mode should be set to 'Off' " -"in you php.ini file and is deprecated as of PHP 5.3.0. For any issues in " -"this section please contact your hosting provider or server administrator. " -"For additional information see our online documentation." -msgstr "" -"PHP dans ses versions 5.2.17 ou supérieures est nécessaire. La logique de " -"versioning de PHP fonctionne de telle façon que 5.2.9 est inférieur à " -"5.2.17. Pour que la compression soit activée, l'extension ZipArchive de " -"PHP est requise. Le mode sécurité (Safe Mode) doit être désactivé (Off) dans " -"votre fichier php.ini ; cette fonction n'est plus supportée après PHP " -"5.3.0. En cas de problèmes avec cette section, merci de contacter votre " -"hébergeur ou administrateur système. Pour plus d'informations, veuillez " -"vous reporter à notre documentation en ligne." - -#: views/packages/new1.base.php:169 -msgid "Permissions" -msgstr "Permissions" - -#: views/packages/new1.base.php:172 -msgid "Required Paths" -msgstr "Chemins" - -#: views/packages/new1.base.php:183 -msgid "" -"Permissions can be difficult to resolve on some systems. If the plugin can " -"not read the above paths here are a few things to try. 1) Set the above " -"paths to have permissions of 755 for directories and 644 for files. You can " -"temporarily try 777 however, be sure you don’t leave them this way. 2) Check " -"the owner/group settings for both files and directories. The PHP script " -"owner and the process owner are different. The script owner owns the PHP " -"script but the process owner is the user the script is running as, thus " -"determining its capabilities/privileges in the file system. For more details " -"contact your host or server administrator or visit the 'Help' menu under " -"Duplicator for additional online resources." -msgstr "" -"Les permissions sont parfois difficiles à appréhender sur certains systèmes. " -"Si le plugin n'arrive pas à lire les chemins suivants, voici ce que vous " -"pouvez essayer. 1) Passer les permissions à 755 pour les répertoires et 644 " -"pour les fichiers. Vous pouvez également essayer de passer en 777 mais ne " -"laissez pas ce paramètre par la suite. 2) Vérifier les paramètres de " -"propriétaire ou de groupe pour les fichiers et répertoires. Le script PHP " -"pour les propriétaires et groupes ne fonctionne pas de la même façon. Pour " -"plus de détails, contactez votre hébergeur ou administrateur système. Vous " -"pouvez également aller dans la section 'Aide' pour des ressources " -"supplémentaires." - -#: views/packages/new1.base.php:191 -msgid "Server Support" -msgstr "Compatibilité avec le Serveur" - -#: views/packages/new1.base.php:197 -msgid "MySQL Version" -msgstr "Version de MySQL" - -#: views/packages/new1.base.php:201 -msgid "MySQLi Support" -msgstr "Compatibilité MySQLi" - -#: views/packages/new1.base.php:207 -msgid "" -"MySQL version 5.0+ or better is required and the PHP MySQLi extension (note " -"the trailing 'i') is also required. Contact your server administrator and " -"request that mysqli extension and MySQL Server 5.0+ be installed. Please " -"note in future versions support for other databases and extensions will be " -"added." -msgstr "" -"Une version 5.0 ou supérieure de MySQL ainsi que l'extension MySQLi " -"(remarquez bien le 'i') est nécessaire. Contactez alors votre " -"administrateur pour lui demander que tout soit en règle. Nous ajouterons par " -"la suite la compatibilité avec d'autres bases de données et extensions." - -#: views/packages/new1.base.php:208 -msgid "more info" -msgstr "plus d'information" - -#: views/packages/new1.base.php:217 -msgid "Reserved Files" -msgstr "Fichiers Réservés" - -#: views/packages/new1.base.php:221 -msgid "" -"None of the reserved files (installer.php, installer-data.sql and installer-" -"log.txt) where found from a previous install. This means you are clear to " -"create a new package." -msgstr "" -"Aucun des fichiers 'réservés' n'a été détecté (installer.php, " -"installer-data.sql et installer-log.txt). Cela signifie que vous pouvez " -"créer un nouveau paquet." - -#: views/packages/new1.base.php:224 -msgid "" -"A reserved file(s) was found in the WordPress root directory. Reserved file " -"names are installer.php, installer-data.sql and installer-log.txt. To " -"archive your data correctly please remove any of these files from your " -"WordPress root directory. Then try creating your package again." -msgstr "" -"Un ou plusieurs fichier(s) réservé(s) a été trouvé à la racine du répertoire " -"WordPress. Il se pourrait que cela soit par exemple installer.php, installer-" -"data.sql ou encore installer-log.txt. Afin d'archiver vos données " -"correctement, merci de retirer ces fichiers du répertoire racine. Ensuite, " -"essayez de créer un nouveau paquet." - -#: views/packages/new1.base.php:225 -msgid "Remove Files Now" -msgstr "Supprimer les Fichiers maintenant" - -#: views/packages/new1.base.php:234 -msgid "For additional help please see the " -msgstr "Pour plus d'aide en ligne, allez sur" - -#: views/packages/new1.inc.form.php:10 -msgid "Create a new default name" -msgstr "Créer un nouveau nom par défaut" - -#: views/packages/new1.inc.form.php:23 views/settings/general.php:94 -msgid "Storage" -msgstr "Stockage" - -#: views/packages/new1.inc.form.php:32 -msgid "Type" -msgstr "Type" - -#: views/packages/new1.inc.form.php:33 -msgid "Location" -msgstr "Emplacement" - -#: views/packages/new1.inc.form.php:38 -msgid "Default" -msgstr "Défaut" - -#: views/packages/new1.inc.form.php:39 -msgid "Local" -msgstr "Local" - -#: views/packages/new1.inc.form.php:45 -msgid "" -"All packages including the archive, installer and SQL script are stored in " -"the location above. " -msgstr "" -"Tous les paquets contenant l'archive, l'installeur et le script SQL sont " -"stockés à l'emplacement ci-dessous. " - -#: views/packages/new1.inc.form.php:48 -msgid "Dropbox, FTP and other multiple storage options available in " -msgstr "Dropbox, FTP et d'autres options de stockage sont disponibles avec " - -#: views/packages/new1.inc.form.php:67 -msgid "File filter enabled" -msgstr "Filtre de fichier activé" - -#: views/packages/new1.inc.form.php:68 -msgid "Database filter enabled" -msgstr "Filtre de base de données activé" - -#: views/packages/new1.inc.form.php:77 views/packages/new2.base.php:203 -msgid "Files" -msgstr "Fichiers" - -#: views/packages/new1.inc.form.php:78 views/packages/new1.inc.form.php:195 -#: views/packages/new2.base.php:312 -msgid "Database" -msgstr "Base de Données" - -#: views/packages/new1.inc.form.php:90 -msgid "Enable File Filters" -msgstr "Activer les Filtres de Fichiers" - -#: views/packages/new1.inc.form.php:94 views/packages/new1.inc.form.php:102 -msgid "Separate all filters by semicolon" -msgstr "Séparez tous les filtres par des points-virgules" - -#: views/packages/new1.inc.form.php:94 views/packages/new2.base.php:278 -msgid "Directories" -msgstr "Répertoires" - -#: views/packages/new1.inc.form.php:96 -msgid "root path" -msgstr "Chemin vers la Racine" - -#: views/packages/new1.inc.form.php:97 -msgid "wp-uploads" -msgstr "wp-uploads" - -#: views/packages/new1.inc.form.php:98 -msgid "cache" -msgstr "cache" - -#: views/packages/new1.inc.form.php:99 views/packages/new1.inc.form.php:106 -msgid "(clear)" -msgstr "(effacer)" - -#: views/packages/new1.inc.form.php:102 -msgid "File extensions" -msgstr "Extensions de Fichiers" - -#: views/packages/new1.inc.form.php:104 -msgid "media" -msgstr "media" - -#: views/packages/new1.inc.form.php:105 -msgid "archive" -msgstr "archive" - -#: views/packages/new1.inc.form.php:111 -msgid "" -"The directory paths and extensions above will be be excluded from the " -"archive file if enabled is checked." -msgstr "" -"Les chemins vers le répertoire et les extensions ci-dessous seront exclus de " -"l'archive si vous cochez la case "activer"" - -#: views/packages/new1.inc.form.php:112 -msgid "Use the full path for directories and semicolons to separate all items." -msgstr "" -"Utilisez le chemin complet pour les répertoires et des points virgules pour " -"séparer les fichiers." - -#: views/packages/new1.inc.form.php:123 -msgid "Enable Table Filters" -msgstr "Activer les Filtres de Tables" - -#: views/packages/new1.inc.form.php:124 -msgid "checked tables are excluded" -msgstr "les tables cochées seront exclues" - -#: views/packages/new1.inc.form.php:129 -msgid "Include All" -msgstr "Tout Inclure" - -#: views/packages/new1.inc.form.php:130 -msgid "Exclude All" -msgstr "Tout Exclure" - -#: views/packages/new1.inc.form.php:163 -msgid "" -"Checked tables will not be added to the database script. Excluding certain " -"tables can possibly cause your site or plugins to not work correctly after " -"install!" -msgstr "" -"Les tables sélectionnées ne seront pas ajoutées au script de la base de " -"données. Exclure certaines tables peut potentiellement empêcher votre ou vos " -"plugins de ne pas fonctionner correctement après l'installation !" - -#: views/packages/new1.inc.form.php:181 -msgid "STEP 1 - INPUTS" -msgstr "ÉTAPE 1 - DONNÉES" - -#: views/packages/new1.inc.form.php:184 -msgid "MySQL Server" -msgstr "Serveur MySQL" - -#: views/packages/new1.inc.form.php:187 -msgid "Host" -msgstr "Adresse" - -#: views/packages/new1.inc.form.php:191 -msgid "Host Port" -msgstr "Port de l'hébergement" - -#: views/packages/new1.inc.form.php:203 -msgid "Advanced Options" -msgstr "Options Avancées" - -#: views/packages/new1.inc.form.php:209 -msgid "SSL" -msgstr "SSL" - -#: views/packages/new1.inc.form.php:212 -msgid "Enforce on Admin" -msgstr "Forcer à l'administration" - -#: views/packages/new1.inc.form.php:216 -msgid "Enforce on Logins" -msgstr "Forcer aux connexions" - -#: views/packages/new1.inc.form.php:220 -msgid "Cache" -msgstr "Cache" - -#: views/packages/new1.inc.form.php:223 -msgid "Keep Enabled" -msgstr "Garder Activé" - -#: views/packages/new1.inc.form.php:227 -msgid "Keep Home Path" -msgstr "Garder le chemin de l'accueil" - -#: views/packages/new1.inc.form.php:235 -msgid "STEP 2 - INPUTS" -msgstr "ÉTAPE 2 - DONNÉES" - -#: views/packages/new1.inc.form.php:239 -msgid "New URL" -msgstr "Nouvelle URL" - -#: views/packages/new1.inc.form.php:245 -msgid "The installer can have these fields pre-filled at install time." -msgstr "" -"L'installer peut avoir ces champs pré-remplis lors de l'installation." - -#: views/packages/new1.inc.form.php:245 -msgid "All values are optional." -msgstr "Toutes ces valeurs sont facultatives." - -#: views/packages/new1.inc.form.php:254 -msgid "Reset" -msgstr "Remise à zéro" - -#: views/packages/new1.inc.form.php:255 -msgid "Next" -msgstr "Suivant" - -#: views/packages/new1.inc.form.php:267 -msgid "" -"This will reset all of the current package settings. Would you like to " -"continue?" -msgstr "" -"Cela va remettre à zéro tous les paramètres du paquet en cours. Voulez-vous " -"continuer ?" - -#: views/packages/new2.base.php:64 -msgid "Step 2: System Scan" -msgstr "Étape 2 : Scan du Système" - -#: views/packages/new2.base.php:81 -msgid "Scanning Site" -msgstr "Scan en cours" - -#: views/packages/new2.base.php:83 views/packages/new3.base.php:57 -msgid "Please Wait..." -msgstr "Merci de patienter..." - -#: views/packages/new2.base.php:89 -msgid "Scan Complete" -msgstr "Scan Terminé" - -#: views/packages/new2.base.php:91 -msgid "" -"Scan checks are not required to pass, however they could cause issues on " -"some systems." -msgstr "" -"Il n'est pas nécessaire que tous les résultats du scan soient positifs, " -"cependant cela pourrait poser des problèmes sur certains systèmes." - -#: views/packages/new2.base.php:92 -msgid "Process Time:" -msgstr "Durée du Processus :" - -#: views/packages/new2.base.php:101 -msgid "Server" -msgstr "Serveur" - -#: views/packages/new2.base.php:103 views/tools/controller.php:17 -msgid "Diagnostics" -msgstr "Diagnostics" - -#: views/packages/new2.base.php:112 views/packages/new2.base.php:117 -#: views/tools/diagnostics.php:106 -msgid "Web Server" -msgstr "Serveur Web" - -#: views/packages/new2.base.php:119 -msgid "Supported web servers:" -msgstr "Serveurs web compatibles :" - -#: views/packages/new2.base.php:129 -msgid "PHP Setup" -msgstr "Configuration PHP" - -#: views/packages/new2.base.php:135 -msgid "Open Base Dir" -msgstr "Ouvrir le Répertoire de Base" - -#: views/packages/new2.base.php:137 -msgid "" -"Issues might occur when [open_basedir] is enabled. Work with your server " -"admin to disable this value in the php.ini file if you’re having issues " -"building a package." -msgstr "" -"Duplicator peut rencontrer des problèmes quand [open_basedir] est activé. " -"Merci de voir avec votre administrateur réseau s'il peut désactiver " -"cette fonction dans le fichier php.ini, si vous avez des problèmes pour " -"générer des paquets." - -#: views/packages/new2.base.php:138 views/packages/new2.base.php:148 -#: views/packages/new2.base.php:155 -msgid "details" -msgstr "détails" - -#: views/packages/new2.base.php:143 views/tools/diagnostics.php:189 -msgid "Max Execution Time" -msgstr "Temps Maximum d'Exécution" - -#: views/packages/new2.base.php:145 -#, php-format -msgid "" -"Issues might occur for larger packages when the [max_execution_time] value " -"in the php.ini is too low. The minimum recommended timeout is \"%1$s\" " -"seconds or higher. An attempt is made to override this value if the server " -"allows it. A value of 0 (recommended) indicates that PHP has no time limits." -msgstr "" -"Duplicator peut rencontrer des problèmes quand la valeur de " -"[max_execution_time] dans le fichier php.ini est trop faible. La valeur " -"recommandée est de \"%1$s\" secondes ou plus. Si le serveur l'autorise, " -"le plugin va essayer de forcer cette valeur. Une valeur de 0 (recommandé) " -"signifie qu'il n'y a pas de limite temporelle du côté de PHP." - -#: views/packages/new2.base.php:147 -msgid "" -"Note: Timeouts can also be set at the web server layer, so if the PHP max " -"timeout passes and you still see a build interrupt messages, then your web " -"server could be killing the process. If you are limited on processing " -"time, consider using the database or file filters to shrink the size of your " -"overall package. However use caution as excluding the wrong resources can " -"cause your install to not work properly." -msgstr "" -"Note : Le timeout peut également être utilisé comme couche de serveur. Si le " -"timeout maximum PHP est atteint et que voyez encore des messages d'" -"interruption dans le processus de création de paquet, alors votre serveur " -"doit tuer notre processus. Si vous êtes limités par ce temps de latence, " -"essayez donc d'utiliser les filtres de base de données ou de fichiers " -"afin de diminuer la taille du paquet final. Cependant, faites attention : " -"exclure les mauvaises ressources pourrait empêcher votre installation de " -"fonctionner correctement." - -#: views/packages/new2.base.php:152 -msgid "MySQLi" -msgstr "MySQLi" - -#: views/packages/new2.base.php:154 -msgid "" -"Creating the package does not require the mysqli module. However the " -"installer.php file requires that the PHP module mysqli be installed on the " -"server it is deployed on." -msgstr "" -"La création du paquet ne nécessite pas le modyle mysqli. Cependant le " -"fichier installer.php requiert que mysqli soit installé sur le serveur " -"utilisé pour le déploiement." - -#: views/packages/new2.base.php:164 -msgid "WordPress" -msgstr "WordPress" - -#: views/packages/new2.base.php:169 -msgid "WordPress Version" -msgstr "Version de WordPress" - -#: views/packages/new2.base.php:171 -#, php-format -msgid "" -"It is recommended to have a version of WordPress that is greater than %1$s" -msgstr "" -"Nous vous recommandons d'avoir une version de WordPress supérieure à %1$s" - -#: views/packages/new2.base.php:175 -msgid "Core Files" -msgstr "Fichiers Source" - -#: views/packages/new2.base.php:177 -msgid "" -"If the scanner is unable to locate the wp-config.php file in the root " -"directory, then you will need to manually copy it to its new location." -msgstr "" -"Si le scanner n'est pas en mesure de trouver le fichier wp-config.php " -"dans le répertoire racine alors vous devrez le copier manuellement à son " -"nouvel emplacement." - -#: views/packages/new2.base.php:183 -msgid "Cache Path" -msgstr "Chemin du Cache" - -#: views/packages/new2.base.php:185 -msgid "" -"Cached data will lead to issues at install time and increases your archive " -"size. It is recommended to empty your cache directory at build time. Use " -"caution when removing data from the cache directory. If you have a cache " -"plugin review the documentation for how to empty it; simply removing files " -"might cause errors on your site. The cache size minimum threshold is " -"currently set at " -msgstr "" -"Les données en cache risquent d'entrainer des problèmes influant sur le " -"temps d'installation et la taille de l'archive. Il est fortement " -"recommandé de vider votre répertoire de cache avant de créer un paquet. " -"Faites tout de même attention quand vous retirez des données du répertoire " -"de cache. Si vous utilisez un plugin de cache, merci de suivre leurs " -"instructions pour désinstaller proprement et vider les fichiers en cache. " -"Supprimer manuellement les fichiers de cache pourrait poser des conflits " -"avec d'autres plugins par la suite. La limite de taille minimale de " -"cache est actuellement fixée à " - -#: views/packages/new2.base.php:208 views/packages/new2.base.php:317 -msgid "Enabled" -msgstr "Activé" - -#: views/packages/new2.base.php:223 -msgid "File Count" -msgstr "Nombre de Fichiers" - -#: views/packages/new2.base.php:224 -msgid "Directory Count" -msgstr "Nombre de Répertoires" - -#: views/packages/new2.base.php:227 -#, php-format -msgid "" -"Total size represents all files minus any filters that have been setup. The " -"current thresholds that trigger warnings are %1$s for the entire site and " -"%2$s for large files." -msgstr "" -"La taille totale représente tous les fichiers à l'exception de ceux " -"exclus par vos soins. Le seuil actuel qui déclenche les avertissements est " -"de %1$s pour le site entier et de %2$s pour les fichiers volumineux." - -#: views/packages/new2.base.php:239 -msgid "Name Checks" -msgstr "Vérification des Noms" - -#: views/packages/new2.base.php:244 -msgid "" -"File or directory names may cause issues when working across different " -"environments and servers. Names that are over 250 characters, contain " -"special characters (such as * ? > < : / \\ |) or are unicode might cause " -"issues in a remote enviroment. It is recommended to remove or filter these " -"files before building the archive if you have issues at install time." -msgstr "" -"Des noms de fichiers ou de répertoires invalides peuvent poser des problèmes " -"en fonction des environnements et des serveurs. Les noms invalides dépassent " -"250 caractères ou contiennent des caractères interdits tels que * ? > < : / " -"\\ | ou encore unicodes. Il est recommandé de supprimer ou exclure ces " -"fichiers avant de créer une archive car sinon vous auriez des problèmes lors " -"de l'installation." - -#: views/packages/new2.base.php:247 views/packages/new2.base.php:265 -msgid "Show Paths" -msgstr "Voir les Chemins" - -#: views/packages/new2.base.php:256 -msgid "Large Files" -msgstr "Fichiers Volumineux" - -#: views/packages/new2.base.php:261 -#, php-format -msgid "" -"Large files such as movies or other backuped data can cause issues with " -"timeouts. The current check for large files is %1$s per file. If your " -"having issues creating a package consider excluding these files with the " -"files filter and manually moving them to your new location." -msgstr "" -"Les fichiers volumineux tels que les vidéos ou autres fichiers de sauvegarde " -"peuvent causer des problèmes avec les timeouts. La valeur actuelle pour les " -"fichiers volumineux est de %1$s par fichier. Si vous rencontrez des " -"problèmes lors de la création d'un paquet, envisagez d'exclure ces " -"fichiers et de les déplacer manuellement à leur future destination." - -#: views/packages/new2.base.php:275 -msgid "View Filters" -msgstr "Voir les Filtres" - -#: views/packages/new2.base.php:283 -msgid "No directory filters have been set." -msgstr "Aucun filtre de répertoire n'a été activé." - -#: views/packages/new2.base.php:288 -msgid "File Extensions" -msgstr "Extensions de Fichiers" - -#: views/packages/new2.base.php:293 -msgid "No file extension filters have been set." -msgstr "Aucun filtre d'extension de fichier n'a été activé." - -#: views/packages/new2.base.php:297 -msgid "" -"The lists above are the directories and file extension that will be excluded " -"from the archive." -msgstr "" -"Les répertoires et les extensions de fichiers ci-dessous seront exclus de " -"l'archive." - -#: views/packages/new2.base.php:332 -msgid "Tables" -msgstr "Tables" - -#: views/packages/new2.base.php:333 -msgid "Records" -msgstr "Enregistrements" - -#: views/packages/new2.base.php:336 -msgid "repair and optimization" -msgstr "réparer et optimiser" - -#: views/packages/new2.base.php:337 -#, php-format -msgid "" -"Total size and row count for all database tables are approximate values. " -"The thresholds that trigger warnings are %1$s and %2$s records. Large " -"databases take time to process and can cause issues with server timeout and " -"memory settings. Running a %3$s on your database can also help improve the " -"overall size and performance. If your server supports shell_exec and " -"mysqldump you can try to enable this option from the settings menu." -msgstr "" -"La taille totale et le nombre de colonnes pour les tables de toutes les " -"bases de données sont des valeurs approximatives. Les seuils qui déclenchent " -"des messages d'erreur sont %1$s et %2$s. Les base de données " -"volumineuses sont longues à traiter et peuvent poser des problèmes avec le " -"timeout serveur ainsi que les paramètres de stockage. Disposer d'un %3$s " -"sur votre base de données peut également améliorer la taille totale et les " -"performances. Si votre serveur est compatible shell_exec et mysqldump, " -"essayez d'activer cette option depuis le menu des paramètres." - -#: views/packages/new2.base.php:349 -msgid "Table Details" -msgstr "Détails de la Table" - -#: views/packages/new2.base.php:360 -msgid "Name:" -msgstr "Nom :" - -#: views/packages/new2.base.php:361 -msgid "Host:" -msgstr "Hébergeur :" - -#: views/packages/new2.base.php:362 -msgid "Build Mode:" -msgstr "Mode de Construction :" - -#: views/packages/new2.base.php:373 -msgid "Scan Error" -msgstr "Erreurs de Scan" - -#: views/packages/new2.base.php:374 -msgid "Please try again!" -msgstr "Merci de réessayer !" - -#: views/packages/new2.base.php:376 views/packages/new3.base.php:111 -msgid "Server Status:" -msgstr "Statut Serveur :" - -#: views/packages/new2.base.php:379 views/packages/new3.base.php:115 -msgid "Error Message:" -msgstr "Message d'Erreur :" - -#: views/packages/new2.base.php:386 -msgid "Back" -msgstr "Retour" - -#: views/packages/new2.base.php:387 -msgid "Rescan" -msgstr "Re-Scanner" - -#: views/packages/new2.base.php:486 -msgid "Unable to report on any tables" -msgstr "Impossible d'acquérir une quelconque table" - -#: views/packages/new2.base.php:495 -msgid "Unable to report on database stats" -msgstr "Impossible d'acquérir les statistiques de la base de données" - -#: views/packages/new2.base.php:514 -msgid "DIR" -msgstr "REPERTOIRE" - -#: views/packages/new2.base.php:520 views/packages/new2.base.php:533 -msgid "FILE" -msgstr "FICHIER" - -#: views/packages/new2.base.php:523 -msgid "No name warning issues found." -msgstr "Pas de problème de nom de fichiers." - -#: views/packages/new2.base.php:529 -msgid "No large files found." -msgstr "Aucun fichier volumineux trouvé." - -#: views/packages/new3.base.php:38 -msgid "Step 3: Build Package" -msgstr "Étape 3 : Assemblage du Paquet" - -#: views/packages/new3.base.php:55 -msgid "Building Package" -msgstr "Assemblage du Paquet en cours" - -#: views/packages/new3.base.php:58 -msgid "Keep this window open during the build process." -msgstr "Gardez cette fenêtre ouverte pendant le processus d'assemblage." - -#: views/packages/new3.base.php:59 -msgid "This may take several minutes." -msgstr "Cela peut prendre plusieurs minutes." - -#: views/packages/new3.base.php:63 -msgid "Build Status" -msgstr "Statut de l'Assemblage" - -#: views/packages/new3.base.php:70 -msgid "Package Completed" -msgstr "Paquet Assemblé" - -#: views/packages/new3.base.php:75 -msgid "Process Time" -msgstr "Temps d'Exécution" - -#: views/packages/new3.base.php:100 -msgid "Build Interrupt" -msgstr "Interruption de l'Assemblage" - -#: views/packages/new3.base.php:101 -msgid "The current build has experienced an issue." -msgstr "L'assemblage en cours a rencontré une erreur." - -#: views/packages/new3.base.php:103 -msgid "Please try the process again." -msgstr "Merci de réessayer l'assemblage à nouveau." - -#: views/packages/new3.base.php:105 -msgid "Diagnose" -msgstr "Diagnostic" - -#: views/packages/new3.base.php:106 -msgid "Try Again" -msgstr "Merci de réessayer" - -#: views/packages/new3.base.php:122 -msgid "Notice" -msgstr "Notification" - -#: views/packages/new3.base.php:125 -msgid "Build Folder:" -msgstr "Répertoires de l'Assemblage :" - -#: views/packages/new3.base.php:127 -msgid "" -"Some servers close connections quickly; yet the build can continue to run in " -"the background. To validate if a build is still running; open the 'tmp' " -"folder above and see if the archive file is growing in size. If it is not " -"then your server has strict timeout constraints. Please visit the support " -"page for additional resources." -msgstr "" -"Certains serveurs coupent leur connexion rapidement, cependant le processus " -"continue à fonctionner en arrière-plan. Pour vérifier qu'une création de " -"paquet est en cours, ouvrez le répertoire "tmp" ce-dessous and " -"regardez si l'archive est en train de grandir en taille. Si ce n'est pas " -"le cas, alors votre serveur a des timeouts stricts. Vous pouvez aller voir " -"la section "Aide" pour des ressources additionnelles. " - -#: views/packages/new3.base.php:136 -msgid "Package Log" -msgstr "Journaux des Paquets" - -#: views/settings/controller.php:22 views/tools/diagnostics.php:87 -msgid "General" -msgstr "Général" - -#: views/settings/general.php:6 -msgid "Settings Saved" -msgstr "Paramètres Sauvegardés" - -#: views/settings/general.php:75 -msgid "Plugin" -msgstr "Plugin" - -#: views/settings/general.php:83 -msgid "Uninstall" -msgstr "Désinstallation" - -#: views/settings/general.php:86 -msgid "Delete Plugin Settings" -msgstr "Effacer les paramètres du plugin" - -#: views/settings/general.php:89 -msgid "Delete Entire Storage Directory" -msgstr "Effacer tout le Répertoire de Stockage" - -#: views/settings/general.php:96 -msgid "Full Path" -msgstr "Chemin Complet" - -#: views/settings/general.php:99 -msgid "Disable .htaccess File In Storage Directory" -msgstr "Désactiver le fichier .htaccess dans le Répertoire de Stockage" - -#: views/settings/general.php:101 -msgid "Disable if issues occur when downloading installer/archive files." -msgstr "" -"Désactivez-le si vous n'arrivez pas à télécharger l'installer ou les " -"fichiers d'archive." - -#: views/settings/general.php:114 -msgid "Archive Flush" -msgstr "Effacement des Archives" - -#: views/settings/general.php:117 -msgid "Attempt Network Keep Alive" -msgstr "Tenter de garder le réseau en ligne" - -#: views/settings/general.php:118 -msgid "recommended only for large archives" -msgstr "recommandé seulement pour les archives volumineuses" - -#: views/settings/general.php:120 -msgid "" -"This will attempt to keep a network connection established for large " -"archives." -msgstr "" -"Ceci va essayer de garder une connexion réseau pour les archives " -"volumineuses." - -#: views/settings/general.php:125 -msgid "Database Build" -msgstr "Base de Données construite" - -#: views/settings/general.php:128 -msgid "Use PHP" -msgstr "Utiliser PHP" - -#: views/settings/general.php:131 -msgid "Query Limit Size" -msgstr "Limite de Taille des Requêtes" - -#: views/settings/general.php:140 -msgid "higher values speed up build times but uses more memory" -msgstr "" -"des valeurs élevées accélèrent le processus mais consomment plus de mémoire" - -#: views/settings/general.php:147 -msgid "This server does not have shell_exec configured to run." -msgstr "Ce serveur n'a pas shell_exec de paramétré." - -#: views/settings/general.php:149 -msgid "Please contact the server administrator to enable this feature." -msgstr "" -"Merci de contacter votre administrateur réseau pour activer cette " -"fonctionnalité." - -#: views/settings/general.php:154 -msgid "Use mysqldump" -msgstr "Utiliser mysqldump" - -#: views/settings/general.php:155 -msgid "recommended for large databases" -msgstr "recommandé pour les bases de données volumineuses" - -#: views/settings/general.php:160 -msgid "Working Path:" -msgstr "Chemin Fonctionnel :" - -#: views/settings/general.php:166 -msgid "" -"Mysqldump was not found at its default location or the location provided. " -"Please enter a path to a valid location where mysqldump can run. If the " -"problem persist contact your server administrator." -msgstr "" -"Mysqldump n'a pas été trouvé à son emplacement par défaut ou à l'" -"emplacement fourni. Merci d'entrer le chemin vers un emplacement où " -"mysqldump pourra tourner. Si le problème persiste, contactez votre " -"administrateur réseau." - -#: views/settings/general.php:171 -msgid "Add Custom Path:" -msgstr "Ajouter un chemin personnalisé :" - -#: views/settings/general.php:175 -msgid "This is the path to your mysqldump program." -msgstr "C'est le chemin vers le programme mysqldump." - -#: views/settings/general.php:184 -msgid "Package Debug" -msgstr "Débogage des Paquets" - -#: views/settings/general.php:187 -msgid "Show Package Debug Status in Packages Screen" -msgstr "Montrer le statut de débogage dans l'écran des Paquets" - -#: views/settings/general.php:195 -msgid "Roles & Capabilities" -msgstr "Rôles et Droits" - -#: views/settings/general.php:200 -msgid "Custom Roles" -msgstr "Rôles personnalisés" - -#: views/settings/general.php:203 -msgid "Enable User Role Editor Plugin Integration" -msgstr "Activer l'intégration avec le plugin User Rôle Editor" - -#: views/settings/general.php:210 -msgid "The User Role Editor Plugin" -msgstr "Le plugin User Rôle Editor" - -#: views/settings/general.php:211 -msgid "Free" -msgstr "Gratuit" - -#: views/settings/general.php:212 -msgid "or" -msgstr "ou" - -#: views/settings/general.php:213 -msgid "Professional" -msgstr "Professionnel" - -#: views/settings/general.php:214 -msgid "must be installed to use" -msgstr "doit être installé" - -#: views/settings/general.php:215 -msgid "this feature." -msgstr "cette fonctionnalité." - -#: views/settings/general.php:227 -msgid "Save Settings" -msgstr "Sauvegarder les Paramètres" - -#: views/tools/cleanup.php:8 -msgid "Installer File Cleanup Ran." -msgstr "Le Nettoyage des Fichiers d'Installation a eu lieu." - -#: views/tools/cleanup.php:12 views/tools/diagnostics.php:44 -msgid "Legacy data removed." -msgstr "Version originale supprimée." - -#: views/tools/cleanup.php:16 -msgid "Build cache removed." -msgstr "Cache supprimé." - -#: views/tools/cleanup.php:73 -msgid "" -"If the installer files did not successfully get removed, then you WILL need " -"to remove them manually" -msgstr "" -"Si les fichiers d'nstallation ne sont pas supprimés, il vous faudra " -"ABSOLUMENT les enlever manuellement" - -#: views/tools/cleanup.php:74 -msgid "" -"Please remove all installer files to avoid leaving open security issues on " -"your server" -msgstr "" -"Merci de retirer tous les fichiers d'installation pour éviter de laisser " -"des failles de sécurité sur votre serveur" - -#: views/tools/cleanup.php:82 -msgid "Data Cleanup" -msgstr "Nettoyage des Données" - -#: views/tools/cleanup.php:85 -msgid "Delete Reserved Files" -msgstr "Supprimer les Fichiers Réservés" - -#: views/tools/cleanup.php:86 -msgid "Removes all installer files from a previous install" -msgstr "" -"Retirer tous les fichiers d'installation d'une version antérieure" - -#: views/tools/cleanup.php:89 -msgid "Delete Legacy Data" -msgstr "Supprimer les Données Originales" - -#: views/tools/cleanup.php:90 -msgid "Removes all legacy data and settings prior to version" -msgstr "" -"Supprimer toutes les données originales et les paramètres antérieurs à cette " -"version" - -#: views/tools/cleanup.php:93 -msgid "Clear Build Cache" -msgstr "Supprimer le Cache" - -#: views/tools/cleanup.php:94 -msgid "Removes all build data from:" -msgstr "Supprimer toutes les données de :" - -#: views/tools/cleanup.php:107 -#, php-format -msgid "This action will remove all legacy settings prior to version %1$s. " -msgstr "" -"Cette action va supprimer tous les paramètres antérieurs à la version %1$s." - -#: views/tools/cleanup.php:108 -msgid "" -"Legacy settings are only needed if you plan to migrate back to an older " -"version of this plugin." -msgstr "" -"Les paramètres originaux ne sont nécessaires que si vous avez prévu de " -"migrer vers une ancienne version du plugin." - -#: views/tools/cleanup.php:120 -msgid "" -"This process will remove all build cache files. Be sure no packages are " -"currently building or else they will be cancelled." -msgstr "" -"Ce processus va supprimer tous les fichiers de cache. Vérifiez qu'aucun " -"paquet ne soit en cours de création car sinon il serait supprimé." - -#: views/tools/controller.php:16 -msgid "Logging" -msgstr "Connexion" - -#: views/tools/controller.php:18 -msgid "Cleanup" -msgstr "Nettoyage" - -#: views/tools/diagnostics.php:18 views/tools/diagnostics.php:19 -msgid "unknow" -msgstr "inconnu" - -#: views/tools/diagnostics.php:39 -msgid "Plugin settings reset." -msgstr "Paramètres des plugins émis à zéro." - -#: views/tools/diagnostics.php:40 -msgid "View state settings reset." -msgstr "Voir l'état de la remise à zéro des paramètres." - -#: views/tools/diagnostics.php:41 -msgid "Active package settings reset." -msgstr "Activer la remise à zéro des paramètres dup paquet" - -#: views/tools/diagnostics.php:81 -msgid "Server Settings" -msgstr "Paramètres Serveur" - -#: views/tools/diagnostics.php:90 -msgid "Duplicator Version" -msgstr "Version de Duplicator" - -#: views/tools/diagnostics.php:94 -msgid "Operating System" -msgstr "Système d'Exploitation" - -#: views/tools/diagnostics.php:98 -msgid "Timezone" -msgstr "Fuseau Horaire" - -#: views/tools/diagnostics.php:102 -msgid "Server Time" -msgstr "Fuseau du Serveur" - -#: views/tools/diagnostics.php:110 -msgid "APC Enabled" -msgstr "APC Activé" - -#: views/tools/diagnostics.php:114 -msgid "Root Path" -msgstr "Chemin vers la Racine" - -#: views/tools/diagnostics.php:118 -msgid "ABSPATH" -msgstr "Chemin Absolu" - -#: views/tools/diagnostics.php:122 -msgid "Plugins Path" -msgstr "Chemin des Plugins" - -#: views/tools/diagnostics.php:126 -msgid "Loaded PHP INI" -msgstr "Charger PHP INI" - -#: views/tools/diagnostics.php:130 -msgid "Server IP" -msgstr "IP du Serveur" - -#: views/tools/diagnostics.php:134 -msgid "Client IP" -msgstr "IP client" - -#: views/tools/diagnostics.php:145 -msgid "Langugage" -msgstr "Langue" - -#: views/tools/diagnostics.php:149 views/tools/diagnostics.php:204 -msgid "Charset" -msgstr "Jeu de Caractères" - -#: views/tools/diagnostics.php:153 -msgid "Memory Limit " -msgstr "Limite de Mémoire" - -#: views/tools/diagnostics.php:154 -msgid "Max" -msgstr "Max" - -#: views/tools/diagnostics.php:172 -msgid "Safe Mode" -msgstr "Mode Sécurité" - -#: views/tools/diagnostics.php:176 -msgid "On" -msgstr "On" - -#: views/tools/diagnostics.php:176 -msgid "Off" -msgstr "Off" - -#: views/tools/diagnostics.php:181 -msgid "Memory Limit" -msgstr "Limite de Mémoire" - -#: views/tools/diagnostics.php:185 -msgid "Memory In Use" -msgstr "Mémoire Utilisée" - -#: views/tools/diagnostics.php:193 -msgid "Shell Exec" -msgstr "Shell Exec" - -#: views/tools/diagnostics.php:194 -msgid "Is Supported" -msgstr "Est Compatible" - -#: views/tools/diagnostics.php:194 -msgid "Not Supported" -msgstr "N'est plus Compatible" - -#: views/tools/diagnostics.php:208 -msgid "Wait Timeout" -msgstr "Temps d'Attente dépassé" - -#: views/tools/diagnostics.php:212 -msgid "Max Allowed Packets" -msgstr "Nombre maximum de paquets de données" - -#: views/tools/diagnostics.php:216 -msgid "msyqldump Path" -msgstr "Chemin du mysqldump" - -#: views/tools/diagnostics.php:220 -msgid "Server Disk" -msgstr "Disque Serveur" - -#: views/tools/diagnostics.php:223 -msgid "Free space" -msgstr "Espace libre" - -#: views/tools/diagnostics.php:226 -msgid "Note: This value is the physical servers hard-drive allocation." -msgstr "" -"Note : Cette donnée est l'allocation du disque dur dans le serveur " -"physique." - -#: views/tools/diagnostics.php:227 -msgid "" -"On shared hosts check your control panel for the 'TRUE' disk space quota " -"value." -msgstr "" -"Pour les hébergements mutualisés, vérifiez dans votre tableau de bord la " -""vraie" valeur d'espace disque." - -#: views/tools/diagnostics.php:243 -msgid "Stored Data" -msgstr "Donnée Enregistrée" - -#: views/tools/diagnostics.php:248 -msgid "Options Values" -msgstr "Options de Valeurs" - -#: views/tools/diagnostics.php:281 -msgid "PHP Information" -msgstr "Information PHP" - -#: views/tools/diagnostics.php:300 -msgid "Delete this option value" -msgstr "Effacer cette option de valeur" - -#: views/tools/logging.php:140 -msgid "Log file not found or unreadable" -msgstr "Fichiers journaux introuvables ou illisibles" - -#: views/tools/logging.php:142 -msgid "" -"Try to create a package, since no log files were found in the snapshots " -"directory with the extension *.log" -msgstr "" -"Essayez de créer un paquet puisqu'aucun fichier journal n'a été " -"trouvé dans le répertoire des instantanés avec l'extension *.log" - -#: views/tools/logging.php:144 -msgid "Reasons for log file not showing" -msgstr "Raisons pour lesquelles le fichier journal ne s'affiche pas" - -#: views/tools/logging.php:145 -msgid "The web server does not support returning .log file extentions" -msgstr "" -"Le serveur web ne prend pas en charge les fichiers avec les extensions .log" - -#: views/tools/logging.php:146 -msgid "" -"The snapshots directory does not have the correct permissions to write " -"files. Try setting the permissions to 755" -msgstr "" -"Le répertoire des instantanés n'a pas les bonnes permissions pour écrire " -"les fichiers. Essayez de passer les permissions à 755" - -#: views/tools/logging.php:147 -msgid "" -"The process that PHP runs under does not have enough permissions to create " -"files. Please contact your hosting provider for more details" -msgstr "" -"Le processus PHP n'a pas assez de permissions pour créer les fichiers. " -"Merci de contacter votre hébergeur pour plus de détails" - -#: views/tools/logging.php:156 views/tools/logging.php:161 -msgid "Options" -msgstr "Options" - -#: views/tools/logging.php:163 -msgid "Refresh" -msgstr "Rafraîchir" - -#: views/tools/logging.php:168 -msgid "Auto Refresh" -msgstr "Rafraîchissement automatique" - -#: views/tools/logging.php:174 -msgid "Last 20 Logs" -msgstr "Les derniers 20 rapports" - -#. Plugin Name of the plugin/theme -msgid "Duplicator" -msgstr "" - -#. Plugin URI of the plugin/theme -msgid "http://www.lifeinthegrid.com/duplicator/" -msgstr "" - -#. Description of the plugin/theme -msgid "" -"Create a backup of your WordPress files and database. Duplicate and move an " -"entire site from one location to another in a few steps. Create a full " -"snapshot of your site at any point in time." -msgstr "" - -#. Author of the plugin/theme -msgid "LifeInTheGrid" -msgstr "" - -#. Author URI of the plugin/theme -msgid "http://www.lifeinthegrid.com" -msgstr "" - -#~ msgid "Backup and Move Made Easy!" -#~ msgstr "La sauvegarde et la duplication rendus faciles !" - -#~ msgid "The top-rated Duplicator plugin is going professional!" -#~ msgstr "Le plugin Duplicator passe en version pro !" - -#~ msgid "Custom Templates" -#~ msgstr "Modèles personnalisés" - -#~ msgid "" -#~ "Customize how each package is created and built with a customized " -#~ "template." -#~ msgstr "" -#~ "Personnalisez la façon dont chaque paquet sera créé avec un modèle " -#~ "prédéfini" - -#~ msgid "Cloud Storage" -#~ msgstr "Stockage sur le Cloud" - -#~ msgid "" -#~ "Backup up your entire package to the cloud with access to services like " -#~ "FTP and Dropbox." -#~ msgstr "" -#~ "Sauvegardez l'intégralité de votre paquet sur le cloud au travers du " -#~ "FTP ou de Dropbox." - -#~ msgid "Queued Processing" -#~ msgstr "Traitement de la file d'attente" - -#~ msgid "" -#~ "Enable the build of larger more complex packages and avoid server " -#~ "timeouts with queued processing." -#~ msgstr "" -#~ "Autorisez la construction de paquets plus gros et plus complexes et " -#~ "évitez les timeouts de votre serveur avec la file d'attente" - -#~ msgid "Format" -#~ msgstr "Format" - -#~ msgid "The Duplicator currently works with these web servers:" -#~ msgstr "" -#~ "Le plugin Duplicator fonctionne actuellement avec ces serveurs web : " - -#~ msgid "PHP Settings" -#~ msgstr "Paramètres PHP" - -#~ msgid "WordPress Settings" -#~ msgstr "Paramètres WordPress" - -#~ msgid "Found" -#~ msgstr "Trouvé" - -#~ msgid "Missing" -#~ msgstr "Manquant" - -#~ msgid "The cache size minimum threshold is currently set at " -#~ msgstr "Le seuil minimum de la taille de cache est actuellement à" - -#~ msgid "Invalid Names" -#~ msgstr "Noms Invalides" - -#~ msgid "Support" -#~ msgstr "Support" - -#~ msgid "By" -#~ msgstr "Par" - -#~ msgid "SQL File" -#~ msgstr "Fichier SQL" - -#~ msgid "Filters" -#~ msgstr "Filtres" - -#~ msgid "Report" -#~ msgstr "Signalez" - -#~ msgid "Check out other great resources" -#~ msgstr "Jetez un oeil à nos autres super ressources" - -#~ msgid "Get Help Now!" -#~ msgstr "Demander de l'aide" - -#~ msgid "support section" -#~ msgstr "le support" - -#~ msgid "support page" -#~ msgstr "le support" - -#~ msgid "Purpose of this package" -#~ msgstr "Raison d'être de ce paquet" - -#~ msgid "FAQ" -#~ msgstr "FAQ" - -#~ msgid "Partner" -#~ msgstr "Partenaire" - -#~ msgid "Approved Hosts" -#~ msgstr "Hébergeurs approuvés" - -#~ msgid "PHP Script Owner" -#~ msgstr "Propriétaire du Script PHP" - -#~ msgid "" -#~ "The above paths should have permissions of 755 for directories and 644 " -#~ "for files. You can temporarily try 777 if you continue to have issues. " -#~ "Also be sure to check the owner/group settings. For more details contact " -#~ "your host or server administrator." -#~ msgstr "" -#~ "Les chemins ci-dessous devraient avoir des permissions de 755 pour les " -#~ "répertoires et 644 pour les fichiers. Vous pouvez les passer à 777 mais " -#~ "seulement de manière temporaire, si vous rencontrez des problèmes. " -#~ "Veillez également à vérifier les paramètres de propriétaire/groupe. Pour " -#~ "plus de détails, contactez votre administrateur réseau." - -#~ msgid "Status Code" -#~ msgstr "Code Statut" - -#~ msgid "" -#~ "The ZipArchive extension for PHP is required for compression. Please " -#~ "contact your hosting provider if you're on a hosted server. For " -#~ "additional information see our online documentation." -#~ msgstr "" -#~ "L'extension ZipArchive pour PHP est requise pour la compression. " -#~ "Merci de contacter votre hébergeur si vous êtes sur un serveur mutualité. " -#~ "Pour plus d'informations, consultez notre aide en ligne." - -#~ msgid "" -#~ "Safe Mode should be set safe_mode=Off in you php.ini file. On hosted " -#~ "servers you may have to request this setting be turned off. Please note " -#~ "that Safe Mode is deprecated as of PHP 5.3.0" -#~ msgstr "" -#~ "Le Mode Sécurité devrait être réglé à safe_mode=Off dans votre fichier " -#~ "php.ini. Pour les hébergements mutualisés, vous devriez demander à ce que " -#~ "ce paramètre soit désactivé. Veuillez également noter que le Mode " -#~ "Sécurité est obsolète depuis la version 5.3.0 de PHP" - -#~ msgid "" -#~ "PHP versions 5.2.17+ or higher is required. Please note that in " -#~ "versioning logic a value such as 5.2.9 is less than 5.2.17. Please " -#~ "contact your server administrator to upgrade to a stable and secure " -#~ "version of PHP" -#~ msgstr "" -#~ "PHP dans sa version 5.2.17+ ou supérieure est requis. Veuillez noter que " -#~ "la logique des versions de PHP veut que 5.2.9 est inférieur à 5.2.17. " -#~ "Contactez alors votre administrateur pour qu'il mette à jour PHP à " -#~ "une version stable et sécurisée." - -#~ msgid "Need a hosting provider that is" -#~ msgstr "Besoin d'un hébergeur qui est" - -#~ msgid "duplicator approved" -#~ msgstr "compatible Duplicator" - -#~ msgid "knowledgebase" -#~ msgstr "base de connaissances" - -#~ msgid "in detail for many of the quick and common answers." -#~ msgstr "en détail pour la plupart des questions les plus courantes." - -#~ msgid "Need Help?" -#~ msgstr "Besoin d'aide ?" - -#~ msgid "Get Hosting!" -#~ msgstr "Trouver un Hébergeur !" - -#~ msgid "" -#~ "Please try the process again. If the problem persists please visit the " -#~ "support page." -#~ msgstr "" -#~ "Merci de réessayer l'assemblage à nouveau. Si le problème persiste, " -#~ "merci de visiter le support." - -#~ msgid "All" -#~ msgstr "Tous" - -#~ msgid "None" -#~ msgstr "Aucun" - -#~ msgid "Cached Data" -#~ msgstr "Données en Cache" - -#~ msgid "max_execution_time" -#~ msgstr "temps_execution_max" - -#~ msgid "" -#~ "Timeouts effect how long a process is allowed to run. The recommended " -#~ "timeout is \"%1$s\" seconds. An attempt is made to override this value if " -#~ "the enviroment allows it. A \"Warn\" status will not be an issue unless " -#~ "your host kills PHP processes after a certain amount of time. " -#~ msgstr "" -#~ "Les timeouts correspondent à la durée pendant laquelle un processus est " -#~ "autorisé d'être actif. Le timeout conseillé est de \"%1$s\" secondes. " -#~ "Un essai va être tenté pour imposer cette valeur si l'environnement " -#~ "le permet. Un message d'erreur ne devrait pas poser problème tant que " -#~ "votre hébergeur ne force pas la fermeture du processus PHP après un " -#~ "certain délai." - -#~ msgid "" -#~ "Timeouts can also be set at the web server layer, please work with your " -#~ "host or server administrator to make sure there are not restrictions for " -#~ "how long a PHP process is allowed to run. If you are limited on " -#~ "processing time, consider using the database or file filters to shrink " -#~ "the size of your overall package. However use caution as excluding the " -#~ "wrong resources can cause your install to not work properly." -#~ msgstr "" -#~ "Les timeouts peuvent également être une couche du serveur web. Merci de " -#~ "vérifier avec votre hébergeur ou votre administrateur réseau qu'il " -#~ "n'y ait pas de restriction de durée aux processus PHP. Si vous êtes " -#~ "limité, envisagez d'utiliser un filtre de base de données ou de " -#~ "fichiers afin de diminuer la taille totale du paquet. Cependant, maniez " -#~ "ces options avec minutie : exclure les mauvaises ressources empêcherait " -#~ "l'installation de fonctionner correctement ensuite." - -#~ msgid "Snapshot Directory" -#~ msgstr "Répertoire des instantanés" - -#~ msgid "Take A Quick 60 Second Survey" -#~ msgstr "Remplir un rapide questionnaire de 60 secondes" - -#~ msgid "Dashboard" -#~ msgstr "Tableau de Bord" - -#~ msgid "All About" -#~ msgstr "A propos" - -#~ msgid "If no log file is present the try to create a package" -#~ msgstr "" -#~ "Si vous ne trouvez pas de fichier journal, essayez de créer un paquet" - -#~ msgid "Duplicator: Create Package Log" -#~ msgstr "Duplicator : Créer les fichiers journaux" - -#~ msgid "" -#~ "Processing may take several minutes, please wait for progress bar to " -#~ "complete on the main status bar" -#~ msgstr "" -#~ "Le processus peut prendre plusieurs minutes, merci d'attendre que la " -#~ "barre de progression soit remplie" - -#~ msgid "" -#~ "Do NOT post this data to public sites like the WordPress.org forums as it " -#~ "contains sensitive data." -#~ msgstr "" -#~ "NE PUBLIEZ PAS ces données sur des sites publics tels que les forums " -#~ "WordPress.com : il s'agit de données sensibles." - -#~ msgid "Saving" -#~ msgstr "Sauvegarde" - -#~ msgid "Ready to create new package." -#~ msgstr "Prêt à créer le nouveau paquet." - -#~ msgid "Please enter a backup name." -#~ msgstr "Merci d'entrer un nom de sauvegarde." - -#~ msgid "Alpanumeric characters only on package name" -#~ msgstr "" -#~ "Seuls les caractères alphanumériques sont acceptés pour les noms de " -#~ "paquets" - -#~ msgid "Evaluating WordPress Setup. Please Wait" -#~ msgstr "Etude de votre installation WordPress. Merci de patienter." - -#~ msgid "Cancel" -#~ msgstr "Abandonner" - -#~ msgid "Checking System Status. Please Wait!" -#~ msgstr "Vérification du statut système. Merci de patienter !" - -#~ msgid "unreadable" -#~ msgstr "illisible" - -#~ msgid "error scanning directory" -#~ msgstr "erreur de lecture du répertoire" - -#~ msgid "AJAX Response" -#~ msgstr "Réponse AJAX" - -#~ msgid "" -#~ "Your LifeInTheGrid should be about working smarter not harder. With the " -#~ "Duplicator you can streamline your workflows and quickly clone a " -#~ "WordPress site in minutes. From Novice to Guru this plugin is designed " -#~ "for Bloggers, Admins, Developers, Designers, Entrepreneurs and anyone who " -#~ "uses WordPress." -#~ msgstr "" -#~ "Votre 'Vie Dans la Matrice' [LifeInTheGrid] devrait être tournée vers un " -#~ "travail plus intelligent, pas plus dur. Avec le Duplicator, vous pouvez " -#~ "rationaliser votre travail et rapidement cloner un site WordPress. Que " -#~ "vous soyez novice ou expert, ce plugin a été pensé pour les blogueurs, " -#~ "webmasters, développeurs, designers, entrepreneurs et tous ceux qui " -#~ "utilisent WordPress." - -#~ msgid "" -#~ "If you run into an issue feel free to submit a support ticket and visit " -#~ "our" -#~ msgstr "" -#~ "Si vous recentrez une erreur, n'hésitez pas à nous soumettre un ticket de " -#~ "support et visiter notre" - -#~ msgid "" -#~ "We also offer premium priority support for those who need feedback within " -#~ "24-48hrs. Please visit our " -#~ msgstr "" -#~ "Nous pouvons assurer un support premium pour ceux qui ont besoin d'aide " -#~ "en 24-48 heures. Merci de visiter notre" - -#~ msgid "service page" -#~ msgstr "page 'service'" - -#~ msgid "for more details." -#~ msgstr "pour plus de détails" - -#~ msgid "" -#~ "Consider a donation of any amount; it will take less than 60 seconds or " -#~ "about as fast as you can duplicate a site. These proceeds help to cover " -#~ "development and support costs. Thanks for your generosity!!" -#~ msgstr "" -#~ "60 secondes c'est le temps approximatif pour cloner un site. Si vous " -#~ "aimez gagner du temps alors faites-nous un don ! Cela nous aidera à " -#~ "couvrir les frais de développement et de support. Merci de votre " -#~ "générosité !" - -#~ msgid "Help out by leaving a 5 star review on the" -#~ msgstr "Aidez-nous en nous donnant un avis à 5 étoiles dans" - -#~ msgid "WordPress plugins directory" -#~ msgstr "le répertoire des plugins WordPress" - -#~ msgid "and by giving your opinion on the survey below." -#~ msgstr "et en nous donnant votre avis grâce au questionnaire ci-dessus." - -#~ msgid "Give us your Opinion?" -#~ msgstr "Vous souhaitez nous donner votre avis ?" - -#~ msgid "" -#~ "Spreading the word gives the plugin a wider audience which helps to pool " -#~ "more resources to test/support/develop and participate to improve the " -#~ "plugin. By getting the word out the Duplicator will continue to improve " -#~ "at a faster rate and harness the power of the open community to push the " -#~ "plugin further." -#~ msgstr "" -#~ "Partagez ce plugin lui donne la chance de toucher une plus large audience " -#~ "afin de trouver plus d'utilisateurs qui pourront nous aider à tester/" -#~ "contribuer/développer et participer à l'amélioration du plugin. En " -#~ "recommandant ce plugin à vos connaissances, cela nous permettra " -#~ "d'améliorer Duplicator à vitesse grand V en bénéficiant du pouvoir de la " -#~ "communauté." - -#~ msgid "Knowledge Base" -#~ msgstr "Base de Connaissances" - -#~ msgid "Blog" -#~ msgstr "Blog" - -#~ msgid "Labs" -#~ msgstr "Labos" - -#~ msgid "Package Name" -#~ msgstr "Nom du Paquet" - -#~ msgid "Create Package" -#~ msgstr "Créer un Paquet" - -#~ msgid "System Check" -#~ msgstr "Vérification du Système" - -#~ msgid "Show Create Log" -#~ msgstr "Voir le fichier journal de création" - -#~ msgid "Ready to create new package" -#~ msgstr "Prêt à créer un nouveau paquet" - -#~ msgid "Owner" -#~ msgstr "Propriétaire" - -#~ msgid "(Download Both)" -#~ msgstr "(Tout Télécharger)" - -#~ msgid "Secure Name" -#~ msgstr "Nom Sécurisé" - -#~ msgid "Show Download Links" -#~ msgstr "Montrer les Liens de Téléchargement" - -#~ msgid "Legacy Version" -#~ msgstr "Version Originale" - -#~ msgid "" -#~ "This package was built with a version that is no longer supported. It is " -#~ "highly recommended that this package be deleted. For more details see the" -#~ msgstr "" -#~ "Ce paquet a été créé avec une version précédente de Duplicator qui n'est " -#~ "plus supportée. Il est vivement recommandé de supprimer ce paquet. Pour " -#~ "plus de détails, allez voir" - -#~ msgid "Online FAQs" -#~ msgstr "les FAQs en ligne" - -#~ msgid "To create a new package, enter a name and click the create button " -#~ msgstr "" -#~ "Pour créer un nouveau paquet, donnez-lui un nom et cliquez sur le bouton " -#~ "\"Créer\"" - -#~ msgid "server's compatibility" -#~ msgstr "compatibilité de votre serveur" - -#~ msgid "with the duplicator" -#~ msgstr "avec Duplicator" - -#~ msgid "This process will backup all your files and database" -#~ msgstr "" -#~ "Ce processus va sauvegarder tous vos fichiers et votre base de données" - -#~ msgid "Creating a package may take several minutes if you have a large site" -#~ msgstr "" -#~ "Créer un paquet peut prendre plusieurs minutes si vous avez un gros site" - -#~ msgid "This window should remain open for the process to complete" -#~ msgstr "" -#~ "Cette fenêtre doit rester ouverte pour que le processus puisse marcher" - -#~ msgid "Please be patient while we work through this Beta version" -#~ msgstr "" -#~ "Merci de votre patience pendant que vous utilisez cette version Beta" - -#~ msgid "Please report any issues to" -#~ msgstr "Signalez-nous tout problème à" - -#~ msgid "Total Storage Used" -#~ msgstr "Mémoire Total Utilisée" - -#~ msgid "" -#~ "For a complete rundown of the Duplicator see the online knowledgebase by " -#~ "clicking the question button or any link below. If you experience " -#~ "issues with creating or installing a package check out the FAQ page first." -#~ msgstr "" -#~ "Pour une explication exhaustive de Duplicator, allez donc voir notre base " -#~ "de connaissances en ligne en cliquant sur le bouton interrogatif ou sur " -#~ "n'importe quel lien ci-dessous. Si vous rencontrez des problèmes pour " -#~ "créer ou installer un paquet, vérifiez d'abord la page FAQ." - -#~ msgid "" -#~ "Not all hosting companies are created equal and to get the most out of " -#~ "the plugin we recommend using hosting providers that we do our own " -#~ "testing on. Please visit our" -#~ msgstr "" -#~ "Tous les hébergeurs ne sont pas égaux. Afin de profiter du maximum du " -#~ "plugin, nous recommandons les hébergeurs que nous avons déjà testé. Allez " -#~ "donc voir notre" - -#~ msgid "Approved Affiliate Hosting Program" -#~ msgstr "Programme Affilié des Hébergeurs Approuvés" - -#~ msgid "" -#~ "and consider making a switch to hosts that we trust and have experienced " -#~ "good success with when using the Duplicator" -#~ msgstr "" -#~ "et envisagez de changer pour un hébergeur de confiance avec lequel nous " -#~ "avons vérifié que Duplicator fonctionnait." - -#~ msgid "" -#~ "If you run into an issue and have already read the FAQs feel free to " -#~ "submit a support ticket and we will try our best to respond within 5-10 " -#~ "business days or sooner if possible." -#~ msgstr "" -#~ "Si vous tombez sur un problème qui n'a pas encore été traité dans les " -#~ "FAQs, n'hésitez pas à nous envoyer un ticket de support et nous ferons " -#~ "notre maximum pour répondre dans les 5 à 10 jours ouvrés ou plus tôt si " -#~ "c'est possible." - -#~ msgid "If you need priority support within 24-48hrs please visit our " -#~ msgstr "" -#~ "Si vous avez besoin d'un support prioritaire en 24-48 heures, merci de " -#~ "visiter notre" - -#~ msgid "" -#~ "for more details. Premium support is 100% refundable if we are unable to " -#~ "resolve your issue." -#~ msgstr "" -#~ "pour plus de détails. Le support Premium est remboursé à 100% si nous " -#~ "n'arrivons pas à résoudre votre problème." - -#~ msgid "" -#~ "Most issues that occur with the Duplicator revolve around how a server is " -#~ "configured. In order to diagnose your issues we will require temporary " -#~ "admin accounts to your cPanel and WordPress Admin. Please fill out the " -#~ msgstr "" -#~ "La plupart des erreurs concernant le Duplicator sont concentrées autour " -#~ "des configurations serveur. Afin de diagnostiquer vos problèmes, il va " -#~ "nous falloir un accès administrateur temporaire vers votre cPanel et " -#~ "votre administration WordPress. Merci de remplir le" - -#~ msgid "Request Quote" -#~ msgstr "formulaire de demande de devis" - -#~ msgid "form and explain your issue in detail." -#~ msgstr "et de nous expliquer en détail vos problèmes." - -#~ msgid "System" -#~ msgstr "Système" - -#~ msgid "FTP" -#~ msgstr "FTP" - -#~ msgid "seconds" -#~ msgstr "secondes" - -#~ msgid "Max Memory" -#~ msgstr "Mémoire Max" - -#~ msgid "WP-Admin email is included. Add extra emails semicolon separated." -#~ msgstr "" -#~ "L'email WP-Admin est inclus. Ajoutez d'autres adresses emails séparées " -#~ "par des points-virgules." - -#~ msgid "Enable character conversion encoding" -#~ msgstr "Activer l'encodage de la conversion des caractères" - -#~ msgid "From" -#~ msgstr "De" - -#~ msgid "to" -#~ msgstr "à" - -#~ msgid "Disable this option for extended or double byte character sets" -#~ msgstr "" -#~ "Désactivez cette option pour les jeux de caractères étendus ou à double " -#~ "octet" - -#~ msgid "" -#~ "Having issues saving these options? Temporarily disable all 'Object " -#~ "Caches' (i.e. W3C Total Object Cache)" -#~ msgstr "" -#~ "Vous rencontrez des problèmes avec ces options ? Désactivez " -#~ "temporairement tous les 'Cache Objet' (dans W3 Total Cache par exemple)" - -#~ msgid "Install URL" -#~ msgstr "URL d'installation" - -#~ msgid "Delete entire snapshot directory when removing plugin" -#~ msgstr "" -#~ "Effacer l'intégralité du répertoire des Instantanés à la désintallation " -#~ "du plugin" - -#~ msgid "Save" -#~ msgstr "Sauvegarder" - -#~ msgid "Close" -#~ msgstr "Fermer" - -#~ msgid "Pre-Zip Overview" -#~ msgstr "Aperçu avant compression" - -#~ msgid "Perform Scan" -#~ msgstr "Faire un Scan" - -#~ msgid "" -#~ "Note: A scan will provide an estimate on the size of your file system. " -#~ "The scan will exclude items in the" -#~ msgstr "" -#~ "Note : Un scan va vous indiquer la taille estimée de votre fichier " -#~ "système. Il va exclure les éléments dans" - -#~ msgid "" -#~ "Files that are not readable by the plugin will not be included in the " -#~ "overview. Directories that are empty will not be included in the final " -#~ "package. " -#~ msgstr "" -#~ "Les fichiers qui ne sont pas lisibles par le plugin ne seront pas inclus " -#~ "dans l'aperçu. Les répertoires vides ne seront pas inclus dans le paquet " -#~ "final." - -#~ msgid "System Constraint" -#~ msgstr "Contraintes du Système" - -#~ msgid "Please try again! An issue has occurred." -#~ msgstr "Merci de réessayer ! Une erreur est survenue." - -#~ msgid "Recommendations" -#~ msgstr "Recommandations" - -#~ msgid "Validate" -#~ msgstr "Valider" - -#~ msgid "your system" -#~ msgstr "votre système" - -#~ msgid "refresh" -#~ msgstr "rafraîchir" - -#~ msgid "the dashboard." -#~ msgstr "le tableau de bord." - -#~ msgid "Monitor" -#~ msgstr "Surveillez" - -#~ msgid "" -#~ "your log file a few more minutes as processing may continue on some " -#~ "systems" -#~ msgstr "" -#~ "vos fichiers journaux encore quelques minutes le temps que le processus " -#~ "passe sur d'autres systèmes" - -#~ msgid "" -#~ "Contact your server admin to have the page timeout increased (see " -#~ "duration below)" -#~ msgstr "" -#~ "Contactez votre administrateur serveur afin qu'il augmente le 'timeout' " -#~ "de la page (voir la durée ci-dessous)" - -#~ msgid "" -#~ "Consider adding a directory filter in the options dialog if the process " -#~ "continues to timeout" -#~ msgstr "" -#~ "Essayez d'ajouter un filtre de répertoire dans les options si le " -#~ "processus continue à être avorté" - -#~ msgid "Check your disk space. For hosted sites review your providers help." -#~ msgstr "" -#~ "Vérifiez votre espace disque. Pour les sites hébergés, demandez l'aide à " -#~ "votre fournisseur." - -#~ msgid "Consider using an" -#~ msgstr "Songez à passer" - -#~ msgid "approved" -#~ msgstr "chez un" - -#~ msgid "hosting provider." -#~ msgstr "hébergeur approuvé." - -#~ msgid "See online help for more details at" -#~ msgstr "Consultez l'aide en ligne pour plus de détails à" - -#~ msgid "Please validate your system configuration." -#~ msgstr "Merci de valider votre configuration système." - -#~ msgid "Click link for details" -#~ msgstr "Cliquez sur le lien pour plus de détails" - -#~ msgid "SYSTEM REQUIRMENTS" -#~ msgstr "BESOINS SYSTEME" - -#~ msgid "" -#~ "The above paths should have permissions of 755 for directories and 644 " -#~ "for files. On some hosts the permission set requires 777. Setting items " -#~ "to 777 is a security issue and should only be set temporarily. Please " -#~ "avoid any hosting company that requires this kind of setup. See the " -#~ "'Duplicator Approved' link at the bottom of this dialog for a list of " -#~ "approved hosting providers." -#~ msgstr "" -#~ "Les chemins ci-dessous devraient avoir des permissions 755 pour les " -#~ "répertoires et 644 pour les fichiers. Certains hébergeurs demandent " -#~ "également de mettre les permissions à 777. Cela représente un danger pour " -#~ "la sécurité de votre site alors ne le laissez que temporairement (à " -#~ "l'exception d'Infomaniak). Pour consulter la liste des hébergeurs " -#~ "approuvés, allez voir la section 'Approuvée par Duplicator' à la fin de " -#~ "cette boîte de dialogue." - -#~ msgid "" -#~ "Also be sure to check the Owner/Group settings and validate they are " -#~ "correct and match other successful directories/files that are " -#~ "accessible. For more details contact your host or visit their help pages " -#~ "for more information on how they implement permissions and group settings." -#~ msgstr "" -#~ "Veillez également à vérifier les paramètres de Propriétaire ou de Groupe " -#~ "pour qu'ils vous donnent bien accès aux bons répertoires/fichiers. Pour " -#~ "plus de détails, contactez votre hébergeur ou visitez leurs pages de " -#~ "support pour plus d'information sur la configuration des permissions et " -#~ "des paramètres de groupe." - -#~ msgid "" -#~ "Safe Mode needs to be disabled in order for the Duplicator to operate " -#~ "correctly. Please set safe_mode = Off in you php.ini file. If you're on " -#~ "a hosted server and don't have access to the php.ini file then you will " -#~ "need to request this setting be updated. Safe Mode is no longer in future " -#~ "versions of PHP. If your host will not work with you to resolve the " -#~ "issue then consider a higher reputable hosting provider." -#~ msgstr "" -#~ "Le Mode Sécurité doit être désactivé afin que Duplicator fonctionne " -#~ "correctement. Merci de mettre safe_mode = Off dans votre fichier php.ini. " -#~ "Si vous êtes sur un serveur mutualisé et que vous n'avez pas accès à ce " -#~ "fichier, vous devrez contacter votre hébergeur pour qu'il le mette à " -#~ "jour. Le Mode Sécurité n'existe plus dans les versions suivantes de PHP. " -#~ "Si votre hébergeur ne vous aide pas à résoudre ce problème, envisagez de " -#~ "changer de fournisseur d'hébergement." - -#~ msgid "" -#~ "In order to complete an install the mysqli extension for PHP is required. " -#~ "If you are on a hosted server please contact your host and request that " -#~ "mysqli extension be enabled. For more information visit: http://php.net/" -#~ "manual/en/mysqli.installation.php" -#~ msgstr "" -#~ "Afin de finaliser l'installation, l'extension mysqli pour PHP est " -#~ "nécessaire. Si vous êtes sur un serveur mutualisé, contactez votre " -#~ "hébergeur et demandez-leur que cette extension soit activée. Pour plus " -#~ "d'informations, allez sur : http://php.net/manual/fr/mysqli.installation." -#~ "php" - -#~ msgid "SYSTEM CHECKS" -#~ msgstr "VERIFICATIONS SYSTEME" - -#~ msgid "Good" -#~ msgstr "Correct" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "PHP 5.2.17+ is required" -#~ msgstr "PHP 5.2.17+ est requis" - -#~ msgid "Fail" -#~ msgstr "Echec" - -#~ msgid "Not detected" -#~ msgstr "Non détecté" - -#~ msgid "PHP SAPI" -#~ msgstr "PHP SAPI" - -#~ msgid "Add to exclusion path now" -#~ msgstr "Ajouter aux chemins exclus maintenant" - -#~ msgid "Directory excluded" -#~ msgstr "Répertoire exclus" - -#~ msgid "Cache Directory Not Found" -#~ msgstr "Répertoire de Cache Introuvable" - -#~ msgid "ONLINE RESOURCES" -#~ msgstr "RESSOURCES EN LIGNE" - -#~ msgid "" -#~ "The following directories should have permissions of 755 and files 644. " -#~ "Keep in mind that PHP may be accessing the paths/files as the user id " -#~ "that the web server runs as." -#~ msgstr "" -#~ "Les répertoires suivants devraient avoir des permissions en 755 et les " -#~ "fichiers en 644. Gardez à l'esprit que PHP peut accéder aux chemins/" -#~ "fichiers avec le même identifiant que le serveur." diff --git a/lang/wpduplicator.mo b/lang/wpduplicator.mo deleted file mode 100644 index b5c96ff4..00000000 Binary files a/lang/wpduplicator.mo and /dev/null differ diff --git a/lang/wpduplicator.po b/lang/wpduplicator.po deleted file mode 100644 index 6a83f514..00000000 --- a/lang/wpduplicator.po +++ /dev/null @@ -1,772 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: WPDuplicator\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 06:56-0700\n" -"PO-Revision-Date: 2012-08-16 06:56-0700\n" -"Last-Translator: Cory Lamle \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-KeywordsList: __;_e\n" -"X-Poedit-Basepath: ./\n" -"X-Poedit-SearchPath-0: ..\n" - -#: ../duplicator.php:195 -msgid "FAQ" -msgstr "" - -#: ../duplicator.php:196 -msgid "Partner" -msgstr "" - -#: ../duplicator.php:197 -msgid "Approved Hosts" -msgstr "" - -#: ../duplicator.php:248 -msgid "Dashboard" -msgstr "" - -#: ../duplicator.php:250 -msgid "Diagnostics" -msgstr "" - -#: ../duplicator.php:281 -msgid "Manage" -msgstr "" - -#: ../installer/log-read.php:42 -msgid "Log file not found or unreadable" -msgstr "" - -#: ../installer/log-read.php:44 -msgid "" -"The log file for the Duplicator Plugin can be found in the snapshots " -"directory with the extension *.log" -msgstr "" - -#: ../installer/log-read.php:45 -msgid "If no log file is present the try to create a package" -msgstr "" - -#: ../installer/log-read.php:47 -msgid "Reasons for log file not showing" -msgstr "" - -#: ../installer/log-read.php:48 -msgid "The web server does not support returning .log file extentions" -msgstr "" - -#: ../installer/log-read.php:49 -msgid "" -"The snapshots directory does not have the correct permissions to write " -"files. Try setting the permissions to 755" -msgstr "" - -#: ../installer/log-read.php:50 -msgid "" -"The process that PHP runs under does not have enough permissions to create " -"files. Please contact your hosting provider for more details" -msgstr "" - -#: ../installer/log-view.php:100 -msgid "Duplicator: Create Package Log" -msgstr "" - -#: ../installer/log-view.php:103 -msgid "" -"Processing may take several minutes, please wait for progress bar to " -"complete on the main status bar" -msgstr "" - -#: ../installer/log-view.php:108 -msgid "Auto Refresh" -msgstr "" - -#: ../installer/log-view.php:109 -msgid "Refresh" -msgstr "" - -#: ../installer/log-view.php:117 -msgid "Support Center" -msgstr "" - -#: ../installer/log-view.php:118 -msgid "" -"Do NOT post this data to public sites like the WordPress.org forums as it " -"contains sensitive data." -msgstr "" - -#: ../inc/javascript.php:133 -msgid "Saving" -msgstr "" - -#: ../inc/javascript.php:154 -msgid "Please select at least one package to delete." -msgstr "" - -#: ../inc/javascript.php:158 -msgid "Are you sure, you want to delete the selected package(s)?" -msgstr "" - -#: ../inc/javascript.php:174 ../inc/javascript.php:213 -#: ../inc/javascript.php:322 ../inc/javascript.php:422 -#: ../inc/javascript.php:441 -msgid "Ready to create new package." -msgstr "" - -#: ../inc/javascript.php:189 -msgid "Please enter a backup name." -msgstr "" - -#: ../inc/javascript.php:197 -msgid "Alpanumeric characters only on package name" -msgstr "" - -#: ../inc/javascript.php:210 -msgid "Evaluating WordPress Setup. Please Wait" -msgstr "" - -#: ../inc/javascript.php:276 -msgid "Cancel" -msgstr "" - -#: ../inc/javascript.php:282 -msgid "Create Package Set" -msgstr "" - -#: ../inc/javascript.php:327 -msgid "Checking System Status. Please Wait!" -msgstr "" - -#: ../inc/javascript.php:353 -msgid "Scanning Please Wait" -msgstr "" - -#: ../inc/javascript.php:358 ../inc/javascript.php:359 -#: ../inc/javascript.php:360 -msgid "unreadable" -msgstr "" - -#: ../inc/javascript.php:361 -msgid "*Scan Error" -msgstr "" - -#: ../inc/javascript.php:362 -msgid "Files" -msgstr "" - -#: ../inc/javascript.php:362 -msgid "Folders" -msgstr "" - -#: ../inc/javascript.php:367 -msgid "error scanning directory" -msgstr "" - -#: ../inc/javascript.php:397 -msgid "DATABASE" -msgstr "" - -#: ../inc/javascript.php:398 -msgid "PACKAGE" -msgstr "" - -#: ../inc/javascript.php:399 -msgid "INSTALLER" -msgstr "" - -#: ../inc/javascript.php:418 -msgid "AJAX Response" -msgstr "" - -#: ../inc/javascript.php:436 -msgid "Creating package may take several minutes. Please Wait... " -msgstr "" - -#: ../inc/javascript.php:437 -msgid "Preview Log" -msgstr "" - -#: ../inc/page.main.php:31 -msgid "By" -msgstr "" - -#: ../inc/page.main.php:38 ../inc/page.main.php:82 -msgid "Package Name" -msgstr "" - -#: ../inc/page.main.php:41 -msgid "Create Package" -msgstr "" - -#: ../inc/page.main.php:42 -msgid "Delete selected package(s)" -msgstr "" - -#: ../inc/page.main.php:45 -msgid "Options" -msgstr "" - -#: ../inc/page.main.php:46 -msgid "System Check" -msgstr "" - -#: ../inc/page.main.php:47 -msgid "Show Create Log" -msgstr "" - -#: ../inc/page.main.php:50 -msgid "Help" -msgstr "" - -#: ../inc/page.main.php:51 -msgid "Partner with us" -msgstr "" - -#: ../inc/page.main.php:60 -msgid "Status" -msgstr "" - -#: ../inc/page.main.php:61 -msgid "Ready to create new package" -msgstr "" - -#: ../inc/page.main.php:77 -msgid "Select all packages" -msgstr "" - -#: ../inc/page.main.php:78 -msgid "Information" -msgstr "" - -#: ../inc/page.main.php:79 -msgid "Owner" -msgstr "" - -#: ../inc/page.main.php:80 -msgid "Created" -msgstr "" - -#: ../inc/page.main.php:81 -msgid "Size" -msgstr "" - -#: ../inc/page.main.php:84 -msgid "Package Set" -msgstr "" - -#: ../inc/page.main.php:85 -msgid "(Download Both)" -msgstr "" - -#: ../inc/page.main.php:116 ../inc/page.main.php:144 -msgid "View" -msgstr "" - -#: ../inc/page.main.php:122 ../inc/view.options.php:10 -msgid "Installer" -msgstr "" - -#: ../inc/page.main.php:123 ../inc/page.main.php:152 ../inc/view.options.php:9 -msgid "Package" -msgstr "" - -#: ../inc/page.main.php:129 -msgid "Version" -msgstr "" - -#: ../inc/page.main.php:130 -msgid "Secure Name" -msgstr "" - -#: ../inc/page.main.php:131 -msgid "Download SQL File" -msgstr "" - -#: ../inc/page.main.php:132 -msgid "Show Download Links" -msgstr "" - -#: ../inc/page.main.php:158 -msgid "Legacy Version" -msgstr "" - -#: ../inc/page.main.php:161 -msgid "" -"This package was built with a version that is no longer supported. It is " -"highly recommended that this package be deleted. For more details see the" -msgstr "" - -#: ../inc/page.main.php:162 -msgid "Online FAQs" -msgstr "" - -#: ../inc/page.main.php:174 -msgid "No packages found" -msgstr "" - -#: ../inc/page.main.php:175 -msgid "To create a new package, enter a name and click the create button " -msgstr "" - -#: ../inc/page.main.php:177 -msgid "Check Your" -msgstr "" - -#: ../inc/page.main.php:178 -msgid "servers compatability" -msgstr "" - -#: ../inc/page.main.php:179 -msgid "with the duplicator" -msgstr "" - -#: ../inc/page.main.php:180 -msgid "This process will backup all your files and database" -msgstr "" - -#: ../inc/page.main.php:181 -msgid "Creating a package may take several minutes if you have a large site" -msgstr "" - -#: ../inc/page.main.php:182 -msgid "This window should remain open for the process to complete" -msgstr "" - -#: ../inc/page.main.php:183 -msgid "Please be patient while we work through this Beta version" -msgstr "" - -#: ../inc/page.main.php:184 -msgid "Please report any issues to" -msgstr "" - -#: ../inc/page.main.php:201 -msgid "Total Storage Used" -msgstr "" - -#: ../inc/view.options.php:4 -msgid "Duplicator Options" -msgstr "" - -#: ../inc/view.options.php:11 -msgid "System" -msgstr "" - -#: ../inc/view.options.php:12 -msgid "FTP" -msgstr "" - -#: ../inc/view.options.php:22 -msgid "Processing" -msgstr "" - -#: ../inc/view.options.php:36 -msgid "Max Time" -msgstr "" - -#: ../inc/view.options.php:36 -msgid "seconds" -msgstr "" - -#: ../inc/view.options.php:37 -msgid "Max Memory" -msgstr "" - -#: ../inc/view.options.php:45 -msgid "Email when completed" -msgstr "" - -#: ../inc/view.options.php:46 -msgid "WP-Admin email is included. Add extra emails semicolon separated." -msgstr "" - -#: ../inc/view.options.php:55 -msgid "Exclusion Filters" -msgstr "" - -#: ../inc/view.options.php:57 -msgid "Directories" -msgstr "" - -#: ../inc/view.options.php:59 -msgid "Root Path" -msgstr "" - -#: ../inc/view.options.php:61 -msgid "File extensions" -msgstr "" - -#: ../inc/view.options.php:64 -msgid "Separate all filters by semicolon" -msgstr "" - -#: ../inc/view.options.php:69 -msgid "Database Encoding" -msgstr "" - -#: ../inc/view.options.php:72 -msgid "Enable character conversion encoding" -msgstr "" - -#: ../inc/view.options.php:77 -msgid "From" -msgstr "" - -#: ../inc/view.options.php:78 -msgid "to" -msgstr "" - -#: ../inc/view.options.php:79 -msgid "Disable this option for extended or double byte character sets" -msgstr "" - -#: ../inc/view.options.php:86 -msgid "" -"Having issues saving these options? Temporarily disable all 'Object " -"Caches' (i.e. W3C Total Object Cache)" -msgstr "" - -#: ../inc/view.options.php:96 -msgid "Settings Defaults" -msgstr "" - -#: ../inc/view.options.php:99 -msgid "Install URL" -msgstr "" - -#: ../inc/view.options.php:106 -msgid "Database Defaults" -msgstr "" - -#: ../inc/view.options.php:109 -msgid "Host" -msgstr "" - -#: ../inc/view.options.php:113 ../inc/view.system.php:8 -msgid "Name" -msgstr "" - -#: ../inc/view.options.php:117 -msgid "User" -msgstr "" - -#: ../inc/view.options.php:122 -msgid "" -"The installer can have these fields pre-filled at install time. These " -"values are optional." -msgstr "" - -#: ../inc/view.options.php:129 -msgid "Uninstall Options" -msgstr "" - -#: ../inc/view.options.php:132 -msgid "Delete Entire Snapshot Directory" -msgstr "" - -#: ../inc/view.options.php:133 -msgid "Snapshot Directory" -msgstr "" - -#: ../inc/view.options.php:161 -msgid "Save" -msgstr "" - -#: ../inc/view.options.php:162 -msgid "Close" -msgstr "" - -#: ../inc/view.system.php:3 -msgid "Package Creation" -msgstr "" - -#: ../inc/view.system.php:5 -msgid "Create a new Package Set?" -msgstr "" - -#: ../inc/view.system.php:10 ../inc/view.system.php:205 -msgid "Pre-Zip Overview" -msgstr "" - -#: ../inc/view.system.php:12 -msgid "Perform Scan" -msgstr "" - -#: ../inc/view.system.php:18 -msgid "" -"Note: A scan will provide an estimate on the size of your file system. The " -"scan will exclude items in the" -msgstr "" - -#: ../inc/view.system.php:19 -msgid "directory filter list" -msgstr "" - -#: ../inc/view.system.php:20 -msgid "" -"Files that are not readable by the plugin will not be included in the " -"overview. Directories that are empty will not be included in the final " -"package. " -msgstr "" - -#: ../inc/view.system.php:29 -msgid "System Constraint" -msgstr "" - -#: ../inc/view.system.php:32 -msgid "Please try again! An issue has occurred." -msgstr "" - -#: ../inc/view.system.php:36 -msgid "Recommendations" -msgstr "" - -#: ../inc/view.system.php:41 -msgid "Validate" -msgstr "" - -#: ../inc/view.system.php:42 -msgid "your system" -msgstr "" - -#: ../inc/view.system.php:43 -msgid "refresh" -msgstr "" - -#: ../inc/view.system.php:44 -msgid "the dashboard." -msgstr "" - -#: ../inc/view.system.php:48 -msgid "Monitor" -msgstr "" - -#: ../inc/view.system.php:49 -msgid "" -"your log file a few more minutes as processing may continue on some systems" -msgstr "" - -#: ../inc/view.system.php:52 -msgid "" -"Contact your server admin to have the page timeout increased (see duration " -"below)" -msgstr "" - -#: ../inc/view.system.php:53 -msgid "" -"Consider adding a directory filter in the options dialog if the process " -"continues to timeout" -msgstr "" - -#: ../inc/view.system.php:54 -msgid "Check your disk space. For hosted sites review your providers help." -msgstr "" - -#: ../inc/view.system.php:57 -msgid "Consider using an" -msgstr "" - -#: ../inc/view.system.php:59 -msgid "approved" -msgstr "" - -#: ../inc/view.system.php:60 -msgid "hosting provider." -msgstr "" - -#: ../inc/view.system.php:64 -msgid "Server Response" -msgstr "" - -#: ../inc/view.system.php:69 -msgid "See online help for more details at" -msgstr "" - -#: ../inc/view.system.php:79 -msgid "System Checks" -msgstr "" - -#: ../inc/view.system.php:82 -msgid "Please validate your system configuration." -msgstr "" - -#: ../inc/view.system.php:83 -msgid "Click link for details" -msgstr "" - -#: ../inc/view.system.php:92 -msgid "SYSTEM REQUIRMENTS" -msgstr "" - -#: ../inc/view.system.php:93 -msgid "File Permissions" -msgstr "" - -#: ../inc/view.system.php:96 -msgid "" -"The following directories should have permissions of 755 and files 644. " -"Keep in mind that PHP may be accessing the paths/files as the user id that " -"the web server runs as." -msgstr "" - -#: ../inc/view.system.php:116 -msgid "Reserved Files" -msgstr "" - -#: ../inc/view.system.php:119 -msgid "" -"If this check fails then a reserved file was found in the WordPress root " -"directory. The following are reserved file names installer.php, installer-" -"data.sql and installer-log.txt. In order to archive your data correctly " -"please remove any of these files from your WordPress root directory. Then " -"try creating your package again." -msgstr "" - -#: ../inc/view.system.php:124 -msgid "Zip Archive Enabled" -msgstr "" - -#: ../inc/view.system.php:127 -msgid "" -"The ZipArchive extension for PHP is required for compression. Please " -"contact your hosting provider if you're on a hosted server. For additional " -"information see our online documentation." -msgstr "" - -#: ../inc/view.system.php:132 -msgid "Safe Mode Off" -msgstr "" - -#: ../inc/view.system.php:135 -msgid "" -"Safe Mode needs to be disabled in order for the Duplicator to operate " -"correctly. Please set safe_mode = Off in you php.ini file. If you're on a " -"hosted server and don't have access to the php.ini file then you will need " -"to request this setting be updated. Safe Mode is no longer in future " -"versions of PHP. If your host will not work with you to resolve the issue " -"then consider a higher reputable hosting provider." -msgstr "" - -#: ../inc/view.system.php:140 -msgid "MySQLi Support" -msgstr "" - -#: ../inc/view.system.php:143 -msgid "" -"In order to complete an install the mysqli extension for PHP is required. If " -"you are on a hosted server please contact your host and request that mysqli " -"extension be enabled. For more information visit: http://php.net/manual/en/" -"mysqli.installation.php" -msgstr "" - -#: ../inc/view.system.php:152 -msgid "SYSTEM CHECKS" -msgstr "" - -#: ../inc/view.system.php:155 -msgid "PHP Version" -msgstr "" - -#: ../inc/view.system.php:157 ../inc/view.system.php:169 -#: ../inc/view.system.php:193 -msgid "Good" -msgstr "" - -#: ../inc/view.system.php:159 ../inc/view.system.php:172 -#: ../inc/view.system.php:175 ../inc/view.system.php:178 -#: ../inc/view.system.php:181 -msgid "OK" -msgstr "" - -#: ../inc/view.system.php:160 -msgid "PHP 5.2.17+ is required" -msgstr "" - -#: ../inc/view.system.php:162 ../inc/view.system.php:184 -#: ../inc/view.system.php:196 -msgid "Fail" -msgstr "" - -#: ../inc/view.system.php:168 ../inc/view.system.php:171 -#: ../inc/view.system.php:174 ../inc/view.system.php:177 -#: ../inc/view.system.php:180 ../inc/view.system.php:183 -msgid "Web Server" -msgstr "" - -#: ../inc/view.system.php:183 -msgid "Not detected" -msgstr "" - -#: ../inc/view.system.php:192 ../inc/view.system.php:195 -msgid "Open Base Dir" -msgstr "" - -#: ../inc/view.system.php:192 -msgid "Off" -msgstr "" - -#: ../inc/view.system.php:195 -msgid "On" -msgstr "" - -#: ../inc/view.system.php:202 -msgid "PHP SAPI" -msgstr "" - -#: ../inc/view.system.php:207 -msgid "Scan Now" -msgstr "" - -#: ../inc/view.system.php:216 -msgid "Cache Directory Found" -msgstr "" - -#: ../inc/view.system.php:217 -msgid "Add to exclusion path now" -msgstr "" - -#: ../inc/view.system.php:219 -msgid "Directory excluded" -msgstr "" - -#: ../inc/view.system.php:220 -msgid "Path" -msgstr "" - -#: ../inc/view.system.php:222 -msgid "Cache Directory Not Found" -msgstr "" - -#: ../inc/view.system.php:228 -msgid "ONLINE RESOURCES" -msgstr "" - -#: ../inc/view.system.php:233 -msgid "For additional online help please visit" -msgstr "" - -#: ../inc/view.system.php:239 -msgid "Need a hosting provider that is" -msgstr "" - -#: ../inc/view.system.php:241 -msgid "Duplicator Approved" -msgstr "" - -#: ../inc/view.system.php:252 -msgid "Download Links" -msgstr "" - -#: ../inc/view.system.php:255 -msgid "The following links contain sensitive data. Please share with caution!" -msgstr "" - -#: ../inc/view.system.php:261 -msgid "" -"The database SQL script is a quick link to your database backup script. An " -"exact copy is also stored in the package." -msgstr "" diff --git a/lang/wpduplicator.pot b/lang/wpduplicator.pot deleted file mode 100644 index 739ddbb0..00000000 --- a/lang/wpduplicator.pot +++ /dev/null @@ -1,1686 +0,0 @@ -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: WPDuplicator\n" -"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/duplicator\n" -"POT-Creation-Date: 2015-07-26 23:49+0200\n" -"PO-Revision-Date: 2015-04-13 09:10-0000\n" -"Last-Translator: Pedro Mendonça \n" -"Language-Team: \n" -"Language: en\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" -"X-Poedit-Basepath: ..\n" -"X-Generator: Poedit 1.8.2\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-WPHeader: duplicator.php\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPathExcluded-0: assets\n" - -#: classes/ui.php:111 -msgid "" -"Reserved Duplicator install file(s) still exists in the root directory. " -"Please delete these file(s) to avoid possible security issues." -msgstr "" - -#: classes/ui.php:112 -msgid "Remove file(s) now" -msgstr "" - -#: classes/ui.php:113 -msgid "Dismiss this notice" -msgstr "" - -#: classes/utility.php:249 -msgid "You do not have sufficient permissions to access this page." -msgstr "" - -#: duplicator.php:102 -msgid "Get Help" -msgstr "" - -#: duplicator.php:102 duplicator.php:191 views/help/help.php:29 -msgid "Help" -msgstr "" - -#: duplicator.php:103 -msgid "Support the Plugin" -msgstr "" - -#: duplicator.php:103 duplicator.php:195 views/help/about.php:41 -msgid "About" -msgstr "" - -#: duplicator.php:179 views/packages/controller.php:76 -#: views/packages/list.base.php:235 -msgid "Packages" -msgstr "" - -#: duplicator.php:183 views/settings/controller.php:19 -msgid "Settings" -msgstr "" - -#: duplicator.php:187 views/tools/controller.php:13 -msgid "Tools" -msgstr "" - -#: duplicator.php:246 -msgid "Manage" -msgstr "" - -#: views/help/about.php:54 -msgid "" -"Created for Admins, Developers and Designers the Duplicator can streamline " -"your workflows and help you quickly clone a WordPress application. " -"Migrating a WordPress site manually can be very time consuming. The " -"Duplicator was made to help you speed up the migration process. Please help " -"us to continue the development effort of this plugin." -msgstr "" - -#: views/help/about.php:64 -msgid "Support Duplicator" -msgstr "" - -#: views/help/about.php:71 -msgid "Partner with Us" -msgstr "" - -#: views/help/about.php:83 -msgid "Keep Active and Online" -msgstr "" - -#: views/help/about.php:90 -msgid "Leave 5 Stars" -msgstr "" - -#: views/help/about.php:107 -msgid "Spread the Word" -msgstr "" - -#: views/help/about.php:113 -msgid "Duplicate Your WordPress" -msgstr "" - -#: views/help/about.php:114 -msgid "Rapid WordPress Duplication by LifeInTheGrid.com" -msgstr "" - -#: views/help/about.php:131 -msgid "Get More Great Tools" -msgstr "" - -#: views/help/gopro.php:37 -msgid "Go Pro!" -msgstr "" - -#: views/help/gopro.php:46 -msgid "Duplicator Pro Has Arrived!" -msgstr "" - -#: views/help/gopro.php:49 -msgid "The simplicity of Duplicator" -msgstr "" - -#: views/help/gopro.php:50 -msgid "with the power the professional requires." -msgstr "" - -#: views/help/gopro.php:57 -msgid "Duplicator Free" -msgstr "" - -#: views/help/gopro.php:60 views/help/gopro.php:88 -msgid "Backup Files & Database" -msgstr "" - -#: views/help/gopro.php:61 views/help/gopro.php:89 -msgid "" -"Compresses all your WordPress files and database into a compressed snapshot " -"archive file." -msgstr "" - -#: views/help/gopro.php:64 views/help/gopro.php:92 -msgid "Directory Filters" -msgstr "" - -#: views/help/gopro.php:65 views/help/gopro.php:93 -msgid "" -"Filter out the directories and file extensions you want to include/exclude " -"in your in your archive file." -msgstr "" - -#: views/help/gopro.php:68 views/help/gopro.php:96 -msgid "Database Table Filters" -msgstr "" - -#: views/help/gopro.php:69 views/help/gopro.php:97 -msgid "" -"Filter out only the database tables you want to include/exclude in your " -"database creation script." -msgstr "" - -#: views/help/gopro.php:72 views/help/gopro.php:100 -msgid "Migration Wizard" -msgstr "" - -#: views/help/gopro.php:73 views/help/gopro.php:101 -msgid "" -"With just two files (archive & installer.php) move your site to a new " -"location." -msgstr "" - -#: views/help/gopro.php:85 views/packages/new1.inc.form.php:50 -msgid "Duplicator Pro" -msgstr "" - -#: views/help/gopro.php:104 -msgid "Scheduled Backups" -msgstr "" - -#: views/help/gopro.php:105 -msgid "" -"Automate the creation of your packages to run at various scheduled intervals." -msgstr "" - -#: views/help/gopro.php:108 -msgid "Dropbox Support" -msgstr "" - -#: views/help/gopro.php:109 -msgid "Backup up your entire site to Dropbox." -msgstr "" - -#: views/help/gopro.php:112 -msgid "FTP Support" -msgstr "" - -#: views/help/gopro.php:113 -msgid "Backup up your entire site to an FTP server." -msgstr "" - -#: views/help/gopro.php:116 -msgid "Customer Support" -msgstr "" - -#: views/help/gopro.php:117 -msgid "" -"Server setups can be quite complex, with pro you get prompt help to get your " -"site backed up and moved." -msgstr "" - -#: views/help/gopro.php:124 -msgid "Check It Out!" -msgstr "" - -#: views/help/help.php:38 -msgid "" -"Migrating WordPress is a complex process and the logic to make all the magic " -"happen smoothly may not work quickly with every site. With over 30,000 " -"plugins and a very complex server eco-system some migrations may run into " -"issues. This is why the Duplicator includes a detailed knowledgebase that " -"can help with many common issues. Resources to additional support, approved " -"hosting, and alternatives to fit your needs can be found below." -msgstr "" - -#: views/help/help.php:50 -msgid "Knowledgebase" -msgstr "" - -#: views/help/help.php:53 -msgid "Complete Online Documentation" -msgstr "" - -#: views/help/help.php:55 -msgid "Choose A Section" -msgstr "" - -#: views/help/help.php:56 -msgid "Quick Start" -msgstr "" - -#: views/help/help.php:57 -msgid "User Guide" -msgstr "" - -#: views/help/help.php:58 -msgid "FAQs" -msgstr "" - -#: views/help/help.php:59 -msgid "Change Log" -msgstr "" - -#: views/help/help.php:60 -msgid "Product Page" -msgstr "" - -#: views/help/help.php:69 -msgid "Online Support" -msgstr "" - -#: views/help/help.php:72 -msgid "Get Help From IT Professionals" -msgstr "" - -#: views/help/help.php:76 -msgid "Get Support!" -msgstr "" - -#: views/help/help.php:88 -msgid "Approved Hosting" -msgstr "" - -#: views/help/help.php:91 -msgid "Servers That Work With Duplicator" -msgstr "" - -#: views/help/help.php:94 -msgid "Trusted Providers!" -msgstr "" - -#: views/help/help.php:104 -msgid "Alternatives" -msgstr "" - -#: views/help/help.php:107 -msgid "Other Commercial Resources" -msgstr "" - -#: views/help/help.php:110 -msgid "Pro Solutions!" -msgstr "" - -#: views/packages/list-nodata.php:7 -msgid "No Packages Found." -msgstr "" - -#: views/packages/list-nodata.php:8 -msgid "Click the 'Create New' button to build a package." -msgstr "" - -#: views/packages/list-nodata.php:13 -msgid "Please visit the" -msgstr "" - -#: views/packages/list-nodata.php:14 views/packages/list-nodata.php:28 -#: views/packages/new1.base.php:234 -msgid "help page" -msgstr "" - -#: views/packages/list-nodata.php:15 -msgid "for additional support" -msgstr "" - -#: views/packages/list-nodata.php:24 -msgid "Older packages prior to 0.5.0 are no longer supported in this version." -msgstr "" - -#: views/packages/list-nodata.php:27 -msgid "To get an older package please visit the" -msgstr "" - -#: views/packages/list-nodata.php:29 -msgid "and look for the Change Log link for additional instructions." -msgstr "" - -#: views/packages/list-nodata.php:33 -msgid "Hide this message" -msgstr "" - -#: views/packages/list.base.php:39 -msgid "Help Support Duplicator" -msgstr "" - -#: views/packages/list.base.php:50 -msgid "Bulk Actions" -msgstr "" - -#: views/packages/list.base.php:51 -msgid "Delete selected package(s)" -msgstr "" - -#: views/packages/list.base.php:51 -msgid "Delete" -msgstr "" - -#: views/packages/list.base.php:53 -msgid "Apply" -msgstr "" - -#: views/packages/list.base.php:58 -msgid "Package Logs" -msgstr "" - -#: views/packages/list.base.php:61 views/packages/new1.base.php:96 -#: views/packages/new2.base.php:69 views/packages/new3.base.php:43 -#: views/packages/new3.base.php:89 -msgid "All Packages" -msgstr "" - -#: views/packages/list.base.php:62 views/packages/new1.base.php:97 -#: views/packages/new2.base.php:70 views/packages/new3.base.php:44 -msgid "Create New" -msgstr "" - -#: views/packages/list.base.php:87 -msgid "Select all packages" -msgstr "" - -#: views/packages/list.base.php:88 views/packages/new3.base.php:108 -msgid "Details" -msgstr "" - -#: views/packages/list.base.php:89 -msgid "Created" -msgstr "" - -#: views/packages/list.base.php:90 views/packages/new2.base.php:222 -#: views/packages/new2.base.php:334 -msgid "Size" -msgstr "" - -#: views/packages/list.base.php:91 views/packages/new1.inc.form.php:6 -#: views/packages/new1.inc.form.php:31 views/packages/new3.base.php:74 -msgid "Name" -msgstr "" - -#: views/packages/list.base.php:93 views/settings/general.php:110 -msgid "Package" -msgstr "" - -#: views/packages/list.base.php:124 -msgid "(No Notes Taken)" -msgstr "" - -#: views/packages/list.base.php:142 views/packages/list.base.php:187 -msgid "View" -msgstr "" - -#: views/packages/list.base.php:147 views/packages/new1.inc.form.php:176 -#: views/packages/new3.base.php:79 -msgid "Installer" -msgstr "" - -#: views/packages/list.base.php:150 views/packages/new1.inc.form.php:65 -#: views/packages/new2.base.php:195 views/packages/new3.base.php:83 -msgid "Archive" -msgstr "" - -#: views/packages/list.base.php:155 views/packages/list.base.php:200 -#: views/settings/general.php:79 views/tools/diagnostics.php:141 -#: views/tools/diagnostics.php:160 views/tools/diagnostics.php:200 -msgid "Version" -msgstr "" - -#: views/packages/list.base.php:156 views/packages/list.base.php:201 -#: views/packages/new1.inc.form.php:199 views/tools/diagnostics.php:168 -msgid "User" -msgstr "" - -#: views/packages/list.base.php:157 views/packages/list.base.php:202 -msgid "Hash" -msgstr "" - -#: views/packages/list.base.php:158 views/packages/list.base.php:207 -#: views/packages/new1.inc.form.php:8 views/packages/new1.inc.form.php:13 -msgid "Notes" -msgstr "" - -#: views/packages/list.base.php:160 -msgid "Links" -msgstr "" - -#: views/packages/list.base.php:161 -msgid "SQL" -msgstr "" - -#: views/packages/list.base.php:162 -msgid "Log" -msgstr "" - -#: views/packages/list.base.php:165 -msgid "Open Scan Report" -msgstr "" - -#: views/packages/list.base.php:166 -msgid "View Package Object" -msgstr "" - -#: views/packages/list.base.php:193 -msgid "View Error Details" -msgstr "" - -#: views/packages/list.base.php:205 -msgid "Unrecoverable Error! Please remove this package." -msgstr "" - -#: views/packages/list.base.php:210 -msgid "" -"This package has encountered errors. Click 'View Log' for more details. " -"For additional support see the " -msgstr "" - -#: views/packages/list.base.php:211 -msgid "online knowledgebase" -msgstr "" - -#: views/packages/list.base.php:213 -msgid "View Log" -msgstr "" - -#: views/packages/list.base.php:236 views/packages/new2.base.php:219 -#: views/packages/new2.base.php:328 -msgid "Total Size" -msgstr "" - -#: views/packages/list.base.php:255 -msgid "Download Links" -msgstr "" - -#: views/packages/list.base.php:258 -msgid "The following links contain sensitive data. Please share with caution!" -msgstr "" - -#: views/packages/list.base.php:264 -msgid "" -"The database SQL script is a quick link to your database backup script. An " -"exact copy is also stored in the package." -msgstr "" - -#: views/packages/list.base.php:287 -msgid "" -"Please select an action from the bulk action drop down menu to perform a " -"specific action." -msgstr "" - -#: views/packages/list.base.php:295 -msgid "Please select at least one package to delete." -msgstr "" - -#: views/packages/list.base.php:299 -msgid "Are you sure, you want to delete the selected package(s)?" -msgstr "" - -#: views/packages/list.base.php:333 -msgid "Package File Links" -msgstr "" - -#: views/packages/list.base.php:336 -msgid "DATABASE" -msgstr "" - -#: views/packages/list.base.php:337 -msgid "PACKAGE" -msgstr "" - -#: views/packages/list.base.php:338 -msgid "INSTALLER" -msgstr "" - -#: views/packages/list.base.php:339 -msgid "LOG" -msgstr "" - -#: views/packages/list.base.php:340 -msgid "REPORT" -msgstr "" - -#: views/packages/new1.base.php:13 -msgid "Package settings have been reset." -msgstr "" - -#: views/packages/new1.base.php:86 views/packages/new2.base.php:59 -#: views/packages/new3.base.php:33 -msgid "Setup" -msgstr "" - -#: views/packages/new1.base.php:87 views/packages/new2.base.php:60 -#: views/packages/new3.base.php:34 -msgid "Scan" -msgstr "" - -#: views/packages/new1.base.php:88 views/packages/new2.base.php:61 -#: views/packages/new2.base.php:388 views/packages/new3.base.php:35 -msgid "Build" -msgstr "" - -#: views/packages/new1.base.php:91 -msgid "Step 1: Package Setup" -msgstr "" - -#: views/packages/new1.base.php:115 -msgid "Requirements:" -msgstr "" - -#: views/packages/new1.base.php:124 -msgid "" -"System requirements must pass for the Duplicator to work properly. Click " -"each link for details." -msgstr "" - -#: views/packages/new1.base.php:130 -msgid "PHP Support" -msgstr "" - -#: views/packages/new1.base.php:136 -msgid "PHP Version" -msgstr "" - -#: views/packages/new1.base.php:140 -msgid "Zip Archive Enabled" -msgstr "" - -#: views/packages/new1.base.php:144 -msgid "Safe Mode Off" -msgstr "" - -#: views/packages/new1.base.php:148 views/packages/new1.base.php:152 -#: views/packages/new1.base.php:156 -msgid "Function" -msgstr "" - -#: views/packages/new1.base.php:161 -msgid "" -"PHP versions 5.2.17+ or higher is required. Please note that in versioning " -"logic a value such as 5.2.9 is less than 5.2.17. For compression to work the " -"ZipArchive extension for PHP is required. Safe Mode should be set to 'Off' " -"in you php.ini file and is deprecated as of PHP 5.3.0. For any issues in " -"this section please contact your hosting provider or server administrator. " -"For additional information see our online documentation." -msgstr "" - -#: views/packages/new1.base.php:169 -msgid "Permissions" -msgstr "" - -#: views/packages/new1.base.php:172 -msgid "Required Paths" -msgstr "" - -#: views/packages/new1.base.php:183 -msgid "" -"Permissions can be difficult to resolve on some systems. If the plugin can " -"not read the above paths here are a few things to try. 1) Set the above " -"paths to have permissions of 755 for directories and 644 for files. You can " -"temporarily try 777 however, be sure you don’t leave them this way. 2) Check " -"the owner/group settings for both files and directories. The PHP script " -"owner and the process owner are different. The script owner owns the PHP " -"script but the process owner is the user the script is running as, thus " -"determining its capabilities/privileges in the file system. For more details " -"contact your host or server administrator or visit the 'Help' menu under " -"Duplicator for additional online resources." -msgstr "" - -#: views/packages/new1.base.php:191 -msgid "Server Support" -msgstr "" - -#: views/packages/new1.base.php:197 -msgid "MySQL Version" -msgstr "" - -#: views/packages/new1.base.php:201 -msgid "MySQLi Support" -msgstr "" - -#: views/packages/new1.base.php:207 -msgid "" -"MySQL version 5.0+ or better is required and the PHP MySQLi extension (note " -"the trailing 'i') is also required. Contact your server administrator and " -"request that mysqli extension and MySQL Server 5.0+ be installed. Please " -"note in future versions support for other databases and extensions will be " -"added." -msgstr "" - -#: views/packages/new1.base.php:208 -msgid "more info" -msgstr "" - -#: views/packages/new1.base.php:217 -msgid "Reserved Files" -msgstr "" - -#: views/packages/new1.base.php:221 -msgid "" -"None of the reserved files (installer.php, installer-data.sql and installer-" -"log.txt) where found from a previous install. This means you are clear to " -"create a new package." -msgstr "" - -#: views/packages/new1.base.php:224 -msgid "" -"A reserved file(s) was found in the WordPress root directory. Reserved file " -"names are installer.php, installer-data.sql and installer-log.txt. To " -"archive your data correctly please remove any of these files from your " -"WordPress root directory. Then try creating your package again." -msgstr "" - -#: views/packages/new1.base.php:225 -msgid "Remove Files Now" -msgstr "" - -#: views/packages/new1.base.php:234 -msgid "For additional help please see the " -msgstr "" - -#: views/packages/new1.inc.form.php:10 -msgid "Create a new default name" -msgstr "" - -#: views/packages/new1.inc.form.php:23 views/settings/general.php:94 -msgid "Storage" -msgstr "" - -#: views/packages/new1.inc.form.php:32 -msgid "Type" -msgstr "" - -#: views/packages/new1.inc.form.php:33 -msgid "Location" -msgstr "" - -#: views/packages/new1.inc.form.php:38 -msgid "Default" -msgstr "" - -#: views/packages/new1.inc.form.php:39 -msgid "Local" -msgstr "" - -#: views/packages/new1.inc.form.php:45 -msgid "" -"All packages including the archive, installer and SQL script are stored in " -"the location above. " -msgstr "" - -#: views/packages/new1.inc.form.php:48 -msgid "Dropbox, FTP and other multiple storage options available in " -msgstr "" - -#: views/packages/new1.inc.form.php:67 -msgid "File filter enabled" -msgstr "" - -#: views/packages/new1.inc.form.php:68 -msgid "Database filter enabled" -msgstr "" - -#: views/packages/new1.inc.form.php:77 views/packages/new2.base.php:203 -msgid "Files" -msgstr "" - -#: views/packages/new1.inc.form.php:78 views/packages/new1.inc.form.php:195 -#: views/packages/new2.base.php:312 -msgid "Database" -msgstr "" - -#: views/packages/new1.inc.form.php:90 -msgid "Enable File Filters" -msgstr "" - -#: views/packages/new1.inc.form.php:94 views/packages/new1.inc.form.php:102 -msgid "Separate all filters by semicolon" -msgstr "" - -#: views/packages/new1.inc.form.php:94 views/packages/new2.base.php:278 -msgid "Directories" -msgstr "" - -#: views/packages/new1.inc.form.php:96 -msgid "root path" -msgstr "" - -#: views/packages/new1.inc.form.php:97 -msgid "wp-uploads" -msgstr "" - -#: views/packages/new1.inc.form.php:98 -msgid "cache" -msgstr "" - -#: views/packages/new1.inc.form.php:99 views/packages/new1.inc.form.php:106 -msgid "(clear)" -msgstr "" - -#: views/packages/new1.inc.form.php:102 -msgid "File extensions" -msgstr "" - -#: views/packages/new1.inc.form.php:104 -msgid "media" -msgstr "" - -#: views/packages/new1.inc.form.php:105 -msgid "archive" -msgstr "" - -#: views/packages/new1.inc.form.php:111 -msgid "" -"The directory paths and extensions above will be be excluded from the " -"archive file if enabled is checked." -msgstr "" - -#: views/packages/new1.inc.form.php:112 -msgid "Use the full path for directories and semicolons to separate all items." -msgstr "" - -#: views/packages/new1.inc.form.php:123 -msgid "Enable Table Filters" -msgstr "" - -#: views/packages/new1.inc.form.php:124 -msgid "checked tables are excluded" -msgstr "" - -#: views/packages/new1.inc.form.php:129 -msgid "Include All" -msgstr "" - -#: views/packages/new1.inc.form.php:130 -msgid "Exclude All" -msgstr "" - -#: views/packages/new1.inc.form.php:163 -msgid "" -"Checked tables will not be added to the database script. Excluding certain " -"tables can possibly cause your site or plugins to not work correctly after " -"install!" -msgstr "" - -#: views/packages/new1.inc.form.php:181 -msgid "STEP 1 - INPUTS" -msgstr "" - -#: views/packages/new1.inc.form.php:184 -msgid "MySQL Server" -msgstr "" - -#: views/packages/new1.inc.form.php:187 -msgid "Host" -msgstr "" - -#: views/packages/new1.inc.form.php:191 -msgid "Host Port" -msgstr "" - -#: views/packages/new1.inc.form.php:203 -msgid "Advanced Options" -msgstr "" - -#: views/packages/new1.inc.form.php:209 -msgid "SSL" -msgstr "" - -#: views/packages/new1.inc.form.php:212 -msgid "Enforce on Admin" -msgstr "" - -#: views/packages/new1.inc.form.php:216 -msgid "Enforce on Logins" -msgstr "" - -#: views/packages/new1.inc.form.php:220 -msgid "Cache" -msgstr "" - -#: views/packages/new1.inc.form.php:223 -msgid "Keep Enabled" -msgstr "" - -#: views/packages/new1.inc.form.php:227 -msgid "Keep Home Path" -msgstr "" - -#: views/packages/new1.inc.form.php:235 -msgid "STEP 2 - INPUTS" -msgstr "" - -#: views/packages/new1.inc.form.php:239 -msgid "New URL" -msgstr "" - -#: views/packages/new1.inc.form.php:245 -msgid "The installer can have these fields pre-filled at install time." -msgstr "" - -#: views/packages/new1.inc.form.php:245 -msgid "All values are optional." -msgstr "" - -#: views/packages/new1.inc.form.php:254 -msgid "Reset" -msgstr "" - -#: views/packages/new1.inc.form.php:255 -msgid "Next" -msgstr "" - -#: views/packages/new1.inc.form.php:267 -msgid "" -"This will reset all of the current package settings. Would you like to " -"continue?" -msgstr "" - -#: views/packages/new2.base.php:64 -msgid "Step 2: System Scan" -msgstr "" - -#: views/packages/new2.base.php:81 -msgid "Scanning Site" -msgstr "" - -#: views/packages/new2.base.php:83 views/packages/new3.base.php:57 -msgid "Please Wait..." -msgstr "" - -#: views/packages/new2.base.php:89 -msgid "Scan Complete" -msgstr "" - -#: views/packages/new2.base.php:91 -msgid "" -"Scan checks are not required to pass, however they could cause issues on " -"some systems." -msgstr "" - -#: views/packages/new2.base.php:92 -msgid "Process Time:" -msgstr "" - -#: views/packages/new2.base.php:101 -msgid "Server" -msgstr "" - -#: views/packages/new2.base.php:103 views/tools/controller.php:17 -msgid "Diagnostics" -msgstr "" - -#: views/packages/new2.base.php:112 views/packages/new2.base.php:117 -#: views/tools/diagnostics.php:106 -msgid "Web Server" -msgstr "" - -#: views/packages/new2.base.php:119 -msgid "Supported web servers:" -msgstr "" - -#: views/packages/new2.base.php:129 -msgid "PHP Setup" -msgstr "" - -#: views/packages/new2.base.php:135 -msgid "Open Base Dir" -msgstr "" - -#: views/packages/new2.base.php:137 -msgid "" -"Issues might occur when [open_basedir] is enabled. Work with your server " -"admin to disable this value in the php.ini file if you’re having issues " -"building a package." -msgstr "" - -#: views/packages/new2.base.php:138 views/packages/new2.base.php:148 -#: views/packages/new2.base.php:155 -msgid "details" -msgstr "" - -#: views/packages/new2.base.php:143 views/tools/diagnostics.php:189 -msgid "Max Execution Time" -msgstr "" - -#: views/packages/new2.base.php:145 -#, php-format -msgid "" -"Issues might occur for larger packages when the [max_execution_time] value " -"in the php.ini is too low. The minimum recommended timeout is \"%1$s\" " -"seconds or higher. An attempt is made to override this value if the server " -"allows it. A value of 0 (recommended) indicates that PHP has no time limits." -msgstr "" - -#: views/packages/new2.base.php:147 -msgid "" -"Note: Timeouts can also be set at the web server layer, so if the PHP max " -"timeout passes and you still see a build interrupt messages, then your web " -"server could be killing the process. If you are limited on processing " -"time, consider using the database or file filters to shrink the size of your " -"overall package. However use caution as excluding the wrong resources can " -"cause your install to not work properly." -msgstr "" - -#: views/packages/new2.base.php:152 -msgid "MySQLi" -msgstr "" - -#: views/packages/new2.base.php:154 -msgid "" -"Creating the package does not require the mysqli module. However the " -"installer.php file requires that the PHP module mysqli be installed on the " -"server it is deployed on." -msgstr "" - -#: views/packages/new2.base.php:164 -msgid "WordPress" -msgstr "" - -#: views/packages/new2.base.php:169 -msgid "WordPress Version" -msgstr "" - -#: views/packages/new2.base.php:171 -#, php-format -msgid "" -"It is recommended to have a version of WordPress that is greater than %1$s" -msgstr "" - -#: views/packages/new2.base.php:175 -msgid "Core Files" -msgstr "" - -#: views/packages/new2.base.php:177 -msgid "" -"If the scanner is unable to locate the wp-config.php file in the root " -"directory, then you will need to manually copy it to its new location." -msgstr "" - -#: views/packages/new2.base.php:183 -msgid "Cache Path" -msgstr "" - -#: views/packages/new2.base.php:185 -msgid "" -"Cached data will lead to issues at install time and increases your archive " -"size. It is recommended to empty your cache directory at build time. Use " -"caution when removing data from the cache directory. If you have a cache " -"plugin review the documentation for how to empty it; simply removing files " -"might cause errors on your site. The cache size minimum threshold is " -"currently set at " -msgstr "" - -#: views/packages/new2.base.php:208 views/packages/new2.base.php:317 -msgid "Enabled" -msgstr "" - -#: views/packages/new2.base.php:223 -msgid "File Count" -msgstr "" - -#: views/packages/new2.base.php:224 -msgid "Directory Count" -msgstr "" - -#: views/packages/new2.base.php:227 -#, php-format -msgid "" -"Total size represents all files minus any filters that have been setup. The " -"current thresholds that trigger warnings are %1$s for the entire site and " -"%2$s for large files." -msgstr "" - -#: views/packages/new2.base.php:239 -msgid "Name Checks" -msgstr "" - -#: views/packages/new2.base.php:244 -msgid "" -"File or directory names may cause issues when working across different " -"environments and servers. Names that are over 250 characters, contain " -"special characters (such as * ? > < : / \\ |) or are unicode might cause " -"issues in a remote enviroment. It is recommended to remove or filter these " -"files before building the archive if you have issues at install time." -msgstr "" - -#: views/packages/new2.base.php:247 views/packages/new2.base.php:265 -msgid "Show Paths" -msgstr "" - -#: views/packages/new2.base.php:256 -msgid "Large Files" -msgstr "" - -#: views/packages/new2.base.php:261 -#, php-format -msgid "" -"Large files such as movies or other backuped data can cause issues with " -"timeouts. The current check for large files is %1$s per file. If your " -"having issues creating a package consider excluding these files with the " -"files filter and manually moving them to your new location." -msgstr "" - -#: views/packages/new2.base.php:275 -msgid "View Filters" -msgstr "" - -#: views/packages/new2.base.php:283 -msgid "No directory filters have been set." -msgstr "" - -#: views/packages/new2.base.php:288 -msgid "File Extensions" -msgstr "" - -#: views/packages/new2.base.php:293 -msgid "No file extension filters have been set." -msgstr "" - -#: views/packages/new2.base.php:297 -msgid "" -"The lists above are the directories and file extension that will be excluded " -"from the archive." -msgstr "" - -#: views/packages/new2.base.php:332 -msgid "Tables" -msgstr "" - -#: views/packages/new2.base.php:333 -msgid "Records" -msgstr "" - -#: views/packages/new2.base.php:336 -msgid "repair and optimization" -msgstr "" - -#: views/packages/new2.base.php:337 -#, php-format -msgid "" -"Total size and row count for all database tables are approximate values. " -"The thresholds that trigger warnings are %1$s and %2$s records. Large " -"databases take time to process and can cause issues with server timeout and " -"memory settings. Running a %3$s on your database can also help improve the " -"overall size and performance. If your server supports shell_exec and " -"mysqldump you can try to enable this option from the settings menu." -msgstr "" - -#: views/packages/new2.base.php:349 -msgid "Table Details" -msgstr "" - -#: views/packages/new2.base.php:360 -msgid "Name:" -msgstr "" - -#: views/packages/new2.base.php:361 -msgid "Host:" -msgstr "" - -#: views/packages/new2.base.php:362 -msgid "Build Mode:" -msgstr "" - -#: views/packages/new2.base.php:373 -msgid "Scan Error" -msgstr "" - -#: views/packages/new2.base.php:374 -msgid "Please try again!" -msgstr "" - -#: views/packages/new2.base.php:376 views/packages/new3.base.php:111 -msgid "Server Status:" -msgstr "" - -#: views/packages/new2.base.php:379 views/packages/new3.base.php:115 -msgid "Error Message:" -msgstr "" - -#: views/packages/new2.base.php:386 -msgid "Back" -msgstr "" - -#: views/packages/new2.base.php:387 -msgid "Rescan" -msgstr "" - -#: views/packages/new2.base.php:486 -msgid "Unable to report on any tables" -msgstr "" - -#: views/packages/new2.base.php:495 -msgid "Unable to report on database stats" -msgstr "" - -#: views/packages/new2.base.php:514 -msgid "DIR" -msgstr "" - -#: views/packages/new2.base.php:520 views/packages/new2.base.php:533 -msgid "FILE" -msgstr "" - -#: views/packages/new2.base.php:523 -msgid "No name warning issues found." -msgstr "" - -#: views/packages/new2.base.php:529 -msgid "No large files found." -msgstr "" - -#: views/packages/new3.base.php:38 -msgid "Step 3: Build Package" -msgstr "" - -#: views/packages/new3.base.php:55 -msgid "Building Package" -msgstr "" - -#: views/packages/new3.base.php:58 -msgid "Keep this window open during the build process." -msgstr "" - -#: views/packages/new3.base.php:59 -msgid "This may take several minutes." -msgstr "" - -#: views/packages/new3.base.php:63 -msgid "Build Status" -msgstr "" - -#: views/packages/new3.base.php:70 -msgid "Package Completed" -msgstr "" - -#: views/packages/new3.base.php:75 -msgid "Process Time" -msgstr "" - -#: views/packages/new3.base.php:100 -msgid "Build Interrupt" -msgstr "" - -#: views/packages/new3.base.php:101 -msgid "The current build has experienced an issue." -msgstr "" - -#: views/packages/new3.base.php:103 -msgid "Please try the process again." -msgstr "" - -#: views/packages/new3.base.php:105 -msgid "Diagnose" -msgstr "" - -#: views/packages/new3.base.php:106 -msgid "Try Again" -msgstr "" - -#: views/packages/new3.base.php:122 -msgid "Notice" -msgstr "" - -#: views/packages/new3.base.php:125 -msgid "Build Folder:" -msgstr "" - -#: views/packages/new3.base.php:127 -msgid "" -"Some servers close connections quickly; yet the build can continue to run in " -"the background. To validate if a build is still running; open the 'tmp' " -"folder above and see if the archive file is growing in size. If it is not " -"then your server has strict timeout constraints. Please visit the support " -"page for additional resources." -msgstr "" - -#: views/packages/new3.base.php:136 -msgid "Package Log" -msgstr "" - -#: views/settings/controller.php:22 views/tools/diagnostics.php:87 -msgid "General" -msgstr "" - -#: views/settings/general.php:6 -msgid "Settings Saved" -msgstr "" - -#: views/settings/general.php:75 -msgid "Plugin" -msgstr "" - -#: views/settings/general.php:83 -msgid "Uninstall" -msgstr "" - -#: views/settings/general.php:86 -msgid "Delete Plugin Settings" -msgstr "" - -#: views/settings/general.php:89 -msgid "Delete Entire Storage Directory" -msgstr "" - -#: views/settings/general.php:96 -msgid "Full Path" -msgstr "" - -#: views/settings/general.php:99 -msgid "Disable .htaccess File In Storage Directory" -msgstr "" - -#: views/settings/general.php:101 -msgid "Disable if issues occur when downloading installer/archive files." -msgstr "" - -#: views/settings/general.php:114 -msgid "Archive Flush" -msgstr "" - -#: views/settings/general.php:117 -msgid "Attempt Network Keep Alive" -msgstr "" - -#: views/settings/general.php:118 -msgid "recommended only for large archives" -msgstr "" - -#: views/settings/general.php:120 -msgid "" -"This will attempt to keep a network connection established for large " -"archives." -msgstr "" - -#: views/settings/general.php:125 -msgid "Database Build" -msgstr "" - -#: views/settings/general.php:128 -msgid "Use PHP" -msgstr "" - -#: views/settings/general.php:131 -msgid "Query Limit Size" -msgstr "" - -#: views/settings/general.php:140 -msgid "higher values speed up build times but uses more memory" -msgstr "" - -#: views/settings/general.php:147 -msgid "This server does not have shell_exec configured to run." -msgstr "" - -#: views/settings/general.php:149 -msgid "Please contact the server administrator to enable this feature." -msgstr "" - -#: views/settings/general.php:154 -msgid "Use mysqldump" -msgstr "" - -#: views/settings/general.php:155 -msgid "recommended for large databases" -msgstr "" - -#: views/settings/general.php:160 -msgid "Working Path:" -msgstr "" - -#: views/settings/general.php:166 -msgid "" -"Mysqldump was not found at its default location or the location provided. " -"Please enter a path to a valid location where mysqldump can run. If the " -"problem persist contact your server administrator." -msgstr "" - -#: views/settings/general.php:171 -msgid "Add Custom Path:" -msgstr "" - -#: views/settings/general.php:175 -msgid "This is the path to your mysqldump program." -msgstr "" - -#: views/settings/general.php:184 -msgid "Package Debug" -msgstr "" - -#: views/settings/general.php:187 -msgid "Show Package Debug Status in Packages Screen" -msgstr "" - -#: views/settings/general.php:195 -msgid "Roles & Capabilities" -msgstr "" - -#: views/settings/general.php:200 -msgid "Custom Roles" -msgstr "" - -#: views/settings/general.php:203 -msgid "Enable User Role Editor Plugin Integration" -msgstr "" - -#: views/settings/general.php:210 -msgid "The User Role Editor Plugin" -msgstr "" - -#: views/settings/general.php:211 -msgid "Free" -msgstr "" - -#: views/settings/general.php:212 -msgid "or" -msgstr "" - -#: views/settings/general.php:213 -msgid "Professional" -msgstr "" - -#: views/settings/general.php:214 -msgid "must be installed to use" -msgstr "" - -#: views/settings/general.php:215 -msgid "this feature." -msgstr "" - -#: views/settings/general.php:227 -msgid "Save Settings" -msgstr "" - -#: views/tools/cleanup.php:8 -msgid "Installer File Cleanup Ran." -msgstr "" - -#: views/tools/cleanup.php:12 views/tools/diagnostics.php:44 -msgid "Legacy data removed." -msgstr "" - -#: views/tools/cleanup.php:16 -msgid "Build cache removed." -msgstr "" - -#: views/tools/cleanup.php:73 -msgid "" -"If the installer files did not successfully get removed, then you WILL need " -"to remove them manually" -msgstr "" - -#: views/tools/cleanup.php:74 -msgid "" -"Please remove all installer files to avoid leaving open security issues on " -"your server" -msgstr "" - -#: views/tools/cleanup.php:82 -msgid "Data Cleanup" -msgstr "" - -#: views/tools/cleanup.php:85 -msgid "Delete Reserved Files" -msgstr "" - -#: views/tools/cleanup.php:86 -msgid "Removes all installer files from a previous install" -msgstr "" - -#: views/tools/cleanup.php:89 -msgid "Delete Legacy Data" -msgstr "" - -#: views/tools/cleanup.php:90 -msgid "Removes all legacy data and settings prior to version" -msgstr "" - -#: views/tools/cleanup.php:93 -msgid "Clear Build Cache" -msgstr "" - -#: views/tools/cleanup.php:94 -msgid "Removes all build data from:" -msgstr "" - -#: views/tools/cleanup.php:107 -#, php-format -msgid "This action will remove all legacy settings prior to version %1$s. " -msgstr "" - -#: views/tools/cleanup.php:108 -msgid "" -"Legacy settings are only needed if you plan to migrate back to an older " -"version of this plugin." -msgstr "" - -#: views/tools/cleanup.php:120 -msgid "" -"This process will remove all build cache files. Be sure no packages are " -"currently building or else they will be cancelled." -msgstr "" - -#: views/tools/controller.php:16 -msgid "Logging" -msgstr "" - -#: views/tools/controller.php:18 -msgid "Cleanup" -msgstr "" - -#: views/tools/diagnostics.php:18 views/tools/diagnostics.php:19 -msgid "unknow" -msgstr "" - -#: views/tools/diagnostics.php:39 -msgid "Plugin settings reset." -msgstr "" - -#: views/tools/diagnostics.php:40 -msgid "View state settings reset." -msgstr "" - -#: views/tools/diagnostics.php:41 -msgid "Active package settings reset." -msgstr "" - -#: views/tools/diagnostics.php:81 -msgid "Server Settings" -msgstr "" - -#: views/tools/diagnostics.php:90 -msgid "Duplicator Version" -msgstr "" - -#: views/tools/diagnostics.php:94 -msgid "Operating System" -msgstr "" - -#: views/tools/diagnostics.php:98 -msgid "Timezone" -msgstr "" - -#: views/tools/diagnostics.php:102 -msgid "Server Time" -msgstr "" - -#: views/tools/diagnostics.php:110 -msgid "APC Enabled" -msgstr "" - -#: views/tools/diagnostics.php:114 -msgid "Root Path" -msgstr "" - -#: views/tools/diagnostics.php:118 -msgid "ABSPATH" -msgstr "" - -#: views/tools/diagnostics.php:122 -msgid "Plugins Path" -msgstr "" - -#: views/tools/diagnostics.php:126 -msgid "Loaded PHP INI" -msgstr "" - -#: views/tools/diagnostics.php:130 -msgid "Server IP" -msgstr "" - -#: views/tools/diagnostics.php:134 -msgid "Client IP" -msgstr "" - -#: views/tools/diagnostics.php:145 -msgid "Langugage" -msgstr "" - -#: views/tools/diagnostics.php:149 views/tools/diagnostics.php:204 -msgid "Charset" -msgstr "" - -#: views/tools/diagnostics.php:153 -msgid "Memory Limit " -msgstr "" - -#: views/tools/diagnostics.php:154 -msgid "Max" -msgstr "" - -#: views/tools/diagnostics.php:172 -msgid "Safe Mode" -msgstr "" - -#: views/tools/diagnostics.php:176 -msgid "On" -msgstr "" - -#: views/tools/diagnostics.php:176 -msgid "Off" -msgstr "" - -#: views/tools/diagnostics.php:181 -msgid "Memory Limit" -msgstr "" - -#: views/tools/diagnostics.php:185 -msgid "Memory In Use" -msgstr "" - -#: views/tools/diagnostics.php:193 -msgid "Shell Exec" -msgstr "" - -#: views/tools/diagnostics.php:194 -msgid "Is Supported" -msgstr "" - -#: views/tools/diagnostics.php:194 -msgid "Not Supported" -msgstr "" - -#: views/tools/diagnostics.php:208 -msgid "Wait Timeout" -msgstr "" - -#: views/tools/diagnostics.php:212 -msgid "Max Allowed Packets" -msgstr "" - -#: views/tools/diagnostics.php:216 -msgid "msyqldump Path" -msgstr "" - -#: views/tools/diagnostics.php:220 -msgid "Server Disk" -msgstr "" - -#: views/tools/diagnostics.php:223 -msgid "Free space" -msgstr "" - -#: views/tools/diagnostics.php:226 -msgid "Note: This value is the physical servers hard-drive allocation." -msgstr "" - -#: views/tools/diagnostics.php:227 -msgid "" -"On shared hosts check your control panel for the 'TRUE' disk space quota " -"value." -msgstr "" - -#: views/tools/diagnostics.php:243 -msgid "Stored Data" -msgstr "" - -#: views/tools/diagnostics.php:248 -msgid "Options Values" -msgstr "" - -#: views/tools/diagnostics.php:281 -msgid "PHP Information" -msgstr "" - -#: views/tools/diagnostics.php:300 -msgid "Delete this option value" -msgstr "" - -#: views/tools/logging.php:140 -msgid "Log file not found or unreadable" -msgstr "" - -#: views/tools/logging.php:142 -msgid "" -"Try to create a package, since no log files were found in the snapshots " -"directory with the extension *.log" -msgstr "" - -#: views/tools/logging.php:144 -msgid "Reasons for log file not showing" -msgstr "" - -#: views/tools/logging.php:145 -msgid "The web server does not support returning .log file extentions" -msgstr "" - -#: views/tools/logging.php:146 -msgid "" -"The snapshots directory does not have the correct permissions to write " -"files. Try setting the permissions to 755" -msgstr "" - -#: views/tools/logging.php:147 -msgid "" -"The process that PHP runs under does not have enough permissions to create " -"files. Please contact your hosting provider for more details" -msgstr "" - -#: views/tools/logging.php:156 views/tools/logging.php:161 -msgid "Options" -msgstr "" - -#: views/tools/logging.php:163 -msgid "Refresh" -msgstr "" - -#: views/tools/logging.php:168 -msgid "Auto Refresh" -msgstr "" - -#: views/tools/logging.php:174 -msgid "Last 20 Logs" -msgstr "" - -#. Plugin Name of the plugin/theme -msgid "Duplicator" -msgstr "" - -#. Plugin URI of the plugin/theme -msgid "http://www.lifeinthegrid.com/duplicator/" -msgstr "" - -#. Description of the plugin/theme -msgid "" -"Create a backup of your WordPress files and database. Duplicate and move an " -"entire site from one location to another in a few steps. Create a full " -"snapshot of your site at any point in time." -msgstr "" - -#. Author of the plugin/theme -msgid "LifeInTheGrid" -msgstr "" - -#. Author URI of the plugin/theme -msgid "http://www.lifeinthegrid.com" -msgstr "" diff --git a/languages/duplicator-en_US.mo b/languages/duplicator-en_US.mo new file mode 100644 index 00000000..70ee0dd1 Binary files /dev/null and b/languages/duplicator-en_US.mo differ diff --git a/languages/duplicator-en_US.po b/languages/duplicator-en_US.po new file mode 100644 index 00000000..69affd93 --- /dev/null +++ b/languages/duplicator-en_US.po @@ -0,0 +1,5780 @@ +# Copyright (C) 2023 Snap Creek +# This file is distributed under the same license as the Duplicator plugin. +msgid "" +msgstr "" +"Project-Id-Version: Duplicator 1.5.3\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/duplicator\n" +"POT-Creation-Date: 2023-11-06 12:12-0600\n" +"PO-Revision-Date: 2023-11-06 12:12-0600\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.0.1\n" +"X-Poedit-KeywordsList: __;_e;esc_html_e;esc_html__;_x;_ex;esc_attr_e;" +"esc_attr__\n" +"X-Poedit-Basepath: ..\n" +"X-Poedit-SearchPath-0: .\n" + +#: assets/js/javascript.php:270 +msgid "Copied: " +msgstr "" + +#: assets/js/javascript.php:270 assets/js/javascript.php:272 +msgid "unable to copy" +msgstr "" + +#: assets/js/javascript.php:276 assets/js/javascript.php:280 +msgid "Copy to Clipboard!" +msgstr "" + +#: classes/class.logging.php:161 +msgid "No Log" +msgstr "" + +#: classes/class.server.php:325 +msgid "(directory)" +msgstr "" + +#: classes/package/class.pack.database.php:600 +msgid "" +"Shell mysql dump error. Change SQL Mode to the \"PHP Code\" in the " +"Duplicator > Settings > Packages." +msgstr "" + +#: classes/package/class.pack.database.php:749 +msgid "Please contact your DataBase administrator to fix the error." +msgstr "" + +#: classes/package/class.pack.installer.php:140 +msgid "Error reading DupArchive expander" +msgstr "" + +#: classes/package/class.pack.installer.php:153 +msgid "Error writing installer contents" +msgstr "" + +#: classes/package/class.pack.installer.php:761 +#, php-format +msgid "Zip archive %1s not present." +msgstr "" + +#: classes/package/class.pack.installer.php:834 +#: classes/package/class.pack.php:1010 +#, php-format +msgid "ERROR: Cannot open created archive. Error code = %1$s" +msgstr "" + +#: classes/package/class.pack.installer.php:838 +#: classes/package/class.pack.php:1015 +msgid "ERROR: Archive is not valid zip archive." +msgstr "" + +#: classes/package/class.pack.installer.php:841 +#: classes/package/class.pack.php:1019 +msgid "ERROR: Archive doesn't pass consistency check." +msgstr "" + +#: classes/package/class.pack.installer.php:844 +#: classes/package/class.pack.php:1024 +msgid "ERROR: Archive checksum is bad." +msgstr "" + +#: classes/package/class.pack.installer.php:860 +msgid "ARCHIVE CONSISTENCY TEST: FAIL" +msgstr "" + +#: classes/package/class.pack.installer.php:863 +msgid "ARCHIVE CONSISTENCY TEST: PASS" +msgstr "" + +#: classes/package/class.pack.php:350 +msgid "Package name can't be empty" +msgstr "" + +#: classes/package/class.pack.php:359 +#, php-format +msgid "Directories: %1$s isn't a valid path" +msgstr "" + +#: classes/package/class.pack.php:368 +#, php-format +msgid "File extension: %1$s isn't a valid extension" +msgstr "" + +#: classes/package/class.pack.php:377 +#, php-format +msgid "Files: %1$s isn't a valid file name" +msgstr "" + +#: classes/package/class.pack.php:386 +#, php-format +msgid "MySQL Server Host: %1$s isn't a valid host" +msgstr "" + +#: classes/package/class.pack.php:396 +#, php-format +msgid "MySQL Server Port: %1$s isn't a valid port" +msgstr "" + +#: classes/package/class.pack.php:940 +#, php-format +msgid "" +"Can't find Scanfile %s. Please ensure there no non-English characters in the " +"package or schedule name." +msgstr "" + +#: classes/package/class.pack.php:961 +#, php-format +msgid "EXPECTED FILE/DIRECTORY COUNT: %1$s" +msgstr "" + +#: classes/package/class.pack.php:962 +#, php-format +msgid "ACTUAL FILE/DIRECTORY COUNT: %1$s" +msgstr "" + +#: classes/package/class.pack.php:1034 +msgid "ARCHIVE CONSISTENCY TEST: Pass" +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:35 +msgid "" +"Package build appears stuck so marking package as failed. Is the Max Worker " +"Time set too high?." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:36 +msgid "Build Failure" +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:61 +msgid "Click on \"Resolve This\" button to fix the JSON settings." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:71 +#, php-format +msgid "" +"ERROR: Can't find Scanfile %s. Please ensure there no non-English characters " +"in the package or schedule name." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:157 +msgid "Problem adding items to archive." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:158 +msgid "Problems adding items to archive." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:232 +msgid "Critical failure present in validation" +msgstr "" + +#: classes/ui/class.ui.dialog.php:86 +msgid "Processing please wait..." +msgstr "" + +#: classes/ui/class.ui.dialog.php:89 +msgid "OK" +msgstr "" + +#: classes/ui/class.ui.dialog.php:90 deactivation.php:155 +msgid "Cancel" +msgstr "" + +#: classes/ui/class.ui.screen.base.php:132 +msgid "" +"Need Help? Please check out these resources first:
                    • %s removed for security reasons" +msgstr "" + +#: src/Core/MigrationMng.php:324 +#, php-format +msgid "" +"Can't remove installer file %s, please remove it for security reasons" +msgstr "" + +#: src/Core/MigrationMng.php:335 +#, php-format +msgid "Installer file %s renamed with HASH" +msgstr "" + +#: src/Core/MigrationMng.php:341 +#, php-format +msgid "" +"Can't rename installer file %s with HASH, please remove it for " +"security reasons" +msgstr "" + +#: src/Core/MigrationMng.php:373 +msgid "Original files folder moved in installer backup directory" +msgstr "" + +#: src/Core/MigrationMng.php:378 +#, php-format +msgid "Can't move %s to %s" +msgstr "" + +#: src/Core/MigrationMng.php:395 +msgid "Installer log" +msgstr "" + +#: src/Core/MigrationMng.php:396 +msgid "Installer boot log" +msgstr "" + +#: src/Core/MigrationMng.php:397 +msgid "Original files folder" +msgstr "" + +#: src/Core/Notifications/Review.php:91 +#, php-format +msgid "Are you enjoying %s?" +msgstr "" + +#: src/Core/Notifications/Review.php:94 +#: template/admin_pages/settings/general/general.php:299 +msgid "Yes" +msgstr "" + +#: src/Core/Notifications/Review.php:98 +msgid "Not really" +msgstr "" + +#: src/Core/Notifications/Review.php:106 +msgid "" +"That’s awesome! Could you please do me a BIG favor and give it a 5-star " +"rating on WordPress to help us spread the word and boost our motivation?" +msgstr "" + +#: src/Core/Notifications/Review.php:110 +msgid "~ John Turner
                      President of Duplicator" +msgstr "" + +#: src/Core/Notifications/Review.php:114 +msgid "Ok, you deserve it" +msgstr "" + +#: src/Core/Notifications/Review.php:118 +msgid "Nope, maybe later" +msgstr "" + +#: src/Core/Notifications/Review.php:122 +msgid "I already did" +msgstr "" + +#: src/Core/Notifications/Review.php:130 +msgid "" +"We're sorry to hear you aren't enjoying Duplicator. We would love a chance " +"to improve. Could you take a minute and let us know what we can do better?" +msgstr "" + +#: src/Core/Notifications/Review.php:137 +msgid "Give Feedback" +msgstr "" + +#: src/Core/Notifications/Review.php:141 +msgid "No thanks" +msgstr "" + +#: src/Core/Notifications/Review.php:195 +#, php-format +msgid "" +"Please rate Duplicator
                      ★★★★★ on WordPress.org to help " +"us spread the word. Thank you from the Duplicator team!" +msgstr "" + +#: src/Libs/OneClickUpgrade/ConnectSkin.php:35 +msgid "There was an error installing Duplicator Pro. Please try again." +msgstr "" + +#: src/Lite/Requirements.php:49 +msgid "Can't enable Duplicator LITE if the PRO version is enabled." +msgstr "" + +#: src/Lite/Requirements.php:50 +msgid "" +"Please deactivate Duplicator PRO, then reactivate LITE version from the " +msgstr "" + +#: src/Lite/Requirements.php:51 src/Lite/Requirements.php:138 +msgid "plugins page" +msgstr "" + +#: src/Lite/Requirements.php:132 +msgid "Duplicator Notice:" +msgstr "" + +#: src/Lite/Requirements.php:133 +msgid "" +"The \"Duplicator Lite\" and \"Duplicator Pro\" plugins cannot both be active " +"at the same time. " +msgstr "" + +#: src/Lite/Requirements.php:136 +msgid "" +"To use \"Duplicator LITE\" please deactivate \"Duplicator PRO\" from the " +msgstr "" + +#: src/Utils/CachesPurge/CacheItem.php:61 +#, php-format +msgid "All caches on %s have been purged." +msgstr "" + +#: src/Utils/CachesPurge/CacheItem.php:100 +#: src/Utils/CachesPurge/CacheItem.php:104 +#, php-format +msgid "Error on caches purge of %s." +msgstr "" + +#: src/Utils/CronUtils.php:32 +msgid "Once a Day" +msgstr "" + +#: src/Utils/CronUtils.php:37 +msgid "Once a Week" +msgstr "" + +#: src/Utils/CronUtils.php:42 +msgid "Once a Month" +msgstr "" + +#: src/Utils/DuplicatorPhpVersionCheck.php:59 +#, php-format +msgid "" +"DUPLICATOR: Your system is running a very old version of PHP (%s) that is no " +"longer supported by Duplicator. " +msgstr "" + +#: src/Utils/DuplicatorPhpVersionCheck.php:69 +#, php-format +msgid "" +"Please ask your host or server administrator to update to PHP %1s or greater." +msgstr "" + +#: src/Utils/DuplicatorPhpVersionCheck.php:78 +#, php-format +msgid "" +"If this is not possible, please visit the FAQ link titled \n" +" %1$s\"What version of PHP Does Duplicator " +"Support?\"%2$s\n" +" for instructions on how to download a previous " +"version of Duplicator compatible with PHP %3$s." +msgstr "" + +#: src/Utils/Email/EmailSummary.php:102 +msgid "Successful" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:107 +msgid "Failed" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:122 +msgid "Never" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:123 +msgid "Daily" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:124 +msgid "Weekly" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:125 +msgid "Monthly" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:139 +msgid "day" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:141 +msgid "month" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:144 +msgid "week" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraItem.php:180 +msgid "Active" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraItem.php:182 +msgid "Inactive" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraItem.php:184 +msgid "Not Installed" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:85 +msgid "Plugin slug is empty" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:90 +msgid "Plugin not found" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:115 +msgid "OptinMonster" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:118 +msgid "" +"Instantly get more subscribers, leads, and sales with the #1 conversion " +"optimization toolkit. Create high converting popups, announcement bars, spin " +"a wheel, and more with smart targeting and personalization." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:127 +#: src/Views/DashboardWidget.php:210 +msgid "MonsterInsights" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:131 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:143 +msgid "" +"The leading WordPress analytics plugin that shows you how people find and " +"use your website, so you can make data driven decisions to grow your " +"business. Properly set up Google Analytics without writing code." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:139 +msgid "MonsterInsights Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:152 +msgid "WPForms" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:156 +msgid "" +"The best drag & drop WordPress form builder. Easily create beautiful contact " +"forms, surveys, payment forms, and more with our 100+ form templates. " +"Trusted by over 4 million websites as the best forms plugin." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:164 +msgid "WPForms Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:168 +msgid "" +"The easiest drag & drop WordPress form builder plugin to create beautiful " +"contact forms, subscription forms, payment forms, and more in minutes. No " +"coding skills required." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:177 +#: src/Views/DashboardWidget.php:234 +msgid "WP Mail SMTP" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:181 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:193 +msgid "" +"Improve your WordPress email deliverability and make sure that your website " +"emails reach user's inbox with the #1 SMTP plugin for WordPress. Over 3 " +"million websites use it to fix WordPress email issues." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:189 +msgid "WP Mail SMTP Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:202 +#: src/Views/DashboardWidget.php:218 +msgid "AIOSEO" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:206 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:218 +msgid "" +"The original WordPress SEO plugin and toolkit that improves your website's " +"search rankings. Comes with all the SEO features like Local SEO, WooCommerce " +"SEO, sitemaps, SEO optimizer, schema, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:214 +msgid "AIOSEO Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:227 +#: src/Views/DashboardWidget.php:226 +msgid "SeedProd" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:230 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:239 +msgid "" +"The best WordPress coming soon page plugin to create a beautiful coming soon " +"page, maintenance mode page, or landing page. No coding skills required." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:236 +msgid "SeedProd Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:246 +msgid "RafflePress" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:250 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:262 +msgid "" +"Turn your website visitors into brand ambassadors! Easily grow your email " +"list, website traffic, and social media followers with the most powerful " +"giveaways & contests plugin for WordPress." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:258 +msgid "RafflePress Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:271 +msgid "PushEngage" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:275 +msgid "" +"Connect with your visitors after they leave your website with the leading " +"web push notification software. Over 10,000+ businesses worldwide use " +"PushEngage to send 9 billion notifications each month." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:286 +msgid "Smash Balloon Instagram Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:290 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:302 +msgid "" +"Easily display Instagram content on your WordPress site without writing any " +"code. Comes with multiple templates, ability to show content from multiple " +"accounts, hashtags, and more. Trusted by 1 million websites." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:298 +msgid "Smash Balloon Instagram Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:311 +msgid "Smash Balloon Facebook Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:315 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:327 +msgid "" +"Easily display Facebook content on your WordPress site without writing any " +"code. Comes with multiple templates, ability to embed albums, group content, " +"reviews, live videos, comments, and reactions." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:323 +msgid "Smash Balloon Facebook Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:336 +msgid "Smash Balloon Twitter Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:340 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:352 +msgid "" +"Easily display Twitter content in WordPress without writing any code. Comes " +"with multiple layouts, ability to combine multiple Twitter feeds, Twitter " +"card support, tweet moderation, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:348 +msgid "Smash Balloon Twitter Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:361 +msgid "Smash Balloon YouTube Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:365 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:377 +msgid "" +"Easily display YouTube videos on your WordPress site without writing any " +"code. Comes with multiple layouts, ability to embed live streams, video " +"filtering, ability to combine multiple channel videos, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:373 +msgid "Smash Balloon YouTube Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:386 +msgid "TrustPulse" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:390 +msgid "" +"Boost your sales and conversions by up to 15% with real-time social proof " +"notifications. TrustPulse helps you show live user activity and purchases to " +"help convince other users to purchase." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:402 +msgid "SearchWP" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:406 +msgid "" +"The most advanced WordPress search plugin. Customize your WordPress search " +"algorithm, reorder search results, track search metrics, and everything you " +"need to leverage search to grow your business." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:416 +msgid "AffiliateWP" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:420 +msgid "" +"The #1 affiliate management plugin for WordPress. Easily create an affiliate " +"program for your eCommerce store or membership site within minutes and start " +"growing your sales with the power of referral marketing." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:431 +msgid "WP Simple Pay" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:435 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:447 +msgid "" +"The #1 Stripe payments plugin for WordPress. Start accepting one-time and " +"recurring payments on your WordPress site without setting up a shopping " +"cart. No code required." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:443 +msgid "WP Simple Pay Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:456 +msgid "Easy Digital Downloads" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:459 +msgid "" +"The best WordPress eCommerce plugin for selling digital downloads. Start " +"selling eBooks, software, music, digital art, and more within minutes. " +"Accept payments, manage subscriptions, advanced access control, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:468 +msgid "Sugar Calendar" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:471 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:480 +msgid "" +"A simple & powerful event calendar plugin for WordPress that comes with all " +"the event management features including payments, scheduling, timezones, " +"ticketing, recurring events, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:477 +msgid "Sugar Calendar Pro" +msgstr "" + +#: src/Utils/Upsell.php:40 src/Utils/Upsell.php:66 +#: template/admin_pages/welcome/features.php:54 +msgid "Secure File Encryption" +msgstr "" + +#: src/Utils/Upsell.php:41 src/Utils/Upsell.php:67 +#: template/admin_pages/welcome/features.php:62 +msgid "Server to Server Import" +msgstr "" + +#: src/Utils/Upsell.php:43 +msgid "Cloud Storage - Google Drive" +msgstr "" + +#: src/Utils/Upsell.php:44 +msgid "Cloud Storage - Amazon S3" +msgstr "" + +#: src/Utils/Upsell.php:45 +msgid "Cloud Storage - DropBox" +msgstr "" + +#: src/Utils/Upsell.php:46 +msgid "Cloud Storage - OneDrive" +msgstr "" + +#: src/Utils/Upsell.php:47 +msgid "Cloud Storage - FTP/SFTP" +msgstr "" + +#: src/Utils/Upsell.php:50 +msgid "Multisite Network Support" +msgstr "" + +#: src/Utils/Upsell.php:51 src/Utils/Upsell.php:80 +msgid "Email Alerts" +msgstr "" + +#: src/Utils/Upsell.php:70 +msgid "Smart Migration Wizard" +msgstr "" + +#: src/Utils/Upsell.php:72 +msgid "Streamlined Installer" +msgstr "" + +#: src/Utils/Upsell.php:73 +msgid "Developer Hooks" +msgstr "" + +#: src/Utils/Upsell.php:74 +msgid "Managed Hosting Support" +msgstr "" + +#: src/Utils/Upsell.php:77 +msgid "Migrate Duplicator Settings" +msgstr "" + +#: src/Utils/Upsell.php:78 +msgid "Regenerate SALTS" +msgstr "" + +#: src/Utils/Upsell.php:79 +msgid "Multisite Network" +msgstr "" + +#: src/Utils/Upsell.php:81 +msgid "Custom Search & Replace" +msgstr "" + +#: src/Views/AdminNotices.php:194 +msgid "Safe Mode:" +msgstr "" + +#: src/Views/AdminNotices.php:195 +msgid "" +"During the install safe mode was enabled deactivating all plugins.
                      " +"Please be sure to " +msgstr "" + +#: src/Views/AdminNotices.php:196 +msgid "re-activate the plugins" +msgstr "" + +#: src/Views/AdminNotices.php:202 views/parts/migration-message.php:17 +msgid "This site has been successfully migrated!" +msgstr "" + +#: src/Views/AdminNotices.php:203 +msgid "Final step(s):" +msgstr "" + +#: src/Views/AdminNotices.php:204 +msgid "" +"This message will be removed after all installer files are removed. " +"Installer files must be removed to maintain a secure site. Click the link " +"above or button below to remove all installer files and complete the " +"migration." +msgstr "" + +#: src/Views/AdminNotices.php:211 views/parts/migration-message.php:52 +msgid "Remove Installation Files Now!" +msgstr "" + +#: src/Views/AdminNotices.php:215 +msgid "Optionally, Review Duplicator at WordPress.org..." +msgstr "" + +#: src/Views/AdminNotices.php:221 src/Views/AdminNotices.php:304 +#: views/parts/migration-almost-complete.php:17 +msgid "Migration Almost Complete!" +msgstr "" + +#: src/Views/AdminNotices.php:223 +msgid "" +"Reserved Duplicator installation files have been detected in the root " +"directory. Please delete these installation files to avoid security issues. " +"
                      Go to:Duplicator > Tools > Information >Stored Data and click the " +"\"Remove Installation Files\" button" +msgstr "" + +#: src/Views/AdminNotices.php:231 views/parts/migration-almost-complete.php:33 +msgid "Take me there now!" +msgstr "" + +#: src/Views/AdminNotices.php:247 +msgid "Redirecting Please Wait..." +msgstr "" + +#: src/Views/AdminNotices.php:250 +msgid "Invalid token permissions to perform this request." +msgstr "" + +#: src/Views/AdminNotices.php:294 +#, php-format +msgid "Activate %s" +msgstr "" + +#: src/Views/AdminNotices.php:304 +msgid "Warning!" +msgstr "" + +#: src/Views/AdminNotices.php:306 +msgid "" +"Plugin(s) listed here have been deactivated during installation to help " +"prevent issues. Please activate them to finish this migration: " +msgstr "" + +#: src/Views/AdminNotices.php:377 +msgid "Congrats!" +msgstr "" + +#: src/Views/AdminNotices.php:382 +#, php-format +msgid "" +"You created over %d packages with Duplicator. Great job! If you can spare a " +"minute, \n" +" please help us by leaving a five star review " +"on WordPress.org." +msgstr "" + +#: src/Views/AdminNotices.php:394 +msgid "Sure! I'd love to help" +msgstr "" + +#: src/Views/AdminNotices.php:397 +msgid "Hide Notification" +msgstr "" + +#: src/Views/AdminNotices.php:420 +msgid "" +"Duplicator
                      Your logged-in user role does not have " +"export \n" +" capability so you don't have access to Duplicator " +"functionality." +msgstr "" + +#: src/Views/AdminNotices.php:427 +#, php-format +msgid "" +"RECOMMENDATION: Add export capability to your role. See " +"FAQ: %1$sWhy is the Duplicator/Packages menu missing from my admin menu?%2$s" +msgstr "" + +#: src/Views/DashboardWidget.php:42 template/mail/email_summary.php:29 +msgid "Duplicator" +msgstr "" + +#: src/Views/DashboardWidget.php:162 +msgid "A package is currently running." +msgstr "" + +#: src/Views/DashboardWidget.php:179 +msgid "No packages have been created yet." +msgstr "" + +#: src/Views/DashboardWidget.php:191 +#, php-format +msgid "%s ago" +msgstr "" + +#: src/Views/EducationElements.php:108 +msgid "" +"Scheduled Backups - Ensure that important data is regularly and consistently " +"backed up, allowing for quick and efficient recovery in case of data loss." +msgstr "" + +#: src/Views/EducationElements.php:110 +msgid "" +"Cloud Backups - Back up to Dropbox, FTP, Google Drive, OneDrive, or Amazon " +"S3 and more for safe storage." +msgstr "" + +#: src/Views/EducationElements.php:111 +msgid "" +"Recovery Points - Recovery Points provides protection against mistakes and " +"bad updates by letting you quickly rollback your system to a known, good " +"state." +msgstr "" + +#: src/Views/EducationElements.php:113 +msgid "" +"Secure File Encryption - Protect and secure the archive file with industry-" +"standard AES-256 encryption" +msgstr "" + +#: src/Views/EducationElements.php:114 +msgid "" +"Server to Server Import - Direct package import from source server or cloud " +"storage using URL. No need to download the package to your desktop machine " +"first." +msgstr "" + +#: src/Views/EducationElements.php:116 +msgid "" +"File & Database Table Filters - Use file and database filters to pick and " +"choose exactly what you want to backup or transfer. No bloat!" +msgstr "" + +#: src/Views/EducationElements.php:118 +msgid "" +"Large Site Support - Duplicator Pro has developed a new way to package " +"backups especially tailored for larger site. No server timeouts or other " +"restrictions." +msgstr "" + +#: src/Views/EducationElements.php:120 +msgid "" +"Mulstisite Support - Duplicator Pro supports multisite network backup & " +"migration. You can even install a subsite as a standalone site." +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:17 +msgid "Activated" +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:22 +msgid "Activate" +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:28 +msgid "Install Plugin" +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:46 +msgid "Status:" +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:4 +msgid "" +"Hello and welcome to Duplicator, the most reliable WordPress backup and " +"migration plugin. At Duplicator, we build software that helps protect your " +"website with our reliable secure backups and migrate your website without " +"any manual effort." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:9 +msgid "" +"Over the years, we found that most WordPress backup and migration plugins " +"were unreliable, buggy, slow, and very hard to use. So we started with a " +"simple goal: build a WordPress backup and migration plugin that’s both easy " +"and powerful." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:14 +msgid "" +"Our goal is to take the pain out of creating backups, migrations, and make " +"it easy." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:22 +#, php-format +msgid "" +"Duplicator is brought to you by the same team that’s behind the largest " +"WordPress resource site, WPBeginner, the most popular lead-generation software, OptinMonster, the best WordPress analytics plugin, MonsterInsights, and more!" +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:43 +msgid "" +"Yup, we know a thing or two about building awesome products that customers " +"love." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:49 +msgid "The Awesome Motive Team photo" +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:51 +msgid "The Awesome Motive Team" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:25 +msgid "Creating Your First Package" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:28 +msgid "" +"Want to get started creating your first package with Duplicator? By " +"following the step by step instructions in this walkthrough, you can easily " +"create a backup or migration." +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:32 +msgid "" +"To begin, you’ll need to be logged into the WordPress admin area. Once " +"there, click on Duplicator in the admin sidebar to go the Packages page." +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:36 +msgid "" +"In the Packages page, the packages list will be empty because there are no " +"packages yet. To create a new package, click on the Create New button, and " +"this will launch the Package Creation Wizard." +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:47 +msgid "Quick Start Guide" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:56 +msgid "How to Create a Package" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:65 +msgid "How to Migrate to a New Site" +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:25 +#: template/parts/Education/callout-cta.php:22 +msgid "Get Duplicator Pro and Unlock all the Powerful Features" +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:32 +msgid "" +"Thanks for being a loyal Duplicator Lite user. Upgrade to Duplicator " +"Pro to unlock all the awesome features and experience
                      why " +"Duplicator is consistently rated the best WordPress migration plugin." +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:49 +#, php-format +msgid "" +"We know that you will truly love Duplicator. It has over 4000+ five " +"star ratings (%s) and is active on over 1 million websites." +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:93 +#: template/admin_pages/about_us/lite_vs_pro/main.php:94 +msgid "Get Duplicator Pro Today and Unlock all the Powerful Features" +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:102 +#: template/admin_pages/about_us/lite_vs_pro/main.php:103 +#, php-format +msgid "" +"Bonus: Duplicator Lite users get %1$d%% off " +"regular price, automatically applied at checkout." +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:29 +msgid "" +"Get the most out of Duplicator by upgrading to Pro and unlocking all of the " +"powerful features." +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:38 +msgid "Feature" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:43 +msgid "Lite" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:48 +msgid "Pro" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:67 +#: template/admin_pages/about_us/lite_vs_pro/main.php:77 +msgid "Included" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:68 +msgid "Not Available" +msgstr "" + +#: template/admin_pages/about_us/tabs.php:21 +msgid "Getting Started" +msgstr "" + +#: template/admin_pages/about_us/tabs.php:25 +msgid "Lite vs Pro" +msgstr "" + +#: template/admin_pages/settings/general/email_summary.php:19 +msgid "Email Summary" +msgstr "" + +#: template/admin_pages/settings/general/email_summary.php:23 +msgid "Frequency" +msgstr "" + +#: template/admin_pages/settings/general/email_summary.php:36 +#, php-format +msgid "You can view the email summary example %1shere%2s." +msgstr "" + +#: template/admin_pages/settings/general/general.php:25 +msgid "General Settings Saved" +msgstr "" + +#: template/admin_pages/settings/general/general.php:108 +msgid "Plugin" +msgstr "" + +#: template/admin_pages/settings/general/general.php:112 +#: views/packages/details/detail.php:130 +#: views/tools/diagnostics/inc.settings.php:101 +#: views/tools/diagnostics/inc.settings.php:121 +#: views/tools/diagnostics/inc.settings.php:194 +msgid "Version" +msgstr "" + +#: template/admin_pages/settings/general/general.php:120 +msgid "Uninstall" +msgstr "" + +#: template/admin_pages/settings/general/general.php:124 +msgid "Delete Plugin Settings" +msgstr "" + +#: template/admin_pages/settings/general/general.php:128 +msgid "Delete Entire Storage Directory" +msgstr "" + +#: template/admin_pages/settings/general/general.php:133 +msgid "Usage statistics" +msgstr "" + +#: template/admin_pages/settings/general/general.php:137 +msgid "Usage statistics are hardcoded disallowed." +msgstr "" + +#: template/admin_pages/settings/general/general.php:147 +msgid "Enable usage tracking" +msgstr "" + +#: template/admin_pages/settings/general/general.php:150 +msgid "Usage Tracking" +msgstr "" + +#: template/admin_pages/settings/general/general.php:159 +msgid "Hide Announcements" +msgstr "" + +#: template/admin_pages/settings/general/general.php:168 +msgid "Check this option to hide plugin announcements and update details." +msgstr "" + +#: template/admin_pages/settings/general/general.php:176 +msgid "Debug" +msgstr "" + +#: template/admin_pages/settings/general/general.php:180 +msgid "Debugging" +msgstr "" + +#: template/admin_pages/settings/general/general.php:183 +msgid "Enable debug options throughout user interface" +msgstr "" + +#: template/admin_pages/settings/general/general.php:187 +msgid "Trace Log" +msgstr "" + +#: template/admin_pages/settings/general/general.php:190 +#: template/parts/DashboardWidget/sections-section.php:51 +#: views/packages/main/s2.scan3.php:44 views/packages/main/s2.scan3.php:409 +#: views/packages/main/s2.scan3.php:745 +#: views/tools/diagnostics/inc.settings.php:178 +msgid "Enabled" +msgstr "" + +#: template/admin_pages/settings/general/general.php:193 +msgid "" +"Turns on detailed operation logging. Logging will occur in both PHP error " +"and local trace logs." +msgstr "" + +#: template/admin_pages/settings/general/general.php:195 +msgid "" +"WARNING: Only turn on this setting when asked to by support as tracing will " +"impact performance." +msgstr "" + +#: template/admin_pages/settings/general/general.php:203 +msgid "Download Trace Log" +msgstr "" + +#: template/admin_pages/settings/general/general.php:211 +msgid "Advanced" +msgstr "" + +#: template/admin_pages/settings/general/general.php:218 +msgid "Reset Packages" +msgstr "" + +#: template/admin_pages/settings/general/general.php:222 +msgid "" +"This process will reset all packages by deleting those without a completed " +"status, reset the active package id and perform a cleanup of the build tmp " +"file." +msgstr "" + +#: template/admin_pages/settings/general/general.php:226 +msgid "Reset Settings" +msgstr "" + +#: template/admin_pages/settings/general/general.php:228 +msgid "" +"This action should only be used if the packages screen is having issues or a " +"build is stuck." +msgstr "" + +#: template/admin_pages/settings/general/general.php:234 +msgid "Archive scan" +msgstr "" + +#: template/admin_pages/settings/general/general.php:237 +msgid "Skip" +msgstr "" + +#: template/admin_pages/settings/general/general.php:240 +msgid "" +"If enabled all files check on scan will be skipped before package creation. " +"In some cases, this option can be beneficial if the scan process is having " +"issues running or returning errors." +msgstr "" + +#: template/admin_pages/settings/general/general.php:247 +msgid "Foreign JavaScript" +msgstr "" + +#: template/admin_pages/settings/general/general.php:250 +#: template/admin_pages/settings/general/general.php:264 +msgid "Disable" +msgstr "" + +#: template/admin_pages/settings/general/general.php:253 +msgid "" +"Check this option if other plugins/themes JavaScript files are conflicting " +"with Duplicator." +msgstr "" + +#: template/admin_pages/settings/general/general.php:255 +#: template/admin_pages/settings/general/general.php:269 +msgid "" +"Do not modify this setting unless you know the expected result or have " +"talked to support." +msgstr "" + +#: template/admin_pages/settings/general/general.php:261 +msgid "Foreign CSS" +msgstr "" + +#: template/admin_pages/settings/general/general.php:267 +msgid "" +"Check this option if other plugins/themes CSS files are conflicting with " +"Duplicator." +msgstr "" + +#: template/admin_pages/settings/general/general.php:283 +msgid "Save General Settings" +msgstr "" + +#: template/admin_pages/settings/general/general.php:294 +msgid "Reset Packages ?" +msgstr "" + +#: template/admin_pages/settings/general/general.php:295 +msgid "" +"This will clear and reset all of the current temporary packages. Would you " +"like to continue?" +msgstr "" + +#: template/admin_pages/settings/general/general.php:296 +msgid "Resetting settings, Please Wait..." +msgstr "" + +#: template/admin_pages/settings/general/general.php:300 +msgid "No" +msgstr "" + +#: template/admin_pages/settings/general/general.php:306 +msgid "AJAX Call Error!" +msgstr "" + +#: template/admin_pages/settings/general/general.php:309 +#, php-format +msgid "" +"AJAX error encountered when resetting packages. Please see %1$sthis FAQ " +"entry%2$s for possible resolutions." +msgstr "" + +#: template/admin_pages/settings/general/general.php:323 +#: template/admin_pages/settings/general/general.php:376 +msgid "RESPONSE ERROR!" +msgstr "" + +#: template/admin_pages/settings/general/general.php:366 +msgid "Packages successfully reset" +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:19 +msgid "All information sent to the server is anonymous." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:20 +msgid "No information about storage or package's content are sent." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:27 +msgid "" +"Usage tracking for Duplicator helps us better understand our users and their " +"website needs by looking \n" +" at a range of server and website environments." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:33 +msgid "" +"This allows us to continuously improve our product as well as our Q&A / " +"testing process." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:35 +msgid "" +"Below is the list of information that Duplicator collects as part of the " +"usage tracking:" +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:41 +msgid "" +"PHP Version: so we know which PHP versions we have to test against " +"(no one likes whitescreens or log files full of errors)." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:49 +msgid "" +"WordPress Version: so we know which WordPress versions to support and " +"test against." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:57 +msgid "" +"MySQL Version: so we know which versions of MySQL to support and test " +"against for our custom tables." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:65 +msgid "" +"Duplicator Version: so we know which versions of Duplicator are " +"potentially responsible for issues when we get bug reports, \n" +" allowing us to identify issues and release solutions much faster." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:74 +msgid "" +"Plugins and Themes infos: so we can figure out which ones I can " +"generate compatibility errors with Duplicator." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:82 +msgid "" +"Site info: General information about the site such as database, file " +"size, number of users, and sites in case it is a multisite. \n" +" This is useful for us to understand the critical issues of " +"package creation." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:91 +msgid "" +"Packages infos: Information about the packages created and the type " +"of components included." +msgstr "" + +#: template/admin_pages/welcome/features.php:21 +msgid "Duplicator Features" +msgstr "" + +#: template/admin_pages/welcome/features.php:22 +msgid "" +"Duplicator is both easy to use and extremely powerful. We have tons of " +"helpful features that allow us to give you everything you need from a backup " +"& migration plugin." +msgstr "" + +#: template/admin_pages/welcome/features.php:30 +msgid "" +"Ensure that important data is regularly and consistently backed up, allowing " +"for quick and efficient recovery in case of data loss." +msgstr "" + +#: template/admin_pages/welcome/features.php:37 +msgid "Cloud Backups" +msgstr "" + +#: template/admin_pages/welcome/features.php:39 +msgid "" +"Back up to Dropbox, FTP, Google Drive, OneDrive, or Amazon S3 and more for " +"safe storage." +msgstr "" + +#: template/admin_pages/welcome/features.php:47 +#: template/mocks/recovery/content-popup.php:15 +msgid "" +"Recovery Points provides protection against mistakes and bad updates by " +"letting you quickly rollback your system to a known, good state." +msgstr "" + +#: template/admin_pages/welcome/features.php:56 +#: views/packages/main/s1.setup2.php:353 +msgid "" +"Protect and secure the archive file with industry-standard AES-256 " +"encryption." +msgstr "" + +#: template/admin_pages/welcome/features.php:64 +msgid "" +"Direct package import from source server or cloud storage using URL. No need " +"to download the package to your desktop machine first." +msgstr "" + +#: template/admin_pages/welcome/features.php:73 +msgid "" +"Use file and database filters to pick and choose exactly what you want to " +"backup or transfer. No bloat!" +msgstr "" + +#: template/admin_pages/welcome/features.php:80 +msgid "Large Site Support" +msgstr "" + +#: template/admin_pages/welcome/features.php:82 +msgid "" +"Duplicator Pro has developed a new way to package backups especially " +"tailored for larger site. No server timeouts or other restrictions." +msgstr "" + +#: template/admin_pages/welcome/features.php:89 +msgid "Multisite Support" +msgstr "" + +#: template/admin_pages/welcome/features.php:91 +msgid "" +"Duplicator Pro supports multisite network backup & migration. You can even " +"install a subsite as a standalone site." +msgstr "" + +#: template/admin_pages/welcome/features.php:101 +msgid "See All Features" +msgstr "" + +#: template/admin_pages/welcome/footer.php:25 +#: template/admin_pages/welcome/intro.php:44 +msgid "Create Your First Package" +msgstr "" + +#: template/admin_pages/welcome/footer.php:34 +msgid "Upgrade to Duplicator Pro" +msgstr "" + +#: template/admin_pages/welcome/intro.php:24 +msgid "Willie the Duplicator mascot" +msgstr "" + +#: template/admin_pages/welcome/intro.php:28 +msgid "" +"Thank you for choosing Duplicator - the most powerful WordPress Migration " +"and Backup plugin in the market." +msgstr "" + +#: template/admin_pages/welcome/intro.php:32 +#: template/admin_pages/welcome/intro.php:34 +msgid "Watch how to create your first form" +msgstr "" + +#: template/admin_pages/welcome/intro.php:38 +msgid "" +"Duplicator makes it easy to create backups and migrations in WordPress. Get " +"started by creating a new package or read our quick start guide." +msgstr "" + +#: template/admin_pages/welcome/intro.php:51 +msgid "Read the Full Guide" +msgstr "" + +#: template/admin_pages/welcome/testimonials.php:20 +msgid "Testimonials" +msgstr "" + +#: template/admin_pages/welcome/testimonials.php:28 +msgid "" +"It walked me step-by-step through the process of migrating a WordPress " +"website. If you want to save a ton of time with WP migration, I very " +"much recommend this plugin!" +msgstr "" + +#: template/admin_pages/welcome/testimonials.php:45 +msgid "" +"Duplicator Pro is the best WordPress migration & backup plugin I have " +"ever used. I will be recommending this plugin to everyone I can." +msgstr "" + +#: template/admin_pages/welcome/upgrade-cta.php:21 +msgid "Upgrade to PRO" +msgstr "" + +#: template/admin_pages/welcome/upgrade-cta.php:36 +#: template/mocks/storage/popup.php:37 template/mocks/storage/storage.php:68 +#: views/tools/diagnostics/support.php:91 +msgid "Upgrade Now" +msgstr "" + +#: template/mail/email_summary.php:78 +#, php-format +msgid "Here's a quick overview of your backups in the past %s." +msgstr "" + +#: template/mail/email_summary.php:88 +msgid "Did you know?" +msgstr "" + +#: template/mail/email_summary.php:94 +msgid "" +"With Duplicator Pro you can create fully automatic backups! Schedule your " +"preferred intervals for backups - daily, weekly, or monthly and never worry " +"about data loss again!" +msgstr "" + +#: template/mail/email_summary.php:100 +msgid "" +"With Duplicator Pro you can store backups in Google Drive, Amazon S3, " +"OneDrive, Dropbox, or any SFTP/FTP server for added protection." +msgstr "" + +#: template/mail/email_summary.php:123 +msgid "Below are the total numbers of successful and failed backups." +msgstr "" + +#: template/mail/email_summary.php:128 +msgid "State" +msgstr "" + +#: template/mail/email_summary.php:131 +msgid "Backups" +msgstr "" + +#: template/mail/email_summary.php:153 +msgid "No backups were created in the past week." +msgstr "" + +#: template/mail/email_summary.php:166 +#, php-format +msgid "This email was auto-generated and sent from %s." +msgstr "" + +#: template/mocks/import/content-popup.php:19 +#, php-format +msgid "" +"In addition to the classic installer method on an empty site, Duplicator Pro " +"now supports Drag and Drop migrations and site restores! Simply drag the " +"bundled site archive to the site you wish to overwrite." +msgstr "" + +#: template/mocks/import/import.php:201 +msgid "Overwrite a WordPress site with Drag and Drop Import!" +msgstr "" + +#: template/mocks/import/import.php:202 +msgid "Drag and Drop Import is not available in Duplicator Lite!" +msgstr "" + +#: template/mocks/recovery/recovery.php:116 +msgid "Rollback your sites with Recovery Points!" +msgstr "" + +#: template/mocks/recovery/recovery.php:117 +msgid "Recovery Points are not supported in Duplicator Lite!" +msgstr "" + +#: template/mocks/schedule/content-popup.php:15 +msgid "" +"Scheduled Backups provide peace of mind and ensure that critical data can be " +"quickly and easily restored in the event of a disaster or loss. Duplicator " +"Pro supports Hourly, Daily, Weekly and Monthly scheduled backups." +msgstr "" + +#: template/mocks/schedule/content-popup.php:24 +msgid "" +"Supported Cloud Storage: Google Drive, Dropbox, Microsoft One Drive, Amazon " +"S3 (or any compatible S3 service), and FTP/SFTP Storage." +msgstr "" + +#: template/mocks/schedule/schedules.php:279 +msgid "Automate your workflow with scheduled backups!" +msgstr "" + +#: template/mocks/schedule/schedules.php:280 +msgid "Duplicator Lite does not support scheduled backups!" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:15 +msgid "Roles and Permissions" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:19 +msgid "" +"Select the user roles and/or users that are allowed to manage different " +"aspects of Duplicator." +msgstr "" + +#: template/mocks/settings/access/capabilities.php:20 +msgid "By default, all permissions are provided only to administrator users." +msgstr "" + +#: template/mocks/settings/access/capabilities.php:21 +msgid "" +"Some capabilities depend on others so If you select for example storage " +"capability automatically the package read and package edit capabilities are " +"assigned" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:23 +msgid "It is not possible to self remove the manage settings capabilities." +msgstr "" + +#: template/mocks/settings/access/capabilities.php:28 +msgid "Package Read " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:32 +#: template/mocks/settings/access/capabilities.php:42 +#: template/mocks/settings/access/capabilities.php:52 +#: template/mocks/settings/access/capabilities.php:62 +#: template/mocks/settings/access/capabilities.php:72 +#: template/mocks/settings/access/capabilities.php:82 +#: template/mocks/settings/access/capabilities.php:92 +#: template/mocks/settings/access/capabilities.php:102 +#: template/mocks/settings/access/capabilities.php:112 +msgid "Administrator" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:38 +msgid " - Package Edit " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:48 +msgid " - - Manage Schedules " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:58 +msgid " - - Manage Storages " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:68 +msgid " - Restore Backup " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:78 +msgid " - - Package Import " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:88 +msgid " - Package Export " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:98 +msgid " - Manage Settings " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:108 +msgid " - - Manage License Settings " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:124 +msgid "Advanced Backup Permissions are not available in Duplicator Lite!" +msgstr "" + +#: template/mocks/settings/access/content-popup.php:16 +msgid "" +"Elevate your backup capabilities with advanced permissions, allowing for " +"precise control over the creation, exportation, restoration, and management " +"of control settings. Enjoy granular access control to ensure only authorized " +"users can perform these critical functions." +msgstr "" + +#: template/mocks/storage/popup.php:17 +msgid "Store to Multiple Endpoints with Duplicator Pro" +msgstr "" + +#: template/mocks/storage/popup.php:30 +msgid "" +"Set up one-time storage locations and automatically push the package to your " +"destination." +msgstr "" + +#: template/mocks/storage/storage.php:61 +msgid "Remote Cloud Backups is a PRO feature" +msgstr "" + +#: template/mocks/storage/storage.php:62 +msgid "" +"Back up to Dropbox, FTP, Google Drive, OneDrive, Amazon S3 or Amazon S3 " +"compatible for safe off-site storage." +msgstr "" + +#: template/mocks/storage/storage.php:79 views/packages/main/packages.php:95 +msgid "Bulk Actions" +msgstr "" + +#: template/mocks/storage/storage.php:81 views/packages/main/packages.php:98 +msgid "Delete" +msgstr "" + +#: template/mocks/storage/storage.php:93 +msgid "Add New" +msgstr "" + +#: template/mocks/storage/storage.php:108 views/packages/details/detail.php:98 +#: views/packages/details/detail.php:284 views/packages/details/detail.php:420 +#: views/packages/main/packages.php:196 views/packages/main/s1.setup2.php:83 +#: views/packages/main/s1.setup2.php:120 views/packages/main/s2.scan3.php:717 +msgid "Name" +msgstr "" + +#: template/mocks/storage/storage.php:109 views/packages/details/detail.php:285 +#: views/packages/details/detail.php:424 views/packages/main/s1.setup2.php:121 +#: views/settings/license.php:23 +msgid "Type" +msgstr "" + +#: template/mocks/storage/storage.php:146 +#, php-format +msgid "Total: %s" +msgstr "" + +#: template/mocks/templates/content-popup.php:15 +msgid "" +"If you install the same theme, plugins or content on all your WordPress " +"sites then Duplicator can save you a lot of time." +msgstr "" + +#: template/mocks/templates/content-popup.php:23 +msgid "" +"Instead of manually configuring the same themes and plugins over and over, " +"just configure one site and bundle it into a Duplicator package. Install the " +"package to create a pre-configured site on as many locations as you want!" +msgstr "" + +#: template/mocks/templates/templates.php:194 +msgid "Easily customize your backups with templates!" +msgstr "" + +#: template/mocks/templates/templates.php:195 +msgid "Templates are not available in Duplicator Lite!" +msgstr "" + +#: template/mocks/transfer/content-popup.php:15 +msgid "" +"With manual transfers you can upload your backup to remote storages even " +"after you have created them." +msgstr "" + +#: template/mocks/transfer/transfer.php:230 +msgid "Manually transfer backups to remote storages!" +msgstr "" + +#: template/mocks/transfer/transfer.php:231 +msgid "Remote storages are not available in Duplicator Lite!" +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:22 +msgid "Package creation" +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:24 +msgid "" +"This will create a new package. If a package is currently running then this " +"button will be disabled." +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:31 +msgid "Last backup:" +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:46 +#: views/packages/main/packages.php:144 views/packages/main/s3.build.php:135 +msgid "Create New" +msgstr "" + +#: template/parts/DashboardWidget/recently-packages.php:28 +msgid "Recently Packages" +msgstr "" + +#: template/parts/DashboardWidget/recently-packages.php:47 +#, php-format +msgid "Packages: %1$d, Failures: %2$d" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:36 +msgid "Recommended Plugin:" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:42 +msgid "Install" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:45 +msgid "Learn More" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:50 +msgid "Dismiss recommended plugin" +msgstr "" + +#: template/parts/DashboardWidget/sections-section.php:56 +#: views/packages/main/s1.setup2.php:562 +msgid "Next" +msgstr "" + +#: template/parts/DashboardWidget/sections-section.php:98 +msgid "Recovery Point" +msgstr "" + +#: template/parts/DashboardWidget/sections-section.php:103 +msgid "Not set" +msgstr "" + +#: template/parts/Education/callout-cta.php:21 +#: template/parts/Notifications/main.php:24 +msgid "Dismiss this message" +msgstr "" + +#: template/parts/Education/callout-cta.php:25 +msgid "" +"Thanks for being a loyal Duplicator Lite user. Upgrade to Duplicator Pro to " +"unlock all the awesome features and experience why Duplicator is " +"consistently rated the best WordPress migration plugin." +msgstr "" + +#: template/parts/Education/callout-cta.php:35 +#, php-format +msgid "" +"We know that you will truly love Duplicator. It has over 4000+ five star " +"ratings (%s) and is active on over 1 million websites." +msgstr "" + +#: template/parts/Education/callout-cta.php:50 +msgid "Pro Features:" +msgstr "" + +#: template/parts/Education/callout-cta.php:66 +msgid "Get Duplicator Pro Today and Unlock all the Powerful Features »" +msgstr "" + +#: template/parts/Education/callout-cta.php:73 +#, php-format +msgid "" +"Bonus: Duplicator Lite users get %1$d%% off regular price,automatically applied at " +"checkout." +msgstr "" + +#: template/parts/Education/did-you-know-blurb.php:22 +#, php-format +msgid "Did you know Duplicator Pro has: %s?" +msgstr "" + +#: template/parts/Education/did-you-know-blurb.php:24 +#: views/packages/main/s1.setup2.php:358 +msgid "Upgrade To Pro" +msgstr "" + +#: template/parts/Education/packages-bottom-bar.php:27 +msgid "Upgrade to Pro to Unlock..." +msgstr "" + +#: template/parts/Education/packages-bottom-bar.php:36 +msgid "Upgrade Now & Save!" +msgstr "" + +#: template/parts/Education/static-popup.php:31 +msgid "Upgrade to Duplicator Pro Now" +msgstr "" + +#: template/parts/Education/subscribe-form.php:24 +msgid "Email Address" +msgstr "" + +#: template/parts/Education/subscribe-form.php:26 +msgid "Subscribe" +msgstr "" + +#: template/parts/Education/subscribe-form.php:29 +msgid "Get tips and product updates straight to your inbox." +msgstr "" + +#: template/parts/Notifications/main.php:20 +msgid "Notifications" +msgstr "" + +#: template/parts/Notifications/main.php:29 +msgid "Previous message" +msgstr "" + +#: template/parts/Notifications/main.php:33 +msgid "Next message" +msgstr "" + +#: template/parts/Notifications/single-message.php:21 +msgid "Watch video" +msgstr "" + +#: template/parts/filters/package_components.php:28 +msgid "" +"Package components allow you to include/exclude differents part of your " +"WordPress installation in the package.

                      Database: Include the " +"database in the package.
                      Plugins: Include the plugins in the " +"package. With the 'active only' option enabled, only active plugins will be " +"included in the package.
                      Themes: Include the themes in the " +"package. With the 'active only' option enabled, only active themes will be " +"included in the package.
                      Media: Include the 'uploads' folder.Other: Include non-WordPress files and folders in the root " +"directory.
                      " +msgstr "" + +#: template/parts/filters/package_components.php:39 +msgid "" +"File filters allow you to exclude files and folders from the package. To " +"enable path and extension filters check the checkbox. Enter the full path of " +"the files and folders you want to exclude from the package as a semicolon " +"(;) seperated list." +msgstr "" + +#: template/parts/filters/package_components.php:41 +msgid "" +"File extension filters allow you to exclude files with certain file " +"extensions from the package e.g. zip;rar;pdf etc. Enter the file extensions " +"you want to exclude from the package as a semicolon (;) seperated list." +msgstr "" + +#: template/parts/filters/package_components.php:49 +msgid "Components" +msgstr "" + +#: template/parts/filters/package_components.php:51 +msgid "Package Components (Pro feature)" +msgstr "" + +#: template/parts/filters/package_components.php:86 +#: views/packages/details/detail.php:516 views/packages/main/s1.setup2.php:213 +#: views/packages/main/s1.setup2.php:485 views/packages/main/s2.scan3.php:403 +#: views/packages/main/s2.scan3.php:723 views/settings/packages.php:91 +msgid "Database" +msgstr "" + +#: template/parts/filters/package_components.php:93 +msgid "Plugins" +msgstr "" + +#: template/parts/filters/package_components.php:99 +msgid "Only Active Plugins" +msgstr "" + +#: template/parts/filters/package_components.php:106 +msgid "Themes" +msgstr "" + +#: template/parts/filters/package_components.php:112 +msgid "Only Active Themes" +msgstr "" + +#: template/parts/filters/package_components.php:119 +msgid "Media" +msgstr "" + +#: template/parts/filters/package_components.php:126 +msgid "Other" +msgstr "" + +#: template/parts/filters/package_components.php:134 +#: views/packages/details/detail.php:376 views/packages/details/detail.php:441 +#: views/packages/main/s1.setup2.php:225 +msgid "Filters" +msgstr "" + +#: template/parts/filters/package_components.php:138 +msgid "Path Filters" +msgstr "" + +#: template/parts/filters/package_components.php:157 +#: template/parts/filters/package_components.php:159 +msgid "File Extensions" +msgstr "" + +#: template/parts/filters/package_components.php:175 +msgid "" +"Overview:
                      This advanced option excludes all files from the " +"archive. Only the database and a copy of the installer.php will be included " +"in the archive.zip file. The option can be used for backing up and moving " +"only the database." +msgstr "" + +#: template/parts/filters/package_components.php:188 +msgid "" +" Notice:
                      Installing only " +"the database over an existing site may have unintended consequences. Be " +"sure to know the state of your system before installing the database without " +"the associated files. " +msgstr "" + +#: template/parts/filters/package_components.php:201 +msgid "" +"For example, if you have WordPress 5.6 on this site and you copy this site's " +"database to a host that has WordPress 5.8 files then the source code of the " +"files will not be in sync with the database causing possible errors. This " +"can also be true of plugins and themes. When moving only the database be " +"sure to know the database will be compatible with ALL source code files. " +"Please use this advanced feature with caution!" +msgstr "" + +#: template/parts/filters/package_components.php:212 +msgid "" +"Install Time:
                      When installing a database only package please " +"visit the " +msgstr "" + +#: template/parts/filters/package_components.php:223 +msgid "database only quick start" +msgstr "" + +#: template/parts/filters/package_components.php:233 +#, php-format +msgid "" +"The Media Only and Custom options are not included in " +"Duplicator Lite. To enable advanced options please %1$supgrade to Pro%2$s." +msgstr "" + +#: template/parts/notice-bar.php:45 +#, php-format +msgid "" +"You're using Duplicator Lite. To unlock more features " +"consider upgrading to Pro" +msgstr "" + +#: template/parts/notice-bar.php:65 +msgid "Dismiss this message." +msgstr "" + +#: views/packages/details/controller.php:35 +#, php-format +msgid "" +"This package contains an error. Please review the %1$spackage log%2$s for " +"details." +msgstr "" + +#: views/packages/details/controller.php:45 +#, php-format +msgid "For help visit the %1$sFAQ%2$s and %3$sresources page%4$s." +msgstr "" + +#: views/packages/details/controller.php:61 +msgid "Details" +msgstr "" + +#: views/packages/details/controller.php:64 +msgid "Transfer" +msgstr "" + +#: views/packages/details/detail.php:80 +msgid "Invalid Package ID request. Please try again!" +msgstr "" + +#: views/packages/details/detail.php:92 views/settings/controller.php:31 +#: views/tools/controller.php:25 views/tools/diagnostics/inc.settings.php:35 +msgid "General" +msgstr "" + +#: views/packages/details/detail.php:106 +msgid "ID" +msgstr "" + +#: views/packages/details/detail.php:110 +msgid "Hash" +msgstr "" + +#: views/packages/details/detail.php:114 +msgid "Full Name" +msgstr "" + +#: views/packages/details/detail.php:122 views/packages/main/s1.setup2.php:92 +#: views/packages/main/s2.scan3.php:718 +msgid "Notes" +msgstr "" + +#: views/packages/details/detail.php:123 +msgid "- no notes -" +msgstr "" + +#: views/packages/details/detail.php:126 views/packages/main/packages.php:194 +msgid "Created" +msgstr "" + +#: views/packages/details/detail.php:138 views/packages/main/s2.scan2.php:109 +msgid "WordPress" +msgstr "" + +#: views/packages/details/detail.php:139 views/packages/details/detail.php:143 +#: views/packages/details/detail.php:148 views/packages/details/detail.php:149 +#: views/packages/details/detail.php:166 +msgid "- unknown -" +msgstr "" + +#: views/packages/details/detail.php:142 +msgid "PHP" +msgstr "" + +#: views/packages/details/detail.php:146 +msgid "Mysql" +msgstr "" + +#: views/packages/details/detail.php:157 +msgid "Runtime" +msgstr "" + +#: views/packages/details/detail.php:158 +msgid "error running" +msgstr "" + +#: views/packages/details/detail.php:161 +msgid "Status" +msgstr "" + +#: views/packages/details/detail.php:162 +msgid "completed" +msgstr "" + +#: views/packages/details/detail.php:162 +msgid "in-complete" +msgstr "" + +#: views/packages/details/detail.php:165 views/packages/details/detail.php:520 +#: views/packages/main/s1.setup2.php:498 +#: views/tools/diagnostics/inc.settings.php:129 +msgid "User" +msgstr "" + +#: views/packages/details/detail.php:169 views/packages/details/detail.php:399 +#: views/packages/main/s1.setup2.php:212 views/packages/main/s2.scan3.php:34 +#: views/packages/main/s2.scan3.php:774 views/packages/main/s2.scan3.php:826 +msgid "Files" +msgstr "" + +#: views/packages/details/detail.php:175 +msgid "Download hashed installer ([name]_[hash]_[time]_installer.php)" +msgstr "" + +#: views/packages/details/detail.php:178 +msgid "Download basic installer (installer.php)" +msgstr "" + +#: views/packages/details/detail.php:184 +msgid "Click buttons or links to download." +msgstr "" + +#: views/packages/details/detail.php:196 +msgid "Share File Links" +msgstr "" + +#: views/packages/details/detail.php:207 views/packages/details/detail.php:352 +#: views/packages/main/packages.php:297 views/packages/main/s1.setup2.php:186 +#: views/packages/main/s2.scan3.php:27 views/packages/main/s3.build.php:183 +#: views/settings/packages.php:250 +msgid "Archive" +msgstr "" + +#: views/packages/details/detail.php:215 +msgid "Build Log" +msgstr "" + +#: views/packages/details/detail.php:223 views/packages/details/detail.php:464 +#: views/packages/main/packages.php:291 views/packages/main/s1.setup2.php:370 +#: views/packages/main/s3.build.php:180 views/settings/packages.php:326 +msgid "Installer" +msgstr "" + +#: views/packages/details/detail.php:228 +msgid "The installer is also available inside the archive file." +msgstr "" + +#: views/packages/details/detail.php:242 +msgid "Download Links" +msgstr "" + +#: views/packages/details/detail.php:245 +msgid "The following links contain sensitive data. Share with caution!" +msgstr "" + +#: views/packages/details/detail.php:286 +msgid "Locations" +msgstr "" + +#: views/packages/details/detail.php:292 views/packages/main/s1.setup2.php:131 +msgid "Default" +msgstr "" + +#: views/packages/details/detail.php:296 views/packages/main/s1.setup2.php:135 +msgid "(Legacy Path)" +msgstr "" + +#: views/packages/details/detail.php:298 views/packages/main/s1.setup2.php:137 +msgid "(Contents Path)" +msgstr "" + +#: views/packages/details/detail.php:305 views/packages/main/s1.setup2.php:144 +msgid "Local" +msgstr "" + +#: views/packages/details/detail.php:320 views/packages/main/s1.setup2.php:153 +#, php-format +msgid "" +"Back up this site to %1$s, %2$s, %3$s, %4$s, %5$s and other locations with " +msgstr "" + +#: views/packages/details/detail.php:331 views/packages/main/packages.php:174 +#: views/packages/main/packages.php:340 views/packages/main/s1.setup2.php:162 +#: views/packages/main/s2.scan3.php:590 views/packages/main/s2.scan3.php:685 +#: views/packages/main/s3.build.php:228 +msgid "Duplicator Pro" +msgstr "" + +#: views/packages/details/detail.php:334 views/packages/main/s1.setup2.php:165 +msgid "Additional Storage:" +msgstr "" + +#: views/packages/details/detail.php:335 views/packages/main/s1.setup2.php:166 +msgid "" +"Duplicator Pro allows you to create a package and store it at a custom " +"location on this server or to a remote cloud location such as Google Drive, " +"Amazon, Dropbox and many more." +msgstr "" + +#: views/packages/details/detail.php:360 +msgid "FILES" +msgstr "" + +#: views/packages/details/detail.php:364 +msgid "Build Mode" +msgstr "" + +#: views/packages/details/detail.php:371 +msgid "Database Mode" +msgstr "" + +#: views/packages/details/detail.php:372 +msgid "Archive Database Only Enabled" +msgstr "" + +#: views/packages/details/detail.php:380 views/packages/main/s2.scan3.php:752 +#: views/packages/main/s2.scan3.php:817 +msgid "Directories" +msgstr "" + +#: views/packages/details/detail.php:384 views/packages/details/detail.php:394 +#: views/packages/details/detail.php:403 views/packages/details/detail.php:451 +msgid "- no filters -" +msgstr "" + +#: views/packages/details/detail.php:390 views/packages/main/s2.scan3.php:763 +msgid "Extensions" +msgstr "" + +#: views/packages/details/detail.php:416 +msgid "DATABASE" +msgstr "" + +#: views/packages/details/detail.php:428 views/packages/main/s1.setup2.php:301 +#: views/settings/packages.php:95 +msgid "SQL Mode" +msgstr "" + +#: views/packages/details/detail.php:434 views/packages/main/s2.scan3.php:734 +msgid "MySQL Compatibility Mode Enabled" +msgstr "" + +#: views/packages/details/detail.php:435 views/packages/main/s1.setup2.php:313 +#: views/packages/main/s2.scan2.php:64 views/packages/main/s2.scan2.php:75 +#: views/packages/main/s2.scan2.php:81 views/packages/main/s2.scan3.php:735 +msgid "details" +msgstr "" + +#: views/packages/details/detail.php:447 views/packages/main/s2.scan3.php:432 +msgid "Tables" +msgstr "" + +#: views/packages/details/detail.php:472 views/packages/main/s1.setup1.php:62 +#: views/packages/main/s1.setup2.php:400 views/packages/main/s2.scan1.php:187 +#: views/packages/main/s2.scan2.php:10 views/packages/main/s3.build.php:111 +msgid "Setup" +msgstr "" + +#: views/packages/details/detail.php:477 views/packages/main/s1.setup2.php:414 +msgid "Security" +msgstr "" + +#: views/packages/details/detail.php:482 +msgid "Password Protection Enabled" +msgstr "" + +#: views/packages/details/detail.php:484 +msgid "Password Protection Disabled" +msgstr "" + +#: views/packages/details/detail.php:495 views/packages/main/s1.setup2.php:430 +msgid "Show/Hide Password" +msgstr "" + +#: views/packages/details/detail.php:508 views/packages/main/s1.setup2.php:456 +msgid " MySQL Server" +msgstr "" + +#: views/packages/details/detail.php:512 views/packages/main/s1.setup2.php:459 +msgid "Host" +msgstr "" + +#: views/packages/details/detail.php:513 views/packages/details/detail.php:517 +#: views/packages/details/detail.php:521 +msgid "- not set -" +msgstr "" + +#: views/packages/details/detail.php:529 +msgid "View Package Object" +msgstr "" + +#: views/packages/details/detail.php:546 +msgid "Package File Links" +msgstr "" + +#: views/packages/details/detail.php:551 +msgid "ARCHIVE" +msgstr "" + +#: views/packages/details/detail.php:552 +msgid "LOG" +msgstr "" + +#: views/packages/main/controller.php:9 +msgid "An invalid request was made to this page." +msgstr "" + +#: views/packages/main/controller.php:10 +msgid "Please retry by going to the" +msgstr "" + +#: views/packages/main/controller.php:11 +msgid "Packages Screen" +msgstr "" + +#: views/packages/main/controller.php:59 +msgid "Packages » All" +msgstr "" + +#: views/packages/main/controller.php:63 views/packages/main/controller.php:67 +#: views/packages/main/controller.php:71 +msgid "Packages » New" +msgstr "" + +#: views/packages/main/packages.php:26 +msgid "" +"When clicking the Installer download button, the 'Save as' dialog is " +"currently defaulting the name to 'installer.php'. To improve the security " +"and get more information, go to: Settings > Packages Tab > Installer > Name " +"option or click on the gear icon at the top of this page." +msgstr "" + +#: views/packages/main/packages.php:29 +msgid "" +"When clicking the Installer download button, the 'Save as' dialog is " +"defaulting the name to '[name]_[hash]_[time]_installer.php'. This is the " +"secure and recommended option. For more information, go to: Settings > " +"Packages Tab > Installer > Name or click on the gear icon at the top of this " +"page.

                      To quickly copy the hashed installer name, to your clipboard " +"use the copy icon link or click the installer name and manually copy the " +"selected text." +msgstr "" + +#: views/packages/main/packages.php:97 +msgid "Delete selected package(s)" +msgstr "" + +#: views/packages/main/packages.php:103 +msgid "Apply" +msgstr "" + +#: views/packages/main/packages.php:107 +msgid "Get Help" +msgstr "" + +#: views/packages/main/packages.php:120 views/tools/controller.php:26 +msgid "Templates" +msgstr "" + +#: views/packages/main/packages.php:132 views/tools/controller.php:27 +msgid "Recovery" +msgstr "" + +#: views/packages/main/packages.php:160 views/packages/main/packages.php:213 +msgid "No Packages Found" +msgstr "" + +#: views/packages/main/packages.php:161 views/packages/main/packages.php:214 +msgid "Click 'Create New' to Archive Site" +msgstr "" + +#: views/packages/main/packages.php:163 views/packages/main/packages.php:216 +msgid "New to Duplicator?" +msgstr "" + +#: views/packages/main/packages.php:165 views/packages/main/packages.php:218 +msgid "Visit the 'Quick Start' guide!" +msgstr "" + +#: views/packages/main/packages.php:171 views/packages/main/packages.php:337 +msgid "Duplicator Lite does not officially support WordPress multisite." +msgstr "" + +#: views/packages/main/packages.php:173 views/packages/main/s3.build.php:227 +msgid "We strongly recommend upgrading to " +msgstr "" + +#: views/packages/main/packages.php:192 +msgid "Select all packages" +msgstr "" + +#: views/packages/main/packages.php:195 views/packages/main/s2.scan3.php:95 +#: views/packages/main/s2.scan3.php:431 +msgid "Size" +msgstr "" + +#: views/packages/main/packages.php:198 +msgid "Installer Name" +msgstr "" + +#: views/packages/main/packages.php:200 views/packages/main/s3.build.php:214 +msgid "Installer Name:" +msgstr "" + +#: views/packages/main/packages.php:205 views/packages/main/s2.scan3.php:716 +msgid "Package" +msgstr "" + +#: views/packages/main/packages.php:252 +msgid "Archive created as zip file" +msgstr "" + +#: views/packages/main/packages.php:253 +msgid "Archive created as daf file" +msgstr "" + +#: views/packages/main/packages.php:258 views/packages/main/s1.setup2.php:200 +#: views/packages/main/s2.scan3.php:41 views/packages/main/s2.scan3.php:62 +msgid "Database Only" +msgstr "" + +#: views/packages/main/packages.php:262 +msgid "Package Build Running" +msgstr "" + +#: views/packages/main/packages.php:263 +msgid "" +"To stop or reset this package build goto Settings > Advanced > Reset Packages" +msgstr "" + +#: views/packages/main/packages.php:280 +msgid "Click to configure installer name." +msgstr "" + +#: views/packages/main/packages.php:299 +msgid "Package Details" +msgstr "" + +#: views/packages/main/packages.php:316 +msgid "Error Processing" +msgstr "" + +#: views/packages/main/packages.php:333 +msgid "Trace Logging Enabled. Please disable when trace capture is complete." +msgstr "" + +#: views/packages/main/packages.php:339 +msgid "We strongly recommend using" +msgstr "" + +#: views/packages/main/packages.php:345 +msgid "Current Server Time" +msgstr "" + +#: views/packages/main/packages.php:348 views/packages/main/s3.build.php:459 +msgid "Time" +msgstr "" + +#: views/packages/main/packages.php:363 +msgid "Items" +msgstr "" + +#: views/packages/main/packages.php:374 +msgid "Bulk Action Required" +msgstr "" + +#: views/packages/main/packages.php:376 +msgid "" +"No selections made! Please select an action from the \"Bulk Actions\" drop " +"down menu." +msgstr "" + +#: views/packages/main/packages.php:380 +msgid "Selection Required" +msgstr "" + +#: views/packages/main/packages.php:382 +msgid "No selections made! Please select at least one package to delete." +msgstr "" + +#: views/packages/main/packages.php:386 +msgid "Delete Packages?" +msgstr "" + +#: views/packages/main/packages.php:387 +msgid "Are you sure you want to delete the selected package(s)?" +msgstr "" + +#: views/packages/main/packages.php:388 +msgid "Removing Packages, Please Wait..." +msgstr "" + +#: views/packages/main/packages.php:395 +msgid "Duplicator Help" +msgstr "" + +#: views/packages/main/packages.php:400 +msgid "Alert!" +msgstr "" + +#: views/packages/main/packages.php:401 +msgid "A package is being processed. Retry later." +msgstr "" + +#: views/packages/main/packages.php:408 +msgid "Common Questions:" +msgstr "" + +#: views/packages/main/packages.php:411 +msgid "How do I create a package" +msgstr "" + +#: views/packages/main/packages.php:415 +msgid "How do I install a package?" +msgstr "" + +#: views/packages/main/packages.php:419 +msgid "Frequently Asked Questions!" +msgstr "" + +#: views/packages/main/packages.php:423 +msgid "Other Resources:" +msgstr "" + +#: views/packages/main/packages.php:425 +msgid "Need help with the plugin?" +msgstr "" + +#: views/packages/main/packages.php:429 views/packages/main/s3.build.php:288 +msgid "Help review the plugin!" +msgstr "" + +#: views/packages/main/s1.setup1.php:12 +msgid "Package settings have been reset." +msgstr "" + +#: views/packages/main/s1.setup1.php:63 views/packages/main/s2.scan1.php:188 +#: views/packages/main/s3.build.php:112 +msgid "Scan" +msgstr "" + +#: views/packages/main/s1.setup1.php:64 views/packages/main/s2.scan1.php:189 +#: views/packages/main/s2.scan1.php:273 views/packages/main/s3.build.php:113 +msgid "Build" +msgstr "" + +#: views/packages/main/s1.setup1.php:69 +msgid "Step 1: Choose the WordPress contents to backup." +msgstr "" + +#: views/packages/main/s1.setup1.php:88 +msgid "Requirements:" +msgstr "" + +#: views/packages/main/s1.setup1.php:97 +msgid "" +"System requirements must pass for the Duplicator to work properly. Click " +"each link for details." +msgstr "" + +#: views/packages/main/s1.setup1.php:103 +msgid "PHP Support" +msgstr "" + +#: views/packages/main/s1.setup1.php:109 views/packages/main/s2.scan2.php:56 +msgid "PHP Version" +msgstr "" + +#: views/packages/main/s1.setup1.php:111 +msgid "PHP versions 5.2.9+ or higher is required." +msgstr "" + +#: views/packages/main/s1.setup1.php:115 +msgid "Zip Archive Enabled" +msgstr "" + +#: views/packages/main/s1.setup1.php:120 +msgid "ZipArchive extension is required or" +msgstr "" + +#: views/packages/main/s1.setup1.php:121 +msgid "Switch to DupArchive" +msgstr "" + +#: views/packages/main/s1.setup1.php:122 +msgid "to by-pass this requirement." +msgstr "" + +#: views/packages/main/s1.setup1.php:129 +msgid "Safe Mode Off" +msgstr "" + +#: views/packages/main/s1.setup1.php:131 +msgid "" +"Safe Mode should be set to Off in you php.ini file and is deprecated as of " +"PHP 5.3.0." +msgstr "" + +#: views/packages/main/s1.setup1.php:134 views/packages/main/s1.setup1.php:139 +#: views/packages/main/s1.setup1.php:144 +msgid "Function" +msgstr "" + +#: views/packages/main/s1.setup1.php:150 +msgid "" +"For any issues in this section please contact your hosting provider or " +"server administrator. For additional information see our online " +"documentation." +msgstr "" + +#: views/packages/main/s1.setup1.php:158 +msgid "Required Paths" +msgstr "" + +#: views/packages/main/s1.setup1.php:180 +msgid "" +"If the root WordPress path is not writable by PHP on some systems this can " +"cause issues." +msgstr "" + +#: views/packages/main/s1.setup1.php:183 +msgid "" +"If Duplicator does not have enough permissions then you will need to " +"manually create the paths above.   " +msgstr "" + +#: views/packages/main/s1.setup1.php:192 +msgid "Server Support" +msgstr "" + +#: views/packages/main/s1.setup1.php:198 +msgid "MySQL Version" +msgstr "" + +#: views/packages/main/s1.setup1.php:202 +msgid "MySQLi Support" +msgstr "" + +#: views/packages/main/s1.setup1.php:209 +msgid "" +"MySQL version 5.0+ or better is required and the PHP MySQLi extension (note " +"the trailing 'i') is also required. Contact your server administrator and " +"request that mysqli extension and MySQL Server 5.0+ be installed." +msgstr "" + +#: views/packages/main/s1.setup1.php:213 +#: views/tools/diagnostics/inc.data.php:26 +msgid "more info" +msgstr "" + +#: views/packages/main/s1.setup1.php:224 +msgid "" +"The function mysqli_real_escape_string is not working properly. Please " +"consult host support and ask them to switch to a different PHP version or " +"configuration." +msgstr "" + +#: views/packages/main/s1.setup1.php:233 +msgid "Reserved Files" +msgstr "" + +#: views/packages/main/s1.setup1.php:238 +msgid "" +"None of the reserved files where found from a previous install. This means " +"you are clear to create a new package." +msgstr "" + +#: views/packages/main/s1.setup1.php:246 +msgid "WordPress Root Path:" +msgstr "" + +#: views/packages/main/s1.setup1.php:249 +msgid "" +" To archive your data correctly please remove any of these files from your " +"WordPress root directory. " +msgstr "" + +#: views/packages/main/s1.setup1.php:251 +msgid "Remove Files Now" +msgstr "" + +#: views/packages/main/s1.setup2.php:86 +msgid "Add Notes" +msgstr "" + +#: views/packages/main/s1.setup2.php:89 +msgid "Toggle a default name" +msgstr "" + +#: views/packages/main/s1.setup2.php:109 +msgid "" +"This is the storage location on this server where the archive and installer " +"files will be saved." +msgstr "" + +#: views/packages/main/s1.setup2.php:112 +msgid "[Storage Options]" +msgstr "" + +#: views/packages/main/s1.setup2.php:122 views/settings/storage.php:71 +msgid "Location" +msgstr "" + +#: views/packages/main/s1.setup2.php:191 +msgid "File filter enabled" +msgstr "" + +#: views/packages/main/s1.setup2.php:195 +msgid "Database filter enabled" +msgstr "" + +#: views/packages/main/s1.setup2.php:199 +msgid "Archive Only the Database" +msgstr "" + +#: views/packages/main/s1.setup2.php:214 +msgid "File Archive Encryption" +msgstr "" + +#: views/packages/main/s1.setup2.php:232 +msgid "Enable Table Filters" +msgstr "" + +#: views/packages/main/s1.setup2.php:234 +msgid "Enable Table Filters:" +msgstr "" + +#: views/packages/main/s1.setup2.php:235 +msgid "" +"Checked tables will not be added to the database script. Excluding certain " +"tables can possibly cause your site or plugins to not work correctly after " +"install!" +msgstr "" + +#: views/packages/main/s1.setup2.php:242 +msgid "Include All" +msgstr "" + +#: views/packages/main/s1.setup2.php:243 +msgid "Exclude All" +msgstr "" + +#: views/packages/main/s1.setup2.php:288 +msgid "Checked tables will be excluded from the database script. " +msgstr "" + +#: views/packages/main/s1.setup2.php:289 +msgid "" +"Excluding certain tables can cause your site or plugins to not work " +"correctly after install!
                      " +msgstr "" + +#: views/packages/main/s1.setup2.php:290 +msgid "" +" Use caution when excluding tables! It is highly " +"recommended to not exclude WordPress core tables*, unless you know the " +"impact." +msgstr "" + +#: views/packages/main/s1.setup2.php:296 +msgid "Configuration" +msgstr "" + +#: views/packages/main/s1.setup2.php:305 +msgid "Compatibility Mode" +msgstr "" + +#: views/packages/main/s1.setup2.php:307 +msgid "Compatibility Mode:" +msgstr "" + +#: views/packages/main/s1.setup2.php:308 +msgid "" +"This is an advanced database backwards compatibility feature that should " +"ONLY be used if having problems installing packages. If the database server " +"version is lower than the version where the package was built then these " +"options may help generate a script that is more compliant with the older " +"database server. It is recommended to try each option separately starting " +"with mysql40." +msgstr "" + +#: views/packages/main/s1.setup2.php:328 +msgid "mysql40" +msgstr "" + +#: views/packages/main/s1.setup2.php:332 +msgid "no_table_options" +msgstr "" + +#: views/packages/main/s1.setup2.php:336 +msgid "no_key_options" +msgstr "" + +#: views/packages/main/s1.setup2.php:340 +msgid "no_field_options" +msgstr "" + +#: views/packages/main/s1.setup2.php:345 +msgid "This option is only available with mysqldump mode." +msgstr "" + +#: views/packages/main/s1.setup2.php:373 +msgid "Installer password protection is on" +msgstr "" + +#: views/packages/main/s1.setup2.php:376 +msgid "Installer password protection is off" +msgstr "" + +#: views/packages/main/s1.setup2.php:387 +msgid "The installer file is used to redeploy/install the archive contents." +msgstr "" + +#: views/packages/main/s1.setup2.php:389 +msgid "All values in this section are" +msgstr "" + +#: views/packages/main/s1.setup2.php:389 +msgid "optional" +msgstr "" + +#: views/packages/main/s1.setup2.php:391 +msgid "Setup/Prefills" +msgstr "" + +#: views/packages/main/s1.setup2.php:392 +msgid "" +"All values in this section are OPTIONAL! If you know ahead of time the " +"database input fields the installer will use, then you can optionally enter " +"them here and they will be prefilled at install time. Otherwise you can " +"just enter them in at install time and ignore all these options in the " +"Installer section." +msgstr "" + +#: views/packages/main/s1.setup2.php:403 views/packages/main/s1.setup2.php:408 +msgid "Branding" +msgstr "" + +#: views/packages/main/s1.setup2.php:406 +msgid "Available with Duplicator Pro!" +msgstr "" + +#: views/packages/main/s1.setup2.php:409 +msgid "" +"Branding is a way to customize the installer look and feel. With branding " +"you can create multiple brands of installers." +msgstr "" + +#: views/packages/main/s1.setup2.php:421 +msgid "Enable Password Protection" +msgstr "" + +#: views/packages/main/s1.setup2.php:423 +msgid "Security:" +msgstr "" + +#: views/packages/main/s1.setup2.php:424 +msgid "" +"Enabling this option will allow for basic password protection on the " +"installer. Before running the installer the password below must be entered " +"before proceeding with an install. This password is a general deterrent and " +"should not be substituted for properly keeping your files secure. Be sure " +"to remove all installer files when the install process is completed." +msgstr "" + +#: views/packages/main/s1.setup2.php:439 +msgid "Prefills" +msgstr "" + +#: views/packages/main/s1.setup2.php:447 views/settings/packages.php:338 +msgid "Basic" +msgstr "" + +#: views/packages/main/s1.setup2.php:448 +msgid "cPanel" +msgstr "" + +#: views/packages/main/s1.setup2.php:467 +msgid "example: localhost (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:472 +msgid "Host Port" +msgstr "" + +#: views/packages/main/s1.setup2.php:480 +msgid "example: 3306 (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:493 +msgid "example: DatabaseName (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:506 +msgid "example: DatabaseUserName (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:511 +#: views/tools/diagnostics/inc.settings.php:109 +#: views/tools/diagnostics/inc.settings.php:202 +msgid "Charset" +msgstr "" + +#: views/packages/main/s1.setup2.php:519 +msgid "example: utf8 (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:524 +msgid "Collation" +msgstr "" + +#: views/packages/main/s1.setup2.php:532 +msgid "example: utf8_general_ci (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:544 +msgid "" +"Create the database and database user at install time without leaving the " +"installer!" +msgstr "" + +#: views/packages/main/s1.setup2.php:545 +msgid "This feature is only availble in " +msgstr "" + +#: views/packages/main/s1.setup2.php:547 +msgid "Duplicator Pro!" +msgstr "" + +#: views/packages/main/s1.setup2.php:549 +msgid "This feature works only with hosts that support cPanel." +msgstr "" + +#: views/packages/main/s1.setup2.php:561 +msgid "Reset" +msgstr "" + +#: views/packages/main/s1.setup2.php:571 +msgid "Reset Package Settings?" +msgstr "" + +#: views/packages/main/s1.setup2.php:572 +msgid "" +"This will clear and reset all of the current package settings. Would you " +"like to continue?" +msgstr "" + +#: views/packages/main/s2.scan1.php:160 +msgid "Input fields not valid" +msgstr "" + +#: views/packages/main/s2.scan1.php:161 views/packages/main/s2.scan1.php:222 +msgid "Please try again!" +msgstr "" + +#: views/packages/main/s2.scan1.php:163 views/packages/main/s2.scan1.php:227 +#: views/packages/main/s3.build.php:503 +msgid "Error Message:" +msgstr "" + +#: views/packages/main/s2.scan1.php:173 views/packages/main/s2.scan1.php:271 +msgid "Back" +msgstr "" + +#: views/packages/main/s2.scan1.php:193 +msgid "Step 2: Scan site for configuration & system notices." +msgstr "" + +#: views/packages/main/s2.scan1.php:209 +msgid "Scanning Site" +msgstr "" + +#: views/packages/main/s2.scan1.php:211 views/packages/main/s3.build.php:152 +msgid "Please Wait..." +msgstr "" + +#: views/packages/main/s2.scan1.php:212 +msgid "Keep this window open during the scan process." +msgstr "" + +#: views/packages/main/s2.scan1.php:213 +msgid "This can take several minutes." +msgstr "" + +#: views/packages/main/s2.scan1.php:221 +msgid "Scan Error" +msgstr "" + +#: views/packages/main/s2.scan1.php:224 views/packages/main/s3.build.php:486 +msgid "Server Status:" +msgstr "" + +#: views/packages/main/s2.scan1.php:236 +msgid "Scan Complete" +msgstr "" + +#: views/packages/main/s2.scan1.php:238 +msgid "Scan Time:" +msgstr "" + +#: views/packages/main/s2.scan1.php:254 +msgid "" +"Scan checks are not required to pass, however they could cause issues on " +"some systems." +msgstr "" + +#: views/packages/main/s2.scan1.php:256 +msgid "" +"Please review the details for each section by clicking on the detail title." +msgstr "" + +#: views/packages/main/s2.scan1.php:262 +msgid "Do you want to continue?" +msgstr "" + +#: views/packages/main/s2.scan1.php:264 +msgid "At least one or more checkboxes were checked in \"Quick Filters\"." +msgstr "" + +#: views/packages/main/s2.scan1.php:265 +msgid "To apply a \"Quick Filter\" click the \"Add Filters & Rescan\" button" +msgstr "" + +#: views/packages/main/s2.scan1.php:267 +msgid "Yes. Continue without applying any file filters." +msgstr "" + +#: views/packages/main/s2.scan1.php:272 +msgid "Rescan" +msgstr "" + +#: views/packages/main/s2.scan1.php:416 +msgid "Unable to perform a full scan, please try the following actions:" +msgstr "" + +#: views/packages/main/s2.scan1.php:417 +msgid "" +"1. Go back and create a root path directory filter to validate the site is " +"scan-able." +msgstr "" + +#: views/packages/main/s2.scan1.php:418 +msgid "" +"2. Continue to add/remove filters to isolate which path is causing issues." +msgstr "" + +#: views/packages/main/s2.scan1.php:419 +msgid "3. This message will go away once the correct filters are applied." +msgstr "" + +#: views/packages/main/s2.scan1.php:421 +msgid "Common Issues:" +msgstr "" + +#: views/packages/main/s2.scan1.php:423 +msgid "" +"- On some budget hosts scanning over 30k files can lead to timeout/gateway " +"issues. Consider scanning only your main WordPress site and avoid trying to " +"backup other external directories." +msgstr "" + +#: views/packages/main/s2.scan1.php:428 +msgid "" +"- Symbolic link recursion can cause timeouts. Ask your server admin if any " +"are present in the scan path. If they are add the full path as a filter and " +"try running the scan again." +msgstr "" + +#: views/packages/main/s2.scan1.php:445 views/packages/main/s2.scan3.php:63 +#: views/packages/main/s2.scan3.php:75 views/packages/main/s2.scan3.php:609 +#: views/packages/main/s3.build.php:370 +msgid "Notice" +msgstr "" + +#: views/packages/main/s2.scan1.php:447 views/packages/main/s2.scan3.php:607 +msgid "Good" +msgstr "" + +#: views/packages/main/s2.scan1.php:448 +msgid "Fail" +msgstr "" + +#: views/packages/main/s2.scan2.php:12 +msgid "Show Diagnostics" +msgstr "" + +#: views/packages/main/s2.scan2.php:13 +msgid "Check Site Health" +msgstr "" + +#: views/packages/main/s2.scan2.php:44 +msgid "System" +msgstr "" + +#: views/packages/main/s2.scan2.php:51 +#: views/tools/diagnostics/inc.settings.php:58 +msgid "Web Server" +msgstr "" + +#: views/packages/main/s2.scan2.php:52 +msgid "Supported web servers: " +msgstr "" + +#: views/packages/main/s2.scan2.php:57 +msgid "" +"The minimum PHP version supported by Duplicator is 5.2.9. It is highly " +"recommended to use PHP 5.3+ for improved stability. For international " +"language support please use PHP 7.0+." +msgstr "" + +#: views/packages/main/s2.scan2.php:62 +msgid "PHP Open Base Dir" +msgstr "" + +#: views/packages/main/s2.scan2.php:63 +msgid "" +"Issues might occur when [open_basedir] is enabled. Work with your server " +"admin to disable this value in the php.ini file if you’re having issues " +"building a package." +msgstr "" + +#: views/packages/main/s2.scan2.php:68 views/packages/main/s3.build.php:466 +msgid "PHP Max Execution Time" +msgstr "" + +#: views/packages/main/s2.scan2.php:69 +msgid "" +"Timeouts may occur for larger packages when [max_execution_time] time in the " +"php.ini is too low. A value of 0 (recommended) indicates that PHP has no " +"time limits. An attempt is made to override this value if the server allows " +"it." +msgstr "" + +#: views/packages/main/s2.scan2.php:72 +msgid "" +"Note: Timeouts can also be set at the web server layer, so if the PHP max " +"timeout passes and you still see a build timeout messages, then your web " +"server could be killing the process. If you are on a budget host and " +"limited on processing time, consider using the database or file filters to " +"shrink the size of your overall package. However use caution as excluding " +"the wrong resources can cause your install to not work properly." +msgstr "" + +#: views/packages/main/s2.scan2.php:79 +msgid "Get faster builds with Duplicator Pro with access to shell_exec zip." +msgstr "" + +#: views/packages/main/s2.scan2.php:86 +msgid "Managed Host" +msgstr "" + +#: views/packages/main/s2.scan2.php:87 +msgid "" +"A managed host is a WordPress host that tightly controls the server " +"environment so that the software running on it can be closely ‘managed’ by " +"the hosting company. Managed hosts typically have constraints imposed to " +"facilitate this management, including the locking down of certain files and " +"directories as well as non-standard configurations." +msgstr "" + +#: views/packages/main/s2.scan2.php:90 +msgid "" +"Duplicator Lite allows users to build a package on managed hosts, however, " +"the installer may not properly install packages created on managed hosts due " +"to the non-standard configurations of managed hosts. It is also possible the " +"package engine of Duplicator Lite won’t be able to capture all of the " +"necessary data of a site running on a managed host." +msgstr "" + +#: views/packages/main/s2.scan2.php:93 +msgid "" +"Due to these constraints Lite does not officially support the migration " +"of managed hosts. It’s possible one could get the package to install but " +"it may require custom manual effort. To get support and the advanced " +"installer processing required for managed host support we encourage users to " +"some budget hosts may cause timeouts. " +msgstr "" + +#: views/packages/main/s2.scan3.php:100 +msgid "more details..." +msgstr "" + +#: views/packages/main/s2.scan3.php:106 +#, php-format +msgid "" +"This notice is triggered at [%s] and can be ignored on most hosts. If " +"during the build process you see a \"Host Build Interrupt\" message then " +"this host has strict processing limits. Below are some options you can take " +"to overcome constraints set up on this host." +msgstr "" + +#: views/packages/main/s2.scan3.php:116 +msgid "Timeout Options" +msgstr "" + +#: views/packages/main/s2.scan3.php:119 +msgid "" +"Apply the \"Quick Filters\" below or click the back button to apply on " +"previous page." +msgstr "" + +#: views/packages/main/s2.scan3.php:124 +#, php-format +msgid "" +"See the FAQ link to adjust this hosts timeout limits: %1$sWhat can I try for " +"Timeout Issues?%2$s" +msgstr "" + +#: views/packages/main/s2.scan3.php:137 +#, php-format +msgid "Consider trying multi-threaded support in %1$sDuplicator Pro%2$s." +msgstr "" + +#: views/packages/main/s2.scan3.php:149 +#, php-format +msgid "" +"Files over %1$s are listed below. Larger files such as movies or zipped " +"content can cause timeout issues on some budget hosts. If you are having " +"issues creating a package try excluding the directory paths below or go back " +"to Step 1 and add them." +msgstr "" + +#: views/packages/main/s2.scan3.php:157 views/packages/main/s2.scan3.php:244 +#: views/packages/main/s2.scan3.php:293 +msgid "Quick Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:158 +msgid "Large Files" +msgstr "" + +#: views/packages/main/s2.scan3.php:161 views/packages/main/s2.scan3.php:296 +msgid "Hide All" +msgstr "" + +#: views/packages/main/s2.scan3.php:162 views/packages/main/s2.scan3.php:297 +msgid "Show All" +msgstr "" + +#: views/packages/main/s2.scan3.php:172 views/packages/main/s2.scan3.php:312 +msgid "" +"Core WordPress directories should not be filtered. Use caution when " +"excluding files." +msgstr "" + +#: views/packages/main/s2.scan3.php:192 +msgid "No large files found during this scan." +msgstr "" + +#: views/packages/main/s2.scan3.php:195 +msgid "" +"No large files found during this scan. If you're having issues building a " +"package click the back button and try adding a file filter to non-essential " +"files paths like wp-content/uploads. These excluded files can then be " +"manually moved to the new location after you have ran the migration " +"installer." +msgstr "" + +#: views/packages/main/s2.scan3.php:208 views/packages/main/s2.scan3.php:338 +msgid "" +"*Checking a directory will exclude all items recursively from that path " +"down. Please use caution when filtering directories." +msgstr "" + +#: views/packages/main/s2.scan3.php:211 views/packages/main/s2.scan3.php:267 +#: views/packages/main/s2.scan3.php:341 +msgid "Add Filters & Rescan" +msgstr "" + +#: views/packages/main/s2.scan3.php:213 views/packages/main/s2.scan3.php:343 +msgid "Copy Paths to Clipboard" +msgstr "" + +#: views/packages/main/s2.scan3.php:229 +msgid "Addon Sites" +msgstr "" + +#: views/packages/main/s2.scan3.php:235 +msgid "" +"An \"Addon Site\" is a separate WordPress site(s) residing in subdirectories " +"within this site. If you confirm these to be separate sites, then it is " +"recommended that you exclude them by checking the corresponding boxes below " +"and clicking the 'Add Filters & Rescan' button. To backup the other sites " +"install the plugin on the sites needing to be backed-up." +msgstr "" + +#: views/packages/main/s2.scan3.php:258 +msgid "No add on sites found." +msgstr "" + +#: views/packages/main/s2.scan3.php:264 +msgid "*Checking a directory will exclude all items in that path recursively." +msgstr "" + +#: views/packages/main/s2.scan3.php:280 views/packages/main/s2.scan3.php:294 +msgid "Name Checks" +msgstr "" + +#: views/packages/main/s2.scan3.php:285 +msgid "" +"Unicode and special characters such as \"*?><:/\\|\", can be problematic on " +"some hosts." +msgstr "" + +#: views/packages/main/s2.scan3.php:286 +msgid "" +" Only consider using this filter if the package build is failing. Select " +"files that are not important to your site or you can migrate manually." +msgstr "" + +#: views/packages/main/s2.scan3.php:287 +msgid "" +"If this environment/system and the system where it will be installed are set " +"up to support Unicode and long paths then these filters can be ignored. If " +"you run into issues with creating or installing a package, then is " +"recommended to filter these paths." +msgstr "" + +#: views/packages/main/s2.scan3.php:332 +msgid "No file/directory name warnings found." +msgstr "" + +#: views/packages/main/s2.scan3.php:355 +msgid "Read Checks" +msgstr "" + +#: views/packages/main/s2.scan3.php:360 +msgid "" +"PHP is unable to read the following items and they will NOT be included in " +"the package. Please work with your host to adjust the permissions or " +"resolve the symbolic-link(s) shown in the lists below. If these items are " +"not needed then this notice can be ignored." +msgstr "" + +#: views/packages/main/s2.scan3.php:366 +msgid "Unreadable Items:" +msgstr "" + +#: views/packages/main/s2.scan3.php:373 +msgid "No unreadable items found." +msgstr "" + +#: views/packages/main/s2.scan3.php:377 +msgid "Recursive Links:" +msgstr "" + +#: views/packages/main/s2.scan3.php:384 +msgid "No recursive sym-links found." +msgstr "" + +#: views/packages/main/s2.scan3.php:415 +msgid "Database Size:" +msgstr "" + +#: views/packages/main/s2.scan3.php:416 +msgid "" +"The database size represents only the included tables. The process for " +"gathering the size uses the query SHOW TABLE STATUS. The overall size of " +"the database file can impact the final size of the package." +msgstr "" + +#: views/packages/main/s2.scan3.php:426 views/packages/main/s3.build.php:326 +#: views/packages/screen.php:65 +msgid "Overview" +msgstr "" + +#: views/packages/main/s2.scan3.php:430 +msgid "TOTAL SIZE" +msgstr "" + +#: views/packages/main/s2.scan3.php:433 +msgid "Records" +msgstr "" + +#: views/packages/main/s2.scan3.php:436 +#, php-format +msgid "" +"Total size and row counts are approximate values. The thresholds that " +"trigger notices are %1$s records total for the entire database. Larger " +"databases take more time to process. On some budget hosts that have cpu/" +"memory/timeout limits this may cause issues." +msgstr "" + +#: views/packages/main/s2.scan3.php:441 +msgid "TABLE DETAILS:" +msgstr "" + +#: views/packages/main/s2.scan3.php:443 +#, php-format +msgid "" +"The notices for tables are %1$s records or names with upper-case " +"characters. Individual tables will not trigger a notice message, but can " +"help narrow down issues if they occur later on." +msgstr "" + +#: views/packages/main/s2.scan3.php:450 views/packages/main/s2.scan3.php:561 +#: views/packages/main/s2.scan3.php:646 +msgid "RECOMMENDATIONS:" +msgstr "" + +#: views/packages/main/s2.scan3.php:453 +msgid "repair and optimization" +msgstr "" + +#: views/packages/main/s2.scan3.php:454 +#, php-format +msgid "1. Run a %1$s on the table to improve the overall size and performance." +msgstr "" + +#: views/packages/main/s2.scan3.php:456 +msgid "" +"2. Remove post revisions and stale data from tables. Tables such as logs, " +"statistical or other non-critical data should be cleared." +msgstr "" + +#: views/packages/main/s2.scan3.php:458 +msgid "Enable mysqldump" +msgstr "" + +#: views/packages/main/s2.scan3.php:459 +#, php-format +msgid "3. %1$s if this host supports the option." +msgstr "" + +#: views/packages/main/s2.scan3.php:461 +msgid "lower_case_table_names" +msgstr "" + +#: views/packages/main/s2.scan3.php:462 +#, php-format +msgid "" +"4. For table name case sensitivity issues either rename the table with lower " +"case characters or be prepared to work with the %1$s system variable setting." +msgstr "" + +#: views/packages/main/s2.scan3.php:473 +msgid "Triggers" +msgstr "" + +#: views/packages/main/s2.scan3.php:482 +msgid "triggers" +msgstr "" + +#: views/packages/main/s2.scan3.php:483 +#, php-format +msgid "" +"This database makes use of %1$s which can manually be imported at install " +"time. Instructions and SQL statement queries will be provided at install " +"time for users to execute. No actions need to be performed at this time, " +"this message is simply a notice." +msgstr "" + +#: views/packages/main/s2.scan3.php:500 +msgid "Object Access" +msgstr "" + +#: views/packages/main/s2.scan3.php:508 +msgid "" +"The database user for this WordPress site has sufficient permissions to " +"write stored procedures and functions to the sql file of the archive. [The " +"command SHOW CREATE FUNCTION will work.]" +msgstr "" + +#: views/packages/main/s2.scan3.php:513 +msgid "" +"The database user for this WordPress site does NOT sufficient permissions to " +"write stored procedures or functions to the sql file of the archive. Stored " +"procedures will not be added to the sql file." +msgstr "" + +#: views/packages/main/s2.scan3.php:532 +msgid "Total Size" +msgstr "" + +#: views/packages/main/s2.scan3.php:537 +msgid "Total Size:" +msgstr "" + +#: views/packages/main/s2.scan3.php:538 +msgid "The total size of the site (files plus database)." +msgstr "" + +#: views/packages/main/s2.scan3.php:548 +#, php-format +msgid "" +"The build can't continue because the total size of files and the database " +"exceeds the %s limit that can be processed when creating a DupArchive " +"package. " +msgstr "" + +#: views/packages/main/s2.scan3.php:550 +msgid "Click for recommendations." +msgstr "" + +#: views/packages/main/s2.scan3.php:555 views/packages/main/s2.scan3.php:719 +#: views/settings/packages.php:254 +msgid "Archive Engine" +msgstr "" + +#: views/packages/main/s2.scan3.php:556 +#, php-format +msgid "" +"The %s is set to create packages in the 'DupArchive' format. This custom " +"format is used to overcome budget host constraints. With DupArchive, " +"Duplicator is restricted to processing sites up to %s. To process larger " +"sites, consider these recommendations. " +msgstr "" + +#: views/packages/main/s2.scan3.php:566 +msgid "Step 1" +msgstr "" + +#: views/packages/main/s2.scan3.php:567 +#, php-format +msgid "- Add data filters to get the package size under %s: " +msgstr "" + +#: views/packages/main/s2.scan3.php:569 +msgid "" +"- In the 'Size Checks' section above consider adding filters (if notice is " +"shown)." +msgstr "" + +#: views/packages/main/s2.scan3.php:571 +#, php-format +msgid "- In %s consider adding file/directory or database table filters." +msgstr "" + +#: views/packages/main/s2.scan3.php:577 +#, php-format +msgid "- Perform a two part install as %1$sdescribed in the documentation%2$s." +msgstr "" + +#: views/packages/main/s2.scan3.php:586 +msgid "ZipArchive Engine" +msgstr "" + +#: views/packages/main/s2.scan3.php:587 +#, php-format +msgid "" +"- Switch to the %s which requires a capable hosting provider (VPS " +"recommended)." +msgstr "" + +#: views/packages/main/s2.scan3.php:591 +#, php-format +msgid "- Consider upgrading to %s for unlimited large site support." +msgstr "" + +#: views/packages/main/s2.scan3.php:603 +msgid "Mysqldump memory check" +msgstr "" + +#: views/packages/main/s2.scan3.php:616 +msgid "The database size is within the allowed mysqldump size limit." +msgstr "" + +#: views/packages/main/s2.scan3.php:621 +#, php-format +msgid "" +"If you encounter any issues with mysqldump please change the setting SQL " +"Mode to PHP Code. You can do that by opening %1$sDuplicator Pro > Settings > " +"Packages.%2$s" +msgstr "" + +#: views/packages/main/s2.scan3.php:634 +msgid "The database size exceeds the allowed mysqldump size limit." +msgstr "" + +#: views/packages/main/s2.scan3.php:638 +msgid "" +"The database size is larger than the PHP memory_limit value. This can lead " +"into issues when building a package, during which the system can run out of " +"memory. To fix this issue please consider doing one of the below mentioned " +"recommendations." +msgstr "" + +#: views/packages/main/s2.scan3.php:653 +#, php-format +msgid "" +"Please change the setting SQL Mode to PHP Code. You can do that by opening " +"%1$sDuplicator Pro > Settings > Packages.%2$s" +msgstr "" + +#: views/packages/main/s2.scan3.php:667 +#, php-format +msgid "" +"If you want to build the package with mysqldump, increase the PHP " +"memory_limit value in your php.ini file to at least %1$s." +msgstr "" + +#: views/packages/main/s2.scan3.php:684 +msgid "Migrate large, multi-gig sites with" +msgstr "" + +#: views/packages/main/s2.scan3.php:699 +msgid "Scan Details" +msgstr "" + +#: views/packages/main/s2.scan3.php:706 +msgid "Copy Quick Filter Paths" +msgstr "" + +#: views/packages/main/s2.scan3.php:725 +msgid "Name:" +msgstr "" + +#: views/packages/main/s2.scan3.php:726 +msgid "Host:" +msgstr "" + +#: views/packages/main/s2.scan3.php:728 +msgid "Build Mode:" +msgstr "" + +#: views/packages/main/s2.scan3.php:744 +msgid "File Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:745 +#: views/tools/diagnostics/inc.settings.php:178 +msgid "Disabled" +msgstr "" + +#: views/packages/main/s2.scan3.php:759 +msgid "No custom directory filters set." +msgstr "" + +#: views/packages/main/s2.scan3.php:769 +msgid "No file extension filters have been set." +msgstr "" + +#: views/packages/main/s2.scan3.php:781 +msgid "No custom file filters set." +msgstr "" + +#: views/packages/main/s2.scan3.php:785 +msgid "Auto Directory Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:791 +msgid "Auto File Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:804 +msgid "Path filters will be skipped during the archive process when enabled." +msgstr "" + +#: views/packages/main/s2.scan3.php:806 +msgid "[view json result report]" +msgstr "" + +#: views/packages/main/s2.scan3.php:809 +msgid "Auto filters are applied to prevent archiving other backup sets." +msgstr "" + +#: views/packages/main/s2.scan3.php:820 views/packages/main/s2.scan3.php:829 +msgid "Click to Copy" +msgstr "" + +#: views/packages/main/s2.scan3.php:834 +msgid "" +"Copy the paths above and apply them as needed on Step 1 > Archive > " +"Files section." +msgstr "" + +#: views/packages/main/s2.scan3.php:851 +msgid "Directory applied filter set." +msgstr "" + +#: views/packages/main/s2.scan3.php:878 +msgid "No directories have been selected!" +msgstr "" + +#: views/packages/main/s2.scan3.php:882 +msgid "No files have been selected!" +msgstr "" + +#: views/packages/main/s2.scan3.php:920 +msgid "Copied to Clipboard!" +msgstr "" + +#: views/packages/main/s2.scan3.php:922 +msgid "Manual copy of selected text required on this browser." +msgstr "" + +#: views/packages/main/s2.scan3.php:929 +msgid "Initializing Please Wait..." +msgstr "" + +#: views/packages/main/s2.scan3.php:972 views/packages/main/s2.scan3.php:979 +msgid "" +"Error applying filters. Please go back to Step 1 to add filter manually!" +msgstr "" + +#: views/packages/main/s2.scan3.php:1091 +msgid "Unable to report on any tables" +msgstr "" + +#: views/packages/main/s2.scan3.php:1117 +msgid "Unable to report on database stats" +msgstr "" + +#: views/packages/main/s3.build.php:21 +msgid "" +"When clicking the Installer download button, the 'Save as' dialog will " +"default the name to 'installer.php'. To improve the security and get more " +"information, goto: Settings ❯ Packages Tab ❯ Installer Name option." +msgstr "" + +#: views/packages/main/s3.build.php:24 +msgid "" +"When clicking the Installer download button, the 'Save as' dialog will save " +"the name as '[name]_[hash]_[time]_installer.php'. This is the secure and " +"recommended option. For more information goto: Settings ❯ Packages Tab ❯ " +"Installer Name Option. To quickly copy the hashed installer name, to your " +"clipboard use the copy icon link." +msgstr "" + +#: views/packages/main/s3.build.php:117 +msgid "Step 3: Build and download the package files." +msgstr "" + +#: views/packages/main/s3.build.php:150 +msgid "Building Package" +msgstr "" + +#: views/packages/main/s3.build.php:153 +msgid "Keep this window open and do not close during the build process." +msgstr "" + +#: views/packages/main/s3.build.php:154 +msgid "This may take several minutes to complete." +msgstr "" + +#: views/packages/main/s3.build.php:160 +msgid "Build Status" +msgstr "" + +#: views/packages/main/s3.build.php:167 +msgid "Package Build Completed" +msgstr "" + +#: views/packages/main/s3.build.php:171 +msgid "Build Time" +msgstr "" + +#: views/packages/main/s3.build.php:177 +msgid "Download Package Files" +msgstr "" + +#: views/packages/main/s3.build.php:179 +msgid "Click to download installer file" +msgstr "" + +#: views/packages/main/s3.build.php:182 +msgid "Click to download archive file" +msgstr "" + +#: views/packages/main/s3.build.php:187 +msgid "Click to download both files" +msgstr "" + +#: views/packages/main/s3.build.php:189 +msgid "Download Both Files" +msgstr "" + +#: views/packages/main/s3.build.php:193 +msgid "Download Both Files:" +msgstr "" + +#: views/packages/main/s3.build.php:194 +msgid "" +"Clicking this button will open the installer and archive download prompts " +"one after the other with one click verses downloading each file separately " +"with two clicks. On some browsers you may have to disable pop-up warnings " +"on this domain for this to work correctly." +msgstr "" + +#: views/packages/main/s3.build.php:204 +msgid "[Copy Installer Name to Clipboard]" +msgstr "" + +#: views/packages/main/s3.build.php:209 +msgid "[Show Installer Name]" +msgstr "" + +#: views/packages/main/s3.build.php:225 +msgid "Notice:Duplicator Lite does not officially support WordPress multisite." +msgstr "" + +#: views/packages/main/s3.build.php:235 +msgid "How to install this package?" +msgstr "" + +#: views/packages/main/s3.build.php:244 +msgid "Install to Empty Directory " +msgstr "" + +#: views/packages/main/s3.build.php:253 +msgid "Install to an empty directory like a new WordPress install does." +msgstr "" + +#: views/packages/main/s3.build.php:260 +msgid "Overwrite Site" +msgstr "" + +#: views/packages/main/s3.build.php:267 +msgid "Quickly overwrite an existing WordPress site in a few clicks." +msgstr "" + +#: views/packages/main/s3.build.php:274 +msgid "Import Archive and Overwrite Site" +msgstr "" + +#: views/packages/main/s3.build.php:280 +msgid "Drag and drop or use a URL for super-fast installs (requires Pro*)" +msgstr "" + +#: views/packages/main/s3.build.php:297 +msgid "Host Build Interrupt" +msgstr "" + +#: views/packages/main/s3.build.php:298 +msgid "" +"This server cannot complete the build due to host setup constraints, see the " +"error message for more details." +msgstr "" + +#: views/packages/main/s3.build.php:299 +msgid "" +"If the error details are not specific consider the options below by clicking " +"each section." +msgstr "" + +#: views/packages/main/s3.build.php:306 +msgid "Option 1: DupArchive" +msgstr "" + +#: views/packages/main/s3.build.php:311 +msgid "" +"Enable the DupArchive format which is specific to Duplicator and designed to " +"perform better on constrained budget hosts." +msgstr "" + +#: views/packages/main/s3.build.php:316 +msgid "" +"Note:DupArchive on Duplicator only supports sites up to 500MB. If your site " +"is over 500MB then use a file filter on step 1 to get the size below 500MB " +"or try the other options mentioned below. Alternatively, you may want to " +"consider" +msgstr "" + +#: views/packages/main/s3.build.php:323 +msgid " which is capable of migrating sites much larger than 500MB." +msgstr "" + +#: views/packages/main/s3.build.php:327 views/packages/main/s3.build.php:399 +msgid "Please follow these steps:" +msgstr "" + +#: views/packages/main/s3.build.php:329 +msgid "" +"On the scanner step check to make sure your package is under 500MB. If not " +"see additional options below." +msgstr "" + +#: views/packages/main/s3.build.php:331 +msgid "" +"Go to Duplicator > Settings > Packages Tab > Archive Engine >" +msgstr "" + +#: views/packages/main/s3.build.php:332 +msgid "Enable DupArchive" +msgstr "" + +#: views/packages/main/s3.build.php:334 +msgid "Build a new package using the new engine format." +msgstr "" + +#: views/packages/main/s3.build.php:338 +msgid "" +"Note:The DupArchive engine will generate an archive.daf file. This file is " +"very similar to a .zip except that it can only be extracted by the installer." +"php file or the" +msgstr "" + +#: views/packages/main/s3.build.php:341 +msgid "commandline extraction tool" +msgstr "" + +#: views/packages/main/s3.build.php:351 +msgid "Option 2: File Filters" +msgstr "" + +#: views/packages/main/s3.build.php:356 +msgid "" +"The first pass for reading files on some budget hosts maybe slow and have " +"conflicts with strict timeout settings setup by the hosting provider. In " +"these cases, it is recommended to retry the build by adding file filters to " +"larger files/directories." +msgstr "" + +#: views/packages/main/s3.build.php:361 +msgid "" +"For example, you could filter out the \"/wp-content/uploads/\" folder to " +"create the package then move the files from that directory over manually. " +"If this work-flow is not desired or does not work please check-out the other " +"options below." +msgstr "" + +#: views/packages/main/s3.build.php:366 +msgid "Retry Build With Filters" +msgstr "" + +#: views/packages/main/s3.build.php:374 +msgid "Build Folder:" +msgstr "" + +#: views/packages/main/s3.build.php:376 +msgid "" +"On some servers the build will continue to run in the background. To " +"validate if a build is still running; open the 'tmp' folder above and see if " +"the archive file is growing in size or check the main packages screen to see " +"if the package completed. If it is not then your server has strict timeout " +"constraints." +msgstr "" + +#: views/packages/main/s3.build.php:389 +msgid "Option 3: Two-Part Install" +msgstr "" + +#: views/packages/main/s3.build.php:394 +msgid "" +"A two-part install minimizes server load and can avoid I/O and CPU issues " +"encountered on some budget hosts. With this procedure you simply build a " +"'database-only' archive, manually move the website files, and then run the " +"installer to complete the process." +msgstr "" + +#: views/packages/main/s3.build.php:398 +msgid " Overview" +msgstr "" + +#: views/packages/main/s3.build.php:401 +msgid "Click the button below to go back to Step 1." +msgstr "" + +#: views/packages/main/s3.build.php:402 +msgid "" +"On Step 1 the \"Archive Only the Database\" checkbox will be auto checked." +msgstr "" + +#: views/packages/main/s3.build.php:420 +msgid "Yes. I have read the above overview and would like to continue!" +msgstr "" + +#: views/packages/main/s3.build.php:422 +msgid "Start Two-Part Install Process" +msgstr "" + +#: views/packages/main/s3.build.php:432 +msgid "Option 4: Configure Server" +msgstr "" + +#: views/packages/main/s3.build.php:436 +msgid "OPTION 4:" +msgstr "" + +#: views/packages/main/s3.build.php:437 +msgid "" +"This option is available on some hosts that allow for users to adjust server " +"configurations. With this option you will be directed to an FAQ page that " +"will show various recommendations you can take to improve/unlock constraints " +"set up on this server." +msgstr "" + +#: views/packages/main/s3.build.php:446 +msgid "Diagnose Server Setup" +msgstr "" + +#: views/packages/main/s3.build.php:450 +msgid "RUNTIME DETAILS" +msgstr "" + +#: views/packages/main/s3.build.php:453 +msgid "Allowed Runtime:" +msgstr "" + +#: views/packages/main/s3.build.php:457 +msgid "PHP Max Execution" +msgstr "" + +#: views/packages/main/s3.build.php:467 +msgid "" +"This value is represented in seconds. A value of 0 means no timeout limit is " +"set for PHP." +msgstr "" + +#: views/packages/main/s3.build.php:471 views/settings/packages.php:208 +msgid "Mode" +msgstr "" + +#: views/packages/main/s3.build.php:477 +msgid "PHP Max Execution Mode" +msgstr "" + +#: views/packages/main/s3.build.php:479 +msgid "" +"If the value is [dynamic] then its possible for PHP to run longer than the " +"default. If the value is [fixed] then PHP will not be allowed to run longer " +"than the default.

                      If this value is larger than the [Allowed " +"Runtime] above then the web server has been enabled with a timeout cap and " +"is overriding the PHP max time setting." +msgstr "" + +#: views/packages/main/s3.build.php:487 +msgid "unavailable" +msgstr "" + +#: views/packages/main/s3.build.php:499 +msgid "System Details" +msgstr "" + +#: views/packages/main/s3.build.php:506 +msgid "Error status unavailable." +msgstr "" + +#: views/packages/main/s3.build.php:514 +msgid "See Package Log For Complete Details" +msgstr "" + +#: views/packages/screen.php:76 +msgid "" +" Packages » All
                      The 'Packages' " +"section is the main interface for managing all the packages that have been " +"created. A Package consists of two core files, the 'archive.zip' and the " +"'installer.php' file. The archive file is a zip file containing all your " +"WordPress files and a copy of your WordPress database. The installer file " +"is a php file that when browsed to via a web browser presents a wizard that " +"redeploys/installs the website by extracting the archive file and installing " +"the database. To create a package, click the 'Create New' button and " +"follow the prompts.

                      Downloads
                      To download the package files click on the Installer and Archive " +"buttons after creating a package. The archive file will have a copy of the " +"installer inside of it named installer-backup.php in case the original " +"installer file is lost. To see the details of a package click on the details button.

                      Archive Types
                      An archive file can be saved as either " +"a .zip file or .daf file. A zip file is a common archive format used to " +"compress and group files. The daf file short for 'Duplicator Archive " +"Format' is a custom format used specifically for working with larger " +"packages and scale-ability issues on many shared hosting platforms. Both " +"formats work very similar. The main difference is that the daf file can " +"only be extracted using the installer.php file or the

                      To exclude a database table, check the box labeled 'Enable Table Filters' " +"and check the table name to exclude. To include only a copy of your database " +"in the archive file check the box labeled 'Archive Only the Database'. The " +"installer.php file can optionally be pre-filled with data at install time " +"but is not required.

                      " +msgstr "" + +#: views/packages/screen.php:133 +msgid "" +"Packages » 3 Build
                      The final step in the build process where the " +"installer script and archive of the website can be downloaded. To start " +"the install process follow these steps:
                      1. Download the installer.php " +"and archive.zip files to your local computer.
                      2. For localhost installs " +"be sure you have PHP, Apache & MySQL installed on your local computer with " +"software such as XAMPP, Instant WordPress or MAMP for MAC. Place the package." +"zip and installer.php into any empty directory under your webroot then " +"browse to the installer.php via your web browser to launch the install " +"wizard.
                      3. For remote installs use FTP or cPanel to upload both the " +"archive.zip and installer.php to your hosting provider. Place the files in a " +"new empty directory under your host's webroot accessible from a valid URL " +"such as http://your-domain/your-wp-directory/installer.php to launch the " +"install wizard. On some hosts the root directory will be a something like " +"public_html -or- www. If your're not sure contact your hosting provider.
                      For complete instructions see:
                      upgrading to PRO." +msgstr "" + +#: views/settings/license.php:63 +#, php-format +msgid "" +"As a valued Duplicator Lite user you receive %1$d%% off, " +"automatically applied at checkout!" +msgstr "" + +#: views/settings/license.php:72 +msgid "" +"Already purchased? Simply enter your license key below to enable " +"Duplicator PRO!" +msgstr "" + +#: views/settings/license.php:74 +msgid "Paste license key here" +msgstr "" + +#: views/settings/license.php:75 +msgid "One click Upgrade to Pro" +msgstr "" + +#: views/settings/packages.php:14 +msgid "Package Settings Saved" +msgstr "" + +#: views/settings/packages.php:99 +msgid "Mysqldump" +msgstr "" + +#: views/settings/packages.php:109 +msgid "PHP Code" +msgstr "" + +#: views/settings/packages.php:119 +msgid "" +"This server does not support the PHP shell_exec or exec function which is " +"required for mysqldump to run. " +msgstr "" + +#: views/settings/packages.php:120 +msgid "Please contact the host or server administrator to enable this feature." +msgstr "" + +#: views/settings/packages.php:125 views/tools/diagnostics/logging.php:183 +msgid "Host Recommendation:" +msgstr "" + +#: views/settings/packages.php:126 views/tools/diagnostics/logging.php:184 +msgid "" +"Duplicator recommends going with the high performance pro plan or better " +"from our recommended list" +msgstr "" + +#: views/settings/packages.php:131 +#, php-format +msgid "" +"Please visit our recommended %1$shost list%2$s for reliable access to " +"mysqldump." +msgstr "" + +#: views/settings/packages.php:150 +msgid "Successfully Found:" +msgstr "" + +#: views/settings/packages.php:157 +msgid "" +"Mysqldump was not found at its default location or the location provided. " +"Please enter a custom path to a valid location where mysqldump can run. If " +"the problem persist contact your host or server administrator. " +msgstr "" + +#: views/settings/packages.php:162 +#, php-format +msgid "See the %1$shost list%2$s for reliable access to mysqldump." +msgstr "" + +#: views/settings/packages.php:175 +msgid "Custom Path" +msgstr "" + +#: views/settings/packages.php:177 +msgid "mysqldump path:" +msgstr "" + +#: views/settings/packages.php:179 +msgid "" +"Add a custom path if the path to mysqldump is not properly detected. For " +"all paths use a forward slash as the path seperator. On Linux systems use " +"mysqldump for Windows systems use mysqldump.exe. If the path tried does not " +"work please contact your hosting provider for details on the correct path." +msgstr "" + +#: views/settings/packages.php:188 +msgid "/usr/bin/mypath/mysqldump" +msgstr "" + +#: views/settings/packages.php:193 +msgid "" +" The custom path provided " +"is not recognized as a valid mysqldump file:
                      " +msgstr "" + +#: views/settings/packages.php:211 +msgid "Single-Threaded" +msgstr "" + +#: views/settings/packages.php:214 +msgid "Multi-Threaded (Pro)" +msgstr "" + +#: views/settings/packages.php:218 +msgid "PHP Code Mode:" +msgstr "" + +#: views/settings/packages.php:220 +msgid "" +"Single-Threaded mode attempts to create the entire database script in one " +"request. Multi-Threaded mode allows the database script to be chunked over " +"multiple requests. Multi-Threaded mode is typically slower but much more " +"reliable especially for larger databases." +msgstr "" + +#: views/settings/packages.php:222 +msgid "

                      Multi-Threaded mode is only available in Duplicator Pro." +msgstr "" + +#: views/settings/packages.php:225 +msgid "Query Limit Size" +msgstr "" + +#: views/settings/packages.php:235 +msgid "PHP Query Limit Size" +msgstr "" + +#: views/settings/packages.php:237 +msgid "" +"A higher limit size will speed up the database build time, however it will " +"use more memory. If your host has memory caps start off low." +msgstr "" + +#: views/settings/packages.php:259 +msgid "ZipArchive" +msgstr "" + +#: views/settings/packages.php:265 +msgid "DupArchive" +msgstr "" + +#: views/settings/packages.php:273 +msgid "Creates a archive format (archive.zip)." +msgstr "" + +#: views/settings/packages.php:276 +msgid "" +"This option uses the internal PHP ZipArchive classes to create a zip file." +msgstr "" + +#: views/settings/packages.php:278 +msgid "" +"Duplicator Lite has no fixed size constraints for zip formats. The only " +"constraints are timeouts on the server." +msgstr "" + +#: views/settings/packages.php:288 +msgid "Creates a custom archive format (archive.daf)." +msgstr "" + +#: views/settings/packages.php:291 +msgid "" +"This option is recommended for large sites or sites on constrained servers." +msgstr "" + +#: views/settings/packages.php:292 +msgid "Duplicator Lite has a fixed constraint of 500MB for daf formats." +msgstr "" + +#: views/settings/packages.php:296 +#, php-format +msgid "" +"Consider upgrading to %1$sDuplicator Pro%2$s for unlimited large site " +"support with DupArchive." +msgstr "" + +#: views/settings/packages.php:310 +msgid "Archive Flush" +msgstr "" + +#: views/settings/packages.php:313 +msgid "Attempt Network Keep Alive" +msgstr "" + +#: views/settings/packages.php:314 +msgid "enable only for large archives" +msgstr "" + +#: views/settings/packages.php:317 +msgid "" +"This will attempt to keep a network connection established for large " +"archives." +msgstr "" + +#: views/settings/packages.php:319 +msgid " Valid only when Archive Engine for ZipArchive is enabled." +msgstr "" + +#: views/settings/packages.php:330 +msgid "File Name" +msgstr "" + +#: views/settings/packages.php:332 +msgid "Default 'Save as' name:" +msgstr "" + +#: views/settings/packages.php:347 +msgid "Secure" +msgstr "" + +#: views/settings/packages.php:348 +msgid "recommended" +msgstr "" + +#: views/settings/packages.php:351 +msgid "To understand the importance and usage of the installer name, please" +msgstr "" + +#: views/settings/packages.php:352 +msgid "read this section" +msgstr "" + +#: views/settings/packages.php:356 +msgid "" +"Using a 'Secure' file helps prevent unauthorized access to the installer " +"file." +msgstr "" + +#: views/settings/packages.php:357 +msgid "Example" +msgstr "" + +#: views/settings/packages.php:362 +msgid "" +"This setting specifies the name of the installer used at download-time. " +"Independent of the value of this setting, you can change the name of the " +"installer in the \"Save as\" file dialog at download-time. If you choose to " +"use a custom name, use a file name that is known only to you. Installer " +"filenames must end in \"php\". Changes to the archive file should not be " +"made." +msgstr "" + +#: views/settings/packages.php:372 +msgid "" +"Do not to leave any installer files on the destination server, after " +"installing the migrated/restored site. Logon as a WordPress administrator " +"and follow the prompts to remove the installer files or remove them manually." +msgstr "" + +#: views/settings/packages.php:380 +msgid "" +"Tip: Each row on the packages screen includes a copy button to copy the " +"installer name to the clipboard. Paste the installer name from the " +"clipboard into the URL being used to install the destination site. This " +"feature is handy when using the secure installer name." +msgstr "" + +#: views/settings/packages.php:391 +msgid "Visuals" +msgstr "" + +#: views/settings/packages.php:395 +msgid "Created Format" +msgstr "" + +#: views/settings/packages.php:399 +msgid "By Year" +msgstr "" + +#: views/settings/packages.php:406 +msgid "By Month" +msgstr "" + +#: views/settings/packages.php:413 +msgid "By Day" +msgstr "" + +#: views/settings/packages.php:421 +msgid "" +"The UTC date format shown in the 'Created' column on the Packages screen." +msgstr "" + +#: views/settings/packages.php:422 +msgid "" +"To use WordPress timezone formats consider an upgrade to Duplicator Pro." +msgstr "" + +#: views/settings/packages.php:431 +msgid "Save Package Settings" +msgstr "" + +#: views/settings/storage.php:16 +msgid "Storage Settings Saved" +msgstr "" + +#: views/settings/storage.php:42 +msgid "Storage folder move problem" +msgstr "" + +#: views/settings/storage.php:45 +#, php-format +msgid "Duplicator can't change the storage folder to %s" +msgstr "" + +#: views/settings/storage.php:46 +#, php-format +msgid "Check the parent folder permissions. ( %s )" +msgstr "" + +#: views/settings/storage.php:78 +msgid "Legacy Path:" +msgstr "" + +#: views/settings/storage.php:87 +msgid "Contents Path:" +msgstr "" + +#: views/settings/storage.php:93 +msgid "" +"The storage location is where all package files are stored to disk. If your " +"host has troubles writing content to the 'Legacy Path' then use the " +"'Contents Path'. Upon clicking the save button all files are moved to the " +"new location and the previous path is removed." +msgstr "" + +#: views/settings/storage.php:98 +msgid "More Advanced Storage Options..." +msgstr "" + +#: views/settings/storage.php:103 +msgid "Apache .htaccess" +msgstr "" + +#: views/settings/storage.php:106 +msgid "Disable .htaccess file in storage directory" +msgstr "" + +#: views/settings/storage.php:109 +msgid "" +"When checked this setting will prevent Duplicator from laying down an ." +"htaccess file in the storage location above." +msgstr "" + +#: views/settings/storage.php:110 +msgid "" +"Only disable this option if issues occur when downloading either the " +"installer/archive files." +msgstr "" + +#: views/settings/storage.php:118 +msgid "Save Storage Settings" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:11 +msgid "Stored Data" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:16 +msgid "Data Cleanup" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:21 +msgid "Remove Installation Files" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:25 +msgid "Removes all reserved installer files." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:30 +msgid "" +"Clicking on the 'Remove Installation Files' button will attempt to remove " +"the installer files used by Duplicator. These files should not be left on " +"production systems for security reasons. Below are the files that should be " +"removed." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:45 +msgid "Clear Build Cache" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:48 +msgid "Removes all build data from:" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:53 +msgid "Options Values" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:87 +msgid "Delete Option?" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:88 +msgid "Delete the option value just selected?" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:89 +msgid "Removing Option, Please Wait..." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:94 +msgid "Clear Build Cache?" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:95 +msgid "" +"This process will remove all build cache files. Be sure no packages are " +"currently building or else they will be cancelled." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:107 +msgid "Delete the option value" +msgstr "" + +#: views/tools/diagnostics/inc.phpinfo.php:26 +msgid "PHP Information" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:5 +#: views/tools/diagnostics/inc.settings.php:6 +msgid "unknow" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:29 +msgid "Server Settings" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:38 +msgid "Duplicator Version" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:44 +msgid "Operating System" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:49 +msgid "Timezone" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:54 +msgid "Server Time" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:69 +msgid "ABSPATH" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:73 +msgid "Plugins Path" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:77 +msgid "Loaded PHP INI" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:81 +msgid "Server IP" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:88 +msgid "Can't detect" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:94 +msgid "Client IP" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:105 +msgid "Language" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:113 +msgid "Memory Limit " +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:114 +msgid "Max" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:133 +msgid "Process" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:137 +msgid "Safe Mode" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:141 +msgid "On" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:141 +msgid "Off" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:146 +msgid "Memory Limit" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:150 +msgid "Memory In Use" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:154 +#: views/tools/diagnostics/inc.settings.php:163 +msgid "Max Execution Time" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:164 +msgid "" +"If the value shows dynamic then this means its possible for PHP to run " +"longer than the default. If the value is fixed then PHP will not be allowed " +"to run longer than the default." +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:169 +msgid "Shell Exec" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:170 +#: views/tools/diagnostics/inc.settings.php:174 +msgid "Is Supported" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:170 +#: views/tools/diagnostics/inc.settings.php:174 +msgid "Not Supported" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:173 +msgid "Shell Exec Zip" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:177 +msgid "Suhosin Extension" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:181 +msgid "Architecture " +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:187 +msgid "Error Log File " +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:198 +msgid "Comments" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:206 +msgid "Wait Timeout" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:210 +msgid "Max Allowed Packets" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:214 +msgid "msyqldump Path" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:218 +msgid "Server Disk" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:221 +msgid "Free space" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:224 +msgid "Unable to calculate space on this server." +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:230 +msgid "Note: This value is the physical servers hard-drive allocation." +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:231 +msgid "" +"On shared hosts check your control panel for the 'TRUE' disk space quota " +"value." +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:16 +msgid "Run Validator" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:17 +msgid "" +"This will run the scan validation check. This may take several minutes. Do " +"you want to Continue?" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:28 +msgid "Scan Validator" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:33 +msgid "" +"This utility will help to find unreadable files and sys-links in your " +"environment that can lead to issues during the scan process. " +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:34 +msgid "" +"The utility will also shows how many files and directories you have in your " +"system. This process may take several minutes to run. " +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:35 +msgid "" +"If there is a recursive loop on your system then the process has a built in " +"check to stop after a large set of files and directories have been scanned. " +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:36 +msgid "" +"A message will show indicated that that a scan depth has been reached. If " +"you have issues with the package scanner (step 2) during the build process " +"then try to add The paths below to your file filters to allow the scanner to " +"finish." +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:43 +#: views/tools/diagnostics/inc.validator.php:157 +msgid "Run Scan Integrity Validation" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:77 +msgid "Note: Symlinks are not discoverable on Windows OS with PHP" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:126 +msgid "Scanning Environment... This may take a few minutes." +msgstr "" + +#: views/tools/diagnostics/information.php:27 +msgid "File Found: Unable to remove" +msgstr "" + +#: views/tools/diagnostics/information.php:43 +msgid "Build cache removed." +msgstr "" + +#: views/tools/diagnostics/information.php:62 +msgid "Plugin settings reset." +msgstr "" + +#: views/tools/diagnostics/information.php:65 +msgid "View state settings reset." +msgstr "" + +#: views/tools/diagnostics/information.php:68 +msgid "Active package settings reset." +msgstr "" + +#: views/tools/diagnostics/logging.php:169 +msgid "Log file not found or unreadable" +msgstr "" + +#: views/tools/diagnostics/logging.php:170 +msgid "" +"Try to create a package, since no log files were found in the snapshots " +"directory with the extension *.log" +msgstr "" + +#: views/tools/diagnostics/logging.php:171 +msgid "Reasons for log file not showing" +msgstr "" + +#: views/tools/diagnostics/logging.php:172 +msgid "The web server does not support returning .log file extentions" +msgstr "" + +#: views/tools/diagnostics/logging.php:173 +msgid "" +"The snapshots directory does not have the correct permissions to write " +"files. Try setting the permissions to 755" +msgstr "" + +#: views/tools/diagnostics/logging.php:174 +msgid "" +"The process that PHP runs under does not have enough permissions to create " +"files. Please contact your hosting provider for more details" +msgstr "" + +#: views/tools/diagnostics/logging.php:190 +#, php-format +msgid "" +"Consider our recommended %1$shost list%2$s if you’re unhappy with your " +"current provider" +msgstr "" + +#: views/tools/diagnostics/logging.php:200 +#: views/tools/diagnostics/logging.php:205 +msgid "Options" +msgstr "" + +#: views/tools/diagnostics/logging.php:207 +msgid "Refresh" +msgstr "" + +#: views/tools/diagnostics/logging.php:210 +msgid "Auto Refresh" +msgstr "" + +#: views/tools/diagnostics/logging.php:216 +msgid "Package Logs" +msgstr "" + +#: views/tools/diagnostics/logging.php:217 +msgid "Top 20" +msgstr "" + +#: views/tools/diagnostics/main.php:43 +msgid "Information" +msgstr "" + +#: views/tools/diagnostics/main.php:44 +msgid "Logs" +msgstr "" + +#: views/tools/diagnostics/support.php:36 +msgid "" +"Migrating WordPress is a complex process and the logic to make all the magic " +"happen smoothly may not work quickly with every site. With over 30,000 " +"plugins and a very complex server eco-system some migrations may run into " +"issues. This is why the Duplicator includes a detailed knowledgebase that " +"can help with many common issues. Resources to additional support, approved " +"hosting, and alternatives to fit your needs can be found below." +msgstr "" + +#: views/tools/diagnostics/support.php:51 +msgid "Knowledgebase" +msgstr "" + +#: views/tools/diagnostics/support.php:54 +msgid "Complete Online Documentation" +msgstr "" + +#: views/tools/diagnostics/support.php:58 +msgid "Choose A Section" +msgstr "" + +#: views/tools/diagnostics/support.php:63 +msgid "Quick Start" +msgstr "" + +#: views/tools/diagnostics/support.php:66 +msgid "User Guide" +msgstr "" + +#: views/tools/diagnostics/support.php:71 +msgid "FAQs" +msgstr "" + +#: views/tools/diagnostics/support.php:74 +msgid "Change Log" +msgstr "" + +#: views/tools/diagnostics/support.php:84 +msgid "Premium Support" +msgstr "" + +#: views/tools/diagnostics/support.php:87 +msgid "" +"Having a problem with your back up or migrations? Upgrade to get our Premium " +"Support." +msgstr "" diff --git a/languages/duplicator.pot b/languages/duplicator.pot new file mode 100644 index 00000000..b2aeee76 --- /dev/null +++ b/languages/duplicator.pot @@ -0,0 +1,4974 @@ +# Copyright (C) 2023 Snap Creek +# This file is distributed under the same license as the Duplicator plugin. +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Duplicator 1.5.3\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/duplicator\n" +"POT-Creation-Date: 2023-11-06 12:12-0600\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0.1\n" +"X-Poedit-KeywordsList: __;_e;esc_html_e;esc_html__;_x;_ex;esc_attr_e;esc_attr__\n" +"X-Poedit-Basepath: ..\n" +"X-Poedit-SearchPath-0: .\n" + +#: assets/js/javascript.php:270 +msgid "Copied: " +msgstr "" + +#: assets/js/javascript.php:270 assets/js/javascript.php:272 +msgid "unable to copy" +msgstr "" + +#: assets/js/javascript.php:276 assets/js/javascript.php:280 +msgid "Copy to Clipboard!" +msgstr "" + +#: classes/class.logging.php:161 +msgid "No Log" +msgstr "" + +#: classes/class.server.php:325 +msgid "(directory)" +msgstr "" + +#: classes/package/class.pack.database.php:600 +msgid "Shell mysql dump error. Change SQL Mode to the \"PHP Code\" in the Duplicator > Settings > Packages." +msgstr "" + +#: classes/package/class.pack.database.php:749 +msgid "Please contact your DataBase administrator to fix the error." +msgstr "" + +#: classes/package/class.pack.installer.php:140 +msgid "Error reading DupArchive expander" +msgstr "" + +#: classes/package/class.pack.installer.php:153 +msgid "Error writing installer contents" +msgstr "" + +#: classes/package/class.pack.installer.php:761 +#, php-format +msgid "Zip archive %1s not present." +msgstr "" + +#: classes/package/class.pack.installer.php:834 +#: classes/package/class.pack.php:1010 +#, php-format +msgid "ERROR: Cannot open created archive. Error code = %1$s" +msgstr "" + +#: classes/package/class.pack.installer.php:838 +#: classes/package/class.pack.php:1015 +msgid "ERROR: Archive is not valid zip archive." +msgstr "" + +#: classes/package/class.pack.installer.php:841 +#: classes/package/class.pack.php:1019 +msgid "ERROR: Archive doesn't pass consistency check." +msgstr "" + +#: classes/package/class.pack.installer.php:844 +#: classes/package/class.pack.php:1024 +msgid "ERROR: Archive checksum is bad." +msgstr "" + +#: classes/package/class.pack.installer.php:860 +msgid "ARCHIVE CONSISTENCY TEST: FAIL" +msgstr "" + +#: classes/package/class.pack.installer.php:863 +msgid "ARCHIVE CONSISTENCY TEST: PASS" +msgstr "" + +#: classes/package/class.pack.php:350 +msgid "Package name can't be empty" +msgstr "" + +#: classes/package/class.pack.php:359 +#, php-format +msgid "Directories: %1$s isn't a valid path" +msgstr "" + +#: classes/package/class.pack.php:368 +#, php-format +msgid "File extension: %1$s isn't a valid extension" +msgstr "" + +#: classes/package/class.pack.php:377 +#, php-format +msgid "Files: %1$s isn't a valid file name" +msgstr "" + +#: classes/package/class.pack.php:386 +#, php-format +msgid "MySQL Server Host: %1$s isn't a valid host" +msgstr "" + +#: classes/package/class.pack.php:396 +#, php-format +msgid "MySQL Server Port: %1$s isn't a valid port" +msgstr "" + +#: classes/package/class.pack.php:940 +#, php-format +msgid "Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name." +msgstr "" + +#: classes/package/class.pack.php:961 +#, php-format +msgid "EXPECTED FILE/DIRECTORY COUNT: %1$s" +msgstr "" + +#: classes/package/class.pack.php:962 +#, php-format +msgid "ACTUAL FILE/DIRECTORY COUNT: %1$s" +msgstr "" + +#: classes/package/class.pack.php:1034 +msgid "ARCHIVE CONSISTENCY TEST: Pass" +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:35 +msgid "Package build appears stuck so marking package as failed. Is the Max Worker Time set too high?." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:36 +msgid "Build Failure" +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:61 +msgid "Click on \"Resolve This\" button to fix the JSON settings." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:71 +#, php-format +msgid "ERROR: Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:157 +msgid "Problem adding items to archive." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:158 +msgid "Problems adding items to archive." +msgstr "" + +#: classes/package/duparchive/class.pack.archive.duparchive.php:232 +msgid "Critical failure present in validation" +msgstr "" + +#: classes/ui/class.ui.dialog.php:86 +msgid "Processing please wait..." +msgstr "" + +#: classes/ui/class.ui.dialog.php:89 +msgid "OK" +msgstr "" + +#: classes/ui/class.ui.dialog.php:90 deactivation.php:155 +msgid "Cancel" +msgstr "" + +#: classes/ui/class.ui.screen.base.php:132 +msgid "Need Help? Please check out these resources first:
                      • %s removed for security reasons" +msgstr "" + +#: src/Core/MigrationMng.php:324 +#, php-format +msgid "Can't remove installer file %s, please remove it for security reasons" +msgstr "" + +#: src/Core/MigrationMng.php:335 +#, php-format +msgid "Installer file %s renamed with HASH" +msgstr "" + +#: src/Core/MigrationMng.php:341 +#, php-format +msgid "Can't rename installer file %s with HASH, please remove it for security reasons" +msgstr "" + +#: src/Core/MigrationMng.php:373 +msgid "Original files folder moved in installer backup directory" +msgstr "" + +#: src/Core/MigrationMng.php:378 +#, php-format +msgid "Can't move %s to %s" +msgstr "" + +#: src/Core/MigrationMng.php:395 +msgid "Installer log" +msgstr "" + +#: src/Core/MigrationMng.php:396 +msgid "Installer boot log" +msgstr "" + +#: src/Core/MigrationMng.php:397 +msgid "Original files folder" +msgstr "" + +#: src/Core/Notifications/Review.php:91 +#, php-format +msgid "Are you enjoying %s?" +msgstr "" + +#: src/Core/Notifications/Review.php:94 +#: template/admin_pages/settings/general/general.php:299 +msgid "Yes" +msgstr "" + +#: src/Core/Notifications/Review.php:98 +msgid "Not really" +msgstr "" + +#: src/Core/Notifications/Review.php:106 +msgid "That’s awesome! Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?" +msgstr "" + +#: src/Core/Notifications/Review.php:110 +msgid "~ John Turner
                        President of Duplicator" +msgstr "" + +#: src/Core/Notifications/Review.php:114 +msgid "Ok, you deserve it" +msgstr "" + +#: src/Core/Notifications/Review.php:118 +msgid "Nope, maybe later" +msgstr "" + +#: src/Core/Notifications/Review.php:122 +msgid "I already did" +msgstr "" + +#: src/Core/Notifications/Review.php:130 +msgid "We're sorry to hear you aren't enjoying Duplicator. We would love a chance to improve. Could you take a minute and let us know what we can do better?" +msgstr "" + +#: src/Core/Notifications/Review.php:137 +msgid "Give Feedback" +msgstr "" + +#: src/Core/Notifications/Review.php:141 +msgid "No thanks" +msgstr "" + +#: src/Core/Notifications/Review.php:195 +#, php-format +msgid "Please rate Duplicator
                        ★★★★★ on WordPress.org to help us spread the word. Thank you from the Duplicator team!" +msgstr "" + +#: src/Libs/OneClickUpgrade/ConnectSkin.php:35 +msgid "There was an error installing Duplicator Pro. Please try again." +msgstr "" + +#: src/Lite/Requirements.php:49 +msgid "Can't enable Duplicator LITE if the PRO version is enabled." +msgstr "" + +#: src/Lite/Requirements.php:50 +msgid "Please deactivate Duplicator PRO, then reactivate LITE version from the " +msgstr "" + +#: src/Lite/Requirements.php:51 src/Lite/Requirements.php:138 +msgid "plugins page" +msgstr "" + +#: src/Lite/Requirements.php:132 +msgid "Duplicator Notice:" +msgstr "" + +#: src/Lite/Requirements.php:133 +msgid "The \"Duplicator Lite\" and \"Duplicator Pro\" plugins cannot both be active at the same time. " +msgstr "" + +#: src/Lite/Requirements.php:136 +msgid "To use \"Duplicator LITE\" please deactivate \"Duplicator PRO\" from the " +msgstr "" + +#: src/Utils/CachesPurge/CacheItem.php:61 +#, php-format +msgid "All caches on %s have been purged." +msgstr "" + +#: src/Utils/CachesPurge/CacheItem.php:100 +#: src/Utils/CachesPurge/CacheItem.php:104 +#, php-format +msgid "Error on caches purge of %s." +msgstr "" + +#: src/Utils/CronUtils.php:32 +msgid "Once a Day" +msgstr "" + +#: src/Utils/CronUtils.php:37 +msgid "Once a Week" +msgstr "" + +#: src/Utils/CronUtils.php:42 +msgid "Once a Month" +msgstr "" + +#: src/Utils/DuplicatorPhpVersionCheck.php:59 +#, php-format +msgid "DUPLICATOR: Your system is running a very old version of PHP (%s) that is no longer supported by Duplicator. " +msgstr "" + +#: src/Utils/DuplicatorPhpVersionCheck.php:69 +#, php-format +msgid "Please ask your host or server administrator to update to PHP %1s or greater." +msgstr "" + +#: src/Utils/DuplicatorPhpVersionCheck.php:78 +#, php-format +msgid "" +"If this is not possible, please visit the FAQ link titled \n" +" %1$s\"What version of PHP Does Duplicator Support?\"%2$s\n" +" for instructions on how to download a previous version of Duplicator compatible with PHP %3$s." +msgstr "" + +#: src/Utils/Email/EmailSummary.php:102 +msgid "Successful" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:107 +msgid "Failed" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:122 +msgid "Never" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:123 +msgid "Daily" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:124 +msgid "Weekly" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:125 +msgid "Monthly" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:139 +msgid "day" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:141 +msgid "month" +msgstr "" + +#: src/Utils/Email/EmailSummary.php:144 +msgid "week" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraItem.php:180 +msgid "Active" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraItem.php:182 +msgid "Inactive" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraItem.php:184 +msgid "Not Installed" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:85 +msgid "Plugin slug is empty" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:90 +msgid "Plugin not found" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:115 +msgid "OptinMonster" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:118 +msgid "Instantly get more subscribers, leads, and sales with the #1 conversion optimization toolkit. Create high converting popups, announcement bars, spin a wheel, and more with smart targeting and personalization." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:127 +#: src/Views/DashboardWidget.php:210 +msgid "MonsterInsights" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:131 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:143 +msgid "The leading WordPress analytics plugin that shows you how people find and use your website, so you can make data driven decisions to grow your business. Properly set up Google Analytics without writing code." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:139 +msgid "MonsterInsights Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:152 +msgid "WPForms" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:156 +msgid "The best drag & drop WordPress form builder. Easily create beautiful contact forms, surveys, payment forms, and more with our 100+ form templates. Trusted by over 4 million websites as the best forms plugin." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:164 +msgid "WPForms Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:168 +msgid "The easiest drag & drop WordPress form builder plugin to create beautiful contact forms, subscription forms, payment forms, and more in minutes. No coding skills required." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:177 +#: src/Views/DashboardWidget.php:234 +msgid "WP Mail SMTP" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:181 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:193 +msgid "Improve your WordPress email deliverability and make sure that your website emails reach user's inbox with the #1 SMTP plugin for WordPress. Over 3 million websites use it to fix WordPress email issues." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:189 +msgid "WP Mail SMTP Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:202 +#: src/Views/DashboardWidget.php:218 +msgid "AIOSEO" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:206 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:218 +msgid "The original WordPress SEO plugin and toolkit that improves your website's search rankings. Comes with all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:214 +msgid "AIOSEO Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:227 +#: src/Views/DashboardWidget.php:226 +msgid "SeedProd" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:230 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:239 +msgid "The best WordPress coming soon page plugin to create a beautiful coming soon page, maintenance mode page, or landing page. No coding skills required." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:236 +msgid "SeedProd Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:246 +msgid "RafflePress" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:250 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:262 +msgid "Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with the most powerful giveaways & contests plugin for WordPress." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:258 +msgid "RafflePress Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:271 +msgid "PushEngage" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:275 +msgid "Connect with your visitors after they leave your website with the leading web push notification software. Over 10,000+ businesses worldwide use PushEngage to send 9 billion notifications each month." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:286 +msgid "Smash Balloon Instagram Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:290 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:302 +msgid "Easily display Instagram content on your WordPress site without writing any code. Comes with multiple templates, ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:298 +msgid "Smash Balloon Instagram Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:311 +msgid "Smash Balloon Facebook Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:315 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:327 +msgid "Easily display Facebook content on your WordPress site without writing any code. Comes with multiple templates, ability to embed albums, group content, reviews, live videos, comments, and reactions." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:323 +msgid "Smash Balloon Facebook Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:336 +msgid "Smash Balloon Twitter Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:340 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:352 +msgid "Easily display Twitter content in WordPress without writing any code. Comes with multiple layouts, ability to combine multiple Twitter feeds, Twitter card support, tweet moderation, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:348 +msgid "Smash Balloon Twitter Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:361 +msgid "Smash Balloon YouTube Feeds" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:365 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:377 +msgid "Easily display YouTube videos on your WordPress site without writing any code. Comes with multiple layouts, ability to embed live streams, video filtering, ability to combine multiple channel videos, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:373 +msgid "Smash Balloon YouTube Feeds Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:386 +msgid "TrustPulse" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:390 +msgid "Boost your sales and conversions by up to 15% with real-time social proof notifications. TrustPulse helps you show live user activity and purchases to help convince other users to purchase." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:402 +msgid "SearchWP" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:406 +msgid "The most advanced WordPress search plugin. Customize your WordPress search algorithm, reorder search results, track search metrics, and everything you need to leverage search to grow your business." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:416 +msgid "AffiliateWP" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:420 +msgid "The #1 affiliate management plugin for WordPress. Easily create an affiliate program for your eCommerce store or membership site within minutes and start growing your sales with the power of referral marketing." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:431 +msgid "WP Simple Pay" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:435 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:447 +msgid "The #1 Stripe payments plugin for WordPress. Start accepting one-time and recurring payments on your WordPress site without setting up a shopping cart. No code required." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:443 +msgid "WP Simple Pay Pro" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:456 +msgid "Easy Digital Downloads" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:459 +msgid "The best WordPress eCommerce plugin for selling digital downloads. Start selling eBooks, software, music, digital art, and more within minutes. Accept payments, manage subscriptions, advanced access control, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:468 +msgid "Sugar Calendar" +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:471 +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:480 +msgid "A simple & powerful event calendar plugin for WordPress that comes with all the event management features including payments, scheduling, timezones, ticketing, recurring events, and more." +msgstr "" + +#: src/Utils/ExtraPlugins/ExtraPluginsMng.php:477 +msgid "Sugar Calendar Pro" +msgstr "" + +#: src/Utils/Upsell.php:40 src/Utils/Upsell.php:66 +#: template/admin_pages/welcome/features.php:54 +msgid "Secure File Encryption" +msgstr "" + +#: src/Utils/Upsell.php:41 src/Utils/Upsell.php:67 +#: template/admin_pages/welcome/features.php:62 +msgid "Server to Server Import" +msgstr "" + +#: src/Utils/Upsell.php:43 +msgid "Cloud Storage - Google Drive" +msgstr "" + +#: src/Utils/Upsell.php:44 +msgid "Cloud Storage - Amazon S3" +msgstr "" + +#: src/Utils/Upsell.php:45 +msgid "Cloud Storage - DropBox" +msgstr "" + +#: src/Utils/Upsell.php:46 +msgid "Cloud Storage - OneDrive" +msgstr "" + +#: src/Utils/Upsell.php:47 +msgid "Cloud Storage - FTP/SFTP" +msgstr "" + +#: src/Utils/Upsell.php:50 +msgid "Multisite Network Support" +msgstr "" + +#: src/Utils/Upsell.php:51 src/Utils/Upsell.php:80 +msgid "Email Alerts" +msgstr "" + +#: src/Utils/Upsell.php:70 +msgid "Smart Migration Wizard" +msgstr "" + +#: src/Utils/Upsell.php:72 +msgid "Streamlined Installer" +msgstr "" + +#: src/Utils/Upsell.php:73 +msgid "Developer Hooks" +msgstr "" + +#: src/Utils/Upsell.php:74 +msgid "Managed Hosting Support" +msgstr "" + +#: src/Utils/Upsell.php:77 +msgid "Migrate Duplicator Settings" +msgstr "" + +#: src/Utils/Upsell.php:78 +msgid "Regenerate SALTS" +msgstr "" + +#: src/Utils/Upsell.php:79 +msgid "Multisite Network" +msgstr "" + +#: src/Utils/Upsell.php:81 +msgid "Custom Search & Replace" +msgstr "" + +#: src/Views/AdminNotices.php:194 +msgid "Safe Mode:" +msgstr "" + +#: src/Views/AdminNotices.php:195 +msgid "During the install safe mode was enabled deactivating all plugins.
                        Please be sure to " +msgstr "" + +#: src/Views/AdminNotices.php:196 +msgid "re-activate the plugins" +msgstr "" + +#: src/Views/AdminNotices.php:202 views/parts/migration-message.php:17 +msgid "This site has been successfully migrated!" +msgstr "" + +#: src/Views/AdminNotices.php:203 +msgid "Final step(s):" +msgstr "" + +#: src/Views/AdminNotices.php:204 +msgid "This message will be removed after all installer files are removed. Installer files must be removed to maintain a secure site. Click the link above or button below to remove all installer files and complete the migration." +msgstr "" + +#: src/Views/AdminNotices.php:211 views/parts/migration-message.php:52 +msgid "Remove Installation Files Now!" +msgstr "" + +#: src/Views/AdminNotices.php:215 +msgid "Optionally, Review Duplicator at WordPress.org..." +msgstr "" + +#: src/Views/AdminNotices.php:221 src/Views/AdminNotices.php:304 +#: views/parts/migration-almost-complete.php:17 +msgid "Migration Almost Complete!" +msgstr "" + +#: src/Views/AdminNotices.php:223 +msgid "Reserved Duplicator installation files have been detected in the root directory. Please delete these installation files to avoid security issues.
                        Go to:Duplicator > Tools > Information >Stored Data and click the \"Remove Installation Files\" button" +msgstr "" + +#: src/Views/AdminNotices.php:231 views/parts/migration-almost-complete.php:33 +msgid "Take me there now!" +msgstr "" + +#: src/Views/AdminNotices.php:247 +msgid "Redirecting Please Wait..." +msgstr "" + +#: src/Views/AdminNotices.php:250 +msgid "Invalid token permissions to perform this request." +msgstr "" + +#: src/Views/AdminNotices.php:294 +#, php-format +msgid "Activate %s" +msgstr "" + +#: src/Views/AdminNotices.php:304 +msgid "Warning!" +msgstr "" + +#: src/Views/AdminNotices.php:306 +msgid "Plugin(s) listed here have been deactivated during installation to help prevent issues. Please activate them to finish this migration: " +msgstr "" + +#: src/Views/AdminNotices.php:377 +msgid "Congrats!" +msgstr "" + +#: src/Views/AdminNotices.php:382 +#, php-format +msgid "" +"You created over %d packages with Duplicator. Great job! If you can spare a minute, \n" +" please help us by leaving a five star review on WordPress.org." +msgstr "" + +#: src/Views/AdminNotices.php:394 +msgid "Sure! I'd love to help" +msgstr "" + +#: src/Views/AdminNotices.php:397 +msgid "Hide Notification" +msgstr "" + +#: src/Views/AdminNotices.php:420 +msgid "" +"Duplicator
                        Your logged-in user role does not have export \n" +" capability so you don't have access to Duplicator functionality." +msgstr "" + +#: src/Views/AdminNotices.php:427 +#, php-format +msgid "RECOMMENDATION: Add export capability to your role. See FAQ: %1$sWhy is the Duplicator/Packages menu missing from my admin menu?%2$s" +msgstr "" + +#: src/Views/DashboardWidget.php:42 template/mail/email_summary.php:29 +msgid "Duplicator" +msgstr "" + +#: src/Views/DashboardWidget.php:162 +msgid "A package is currently running." +msgstr "" + +#: src/Views/DashboardWidget.php:179 +msgid "No packages have been created yet." +msgstr "" + +#: src/Views/DashboardWidget.php:191 +#, php-format +msgid "%s ago" +msgstr "" + +#: src/Views/EducationElements.php:108 +msgid "Scheduled Backups - Ensure that important data is regularly and consistently backed up, allowing for quick and efficient recovery in case of data loss." +msgstr "" + +#: src/Views/EducationElements.php:110 +msgid "Cloud Backups - Back up to Dropbox, FTP, Google Drive, OneDrive, or Amazon S3 and more for safe storage." +msgstr "" + +#: src/Views/EducationElements.php:111 +msgid "Recovery Points - Recovery Points provides protection against mistakes and bad updates by letting you quickly rollback your system to a known, good state." +msgstr "" + +#: src/Views/EducationElements.php:113 +msgid "Secure File Encryption - Protect and secure the archive file with industry-standard AES-256 encryption" +msgstr "" + +#: src/Views/EducationElements.php:114 +msgid "Server to Server Import - Direct package import from source server or cloud storage using URL. No need to download the package to your desktop machine first." +msgstr "" + +#: src/Views/EducationElements.php:116 +msgid "File & Database Table Filters - Use file and database filters to pick and choose exactly what you want to backup or transfer. No bloat!" +msgstr "" + +#: src/Views/EducationElements.php:118 +msgid "Large Site Support - Duplicator Pro has developed a new way to package backups especially tailored for larger site. No server timeouts or other restrictions." +msgstr "" + +#: src/Views/EducationElements.php:120 +msgid "Mulstisite Support - Duplicator Pro supports multisite network backup & migration. You can even install a subsite as a standalone site." +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:17 +msgid "Activated" +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:22 +msgid "Activate" +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:28 +msgid "Install Plugin" +msgstr "" + +#: template/admin_pages/about_us/about_us/extra_plugin_item.php:46 +msgid "Status:" +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:4 +msgid "Hello and welcome to Duplicator, the most reliable WordPress backup and migration plugin. At Duplicator, we build software that helps protect your website with our reliable secure backups and migrate your website without any manual effort." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:9 +msgid "Over the years, we found that most WordPress backup and migration plugins were unreliable, buggy, slow, and very hard to use. So we started with a simple goal: build a WordPress backup and migration plugin that’s both easy and powerful." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:14 +msgid "Our goal is to take the pain out of creating backups, migrations, and make it easy." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:22 +#, php-format +msgid "Duplicator is brought to you by the same team that’s behind the largest WordPress resource site, WPBeginner, the most popular lead-generation software, OptinMonster, the best WordPress analytics plugin, MonsterInsights, and more!" +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:43 +msgid "Yup, we know a thing or two about building awesome products that customers love." +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:49 +msgid "The Awesome Motive Team photo" +msgstr "" + +#: template/admin_pages/about_us/about_us/info.php:51 +msgid "The Awesome Motive Team" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:25 +msgid "Creating Your First Package" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:28 +msgid "Want to get started creating your first package with Duplicator? By following the step by step instructions in this walkthrough, you can easily create a backup or migration." +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:32 +msgid "To begin, you’ll need to be logged into the WordPress admin area. Once there, click on Duplicator in the admin sidebar to go the Packages page." +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:36 +msgid "In the Packages page, the packages list will be empty because there are no packages yet. To create a new package, click on the Create New button, and this will launch the Package Creation Wizard." +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:47 +msgid "Quick Start Guide" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:56 +msgid "How to Create a Package" +msgstr "" + +#: template/admin_pages/about_us/getting_started/first_package.php:65 +msgid "How to Migrate to a New Site" +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:25 +#: template/parts/Education/callout-cta.php:22 +msgid "Get Duplicator Pro and Unlock all the Powerful Features" +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:32 +msgid "Thanks for being a loyal Duplicator Lite user. Upgrade to Duplicator Pro to unlock all the awesome features and experience
                        why Duplicator is consistently rated the best WordPress migration plugin." +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:49 +#, php-format +msgid "We know that you will truly love Duplicator. It has over 4000+ five star ratings (%s) and is active on over 1 million websites." +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:93 +#: template/admin_pages/about_us/lite_vs_pro/main.php:94 +msgid "Get Duplicator Pro Today and Unlock all the Powerful Features" +msgstr "" + +#: template/admin_pages/about_us/getting_started/get_pro.php:102 +#: template/admin_pages/about_us/lite_vs_pro/main.php:103 +#, php-format +msgid "Bonus: Duplicator Lite users get %1$d%% off regular price, automatically applied at checkout." +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:29 +msgid "Get the most out of Duplicator by upgrading to Pro and unlocking all of the powerful features." +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:38 +msgid "Feature" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:43 +msgid "Lite" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:48 +msgid "Pro" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:67 +#: template/admin_pages/about_us/lite_vs_pro/main.php:77 +msgid "Included" +msgstr "" + +#: template/admin_pages/about_us/lite_vs_pro/main.php:68 +msgid "Not Available" +msgstr "" + +#: template/admin_pages/about_us/tabs.php:21 +msgid "Getting Started" +msgstr "" + +#: template/admin_pages/about_us/tabs.php:25 +msgid "Lite vs Pro" +msgstr "" + +#: template/admin_pages/settings/general/email_summary.php:19 +msgid "Email Summary" +msgstr "" + +#: template/admin_pages/settings/general/email_summary.php:23 +msgid "Frequency" +msgstr "" + +#: template/admin_pages/settings/general/email_summary.php:36 +#, php-format +msgid "You can view the email summary example %1shere%2s." +msgstr "" + +#: template/admin_pages/settings/general/general.php:25 +msgid "General Settings Saved" +msgstr "" + +#: template/admin_pages/settings/general/general.php:108 +msgid "Plugin" +msgstr "" + +#: template/admin_pages/settings/general/general.php:112 +#: views/packages/details/detail.php:130 +#: views/tools/diagnostics/inc.settings.php:101 +#: views/tools/diagnostics/inc.settings.php:121 +#: views/tools/diagnostics/inc.settings.php:194 +msgid "Version" +msgstr "" + +#: template/admin_pages/settings/general/general.php:120 +msgid "Uninstall" +msgstr "" + +#: template/admin_pages/settings/general/general.php:124 +msgid "Delete Plugin Settings" +msgstr "" + +#: template/admin_pages/settings/general/general.php:128 +msgid "Delete Entire Storage Directory" +msgstr "" + +#: template/admin_pages/settings/general/general.php:133 +msgid "Usage statistics" +msgstr "" + +#: template/admin_pages/settings/general/general.php:137 +msgid "Usage statistics are hardcoded disallowed." +msgstr "" + +#: template/admin_pages/settings/general/general.php:147 +msgid "Enable usage tracking" +msgstr "" + +#: template/admin_pages/settings/general/general.php:150 +msgid "Usage Tracking" +msgstr "" + +#: template/admin_pages/settings/general/general.php:159 +msgid "Hide Announcements" +msgstr "" + +#: template/admin_pages/settings/general/general.php:168 +msgid "Check this option to hide plugin announcements and update details." +msgstr "" + +#: template/admin_pages/settings/general/general.php:176 +msgid "Debug" +msgstr "" + +#: template/admin_pages/settings/general/general.php:180 +msgid "Debugging" +msgstr "" + +#: template/admin_pages/settings/general/general.php:183 +msgid "Enable debug options throughout user interface" +msgstr "" + +#: template/admin_pages/settings/general/general.php:187 +msgid "Trace Log" +msgstr "" + +#: template/admin_pages/settings/general/general.php:190 +#: template/parts/DashboardWidget/sections-section.php:51 +#: views/packages/main/s2.scan3.php:44 views/packages/main/s2.scan3.php:409 +#: views/packages/main/s2.scan3.php:745 +#: views/tools/diagnostics/inc.settings.php:178 +msgid "Enabled" +msgstr "" + +#: template/admin_pages/settings/general/general.php:193 +msgid "Turns on detailed operation logging. Logging will occur in both PHP error and local trace logs." +msgstr "" + +#: template/admin_pages/settings/general/general.php:195 +msgid "WARNING: Only turn on this setting when asked to by support as tracing will impact performance." +msgstr "" + +#: template/admin_pages/settings/general/general.php:203 +msgid "Download Trace Log" +msgstr "" + +#: template/admin_pages/settings/general/general.php:211 +msgid "Advanced" +msgstr "" + +#: template/admin_pages/settings/general/general.php:218 +msgid "Reset Packages" +msgstr "" + +#: template/admin_pages/settings/general/general.php:222 +msgid "This process will reset all packages by deleting those without a completed status, reset the active package id and perform a cleanup of the build tmp file." +msgstr "" + +#: template/admin_pages/settings/general/general.php:226 +msgid "Reset Settings" +msgstr "" + +#: template/admin_pages/settings/general/general.php:228 +msgid "This action should only be used if the packages screen is having issues or a build is stuck." +msgstr "" + +#: template/admin_pages/settings/general/general.php:234 +msgid "Archive scan" +msgstr "" + +#: template/admin_pages/settings/general/general.php:237 +msgid "Skip" +msgstr "" + +#: template/admin_pages/settings/general/general.php:240 +msgid "If enabled all files check on scan will be skipped before package creation. In some cases, this option can be beneficial if the scan process is having issues running or returning errors." +msgstr "" + +#: template/admin_pages/settings/general/general.php:247 +msgid "Foreign JavaScript" +msgstr "" + +#: template/admin_pages/settings/general/general.php:250 +#: template/admin_pages/settings/general/general.php:264 +msgid "Disable" +msgstr "" + +#: template/admin_pages/settings/general/general.php:253 +msgid "Check this option if other plugins/themes JavaScript files are conflicting with Duplicator." +msgstr "" + +#: template/admin_pages/settings/general/general.php:255 +#: template/admin_pages/settings/general/general.php:269 +msgid "Do not modify this setting unless you know the expected result or have talked to support." +msgstr "" + +#: template/admin_pages/settings/general/general.php:261 +msgid "Foreign CSS" +msgstr "" + +#: template/admin_pages/settings/general/general.php:267 +msgid "Check this option if other plugins/themes CSS files are conflicting with Duplicator." +msgstr "" + +#: template/admin_pages/settings/general/general.php:283 +msgid "Save General Settings" +msgstr "" + +#: template/admin_pages/settings/general/general.php:294 +msgid "Reset Packages ?" +msgstr "" + +#: template/admin_pages/settings/general/general.php:295 +msgid "This will clear and reset all of the current temporary packages. Would you like to continue?" +msgstr "" + +#: template/admin_pages/settings/general/general.php:296 +msgid "Resetting settings, Please Wait..." +msgstr "" + +#: template/admin_pages/settings/general/general.php:300 +msgid "No" +msgstr "" + +#: template/admin_pages/settings/general/general.php:306 +msgid "AJAX Call Error!" +msgstr "" + +#: template/admin_pages/settings/general/general.php:309 +#, php-format +msgid "AJAX error encountered when resetting packages. Please see %1$sthis FAQ entry%2$s for possible resolutions." +msgstr "" + +#: template/admin_pages/settings/general/general.php:323 +#: template/admin_pages/settings/general/general.php:376 +msgid "RESPONSE ERROR!" +msgstr "" + +#: template/admin_pages/settings/general/general.php:366 +msgid "Packages successfully reset" +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:19 +msgid "All information sent to the server is anonymous." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:20 +msgid "No information about storage or package's content are sent." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:27 +msgid "" +"Usage tracking for Duplicator helps us better understand our users and their website needs by looking \n" +" at a range of server and website environments." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:33 +msgid "This allows us to continuously improve our product as well as our Q&A / testing process." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:35 +msgid "Below is the list of information that Duplicator collects as part of the usage tracking:" +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:41 +msgid "PHP Version: so we know which PHP versions we have to test against (no one likes whitescreens or log files full of errors)." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:49 +msgid "WordPress Version: so we know which WordPress versions to support and test against." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:57 +msgid "MySQL Version: so we know which versions of MySQL to support and test against for our custom tables." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:65 +msgid "" +"Duplicator Version: so we know which versions of Duplicator are potentially responsible for issues when we get bug reports, \n" +" allowing us to identify issues and release solutions much faster." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:74 +msgid "Plugins and Themes infos: so we can figure out which ones I can generate compatibility errors with Duplicator." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:82 +msgid "" +"Site info: General information about the site such as database, file size, number of users, and sites in case it is a multisite. \n" +" This is useful for us to understand the critical issues of package creation." +msgstr "" + +#: template/admin_pages/settings/general/usage_tracking_tooltip.php:91 +msgid "Packages infos: Information about the packages created and the type of components included." +msgstr "" + +#: template/admin_pages/welcome/features.php:21 +msgid "Duplicator Features" +msgstr "" + +#: template/admin_pages/welcome/features.php:22 +msgid "Duplicator is both easy to use and extremely powerful. We have tons of helpful features that allow us to give you everything you need from a backup & migration plugin." +msgstr "" + +#: template/admin_pages/welcome/features.php:30 +msgid "Ensure that important data is regularly and consistently backed up, allowing for quick and efficient recovery in case of data loss." +msgstr "" + +#: template/admin_pages/welcome/features.php:37 +msgid "Cloud Backups" +msgstr "" + +#: template/admin_pages/welcome/features.php:39 +msgid "Back up to Dropbox, FTP, Google Drive, OneDrive, or Amazon S3 and more for safe storage." +msgstr "" + +#: template/admin_pages/welcome/features.php:47 +#: template/mocks/recovery/content-popup.php:15 +msgid "Recovery Points provides protection against mistakes and bad updates by letting you quickly rollback your system to a known, good state." +msgstr "" + +#: template/admin_pages/welcome/features.php:56 +#: views/packages/main/s1.setup2.php:353 +msgid "Protect and secure the archive file with industry-standard AES-256 encryption." +msgstr "" + +#: template/admin_pages/welcome/features.php:64 +msgid "Direct package import from source server or cloud storage using URL. No need to download the package to your desktop machine first." +msgstr "" + +#: template/admin_pages/welcome/features.php:73 +msgid "Use file and database filters to pick and choose exactly what you want to backup or transfer. No bloat!" +msgstr "" + +#: template/admin_pages/welcome/features.php:80 +msgid "Large Site Support" +msgstr "" + +#: template/admin_pages/welcome/features.php:82 +msgid "Duplicator Pro has developed a new way to package backups especially tailored for larger site. No server timeouts or other restrictions." +msgstr "" + +#: template/admin_pages/welcome/features.php:89 +msgid "Multisite Support" +msgstr "" + +#: template/admin_pages/welcome/features.php:91 +msgid "Duplicator Pro supports multisite network backup & migration. You can even install a subsite as a standalone site." +msgstr "" + +#: template/admin_pages/welcome/features.php:101 +msgid "See All Features" +msgstr "" + +#: template/admin_pages/welcome/footer.php:25 +#: template/admin_pages/welcome/intro.php:44 +msgid "Create Your First Package" +msgstr "" + +#: template/admin_pages/welcome/footer.php:34 +msgid "Upgrade to Duplicator Pro" +msgstr "" + +#: template/admin_pages/welcome/intro.php:24 +msgid "Willie the Duplicator mascot" +msgstr "" + +#: template/admin_pages/welcome/intro.php:28 +msgid "Thank you for choosing Duplicator - the most powerful WordPress Migration and Backup plugin in the market." +msgstr "" + +#: template/admin_pages/welcome/intro.php:32 +#: template/admin_pages/welcome/intro.php:34 +msgid "Watch how to create your first form" +msgstr "" + +#: template/admin_pages/welcome/intro.php:38 +msgid "Duplicator makes it easy to create backups and migrations in WordPress. Get started by creating a new package or read our quick start guide." +msgstr "" + +#: template/admin_pages/welcome/intro.php:51 +msgid "Read the Full Guide" +msgstr "" + +#: template/admin_pages/welcome/testimonials.php:20 +msgid "Testimonials" +msgstr "" + +#: template/admin_pages/welcome/testimonials.php:28 +msgid "It walked me step-by-step through the process of migrating a WordPress website. If you want to save a ton of time with WP migration, I very much recommend this plugin!" +msgstr "" + +#: template/admin_pages/welcome/testimonials.php:45 +msgid "Duplicator Pro is the best WordPress migration & backup plugin I have ever used. I will be recommending this plugin to everyone I can." +msgstr "" + +#: template/admin_pages/welcome/upgrade-cta.php:21 +msgid "Upgrade to PRO" +msgstr "" + +#: template/admin_pages/welcome/upgrade-cta.php:36 +#: template/mocks/storage/popup.php:37 template/mocks/storage/storage.php:68 +#: views/tools/diagnostics/support.php:91 +msgid "Upgrade Now" +msgstr "" + +#: template/mail/email_summary.php:78 +#, php-format +msgid "Here's a quick overview of your backups in the past %s." +msgstr "" + +#: template/mail/email_summary.php:88 +msgid "Did you know?" +msgstr "" + +#: template/mail/email_summary.php:94 +msgid "With Duplicator Pro you can create fully automatic backups! Schedule your preferred intervals for backups - daily, weekly, or monthly and never worry about data loss again!" +msgstr "" + +#: template/mail/email_summary.php:100 +msgid "With Duplicator Pro you can store backups in Google Drive, Amazon S3, OneDrive, Dropbox, or any SFTP/FTP server for added protection." +msgstr "" + +#: template/mail/email_summary.php:123 +msgid "Below are the total numbers of successful and failed backups." +msgstr "" + +#: template/mail/email_summary.php:128 +msgid "State" +msgstr "" + +#: template/mail/email_summary.php:131 +msgid "Backups" +msgstr "" + +#: template/mail/email_summary.php:153 +msgid "No backups were created in the past week." +msgstr "" + +#: template/mail/email_summary.php:166 +#, php-format +msgid "This email was auto-generated and sent from %s." +msgstr "" + +#: template/mocks/import/content-popup.php:19 +#, php-format +msgid "In addition to the classic installer method on an empty site, Duplicator Pro now supports Drag and Drop migrations and site restores! Simply drag the bundled site archive to the site you wish to overwrite." +msgstr "" + +#: template/mocks/import/import.php:201 +msgid "Overwrite a WordPress site with Drag and Drop Import!" +msgstr "" + +#: template/mocks/import/import.php:202 +msgid "Drag and Drop Import is not available in Duplicator Lite!" +msgstr "" + +#: template/mocks/recovery/recovery.php:116 +msgid "Rollback your sites with Recovery Points!" +msgstr "" + +#: template/mocks/recovery/recovery.php:117 +msgid "Recovery Points are not supported in Duplicator Lite!" +msgstr "" + +#: template/mocks/schedule/content-popup.php:15 +msgid "Scheduled Backups provide peace of mind and ensure that critical data can be quickly and easily restored in the event of a disaster or loss. Duplicator Pro supports Hourly, Daily, Weekly and Monthly scheduled backups." +msgstr "" + +#: template/mocks/schedule/content-popup.php:24 +msgid "Supported Cloud Storage: Google Drive, Dropbox, Microsoft One Drive, Amazon S3 (or any compatible S3 service), and FTP/SFTP Storage." +msgstr "" + +#: template/mocks/schedule/schedules.php:279 +msgid "Automate your workflow with scheduled backups!" +msgstr "" + +#: template/mocks/schedule/schedules.php:280 +msgid "Duplicator Lite does not support scheduled backups!" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:15 +msgid "Roles and Permissions" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:19 +msgid "Select the user roles and/or users that are allowed to manage different aspects of Duplicator." +msgstr "" + +#: template/mocks/settings/access/capabilities.php:20 +msgid "By default, all permissions are provided only to administrator users." +msgstr "" + +#: template/mocks/settings/access/capabilities.php:21 +msgid "Some capabilities depend on others so If you select for example storage capability automatically the package read and package edit capabilities are assigned" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:23 +msgid "It is not possible to self remove the manage settings capabilities." +msgstr "" + +#: template/mocks/settings/access/capabilities.php:28 +msgid "Package Read " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:32 +#: template/mocks/settings/access/capabilities.php:42 +#: template/mocks/settings/access/capabilities.php:52 +#: template/mocks/settings/access/capabilities.php:62 +#: template/mocks/settings/access/capabilities.php:72 +#: template/mocks/settings/access/capabilities.php:82 +#: template/mocks/settings/access/capabilities.php:92 +#: template/mocks/settings/access/capabilities.php:102 +#: template/mocks/settings/access/capabilities.php:112 +msgid "Administrator" +msgstr "" + +#: template/mocks/settings/access/capabilities.php:38 +msgid " - Package Edit " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:48 +msgid " - - Manage Schedules " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:58 +msgid " - - Manage Storages " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:68 +msgid " - Restore Backup " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:78 +msgid " - - Package Import " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:88 +msgid " - Package Export " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:98 +msgid " - Manage Settings " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:108 +msgid " - - Manage License Settings " +msgstr "" + +#: template/mocks/settings/access/capabilities.php:124 +msgid "Advanced Backup Permissions are not available in Duplicator Lite!" +msgstr "" + +#: template/mocks/settings/access/content-popup.php:16 +msgid "Elevate your backup capabilities with advanced permissions, allowing for precise control over the creation, exportation, restoration, and management of control settings. Enjoy granular access control to ensure only authorized users can perform these critical functions." +msgstr "" + +#: template/mocks/storage/popup.php:17 +msgid "Store to Multiple Endpoints with Duplicator Pro" +msgstr "" + +#: template/mocks/storage/popup.php:30 +msgid "Set up one-time storage locations and automatically push the package to your destination." +msgstr "" + +#: template/mocks/storage/storage.php:61 +msgid "Remote Cloud Backups is a PRO feature" +msgstr "" + +#: template/mocks/storage/storage.php:62 +msgid "Back up to Dropbox, FTP, Google Drive, OneDrive, Amazon S3 or Amazon S3 compatible for safe off-site storage." +msgstr "" + +#: template/mocks/storage/storage.php:79 views/packages/main/packages.php:95 +msgid "Bulk Actions" +msgstr "" + +#: template/mocks/storage/storage.php:81 views/packages/main/packages.php:98 +msgid "Delete" +msgstr "" + +#: template/mocks/storage/storage.php:93 +msgid "Add New" +msgstr "" + +#: template/mocks/storage/storage.php:108 views/packages/details/detail.php:98 +#: views/packages/details/detail.php:284 views/packages/details/detail.php:420 +#: views/packages/main/packages.php:196 views/packages/main/s1.setup2.php:83 +#: views/packages/main/s1.setup2.php:120 views/packages/main/s2.scan3.php:717 +msgid "Name" +msgstr "" + +#: template/mocks/storage/storage.php:109 views/packages/details/detail.php:285 +#: views/packages/details/detail.php:424 views/packages/main/s1.setup2.php:121 +#: views/settings/license.php:23 +msgid "Type" +msgstr "" + +#: template/mocks/storage/storage.php:146 +#, php-format +msgid "Total: %s" +msgstr "" + +#: template/mocks/templates/content-popup.php:15 +msgid "If you install the same theme, plugins or content on all your WordPress sites then Duplicator can save you a lot of time." +msgstr "" + +#: template/mocks/templates/content-popup.php:23 +msgid "Instead of manually configuring the same themes and plugins over and over, just configure one site and bundle it into a Duplicator package. Install the package to create a pre-configured site on as many locations as you want!" +msgstr "" + +#: template/mocks/templates/templates.php:194 +msgid "Easily customize your backups with templates!" +msgstr "" + +#: template/mocks/templates/templates.php:195 +msgid "Templates are not available in Duplicator Lite!" +msgstr "" + +#: template/mocks/transfer/content-popup.php:15 +msgid "With manual transfers you can upload your backup to remote storages even after you have created them." +msgstr "" + +#: template/mocks/transfer/transfer.php:230 +msgid "Manually transfer backups to remote storages!" +msgstr "" + +#: template/mocks/transfer/transfer.php:231 +msgid "Remote storages are not available in Duplicator Lite!" +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:22 +msgid "Package creation" +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:24 +msgid "This will create a new package. If a package is currently running then this button will be disabled." +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:31 +msgid "Last backup:" +msgstr "" + +#: template/parts/DashboardWidget/package-create-section.php:46 +#: views/packages/main/packages.php:144 views/packages/main/s3.build.php:135 +msgid "Create New" +msgstr "" + +#: template/parts/DashboardWidget/recently-packages.php:28 +msgid "Recently Packages" +msgstr "" + +#: template/parts/DashboardWidget/recently-packages.php:47 +#, php-format +msgid "Packages: %1$d, Failures: %2$d" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:36 +msgid "Recommended Plugin:" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:42 +msgid "Install" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:45 +msgid "Learn More" +msgstr "" + +#: template/parts/DashboardWidget/recommended-section.php:50 +msgid "Dismiss recommended plugin" +msgstr "" + +#: template/parts/DashboardWidget/sections-section.php:56 +#: views/packages/main/s1.setup2.php:562 +msgid "Next" +msgstr "" + +#: template/parts/DashboardWidget/sections-section.php:98 +msgid "Recovery Point" +msgstr "" + +#: template/parts/DashboardWidget/sections-section.php:103 +msgid "Not set" +msgstr "" + +#: template/parts/Education/callout-cta.php:21 +#: template/parts/Notifications/main.php:24 +msgid "Dismiss this message" +msgstr "" + +#: template/parts/Education/callout-cta.php:25 +msgid "Thanks for being a loyal Duplicator Lite user. Upgrade to Duplicator Pro to unlock all the awesome features and experience why Duplicator is consistently rated the best WordPress migration plugin." +msgstr "" + +#: template/parts/Education/callout-cta.php:35 +#, php-format +msgid "We know that you will truly love Duplicator. It has over 4000+ five star ratings (%s) and is active on over 1 million websites." +msgstr "" + +#: template/parts/Education/callout-cta.php:50 +msgid "Pro Features:" +msgstr "" + +#: template/parts/Education/callout-cta.php:66 +msgid "Get Duplicator Pro Today and Unlock all the Powerful Features »" +msgstr "" + +#: template/parts/Education/callout-cta.php:73 +#, php-format +msgid "Bonus: Duplicator Lite users get %1$d%% off regular price,automatically applied at checkout." +msgstr "" + +#: template/parts/Education/did-you-know-blurb.php:22 +#, php-format +msgid "Did you know Duplicator Pro has: %s?" +msgstr "" + +#: template/parts/Education/did-you-know-blurb.php:24 +#: views/packages/main/s1.setup2.php:358 +msgid "Upgrade To Pro" +msgstr "" + +#: template/parts/Education/packages-bottom-bar.php:27 +msgid "Upgrade to Pro to Unlock..." +msgstr "" + +#: template/parts/Education/packages-bottom-bar.php:36 +msgid "Upgrade Now & Save!" +msgstr "" + +#: template/parts/Education/static-popup.php:31 +msgid "Upgrade to Duplicator Pro Now" +msgstr "" + +#: template/parts/Education/subscribe-form.php:24 +msgid "Email Address" +msgstr "" + +#: template/parts/Education/subscribe-form.php:26 +msgid "Subscribe" +msgstr "" + +#: template/parts/Education/subscribe-form.php:29 +msgid "Get tips and product updates straight to your inbox." +msgstr "" + +#: template/parts/Notifications/main.php:20 +msgid "Notifications" +msgstr "" + +#: template/parts/Notifications/main.php:29 +msgid "Previous message" +msgstr "" + +#: template/parts/Notifications/main.php:33 +msgid "Next message" +msgstr "" + +#: template/parts/Notifications/single-message.php:21 +msgid "Watch video" +msgstr "" + +#: template/parts/filters/package_components.php:28 +msgid "Package components allow you to include/exclude differents part of your WordPress installation in the package.

                        Database: Include the database in the package.
                        Plugins: Include the plugins in the package. With the 'active only' option enabled, only active plugins will be included in the package.
                        Themes: Include the themes in the package. With the 'active only' option enabled, only active themes will be included in the package.
                        Media: Include the 'uploads' folder.
                        Other: Include non-WordPress files and folders in the root directory.
                        " +msgstr "" + +#: template/parts/filters/package_components.php:39 +msgid "File filters allow you to exclude files and folders from the package. To enable path and extension filters check the checkbox. Enter the full path of the files and folders you want to exclude from the package as a semicolon (;) seperated list." +msgstr "" + +#: template/parts/filters/package_components.php:41 +msgid "File extension filters allow you to exclude files with certain file extensions from the package e.g. zip;rar;pdf etc. Enter the file extensions you want to exclude from the package as a semicolon (;) seperated list." +msgstr "" + +#: template/parts/filters/package_components.php:49 +msgid "Components" +msgstr "" + +#: template/parts/filters/package_components.php:51 +msgid "Package Components (Pro feature)" +msgstr "" + +#: template/parts/filters/package_components.php:86 +#: views/packages/details/detail.php:516 views/packages/main/s1.setup2.php:213 +#: views/packages/main/s1.setup2.php:485 views/packages/main/s2.scan3.php:403 +#: views/packages/main/s2.scan3.php:723 views/settings/packages.php:91 +msgid "Database" +msgstr "" + +#: template/parts/filters/package_components.php:93 +msgid "Plugins" +msgstr "" + +#: template/parts/filters/package_components.php:99 +msgid "Only Active Plugins" +msgstr "" + +#: template/parts/filters/package_components.php:106 +msgid "Themes" +msgstr "" + +#: template/parts/filters/package_components.php:112 +msgid "Only Active Themes" +msgstr "" + +#: template/parts/filters/package_components.php:119 +msgid "Media" +msgstr "" + +#: template/parts/filters/package_components.php:126 +msgid "Other" +msgstr "" + +#: template/parts/filters/package_components.php:134 +#: views/packages/details/detail.php:376 views/packages/details/detail.php:441 +#: views/packages/main/s1.setup2.php:225 +msgid "Filters" +msgstr "" + +#: template/parts/filters/package_components.php:138 +msgid "Path Filters" +msgstr "" + +#: template/parts/filters/package_components.php:157 +#: template/parts/filters/package_components.php:159 +msgid "File Extensions" +msgstr "" + +#: template/parts/filters/package_components.php:175 +msgid "Overview:
                        This advanced option excludes all files from the archive. Only the database and a copy of the installer.php will be included in the archive.zip file. The option can be used for backing up and moving only the database." +msgstr "" + +#: template/parts/filters/package_components.php:188 +msgid " Notice:
                        Installing only the database over an existing site may have unintended consequences. Be sure to know the state of your system before installing the database without the associated files. " +msgstr "" + +#: template/parts/filters/package_components.php:201 +msgid "For example, if you have WordPress 5.6 on this site and you copy this site's database to a host that has WordPress 5.8 files then the source code of the files will not be in sync with the database causing possible errors. This can also be true of plugins and themes. When moving only the database be sure to know the database will be compatible with ALL source code files. Please use this advanced feature with caution!" +msgstr "" + +#: template/parts/filters/package_components.php:212 +msgid "Install Time:
                        When installing a database only package please visit the " +msgstr "" + +#: template/parts/filters/package_components.php:223 +msgid "database only quick start" +msgstr "" + +#: template/parts/filters/package_components.php:233 +#, php-format +msgid "The Media Only and Custom options are not included in Duplicator Lite. To enable advanced options please %1$supgrade to Pro%2$s." +msgstr "" + +#: template/parts/notice-bar.php:45 +#, php-format +msgid "You're using Duplicator Lite. To unlock more features consider upgrading to Pro" +msgstr "" + +#: template/parts/notice-bar.php:65 +msgid "Dismiss this message." +msgstr "" + +#: views/packages/details/controller.php:35 +#, php-format +msgid "This package contains an error. Please review the %1$spackage log%2$s for details." +msgstr "" + +#: views/packages/details/controller.php:45 +#, php-format +msgid "For help visit the %1$sFAQ%2$s and %3$sresources page%4$s." +msgstr "" + +#: views/packages/details/controller.php:61 +msgid "Details" +msgstr "" + +#: views/packages/details/controller.php:64 +msgid "Transfer" +msgstr "" + +#: views/packages/details/detail.php:80 +msgid "Invalid Package ID request. Please try again!" +msgstr "" + +#: views/packages/details/detail.php:92 views/settings/controller.php:31 +#: views/tools/controller.php:25 views/tools/diagnostics/inc.settings.php:35 +msgid "General" +msgstr "" + +#: views/packages/details/detail.php:106 +msgid "ID" +msgstr "" + +#: views/packages/details/detail.php:110 +msgid "Hash" +msgstr "" + +#: views/packages/details/detail.php:114 +msgid "Full Name" +msgstr "" + +#: views/packages/details/detail.php:122 views/packages/main/s1.setup2.php:92 +#: views/packages/main/s2.scan3.php:718 +msgid "Notes" +msgstr "" + +#: views/packages/details/detail.php:123 +msgid "- no notes -" +msgstr "" + +#: views/packages/details/detail.php:126 views/packages/main/packages.php:194 +msgid "Created" +msgstr "" + +#: views/packages/details/detail.php:138 views/packages/main/s2.scan2.php:109 +msgid "WordPress" +msgstr "" + +#: views/packages/details/detail.php:139 views/packages/details/detail.php:143 +#: views/packages/details/detail.php:148 views/packages/details/detail.php:149 +#: views/packages/details/detail.php:166 +msgid "- unknown -" +msgstr "" + +#: views/packages/details/detail.php:142 +msgid "PHP" +msgstr "" + +#: views/packages/details/detail.php:146 +msgid "Mysql" +msgstr "" + +#: views/packages/details/detail.php:157 +msgid "Runtime" +msgstr "" + +#: views/packages/details/detail.php:158 +msgid "error running" +msgstr "" + +#: views/packages/details/detail.php:161 +msgid "Status" +msgstr "" + +#: views/packages/details/detail.php:162 +msgid "completed" +msgstr "" + +#: views/packages/details/detail.php:162 +msgid "in-complete" +msgstr "" + +#: views/packages/details/detail.php:165 views/packages/details/detail.php:520 +#: views/packages/main/s1.setup2.php:498 +#: views/tools/diagnostics/inc.settings.php:129 +msgid "User" +msgstr "" + +#: views/packages/details/detail.php:169 views/packages/details/detail.php:399 +#: views/packages/main/s1.setup2.php:212 views/packages/main/s2.scan3.php:34 +#: views/packages/main/s2.scan3.php:774 views/packages/main/s2.scan3.php:826 +msgid "Files" +msgstr "" + +#: views/packages/details/detail.php:175 +msgid "Download hashed installer ([name]_[hash]_[time]_installer.php)" +msgstr "" + +#: views/packages/details/detail.php:178 +msgid "Download basic installer (installer.php)" +msgstr "" + +#: views/packages/details/detail.php:184 +msgid "Click buttons or links to download." +msgstr "" + +#: views/packages/details/detail.php:196 +msgid "Share File Links" +msgstr "" + +#: views/packages/details/detail.php:207 views/packages/details/detail.php:352 +#: views/packages/main/packages.php:297 views/packages/main/s1.setup2.php:186 +#: views/packages/main/s2.scan3.php:27 views/packages/main/s3.build.php:183 +#: views/settings/packages.php:250 +msgid "Archive" +msgstr "" + +#: views/packages/details/detail.php:215 +msgid "Build Log" +msgstr "" + +#: views/packages/details/detail.php:223 views/packages/details/detail.php:464 +#: views/packages/main/packages.php:291 views/packages/main/s1.setup2.php:370 +#: views/packages/main/s3.build.php:180 views/settings/packages.php:326 +msgid "Installer" +msgstr "" + +#: views/packages/details/detail.php:228 +msgid "The installer is also available inside the archive file." +msgstr "" + +#: views/packages/details/detail.php:242 +msgid "Download Links" +msgstr "" + +#: views/packages/details/detail.php:245 +msgid "The following links contain sensitive data. Share with caution!" +msgstr "" + +#: views/packages/details/detail.php:286 +msgid "Locations" +msgstr "" + +#: views/packages/details/detail.php:292 views/packages/main/s1.setup2.php:131 +msgid "Default" +msgstr "" + +#: views/packages/details/detail.php:296 views/packages/main/s1.setup2.php:135 +msgid "(Legacy Path)" +msgstr "" + +#: views/packages/details/detail.php:298 views/packages/main/s1.setup2.php:137 +msgid "(Contents Path)" +msgstr "" + +#: views/packages/details/detail.php:305 views/packages/main/s1.setup2.php:144 +msgid "Local" +msgstr "" + +#: views/packages/details/detail.php:320 views/packages/main/s1.setup2.php:153 +#, php-format +msgid "Back up this site to %1$s, %2$s, %3$s, %4$s, %5$s and other locations with " +msgstr "" + +#: views/packages/details/detail.php:331 views/packages/main/packages.php:174 +#: views/packages/main/packages.php:340 views/packages/main/s1.setup2.php:162 +#: views/packages/main/s2.scan3.php:590 views/packages/main/s2.scan3.php:685 +#: views/packages/main/s3.build.php:228 +msgid "Duplicator Pro" +msgstr "" + +#: views/packages/details/detail.php:334 views/packages/main/s1.setup2.php:165 +msgid "Additional Storage:" +msgstr "" + +#: views/packages/details/detail.php:335 views/packages/main/s1.setup2.php:166 +msgid "Duplicator Pro allows you to create a package and store it at a custom location on this server or to a remote cloud location such as Google Drive, Amazon, Dropbox and many more." +msgstr "" + +#: views/packages/details/detail.php:360 +msgid "FILES" +msgstr "" + +#: views/packages/details/detail.php:364 +msgid "Build Mode" +msgstr "" + +#: views/packages/details/detail.php:371 +msgid "Database Mode" +msgstr "" + +#: views/packages/details/detail.php:372 +msgid "Archive Database Only Enabled" +msgstr "" + +#: views/packages/details/detail.php:380 views/packages/main/s2.scan3.php:752 +#: views/packages/main/s2.scan3.php:817 +msgid "Directories" +msgstr "" + +#: views/packages/details/detail.php:384 views/packages/details/detail.php:394 +#: views/packages/details/detail.php:403 views/packages/details/detail.php:451 +msgid "- no filters -" +msgstr "" + +#: views/packages/details/detail.php:390 views/packages/main/s2.scan3.php:763 +msgid "Extensions" +msgstr "" + +#: views/packages/details/detail.php:416 +msgid "DATABASE" +msgstr "" + +#: views/packages/details/detail.php:428 views/packages/main/s1.setup2.php:301 +#: views/settings/packages.php:95 +msgid "SQL Mode" +msgstr "" + +#: views/packages/details/detail.php:434 views/packages/main/s2.scan3.php:734 +msgid "MySQL Compatibility Mode Enabled" +msgstr "" + +#: views/packages/details/detail.php:435 views/packages/main/s1.setup2.php:313 +#: views/packages/main/s2.scan2.php:64 views/packages/main/s2.scan2.php:75 +#: views/packages/main/s2.scan2.php:81 views/packages/main/s2.scan3.php:735 +msgid "details" +msgstr "" + +#: views/packages/details/detail.php:447 views/packages/main/s2.scan3.php:432 +msgid "Tables" +msgstr "" + +#: views/packages/details/detail.php:472 views/packages/main/s1.setup1.php:62 +#: views/packages/main/s1.setup2.php:400 views/packages/main/s2.scan1.php:187 +#: views/packages/main/s2.scan2.php:10 views/packages/main/s3.build.php:111 +msgid "Setup" +msgstr "" + +#: views/packages/details/detail.php:477 views/packages/main/s1.setup2.php:414 +msgid "Security" +msgstr "" + +#: views/packages/details/detail.php:482 +msgid "Password Protection Enabled" +msgstr "" + +#: views/packages/details/detail.php:484 +msgid "Password Protection Disabled" +msgstr "" + +#: views/packages/details/detail.php:495 views/packages/main/s1.setup2.php:430 +msgid "Show/Hide Password" +msgstr "" + +#: views/packages/details/detail.php:508 views/packages/main/s1.setup2.php:456 +msgid " MySQL Server" +msgstr "" + +#: views/packages/details/detail.php:512 views/packages/main/s1.setup2.php:459 +msgid "Host" +msgstr "" + +#: views/packages/details/detail.php:513 views/packages/details/detail.php:517 +#: views/packages/details/detail.php:521 +msgid "- not set -" +msgstr "" + +#: views/packages/details/detail.php:529 +msgid "View Package Object" +msgstr "" + +#: views/packages/details/detail.php:546 +msgid "Package File Links" +msgstr "" + +#: views/packages/details/detail.php:551 +msgid "ARCHIVE" +msgstr "" + +#: views/packages/details/detail.php:552 +msgid "LOG" +msgstr "" + +#: views/packages/main/controller.php:9 +msgid "An invalid request was made to this page." +msgstr "" + +#: views/packages/main/controller.php:10 +msgid "Please retry by going to the" +msgstr "" + +#: views/packages/main/controller.php:11 +msgid "Packages Screen" +msgstr "" + +#: views/packages/main/controller.php:59 +msgid "Packages » All" +msgstr "" + +#: views/packages/main/controller.php:63 views/packages/main/controller.php:67 +#: views/packages/main/controller.php:71 +msgid "Packages » New" +msgstr "" + +#: views/packages/main/packages.php:26 +msgid "When clicking the Installer download button, the 'Save as' dialog is currently defaulting the name to 'installer.php'. To improve the security and get more information, go to: Settings > Packages Tab > Installer > Name option or click on the gear icon at the top of this page." +msgstr "" + +#: views/packages/main/packages.php:29 +msgid "When clicking the Installer download button, the 'Save as' dialog is defaulting the name to '[name]_[hash]_[time]_installer.php'. This is the secure and recommended option. For more information, go to: Settings > Packages Tab > Installer > Name or click on the gear icon at the top of this page.

                        To quickly copy the hashed installer name, to your clipboard use the copy icon link or click the installer name and manually copy the selected text." +msgstr "" + +#: views/packages/main/packages.php:97 +msgid "Delete selected package(s)" +msgstr "" + +#: views/packages/main/packages.php:103 +msgid "Apply" +msgstr "" + +#: views/packages/main/packages.php:107 +msgid "Get Help" +msgstr "" + +#: views/packages/main/packages.php:120 views/tools/controller.php:26 +msgid "Templates" +msgstr "" + +#: views/packages/main/packages.php:132 views/tools/controller.php:27 +msgid "Recovery" +msgstr "" + +#: views/packages/main/packages.php:160 views/packages/main/packages.php:213 +msgid "No Packages Found" +msgstr "" + +#: views/packages/main/packages.php:161 views/packages/main/packages.php:214 +msgid "Click 'Create New' to Archive Site" +msgstr "" + +#: views/packages/main/packages.php:163 views/packages/main/packages.php:216 +msgid "New to Duplicator?" +msgstr "" + +#: views/packages/main/packages.php:165 views/packages/main/packages.php:218 +msgid "Visit the 'Quick Start' guide!" +msgstr "" + +#: views/packages/main/packages.php:171 views/packages/main/packages.php:337 +msgid "Duplicator Lite does not officially support WordPress multisite." +msgstr "" + +#: views/packages/main/packages.php:173 views/packages/main/s3.build.php:227 +msgid "We strongly recommend upgrading to " +msgstr "" + +#: views/packages/main/packages.php:192 +msgid "Select all packages" +msgstr "" + +#: views/packages/main/packages.php:195 views/packages/main/s2.scan3.php:95 +#: views/packages/main/s2.scan3.php:431 +msgid "Size" +msgstr "" + +#: views/packages/main/packages.php:198 +msgid "Installer Name" +msgstr "" + +#: views/packages/main/packages.php:200 views/packages/main/s3.build.php:214 +msgid "Installer Name:" +msgstr "" + +#: views/packages/main/packages.php:205 views/packages/main/s2.scan3.php:716 +msgid "Package" +msgstr "" + +#: views/packages/main/packages.php:252 +msgid "Archive created as zip file" +msgstr "" + +#: views/packages/main/packages.php:253 +msgid "Archive created as daf file" +msgstr "" + +#: views/packages/main/packages.php:258 views/packages/main/s1.setup2.php:200 +#: views/packages/main/s2.scan3.php:41 views/packages/main/s2.scan3.php:62 +msgid "Database Only" +msgstr "" + +#: views/packages/main/packages.php:262 +msgid "Package Build Running" +msgstr "" + +#: views/packages/main/packages.php:263 +msgid "To stop or reset this package build goto Settings > Advanced > Reset Packages" +msgstr "" + +#: views/packages/main/packages.php:280 +msgid "Click to configure installer name." +msgstr "" + +#: views/packages/main/packages.php:299 +msgid "Package Details" +msgstr "" + +#: views/packages/main/packages.php:316 +msgid "Error Processing" +msgstr "" + +#: views/packages/main/packages.php:333 +msgid "Trace Logging Enabled. Please disable when trace capture is complete." +msgstr "" + +#: views/packages/main/packages.php:339 +msgid "We strongly recommend using" +msgstr "" + +#: views/packages/main/packages.php:345 +msgid "Current Server Time" +msgstr "" + +#: views/packages/main/packages.php:348 views/packages/main/s3.build.php:459 +msgid "Time" +msgstr "" + +#: views/packages/main/packages.php:363 +msgid "Items" +msgstr "" + +#: views/packages/main/packages.php:374 +msgid "Bulk Action Required" +msgstr "" + +#: views/packages/main/packages.php:376 +msgid "No selections made! Please select an action from the \"Bulk Actions\" drop down menu." +msgstr "" + +#: views/packages/main/packages.php:380 +msgid "Selection Required" +msgstr "" + +#: views/packages/main/packages.php:382 +msgid "No selections made! Please select at least one package to delete." +msgstr "" + +#: views/packages/main/packages.php:386 +msgid "Delete Packages?" +msgstr "" + +#: views/packages/main/packages.php:387 +msgid "Are you sure you want to delete the selected package(s)?" +msgstr "" + +#: views/packages/main/packages.php:388 +msgid "Removing Packages, Please Wait..." +msgstr "" + +#: views/packages/main/packages.php:395 +msgid "Duplicator Help" +msgstr "" + +#: views/packages/main/packages.php:400 +msgid "Alert!" +msgstr "" + +#: views/packages/main/packages.php:401 +msgid "A package is being processed. Retry later." +msgstr "" + +#: views/packages/main/packages.php:408 +msgid "Common Questions:" +msgstr "" + +#: views/packages/main/packages.php:411 +msgid "How do I create a package" +msgstr "" + +#: views/packages/main/packages.php:415 +msgid "How do I install a package?" +msgstr "" + +#: views/packages/main/packages.php:419 +msgid "Frequently Asked Questions!" +msgstr "" + +#: views/packages/main/packages.php:423 +msgid "Other Resources:" +msgstr "" + +#: views/packages/main/packages.php:425 +msgid "Need help with the plugin?" +msgstr "" + +#: views/packages/main/packages.php:429 views/packages/main/s3.build.php:288 +msgid "Help review the plugin!" +msgstr "" + +#: views/packages/main/s1.setup1.php:12 +msgid "Package settings have been reset." +msgstr "" + +#: views/packages/main/s1.setup1.php:63 views/packages/main/s2.scan1.php:188 +#: views/packages/main/s3.build.php:112 +msgid "Scan" +msgstr "" + +#: views/packages/main/s1.setup1.php:64 views/packages/main/s2.scan1.php:189 +#: views/packages/main/s2.scan1.php:273 views/packages/main/s3.build.php:113 +msgid "Build" +msgstr "" + +#: views/packages/main/s1.setup1.php:69 +msgid "Step 1: Choose the WordPress contents to backup." +msgstr "" + +#: views/packages/main/s1.setup1.php:88 +msgid "Requirements:" +msgstr "" + +#: views/packages/main/s1.setup1.php:97 +msgid "System requirements must pass for the Duplicator to work properly. Click each link for details." +msgstr "" + +#: views/packages/main/s1.setup1.php:103 +msgid "PHP Support" +msgstr "" + +#: views/packages/main/s1.setup1.php:109 views/packages/main/s2.scan2.php:56 +msgid "PHP Version" +msgstr "" + +#: views/packages/main/s1.setup1.php:111 +msgid "PHP versions 5.2.9+ or higher is required." +msgstr "" + +#: views/packages/main/s1.setup1.php:115 +msgid "Zip Archive Enabled" +msgstr "" + +#: views/packages/main/s1.setup1.php:120 +msgid "ZipArchive extension is required or" +msgstr "" + +#: views/packages/main/s1.setup1.php:121 +msgid "Switch to DupArchive" +msgstr "" + +#: views/packages/main/s1.setup1.php:122 +msgid "to by-pass this requirement." +msgstr "" + +#: views/packages/main/s1.setup1.php:129 +msgid "Safe Mode Off" +msgstr "" + +#: views/packages/main/s1.setup1.php:131 +msgid "Safe Mode should be set to Off in you php.ini file and is deprecated as of PHP 5.3.0." +msgstr "" + +#: views/packages/main/s1.setup1.php:134 views/packages/main/s1.setup1.php:139 +#: views/packages/main/s1.setup1.php:144 +msgid "Function" +msgstr "" + +#: views/packages/main/s1.setup1.php:150 +msgid "For any issues in this section please contact your hosting provider or server administrator. For additional information see our online documentation." +msgstr "" + +#: views/packages/main/s1.setup1.php:158 +msgid "Required Paths" +msgstr "" + +#: views/packages/main/s1.setup1.php:180 +msgid "If the root WordPress path is not writable by PHP on some systems this can cause issues." +msgstr "" + +#: views/packages/main/s1.setup1.php:183 +msgid "If Duplicator does not have enough permissions then you will need to manually create the paths above.   " +msgstr "" + +#: views/packages/main/s1.setup1.php:192 +msgid "Server Support" +msgstr "" + +#: views/packages/main/s1.setup1.php:198 +msgid "MySQL Version" +msgstr "" + +#: views/packages/main/s1.setup1.php:202 +msgid "MySQLi Support" +msgstr "" + +#: views/packages/main/s1.setup1.php:209 +msgid "MySQL version 5.0+ or better is required and the PHP MySQLi extension (note the trailing 'i') is also required. Contact your server administrator and request that mysqli extension and MySQL Server 5.0+ be installed." +msgstr "" + +#: views/packages/main/s1.setup1.php:213 +#: views/tools/diagnostics/inc.data.php:26 +msgid "more info" +msgstr "" + +#: views/packages/main/s1.setup1.php:224 +msgid "The function mysqli_real_escape_string is not working properly. Please consult host support and ask them to switch to a different PHP version or configuration." +msgstr "" + +#: views/packages/main/s1.setup1.php:233 +msgid "Reserved Files" +msgstr "" + +#: views/packages/main/s1.setup1.php:238 +msgid "None of the reserved files where found from a previous install. This means you are clear to create a new package." +msgstr "" + +#: views/packages/main/s1.setup1.php:246 +msgid "WordPress Root Path:" +msgstr "" + +#: views/packages/main/s1.setup1.php:249 +msgid " To archive your data correctly please remove any of these files from your WordPress root directory. " +msgstr "" + +#: views/packages/main/s1.setup1.php:251 +msgid "Remove Files Now" +msgstr "" + +#: views/packages/main/s1.setup2.php:86 +msgid "Add Notes" +msgstr "" + +#: views/packages/main/s1.setup2.php:89 +msgid "Toggle a default name" +msgstr "" + +#: views/packages/main/s1.setup2.php:109 +msgid "This is the storage location on this server where the archive and installer files will be saved." +msgstr "" + +#: views/packages/main/s1.setup2.php:112 +msgid "[Storage Options]" +msgstr "" + +#: views/packages/main/s1.setup2.php:122 views/settings/storage.php:71 +msgid "Location" +msgstr "" + +#: views/packages/main/s1.setup2.php:191 +msgid "File filter enabled" +msgstr "" + +#: views/packages/main/s1.setup2.php:195 +msgid "Database filter enabled" +msgstr "" + +#: views/packages/main/s1.setup2.php:199 +msgid "Archive Only the Database" +msgstr "" + +#: views/packages/main/s1.setup2.php:214 +msgid "File Archive Encryption" +msgstr "" + +#: views/packages/main/s1.setup2.php:232 +msgid "Enable Table Filters" +msgstr "" + +#: views/packages/main/s1.setup2.php:234 +msgid "Enable Table Filters:" +msgstr "" + +#: views/packages/main/s1.setup2.php:235 +msgid "Checked tables will not be added to the database script. Excluding certain tables can possibly cause your site or plugins to not work correctly after install!" +msgstr "" + +#: views/packages/main/s1.setup2.php:242 +msgid "Include All" +msgstr "" + +#: views/packages/main/s1.setup2.php:243 +msgid "Exclude All" +msgstr "" + +#: views/packages/main/s1.setup2.php:288 +msgid "Checked tables will be excluded from the database script. " +msgstr "" + +#: views/packages/main/s1.setup2.php:289 +msgid "Excluding certain tables can cause your site or plugins to not work correctly after install!
                        " +msgstr "" + +#: views/packages/main/s1.setup2.php:290 +msgid " Use caution when excluding tables! It is highly recommended to not exclude WordPress core tables*, unless you know the impact." +msgstr "" + +#: views/packages/main/s1.setup2.php:296 +msgid "Configuration" +msgstr "" + +#: views/packages/main/s1.setup2.php:305 +msgid "Compatibility Mode" +msgstr "" + +#: views/packages/main/s1.setup2.php:307 +msgid "Compatibility Mode:" +msgstr "" + +#: views/packages/main/s1.setup2.php:308 +msgid "This is an advanced database backwards compatibility feature that should ONLY be used if having problems installing packages. If the database server version is lower than the version where the package was built then these options may help generate a script that is more compliant with the older database server. It is recommended to try each option separately starting with mysql40." +msgstr "" + +#: views/packages/main/s1.setup2.php:328 +msgid "mysql40" +msgstr "" + +#: views/packages/main/s1.setup2.php:332 +msgid "no_table_options" +msgstr "" + +#: views/packages/main/s1.setup2.php:336 +msgid "no_key_options" +msgstr "" + +#: views/packages/main/s1.setup2.php:340 +msgid "no_field_options" +msgstr "" + +#: views/packages/main/s1.setup2.php:345 +msgid "This option is only available with mysqldump mode." +msgstr "" + +#: views/packages/main/s1.setup2.php:373 +msgid "Installer password protection is on" +msgstr "" + +#: views/packages/main/s1.setup2.php:376 +msgid "Installer password protection is off" +msgstr "" + +#: views/packages/main/s1.setup2.php:387 +msgid "The installer file is used to redeploy/install the archive contents." +msgstr "" + +#: views/packages/main/s1.setup2.php:389 +msgid "All values in this section are" +msgstr "" + +#: views/packages/main/s1.setup2.php:389 +msgid "optional" +msgstr "" + +#: views/packages/main/s1.setup2.php:391 +msgid "Setup/Prefills" +msgstr "" + +#: views/packages/main/s1.setup2.php:392 +msgid "All values in this section are OPTIONAL! If you know ahead of time the database input fields the installer will use, then you can optionally enter them here and they will be prefilled at install time. Otherwise you can just enter them in at install time and ignore all these options in the Installer section." +msgstr "" + +#: views/packages/main/s1.setup2.php:403 views/packages/main/s1.setup2.php:408 +msgid "Branding" +msgstr "" + +#: views/packages/main/s1.setup2.php:406 +msgid "Available with Duplicator Pro!" +msgstr "" + +#: views/packages/main/s1.setup2.php:409 +msgid "Branding is a way to customize the installer look and feel. With branding you can create multiple brands of installers." +msgstr "" + +#: views/packages/main/s1.setup2.php:421 +msgid "Enable Password Protection" +msgstr "" + +#: views/packages/main/s1.setup2.php:423 +msgid "Security:" +msgstr "" + +#: views/packages/main/s1.setup2.php:424 +msgid "Enabling this option will allow for basic password protection on the installer. Before running the installer the password below must be entered before proceeding with an install. This password is a general deterrent and should not be substituted for properly keeping your files secure. Be sure to remove all installer files when the install process is completed." +msgstr "" + +#: views/packages/main/s1.setup2.php:439 +msgid "Prefills" +msgstr "" + +#: views/packages/main/s1.setup2.php:447 views/settings/packages.php:338 +msgid "Basic" +msgstr "" + +#: views/packages/main/s1.setup2.php:448 +msgid "cPanel" +msgstr "" + +#: views/packages/main/s1.setup2.php:467 +msgid "example: localhost (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:472 +msgid "Host Port" +msgstr "" + +#: views/packages/main/s1.setup2.php:480 +msgid "example: 3306 (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:493 +msgid "example: DatabaseName (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:506 +msgid "example: DatabaseUserName (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:511 +#: views/tools/diagnostics/inc.settings.php:109 +#: views/tools/diagnostics/inc.settings.php:202 +msgid "Charset" +msgstr "" + +#: views/packages/main/s1.setup2.php:519 +msgid "example: utf8 (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:524 +msgid "Collation" +msgstr "" + +#: views/packages/main/s1.setup2.php:532 +msgid "example: utf8_general_ci (value is optional)" +msgstr "" + +#: views/packages/main/s1.setup2.php:544 +msgid "Create the database and database user at install time without leaving the installer!" +msgstr "" + +#: views/packages/main/s1.setup2.php:545 +msgid "This feature is only availble in " +msgstr "" + +#: views/packages/main/s1.setup2.php:547 +msgid "Duplicator Pro!" +msgstr "" + +#: views/packages/main/s1.setup2.php:549 +msgid "This feature works only with hosts that support cPanel." +msgstr "" + +#: views/packages/main/s1.setup2.php:561 +msgid "Reset" +msgstr "" + +#: views/packages/main/s1.setup2.php:571 +msgid "Reset Package Settings?" +msgstr "" + +#: views/packages/main/s1.setup2.php:572 +msgid "This will clear and reset all of the current package settings. Would you like to continue?" +msgstr "" + +#: views/packages/main/s2.scan1.php:160 +msgid "Input fields not valid" +msgstr "" + +#: views/packages/main/s2.scan1.php:161 views/packages/main/s2.scan1.php:222 +msgid "Please try again!" +msgstr "" + +#: views/packages/main/s2.scan1.php:163 views/packages/main/s2.scan1.php:227 +#: views/packages/main/s3.build.php:503 +msgid "Error Message:" +msgstr "" + +#: views/packages/main/s2.scan1.php:173 views/packages/main/s2.scan1.php:271 +msgid "Back" +msgstr "" + +#: views/packages/main/s2.scan1.php:193 +msgid "Step 2: Scan site for configuration & system notices." +msgstr "" + +#: views/packages/main/s2.scan1.php:209 +msgid "Scanning Site" +msgstr "" + +#: views/packages/main/s2.scan1.php:211 views/packages/main/s3.build.php:152 +msgid "Please Wait..." +msgstr "" + +#: views/packages/main/s2.scan1.php:212 +msgid "Keep this window open during the scan process." +msgstr "" + +#: views/packages/main/s2.scan1.php:213 +msgid "This can take several minutes." +msgstr "" + +#: views/packages/main/s2.scan1.php:221 +msgid "Scan Error" +msgstr "" + +#: views/packages/main/s2.scan1.php:224 views/packages/main/s3.build.php:486 +msgid "Server Status:" +msgstr "" + +#: views/packages/main/s2.scan1.php:236 +msgid "Scan Complete" +msgstr "" + +#: views/packages/main/s2.scan1.php:238 +msgid "Scan Time:" +msgstr "" + +#: views/packages/main/s2.scan1.php:254 +msgid "Scan checks are not required to pass, however they could cause issues on some systems." +msgstr "" + +#: views/packages/main/s2.scan1.php:256 +msgid "Please review the details for each section by clicking on the detail title." +msgstr "" + +#: views/packages/main/s2.scan1.php:262 +msgid "Do you want to continue?" +msgstr "" + +#: views/packages/main/s2.scan1.php:264 +msgid "At least one or more checkboxes were checked in \"Quick Filters\"." +msgstr "" + +#: views/packages/main/s2.scan1.php:265 +msgid "To apply a \"Quick Filter\" click the \"Add Filters & Rescan\" button" +msgstr "" + +#: views/packages/main/s2.scan1.php:267 +msgid "Yes. Continue without applying any file filters." +msgstr "" + +#: views/packages/main/s2.scan1.php:272 +msgid "Rescan" +msgstr "" + +#: views/packages/main/s2.scan1.php:416 +msgid "Unable to perform a full scan, please try the following actions:" +msgstr "" + +#: views/packages/main/s2.scan1.php:417 +msgid "1. Go back and create a root path directory filter to validate the site is scan-able." +msgstr "" + +#: views/packages/main/s2.scan1.php:418 +msgid "2. Continue to add/remove filters to isolate which path is causing issues." +msgstr "" + +#: views/packages/main/s2.scan1.php:419 +msgid "3. This message will go away once the correct filters are applied." +msgstr "" + +#: views/packages/main/s2.scan1.php:421 +msgid "Common Issues:" +msgstr "" + +#: views/packages/main/s2.scan1.php:423 +msgid "- On some budget hosts scanning over 30k files can lead to timeout/gateway issues. Consider scanning only your main WordPress site and avoid trying to backup other external directories." +msgstr "" + +#: views/packages/main/s2.scan1.php:428 +msgid "- Symbolic link recursion can cause timeouts. Ask your server admin if any are present in the scan path. If they are add the full path as a filter and try running the scan again." +msgstr "" + +#: views/packages/main/s2.scan1.php:445 views/packages/main/s2.scan3.php:63 +#: views/packages/main/s2.scan3.php:75 views/packages/main/s2.scan3.php:609 +#: views/packages/main/s3.build.php:370 +msgid "Notice" +msgstr "" + +#: views/packages/main/s2.scan1.php:447 views/packages/main/s2.scan3.php:607 +msgid "Good" +msgstr "" + +#: views/packages/main/s2.scan1.php:448 +msgid "Fail" +msgstr "" + +#: views/packages/main/s2.scan2.php:12 +msgid "Show Diagnostics" +msgstr "" + +#: views/packages/main/s2.scan2.php:13 +msgid "Check Site Health" +msgstr "" + +#: views/packages/main/s2.scan2.php:44 +msgid "System" +msgstr "" + +#: views/packages/main/s2.scan2.php:51 +#: views/tools/diagnostics/inc.settings.php:58 +msgid "Web Server" +msgstr "" + +#: views/packages/main/s2.scan2.php:52 +msgid "Supported web servers: " +msgstr "" + +#: views/packages/main/s2.scan2.php:57 +msgid "The minimum PHP version supported by Duplicator is 5.2.9. It is highly recommended to use PHP 5.3+ for improved stability. For international language support please use PHP 7.0+." +msgstr "" + +#: views/packages/main/s2.scan2.php:62 +msgid "PHP Open Base Dir" +msgstr "" + +#: views/packages/main/s2.scan2.php:63 +msgid "Issues might occur when [open_basedir] is enabled. Work with your server admin to disable this value in the php.ini file if you’re having issues building a package." +msgstr "" + +#: views/packages/main/s2.scan2.php:68 views/packages/main/s3.build.php:466 +msgid "PHP Max Execution Time" +msgstr "" + +#: views/packages/main/s2.scan2.php:69 +msgid "Timeouts may occur for larger packages when [max_execution_time] time in the php.ini is too low. A value of 0 (recommended) indicates that PHP has no time limits. An attempt is made to override this value if the server allows it." +msgstr "" + +#: views/packages/main/s2.scan2.php:72 +msgid "Note: Timeouts can also be set at the web server layer, so if the PHP max timeout passes and you still see a build timeout messages, then your web server could be killing the process. If you are on a budget host and limited on processing time, consider using the database or file filters to shrink the size of your overall package. However use caution as excluding the wrong resources can cause your install to not work properly." +msgstr "" + +#: views/packages/main/s2.scan2.php:79 +msgid "Get faster builds with Duplicator Pro with access to shell_exec zip." +msgstr "" + +#: views/packages/main/s2.scan2.php:86 +msgid "Managed Host" +msgstr "" + +#: views/packages/main/s2.scan2.php:87 +msgid "A managed host is a WordPress host that tightly controls the server environment so that the software running on it can be closely ‘managed’ by the hosting company. Managed hosts typically have constraints imposed to facilitate this management, including the locking down of certain files and directories as well as non-standard configurations." +msgstr "" + +#: views/packages/main/s2.scan2.php:90 +msgid "Duplicator Lite allows users to build a package on managed hosts, however, the installer may not properly install packages created on managed hosts due to the non-standard configurations of managed hosts. It is also possible the package engine of Duplicator Lite won’t be able to capture all of the necessary data of a site running on a managed host." +msgstr "" + +#: views/packages/main/s2.scan2.php:93 +msgid "Due to these constraints Lite does not officially support the migration of managed hosts. It’s possible one could get the package to install but it may require custom manual effort. To get support and the advanced installer processing required for managed host support we encourage users to some budget hosts may cause timeouts. " +msgstr "" + +#: views/packages/main/s2.scan3.php:100 +msgid "more details..." +msgstr "" + +#: views/packages/main/s2.scan3.php:106 +#, php-format +msgid "This notice is triggered at [%s] and can be ignored on most hosts. If during the build process you see a \"Host Build Interrupt\" message then this host has strict processing limits. Below are some options you can take to overcome constraints set up on this host." +msgstr "" + +#: views/packages/main/s2.scan3.php:116 +msgid "Timeout Options" +msgstr "" + +#: views/packages/main/s2.scan3.php:119 +msgid "Apply the \"Quick Filters\" below or click the back button to apply on previous page." +msgstr "" + +#: views/packages/main/s2.scan3.php:124 +#, php-format +msgid "See the FAQ link to adjust this hosts timeout limits: %1$sWhat can I try for Timeout Issues?%2$s" +msgstr "" + +#: views/packages/main/s2.scan3.php:137 +#, php-format +msgid "Consider trying multi-threaded support in %1$sDuplicator Pro%2$s." +msgstr "" + +#: views/packages/main/s2.scan3.php:149 +#, php-format +msgid "Files over %1$s are listed below. Larger files such as movies or zipped content can cause timeout issues on some budget hosts. If you are having issues creating a package try excluding the directory paths below or go back to Step 1 and add them." +msgstr "" + +#: views/packages/main/s2.scan3.php:157 views/packages/main/s2.scan3.php:244 +#: views/packages/main/s2.scan3.php:293 +msgid "Quick Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:158 +msgid "Large Files" +msgstr "" + +#: views/packages/main/s2.scan3.php:161 views/packages/main/s2.scan3.php:296 +msgid "Hide All" +msgstr "" + +#: views/packages/main/s2.scan3.php:162 views/packages/main/s2.scan3.php:297 +msgid "Show All" +msgstr "" + +#: views/packages/main/s2.scan3.php:172 views/packages/main/s2.scan3.php:312 +msgid "Core WordPress directories should not be filtered. Use caution when excluding files." +msgstr "" + +#: views/packages/main/s2.scan3.php:192 +msgid "No large files found during this scan." +msgstr "" + +#: views/packages/main/s2.scan3.php:195 +msgid "No large files found during this scan. If you're having issues building a package click the back button and try adding a file filter to non-essential files paths like wp-content/uploads. These excluded files can then be manually moved to the new location after you have ran the migration installer." +msgstr "" + +#: views/packages/main/s2.scan3.php:208 views/packages/main/s2.scan3.php:338 +msgid "*Checking a directory will exclude all items recursively from that path down. Please use caution when filtering directories." +msgstr "" + +#: views/packages/main/s2.scan3.php:211 views/packages/main/s2.scan3.php:267 +#: views/packages/main/s2.scan3.php:341 +msgid "Add Filters & Rescan" +msgstr "" + +#: views/packages/main/s2.scan3.php:213 views/packages/main/s2.scan3.php:343 +msgid "Copy Paths to Clipboard" +msgstr "" + +#: views/packages/main/s2.scan3.php:229 +msgid "Addon Sites" +msgstr "" + +#: views/packages/main/s2.scan3.php:235 +msgid "An \"Addon Site\" is a separate WordPress site(s) residing in subdirectories within this site. If you confirm these to be separate sites, then it is recommended that you exclude them by checking the corresponding boxes below and clicking the 'Add Filters & Rescan' button. To backup the other sites install the plugin on the sites needing to be backed-up." +msgstr "" + +#: views/packages/main/s2.scan3.php:258 +msgid "No add on sites found." +msgstr "" + +#: views/packages/main/s2.scan3.php:264 +msgid "*Checking a directory will exclude all items in that path recursively." +msgstr "" + +#: views/packages/main/s2.scan3.php:280 views/packages/main/s2.scan3.php:294 +msgid "Name Checks" +msgstr "" + +#: views/packages/main/s2.scan3.php:285 +msgid "Unicode and special characters such as \"*?><:/\\|\", can be problematic on some hosts." +msgstr "" + +#: views/packages/main/s2.scan3.php:286 +msgid " Only consider using this filter if the package build is failing. Select files that are not important to your site or you can migrate manually." +msgstr "" + +#: views/packages/main/s2.scan3.php:287 +msgid "If this environment/system and the system where it will be installed are set up to support Unicode and long paths then these filters can be ignored. If you run into issues with creating or installing a package, then is recommended to filter these paths." +msgstr "" + +#: views/packages/main/s2.scan3.php:332 +msgid "No file/directory name warnings found." +msgstr "" + +#: views/packages/main/s2.scan3.php:355 +msgid "Read Checks" +msgstr "" + +#: views/packages/main/s2.scan3.php:360 +msgid "PHP is unable to read the following items and they will NOT be included in the package. Please work with your host to adjust the permissions or resolve the symbolic-link(s) shown in the lists below. If these items are not needed then this notice can be ignored." +msgstr "" + +#: views/packages/main/s2.scan3.php:366 +msgid "Unreadable Items:" +msgstr "" + +#: views/packages/main/s2.scan3.php:373 +msgid "No unreadable items found." +msgstr "" + +#: views/packages/main/s2.scan3.php:377 +msgid "Recursive Links:" +msgstr "" + +#: views/packages/main/s2.scan3.php:384 +msgid "No recursive sym-links found." +msgstr "" + +#: views/packages/main/s2.scan3.php:415 +msgid "Database Size:" +msgstr "" + +#: views/packages/main/s2.scan3.php:416 +msgid "The database size represents only the included tables. The process for gathering the size uses the query SHOW TABLE STATUS. The overall size of the database file can impact the final size of the package." +msgstr "" + +#: views/packages/main/s2.scan3.php:426 views/packages/main/s3.build.php:326 +#: views/packages/screen.php:65 +msgid "Overview" +msgstr "" + +#: views/packages/main/s2.scan3.php:430 +msgid "TOTAL SIZE" +msgstr "" + +#: views/packages/main/s2.scan3.php:433 +msgid "Records" +msgstr "" + +#: views/packages/main/s2.scan3.php:436 +#, php-format +msgid "Total size and row counts are approximate values. The thresholds that trigger notices are %1$s records total for the entire database. Larger databases take more time to process. On some budget hosts that have cpu/memory/timeout limits this may cause issues." +msgstr "" + +#: views/packages/main/s2.scan3.php:441 +msgid "TABLE DETAILS:" +msgstr "" + +#: views/packages/main/s2.scan3.php:443 +#, php-format +msgid "The notices for tables are %1$s records or names with upper-case characters. Individual tables will not trigger a notice message, but can help narrow down issues if they occur later on." +msgstr "" + +#: views/packages/main/s2.scan3.php:450 views/packages/main/s2.scan3.php:561 +#: views/packages/main/s2.scan3.php:646 +msgid "RECOMMENDATIONS:" +msgstr "" + +#: views/packages/main/s2.scan3.php:453 +msgid "repair and optimization" +msgstr "" + +#: views/packages/main/s2.scan3.php:454 +#, php-format +msgid "1. Run a %1$s on the table to improve the overall size and performance." +msgstr "" + +#: views/packages/main/s2.scan3.php:456 +msgid "2. Remove post revisions and stale data from tables. Tables such as logs, statistical or other non-critical data should be cleared." +msgstr "" + +#: views/packages/main/s2.scan3.php:458 +msgid "Enable mysqldump" +msgstr "" + +#: views/packages/main/s2.scan3.php:459 +#, php-format +msgid "3. %1$s if this host supports the option." +msgstr "" + +#: views/packages/main/s2.scan3.php:461 +msgid "lower_case_table_names" +msgstr "" + +#: views/packages/main/s2.scan3.php:462 +#, php-format +msgid "4. For table name case sensitivity issues either rename the table with lower case characters or be prepared to work with the %1$s system variable setting." +msgstr "" + +#: views/packages/main/s2.scan3.php:473 +msgid "Triggers" +msgstr "" + +#: views/packages/main/s2.scan3.php:482 +msgid "triggers" +msgstr "" + +#: views/packages/main/s2.scan3.php:483 +#, php-format +msgid "This database makes use of %1$s which can manually be imported at install time. Instructions and SQL statement queries will be provided at install time for users to execute. No actions need to be performed at this time, this message is simply a notice." +msgstr "" + +#: views/packages/main/s2.scan3.php:500 +msgid "Object Access" +msgstr "" + +#: views/packages/main/s2.scan3.php:508 +msgid "The database user for this WordPress site has sufficient permissions to write stored procedures and functions to the sql file of the archive. [The command SHOW CREATE FUNCTION will work.]" +msgstr "" + +#: views/packages/main/s2.scan3.php:513 +msgid "The database user for this WordPress site does NOT sufficient permissions to write stored procedures or functions to the sql file of the archive. Stored procedures will not be added to the sql file." +msgstr "" + +#: views/packages/main/s2.scan3.php:532 +msgid "Total Size" +msgstr "" + +#: views/packages/main/s2.scan3.php:537 +msgid "Total Size:" +msgstr "" + +#: views/packages/main/s2.scan3.php:538 +msgid "The total size of the site (files plus database)." +msgstr "" + +#: views/packages/main/s2.scan3.php:548 +#, php-format +msgid "The build can't continue because the total size of files and the database exceeds the %s limit that can be processed when creating a DupArchive package. " +msgstr "" + +#: views/packages/main/s2.scan3.php:550 +msgid "Click for recommendations." +msgstr "" + +#: views/packages/main/s2.scan3.php:555 views/packages/main/s2.scan3.php:719 +#: views/settings/packages.php:254 +msgid "Archive Engine" +msgstr "" + +#: views/packages/main/s2.scan3.php:556 +#, php-format +msgid "The %s is set to create packages in the 'DupArchive' format. This custom format is used to overcome budget host constraints. With DupArchive, Duplicator is restricted to processing sites up to %s. To process larger sites, consider these recommendations. " +msgstr "" + +#: views/packages/main/s2.scan3.php:566 +msgid "Step 1" +msgstr "" + +#: views/packages/main/s2.scan3.php:567 +#, php-format +msgid "- Add data filters to get the package size under %s: " +msgstr "" + +#: views/packages/main/s2.scan3.php:569 +msgid "- In the 'Size Checks' section above consider adding filters (if notice is shown)." +msgstr "" + +#: views/packages/main/s2.scan3.php:571 +#, php-format +msgid "- In %s consider adding file/directory or database table filters." +msgstr "" + +#: views/packages/main/s2.scan3.php:577 +#, php-format +msgid "- Perform a two part install as %1$sdescribed in the documentation%2$s." +msgstr "" + +#: views/packages/main/s2.scan3.php:586 +msgid "ZipArchive Engine" +msgstr "" + +#: views/packages/main/s2.scan3.php:587 +#, php-format +msgid "- Switch to the %s which requires a capable hosting provider (VPS recommended)." +msgstr "" + +#: views/packages/main/s2.scan3.php:591 +#, php-format +msgid "- Consider upgrading to %s for unlimited large site support." +msgstr "" + +#: views/packages/main/s2.scan3.php:603 +msgid "Mysqldump memory check" +msgstr "" + +#: views/packages/main/s2.scan3.php:616 +msgid "The database size is within the allowed mysqldump size limit." +msgstr "" + +#: views/packages/main/s2.scan3.php:621 +#, php-format +msgid "If you encounter any issues with mysqldump please change the setting SQL Mode to PHP Code. You can do that by opening %1$sDuplicator Pro > Settings > Packages.%2$s" +msgstr "" + +#: views/packages/main/s2.scan3.php:634 +msgid "The database size exceeds the allowed mysqldump size limit." +msgstr "" + +#: views/packages/main/s2.scan3.php:638 +msgid "The database size is larger than the PHP memory_limit value. This can lead into issues when building a package, during which the system can run out of memory. To fix this issue please consider doing one of the below mentioned recommendations." +msgstr "" + +#: views/packages/main/s2.scan3.php:653 +#, php-format +msgid "Please change the setting SQL Mode to PHP Code. You can do that by opening %1$sDuplicator Pro > Settings > Packages.%2$s" +msgstr "" + +#: views/packages/main/s2.scan3.php:667 +#, php-format +msgid "If you want to build the package with mysqldump, increase the PHP memory_limit value in your php.ini file to at least %1$s." +msgstr "" + +#: views/packages/main/s2.scan3.php:684 +msgid "Migrate large, multi-gig sites with" +msgstr "" + +#: views/packages/main/s2.scan3.php:699 +msgid "Scan Details" +msgstr "" + +#: views/packages/main/s2.scan3.php:706 +msgid "Copy Quick Filter Paths" +msgstr "" + +#: views/packages/main/s2.scan3.php:725 +msgid "Name:" +msgstr "" + +#: views/packages/main/s2.scan3.php:726 +msgid "Host:" +msgstr "" + +#: views/packages/main/s2.scan3.php:728 +msgid "Build Mode:" +msgstr "" + +#: views/packages/main/s2.scan3.php:744 +msgid "File Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:745 +#: views/tools/diagnostics/inc.settings.php:178 +msgid "Disabled" +msgstr "" + +#: views/packages/main/s2.scan3.php:759 +msgid "No custom directory filters set." +msgstr "" + +#: views/packages/main/s2.scan3.php:769 +msgid "No file extension filters have been set." +msgstr "" + +#: views/packages/main/s2.scan3.php:781 +msgid "No custom file filters set." +msgstr "" + +#: views/packages/main/s2.scan3.php:785 +msgid "Auto Directory Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:791 +msgid "Auto File Filters" +msgstr "" + +#: views/packages/main/s2.scan3.php:804 +msgid "Path filters will be skipped during the archive process when enabled." +msgstr "" + +#: views/packages/main/s2.scan3.php:806 +msgid "[view json result report]" +msgstr "" + +#: views/packages/main/s2.scan3.php:809 +msgid "Auto filters are applied to prevent archiving other backup sets." +msgstr "" + +#: views/packages/main/s2.scan3.php:820 views/packages/main/s2.scan3.php:829 +msgid "Click to Copy" +msgstr "" + +#: views/packages/main/s2.scan3.php:834 +msgid "Copy the paths above and apply them as needed on Step 1 > Archive > Files section." +msgstr "" + +#: views/packages/main/s2.scan3.php:851 +msgid "Directory applied filter set." +msgstr "" + +#: views/packages/main/s2.scan3.php:878 +msgid "No directories have been selected!" +msgstr "" + +#: views/packages/main/s2.scan3.php:882 +msgid "No files have been selected!" +msgstr "" + +#: views/packages/main/s2.scan3.php:920 +msgid "Copied to Clipboard!" +msgstr "" + +#: views/packages/main/s2.scan3.php:922 +msgid "Manual copy of selected text required on this browser." +msgstr "" + +#: views/packages/main/s2.scan3.php:929 +msgid "Initializing Please Wait..." +msgstr "" + +#: views/packages/main/s2.scan3.php:972 views/packages/main/s2.scan3.php:979 +msgid "Error applying filters. Please go back to Step 1 to add filter manually!" +msgstr "" + +#: views/packages/main/s2.scan3.php:1091 +msgid "Unable to report on any tables" +msgstr "" + +#: views/packages/main/s2.scan3.php:1117 +msgid "Unable to report on database stats" +msgstr "" + +#: views/packages/main/s3.build.php:21 +msgid "When clicking the Installer download button, the 'Save as' dialog will default the name to 'installer.php'. To improve the security and get more information, goto: Settings ❯ Packages Tab ❯ Installer Name option." +msgstr "" + +#: views/packages/main/s3.build.php:24 +msgid "When clicking the Installer download button, the 'Save as' dialog will save the name as '[name]_[hash]_[time]_installer.php'. This is the secure and recommended option. For more information goto: Settings ❯ Packages Tab ❯ Installer Name Option. To quickly copy the hashed installer name, to your clipboard use the copy icon link." +msgstr "" + +#: views/packages/main/s3.build.php:117 +msgid "Step 3: Build and download the package files." +msgstr "" + +#: views/packages/main/s3.build.php:150 +msgid "Building Package" +msgstr "" + +#: views/packages/main/s3.build.php:153 +msgid "Keep this window open and do not close during the build process." +msgstr "" + +#: views/packages/main/s3.build.php:154 +msgid "This may take several minutes to complete." +msgstr "" + +#: views/packages/main/s3.build.php:160 +msgid "Build Status" +msgstr "" + +#: views/packages/main/s3.build.php:167 +msgid "Package Build Completed" +msgstr "" + +#: views/packages/main/s3.build.php:171 +msgid "Build Time" +msgstr "" + +#: views/packages/main/s3.build.php:177 +msgid "Download Package Files" +msgstr "" + +#: views/packages/main/s3.build.php:179 +msgid "Click to download installer file" +msgstr "" + +#: views/packages/main/s3.build.php:182 +msgid "Click to download archive file" +msgstr "" + +#: views/packages/main/s3.build.php:187 +msgid "Click to download both files" +msgstr "" + +#: views/packages/main/s3.build.php:189 +msgid "Download Both Files" +msgstr "" + +#: views/packages/main/s3.build.php:193 +msgid "Download Both Files:" +msgstr "" + +#: views/packages/main/s3.build.php:194 +msgid "Clicking this button will open the installer and archive download prompts one after the other with one click verses downloading each file separately with two clicks. On some browsers you may have to disable pop-up warnings on this domain for this to work correctly." +msgstr "" + +#: views/packages/main/s3.build.php:204 +msgid "[Copy Installer Name to Clipboard]" +msgstr "" + +#: views/packages/main/s3.build.php:209 +msgid "[Show Installer Name]" +msgstr "" + +#: views/packages/main/s3.build.php:225 +msgid "Notice:Duplicator Lite does not officially support WordPress multisite." +msgstr "" + +#: views/packages/main/s3.build.php:235 +msgid "How to install this package?" +msgstr "" + +#: views/packages/main/s3.build.php:244 +msgid "Install to Empty Directory " +msgstr "" + +#: views/packages/main/s3.build.php:253 +msgid "Install to an empty directory like a new WordPress install does." +msgstr "" + +#: views/packages/main/s3.build.php:260 +msgid "Overwrite Site" +msgstr "" + +#: views/packages/main/s3.build.php:267 +msgid "Quickly overwrite an existing WordPress site in a few clicks." +msgstr "" + +#: views/packages/main/s3.build.php:274 +msgid "Import Archive and Overwrite Site" +msgstr "" + +#: views/packages/main/s3.build.php:280 +msgid "Drag and drop or use a URL for super-fast installs (requires Pro*)" +msgstr "" + +#: views/packages/main/s3.build.php:297 +msgid "Host Build Interrupt" +msgstr "" + +#: views/packages/main/s3.build.php:298 +msgid "This server cannot complete the build due to host setup constraints, see the error message for more details." +msgstr "" + +#: views/packages/main/s3.build.php:299 +msgid "If the error details are not specific consider the options below by clicking each section." +msgstr "" + +#: views/packages/main/s3.build.php:306 +msgid "Option 1: DupArchive" +msgstr "" + +#: views/packages/main/s3.build.php:311 +msgid "Enable the DupArchive format which is specific to Duplicator and designed to perform better on constrained budget hosts." +msgstr "" + +#: views/packages/main/s3.build.php:316 +msgid "Note:DupArchive on Duplicator only supports sites up to 500MB. If your site is over 500MB then use a file filter on step 1 to get the size below 500MB or try the other options mentioned below. Alternatively, you may want to consider" +msgstr "" + +#: views/packages/main/s3.build.php:323 +msgid " which is capable of migrating sites much larger than 500MB." +msgstr "" + +#: views/packages/main/s3.build.php:327 views/packages/main/s3.build.php:399 +msgid "Please follow these steps:" +msgstr "" + +#: views/packages/main/s3.build.php:329 +msgid "On the scanner step check to make sure your package is under 500MB. If not see additional options below." +msgstr "" + +#: views/packages/main/s3.build.php:331 +msgid "Go to Duplicator > Settings > Packages Tab > Archive Engine >" +msgstr "" + +#: views/packages/main/s3.build.php:332 +msgid "Enable DupArchive" +msgstr "" + +#: views/packages/main/s3.build.php:334 +msgid "Build a new package using the new engine format." +msgstr "" + +#: views/packages/main/s3.build.php:338 +msgid "Note:The DupArchive engine will generate an archive.daf file. This file is very similar to a .zip except that it can only be extracted by the installer.php file or the" +msgstr "" + +#: views/packages/main/s3.build.php:341 +msgid "commandline extraction tool" +msgstr "" + +#: views/packages/main/s3.build.php:351 +msgid "Option 2: File Filters" +msgstr "" + +#: views/packages/main/s3.build.php:356 +msgid "The first pass for reading files on some budget hosts maybe slow and have conflicts with strict timeout settings setup by the hosting provider. In these cases, it is recommended to retry the build by adding file filters to larger files/directories." +msgstr "" + +#: views/packages/main/s3.build.php:361 +msgid "For example, you could filter out the \"/wp-content/uploads/\" folder to create the package then move the files from that directory over manually. If this work-flow is not desired or does not work please check-out the other options below." +msgstr "" + +#: views/packages/main/s3.build.php:366 +msgid "Retry Build With Filters" +msgstr "" + +#: views/packages/main/s3.build.php:374 +msgid "Build Folder:" +msgstr "" + +#: views/packages/main/s3.build.php:376 +msgid "On some servers the build will continue to run in the background. To validate if a build is still running; open the 'tmp' folder above and see if the archive file is growing in size or check the main packages screen to see if the package completed. If it is not then your server has strict timeout constraints." +msgstr "" + +#: views/packages/main/s3.build.php:389 +msgid "Option 3: Two-Part Install" +msgstr "" + +#: views/packages/main/s3.build.php:394 +msgid "A two-part install minimizes server load and can avoid I/O and CPU issues encountered on some budget hosts. With this procedure you simply build a 'database-only' archive, manually move the website files, and then run the installer to complete the process." +msgstr "" + +#: views/packages/main/s3.build.php:398 +msgid " Overview" +msgstr "" + +#: views/packages/main/s3.build.php:401 +msgid "Click the button below to go back to Step 1." +msgstr "" + +#: views/packages/main/s3.build.php:402 +msgid "On Step 1 the \"Archive Only the Database\" checkbox will be auto checked." +msgstr "" + +#: views/packages/main/s3.build.php:420 +msgid "Yes. I have read the above overview and would like to continue!" +msgstr "" + +#: views/packages/main/s3.build.php:422 +msgid "Start Two-Part Install Process" +msgstr "" + +#: views/packages/main/s3.build.php:432 +msgid "Option 4: Configure Server" +msgstr "" + +#: views/packages/main/s3.build.php:436 +msgid "OPTION 4:" +msgstr "" + +#: views/packages/main/s3.build.php:437 +msgid "This option is available on some hosts that allow for users to adjust server configurations. With this option you will be directed to an FAQ page that will show various recommendations you can take to improve/unlock constraints set up on this server." +msgstr "" + +#: views/packages/main/s3.build.php:446 +msgid "Diagnose Server Setup" +msgstr "" + +#: views/packages/main/s3.build.php:450 +msgid "RUNTIME DETAILS" +msgstr "" + +#: views/packages/main/s3.build.php:453 +msgid "Allowed Runtime:" +msgstr "" + +#: views/packages/main/s3.build.php:457 +msgid "PHP Max Execution" +msgstr "" + +#: views/packages/main/s3.build.php:467 +msgid "This value is represented in seconds. A value of 0 means no timeout limit is set for PHP." +msgstr "" + +#: views/packages/main/s3.build.php:471 views/settings/packages.php:208 +msgid "Mode" +msgstr "" + +#: views/packages/main/s3.build.php:477 +msgid "PHP Max Execution Mode" +msgstr "" + +#: views/packages/main/s3.build.php:479 +msgid "If the value is [dynamic] then its possible for PHP to run longer than the default. If the value is [fixed] then PHP will not be allowed to run longer than the default.

                        If this value is larger than the [Allowed Runtime] above then the web server has been enabled with a timeout cap and is overriding the PHP max time setting." +msgstr "" + +#: views/packages/main/s3.build.php:487 +msgid "unavailable" +msgstr "" + +#: views/packages/main/s3.build.php:499 +msgid "System Details" +msgstr "" + +#: views/packages/main/s3.build.php:506 +msgid "Error status unavailable." +msgstr "" + +#: views/packages/main/s3.build.php:514 +msgid "See Package Log For Complete Details" +msgstr "" + +#: views/packages/screen.php:76 +msgid " Packages » All
                        The 'Packages' section is the main interface for managing all the packages that have been created. A Package consists of two core files, the 'archive.zip' and the 'installer.php' file. The archive file is a zip file containing all your WordPress files and a copy of your WordPress database. The installer file is a php file that when browsed to via a web browser presents a wizard that redeploys/installs the website by extracting the archive file and installing the database. To create a package, click the 'Create New' button and follow the prompts.

                        Downloads
                        To download the package files click on the Installer and Archive buttons after creating a package. The archive file will have a copy of the installer inside of it named installer-backup.php in case the original installer file is lost. To see the details of a package click on the details button.

                        Archive Types
                        An archive file can be saved as either a .zip file or .daf file. A zip file is a common archive format used to compress and group files. The daf file short for 'Duplicator Archive Format' is a custom format used specifically for working with larger packages and scale-ability issues on many shared hosting platforms. Both formats work very similar. The main difference is that the daf file can only be extracted using the installer.php file or the

                        To exclude a database table, check the box labeled 'Enable Table Filters' and check the table name to exclude. To include only a copy of your database in the archive file check the box labeled 'Archive Only the Database'. The installer.php file can optionally be pre-filled with data at install time but is not required.

                        " +msgstr "" + +#: views/packages/screen.php:133 +msgid "Packages » 3 Build
                        The final step in the build process where the installer script and archive of the website can be downloaded. To start the install process follow these steps:
                        1. Download the installer.php and archive.zip files to your local computer.
                        2. For localhost installs be sure you have PHP, Apache & MySQL installed on your local computer with software such as XAMPP, Instant WordPress or MAMP for MAC. Place the package.zip and installer.php into any empty directory under your webroot then browse to the installer.php via your web browser to launch the install wizard.
                        3. For remote installs use FTP or cPanel to upload both the archive.zip and installer.php to your hosting provider. Place the files in a new empty directory under your host's webroot accessible from a valid URL such as http://your-domain/your-wp-directory/installer.php to launch the install wizard. On some hosts the root directory will be a something like public_html -or- www. If your're not sure contact your hosting provider.
                        For complete instructions see:
                        upgrading to PRO." +msgstr "" + +#: views/settings/license.php:63 +#, php-format +msgid "As a valued Duplicator Lite user you receive %1$d%% off, automatically applied at checkout!" +msgstr "" + +#: views/settings/license.php:72 +msgid "Already purchased? Simply enter your license key below to enable Duplicator PRO!" +msgstr "" + +#: views/settings/license.php:74 +msgid "Paste license key here" +msgstr "" + +#: views/settings/license.php:75 +msgid "One click Upgrade to Pro" +msgstr "" + +#: views/settings/packages.php:14 +msgid "Package Settings Saved" +msgstr "" + +#: views/settings/packages.php:99 +msgid "Mysqldump" +msgstr "" + +#: views/settings/packages.php:109 +msgid "PHP Code" +msgstr "" + +#: views/settings/packages.php:119 +msgid "This server does not support the PHP shell_exec or exec function which is required for mysqldump to run. " +msgstr "" + +#: views/settings/packages.php:120 +msgid "Please contact the host or server administrator to enable this feature." +msgstr "" + +#: views/settings/packages.php:125 views/tools/diagnostics/logging.php:183 +msgid "Host Recommendation:" +msgstr "" + +#: views/settings/packages.php:126 views/tools/diagnostics/logging.php:184 +msgid "Duplicator recommends going with the high performance pro plan or better from our recommended list" +msgstr "" + +#: views/settings/packages.php:131 +#, php-format +msgid "Please visit our recommended %1$shost list%2$s for reliable access to mysqldump." +msgstr "" + +#: views/settings/packages.php:150 +msgid "Successfully Found:" +msgstr "" + +#: views/settings/packages.php:157 +msgid "Mysqldump was not found at its default location or the location provided. Please enter a custom path to a valid location where mysqldump can run. If the problem persist contact your host or server administrator. " +msgstr "" + +#: views/settings/packages.php:162 +#, php-format +msgid "See the %1$shost list%2$s for reliable access to mysqldump." +msgstr "" + +#: views/settings/packages.php:175 +msgid "Custom Path" +msgstr "" + +#: views/settings/packages.php:177 +msgid "mysqldump path:" +msgstr "" + +#: views/settings/packages.php:179 +msgid "Add a custom path if the path to mysqldump is not properly detected. For all paths use a forward slash as the path seperator. On Linux systems use mysqldump for Windows systems use mysqldump.exe. If the path tried does not work please contact your hosting provider for details on the correct path." +msgstr "" + +#: views/settings/packages.php:188 +msgid "/usr/bin/mypath/mysqldump" +msgstr "" + +#: views/settings/packages.php:193 +msgid " The custom path provided is not recognized as a valid mysqldump file:
                        " +msgstr "" + +#: views/settings/packages.php:211 +msgid "Single-Threaded" +msgstr "" + +#: views/settings/packages.php:214 +msgid "Multi-Threaded (Pro)" +msgstr "" + +#: views/settings/packages.php:218 +msgid "PHP Code Mode:" +msgstr "" + +#: views/settings/packages.php:220 +msgid "Single-Threaded mode attempts to create the entire database script in one request. Multi-Threaded mode allows the database script to be chunked over multiple requests. Multi-Threaded mode is typically slower but much more reliable especially for larger databases." +msgstr "" + +#: views/settings/packages.php:222 +msgid "

                        Multi-Threaded mode is only available in Duplicator Pro." +msgstr "" + +#: views/settings/packages.php:225 +msgid "Query Limit Size" +msgstr "" + +#: views/settings/packages.php:235 +msgid "PHP Query Limit Size" +msgstr "" + +#: views/settings/packages.php:237 +msgid "A higher limit size will speed up the database build time, however it will use more memory. If your host has memory caps start off low." +msgstr "" + +#: views/settings/packages.php:259 +msgid "ZipArchive" +msgstr "" + +#: views/settings/packages.php:265 +msgid "DupArchive" +msgstr "" + +#: views/settings/packages.php:273 +msgid "Creates a archive format (archive.zip)." +msgstr "" + +#: views/settings/packages.php:276 +msgid "This option uses the internal PHP ZipArchive classes to create a zip file." +msgstr "" + +#: views/settings/packages.php:278 +msgid "Duplicator Lite has no fixed size constraints for zip formats. The only constraints are timeouts on the server." +msgstr "" + +#: views/settings/packages.php:288 +msgid "Creates a custom archive format (archive.daf)." +msgstr "" + +#: views/settings/packages.php:291 +msgid "This option is recommended for large sites or sites on constrained servers." +msgstr "" + +#: views/settings/packages.php:292 +msgid "Duplicator Lite has a fixed constraint of 500MB for daf formats." +msgstr "" + +#: views/settings/packages.php:296 +#, php-format +msgid "Consider upgrading to %1$sDuplicator Pro%2$s for unlimited large site support with DupArchive." +msgstr "" + +#: views/settings/packages.php:310 +msgid "Archive Flush" +msgstr "" + +#: views/settings/packages.php:313 +msgid "Attempt Network Keep Alive" +msgstr "" + +#: views/settings/packages.php:314 +msgid "enable only for large archives" +msgstr "" + +#: views/settings/packages.php:317 +msgid "This will attempt to keep a network connection established for large archives." +msgstr "" + +#: views/settings/packages.php:319 +msgid " Valid only when Archive Engine for ZipArchive is enabled." +msgstr "" + +#: views/settings/packages.php:330 +msgid "File Name" +msgstr "" + +#: views/settings/packages.php:332 +msgid "Default 'Save as' name:" +msgstr "" + +#: views/settings/packages.php:347 +msgid "Secure" +msgstr "" + +#: views/settings/packages.php:348 +msgid "recommended" +msgstr "" + +#: views/settings/packages.php:351 +msgid "To understand the importance and usage of the installer name, please" +msgstr "" + +#: views/settings/packages.php:352 +msgid "read this section" +msgstr "" + +#: views/settings/packages.php:356 +msgid "Using a 'Secure' file helps prevent unauthorized access to the installer file." +msgstr "" + +#: views/settings/packages.php:357 +msgid "Example" +msgstr "" + +#: views/settings/packages.php:362 +msgid "This setting specifies the name of the installer used at download-time. Independent of the value of this setting, you can change the name of the installer in the \"Save as\" file dialog at download-time. If you choose to use a custom name, use a file name that is known only to you. Installer filenames must end in \"php\". Changes to the archive file should not be made." +msgstr "" + +#: views/settings/packages.php:372 +msgid "Do not to leave any installer files on the destination server, after installing the migrated/restored site. Logon as a WordPress administrator and follow the prompts to remove the installer files or remove them manually." +msgstr "" + +#: views/settings/packages.php:380 +msgid "Tip: Each row on the packages screen includes a copy button to copy the installer name to the clipboard. Paste the installer name from the clipboard into the URL being used to install the destination site. This feature is handy when using the secure installer name." +msgstr "" + +#: views/settings/packages.php:391 +msgid "Visuals" +msgstr "" + +#: views/settings/packages.php:395 +msgid "Created Format" +msgstr "" + +#: views/settings/packages.php:399 +msgid "By Year" +msgstr "" + +#: views/settings/packages.php:406 +msgid "By Month" +msgstr "" + +#: views/settings/packages.php:413 +msgid "By Day" +msgstr "" + +#: views/settings/packages.php:421 +msgid "The UTC date format shown in the 'Created' column on the Packages screen." +msgstr "" + +#: views/settings/packages.php:422 +msgid "To use WordPress timezone formats consider an upgrade to Duplicator Pro." +msgstr "" + +#: views/settings/packages.php:431 +msgid "Save Package Settings" +msgstr "" + +#: views/settings/storage.php:16 +msgid "Storage Settings Saved" +msgstr "" + +#: views/settings/storage.php:42 +msgid "Storage folder move problem" +msgstr "" + +#: views/settings/storage.php:45 +#, php-format +msgid "Duplicator can't change the storage folder to %s" +msgstr "" + +#: views/settings/storage.php:46 +#, php-format +msgid "Check the parent folder permissions. ( %s )" +msgstr "" + +#: views/settings/storage.php:78 +msgid "Legacy Path:" +msgstr "" + +#: views/settings/storage.php:87 +msgid "Contents Path:" +msgstr "" + +#: views/settings/storage.php:93 +msgid "The storage location is where all package files are stored to disk. If your host has troubles writing content to the 'Legacy Path' then use the 'Contents Path'. Upon clicking the save button all files are moved to the new location and the previous path is removed." +msgstr "" + +#: views/settings/storage.php:98 +msgid "More Advanced Storage Options..." +msgstr "" + +#: views/settings/storage.php:103 +msgid "Apache .htaccess" +msgstr "" + +#: views/settings/storage.php:106 +msgid "Disable .htaccess file in storage directory" +msgstr "" + +#: views/settings/storage.php:109 +msgid "When checked this setting will prevent Duplicator from laying down an .htaccess file in the storage location above." +msgstr "" + +#: views/settings/storage.php:110 +msgid "Only disable this option if issues occur when downloading either the installer/archive files." +msgstr "" + +#: views/settings/storage.php:118 +msgid "Save Storage Settings" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:11 +msgid "Stored Data" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:16 +msgid "Data Cleanup" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:21 +msgid "Remove Installation Files" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:25 +msgid "Removes all reserved installer files." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:30 +msgid "Clicking on the 'Remove Installation Files' button will attempt to remove the installer files used by Duplicator. These files should not be left on production systems for security reasons. Below are the files that should be removed." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:45 +msgid "Clear Build Cache" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:48 +msgid "Removes all build data from:" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:53 +msgid "Options Values" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:87 +msgid "Delete Option?" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:88 +msgid "Delete the option value just selected?" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:89 +msgid "Removing Option, Please Wait..." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:94 +msgid "Clear Build Cache?" +msgstr "" + +#: views/tools/diagnostics/inc.data.php:95 +msgid "This process will remove all build cache files. Be sure no packages are currently building or else they will be cancelled." +msgstr "" + +#: views/tools/diagnostics/inc.data.php:107 +msgid "Delete the option value" +msgstr "" + +#: views/tools/diagnostics/inc.phpinfo.php:26 +msgid "PHP Information" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:5 +#: views/tools/diagnostics/inc.settings.php:6 +msgid "unknow" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:29 +msgid "Server Settings" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:38 +msgid "Duplicator Version" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:44 +msgid "Operating System" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:49 +msgid "Timezone" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:54 +msgid "Server Time" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:69 +msgid "ABSPATH" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:73 +msgid "Plugins Path" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:77 +msgid "Loaded PHP INI" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:81 +msgid "Server IP" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:88 +msgid "Can't detect" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:94 +msgid "Client IP" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:105 +msgid "Language" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:113 +msgid "Memory Limit " +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:114 +msgid "Max" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:133 +msgid "Process" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:137 +msgid "Safe Mode" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:141 +msgid "On" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:141 +msgid "Off" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:146 +msgid "Memory Limit" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:150 +msgid "Memory In Use" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:154 +#: views/tools/diagnostics/inc.settings.php:163 +msgid "Max Execution Time" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:164 +msgid "If the value shows dynamic then this means its possible for PHP to run longer than the default. If the value is fixed then PHP will not be allowed to run longer than the default." +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:169 +msgid "Shell Exec" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:170 +#: views/tools/diagnostics/inc.settings.php:174 +msgid "Is Supported" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:170 +#: views/tools/diagnostics/inc.settings.php:174 +msgid "Not Supported" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:173 +msgid "Shell Exec Zip" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:177 +msgid "Suhosin Extension" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:181 +msgid "Architecture " +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:187 +msgid "Error Log File " +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:198 +msgid "Comments" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:206 +msgid "Wait Timeout" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:210 +msgid "Max Allowed Packets" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:214 +msgid "msyqldump Path" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:218 +msgid "Server Disk" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:221 +msgid "Free space" +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:224 +msgid "Unable to calculate space on this server." +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:230 +msgid "Note: This value is the physical servers hard-drive allocation." +msgstr "" + +#: views/tools/diagnostics/inc.settings.php:231 +msgid "On shared hosts check your control panel for the 'TRUE' disk space quota value." +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:16 +msgid "Run Validator" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:17 +msgid "This will run the scan validation check. This may take several minutes. Do you want to Continue?" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:28 +msgid "Scan Validator" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:33 +msgid "This utility will help to find unreadable files and sys-links in your environment that can lead to issues during the scan process. " +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:34 +msgid "The utility will also shows how many files and directories you have in your system. This process may take several minutes to run. " +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:35 +msgid "If there is a recursive loop on your system then the process has a built in check to stop after a large set of files and directories have been scanned. " +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:36 +msgid "A message will show indicated that that a scan depth has been reached. If you have issues with the package scanner (step 2) during the build process then try to add The paths below to your file filters to allow the scanner to finish." +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:43 +#: views/tools/diagnostics/inc.validator.php:157 +msgid "Run Scan Integrity Validation" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:77 +msgid "Note: Symlinks are not discoverable on Windows OS with PHP" +msgstr "" + +#: views/tools/diagnostics/inc.validator.php:126 +msgid "Scanning Environment... This may take a few minutes." +msgstr "" + +#: views/tools/diagnostics/information.php:27 +msgid "File Found: Unable to remove" +msgstr "" + +#: views/tools/diagnostics/information.php:43 +msgid "Build cache removed." +msgstr "" + +#: views/tools/diagnostics/information.php:62 +msgid "Plugin settings reset." +msgstr "" + +#: views/tools/diagnostics/information.php:65 +msgid "View state settings reset." +msgstr "" + +#: views/tools/diagnostics/information.php:68 +msgid "Active package settings reset." +msgstr "" + +#: views/tools/diagnostics/logging.php:169 +msgid "Log file not found or unreadable" +msgstr "" + +#: views/tools/diagnostics/logging.php:170 +msgid "Try to create a package, since no log files were found in the snapshots directory with the extension *.log" +msgstr "" + +#: views/tools/diagnostics/logging.php:171 +msgid "Reasons for log file not showing" +msgstr "" + +#: views/tools/diagnostics/logging.php:172 +msgid "The web server does not support returning .log file extentions" +msgstr "" + +#: views/tools/diagnostics/logging.php:173 +msgid "The snapshots directory does not have the correct permissions to write files. Try setting the permissions to 755" +msgstr "" + +#: views/tools/diagnostics/logging.php:174 +msgid "The process that PHP runs under does not have enough permissions to create files. Please contact your hosting provider for more details" +msgstr "" + +#: views/tools/diagnostics/logging.php:190 +#, php-format +msgid "Consider our recommended %1$shost list%2$s if you’re unhappy with your current provider" +msgstr "" + +#: views/tools/diagnostics/logging.php:200 +#: views/tools/diagnostics/logging.php:205 +msgid "Options" +msgstr "" + +#: views/tools/diagnostics/logging.php:207 +msgid "Refresh" +msgstr "" + +#: views/tools/diagnostics/logging.php:210 +msgid "Auto Refresh" +msgstr "" + +#: views/tools/diagnostics/logging.php:216 +msgid "Package Logs" +msgstr "" + +#: views/tools/diagnostics/logging.php:217 +msgid "Top 20" +msgstr "" + +#: views/tools/diagnostics/main.php:43 +msgid "Information" +msgstr "" + +#: views/tools/diagnostics/main.php:44 +msgid "Logs" +msgstr "" + +#: views/tools/diagnostics/support.php:36 +msgid "Migrating WordPress is a complex process and the logic to make all the magic happen smoothly may not work quickly with every site. With over 30,000 plugins and a very complex server eco-system some migrations may run into issues. This is why the Duplicator includes a detailed knowledgebase that can help with many common issues. Resources to additional support, approved hosting, and alternatives to fit your needs can be found below." +msgstr "" + +#: views/tools/diagnostics/support.php:51 +msgid "Knowledgebase" +msgstr "" + +#: views/tools/diagnostics/support.php:54 +msgid "Complete Online Documentation" +msgstr "" + +#: views/tools/diagnostics/support.php:58 +msgid "Choose A Section" +msgstr "" + +#: views/tools/diagnostics/support.php:63 +msgid "Quick Start" +msgstr "" + +#: views/tools/diagnostics/support.php:66 +msgid "User Guide" +msgstr "" + +#: views/tools/diagnostics/support.php:71 +msgid "FAQs" +msgstr "" + +#: views/tools/diagnostics/support.php:74 +msgid "Change Log" +msgstr "" + +#: views/tools/diagnostics/support.php:84 +msgid "Premium Support" +msgstr "" + +#: views/tools/diagnostics/support.php:87 +msgid "Having a problem with your back up or migrations? Upgrade to get our Premium Support." +msgstr "" diff --git a/languages/index.php b/languages/index.php new file mode 100644 index 00000000..e0ee5083 --- /dev/null +++ b/languages/index.php @@ -0,0 +1,3 @@ + + * @package Encoding + * @version 2.0 + * @link https://github.com/neitanod/forceutf8 + * @example https://github.com/neitanod/forceutf8 + * @license Revised BSD + */ + +//namespace ForceUTF8; +if (!class_exists('DUP_Encoding')) { + class DUP_Encoding + { + const ICONV_TRANSLIT = "TRANSLIT"; + const ICONV_IGNORE = "IGNORE"; + const WITHOUT_ICONV = ""; + protected static $win1252ToUtf8 = array( + 128 => "\xe2\x82\xac", + + 130 => "\xe2\x80\x9a", + 131 => "\xc6\x92", + 132 => "\xe2\x80\x9e", + 133 => "\xe2\x80\xa6", + 134 => "\xe2\x80\xa0", + 135 => "\xe2\x80\xa1", + 136 => "\xcb\x86", + 137 => "\xe2\x80\xb0", + 138 => "\xc5\xa0", + 139 => "\xe2\x80\xb9", + 140 => "\xc5\x92", + 142 => "\xc5\xbd", + 145 => "\xe2\x80\x98", + 146 => "\xe2\x80\x99", + 147 => "\xe2\x80\x9c", + 148 => "\xe2\x80\x9d", + 149 => "\xe2\x80\xa2", + 150 => "\xe2\x80\x93", + 151 => "\xe2\x80\x94", + 152 => "\xcb\x9c", + 153 => "\xe2\x84\xa2", + 154 => "\xc5\xa1", + 155 => "\xe2\x80\xba", + 156 => "\xc5\x93", + + 158 => "\xc5\xbe", + 159 => "\xc5\xb8" + ); + protected static $brokenUtf8ToUtf8 = array( + "\xc2\x80" => "\xe2\x82\xac", + + "\xc2\x82" => "\xe2\x80\x9a", + "\xc2\x83" => "\xc6\x92", + "\xc2\x84" => "\xe2\x80\x9e", + "\xc2\x85" => "\xe2\x80\xa6", + "\xc2\x86" => "\xe2\x80\xa0", + "\xc2\x87" => "\xe2\x80\xa1", + "\xc2\x88" => "\xcb\x86", + "\xc2\x89" => "\xe2\x80\xb0", + "\xc2\x8a" => "\xc5\xa0", + "\xc2\x8b" => "\xe2\x80\xb9", + "\xc2\x8c" => "\xc5\x92", + + "\xc2\x8e" => "\xc5\xbd", + + + "\xc2\x91" => "\xe2\x80\x98", + "\xc2\x92" => "\xe2\x80\x99", + "\xc2\x93" => "\xe2\x80\x9c", + "\xc2\x94" => "\xe2\x80\x9d", + "\xc2\x95" => "\xe2\x80\xa2", + "\xc2\x96" => "\xe2\x80\x93", + "\xc2\x97" => "\xe2\x80\x94", + "\xc2\x98" => "\xcb\x9c", + "\xc2\x99" => "\xe2\x84\xa2", + "\xc2\x9a" => "\xc5\xa1", + "\xc2\x9b" => "\xe2\x80\xba", + "\xc2\x9c" => "\xc5\x93", + + "\xc2\x9e" => "\xc5\xbe", + "\xc2\x9f" => "\xc5\xb8" + ); + protected static $utf8ToWin1252 = array( + "\xe2\x82\xac" => "\x80", + + "\xe2\x80\x9a" => "\x82", + "\xc6\x92" => "\x83", + "\xe2\x80\x9e" => "\x84", + "\xe2\x80\xa6" => "\x85", + "\xe2\x80\xa0" => "\x86", + "\xe2\x80\xa1" => "\x87", + "\xcb\x86" => "\x88", + "\xe2\x80\xb0" => "\x89", + "\xc5\xa0" => "\x8a", + "\xe2\x80\xb9" => "\x8b", + "\xc5\x92" => "\x8c", + + "\xc5\xbd" => "\x8e", + + + "\xe2\x80\x98" => "\x91", + "\xe2\x80\x99" => "\x92", + "\xe2\x80\x9c" => "\x93", + "\xe2\x80\x9d" => "\x94", + "\xe2\x80\xa2" => "\x95", + "\xe2\x80\x93" => "\x96", + "\xe2\x80\x94" => "\x97", + "\xcb\x9c" => "\x98", + "\xe2\x84\xa2" => "\x99", + "\xc5\xa1" => "\x9a", + "\xe2\x80\xba" => "\x9b", + "\xc5\x93" => "\x9c", + + "\xc5\xbe" => "\x9e", + "\xc5\xb8" => "\x9f" + ); + + public static function toUTF8($text) + { + /** + * Function \ForceUTF8\Encoding::toUTF8 + * + * This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8. + * + * It assumes that the encoding of the original string is either Windows-1252 or ISO 8859-1. + * + * It may fail to convert characters to UTF-8 if they fall into one of these scenarios: + * + * 1) when any of these characters: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß + * are followed by any of these: ("group B") + * ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶•¸¹º»¼½¾¿ + * For example: %ABREPRESENT%C9%BB. «REPRESENTÉ» + * The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB) + * is also a valid unicode character, and will be left unchanged. + * + * 2) when any of these: àáâãäåæçèéêëìíîï are followed by TWO chars from group B, + * 3) when any of these: ðñòó are followed by THREE chars from group B. + * + * @name toUTF8 + * @param string $text Any string. + * @return string The same string, UTF8 encoded + * + */ + + if (is_array($text)) { + foreach ($text as $k => $v) { + $text[$k] = self::toUTF8($v); + } + return $text; + } + + if (!is_string($text)) { + return $text; + } + + $max = self::strlen($text); + $buf = ""; + for ($i = 0; $i < $max; $i++) { + $c1 = $text[$i]; + if ($c1 >= "\xc0") { + //Should be converted to UTF8, if it's not UTF8 already + $c2 = $i + 1 >= $max ? "\x00" : $text[$i + 1]; + $c3 = $i + 2 >= $max ? "\x00" : $text[$i + 2]; + $c4 = $i + 3 >= $max ? "\x00" : $text[$i + 3]; + if ($c1 >= "\xc0" & $c1 <= "\xdf") { + //looks like 2 bytes UTF8 + if ($c2 >= "\x80" && $c2 <= "\xbf") { + //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2; + $i++; + } else { + //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } elseif ($c1 >= "\xe0" & $c1 <= "\xef") { + //looks like 3 bytes UTF8 + if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf") { + //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2 . $c3; + $i = $i + 2; + } else { + //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } elseif ($c1 >= "\xf0" & $c1 <= "\xf7") { + //looks like 4 bytes UTF8 + if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf") { + //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2 . $c3 . $c4; + $i = $i + 3; + } else { + //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } else { + //doesn't look like UTF8, but should be converted + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = (($c1 & "\x3f") | "\x80"); + $buf .= $cc1 . $cc2; + } + } elseif (($c1 & "\xc0") == "\x80") { + // needs conversion + if (isset(self::$win1252ToUtf8[ord($c1)])) { +//found in Windows-1252 special cases + $buf .= self::$win1252ToUtf8[ord($c1)]; + } else { + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = (($c1 & "\x3f") | "\x80"); + $buf .= $cc1 . $cc2; + } + } else { + // it doesn't need conversion + $buf .= $c1; + } + } + return $buf; + } + + public static function toWin1252($text, $option = self::WITHOUT_ICONV) + { + if (is_array($text)) { + foreach ($text as $k => $v) { + $text[$k] = self::toWin1252($v, $option); + } + return $text; + } elseif (is_string($text)) { + return self::utf8_decode($text, $option); + } else { + return $text; + } + } + + public static function toISO8859($text) + { + return self::toWin1252($text); + } + + public static function toLatin1($text) + { + return self::toWin1252($text); + } + + public static function fixUTF8($text, $option = self::WITHOUT_ICONV) + { + if (is_array($text)) { + foreach ($text as $k => $v) { + $text[$k] = self::fixUTF8($v, $option); + } + return $text; + } + + $last = ""; + while ($last <> $text) { + $last = $text; + $text = self::toUTF8(self::utf8_decode($text, $option)); + } + $text = self::toUTF8(self::utf8_decode($text, $option)); + return $text; + } + + public static function UTF8FixWin1252Chars($text) + { + // If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1 + // (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it. + // See: http://en.wikipedia.org/wiki/Windows-1252 + + return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text); + } + + public static function removeBOM($str = "") + { + if (substr($str, 0, 3) == pack("CCC", 0xef, 0xbb, 0xbf)) { + $str = substr($str, 3); + } + return $str; + } + + protected static function strlen($text) + { + if ((version_compare(PHP_VERSION, '7.2.0') >= 0)) { + return (function_exists('mb_strlen')) + ? mb_strlen($text, '8bit') + : strlen($text); + } else { + return (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload')) & 2) + ? mb_strlen($text, '8bit') + : strlen($text); + } + } + + public static function normalizeEncoding($encodingLabel) + { + $encoding = strtoupper($encodingLabel); + $encoding = preg_replace('/[^a-zA-Z0-9\s]/', '', $encoding); + $equivalences = array( + 'ISO88591' => 'ISO-8859-1', + 'ISO8859' => 'ISO-8859-1', + 'ISO' => 'ISO-8859-1', + 'LATIN1' => 'ISO-8859-1', + 'LATIN' => 'ISO-8859-1', + 'UTF8' => 'UTF-8', + 'UTF' => 'UTF-8', + 'WIN1252' => 'ISO-8859-1', + 'WINDOWS1252' => 'ISO-8859-1' + ); + if (empty($equivalences[$encoding])) { + return 'UTF-8'; + } + + return $equivalences[$encoding]; + } + + public static function encode($encodingLabel, $text) + { + $encodingLabel = self::normalizeEncoding($encodingLabel); + if ($encodingLabel == 'ISO-8859-1') { + return self::toLatin1($text); + } + return self::toUTF8($text); + } + + protected static function utf8_decode($text, $option) + { + if ($option == self::WITHOUT_ICONV || !function_exists('iconv')) { + $o = utf8_decode(str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text))); + } else { + $o = iconv("UTF-8", "Windows-1252" . ($option == self::ICONV_TRANSLIT ? '//TRANSLIT' : ($option == self::ICONV_IGNORE ? '//IGNORE' : '')), $text); + } + return $o; + } + } + +} diff --git a/lib/forceutf8/README.md b/lib/forceutf8/README.md new file mode 100644 index 00000000..d2131c3d --- /dev/null +++ b/lib/forceutf8/README.md @@ -0,0 +1,61 @@ +forceutf8 +========= + +PHP Class Encoding featuring popular \ForceUTF8\Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings. + +Description +=========== + +If you apply the PHP function utf8_encode() to an already-UTF8 string it will return a garbled UTF8 string. + +This class addresses this issue and provides a handy static function called \ForceUTF8\Encoding::toUTF8(). + +You don't need to know what the encoding of your strings is. It can be Latin1 (iso 8859-1), Windows-1252 or UTF8, or the string can have a mix of them. \ForceUTF8\Encoding::toUTF8() will convert everything to UTF8. + +Sometimes you have to deal with services that are unreliable in terms of encoding, possibly mixing UTF8 and Latin1 in the same string. + +Update: + +I've included another function, \ForceUTF8\Encoding::fixUTF8(), which will fix the double (or multiple) encoded UTF8 string that looks garbled. + +Usage: +====== + + use \ForceUTF8\Encoding; + + $utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string); + + $latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string); + +also: + + $utf8_string = Encoding::fixUTF8($garbled_utf8_string); + +Examples: + + use \ForceUTF8\Encoding; + + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + +will output: + + Fédération Camerounaise de Football + Fédération Camerounaise de Football + Fédération Camerounaise de Football + Fédération Camerounaise de Football + +Install via composer: +===================== +Edit your composer.json file to include the following: + +```json +{ + "require": { + "neitanod/forceutf8": "dev-master" + } +} +``` + diff --git a/lib/forceutf8/index.php b/lib/forceutf8/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/lib/forceutf8/index.php @@ -0,0 +1,3 @@ + The Duplicator gives WordPress administrators the ability to migrate, copy or clone a site from one location to another. The plugin also serves as a simple backup utility. The Duplicator supports both serialized and base64 serialized string replacement. If you need to move WordPress or backup WordPress this plugin can help simplify the process. For complete details visit [lifeinthegrid.com](http://lifeinthegrid.com/). - -= Quick Video Demo = -http://www.youtube.com/watch?v=yZ7pHmR9JC8 - -= Disclaimer = - This plugin does require above average technical knowledge. If you plan to move WordPress or backup WordPress please use it at your own risk and do not forget to back up your files and databases beforehand with other backup system. Please do not attempt to use the plugin if you're new to WordPress or have a limited technical background. Please seek out professional help if your in question of anything. If you need to move WordPress or backup WordPress and you don't have a firm grasp on using WordPress then you can get additional help from the Duplicator [resources page](http://lifeinthegrid.com/labs/duplicator/) . - -= Developers = - This tool is great to move WordPress or backup Wordpress sites and for pulling a production site down onto your local machine for testing and validation. It also works good for developing locally and then pushing up to a production server for a first time site release. - -= Please Note = -This project is currently in Beta, the underlying logic to backup WordPress, move WordPress and transfer WordPress are very complex. It's impossible to know how each system is setup; this is why your feedback is important to us. Thanks for helping us to make WordPress the best blogging platform in the world. - -= Active Contributors = -
                      • [Paal Joachim Romdahl](http://www.easywebdesigntutorials.com) (Training)
                      • -
                      • [Hans-M. Herbrand](http://www.web266.de) (German)
                      • -
                      • [Nicolas Richer](http://nicolasricher.fr) (French)
                      • - -= Other Contributors = -
                      • [Emilio De Fez](http://www.canaryas.com) (Spanish)
                      • -
                      • [Marco Andrei Kichalowsky](http://www.arsnovasolucoes.com) (Portuguese)
                      • -Jonathan Foote, Tomas Gurny, Aaron Crawford - -= Donate = -Enjoy using *Duplicator*? Please consider [making a donation](http://lifeinthegrid.com/partner/) to support the project's continued development. - - - -== Installation == - -1. Upload `duplicator` folder to the `/wp-content/plugins/` directory -2. Activate the plugin through the 'Plugins' menu in WordPress -3. Click on the Duplicator link from the main menu -4. Check out the help by clicking the help icon and create your first package. - -The Duplicator requires php 5.3 or higher. - -== Frequently Asked Questions == - -= I'm having issues getting the plugin to work what should I do? = - -See the [FAQs](http://lifeinthegrid.com/duplicator-faq) page for a detailed rundown of common issues - -= Are there any videos I can watch? = - -Yes. Please see the [tutorial section](http://lifeinthegrid.com/duplicator-tutorials] on the user guide for videos. - - -= Where can I get more information and support for this plugin? = - -Visit the [Duplicator Page](http://lifeinthegrid.com/duplicator) at lifeinthegrid.com - - -= Can I test this in a non-production environment? = - -Yes. Put WordPress on [your computer](http://lifeinthegrid.com/xampp) by watching the video below. - -http://www.youtube.com/watch?v=-hF7FbTQIkk - -= Is this plugin compatible with WordPress Multi-Site (MU)? = - -No. Hopefully in future versions we will support MU - - -== Screenshots == - -1. Main Interface for all Packages -2. Create Package Step 1 -3. Create Package Step 2 -4. Build Process -5. Installer Screen - - -== Changelog == - -Please see the following url: -http://lifeinthegrid.com/duplicator-log - - - - -== Upgrade Notice == - -Please use our ticketing system when submitting your logs. Please do not post to the forums. - - - - - - - - - - - - - +=== Duplicator - WordPress Migration & Backup Plugin === +Contributors: seedprod, smub, andreamk +Tags: migration, backup, duplicate, move, migrate, restore, transfer, clone, automate, copy site, migrator +Requires at least: 4.0 +Tested up to: 6.4 +Requires PHP: 5.3.8 +Stable tag: 1.5.7 +License: GPLv2 +WordPress migration and backups are much easier with Duplicator! Clone, backup, move and transfer an entire site from one location to another. + +== Description == + +> With over **30 million downloads** Duplicator successfully gives WordPress users the ability to migrate, copy, move or clone a site from one location to another and also serves as a simple backup utility. Duplicator handles serialized and base64 serialized replacements. Standard WordPress migration and WordPress backups are easily handled by this plugin as are **zero downtime migrations**. + +For complete details visit [duplicator.com](https://duplicator.com/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=desc_details&utm_campaign=duplicator_free). + += Quick Video Demo = +https://www.youtube.com/watch?v=94wzCqPkQY0 + += Overview = +Duplicator is the most powerful migrator available. It enables you to: + +* Move, migrate or clone a WordPress site between domains or hosts with **zero downtime** +* Pull down a live site to localhost for development +* Transfer a WordPress site from one host to another +* Manually backup a WordPress site or parts of a site +* Duplicate a live site to a staging area or vice versa +* Bundle up an entire WordPress site for easy reuse or distribution +* Perform a full WordPress migration without struggling with messy import/export sql scripts + += Migrate WordPress and Run WordPress Backups = +Duplicator creates a package that bundles all the site's plugins, themes, content, database and WordPress files into a simple zip file called a package. This package can then be used to easily migrate a WordPress site to any location you wish. Move on the same server, across servers and pretty much any location a WordPress site can be hosted. *WordPress is not required for installation* since the package contains all site files. + += Improve Your Workflow with Pre-Bundled Sites = +Duplicator lets you make your own preconfigured sites to eliminate rework. Instead of manually configuring your favorite theme, set of plugins or content over and over, now just configure a single site and bundle it up into a Duplicator package. Once you have the bundled site, you can migrate the WordPress site over and over to different locations to instantly create many preconfigured sites! + += Duplicator Pro = +Duplicator Pro takes Duplicator to the next level with features you'll really appreciate, such as: + +* Drag and Drop installs - just drag an archive to the destination site! +* Scheduled backups +* Cloud Storage to Dropbox, Google Drive, Microsoft OneDrive, Amazon S3 and FTP/SFTP +* A special 2-step streamlined installer mode for mega-fast installs +* Recovery Points added for very fast emergency site restores +* Support for Managed hosts such as WordPress.com, WPEngine, GoDaddy Managed, and more +* Multi-threaded to support larger web sites & databases +* Migrate an entire multisite WordPress network in one shot +* Install a multisite subsite as a new standalone website +* Database and user creation *in the installer* with cPanel API +* Connect to cPanel directly from installer +* Custom plugin hooks for developers +* Email notifications +* Professional support +* ... and much more! + +Check out [Duplicator Pro](https://duplicator.com/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=wpo_premium&utm_campaign=duplicator_pro) today! + += Please Note = +The underlying logic to backup WordPress, move WordPress and transfer WordPress are complex and it's impossible to know how each system is setup; this is why your feedback is important to us. Thanks for helping us to make WordPress the best blogging platform in the world. + += Disclaimer = +This plugin does require some technical knowledge. If you plan to migrate WordPress or backup WordPress please use it at your own risk and don't forget to back up your files and databases beforehand. If you need to move or backup WordPress and would like additional help please visit the Duplicator [resources section](https://duplicator.com/knowledge-base/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=free_disclaimer&utm_campaign=duplicator_free) . + +== Screenshots == + +1. Main Interface for all Packages +2. Create Package Step 1 +3. Create Package Step 2 +4. Build Process +5. Installer Screen + +== Frequently Asked Questions == + += Does Duplicator have a knowledge base or FAQ? = +Yes. Please see [all documents](https://duplicator.com/knowledge-base/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=faq_docs&utm_campaign=duplicator_free) at duplicator.com + += Installation Instructions = +1. Upload `duplicator` folder to the `/wp-content/plugins/` directory +2. Activate the plugin through the 'Plugins' menu in WordPress +3. Click on the Duplicator link from the main menu +4. Check out the help by clicking the help icon and create your first package. + +The Duplicator requires php 5.3 or higher. + + += Are there any videos I can watch? = +Yes. Please see the [video section](https://duplicator.com/knowledge-base-article-categories/quick-start-videos/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=faq_videos&utm_campaign=duplicator_free) on the FAQ. + += Is this plugin compatible with WordPress multisite (MU)? = +Duplicator isn't, however [Duplicator Pro](https://duplicator.com/knowledge-base-article-categories/multisite/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=faq_dpro_multisiteinfo&utm_campaign=duplicator_pro) supports full multisite network migrations/backups and also can install a multisite subsite as a standalone site. + += Where can I get more help and support for this plugin? = +Purchase a Pro License for quick support [Duplicator Pro](https://duplicator.com/pricing/?utm_source=duplicator_free&utm_medium=wp_org&utm_content=faq_support&utm_campaign=duplicator_free) + + +== Changelog == + +Please see the following url: +[https://duplicator.com/knowledge-base/changelog/](https://duplicator.com/knowledge-base/changelog/?lite&utm_source=duplicator_free&utm_medium=wp_org&utm_content=changelog_support&utm_campaign=duplicator_free) + + + +== Upgrade Notice == diff --git a/src/Ajax/AbstractAjaxService.php b/src/Ajax/AbstractAjaxService.php new file mode 100644 index 00000000..4f7054d2 --- /dev/null +++ b/src/Ajax/AbstractAjaxService.php @@ -0,0 +1,31 @@ + null, + 'output' => '', + 'message' => '' + ); + + ob_start(); + try { + DUP_Handler::init_error_handler(); + $nonce = SnapUtil::sanitizeNSCharsNewline($nonce); + if (!is_null($nonceaction) && !wp_verify_nonce($nonce, $nonceaction)) { + DUP_Log::trace('Security issue'); + throw new Exception('Security issue'); + } + if (!is_null($capability)) { + DUP_Util::hasCapability($capability, DUP_Util::SECURE_ISSUE_THROW); + } + + // execute ajax function + $result['funcData'] = call_user_func($callback); + } catch (Exception $e) { + $error = true; + $result['message'] = $e->getMessage(); + } + + $result['output'] = ob_get_clean(); + if ($errorUnespectedOutput && !empty($result['output'])) { + $error = true; + } + + if ($error) { + wp_send_json_error($result); + } else { + wp_send_json_success($result); + } + } +} diff --git a/src/Ajax/ServicesDashboard.php b/src/Ajax/ServicesDashboard.php new file mode 100644 index 00000000..7bf94119 --- /dev/null +++ b/src/Ajax/ServicesDashboard.php @@ -0,0 +1,80 @@ +addAjaxCall('wp_ajax_duplicator_dashboad_widget_info', 'dashboardWidgetInfo'); + $this->addAjaxCall('wp_ajax_duplicator_dismiss_recommended_plugin', 'dismissRecommendedPlugin'); + } + + /** + * Set recovery callback + * + * @return array + */ + public static function dashboardWidgetInfoCallback() + { + $result = array( + 'isRunning' => DUP_Package::isPackageRunning(), + 'lastBackupInfo' => DashboardWidget::getLastBackupString() + ); + return $result; + } + + /** + * Set recovery action + * + * @return void + */ + public function dashboardWidgetInfo() + { + AjaxWrapper::json( + array(__CLASS__, 'dashboardWidgetInfoCallback'), + 'duplicator_dashboad_widget_info', + $_POST['nonce'], + 'export' + ); + } + + /** + * Set dismiss recommended callback + * + * @return bool + */ + public static function dismissRecommendedPluginCallback() + { + return (update_user_meta(get_current_user_id(), DashboardWidget::RECOMMENDED_PLUGIN_DISMISSED_OPT_KEY, true) !== false); + } + + /** + * Set recovery action + * + * @return void + */ + public function dismissRecommendedPlugin() + { + AjaxWrapper::json( + array(__CLASS__, 'dismissRecommendedPluginCallback'), + 'duplicator_dashboad_widget_dismiss_recommended', + $_POST['nonce'], + 'export' + ); + } +} diff --git a/src/Ajax/ServicesEducation.php b/src/Ajax/ServicesEducation.php new file mode 100644 index 00000000..051fe609 --- /dev/null +++ b/src/Ajax/ServicesEducation.php @@ -0,0 +1,472 @@ +addAjaxCall('wp_ajax_duplicator_settings_callout_cta_dismiss', 'dismissCalloutCTA'); + $this->addAjaxCall('wp_ajax_duplicator_packages_bottom_bar_dismiss', 'dismissBottomBar'); + $this->addAjaxCall('wp_ajax_duplicator_email_subscribe', 'setEmailSubscribed'); + $this->addAjaxCall('wp_ajax_duplicator_one_click_upgrade_prepare', 'prepareForOneClickUpgrade'); + $this->addAjaxCall('wp_ajax_duplicator_finalize_oneclick_upr', 'finalizeOneClickUpgrade'); + $this->addAjaxCall('wp_ajax_nopriv_duplicator_lite_run_one_click_upgrade', 'oneClickUpgrade'); + $this->addAjaxCall('wp_ajax_duplicator_lite_run_one_click_upgrade', 'oneClickUpgrade'); + } + + /** + * Set email subscribed + * + * @return bool + */ + public static function setEmailSubscribedCallback() + { + $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE); + if (is_null($email)) { + throw new \Exception('Invalid email'); + } + + $response = wp_remote_post(self::REMOTE_SUBSCRIBE_URL, array( + 'method' => 'POST', + 'timeout' => 45, + 'body' => array('email' => $email) + )); + + if (is_wp_error($response) || 200 !== wp_remote_retrieve_response_code($response)) { + $error_msg = $response->get_error_code() . ': ' . $response->get_error_message(); + error_log($error_msg); + throw new \Exception($error_msg); + } + + return (update_user_meta(get_current_user_id(), EducationElements::DUP_EMAIL_SUBSCRIBED_OPT_KEY, true) !== false); + } + + /** + * Set recovery action + * + * @return void + */ + public function setEmailSubscribed() + { + AjaxWrapper::json( + array(__CLASS__, 'setEmailSubscribedCallback'), + 'duplicator_email_subscribe', + $_POST['nonce'], + 'export' + ); + } + + /** + * Set dismiss callout CTA callback + * + * @return bool + */ + public static function dismissCalloutCTACallback() + { + return (update_user_meta(get_current_user_id(), EducationElements::DUP_SETTINGS_FOOTER_CALLOUT_DISMISSED, true) !== false); + } + + /** + * Dismiss callout CTA + * + * @return void + */ + public function dismissCalloutCTA() + { + AjaxWrapper::json( + array(__CLASS__, 'dismissCalloutCTACallback'), + 'duplicator_settings_callout_cta_dismiss', + $_POST['nonce'], + 'export' + ); + } + + /** + * Dismiss bottom bar callback + * + * @return bool + */ + public static function dismissBottomBarCallback() + { + return (update_user_meta(get_current_user_id(), EducationElements::DUP_PACKAGES_BOTTOM_BAR_DISMISSED, true) !== false); + } + + /** + * Dismiss bottom bar + * + * @return void + */ + public function dismissBottomBar() + { + AjaxWrapper::json( + array(__CLASS__, 'dismissBottomBarCallback'), + 'duplicator_packages_bottom_bar_dismiss', + $_POST['nonce'], + 'export' + ); + } + + + /** + * Generate oth and save it into a db option, save also license key into a db option. + * Returns all values necessary for creating a request to remote endpoint + * + * @throws Exception In case it failed to save data into db + * @return array Contains: + */ + public static function prepareForOneClickUpgradeCallback() + { + DUP_Log::trace("User requested One Click Upgrade."); + + $oth = wp_generate_password(30, false, false); // Generate random oth + $licenseKey = sanitize_text_field($_REQUEST["license_key"]); + + delete_option(self::OPTION_KEY_ONE_CLICK_UPGRADE_OTH); + delete_option(self::LICENSE_KEY_OPTION_AUTO_ACTIVE); + $ok1 = update_option(self::OPTION_KEY_ONE_CLICK_UPGRADE_OTH, $oth); + $ok2 = update_option(self::LICENSE_KEY_OPTION_AUTO_ACTIVE, $licenseKey); + + if (!$ok1 || !$ok2) { + throw new Exception("Problem saving new parameters into options table in prepareForOneClickUpgradeCallback."); + } + $returnData = array(); + + $returnData["success"] = true; + $returnData["error_msg"] = ""; + + $returnData["oth"] = self::hashOth($oth); + $returnData["license_key"] = $licenseKey; + $returnData["version"] = DUPLICATOR_VERSION; + $returnData["redirect"] = base64_encode(admin_url('admin-ajax.php?action=duplicator_finalize_oneclick_upr')); + $returnData["endpoint"] = admin_url('admin-ajax.php'); + $returnData["siteurl"] = admin_url(); + $returnData["homeurl"] = home_url(); + + $returnData["response"] = ""; // Store response + $returnData["file"] = ""; + + // Activate license for this home_url. We can't use download link + // without first activating license. + $api_params = array( + 'edd_action' => 'activate_license', + 'license' => $licenseKey, + 'item_name' => "Duplicator Pro", // the name of our product in EDD, + 'url' => home_url() + ); + + global $wp_version; + $agent_string = "WordPress/" . $wp_version; + DUP_Log::trace("Wordpress agent string $agent_string"); + + $requestParam = array( + 'timeout' => 15, + 'sslverify' => false, + 'user-agent' => $agent_string, + 'body' => $api_params + ); + + if (($data = self::licenseUpgradeRequests($requestParam, $requestError)) === false) { + $returnData["success"] = false; + $returnData["error_msg"] = self::licenseUpgradeMessageError($requestError); + return $returnData; + } elseif (!isset($data->license) || $data->license != 'valid') { + $returnData["success"] = false; + $returnData["error_msg"] = self::licenseUpgradeMessageError(array( + 'code' => 0, + 'message' => 'License key in invalid', + 'details' => '' + )); + return $returnData; + } + + // Fetch direct url and set $returnData["file"]. It is a direct url to download Pro version. + // It can be used only after license is activated for the given website. + $api_params = array( + 'edd_action' => 'get_version', + 'license' => $licenseKey, + 'item_name' => "Duplicator Pro", + 'slug' => "duplicator-pro", + 'author' => "Snap Creek Software", + 'url' => home_url(), + 'beta' => false, + 'php_version' => phpversion(), + 'wp_version' => get_bloginfo('version'), + ); + + $requestParam = array( + 'timeout' => 15, + 'sslverify' => false, + 'body' => $api_params, + ); + + if (($data = self::licenseUpgradeRequests($requestParam, $requestError)) === false) { + $returnData["success"] = false; + $returnData["error_msg"] = self::licenseUpgradeMessageError($requestError); + return $returnData; + } elseif (!isset($data->download_link) || empty($data->download_link)) { + $returnData["success"] = false; + $returnData["error_msg"] = self::licenseUpgradeMessageError(array( + 'code' => 0, + 'message' => 'License key download URL is invalid', + 'details' => '' + )); + return $returnData; + } + + $returnData["file"] = base64_encode($data->download_link); + return $returnData; + } + + /** + * Returh hashed OTH + * + * @param string $oth OTH + * + * @return string Hashed OTH + */ + protected static function hashOth($oth) + { + return hash_hmac('sha512', $oth, wp_salt()); + } + + /** + * License upgrade requests + * + * @param array $params Parameters + * @param array $requestError Request error + * + * @return false|object False on error, array data on success + */ + protected static function licenseUpgradeRequests($params, &$requestError = array()) + { + try { + $requestError = array( + 'code' => -1, + 'message' => '', + 'details' => '', + ); + DUP_Log::traceObject("License request params:", $params); + + $response = wp_remote_post(self::DUPLICATOR_STORE_URL, $params); + if (is_wp_error($response)) { + /** @var WP_Error $response */ + $requestError['code'] = $response->get_error_code(); + $requestError['message'] = $response->get_error_message(); + $requestError['details'] = SnapJson::jsonEncodePPrint($response->get_error_data()); + } elseif ($response['response']['code'] < 200 || $response['response']['code'] >= 300) { + $requestError['code'] = $response['response']['code']; + $requestError['message'] = $response['response']['message']; + $requestError['details'] = SnapJson::jsonEncodePPrint($response); + } else { + $data = json_decode(wp_remote_retrieve_body($response)); + if (!is_object($data)) { + $requestError['code'] = -1; + $requestError['message'] = __('Invalid license JSON data.', 'duplicator-pro'); + $requestError['details'] = 'Response: ' . wp_remote_retrieve_body($response); + } else { + return $data; + } + } + } catch (Exception $e) { + $requestError['code'] = -1; + $requestError['message'] = 'Exception ' . $e->getMessage(); + $requestError['details'] = $e->getTraceAsString(); + } + + return false; + } + + /** + * License upgrade message error + * + * @param array $requestError Request error + * + * @return void + */ + protected static function licenseUpgradeMessageError($requestError) + { + ob_start(); + ?> +

                        + +

                        +

                        +
                        + +

                        + 'duplicator-settings' ), + admin_url('admin.php') + ) + ); + + $creds = request_filesystem_credentials($url, '', false, false, null); + + // Check for file system permissions. + if (false === $creds || ! \WP_Filesystem($creds)) { + DUP_Log::trace("ERROR: There was an error while installing an upgrade. " . + "Please check file system permissions and try again. " . + "Also, you can download the plugin from wpforms.com and install it manually."); + $response["error"] = true; + print(json_encode($response)); + die(); + } + // We do not need any extra credentials if we have gotten this far, so let's install the plugin. + + // Do not allow WordPress to search/download translations, as this will break JS output. + remove_action('upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20); + + // Create the plugin upgrader with custom skin. + $installer = new PluginSilentUpgrader(new ConnectSkin()); + DUP_Log::trace("Starting Pro plugin installer..."); + $installer->install( $file ); // phpcs:ignore + DUP_Log::trace("Pro plugin installer finished."); + + // Flush the cache and return the newly installed plugin basename. + wp_cache_flush(); + $plugin_basename = $installer->plugin_info(); + + if ($plugin_basename) { + $proDir = dirname($plugin_basename); + if ( + $proDir != "duplicator-pro" && + !rename(WP_PLUGIN_DIR . "/" . $proDir, WP_PLUGIN_DIR . "/duplicator-pro") + ) { + DUP_Log::trace("ERROR: ERROR: Failed renaming \"$proDir\" to \"duplicator-pro\"."); + $response["error"] = true; + print(json_encode($response)); + die(); + } + // Here Pro is downloaded successfully + } else { + DUP_Log::trace("ERROR: Installation of Pro version failed."); + $response["error"] = true; + print(json_encode($response)); + die(); + } + } + + DUP_Log::trace("SUCCESS: Duplicator Pro plugin exists and is ready to be activated."); + $response["success"] = true; + print(json_encode($response)); + die(); + } + + /** + * Checks if duplicator-pro exists. If it does not, then it redirects to Lite settings license page. + * Otherwise deactivates Lite and redirects to Pro plugin activation link. + * + * @return void + */ + public function finalizeOneClickUpgrade() + { + DUP_Log::trace("Running finalization of One Click Upgrade."); + + if (!is_dir(WP_PLUGIN_DIR . "/duplicator-pro")) { + DUP_Log::trace("plugins/duplicator-pro folder does not exist, redirect to Lite settings license page."); + $licensePageUrl = is_multisite() ? + network_admin_url('admin.php?page=duplicator-settings&tab=license') : + admin_url('admin.php?page=duplicator-settings&tab=license'); + header("Location: $licensePageUrl"); + die(); + } + // Here we know that plugins/duplicator-pro folder exists for sure. + + // Deactivate Lite + deactivate_plugins(DUPLICATOR_PLUGIN_PATH . "/duplicator.php"); + DUP_Log::trace("Lite plugin is deactivated."); + + // Now to activate Pro plugin we need to create a separate request. + DUP_Log::trace("Doing Pro activation."); + $plugin = "duplicator-pro/duplicator-pro.php"; + $pluginsAdminUrl = is_multisite() ? network_admin_url('plugins.php') : admin_url('plugins.php'); + $activateProUrl = esc_url_raw( + add_query_arg( + array( + 'action' => 'activate', + 'plugin' => $plugin, + '_wpnonce' => wp_create_nonce("activate-plugin_$plugin") + ), + $pluginsAdminUrl + ) + ); + header("Location: $activateProUrl"); + die(); + // $activated = activate_plugin($plugin, '', true, true); // This won't work + } +} diff --git a/src/Ajax/ServicesExtraPlugins.php b/src/Ajax/ServicesExtraPlugins.php new file mode 100644 index 00000000..91087439 --- /dev/null +++ b/src/Ajax/ServicesExtraPlugins.php @@ -0,0 +1,56 @@ +addAjaxCall('wp_ajax_duplicator_install_extra_plugin', 'extraPluginInstall'); + } + + /** + * Install and activate or just activate plugin + * + * @return string + */ + public static function extraPluginInstallCallback() + { + $slug = filter_input(INPUT_POST, 'plugin', FILTER_SANITIZE_STRING); + $message = ''; + + if (!ExtraPluginsMng::getInstance()->install($slug, $message)) { + throw new \Exception($message); + } + + return $message; + } + + /** + * Addon plugin install action callback + * + * @return void + */ + public function extraPluginInstall() + { + AjaxWrapper::json( + array(__CLASS__, 'extraPluginInstallCallback'), + 'duplicator_install_extra_plugin', + $_POST['nonce'], + 'install_plugins' + ); + } +} diff --git a/src/Ajax/ServicesNotifications.php b/src/Ajax/ServicesNotifications.php new file mode 100644 index 00000000..8216cbb1 --- /dev/null +++ b/src/Ajax/ServicesNotifications.php @@ -0,0 +1,69 @@ +addAjaxCall('wp_ajax_duplicator_notification_dismiss', 'setDissmisedNotifications'); + } + + /** + * Dismiss notification + * + * @return bool + */ + public static function dismissNotifications() + { + $id = sanitize_key($_POST['id']); + $type = is_numeric($id) ? 'feed' : 'events'; + $option = Notifications::getOption(); + + $option['dismissed'][] = $id; + $option['dismissed'] = array_unique($option['dismissed']); + + // Remove notification. + if (!is_array($option[$type]) || empty($option[$type])) { + throw new \Exception('Notification type not set.'); + } + + foreach ($option[$type] as $key => $notification) { + if ((string)$notification['id'] === (string)$id) { + unset($option[$type][$key]); + + break; + } + } + + return update_option(Notifications::DUPLICATOR_NOTIFICATIONS_OPT_KEY, $option); + } + + /** + * Set dismiss notification action + * + * @return void + */ + public function setDissmisedNotifications() + { + AjaxWrapper::json( + array(__CLASS__, 'dismissNotifications'), + Notifications::DUPLICATOR_NOTIFICATION_NONCE_KEY, + $_POST['nonce'], + 'manage_options' + ); + } +} diff --git a/src/Controllers/AboutUsController.php b/src/Controllers/AboutUsController.php new file mode 100644 index 00000000..061d1320 --- /dev/null +++ b/src/Controllers/AboutUsController.php @@ -0,0 +1,219 @@ + admin_url('admin-ajax.php'), + 'extra_plugin_install_nonce' => wp_create_nonce('duplicator_install_extra_plugin'), + ) + ); + + wp_enqueue_style( + 'duplicator-about', + DUPLICATOR_PLUGIN_URL . "assets/css/about.css", + array(), + DUPLICATOR_VERSION + ); + } + + /** + * Render welcome screen + * + * @return void + */ + public static function render() + { + $levels = ControllersManager::getMenuLevels(); + TplMng::getInstance()->render( + 'admin_pages/about_us/tabs', + array( + 'active_tab' => is_null($levels[ControllersManager::QUERY_STRING_MENU_KEY_L2]) ? + self::ABOUT_US_TAB : $levels[ControllersManager::QUERY_STRING_MENU_KEY_L2] + ), + true + ); + + switch ($levels[ControllersManager::QUERY_STRING_MENU_KEY_L2]) { + case self::GETTING_STARTED: + TplMng::getInstance()->render('admin_pages/about_us/getting_started/main', array(), true); + break; + case self::LITE_VS_PRO: + TplMng::getInstance()->render('admin_pages/about_us/lite_vs_pro/main', array(), true); + break; + case self::ABOUT_US_TAB: + default: + TplMng::getInstance()->render('admin_pages/about_us/about_us/main', array(), true); + break; + } + } + + /** + * Returns the lite vs pro features as an array + * + * @return array + */ + public static function getLiteVsProFeatures() + { + if (!empty(self::$liteVsProfeatures)) { + return self::$liteVsProfeatures; + } + + self::$liteVsProfeatures = array( + array( + 'title' => __('Backup Files & Database', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_FULL, + ), + array( + 'title' => __('File & Database Table Filters', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_FULL, + ), + array( + 'title' => __('Migration Wizard', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_FULL, + ), + array( + 'title' => __('Overwrite Live Site', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_FULL, + ), + array( + 'title' => __('Drag & Drop Installs', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_PARTIAL, + 'lite_text' => __('Classic WordPress-less Installs Only', 'duplicator'), + 'pro_text' => __( + 'Drag and Drop migrations and site restores! Simply drag the bundled site archive to the site you wish to overwrite.', + 'duplicator' + ) + ), + array( + 'title' => __('Scheduled Backups', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Ensure that your important data is regularly and consistently backed up, allowing for quick and efficient recovery in case of data loss.', + 'duplicator' + ) + ), + array( + 'title' => __('Recovery Points', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Recovery Points provide protection against mistakes and bad updates by letting you quickly rollback your system to a known, good state.', + 'duplicator' + ) + ), + array( + 'title' => __('Cloud Storage', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Back up to Dropbox, FTP, Google Drive, OneDrive, Amazon S3 or any S3-compatible storage service for safe storage.', + 'duplicator' + ) + ), + array( + 'title' => __('Larger Site Support', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'We\'ve developed a new way to package backups especially tailored for larger site. No server timeouts or other restrictions!', + 'duplicator' + ) + ), + array( + 'title' => __('Server-to-Server Import', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Direct Server Transfers allow you to build an archive, then directly transfer it from the source ' . + 'server to the destination server for a lightning fast migration!', + 'duplicator' + ) + ), + array( + 'title' => __('Multisite support', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Supports multisite network backup & migration. Subsite As Standalone Install, Standalone ' . + 'Import Into Multisite and Import Subsite Into Multisite', + 'duplicator' + ) + ), + array( + 'title' => __('Installer Branding', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __('Create your own custom-configured WordPress site and "Brand" the installer file with your look and feel.', 'duplicator') + ), + array( + 'title' => __('Archive Encryption', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __('Protect and secure the archive file with industry-standard AES-256 encryption!', 'duplicator') + ), + array( + 'title' => __('Advanced Backup Permissions', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Enjoy granular access control to ensure only authorized users can perform these critical functions.', + 'duplicator' + ) + ), + array( + 'title' => __('Enhanced Features', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Enhanced features include: Managed Hosting Support, Shared Database Support, Streamlined Installer, Email Alerts and more...', + 'duplicator' + ) + ), + array( + 'title' => __('Advanced Features', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'pro_text' => __( + 'Advanced features included: Hourly Schedules, Custom Search & Replace, Migrate Duplicator Settings, Regenerate Salts and Developer Hooks', + 'duplicator' + ) + ), + array( + 'title' => __('Customer Support', 'duplicator'), + 'lite_enabled' => self::LITE_ENABLED_NONE, + 'lite_text' => __('Limited Support', 'duplicator'), + 'pro_text' => __('Priority Support', 'duplicator') + ) + ); + + return self::$liteVsProfeatures; + } +} diff --git a/src/Controllers/EmailSummaryPreviewPageController.php b/src/Controllers/EmailSummaryPreviewPageController.php new file mode 100644 index 00000000..c7e924e8 --- /dev/null +++ b/src/Controllers/EmailSummaryPreviewPageController.php @@ -0,0 +1,37 @@ +render('mail/email_summary', array( + 'packages' => EmailSummary::getInstance()->getPackagesInfo() + )); + die; + } +} diff --git a/src/Controllers/StorageController.php b/src/Controllers/StorageController.php new file mode 100644 index 00000000..44181fc6 --- /dev/null +++ b/src/Controllers/StorageController.php @@ -0,0 +1,125 @@ +render('mocks/storage/storage', array( + 'storages' => self::getStoragesData() + ), true); + } + + /** + * Fet storage alert dialog box + * + * @param string $utm_medium UTM medium for the upsell link + * + * @return DUP_UI_Dialog + */ + public static function getDialogBox($utm_medium) + { + require_once(DUPLICATOR_PLUGIN_PATH . '/classes/ui/class.ui.dialog.php'); + + $storageAlert = new DUP_UI_Dialog(); + $storageAlert->title = __('Advanced Storage', 'duplicator'); + $storageAlert->height = 600; + $storageAlert->width = 550; + $storageAlert->okText = ''; + $storageAlert->message = TplMng::getInstance()->render('mocks/storage/popup', array( + 'storages' => self::getStoragesData(), + 'utm_medium' => $utm_medium, + ), false); + $storageAlert->initAlert(); + + return $storageAlert; + } + + /** + * Returns the storage data for the view + * + * @return array[] + */ + private static function getStoragesData() + { + return array( + array( + 'title' => __('Amazon S3', 'duplicator'), + 'label' => __('Amazon S3', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/aws.svg', + ), + array( + 'title' => __('Google Drive', 'duplicator'), + 'label' => __('Google Drive', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/google-drive.svg', + ), + array( + 'title' => __('OneDrive', 'duplicator'), + 'label' => __('OneDrive', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/onedrive.svg', + ), + array( + 'title' => __('DropBox', 'duplicator'), + 'label' => __('DropBox', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/dropbox.svg', + ), + array( + 'title' => __('FTP/SFTP', 'duplicator'), + 'label' => __('FTP/SFTP', 'duplicator'), + 'fa-class' => 'fas fa-network-wired', + ), + array( + 'title' => __('Google Cloud Storage', 'duplicator'), + 'label' => __('Google Cloud Storage', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/google-cloud.svg', + ), + array( + 'title' => __('Back Blaze', 'duplicator'), + 'label' => __('Back Blaze', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/backblaze.svg', + ), + array( + 'title' => __('Cloudflare R2', 'duplicator'), + 'label' => __('Cloudflare R2', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/cloudflare.svg', + ), + array( + 'title' => __('Digital Ocean Spaces', 'duplicator'), + 'label' => __('Digital Ocean Spaces', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/digital-ocean.svg', + ), + array( + 'title' => __('Vultr Object Storage', 'duplicator'), + 'label' => __('Vultr Object Storage', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/vultr.svg', + ), + array( + 'title' => __('Dream Objects', 'duplicator'), + 'label' => __('Dream Objects', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/dreamhost.svg', + ), + array( + 'title' => __('Wasabi', 'duplicator'), + 'label' => __('Wasabi', 'duplicator'), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/wasabi.svg', + ), + array( + 'title' => __('S3-Compatible Provider', 'duplicator'), + 'label' => __( + 'S3-Compatible (Generic) Cloudian, Cloudn, Connectria, Constant, Exoscal, Eucalyptus, Nifty, Nimbula, Minio, etc...', + 'duplicator' + ), + 'iconUrl' => DUPLICATOR_PLUGIN_URL . 'assets/img/aws.svg', + ), + ); + } +} diff --git a/src/Controllers/WelcomeController.php b/src/Controllers/WelcomeController.php new file mode 100644 index 00000000..a7292be7 --- /dev/null +++ b/src/Controllers/WelcomeController.php @@ -0,0 +1,130 @@ +render('admin_pages/welcome/welcome', array(), true); + } +} diff --git a/src/Core/Bootstrap.php b/src/Core/Bootstrap.php new file mode 100644 index 00000000..3d629773 --- /dev/null +++ b/src/Core/Bootstrap.php @@ -0,0 +1,550 @@ +init(); + DUP_Settings::init(); + DUP_Log::Init(); + DUP_Util::init(); + DUP_DB::init(); + MigrationMng::init(); + Notice::init(); + NoticeBar::init(); + Review::init(); + AdminNotices::init(); + DUP_Web_Services::init(); + WelcomeController::init(); + DashboardWidget::init(); + EducationElements::init(); + Notifications::init(); + EmailSummaryPreviewPageController::init(); + $dashboardService = new ServicesDashboard(); + $dashboardService->init(); + $extraPlugin = new ServicesExtraPlugins(); + $extraPlugin->init(); + $educationService = new ServicesEducation(); + $educationService->init(); + } + } + + /** + * Return admin body classes + * + * @param string $classes classes + * + * @return string + */ + public static function addBodyClass($classes) + { + if (ControllersManager::isDuplicatorPage()) { + $classes .= ' duplicator-pages'; + } + return $classes; + } + + /** + * Hooked into `plugins_loaded`. Routines used to update the plugin + * + * @return null + */ + public static function update() + { + if (DUPLICATOR_VERSION != get_option(DUP_LITE_Plugin_Upgrade::DUP_VERSION_OPT_KEY)) { + DUP_LITE_Plugin_Upgrade::onActivationAction(); + // $snapShotDirPerm = substr(sprintf("%o", fileperms(DUP_Settings::getSsdirPath())),-4); + } + load_plugin_textdomain('duplicator'); + } + + /** + * Load text domain for translation + * + * @return void + */ + public static function loadTextdomain() + { + load_plugin_textdomain('duplicator', false, false); + } + + /** + * User role editor integration + * + * @return void + */ + public static function wpfrontIntegrate() + { + if (DUP_Settings::Get('wpfront_integrate')) { + do_action('wpfront_user_role_editor_duplicator_init', array('export', 'manage_options', 'read')); + } + } + + /** + * Hooked into `admin_init`. Init routines for all admin pages + * + * @return void + */ + public static function adminInit() + { + add_action('in_admin_header', array('Duplicator\\Views\\ViewHelper', 'adminLogoHeader'), 100); + + /* CSS */ + wp_register_style('dup-jquery-ui', DUPLICATOR_PLUGIN_URL . 'assets/css/jquery-ui.css', null, "1.11.2"); + wp_register_style('dup-font-awesome', DUPLICATOR_PLUGIN_URL . 'assets/css/fontawesome-all.min.css', null, '5.7.2'); + wp_register_style('dup-plugin-global-style', DUPLICATOR_PLUGIN_URL . 'assets/css/global_admin_style.css', null, DUPLICATOR_VERSION); + wp_register_style('dup-plugin-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', array('dup-plugin-global-style'), DUPLICATOR_VERSION); + + wp_register_style('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.css', null, '2.2.1'); + wp_register_style('dup-parsley-style', DUPLICATOR_PLUGIN_URL . 'assets/css/parsley.css', null, '2.3.5'); + /* JS */ + wp_register_script('dup-handlebars', DUPLICATOR_PLUGIN_URL . 'assets/js/handlebars.min.js', array('jquery'), '4.0.10'); + wp_register_script('dup-parsley', DUPLICATOR_PLUGIN_URL . 'assets/js/parsley.min.js', array('jquery'), '1.1.18'); + wp_register_script('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.js', array('jquery'), '2.2.1'); + + add_action('admin_head', array('DUP_UI_Screen', 'getCustomCss')); + // Clean tmp folder + DUP_Package::not_active_files_tmp_cleanup(); + + $unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js'); + $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css'); + if ($unhook_third_party_js || $unhook_third_party_css) { + add_action('admin_enqueue_scripts', array(__CLASS__, 'unhookThirdPartyAssets'), 99999, 1); + } + } + + /** + * Hooked into `admin_menu`. Loads all of the wp left nav admin menus for Duplicator + * + * @return void + */ + public static function menuInit() + { + //SVG Icon: See https://websemantics.uk/tools/image-to-data-uri-converter/ + $hook_prefix = add_menu_page('Duplicator Plugin', 'Duplicator', 'export', 'duplicator', null, DUP_Constants::ICON_SVG); + add_action('admin_print_scripts-' . $hook_prefix, array(__CLASS__, 'scripts')); + add_action('admin_print_styles-' . $hook_prefix, array(__CLASS__, 'styles')); + + //Submenus are displayed in the same order they have in the array + $subMenuItems = self::getSubmenuItems(); + foreach ($subMenuItems as $k => $subMenuItem) { + $subMenuItems[$k]['hook_prefix'] = add_submenu_page( + $subMenuItem['parent_slug'], + $subMenuItem['page_title'], + $subMenuItem['menu_title'], + $subMenuItem['capability'], + $subMenuItem['menu_slug'], + $subMenuItem['callback'], + $k + ); + add_action('admin_print_scripts-' . $subMenuItems[$k]['hook_prefix'], array(__CLASS__, 'scripts')); + + if (isset($subMenuItem['enqueue_style_callback'])) { + add_action('admin_print_styles-' . $subMenuItems[$k]['hook_prefix'], $subMenuItem['enqueue_style_callback']); + } + add_action('admin_print_styles-' . $subMenuItems[$k]['hook_prefix'], array(__CLASS__, 'styles')); + } + $GLOBALS['DUP_Package_Screen'] = new DUP_Package_Screen($subMenuItems[0]['hook_prefix']); + } + + /** + * Submenu datas + * + * @return array[] + */ + protected static function getSubmenuItems() + { + $proTitle = '' . __('Upgrade to Pro', 'duplicator') . ''; + $dupMenuNew = ' ' . __('NEW!', 'duplicator') . ''; + return array( + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('Packages', 'duplicator'), + 'menu_title' => __('Packages', 'duplicator'), + 'capability' => 'export', + 'menu_slug' => ControllersManager::MAIN_MENU_SLUG, + 'callback' => function () { + include(DUPLICATOR_PLUGIN_PATH . 'views/packages/controller.php'); + } + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('Import', 'duplicator'), + 'menu_title' => __('Import', 'duplicator'), + 'capability' => 'export', + 'menu_slug' => ControllersManager::IMPORT_SUBMENU_SLUG, + 'callback' => function () { + TplMng::getInstance()->render('mocks/import/import'); + }, + 'enqueue_style_callback' => array(__CLASS__, 'mocksStyles') + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('Schedules', 'duplicator'), + 'menu_title' => __('Schedules', 'duplicator') . $dupMenuNew, + 'capability' => 'export', + 'menu_slug' => ControllersManager::SCHEDULES_SUBMENU_SLUG, + 'callback' => function () { + TplMng::getInstance()->render('mocks/schedule/schedules'); + }, + 'enqueue_style_callback' => array(__CLASS__, 'mocksStyles') + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('Storage', 'duplicator'), + 'menu_title' => '' . __('Storage', 'duplicator') . '', + 'capability' => 'export', + 'menu_slug' => ControllersManager::STORAGE_SUBMENU_SLUG, + 'callback' => array('Duplicator\\Controllers\\StorageController', 'render'), + 'enqueue_style_callback' => array(__CLASS__, 'mocksStyles') + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('Tools', 'duplicator'), + 'menu_title' => __('Tools', 'duplicator'), + 'capability' => 'manage_options', + 'menu_slug' => ControllersManager::TOOLS_SUBMENU_SLUG, + 'callback' => function () { + include(DUPLICATOR_PLUGIN_PATH . 'views/tools/controller.php'); + }, + 'enqueue_style_callback' => array(__CLASS__, 'mocksStyles') + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('Settings', 'duplicator'), + 'menu_title' => __('Settings', 'duplicator'), + 'capability' => 'manage_options', + 'menu_slug' => ControllersManager::SETTINGS_SUBMENU_SLUG, + 'callback' => function () { + include(DUPLICATOR_PLUGIN_PATH . 'views/settings/controller.php'); + } + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => __('About Duplicator', 'duplicator'), + 'menu_title' => __('About Us', 'duplicator'), + 'capability' => 'manage_options', + 'menu_slug' => ControllersManager::ABOUT_US_SUBMENU_SLUG, + 'callback' => array('Duplicator\\Controllers\\AboutUsController', 'render'), + 'enqueue_style_callback' => array('Duplicator\\Controllers\\AboutUsController', 'enqueues') + ), + array( + 'parent_slug' => 'duplicator', + 'page_title' => $proTitle, + 'menu_title' => $proTitle, + 'capability' => 'manage_options', + 'menu_slug' => Upsell::getCampaignUrl('admin-menu', 'Upgrade to Pro'), + 'callback' => null, + ) + ); + } + + /** + * Hooked into `admin_enqueue_scripts`. Init routines for all admin pages + * + * @access global + * @return null + */ + public static function adminEqueueScripts() + { + wp_enqueue_script('dup-global-script', DUPLICATOR_PLUGIN_URL . 'assets/js/global-admin-script.js', array('jquery'), DUPLICATOR_VERSION, true); + wp_localize_script( + 'dup-global-script', + 'dup_global_script_data', + array( + 'nonce_admin_notice_to_dismiss' => wp_create_nonce('duplicator_admin_notice_to_dismiss'), + 'nonce_settings_callout_to_dismiss' => wp_create_nonce('duplicator_settings_callout_cta_dismiss'), + 'nonce_packages_bottom_bar_dismiss' => wp_create_nonce('duplicator_packages_bottom_bar_dismiss'), + 'nonce_email_subscribe' => wp_create_nonce('duplicator_email_subscribe'), + 'nonce_dashboard_widged_info' => wp_create_nonce("duplicator_dashboad_widget_info"), + 'nonce_dashboard_widged_dismiss_recommended' => wp_create_nonce("duplicator_dashboad_widget_dismiss_recommended"), + 'ajaxurl' => admin_url('admin-ajax.php') + ) + ); + + wp_enqueue_script('dup-one-click-upgrade-script', DUPLICATOR_PLUGIN_URL . 'assets/js/one-click-upgrade.js', array('jquery'), DUPLICATOR_VERSION, true); + wp_localize_script( + 'dup-one-click-upgrade-script', + 'dup_one_click_upgrade_script_data', + array( + 'nonce_one_click_upgrade' => wp_create_nonce('duplicator_one_click_upgrade_prepare'), + 'ajaxurl' => admin_url('admin-ajax.php') + ) + ); + + wp_enqueue_style('dup-plugin-global-style'); + } + + /** + * Add the PRO badge to left sidebar menu item. + * + * @return void + */ + public static function adjustProMenuItemClass() + { + //Add to footer so it's applied on hovered item too + ?> + + + ' . esc_html__("Manage", 'duplicator') . ''; + array_unshift($links, $settings_link); + */ + $upgrade_link = '' . + '' . + esc_html__("Upgrade to Pro", 'duplicator') . + ''; + array_unshift($links, $upgrade_link); + } + return $links; + } + + /** + * Adds links to the plugins manager page + * + * @param string[] $links links + * @param string $file file + * + * @return string The meta help link data for the plugins manager + */ + public static function metaLinks($links, $file) + { + $plugin = plugin_basename(DUPLICATOR_LITE_FILE); + // create link + if ($file == $plugin) { + $links[] = '' . + esc_html__('Manage', 'duplicator') . + ''; + return $links; + } + return $links; + } + + /** + * Remove all external styles and scripts coming from other plugins + * which may cause compatibility issue, especially with React + * + * @param string $hook hook + * + * @return void + */ + public static function unhookThirdPartyAssets($hook) + { + /* + $hook values in duplicator admin pages: + toplevel_page_duplicator + duplicator_page_duplicator-tools + duplicator_page_duplicator-settings + duplicator_page_duplicator-gopro + */ + if (strpos($hook, 'duplicator') !== false && strpos($hook, 'duplicator-pro') === false) { + $unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js'); + $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css'); + $assets = array(); + if ($unhook_third_party_css) { + $assets['styles'] = wp_styles(); + } + if ($unhook_third_party_js) { + $assets['scripts'] = wp_scripts(); + } + foreach ($assets as $type => $asset) { + foreach ($asset->registered as $handle => $dep) { + $src = $dep->src; + // test if the src is coming from /wp-admin/ or /wp-includes/ or /wp-fsqm-pro/. + if ( + is_string($src) && // For some built-ins, $src is true|false + strpos($src, 'wp-admin') === false && + strpos($src, 'wp-include') === false && + // things below are specific to your plugin, so change them + strpos($src, 'duplicator') === false && + strpos($src, 'woocommerce') === false && + strpos($src, 'jetpack') === false && + strpos($src, 'debug-bar') === false + ) { + 'scripts' === $type ? wp_dequeue_script($handle) : wp_dequeue_style($handle); + } + } + } + } + } +} diff --git a/src/Core/Controllers/ControllersManager.php b/src/Core/Controllers/ControllersManager.php new file mode 100644 index 00000000..7d4301d6 --- /dev/null +++ b/src/Core/Controllers/ControllersManager.php @@ -0,0 +1,227 @@ + 'new1', + '_wpnonce' => wp_create_nonce('new1-package') + ) + ); + } + + /** + * Return package detail link + * + * @param int $packageId package id + * + * @return string + */ + public static function getPackageDetailUrl($packageId) + { + return self::getMenuLink( + self::PACKAGES_SUBMENU_SLUG, + 'detail', + null, + array( + 'action' => 'detail', + 'id' => $packageId + ) + ); + } +} diff --git a/src/Core/MigrationMng.php b/src/Core/MigrationMng.php new file mode 100644 index 00000000..b8061814 --- /dev/null +++ b/src/Core/MigrationMng.php @@ -0,0 +1,542 @@ + array(), + 'stored' => array(), + 'instFile' => array() + ); + + /** + * Init + * + * @return void + */ + public static function init() + { + add_action('admin_init', array(__CLASS__, 'adminInit')); + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'removeFirstLoginOption')); + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'renameInstallersPhpFiles')); + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'storeMigrationFiles')); + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'setDupSettingsAfterInstall')); + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'usageStatistics')); + // save cleanup report after actions + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'saveCleanupReport'), 100); + + // LAST BEACAUSE MAKE A WP_REDIRECT + add_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, array(__CLASS__, 'autoCleanFileAfterInstall'), 99999); + } + + /** + * Admin Init function + * + * @return void + */ + public static function adminInit() + { + if (self::isFirstLoginAfterInstall()) { + add_action('current_screen', array(__CLASS__, 'wpAdminHook'), 99999); + update_option(AdminNotices::OPTION_KEY_MIGRATION_SUCCESS_NOTICE, true); + do_action(self::HOOK_FIRST_LOGIN_AFTER_INSTALL, self::getMigrationData()); + } + } + + /** + * Admin Hook function + * + * @return void + */ + public static function wpAdminHook() + { + if (!DUP_CTRL_Tools::isToolPage()) { + wp_redirect(DUP_CTRL_Tools::getDiagnosticURL(false)); + exit; + } + } + + /** + * + * @return boolean + */ + public static function isFirstLoginAfterInstall() + { + if (is_user_logged_in() && get_option(self::FIRST_LOGIN_OPTION, false)) { + if (is_multisite()) { + if (is_super_admin()) { + return true; + } + } else { + if (current_user_can('manage_options')) { + return true; + } + } + } + + return false; + } + + /** + * Purge all caches + * + * @return string[] // messages + */ + public static function purgeCaches() + { + if ( + self::getMigrationData('restoreBackupMode') || + in_array(self::getMigrationData('installType'), array(4,5,6,7)) //update with define when installerstat will be in namespace + ) { + return array(); + } + + return CachesPurge::purgeAll(); + } + + /** + * Clean after install + * + * @param array $migrationData migration data + * + * @return void + */ + public static function usageStatistics($migrationData) + { + $migrationData = (object) $migrationData; + PluginData::getInstance()->updateFromMigrateData($migrationData); + CommStats::installerSend(); + } + + /** + * + * @param array $migrationData Migration data + * + * @return void + */ + public static function autoCleanFileAfterInstall($migrationData) + { + if ($migrationData == false || $migrationData['cleanInstallerFiles'] == false) { + return; + } + + wp_redirect(DUP_CTRL_Tools::getCleanFilesAcrtionUrl(false)); + exit; + } + + /** + * + * @param array $migrationData Migration data + * + * @return void + */ + public static function setDupSettingsAfterInstall($migrationData) + { + flush_rewrite_rules(true); + } + + /** + * return cleanup report + * + * @return array + */ + public static function getCleanupReport() + { + $option = get_option(self::CLEAN_INSTALL_REPORT_OPTION); + if (is_array($option)) { + self::$migrationCleanupReport = array_merge(self::$migrationCleanupReport, $option); + } + + return self::$migrationCleanupReport; + } + + /** + * save clean up report in wordpress options + * + * @return boolean + */ + public static function saveCleanupReport() + { + return add_option(self::CLEAN_INSTALL_REPORT_OPTION, self::$migrationCleanupReport, '', 'no'); + } + + /** + * + * @param array $migrationData Migration data + * + * @return void + */ + public static function removeFirstLoginOption($migrationData) + { + delete_option(self::FIRST_LOGIN_OPTION); + } + + /** + * + * @staticvar array $migrationData + * + * @param string|null $key Key to get from migration data + * + * @return mixed + */ + public static function getMigrationData($key = null) + { + static $migrationData = null; + if (is_null($migrationData)) { + $migrationData = get_option(self::MIGRATION_DATA_OPTION, false); + if (is_string($migrationData)) { + $migrationData = json_decode($migrationData, true); + } + } + + if (is_null($key)) { + return $migrationData; + } elseif (isset($migrationData[$key])) { + return $migrationData[$key]; + } else { + return false; + } + } + + /** + * + * @return string + */ + public static function getSaveModeWarning() + { + switch (self::getMigrationData('safeMode')) { + case 1: + //safe_mode basic + return __('NOTICE: Safe mode (Basic) was enabled during install, be sure to re-enable all your plugins.', 'duplicator'); + case 2: + //safe_mode advance + return __('NOTICE: Safe mode (Advanced) was enabled during install, be sure to re-enable all your plugins.', 'duplicator'); + case 0: + default: + return ''; + } + } + + /** + * Check the root path and in case there are installer files without hashes rename them. + * + * @param integer $fileTimeDelay If the file is younger than $fileTimeDelay seconds then it is not renamed. + * + * @return void + */ + public static function renameInstallersPhpFiles($fileTimeDelay = 0) + { + $fileTimeDelay = is_numeric($fileTimeDelay) ? (int) $fileTimeDelay : 0; + + $pathsTocheck = array( + SnapIO::safePathTrailingslashit(ABSPATH), + SnapIO::safePathTrailingslashit(SnapWP::getHomePath()), + SnapIO::safePathTrailingslashit(WP_CONTENT_DIR) + ); + + $migrationData = self::getMigrationData(); + if (isset($migrationData['installerPath'])) { + $pathsTocheck[] = SnapIO::safePathTrailingslashit(dirname($migrationData['installerPath'])); + } + if (isset($migrationData['dupInstallerPath'])) { + $pathsTocheck[] = SnapIO::safePathTrailingslashit(dirname($migrationData['dupInstallerPath'])); + } + $pathsTocheck = array_unique($pathsTocheck); + + $filesToCheck = array(); + foreach ($pathsTocheck as $cFolder) { + if ( + !is_dir($cFolder) || + !is_writable($cFolder) // rename permissions + ) { + continue; + } + $cFile = $cFolder . 'installer.php'; + if ( + !is_file($cFile) || + !SnapIO::chmod($cFile, 'u+rw') || + !is_readable($cFile) + ) { + continue; + } + $filesToCheck[] = $cFile; + } + + $installerTplCheck = '/const\s+ARCHIVE_FILENAME\s*=\s*[\'"](.+?)[\'"]\s*;.*const\s+PACKAGE_HASH\s*=\s*[\'"](.+?)[\'"]\s*;/s'; + + foreach ($filesToCheck as $file) { + $fileName = basename($file); + + if ($fileTimeDelay > 0 && (time() - filemtime($file)) < $fileTimeDelay) { + continue; + } + + if (($content = @file_get_contents($file, false, null)) === false) { + continue; + } + $matches = null; + if (preg_match($installerTplCheck, $content, $matches) !== 1) { + continue; + } + + $archiveName = $matches[1]; + $hash = $matches[2]; + $matches = null; + + + if (preg_match(DUPLICATOR_ARCHIVE_REGEX_PATTERN, $archiveName, $matches) !== 1) { + if (SnapIO::unlink($file)) { + self::$migrationCleanupReport['instFile'][] = "
                        " + . " " + . sprintf(__('Installer file %s removed for security reasons', 'duplicator'), esc_html($fileName)) + . "
                        "; + } else { + self::$migrationCleanupReport['instFile'][] = "
                        " + . ' ' + . sprintf(__('Can\'t remove installer file %s, please remove it for security reasons', 'duplicator'), esc_html($fileName)) + . '
                        '; + } + continue; + } + + $archiveHash = $matches[1]; + if (strpos($file, $archiveHash) === false) { + if (SnapIO::rename($file, dirname($file) . '/' . $archiveHash . '_installer.php', true)) { + self::$migrationCleanupReport['instFile'][] = "
                        " + . " " + . sprintf(__('Installer file %s renamed with HASH', 'duplicator'), esc_html($fileName)) + . "
                        "; + } else { + self::$migrationCleanupReport['instFile'][] = "
                        " + . ' ' + . sprintf( + __('Can\'t rename installer file %s with HASH, please remove it for security reasons', 'duplicator'), + esc_html($fileName) + ) + . '
                        '; + } + } + } + } + + /** + * + * @param array $migrationData Migration data + * + * @return void + */ + public static function storeMigrationFiles($migrationData) + { + $ssdInstallerPath = DUP_Settings::getSsdirInstallerPath(); + wp_mkdir_p($ssdInstallerPath); + SnapIO::emptyDir($ssdInstallerPath); + + $filesToMove = array( + $migrationData['installerLog'], + $migrationData['installerBootLog'], + $migrationData['origFileFolderPath'] + ); + + foreach ($filesToMove as $path) { + if (file_exists($path)) { + if (SnapIO::rcopy($path, $ssdInstallerPath . '/' . basename($path), true)) { + self::$migrationCleanupReport['stored'] = "
                        " + . " " + . __('Original files folder moved in installer backup directory', 'duplicator') . " - " . esc_html($path) . + "
                        "; + } else { + self::$migrationCleanupReport['stored'] = "
                        " + . ' ' + . sprintf(__('Can\'t move %s to %s', 'duplicator'), esc_html($path), $ssdInstallerPath) + . '
                        '; + } + } + } + } + + /** + * + * @return array + */ + public static function getStoredMigrationLists() + { + if (($migrationData = self::getMigrationData()) == false) { + $filesToCheck = array(); + } else { + $filesToCheck = array( + $migrationData['installerLog'] => __('Installer log', 'duplicator'), + $migrationData['installerBootLog'] => __('Installer boot log', 'duplicator'), + $migrationData['origFileFolderPath'] => __('Original files folder', 'duplicator') + ); + } + + $result = array(); + + foreach ($filesToCheck as $path => $label) { + $storedPath = DUP_Settings::getSsdirInstallerPath() . '/' . basename($path); + if (!file_exists($storedPath)) { + continue; + } + $result[$storedPath] = $label; + } + + return $result; + } + + /** + * + * @return bool + */ + public static function haveFileToClean() + { + return count(self::checkInstallerFilesList()) > 0; + } + + /** + * Gets a list of all the installer files and directory by name and full path + * + * @remarks + * FILES: installer.php, installer-backup.php, dup-installer-bootlog__[HASH].txt + * DIRS: dup-installer + * Last set is for lazy developer cleanup files that a developer may have + * accidentally left around lets be proactive for the user just in case. + * + * @return [string] // [file_name] + */ + public static function getGenericInstallerFiles() + { + return array( + 'installer.php', + '[HASH]installer-backup.php', + 'dup-installer', + 'dup-installer[HASH]', + 'dup-installer-bootlog__[HASH].txt', + '[HASH]_archive.zip|daf' + ); + } + + /** + * + * @return string[] + * @throws Exception + */ + public static function checkInstallerFilesList() + { + $migrationData = self::getMigrationData(); + + $foldersToChkeck = array( + SnapIO::safePathTrailingslashit(ABSPATH), + SnapWP::getHomePath(), + ); + + $result = array(); + + if (!empty($migrationData)) { + if ( + file_exists($migrationData['archivePath']) && + !DUP_Archive::isBackupPathChild($migrationData['archivePath']) + ) { + $result[] = $migrationData['archivePath']; + } + if ( + self::isInstallerFile($migrationData['installerPath']) && + !DUP_Archive::isBackupPathChild($migrationData['archivePath']) + ) { + $result[] = $migrationData['installerPath']; + } + if (file_exists($migrationData['installerBootLog'])) { + $result[] = $migrationData['installerBootLog']; + } + if (file_exists($migrationData['dupInstallerPath'])) { + $result[] = $migrationData['dupInstallerPath']; + } + } + + foreach ($foldersToChkeck as $folder) { + $result = array_merge($result, SnapIO::regexGlob($folder, array( + 'regexFile' => array( + DUPLICATOR_ARCHIVE_REGEX_PATTERN, + DUPLICATOR_INSTALLER_REGEX_PATTERN, + DUPLICATOR_DUP_INSTALLER_BOOTLOG_REGEX_PATTERN, + DUPLICATOR_DUP_INSTALLER_OWRPARAM_REGEX_PATTERN + ), + 'regexFolder' => array( + DUPLICATOR_DUP_INSTALLER_FOLDER_REGEX_PATTERN + ) + ))); + } + + $result = array_map(array('Duplicator\\Libs\\Snap\\SnapIO', 'safePathUntrailingslashit'), $result); + return array_unique($result); + } + + /** + * @param $path string Path to check + * + * @return bool true if the file at current path is the installer file + */ + public static function isInstallerFile($path) + { + if (!is_file($path) || !is_array($last5Lines = SnapIO::getLastLinesOfFile($path, 5)) || empty($last5Lines)) { + return false; + } + + return strpos(implode("", $last5Lines), "DUPLICATOR_INSTALLER_EOF") !== false; + } + + /** + * Clear all the installer files and directory + * + * @return array + */ + public static function cleanMigrationFiles() + { + $cleanList = self::checkInstallerFilesList(); + + $result = array(); + + foreach ($cleanList as $path) { + try { + $success = (SnapIO::rrmdir($path) !== false); + } catch (Exception $ex) { + $success = false; + } catch (Error $ex) { + $success = false; + } + + $result[$path] = $success; + } + + delete_option(self::CLEAN_INSTALL_REPORT_OPTION); + + return $result; + } +} diff --git a/src/Core/Notifications/Notice.php b/src/Core/Notifications/Notice.php new file mode 100644 index 00000000..b6f8d060 --- /dev/null +++ b/src/Core/Notifications/Notice.php @@ -0,0 +1,391 @@ + admin_url('admin-ajax.php'), + 'nonce' => wp_create_nonce('duplicator-admin-notice'), + ) + ); + } + + /** + * Display the notices. + * + * @return void + */ + public static function display() + { + + $dismissed_notices = get_user_meta(get_current_user_id(), self::DISMISSED_NOTICES_OPTKEY, true); + $dismissed_notices = is_array($dismissed_notices) ? $dismissed_notices : array(); + $dismissed_notices = array_merge($dismissed_notices, (array)get_option(self::DISMISSED_NOTICES_OPTKEY, array())); + + foreach (self::$notices as $slug => $notice) { + if (isset($dismissed_notices[$slug])) { + unset(self::$notices[$slug]); + } + } + + $output = implode('', self::$notices); + + echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + // Enqueue script only when it's needed. + if (strpos($output, 'is-dismissible') !== false) { + self::enqueues(); + } + } + + /** + * Add notice to the registry. + * + * @param string $message Message to display. + * @param string $slug Unique slug identifying the notice + * @param string $type Type of the notice. Can be [ '' (default) | 'info' | 'error' | 'success' | 'warning' ]. + * @param array $args The array of additional arguments. Please see the $defaults array below. + * + * @return void + */ + public static function add($message, $slug, $type = '', $args = array()) + { + $defaults = array( + 'dismiss' => self::DISMISS_NONE, // Dismissible level: one of the self::DISMISS_* const. By default notice is not dismissible. + 'autop' => true, // `false` if not needed to pass message through wpautop(). + 'class' => '' // Additional CSS class. + ); + + $args = wp_parse_args($args, $defaults); + $dismiss = (int)$args['dismiss']; + $classes = array(); + + if (!empty($type)) { + $classes[] = 'notice-' . esc_attr(sanitize_key($type)); + } + + if (!empty($args['class'])) { + $classes[] = esc_attr(sanitize_key($args['class'])); + } + + if ($dismiss > self::DISMISS_NONE) { + $classes[] = 'is-dismissible'; + } + + $id = $dismiss === self::DISMISS_GLOBAL ? self::DEFAULT_PREFIX . self::GLOBAL_PREFIX . $slug : self::DEFAULT_PREFIX . $slug; + $message = $args['autop'] ? wpautop($message) : $message; + $notice = sprintf( + '
                        %s
                        ', + esc_attr(implode(' ', $classes)), + esc_attr($id), + $message + ); + + self::$notices[$slug] = $notice; + } + + /** + * Add multistep notice. + * + * @param array $steps Array of info for each step. + * @param string $slug Unique slug identifying the notice + * @param string $type Type of the notice. Can be [ '' (default) | 'info' | 'error' | 'success' | 'warning' ]. + * @param array $args Array of additional arguments. Details in the self::add() method. + * + * @return void + */ + public static function addMultistep($steps, $slug, $type = '', $args = array()) + { + $content = '
                        '; + foreach ($steps as $i => $step) { + $hide = $i === 0 ? '' : ' style="display: none;"'; + $content .= '
                        '; + + $content .= $step['message']; + $content .= "

                        "; + foreach ($step["links"] as $link) { + $url = isset($link['url']) ? $link['url'] : "#"; + $target = isset($link['url']) ? 'target="_blank"' : ''; + $switch = isset($link['switch']) ? ' data-step="' . $link['switch'] . '"' : ''; + $dismiss = isset($link['dismiss']) && $link['dismiss'] ? ' class="dup-notice-dismiss"' : ''; + + $content .= '' . $link['text'] . '
                        '; + } + $content .= "

                        "; + $content .= "
                        "; + } + $content .= "
                        "; + + self::add($content, $slug, $type, $args); + } + + /** + * Add info notice. + * + * @param string $message Message to display. + * @param string $slug Unique slug identifying the notice + * @param array $args Array of additional arguments. Details in the self::add() method. + * + * @return void + */ + public static function info($message, $slug, $args = array()) + { + + self::add($message, $slug, self::NOTICE_TYPE_INFO, $args); + } + + /** + * Add error notice. + * + * @param string $message Message to display. + * @param string $slug Unique slug identifying the notice + * @param array $args Array of additional arguments. Details in the self::add() method. + * + * @return void + */ + public static function error($message, $slug, $args = array()) + { + + self::add($message, $slug, self::NOTICE_TYPE_ERROR, $args); + } + + /** + * Add success notice. + * + * @param string $message Message to display. + * @param string $slug Unique slug identifying the notice + * @param array $args Array of additional arguments. Details in the self::add() method. + * + * @return void + */ + public static function success($message, $slug, $args = array()) + { + + self::add($message, $slug, self::NOTICE_TYPE_SUCCESS, $args); + } + + /** + * Add warning notice. + * + * @param string $message Message to display. + * @param string $slug Unique slug identifying the notice + * @param array $args Array of additional arguments. Details in the self::add() method. + * + * @return void + */ + public static function warning($message, $slug, $args = array()) + { + + self::add($message, $slug, self::NOTICE_TYPE_WARNING, $args); + } + + /** + * AJAX routine that updates dismissed notices meta data. + * + * @return void + */ + public static function dismissAjax() + { + + // Run a security check. + check_ajax_referer('duplicator-admin-notice', 'nonce'); + + // Sanitize POST data. + $post = array_map('sanitize_key', wp_unslash($_POST)); + + // Update notices meta data. + if (strpos($post['id'], self::GLOBAL_PREFIX) !== false) { + // Check for permissions. + if (!current_user_can('manage_options')) { + wp_send_json_error(); + } + + $notices = self::dismissGlobal($post['id']); + $level = self::DISMISS_GLOBAL; + } else { + $notices = self::dismissUser($post['id']); + $level = self::DISMISS_USER; + } + + /** + * Allows developers to apply additional logic to the dismissing notice process. + * Executes after updating option or user meta (according to the notice level). + * + * @param string $notice_id Notice ID (slug). + * @param integer $level Notice level. + * @param array $notices Dismissed notices. + */ + do_action('duplicator_admin_notice_dismiss_ajax', $post['id'], $level, $notices); + + wp_send_json_success( + array( + 'id' => $post['id'], + 'time' => time(), + 'level' => $level, + 'notices' => $notices + ) + ); + } + + /** + * AJAX sub-routine that updates dismissed notices option. + * + * @param string $id Notice Id. + * + * @return array Notices. + */ + private static function dismissGlobal($id) + { + + $id = str_replace(self::GLOBAL_PREFIX, '', $id); + $notices = get_option(self::DISMISSED_NOTICES_OPTKEY, array()); + $notices[$id] = array( + 'time' => time() + ); + + update_option(self::DISMISSED_NOTICES_OPTKEY, $notices, true); + + return $notices; + } + + /** + * AJAX sub-routine that updates dismissed notices user meta. + * + * @param string $id Notice Id. + * + * @return array Notices. + */ + private static function dismissUser($id) + { + + $user_id = get_current_user_id(); + $notices = get_user_meta($user_id, self::DISMISSED_NOTICES_OPTKEY, true); + $notices = !is_array($notices) ? array() : $notices; + $notices[$id] = array( + 'time' => time() + ); + + update_user_meta($user_id, self::DISMISSED_NOTICES_OPTKEY, $notices); + + return $notices; + } + + /** + * Delete related option + * + * @return void + */ + public static function deleteOption() + { + delete_option(self::DISMISSED_NOTICES_OPTKEY); + } +} diff --git a/src/Core/Notifications/NoticeBar.php b/src/Core/Notifications/NoticeBar.php new file mode 100644 index 00000000..6445a5e4 --- /dev/null +++ b/src/Core/Notifications/NoticeBar.php @@ -0,0 +1,81 @@ + $value) { + if (strlen((string) $value) == 0) { + continue; + } + $utm_content .= ucfirst($key) . ' ' . $value . ' '; + } + $utm_content = trim($utm_content); + + TplMng::getInstance()->render('/parts/notice-bar', array( + 'utm_content' => $utm_content + )); + } + + /** + * Dismiss notice bar ajax action + * + * @return void + */ + public static function dismissNoticeBar() + { + // Run a security check. + check_ajax_referer('duplicator-notice-bar-dismiss', 'nonce'); + update_user_meta(get_current_user_id(), self::NOTICE_BAR_DISMISSED_OPT_KEY, true); + } + + /** + * Delete related option + * + * @return bool true on success, false on failure + */ + public static function deleteOption() + { + return SnapWP::deleteUserMetaKey(self::NOTICE_BAR_DISMISSED_OPT_KEY); + } +} diff --git a/src/Core/Notifications/Notifications.php b/src/Core/Notifications/Notifications.php new file mode 100644 index 00000000..6696e875 --- /dev/null +++ b/src/Core/Notifications/Notifications.php @@ -0,0 +1,605 @@ +init(); + } + + /** + * Check if user has access and is enabled. + * + * @return bool + */ + public static function hasAccess() + { + return current_user_can('manage_options'); + } + + /** + * Get option value. + * + * @param bool $cache Reference property cache if available. + * + * @return array + */ + public static function getOption($cache = true) + { + if (self::$option && $cache) { + return self::$option; + } + + $option = get_option(self::DUPLICATOR_NOTIFICATIONS_OPT_KEY, array()); + + self::$option = array( + 'update' => !empty($option['update']) ? (int)$option['update'] : 0, + 'feed' => !empty($option['feed']) ? (array)$option['feed'] : array(), + 'events' => !empty($option['events']) ? (array)$option['events'] : array(), + 'dismissed' => !empty($option['dismissed']) ? (array)$option['dismissed'] : array() + ); + + return self::$option; + } + + /** + * Fetch notifications from feed. + * + * @return array + */ + public static function fetchFeed() + { + $response = wp_remote_get( + self::SOURCE_URL, + array( + 'timeout' => 10, + 'user-agent' => self::getUserAgent(), + ) + ); + + if (is_wp_error($response)) { + return array(); + } + + $body = wp_remote_retrieve_body($response); + + if (empty($body)) { + return array(); + } + + return self::verify(json_decode($body, true)); + } + + /** + * Verify notification data before it is saved. + * + * @param array $notifications Array of notifications items to verify. + * + * @return array + */ + public static function verify($notifications) + { + $data = array(); + if (!is_array($notifications) || empty($notifications)) { + return $data; + } + + foreach ($notifications as $notification) { + // Ignore if one of the conditional checks is true: + // + // 1. notification message is empty. + // 2. license type does not match. + // 3. notification is expired. + // 4. notification has already been dismissed. + // 5. notification existed before installing Duplicator. + // (Prevents bombarding the user with notifications after activation). + if ( + empty($notification['content']) || + !self::isLicenseTypeMatch($notification) || + self::isExpired($notification) || + self::isDismissed($notification) || + self::isExisted($notification) + ) { + continue; + } + + $data[] = $notification; + } + + return $data; + } + + /** + * Verify saved notification data for active notifications. + * + * @param array $notifications Array of notifications items to verify. + * + * @return array + */ + public static function verifyActive($notifications) + { + if (!is_array($notifications) || empty($notifications)) { + return array(); + } + + $current_timestamp = time(); + + // Remove notifications that are not active. + foreach ($notifications as $key => $notification) { + if ( + (!empty($notification['start']) && $current_timestamp < strtotime($notification['start'])) || + (!empty($notification['end']) && $current_timestamp > strtotime($notification['end'])) + ) { + unset($notifications[$key]); + } + } + + return $notifications; + } + + /** + * Get notification data. + * + * @return array + */ + public static function get() + { + if (!self::hasAccess()) { + return array(); + } + + $option = self::getOption(); + + $feed = !empty($option['feed']) ? self::verifyActive($option['feed']) : array(); + $events = !empty($option['events']) ? self::verifyActive($option['events']) : array(); + + return array_merge($feed, $events); + } + + /** + * Get notification count. + * + * @return int + */ + public static function getCount() + { + return count(self::get()); + } + + /** + * Add a new Event Driven notification. + * + * @param array $notification Notification data. + * + * @return void + */ + public static function add($notification) + { + if (!self::isValid($notification)) { + return; + } + + $option = self::getOption(); + + // Notification ID already exists. + if (!empty($option['events'][$notification['id']])) { + return; + } + + $notification = self::verify(array($notification)); + update_option( + self::DUPLICATOR_NOTIFICATIONS_OPT_KEY, + array( + 'update' => $option['update'], + 'feed' => $option['feed'], + 'events' => array_merge($notification, $option['events']), + 'dismissed' => $option['dismissed'], + ) + ); + } + + /** + * Determine if notification data is valid. + * + * @param array $notification Notification data. + * + * @return bool + */ + public static function isValid($notification) + { + if (empty($notification['id'])) { + return false; + } + + return count(self::verify(array($notification))) > 0; + } + + /** + * Determine if notification has already been dismissed. + * + * @param array $notification Notification data. + * + * @return bool + */ + private static function isDismissed($notification) + { + $option = self::getOption(); + + return !empty($option['dismissed']) && in_array($notification['id'], $option['dismissed']); + } + + /** + * Determine if license type is match. + * + * @param array $notification Notification data. + * + * @return bool + */ + private static function isLicenseTypeMatch($notification) + { + // A specific license type is not required. + $notification['type'] = (array)$notification['type']; + if (empty($notification['type'])) { + return false; + } + + if (in_array('any', $notification['type'])) { + return true; + } + + return in_array(self::getLicenseType(), (array)$notification['type'], true); + } + + /** + * Determine if notification is expired. + * + * @param array $notification Notification data. + * + * @return bool + */ + private static function isExpired($notification) + { + return !empty($notification['end']) && time() > strtotime($notification['end']); + } + + /** + * Determine if notification existed before installing Duplicator. + * + * @param array $notification Notification data. + * + * @return bool + */ + private static function isExisted($notification) + { + $installInfo = DUP_LITE_Plugin_Upgrade::getInstallInfo(); + return (!empty($notification['start']) && $installInfo['time'] > strtotime($notification['start'])); + } + + /** + * Update notification data from feed. + * + * @return void + */ + public static function update() + { + $option = self::getOption(); + + //Only update twice daily + if ($option['update'] !== 0 && time() < $option['update'] + DAY_IN_SECONDS / 2) { + return; + } + + $data = array( + 'update' => time(), + 'feed' => self::fetchFeed(), + 'events' => $option['events'], + 'dismissed' => $option['dismissed'], + ); + + /** + * Allow changing notification data before it will be updated in database. + * + * @param array $data New notification data. + */ + $data = (array)apply_filters('duplicator_admin_notifications_update_data', $data); + + update_option(self::DUPLICATOR_NOTIFICATIONS_OPT_KEY, $data); + } + + /** + * Remove notification data from database before a plugin is deactivated. + * + * @param string $plugin Path to the plugin file relative to the plugins directory. + * + * @return void + */ + public static function delete($plugin) + { + $duplicator_plugins = array( + 'duplicator-lite/duplicator.php', + 'duplicator/duplicator.php', + ); + + if (!in_array($plugin, $duplicator_plugins, true)) { + return; + } + + delete_option(self::DUPLICATOR_NOTIFICATIONS_OPT_KEY); + } + + /** + * Enqueue assets on Form Overview admin page. + * + * @return void + */ + public static function enqueues() + { + if (!self::getCount()) { + return; + } + + wp_enqueue_style( + 'dup-admin-notifications', + DUPLICATOR_PLUGIN_URL . "assets/css/admin-notifications.css", + array('dup-lity'), + DUPLICATOR_VERSION + ); + + wp_enqueue_script( + 'dup-admin-notifications', + DUPLICATOR_PLUGIN_URL . "assets/js/notifications/admin-notifications.js", + array('jquery', 'dup-lity'), + DUPLICATOR_VERSION, + true + ); + + wp_localize_script( + 'dup-admin-notifications', + 'dup_admin_notifications', + array( + 'ajax_url' => admin_url('admin-ajax.php'), + 'nonce' => wp_create_nonce(self::DUPLICATOR_NOTIFICATION_NONCE_KEY), + ) + ); + + // Lity. + wp_enqueue_style( + 'dup-lity', + DUPLICATOR_PLUGIN_URL . 'assets/lib/lity/lity.min.css', + array(), + DUPLICATOR_VERSION + ); + + wp_enqueue_script( + 'dup-lity', + DUPLICATOR_PLUGIN_URL . 'assets/lib/lity/lity.min.js', + array('jquery'), + DUPLICATOR_VERSION, + true + ); + } + + /** + * Output notifications on Form Overview admin area. + * + * @return void + */ + public static function output() + { + $notificationsData = self::get(); + + if (empty($notificationsData)) { + return; + } + + + $content_allowed_tags = array( + 'br' => array(), + 'em' => array(), + 'strong' => array(), + 'span' => array( + 'style' => array() + ), + 'p' => array( + 'id' => array(), + 'class' => array() + ), + 'a' => array( + 'href' => array(), + 'target' => array(), + 'rel' => array() + ) + ); + + $notifications = array(); + foreach ($notificationsData as $notificationData) { + // Prepare required arguments. + $notificationData = wp_parse_args( + $notificationData, + array( + 'id' => 0, + 'title' => '', + 'content' => '', + 'video' => '' + ) + ); + + $title = self::getComponentData($notificationData['title']); + $content = self::getComponentData($notificationData['content']); + + if (!$title && !$content) { + continue; + } + + $notifications[] = array( + 'id' => $notificationData['id'], + 'title' => $title, + 'btns' => self::getButtonsData($notificationData), + 'content' => wp_kses(wpautop($content), $content_allowed_tags), + 'video_url' => wp_http_validate_url(self::getComponentData($notificationData['video'])), + ); + } + + self::enqueues(); + TplMng::getInstance()->render( + 'parts/Notifications/main', + array( + 'notifications' => $notifications + ) + ); + } + + /** + * Retrieve notification's buttons. + * + * @param array $notification Notification data. + * + * @return array + */ + private static function getButtonsData($notification) + { + if (empty($notification['btn']) || !is_array($notification['btn'])) { + return array(); + } + + $buttons = array(); + if (!empty($notification['btn']['main_text']) && !empty($notification['btn']['main_url'])) { + $buttons[] = array( + 'type' => 'primary', + 'text' => $notification['btn']['main_text'], + 'url' => self::prepareBtnUrl($notification['btn']['main_url']), + 'target' => '_blank' + ); + } + + if (!empty($notification['btn']['alt_text']) && !empty($notification['btn']['alt_url'])) { + $buttons[] = array( + 'type' => 'secondary', + 'text' => $notification['btn']['alt_text'], + 'url' => self::prepareBtnUrl($notification['btn']['alt_url']), + 'target' => '_blank' + ); + } + + return $buttons; + } + + /** + * Retrieve notification's component data by a license type. + * + * @param mixed $data Component data. + * + * @return false|mixed + */ + private static function getComponentData($data) + { + if (empty($data['license'])) { + return $data; + } + + $license_type = self::getLicenseType(); + return !empty($data['license'][$license_type]) ? $data['license'][$license_type] : false; + } + + /** + * Retrieve the current installation license type (always lowercase). + * + * @return string + */ + private static function getLicenseType() + { + return 'lite'; + } + + /** + * Prepare button URL. + * + * @param string $btnUrl Button url. + * + * @return string + */ + private static function prepareBtnUrl($btnUrl) + { + if (empty($btnUrl)) { + return ''; + } + + $replace_tags = array( + '{admin_url}' => admin_url() + ); + + return wp_http_validate_url(str_replace(array_keys($replace_tags), array_values($replace_tags), $btnUrl)); + } + + /** + * User agent that will be used for the request + * + * @return string + */ + private static function getUserAgent() + { + return 'WordPress/' . get_bloginfo('version') . '; ' . get_bloginfo('url') . '; Duplicator/Lite-' . DUPLICATOR_VERSION; + } +} diff --git a/src/Core/Notifications/Review.php b/src/Core/Notifications/Review.php new file mode 100644 index 00000000..0d2ccc7b --- /dev/null +++ b/src/Core/Notifications/Review.php @@ -0,0 +1,214 @@ + '=' , 'status' => \DUP_PackageStatus::COMPLETE ) + )); + + // Display if plugin has been installed for at least 3 days and has a package installed + if ((($installInfo['time'] + (DAY_IN_SECONDS * 3)) < time() && $numberOfPackages > 0)) { + $display = true; + } + + //Display if it's been 3 days after a successful migration + $migrationTime = MigrationMng::getMigrationData('time'); + if (!$display && $migrationTime !== false && (($migrationTime + (DAY_IN_SECONDS * 3)) < time())) { + $display = true; + } + + if (!$display) { + return; + } + + Notice::addMultistep( + array( + array( + "message" => "

                        " . sprintf(__('Are you enjoying %s?', 'duplicator'), 'Duplicator') . "

                        ", + "links" => array( + array( + "text" => __('Yes', 'duplicator'), + "switch" => 1 + ), + array( + "text" => __('Not really', 'duplicator'), + "switch" => 2 + ) + ) + ), + array( + "message" => "

                        " . + __( + 'That’s awesome! Could you please do me a BIG favor and give it a 5-star rating on ' . + 'WordPress to help us spread the word and boost our motivation?', + 'duplicator' + ) . "

                        " . + "

                        " . wp_kses(__('~ John Turner
                        President of Duplicator', 'duplicator'), array('br' => array())) . "

                        ", + "links" => array( + array( + "url" => self::getReviewUrl(), + "text" => __('Ok, you deserve it', 'duplicator'), + "dismiss" => true + ), + array( + "text" => __('Nope, maybe later', 'duplicator'), + "dismiss" => true + ), + array( + "text" => __('I already did', 'duplicator'), + "dismiss" => true + ) + ) + ), + array( + "message" => "

                        " . + __( + 'We\'re sorry to hear you aren\'t enjoying Duplicator. We would love a chance to improve. ' . + 'Could you take a minute and let us know what we can do better?', + 'duplicator' + ) . "

                        ", + "links" => array( + array( + "url" => self::getFeedbackUrl(), + "text" => __('Give Feedback', 'duplicator'), + "dismiss" => true + ), + array( + "text" => __('No thanks', 'duplicator'), + "dismiss" => true + ) + ) + ) + ), + self::REVIEW_REQUEST_NOTICE_SLUG, + Notice::NOTICE_TYPE_INFO, + array( + 'dismiss' => Notice::DISMISS_GLOBAL, + 'autop' => false, + 'class' => 'dup-review-notice', + ) + ); + } + + /** + * @return string The review url on wordpress.org + */ + public static function getReviewUrl() + { + return "https://wordpress.org/support/plugin/duplicator/reviews/?filter=5#new-post"; + } + + /** + * @return string The snapcreek feedback url + */ + public static function getFeedbackUrl() + { + return DUPLICATOR_BLOG_URL . "contact/"; + } + + /** + * When user is on a Duplicator related admin page, display footer text + * that graciously asks them to rate us. + * + * @param string $text Footer text. + * + * @return string + */ + public static function adminFooter($text) + { + //Show only on duplicator pages + if ( + ! is_admin() || + empty($_REQUEST['page']) || + strpos($_REQUEST['page'], 'duplicator') === false + ) { + return false; + } + + $text = sprintf( + wp_kses( /* translators: $1$s - WPForms plugin name; $2$s - WP.org review link; $3$s - WP.org review link. */ + __( + 'Please rate Duplicator ' . + '★★★★★' . + ' on WordPress.org to help us spread the word. Thank you from the Duplicator team!', + 'duplicator' + ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), + 'rel' => array(), + ), + 'strong' => array() + ) + ), + self::getReviewUrl() + ); + + return $text; + } +} diff --git a/src/Core/Unistall.php b/src/Core/Unistall.php new file mode 100644 index 00000000..522aea4a --- /dev/null +++ b/src/Core/Unistall.php @@ -0,0 +1,42 @@ +')) { + return; + } + + if (($data = get_option(EmailSummary::INFO_OPT_OLD_KEY)) !== false) { + update_option(EmailSummary::INFO_OPT_KEY, $data); + delete_option(EmailSummary::INFO_OPT_OLD_KEY); + } + } + + /** + * Update storage position option + * + * @param false|string $currentVersion current Duplicator version, false if is first installation + * + * @return void + */ + private static function updateStoragePostition($currentVersion) + { + //PRE 1.3.35 + //Do not update to new wp-content storage till after + if ($currentVersion !== false && version_compare($currentVersion, self::FIRST_VERSION_NEW_STORAGE_POSITION, '<')) { + DUP_Settings::Set('storage_position', DUP_Settings::STORAGE_POSITION_LEGACY); + } + } +} diff --git a/src/Core/Views/TplMng.php b/src/Core/Views/TplMng.php new file mode 100644 index 00000000..08720c88 --- /dev/null +++ b/src/Core/Views/TplMng.php @@ -0,0 +1,244 @@ +mainFolder = DUPLICATOR_PLUGIN_PATH . '/template/'; + } + + /** + * If strip spaces is true in render method spaced between tag are removed + * + * @param bool $strip if true strip spaces + * + * @return void + */ + public static function setStripSpaces($strip) + { + self::$stripSpaces = (bool) $strip; + } + + /** + * Set template global value in template data + * + * @param string $key global value key + * @param mixed $val value + * + * @return void + */ + public function setGlobalValue($key, $val) + { + $this->globalData[$key] = $val; + } + + /** + * Remove global value if exist + * + * @param string $key gloval value key + * + * @return void + */ + public function unsetGlobalValue($key) + { + if (isset($this->globalData[$key])) { + unset($this->globalData[$key]); + } + } + + /** + * Return true if global values exists + * + * @param string $key gloval value key + * + * @return bool + */ + public function hasGlobalValue($key) + { + return isset($this->globalData[$key]); + } + + /** + * Multiple global data set + * + * @param array $data data tu set in global data + * + * @return void + */ + public function updateGlobalData(array $data = array()) + { + $this->globalData = array_merge($this->globalData, (array) $data); + } + + /** + * Return global data + * + * @return array + */ + public function getGlobalData() + { + return $this->globalData; + } + + /** + * Render template + * + * @param string $slugTpl template file is a relative path from root template folder + * @param array $args array key / val where key is the var name in template + * @param bool $echo if false return template in string + * + * @return string + */ + public function render($slugTpl, $args = array(), $echo = true) + { + ob_start(); + if (($renderFile = $this->getFileTemplate($slugTpl)) !== false) { + $tplData = apply_filters(self::getDataHook($slugTpl), array_merge($this->globalData, $args)); + $tplMng = $this; + require($renderFile); + } else { + echo '

                        FILE TPL NOT FOUND: ' . $slugTpl . '

                        '; + } + $renderResult = apply_filters(self::getRenderHook($slugTpl), ob_get_clean()); + + if (self::$stripSpaces) { + $renderResult = preg_replace('~>[\n\s]+<~', '><', $renderResult); + } + if ($echo) { + echo $renderResult; + return ''; + } else { + return $renderResult; + } + } + + /** + * Render template in json string + * + * @param string $slugTpl template file is a relative path from root template folder + * @param array $args array key / val where key is the var name in template + * @param bool $echo if false return template in string + * + * @return string + */ + public function renderJson($slugTpl, $args = array(), $echo = true) + { + $renderResult = SnapJson::jsonEncode($this->render($slugTpl, $args, false)); + if ($echo) { + echo $renderResult; + return ''; + } else { + return $renderResult; + } + } + + /** + * Render template apply esc attr + * + * @param string $slugTpl template file is a relative path from root template folder + * @param array $args array key / val where key is the var name in template + * @param bool $echo if false return template in string + * + * @return string + */ + public function renderEscAttr($slugTpl, $args = array(), $echo = true) + { + $renderResult = esc_attr($this->render($slugTpl, $args, false)); + if ($echo) { + echo $renderResult; + return ''; + } else { + return $renderResult; + } + } + + /** + * Get hook unique from template slug + * + * @param string $slugTpl template slug + * + * @return string + */ + public static function tplFileToHookSlug($slugTpl) + { + return str_replace(array('\\', '/', '.'), '_', $slugTpl); + } + + /** + * Return data hook from template slug + * + * @param string $slugTpl template slug + * + * @return string + */ + public static function getDataHook($slugTpl) + { + return 'duplicator_template_data_' . self::tplFileToHookSlug($slugTpl); + } + + /** + * Return render hook from template slug + * + * @param string $slugTpl template slug + * + * @return string + */ + public static function getRenderHook($slugTpl) + { + return 'duplicator_template_render_' . self::tplFileToHookSlug($slugTpl); + } + + /** + * Acctept html of php extensions. if the file have unknown extension automatic add the php extension + * + * @param string $slugTpl template slug + * + * @return boolean|string return false if don\'t find the template file + */ + protected function getFileTemplate($slugTpl) + { + $fullPath = $this->mainFolder . $slugTpl . '.php'; + + if (file_exists($fullPath)) { + return $fullPath; + } else { + return false; + } + } +} diff --git a/src/Libs/Certificates/cacert.pem b/src/Libs/Certificates/cacert.pem new file mode 100644 index 00000000..0bf312fe --- /dev/null +++ b/src/Libs/Certificates/cacert.pem @@ -0,0 +1,3232 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue Oct 26 03:12:05 2021 GMT +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.28. +## SHA256: bb36818a81feaa4cca61101e6d6276cd09e972efcb08112dfed846918ca41d7f +## + + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +======================================== +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz +0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j +Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn +RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O ++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq +/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE +Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM +lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 +yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ +eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW +FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ +7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ +Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM +8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi +FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi +yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c +J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw +sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl +OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV +MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF +JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +Staat der Nederlanden EV Root CA +================================ +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M +MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl +cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk +SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW +O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r +0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 +Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV +XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr +08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV +0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd +74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx +fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa +ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu +c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq +5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN +b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN +f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi +5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 +WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK +DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy +eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +TrustCor RootCert CA-1 +====================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx +MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu +YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe +VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy +dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq +jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4 +pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0 +JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h +gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw +/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j +BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5 +mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C +qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P +3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +TrustCor RootCert CA-2 +====================== +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w +DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT +eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0 +eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy +MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h +bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0 +IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb +ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk +RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1 +oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb +XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1 +/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q +jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP +eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg +rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU +2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h +Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp +kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv +2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3 +S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw +PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv +DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU +RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE +xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX +RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ +-----END CERTIFICATE----- + +TrustCor ECA-1 +============== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw +N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5 +MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y +IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR +MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23 +xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc +p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+ +fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj +YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL +f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u +/ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs +J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC +jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +GlobalSign Root CA - R6 +======================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX +R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i +YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs +U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss +grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE +3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF +vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM +PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ +azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O +WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy +CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP +0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN +b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV +HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 +lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY +BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym +Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr +3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 +0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T +uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK +oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t +JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GC CA +=============================== +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD +SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo +MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa +Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL +ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr +VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab +NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E +AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk +AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG +EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv +b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG +A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx +9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r +aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW +r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM +LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly +4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr +06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om +3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu +JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM +BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv +fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm +ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b +gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq +4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr +tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo +pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0 +sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql +CFF1pkgl +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG +EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv +b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG +A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk +k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo +7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI +m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm +dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu +ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz +cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl +aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy +5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM +BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ ++YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw +c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da +WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r +n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu +Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ +7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs +gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld +o/DUhgkC +-----END CERTIFICATE----- + +GTS Root R3 +=========== +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU +Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej +QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP +0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0 +glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa +KaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa +6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj +QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV +2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI +N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x +zPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +UCA Global G2 Root +================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x +NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU +cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT +oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV +8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS +h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o +LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ +R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe +KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa +4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc +OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 +8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo +5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A +Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 +yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX +c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo +jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk +bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x +ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn +RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== +-----END CERTIFICATE----- + +UCA Extended Validation Root +============================ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u +IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G +A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs +iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF +Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu +eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR +59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH +0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR +el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv +B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth +WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS +NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS +3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM +aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 +dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb ++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW +F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi +GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc +GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi +djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr +dhh2n1ax +-----END CERTIFICATE----- + +Certigna Root CA +================ +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE +BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ +MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda +MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz +MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX +stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz +KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 +JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 +XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq +4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej +wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ +lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI +jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ +/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy +dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h +LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl +cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt +OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP +TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq +7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 +4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd +8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS +6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY +tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS +aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde +E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +emSign Root CA - G1 +=================== +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET +MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl +ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx +ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk +aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN +LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 +cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW +DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ +6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH +hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 +vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q +NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q ++Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih +U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +emSign ECC Root CA - G3 +======================= +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG +A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg +MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 +MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 +ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc +58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr +MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D +CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 +jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +emSign Root CA - C1 +=================== +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx +EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp +Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD +ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up +ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ +Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX +OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V +I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms +lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ +XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp +/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 +NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 +wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ +BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +emSign ECC Root CA - C3 +======================= +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG +A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF +Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD +ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd +6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 +SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA +B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA +MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU +ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 3 +======================= +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG +A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK +Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 +MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv +bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX +SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz +iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf +jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim +5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe +sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj +0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ +JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u +y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h ++bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG +xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID +AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN +AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw +W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld +y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov ++BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc +eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw +9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 +nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY +hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB +60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq +dBb9HxEGmpv0 +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G4 +========================================= +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu +bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 +dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT +AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D +umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV +3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds +8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ +e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 +ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X +xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV +7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW +Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n +MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q +jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht +7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK +YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt +jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ +m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW +RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA +JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G ++TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT +kcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +Microsoft ECC Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND +IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 +MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 +thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB +eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM ++Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf +Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR +eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +Microsoft RSA Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg +UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw +NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml +7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e +S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 +1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ +dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F +yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS +MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr +lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ +0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ +ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og +6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 +dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk ++ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex +/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy +AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW +ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE +7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT +c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D +5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +e-Szigno Root CA 2017 +===================== +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw +DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt +MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa +Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE +CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp +Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx +s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv +vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA +tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO +svxyqltZ+efcMQ== +-----END CERTIFICATE----- + +certSIGN Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw +EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy +MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH +TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 +N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk +abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg +wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp +dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh +ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 +jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf +95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc +z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL +iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB +ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB +/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 +8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 +BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW +atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU +Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M +NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N +0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +Trustwave Global Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 +zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf +LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq +stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o +WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ +OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 +Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE +uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm ++9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj +ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H +PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H +ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla +4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R +vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd +zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O +856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH +Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu +3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP +29FpHOTKyeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +Trustwave Global ECC P256 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 +NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj +43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm +P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt +0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz +RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +Trustwave Global ECC P384 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 +NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH +Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr +/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV +HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn +ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl +CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== +-----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- diff --git a/src/Libs/DupArchive/DupArchive.php b/src/Libs/DupArchive/DupArchive.php new file mode 100644 index 00000000..69bc8b2a --- /dev/null +++ b/src/Libs/DupArchive/DupArchive.php @@ -0,0 +1,286 @@ +': + $retVal = self::HEADER_TYPE_DIR; + break; + case '': + $retVal = self::HEADER_TYPE_FILE; + break; + case '': + $retVal = self::HEADER_TYPE_GLOB; + break; + default: + throw new Exception("Invalid header marker {$marker}. Location:" . ftell($archiveHandle)); + } + } + + return $retVal; + } + + /** + * Get archive index data + * + * @param string $archivePath archive path + * + * @return bool|array return index data, false if don't exists + */ + public static function getIndexData($archivePath) + { + try { + $indexContent = self::getSrcFile($archivePath, self::INDEX_FILE_NAME, 0, 3000, false); + if ($indexContent === false) { + return false; + } + $indexData = json_decode(rtrim($indexContent, "\0"), true); + + if (!is_array($indexData)) { + return false; + } + } catch (Exception $e) { + return false; + } catch (Error $e) { + return false; + } + + return $indexData; + } + + /** + * Get extra files offset if set or 0 + * + * @param string $archivePath archive path + * + * @return int + */ + public static function getExtraOffset($archivePath) + { + if (($indexData = self::getIndexData($archivePath)) === false) { + return 0; + } + return (isset($indexData[self::EXTRA_FILES_POS_KEY]) ? $indexData[self::EXTRA_FILES_POS_KEY] : 0); + } + + /** + * Add file in archive from src + * + * @param string $archivePath archive path + * @param string $relativePath relative path + * @param int $offset start search location + * @param int $sizeToSearch max size where search + * + * @return bool|int false if file not found of path position + */ + public static function seachPathInArchive($archivePath, $relativePath, $offset = 0, $sizeToSearch = 0) + { + if (($archiveHandle = fopen($archivePath, 'rb')) === false) { + throw new Exception("Can’t open archive at $archivePath!"); + } + $result = self::searchPath($archivePath, $relativePath, $offset, $sizeToSearch); + @fclose($archiveHandle); + return $result; + } + + /** + * Search path, if found set and return position + * + * @param resource $archiveHandle dup archive resource + * @param string $relativePath relative path to extract + * @param int $offset start search location + * @param int $sizeToSearch max size where search + * + * @return bool|int false if file not found of path position + */ + public static function searchPath($archiveHandle, $relativePath, $offset = 0, $sizeToSearch = 0) + { + if (!is_resource($archiveHandle)) { + throw new Exception('Archive handle must be a resource'); + } + + if (fseek($archiveHandle, $offset, SEEK_SET) < 0) { + return false; + } + + if ($offset == 0) { + DupArchiveReaderHeader::readFromArchive($archiveHandle); + } + + $result = false; + $position = ftell($archiveHandle); + $continue = true; + + do { + switch (($type = self::getNextHeaderType($archiveHandle))) { + case self::HEADER_TYPE_FILE: + $currentFileHeader = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, true, true); + if ($currentFileHeader->relativePath == $relativePath) { + $continue = false; + $result = $position; + } + break; + case self::HEADER_TYPE_DIR: + $directoryHeader = DupArchiveReaderDirectoryHeader::readFromArchive($archiveHandle, true); + if ($directoryHeader->relativePath == $relativePath) { + $continue = false; + $result = $position; + } + break; + case self::HEADER_TYPE_NONE: + $continue = false; + break; + default: + throw new Exception('Invali header type "' . $type . '"'); + } + $position = ftell($archiveHandle); + if ($sizeToSearch > 0 && ($position - $offset) >= $sizeToSearch) { + break; + } + } while ($continue); + + if ($result !== false) { + if (fseek($archiveHandle, $result, SEEK_SET) < 0) { + return false; + } + } + return $result; + } + + /** + * Get file content + * + * @param string $archivePath archvie path + * @param string $relativePath relative path to extract + * @param int $offset start search location + * @param int $sizeToSearch max size where search + * @param bool $isCompressed true if is compressed + * + * @return bool|string false if file not found + */ + public static function getSrcFile($archivePath, $relativePath, $offset = 0, $sizeToSearch = 0, $isCompressed = null) + { + if (($archiveHandle = fopen($archivePath, 'rb')) === false) { + throw new Exception("Can’t open archive at $archivePath!"); + } + $archiveHeader = DupArchiveReaderHeader::readFromArchive($archiveHandle); + if (is_null($isCompressed)) { + $isCompressed = $archiveHeader->isCompressed; + } + + if (self::searchPath($archiveHandle, $relativePath, $offset, $sizeToSearch) === false) { + return false; + } + + if (self::getNextHeaderType($archiveHandle) != self::HEADER_TYPE_FILE) { + return false; + } + + $header = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, false, true); + $result = self::getSrcFromHeader($archiveHandle, $header, $isCompressed); + @fclose($archiveHandle); + return $result; + } + + /** + * Get src file form header + * + * @param resource $archiveHandle archive handle + * @param DupArchiveReaderFileHeader $fileHeader file header + * @param bool $isCompressed true if is compressed + * + * @return string + */ + protected static function getSrcFromHeader($archiveHandle, DupArchiveReaderFileHeader $fileHeader, $isCompressed) + { + if ($fileHeader->fileSize == 0) { + return ''; + } + $dataSize = 0; + $result = ''; + + do { + $globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle); + $result .= DupArchiveReaderGlobHeader::readContent($archiveHandle, $globHeader, $isCompressed); + $dataSize += $globHeader->originalSize; + } while ($dataSize < $fileHeader->fileSize); + + return $result; + } + + /** + * Skip file in archive + * + * @param resource $archiveHandle dup archive resource + * @param DupArchiveFileHeader $fileHeader file header + * + * @return void + */ + protected static function skipFileInArchive($archiveHandle, DupArchiveReaderFileHeader $fileHeader) + { + if ($fileHeader->fileSize == 0) { + return; + } + $dataSize = 0; + + do { + $globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle, true); + $dataSize += $globHeader->originalSize; + } while ($dataSize < $fileHeader->fileSize); + } + + /** + * Assumes we are on one header and just need to get to the next + * + * @param resource $archiveHandle dup archive resource + * + * @return void + */ + protected static function skipToNextHeader($archiveHandle) + { + $headerType = self::getNextHeaderType($archiveHandle); + switch ($headerType) { + case self::HEADER_TYPE_FILE: + $fileHeader = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, false, true); + self::skipFileInArchive($archiveHandle, $fileHeader); + break; + case self::HEADER_TYPE_DIR: + DupArchiveReaderDirectoryHeader::readFromArchive($archiveHandle, true); + break; + case self::HEADER_TYPE_NONE: + false; + } + } +} diff --git a/src/Libs/DupArchive/DupArchiveEngine.php b/src/Libs/DupArchive/DupArchiveEngine.php new file mode 100644 index 00000000..6545013d --- /dev/null +++ b/src/Libs/DupArchive/DupArchiveEngine.php @@ -0,0 +1,827 @@ +basepathLength); + $result = ltrim($result, '/'); + if ($createState->newBasePath !== null) { + $result = $createState->newBasePath . $result; + } + } else { + $safePath = SnapIO::safePathUntrailingslashit($path); + $result = ltrim( + $createState->newBasePath . preg_replace('/^' . preg_quote(self::$targetRootPath, '/') . '(.*)/m', '$1', $safePath), + '/' + ); + } + return $result; + } + + /** + * Get archvie info from path + * + * @param string $filepath archvie path + * + * @return DupArchiveInfo + */ + public static function getArchiveInfo($filepath) + { + $archiveInfo = new DupArchiveInfo(); + + DupArchiveUtil::log("archive size=" . filesize($filepath)); + $archiveHandle = SnapIO::fopen($filepath, 'rb'); + $archiveInfo->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle); + $moreToRead = true; + + while ($moreToRead) { + $headerType = self::getNextHeaderType($archiveHandle); + + // DupArchiveUtil::log("next header type=$headerType: " . ftell($archiveHandle)); + + switch ($headerType) { + case self::HEADER_TYPE_FILE: + $fileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, true, true); + $archiveInfo->fileHeaders[] = $fileHeader; + DupArchiveUtil::log("file" . $fileHeader->relativePath); + break; + + case self::HEADER_TYPE_DIR: + $directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true); + + $archiveInfo->directoryHeaders[] = $directoryHeader; + break; + + case self::HEADER_TYPE_NONE: + $moreToRead = false; + } + } + return $archiveInfo; + } + + /** + * Add folder to archive + * + * can't span requests since create state can't store list of files + * + * @param string $archiveFilepath archive file + * @param string $directory folder to add + * @param string $basepath base path to consider (?) + * @param boolean $includeFiles if true include files + * @param string $newBasepath new base path + * @param int $globSize global size + * + * @return stdClass + */ + public static function addDirectoryToArchiveST( + $archiveFilepath, + $directory, + $basepath, + $includeFiles = false, + $newBasepath = null, + $globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE + ) { + if ($includeFiles) { + $scan = DupArchiveScanUtil::createScanObject($directory); + } else { + $scan = new stdClass(); + $scan->Files = array(); + $scan->Dirs = array(); + } + + $createState = new DupArchiveSimpleCreateState(); + + $createState->archiveOffset = filesize($archiveFilepath); + $createState->archivePath = $archiveFilepath; + $createState->basePath = $basepath; + $createState->basepathLength = strlen($basepath); + $createState->timerEnabled = false; + $createState->globSize = $globSize; + $createState->newBasePath = $newBasepath; + + self::addItemsToArchive($createState, $scan); + + $retVal = new stdClass(); + $retVal->numDirsAdded = $createState->currentDirectoryIndex; + $retVal->numFilesAdded = $createState->currentFileIndex; + + if ($createState->skippedFileCount > 0) { + throw new Exception("One or more files were were not able to be added when adding {$directory} to {$archiveFilepath}"); + } elseif ($createState->skippedDirectoryCount > 0) { + throw new Exception("One or more directories were not able to be added when adding {$directory} to {$archiveFilepath}"); + } + + return $retVal; + } + + /** + * Add relative file to archive + * + * @param string $archiveFilepath archive file + * @param string $filepath file to add + * @param string $relativePath relative path in archive + * @param int $globSize global size + * + * @return void + */ + public static function addRelativeFileToArchiveST( + $archiveFilepath, + $filepath, + $relativePath, + $globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE + ) { + $createState = new DupArchiveSimpleCreateState(); + + $createState->archiveOffset = filesize($archiveFilepath); + $createState->archivePath = $archiveFilepath; + $createState->basePath = null; + $createState->basepathLength = 0; + $createState->timerEnabled = false; + $createState->globSize = $globSize; + + $scan = new stdClass(); + + $scan->Files = array(); + $scan->Dirs = array(); + + $scan->Files[] = $filepath; + + if ($relativePath != null) { + $scan->FileAliases = array(); + $scan->FileAliases[$filepath] = $relativePath; + } + + self::addItemsToArchive($createState, $scan); + } + + /** + * Add file in archive from src + * + * @param string|resource $archive Archive path or archive handle + * @param string $src source string + * @param string $relativeFilePath relative path + * @param int $forceSize if 0 size is auto of content is filled of \0 char to size + * + * @return bool + */ + public static function addFileFromSrc( + $archive, + $src, + $relativeFilePath, + $forceSize = 0 + ) { + if (is_resource($archive)) { + $archiveHandle = $archive; + SnapIO::fseek($archiveHandle, 0, SEEK_SET); + } else { + if (($archiveHandle = SnapIO::fopen($archive, 'r+b')) == false) { + throw new Exception('Can\'t open archive'); + } + } + + $createState = new DupArchiveSimpleCreateState(); + $createState->archiveOffset = SnapIO::ftell($archiveHandle); + $createState->basePath = dirname($relativeFilePath); + $createState->basepathLength = strlen($createState->basePath); + $createState->timerEnabled = false; + + if ($forceSize == 0) { + $archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle); + $createState->isCompressed = $archiveHeader->isCompressed; + } else { + // ff force size is enables the src isn't compress + $createState->isCompressed = false; + } + + SnapIO::fseek($archiveHandle, 0, SEEK_END); + + $result = DupArchiveFileProcessor::writeFileSrcToArchive($createState, $archiveHandle, $src, $relativeFilePath, $forceSize); + + if (!is_resource($archive)) { + SnapIO::fclose($archiveHandle); + } + return $result; + } + + /** + * Add file in archive from src + * + * @param string $archiveFilepath archive path + * @param string $src source string + * @param string $relativeFilePath relative path + * @param int $offset start search location + * @param int $sizeToSearch max size where search + * + * @return bool + */ + public static function replaceFileContent( + $archiveFilepath, + $src, + $relativeFilePath, + $offset = 0, + $sizeToSearch = 0 + ) { + if (($archiveHandle = SnapIO::fopen($archiveFilepath, 'r+b')) == false) { + throw new Exception('Can\'t open archive'); + } + + if (($filePos = self::searchPath($archiveHandle, $relativeFilePath, $offset, $sizeToSearch)) == false) { + return false; + } + $fileHeader = DupArchiveReaderFileHeader::readFromArchive($archiveHandle); + $globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle); + SnapIO::fseek($archiveHandle, $filePos); + + $createState = new DupArchiveSimpleCreateState(); + $createState->archivePath = $archiveFilepath; + $createState->archiveOffset = $filePos; + $createState->basePath = dirname($relativeFilePath); + $createState->basepathLength = strlen($createState->basePath); + $createState->timerEnabled = false; + $createState->isCompressed = false; // replaced content can't be compressed + + $forceSize = $globHeader->storedSize; + + $result = DupArchiveFileProcessor::writeFileSrcToArchive($createState, $archiveHandle, $src, $relativeFilePath, $forceSize); + SnapIO::fclose($archiveHandle); + + return $result; + } + + + /** + * Add file in archive using base dir + * + * @param string $archiveFilepath archive file + * @param string $basePath base path + * @param string $filepath file to add + * @param int $globSize global size + * + * @return void + */ + public static function addFileToArchiveUsingBaseDirST( + $archiveFilepath, + $basePath, + $filepath, + $globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE + ) { + $createState = new DupArchiveSimpleCreateState(); + + $createState->archiveOffset = filesize($archiveFilepath); + $createState->archivePath = $archiveFilepath; + $createState->basePath = $basePath; + $createState->basepathLength = strlen($basePath); + $createState->timerEnabled = false; + $createState->globSize = $globSize; + + $scan = new stdClass(); + + $scan->Files = array(); + $scan->Dirs = array(); + + $scan->Files[] = $filepath; + + self::addItemsToArchive($createState, $scan); + } + + /** + * Create archive + * + * @param string $archivePath archive file path + * @param bool $isCompressed is compressed + * + * @return void + */ + public static function createArchive($archivePath, $isCompressed) + { + if (($archiveHandle = SnapIO::fopen($archivePath, 'w+b')) === false) { + throw new Exception('Can\t create dup archvie file ' . $archivePath); + } + + $archiveHeader = DupArchiveHeader::create($isCompressed); + $archiveHeader->writeToArchive($archiveHandle); + + //reserver space for index + $src = json_encode(array('test')); + $src .= str_repeat("\0", self::INDEX_FILE_SIZE - strlen($src)); + self::addFileFromSrc($archiveHandle, $src, self::INDEX_FILE_NAME, self::INDEX_FILE_SIZE); + + // Intentionally do not write build state since if something goes wrong we went it to start over on the archive + SnapIO::fclose($archiveHandle); + } + + /** + * Add items to archive + * + * @param DupArchiveCreateState $createState create state info + * @param stdClass $scanFSInfo scan if + * + * @return void + */ + public static function addItemsToArchive(DupArchiveCreateState $createState, stdClass $scanFSInfo) + { + if ($createState->globSize == -1) { + $createState->globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE; + } + + DupArchiveUtil::tlogObject("addItemsToArchive start", $createState); + + $directoryCount = count($scanFSInfo->Dirs); + $fileCount = count($scanFSInfo->Files); + $createState->startTimer(); + $archiveHandle = SnapIO::fopen($createState->archivePath, 'r+b'); + + DupArchiveUtil::tlog("Archive size=", filesize($createState->archivePath)); + DupArchiveUtil::tlog("Archive location is now " . SnapIO::ftell($archiveHandle)); + + $archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle); + + $createState->isCompressed = $archiveHeader->isCompressed; + + if ($createState->archiveOffset == filesize($createState->archivePath)) { + DupArchiveUtil::tlog( + "Seeking to end of archive location because of offset {$createState->archiveOffset} " . + "for file size " . filesize($createState->archivePath) + ); + SnapIO::fseek($archiveHandle, 0, SEEK_END); + } else { + DupArchiveUtil::tlog("Seeking archive offset {$createState->archiveOffset} for file size " . filesize($createState->archivePath)); + SnapIO::fseek($archiveHandle, $createState->archiveOffset); + } + + while (($createState->currentDirectoryIndex < $directoryCount) && (!$createState->timedOut())) { + if ($createState->throttleDelayInUs !== 0) { + usleep($createState->throttleDelayInUs); + } + + $directory = $scanFSInfo->Dirs[$createState->currentDirectoryIndex]; + + try { + $relativeDirectoryPath = ''; + + if (isset($scanFSInfo->DirectoryAliases) && array_key_exists($directory, $scanFSInfo->DirectoryAliases)) { + $relativeDirectoryPath = $scanFSInfo->DirectoryAliases[$directory]; + } else { + $relativeDirectoryPath = self::getLocalPath($directory, $createState); + } + + if ($relativeDirectoryPath !== '') { + DupArchiveDirectoryProcessor::writeDirectoryToArchive($createState, $archiveHandle, $directory, $relativeDirectoryPath); + } else { + $createState->skippedDirectoryCount++; + $createState->currentDirectoryIndex++; + } + } catch (Exception $ex) { + DupArchiveUtil::log("Failed to add {$directory} to archive. Error: " . $ex->getMessage(), true); + + $createState->addFailure(DupArchiveProcessingFailure::TYPE_DIRECTORY, $directory, $ex->getMessage(), false); + $createState->currentDirectoryIndex++; + $createState->skippedDirectoryCount++; + $createState->save(); + } + } + + $createState->archiveOffset = SnapIO::ftell($archiveHandle); + + $workTimestamp = time(); + while (($createState->currentFileIndex < $fileCount) && (!$createState->timedOut())) { + $filepath = $scanFSInfo->Files[$createState->currentFileIndex]; + + try { + $relativeFilePath = ''; + + if (isset($scanFSInfo->FileAliases) && array_key_exists($filepath, $scanFSInfo->FileAliases)) { + $relativeFilePath = $scanFSInfo->FileAliases[$filepath]; + } else { + $relativeFilePath = self::getLocalPath($filepath, $createState); + } + + // Uncomment when testing error handling +// if((strpos($relativeFilePath, 'dup-installer') !== false) || (strpos($relativeFilePath, 'lib') !== false)) { +// Dup_Log::Trace("Was going to do intentional error to {$relativeFilePath} but skipping"); +// } else { +// throw new Exception("#### intentional file error when writing " . $relativeFilePath); +// } +// } + + DupArchiveFileProcessor::writeFilePortionToArchive($createState, $archiveHandle, $filepath, $relativeFilePath); + + if (($createState->isRobust) && (time() - $workTimestamp >= 1)) { + DupArchiveUtil::log("Robust mode create state save"); + + // When in robustness mode save the state every second + $workTimestamp = time(); + $createState->working = ($createState->currentDirectoryIndex < $directoryCount) || ($createState->currentFileIndex < $fileCount); + $createState->save(); + } + } catch (Snap32BitSizeLimitException $ex) { + throw $ex; + } catch (Exception $ex) { + DupArchiveUtil::log("Failed to add {$filepath} to archive. Error: " . $ex->getMessage() . $ex->getTraceAsString(), true); + $createState->currentFileIndex++; + $createState->skippedFileCount++; + $createState->addFailure(DupArchiveProcessingFailure::TYPE_FILE, $filepath, $ex->getMessage(), ($ex->getCode() === self::EXCEPTION_FATAL)); + $createState->save(); + } + } + + $createState->working = ($createState->currentDirectoryIndex < $directoryCount) || ($createState->currentFileIndex < $fileCount); + $createState->save(); + + SnapIO::fclose($archiveHandle); + + if (!$createState->working) { + DupArchiveUtil::log("compress done"); + } else { + DupArchiveUtil::tlog("compress not done so continuing later"); + } + } + + /** + * Expand archive + * + * @param DupArchiveExpandState $expandState expand state + * + * @return void + */ + public static function expandArchive(DupArchiveExpandState $expandState) + { + $expandState->startTimer(); + $archiveHandle = SnapIO::fopen($expandState->archivePath, 'rb'); + + SnapIO::fseek($archiveHandle, $expandState->archiveOffset); + + if ($expandState->archiveOffset == 0) { + $expandState->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle); + $expandState->isCompressed = $expandState->archiveHeader->isCompressed; + $expandState->archiveOffset = SnapIO::ftell($archiveHandle); + + $expandState->save(); + } else { + DupArchiveUtil::log("#### seeking archive offset {$expandState->archiveOffset}"); + } + + DupArchiveUtil::log('DUP EXPAND OFFSET ' . $expandState->archiveOffset); + + if ((!$expandState->validateOnly) || ($expandState->validationType == DupArchiveExpandState::VALIDATION_FULL)) { + $moreItems = self::expandItems($expandState, $archiveHandle); + } else { + $moreItems = self::standardValidateItems($expandState, $archiveHandle); + } + + $expandState->working = $moreItems; + $expandState->save(); + + SnapIO::fclose($archiveHandle, false); + + if (!$expandState->working) { + DupArchiveUtil::log("DUP EXPAND DONE"); + + if (($expandState->expectedFileCount != -1) && ($expandState->expectedFileCount != $expandState->fileWriteCount)) { + $expandState->addFailure( + DupArchiveProcessingFailure::TYPE_FILE, + 'Archive', + "Number of files expected ({$expandState->expectedFileCount}) doesn't equal number written ({$expandState->fileWriteCount})." + ); + } + + if (($expandState->expectedDirectoryCount != -1) && ($expandState->expectedDirectoryCount != $expandState->directoryWriteCount)) { + $expandState->addFailure( + DupArchiveProcessingFailure::TYPE_DIRECTORY, + 'Archive', + "Number of directories expected ({$expandState->expectedDirectoryCount}) " . + "doesn't equal number written ({$expandState->directoryWriteCount})." + ); + } + } else { + DupArchiveUtil::tlogObject("expand not done so continuing later", $expandState); + } + } + + /** + * Single-threaded file expansion + * + * @param string $archiveFilePath archive path + * @param string $relativeFilePaths relative file path in archive + * @param string $destPath destination path + * + * @return void + */ + public static function expandFiles($archiveFilePath, $relativeFilePaths, $destPath) + { + // Not setting timeout timestamp so it will never timeout + DupArchiveUtil::tlog("opening archive {$archiveFilePath}"); + + $archiveHandle = SnapIO::fopen($archiveFilePath, 'r'); + + /* @var $expandState DupArchiveSimpleExpandState */ + $expandState = new DupArchiveSimpleExpandState(); + + $expandState->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle); + $expandState->isCompressed = $expandState->archiveHeader->isCompressed; + $expandState->archiveOffset = SnapIO::ftell($archiveHandle); + $expandState->includedFiles = $relativeFilePaths; + $expandState->filteredDirectories = array('*'); + $expandState->filteredFiles = array('*'); + // $expandState->basePath = $destPath . '/tempExtract'; // RSR remove once extract works + $expandState->basePath = $destPath; // RSR remove once extract works + // TODO: Filter out all directories/files except those in the list + self::expandItems($expandState, $archiveHandle); + } + + /** + * Expand dup archive items + * + * @param DupArchiveExpandState $expandState dup archive expand state + * @param resource $archiveHandle dup archvie resource + * + * @return bool true if more to read + */ + private static function expandItems(DupArchiveExpandState $expandState, $archiveHandle) + { + $moreToRead = true; + $workTimestamp = time(); + + while ($moreToRead && (!$expandState->timedOut())) { + if ($expandState->throttleDelayInUs !== 0) { + usleep($expandState->throttleDelayInUs); + } + + if ($expandState->currentFileHeader != null) { + DupArchiveUtil::tlog("Writing file {$expandState->currentFileHeader->relativePath}"); + + if (self::filePassesFilters($expandState)) { + try { + $fileCompleted = DupArchiveFileProcessor::writeToFile($expandState, $archiveHandle); + } catch (Exception $ex) { + DupArchiveUtil::log("Failed to write to {$expandState->currentFileHeader->relativePath}. Error: " . $ex->getMessage(), true); + + // Reset things - skip over this file within the archive. + SnapIO::fseek($archiveHandle, $expandState->lastHeaderOffset); + self::skipToNextHeader($archiveHandle, $expandState->currentFileHeader); + + $expandState->archiveOffset = ftell($archiveHandle); + $expandState->addFailure( + DupArchiveProcessingFailure::TYPE_FILE, + $expandState->currentFileHeader->relativePath, + $ex->getMessage(), + false + ); + $expandState->resetForFile(); + $expandState->lastHeaderOffset = -1; + $expandState->save(); + } + } else { + self::skipFileInArchive($archiveHandle, $expandState->currentFileHeader); + $expandState->resetForFile(); + } + } else { + // Header is null so read in the next one + $expandState->lastHeaderOffset = @ftell($archiveHandle); + $headerType = self::getNextHeaderType($archiveHandle); + + DupArchiveUtil::tlog('header type ' . $headerType); + switch ($headerType) { + case self::HEADER_TYPE_FILE: + DupArchiveUtil::tlog('File header'); + $expandState->currentFileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, false, true); + $expandState->archiveOffset = @ftell($archiveHandle); + DupArchiveUtil::tlog('Just read file header from archive'); + break; + case self::HEADER_TYPE_DIR: + DupArchiveUtil::tlog('Directory Header'); + $directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true); + + if (self::passesDirectoryExclusion($expandState, $directoryHeader->relativePath)) { + $createdDirectory = true; + + if (!$expandState->validateOnly) { + $createdDirectory = DupArchiveFileProcessor::createDirectory($expandState, $directoryHeader); + } + + if ($createdDirectory) { + $expandState->directoryWriteCount++; + } + } + $expandState->archiveOffset = ftell($archiveHandle); + DupArchiveUtil::tlog('Just read directory header ' . $directoryHeader->relativePath . ' from archive'); + break; + case self::HEADER_TYPE_NONE: + $moreToRead = false; + } + } + + if (($expandState->isRobust) && (time() - $workTimestamp >= 1)) { + DupArchiveUtil::log("Robust mode extract state save for standard validate"); + + // When in robustness mode save the state every second + $workTimestamp = time(); + $expandState->save(); + } + } + + $expandState->save(); + + return $moreToRead; + } + + /** + * check exclude dir + * + * @param DupArchiveExpandState $expandState dup archive expand state + * @param string $candidate check exclude dir + * + * @return bool + */ + private static function passesDirectoryExclusion(DupArchiveExpandState $expandState, $candidate) + { + foreach ($expandState->filteredDirectories as $directoryFilter) { + if ($directoryFilter === '*') { + return false; + } + + if (SnapIO::getRelativePath($candidate, $directoryFilter) !== false) { + return false; + } + } + + if (in_array($candidate, $expandState->excludedDirWithoutChilds)) { + return false; + } + + return true; + } + + /** + * Check flils filters + * + * @param DupArchiveExpandState $expandState dup archive expand state + * + * @return boolean + */ + private static function filePassesFilters(DupArchiveExpandState $expandState) + { + $candidate = $expandState->currentFileHeader->relativePath; + + // Included files trumps all exclusion filters + foreach ($expandState->includedFiles as $includedFile) { + if ($includedFile === $candidate) { + return true; + } + } + + if (self::passesDirectoryExclusion($expandState, $candidate)) { + foreach ($expandState->filteredFiles as $fileFilter) { + if ($fileFilter === '*' || $fileFilter === $candidate) { + return false; + } + } + } else { + return false; + } + + return true; + } + + /** + * Validate items + * + * @param DupArchiveExpandState $expandState dup archive expan state + * @param resource $archiveHandle dup archive resource + * + * @return bool true if more to read + */ + private static function standardValidateItems(DupArchiveExpandState $expandState, $archiveHandle) + { + $moreToRead = true; + + $to = $expandState->timedOut(); + $workTimestamp = time(); + + while ($moreToRead && (!$to)) { + if ($expandState->throttleDelayInUs !== 0) { + usleep($expandState->throttleDelayInUs); + } + + if ($expandState->currentFileHeader != null) { + try { + $fileCompleted = DupArchiveFileProcessor::standardValidateFileEntry($expandState, $archiveHandle); + + if ($fileCompleted) { + $expandState->resetForFile(); + } + + // Expand state taken care of within the write to file to ensure consistency + } catch (Exception $ex) { + DupArchiveUtil::log("Failed validate file in archive. Error: " . $ex->getMessage(), true); + DupArchiveUtil::logObject("expand state", $expandState, true); + // $expandState->currentFileIndex++; + // RSR TODO: Need way to skip past that file + + $expandState->addFailure(DupArchiveProcessingFailure::TYPE_FILE, $expandState->currentFileHeader->relativePath, $ex->getMessage()); + $expandState->save(); + + $moreToRead = false; + } + } else { + $headerType = self::getNextHeaderType($archiveHandle); + + switch ($headerType) { + case self::HEADER_TYPE_FILE: + $expandState->currentFileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, false, true); + $expandState->archiveOffset = ftell($archiveHandle); + break; + case self::HEADER_TYPE_DIR: + $directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true); + $expandState->directoryWriteCount++; + $expandState->archiveOffset = ftell($archiveHandle); + break; + case self::HEADER_TYPE_NONE: + $moreToRead = false; + } + } + + if (($expandState->isRobust) && (time() - $workTimestamp >= 1)) { + DupArchiveUtil::log("Robust mdoe extract state save for standard validate"); + + // When in robustness mode save the state every second + $workTimestamp = time(); + $expandState->save(); + } + $to = $expandState->timedOut(); + } + + $expandState->save(); + + return $moreToRead; + } +} diff --git a/src/Libs/DupArchive/DupArchiveExpandBasicEngine.php b/src/Libs/DupArchive/DupArchiveExpandBasicEngine.php new file mode 100644 index 00000000..e8e0f3f3 --- /dev/null +++ b/src/Libs/DupArchive/DupArchiveExpandBasicEngine.php @@ -0,0 +1,272 @@ +destDirectory = $destDirectory; + $writeInfo->isCompressed = $archiveHeader->isCompressed; + + if ($offset > 0) { + fseek($archiveHandle, $offset); + } + + $moreToRead = true; + + while ($moreToRead) { + if ($writeInfo->currentFileHeader != null) { + try { + if (self::passesInclusionFilter($inclusionFilter, $writeInfo->currentFileHeader->relativePath)) { + self::writeToFile($archiveHandle, $writeInfo); + $writeInfo->fileWriteCount++; + } elseif ($writeInfo->currentFileHeader->fileSize > 0) { + self::skipFileInArchive($archiveHandle, $writeInfo->currentFileHeader); + } + $writeInfo->currentFileHeader = null; + // Expand state taken care of within the write to file to ensure consistency + } catch (Exception $ex) { + if (!$ignoreErrors) { + throw $ex; + } + } + } else { + $headerType = self::getNextHeaderType($archiveHandle); + + switch ($headerType) { + case self::HEADER_TYPE_FILE: + $writeInfo->currentFileHeader = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, false, true); + break; + case self::HEADER_TYPE_DIR: + $directoryHeader = DupArchiveReaderDirectoryHeader::readFromArchive($archiveHandle, true); + // self::log("considering $inclusionFilter and {$directoryHeader->relativePath}"); + if (self::passesInclusionFilter($inclusionFilter, $directoryHeader->relativePath)) { + // self::log("passed"); + $directory = "{$writeInfo->destDirectory}/{$directoryHeader->relativePath}"; + + // $mode = $directoryHeader->permissions; + // rodo handle this more elegantly @mkdir($directory, $directoryHeader->permissions, true); + if (is_callable(self::$mkdirCallback)) { + call_user_func(self::$mkdirCallback, $directory, 'u+rwx', true); + } else { + mkdir($directory, 0755, true); + } + $writeInfo->directoryWriteCount++; + } else { + // self::log("didnt pass"); + } + break; + case self::HEADER_TYPE_NONE: + $moreToRead = false; + } + } + } + + fclose($archiveHandle); + } + + /** + * Write to file + * + * @param resource $archiveHandle archive file handle + * @param DupArchiveExpanderInfo $writeInfo write info + * + * @return void + */ + private static function writeToFile($archiveHandle, DupArchiveExpanderInfo $writeInfo) + { + $destFilePath = $writeInfo->getCurrentDestFilePath(); + + if ($writeInfo->currentFileHeader->fileSize > 0) { + $parentDir = dirname($destFilePath); + if (!file_exists($parentDir)) { + if (is_callable(self::$mkdirCallback)) { + $res = call_user_func(self::$mkdirCallback, $parentDir, 'u+rwx', true); + } else { + $res = mkdir($parentDir, 0755, true); + } + if (!$res) { + throw new Exception("Couldn't create {$parentDir}"); + } + } + + $destFileHandle = fopen($destFilePath, 'wb+'); + if ($destFileHandle === false) { + throw new Exception("Couldn't open {$destFilePath} for writing."); + } + + do { + self::appendGlobToFile($archiveHandle, $destFileHandle, $writeInfo); + + $currentFileOffset = ftell($destFileHandle); + + $moreGlobstoProcess = $currentFileOffset < $writeInfo->currentFileHeader->fileSize; + } while ($moreGlobstoProcess); + + fclose($destFileHandle); + + if (is_callable(self::$chmodCallback)) { + call_user_func(self::$chmodCallback, $destFilePath, 'u+rw'); + } else { + chmod($destFilePath, 0644); + } + + self::validateExpandedFile($writeInfo); + } else { + if (touch($destFilePath) === false) { + throw new Exception("Couldn't create $destFilePath"); + } + + if (is_callable(self::$chmodCallback)) { + call_user_func(self::$chmodCallback, $destFilePath, 'u+rw'); + } else { + chmod($destFilePath, 0644); + } + } + } + + /** + * Validate file + * + * @param DupArchiveExpanderInfo $writeInfo write info + * + * @return void + */ + private static function validateExpandedFile(DupArchiveExpanderInfo $writeInfo) + { + if ($writeInfo->currentFileHeader->hash !== '00000000000000000000000000000000') { + $hash = hash_file('crc32b', $writeInfo->getCurrentDestFilePath()); + + if ($hash !== $writeInfo->currentFileHeader->hash) { + throw new Exception("MD5 validation fails for {$writeInfo->getCurrentDestFilePath()}"); + } + } + } + + /** + * Undocumented function + * Assumption is that archive handle points to a glob header on this call + * + * @param resource $archiveHandle archive handle + * @param resource $destFileHandle dest file handle + * @param DupArchiveExpanderInfo $writeInfo write info + * + * @return void + */ + private static function appendGlobToFile($archiveHandle, $destFileHandle, DupArchiveExpanderInfo $writeInfo) + { + $globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle, false); + $globContents = fread($archiveHandle, $globHeader->storedSize); + + if ($globContents === false) { + throw new Exception("Error reading glob from " . $writeInfo->getCurrentDestFilePath()); + } + + if ($writeInfo->isCompressed) { + $globContents = gzinflate($globContents); + } + + if (fwrite($destFileHandle, $globContents) !== strlen($globContents)) { + throw new Exception("Unable to write all bytes of data glob to storage."); + } + } + + /** + * Check filter + * + * @param string $filter filter + * @param string $candidate candidate + * + * @return bool + */ + private static function passesInclusionFilter($filter, $candidate) + { + return (substr($candidate, 0, strlen($filter)) == $filter); + } +} diff --git a/src/Libs/DupArchive/DupArchiveLoggerBase.php b/src/Libs/DupArchive/DupArchiveLoggerBase.php new file mode 100644 index 00000000..a3f83b97 --- /dev/null +++ b/src/Libs/DupArchive/DupArchiveLoggerBase.php @@ -0,0 +1,23 @@ +relativePathLength == 0) { + // Don't allow a base path to be written to the archive + return; + } + + $headerString = '' . + $this->mtime . '

                        ' . + $this->permissions . '

                        ' . + $this->relativePathLength . '' . + $this->relativePath . '
                        '; + + //SnapIO::fwrite($archiveHandle, $headerString); + $bytes_written = @fwrite($archiveHandle, $headerString); + + if ($bytes_written === false) { + throw new Exception('Error writing to file.'); + } else { + return $bytes_written; + } + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveFileHeader.php b/src/Libs/DupArchive/Headers/DupArchiveFileHeader.php new file mode 100644 index 00000000..8049bb61 --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveFileHeader.php @@ -0,0 +1,119 @@ +fileSize = SnapIO::filesize($filepath); + $instance->permissions = substr(sprintf('%o', fileperms($filepath)), -4); + $instance->mtime = SnapIO::filemtime($filepath); + + if ($instance->fileSize > self::MAX_SIZE_FOR_HASHING) { + $instance->hash = "00000000000000000000000000000000"; + } else { + $instance->hash = hash_file('crc32b', $filepath); + } + + $instance->relativePath = $relativeFilePath; + $instance->relativePathLength = strlen($instance->relativePath); + + return $instance; + } + + /** + * create header from src + * + * @param string $src source string + * @param string $relativeFilePath relative path in archvie + * @param int $forceSize if 0 size is auto of content is filled of \0 char to size + * + * @return static + */ + public static function createFromSrc($src, $relativeFilePath, $forceSize = 0) + { + $instance = new static(); + + $instance->fileSize = strlen($src); + $instance->permissions = '0644'; + $instance->mtime = time(); + + $srcLen = strlen($src); + + if ($forceSize > 0 && $srcLen < $forceSize) { + $charsToAdd = $forceSize - $srcLen; + $src .= str_repeat("\0", $charsToAdd); + } + + if ($instance->fileSize > self::MAX_SIZE_FOR_HASHING) { + $instance->hash = "00000000000000000000000000000000"; + } else { + $instance->hash = hash('crc32b', $src); + } + + $instance->relativePath = $relativeFilePath; + $instance->relativePathLength = strlen($instance->relativePath); + + return $instance; + } + + /** + * Write header in archive + * + * @param resource $archiveHandle archive resource + * + * @return int bytes written + */ + public function writeToArchive($archiveHandle) + { + $headerString = '' . + $this->fileSize . '' . + $this->mtime . '

                        ' . + $this->permissions . '

                        ' . + $this->hash . '' . + $this->relativePathLength . '' . + $this->relativePath . '
                        '; + + //SnapIO::fwrite($archiveHandle, $headerString); + $bytes_written = @fwrite($archiveHandle, $headerString); + + if ($bytes_written === false) { + throw new Exception('Error writing to file.'); + } else { + return $bytes_written; + } + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveGlobHeader.php b/src/Libs/DupArchive/Headers/DupArchiveGlobHeader.php new file mode 100644 index 00000000..c6412ef0 --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveGlobHeader.php @@ -0,0 +1,48 @@ +xxxx
                        + + $headerString = '' . $this->originalSize . '' . $this->storedSize . '' . $this->hash . ''; + + //SnapIO::fwrite($archiveHandle, $headerString); + $bytes_written = @fwrite($archiveHandle, $headerString); + + if ($bytes_written === false) { + throw new Exception('Error writing to file.'); + } else { + return $bytes_written; + } + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveHeader.php b/src/Libs/DupArchive/Headers/DupArchiveHeader.php new file mode 100644 index 00000000..f0fe1550 --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveHeader.php @@ -0,0 +1,53 @@ +version = DupArchiveEngine::DUPARCHIVE_VERSION; + $instance->isCompressed = $isCompressed; + return $instance; + } + + /** + * Write header to archive + * + * @param resource $archiveHandle archive resource + * + * @return void + */ + public function writeToArchive($archiveHandle) + { + SnapIO::fwrite($archiveHandle, '' . $this->version . '' . ($this->isCompressed ? 'true' : 'false') . ''); + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveHeaderU.php b/src/Libs/DupArchive/Headers/DupArchiveHeaderU.php new file mode 100644 index 00000000..a6cc2f31 --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveHeaderU.php @@ -0,0 +1,44 @@ +'; + $expectedEnd = ''; + + $startingElement = fread($archiveHandle, strlen($expectedStart)); + + if ($startingElement !== $expectedStart) { + throw new Exception("Invalid starting element. Was expecting {$expectedStart} but got {$startingElement}"); + } + + $headerString = stream_get_line($archiveHandle, self::MAX_FILED_LEN, $expectedEnd); + + if ($headerString === false) { + throw new Exception('Error reading line.'); + } + + return $headerString; + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveReaderDirectoryHeader.php b/src/Libs/DupArchive/Headers/DupArchiveReaderDirectoryHeader.php new file mode 100644 index 00000000..14baec4f --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveReaderDirectoryHeader.php @@ -0,0 +1,79 @@ + + $startElement = fread($archiveHandle, 3); + + if ($startElement === false) { + if (feof($archiveHandle)) { + return false; + } else { + throw new Exception('Error reading directory header'); + } + } + + if ($startElement != '') { + throw new Exception("Invalid directory header marker found [{$startElement}] : location " . ftell($archiveHandle)); + } + } + + $instance->mtime = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'MT'); + $instance->permissions = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'P'); + $instance->relativePathLength = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'RPL'); + + // Skip the + fread($archiveHandle, 4); + + $instance->relativePath = fread($archiveHandle, $instance->relativePathLength); + + // Skip the + // fread($archiveHandle, 5); + + // Skip the + // fread($archiveHandle, 4); + + // Skip the and the + fread($archiveHandle, 9); + + return $instance; + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveReaderFileHeader.php b/src/Libs/DupArchive/Headers/DupArchiveReaderFileHeader.php new file mode 100644 index 00000000..7922c15e --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveReaderFileHeader.php @@ -0,0 +1,100 @@ + 20000 files -> 1.2MB larger + * xxxxxx + * # F#x#x#x#x#x#x! + * + * @param resource $archiveHandle archive resource + * @param boolean $skipContents if true skip contents + * @param boolean $skipMarker if true skip marker + * + * @return static + */ + public static function readFromArchive($archiveHandle, $skipContents = false, $skipMarker = false) + { + // RSR TODO Read header from archive handle and populate members + // TODO: return null if end of archive or throw exception if can read something but its not a file header + + $instance = new static(); + + if (!$skipMarker) { + $marker = @fread($archiveHandle, 3); + + if ($marker === false) { + if (feof($archiveHandle)) { + return false; + } else { + throw new Exception('Error reading file header'); + } + } + + if ($marker != '') { + throw new Exception("Invalid file header marker found [{$marker}] : location " . ftell($archiveHandle)); + } + } + + $instance->fileSize = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'FS'); + $instance->mtime = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'MT'); + $instance->permissions = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'P'); + $instance->hash = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'HA'); + $instance->relativePathLength = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'RPL'); + + // Skip + fread($archiveHandle, 4); + $instance->relativePath = fread($archiveHandle, $instance->relativePathLength); + + // Skip + // fread($archiveHandle, 5); + + // Skip the + // fread($archiveHandle, 4); + + // Skip the and the
                        + fread($archiveHandle, 9); + + if ($skipContents && ($instance->fileSize > 0)) { + $dataSize = 0; + $moreGlobs = true; + while ($moreGlobs) { + $globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle, true); + $dataSize += $globHeader->originalSize; + $moreGlobs = ($dataSize < $instance->fileSize); + } + } + + return $instance; + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveReaderGlobHeader.php b/src/Libs/DupArchive/Headers/DupArchiveReaderGlobHeader.php new file mode 100644 index 00000000..99ed2983 --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveReaderGlobHeader.php @@ -0,0 +1,88 @@ +') { + throw new Exception("Invalid glob header marker found {$startElement}. location:" . ftell($archiveHandle)); + } + + $instance->originalSize = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'OS'); + $instance->storedSize = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'SS'); + $instance->hash = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'HA'); + + // Skip the + fread($archiveHandle, 4); + + if ($skipGlob) { + if (fseek($archiveHandle, $instance->storedSize, SEEK_CUR) === -1) { + throw new Exception("Can't fseek when skipping glob at location:" . ftell($archiveHandle)); + } + } + + return $instance; + } + + /** + * Get glob content from header + * + * @param resource $archiveHandle archive hadler + * @param self $header chunk glob header + * @param bool $isCompressed true if is compressed + * + * @return string + */ + public static function readContent($archiveHandle, self $header, $isCompressed) + { + if ($header->storedSize == 0) { + return 0; + } + + if (($globContents = fread($archiveHandle, $header->storedSize)) === false) { + throw new Exception("Error reading glob content"); + } + + return ($isCompressed ? gzinflate($globContents) : $globContents); + } +} diff --git a/src/Libs/DupArchive/Headers/DupArchiveReaderHeader.php b/src/Libs/DupArchive/Headers/DupArchiveReaderHeader.php new file mode 100644 index 00000000..d3aafa3d --- /dev/null +++ b/src/Libs/DupArchive/Headers/DupArchiveReaderHeader.php @@ -0,0 +1,55 @@ +') { + throw new Exception("Invalid archive header marker found {$startElement}"); + } + + $instance->version = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'V'); + $instance->isCompressed = filter_var(DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'C'), FILTER_VALIDATE_BOOLEAN); + + // Skip the + fgets($archiveHandle, 5); + return $instance; + } +} diff --git a/src/Libs/DupArchive/Info/DupArchiveExpanderInfo.php b/src/Libs/DupArchive/Info/DupArchiveExpanderInfo.php new file mode 100644 index 00000000..23913bf0 --- /dev/null +++ b/src/Libs/DupArchive/Info/DupArchiveExpanderInfo.php @@ -0,0 +1,28 @@ +destDirectory != null) { + return "{$this->destDirectory}/{$this->currentFileHeader->relativePath}"; + } else { + return null; + } + } +} diff --git a/src/Libs/DupArchive/Info/DupArchiveInfo.php b/src/Libs/DupArchive/Info/DupArchiveInfo.php new file mode 100644 index 00000000..6706e49e --- /dev/null +++ b/src/Libs/DupArchive/Info/DupArchiveInfo.php @@ -0,0 +1,25 @@ +fileHeaders = array(); + $this->directoryHeaders = array(); + } +} diff --git a/src/Libs/DupArchive/Processors/DupArchiveDirectoryProcessor.php b/src/Libs/DupArchive/Processors/DupArchiveDirectoryProcessor.php new file mode 100644 index 00000000..aa21d0fe --- /dev/null +++ b/src/Libs/DupArchive/Processors/DupArchiveDirectoryProcessor.php @@ -0,0 +1,45 @@ +permissions = substr(sprintf('%o', fileperms($sourceDirectoryPath)), -4); + $directoryHeader->mtime = SnapIO::filemtime($sourceDirectoryPath); + $directoryHeader->relativePath = $relativeDirectoryPath; + $directoryHeader->relativePathLength = strlen($directoryHeader->relativePath); + + $directoryHeader->writeToArchive($archiveHandle); + + // Just increment this here - the actual state save is on the outside after timeout or completion of all directories + $createState->currentDirectoryIndex++; + } +} diff --git a/src/Libs/DupArchive/Processors/DupArchiveFileProcessor.php b/src/Libs/DupArchive/Processors/DupArchiveFileProcessor.php new file mode 100644 index 00000000..a7179ba5 --- /dev/null +++ b/src/Libs/DupArchive/Processors/DupArchiveFileProcessor.php @@ -0,0 +1,548 @@ +archiveOffset = SnapIO::ftell($archiveHandle); + $createState->currentFileIndex++; + $createState->currentFileOffset = 0; + $createState->skippedFileCount++; + $createState->addFailure(DupArchiveProcessingFailure::TYPE_FILE, $sourceFilepath, "Couldn't open $sourceFilepath", false); + return; + } + + if ($createState->currentFileOffset > 0) { + SnapIO::fseek($sourceHandle, $createState->currentFileOffset); + } else { + $fileHeader = DupArchiveFileHeader::createFromFile($sourceFilepath, $relativeFilePath); + $fileHeader->writeToArchive($archiveHandle); + } + + $sourceFileSize = filesize($sourceFilepath); + + $moreFileDataToProcess = true; + + while ((!$createState->timedOut()) && $moreFileDataToProcess) { + if ($createState->throttleDelayInUs !== 0) { + usleep($createState->throttleDelayInUs); + } + + $moreFileDataToProcess = self::appendGlobToArchive($createState, $archiveHandle, $sourceHandle, $sourceFilepath, $sourceFileSize); + $createState->archiveOffset = SnapIO::ftell($archiveHandle); + + if ($moreFileDataToProcess) { + $createState->currentFileOffset += $createState->globSize; + } else { + $createState->currentFileIndex++; + $createState->currentFileOffset = 0; + } + + // Only writing state after full group of files have been written - less reliable but more efficient + // $createState->save(); + } + + SnapIO::fclose($sourceHandle); + } + + /** + * Write file to archive from source + * + * @param DupArchiveCreateState $createState dup archive create state + * @param resource $archiveHandle archive resource + * @param string $src source string + * @param string $relativeFilePath relative file path + * @param int $forceSize if 0 size is auto of content is filled of \0 char to size + * + * @return void + */ + public static function writeFileSrcToArchive( + DupArchiveCreateState $createState, + $archiveHandle, + $src, + $relativeFilePath, + $forceSize = 0 + ) { + DupArchiveUtil::tlog("writeFileSrcToArchive"); + + $fileHeader = DupArchiveFileHeader::createFromSrc($src, $relativeFilePath, $forceSize); + $fileHeader->writeToArchive($archiveHandle); + + self::appendFileSrcToArchive($createState, $archiveHandle, $src, $forceSize); + $createState->currentFileIndex++; + $createState->currentFileOffset = 0; + $createState->archiveOffset = SnapIO::ftell($archiveHandle); + } + + /** + * Expand du archive + * + * Assumption is that this is called at the beginning of a glob header since file header already writtern + * + * @param DupArchiveExpandState $expandState expand state + * @param resource $archiveHandle archive resource + * + * @return bool true on success + */ + public static function writeToFile(DupArchiveExpandState $expandState, $archiveHandle) + { + if (isset($expandState->fileRenames[$expandState->currentFileHeader->relativePath])) { + $destFilepath = $expandState->fileRenames[$expandState->currentFileHeader->relativePath]; + } else { + $destFilepath = self::getNewFilePath($expandState->basePath, $expandState->currentFileHeader->relativePath); + } + $parentDir = dirname($destFilepath); + + $moreGlobstoProcess = true; + + SnapIO::dirWriteCheckOrMkdir($parentDir, 'u+rwx', true); + + if ($expandState->currentFileHeader->fileSize > 0) { + if ($expandState->currentFileOffset > 0) { + $destFileHandle = SnapIO::fopen($destFilepath, 'r+b'); + SnapIO::fseek($destFileHandle, $expandState->currentFileOffset); + } else { + $destFileHandle = SnapIO::fopen($destFilepath, 'w+b'); + } + + while (!$expandState->timedOut()) { + $moreGlobstoProcess = $expandState->currentFileOffset < $expandState->currentFileHeader->fileSize; + + if ($moreGlobstoProcess) { + if ($expandState->throttleDelayInUs !== 0) { + usleep($expandState->throttleDelayInUs); + } + + self::appendGlobToFile($expandState, $archiveHandle, $destFileHandle, $destFilepath); + + $expandState->currentFileOffset = ftell($destFileHandle); + $expandState->archiveOffset = SnapIO::ftell($archiveHandle); + + $moreGlobstoProcess = $expandState->currentFileOffset < $expandState->currentFileHeader->fileSize; + + if (!$moreGlobstoProcess) { + break; + } + } else { + // rsr todo record fclose error + @fclose($destFileHandle); + $destFileHandle = null; + + if ($expandState->validationType == DupArchiveExpandState::VALIDATION_FULL) { + self::validateExpandedFile($expandState); + } + break; + } + } + + DupArchiveUtil::tlog('Out of glob loop'); + + if ($destFileHandle != null) { + // rsr todo record file close error + @fclose($destFileHandle); + $destFileHandle = null; + } + + if (!$moreGlobstoProcess && $expandState->validateOnly && ($expandState->validationType == DupArchiveExpandState::VALIDATION_FULL)) { + if (!is_writable($destFilepath)) { + SnapIO::chmod($destFilepath, 'u+rw'); + } + if (@unlink($destFilepath) === false) { + // $expandState->addFailure(DupArchiveFailureTypes::File, $destFilepath, "Couldn't delete {$destFilepath} during validation", false); + // TODO: Have to know how to handle this - want to report it but don’t want to mess up validation - + // some non critical errors could be important to validation + } + } + } else { + // 0 length file so just touch it + $moreGlobstoProcess = false; + + if (file_exists($destFilepath)) { + @unlink($destFilepath); + } + + if (touch($destFilepath) === false) { + throw new Exception("Couldn't create {$destFilepath}"); + } + } + + if (!$moreGlobstoProcess) { + self::setFileMode($expandState, $destFilepath); + self::setFileTimes($expandState, $destFilepath); + DupArchiveUtil::tlog('No more globs to process'); + + $expandState->fileWriteCount++; + $expandState->resetForFile(); + } + + return !$moreGlobstoProcess; + } + + /** + * Create directory + * + * @param DupArchiveExpandState $expandState expand state + * @param DupArchiveDirectoryHeader $directoryHeader directory header + * + * @return boolean + */ + public static function createDirectory(DupArchiveExpandState $expandState, DupArchiveDirectoryHeader $directoryHeader) + { + /* @var $expandState DupArchiveExpandState */ + $destDirPath = self::getNewFilePath($expandState->basePath, $directoryHeader->relativePath); + + $mode = $directoryHeader->permissions; + + if ($expandState->directoryModeOverride != -1) { + $mode = $expandState->directoryModeOverride; + } + + if (!SnapIO::dirWriteCheckOrMkdir($destDirPath, $mode, true)) { + $error_message = "Unable to create directory $destDirPath"; + $expandState->addFailure(DupArchiveProcessingFailure::TYPE_DIRECTORY, $directoryHeader->relativePath, $error_message, false); + DupArchiveUtil::tlog($error_message); + return false; + } else { + return true; + } + } + + /** + * Set file mode if is enabled + * + * @param DupArchiveExpandState $expandState dup expand state + * @param string $filePath file path + * + * @return bool + */ + public static function setFileMode(DupArchiveExpandState $expandState, $filePath) + { + if ($expandState->fileModeOverride === -1) { + return; + } + return SnapIO::chmod($filePath, $expandState->fileModeOverride); + } + + /** + * Set original file times if enabled + * + * @param DupArchiveExpandState $expandState dup expand state + * @param string $filePath File path + * + * @return bool true if success, false otherwise + */ + protected static function setFileTimes(DupArchiveExpandState $expandState, $filePath) + { + if (!$expandState->keepFileTime) { + return true; + } + if (!file_exists($filePath)) { + return false; + } + return touch($filePath, $expandState->currentFileHeader->mtime); + } + + /** + * Validate file entry + * + * @param DupArchiveExpandState $expandState dup expand state + * @param resource $archiveHandle dup archive resource + * + * @return bool + */ + public static function standardValidateFileEntry(DupArchiveExpandState $expandState, $archiveHandle) + { + $moreGlobstoProcess = $expandState->currentFileOffset < $expandState->currentFileHeader->fileSize; + + if (!$moreGlobstoProcess) { + // Not a 'real' write but indicates that we actually did fully process a file in the archive + $expandState->fileWriteCount++; + } else { + while ((!$expandState->timedOut()) && $moreGlobstoProcess) { + // Read in the glob header but leave the pointer at the payload + $globHeader = DupArchiveGlobHeader::readFromArchive($archiveHandle, false); + $globContents = fread($archiveHandle, $globHeader->storedSize); + + if ($globContents === false) { + throw new Exception("Error reading glob from archive"); + } + + $hash = hash('crc32b', $globContents); + + if ($hash != $globHeader->hash) { + $expandState->addFailure( + DupArchiveProcessingFailure::TYPE_FILE, + $expandState->currentFileHeader->relativePath, + 'Hash mismatch on DupArchive file entry', + true + ); + DupArchiveUtil::tlog("Glob hash mismatch during standard check of {$expandState->currentFileHeader->relativePath}"); + } else { + // DupArchiveUtil::tlog("Glob MD5 passes"); + } + + $expandState->currentFileOffset += $globHeader->originalSize; + $expandState->archiveOffset = SnapIO::ftell($archiveHandle); + $moreGlobstoProcess = $expandState->currentFileOffset < $expandState->currentFileHeader->fileSize; + + if (!$moreGlobstoProcess) { + $expandState->fileWriteCount++; + $expandState->resetForFile(); + } + } + } + + return !$moreGlobstoProcess; + } + + /** + * Validate file + * + * @param DupArchiveExpandState $expandState dup expand state + * + * @return void + */ + private static function validateExpandedFile(DupArchiveExpandState $expandState) + { + /* @var $expandState DupArchiveExpandState */ + $destFilepath = self::getNewFilePath($expandState->basePath, $expandState->currentFileHeader->relativePath); + + if ($expandState->currentFileHeader->hash !== '00000000000000000000000000000000') { + $hash = hash_file('crc32b', $destFilepath); + + if ($hash !== $expandState->currentFileHeader->hash) { + $expandState->addFailure(DupArchiveProcessingFailure::TYPE_FILE, $destFilepath, "MD5 mismatch for {$destFilepath}", false); + } else { + DupArchiveUtil::tlog('MD5 Match for ' . $destFilepath); + } + } else { + DupArchiveUtil::tlog('MD5 non match is 0\'s'); + } + } + + /** + * Append file to archive + * + * @param DupArchiveCreateState $createState create state + * @param resource $archiveHandle archive resource + * @param resource $sourceFilehandle file resource + * @param string $sourceFilepath file path + * @param int $fileSize file size + * + * @return bool true if more file remaning + */ + private static function appendGlobToArchive( + DupArchiveCreateState $createState, + $archiveHandle, + $sourceFilehandle, + $sourceFilepath, + $fileSize + ) { + DupArchiveUtil::tlog("Appending file glob to archive for file {$sourceFilepath} at file offset {$createState->currentFileOffset}"); + + if ($fileSize == 0) { + return false; + } + + $fileSize -= $createState->currentFileOffset; + $globContents = @fread($sourceFilehandle, $createState->globSize); + + if ($globContents === false) { + throw new Exception("Error reading $sourceFilepath"); + } + + $originalSize = strlen($globContents); + + if ($createState->isCompressed) { + $globContents = gzdeflate($globContents, 2); // 2 chosen as best compromise between speed and size + $storeSize = strlen($globContents); + } else { + $storeSize = $originalSize; + } + + $globHeader = new DupArchiveGlobHeader(); + $globHeader->originalSize = $originalSize; + $globHeader->storedSize = $storeSize; + $globHeader->hash = hash('crc32b', $globContents); + $globHeader->writeToArchive($archiveHandle); + + if (@fwrite($archiveHandle, $globContents) === false) { + // Considered fatal since we should always be able to write to the archive - + // plus the header has already been written (could back this out later though) + throw new Exception( + "Error writing $sourceFilepath to archive. Ensure site still hasn't run out of space.", + DupArchiveEngine::EXCEPTION_FATAL + ); + } + + $fileSizeRemaining = $fileSize - $createState->globSize; + $moreFileRemaining = $fileSizeRemaining > 0; + + return $moreFileRemaining; + } + + /** + * Append file in dup archvie from source string + * + * @param DupArchiveCreateState $createState create state + * @param resource $archiveHandle archive handle + * @param string $src source to add + * @param int $forceSize if 0 size is auto of content is filled of \0 char to size + * + * @return bool + */ + private static function appendFileSrcToArchive( + DupArchiveCreateState $createState, + $archiveHandle, + $src, + $forceSize = 0 + ) { + DupArchiveUtil::tlog("Appending file glob to archive from src"); + + if (($originalSize = strlen($src)) == 0 && $forceSize == 0) { + return false; + } + + if ($forceSize == 0 && $createState->isCompressed) { + $src = gzdeflate($src, 2); // 2 chosen as best compromise between speed and size + $storeSize = strlen($src); + } else { + $storeSize = $originalSize; + } + + if ($forceSize > 0 && $storeSize < $forceSize) { + $charsToAdd = $forceSize - $storeSize; + $src .= str_repeat("\0", $charsToAdd); + $storeSize = $forceSize; + } + + $globHeader = new DupArchiveGlobHeader(); + $globHeader->originalSize = $originalSize; + $globHeader->storedSize = $storeSize; + $globHeader->hash = hash('crc32b', $src); + $globHeader->writeToArchive($archiveHandle); + + + if (SnapIO::fwriteChunked($archiveHandle, $src) === false) { + // Considered fatal since we should always be able to write to the archive - + // plus the header has already been written (could back this out later though) + throw new Exception( + "Error writing SRC to archive. Ensure site still hasn't run out of space.", + DupArchiveEngine::EXCEPTION_FATAL + ); + } + + return true; + } + + /** + * Extract file from dup archive + * Assumption is that archive handle points to a glob header on this call + * + * @param DupArchiveExpandState $expandState dup archive expand state + * @param resource $archiveHandle archvie resource + * @param resource $destFileHandle file resource + * @param string $destFilePath file path + * + * @return void + */ + private static function appendGlobToFile( + DupArchiveExpandState $expandState, + $archiveHandle, + $destFileHandle, + $destFilePath + ) { + DupArchiveUtil::tlog('Appending file glob to file ' . $destFilePath . ' at file offset ' . $expandState->currentFileOffset); + + // Read in the glob header but leave the pointer at the payload + $globHeader = DupArchiveGlobHeader::readFromArchive($archiveHandle, false); + if (($globContents = DupArchiveGlobHeader::readContent($archiveHandle, $globHeader, $expandState->archiveHeader->isCompressed)) === false) { + throw new Exception("Error reading glob from $destFilePath"); + } + + if (@fwrite($destFileHandle, $globContents) === false) { + throw new Exception("Error writing glob to $destFilePath"); + } else { + DupArchiveUtil::tlog('Successfully wrote glob'); + } + } +} diff --git a/src/Libs/DupArchive/Processors/DupArchiveProcessingFailure.php b/src/Libs/DupArchive/Processors/DupArchiveProcessingFailure.php new file mode 100644 index 00000000..7f124f8a --- /dev/null +++ b/src/Libs/DupArchive/Processors/DupArchiveProcessingFailure.php @@ -0,0 +1,24 @@ + fullNewPath */ + public $fileRenames = array(); + public $directoryModeOverride = -1; + public $fileModeOverride = -1; + public $lastHeaderOffset = -1; + /** @var bool */ + public $keepFileTime = false; + + /** + * Reset state for file + * + * @return void + */ + public function resetForFile() + { + $this->currentFileHeader = null; + $this->currentFileOffset = 0; + } + + /** + * save expand state + * + * @return void + */ + abstract public function save(); +} diff --git a/src/Libs/DupArchive/States/DupArchiveSimpleCreateState.php b/src/Libs/DupArchive/States/DupArchiveSimpleCreateState.php new file mode 100644 index 00000000..1f88611c --- /dev/null +++ b/src/Libs/DupArchive/States/DupArchiveSimpleCreateState.php @@ -0,0 +1,34 @@ +currentDirectoryIndex = 0; + $this->currentFileIndex = 0; + $this->currentFileOffset = 0; + } + + /** + * Save state + * + * @return void + */ + public function save() + { + } +} diff --git a/src/Libs/DupArchive/States/DupArchiveSimpleExpandState.php b/src/Libs/DupArchive/States/DupArchiveSimpleExpandState.php new file mode 100644 index 00000000..657af8a9 --- /dev/null +++ b/src/Libs/DupArchive/States/DupArchiveSimpleExpandState.php @@ -0,0 +1,31 @@ +failures) > 0) { + foreach ($this->failures as $failure) { + if ($failure->isCritical) { + return true; + } + } + } + + return false; + } + + /** + * Che failure summary + * + * @param boolean $includeCritical include critical failures + * @param boolean $includeWarnings include warnings failures + * + * @return string + */ + public function getFailureSummary($includeCritical = true, $includeWarnings = false) + { + if (count($this->failures) > 0) { + $message = ''; + + foreach ($this->failures as $failure) { + if ($includeCritical || !$failure->isCritical) { + $message .= "\n" . $this->getFailureString($failure); + } + } + + return $message; + } else { + if ($includeCritical) { + if ($includeWarnings) { + return 'No errors or warnings.'; + } else { + return 'No errors.'; + } + } else { + return 'No warnings.'; + } + } + } + + /** + * Return failure string from item + * + * @param DupArchiveProcessingFailure $failure failure item + * + * @return string + */ + public function getFailureString(DupArchiveProcessingFailure $failure) + { + $s = ''; + + if ($failure->isCritical) { + $s = 'CRITICAL: '; + } + + return "{$s}{$failure->subject} : {$failure->description}"; + } + + /** + * Add failure item + * + * @param int $type failure type enum + * @param string $subject failure subject + * @param string $description failure description + * @param boolean $isCritical true if is critical + * + * @return DupArchiveProcessingFailure + */ + public function addFailure($type, $subject, $description, $isCritical = true) + { + $this->failureCount++; + if ($this->failureCount > self::MAX_FAILURE) { + return false; + } + + $failure = new DupArchiveProcessingFailure(); + + $failure->type = $type; + $failure->subject = $subject; + $failure->description = $description; + $failure->isCritical = $isCritical; + + $this->failures[] = $failure; + + return $failure; + } + + /** + * Set start time + * + * @return void + */ + public function startTimer() + { + if ($this->timerEnabled) { + $this->timeoutTimestamp = time() + $this->timeSliceInSecs; + } + } + + /** + * Check if is timeout + * + * @return bool + */ + public function timedOut() + { + if ($this->timerEnabled) { + if ($this->timeoutTimestamp != -1) { + return time() >= $this->timeoutTimestamp; + } else { + return false; + } + } else { + return false; + } + } +} diff --git a/src/Libs/DupArchive/Utils/DupArchiveScanUtil.php b/src/Libs/DupArchive/Utils/DupArchiveScanUtil.php new file mode 100644 index 00000000..2a1a23c0 --- /dev/null +++ b/src/Libs/DupArchive/Utils/DupArchiveScanUtil.php @@ -0,0 +1,96 @@ +Dirs = DupArchiveUtil::expandDirectories($sourceDirectory, true); + $scan->Files = DupArchiveUtil::expandFiles($sourceDirectory, true); + + return $scan; + } + + /** + * Scan folder and add result to scan file + * + * @param string $scanFilepath scan file + * @param string $sourceDirectory folder to scan + * + * @return void + */ + public static function createScan($scanFilepath, $sourceDirectory) + { + DupArchiveUtil::tlog("Creating scan"); + + $scan = self::createScanObject($sourceDirectory); + $scan_handle = fopen($scanFilepath, 'w'); + + if ($scan_handle === false) { + echo "Couldn't create scan file"; + die(); + } + + $jsn = SnapJson::jsonEncode($scan); + + fwrite($scan_handle, $jsn); + return $scan; + } +} diff --git a/src/Libs/DupArchive/Utils/DupArchiveUtil.php b/src/Libs/DupArchive/Utils/DupArchiveUtil.php new file mode 100644 index 00000000..32153ee8 --- /dev/null +++ b/src/Libs/DupArchive/Utils/DupArchiveUtil.php @@ -0,0 +1,165 @@ +log($s, $flush, $callingFunctionName); + } else { + // throw new Exception('Logging object not initialized'); + } + } + + /** + * Write trace log + * + * @param string $s log string + * @param boolean $flush if true flosh name + * @param string $callingFunctionName function has called log + * + * @return void + */ + public static function tlog($s, $flush = false, $callingFunctionName = null) + { + if (self::$TRACE_ON) { + if ($callingFunctionName === null) { + $callingFunctionName = SnapUtil::getCallingFunctionName(); + } + + self::log("####{$s}", $flush, $callingFunctionName); + } + } + + /** + * Write object in trace log + * + * @param string $s log string + * @param mixed $o value to write in log + * @param boolean $flush if true flosh name + * @param string $callingFunctionName function has called log + * + * @return void + */ + public static function tlogObject($s, $o, $flush = false, $callingFunctionName = null) + { + if (is_object($o)) { + $o = get_object_vars($o); + } + + $ostring = print_r($o, true); + + if ($callingFunctionName === null) { + $callingFunctionName = SnapUtil::getCallingFunctionName(); + } + + self::tlog($s, $flush, $callingFunctionName); + self::tlog($ostring, $flush, $callingFunctionName); + } + + /** + * Write object in log + * + * @param string $s log string + * @param mixed $o value to write in log + * @param boolean $flush if true flosh name + * @param string $callingFunctionName function has called log + * + * @return void + */ + public static function logObject($s, $o, $flush = false, $callingFunctionName = null) + { + $ostring = print_r($o, true); + + if ($callingFunctionName === null) { + $callingFunctionName = SnapUtil::getCallingFunctionName(); + } + + self::log($s, $flush, $callingFunctionName); + self::log($ostring, $flush, $callingFunctionName); + } +} diff --git a/src/Libs/OneClickUpgrade/ConnectSkin.php b/src/Libs/OneClickUpgrade/ConnectSkin.php new file mode 100644 index 00000000..37895fa7 --- /dev/null +++ b/src/Libs/OneClickUpgrade/ConnectSkin.php @@ -0,0 +1,41 @@ + \esc_html__('There was an error installing Duplicator Pro. Please try again.', 'duplicator'), + ) + ); + die; + } + } +} diff --git a/src/Libs/OneClickUpgrade/PluginSilentUpgrader.php b/src/Libs/OneClickUpgrade/PluginSilentUpgrader.php new file mode 100644 index 00000000..f0eb57e3 --- /dev/null +++ b/src/Libs/OneClickUpgrade/PluginSilentUpgrader.php @@ -0,0 +1,628 @@ + '', // Please always pass this. + 'destination' => '', // And this + 'clear_destination' => false, + 'abort_if_destination_exists' => true, // Abort if the Destination directory exists, Pass clear_destination as false please + 'clear_working' => true, + 'is_multi' => false, + 'hook_extra' => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters. + ); + + $options = wp_parse_args($options, $defaults); + + /** + * Filter the package options before running an update. + * + * See also {@see 'upgrader_process_complete'}. + * + * @since 4.3.0 + * + * @param array $options { + * Options used by the upgrader. + * + * @type string $package Package for update. + * @type string $destination Update location. + * @type bool $clear_destination Clear the destination resource. + * @type bool $clear_working Clear the working resource. + * @type bool $abort_if_destination_exists Abort if the Destination directory exists. + * @type bool $is_multi Whether the upgrader is running multiple times. + * @type array $hook_extra { + * Extra hook arguments. + * + * @type string $action Type of action. Default 'update'. + * @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'. + * @type bool $bulk Whether the update process is a bulk update. Default true. + * @type string $plugin Path to the plugin file relative to the plugins directory. + * @type string $theme The stylesheet or template name of the theme. + * @type string $language_update_type The language pack update type. Accepts 'plugin', 'theme', + * or 'core'. + * @type object $language_update The language pack update offer. + * } + * } + */ + $options = apply_filters('upgrader_package_options', $options); + + if (! $options['is_multi']) { // call $this->header separately if running multiple times + $this->skin->header(); + } + + // Connect to the Filesystem first. + $res = $this->fs_connect(array( WP_CONTENT_DIR, $options['destination'] )); + // Mainly for non-connected filesystem. + if (! $res) { + if (! $options['is_multi']) { + $this->skin->footer(); + } + return false; + } + + $this->skin->before(); + + if (is_wp_error($res)) { + $this->skin->error($res); + $this->skin->after(); + if (! $options['is_multi']) { + $this->skin->footer(); + } + return $res; + } + + /* + * Download the package (Note, This just returns the filename + * of the file if the package is a local file) + */ + $download = $this->downloadPackage($options['package'], true); + + // Allow for signature soft-fail. + // WARNING: This may be removed in the future. + if (is_wp_error($download) && $download->get_error_data('softfail-filename')) { + // Don't output the 'no signature could be found' failure message for now. + if ((string) $download->get_error_code() !== 'signature_verification_no_signature' || WP_DEBUG) { + // Outout the failure error as a normal feedback, and not as an error: + //$this->skin->feedback( $download->get_error_message() ); + + // Report this failure back to WordPress.org for debugging purposes. + wp_version_check( + array( + 'signature_failure_code' => $download->get_error_code(), + 'signature_failure_data' => $download->get_error_data(), + ) + ); + } + + // Pretend this error didn't happen. + $download = $download->get_error_data('softfail-filename'); + } + + if (is_wp_error($download)) { + $this->skin->error($download); + $this->skin->after(); + if (! $options['is_multi']) { + $this->skin->footer(); + } + return $download; + } + + $delete_package = ( (string) $download !== (string) $options['package'] ); // Do not delete a "local" file. + + // Unzips the file into a temporary directory. + $working_dir = $this->unpackPackage($download, $delete_package); + if (is_wp_error($working_dir)) { + $this->skin->error($working_dir); + $this->skin->after(); + if (! $options['is_multi']) { + $this->skin->footer(); + } + return $working_dir; + } + + // With the given options, this installs it to the destination directory. + $result = $this->installPackage( + array( + 'source' => $working_dir, + 'destination' => $options['destination'], + 'clear_destination' => $options['clear_destination'], + 'abort_if_destination_exists' => $options['abort_if_destination_exists'], + 'clear_working' => $options['clear_working'], + 'hook_extra' => $options['hook_extra'], + ) + ); + + $this->skin->set_result($result); + if (is_wp_error($result)) { + $this->skin->error($result); + //$this->skin->feedback( 'process_failed' ); + } else { + // Installation succeeded. + //$this->skin->feedback( 'process_success' ); + } + + $this->skin->after(); + + if (! $options['is_multi']) { + + /** + * Fire when the upgrader process is complete. + * + * See also {@see 'upgrader_package_options'}. + * + * @since 3.6.0 + * @since 3.7.0 Added to WP_Upgrader::run(). + * @since 4.6.0 `$translations` was added as a possible argument to `$hook_extra`. + * + * @param WP_Upgrader $this WP_Upgrader instance. In other contexts, $this, might be a + * Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or + * Language_Pack_Upgrader instance. + * @param array $hook_extra { + * Array of bulk item update data. + * + * @type string $action Type of action. Default 'update'. + * @type string $type Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'. + * @type bool $bulk Whether the update process is a bulk update. Default true. + * @type array $plugins Array of the basename paths of the plugins' main files. + * @type array $themes The theme slugs. + * @type array $translations { + * Array of translations update data. + * + * @type string $language The locale the translation is for. + * @type string $type Type of translation. Accepts 'plugin', 'theme', or 'core'. + * @type string $slug Text domain the translation is for. The slug of a theme/plugin or + * 'default' for core translations. + * @type string $version The version of a theme, plugin, or core. + * } + * } + */ + do_action('upgrader_process_complete', $this, $options['hook_extra']); + + $this->skin->footer(); + } + + return $result; + } + + /** + * Toggle maintenance mode for the site. + * + * Create/delete the maintenance file to enable/disable maintenance mode. + * + * @since 2.8.0 + * + * @global WP_Filesystem_Base $wp_filesystem Subclass + * + * @param bool $enable True to enable maintenance mode, false to disable. + * + * @return void + */ + public function maintenanceMode($enable = false) + { + global $wp_filesystem; + $file = $wp_filesystem->abspath() . '.maintenance'; + if ($enable) { + //$this->skin->feedback( 'maintenance_start' ); + // Create maintenance file to signal that we are upgrading + $maintenance_string = ''; + $wp_filesystem->delete($file); + $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE); + } elseif (! $enable && $wp_filesystem->exists($file)) { + //$this->skin->feedback( 'maintenance_end' ); + $wp_filesystem->delete($file); + } + } + + /** + * Download a package. + * + * @since 2.8.0 + * @since 5.5.0 Added the `$hook_extra` parameter. + * + * @param string $package The URI of the package. If this is the full path to an + * existing local file, it will be returned untouched. + * @param bool $check_signatures Whether to validate file signatures. Default false. + * @param array $hook_extra Extra arguments to pass to the filter hooks. Default empty array. + * + * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object. + */ + public function downloadPackage($package, $check_signatures = false, $hook_extra = array()) + { + + /** + * Filters whether to return the package. + * + * @since 3.7.0 + * @since 5.5.0 Added the `$hook_extra` parameter. + * + * @param bool $reply Whether to bail without returning the package. + * Default false. + * @param string $package The package file name. + * @param WP_Upgrader $this The WP_Upgrader instance. + * @param array $hook_extra Extra arguments passed to hooked filters. + */ + $reply = apply_filters('upgrader_pre_download', false, $package, $this, $hook_extra); + if (false !== $reply) { + return $reply; + } + + if (! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package)) { // Local file or remote? + return $package; // Must be a local file. + } + + if (empty($package)) { + return new WP_Error('no_package', $this->strings['no_package']); + } + + //$this->skin->feedback( 'downloading_package', $package ); + + $download_file = download_url($package, 300, $check_signatures); + + if (is_wp_error($download_file) && ! $download_file->get_error_data('softfail-filename')) { + return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message()); + } + + return $download_file; + } + + /** + * Unpack a compressed package file. + * + * @since 2.8.0 + * + * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. + * + * @param string $package Full path to the package file. + * @param bool $delete_package Optional. Whether to delete the package file after attempting + * to unpack it. Default true. + * + * @return string|WP_Error The path to the unpacked contents, or a WP_Error on failure. + */ + public function unpackPackage($package, $delete_package = true) + { + global $wp_filesystem; + + //$this->skin->feedback( 'unpack_package' ); + + $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; + + //Clean up contents of upgrade directory beforehand. + $upgrade_files = $wp_filesystem->dirlist($upgrade_folder); + if (! empty($upgrade_files)) { + foreach ($upgrade_files as $file) { + $wp_filesystem->delete($upgrade_folder . $file['name'], true); + } + } + + // We need a working directory - Strip off any .tmp or .zip suffixes + $working_dir = $upgrade_folder . basename(basename($package, '.tmp'), '.zip'); + + // Clean up working directory + if ($wp_filesystem->is_dir($working_dir)) { + $wp_filesystem->delete($working_dir, true); + } + + // Unzip package to working directory + $result = unzip_file($package, $working_dir); + + // Once extracted, delete the package if required. + if ($delete_package) { + unlink($package); + } + + if (is_wp_error($result)) { + $wp_filesystem->delete($working_dir, true); + if ($result->get_error_code() === 'incompatible_archive') { + return new WP_Error('incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data()); + } + + return $result; + } + + return $working_dir; + } + + /** + * Install a package. + * + * Copies the contents of a package form a source directory, and installs them in + * a destination directory. Optionally removes the source. It can also optionally + * clear out the destination folder if it already exists. + * + * @since 2.8.0 + * + * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. + * @global array $wp_theme_directories + * + * @param array|string $args { + * Optional. Array or string of arguments for installing a package. Default empty array. + * + * @type string $source Required path to the package source. Default empty. + * @type string $destination Required path to a folder to install the package in. + * Default empty. + * @type bool $clear_destination Whether to delete any files already in the destination + * folder. Default false. + * @type bool $clear_working Whether to delete the files form the working directory + * after copying to the destination. Default false. + * @type bool $abort_if_destination_exists Whether to abort the installation if + * the destination folder already exists. Default true. + * @type array $hook_extra Extra arguments to pass to the filter hooks called by + * WP_Upgrader::install_package(). Default empty array. + * } + * + * @return array|WP_Error The result (also stored in `WP_Upgrader::$result`), or a WP_Error on failure. + */ + public function installPackage($args = array()) + { + global $wp_filesystem, $wp_theme_directories; + + $defaults = array( + 'source' => '', // Please always pass this + 'destination' => '', // and this + 'clear_destination' => false, + 'clear_working' => false, + 'abort_if_destination_exists' => true, + 'hook_extra' => array(), + ); + + $args = wp_parse_args($args, $defaults); + + // These were previously extract()'d. + $source = $args['source']; + $destination = $args['destination']; + $clear_destination = $args['clear_destination']; + + \Duplicator\Libs\Snap\SnapUtil::duplicatorSetTimeLimit(300); + + if (empty($source) || empty($destination)) { + return new WP_Error('bad_request', $this->strings['bad_request']); + } + //$this->skin->feedback( 'installing_package' ); + + /** + * Filter the install response before the installation has started. + * + * Returning a truthy value, or one that could be evaluated as a WP_Error + * will effectively short-circuit the installation, returning that value + * instead. + * + * @since 2.8.0 + * + * @param bool|WP_Error $response Response. + * @param array $hook_extra Extra arguments passed to hooked filters. + */ + $res = apply_filters('upgrader_pre_install', true, $args['hook_extra']); + + if (is_wp_error($res)) { + return $res; + } + + // Retain the Original source and destinations. + $remote_source = $args['source']; + $local_destination = $destination; + + $source_files = array_keys($wp_filesystem->dirlist($remote_source)); + $remote_destination = $wp_filesystem->find_folder($local_destination); + $count_source_files = count($source_files); + + // Locate which directory to copy to the new folder, This is based on the actual folder holding the files. + if ( + $count_source_files === 1 && + $wp_filesystem->is_dir(trailingslashit($args['source']) . $source_files[0] . '/') + ) { // Only one folder? Then we want its contents. + $source = trailingslashit($args['source']) . trailingslashit($source_files[0]); + } elseif ($count_source_files === 0) { + return new WP_Error('incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files']); // There are no files? + } else { // It's only a single file, the upgrader will use the folder name of this file as the destination folder. Folder name is based on zip filename. + $source = trailingslashit($args['source']); + } + + /** + * Filter the source file location for the upgrade package. + * + * @since 2.8.0 + * @since 4.4.0 The $hook_extra parameter became available. + * + * @param string $source File source location. + * @param string $remote_source Remote file source location. + * @param WP_Upgrader $this WP_Upgrader instance. + * @param array $hook_extra Extra arguments passed to hooked filters. + */ + $source = apply_filters('upgrader_source_selection', $source, $remote_source, $this, $args['hook_extra']); + + if (is_wp_error($source)) { + return $source; + } + + // Has the source location changed? If so, we need a new source_files list. + if ($source !== $remote_source) { + $source_files = array_keys($wp_filesystem->dirlist($source)); + } + + /* + * Protection against deleting files in any important base directories. + * Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the + * destination directory (WP_PLUGIN_DIR / wp-content/themes) intending + * to copy the directory into the directory, whilst they pass the source + * as the actual files to copy. + */ + $protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' ); + + if (is_array($wp_theme_directories)) { + $protected_directories = array_merge($protected_directories, $wp_theme_directories); + } + + if (in_array($destination, $protected_directories)) { + $remote_destination = trailingslashit($remote_destination) . trailingslashit(basename($source)); + $destination = trailingslashit($destination) . trailingslashit(basename($source)); + } + + if ($clear_destination) { + // We're going to clear the destination if there's something there. + $removed = $this->clear_destination($remote_destination); + + /** + * Filter whether the upgrader cleared the destination. + * + * @since 2.8.0 + * + * @param mixed $removed Whether the destination was cleared. true on success, WP_Error on failure. + * @param string $local_destination The local package destination. + * @param string $remote_destination The remote package destination. + * @param array $hook_extra Extra arguments passed to hooked filters. + */ + $removed = apply_filters('upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra']); + + if (is_wp_error($removed)) { + return $removed; + } + } elseif ($args['abort_if_destination_exists'] && $wp_filesystem->exists($remote_destination)) { + // If we're not clearing the destination folder and something exists there already, Bail. + // But first check to see if there are actually any files in the folder. + $_files = $wp_filesystem->dirlist($remote_destination); + + if (! empty($_files)) { + $wp_filesystem->delete($remote_source, true); // Clear out the source files. + + return new WP_Error('folder_exists', $this->strings['folder_exists'], $remote_destination); + } + } + + // Create destination if needed. + if (! $wp_filesystem->exists($remote_destination)) { + if (! $wp_filesystem->mkdir($remote_destination, FS_CHMOD_DIR)) { + return new WP_Error('mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination); + } + } + + // Copy new version of item into place. + $result = copy_dir($source, $remote_destination); + + if (is_wp_error($result)) { + if ($args['clear_working']) { + $wp_filesystem->delete($remote_source, true); + } + + return $result; + } + + // Clear the Working folder? + if ($args['clear_working']) { + $wp_filesystem->delete($remote_source, true); + } + + $destination_name = basename(str_replace($local_destination, '', $destination)); + + if ($destination_name === '.') { + $destination_name = ''; + } + + $this->result = compact('source', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination'); + + /** + * Filter the installation response after the installation has finished. + * + * @since 2.8.0 + * + * @param bool $response Installation response. + * @param array $hook_extra Extra arguments passed to hooked filters. + * @param array $result Installation result data. + */ + $res = apply_filters('upgrader_post_install', true, $args['hook_extra'], $this->result); + + if (is_wp_error($res)) { + $this->result = $res; + + return $res; + } + + // Bombard the calling function will all the info which we've just used. + return $this->result; + } + + /** + * Install a plugin package. + * + * @since 1.6.3 + * + * @param string $package The full local path or URI of the package. + * @param array $args Optional. Other arguments for installing a plugin package. Default empty array. + * + * @return bool|\WP_Error True if the installation was successful, false or a WP_Error otherwise. + */ + public function install($package, $args = array()) + { + + DUP_Log::trace("About to call parent::install..."); + $result = parent::install($package, $args); + DUP_Log::trace("parent::install finished."); + + if (true === $result) { + do_action('duplicator_pro_plugin_installed', $package); + } + + return $result; + } +} diff --git a/src/Libs/OneClickUpgrade/PluginSilentUpgraderSkin.php b/src/Libs/OneClickUpgrade/PluginSilentUpgraderSkin.php new file mode 100644 index 00000000..3e2ac195 --- /dev/null +++ b/src/Libs/OneClickUpgrade/PluginSilentUpgraderSkin.php @@ -0,0 +1,67 @@ +type = $type; + break; + default: + throw new Exception('Invalid item type'); + } + + if (strlen($key) == 0) { + throw new Exception('Key can\'t be empty'); + } + $this->required = $required; + $this->itemKey = (string) $key; + $this->link = (string) $link; + $this->troubleshoot = (string) $troubleshoot; + } + + /** + * Get the value of type + * + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * Get the value of itemKey + * + * @return string + */ + public function getItemKey() + { + return $this->itemKey; + } + + /** + * true if is required + * + * @return bool + */ + public function isRequired() + { + return $this->required; + } + + /** + * Check if item exists + * + * @return bool + */ + public function check() + { + $result = false; + + switch ($this->type) { + case self::TYPE_FUNCTION: + $result = function_exists($this->itemKey); + break; + case self::TYPE_CLASS: + $result = SnapUtil::classExists($this->itemKey); + break; + default: + throw new Exception('Invalid item type'); + } + + if ($result == false && is_callable($this->failCallback)) { + call_user_func($this->failCallback, $this); + } + return $result; + } + + /** + * Set the value of failCallback + * + * @param callable $failCallback fail callback function + * + * @return void + */ + public function setFailCallback($failCallback) + { + $this->failCallback = $failCallback; + } + + /** + * Check all Functionalities in list + * + * @param self[] $funcs Functionalities list + * @param bool $requiredOnly if true skip functs not required + * @param self[] $notPassList list of items that not have pass the test + * + * @return bool + */ + public static function checkList($funcs, $requiredOnly = false, &$notPassList = array()) + { + if (!is_array($funcs)) { + throw new Exception('funcs must be an array'); + } + + $notPassList = array(); + + foreach ($funcs as $func) { + if ($requiredOnly && !$func->isRequired()) { + continue; + } + + if ($func->check() === false) { + $notPassList[] = $func; + } + } + + return (count($notPassList) === 0); + } +} diff --git a/src/Libs/Snap/JsonSerializable.php b/src/Libs/Snap/JsonSerializable.php new file mode 100644 index 00000000..238466f4 --- /dev/null +++ b/src/Libs/Snap/JsonSerializable.php @@ -0,0 +1,30 @@ + $reflect->name); + } + + if (method_exists($obj, '__sleep')) { + $includeProps = $obj->__sleep(); + if (!is_array($includeProps)) { + throw new Exception('__sleep method must return an array'); + } + } else { + $includeProps = true; + } + + // Get all props of current class but not props private of parent class and static props + foreach ($reflect->getProperties() as $prop) { + if ($prop->isStatic()) { + continue; + } + $propName = $prop->getName(); + if ($includeProps !== true && !in_array($propName, $includeProps)) { + continue; + } + $prop->setAccessible(true); + $propValue = $prop->getValue($obj); + $result[$propName] = self::valueToJsonData($propValue, $flags, $objParents); + } + + return $result; + } + + /** + * Recursive parse values, all objects are transformed to array + * + * @param mixed $value valute to parse + * @param int $flags flags bitmask + * @param string[] $objParents objs parents unique hash ids + * + * @return mixed + */ + final public static function valueToJsonData($value, $flags = 0, $objParents = array()) + { + switch (gettype($value)) { + case "boolean": + case "integer": + case "double": + case "string": + case "NULL": + return $value; + case "array": + $result = array(); + foreach ($value as $key => $arrayVal) { + $result[$key] = self::valueToJsonData($arrayVal, $flags, $objParents); + } + return $result; + case "object": + $objHash = spl_object_hash($value); + if (in_array($objHash, $objParents)) { + // prevent infinite recursion loop + return null; + } + $objParents[] = $objHash; + return self::objectToJsonData($value, $flags, $objParents); + case "resource": + case "resource (closed)": + case "unknown type": + default: + return null; + } + } + + /** + * Return value from json decoded data + * + * @param mixed $value json decoded data + * + * @return mixed + */ + final protected static function jsonDataToValue($value) + { + switch (gettype($value)) { + case 'array': + if (($newClassName = self::getClassFromArray($value)) === false) { + $result = array(); + foreach ($value as $key => $arrayVal) { + $result[$key] = self::jsonDataToValue($arrayVal); + } + } else { + $result = self::fillObjFromValue($value, self::getObjFromClass($newClassName)); + } + return $result; + case 'boolean': + case 'integer': + case 'double': + case 'string': + case "NULL": + return $value; + default: + return null; + } + } + + /** + * Get object from class name, if class don't exists return StdClass. + * With PHP 5.4.0 the object is intialized without call the constructor. + * + * @param string $class class name + * + * @return object + */ + final protected static function getObjFromClass($class) + { + if (class_exists($class)) { + if (version_compare(PHP_VERSION, '5.4.0') >= 0) { + $classReflect = new ReflectionClass($class); + return $classReflect->newInstanceWithoutConstructor(); + } else { + return new $class(); + } + } else { + return new \StdClass(); + } + } + + /** + * Fill passed object from array values + * + * @param array $value value from json data + * @param object $obj object to fill with json data + * + * @return object + */ + final protected static function fillObjFromValue($value, $obj) + { + if ($obj instanceof \stdClass) { + foreach ($value as $arrayProp => $arrayValue) { + if ($arrayProp == self::CLASS_KEY_FOR_JSON_SERIALIZE) { + continue; + } + $obj->{$arrayProp} = self::jsonDataToValue($arrayValue); + } + } else { + $reflect = new ReflectionObject($obj); + foreach ($reflect->getProperties() as $prop) { + $prop->setAccessible(true); + $propName = $prop->getName(); + if (!isset($value[$propName]) || $prop->isStatic()) { + continue; + } + $prop->setValue($obj, self::jsonDataToValue($value[$propName])); + } + + if (method_exists($obj, '__wakeup')) { + $obj->__wakeup(); + } + } + return $obj; + } + + /** + * Return class name from array values + * + * @param array $array array data + * + * @return bool|string false if prop not found + */ + final protected static function getClassFromArray($array) + { + return (isset($array[self::CLASS_KEY_FOR_JSON_SERIALIZE]) ? $array[self::CLASS_KEY_FOR_JSON_SERIALIZE] : false); + } +} diff --git a/src/Libs/Snap/JsonSerialize/JsonSerialize.php b/src/Libs/Snap/JsonSerialize/JsonSerialize.php new file mode 100644 index 00000000..1bc9ccba --- /dev/null +++ b/src/Libs/Snap/JsonSerialize/JsonSerialize.php @@ -0,0 +1,83 @@ +=') ? json_decode($json, true, $depth, $flags) : json_decode($json, true, $depth) + ); + return self::jsonDataToValue($publicArray); + } + + /** + * Unserialize json on passed object + * + * @param string $json json string + * @param object|string $obj object to fill or class name + * @param integer $depth json_decode depth + * @param integer $flags json_decode flags + * + * @link https://www.php.net/manual/en/function.json-decode.php + * + * @return object + */ + public static function unserializeToObj($json, $obj, $depth = 512, $flags = 0) + { + if (is_object($obj)) { + } elseif (is_string($obj) && class_exists($obj)) { + $obj = self::getObjFromClass($obj); + } else { + throw new Exception('invalid obj param'); + } + // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.json_decode_optionsFound + $value = (version_compare(PHP_VERSION, '5.4', '>=') ? json_decode($json, true, $depth, $flags) : json_decode($json, true, $depth) + ); + if (!is_array($value)) { + throw new Exception('json value isn\'t an array VALUE: ' . SnapLog::v2str($value)); + } + return self::fillObjFromValue($value, $obj); + } +} diff --git a/src/Libs/Snap/Snap32BitSizeLimitException.php b/src/Libs/Snap/Snap32BitSizeLimitException.php new file mode 100644 index 00000000..673f4dd9 --- /dev/null +++ b/src/Libs/Snap/Snap32BitSizeLimitException.php @@ -0,0 +1,13 @@ + */ + private static $cache = array(); + + /** + * Return array if primary key is composite key + * + * @param mysqli|resource $dbh database connection + * @param string $tableName table name + * @param null|callable $logCallback log callback + * + * @return false|string|string[] return unique index column ky or false if don't exists + */ + public static function getUniqueIndexColumn($dbh, $tableName, $logCallback = null) + { + $cacheKey = self::CACHE_PREFIX_PRIMARY_KEY_COLUMN . $tableName; + + if (!isset(self::$cache[$cacheKey])) { + $query = 'SHOW COLUMNS FROM `' . self::realEscapeString($dbh, $tableName) . '` WHERE `Key` IN ("PRI","UNI")'; + if (($result = self::query($dbh, $query)) === false) { + if (is_callable($logCallback)) { + call_user_func($logCallback, $dbh, $result, $query); + } + throw new \Exception('SHOW KEYS QUERY ERROR: ' . self::error($dbh)); + } + + if (is_callable($logCallback)) { + call_user_func($logCallback, $dbh, $result, $query); + } + + if (self::numRows($result) == 0) { + self::$cache[$cacheKey] = false; + } else { + $primary = false; + $excludePrimary = false; + $unique = false; + + while ($row = self::fetchAssoc($result)) { + switch ($row['Key']) { + case 'PRI': + if ($primary === false) { + $primary = $row['Field']; + } else { + if (is_scalar($primary)) { + $primary = array($primary); + } + $primary[] = $row['Field']; + } + + if (preg_match('/^(?:var)?binary/i', $row['Type'])) { + // exclude binary or varbynary columns + $excludePrimary = true; + } + break; + case 'UNI': + if (!preg_match('/^(?:var)?binary/i', $row['Type'])) { + // exclude binary or varbynary columns + $unique = $row['Field']; + } + break; + default: + break; + } + } + if ($primary !== false && $excludePrimary === false) { + self::$cache[$cacheKey] = $primary; + } elseif ($unique !== false) { + self::$cache[$cacheKey] = $unique; + } else { + self::$cache[$cacheKey] = false; + } + } + self::freeResult($result); + } + + return self::$cache[$cacheKey]; + } + + /** + * Escape the regex for mysql queries, the mysqli_real_escape must be applied anyway to the generated string + * + * @param string $regex Regex + * + * @return string Escaped regex + */ + public static function quoteRegex($regex) + { + // preg_quote takes a string and escapes special characters with a backslash. + // It is meant for PHP regexes, not MySQL regexes, and it does not escape &, + // which is needed for MySQL. So we only need to modify it like so: + // https://stackoverflow.com/questions/3782379/whats-the-best-way-to-escape-user-input-for-regular-expressions-in-mysql + return preg_replace('/&/', '\\&', preg_quote($regex, null /* no delimiter */)); + } + + /** + * Returns the offset from the current row + * + * @param mixed[] $row current database row + * @param int|string|string[] $indexColumns columns of the row that generated the index offset + * @param mixed $lastOffset last offset + * + * @return mixed + */ + public static function getOffsetFromRowAssoc($row, $indexColumns, $lastOffset) + { + if (is_array($indexColumns)) { + $result = array(); + foreach ($indexColumns as $col) { + $result[$col] = isset($row[$col]) ? $row[$col] : 0; + } + return $result; + } elseif (strlen($indexColumns) > 0) { + return isset($row[$indexColumns]) ? $row[$indexColumns] : 0; + } else { + if (is_scalar($lastOffset)) { + return $lastOffset + 1; + } else { + return $lastOffset; + } + } + } + + /** + * This function performs a select by structuring the primary key as offset if the table has a primary key. + * For optimization issues, no checks are performed on the input query and it is assumed that the select has at least a where value. + * If there are no conditions, you still have to perform an always true condition, for example + * SELECT * FROM `copy1_postmeta` WHERE 1 + * + * @param mysqli|resource $dbh database connection + * @param string $query query string + * @param string $table table name + * @param int $offset row offset + * @param int $limit limit of query, 0 no limit + * @param mixed $lastRowOffset last offset to use on next function call + * @param null|callable $logCallback log callback + * + * @return mysqli_result + */ + public static function selectUsingPrimaryKeyAsOffset($dbh, $query, $table, $offset, $limit, &$lastRowOffset = null, $logCallback = null) + { + $where = ''; + $orderby = ''; + $offsetStr = ''; + $limitStr = $limit > 0 ? ' LIMIT ' . $limit : ''; + + if (($primaryColumn = self::getUniqueIndexColumn($dbh, $table, $logCallback)) == false) { + $offsetStr = ' OFFSET ' . (is_scalar($offset) ? $offset : 0); + } else { + if (is_array($primaryColumn)) { + // COMPOSITE KEY + $orderByCols = array(); + foreach ($primaryColumn as $colIndex => $col) { + $orderByCols[] = '`' . $col . '` ASC'; + } + $orderby = ' ORDER BY ' . implode(',', $orderByCols); + } else { + $orderby = ' ORDER BY `' . $primaryColumn . '` ASC'; + } + $where = self::getOffsetKeyCondition($dbh, $primaryColumn, $offset); + } + $query .= $where . $orderby . $limitStr . $offsetStr; + + if (($result = self::query($dbh, $query)) === false) { + if (is_callable($logCallback)) { + call_user_func($logCallback, $dbh, $result, $query); + } + throw new \Exception('SELECT ERROR: ' . self::error($dbh) . ' QUERY: ' . $query); + } + + if (is_callable($logCallback)) { + call_user_func($logCallback, $dbh, $result, $query); + } + + if (self::dbConnTypeByResult($result) === self::CONN_MYSQLI) { + if ($primaryColumn == false) { + $lastRowOffset = $offset + $result->num_rows; + } else { + if ($result->num_rows == 0) { + $lastRowOffset = $offset; + } else { + $result->data_seek(($result->num_rows - 1)); + $row = $result->fetch_assoc(); + if (is_array($primaryColumn)) { + $lastRowOffset = array(); + foreach ($primaryColumn as $col) { + $lastRowOffset[$col] = $row[$col]; + } + } else { + $lastRowOffset = $row[$primaryColumn]; + } + $result->data_seek(0); + } + } + } else { + if ($primaryColumn == false) { + $lastRowOffset = $offset + mysql_num_rows($result); // @phpstan-ignore-line + } else { + if (mysql_num_rows($result) == 0) { // @phpstan-ignore-line + $lastRowOffset = $offset; + } else { + mysql_data_seek($result, (mysql_num_rows($result) - 1)); // @phpstan-ignore-line + $row = mysql_fetch_assoc($result); // @phpstan-ignore-line + if (is_array($primaryColumn)) { + $lastRowOffset = array(); + foreach ($primaryColumn as $col) { + $lastRowOffset[$col] = $row[$col]; + } + } else { + $lastRowOffset = $row[$primaryColumn]; + } + mysql_data_seek($result, 0); // @phpstan-ignore-line + } + } + } + + return $result; + } + + /** + * Depending on the structure type of the primary key returns the condition to position at the right offset + * + * @param mysqli|resource $dbh database connection + * @param string|string[] $primaryColumn primaricolumng index + * @param mixed $offset offset + * + * @return string + */ + protected static function getOffsetKeyCondition($dbh, $primaryColumn, $offset) + { + $condition = ''; + + if ($offset === 0) { + return ''; + } + + // COUPOUND KEY + if (is_array($primaryColumn)) { + $isFirstCond = true; + + foreach ($primaryColumn as $colIndex => $col) { + if (is_array($offset) && isset($offset[$col])) { + if ($isFirstCond) { + $isFirstCond = false; + } else { + $condition .= ' OR '; + } + $condition .= ' ('; + for ($prevColIndex = 0; $prevColIndex < $colIndex; $prevColIndex++) { + $condition .= + ' `' . $primaryColumn[$prevColIndex] . '` = "' . + self::realEscapeString($dbh, $offset[$primaryColumn[$prevColIndex]]) . '" AND '; + } + $condition .= ' `' . $col . '` > "' . self::realEscapeString($dbh, $offset[$col]) . '")'; + } + } + } else { + $condition = '`' . $primaryColumn . '` > "' . self::realEscapeString($dbh, (is_scalar($offset) ? $offset : 0)) . '"'; + } + + return (strlen($condition) ? ' AND (' . $condition . ')' : ''); + } + + /** + * get current database engine (mysql, maria, percona) + * + * @param mysqli|resource $dbh database connection + * + * @return string + */ + public static function getDBEngine($dbh) + { + if (($result = self::query($dbh, "SHOW VARIABLES LIKE 'version%'")) === false) { + // on query error assume is mysql. + return self::DB_ENGINE_MYSQL; + } + + $rows = array(); + while ($row = self::fetchRow($result)) { + $rows[] = $row; + } + self::freeResult($result); + + $version = isset($rows[0][1]) ? $rows[0][1] : false; + $versionComment = isset($rows[1][1]) ? $rows[1][1] : false; + + //Default is mysql + if ($version === false && $versionComment === false) { + return self::DB_ENGINE_MYSQL; + } + + if (stripos($version, 'maria') !== false || stripos($versionComment, 'maria') !== false) { + return self::DB_ENGINE_MARIA; + } + + if (stripos($version, 'percona') !== false || stripos($versionComment, 'percona') !== false) { + return self::DB_ENGINE_PERCONA; + } + + return self::DB_ENGINE_MYSQL; + } + + /** + * Escape string + * + * @param resource|mysqli $dbh database connection + * @param string $string string to escape + * + * @return string Returns an escaped string. + */ + public static function realEscapeString($dbh, $string) + { + if (self::dbConnType($dbh) === self::CONN_MYSQLI) { + return mysqli_real_escape_string($dbh, $string); + } else { + return mysql_real_escape_string($string, $dbh); // @phpstan-ignore-line + } + } + + /** + * + * @param resource|mysqli $dbh database connection + * @param string $query query string + * + * @return mixed

                        Returns FALSE on failure. For successful SELECT, SHOW, DESCRIBE or + * EXPLAIN queries mysqli_query() will return a mysqli_result object. + * For other successful queries mysqli_query() will return TRUE.

                        + */ + public static function query($dbh, $query) + { + try { + if (self::dbConnType($dbh) === self::CONN_MYSQLI) { + return mysqli_query($dbh, $query); + } else { + return mysql_query($query, $dbh); // @phpstan-ignore-line + } + } catch (Exception $e) { + return false; + } + } + + /** + * + * @param resource|mysqli_result $result query result + * + * @return int + */ + public static function numRows($result) + { + if (self::dbConnTypeByResult($result) === self::CONN_MYSQLI) { + return $result->num_rows; + } else { + return mysql_num_rows($result); // @phpstan-ignore-line + } + } + + /** + * + * @param resource|mysqli_result $result query result + * + * @return string[]|null|false Returns an array of strings that corresponds to the fetched row. NULL if there are no more rows in result set + */ + public static function fetchRow($result) + { + if (self::dbConnTypeByResult($result) === self::CONN_MYSQLI) { + return mysqli_fetch_row($result); + } elseif (is_resource($result)) { + return mysql_fetch_row($result); // @phpstan-ignore-line + } else { + return false; + } + } + + /** + * + * @param resource|mysqli_result $result query result + * + * @return string[]|null|false Returns an associative array of values representing the fetched row in the result set, + * where each key in the array represents the name of one of the result set's + * columns or null if there are no more rows in result set. + */ + public static function fetchAssoc($result) + { + if (self::dbConnTypeByResult($result) === self::CONN_MYSQLI) { + return mysqli_fetch_assoc($result); + } elseif (is_resource($result)) { + return mysql_fetch_assoc($result); // @phpstan-ignore-line + } else { + return false; + } + } + + /** + * + * @param resource|mysqli_result $result query result + * + * @return boolean + */ + public static function freeResult($result) + { + if (self::dbConnTypeByResult($result) === self::CONN_MYSQLI) { + $result->free(); + return true; + } elseif (is_resource($result)) { + return mysql_free_result($result); // @phpstan-ignore-line + } else { + $result = null; + return true; + } + } + + /** + * + * @param resource|mysqli $dbh database connection + * + * @return string + */ + public static function error($dbh) + { + if (self::dbConnType($dbh) === self::CONN_MYSQLI) { + if ($dbh instanceof mysqli) { + return mysqli_error($dbh); + } else { + return 'Unable to retrieve the error message from MySQL'; + } + } else { + if (is_resource($dbh)) { + return mysql_error($dbh); // @phpstan-ignore-line + } else { + return 'Unable to retrieve the error message from MySQL'; + } + } + } + + /** + * + * @param resource|mysqli $dbh database connection + * + * @return string // self::CONN_MYSQLI|self::CONN_MYSQL + */ + public static function dbConnType($dbh) + { + return (is_object($dbh) && get_class($dbh) == 'mysqli') ? self::CONN_MYSQLI : self::CONN_MYSQL; + } + + /** + * + * @param resource|mysqli_result $result query resyult + * + * @return string Enum self::CONN_MYSQLI|self::CONN_MYSQL + */ + public static function dbConnTypeByResult($result) + { + return (is_object($result) && get_class($result) == 'mysqli_result') ? self::CONN_MYSQLI : self::CONN_MYSQL; + } + + /** + * This function takes in input the values of a multiple inster with this format + * (v1, v2, v3 ...),(v1, v2, v3, ...),... + * and returns a two dimensional array where each item is a row containing the list of values + * [ + * [v1, v2, v3 ...], + * [v1, v2, v3 ...], + * ... + * ] + * The return values are not processed but are taken exactly as they are in the dump file. + * So if they are escaped it remains unchanged + * + * @param string $query query values + * + * @return array> + */ + public static function getValuesFromQueryInsert($query) + { + $result = array(); + $isItemOpen = false; + $isStringOpen = false; + $char = ''; + $pChar = ''; + + $currentItem = array(); + $currentValue = ''; + + for ($i = 0; $i < strlen($query); $i++) { + $pChar = $char; + $char = $query[$i]; + + switch ($char) { + case '(': + if ($isItemOpen == false && !$isStringOpen) { + $isItemOpen = true; + continue 2; + } + break; + case ')': + if ($isItemOpen && !$isStringOpen) { + $isItemOpen = false; + $currentItem[] = trim($currentValue); + $currentValue = ''; + $result[] = $currentItem; + $currentItem = array(); + continue 2; + } + break; + case '\'': + case '"': + if ($isStringOpen === false && $pChar !== '\\') { + $isStringOpen = $char; + } elseif ($isStringOpen === $char && $pChar !== '\\') { + $isStringOpen = false; + } + break; + case ',': + if ($isItemOpen == false) { + continue 2; + } elseif ($isStringOpen === false) { + $currentItem[] = trim($currentValue); + $currentValue = ''; + continue 2; + } + break; + default: + break; + } + + if ($isItemOpen == false) { + continue; + } + + $currentValue .= $char; + } + return $result; + } + + /** + * This is the inverse of getValuesFromQueryInsert, from an array of values it returns the valody of an insert query + * + * @param mixed[] $values rows values + * + * @return string + */ + public static function getQueryInsertValuesFromArray(array $values) + { + + return implode( + ',', + array_map( + function ($rowVals) { + return '(' . implode(',', $rowVals) . ')'; + }, + $values + ) + ); + } + + /** + * Returns the content of a value resulting from getValuesFromQueryInsert in string + * Then remove the outer quotes and escape + * "value\"test" become value"test + * + * @param string $value value + * + * @return string + */ + public static function parsedQueryValueToString($value) + { + $result = preg_replace('/^[\'"]?(.*?)[\'"]?$/s', '$1', $value); + return stripslashes($result); + } + + /** + * Returns the content of a value resulting from getValuesFromQueryInsert in int + * Then remove the outer quotes and escape + * "100" become (int)100 + * + * @param string $value value + * + * @return int + */ + public static function parsedQueryValueToInt($value) + { + return (int) preg_replace('/^[\'"]?(.*?)[\'"]?$/s', '$1', $value); + } + + /** + * Return the list of mysqlrealconnect existing flags values from mask + * + * @see https://www.php.net/manual/en/mysqli.real-connect.php + * + * @param bool $returnStr if true return define string else values + * @param null|int[] $filter if not null only the values that exist and are contained in the array are returned + * + * @return int[]|string[] + */ + public static function getMysqlConnectFlagsList($returnStr = true, $filter = null) + { + static $flagsList = null; + + if (is_null($flagsList)) { + $flagsList = array(); + + if (defined('MYSQLI_CLIENT_COMPRESS')) { + $flagsList[MYSQLI_CLIENT_COMPRESS] = 'MYSQLI_CLIENT_COMPRESS'; + } + if (defined('MYSQLI_CLIENT_FOUND_ROWS')) { + $flagsList[MYSQLI_CLIENT_FOUND_ROWS] = 'MYSQLI_CLIENT_FOUND_ROWS'; + } + if (defined('MYSQLI_CLIENT_IGNORE_SPACE')) { + $flagsList[MYSQLI_CLIENT_IGNORE_SPACE] = 'MYSQLI_CLIENT_IGNORE_SPACE'; + } + if (defined('MYSQLI_CLIENT_INTERACTIVE')) { + $flagsList[MYSQLI_CLIENT_INTERACTIVE] = 'MYSQLI_CLIENT_INTERACTIVE'; + } + if (defined('MYSQLI_CLIENT_SSL')) { + $flagsList[MYSQLI_CLIENT_SSL] = 'MYSQLI_CLIENT_SSL'; + } + if (defined('MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT')) { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.mysqli_client_ssl_dont_verify_server_certFound + $flagsList[MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT] = 'MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT'; + } + } + + if (is_null($filter)) { + $result = $flagsList; + } else { + $result = array(); + foreach ($flagsList as $flagVal => $flag) { + if (!in_array($flagVal, $filter)) { + continue; + } + $result[$flagVal] = $flag; + } + } + + if ($returnStr) { + return array_values($result); + } else { + return array_keys($result); + } + } + + /** + * Return the list of mysqlrealconnect flags values from mask + * + * @see https://www.php.net/manual/en/mysqli.real-connect.php + * + * @param int $value mask value + * + * @return int[] + */ + public static function getMysqlConnectFlagsFromMaskVal($value) + { + /* + MYSQLI_CLIENT_COMPRESS 32 + MYSQLI_CLIENT_FOUND_ROWS 2 + MYSQLI_CLIENT_IGNORE_SPACE 256 + MYSQLI_CLIENT_INTERACTIVE 1024 + MYSQLI_CLIENT_SSL 2048 + MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT 64 + */ + + $result = array(); + + foreach (self::getMysqlConnectFlagsList(false) as $flagVal) { + if (($value & $flagVal) > 0) { + $result[] = $flagVal; + } + } + + return $result; + } + + /** + * Returns a list of redundant case insensitive duplicate tables + * + * @param string $prefix The WP table prefix + * @param string[] $duplicates List of case insensitive duplicate table names + * + * @return string[] + */ + public static function getRedundantDuplicateTables($prefix, $duplicates) + { + //core tables are not redundant, check with priority + foreach (SnapWP::getSiteCoreTables() as $coreTable) { + if (($k = array_search($prefix . $coreTable, $duplicates)) !== false) { + unset($duplicates[$k]); + return array_values($duplicates); + } + } + + foreach ($duplicates as $i => $tableName) { + if (stripos($tableName, $prefix) === 0) { + //table has prefix, the case sensitive match is not redundant + if (strpos($tableName, $prefix) === 0) { + unset($duplicates[$i]); + break; + } + + //no case sensitive match is present, first table is not redundant + if ($i === (count($duplicates) - 1)) { + unset($duplicates[0]); + break; + } + } else { + //no prefix present, first table not redundant + unset($duplicates[$i]); + break; + } + } + + return array_values($duplicates); + } +} diff --git a/src/Libs/Snap/SnapIO.php b/src/Libs/Snap/SnapIO.php new file mode 100644 index 00000000..f8e15101 --- /dev/null +++ b/src/Libs/Snap/SnapIO.php @@ -0,0 +1,1748 @@ + $args array key/val where key is the var name in include + * @param bool $required if true is required + * + * @return string + * + * @throws Exception // thorw exception if is $required and file can't be read + */ + public static function getInclude($path, $args = array(), $required = true) + { + if (!is_readable($path)) { + if ($required) { + throw new Exception('Can\'t read required file ' . $path); + } else { + return ''; + } + } + + foreach ($args as $var => $value) { + ${$var} = $value; + } + + ob_start(); + if ($required) { + require($path); + } else { + include($path); + } + return ob_get_clean(); + } + + /** + * Copy file + * + * @param string $source source path + * @param string $dest detination path + * @param boolean $overwriteIfExists if true and file exists the file is overwritten + * + * @return boolean Returns true on success or false on failure. + */ + public static function copy($source, $dest, $overwriteIfExists = true) + { + if (file_exists($dest)) { + if ($overwriteIfExists) { + self::rm($dest); + } else { + return false; + } + } + return copy($source, $dest); + } + + /** + * Copy part of file, if offset is 0 anf to file exists is truncated + * + * @param string|resource $from file name or resource + * @param string|resource $to file name or resource + * @param int<0, max> $offset copy offset + * @param int<-1, max> $length copy if -1 copy ot the end of file + * + * @return bool true on success or false on fail. + */ + public static function copyFilePart($from, $to, $offset = 0, $length = -1) + { + $closeFrom = false; + $closeTo = false; + $fromStream = null; + $toStream = null; + if (is_resource($from)) { + $fromStream = $from; + } else { + if (!is_file((string) $from)) { + return false; + } + if (($fromStream = self::fopen($from, 'r')) === false) { + return false; + } + $closeFrom = true; + } + if (is_resource($to)) { + $toStream = $to; + } else { + $mode = ($offset == 0 ? 'w+' : 'c+'); + if (($toStream = SnapIO::fopen($to, $mode)) === false) { + return false; + } + $closeTo = true; + } + if ($offset === 0) { + if (ftruncate($toStream, 0) === false) { + return false; + } + } + if (fseek($toStream, $offset) === -1) { + return false; + } + if ($closeFrom && is_resource($fromStream)) { + fclose($fromStream); + } + if ($closeTo && is_resource($toStream)) { + fclose($toStream); + } + return (stream_copy_to_stream($fromStream, $toStream, ($length < 0 ? null : $length), $offset) !== false); + } + + /** + * Copy recursive folder content + * + * @param string $source source path + * @param string $dest detination path + * + * @return boolean Returns true on success or false on failure. + */ + public static function rcopy($source, $dest) + { + if (!is_readable($source)) { + return false; + } + + if (is_dir($source)) { + if (!file_exists($dest)) { + if (!self::mkdir($dest)) { + return false; + } + } + + if (($handle = opendir($source)) == false) { + return false; + } + + while ($file = readdir($handle)) { + if ($file == "." || $file == "..") { + continue; + } + + if (!self::rcopy($source . '/' . $file, $dest . '/' . $file)) { + closedir($handle); + return false; + } + } + closedir($handle); + return true; + } else { + return copy($source, $dest); + } + } + + /** + * Untrailingslashit path + * + * @param string $path file path + * + * @return string + */ + public static function untrailingslashit($path) + { + return rtrim($path, '/\\'); + } + + /** + * Trailingslashit path + * + * @param string $path file path + * + * @return string + */ + public static function trailingslashit($path) + { + return self::untrailingslashit($path) . '/'; + } + + /** + * Normalize path + * + * @param string $path file path + * @param boolean $real if true apply realpath function + * + * @return string + */ + public static function safePath($path, $real = false) + { + if ($real) { + if (($res = realpath($path)) === false) { + $res = $path; + } + } else { + $res = $path; + } + return self::normalizePath($res); + } + + /** + * Untrailingslashit and normalize path + * + * @param string $path file path + * @param boolean $real if true apply realpath function + * + * @return string + */ + public static function safePathUntrailingslashit($path, $real = false) + { + if ($real) { + if (($res = realpath($path)) === false) { + $res = $path; + } + } else { + $res = $path; + } + return rtrim(self::normalizePath($res), '/'); + } + + /** + * Trailingslashit and normalize path + * + * @param string $path file path + * @param boolean $real if true apply realpath function + * + * @return string + */ + public static function safePathTrailingslashit($path, $real = false) + { + return self::safePathUntrailingslashit($path, $real) . '/'; + } + + /** + * Remove file path + * + * @param string $file path + * + * @return bool Returns TRUE on success or FALSE on failure. + */ + public static function unlink($file) + { + try { + if (!file_exists($file)) { + return true; + } + if (!function_exists('unlink') || is_dir($file)) { + return false; + } + self::chmod($file, 'u+rw'); + return @unlink($file); + } catch (Exception $e) { + return false; + } catch (Error $e) { + return false; + } + } + + /** + * Rename file from old name to new name + * + * @param string $oldname path + * @param string $newname path + * @param bool $removeIfExists if true remove exists file + * + * @return bool Returns TRUE on success or FALSE on failure. + */ + public static function rename($oldname, $newname, $removeIfExists = false) + { + try { + if (!file_exists($oldname) || !function_exists('rename')) { + return false; + } + + if ($removeIfExists && file_exists($newname)) { + if (!self::rrmdir($newname)) { + return false; + } + } + return @rename($oldname, $newname); + } catch (Exception $e) { + return false; + } catch (Error $e) { + return false; + } + } + + /** + * Open file + * + * @param string $filepath File path + * @param string $mode The mode parameter specifies the type of access you require to the stream. + * @param boolean $throwOnError thorw exception on error + * + * @return boolean|resource Returns a file pointer resource on success, or false on failure + */ + public static function fopen($filepath, $mode, $throwOnError = true) + { + if (strlen($filepath) > PHP_MAXPATHLEN) { + throw new Exception('Skipping a file that exceeds allowed max path length [' . PHP_MAXPATHLEN . ']. File: ' . $filepath); + } + + if (SnapString::startsWith($mode, 'w') || SnapString::startsWith($mode, 'c') || file_exists($filepath)) { + $file_handle = @fopen($filepath, $mode); + } else { + if ($throwOnError) { + throw new Exception("$filepath doesn't exist"); + } else { + return false; + } + } + + if (!is_resource($file_handle)) { + if ($throwOnError) { + throw new Exception("Error opening $filepath"); + } else { + return false; + } + } else { + return $file_handle; + } + } + + /** + * Touch file + * + * @param string $filepath File path + * @param int $time The touch time. If time is not supplied, the current system time is used. + * + * @return bool Returns true on success or false on failure. + */ + public static function touch($filepath, $time = null) + { + if (!function_exists('touch')) { + return false; + } + + if ($time === null) { + $time = time(); + } + return @touch($filepath, $time); + } + + /** + * Remove folder + * + * @param string $dirname dir path + * @param boolean $mustExist if true and folder don't esist thorw error + * + * @return void + */ + public static function rmdir($dirname, $mustExist = false) + { + if (file_exists($dirname)) { + self::chmod($dirname, 'u+rwx'); + if (self::rrmdir($dirname) === false) { + throw new Exception("Couldn't remove {$dirname}"); + } + } elseif ($mustExist) { + throw new Exception("{$dirname} doesn't exist"); + } + } + + /** + * Remove file + * + * @param string $filepath file path + * @param boolean $mustExist if true and folder don't esist thorw error + * + * @return void + */ + public static function rm($filepath, $mustExist = false) + { + if (file_exists($filepath)) { + self::chmod($filepath, 'u+rw'); + if (@unlink($filepath) === false) { + throw new Exception("Couldn't remove {$filepath}"); + } + } elseif ($mustExist) { + throw new Exception("{$filepath} doesn't exist"); + } + } + + /** + * string string in file + * + * @param resource $handle file handle + * @param string $string fwrite string + * + * @return int bytes written + */ + public static function fwrite($handle, $string) + { + $bytes_written = @fwrite($handle, $string); + + if ($bytes_written != strlen($string)) { + throw new Exception('Error writing all bytes to file.'); + } else { + return $bytes_written; + } + } + + /** + * Wrinte file in chunk mode. For big data. + * + * @param resource $handle file handle + * @param string $content fwrite string + * + * @return int bytes written + * + * @throws Exception + */ + public static function fwriteChunked($handle, $content) + { + if (strlen($content) == 0) { + return 0; + } + + $pieces = str_split($content, self::FWRITE_CHUNK_SIZE); + $written = 0; + + foreach ($pieces as $piece) { + if (($fwResult = @fwrite($handle, $piece, self::FWRITE_CHUNK_SIZE)) === false) { + throw new Exception('Error writing to file.'); + } + $written += $fwResult; + } + + if ($written != strlen($content)) { + throw new Exception('Error writing all bytes to file.'); + } + + return $written; + } + + /** + * Append file $from to file $to, if $to file don't exits create it. + * In case of error throw exceptions. + * + * @param string $from file path + * @param string $to file path + * + * @return int writte bytes + */ + public static function appendFileToFile($from, $to) + { + try { + $written = 0; + $fromHd = false; + $toHd = false; + + if (!file_exists($from) || !is_readable($from)) { + throw new Exception('File: ' . $from . ' don\'t exists os isn\'t readable'); + } + + if (file_exists($to) && !is_writable($to)) { + throw new Exception('File: ' . $to . ' isn\'t writeable'); + } + + if (($fromHd = @fopen($from, "rb")) === false) { + throw new Exception('Could not open file: ' . $from); + } + + if (($toHd = @fopen($to, "ab")) === false) { + throw new Exception('Could not open file: ' . $to); + } + + if (($fromStat = fstat($fromHd)) == false) { + throw new Exception('Can\t stat file: ' . $from); + } + + while ($buffer = fread($fromHd, self::FWRITE_CHUNK_SIZE)) { + if (($fwResult = @fwrite($toHd, $buffer)) === false) { + throw new Exception('Error writing to file ' . $to); + } + $written += $fwResult; + } + + if ($written != $fromStat['size']) { + throw new Exception('Error on file append, written bytes ' . $written . ' expected ' . $fromStat['size']); + } + } catch (Exception $e) { + if ($fromHd !== false) { + fclose($fromHd); + } + if ($toHd !== false) { + fclose($toHd); + } + throw $e; + } + + fclose($fromHd); + fclose($toHd); + + return $written; + } + + /** + * File get + * + * @param resource $handle file handle + * @param int $length max num bytes + * + * @return string + */ + public static function fgets($handle, $length) + { + $line = fgets($handle, $length); + + if ($line === false) { + throw new Exception('Error reading line.'); + } + + return $line; + } + + /** + * File close + * + * @param resource $handle file handle + * @param boolean $exception_on_fail if true thorw exception on fail + * + * @return void + */ + public static function fclose($handle, $exception_on_fail = true) + { + if ((@fclose($handle) === false) && $exception_on_fail) { + throw new Exception("Error closing file"); + } + } + + /** + * Exec a flock, thow exception on failure + * + * @param resource $handle file handle + * @param int $operation flock openration + * + * @return void + */ + public static function flock($handle, $operation) + { + if (@flock($handle, $operation) === false) { + throw new Exception("Error locking file"); + } + } + + /** + * Returns the current position of the file read/write pointer + * throw exception on failure + * + * @param resource $file_handle file handle + * + * @return int + */ + public static function ftell($file_handle) + { + $position = @ftell($file_handle); + + if ($position === false) { + throw new Exception("Couldn't retrieve file offset."); + } else { + return $position; + } + } + + /** + * Safely remove a directory and recursively files and directory upto multiple sublevels + * + * @param string $path The full path to the directory to remove + * + * @return bool Returns true if all content was removed + */ + public static function rrmdir($path) + { + if (is_dir($path)) { + if (($dh = opendir($path)) === false) { + return false; + } + while (($object = readdir($dh)) !== false) { + if ($object == "." || $object == "..") { + continue; + } + if (!self::rrmdir($path . "/" . $object)) { + closedir($dh); + return false; + } + } + closedir($dh); + return @rmdir($path); + } else { + if (is_writable($path)) { + return @unlink($path); + } else { + return false; + } + } + } + + /** + * Return files size, throw eception on failure + * + * @param string $filename file path + * + * @return int + */ + public static function filesize($filename) + { + $file_size = @filesize($filename); + + if ($file_size === false) { + throw new Exception("Error retrieving file size of $filename"); + } + + return $file_size; + } + + /** + * Fseek on file, throw exception on failure + * + * @param resource $handle file handle + * @param int $offset The offset. + * @param int $whence whence values are: SEEK_SET + * - Set position equal to offset bytes. SEEK_CUR + * - Set position to current location plus offset. SEEK_END + * - Set position to end-of-file plus offset. + * + * @return void + */ + public static function fseek($handle, $offset, $whence = SEEK_SET) + { + $ret_val = @fseek($handle, $offset, $whence); + + if ($ret_val !== 0) { + $filepath = stream_get_meta_data($handle); + $filepath = $filepath["uri"]; + $filesize = self::filesize($filepath); + + if ( + abs($offset) > self::FILE_SIZE_LIMIT_32BIT || + $filesize > self::FILE_SIZE_LIMIT_32BIT || + ($offset <= 0 && ($whence == SEEK_SET || $whence == SEEK_END)) + ) { + //This check is not strict, but in most cases 32 Bit PHP will be the issue + throw new Snap32BitSizeLimitException("Trying to seek on a file beyond the capability of 32 bit PHP. offset=$offset filesize=$filesize"); + } else { + throw new Exception("Error seeking to file offset $offset. Retval = $ret_val"); + } + } + } + + /** + * Gets file modification time + * + * @param string $filename file path + * + * @return int|false the time the file was last modified, or false on failure. + * The time is returned as a Unix timestamp, which is suitable for the date function + */ + public static function filemtime($filename) + { + $mtime = filemtime($filename); + + if ($mtime === false) { + throw new Exception("Cannot retrieve last modified time of $filename"); + } + + return $mtime; + } + + /** + * File put content, thorw exception on failure + * + * @param string $filename file path + * @param mixed $data The data to write. Can be either a string, an array or a stream resource. + + * @return bool + */ + public static function filePutContents($filename, $data) + { + if (($dirFile = realpath(dirname($filename))) === false) { + throw new Exception('FILE ERROR: put_content for file ' . $filename . ' failed [realpath fail]'); + } + if (!is_dir($dirFile)) { + throw new Exception('FILE ERROR: put_content for file ' . $filename . ' failed [dir ' . $dirFile . ' doesn\'t exist]'); + } + if (!is_writable($dirFile)) { + throw new Exception('FILE ERROR: put_content for file ' . $filename . ' failed [dir ' . $dirFile . ' exists but isn\'t writable]'); + } + $realFileName = $dirFile . basename($filename); + if (file_exists($realFileName) && !is_writable($realFileName)) { + throw new Exception('FILE ERROR: put_content for file ' . $filename . ' failed [file exist ' . $realFileName . ' but isn\'t writable'); + } + if (file_put_contents($filename, $data) === false) { + throw new Exception('FILE ERROR: put_content for file ' . $filename . ' failed [Couldn\'t write data to ' . $realFileName . ']'); + } + return true; + } + + /** + * this function make a chmod only if the are different from perms input and if chmod function is enabled + * + * this function handles the variable MODE in a way similar to the chmod of lunux + * So the MODE variable can be + * 1) an octal number (0755) + * 2) a string that defines an octal number ("644") + * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+ + * + * examples + * u+rw add read and write at the user + * u+rw,uo-wx add read and write ad the user and remove wx at groupd and other + * a=rw is equal at 666 + * u=rwx,go-rwx is equal at 700 + * + * @param string $file file path + * @param int|string $mode permission mode + * + * @return boolean + */ + public static function chmod($file, $mode) + { + if (!file_exists($file)) { + return false; + } + + $octalMode = 0; + + if (is_int($mode)) { + $octalMode = $mode; + } elseif (is_numeric($mode)) { + $octalMode = intval((($mode[0] === '0' ? '' : '0') . $mode), 8); + } elseif (is_string($mode) && preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) { + if (!function_exists('fileperms')) { + return false; + } + + // start by file permission + $octalMode = (fileperms($file) & 0777); + + foreach ($gMatch as $matches) { + // [ugo] or a = ugo + $group = $matches[1]; + if ($group === 'a') { + $group = 'ugo'; + } + // can be + - = + $action = $matches[2]; + // [rwx] + $gPerms = $matches[3]; + + // reset octal group perms + $octalGroupMode = 0; + + // Init sub perms + $subPerm = 0; + $subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001 + $subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010 + $subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100 + + $ugoLen = strlen($group); + + if ($action === '=') { + // generate octal group permsissions and ugo mask invert + $ugoMaskInvert = 0777; + for ($i = 0; $i < $ugoLen; $i++) { + switch ($group[$i]) { + case 'u': + $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000 + $ugoMaskInvert = $ugoMaskInvert & 077; + break; + case 'g': + $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000 + $ugoMaskInvert = $ugoMaskInvert & 0707; + break; + case 'o': + $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx + $ugoMaskInvert = $ugoMaskInvert & 0770; + break; + } + } + // apply = action + $octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode); + } else { + // generate octal group permsissions + for ($i = 0; $i < $ugoLen; $i++) { + switch ($group[$i]) { + case 'u': + $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000 + break; + case 'g': + $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000 + break; + case 'o': + $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx + break; + } + } + // apply + or - action + switch ($action) { + case '+': + $octalMode = $octalMode | $octalGroupMode; + break; + case '-': + $octalMode = $octalMode & ~$octalGroupMode; + break; + } + } + } + } else { + return true; + } + + // if input permissions are equal at file permissions return true without performing chmod + if (function_exists('fileperms') && $octalMode === (fileperms($file) & 0777)) { + return true; + } + + if (!function_exists('chmod')) { + return false; + } + + return @chmod($file, $octalMode); + } + + /** + * Return file perms in string + * + * @param int|string $perms permssions + * + * @return string|false false if fail + */ + public static function permsToString($perms) + { + if (is_int($perms)) { + return decoct($perms); + } elseif (is_numeric($perms)) { + return ($perms[0] === '0' ? '' : '0') . $perms; + } elseif (is_string($perms)) { + return $perms; + } else { + return false; + } + } + + /** + * this function creates a folder if it does not exist and performs a chmod. + * it is different from the normal mkdir function to which an umask is applied to the input permissions. + * + * this function handles the variable MODE in a way similar to the chmod of lunux + * So the MODE variable can be + * 1) an octal number (0755) + * 2) a string that defines an octal number ("644") + * 3) a string with the following format [ugoa]*([-+=]([rwx]*)+ + * + * @param string $path folder path + * @param int|string $mode mode permissions + * @param bool $recursive Allows the creation of nested directories specified in the pathname. Default to false. + * @param resource $context not used for windows bug + * + * @return boolean bool TRUE on success or FALSE on failure. + * + * @todo check recursive true and multiple chmod + */ + public static function mkdir($path, $mode = 0777, $recursive = false, $context = null) + { + if (strlen($path) > PHP_MAXPATHLEN) { + throw new Exception('Skipping a file that exceeds allowed max path length [' . PHP_MAXPATHLEN . ']. File: ' . $path); + } + + if (!file_exists($path)) { + if (!function_exists('mkdir')) { + return false; + } + if (!@mkdir($path, 0777, $recursive)) { + return false; + } + } + + return self::chmod($path, $mode); + } + + /** + * this function call snap mkdir if te folder don't exists od don't have write or exec permissions + * + * this function handles the variable MODE in a way similar to the chmod of lunux + * The mode variable can be set to have more flexibility but not giving the user write and read and exec permissions doesn't make much sense + * + * @param string $path folder path + * @param int|string $mode mode permissions + * @param bool $recursive Allows the creation of nested directories specified in the pathname. Default to false. + * @param resource $context not used for windows bug + * + * @return boolean bool TRUE on success or FALSE on failure. + */ + public static function dirWriteCheckOrMkdir($path, $mode = 'u+rwx', $recursive = false, $context = null) + { + if (!file_exists($path)) { + return self::mkdir($path, $mode, $recursive, $context); + } elseif (!is_writable($path) || (function_exists('is_executable') && !is_executable($path))) { + return self::chmod($path, $mode); + } else { + return true; + } + } + + /** + * from wordpress function wp_is_stream + * + * @param string $path The resource path or URL. + * + * @return bool True if the path is a stream URL. + */ + public static function isStream($path) + { + $scheme_separator = strpos($path, '://'); + + if (false === $scheme_separator) { + // $path isn't a stream + return false; + } + + $stream = substr($path, 0, $scheme_separator); + + return in_array($stream, stream_get_wrappers(), true); + } + + /** + * From Wordpress function: wp_mkdir_p + * + * Recursive directory creation based on full path. + * + * Will attempt to set permissions on folders. + * + * @param string $target Full path to attempt to create. + * + * @return bool Whether the path was created. True if path already exists. + */ + public static function mkdirP($target) + { + $wrapper = null; + + // Strip the protocol. + if (self::isStream($target)) { + list( $wrapper, $target ) = explode('://', $target, 2); + } + + // From php.net/mkdir user contributed notes. + $target = str_replace('//', '/', $target); + + // Put the wrapper back on the target. + if ($wrapper !== null) { + $target = $wrapper . '://' . $target; + } + + /* + * Safe mode fails with a trailing slash under certain PHP versions. + * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency. + */ + $target = rtrim($target, '/'); + if (empty($target)) { + $target = '/'; + } + + if (file_exists($target)) { + return @is_dir($target); + } + + // We need to find the permissions of the parent folder that exists and inherit that. + $target_parent = dirname($target); + while ('.' != $target_parent && !is_dir($target_parent) && dirname($target_parent) !== $target_parent) { + $target_parent = dirname($target_parent); + } + + // Get the permission bits. + if ($stat = @stat($target_parent)) { + $dir_perms = $stat['mode'] & 0007777; + } else { + $dir_perms = 0777; + } + + if (@mkdir($target, $dir_perms, true)) { + /* + * If a umask is set that modifies $dir_perms, we'll have to re-set + * the $dir_perms correctly with chmod() + */ + if ($dir_perms != ( $dir_perms & ~umask() )) { + $folder_parts = explode('/', substr($target, strlen($target_parent) + 1)); + for ($i = 1, $c = count($folder_parts); $i <= $c; $i++) { + @chmod($target_parent . '/' . implode('/', array_slice($folder_parts, 0, $i)), $dir_perms); + } + } + + return true; + } + + return false; + } + + /** + * This function returns the relative path to mainPath + * + * @param string $path file path + * @param string $mainPath main path + * @param bool $real if true check real path + * + * @return bool|string false if path isn't a sub path of main path or return the relative path + */ + public static function getRelativePath($path, $mainPath, $real = false) + { + if (strlen($mainPath) == 0) { + return ltrim(self::safePathUntrailingslashit($path, $real), '/'); + } + + $safePath = self::safePathUntrailingslashit($path, $real); + $safeMainPath = self::safePathUntrailingslashit($mainPath, $real); + + if ($safePath === $safeMainPath) { + return ''; + } elseif (strpos($safePath, self::trailingslashit($safeMainPath)) === 0) { + return ltrim(substr($safePath, strlen($safeMainPath)), '/'); + } else { + return false; + } + } + + /** + * Check if path is child of mainPath + * + * @param string $path file path + * @param string $mainPath main path + * @param boolean $reverseCheck if true check if path is child of mainpath and if mainPash is child of path + * @param boolean $trueIfEquals if paths are equals and is true return true else false + * + * @return boolean + */ + public static function isChildPath($path, $mainPath, $reverseCheck = false, $trueIfEquals = true) + { + if (strlen($mainPath) == 0) { + return true; + } + + if ($reverseCheck && strlen($path) == 0) { + return true; + } + + $safePath = self::safePathUntrailingslashit($path); + $safeMainPath = self::safePathUntrailingslashit($mainPath); + + if ($safePath === $safeMainPath) { + return $trueIfEquals; + } elseif (strpos($safePath, self::trailingslashit($safeMainPath)) === 0) { + return true; + } elseif ($reverseCheck && strpos($safeMainPath, self::trailingslashit($safePath)) === 0) { + return true; + } else { + return false; + } + } + + /** + * Return sorted array by subfolders count + * + * @param string[] $paths paths lists + * @param boolean $childsFirst if true put childs before parents + * @param boolean $maintainIndex if true maintain array indexes + * @param boolean $sortKeys if true sort by keys + * + * @return string[] + */ + public static function sortBySubfoldersCount($paths, $childsFirst = false, $maintainIndex = false, $sortKeys = false) + { + if ($sortKeys) { + $function = 'uksort'; + } elseif ($maintainIndex) { + $function = 'uasort'; + } else { + $function = 'usort'; + } + + $function($paths, function ($a, $b) use ($childsFirst) { + $lenA = count(preg_split('/[\\\\\/]+/', $a)); + $lenB = count(preg_split('/[\\\\\/]+/', $b)); + if ($lenA === $lenB) { + return strcmp($a, $b) * ($childsFirst ? -1 : 1); + } elseif ($lenA > $lenB) { + return ($childsFirst ? -1 : 1); + } else { + return ($childsFirst ? 1 : -1); + } + }); + return $paths; + } + + /** + * from wp_normalize_path + * + * @param string $path Path to normalize. + * + * @return string Normalized path. + */ + public static function normalizePath($path) + { + $wrapper = ''; + if (self::isStream($path)) { + list( $wrapper, $path ) = explode('://', $path, 2); + $wrapper .= '://'; + } + + // Standardise all paths to use / + $path = str_replace('\\', '/', $path); + + // Replace multiple slashes down to a singular, allowing for network shares having two slashes. + $path = preg_replace('|(?<=.)/+|', '/', $path); + if (strpos($path, '//') === 0) { + $path = substr($path, 1); + } + + // Windows paths should uppercase the drive letter + if (':' === substr($path, 1, 1)) { + $path = ucfirst($path); + } + + return $wrapper . $path; + } + + /** + * Get common parent path from given paths + * + * @param string[] $paths list of paths + * + * @return string common parent path + */ + public static function getCommonPath($paths = array()) + { + if (empty($paths)) { + return ''; + } if (!is_array($paths)) { + $paths = array($paths); + } else { + $paths = array_values($paths); + } + + $pathAssoc = array(); + $numPaths = count($paths); + $minPathCouts = PHP_INT_MAX; + + for ($i = 0; $i < $numPaths; $i++) { + $pathAssoc[$i] = explode('/', self::safePathUntrailingslashit($paths[$i])); + $pathCount = count($pathAssoc[$i]); + if ($minPathCouts > $pathCount) { + $minPathCouts = $pathCount; + } + } + + for ($partIndex = 0; $partIndex < $minPathCouts; $partIndex++) { + $currentPart = $pathAssoc[0][$partIndex]; + for ($currentPath = 1; $currentPath < $numPaths; $currentPath++) { + if ($pathAssoc[$currentPath][$partIndex] != $currentPart) { + break 2; + } + } + } + + $resultParts = array_slice($pathAssoc[0], 0, $partIndex); + + return implode('/', $resultParts); + } + + /** + * remove root path transforming the current path into a relative path + * + * ex. /aaa/bbb become aaa/bbb + * ex. C:\aaa\bbb become aaa\bbb + * + * @param string $path file path + * + * @return string + */ + public static function removeRootPath($path) + { + return preg_replace('/^(?:[A-Za-z]:)?[\/](.*)/', '$1', $path); + } + + /** + * Returns the last N lines of a file. Simular to tail command + * + * @param string $filepath The full path to the file to be tailed + * @param int $lines The number of lines to return with each tail call + * + * @return false|string The last N parts of the file, flse on failure + */ + public static function tailFile($filepath, $lines = 2) + { + // Open file + $f = @fopen($filepath, "rb"); + if ($f === false) { + return false; + } + + // Sets buffer size + $buffer = 256; + + // Jump to last character + fseek($f, -1, SEEK_END); + + // Read it and adjust line number if necessary + // (Otherwise the result would be wrong if file doesn't end with a blank line) + if (fread($f, 1) != "\n") { + $lines -= 1; + } + + // Start reading + $output = ''; + $chunk = ''; + + // While we would like more + while (ftell($f) > 0 && $lines >= 0) { + // Figure out how far back we should jump + $seek = min(ftell($f), $buffer); + // Do the jump (backwards, relative to where we are) + fseek($f, -$seek, SEEK_CUR); + // Read a chunk and prepend it to our output + $output = ($chunk = fread($f, $seek)) . $output; + // Jump back to where we started reading + fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR); + // Decrease our line counter + $lines -= substr_count($chunk, "\n"); + } + + // While we have too many lines + // (Because of buffer size we might have read too many) + while ($lines++ < 0) { + // Find first newline and remove all text before that + $output = substr($output, strpos($output, "\n") + 1); + } + fclose($f); + return trim($output); + } + + /** + * @param string $filepath path to file to be downloaded + * @param string $downloadName name to be downloaded as + * @param int $bufferSize file chunks to be served + * @param bool $limitRate if set to true the download rate will be limited to $bufferSize/seconds + * + * @return void + */ + public static function serveFileForDownload($filepath, $downloadName, $bufferSize = 0, $limitRate = false) + { + // Process download + if (!file_exists($filepath)) { + throw new Exception("File does not exist!"); + } + + if (!is_file($filepath)) { + throw new Exception("'$filepath' is not a file!"); + } + + // Clean output buffers + SnapUtil::obCleanAll(false); + + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="' . $downloadName . '"'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . filesize($filepath)); + flush(); // Flush system output buffer + + if ($bufferSize <= 0) { + readfile($filepath); + exit; + } + + $fp = @fopen($filepath, 'r'); + if (!is_resource($fp)) { + throw new Exception('Fail to open the file ' . $filepath); + } + + while (!feof($fp) && ($data = fread($fp, $bufferSize)) !== false) { + echo $data; + + if ($limitRate) { + sleep(1); + } + } + @fclose($fp); + exit; + } + + /** + * Return lasts fine of file + * + * @param string $path Path to the file + * @param int $n Number of lines to get + * @param int $charLimit Number of chars to include in each line + * + * @return bool|string[] Last $n lines of file + */ + public static function getLastLinesOfFile($path, $n, $charLimit = null) + { + if (!is_readable($path)) { + return false; + } + + if (($handle = self::fopen($path, 'r', false)) === false) { + return false; + } + + $result = array(); + $pos = -1; + $currentLine = ''; + $counter = 0; + + while ($counter < $n && -1 !== fseek($handle, $pos, SEEK_END)) { + $char = fgetc($handle); + if (PHP_EOL == $char) { + $trimmedValue = trim($currentLine); + if (is_null($charLimit)) { + $currentLine = substr($currentLine, 0); + } else { + $currentLine = substr($currentLine, 0, (int) $charLimit); + if (strlen($currentLine) == $charLimit) { + $currentLine .= '...'; + } + } + + if (!empty($trimmedValue)) { + $result[] = $currentLine; + $counter++; + } + $currentLine = ''; + } else { + $currentLine = $char . $currentLine; + } + $pos--; + } + self::fclose($handle, false); + + return array_reverse($result); + } + + /** + * Thif function scan a folder filter by regex + * + * Options + * regexFile: [bool|string|array] if is bool alrays or never match, if is string o array of string check if rexeses match file name + * regexFolder: [bool|string|array] if is bool alrays or never match, if is string o array of string check if rexeses match file name + * checkFullPath: bool if false only current file/folder name is passed at regex if true is passed the full path + * recursive: bool if false check only passed folder or all sub folder recursively + * invert: bool if false pass invert the result + * childFirst: bool if false is parsed parent folters first or child folders first + * + * @param string $dir dir to scan + * @param array $options array{ + * regexFile?: bool|string, + * regexFolder?: bool|string, + * checkFullPath?: bool, + * recursive?: bool, + * invert?: bool, + * childFirst?: bool + * } + * + * @return string[] paths lists + */ + public static function regexGlob($dir, $options) + { + $result = array(); + + self::regexGlobCallback($dir, function ($path) use (&$result) { + $result[] = $path; + }, $options); + + return $result; + } + + /** + * Execute the callback function foreach right element, private function for optimization + * + * Options + * regexFile: [bool|string|array] if is bool alrays or never match, if is string o array of string check if rexeses match file name + * regexFolder: [bool|string|array] if is bool alrays or never match, if is string o array of string check if rexeses match file name + * checkFullPath: bool if false only current file/folder name is passed at regex if true is passed the full path + * recursive: bool if false check only passed folder or all sub folder recursively + * invert: bool if false pass invert the result + * childFirst: bool if false is parsed parent folters first or child folders first + * symlinks: string[] list a symblink parsed + * + * @param string $dir dir to scan + * @param callable $callback callback function + * @param array $options array{ + * regexFile?: bool|string, + * regexFolder?: bool|string, + * checkFullPath?: bool, + * recursive?: bool, + * invert?: bool, + * childFirst?: bool, + * symlinks?: string[] + * } + * + * @return boolean Returns true on success or false on failure. + */ + protected static function regexGlobCallbackPrivate($dir, $callback, &$options) + { + if (($dh = opendir($dir)) == false) { + return false; + } + + while (($elem = readdir($dh)) !== false) { + if ($elem === '.' || $elem === '..') { + continue; + } + + $fullPath = $dir . $elem; + $isDir = is_dir($fullPath); + if (($regex = $isDir ? $options['regexFolder'] : $options['regexFile']) === false) { + continue; + } + + if ($isDir && is_link($fullPath)) { + $realPath = self::safePathUntrailingslashit($fullPath, true); + if (in_array($realPath, $options['symlinks'])) { + continue; + } + $options['symlinks'][] = $realPath; + } + + if (is_bool($regex)) { + $match = $regex; + } else { + $match = false; + $pathCheck = $options['checkFullPath'] ? $fullPath : $elem; + + foreach ($regex as $currentRegex) { + if (preg_match($currentRegex, $pathCheck) === 1) { + $match = true; + break; + } + } + + if ($options['invert']) { + $match = !$match; + } + } + + if ($match) { + if ($isDir && $options['execChildFirst']) { + self::regexGlobCallbackPrivate($fullPath . '/', $callback, $options); + } + + call_user_func($callback, $fullPath); + + if ($isDir && $options['execChildAfter']) { + self::regexGlobCallbackPrivate($fullPath . '/', $callback, $options); + } + } + } + closedir($dh); + + return true; + } + + /** + * Execute the callback function foreach right element (folder or files) + * + * Options + * regexFile: [bool|string|array] if is bool alrays or never match, if is string o array of string check if rexeses match file name + * regexFolder: [bool|string|array] if is bool alrays or never match, if is string o array of string check if rexeses match file name + * checkFullPath: bool if false only current file/folder name is passed at regex if true is passed the full path + * recursive: bool if false check only passed folder or all sub folder recursively + * invert: bool if false pass invert the result + * childFirst: bool if false is parsed parent folters first or child folders first + * + * @param string $dir dir to scan + * @param callable $callback callback function + * @param array $options array{ + * regexFile?: bool|string, + * regexFolder?: bool|string, + * checkFullPath?: bool, + * recursive?: bool, + * invert?: bool, + * childFirst?: bool + * } + * + * @return boolean Returns true on success or false on failure. + */ + public static function regexGlobCallback($dir, $callback, $options = array()) + { + $dir = self::safePathTrailingslashit($dir); + + if (!is_dir($dir) || !is_readable($dir)) { + return false; + } + + if (!is_callable($callback)) { + return false; + } + + $options = array_merge(array( + 'regexFile' => true, + 'regexFolder' => true, + 'checkFullPath' => false, + 'recursive' => false, + 'invert' => false, + 'childFirst' => false, + 'symlinks' => array() + ), (array) $options); + + if (is_bool($options['regexFile'])) { + $options['regexFile'] = ($options['regexFile'] xor $options['invert']); + } elseif (is_scalar($options['regexFile'])) { + $options['regexFile'] = array($options['regexFile']); + } + + if (is_bool($options['regexFolder'])) { + $options['regexFolder'] = ($options['regexFolder'] xor $options['invert']); + } elseif (is_scalar($options['regexFolder'])) { + $options['regexFolder'] = array($options['regexFolder']); + } + + // optimizization + $options['execChildFirst'] = ($options['recursive'] && $options['childFirst'] === true); + $options['execChildAfter'] = ($options['recursive'] && $options['childFirst'] === false); + + return self::regexGlobCallbackPrivate($dir, $callback, $options); + } + + /** + * Empty passed dir + * + * @param string $dir folder to empty + * @param string[] $filter childs name to skip + * + * @return boolean Returns true on success or false on failure. + */ + public static function emptyDir($dir, $filter = array()) + { + $dir = self::safePathTrailingslashit($dir); + if (!is_dir($dir) || !is_readable($dir)) { + return false; + } + + if (($dh = opendir($dir)) == false) { + return false; + } + + $listToDelete = array(); + + while (($elem = readdir($dh)) !== false) { + if ($elem === '.' || $elem === '..') { + continue; + } + + if (in_array($elem, $filter)) { + continue; + } + + $fullPath = $dir . $elem; + if (self::chmod($fullPath, 'ugo+rwx')) { + $listToDelete[] = $fullPath; + } + } + closedir($dh); + + foreach ($listToDelete as $path) { + self::rrmdir($path); + } + return true; + } + + /** + * Returns a path to the base root folder of path taking into account the + * open_basedir setting. + * + * @param string $path file path + * + * @return bool|string Base root path of $path if it's accessible, otherwise false; + */ + public static function getMaxAllowedRootOfPath($path) + { + $path = self::safePathUntrailingslashit($path, true); + + if (!self::isOpenBaseDirEnabled()) { + $parts = explode("/", $path); + return $parts[0] . "/"; + } else { + return self::getOpenBaseDirRootOfPath($path); + } + } + + /** + * Check if php.ini open_basedir is enabled + * + * @return bool true if open_basedir is set + */ + public static function isOpenBaseDirEnabled() + { + $iniVar = ini_get("open_basedir"); + return (strlen($iniVar) > 0); + } + + /** + * Get open_basedir list paths + * + * @return string[] Paths contained in the open_basedir setting. Empty array if the setting is not enabled. + */ + public static function getOpenBaseDirPaths() + { + if (!($openBase = ini_get("open_basedir"))) { + return array(); + } + return explode(PATH_SEPARATOR, $openBase); + } + + /** + * Get open base dir root path of path + * + * @param string $path file path + * + * @return bool|string Path to the base dir of $path if it exists, otherwise false + */ + public static function getOpenBaseDirRootOfPath($path) + { + foreach (self::getOpenBaseDirPaths() as $allowedPath) { + $allowedPath = $allowedPath !== "/" ? self::safePathUntrailingslashit($allowedPath) : "/"; + if (strpos($path, $allowedPath) === 0) { + return $allowedPath; + } + } + + return false; + } + + /** + * this function is similar at dirname but if empty path return empty value not . + * and is SO indipendent so work on not normalized path + * + * @param string $path file path + * + * @return string + */ + public static function getRelativeDirname($path) + { + if (preg_match('/^(.*)[\/]+/', $path, $matches) !== 1) { + return ''; + } + + return $matches[1]; + } + + /** + * Set full user permissions on folder (rwx) + * + * @param string $path dir path + * + * @return boolean // return false if folder don't have read write permission on folder + */ + public static function dirAddFullPermsAndCheckResult($path) + { + if (!SnapIO::chmod($path, 'u+rwx')) { + return false; + } + + if (!is_readable($path) || !is_writable($path)) { + return false; + } + + if (function_exists('is_executable') && !is_executable($path) && !SnapOS::isWindows()) { + return false; + } + + return true; + } + + /** + * set full user permissions on file (rwx) + * + * @param string $path file path + * + * @return boolean // return false if folder don't have read write permission on folder + */ + public static function fileAddFullPermsAndCheckResult($path) + { + if (!SnapIO::chmod($path, 'u+rw')) { + return false; + } + + if (!is_readable($path) || !is_writable($path)) { + return false; + } + + return true; + } + + /** + * Returns the total size of a filesystem or disk partition in bytes + * + * @param string $directory path + * + * @return int rturn number of bytes or -1 on failure + */ + public static function diskTotalSpace($directory) + { + if (!function_exists('disk_total_space')) { + return -1; + } + + if (($space = disk_total_space($directory)) === false) { + return -1; + } + + return (int) round($space); + } + + /** + * Returns available space in directory in bytes + * + * @param string $directory path + * + * @return int rturn number of bytes or -1 on failure + */ + public static function diskFreeSpace($directory) + { + if (!function_exists('disk_free_space')) { + return -1; + } + + if (($space = disk_free_space($directory)) === false) { + return -1; + } + + return (int) round($space); + } +} diff --git a/src/Libs/Snap/SnapJson.php b/src/Libs/Snap/SnapJson.php new file mode 100644 index 00000000..95b21c09 --- /dev/null +++ b/src/Libs/Snap/SnapJson.php @@ -0,0 +1,302 @@ +=')) { + $args = array($data, $options, $depth); + } elseif (version_compare(PHP_VERSION, '5.3', '>=')) { + $args = array($data, $options); + } else { + $args = array($data); + } + + $preparedData = self::jsonPrepareData($data); + // Prepare the data for JSON serialization. + $args[0] = $preparedData; + + $json = @call_user_func_array('json_encode', $args); + + // If json_encode() was successful, no need to do more sanity checking. + // ... unless we're in an old version of PHP, and json_encode() returned + // a string containing 'null'. Then we need to do more sanity checking. + if (false !== $json && ( version_compare(PHP_VERSION, '5.5', '>=') || false === strpos($json, 'null') )) { + return $json; + } + + try { + $args[0] = self::jsonSanityCheck($preparedData, $depth); + } catch (\Exception $e) { + return false; + } + + return call_user_func_array('json_encode', $args); + } + + /** + * wp_json_encode with pretty print if define exists + * + * @param mixed $data Variable (usually an array or object) to encode as JSON. + * @param int $options Optional. Options to be passed to json_encode(). Default 0. + * @param int $depth Optional. Maximum depth to walk through $data. Must be + * greater than 0. Default 512. + * + * @return string|false The JSON encoded string, or false if it cannot be encoded. + */ + public static function jsonEncodePPrint($data, $options = 0, $depth = 512) + { + if (defined('JSON_PRETTY_PRINT')) { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_pretty_printFound + return self::jsonEncode($data, JSON_PRETTY_PRINT | $options, $depth); + } else { + return self::jsonEncode($data, $options, $depth); + } + } + + /** + * Prepares response data to be serialized to JSON. + * + * This supports the JsonSerializable interface for PHP 5.2-5.3 as well. + * + * @param mixed $data Native representation. + * + * @return bool|int|float|null|string|mixed[] Data ready for `json_encode()`. + */ + private static function jsonPrepareData($data) + { + if ( + !defined('WP_JSON_SERIALIZE_COMPATIBLE') || + WP_JSON_SERIALIZE_COMPATIBLE === false + ) { + return $data; + } + + switch (gettype($data)) { + case 'boolean': + case 'integer': + case 'double': + case 'string': + case 'NULL': + // These values can be passed through. + return $data; + + case 'array': + // Arrays must be mapped in case they also return objects. + return array_map(array(__CLASS__, 'jsonPrepareData'), $data); + + case 'object': + // If this is an incomplete object (__PHP_Incomplete_Class), bail. + if (!is_object($data)) { + return null; + } + + if ($data instanceof \JsonSerializable) { + $data = $data->jsonSerialize(); + } else { + $data = get_object_vars($data); + } + + // Now, pass the array (or whatever was returned from jsonSerialize through). + return self::jsonPrepareData($data); + + default: + return null; + } + } + + /** + * Perform sanity checks on data that shall be encoded to JSON. + * + * @ignore + * @since 4.1.0 + * @access private + * + * @see wp_json_encode() + * + * @param mixed $data Variable (usually an array or object) to encode as JSON. + * @param int $depth Maximum depth to walk through $data. Must be greater than 0. + * + * @return mixed The sanitized data that shall be encoded to JSON. + */ + private static function jsonSanityCheck($data, $depth) + { + if ($depth < 0) { + throw new \Exception('Reached depth limit'); + } + + if ($data instanceof \JsonSerializable) { + $data = $data->jsonSerialize(); + } + + if (is_array($data)) { + $output = array(); + foreach ($data as $id => $el) { + // Don't forget to sanitize the ID! + if (is_string($id)) { + $clean_id = self::jsonConvertString($id); + } else { + $clean_id = $id; + } + + // Check the element type, so that we're only recursing if we really have to. + if (is_array($el) || is_object($el)) { + $output[$clean_id] = self::jsonSanityCheck($el, $depth - 1); + } elseif (is_string($el)) { + $output[$clean_id] = self::jsonConvertString($el); + } else { + $output[$clean_id] = $el; + } + } + } elseif (is_object($data)) { + $output = new \stdClass(); + foreach ($data as $id => $el) { + if (is_string($id)) { + $clean_id = self::jsonConvertString($id); + } else { + $clean_id = $id; + } + + if (is_array($el) || is_object($el)) { + $output->$clean_id = self::jsonSanityCheck($el, $depth - 1); + } elseif (is_string($el)) { + $output->$clean_id = self::jsonConvertString($el); + } else { + $output->$clean_id = $el; + } + } + } elseif (is_string($data)) { + return self::jsonConvertString($data); + } else { + return $data; + } + + return $output; + } + + /** + * Return json string + * + * @param string $string data + * + * @return string + */ + private static function jsonConvertString($string) + { + static $use_mb = null; + if (is_null($use_mb)) { + $use_mb = function_exists('mb_convert_encoding'); + } + + if ($use_mb) { + $encoding = mb_detect_encoding($string, mb_detect_order(), true); + if ($encoding) { + return mb_convert_encoding($string, 'UTF-8', $encoding); + } else { + return mb_convert_encoding($string, 'UTF-8', 'UTF-8'); + } + } else { + return self::checkInvalidUTF8($string, true); + } + } + + /** + * Checks for invalid UTF8 in a string. + * + * @param string $string The text which is to be checked. + * @param bool $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false. + * + * @return string The checked text. + */ + public static function checkInvalidUTF8($string, $strip = false) + { + $string = (string) $string; + + if (0 === strlen($string)) { + return ''; + } + + // Check for support for utf8 in the installed PCRE library once and store the result in a static + static $utf8_pcre = null; + if (!isset($utf8_pcre)) { + $utf8_pcre = @preg_match('/^./u', 'a'); + } + // We can't demand utf8 in the PCRE installation, so just return the string in those cases + if (!$utf8_pcre) { + return $string; + } + + // preg_match fails when it encounters invalid UTF8 in $string + if (1 === @preg_match('/^./us', $string)) { + return $string; + } + + // Attempt to strip the bad chars if requested (not recommended) + if ($strip && function_exists('iconv')) { + return iconv('utf-8', 'utf-8', $string); + } + + return ''; + } + + /** + * todo remove esc_attr wp function + * + * @param mixed $val object to be encoded + * + * @return string escaped json string + */ + public static function jsonEncodeEscAttr($val) + { + return esc_attr(json_encode($val)); + } + + /** + * this function return a json encoded string without quotes at the beginning and the end + * + * @param string $string json string + * + * @return string + */ + public static function getJsonWithoutQuotes($string) + { + if (!is_string($string)) { + throw new \Exception('the function getJsonStringWithoutQuotes take only strings'); + } + + return substr(self::jsonEncode($string), 1, -1); + } +} diff --git a/src/Libs/Snap/SnapLog.php b/src/Libs/Snap/SnapLog.php new file mode 100644 index 00000000..d64ffcb4 --- /dev/null +++ b/src/Libs/Snap/SnapLog.php @@ -0,0 +1,223 @@ +"; + $lfp = self::$logFilepath; + // echo "logging $s to {$lfp}
                        "; + if (self::$logFilepath === null) { + throw new Exception('Logging not initialized'); + } + + if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { + $timepart = $_SERVER['REQUEST_TIME_FLOAT']; + } else { + $timepart = $_SERVER['REQUEST_TIME']; + } + + $thread_id = sprintf("%08x", abs(crc32($_SERVER['REMOTE_ADDR'] . $timepart . $_SERVER['REMOTE_PORT']))); + + $s = $thread_id . ' ' . date('h:i:s') . ":$s"; + + if (self::$logHandle === null) { + self::$logHandle = fopen(self::$logFilepath, 'a'); + } + + fwrite(self::$logHandle, "$s\n"); + + if ($flush) { + fflush(self::$logHandle); + + fclose(self::$logHandle); + + self::$logHandle = fopen(self::$logFilepath, 'a'); + } + } + + /** + * Get formatted string fo value + * + * @param mixed $var value to convert to string + * @param bool $checkCallable if true check if var is callable and display it + * + * @return string + */ + public static function v2str($var, $checkCallable = false) + { + if ($checkCallable && is_callable($var)) { + return '(callable) ' . print_r($var, true); + } + switch (gettype($var)) { + case "boolean": + return $var ? 'true' : 'false'; + case "integer": + case "double": + return (string) $var; + case "string": + return '"' . $var . '"'; + case "array": + case "object": + return print_r($var, true); + case "resource": + case "resource (closed)": + case "NULL": + case "unknown type": + default: + return gettype($var); + } + } + + /** + * Get backtrace of calling line + * + * @param string $message message + * + * @return string + */ + public static function getCurrentbacktrace($message = 'getCurrentLineTrace') + { + $callers = debug_backtrace(); + array_shift($callers); + $file = $callers[0]['file']; + $line = $callers[0]['line']; + $result = 'BACKTRACE: ' . $message . "\n"; + $result .= "\t[" . $file . ':' . $line . "]\n"; + $result .= self::traceToString($callers, 1, true); + return $result; + } + + /** + * Get trace string + * + * @param mixed[] $callers result of debug_backtrace + * @param int $fromLevel level to start + * @param bool $tab if true apply tab foreach line + * + * @return string + */ + public static function traceToString($callers, $fromLevel = 0, $tab = false) + { + $result = ''; + for ($i = $fromLevel; $i < count($callers); $i++) { + $result .= ($tab ? "\t" : ''); + $trace = $callers[$i]; + if (!empty($trace['class'])) { + $result .= str_pad('TRACE[' . $i . '] CLASS___: ' . $trace['class'] . $trace['type'] . $trace['function'], 45, ' '); + } else { + $result .= str_pad('TRACE[' . $i . '] FUNCTION: ' . $trace['function'], 45, ' '); + } + if (isset($trace['file'])) { + $result .= ' FILE: ' . $trace['file'] . '[' . $trace['line'] . ']'; + } else { + $result .= ' NO FILE'; + } + $result .= "\n"; + } + return $result; + } + + /** + * Get exception message file line trace + * + * @param Exception|Error $e exception object + * @param bool $displayMessage if true diplay exception message + * + * @return string + */ + public static function getTextException($e, $displayMessage = true) + { + $result = ($displayMessage ? $e->getMessage() . "\n" : ''); + return $result . "FILE:" . $e->getFile() . '[' . $e->getLIne() . "]\n" . + "TRACE:\n" . $e->getTraceAsString(); + } +} diff --git a/src/Libs/Snap/SnapOS.php b/src/Libs/Snap/SnapOS.php new file mode 100644 index 00000000..6d5752a1 --- /dev/null +++ b/src/Libs/Snap/SnapOS.php @@ -0,0 +1,43 @@ + */ + protected $origFolderEntries = array(); + /** @var string */ + protected $rootPath = null; + + /** + * Class constructor + * + * @param string $root wordpress root path + * @param string $origFolderParentPath orig files folder path + * @param string $hash package hash + */ + public function __construct($root, $origFolderParentPath, $hash) + { + $this->rootPath = SnapIO::safePathUntrailingslashit($root, true); + $this->origFilesFolder = SnapIO::safePathTrailingslashit($origFolderParentPath, true) . self::ORIG_FOLDER_PREFIX . $hash; + $this->persistanceFile = $this->origFilesFolder . '/' . self::PERSISTANCE_FILE_NAME; + + if (file_exists($this->persistanceFile)) { + $this->load(); + } + } + + /** + * Create a main folder if don't exist and load the entries + * + * @param boolean $reset if strue reset orig file folder + * + * @return void + */ + public function init($reset = false) + { + $this->createMainFolder($reset); + $this->load(); + } + + /** + * Create orig file folder + * + * @param boolean $reset if true delete current folder + * + * @return boolean return true if succeded + * + * @throws \Exception + */ + protected function createMainFolder($reset = false) + { + if ($reset) { + $this->deleteMainFolder(); + } + + if (!file_exists($this->origFilesFolder)) { + if (!SnapIO::mkdir($this->origFilesFolder, 'u+rwx')) { + throw new \Exception('Can\'t create the original files folder ' . SnapLog::v2str($this->origFilesFolder)); + } + } + + $htaccessFile = $this->origFilesFolder . '/.htaccess'; + if (!file_exists($htaccessFile)) { + $content = <<persistanceFile)) { + $this->save(); + } + + return true; + } + + /** + * @return string Main folder path + * @throws \Exception + */ + public function getMainFolder() + { + if (!file_exists($this->origFilesFolder)) { + throw new \Exception('Can\'t get the original files folder ' . SnapLog::v2str($this->origFilesFolder)); + } + + return $this->origFilesFolder; + } + + /** + * delete origianl files folder + * + * @return boolean + * @throws \Exception + */ + public function deleteMainFolder() + { + if (file_exists($this->origFilesFolder) && !SnapIO::rrmdir($this->origFilesFolder)) { + throw new \Exception('Can\'t delete the original files folder ' . SnapLog::v2str($this->origFilesFolder)); + } + $this->origFolderEntries = array(); + + return true; + } + + /** + * add a entry on original folder. + * + * @param string $identifier entry identifier + * @param string $path entry path. can be a file or a folder + * @param string $mode MODE_MOVE move the item in original folder + * MODE_COPY copy the item in original folder + * @param bool|string $rename if rename is a string the item is renamed in original folder. + * + * @return boolean true if succeded + */ + public function addEntry($identifier, $path, $mode = self::MODE_MOVE, $rename = false) + { + if (!file_exists($path)) { + return false; + } + + $baseName = empty($rename) ? basename($path) : $rename; + + if (($relativePath = SnapIO::getRelativePath($path, $this->rootPath)) === false) { + $isRelative = false; + } else { + $isRelative = true; + } + $parentFolder = $isRelative ? dirname($relativePath) : SnapIO::removeRootPath(dirname($path)); + if (empty($parentFolder) || $parentFolder === '.') { + $parentFolder = ''; + } else { + $parentFolder .= '/'; + } + $targetFolder = $this->origFilesFolder . '/' . $parentFolder; + if (!file_exists($targetFolder)) { + SnapIO::mkdirP($targetFolder); + } + $dest = $targetFolder . $baseName; + + switch ($mode) { + case self::MODE_MOVE: + // Don't use rename beacause new files must have the current script owner + if (!SnapIO::rcopy($path, $dest)) { + throw new \Exception('Can\'t copy the original file ' . SnapLog::v2str($path)); + } + if (!SnapIO::rrmdir($path)) { + throw new \Exception('Can\'t remove the original file ' . SnapLog::v2str($path)); + } + break; + case self::MODE_COPY: + if (!SnapIO::rcopy($path, $dest)) { + throw new \Exception('Can\'t copy the original file ' . SnapLog::v2str($path)); + } + break; + default: + throw new \Exception('invalid mode addEntry'); + } + + $this->origFolderEntries[$identifier] = array( + 'baseName' => $baseName, + 'source' => $isRelative ? $relativePath : $path, + 'stored' => $parentFolder . $baseName, + 'mode' => $mode, + 'isRelative' => $isRelative + ); + + $this->save(); + return true; + } + + /** + * Get entry info from identifier + * + * @param string $identifier orig file identifier + * + * @return false|array{baseName:string, source:string, stored: string, mode:string, isRelative: bool} false if entry don't exists + */ + public function getEntry($identifier) + { + if (isset($this->origFolderEntries[$identifier])) { + return $this->origFolderEntries[$identifier]; + } else { + return false; + } + } + + /** + * Get entry stored path in original folder + * + * @param string $identifier orig file identifier + * + * @return boolean|string false if entry don't exists + */ + public function getEntryStoredPath($identifier) + { + if (isset($this->origFolderEntries[$identifier])) { + return $this->origFilesFolder . '/' . $this->origFolderEntries[$identifier]['stored']; + } else { + return false; + } + } + + /** + * Return true if identifier org file is relative path + * + * @param string $identifier orig file identifier + * + * @return boolean + */ + public function isRelative($identifier) + { + if (isset($this->origFolderEntries[$identifier])) { + return $this->origFolderEntries[$identifier]['isRelative']; + } else { + return false; + } + } + + /** + * Get entry target restore path + * + * @param string $identifier orig file identifier + * @param null|string $defaultIfIsAbsolute if isn't null return the value if path is absolute + * + * @return false|string false if entry don't exists + */ + public function getEntryTargetPath($identifier, $defaultIfIsAbsolute = null) + { + if (isset($this->origFolderEntries[$identifier])) { + if ($this->origFolderEntries[$identifier]['isRelative']) { + return $this->rootPath . '/' . $this->origFolderEntries[$identifier]['source']; + } else { + if (is_null($defaultIfIsAbsolute)) { + return $this->origFolderEntries[$identifier]['source']; + } else { + return $defaultIfIsAbsolute; + } + } + } else { + return false; + } + } + + /** + * this function restore current entry in original position. + * If mode is copy it simply delete the entry else move the entry in original position + * + * @param string $identifier identified of current entrye + * @param boolean $save update saved entries + * @param null|string $defaultIfIsAbsolute if isn't null return the value if path is absolute + * + * @return boolean true if succeded + */ + public function restoreEntry($identifier, $save = true, $defaultIfIsAbsolute = null) + { + if (!isset($this->origFolderEntries[$identifier])) { + return false; + } + + $stored = $this->getEntryStoredPath($identifier); + if (($original = $this->getEntryTargetPath($identifier, $defaultIfIsAbsolute)) === false) { + return false; + } + + switch ($this->origFolderEntries[$identifier]['mode']) { + case self::MODE_MOVE: + if (!SnapIO::rename($stored, $original)) { + throw new \Exception('Can\'t move the original file ' . SnapLog::v2str($stored)); + } + break; + case self::MODE_COPY: + if (!SnapIO::rrmdir($stored)) { + throw new \Exception('Can\'t delete entry ' . SnapLog::v2str($stored)); + } + break; + default: + throw new \Exception('invalid mode addEntry'); + } + + unset($this->origFolderEntries[$identifier]); + if ($save) { + $this->save(); + } + return true; + } + + /** + * Put all entries on original position and empty original folder + * + * @param string[] $exclude identifiers list t exclude + * + * @return boolean + */ + public function restoreAll($exclude = array()) + { + foreach (array_keys($this->origFolderEntries) as $ident) { + if (in_array($ident, $exclude)) { + continue; + } + $this->restoreEntry($ident, false); + } + $this->save(); + return true; + } + + /** + * Save notices from json file + * + * @return bool + */ + public function save() + { + if (!file_put_contents($this->persistanceFile, SnapJson::jsonEncodePPrint($this->origFolderEntries))) { + throw new \Exception('Can\'t write persistence file'); + } + return true; + } + + /** + * Load notice from json file + * + * @return bool + */ + private function load() + { + if (file_exists($this->persistanceFile)) { + $json = file_get_contents($this->persistanceFile); + $this->origFolderEntries = json_decode($json, true); + } else { + $this->origFolderEntries = array(); + } + return true; + } +} diff --git a/src/Libs/Snap/SnapString.php b/src/Libs/Snap/SnapString.php new file mode 100644 index 00000000..533ab1a8 --- /dev/null +++ b/src/Libs/Snap/SnapString.php @@ -0,0 +1,186 @@ + $maxWidth) { + $s = substr($s, 0, $maxWidth - 3) . '...'; + } + + return $s; + } + + /** + * Returns true if the $haystack string starts with the $needle + * + * @param string $haystack The full string to search in + * @param string $needle The string to for + * + * @return bool Returns true if the $haystack string starts with the $needle + */ + public static function startsWith($haystack, $needle) + { + return (strpos($haystack, $needle) === 0); + } + + /** + * Returns true if the $haystack string end with the $needle + * + * @param string $haystack The full string to search in + * @param string $needle The string to for + * + * @return bool Returns true if the $haystack string starts with the $needle + */ + public static function endsWith($haystack, $needle) + { + $length = strlen($needle); + if ($length == 0) { + return true; + } + return (substr($haystack, -$length) === $needle); + } + + /** + * Returns true if the $needle is found in the $haystack + * + * @param string $haystack The full string to search in + * @param string $needle The string to for + * + * @return bool + */ + public static function contains($haystack, $needle) + { + $pos = strpos($haystack, $needle); + return ($pos !== false); + } + + /** + * Implode array key values to a string + * + * @param string $glue separator + * @param mixed[] $pieces array fo implode + * @param string $format format + * + * @return string + */ + public static function implodeKeyVals($glue, $pieces, $format = '%s="%s"') + { + $strList = array(); + foreach ($pieces as $key => $value) { + if (is_scalar($value)) { + $strList[] = sprintf($format, $key, $value); + } else { + $strList[] = sprintf($format, $key, print_r($value, true)); + } + } + return implode($glue, $strList); + } + + /** + * Replace last occurrence + * + * @param string $search The value being searched for + * @param string $replace The replacement value that replaces found search values + * @param string $str The string or array being searched and replaced on, otherwise known as the haystack + * @param boolean $caseSensitive Whether the replacement should be case sensitive or not + * + * @return string + */ + public static function strLastReplace($search, $replace, $str, $caseSensitive = true) + { + $pos = $caseSensitive ? strrpos($str, $search) : strripos($str, $search); + if (false !== $pos) { + $str = substr_replace($str, $replace, $pos, strlen($search)); + } + return $str; + } + + /** + * Check if passed string have html tags + * + * @param string $string input string + * + * @return boolean + */ + public static function isHTML($string) + { + return ($string != strip_tags($string)); + } + + /** + * Safe way to get number of characters + * + * @param ?string $string input string + * + * @return int + */ + public static function stringLength($string) + { + if (!isset($string) || $string == "") { // null == "" is also true + return 0; + } + return strlen($string); + } + + /** + * Returns case insensitive duplicates + * + * @param string[] $strings The array of strings to check for duplicates + * + * @return array + */ + public static function getCaseInsesitiveDuplicates($strings) + { + $duplicates = array(); + for ($i = 0; $i < count($strings) - 1; $i++) { + $key = strtolower($strings[$i]); + + //already found all instances so don't check again + if (isset($duplicates[$key])) { + continue; + } + + for ($j = $i + 1; $j < count($strings); $j++) { + if ($strings[$i] !== $strings[$j] && $key === strtolower($strings[$j])) { + $duplicates[$key][] = $strings[$j]; + } + } + + //duplicates were found, add the comparing string to list + if (isset($duplicates[$key])) { + $duplicates[$key][] = $strings[$i]; + } + } + + return $duplicates; + } +} diff --git a/src/Libs/Snap/SnapURL.php b/src/Libs/Snap/SnapURL.php new file mode 100644 index 00000000..c766299e --- /dev/null +++ b/src/Libs/Snap/SnapURL.php @@ -0,0 +1,237 @@ + */ + protected static $DEF_ARRAY_PARSE_URL = array( + 'scheme' => false, + 'host' => false, + 'port' => false, + 'user' => false, + 'pass' => false, + 'path' => '', + 'query' => false, + 'fragment' => false + ); + + /** + * Append a new query value to the end of a URL + * + * @param string $url The URL to append the new value to + * @param string $key The new key name + * @param ?scalar $value The new key name value + * + * @return string Returns the new URL with with the query string name and value + */ + public static function appendQueryValue($url, $key, $value) + { + $separator = (parse_url($url, PHP_URL_QUERY) == null) ? '?' : '&'; + $modified_url = $url . "$separator$key=" . $value; + + return $modified_url; + } + + /** + * Add www. in url if don't have + * + * @param string $url input URL + * + * @return string + */ + public static function wwwAdd($url) + { + return preg_replace('/^((?:\w+\:)?\/\/)?(?!www\.)(.+)/', '$1www.$2', $url); + } + + /** + * Remove www. in url if don't have + * + * @param string $url input URL + * + * @return string + */ + public static function wwwRemove($url) + { + return preg_replace('/^((?:\w+\:)?\/\/)?www\.(.+)/', '$1$2', $url); + } + + /** + * Fetches current URL via PHP + * + * @param bool $queryString If true the query string will also be returned. + * @param boolean $requestUri If true check REQUEST_URI else SCRIPT_NAME + * @param int $getParentDirLevel If 0 get current script name or parent folder, if 1 parent folder if 2 parent of parent folder ... + * + * @return string The current page url + */ + public static function getCurrentUrl($queryString = true, $requestUri = false, $getParentDirLevel = 0) + { + // *** HOST + if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) { + $host = $_SERVER['HTTP_X_ORIGINAL_HOST']; + } else { + $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; //WAS SERVER_NAME and caused problems on some boxes + } + + // *** PROTOCOL + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER ['HTTPS'] = 'on'; + } + if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'https') { + $_SERVER ['HTTPS'] = 'on'; + } + if (isset($_SERVER['HTTP_CF_VISITOR'])) { + $visitor = json_decode($_SERVER['HTTP_CF_VISITOR']); + if (is_object($visitor) && property_exists($visitor, 'scheme') && $visitor->scheme == 'https') { + $_SERVER ['HTTPS'] = 'on'; + } + } + $protocol = 'http' . ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') ? 's' : ''); + + if ($requestUri) { + $serverUrlSelf = preg_replace('/\?.*$/', '', $_SERVER['REQUEST_URI']); + } else { + // *** SCRIPT NAME + $serverUrlSelf = $_SERVER['SCRIPT_NAME']; + for ($i = 0; $i < $getParentDirLevel; $i++) { + $serverUrlSelf = preg_match('/^[\\\\\/]?$/', dirname($serverUrlSelf)) ? '' : dirname($serverUrlSelf); + } + } + + // *** QUERY STRING + $query = ($queryString && isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0 ) ? '?' . $_SERVER['QUERY_STRING'] : ''; + + return $protocol . '://' . $host . $serverUrlSelf . $query; + } + + /** + * Get current query string data array + * + * @return string[] + */ + public static function getCurrentQueryURLdata() + { + $result = array(); + if (!isset($_SERVER['QUERY_STRING']) || strlen($_SERVER['QUERY_STRING']) == 0) { + return $result; + } + + parse_str($_SERVER['QUERY_STRING'], $result); + + return $result; + } + + /** + * this function is a native PHP parse_url wrapper + * this function returns an associative array with all the keys present and the values = false if they do not exist. + * + * @param string $url

                        The URL to parse. Invalid characters are replaced by _.

                        + * @param int $component if != 1 return specific URL component + * + * @return mixed[]|string|int|null|false

                        On seriously malformed URLs, parse_url() may return FALSE.

                        + *

                        If the component parameter is omitted, an associative array is returned. + * At least one element will be present within the array. Potential keys within this array are:

                        + *
                          + *
                        • scheme - e.g. http
                        • + *
                        • host
                        • + *
                        • port
                        • + *
                        • user
                        • + *
                        • pass
                        • + *
                        • path
                        • + *
                        • query - after the question mark ?
                        • + *
                        • fragment - after the hashmark #
                        • + *
                        + *

                        If the component parameter is specified, + * parse_url() returns a string (or an integer, + * in the case of PHP_URL_PORT) instead of an array. + * If the requested component doesn't exist within the given URL, NULL will be returned.

                        + */ + public static function parseUrl($url, $component = -1) + { + if (preg_match('/^([a-zA-Z0-9]+\:)?\/\//', $url) !== 1) { + // fix invalid URL for only host string ex. 'myhost.com' + $url = '//' . $url; + } + + $result = parse_url($url, $component); + if (is_array($result)) { + $result = array_merge(self::$DEF_ARRAY_PARSE_URL, $result); + } + + return $result; + } + + /** + * Remove scheme from URL + * + * @param string $url source url + * @param bool $removeWww if true remove www + * + * @return string + */ + public static function removeScheme($url, $removeWww = false) + { + $parts = self::parseUrl($url); + unset($parts['scheme']); + $result = self::buildUrl($parts); + if ($removeWww) { + $result = self::wwwRemove($result); + } + return ltrim($result, '/'); + } + + /** + * this function build a url from array result of parse url. + * if work with both parse_url native function result and snap parseUrl result + * + * @param array $parts url parts from parseUrl + * + * @return bool|string return false if param isn't array + */ + public static function buildUrl($parts) + { + if (!is_array($parts)) { + return false; + } + + $result = ''; + $result .= (isset($parts['scheme']) && $parts['scheme'] !== false) ? $parts['scheme'] . ':' : ''; + $result .= ( + (isset($parts['user']) && $parts['user'] !== false) || + (isset($parts['host']) && $parts['host'] !== false)) ? '//' : ''; + + $result .= (isset($parts['user']) && $parts['user'] !== false) ? $parts['user'] : ''; + $result .= (isset($parts['pass']) && $parts['pass'] !== false) ? ':' . $parts['pass'] : ''; + $result .= (isset($parts['user']) && $parts['user'] !== false) ? '@' : ''; + + $result .= (isset($parts['host']) && $parts['host'] !== false) ? $parts['host'] : ''; + $result .= (isset($parts['port']) && $parts['port'] !== false) ? ':' . $parts['port'] : ''; + + $result .= (isset($parts['path']) && $parts['path'] !== false) ? $parts['path'] : ''; + $result .= (isset($parts['query']) && $parts['query'] !== false) ? '?' . $parts['query'] : ''; + $result .= (isset($parts['fragment']) && $parts['fragment'] !== false) ? '#' . $parts['fragment'] : ''; + + return $result; + } + + /** + * Encode alla chars + * + * @param string $url input URL + * + * @return string + */ + public static function urlEncodeAll($url) + { + $hex = unpack('H*', urldecode($url)); + return preg_replace('~..~', '%$0', strtoupper($hex[1])); + } +} diff --git a/src/Libs/Snap/SnapUtil.php b/src/Libs/Snap/SnapUtil.php new file mode 100644 index 00000000..c66e2e6b --- /dev/null +++ b/src/Libs/Snap/SnapUtil.php @@ -0,0 +1,957 @@ + 0) { + $percent = $startingPercent + (($endingPercent - $startingPercent) * ($currentTaskCount / (float) $totalTaskCount)); + } else { + $percent = $startingPercent; + } + + return min(max($startingPercent, $percent), $endingPercent); + } + + /** + * Compare two versions like version_compare but the ability to enter the number of levels to compare. + * For example, if the level is 2 between 4.1.1 and 4.1.2.1, 4.1 is compared with 4.1 and so they are equal. + * + * @param string $version1 version one + * @param string $version2 version two + * @param string $operator operetor type + * @param int $vLevel version level 0 is all levels + * + * @return int|bool + */ + public static function versionCompare($version1, $version2, $operator = null, $vLevel = 0) + { + if ($vLevel > 0) { + $tV1 = array_slice(preg_split("/[.-]/", $version1), 0, $vLevel); + $version1 = implode('.', $tV1); + $tV2 = array_slice(preg_split("/[.-]/", $version2), 0, $vLevel); + $version2 = implode('.', $tV2); + } + return version_compare($version1, $version2, $operator); + } + + /** + * Return version with level + * + * @param string $version version + * @param int $vLevel version level 0 is all levels + * + * @return string + */ + public static function getVersion($version, $vLevel = 0) + { + if ($vLevel > 0) { + $tV1 = array_slice(preg_split("/[.-]/", $version), 0, $vLevel); + $version = implode('.', $tV1); + } + return $version; + } + + /** + * Return true if is PHP7+ + * + * @return bool + */ + public static function isPHP7Plus() + { + static $isPHP7Plus = null; + if (is_null($isPHP7Plus)) { + $isPHP7Plus = version_compare(PHP_VERSION, '7.0.0', '>='); + } + return $isPHP7Plus; + } + + /** + * Groups an array into arrays by a given key, or set of keys, shared between all array members. + * + * Based on {@author Jake Zatecky}'s {@link https://github.com/jakezatecky/array_group_by array_group_by()} function. + * This variant allows $key to be closures. + * + * @param mixed[] $array The array to have grouping performed on. + * @param mixed $key The key to group or split by. Can be a _string_, an _integer_, a _float_, or a _callable_. + * - If the key is a callback, it must return a valid key from the array. - If the key is + * _NULL_, the iterated element is skipped. - string|int callback ( mixed $item ) + * + * @return mixed[]|null Returns a multidimensional array or `null` if `$key` is invalid. + */ + public static function arrayGroupBy(array $array, $key) + { + if (!is_string($key) && !is_int($key) && !is_float($key) && !is_callable($key)) { + trigger_error('array_group_by(): The key should be a string, an integer, or a callback', E_USER_ERROR); + } + $func = (!is_string($key) && is_callable($key) ? $key : null); + $_key = $key; + // Load the new array, splitting by the target key + $grouped = array(); + foreach ($array as $value) { + $key = null; + if (is_callable($func)) { + $key = call_user_func($func, $value); + } elseif (is_object($value) && isset($value->{$_key})) { + $key = $value->{$_key}; + } elseif (isset($value[$_key])) { + $key = $value[$_key]; + } + if ($key === null) { + continue; + } + $grouped[$key][] = $value; + } + // Recursively build a nested grouping if more parameters are supplied + // Each grouped array value is grouped according to the next sequential key + if (func_num_args() > 2) { + $args = func_get_args(); + foreach ($grouped as $key => $value) { + $params = array_merge(array($value), array_slice($args, 2, func_num_args())); + $grouped[$key] = call_user_func_array(array(__CLASS__, 'arrayGroupBy'), $params); + } + } + return $grouped; + } + + /** + * Converts human readable types (10GB) to bytes + * + * @param string $from A human readable byte size such as 100MB + * + * @return int<-1, max> Returns and integer of the byte size, -1 if isn't well formatted + */ + public static function convertToBytes($from) + { + if (is_numeric($from)) { + return (int) $from; + } + + $number = (int) substr($from, 0, -2); + switch (strtoupper(substr($from, -2))) { + case "KB": + return $number * 1024; + case "MB": + return $number * pow(1024, 2); + case "GB": + return $number * pow(1024, 3); + case "TB": + return $number * pow(1024, 4); + case "PB": + return $number * pow(1024, 5); + } + + $number = (int) substr($from, 0, -1); + switch (strtoupper(substr($from, -1))) { + case "K": + return $number * 1024; + case "M": + return $number * pow(1024, 2); + case "G": + return $number * pow(1024, 3); + case "T": + return $number * pow(1024, 4); + case "P": + return $number * pow(1024, 5); + } + + return -1; + } + + /** + * Sanitize input for XSS code + * + * @param string $input The value to sanitize + * + * @return string Returns the input value cleaned up. + */ + public static function sanitize($input) + { + return htmlspecialchars(self::sanitizeNSChars($input)); + } + + /** + * Remove all non stamp chars from string + * + * @param string $string input string + * + * @return string + */ + public static function sanitizeNSChars($string) + { + return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', (string) $string); + } + + /** + * remove all non stamp chars from string and newline + * trim string + * + * @param string $string input string + * + * @return string + */ + public static function sanitizeNSCharsNewline($string) + { + return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\r\n]/u', '', (string) $string); + } + + /** + * Remove all non stamp chars, newline, spaces and tabulation from string + * + * @param string $string input string + * + * @return string + */ + public static function sanitizeNSCharsNewlineTabs($string) + { + return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\r\n\s]/u', '', (string) $string); + } + + /** + * remove all non stamp chars from string and newline + * trim string + * + * @param string $string input string + * + * @return string + */ + public static function sanitizeNSCharsNewlineTrim($string) + { + return trim(self::sanitizeNSCharsNewline($string)); + } + + /** + * Determines whether a PHP ini value is changeable at runtime. + * + * @since 4.6.0 + * + * @staticvar array $ini_all + * + * @link https://secure.php.net/manual/en/function.ini-get-all.php + * + * @param string $setting The name of the ini setting to check. + * + * @return bool True if the value is changeable at runtime. False otherwise. + */ + public static function isIniValChangeable($setting) + { + // if ini_set is disabled can change the values + if (!function_exists('ini_set')) { + return false; + } + + static $ini_all; + + if (!isset($ini_all)) { + $ini_all = false; + // Sometimes `ini_get_all()` is disabled via the `disable_functions` option for "security purposes". + if (function_exists('ini_get_all')) { + $ini_all = ini_get_all(); + } + } + + // Bit operator to workaround https://bugs.php.net/bug.php?id=44936 which changes access level to 63 in PHP 5.2.6 - 5.2.17. + if (isset($ini_all[$setting]['access']) && ( INI_ALL === ( $ini_all[$setting]['access'] & 7 ) || INI_USER === ( $ini_all[$setting]['access'] & 7 ) )) { + return true; + } + + // If we were unable to retrieve the details, fail gracefully to assume it's changeable. + if (!is_array($ini_all)) { + return true; + } + + return false; + } + + /** + * get php.ini value + * + * @param string $key php ini value + * @param mixed $default default valu if init_get is disabled or key don't exists + * @param string $returnType the return type, accept only scalar values (bool, int, float, string) + * + * @return mixed + */ + public static function phpIniGet($key, $default, $returnType = 'string') + { + if (!function_exists('ini_get')) { + return $default; + } + + if (($result = ini_get($key)) === false) { + return $default; + } + + switch ($returnType) { + case "bool": + return filter_var($result, FILTER_VALIDATE_BOOLEAN); + case "int": + return (int) $result; + case "float": + return (float) $result; + case "string": + return (string) $result; + default: + throw new Exception('Invalid return type ' . $returnType); + } + } + + /** + * The val value returns if it is between min and max otherwise it returns min or max + * + * @param int|float $val input value + * @param int|float $min min value + * @param int|float $max max value + * + * @return int + */ + public static function getIntBetween($val, $min, $max) + { + return min((int) $max, max((int) $min, (int) $val)); + } + + /** + * Gets a specific external variable by name and optionally filters it by request + * + * @param string $variable_name

                        Name of a variable to get.

                        + * @param int $filter

                        The ID of the filter to apply. The Types of filters manual page lists the available filters.

                        + *

                        If omitted, FILTER_DEFAULT will be used, which is equivalent to + * FILTER_UNSAFE_RAW. This will result in no filtering taking place by + * default.

                        + * @param mixed[]|int $options

                        Associative array of options or bitwise disjunction of flags. + * If filter accepts options, flags can be provided in "flags" field of array.

                        + * + * @return mixed Value of the requested variable on success + * + * @link http://php.net/manual/en/function.filter-input.php + * @see filter_var(), filter_input_array(), filter_var_array() + */ + public static function filterInputRequest($variable_name, $filter = FILTER_DEFAULT, $options = 0) + { + if (isset($_GET[$variable_name]) && !isset($_POST[$variable_name])) { + return filter_input(INPUT_GET, $variable_name, $filter, $options); + } + + return filter_input(INPUT_POST, $variable_name, $filter, $options); + } + + /** + * Return input from type + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, or INPUT_ENV, self::INPUT_REQUEST + * + * @return mixed[] + */ + public static function getInputFromType($type) + { + switch ($type) { + case INPUT_GET: + return $_GET; + case INPUT_POST: + return $_POST; + case INPUT_COOKIE: + return $_COOKIE; + case INPUT_SERVER: + return $_SERVER; + case INPUT_ENV: + return $_ENV; + case self::INPUT_REQUEST: + return array_merge($_GET, $_POST); + default: + throw new Exception('Invalid type ' . $type); + } + } + + /** + * Default filter sanitize string, apply sanitizeNSChars function. + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, or INPUT_ENV. + * @param string $var_name Name of a variable to get. + * @param mixed $default default value if dont exists + * + * @return string + */ + public static function filterInputDefaultSanitizeString($type, $var_name, $default = '') + { + $filter = FILTER_UNSAFE_RAW; + $options = array( + 'options' => array( 'default' => null) + ); + if ($type == self::INPUT_REQUEST) { + $result = self::filterInputRequest($var_name, $filter, $options); + } else { + $result = filter_input($type, $var_name, $filter, $options); + } + if (is_null($result)) { + return $default; + } + return self::sanitizeNSChars($result); + } + + /** + * All characters that are not explicitly accepted are removed. + * By default, only alphanumeric characters are accepted. + * + * @param mixed $input input value + * @param string $extraAcceptChars extra accepted chars + * + * @return string|string[] + */ + public static function sanitizeStrict($input, $extraAcceptChars = '') + { + $regex = '/[^a-zA-Z0-9' . preg_quote($extraAcceptChars, '/') . ' ]/m'; + if (is_scalar($input) || is_null($input)) { + $input = (string) $input; + } elseif (is_array($input)) { + } elseif (is_object($input)) { + $input = (array) $input; + } else { + $input = ''; + } + + if (is_array($input)) { + foreach ($input as $key => $val) { + $input[$key] = self::sanitizeStrict($val, $extraAcceptChars); + } + return $input; + } + + $result = preg_replace($regex, '', $input); + return (is_null($result) ? '' : $result); + } + + /** + * Sanitize value to int + * + * @param mixed $input Input value + * @param int $default Default value if input isnt valid + * + * @return int + */ + public static function sanitizeInt($input, $default = 0) + { + if (!is_scalar($input)) { + return $default; + } elseif (is_bool($input)) { + return (int) $input; + } else { + return filter_var($input, FILTER_VALIDATE_INT, array('options' => array( 'default' => $default))); + } + } + + /** + * Sanitize value to bool + * + * @param mixed $input Input value + * + * @return bool + */ + public static function sanitizeBool($input) + { + if (!is_scalar($input)) { + return false; + } elseif (is_bool($input)) { + return $input; + } else { + return filter_var($input, FILTER_VALIDATE_BOOLEAN); + } + } + + /** + * Sanitize value from input $_GET, $_POST, $_REQUEST ... + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV or SnapUtil::INPUT_REQUEST + * @param string $varName Name of a variable to get. + * @param mixed $default default value if var $varName don't exists + * @param string $extraAcceptChars extra accepted chars + * + * @return string|string[]|mixed return default value if varName isn't defined + */ + public static function sanitizeStrictInput($type, $varName, $default = false, $extraAcceptChars = '') + { + if (($value = self::getValueByType($type, $varName)) === null) { + return $default; + } + + return self::sanitizeStrict($value, $extraAcceptChars); + } + + /** + * Sanitize value from input $_GET, $_POST, $_REQUEST ... + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV or SnapUtil::INPUT_REQUEST + * @param string $varName Name of a variable to get. + * @param int $default default value if var $varName don't exists + * + * @return int return default value if varName isn't defined + */ + public static function sanitizeIntInput($type, $varName, $default = 0) + { + if (($value = self::getValueByType($type, $varName)) === null) { + return $default; + } + + return self::sanitizeInt($value); + } + + /** + * Sanitize value from input $_GET, $_POST, $_REQUEST ... + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV or SnapUtil::INPUT_REQUEST + * @param string $varName Name of a variable to get. + * @param null|bool $default default value if var $varName don't exists + * + * @return bool return default value if varName isn't defined + */ + public static function sanitizeBoolInput($type, $varName, $default = false) + { + if (($value = self::getValueByType($type, $varName)) === null) { + return $default; + } + + return self::sanitizeBool($value); + } + + /** + * Sanitize value from input $_GET, $_POST, $_REQUEST ... + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV or SnapUtil::INPUT_REQUEST + * @param string $varName Name of a variable to get. + * @param mixed $default default value if var $varName don't exists + * + * @return string|string[]|mixed return default value if varName isn't defined + */ + public static function sanitizeInput($type, $varName, $default = false) + { + if (($value = self::getValueByType($type, $varName)) === null) { + return $default; + } + return self::sanitize($value); + } + + /** + * Return value input by type null if don't exists + * + * @param int $type One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV or SnapUtil::INPUT_REQUEST + * @param string $varName Name of a variable to get. + * + * @return string|string[]|null + */ + protected static function getValueByType($type, $varName) + { + $doNothingCallback = function ($v) { + return $v; + }; + + if ($type === self::INPUT_REQUEST) { + $type = ((isset($_GET[$varName]) && !isset($_POST[$varName])) ? INPUT_GET : INPUT_POST); + } + $value = filter_input($type, $varName, FILTER_CALLBACK, array('options' => $doNothingCallback)); + + /** @var string|string[]|null $value */ + return $value; + } + + /** + * Gets external variables and optionally filters them + *

                        This function is useful for retrieving many values without repetitively calling filter_input().

                        + * + * @param mixed[]|int $definition

                        An array defining the arguments. + * A valid key is a string containing a variable name and a valid value is either a filter type, + * or an array optionally specifying the filter, flags and options. + * If the value is an array, valid keys are filter which specifies the filter type, + * flags which specifies any flags that apply to the filter, and options + * which specifies any options that apply to the filter. See the example below for a better understanding.

                        + *

                        This parameter can be also an integer holding a filter constant. + * Then all values in the input array are filtered by this filter.

                        + * @param bool $add_empty

                        Add missing keys as NULL to the return value.

                        + * + * @return mixed An array containing the values of the requested variables on success. + * + * @link http://php.net/manual/en/function.filter-input-array.php + * @see filter_input(), filter_var_array() + */ + public static function filterInputRequestArray($definition = FILTER_DEFAULT, $add_empty = true) + { + if (!is_array($definition) || count($definition) === 0) { + return array(); + } + $getKeys = array_keys($_GET); + $postKeys = array_keys($_POST); + $keys = array_keys($definition); + + if (count(array_intersect($keys, $getKeys)) && !count(array_intersect($keys, $postKeys))) { + $type = INPUT_GET; + } else { + $type = INPUT_POST; + } + + // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.filter_input_array_add_emptyFound + $result = filter_input_array($type, $definition, $add_empty); + + if (!is_array($result)) { + $result = array(); + foreach ($keys as $key) { + $result[$key] = null; + } + } + return $result; + } + + /** + * Close all buffers and return content + * + * @param bool $getContent If true it returns buffer content, otherwise it is discarded + * + * @return string + */ + public static function obCleanAll($getContent = true) + { + $result = ''; + for ($i = 0; $i < ob_get_level(); $i++) { + if ($getContent) { + $result .= ob_get_contents(); + } + ob_clean(); + } + return $result; + } + + /** + * Array map recursively + * + * @param callable $callback callback function + * @param mixed[] $array array input + * + * @return mixed[] + */ + public static function arrayMapRecursive($callback, $array) + { + if (!is_array($array)) { + throw new Exception('$array must be an array'); + } + if (!is_callable($callback)) { + throw new Exception('$callback must be callable'); + } + $func = function ($item) use (&$func, &$callback) { + return is_array($item) ? array_map($func, $item) : call_user_func($callback, $item); + }; + return array_map($func, $array); + } + + /** + * Implemented array_key_first + * + * @link https://www.php.net/manual/en/function.array-key-first.php + * + * @param mixed[] $arr array input + * + * @return int|string|null + */ + public static function arrayKeyFirst($arr) + { + if (!function_exists('array_key_first')) { + foreach ($arr as $key => $unused) { + return $key; + } + return null; + } else { + // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_key_firstFound + return array_key_first($arr); + } + } + + /** + * Get number of bit supported by PHP + * + * @return string + */ + public static function getArchitectureString() + { + return (PHP_INT_SIZE * 8) . '-bit'; + } + + /** + * In array check by callback + * + * @param mixed[] $haystack array input + * @param callable $callback callback function + * + * @return null|bool + */ + public static function inArrayExtended($haystack, $callback) + { + if (!is_callable($callback)) { + return null; + } + + foreach ($haystack as $value) { + if (call_user_func($callback, $value)) { + return true; + } + } + + return false; + } + + /** + * This is a binary recursion, so it only works on an ordered array of integers. + * (If it is not ordered, it does not work) + * + * The advantage of using this search instead of normal array search is that the complexity goes from O(n) to O(log n). + * + * @param int[] $array array values + * @param int $x element to search + * + * @return bool + */ + public static function binarySearch($array, $x) + { + if (count($array) === 0) { + return false; + } + $low = 0; + $high = count($array) - 1; + + while ($low <= $high) { + $mid = floor(($low + $high) / 2); + + if ($array[$mid] == $x) { + return true; + } + if ($x < $array[$mid]) { + $high = $mid - 1; + } else { + $low = $mid + 1; + } + } + return false; + } + + /** + * Generates a random password drawn from the defined set of characters. + * Copy of the wp_generate_password() function from wp-includes/pluggable.php with minor tweaks + * + * @param int $length Optional. The length of password to generate. Default 12. + * @param bool $special_chars Optional. Whether to include standard special characters. + * Default true. + * @param bool $extra_special_chars Optional. Whether to include other special characters. + * Used when generating secret keys and salts. Default false. + * + * @return string The random password. + */ + public static function generatePassword($length = 12, $special_chars = true, $extra_special_chars = false) + { + $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + if ($special_chars) { + $chars .= '!@#$%^&*()'; + } + if ($extra_special_chars) { + $chars .= '-_ []{}<>~`+=,.;:/?|'; + } + + $password = ''; + for ($i = 0; $i < $length; $i++) { + $password .= substr($chars, self::rand(0, strlen($chars) - 1), 1); + } + + return $password; + } + + /** + * Generates a random number + * Copy of the wp_rand() function from wp-includes/pluggable.php with minor tweaks + * + * @param int $min Lower limit for the generated number + * @param int $max Upper limit for the generated number + * + * @return int A random number between min and max + */ + public static function rand($min = 0, $max = 0) + { + global $rnd_value; + // Some misconfigured 32bit environments (Entropy PHP, for example) truncate integers + // larger than PHP_INT_MAX to PHP_INT_MAX rather than overflowing them to floats. + $max_random_number = 3000000000 === 2147483647 ? (float) "4294967295" : 4294967295; // @phpstan-ignore-line + // 4294967295 = 0xffffffff + // We only handle Ints, floats are truncated to their integer value. + $min = (int) $min; + $max = (int) $max; + // Use PHP's CSPRNG, or a compatible method + static $use_random_int_functionality = null; + if (is_null($use_random_int_functionality)) { + $use_random_int_functionality = function_exists('random_int'); + } + if ($use_random_int_functionality) { + try { + $_max = ( 0 != $max ) ? $max : $max_random_number; + // rand() can accept arguments in either order, PHP cannot. + $_max = max($min, $_max); + $_min = min($min, $_max); + // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.random_intFound + $val = random_int($_min, $_max); + if (false !== $val) { + return abs(intval($val)); + } else { // @phpstan-ignore-line + $use_random_int_functionality = false; + } + } catch (Error $e) { + $use_random_int_functionality = false; + } catch (Exception $e) { + $use_random_int_functionality = false; + } + } + + // Reset $rnd_value after 14 uses + // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value + if (strlen($rnd_value) < 8) { + static $seed = ''; + $rnd_value = md5(uniqid(microtime() . mt_rand(), true) . $seed); + $rnd_value .= sha1($rnd_value); + $rnd_value .= sha1($rnd_value . $seed); + $seed = md5($seed . $rnd_value); + } + + // Take the first 8 digits for our value + $value = substr($rnd_value, 0, 8); + // Strip the first eight, leaving the remainder for the next call to rand(). + $rnd_value = substr($rnd_value, 8); + $value = abs(hexdec($value)); + // Reduce the value to be within the min - max range + if ($max != 0) { + $value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 ); + } + + return abs(intval($value)); + } + + /** + * Returns true if the class exists, false otherwise + * + * @param string $className Name of the class to check if it exists + * @param boolean $autoload Parameter that will be passed to class_exists as second + * + * @return boolean + */ + public static function classExists($className, $autoload = true) + { + if (!class_exists($className, $autoload)) { + return false; + } + if (function_exists("ini_get")) { + $disabled = explode(',', ini_get('disable_classes')); + return in_array($className, $disabled) ? false : true; + } + // We can only suppose that it exists, can't be 100% sure, but it's the best guess + return true; + } + + /** + * Function phpinfo wrapper + * + * @see https://www.php.net/manual/en/function.phpinfo.php + * + * @param int $flags see phpinfo function flags + * + * @return bool Returns true on success or false on failure. + */ + public static function phpinfo($flags = INFO_ALL) + { + if (!function_exists('phpinfo')) { + return false; + } + return phpinfo($flags); + } + + /** + * Wrapper for set_time_limit to see if it is enabled. + * + * @since 1.6.4 + * + * @param int $limit Time limit. + * + * @return void + */ + public static function duplicatorSetTimeLimit($limit = 0) + { + + if ( + function_exists('set_time_limit') && + false === strpos(ini_get('disable_functions'), 'set_time_limit') && + ! ini_get('safe_mode') + ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved + @set_time_limit( $limit ); // @codingStandardsIgnoreLine + } + } +} diff --git a/src/Libs/Snap/SnapWP.php b/src/Libs/Snap/SnapWP.php new file mode 100644 index 00000000..821711d5 --- /dev/null +++ b/src/Libs/Snap/SnapWP.php @@ -0,0 +1,1066 @@ + initialized inside wordpress_core_files.php */ + private static $corePathList = null; + + /** + * return safe ABSPATH without last / + * perform safe function only one time + * + * @return string + */ + public static function getSafeAbsPath() + { + static $safeAbsPath = null; + + if (is_null($safeAbsPath)) { + if (defined('ABSPATH')) { + $safeAbsPath = SnapIO::safePathUntrailingslashit(ABSPATH); + } else { + $safeAbsPath = ''; + } + } + + return $safeAbsPath; + } + + + /** + * Return wp-config path or false if not found + * + * @return bool|string + */ + public static function getWPConfigPath() + { + static $configPath = null; + if (is_null($configPath)) { + $absPath = SnapIO::safePathTrailingslashit(ABSPATH, true); + $absParent = dirname($absPath) . '/'; + + if (file_exists($absPath . 'wp-config.php')) { + $configPath = $absPath . 'wp-config.php'; + } elseif (@file_exists($absParent . 'wp-config.php') && !@file_exists($absParent . 'wp-settings.php')) { + $configPath = $absParent . 'wp-config.php'; + } else { + $configPath = false; + } + } + return $configPath; + } + + + /** + * Get wordpress table info by table name + * + * @param string $table table name + * @param string $prefix wordpress prefix + * + * @return array{isCore: bool, havePrefix: bool, subsiteId: int, isMultisiteCore: bool} + */ + public static function getTableInfoByName($table, $prefix) + { + $result = array( + 'isCore' => false, + 'havePrefix' => false, + 'subsiteId' => -1, + 'isMultisiteCore' => false + ); + + if (preg_match('/^' . preg_quote($prefix, '/') . '(?:(\d+)_)?(.+)/', $table, $matches) !== 1) { + return $result; + } + + $result['havePrefix'] = true; + $nameWithoutPrefix = $matches[2]; + $result['isMultisiteCore'] = in_array($nameWithoutPrefix, self::getMultisiteTables()); + $result['isCore'] = $result['isMultisiteCore'] || in_array($nameWithoutPrefix, self::getSiteCoreTables()); + + if (is_numeric($matches[1])) { + $result['subsiteId'] = (int) $matches[1]; + } elseif (!$result['isMultisiteCore']) { + $result['subsiteId'] = 1; + } + return $result; + } + + /** + * Get the list of wp prefixes from given tables list + * + * @param string[] $tables List of table names to check for unique WP prefixes + * + * @return string[] + */ + public static function getUniqueWPTablePrefixes($tables) + { + $userPrefix = array(); + $userMetaPrefix = array(); + + foreach ($tables as $table) { + if (preg_match("/^(.*)users$/m", $table, $matches)) { + $userPrefix[] = $matches[1]; + } elseif (preg_match("/^(.*)usermeta$/m", $table, $matches)) { + $userMetaPrefix[] = $matches[1]; + } + } + + return array_intersect($userPrefix, $userMetaPrefix); + } + + /** + * Modifies the database based on specified SQL statements. + * + * Useful for creating new tables and updating existing tables to a new structure. + * + * From Wordpress dbDelta + * + * @global \wpdb $wpdb WordPress database abstraction object. + * + * @param string[]|string $queries Optional. The query to run. Can be multiple queries + * in an array, or a string of queries separated by + * semicolons. Default empty string. + * @param bool $execute Optional. Whether or not to execute the query right away. + * Default true. + * + * @return string[] Strings containing the results of the various update queries. + */ + public static function dbDelta($queries = '', $execute = true) + { + $mysqliDriver = new \mysqli_driver(); + + $defReporting = $mysqliDriver->report_mode; + mysqli_report(MYSQLI_REPORT_OFF); + + $result = dbDelta($queries, $execute); + mysqli_report($defReporting); + + return $result; + } + + /** + * Schedules cron event if it's not already scheduled. + * + * @param int $timestamp Timestamp of the first next run time + * @param string $cronIntervalName Name of cron interval to be used + * @param string $hook Hook that we want to assign to the given cron interval + * + * @return void + */ + public static function scheduleEvent($timestamp, $cronIntervalName, $hook) + { + if (!wp_next_scheduled($hook)) { + // Assign the hook to the schedule + wp_schedule_event($timestamp, $cronIntervalName, $hook); + } + } + + /** + * Unschedules cron event if it's scheduled. + * + * @param string $hook Name of the hook that we want to unschedule + * + * @return void + */ + public static function unscheduleEvent($hook) + { + if (wp_next_scheduled($hook)) { + // Unschedule the hook + $timestamp = wp_next_scheduled($hook); + wp_unschedule_event($timestamp, $hook); + } + } + + /** + * Get Auto_increment value of wp_blogs table in multisite. + * That is id of the first next subsite that will be imported. + * + * @return int // returns Auto_increment value of wp_blogs table in multisite, + * // returns -1 if Auto_increment value can not be obtained for any reason + */ + public static function getNextSubsiteIdAI() + { + $nextSubsiteIdAI = -1; + if (!is_multisite()) { + return $nextSubsiteIdAI; + } + /** @var \wpdb $wpdb */ + global $wpdb; + + $sql = $wpdb->prepare("SHOW TABLE STATUS LIKE %s", $wpdb->prefix . "blogs"); + $result = $wpdb->get_results($sql, ARRAY_A); + if (count($result) < 1) { + return $nextSubsiteIdAI; + } + $row = $result[0]; + if (array_key_exists("Auto_increment", $row)) { + $nextSubsiteIdAI = intval($row["Auto_increment"]); + } + return $nextSubsiteIdAI; + } + + /** + * From a tables list filters all tables without WP prefix + * + * @param string[] $tables tables list + * + * @return string[] + */ + public static function getTablesWithPrefix($tables) + { + /** @var \wpdb $wpdb */ + global $wpdb; + + $tables = (array) $tables; + + $result = array(); + + foreach ($tables as $table) { + if (strpos($table, $wpdb->prefix) === 0) { + $result[] = $table; + } + } + return $result; + } + + /** + * Check if passed folder is home folder + * + * @param string $folder folder path + * + * @return boolean return true if folder is wordpress home folder + */ + public static function isWpHomeFolder($folder) + { + $indexPhp = SnapIO::trailingslashit($folder) . 'index.php'; + if (!file_exists($indexPhp)) { + return false; + } + + if (($indexContent = file_get_contents($indexPhp)) === false) { + return false; + } + + return (preg_match('/^.*\srequire.*?[\'"].*wp-blog-header\.php[\'"].*?;.*$/s', $indexContent) === 1); + } + + /** + * This function is the equivalent of the get_home_path function but with various fixes + * + * @return string + */ + public static function getHomePath() + { + static $home_path = null; + + if (is_null($home_path)) { + // outside wordpress this function makes no sense + if (!defined('ABSPATH')) { + $home_path = ''; + return $home_path; + } + + if (isset($_SERVER['SCRIPT_FILENAME']) && is_readable($_SERVER['SCRIPT_FILENAME'])) { + $scriptFilename = $_SERVER['SCRIPT_FILENAME']; + } else { + $files = get_included_files(); + $scriptFilename = array_shift($files); + } + + $realScriptDirname = SnapIO::safePathTrailingslashit(dirname($scriptFilename), true); + $realAbsPath = SnapIO::safePathTrailingslashit(ABSPATH, true); + + if (strpos($realScriptDirname, $realAbsPath) === 0) { + // normalize URLs without www + $home = SnapURL::wwwRemove(set_url_scheme(get_option('home'), 'http')); + $siteurl = SnapURL::wwwRemove(set_url_scheme(get_option('siteurl'), 'http')); + + if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) { + if (stripos($siteurl, $home) === 0) { + $wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */ + $pos = strripos( + str_replace('\\', '/', $scriptFilename), + SnapIO::trailingslashit($wp_path_rel_to_home) + ); + $home_path = substr($scriptFilename, 0, $pos); + $home_path = SnapIO::trailingslashit($home_path); + } else { + $home_path = ABSPATH; + } + } else { + $home_path = ABSPATH; + } + } else { + // On frontend the home path is the folder of index.php + $home_path = SnapIO::trailingslashit(dirname($scriptFilename)); + } + + // make sure the folder exists or consider ABSPATH + if (!file_exists($home_path)) { + $home_path = ABSPATH; + } + + $home_path = str_replace('\\', '/', $home_path); + } + return $home_path; + } + + /** + * Return admin url, if is multisite return network_admin_url + * + * @param string $path Optional. Path relative to the admin URL. Default 'admin'. + * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). + * 'http' or 'https' can be passed to force those schemes. + * + * @return string Admin URL link with optional path appended. + */ + public static function getAdminUrl($path, $scheme = 'admin') + { + if (is_multisite()) { + return network_admin_url($path, $scheme); + } else { + return admin_url($path, $scheme); + } + } + + + /** + * Ser relative abs path + * + * @param string $string abs path + * + * @return void + */ + public static function setWpCoreRelativeAbsPath($string = '') + { + self::$wpCoreRelativePath = (string) $string; + } + + /** + * check if path is in wordpress core list + * PATH_FULL and PATH_RELATIVE is better optimized and perform less operations + * + * @param string $path file path + * @param int $fullPath if PATH_AUTO check if is a full path or relative path + * if PATH_FULL remove ABSPATH len without check + * if PATH_RELATIVE consider path a relative path + * @param bool $isSafe if false call rtrim(SnapIO::safePath( PATH ), '/') + * if true consider path a safe path without check + * + * @return boolean + */ + public static function isWpCore($path, $fullPath = self::PATH_AUTO, $isSafe = false) + { + if ($isSafe == false) { + $path = rtrim(SnapIO::safePath($path), '/'); + } + + switch ($fullPath) { + case self::PATH_FULL: + $absPath = self::getSafeAbsPath(); + if (strlen($path) < strlen($absPath)) { + return false; + } + $relPath = ltrim(substr($path, strlen($absPath)), '/'); + break; + case self::PATH_RELATIVE: + if (($relPath = SnapIO::getRelativePath($path, self::$wpCoreRelativePath)) === false) { + return false; + } + break; + case self::PATH_AUTO: + default: + $absPath = self::getSafeAbsPath(); + if (strpos($path, $absPath) === 0) { + $relPath = ltrim(substr($path, strlen($absPath)), '/'); + } else { + $relPath = ltrim($path, '/'); + } + } + + // if rel path is empty is consider root path so is a core folder. + if (strlen($relPath) === 0) { + return true; + } + + $pExploded = explode('/', $relPath); + $corePaths = self::getCorePathsList(); + + foreach ($pExploded as $current) { + if (!isset($corePaths[$current])) { + return false; + } + + if (is_scalar($corePaths[$current])) { + // is file so don't have childs + $corePaths = array(); + } else { + $corePaths = $corePaths[$current]; + } + } + return true; + } + + /** + * + * @param string $relPath If empty is consider abs root path + * + * @return array{dirs: string[], files: string[]} + */ + public static function getWpCoreFilesListInFolder($relPath = '') + { + $corePaths = self::getCorePathsList(); + if (strlen($relPath) > 0) { + $pExploded = explode('/', $relPath); + foreach ($pExploded as $current) { + if (!isset($corePaths[$current])) { + $corePaths = array(); + break; + } + + if (is_scalar($corePaths[$current])) { + // is file so don't have childs + $corePaths = array(); + } else { + $corePaths = $corePaths[$current]; + } + } + } + + $result = array( + 'dirs' => array(), + 'files' => array() + ); + + foreach ($corePaths as $name => $content) { + if (is_array($content)) { + $result['dirs'][] = $name; + } else { + $result['files'][] = $name; + } + } + + return $result; + } + + /** + * Get core path list from relative abs path + * [ + * 'folder' => [ + * 's-folder1' => [ + * file1 => [], + * file2 => [], + * ], + * 's-folder2' => [], + * file1 => [] + * ] + * ] + * + * @return array + */ + public static function getCorePathsList() + { + if (is_null(self::$corePathList)) { + require_once(dirname(__FILE__) . '/wordpress_core_files.php'); + } + return self::$corePathList; + } + + /** + * Get List of core folders inside the wp-content folder + * + * @return string[] + */ + public static function getWPContentCoreDirs() + { + return array( + 'languages', + 'cache' + ); + } + + /** + * Returns the main site ID for the network. + * + * Copied from the source of the get_main_site_id() except first line in https://developer.wordpress.org/reference/functions/get_main_site_id/ + * get_main_site_id() is introduced in WP 4.9.0. It is for backward compatibility + * + * @param int|null $network_id network id + * + * @return int The ID of the main site. + */ + public static function getMainSiteId($network_id = null) + { + // For > WP 4.9.0 + if (function_exists('get_main_site_id')) { + return get_main_site_id($network_id); + } + + if (!is_multisite()) { + return get_current_blog_id(); + } + + $network = function_exists('get_network') ? get_network($network_id) : wp_get_network($network_id); + if (!$network) { + return 0; + } + + return $network->site_id; + } + + /** + * Return object list of sites + * + * @param string|array $args list of filters, see wordpress get_sites function + * + * @return false|WP_Site[]|int[] site list or ids or false if isn't multisite + */ + public static function getSites($args = array()) + { + if (!function_exists('is_multisite') || !is_multisite()) { + return false; + } + + if (!isset($args['number'])) { + $args['number'] = self::DEFAULT_MAX_GET_SITES_NUMBER; + } + + if (function_exists('get_sites')) { + return get_sites($args); + } else { + $result = array(); + $blogs = wp_get_sites($args); + $returnIds = (isset($args['fields']) && $args['fields'] === 'ids'); + foreach ($blogs as $blog) { + if (is_array($blog)) { + $blog = (object) $blog; + } + $result[] = ($returnIds ? $blog->blog_id : $blog); + } + return $result; + } + } + + /** + * Return list of subiste ids + * + * @return int[] + */ + public static function getSitesIds() + { + if (!is_multisite()) { + return array(1); + } + + return SnapWP::getSites(array('fields' => 'ids')); + } + + /** + * return the list of possible dropins plugins + * + * @return string[] + */ + public static function getDropinsPluginsNames() + { + return array( + 'advanced-cache.php', // WP_CACHE + 'db.php', // auto on load + 'db-error.php', // auto on error + 'install.php', // auto on installation + 'maintenance.php', // auto on maintenance + 'object-cache.php', // auto on load + 'php-error.php', // auto on error + 'fatal-error-handler.php', // auto on error + 'sunrise.php', + 'blog-deleted.php', + 'blog-inactive.php', + 'blog-suspended.php' + ); + } + + /** + * Return site and subsite tables names without prefix + * + * @return string[] + */ + public static function getSiteCoreTables() + { + return array( + 'commentmeta', + 'comments', + 'links', + 'options', + 'postmeta', + 'posts', + 'term_relationships', + 'term_taxonomy', + 'terms', + 'termmeta' + ); + } + + /** + * Return multisite general tables without prefix + * + * @return string[] + */ + public static function getMultisiteTables() + { + return array( + 'blogmeta', + 'blogs', + 'blog_versions', + 'registration_log', + 'signups', + 'site', + 'sitemeta' + ); + } + + /** + * Returns gmt_offset * 3600 + * + * @return int timezone offset in seconds + */ + public static function getGMTOffset() + { + return get_option('gmt_offset') ? ((float) get_option('gmt_offset')) * 3600 : 0; + } + + /** + * Returns wp option "timezone_string" + * + * @return string // timezone_string, will be empty if manual offset is chosen + */ + public static function getTimeZoneString() + { + static $timezoneString = null; + if (is_null($timezoneString)) { + $timezoneString = get_option('timezone_string'); + } + return $timezoneString; + } + + /** + * Returns 1 if DST is active on given timestamp, 0 if it's not active. + * Currently active timezone is taken into account. + * + * @param int $timestamp In seconds + * + * @return int 1 if DST is active, 0 otherwise + */ + public static function getDST($timestamp) + { + $timezoneString = self::getTimeZoneString(); + if (!$timezoneString) { + // There is no DST if manual offset is chosen in WP settings timezone + return 0; + } + $date = new \DateTime(); + $date->setTimestamp($timestamp); + $date->setTimezone(new \DateTimeZone($timezoneString)); + return (int) $date->format('I'); + } + + /** + * Converts timestamp to date string with given format, according to + * currently selected timezone in Wordpress settings + * + * @param string $format Format for date + * @param int $timestamp In seconds + * + * @return string Date converted to string in currently selected timezone + */ + public static function getDateInWPTimezone($format, $timestamp) + { + $timezoneString = self::getTimeZoneString(); + if ($timezoneString) { + // Particular timezone is selected, not manual offset. This means that DST could be in place, + // and we can't use current gmt_offset. We have to use the timezone! + $date = new \DateTime(); + $date->setTimestamp($timestamp); + $date->setTimezone(new \DateTimeZone($timezoneString)); + return $date->format($format); + } + // Manual offset is selected. In this case there is no DST so we can + // create the date string using current gmt_offset. + $local_time = $timestamp + SnapWP::getGMTOffset(); + return (string) date($format, $local_time); + } + + /** + * + * @param int $blogId if multisite and blogId > 0 return the user of blog + * + * @return array + */ + public static function getAdminUserLists($blogId = 0) + { + $args = array( + 'fields' => array('ID', 'user_login') + ); + + if (is_multisite()) { + $args['blog_id'] = $blogId; + if ($blogId == 0) { + $args['login__in'] = get_site_option('site_admins'); + } + } else { + $args['role'] = 'administrator'; + } + + return get_users($args); + } + + /** + * Get users count + * + * @return int + */ + public static function getUsersCount() + { + global $wpdb; + $sql = "SELECT COUNT(ID) FROM $wpdb->users"; + return (int) $wpdb->get_var($sql); + } + + /** + * Return post types count + * + * @return array + */ + public static function getPostTypesCount() + { + $postTypes = get_post_types(); + $postTypeCount = array(); + + foreach ($postTypes as $postName) { + $postObj = get_post_type_object($postName); + if (!$postObj->public) { + continue; + } + + /** @var int[] */ + $postCountForTypes = (array) wp_count_posts($postName); + $postCount = 0; + foreach ($postCountForTypes as $num) { + $postCount += $num; + } + $postTypeCount[$postObj->label] = $postCount; + } + + return $postTypeCount; + } + + /** + * Get plugins array info with multisite, must-use and drop-ins + * + * @param string $key User meta key + * + * @return bool true on success, false on failure + */ + public static function deleteUserMetaKey($key) + { + /** @var wpdb $wpdb */ + global $wpdb; + + if ( + $wpdb->delete( + $wpdb->usermeta, + array('meta_key' => $key), + array('%s') + ) === false + ) { + return false; + } + + return true; + } + + /** + * return plugin formatted data from plugin info + * + * @param WP_Theme $theme instance of WP Core class WP_Theme. theme info from get_themes function + * + * @return array + */ + protected static function getThemeArrayData(WP_Theme $theme) + { + $slug = $theme->get_stylesheet(); + $parent = $theme->parent(); + return array( + 'slug' => $slug, + 'themeName' => $theme->get('Name'), + 'version' => $theme->get('Version'), + 'themeURI' => $theme->get('ThemeURI'), + 'parentTheme' => (false === $parent) ? false : $parent->get_stylesheet(), + 'template' => $theme->get_template(), + 'stylesheet' => $theme->get_stylesheet(), + 'description' => $theme->get('Description'), + 'author' => $theme->get('Author'), + "authorURI" => $theme->get('AuthorURI'), + 'tags' => $theme->get('Tags'), + 'isAllowed' => $theme->is_allowed(), + 'isActive' => (is_multisite() ? array() : false), + 'defaultTheme' => (defined('WP_DEFAULT_THEME') && WP_DEFAULT_THEME == $slug), + ); + } + + /** + * get themes array info with active template, stylesheet + * + * @return array + */ + public static function getThemesInfo() + { + if (!function_exists('wp_get_themes')) { + require_once ABSPATH . 'wp-admin/includes/theme.php'; + } + + $result = array(); + + foreach (wp_get_themes() as $slug => $theme) { + $result[$slug] = self::getThemeArrayData($theme); + } + + if (is_multisite()) { + foreach (SnapWP::getSitesIds() as $siteId) { + switch_to_blog($siteId); + $stylesheet = get_stylesheet(); + if (isset($result[$stylesheet])) { + $result[$stylesheet]['isActive'][] = $siteId; + } + + //Also set parent theme to active if it exists + $template = get_template(); + if ($template !== $stylesheet && isset($result[$template])) { + $result[$template]['isActive'][] = $siteId; + } + + restore_current_blog(); + } + } else { + $stylesheet = get_stylesheet(); + if (isset($result[$stylesheet])) { + $result[$stylesheet]['isActive'] = true; + } + + //Also set parent theme to active if it exists + $template = get_template(); + if ($template !== $stylesheet && isset($result[$template])) { + $result[$template]['isActive'] = true; + } + } + + return $result; + } + + /** + * Get plugins array info with multisite, must-use and drop-ins + * + * @param int $filter ENUM: PLUGIN_INFO_ALL, PLUGIN_INFO_ACTIVE, PLUGIN_INFO_INACTIVE + * + * @return array + */ + public static function getPluginsInfo($filter = self::PLUGIN_INFO_ALL) + { + if (!defined('ABSPATH')) { + throw new Exception('This function can be used only on wp'); + } + + if (!function_exists('get_plugins')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + // parse all plugins + $result = array(); + foreach (get_plugins() as $path => $plugin) { + $result[$path] = self::getPluginArrayData($path, $plugin); + $result[$path]['networkActive'] = is_plugin_active_for_network($path); + if (!is_multisite()) { + $result[$path]['active'] = is_plugin_active($path); + } else { + // if is _multisite the active value is an array with the blog ids list where the plugin is active + $result[$path]['active'] = array(); + } + } + + // If is _multisite the active value is an array with the blog ids list where the plugin is active + if (is_multisite()) { + foreach (SnapWP::getSitesIds() as $siteId) { + switch_to_blog($siteId); + foreach ($result as $path => $plugin) { + if (!$result[$path]['networkActive'] && is_plugin_active($path)) { + $result[$path]['active'][] = $siteId; + } + } + restore_current_blog(); + } + } + + // parse all must use plugins + foreach (get_mu_plugins() as $path => $plugin) { + $result[$path] = self::getPluginArrayData($path, $plugin); + $result[$path]['mustUse'] = true; + } + + // parse all dropins plugins + foreach (get_dropins() as $path => $plugin) { + $result[$path] = self::getPluginArrayData($path, $plugin); + $result[$path]['dropIns'] = true; + } + + switch ($filter) { + case self::PLUGIN_INFO_ACTIVE: + return array_filter( + $result, + function ($info) { + return SnapWP::isPluginActiveByInfo($info); + } + ); + case self::PLUGIN_INFO_INACTIVE: + return array_filter( + $result, + function ($info) { + return !SnapWP::isPluginActiveByInfo($info); + } + ); + case self::PLUGIN_INFO_ALL: + default: + return $result; + } + } + + /** + * Determine if a plugin is active by info + * + * @param array{active: bool|bool[], networkActive: bool, dropIns: bool, mustUse: bool} $info Plugin info + * + * @return bool + */ + protected static function isPluginActiveByInfo($info) + { + return ( + $info['active'] === true || + $info['networkActive'] || + ( + is_array($info['active']) && + !empty($info['active']) + ) || + $info['dropIns'] || + $info['mustUse'] + ); + } + + /** + * Check if a plugin is installed + * + * @param string $pluginSlug plugin slug + * + * @return bool + */ + public static function isPluginInstalled($pluginSlug) + { + if (!defined('ABSPATH')) { + throw new Exception('This function can be used only on wp'); + } + + if (!function_exists('get_plugins')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + $plugins = array_keys(get_plugins()); + return in_array($pluginSlug, $plugins); + } + + /** + * return plugin formatted data from plugin info + * plugin info = Array ( + * [Name] => Hello Dolly + * [PluginURI] => http://wordpress.org/extend/plugins/hello-dolly/ + * [Version] => 1.6 + * [Description] => This is not just ... + * [Author] => Matt Mullenweg + * [AuthorURI] => http://ma.tt/ + * [TextDomain] => + * [DomainPath] => + * [Network] => + * [Title] => Hello Dolly + * [AuthorName] => Matt Mullenweg + * ) + * + * @param string $slug plugin slug + * @param array $plugin pluhin info from get_plugins function + * + * @return array + */ + protected static function getPluginArrayData($slug, $plugin) + { + return array( + 'slug' => $slug, + 'name' => $plugin['Name'], + 'version' => $plugin['Version'], + 'pluginURI' => $plugin['PluginURI'], + 'author' => $plugin['Author'], + 'authorURI' => $plugin['AuthorURI'], + 'description' => $plugin['Description'], + 'title' => $plugin['Title'], + 'networkActive' => false, + 'active' => false, + 'mustUse' => false, + 'dropIns' => false + ); + } + + /** + * Retrieves the global WP_Roles instance and instantiates it if necessary. + * Added for compatibility with WP < 4.3 + * + * @return WP_Roles WP_Roles global instance if not already instantiated. + */ + public static function wpRoles() + { + if (function_exists('wp_roles')) { + return wp_roles(); + } + global $wp_roles; + if (! isset($wp_roles)) { + $wp_roles = new WP_Roles(); + } + return $wp_roles; + } +} diff --git a/src/Libs/Snap/index.php b/src/Libs/Snap/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/src/Libs/Snap/index.php @@ -0,0 +1,3 @@ +>>>>> THIS FILE IS GENERATED WITH A SCRIPT, DON'T EDIT IT DIRECTLY <<<<< + * >>>>>> USE THE GENERATOR SCRIPT <<<<< + * + * >>>>>> THIS FILE IS GENERATED WITH A SCRIPT, DON'T EDIT IT DIRECTLY <<<<< + * >>>>>> USE THE GENERATOR SCRIPT <<<<< + * + * >>>>>> THIS FILE IS GENERATED WITH A SCRIPT, DON'T EDIT IT DIRECTLY <<<<< + * >>>>>> USE THE GENERATOR SCRIPT <<<<< + */ + +defined('ABSPATH') || defined('DUPXABSPATH') || exit; + +/* + * >>>>>> THIS FILE IS GENERATED WITH A SCRIPT, DON'T EDIT IT DIRECTLY <<<<< + * >>>>>> USE THE GENERATOR SCRIPT <<<<< + * + * >>>>>> THIS FILE IS GENERATED WITH A SCRIPT, DON'T EDIT IT DIRECTLY <<<<< + * >>>>>> USE THE GENERATOR SCRIPT <<<<< + * + * >>>>>> THIS FILE IS GENERATED WITH A SCRIPT, DON'T EDIT IT DIRECTLY <<<<< + * >>>>>> USE THE GENERATOR SCRIPT <<<<< + */ + +// @phpstan-ignore-next-line +self::$corePathList = array( + 'wp-login.php' => "f", + 'wp-config-sample.php' => "f", + 'license.txt' => "f", + 'wp-activate.php' => "f", + 'wp-comments-post.php' => "f", + 'wp-signup.php' => "f", + 'wp-mail.php' => "f", + 'wp-links-opml.php' => "f", + 'wp-load.php' => "f", + 'wp-blog-header.php' => "f", + 'readme.html' => "f", + 'wp-includes' => array( + 'category-template.php' => "f", + 'class-wp-recovery-mode-email-service.php' => "f", + 'default-constants.php' => "f", + 'class-wp-http-requests-hooks.php' => "f", + 'class-wp-block-patterns-registry.php' => "f", + 'media.php' => "f", + 'block-patterns.php' => "f", + 'functions.php' => "f", + 'ms-network.php' => "f", + 'class-requests.php' => "f", + 'cache.php' => "f", + 'class-wp-dependency.php' => "f", + 'class-wp-http-proxy.php' => "f", + 'class-phpass.php' => "f", + 'ms-settings.php' => "f", + 'style-engine.php' => "f", + 'class-wp-customize-manager.php' => "f", + 'class-wp-block-styles-registry.php' => "f", + 'fonts.php' => "f", + 'class-wp-recovery-mode-key-service.php' => "f", + 'class-walker-category.php' => "f", + 'class-wp-metadata-lazyloader.php' => "f", + 'block-template-utils.php' => "f", + 'blocks.php' => "f", + 'l10n.php' => "f", + 'cron.php' => "f", + 'template.php' => "f", + 'class-wp-widget-factory.php' => "f", + 'class-wp-network.php' => "f", + 'https-migration.php' => "f", + 'nav-menu-template.php' => "f", + 'class-wp-matchesmapregex.php' => "f", + 'feed-rdf.php' => "f", + 'https-detection.php' => "f", + 'theme-previews.php' => "f", + 'widgets' => array( + 'class-wp-widget-pages.php' => "f", + 'class-wp-widget-text.php' => "f", + 'class-wp-widget-custom-html.php' => "f", + 'class-wp-widget-recent-comments.php' => "f", + 'class-wp-widget-tag-cloud.php' => "f", + 'class-wp-widget-links.php' => "f", + 'class-wp-widget-block.php' => "f", + 'class-wp-widget-media-video.php' => "f", + 'class-wp-widget-archives.php' => "f", + 'class-wp-widget-search.php' => "f", + 'class-wp-widget-calendar.php' => "f", + 'class-wp-widget-meta.php' => "f", + 'class-wp-widget-media.php' => "f", + 'class-wp-nav-menu-widget.php' => "f", + 'class-wp-widget-media-audio.php' => "f", + 'class-wp-widget-recent-posts.php' => "f", + 'class-wp-widget-categories.php' => "f", + 'class-wp-widget-rss.php' => "f", + 'class-wp-widget-media-image.php' => "f", + 'class-wp-widget-media-gallery.php' => "f", + ), + 'class-wp-paused-extensions-storage.php' => "f", + 'class-walker-page-dropdown.php' => "f", + 'class-wp-text-diff-renderer-inline.php' => "f", + 'theme-compat' => array( + 'sidebar.php' => "f", + 'embed-404.php' => "f", + 'embed-content.php' => "f", + 'footer-embed.php' => "f", + 'header-embed.php' => "f", + 'header.php' => "f", + 'footer.php' => "f", + 'embed.php' => "f", + 'comments.php' => "f", + 'comments-popup.php' => "f", + ), + 'class-phpmailer.php' => "f", + 'class-wp-post-type.php' => "f", + 'block-supports' => array( + 'elements.php' => "f", + 'layout.php' => "f", + 'dimensions.php' => "f", + 'border.php' => "f", + 'duotone.php' => "f", + 'generated-classname.php' => "f", + 'shadow.php' => "f", + 'position.php' => "f", + 'align.php' => "f", + 'colors.php' => "f", + 'background.php' => "f", + 'typography.php' => "f", + 'settings.php' => "f", + 'utils.php' => "f", + 'custom-classname.php' => "f", + 'spacing.php' => "f", + ), + 'class-wp-locale-switcher.php' => "f", + 'load.php' => "f", + 'class-wp-recovery-mode-cookie-service.php' => "f", + 'class-wp-role.php' => "f", + 'pluggable-deprecated.php' => "f", + 'class-wp-oembed-controller.php' => "f", + 'class-wp-term.php' => "f", + 'class-smtp.php' => "f", + 'capabilities.php' => "f", + 'IXR' => array( + 'class-IXR-server.php' => "f", + 'class-IXR-date.php' => "f", + 'class-IXR-request.php' => "f", + 'class-IXR-error.php' => "f", + 'class-IXR-client.php' => "f", + 'class-IXR-base64.php' => "f", + 'class-IXR-clientmulticall.php' => "f", + 'class-IXR-value.php' => "f", + 'class-IXR-message.php' => "f", + 'class-IXR-introspectionserver.php' => "f", + ), + 'class-wp-text-diff-renderer-table.php' => "f", + 'class-wp-xmlrpc-server.php' => "f", + 'class-wp-site-query.php' => "f", + 'class-wp-admin-bar.php' => "f", + 'session.php' => "f", + 'class-wp-block-type-registry.php' => "f", + 'html-api' => array( + 'class-wp-html-processor-state.php' => "f", + 'class-wp-html-processor.php' => "f", + 'class-wp-html-active-formatting-elements.php' => "f", + 'class-wp-html-text-replacement.php' => "f", + 'class-wp-html-unsupported-exception.php' => "f", + 'class-wp-html-tag-processor.php' => "f", + 'class-wp-html-open-elements.php' => "f", + 'class-wp-html-attribute-token.php' => "f", + 'class-wp-html-token.php' => "f", + 'class-wp-html-span.php' => "f", + ), + 'rewrite.php' => "f", + 'registration-functions.php' => "f", + 'option.php' => "f", + 'class-wp-styles.php' => "f", + 'class-walker-comment.php' => "f", + 'post-formats.php' => "f", + 'class-wp-customize-setting.php' => "f", + 'pluggable.php' => "f", + 'class-wp-block-type.php' => "f", + 'class-wp-http-response.php' => "f", + 'class-wp-error.php' => "f", + 'deprecated.php' => "f", + 'blocks' => array( + 'loginout' => array('block.json' => "f"), + 'pullquote' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'site-tagline.php' => "f", + 'gallery' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'code' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'comments' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'more' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'post-featured-image' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comment-content' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'social-link.php' => "f", + 'pattern' => array('block.json' => "f"), + 'query-no-results' => array('block.json' => "f"), + 'comments-pagination-previous' => array('block.json' => "f"), + 'post-navigation-link.php' => "f", + 'home-link.php' => "f", + 'image' => array( + 'style-rtl.min.css' => "f", + 'view.min.asset.php' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'view.js' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'view.min.js' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'view.asset.php' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'post-terms.php' => "f", + 'latest-posts' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-date' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'block' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'media-text' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'site-title' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'archives.php' => "f", + 'spacer' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comments-pagination-numbers.php' => "f", + 'post-author.php' => "f", + 'comments-title' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'buttons' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'video' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'cover' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-template' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'image.php' => "f", + 'heading.php' => "f", + 'template-part.php' => "f", + 'subhead' => array('block.json' => "f"), + 'site-logo' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'legacy-widget' => array('block.json' => "f"), + 'audio' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'comment-reply-link' => array('block.json' => "f"), + 'comment-date' => array('block.json' => "f"), + 'widget-group' => array('block.json' => "f"), + 'read-more' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'table' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'latest-comments.php' => "f", + 'query.php' => "f", + 'query-pagination' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'social-links' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comments-pagination-previous.php' => "f", + 'button' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'navigation-submenu.php' => "f", + 'term-description' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'rss' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'columns' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'calendar.php' => "f", + 'calendar' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'page-list-item.php' => "f", + 'page-list' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'quote' => array( + 'style-rtl.min.css' => "f", + 'theme-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'post-excerpt.php' => "f", + 'page-list-item' => array('block.json' => "f"), + 'post-comments' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comments-pagination-next.php' => "f", + 'post-navigation-link' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'query-title.php' => "f", + 'text-columns' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comment-author-name.php' => "f", + 'post-author-name' => array('block.json' => "f"), + 'post-content.php' => "f", + 'post-title.php' => "f", + 'post-comments.php' => "f", + 'query-pagination-numbers.php' => "f", + 'query-pagination-previous' => array('block.json' => "f"), + 'separator' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'archives' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-author-name.php' => "f", + 'list-item' => array('block.json' => "f"), + 'social-link' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'avatar' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'site-title.php' => "f", + 'post-template.php' => "f", + 'comment-author-name' => array('block.json' => "f"), + 'missing' => array('block.json' => "f"), + 'shortcode.php' => "f", + 'verse' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'categories' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'term-description.php' => "f", + 'post-title' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'classic' => array('block.json' => "f"), + 'post-terms' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-date.php' => "f", + 'tag-cloud' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'latest-posts.php' => "f", + 'comments-query-loop' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'rss.php' => "f", + 'require-dynamic-blocks.php' => "f", + 'query-title' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comments-pagination-numbers' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'post-author-biography' => array('block.json' => "f"), + 'embed' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'post-comments-form.php' => "f", + 'shortcode' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'query-pagination-previous.php' => "f", + 'comment-edit-link' => array('block.json' => "f"), + 'details' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'query-no-results.php' => "f", + 'comments-pagination-next' => array('block.json' => "f"), + 'file' => array( + 'style-rtl.min.css' => "f", + 'view.min.asset.php' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'view.js' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'view.min.js' => "f", + 'editor-rtl.min.css' => "f", + 'view.asset.php' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'freeform' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'footnotes.php' => "f", + 'legacy-widget.php' => "f", + 'categories.php' => "f", + 'blocks-json.php' => "f", + 'site-tagline' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'home-link' => array('block.json' => "f"), + 'read-more.php' => "f", + 'navigation-link.php' => "f", + 'index.php' => "f", + 'comment-template' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'page-list.php' => "f", + 'template-part' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'theme.min.css' => "f", + ), + 'comments-pagination.php' => "f", + 'site-logo.php' => "f", + 'comment-reply-link.php' => "f", + 'search' => array( + 'style-rtl.min.css' => "f", + 'view.min.asset.php' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'view.js' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'view.min.js' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'view.asset.php' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'list' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-excerpt' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'column' => array('block.json' => "f"), + 'group' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'theme-rtl.min.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'theme.min.css' => "f", + 'style.min.css' => "f", + ), + 'pattern.php' => "f", + 'preformatted' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comments-pagination' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'navigation-link' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'html' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'comment-content.php' => "f", + 'nextpage' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'post-featured-image.php' => "f", + 'comments.php' => "f", + 'latest-comments' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'query-pagination-next.php' => "f", + 'comment-template.php' => "f", + 'query-pagination-numbers' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'navigation-submenu' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'comment-date.php' => "f", + 'comments-title.php' => "f", + 'block.php' => "f", + 'heading' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-comments-form' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'cover.php' => "f", + 'widget-group.php' => "f", + 'gallery.php' => "f", + 'search.php' => "f", + 'post-content' => array( + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + ), + 'tag-cloud.php' => "f", + 'avatar.php' => "f", + 'footnotes' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'comment-edit-link.php' => "f", + 'navigation.php' => "f", + 'post-author' => array( + 'style-rtl.min.css' => "f", + 'block.json' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'file.php' => "f", + 'query-pagination.php' => "f", + 'require-static-blocks.php' => "f", + 'query-pagination-next' => array('block.json' => "f"), + 'query' => array( + 'style-rtl.min.css' => "f", + 'view.min.asset.php' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'view.js' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'view.min.js' => "f", + 'editor-rtl.min.css' => "f", + 'view.asset.php' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'navigation' => array( + 'style-rtl.min.css' => "f", + 'view.min.asset.php' => "f", + 'editor.min.css' => "f", + 'view-modal.js' => "f", + 'editor.css' => "f", + 'view.js' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'view.min.js' => "f", + 'view-modal.min.js' => "f", + 'view-modal.min.asset.php' => "f", + 'editor-rtl.min.css' => "f", + 'view-modal.asset.php' => "f", + 'view.asset.php' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'loginout.php' => "f", + 'paragraph' => array( + 'style-rtl.min.css' => "f", + 'editor.min.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'block.json' => "f", + 'editor-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'post-author-biography.php' => "f", + ), + 'default-filters.php' => "f", + 'ms-load.php' => "f", + 'class-wp-feed-cache.php' => "f", + 'plugin.php' => "f", + 'fonts' => array( + 'dashicons.svg' => "f", + 'dashicons.woff2' => "f", + 'dashicons.ttf' => "f", + 'class-wp-font-face-resolver.php' => "f", + 'dashicons.woff' => "f", + 'dashicons.eot' => "f", + 'class-wp-font-face.php' => "f", + ), + 'query.php' => "f", + 'class-pop3.php' => "f", + 'style-engine' => array( + 'class-wp-style-engine-css-rule.php' => "f", + 'class-wp-style-engine-css-declarations.php' => "f", + 'class-wp-style-engine.php' => "f", + 'class-wp-style-engine-css-rules-store.php' => "f", + 'class-wp-style-engine-processor.php' => "f", + ), + 'class-wp-user-request.php' => "f", + 'class-wp-user-meta-session-tokens.php' => "f", + 'class-wp-oembed.php' => "f", + 'class-wp-editor.php' => "f", + 'class-wp-image-editor-gd.php' => "f", + 'class.wp-scripts.php' => "f", + 'class-walker-nav-menu.php' => "f", + 'author-template.php' => "f", + 'ms-blogs.php' => "f", + 'class-wp-simplepie-sanitize-kses.php' => "f", + 'class-wp-walker.php' => "f", + 'taxonomy.php' => "f", + 'compat.php' => "f", + 'class-wp-block.php' => "f", + 'category.php' => "f", + 'atomlib.php' => "f", + 'class.wp-dependencies.php' => "f", + 'class-wp-recovery-mode.php' => "f", + 'Requests' => array( + 'Utility' => array( + 'CaseInsensitiveDictionary.php' => "f", + 'FilteredIterator.php' => "f", + ), + 'IDNAEncoder.php' => "f", + 'Transport' => array( + 'cURL.php' => "f", + 'fsockopen.php' => "f", + ), + 'library' => array('Requests.php' => "f"), + 'Proxy.php' => "f", + 'IPv6.php' => "f", + 'src' => array( + 'Port.php' => "f", + 'Iri.php' => "f", + 'Utility' => array( + 'CaseInsensitiveDictionary.php' => "f", + 'InputValidator.php' => "f", + 'FilteredIterator.php' => "f", + ), + 'Transport' => array( + 'Curl.php' => "f", + 'Fsockopen.php' => "f", + ), + 'Autoload.php' => "f", + 'Proxy.php' => "f", + 'Ssl.php' => "f", + 'Capability.php' => "f", + 'Exception.php' => "f", + 'Hooks.php' => "f", + 'Proxy' => array('Http.php' => "f"), + 'Response.php' => "f", + 'IdnaEncoder.php' => "f", + 'Auth' => array('Basic.php' => "f"), + 'Ipv6.php' => "f", + 'Requests.php' => "f", + 'Response' => array('Headers.php' => "f"), + 'HookManager.php' => "f", + 'Session.php' => "f", + 'Exception' => array( + 'Http.php' => "f", + 'Transport' => array('Curl.php' => "f"), + 'Http' => array( + 'Status407.php' => "f", + 'Status403.php' => "f", + 'Status410.php' => "f", + 'Status406.php' => "f", + 'Status400.php' => "f", + 'Status431.php' => "f", + 'Status503.php' => "f", + 'Status413.php' => "f", + 'Status500.php' => "f", + 'Status505.php' => "f", + 'Status402.php' => "f", + 'StatusUnknown.php' => "f", + 'Status305.php' => "f", + 'Status304.php' => "f", + 'Status511.php' => "f", + 'Status405.php' => "f", + 'Status501.php' => "f", + 'Status306.php' => "f", + 'Status404.php' => "f", + 'Status504.php' => "f", + 'Status411.php' => "f", + 'Status401.php' => "f", + 'Status418.php' => "f", + 'Status417.php' => "f", + 'Status502.php' => "f", + 'Status412.php' => "f", + 'Status428.php' => "f", + 'Status416.php' => "f", + 'Status414.php' => "f", + 'Status429.php' => "f", + 'Status415.php' => "f", + 'Status408.php' => "f", + 'Status409.php' => "f", + ), + 'ArgumentCount.php' => "f", + 'InvalidArgument.php' => "f", + 'Transport.php' => "f", + ), + 'Auth.php' => "f", + 'Cookie' => array('Jar.php' => "f"), + 'Transport.php' => "f", + 'Cookie.php' => "f", + ), + 'Exception.php' => "f", + 'Hooks.php' => "f", + 'Proxy' => array('HTTP.php' => "f"), + 'Response.php' => "f", + 'IRI.php' => "f", + 'SSL.php' => "f", + 'Auth' => array('Basic.php' => "f"), + 'Response' => array('Headers.php' => "f"), + 'Session.php' => "f", + 'Exception' => array( + 'Transport' => array('cURL.php' => "f"), + 'HTTP' => array( + '431.php' => "f", + '415.php' => "f", + '428.php' => "f", + '414.php' => "f", + '408.php' => "f", + '417.php' => "f", + '502.php' => "f", + '306.php' => "f", + '412.php' => "f", + '410.php' => "f", + '416.php' => "f", + '505.php' => "f", + '401.php' => "f", + '305.php' => "f", + '404.php' => "f", + '403.php' => "f", + '411.php' => "f", + '500.php' => "f", + '429.php' => "f", + '504.php' => "f", + '402.php' => "f", + '501.php' => "f", + '405.php' => "f", + '409.php' => "f", + '406.php' => "f", + '413.php' => "f", + '304.php' => "f", + '418.php' => "f", + '511.php' => "f", + '407.php' => "f", + '503.php' => "f", + '400.php' => "f", + 'Unknown.php' => "f", + ), + 'HTTP.php' => "f", + 'Transport.php' => "f", + ), + 'Auth.php' => "f", + 'Cookie' => array('Jar.php' => "f"), + 'Transport.php' => "f", + 'Cookie.php' => "f", + 'Hooker.php' => "f", + ), + 'robots-template.php' => "f", + 'revision.php' => "f", + 'wp-diff.php' => "f", + 'class-wp-roles.php' => "f", + 'sitemaps' => array( + 'class-wp-sitemaps-index.php' => "f", + 'class-wp-sitemaps-renderer.php' => "f", + 'class-wp-sitemaps-stylesheet.php' => "f", + 'class-wp-sitemaps-registry.php' => "f", + 'class-wp-sitemaps.php' => "f", + 'class-wp-sitemaps-provider.php' => "f", + 'providers' => array( + 'class-wp-sitemaps-posts.php' => "f", + 'class-wp-sitemaps-taxonomies.php' => "f", + 'class-wp-sitemaps-users.php' => "f", + ), + ), + 'js' => array( + 'hoverIntent.js' => "f", + 'wp-a11y.min.js' => "f", + 'media-audiovideo.js' => "f", + 'zxcvbn-async.js' => "f", + 'media-models.js' => "f", + 'twemoji.js' => "f", + 'wp-pointer.js' => "f", + 'customize-preview-nav-menus.min.js' => "f", + 'wp-pointer.min.js' => "f", + 'json2.min.js' => "f", + 'backbone.js' => "f", + 'swfupload' => array( + 'handlers.js' => "f", + 'license.txt' => "f", + 'handlers.min.js' => "f", + 'swfupload.js' => "f", + 'plugins' => array( + 'swfupload.swfobject.js' => "f", + 'swfupload.cookies.js' => "f", + 'swfupload.queue.js' => "f", + 'swfupload.speed.js' => "f", + ), + 'swfupload.swf' => "f", + ), + 'twemoji.min.js' => "f", + 'mce-view.min.js' => "f", + 'swfobject.js' => "f", + 'colorpicker.min.js' => "f", + 'wp-emoji.js' => "f", + 'customize-preview-widgets.min.js' => "f", + 'zxcvbn.min.js' => "f", + 'wp-ajax-response.js' => "f", + 'wp-util.js' => "f", + 'underscore.js' => "f", + 'wp-emoji.min.js' => "f", + 'customize-preview-nav-menus.js' => "f", + 'underscore.min.js' => "f", + 'admin-bar.min.js' => "f", + 'wp-sanitize.js' => "f", + 'imagesloaded.min.js' => "f", + 'thickbox' => array( + 'loadingAnimation.gif' => "f", + 'thickbox.css' => "f", + 'thickbox.js' => "f", + 'macFFBgHack.png' => "f", + ), + 'wplink.min.js' => "f", + 'tinymce' => array( + 'wp-mce-help.php' => "f", + 'themes' => array( + 'modern' => array( + 'theme.js' => "f", + 'theme.min.js' => "f", + ), + 'inlite' => array( + 'theme.js' => "f", + 'theme.min.js' => "f", + ), + ), + 'wp-tinymce.js' => "f", + 'langs' => array('wp-langs-en.js' => "f"), + 'wp-tinymce.js.gz' => "f", + 'license.txt' => "f", + 'utils' => array( + 'mctabs.js' => "f", + 'form_utils.js' => "f", + 'editable_selects.js' => "f", + 'validate.js' => "f", + ), + 'plugins' => array( + 'wordpress' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'directionality' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'image' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpview' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpeditimage' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'hr' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'lists' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpfullscreen' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wptextpattern' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'link' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'fullscreen' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpembed' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wplink' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpdialogs' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'textcolor' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpemoji' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'colorpicker' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'paste' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'compat3x' => array( + 'css' => array('dialog.css' => "f"), + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'charmap' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'tabfocus' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'wpgallery' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + 'media' => array( + 'plugin.js' => "f", + 'moxieplayer.swf' => "f", + 'plugin.min.js' => "f", + ), + 'wpautoresize' => array( + 'plugin.js' => "f", + 'plugin.min.js' => "f", + ), + ), + 'wp-tinymce.php' => "f", + 'tiny_mce_popup.js' => "f", + 'skins' => array( + 'wordpress' => array( + 'wp-content.css' => "f", + 'images' => array( + 'gallery-2x.png' => "f", + 'playlist-video.png' => "f", + 'more-2x.png' => "f", + 'pagebreak.png' => "f", + 'audio.png' => "f", + 'playlist-audio.png' => "f", + 'dashicon-no-alt.png' => "f", + 'dashicon-no.png' => "f", + 'dashicon-edit.png' => "f", + 'embedded.png' => "f", + 'video.png' => "f", + 'pagebreak-2x.png' => "f", + 'gallery.png' => "f", + 'more.png' => "f", + ), + ), + 'lightgray' => array( + 'content.inline.min.css' => "f", + 'content.min.css' => "f", + 'skin.ie7.min.css' => "f", + 'fonts' => array( + 'tinymce-small.json' => "f", + 'tinymce.ttf' => "f", + 'tinymce-small.svg' => "f", + 'tinymce-small.woff' => "f", + 'tinymce.json' => "f", + 'readme.md' => "f", + 'tinymce.svg' => "f", + 'tinymce.woff' => "f", + 'tinymce-small.ttf' => "f", + 'tinymce-small.eot' => "f", + 'tinymce.eot' => "f", + ), + 'img' => array( + 'loader.gif' => "f", + 'object.gif' => "f", + 'trans.gif' => "f", + 'anchor.gif' => "f", + ), + 'skin.min.css' => "f", + ), + ), + 'tinymce.min.js' => "f", + ), + 'wp-emoji-release.min.js' => "f", + 'wp-emoji-loader.min.js' => "f", + 'wp-list-revisions.min.js' => "f", + 'wp-auth-check.js' => "f", + 'api-request.min.js' => "f", + 'customize-models.js' => "f", + 'clipboard.min.js' => "f", + 'customize-preview.min.js' => "f", + 'quicktags.js' => "f", + 'wp-list-revisions.js' => "f", + 'customize-models.min.js' => "f", + 'wp-util.min.js' => "f", + 'customize-preview-widgets.js' => "f", + 'admin-bar.js' => "f", + 'wpdialog.min.js' => "f", + 'wp-lists.min.js' => "f", + 'wp-emoji-loader.js' => "f", + 'clipboard.js' => "f", + 'autosave.min.js' => "f", + 'quicktags.min.js' => "f", + 'customize-selective-refresh.js' => "f", + 'jcrop' => array( + 'Jcrop.gif' => "f", + 'jquery.Jcrop.min.js' => "f", + 'jquery.Jcrop.min.css' => "f", + ), + 'wp-backbone.js' => "f", + 'media-editor.js' => "f", + 'media-editor.min.js' => "f", + 'plupload' => array( + 'handlers.js' => "f", + 'moxie.js' => "f", + 'moxie.min.js' => "f", + 'license.txt' => "f", + 'plupload.flash.swf' => "f", + 'wp-plupload.min.js' => "f", + 'handlers.min.js' => "f", + 'plupload.full.min.js' => "f", + 'wp-plupload.js' => "f", + 'plupload.silverlight.xap' => "f", + 'plupload.js' => "f", + 'plupload.min.js' => "f", + ), + 'media-grid.js' => "f", + 'hoverintent-js.min.js' => "f", + 'media-views.min.js' => "f", + 'wp-embed.js' => "f", + 'heartbeat.min.js' => "f", + 'wp-api.min.js' => "f", + 'customize-views.js' => "f", + 'customize-loader.js' => "f", + 'autosave.js' => "f", + 'crop' => array( + 'cropper.js' => "f", + 'cropper.css' => "f", + 'marqueeHoriz.gif' => "f", + 'marqueeVert.gif' => "f", + ), + 'wp-auth-check.min.js' => "f", + 'jquery' => array( + 'jquery.js' => "f", + 'jquery.form.min.js' => "f", + 'jquery.ui.touch-punch.js' => "f", + 'jquery.table-hotkeys.js' => "f", + 'jquery.query.js' => "f", + 'jquery.hotkeys.min.js' => "f", + 'jquery-migrate.min.js' => "f", + 'jquery.schedule.js' => "f", + 'jquery.hotkeys.js' => "f", + 'suggest.js' => "f", + 'jquery-migrate.js' => "f", + 'jquery.form.js' => "f", + 'jquery.min.js' => "f", + 'ui' => array( + 'effect-bounce.js' => "f", + 'jquery.ui.dialog.min.js' => "f", + 'jquery.ui.menu.min.js' => "f", + 'autocomplete.js' => "f", + 'spinner.js' => "f", + 'progressbar.min.js' => "f", + 'jquery.ui.core.min.js' => "f", + 'datepicker.js' => "f", + 'spinner.min.js' => "f", + 'dialog.min.js' => "f", + 'effect-pulsate.js' => "f", + 'jquery.ui.position.min.js' => "f", + 'jquery.ui.effect-drop.min.js' => "f", + 'checkboxradio.js' => "f", + 'slider.js' => "f", + 'accordion.min.js' => "f", + 'effect-clip.min.js' => "f", + 'controlgroup.min.js' => "f", + 'jquery.ui.sortable.min.js' => "f", + 'jquery.ui.effect.min.js' => "f", + 'effect-explode.min.js' => "f", + 'jquery.ui.effect-transfer.min.js' => "f", + 'dialog.js' => "f", + 'jquery.ui.draggable.min.js' => "f", + 'draggable.min.js' => "f", + 'effect-fold.min.js' => "f", + 'jquery.ui.spinner.min.js' => "f", + 'accordion.js' => "f", + 'effect-fade.min.js' => "f", + 'effect-size.js' => "f", + 'droppable.min.js' => "f", + 'resizable.js' => "f", + 'effect-explode.js' => "f", + 'effect.js' => "f", + 'effect-fade.js' => "f", + 'effect.min.js' => "f", + 'effect-drop.min.js' => "f", + 'jquery.ui.effect-slide.min.js' => "f", + 'selectable.min.js' => "f", + 'effect-transfer.js' => "f", + 'tooltip.min.js' => "f", + 'effect-shake.js' => "f", + 'selectmenu.js' => "f", + 'effect-shake.min.js' => "f", + 'droppable.js' => "f", + 'effect-highlight.min.js' => "f", + 'jquery.ui.datepicker.min.js' => "f", + 'effect-drop.js' => "f", + 'effect-blind.min.js' => "f", + 'button.js' => "f", + 'effect-slide.js' => "f", + 'core.js' => "f", + 'effect-highlight.js' => "f", + 'sortable.min.js' => "f", + 'position.min.js' => "f", + 'effect-fold.js' => "f", + 'jquery.ui.effect-pulsate.min.js' => "f", + 'jquery.ui.mouse.min.js' => "f", + 'jquery.ui.effect-explode.min.js' => "f", + 'jquery.ui.autocomplete.min.js' => "f", + 'effect-size.min.js' => "f", + 'jquery.ui.effect-bounce.min.js' => "f", + 'tabs.js' => "f", + 'core.min.js' => "f", + 'jquery.ui.progressbar.min.js' => "f", + 'effect-clip.js' => "f", + 'effect-puff.min.js' => "f", + 'jquery.ui.selectable.min.js' => "f", + 'checkboxradio.min.js' => "f", + 'effect-transfer.min.js' => "f", + 'menu.min.js' => "f", + 'jquery.ui.tabs.min.js' => "f", + 'resizable.min.js' => "f", + 'effect-scale.js' => "f", + 'jquery.ui.effect-highlight.min.js' => "f", + 'jquery.ui.tooltip.min.js' => "f", + 'jquery.ui.droppable.min.js' => "f", + 'mouse.min.js' => "f", + 'jquery.ui.effect-fade.min.js' => "f", + 'controlgroup.js' => "f", + 'menu.js' => "f", + 'jquery.ui.effect-clip.min.js' => "f", + 'jquery.ui.accordion.min.js' => "f", + 'jquery.ui.resizable.min.js' => "f", + 'effect-pulsate.min.js' => "f", + 'effect-bounce.min.js' => "f", + 'widget.min.js' => "f", + 'jquery.ui.effect-blind.min.js' => "f", + 'tabs.min.js' => "f", + 'datepicker.min.js' => "f", + 'button.min.js' => "f", + 'selectmenu.min.js' => "f", + 'effect-blind.js' => "f", + 'jquery.ui.effect-shake.min.js' => "f", + 'slider.min.js' => "f", + 'effect-scale.min.js' => "f", + 'draggable.js' => "f", + 'jquery.ui.slider.min.js' => "f", + 'mouse.js' => "f", + 'progressbar.js' => "f", + 'jquery.ui.effect-scale.min.js' => "f", + 'sortable.js' => "f", + 'jquery.ui.button.min.js' => "f", + 'tooltip.js' => "f", + 'effect-slide.min.js' => "f", + 'jquery.ui.widget.min.js' => "f", + 'effect-puff.js' => "f", + 'autocomplete.min.js' => "f", + 'selectable.js' => "f", + 'jquery.ui.effect-fold.min.js' => "f", + ), + 'jquery.table-hotkeys.min.js' => "f", + 'suggest.min.js' => "f", + 'jquery.serialize-object.js' => "f", + 'jquery.masonry.min.js' => "f", + 'jquery.color.min.js' => "f", + ), + 'wpdialog.js' => "f", + 'shortcode.js' => "f", + 'colorpicker.js' => "f", + 'tw-sack.min.js' => "f", + 'heartbeat.js' => "f", + 'wp-api.js' => "f", + 'customize-base.js' => "f", + 'media-models.min.js' => "f", + 'wp-custom-header.js' => "f", + 'media-audiovideo.min.js' => "f", + 'mce-view.js' => "f", + 'media-views.js' => "f", + 'wp-embed-template.js' => "f", + 'hoverIntent.min.js' => "f", + 'wp-embed.min.js' => "f", + 'utils.min.js' => "f", + 'customize-views.min.js' => "f", + 'customize-base.min.js' => "f", + 'customize-selective-refresh.min.js' => "f", + 'wp-ajax-response.min.js' => "f", + 'zxcvbn-async.min.js' => "f", + 'wp-lists.js' => "f", + 'comment-reply.min.js' => "f", + 'wp-embed-template.min.js' => "f", + 'wp-backbone.min.js' => "f", + 'wp-a11y.js' => "f", + 'backbone.min.js' => "f", + 'dist' => array( + 'api-fetch.js' => "f", + 'notices.min.js' => "f", + 'edit-site.js' => "f", + 'data-controls.min.js' => "f", + 'wordcount.min.js' => "f", + 'edit-widgets.min.js' => "f", + 'editor.min.js' => "f", + 'rich-text.js' => "f", + 'dom.js' => "f", + 'element.js' => "f", + 'widgets.js' => "f", + 'widgets.min.js' => "f", + 'blocks.min.js' => "f", + 'components.min.js' => "f", + 'edit-widgets.js' => "f", + 'editor.js' => "f", + 'blob.min.js' => "f", + 'components.js' => "f", + 'url.js' => "f", + 'i18n.min.js' => "f", + 'router.js' => "f", + 'data-controls.js' => "f", + 'deprecated.js' => "f", + 'preferences-persistence.min.js' => "f", + 'priority-queue.js' => "f", + 'token-list.min.js' => "f", + 'reusable-blocks.js' => "f", + 'dom-ready.js' => "f", + 'a11y.min.js' => "f", + 'element.min.js' => "f", + 'undo-manager.min.js' => "f", + 'keycodes.js' => "f", + 'list-reusable-blocks.js' => "f", + 'autop.js' => "f", + 'patterns.min.js' => "f", + 'warning.js' => "f", + 'escape-html.js' => "f", + 'blob.js' => "f", + 'block-directory.min.js' => "f", + 'dom-ready.min.js' => "f", + 'annotations.js' => "f", + 'viewport.js' => "f", + 'edit-site.min.js' => "f", + 'viewport.min.js' => "f", + 'private-apis.js' => "f", + 'server-side-render.js' => "f", + 'autop.min.js' => "f", + 'compose.js' => "f", + 'plugins.js' => "f", + 'block-directory.js' => "f", + 'primitives.js' => "f", + 'block-editor.min.js' => "f", + 'primitives.min.js' => "f", + 'keyboard-shortcuts.js' => "f", + 'html-entities.min.js' => "f", + 'notices.js' => "f", + 'wordcount.js' => "f", + 'style-engine.min.js' => "f", + 'core-data.js' => "f", + 'core-commands.min.js' => "f", + 'customize-widgets.min.js' => "f", + 'compose.min.js' => "f", + 'interactivity.js' => "f", + 'warning.min.js' => "f", + 'url.min.js' => "f", + 'block-serialization-default-parser.js' => "f", + 'data.min.js' => "f", + 'edit-post.js' => "f", + 'server-side-render.min.js' => "f", + 'commands.js' => "f", + 'patterns.js' => "f", + 'redux-routine.min.js' => "f", + 'i18n.js' => "f", + 'redux-routine.js' => "f", + 'escape-html.min.js' => "f", + 'edit-post.min.js' => "f", + 'shortcode.js' => "f", + 'token-list.js' => "f", + 'preferences.js' => "f", + 'date.min.js' => "f", + 'hooks.min.js' => "f", + 'undo-manager.js' => "f", + 'html-entities.js' => "f", + 'core-data.min.js' => "f", + 'keycodes.min.js' => "f", + 'priority-queue.min.js' => "f", + 'blocks.js' => "f", + 'format-library.min.js' => "f", + 'development' => array( + 'react-refresh-runtime.js' => "f", + 'react-refresh-entry.min.js' => "f", + 'react-refresh-runtime.min.js' => "f", + 'react-refresh-entry.js' => "f", + ), + 'is-shallow-equal.min.js' => "f", + 'date.js' => "f", + 'commands.min.js' => "f", + 'list-reusable-blocks.min.js' => "f", + 'block-library.js' => "f", + 'style-engine.js' => "f", + 'private-apis.min.js' => "f", + 'plugins.min.js' => "f", + 'nux.min.js' => "f", + 'media-utils.js' => "f", + 'is-shallow-equal.js' => "f", + 'media-utils.min.js' => "f", + 'dom.min.js' => "f", + 'customize-widgets.js' => "f", + 'vendor' => array( + 'moment.min.js' => "f", + 'wp-polyfill-element-closest.min.js' => "f", + 'wp-polyfill-fetch.js' => "f", + 'wp-polyfill-node-contains.js' => "f", + 'moment.js' => "f", + 'regenerator-runtime.min.js' => "f", + 'wp-polyfill-object-fit.min.js' => "f", + 'wp-polyfill-url.js' => "f", + 'react.js' => "f", + 'wp-polyfill.min.js' => "f", + 'wp-polyfill-formdata.js' => "f", + 'wp-polyfill-element-closest.js' => "f", + 'wp-polyfill-dom-rect.min.js' => "f", + 'react.min.js' => "f", + 'wp-polyfill-dom-rect.js' => "f", + 'lodash.min.js' => "f", + 'wp-polyfill-inert.min.js' => "f", + 'wp-polyfill-fetch.min.js' => "f", + 'wp-polyfill-object-fit.js' => "f", + 'react-dom.min.js' => "f", + 'wp-polyfill-formdata.min.js' => "f", + 'wp-polyfill-node-contains.min.js' => "f", + 'react-dom.js' => "f", + 'regenerator-runtime.js' => "f", + 'wp-polyfill-url.min.js' => "f", + 'wp-polyfill.js' => "f", + 'lodash.js' => "f", + 'wp-polyfill-inert.js' => "f", + ), + 'annotations.min.js' => "f", + 'core-commands.js' => "f", + 'block-editor.js' => "f", + 'data.js' => "f", + 'preferences-persistence.js' => "f", + 'interactivity.min.js' => "f", + 'rich-text.min.js' => "f", + 'hooks.js' => "f", + 'api-fetch.min.js' => "f", + 'a11y.js' => "f", + 'block-serialization-default-parser.min.js' => "f", + 'router.min.js' => "f", + 'shortcode.min.js' => "f", + 'format-library.js' => "f", + 'block-library.min.js' => "f", + 'deprecated.min.js' => "f", + 'nux.js' => "f", + 'keyboard-shortcuts.min.js' => "f", + 'preferences.min.js' => "f", + 'reusable-blocks.min.js' => "f", + ), + 'api-request.js' => "f", + 'customize-loader.min.js' => "f", + 'imgareaselect' => array( + 'jquery.imgareaselect.js' => "f", + 'jquery.imgareaselect.min.js' => "f", + 'border-anim-v.gif' => "f", + 'border-anim-h.gif' => "f", + 'imgareaselect.css' => "f", + ), + 'customize-preview.js' => "f", + 'utils.js' => "f", + 'wplink.js' => "f", + 'comment-reply.js' => "f", + 'mediaelement' => array( + 'controls.png' => "f", + 'mediaelement-migrate.js' => "f", + 'renderers' => array( + 'vimeo.js' => "f", + 'vimeo.min.js' => "f", + ), + 'mediaelement-migrate.min.js' => "f", + 'mediaelementplayer-legacy.min.css' => "f", + 'jumpforward.png' => "f", + 'skipback.png' => "f", + 'wp-mediaelement.css' => "f", + 'background.png' => "f", + 'mediaelement-and-player.min.js' => "f", + 'mediaelement.min.js' => "f", + 'mejs-controls.svg' => "f", + 'mediaelementplayer.min.css' => "f", + 'bigplay.png' => "f", + 'controls.svg' => "f", + 'wp-mediaelement.js' => "f", + 'mediaelement.js' => "f", + 'mediaelementplayer-legacy.css' => "f", + 'mejs-controls.png' => "f", + 'mediaelement-and-player.js' => "f", + 'wp-mediaelement.min.js' => "f", + 'wp-playlist.js' => "f", + 'bigplay.svg' => "f", + 'wp-mediaelement.min.css' => "f", + 'mediaelementplayer.css' => "f", + 'wp-playlist.min.js' => "f", + 'loading.gif' => "f", + 'froogaloop.min.js' => "f", + ), + 'media-grid.min.js' => "f", + 'wp-custom-header.min.js' => "f", + 'masonry.min.js' => "f", + 'shortcode.min.js' => "f", + 'wp-sanitize.min.js' => "f", + 'tw-sack.js' => "f", + 'json2.js' => "f", + 'codemirror' => array( + 'esprima.js' => "f", + 'htmlhint-kses.js' => "f", + 'csslint.js' => "f", + 'jsonlint.js' => "f", + 'codemirror.min.css' => "f", + 'codemirror.min.js' => "f", + 'fakejshint.js' => "f", + 'htmlhint.js' => "f", + 'jshint.js' => "f", + ), + ), + 'css' => array( + 'wp-embed-template.min.css' => "f", + 'admin-bar-rtl.css' => "f", + 'wp-auth-check.min.css' => "f", + 'buttons.min.css' => "f", + 'wp-embed-template-ie.min.css' => "f", + 'dashicons.css' => "f", + 'buttons.css' => "f", + 'editor.min.css' => "f", + 'buttons-rtl.css' => "f", + 'jquery-ui-dialog.css' => "f", + 'dashicons.min.css' => "f", + 'jquery-ui-dialog-rtl.min.css' => "f", + 'wp-embed-template-ie.css' => "f", + 'customize-preview.css' => "f", + 'editor.css' => "f", + 'editor-rtl.css' => "f", + 'admin-bar.min.css' => "f", + 'wp-auth-check-rtl.min.css' => "f", + 'admin-bar-rtl.min.css' => "f", + 'wp-pointer.min.css' => "f", + 'wp-pointer-rtl.css' => "f", + 'admin-bar.css' => "f", + 'customize-preview-rtl.min.css' => "f", + 'jquery-ui-dialog.min.css' => "f", + 'wp-pointer-rtl.min.css' => "f", + 'wp-pointer.css' => "f", + 'classic-themes.css' => "f", + 'editor-rtl.min.css' => "f", + 'media-views.min.css' => "f", + 'customize-preview-rtl.css' => "f", + 'media-views-rtl.min.css' => "f", + 'buttons-rtl.min.css' => "f", + 'jquery-ui-dialog-rtl.css' => "f", + 'wp-embed-template.css' => "f", + 'dist' => array( + 'widgets' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'commands' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'customize-widgets' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'list-reusable-blocks' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'reusable-blocks' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'format-library' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'nux' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'edit-post' => array( + 'style-rtl.min.css' => "f", + 'classic-rtl.min.css' => "f", + 'classic.min.css' => "f", + 'style.css' => "f", + 'classic-rtl.css' => "f", + 'style-rtl.css' => "f", + 'classic.css' => "f", + 'style.min.css' => "f", + ), + 'block-directory' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'editor' => array( + 'style-rtl.min.css' => "f", + 'editor-styles-rtl.css' => "f", + 'editor-styles-rtl.min.css' => "f", + 'editor-styles.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'editor-styles.css' => "f", + 'style.min.css' => "f", + ), + 'edit-site' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'block-library' => array( + 'style-rtl.min.css' => "f", + 'reset.min.css' => "f", + 'elements.min.css' => "f", + 'elements-rtl.css' => "f", + 'editor.min.css' => "f", + 'elements-rtl.min.css' => "f", + 'editor-elements-rtl.min.css' => "f", + 'common.min.css' => "f", + 'classic-rtl.min.css' => "f", + 'editor.css' => "f", + 'theme-rtl.css' => "f", + 'editor-rtl.css' => "f", + 'common-rtl.min.css' => "f", + 'theme-rtl.min.css' => "f", + 'reset-rtl.min.css' => "f", + 'reset-rtl.css' => "f", + 'classic.min.css' => "f", + 'editor-rtl.min.css' => "f", + 'theme.css' => "f", + 'editor-elements.min.css' => "f", + 'elements.css' => "f", + 'style.css' => "f", + 'classic-rtl.css' => "f", + 'style-rtl.css' => "f", + 'classic.css' => "f", + 'common.css' => "f", + 'common-rtl.css' => "f", + 'theme.min.css' => "f", + 'editor-elements.css' => "f", + 'reset.css' => "f", + 'style.min.css' => "f", + 'editor-elements-rtl.css' => "f", + ), + 'patterns' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'edit-widgets' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + 'block-editor' => array( + 'style-rtl.min.css' => "f", + 'default-editor-styles-rtl.css' => "f", + 'content.min.css' => "f", + 'default-editor-styles.css' => "f", + 'content-rtl.css' => "f", + 'content-rtl.min.css' => "f", + 'content.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'default-editor-styles.min.css' => "f", + 'style.min.css' => "f", + 'default-editor-styles-rtl.min.css' => "f", + ), + 'components' => array( + 'style-rtl.min.css' => "f", + 'style.css' => "f", + 'style-rtl.css' => "f", + 'style.min.css' => "f", + ), + ), + 'media-views-rtl.css' => "f", + 'customize-preview.min.css' => "f", + 'wp-auth-check.css' => "f", + 'media-views.css' => "f", + 'classic-themes.min.css' => "f", + 'wp-auth-check-rtl.css' => "f", + ), + 'bookmark-template.php' => "f", + 'rest-api.php' => "f", + 'theme-templates.php' => "f", + 'class-http.php' => "f", + 'php-compat' => array('readonly.php' => "f"), + 'post-template.php' => "f", + 'user.php' => "f", + 'class-wp-comment.php' => "f", + 'class-wp-customize-section.php' => "f", + 'registration.php' => "f", + 'Text' => array( + 'Diff.php' => "f", + 'Diff' => array( + 'Engine' => array( + 'string.php' => "f", + 'xdiff.php' => "f", + 'native.php' => "f", + 'shell.php' => "f", + ), + 'Renderer.php' => "f", + 'Renderer' => array('inline.php' => "f"), + ), + ), + 'class-json.php' => "f", + 'shortcodes.php' => "f", + 'class-wp-theme-json-schema.php' => "f", + 'vars.php' => "f", + 'spl-autoload-compat.php' => "f", + 'template-canvas.php' => "f", + 'class-wp-taxonomy.php' => "f", + 'class-wp-site.php' => "f", + 'post.php' => "f", + 'version.php' => "f", + 'ms-files.php' => "f", + 'block-i18n.json' => "f", + 'certificates' => array('ca-bundle.crt' => "f"), + 'navigation-fallback.php' => "f", + 'admin-bar.php' => "f", + 'class-wp-meta-query.php' => "f", + 'link-template.php' => "f", + 'class-snoopy.php' => "f", + 'class-wp-scripts.php' => "f", + 'class-wp-image-editor.php' => "f", + 'class-wp-widget.php' => "f", + 'feed-atom-comments.php' => "f", + 'class-wp-http-streams.php' => "f", + 'functions.wp-scripts.php' => "f", + 'rss.php' => "f", + 'PHPMailer' => array( + 'PHPMailer.php' => "f", + 'Exception.php' => "f", + 'SMTP.php' => "f", + ), + 'class-wp-feed-cache-transient.php' => "f", + 'class-wp-user.php' => "f", + 'post-thumbnail-template.php' => "f", + 'class-wp-recovery-mode-link-service.php' => "f", + 'class-IXR.php' => "f", + 'general-template.php' => "f", + 'ms-site.php' => "f", + 'wlwmanifest.xml' => "f", + 'class-wp-session-tokens.php' => "f", + 'rest-api' => array( + 'class-wp-rest-response.php' => "f", + 'fields' => array( + 'class-wp-rest-term-meta-fields.php' => "f", + 'class-wp-rest-post-meta-fields.php' => "f", + 'class-wp-rest-meta-fields.php' => "f", + 'class-wp-rest-user-meta-fields.php' => "f", + 'class-wp-rest-comment-meta-fields.php' => "f", + ), + 'endpoints' => array( + 'class-wp-rest-edit-site-export-controller.php' => "f", + 'class-wp-rest-global-styles-revisions-controller.php' => "f", + 'class-wp-rest-block-patterns-controller.php' => "f", + 'class-wp-rest-menu-locations-controller.php' => "f", + 'class-wp-rest-block-renderer-controller.php' => "f", + 'class-wp-rest-block-types-controller.php' => "f", + 'class-wp-rest-taxonomies-controller.php' => "f", + 'class-wp-rest-search-controller.php' => "f", + 'class-wp-rest-terms-controller.php' => "f", + 'class-wp-rest-template-autosaves-controller.php' => "f", + 'class-wp-rest-url-details-controller.php' => "f", + 'class-wp-rest-widget-types-controller.php' => "f", + 'class-wp-rest-autosaves-controller.php' => "f", + 'class-wp-rest-posts-controller.php' => "f", + 'class-wp-rest-blocks-controller.php' => "f", + 'class-wp-rest-block-directory-controller.php' => "f", + 'class-wp-rest-settings-controller.php' => "f", + 'class-wp-rest-pattern-directory-controller.php' => "f", + 'class-wp-rest-block-pattern-categories-controller.php' => "f", + 'class-wp-rest-widgets-controller.php' => "f", + 'class-wp-rest-menu-items-controller.php' => "f", + 'class-wp-rest-post-statuses-controller.php' => "f", + 'class-wp-rest-templates-controller.php' => "f", + 'class-wp-rest-post-types-controller.php' => "f", + 'class-wp-rest-comments-controller.php' => "f", + 'class-wp-rest-themes-controller.php' => "f", + 'class-wp-rest-global-styles-controller.php' => "f", + 'class-wp-rest-application-passwords-controller.php' => "f", + 'class-wp-rest-plugins-controller.php' => "f", + 'class-wp-rest-attachments-controller.php' => "f", + 'class-wp-rest-revisions-controller.php' => "f", + 'class-wp-rest-sidebars-controller.php' => "f", + 'class-wp-rest-template-revisions-controller.php' => "f", + 'class-wp-rest-menus-controller.php' => "f", + 'class-wp-rest-site-health-controller.php' => "f", + 'class-wp-rest-users-controller.php' => "f", + 'class-wp-rest-controller.php' => "f", + 'class-wp-rest-navigation-fallback-controller.php' => "f", + ), + 'search' => array( + 'class-wp-rest-search-handler.php' => "f", + 'class-wp-rest-post-search-handler.php' => "f", + 'class-wp-rest-post-format-search-handler.php' => "f", + 'class-wp-rest-term-search-handler.php' => "f", + ), + 'class-wp-rest-server.php' => "f", + 'class-wp-rest-request.php' => "f", + ), + 'media-template.php' => "f", + 'class-wp.php' => "f", + 'images' => array( + 'blank.gif' => "f", + 'wpicons-2x.png' => "f", + 'toggle-arrow.png' => "f", + 'rss.png' => "f", + 'w-logo-blue-white-bg.png' => "f", + 'xit-2x.gif' => "f", + 'uploader-icons-2x.png' => "f", + 'wlw' => array( + 'wp-comments.png' => "f", + 'wp-watermark.png' => "f", + 'wp-icon.png' => "f", + ), + 'arrow-pointer-blue.png' => "f", + 'down_arrow.gif' => "f", + 'admin-bar-sprite-2x.png' => "f", + 'crystal' => array( + 'document.png' => "f", + 'audio.png' => "f", + 'license.txt' => "f", + 'default.png' => "f", + 'text.png' => "f", + 'interactive.png' => "f", + 'spreadsheet.png' => "f", + 'archive.png' => "f", + 'video.png' => "f", + 'code.png' => "f", + ), + 'uploader-icons.png' => "f", + 'w-logo-blue.png' => "f", + 'down_arrow-2x.gif' => "f", + 'xit.gif' => "f", + 'wpspin-2x.gif' => "f", + 'wpicons.png' => "f", + 'arrow-pointer-blue-2x.png' => "f", + 'toggle-arrow-2x.png' => "f", + 'rss-2x.png' => "f", + 'media' => array( + 'document.png' => "f", + 'audio.png' => "f", + 'default.png' => "f", + 'text.png' => "f", + 'interactive.png' => "f", + 'spreadsheet.png' => "f", + 'archive.png' => "f", + 'video.png' => "f", + 'code.png' => "f", + ), + 'spinner-2x.gif' => "f", + 'smilies' => array( + 'icon_sad.gif' => "f", + 'icon_question.gif' => "f", + 'mrgreen.png' => "f", + 'icon_mrgreen.gif' => "f", + 'icon_surprised.gif' => "f", + 'frownie.png' => "f", + 'icon_razz.gif' => "f", + 'simple-smile.png' => "f", + 'icon_neutral.gif' => "f", + 'icon_eek.gif' => "f", + 'icon_confused.gif' => "f", + 'icon_biggrin.gif' => "f", + 'icon_exclaim.gif' => "f", + 'icon_idea.gif' => "f", + 'icon_mad.gif' => "f", + 'icon_cool.gif' => "f", + 'icon_rolleyes.gif' => "f", + 'rolleyes.png' => "f", + 'icon_redface.gif' => "f", + 'icon_wink.gif' => "f", + 'icon_lol.gif' => "f", + 'icon_arrow.gif' => "f", + 'icon_evil.gif' => "f", + 'icon_cry.gif' => "f", + 'icon_smile.gif' => "f", + 'icon_twisted.gif' => "f", + ), + 'spinner.gif' => "f", + 'admin-bar-sprite.png' => "f", + 'icon-pointer-flag.png' => "f", + 'icon-pointer-flag-2x.png' => "f", + 'wpspin.gif' => "f", + ), + 'template-loader.php' => "f", + 'class-wp-embed.php' => "f", + 'rss-functions.php' => "f", + 'class-wp-http-requests-response.php' => "f", + 'class-wp-ajax-response.php' => "f", + 'date.php' => "f", + 'class-wpdb.php' => "f", + 'class-wp-simplepie-file.php' => "f", + 'class-wp-theme-json-resolver.php' => "f", + 'meta.php' => "f", + 'kses.php' => "f", + 'class-wp-tax-query.php' => "f", + 'class-wp-network-query.php' => "f", + 'class-wp-hook.php' => "f", + 'ms-deprecated.php' => "f", + 'class-walker-category-dropdown.php' => "f", + 'class-wp-rewrite.php' => "f", + 'class-simplepie.php' => "f", + 'class.wp-styles.php' => "f", + 'class-wp-block-supports.php' => "f", + 'comment.php' => "f", + 'class-wp-theme-json-data.php' => "f", + 'class-wp-duotone.php' => "f", + 'class-wp-block-parser-frame.php' => "f", + 'sitemaps.php' => "f", + 'block-editor.php' => "f", + 'pomo' => array( + 'entry.php' => "f", + 'mo.php' => "f", + 'translations.php' => "f", + 'streams.php' => "f", + 'po.php' => "f", + 'plural-forms.php' => "f", + ), + 'class-wp-customize-panel.php' => "f", + 'class-wp-http-cookie.php' => "f", + 'ms-default-filters.php' => "f", + 'class-walker-page.php' => "f", + 'bookmark.php' => "f", + 'customize' => array( + 'class-wp-customize-background-image-setting.php' => "f", + 'class-wp-customize-nav-menu-setting.php' => "f", + 'class-wp-customize-filter-setting.php' => "f", + 'class-wp-customize-date-time-control.php' => "f", + 'class-wp-customize-header-image-control.php' => "f", + 'class-wp-customize-nav-menus-panel.php' => "f", + 'class-wp-customize-nav-menu-item-control.php' => "f", + 'class-wp-customize-nav-menu-control.php' => "f", + 'class-wp-customize-custom-css-setting.php' => "f", + 'class-wp-widget-form-customize-control.php' => "f", + 'class-wp-customize-code-editor-control.php' => "f", + 'class-wp-widget-area-customize-control.php' => "f", + 'class-wp-customize-new-menu-control.php' => "f", + 'class-wp-customize-theme-control.php' => "f", + 'class-wp-customize-new-menu-section.php' => "f", + 'class-wp-customize-site-icon-control.php' => "f", + 'class-wp-customize-cropped-image-control.php' => "f", + 'class-wp-customize-upload-control.php' => "f", + 'class-wp-customize-image-control.php' => "f", + 'class-wp-customize-nav-menu-section.php' => "f", + 'class-wp-sidebar-block-editor-control.php' => "f", + 'class-wp-customize-background-image-control.php' => "f", + 'class-wp-customize-header-image-setting.php' => "f", + 'class-wp-customize-nav-menu-location-control.php' => "f", + 'class-wp-customize-partial.php' => "f", + 'class-wp-customize-nav-menu-auto-add-control.php' => "f", + 'class-wp-customize-sidebar-section.php' => "f", + 'class-wp-customize-themes-section.php' => "f", + 'class-wp-customize-themes-panel.php' => "f", + 'class-wp-customize-nav-menu-item-setting.php' => "f", + 'class-wp-customize-nav-menu-name-control.php' => "f", + 'class-wp-customize-nav-menu-locations-control.php' => "f", + 'class-wp-customize-background-position-control.php' => "f", + 'class-wp-customize-color-control.php' => "f", + 'class-wp-customize-media-control.php' => "f", + 'class-wp-customize-selective-refresh.php' => "f", + ), + 'class-wp-customize-control.php' => "f", + 'class-wp-locale.php' => "f", + 'class-wp-navigation-fallback.php' => "f", + 'theme.php' => "f", + 'class-wp-user-query.php' => "f", + 'class-wp-http-ixr-client.php' => "f", + 'ms-functions.php' => "f", + 'SimplePie' => array( + 'Locator.php' => "f", + 'Author.php' => "f", + 'Sanitize.php' => "f", + 'Registry.php' => "f", + 'Caption.php' => "f", + 'HTTP' => array('Parser.php' => "f"), + 'Item.php' => "f", + 'Exception.php' => "f", + 'File.php' => "f", + 'Rating.php' => "f", + 'Restriction.php' => "f", + 'IRI.php' => "f", + 'Parser.php' => "f", + 'Enclosure.php' => "f", + 'Cache.php' => "f", + 'XML' => array( + 'Declaration' => array('Parser.php' => "f"), + ), + 'Decode' => array( + 'HTML' => array('Entities.php' => "f"), + ), + 'Misc.php' => "f", + 'Copyright.php' => "f", + 'Parse' => array('Date.php' => "f"), + 'Content' => array( + 'Type' => array('Sniffer.php' => "f"), + ), + 'Source.php' => "f", + 'Net' => array('IPv6.php' => "f"), + 'Credit.php' => "f", + 'Cache' => array( + 'DB.php' => "f", + 'Memcache.php' => "f", + 'MySQL.php' => "f", + 'Redis.php' => "f", + 'File.php' => "f", + 'Base.php' => "f", + 'Memcached.php' => "f", + ), + 'Core.php' => "f", + 'gzdecode.php' => "f", + 'Category.php' => "f", + ), + 'class-wp-textdomain-registry.php' => "f", + 'class-oembed.php' => "f", + 'class-wp-object-cache.php' => "f", + 'class-wp-dependencies.php' => "f", + 'assets' => array( + 'script-loader-react-refresh-runtime.php' => "f", + 'script-loader-react-refresh-entry.min.php' => "f", + 'script-loader-packages.min.php' => "f", + 'script-loader-react-refresh-runtime.min.php' => "f", + 'script-loader-packages.php' => "f", + 'script-loader-react-refresh-entry.php' => "f", + ), + 'class-feed.php' => "f", + 'class-wp-term-query.php' => "f", + 'class-wp-application-passwords.php' => "f", + 'class-wp-fatal-error-handler.php' => "f", + 'ms-default-constants.php' => "f", + 'feed-rss2.php' => "f", + 'locale.php' => "f", + 'class-wp-list-util.php' => "f", + 'embed.php' => "f", + 'class-wp-customize-widgets.php' => "f", + 'class-wp-block-template.php' => "f", + 'feed-rss2-comments.php' => "f", + 'default-widgets.php' => "f", + 'class-wp-http.php' => "f", + 'class-wp-block-parser.php' => "f", + 'class-wp-classic-to-block-menu-converter.php' => "f", + 'error-protection.php' => "f", + 'ID3' => array( + 'getid3.lib.php' => "f", + 'module.tag.lyrics3.php' => "f", + 'license.commercial.txt' => "f", + 'module.audio.dts.php' => "f", + 'license.txt' => "f", + 'getid3.php' => "f", + 'module.audio.ac3.php' => "f", + 'module.audio.flac.php' => "f", + 'module.tag.apetag.php' => "f", + 'module.audio-video.matroska.php' => "f", + 'module.audio-video.quicktime.php' => "f", + 'module.audio.ogg.php' => "f", + 'module.audio.mp3.php' => "f", + 'module.audio-video.flv.php' => "f", + 'readme.txt' => "f", + 'module.tag.id3v2.php' => "f", + 'module.audio-video.riff.php' => "f", + 'module.audio-video.asf.php' => "f", + 'module.tag.id3v1.php' => "f", + ), + 'global-styles-and-settings.php' => "f", + 'embed-template.php' => "f", + 'update.php' => "f", + 'class-wp-block-editor-context.php' => "f", + 'theme.json' => "f", + 'comment-template.php' => "f", + 'nav-menu.php' => "f", + 'class-wp-query.php' => "f", + 'widgets.php' => "f", + 'formatting.php' => "f", + 'http.php' => "f", + 'class-wp-http-curl.php' => "f", + 'class-wp-block-pattern-categories-registry.php' => "f", + 'cache-compat.php' => "f", + 'feed-atom.php' => "f", + 'block-template.php' => "f", + 'feed.php' => "f", + 'class-wp-block-list.php' => "f", + 'class-wp-customize-nav-menus.php' => "f", + 'class-wp-http-encoding.php' => "f", + 'class-wp-theme.php' => "f", + 'canonical.php' => "f", + 'sodium_compat' => array( + 'lib' => array( + 'namespaced.php' => "f", + 'constants.php' => "f", + 'php72compat_const.php' => "f", + 'sodium_compat.php' => "f", + 'php72compat.php' => "f", + 'stream-xchacha20.php' => "f", + 'ristretto255.php' => "f", + ), + 'autoload-php7.php' => "f", + 'src' => array( + 'Core32' => array( + 'Salsa20.php' => "f", + 'Util.php' => "f", + 'BLAKE2b.php' => "f", + 'HSalsa20.php' => "f", + 'SipHash.php' => "f", + 'Poly1305' => array('State.php' => "f"), + 'XSalsa20.php' => "f", + 'Poly1305.php' => "f", + 'X25519.php' => "f", + 'Int64.php' => "f", + 'Curve25519.php' => "f", + 'Int32.php' => "f", + 'HChaCha20.php' => "f", + 'Curve25519' => array( + 'Fe.php' => "f", + 'H.php' => "f", + 'Ge' => array( + 'Precomp.php' => "f", + 'P2.php' => "f", + 'P1p1.php' => "f", + 'Cached.php' => "f", + 'P3.php' => "f", + ), + 'README.md' => "f", + ), + 'ChaCha20.php' => "f", + 'XChaCha20.php' => "f", + 'Ed25519.php' => "f", + 'ChaCha20' => array( + 'Ctx.php' => "f", + 'IetfCtx.php' => "f", + ), + 'SecretStream' => array('State.php' => "f"), + ), + 'Compat.php' => "f", + 'Crypto32.php' => "f", + 'File.php' => "f", + 'Core' => array( + 'Salsa20.php' => "f", + 'Util.php' => "f", + 'BLAKE2b.php' => "f", + 'HSalsa20.php' => "f", + 'SipHash.php' => "f", + 'Base64' => array( + 'UrlSafe.php' => "f", + 'Original.php' => "f", + 'Common.php' => "f", + ), + 'Poly1305' => array('State.php' => "f"), + 'XSalsa20.php' => "f", + 'Poly1305.php' => "f", + 'X25519.php' => "f", + 'Curve25519.php' => "f", + 'HChaCha20.php' => "f", + 'Curve25519' => array( + 'Fe.php' => "f", + 'H.php' => "f", + 'Ge' => array( + 'Precomp.php' => "f", + 'P2.php' => "f", + 'P1p1.php' => "f", + 'Cached.php' => "f", + 'P3.php' => "f", + ), + 'README.md' => "f", + ), + 'Ristretto255.php' => "f", + 'ChaCha20.php' => "f", + 'XChaCha20.php' => "f", + 'Ed25519.php' => "f", + 'ChaCha20' => array( + 'Ctx.php' => "f", + 'IetfCtx.php' => "f", + ), + 'SecretStream' => array('State.php' => "f"), + ), + 'Crypto.php' => "f", + 'SodiumException.php' => "f", + 'PHP52' => array('SplFixedArray.php' => "f"), + ), + 'composer.json' => "f", + 'namespaced' => array( + 'Compat.php' => "f", + 'File.php' => "f", + 'Core' => array( + 'Salsa20.php' => "f", + 'Util.php' => "f", + 'BLAKE2b.php' => "f", + 'HSalsa20.php' => "f", + 'SipHash.php' => "f", + 'Poly1305' => array('State.php' => "f"), + 'Poly1305.php' => "f", + 'X25519.php' => "f", + 'Curve25519.php' => "f", + 'Xsalsa20.php' => "f", + 'HChaCha20.php' => "f", + 'Curve25519' => array( + 'Fe.php' => "f", + 'H.php' => "f", + 'Ge' => array( + 'Precomp.php' => "f", + 'P2.php' => "f", + 'P1p1.php' => "f", + 'Cached.php' => "f", + 'P3.php' => "f", + ), + ), + 'ChaCha20.php' => "f", + 'XChaCha20.php' => "f", + 'Ed25519.php' => "f", + 'ChaCha20' => array( + 'Ctx.php' => "f", + 'IetfCtx.php' => "f", + ), + ), + 'Crypto.php' => "f", + ), + 'autoload.php' => "f", + 'LICENSE' => "f", + ), + 'class-wp-post.php' => "f", + 'random_compat' => array( + 'random_bytes_dev_urandom.php' => "f", + 'random_bytes_libsodium.php' => "f", + 'random_bytes_libsodium_legacy.php' => "f", + 'error_polyfill.php' => "f", + 'random_bytes_openssl.php' => "f", + 'random.php' => "f", + 'random_bytes_mcrypt.php' => "f", + 'cast_to_int.php' => "f", + 'random_int.php' => "f", + 'random_bytes_com_dotnet.php' => "f", + 'byte_safe_strings.php' => "f", + ), + 'feed-rss.php' => "f", + 'class-wp-date-query.php' => "f", + 'functions.wp-styles.php' => "f", + 'script-loader.php' => "f", + 'class-wp-image-editor-imagick.php' => "f", + 'block-patterns' => array( + 'quote.php' => "f", + 'heading-paragraph.php' => "f", + 'query-grid-posts.php' => "f", + 'text-two-columns.php' => "f", + 'social-links-shared-background-color.php' => "f", + 'query-medium-posts.php' => "f", + 'query-offset-posts.php' => "f", + 'text-two-columns-with-images.php' => "f", + 'text-three-columns-buttons.php' => "f", + 'query-small-posts.php' => "f", + 'three-buttons.php' => "f", + 'large-header-button.php' => "f", + 'two-buttons.php' => "f", + 'large-header.php' => "f", + 'query-standard-posts.php' => "f", + 'two-images.php' => "f", + 'query-large-title-posts.php' => "f", + ), + 'theme-i18n.json' => "f", + 'class-wp-theme-json.php' => "f", + 'class-wp-comment-query.php' => "f", + 'wp-db.php' => "f", + 'class-wp-block-parser-block.php' => "f", + ), + 'wp-cron.php' => "f", + 'index.php' => "f", + 'xmlrpc.php' => "f", + 'wp-settings.php' => "f", + 'wp-trackback.php' => "f", + 'wp-admin' => array( + 'export.php' => "f", + 'media.php' => "f", + 'media-new.php' => "f", + 'freedoms.php' => "f", + 'my-sites.php' => "f", + 'edit-tags.php' => "f", + 'erase-personal-data.php' => "f", + 'edit-link-form.php' => "f", + 'ms-users.php' => "f", + 'customize.php' => "f", + 'user-new.php' => "f", + 'about.php' => "f", + 'export-personal-data.php' => "f", + 'edit-form-blocks.php' => "f", + 'load-scripts.php' => "f", + 'theme-editor.php' => "f", + 'load-styles.php' => "f", + 'setup-config.php' => "f", + 'upload.php' => "f", + 'tools.php' => "f", + 'upgrade.php' => "f", + 'contribute.php' => "f", + 'edit-form-comment.php' => "f", + 'options-privacy.php' => "f", + 'themes.php' => "f", + 'users.php' => "f", + 'edit.php' => "f", + 'options-writing.php' => "f", + 'credits.php' => "f", + 'includes' => array( + 'class-custom-image-header.php' => "f", + 'image-edit.php' => "f", + 'export.php' => "f", + 'ms.php' => "f", + 'media.php' => "f", + 'class-wp-theme-install-list-table.php' => "f", + 'class-bulk-upgrader-skin.php' => "f", + 'class-wp-ms-themes-list-table.php' => "f", + 'class-wp-plugins-list-table.php' => "f", + 'class-wp-upgrader-skins.php' => "f", + 'class-wp-links-list-table.php' => "f", + 'class-walker-nav-menu-checklist.php' => "f", + 'class-wp-ms-users-list-table.php' => "f", + 'class-wp-privacy-data-export-requests-list-table.php' => "f", + 'class-bulk-theme-upgrader-skin.php' => "f", + 'template.php' => "f", + 'class-wp-press-this.php' => "f", + 'class-wp-filesystem-ftpsockets.php' => "f", + 'class-wp-site-health-auto-updates.php' => "f", + 'class-wp-internal-pointers.php' => "f", + 'class-wp-site-health.php' => "f", + 'image.php' => "f", + 'class-plugin-upgrader.php' => "f", + 'edit-tag-messages.php' => "f", + 'class-wp-upgrader.php' => "f", + 'class-theme-upgrader.php' => "f", + 'class-core-upgrader.php' => "f", + 'deprecated.php' => "f", + 'class-wp-comments-list-table.php' => "f", + 'class-wp-privacy-requests-table.php' => "f", + 'dashboard.php' => "f", + 'class-wp-themes-list-table.php' => "f", + 'plugin.php' => "f", + 'class-wp-posts-list-table.php' => "f", + 'upgrade.php' => "f", + 'class-file-upload-upgrader.php' => "f", + 'class-wp-filesystem-base.php' => "f", + 'class-wp-ajax-upgrader-skin.php' => "f", + 'class-wp-privacy-policy-content.php' => "f", + 'class-wp-media-list-table.php' => "f", + 'class-wp-filesystem-ftpext.php' => "f", + 'class-wp-ms-sites-list-table.php' => "f", + 'class-wp-users-list-table.php' => "f", + 'taxonomy.php' => "f", + 'credits.php' => "f", + 'class-wp-list-table.php' => "f", + 'noop.php' => "f", + 'revision.php' => "f", + 'class-language-pack-upgrader-skin.php' => "f", + 'class-wp-post-comments-list-table.php' => "f", + 'class-wp-privacy-data-removal-requests-list-table.php' => "f", + 'import.php' => "f", + 'menu.php' => "f", + 'class-wp-community-events.php' => "f", + 'class-pclzip.php' => "f", + 'user.php' => "f", + 'class-theme-installer-skin.php' => "f", + 'class-wp-filesystem-ssh2.php' => "f", + 'class-wp-upgrader-skin.php' => "f", + 'plugin-install.php' => "f", + 'class-wp-screen.php' => "f", + 'post.php' => "f", + 'class-wp-importer.php' => "f", + 'list-table.php' => "f", + 'class-ftp-pure.php' => "f", + 'class-bulk-plugin-upgrader-skin.php' => "f", + 'continents-cities.php' => "f", + 'class-wp-site-icon.php' => "f", + 'theme-install.php' => "f", + 'class-wp-plugin-install-list-table.php' => "f", + 'class-wp-application-passwords-list-table.php' => "f", + 'admin.php' => "f", + 'options.php' => "f", + 'class-plugin-upgrader-skin.php' => "f", + 'class-language-pack-upgrader.php' => "f", + 'class-plugin-installer-skin.php' => "f", + 'translation-install.php' => "f", + 'misc.php' => "f", + 'class-wp-terms-list-table.php' => "f", + 'class-wp-debug-data.php' => "f", + 'class-walker-category-checklist.php' => "f", + 'ms-deprecated.php' => "f", + 'class-wp-automatic-updater.php' => "f", + 'comment.php' => "f", + 'screen.php' => "f", + 'bookmark.php' => "f", + 'admin-filters.php' => "f", + 'theme.php' => "f", + 'class-wp-list-table-compat.php' => "f", + 'class-automatic-upgrader-skin.php' => "f", + 'privacy-tools.php' => "f", + 'class-walker-nav-menu-edit.php' => "f", + 'class-custom-background.php' => "f", + 'network.php' => "f", + 'class-ftp.php' => "f", + 'update.php' => "f", + 'nav-menu.php' => "f", + 'widgets.php' => "f", + 'class-wp-filesystem-direct.php' => "f", + 'schema.php' => "f", + 'update-core.php' => "f", + 'ms-admin-filters.php' => "f", + 'class-theme-upgrader-skin.php' => "f", + 'ajax-actions.php' => "f", + 'file.php' => "f", + 'class-ftp-sockets.php' => "f", + 'meta-boxes.php' => "f", + ), + 'ms-options.php' => "f", + 'link.php' => "f", + 'revision.php' => "f", + 'privacy.php' => "f", + 'js' => array( + 'xfn.min.js' => "f", + 'password-toggle.min.js' => "f", + 'theme-plugin-editor.min.js' => "f", + 'comment.min.js' => "f", + 'tags.min.js' => "f", + 'auth-app.min.js' => "f", + 'theme.js' => "f", + 'press-this.js' => "f", + 'privacy-tools.min.js' => "f", + 'user-profile.min.js' => "f", + 'media.js' => "f", + 'word-count.min.js' => "f", + 'password-strength-meter.min.js' => "f", + 'editor.min.js' => "f", + 'site-health.js' => "f", + 'media-gallery.js' => "f", + 'language-chooser.js' => "f", + 'custom-background.js' => "f", + 'widgets' => array( + 'media-image-widget.min.js' => "f", + 'media-image-widget.js' => "f", + 'text-widgets.min.js' => "f", + 'media-gallery-widget.js' => "f", + 'media-audio-widget.js' => "f", + 'text-widgets.js' => "f", + 'custom-html-widgets.min.js' => "f", + 'media-gallery-widget.min.js' => "f", + 'media-widgets.min.js' => "f", + 'media-video-widget.min.js' => "f", + 'media-audio-widget.min.js' => "f", + 'media-video-widget.js' => "f", + 'custom-html-widgets.js' => "f", + 'media-widgets.js' => "f", + ), + 'widgets.js' => "f", + 'widgets.min.js' => "f", + 'accordion.min.js' => "f", + 'wp-fullscreen-stub.min.js' => "f", + 'editor.js' => "f", + 'inline-edit-tax.min.js' => "f", + 'theme-plugin-editor.js' => "f", + 'password-strength-meter.js' => "f", + 'image-edit.min.js' => "f", + 'editor-expand.min.js' => "f", + 'inline-edit-post.js' => "f", + 'color-picker.js' => "f", + 'user-suggest.min.js' => "f", + 'edit-comments.min.js' => "f", + 'link.js' => "f", + 'plugin-install.min.js' => "f", + 'xfn.js' => "f", + 'media.min.js' => "f", + 'revisions.min.js' => "f", + 'password-toggle.js' => "f", + 'accordion.js' => "f", + 'color-picker.min.js' => "f", + 'common.js' => "f", + 'svg-painter.js' => "f", + 'wp-fullscreen.min.js' => "f", + 'set-post-thumbnail.min.js' => "f", + 'post.js' => "f", + 'application-passwords.min.js' => "f", + 'farbtastic.js' => "f", + 'gallery.js' => "f", + 'image-edit.js' => "f", + 'site-health.min.js' => "f", + 'link.min.js' => "f", + 'tags-box.js' => "f", + 'customize-nav-menus.js' => "f", + 'nav-menu.js' => "f", + 'media-gallery.min.js' => "f", + 'nav-menu.min.js' => "f", + 'editor-expand.js' => "f", + 'word-count.js' => "f", + 'privacy-tools.js' => "f", + 'code-editor.js' => "f", + 'post.min.js' => "f", + 'press-this.min.js' => "f", + 'customize-widgets.min.js' => "f", + 'theme.min.js' => "f", + 'wp-fullscreen.js' => "f", + 'edit-comments.js' => "f", + 'inline-edit-tax.js' => "f", + 'customize-controls.js' => "f", + 'user-profile.js' => "f", + 'media-upload.js' => "f", + 'revisions.js' => "f", + 'dashboard.min.js' => "f", + 'dashboard.js' => "f", + 'comment.js' => "f", + 'customize-controls.min.js' => "f", + 'custom-header.js' => "f", + 'inline-edit-post.min.js' => "f", + 'set-post-thumbnail.js' => "f", + 'wp-fullscreen-stub.js' => "f", + 'updates.js' => "f", + 'code-editor.min.js' => "f", + 'updates.min.js' => "f", + 'iris.min.js' => "f", + 'svg-painter.min.js' => "f", + 'common.min.js' => "f", + 'customize-nav-menus.min.js' => "f", + 'application-passwords.js' => "f", + 'bookmarklet.min.js' => "f", + 'tags.js' => "f", + 'customize-widgets.js' => "f", + 'gallery.min.js' => "f", + 'bookmarklet.js' => "f", + 'postbox.js' => "f", + 'tags-suggest.min.js' => "f", + 'auth-app.js' => "f", + 'postbox.min.js' => "f", + 'tags-box.min.js' => "f", + 'tags-suggest.js' => "f", + 'language-chooser.min.js' => "f", + 'plugin-install.js' => "f", + 'user-suggest.js' => "f", + 'custom-background.min.js' => "f", + 'media-upload.min.js' => "f", + ), + 'css' => array( + 'forms-rtl.min.css' => "f", + 'customize-controls-rtl.css' => "f", + 'site-icon.min.css' => "f", + 'themes-rtl.min.css' => "f", + 'press-this-editor-rtl.css' => "f", + 'revisions-rtl.min.css' => "f", + 'press-this-rtl.css' => "f", + 'wp-admin.css' => "f", + 'install-rtl.css' => "f", + 'code-editor-rtl.min.css' => "f", + 'widgets.min.css' => "f", + 'themes-rtl.css' => "f", + 'list-tables-rtl.css' => "f", + 'press-this-editor.min.css' => "f", + 'forms.min.css' => "f", + 'customize-nav-menus-rtl.css' => "f", + 'l10n.css' => "f", + 'list-tables.min.css' => "f", + 'press-this.css' => "f", + 'media-rtl.css' => "f", + 'customize-nav-menus.css' => "f", + 'admin-menu.css' => "f", + 'color-picker-rtl.min.css' => "f", + 'login-rtl.min.css' => "f", + 'press-this-editor.css' => "f", + 'color-picker-rtl.css' => "f", + 'nav-menus.css' => "f", + 'site-icon-rtl.css' => "f", + 'ie.css' => "f", + 'edit.css' => "f", + 'edit.min.css' => "f", + 'media.min.css' => "f", + 'about-rtl.min.css' => "f", + 'widgets-rtl.min.css' => "f", + 'common.min.css' => "f", + 'customize-nav-menus.min.css' => "f", + 'press-this-rtl.min.css' => "f", + 'revisions-rtl.css' => "f", + 'farbtastic.min.css' => "f", + 'install-rtl.min.css' => "f", + 'themes.css' => "f", + 'l10n-rtl.min.css' => "f", + 'edit-rtl.min.css' => "f", + 'nav-menus-rtl.min.css' => "f", + 'site-icon-rtl.min.css' => "f", + 'media-rtl.min.css' => "f", + 'colors' => array( + 'sunrise' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + 'blue' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + 'ectoplasm' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + 'modern' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + '_mixins.scss' => "f", + '_admin.scss' => "f", + 'coffee' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + 'ocean' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + 'light' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + 'midnight' => array( + 'colors.min.css' => "f", + 'colors.scss' => "f", + 'colors-rtl.min.css' => "f", + 'colors.css' => "f", + 'colors-rtl.css' => "f", + ), + '_variables.scss' => "f", + ), + 'revisions.min.css' => "f", + 'about.min.css' => "f", + 'common-rtl.min.css' => "f", + 'customize-nav-menus-rtl.min.css' => "f", + 'customize-controls-rtl.min.css' => "f", + 'site-health.css' => "f", + 'code-editor-rtl.css' => "f", + 'edit-rtl.css' => "f", + 'forms.css' => "f", + 'wp-admin-rtl.min.css' => "f", + 'code-editor.css' => "f", + 'customize-widgets-rtl.min.css' => "f", + 'color-picker.min.css' => "f", + 'l10n-rtl.css' => "f", + 'site-icon.css' => "f", + 'customize-widgets.css' => "f", + 'color-picker.css' => "f", + 'dashboard.css' => "f", + 'deprecated-media-rtl.css' => "f", + 'press-this-editor-rtl.min.css' => "f", + 'deprecated-media.min.css' => "f", + 'customize-widgets.min.css' => "f", + 'admin-menu-rtl.min.css' => "f", + 'widgets.css' => "f", + 'revisions.css' => "f", + 'dashboard-rtl.css' => "f", + 'admin-menu-rtl.css' => "f", + 'widgets-rtl.css' => "f", + 'login.min.css' => "f", + 'nav-menus-rtl.css' => "f", + 'ie-rtl.min.css' => "f", + 'ie.min.css' => "f", + 'install.css' => "f", + 'press-this.min.css' => "f", + 'about.css' => "f", + 'admin-menu.min.css' => "f", + 'login-rtl.css' => "f", + 'farbtastic.css' => "f", + 'dashboard.min.css' => "f", + 'forms-rtl.css' => "f", + 'l10n.min.css' => "f", + 'ie-rtl.css' => "f", + 'themes.min.css' => "f", + 'install.min.css' => "f", + 'site-health.min.css' => "f", + 'customize-widgets-rtl.css' => "f", + 'farbtastic-rtl.css' => "f", + 'wp-admin-rtl.css' => "f", + 'common.css' => "f", + 'list-tables.css' => "f", + 'customize-controls.css' => "f", + 'common-rtl.css' => "f", + 'login.css' => "f", + 'dashboard-rtl.min.css' => "f", + 'list-tables-rtl.min.css' => "f", + 'nav-menus.min.css' => "f", + 'deprecated-media.css' => "f", + 'about-rtl.css' => "f", + 'customize-controls.min.css' => "f", + 'site-health-rtl.css' => "f", + 'site-health-rtl.min.css' => "f", + 'media.css' => "f", + 'code-editor.min.css' => "f", + 'deprecated-media-rtl.min.css' => "f", + 'farbtastic-rtl.min.css' => "f", + 'wp-admin.min.css' => "f", + ), + 'site-health-info.php' => "f", + 'user' => array( + 'freedoms.php' => "f", + 'about.php' => "f", + 'credits.php' => "f", + 'privacy.php' => "f", + 'menu.php' => "f", + 'user-edit.php' => "f", + 'admin.php' => "f", + 'profile.php' => "f", + 'index.php' => "f", + ), + 'options-permalink.php' => "f", + 'import.php' => "f", + 'edit-form-advanced.php' => "f", + 'menu.php' => "f", + 'term.php' => "f", + 'custom-background.php' => "f", + 'link-manager.php' => "f", + 'network' => array( + 'freedoms.php' => "f", + 'site-info.php' => "f", + 'setup.php' => "f", + 'user-new.php' => "f", + 'about.php' => "f", + 'theme-editor.php' => "f", + 'upgrade.php' => "f", + 'contribute.php' => "f", + 'themes.php' => "f", + 'users.php' => "f", + 'edit.php' => "f", + 'credits.php' => "f", + 'privacy.php' => "f", + 'site-themes.php' => "f", + 'menu.php' => "f", + 'site-settings.php' => "f", + 'user-edit.php' => "f", + 'plugin-install.php' => "f", + 'theme-install.php' => "f", + 'settings.php' => "f", + 'admin.php' => "f", + 'profile.php' => "f", + 'plugins.php' => "f", + 'site-new.php' => "f", + 'index.php' => "f", + 'site-users.php' => "f", + 'plugin-editor.php' => "f", + 'sites.php' => "f", + 'update.php' => "f", + 'update-core.php' => "f", + ), + 'install-helper.php' => "f", + 'user-edit.php' => "f", + 'async-upload.php' => "f", + 'plugin-install.php' => "f", + 'post.php' => "f", + 'options-discussion.php' => "f", + 'widgets-form.php' => "f", + 'theme-install.php' => "f", + 'admin.php' => "f", + 'options-reading.php' => "f", + 'options.php' => "f", + 'images' => array( + 'about-header-background.svg' => "f", + 'freedom-2.svg' => "f", + 'about-color-palette.svg' => "f", + 'list.png' => "f", + 'icons32-vs-2x.png' => "f", + 'contribute-main.svg' => "f", + 'resize-rtl.gif' => "f", + 'about-texture.png' => "f", + 'privacy.png' => "f", + 'about-header-privacy.svg' => "f", + 'media-button.png' => "f", + 'comment-grey-bubble-2x.png' => "f", + 'freedom-4.svg' => "f", + 'menu-2x.png' => "f", + 'xit-2x.gif' => "f", + 'sort-2x.gif' => "f", + 'media-button-video.gif' => "f", + 'about-color-palette-vert.svg' => "f", + 'icons32.png' => "f", + 'bubble_bg.gif' => "f", + 'media-button-other.gif' => "f", + 'menu.png' => "f", + 'browser-rtl.png' => "f", + 'align-left-2x.png' => "f", + 'browser.png' => "f", + 'sort.gif' => "f", + 'media-button-2x.png' => "f", + 'post-formats.png' => "f", + 'align-center.png' => "f", + 'icons32-2x.png' => "f", + 'resize-2x.gif' => "f", + 'imgedit-icons.png' => "f", + 'align-right-2x.png' => "f", + 'wpspin_light.gif' => "f", + 'freedom-3.svg' => "f", + 'wordpress-logo.svg' => "f", + 'wheel.png' => "f", + 'about-header-brushes.svg' => "f", + 'list-2x.png' => "f", + 'resize.gif' => "f", + 'w-logo-blue.png' => "f", + 'contribute-code.svg' => "f", + 'xit.gif' => "f", + 'imgedit-icons-2x.png' => "f", + 'stars.png' => "f", + 'arrows-2x.png' => "f", + 'about-badge.svg' => "f", + 'menu-vs.png' => "f", + 'about-header-credits.svg' => "f", + 'about-header-contribute.svg' => "f", + 'align-right.png' => "f", + 'align-left.png' => "f", + 'post-formats32.png' => "f", + 'freedoms.png' => "f", + 'align-none-2x.png' => "f", + 'wpspin_light-2x.gif' => "f", + 'freedom-1.svg' => "f", + 'wordpress-logo-white.svg' => "f", + 'resize-rtl-2x.gif' => "f", + 'w-logo-white.png' => "f", + 'se.png' => "f", + 'media-button-image.gif' => "f", + 'yes.png' => "f", + 'wordpress-logo.png' => "f", + 'generic.png' => "f", + 'icons32-vs.png' => "f", + 'menu-vs-2x.png' => "f", + 'align-center-2x.png' => "f", + 'media-button-music.gif' => "f", + 'spinner-2x.gif' => "f", + 'align-none.png' => "f", + 'spinner.gif' => "f", + 'about-header-about.svg' => "f", + 'about-release-badge.svg' => "f", + 'comment-grey-bubble.png' => "f", + 'arrows.png' => "f", + 'privacy.svg' => "f", + 'contribute-no-code.svg' => "f", + 'date-button-2x.gif' => "f", + 'stars-2x.png' => "f", + 'dashboard-background.svg' => "f", + 'no.png' => "f", + 'date-button.gif' => "f", + 'bubble_bg-2x.gif' => "f", + 'post-formats-vs.png' => "f", + 'post-formats32-vs.png' => "f", + 'about-header-freedoms.svg' => "f", + 'loading.gif' => "f", + 'mask.png' => "f", + 'marker.png' => "f", + ), + 'profile.php' => "f", + 'plugins.php' => "f", + 'install.php' => "f", + 'options-head.php' => "f", + 'link-parse-opml.php' => "f", + 'admin-functions.php' => "f", + 'moderation.php' => "f", + 'comment.php' => "f", + 'index.php' => "f", + 'ms-sites.php' => "f", + 'site-health.php' => "f", + 'link-add.php' => "f", + 'edit-comments.php' => "f", + 'plugin-editor.php' => "f", + 'maint' => array('repair.php' => "f"), + 'nav-menus.php' => "f", + 'privacy-policy-guide.php' => "f", + 'network.php' => "f", + 'custom-header.php' => "f", + 'options-general.php' => "f", + 'options-media.php' => "f", + 'post-new.php' => "f", + 'update.php' => "f", + 'widgets.php' => "f", + 'ms-upgrade-network.php' => "f", + 'media-upload.php' => "f", + 'widgets-form-blocks.php' => "f", + 'admin-header.php' => "f", + 'update-core.php' => "f", + 'ms-themes.php' => "f", + 'ms-delete-site.php' => "f", + 'upgrade-functions.php' => "f", + 'menu-header.php' => "f", + 'ms-admin.php' => "f", + 'site-editor.php' => "f", + 'authorize-application.php' => "f", + 'admin-footer.php' => "f", + 'ms-edit.php' => "f", + 'press-this.php' => "f", + 'admin-ajax.php' => "f", + 'admin-post.php' => "f", + 'edit-tag-form.php' => "f", + ), +); diff --git a/src/Libs/WpConfig/WPConfigTransformer.php b/src/Libs/WpConfig/WPConfigTransformer.php new file mode 100644 index 00000000..d4fea092 --- /dev/null +++ b/src/Libs/WpConfig/WPConfigTransformer.php @@ -0,0 +1,496 @@ +wp_config_path = $wp_config_path; + } + + /** + * Checks if a config exists in the wp-config.php file. + * + * @throws Exception If the wp-config.php file is empty. + * @throws Exception If the requested config type is invalid. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * + * @return bool + */ + public function exists($type, $name) + { + $wp_config_src = file_get_contents($this->wp_config_path); + + if (! trim($wp_config_src)) { + throw new Exception('wp-config.php file is empty.'); + } + + // SnapCreek custom change + // Normalize the newline to prevent an issue coming from OSX + $wp_config_src = str_replace(array("\r\n", "\r"), "\n", $wp_config_src); + + $this->wp_config_src = $wp_config_src; + $this->wp_configs = $this->parseWpConfig($this->wp_config_src); + + if (! isset($this->wp_configs[ $type ])) { + throw new Exception("Config type '{$type}' does not exist."); + } + + return isset($this->wp_configs[ $type ][ $name ]); + } + + /** + * Get the value of a config in the wp-config.php file. + * + * @throws Exception If the wp-config.php file is empty. + * @throws Exception If the requested config type is invalid. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * @param bool $get_real_value if true return real value + * + * @return array + */ + public function getValue($type, $name, $get_real_value = true) + { + $wp_config_src = file_get_contents($this->wp_config_path); + if (! trim($wp_config_src)) { + throw new Exception('wp-config.php file is empty.'); + } + + // SnapCreek custom change + // Normalize the newline to prevent an issue coming from OSX + $wp_config_src = str_replace(array("\r\n", "\r"), "\n", $wp_config_src); + + $this->wp_config_src = $wp_config_src; + $this->wp_configs = $this->parseWpConfig($this->wp_config_src); + + if (! isset($this->wp_configs[ $type ])) { + throw new Exception("Config type '{$type}' does not exist."); + } + + // Duplicator Extra + $val = $this->wp_configs[ $type ][ $name ]['value']; + if ($get_real_value) { + return self::getRealValFromVal($val); + } else { + return $val; + } + + return $val; + } + + /** + * Get typed val from string val + * + * @param string $val string value + * + * @return mixed + */ + public static function getRealValFromVal($val) + { + if ($val[0] === '\'') { + // string with ' + $result = substr($val, 1, strlen($val) - 2); + return str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $result); + } elseif ($val[0] === '"') { + // string with " + return json_decode(str_replace('\\$', '$', $val)); + } elseif (strcasecmp($val, 'true') === 0) { + return true; + } elseif (strcasecmp($val, 'false') === 0) { + return false; + } elseif (strcasecmp($val, 'null') === 0) { + return null; + } elseif (preg_match('/^[-+]?[0-9]+$/', $val)) { + return (int) $val; + } elseif (preg_match('/^[-+]?[0-9]+\.[0-9]+$/', $val)) { + return (float) $val; + } else { + return $val; + } + } + + /** + * Adds a config to the wp-config.php file. + * + * @throws Exception If the config value provided is not a string. + * @throws Exception If the config placement anchor could not be located. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * @param string $value Config value. + * @param array $options (optional) Array of special behavior options. + * + * @return bool + */ + public function add($type, $name, $value, array $options = array()) + { + if (! is_string($value)) { + throw new Exception('Config value must be a string.'); + } + + if ($this->exists($type, $name)) { + return false; + } + + $defaults = array( + 'raw' => false, // Display value in raw format without quotes. + 'anchor' => "/* That's all, stop editing!", // Config placement anchor string. + 'separator' => PHP_EOL, // Separator between config definition and anchor string. + 'placement' => 'before', // Config placement direction (insert before or after). + ); + + list( $raw, $anchor, $separator, $placement ) = array_values(array_merge($defaults, $options)); + + $raw = (bool) $raw; + $anchor = (string) $anchor; + $separator = (string) $separator; + $placement = (string) $placement; + + // Custom code by the SnapCreek Team + if (false === strpos($this->wp_config_src, $anchor)) { + $other_anchor_points = array( + '/** Absolute path to the WordPress directory', + // ABSPATH defined check with single quote + "if ( !defined('ABSPATH') )", + "if ( ! defined( 'ABSPATH' ) )", + "if (!defined('ABSPATH') )", + "if(!defined('ABSPATH') )", + "if(!defined('ABSPATH'))", + "if ( ! defined( 'ABSPATH' ))", + "if ( ! defined( 'ABSPATH') )", + "if ( ! defined('ABSPATH' ) )", + "if (! defined( 'ABSPATH' ))", + "if (! defined( 'ABSPATH') )", + "if (! defined('ABSPATH' ) )", + "if ( !defined( 'ABSPATH' ))", + "if ( !defined( 'ABSPATH') )", + "if ( !defined('ABSPATH' ) )", + "if( !defined( 'ABSPATH' ))", + "if( !defined( 'ABSPATH') )", + "if( !defined('ABSPATH' ) )", + // ABSPATH defined check with double quote + 'if ( !defined("ABSPATH") )', + 'if ( ! defined( "ABSPATH" ) )', + 'if (!defined("ABSPATH") )', + 'if(!defined("ABSPATH") )', + 'if(!defined("ABSPATH"))', + 'if ( ! defined( "ABSPATH" ))', + 'if ( ! defined( "ABSPATH") )', + 'if ( ! defined("ABSPATH" ) )', + 'if (! defined( "ABSPATH" ))', + 'if (! defined( "ABSPATH") )', + 'if (! defined("ABSPATH" ) )', + 'if ( !defined( "ABSPATH" ))', + 'if ( !defined( "ABSPATH") )', + 'if ( !defined("ABSPATH" ) )', + 'if( !defined( "ABSPATH" ))', + 'if( !defined( "ABSPATH") )', + 'if( !defined("ABSPATH" ) )', + + '/** Sets up WordPress vars and included files', + 'require_once(ABSPATH', + 'require_once ABSPATH', + 'require_once( ABSPATH', + 'require_once', + "define( 'DB_NAME'", + 'define( "DB_NAME"', + "define('DB_NAME'", + 'define("DB_NAME"', + 'require', + 'include_once', + ); + foreach ($other_anchor_points as $anchor_point) { + $anchor_point = (string) $anchor_point; + if (false !== strpos($this->wp_config_src, $anchor_point)) { + $anchor = $anchor_point; + break; + } + } + } + + if (false === strpos($this->wp_config_src, $anchor)) { + throw new Exception('Unable to locate placement anchor.'); + } + + $new_src = $this->normalize($type, $name, $this->formatValue($value, $raw)); + $new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor; + $contents = str_replace($anchor, $new_src, $this->wp_config_src); + + return $this->save($contents); + } + + /** + * Updates an existing config in the wp-config.php file. + * + * @throws Exception If the config value provided is not a string. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * @param string $value Config value. + * @param array $options (optional) Array of special behavior options. + * + * @return bool + */ + public function update($type, $name, $value, array $options = array()) + { + if (! is_string($value)) { + throw new Exception('Config value must be a string.'); + } + + $defaults = array( + 'add' => true, // Add the config if missing. + 'raw' => false, // Display value in raw format without quotes. + 'normalize' => false, // Normalize config output using WP Coding Standards. + ); + + list( $add, $raw, $normalize ) = array_values(array_merge($defaults, $options)); + + $add = (bool) $add; + $raw = (bool) $raw; + $normalize = (bool) $normalize; + + if (! $this->exists($type, $name)) { + return ( $add ) ? $this->add($type, $name, $value, $options) : false; + } + + $old_src = $this->wp_configs[ $type ][ $name ]['src']; + $old_value = $this->wp_configs[ $type ][ $name ]['value']; + $new_value = $this->formatValue($value, $raw); + + if ($normalize) { + $new_src = $this->normalize($type, $name, $new_value); + } else { + $new_parts = $this->wp_configs[ $type ][ $name ]['parts']; + $new_parts[1] = str_replace($old_value, $new_value, $new_parts[1]); // Only edit the value part. + $new_src = implode('', $new_parts); + } + + $contents = preg_replace( + sprintf('/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote(trim($old_src), '/')), + '$1' . self::REPLACE_TEMP_STIRNG, + $this->wp_config_src + ); + $contents = str_replace(self::REPLACE_TEMP_STIRNG, trim($new_src), $contents); + return $this->save($contents); + } + + /** + * Removes a config from the wp-config.php file. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * + * @return bool + */ + public function remove($type, $name) + { + if (! $this->exists($type, $name)) { + return false; + } + + $pattern = sprintf('/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote($this->wp_configs[ $type ][ $name ]['src'], '/')); + $contents = preg_replace($pattern, '$1', $this->wp_config_src); + + return $this->save($contents); + } + + /** + * Applies formatting to a config value. + * + * @throws Exception When a raw value is requested for an empty string. + * + * @param string $value Config value. + * @param bool $raw Display value in raw format without quotes. + * + * @return mixed + */ + protected function formatValue($value, $raw) + { + if ($raw && '' === trim($value)) { + throw new Exception('Raw value for empty string not supported.'); + } + + return ( $raw ) ? $value : var_export($value, true); + } + + /** + * Normalizes the source output for a name/value pair. + * + * @throws Exception If the requested config type does not support normalization. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * @param mixed $value Config value. + * + * @return string + */ + protected function normalize($type, $name, $value) + { + if ('constant' === $type) { + $placeholder = "define( '%s', %s );"; + } elseif ('variable' === $type) { + $placeholder = '$%s = %s;'; + } else { + throw new Exception("Unable to normalize config type '{$type}'."); + } + + return sprintf($placeholder, $name, $value); + } + + /** + * Parses the source of a wp-config.php file. + * + * @param string $src Config file source. + * + * @return array + */ + protected function parseWpConfig($src) + { + $configs = array(); + $configs['constant'] = array(); + $configs['variable'] = array(); + + if (function_exists('token_get_all')) { + // Strip comments. + foreach (token_get_all($src) as $token) { + if (in_array($token[0], array( T_COMMENT, T_DOC_COMMENT ), true)) { + $src = str_replace($token[1], '', $src); + } + } + } + + preg_match_all( + '/(?<=^|;|<\?php\s|<\?\s)' . + '(\h*define\s*\(\s*[\'"](\w*?)[\'"]\s*)(,\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*)' . + '((?:,\s*(?:true|false)\s*)?\)\s*;)/ims', + $src, + $constants + ); + preg_match_all('/(?<=^|;|<\?php\s|<\?\s)(\h*\$(\w+)\s*=)(\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*;)/ims', $src, $variables); + + if ( + !empty($constants[0]) && + !empty($constants[1]) && + !empty($constants[2]) && + !empty($constants[3]) && + !empty($constants[4]) && + !empty($constants[5]) + ) { + foreach ($constants[2] as $index => $name) { + $configs['constant'][ $name ] = array( + 'src' => $constants[0][ $index ], + 'value' => $constants[4][ $index ], + 'parts' => array( + $constants[1][ $index ], + $constants[3][ $index ], + $constants[5][ $index ], + ), + ); + } + } + + if (! empty($variables[0]) && ! empty($variables[1]) && ! empty($variables[2]) && ! empty($variables[3]) && ! empty($variables[4])) { + // Remove duplicate(s), last definition wins. + $variables[2] = array_reverse(array_unique(array_reverse($variables[2], true)), true); + foreach ($variables[2] as $index => $name) { + $configs['variable'][ $name ] = array( + 'src' => $variables[0][ $index ], + 'value' => $variables[4][ $index ], + 'parts' => array( + $variables[1][ $index ], + $variables[3][ $index ], + ), + ); + } + } + + return $configs; + } + + /** + * Saves new contents to the wp-config.php file. + * + * @throws Exception If the config file content provided is empty. + * @throws Exception If there is a failure when saving the wp-config.php file. + * + * @param string $contents New config contents. + * + * @return bool + */ + protected function save($contents) + { + if (!trim($contents)) { + throw new Exception('Cannot save the wp-config.php file with empty contents.'); + } + + if ($contents === $this->wp_config_src) { + return false; + } + + $result = file_put_contents($this->wp_config_path, $contents, LOCK_EX); + + if (false === $result) { + throw new Exception('Failed to update the wp-config.php file.'); + } + + return true; + } +} diff --git a/src/Libs/WpConfig/WPConfigTransformerSrc.php b/src/Libs/WpConfig/WPConfigTransformerSrc.php new file mode 100644 index 00000000..52b99d9c --- /dev/null +++ b/src/Libs/WpConfig/WPConfigTransformerSrc.php @@ -0,0 +1,99 @@ +wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src); + } + + /** + * Get content string + * + * @return string + */ + public function getSrc() + { + return $this->wp_config_src; + } + + /** + * Checks if a config exists in the wp-config.php src + * + * @throws Exception If the wp-config.php file is empty. + * @throws Exception If the requested config type is invalid. + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * + * @return bool + */ + public function exists($type, $name) + { + $this->wp_configs = $this->parseWpConfig($this->wp_config_src); + + if (!isset($this->wp_configs[$type])) { + throw new Exception("Config type '{$type}' does not exist."); + } + + return isset($this->wp_configs[$type][$name]); + } + + /** + * Get the value of a config in the wp-config.php src + * + * @param string $type Config type (constant or variable). + * @param string $name Config name. + * @param bool $get_real_value if true return typed value + * + * @return array + */ + public function getValue($type, $name, $get_real_value = true) + { + $this->wp_configs = $this->parseWpConfig($this->wp_config_src); + + if (!isset($this->wp_configs[$type])) { + throw new Exception("Config type '{$type}' does not exist."); + } + + // Duplicator Extra + $val = $this->wp_configs[$type][$name]['value']; + if ($get_real_value) { + return self::getRealValFromVal($val); + } else { + return $val; + } + } + + /** + * Update wp_config_src + * + * @param string $contents config content + * + * @return boolean + */ + protected function save($contents) + { + $this->wp_config_src = $contents; + return true; + } +} diff --git a/src/Lite/Requirements.php b/src/Lite/Requirements.php new file mode 100644 index 00000000..59a23516 --- /dev/null +++ b/src/Lite/Requirements.php @@ -0,0 +1,144 @@ +' + . __('Please deactivate Duplicator PRO, then reactivate LITE version from the ', 'duplicator') + . "" . __('plugins page', 'duplicator') . "."; + $result = false; + } + + if ($result === false) { + register_activation_hook($pluginFile, array(__CLASS__, 'deactivateOnActivation')); + } + + return $result; + } + + /** + * + * @param string $plugin plugin slug + * + * @return boolean return true if plugin key is active and plugin file exists + */ + protected static function isPluginActive($plugin) + { + $isActive = false; + if (in_array($plugin, (array) get_option('active_plugins', array()))) { + $isActive = true; + } + + if (is_multisite()) { + $plugins = get_site_option('active_sitewide_plugins'); + if (isset($plugins[$plugin])) { + $isActive = true; + } + } + + return ($isActive && file_exists(WP_PLUGIN_DIR . '/' . $plugin)); + } + + /** + * display admin notice only if user can manage plugins. + * + * @return void + */ + public static function addProEnableNotice() + { + if (current_user_can('activate_plugins')) { + add_action('admin_notices', array(__CLASS__, 'proEnabledNotice')); + } + } + + /** + * display admin notice + * + * @return void + */ + public static function addMultisiteNotice() + { + if (current_user_can('activate_plugins')) { + add_action('admin_notices', array(__CLASS__, 'multisiteNotice')); + } + } + + /** + * deactivate current plugin on activation + * + * @return void + */ + public static function deactivateOnActivation() + { + deactivate_plugins(plugin_basename(self::$pluginFile)); + wp_die(self::$deactivationMessage); + } + + /** + * Display admin notice if duplicator pro is enabled + * + * @return void + */ + public static function proEnabledNotice() + { + $pluginUrl = (is_multisite() ? network_admin_url('plugins.php') : admin_url('plugins.php')); + ?> +
                        +

                        + + + +

                        +

                        + + + . + +

                        +
                        + $mappedPath) { + if (strpos($className, $namespace) !== 0) { + continue; + } + + $filepath = $mappedPath . str_replace('\\', '/', substr($className, strlen($namespace))) . '.php'; + if (file_exists($filepath)) { + include_once($filepath); + return true; + } + } + } + + return false; + } + + /** + * Load external libs + * + * @param string $className class name + * + * @return bool return true if class is loaded + */ + protected static function externalLibs($className) + { + switch (strtolower(ltrim($className, '\\'))) { + default: + return false; + } + } + + /** + * mappgin of some legacy classes + * + * @return array + */ + protected static function customLegacyMapping() + { + return array(); + } + + /** + * Return namespace mapping + * + * @return string[] + */ + protected static function getNamespacesMapping() + { + // the order is important, it is necessary to insert the longest namespaces first + return array( + self::ROOT_INSTALLER_NAMESPACE => DUPLICATOR_LITE_PATH . '/installer/dup-installer/src/', + self::ROOT_NAMESPACE => DUPLICATOR_LITE_PATH . '/src/' + ); + } + + /** + * Returns true if the $haystack string end with the $needle, only for internal use + * + * @param string $haystack The full string to search in + * @param string $needle The string to for + * + * @return bool Returns true if the $haystack string starts with the $needle + */ + protected static function endsWith($haystack, $needle) + { + $length = strlen($needle); + if ($length == 0) { + return true; + } + + return (substr($haystack, -$length) === $needle); + } +} diff --git a/src/Utils/CachesPurge/CacheItem.php b/src/Utils/CachesPurge/CacheItem.php new file mode 100644 index 00000000..c7edb4d2 --- /dev/null +++ b/src/Utils/CachesPurge/CacheItem.php @@ -0,0 +1,108 @@ +name = $name; + if (!is_bool($checkCallback) && !is_callable($checkCallback)) { + throw new Exception('checkCallback must be boolean or callable'); + } + $this->checkCallback = $checkCallback; + + /* purge callback may not exist if the referenced plugin is not initialized. + * That's why the check is performed only if you actually purge the plugin + */ + $this->purgeCallback = $purgeCallback; + $this->purgedMessage = sprintf(__('All caches on %s have been purged.', 'duplicator'), $this->name); + } + + /** + * overwrite default purged message + * + * @param string $message message if item have benn purged + * + * @return void + */ + public function setPurgedMessage($message) + { + $this->purgedMessage = $message; + } + + /** + * purge caches item + * + * @param string $message message if item have benn purged + * + * @return bool + */ + public function purge(&$message) + { + try { + if ( + (is_bool($this->checkCallback) && $this->checkCallback) || + call_user_func($this->checkCallback) == true + ) { + DUP_Log::trace('Purge ' . $this->name); + if (!is_callable($this->purgeCallback)) { + throw new Exception('purgeCallback must be callable'); + } + call_user_func($this->purgeCallback); + $message = $this->purgedMessage; + } + return true; + } catch (Exception $e) { + DUP_Log::trace('Error purge ' . $this->name . ' message:' . $e->getMessage()); + $message = sprintf(__('Error on caches purge of %s.', 'duplicator'), $this->name); + return false; + } catch (Error $e) { + DUP_Log::trace('Error purge ' . $this->name . ' message:' . $e->getMessage()); + $message = sprintf(__('Error on caches purge of %s.', 'duplicator'), $this->name); + return false; + } + } +} diff --git a/src/Utils/CachesPurge/CachesPurge.php b/src/Utils/CachesPurge/CachesPurge.php new file mode 100644 index 00000000..75c3cb92 --- /dev/null +++ b/src/Utils/CachesPurge/CachesPurge.php @@ -0,0 +1,291 @@ +purge($message); + if (strlen($message) > 0 && $result) { + $globalMessages[] = $message; + } + } + + return $globalMessages; + } + + /** + * get list to cache items to purge + * + * @return CacheItem[] + */ + protected static function getPurgePlugins() + { + $items = array(); + $items[] = new CacheItem( + 'Elementor', + function () { + return class_exists("\\Elementor\\Plugin"); + }, + function () { + \Elementor\Plugin::$instance->files_manager->clear_cache(); + } + ); + $items[] = new CacheItem( + 'W3 Total Cache', + function () { + return function_exists('w3tc_pgcache_flush'); + }, + 'w3tc_pgcache_flush' + ); + $items[] = new CacheItem( + 'WP Super Cache', + function () { + return function_exists('wp_cache_clear_cache'); + }, + 'wp_cache_clear_cache' + ); + $items[] = new CacheItem( + 'WP Rocket', + function () { + return function_exists('rocket_clean_domain'); + }, + 'rocket_clean_domain' + ); + $items[] = new CacheItem( + 'Fast velocity minify', + function () { + return function_exists('fvm_purge_static_files'); + }, + 'fvm_purge_static_files' + ); + $items[] = new CacheItem( + 'Cachify', + function () { + return function_exists('cachify_flush_cache'); + }, + 'cachify_flush_cache' + ); + $items[] = new CacheItem( + 'Comet Cache', + function () { + return class_exists('\\comet_cache'); + }, + array('\\comet_cache', 'clear') + ); + $items[] = new CacheItem( + 'Zen Cache', + function () { + return class_exists('\\zencache'); + }, + array('\\zencache', 'clear') + ); + $items[] = new CacheItem( + 'LiteSpeed Cache', + function () { + return has_action('litespeed_purge_all'); + }, + function () { + return do_action('litespeed_purge_all'); + } + ); + $items[] = new CacheItem( + 'WP Cloudflare Super Page Cache', + function () { + return class_exists('\\SW_CLOUDFLARE_PAGECACHE'); + }, + function () { + return do_action("swcfpc_purge_everything"); + } + ); + $items[] = new CacheItem( + 'Hyper Cache', + function () { + return class_exists('\\HyperCache'); + }, + function () { + return do_action('autoptimize_action_cachepurged'); + } + ); + $items[] = new CacheItem( + 'Cache Enabler', + function () { + return has_action('ce_clear_cache'); + }, + function () { + return do_action('ce_clear_cache'); + } + ); + $items[] = new CacheItem( + 'WP Fastest Cache', + function () { + return function_exists('wpfc_clear_all_cache'); + }, + function () { + wpfc_clear_all_cache(true); + } + ); + $items[] = new CacheItem( + 'Breeze', + function () { + return class_exists("\\Breeze_PurgeCache"); + }, + array('\\Breeze_PurgeCache', 'breeze_cache_flush') + ); + $items[] = new CacheItem( + 'Swift Performance', + function () { + return class_exists("\\Swift_Performance_Cache"); + }, + array('\\Swift_Performance_Cache', 'clear_all_cache') + ); + $items[] = new CacheItem( + 'Hummingbird', + function () { + return has_action('wphb_clear_page_cache'); + }, + function () { + return do_action('wphb_clear_page_cache'); + } + ); + $items[] = new CacheItem( + 'WP-Optimize', + function () { + return has_action('wpo_cache_flush'); + }, + function () { + return do_action('wpo_cache_flush'); + } + ); + $items[] = new CacheItem( + 'Wordpress default', + function () { + return function_exists('wp_cache_flush'); + }, + 'wp_cache_flush' + ); + $items[] = new CacheItem( + 'Wordpress permalinks', + function () { + return function_exists('flush_rewrite_rules'); + }, + 'flush_rewrite_rules' + ); + return $items; + } + + /** + * get list to cache items to purge + * + * @return CacheItem[] + */ + protected static function getPurgeHosts() + { + $items = array(); + $items[] = new CacheItem( + 'Godaddy Managed WordPress Hosting', + function () { + return class_exists('\\WPaaS\\Plugin') && method_exists('\\WPass\\Plugin', 'vip'); + }, + function () { + $method = 'BAN'; + $url = home_url(); + $host = wpraiser_get_domain(); + $url = set_url_scheme(str_replace($host, \WPaas\Plugin::vip(), $url), 'http'); + update_option('gd_system_last_cache_flush', time(), 'no'); # purge apc + wp_remote_request( + esc_url_raw($url), + array( + 'method' => $method, + 'blocking' => false, + 'headers' => + array( + 'Host' => $host + ) + ) + ); + } + ); + $items[] = new CacheItem( + 'SG Optimizer (Siteground)', + function () { + return function_exists('sg_cachepress_purge_everything'); + }, + 'sg_cachepress_purge_everything' + ); + $items[] = new CacheItem( + 'WP Engine', + function () { + return (class_exists("\\WpeCommon") && + (method_exists('\\WpeCommon', 'purge_memcached') || + method_exists('\\WpeCommon', 'purge_varnish_cache'))); + }, + function () { + if (method_exists('\\WpeCommon', 'purge_memcached')) { + \WpeCommon::purge_memcached(); + } + if (method_exists('\\WpeCommon', 'purge_varnish_cache')) { + \WpeCommon::purge_varnish_cache(); + } + } + ); + $items[] = new CacheItem( + 'Kinsta', + function () { + global $kinsta_cache; + return ( + (isset($kinsta_cache) && + class_exists('\\Kinsta\\CDN_Enabler')) && + !empty($kinsta_cache->kinsta_cache_purge)); + }, + function () { + global $kinsta_cache; + $kinsta_cache->kinsta_cache_purge->purge_complete_caches(); + } + ); + $items[] = new CacheItem( + 'Pagely', + function () { + return class_exists('\\PagelyCachePurge'); + }, + function () { + $purge_pagely = new \PagelyCachePurge(); + $purge_pagely->purgeAll(); + } + ); + $items[] = new CacheItem( + 'Pressidum', + function () { + return defined('WP_NINUKIS_WP_NAME') && class_exists('\\Ninukis_Plugin'); + }, + function () { + $purge_pressidum = \Ninukis_Plugin::get_instance(); + $purge_pressidum->purgeAllCaches(); + } + ); + + $items[] = new CacheItem( + 'Pantheon Advanced Page Cache plugin', + function () { + return function_exists('pantheon_wp_clear_edge_all'); + }, + 'pantheon_wp_clear_edge_all' + ); + return $items; + } +} diff --git a/src/Utils/CronUtils.php b/src/Utils/CronUtils.php new file mode 100644 index 00000000..e5fc354a --- /dev/null +++ b/src/Utils/CronUtils.php @@ -0,0 +1,47 @@ +> $schedules schedules + * + * @return array> + */ + public static function defaultCronIntervals($schedules) + { + $schedules[self::INTERVAL_DAILTY] = array( + 'interval' => DAY_IN_SECONDS, + 'display' => __('Once a Day', 'duplicator'), + ); + + $schedules[self::INTERVAL_WEEKLY] = array( + 'interval' => WEEK_IN_SECONDS, + 'display' => __('Once a Week', 'duplicator'), + ); + + $schedules[self::INTERVAL_MONTHLY] = array( + 'interval' => MONTH_IN_SECONDS, + 'display' => __('Once a Month', 'duplicator'), + ); + + return $schedules; + } +} diff --git a/src/Utils/DuplicatorPhpVersionCheck.php b/src/Utils/DuplicatorPhpVersionCheck.php new file mode 100644 index 00000000..4d7a481d --- /dev/null +++ b/src/Utils/DuplicatorPhpVersionCheck.php @@ -0,0 +1,93 @@ + +
                        +

                        + +

                        + +
                        + ', + '', + self::$minVer + ); + ?> +

                        +
                        + > List of styles in class => styles format*/ + public static $styles = array( + 'body' => array( + "border-collapse" => "collapse", + "border-spacing" => "0", + "vertical-align" => "top", + "mso-table-lspace" => "0pt", + "mso-table-rspace" => "0pt", + "-ms-text-size-adjust" => "100%", + "-webkit-text-size-adjust" => "100%", + "height" => "100% !important", + "width" => "100% !important", + "min-width" => "100%", + "-moz-box-sizing" => "border-box", + "-webkit-box-sizing" => "border-box", + "box-sizing" => "border-box", + "-webkit-font-smoothing" => "antialiased !important", + "-moz-osx-font-smoothing" => "grayscale !important", + "background-color" => "#e9eaec", + "color" => "#444444", + "font-family" => "'Helvetica Neue', Helvetica, Arial, sans-serif", + "font-weight" => "normal", + "padding" => "0", + "margin" => "0", + "text-align" => "left", + "font-size" => "14px", + "mso-line-height-rule" => "exactly", + "line-height" => "140%", + ), + 'table' => array( + "border-collapse" => "collapse", + "border-spacing" => "0", + "vertical-align" => "top", + "mso-table-lspace" => "0pt", + "mso-table-rspace" => "0pt", + "-ms-text-size-adjust" => "100%", + "-webkit-text-size-adjust" => "100%", + "margin" => "0 auto 0 auto", + "padding" => "0", + "text-align" => "inherit", + ), + 'main-tbl' => array( + "width" => "600px", + ), + 'stats-tbl' => array( + "-ms-text-size-adjust" => "100%", + "-webkit-text-size-adjust" => "100%", + "width" => "100%", + "margin" => "15px 0 38px 0", + ), + 'tr' => array( + "padding" => "0", + "vertical-align" => "top", + "text-align" => "left", + ), + 'td' => array( + "word-wrap" => "break-word", + "-webkit-hyphens" => "auto", + "-moz-hyphens" => "auto", + "hyphens" => "auto", + "border-collapse" => "collapse !important", + "vertical-align" => "top", + "mso-table-lspace" => "0pt", + "mso-table-rspace" => "0pt", + "-ms-text-size-adjust" => "100%", + "-webkit-text-size-adjust" => "100%", + "color" => "#444444", + "font-family" => "'Helvetica Neue', Helvetica, Arial, sans-serif", + "font-weight" => "normal", + "padding" => "0", + "margin" => "0", + "font-size" => "14px", + "mso-line-height-rule" => "exactly", + "line-height" => "140%", + ), + 'stats-count-cell' => array( + 'width' => '1px', + 'text-align' => 'center', + ), + 'unsubscribe' => array( + "padding" => "30px", + "color" => "#72777c", + "font-size" => "12px", + "text-align" => "center", + ), + 'th' => array( + "font-family" => "'Helvetica Neue', Helvetica, Arial, sans-serif", + "margin" => "0", + "text-align" => "left", + "font-size" => "14px", + "mso-line-height-rule" => "exactly", + "line-height" => "140%", + "font-weight" => "700", + "color" => "#777777", + "background" => "#f1f1f1", + "border" => "1px solid #f1f1f1", + "padding" => "17px 20px 17px 20px", + ), + 'stats-cell' => array( + "font-size" => "16px", + "border-top" => "none", + "border-right" => "none", + "border-bottom" => "1px solid #f1f1f1", + "border-left" => "none", + "color" => "#444444", + "padding" => "17px 20px 17px 20px", + ), + 'img' => array( + "outline" => "none", + "text-decoration" => "none", + "width" => "auto", + "clear" => "both", + "-ms-interpolation-mode" => "bicubic", + "display" => "inline-block !important", + "max-width" => "45%", + ), + 'h6' => array( + "padding" => "0", + "text-align" => "left", + "word-wrap" => "normal", + "font-family" => "'Helvetica Neue', Helvetica, Arial, sans-serif", + "font-weight" => "bold", + "mso-line-height-rule" => "exactly", + "line-height" => "130%", + "font-size" => "18px", + "color" => "#444444", + "margin" => "0 0 3px 0", + ), + 'p' => array( + "-ms-text-size-adjust" => "100%", + "-webkit-text-size-adjust" => "100%", + "font-family" => "'Helvetica Neue', Helvetica, Arial, sans-serif", + "font-weight" => "normal", + "padding" => "0", + "text-align" => "left", + "mso-line-height-rule" => "exactly", + "line-height" => "140%", + "overflow-wrap" => "break-word", + "word-wrap" => "break-word", + "-ms-word-break" => "break-all", + "word-break" => "break-word", + "-ms-hyphens" => "auto", + "-moz-hyphens" => "auto", + "-webkit-hyphens" => "auto", + "hyphens" => "auto", + "color" => "#777777", + "font-size" => "14px", + "margin" => "25px 0 25px 0", + ), + 'a' => array( + "-ms-text-size-adjust" => "100%", + "-webkit-text-size-adjust" => "100%", + "font-family" => "'Helvetica Neue', Helvetica, Arial, sans-serif", + "font-weight" => "normal", + "padding" => "0", + "margin" => "0", + "Margin" => "0", + "text-align" => "left", + "mso-line-height-rule" => "exactly", + "line-height" => "140%", + ), + 'footer-link' => array( + "color" => "#72777c", + "text-decoration" => "underline", + ), + 'inline-link' => array( + "color" => "inherit", + "text-decoration" => "underline", + ), + 'stats-title' => array( + "margin" => "0 0 15px 0", + ), + 'subtitle' => array( + "font-size" => "16px", + "margin" => "0 0 15px 0", + ), + 'txt-orange' => array( + "color" => "#e27730", + ), + 'txt-center' => array( + 'text-align' => 'center', + ), + 'logo' => array( + "padding" => "30px 0px", + ), + 'content' => array( + "background-color" => "#ffffff", + "padding" => "60px 75px 45px 75px", + "border-top" => "3px solid #e27730", + "border-right" => "1px solid #dddddd", + "border-bottom" => "1px solid #dddddd", + "border-left" => "1px solid #dddddd", + ), + 'strong' => array( + "font-weight" => "bold", + ), + ); + + /** + * Get Inline CSS of selector or empty if selector not found + * + * @param string $selectors Space separated selectors + * + * @return string + */ + public static function getStyle($selectors) + { + if ($selectors === '') { + return ''; + } + + $selArr = explode(' ', $selectors); + $uniqueStyles = array(); + foreach ($selArr as $i => $selector) { + if (!isset(self::$styles[$selector])) { + continue; + } + + //overwrite repeating styles + foreach (self::$styles[$selector] as $key => $value) { + $uniqueStyles[$key] = $value; + } + } + + $style = ''; + foreach ($uniqueStyles as $key => $value) { + $style .= $key . ': ' . $value . ';'; + } + + return $style; + } + + /** + * Print Inline CSS of selector or empty if selector not found + * + * @param string $selectors Space separated selectors + * + * @return void + */ + public static function printStyle($selectors) + { + echo 'class="' . esc_attr($selectors) . '" style="' . self::getStyle($selectors) . '"'; + } +} diff --git a/src/Utils/Email/EmailSummary.php b/src/Utils/Email/EmailSummary.php new file mode 100644 index 00000000..51814ee4 --- /dev/null +++ b/src/Utils/Email/EmailSummary.php @@ -0,0 +1,170 @@ +manualPackageIds[] = $package->ID; + } elseif ($status === DUP_PackageStatus::ERROR) { + $this->failedPackageIds[] = $package->ID; + } + + $this->save(); + } + + /** + * Returns info about created packages + * + * @return array> + */ + public function getPackagesInfo() + { + $packagesInfo = array(); + $packagesInfo['manual'] = array( + 'name' => __('Successful', 'duplicator'), + 'count' => count($this->manualPackageIds), + ); + + $packagesInfo['failed'] = array( + 'name' => __('Failed', 'duplicator'), + 'count' => count($this->failedPackageIds), + ); + + return $packagesInfo; + } + + /** + * Get all frequency options + * + * @return array + */ + public static function getAllFrequencyOptions() + { + return array( + self::SEND_FREQ_NEVER => esc_html__('Never', 'duplicator'), + self::SEND_FREQ_DAILY => esc_html__('Daily', 'duplicator'), + self::SEND_FREQ_WEEKLY => esc_html__('Weekly', 'duplicator'), + self::SEND_FREQ_MONTHLY => esc_html__('Monthly', 'duplicator'), + ); + } + + /** + * Get the frequency text displayed in the email + * + * @return string + */ + public static function getFrequencyText() + { + $frequency = DUP_Settings::Get('email_summary_frequency'); + switch ($frequency) { + case self::SEND_FREQ_DAILY: + return esc_html__('day', 'duplicator'); + case self::SEND_FREQ_MONTHLY: + return esc_html__('month', 'duplicator'); + case self::SEND_FREQ_WEEKLY: + default: + return esc_html__('week', 'duplicator'); + } + } + + /** + * Reset plugin data + * + * @return bool True if data has been reset, false otherwise + */ + public function resetData() + { + $this->manualPackageIds = array(); + $this->failedPackageIds = array(); + + return $this->save(); + } + + /** + * Save plugin data + * + * @return bool True if data has been saved, false otherwise + */ + private function save() + { + return update_option(self::INFO_OPT_KEY, JsonSerialize::serialize($this)); + } +} diff --git a/src/Utils/Email/EmailSummaryBootstrap.php b/src/Utils/Email/EmailSummaryBootstrap.php new file mode 100644 index 00000000..18b57616 --- /dev/null +++ b/src/Utils/Email/EmailSummaryBootstrap.php @@ -0,0 +1,235 @@ +addPackage($package, $status); + } + + /** + * Send email summary + * + * @return bool True if email was sent + */ + public static function send() + { + $frequency = DUP_Settings::Get('email_summary_frequency'); + if (($recipient = get_option('admin_email')) === false || $frequency === EmailSummary::SEND_FREQ_NEVER) { + return false; + } + + $parsedHomeUrl = wp_parse_url(home_url()); + $siteDomain = $parsedHomeUrl['host']; + + if (is_multisite() && isset($parsedHomeUrl['path'])) { + $siteDomain .= $parsedHomeUrl['path']; + } + + $subject = sprintf( + esc_html_x( + 'Your Weekly Duplicator Summary for %s', + '%s is the site domain', + 'duplicator' + ), + $siteDomain + ); + + $content = TplMng::getInstance()->render('mail/email_summary', array( + 'packages' => EmailSummary::getInstance()->getPackagesInfo(), + ), false); + + add_filter('wp_mail_content_type', array(__CLASS__, 'getMailContentType')); + if (!wp_mail($recipient, $subject, $content)) { + DUP_Log::Trace("FAILED TO SEND EMAIL SUMMARY."); + DUP_Log::Trace("Recipients: " . $recipient); + return false; + } elseif (!EmailSummary::getInstance()->resetData()) { + DUP_Log::Trace("FAILED TO RESET EMAIL SUMMARY DATA."); + return false; + } + + return true; + } + + /** + * Get mail content type + * + * @return string + */ + public static function getMailContentType() + { + return 'text/html'; + } + + /** + * Activation action + * + * @return void + */ + public static function activationAction() + { + $frequency = DUP_Settings::Get('email_summary_frequency'); + if ($frequency === EmailSummary::SEND_FREQ_NEVER) { + return; + } + + if (self::updateCron($frequency) == false) { + DUP_Log::Trace("FAILED TO INIT EMAIL SUMMARY CRON. Frequency: {$frequency}"); + } + } + + /** + * Deactivation action + * + * @return void + */ + public static function deactivationAction() + { + if (self::updateCron(EmailSummary::SEND_FREQ_NEVER) == false) { + DUP_Log::Trace("FAILED TO REMOVE EMAIL SUMMARY CRON."); + } + } + + /** + * Update next send time on frequency setting change + * + * @param string $oldFrequency The old frequency + * @param string $newFrequency The new frequency + * + * @return bool True if the cron was updated or false on error + */ + public static function updateFrequency($oldFrequency, $newFrequency) + { + if ($oldFrequency === $newFrequency) { + return true; + } + + return self::updateCron($newFrequency); + } + + /** + * Updates the WP Cron job base on frequency or settings + * + * @param string $frequency The frequency + * + * @return bool True if the cron was updated or false on error + */ + private static function updateCron($frequency = '') + { + if (strlen($frequency) === 0) { + $frequency = DUP_Settings::Get('email_summary_frequency'); + } + + if ($frequency === EmailSummary::SEND_FREQ_NEVER) { + if (wp_next_scheduled(self::CRON_HOOK)) { + return is_int(wp_clear_scheduled_hook(self::CRON_HOOK)); + } else { + return true; + } + } else { + if ( + wp_next_scheduled(self::CRON_HOOK) + && !is_int(wp_clear_scheduled_hook(self::CRON_HOOK)) //make sure we clear the old cron + ) { + return false; + } + + return (wp_schedule_event( + self::getFirstRunTime($frequency), + self::getCronSchedule($frequency), + self::CRON_HOOK + ) === true); + } + } + + /** + * Set next send time based on frequency + * + * @param string $frequency Frequency + * + * @return int + */ + private static function getFirstRunTime($frequency) + { + switch ($frequency) { + case EmailSummary::SEND_FREQ_DAILY: + $firstRunTime = strtotime('tomorrow 14:00'); + break; + case EmailSummary::SEND_FREQ_WEEKLY: + $firstRunTime = strtotime('next monday 14:00'); + break; + case EmailSummary::SEND_FREQ_MONTHLY: + $firstRunTime = strtotime('first day of next month 14:00'); + break; + case EmailSummary::SEND_FREQ_NEVER: + return 0; + default: + throw new \Exception("Unknown frequency: " . $frequency); + } + + return $firstRunTime - SnapWP::getGMTOffset(); + } + + /** + * Get the cron schedule + * + * @param string $frequency The frequency + * + * @return string + */ + private static function getCronSchedule($frequency) + { + switch ($frequency) { + case EmailSummary::SEND_FREQ_DAILY: + return CronUtils::INTERVAL_DAILTY; + case EmailSummary::SEND_FREQ_WEEKLY: + return CronUtils::INTERVAL_WEEKLY; + case EmailSummary::SEND_FREQ_MONTHLY: + return CronUtils::INTERVAL_MONTHLY; + default: + throw new Exception("Unknown frequency: " . $frequency); + } + } +} diff --git a/src/Utils/ExtraPlugins/ExtraItem.php b/src/Utils/ExtraPlugins/ExtraItem.php new file mode 100644 index 00000000..db14c6a3 --- /dev/null +++ b/src/Utils/ExtraPlugins/ExtraItem.php @@ -0,0 +1,251 @@ +name = $name; + $this->slug = $slug; + $this->icon = $icon; + $this->desc = $desc; + $this->url = $url; + $this->wpOrgURL = $wpOrgURL; + } + + /** + * Returns plugin slug + * + * @return array + */ + public function getSlug() + { + return $this->slug; + } + + /** + * Is plugin active + * + * @return bool + */ + public function isActive() + { + return $this->isInstalled() && is_plugin_active($this->slug); + } + + /** + * Is plugin installed + * + * @return bool + */ + public function isInstalled() + { + static $installedSlugs = null; + if ($installedSlugs === null) { + $installedSlugs = array_keys(get_plugins()); + } + return in_array($this->slug, $installedSlugs); + } + + /** + * Returns pro version of plugin if available + * + * @return ExtraItem|null + */ + public function getPro() + { + return $this->pro; + } + + /** + * Set pro plugin + * + * @param string $name plugin name + * @param string $slug plugin slug + * @param string $icon url to plugin icon + * @param string $desc plugin description + * @param string $url plugin url + * @param string|bool $wpOrgURL plugin url on wordpress.org + * + * @return void + */ + public function setPro($name, $slug, $icon, $desc, $url, $wpOrgURL = false) + { + $this->pro = new self($name, $slug, $icon, $desc, $url, $wpOrgURL); + } + + /** + * Whether to skip lite version of plugin because it is installed and pro version is available + * + * @return bool + */ + public function skipLite() + { + return $this->pro !== null && $this->isActive(); + } + + /** + * Enum of status constants (STATUS_ACTIVE, STATUS_INSTALLED, STATUS_UNINSALED) + * + * @return int return status constant + */ + public function getStatus() + { + if ($this->isActive()) { + return self::STATUS_ACTIVE; + } elseif ($this->isInstalled()) { + return self::STATUS_INSTALLED; + } else { + return self::STATUS_NOT_INSTALLED; + } + } + + /** + * Status text + * + * @return string + */ + public function getStatusText() + { + switch ($this->getStatus()) { + case self::STATUS_ACTIVE: + return __('Active', 'duplicator'); + case self::STATUS_INSTALLED: + return __('Inactive', 'duplicator'); + case self::STATUS_NOT_INSTALLED: + return __('Not Installed', 'duplicator'); + } + } + + /** + * Enum of URL constants (URL_TYPE_GENERIC, URL_TYPE_ZIP) + * + * @return int + */ + public function getURLType() + { + if (SnapString::endsWith($this->url, '.zip')) { + return self::URL_TYPE_ZIP; + } else { + return self::URL_TYPE_GENERIC; + } + } + + /** + * Install this plugin + * + * @return bool true on success + */ + public function install() + { + if ($this->isInstalled()) { + return true; + } + + if (!SnapString::endsWith($this->url, '.zip')) { + throw new \Exception('Invalid plugin url for installation'); + } + + if (!current_user_can('install_plugins')) { + throw new \Exception('User does not have permission to install plugins'); + } + + if (!class_exists('Plugin_Upgrader')) { + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + } + wp_cache_flush(); + + $upgrader = new \Plugin_Upgrader(new \Automatic_Upgrader_Skin()); + if (!$upgrader->install($this->url)) { + throw new \Exception('Failed to install plugin'); + } + + return true; + } + + /** + * Activate this plugin + * + * @return bool true on success + */ + public function activate() + { + if ($this->isActive()) { + return true; + } + + if (!is_null(activate_plugin($this->slug))) { + throw new \Exception('Failed to activate plugin'); + } + + return true; + } +} diff --git a/src/Utils/ExtraPlugins/ExtraPluginsMng.php b/src/Utils/ExtraPlugins/ExtraPluginsMng.php new file mode 100644 index 00000000..f85dd524 --- /dev/null +++ b/src/Utils/ExtraPlugins/ExtraPluginsMng.php @@ -0,0 +1,488 @@ + key slug item */ + protected $plugins = array(); + + /** + * + * @return self + */ + public static function getInstance() + { + if (is_null(self::$instance)) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Singleton constructor + */ + protected function __construct() + { + $this->plugins = self::getInitList(); + } + + /** + * Execute callback for each plugin + * + * @param callable $callback callback function + * + * @return void + */ + public function foreachCallback($callback) + { + if (!is_callable($callback)) { + return; + } + + foreach ($this->plugins as $plugin) { + call_user_func($callback, $plugin); + } + } + + /** + * Returns plugin by slug + * + * @param string $slug plugin slug + * + * @return false|ExtraItem plugin item or false if not found + */ + protected function getBySlug($slug) + { + if (strlen($slug) === 0) { + return false; + } + + if (!isset($this->plugins[$slug])) { + return false; + } + + return (isset($this->plugins[$slug]) ? $this->plugins[$slug] : false); + } + + /** + * Install plugin slug + * + * @param string $slug plugin slug + * @param string $message message + * + * @return bool true if plugin installed and activated or false on failure + */ + public function install($slug, &$message = '') + { + if (strlen($slug) === 0) { + $message = __('Plugin slug is empty', 'duplicator'); + return false; + } + + if (($plugin = $this->getBySlug($slug)) == false) { + $message = __('Plugin not found', 'duplicator'); + return false; + } + + $result = true; + ob_start(); + if ($plugin->install() == false) { + $result = false; + } elseif ($plugin->activate() == false) { + $result = false; + } + $message = ob_get_clean(); + return $result; + } + + /** + * Init addon plugins + * + * @return void + */ + private static function getInitList() + { + $result = array(); + + $item = new ExtraItem( + __('OptinMonster', 'duplicator'), + 'optinmonster/optin-monster-wp-api.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-om.png', + __('Instantly get more subscribers, leads, and sales with the #1 conversion optimization toolkit. Create ' . + 'high converting popups, announcement bars, spin a wheel, and more with smart targeting and personalization.', 'duplicator'), + 'https://downloads.wordpress.org/plugin/optinmonster.zip', + 'https://wordpress.org/plugins/optinmonster/' + ); + + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('MonsterInsights', 'duplicator'), + 'google-analytics-for-wordpress/googleanalytics.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-mi.png', + __( + 'The leading WordPress analytics plugin that shows you how people find and use your website, so you can ' . + 'make data driven decisions to grow your business. Properly set up Google Analytics without writing code.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.zip', + 'https://wordpress.org/plugins/google-analytics-for-wordpress/' + ); + $item->setPro( + __('MonsterInsights Pro', 'duplicator'), + 'google-analytics-premium/googleanalytics-premium.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-mi.png', + __( + 'The leading WordPress analytics plugin that shows you how people find and use your website, so you ' . + 'can make data driven decisions to grow your business. Properly set up Google Analytics without writing code.', + 'duplicator' + ), + 'https://www.monsterinsights.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('WPForms', 'duplicator'), + 'wpforms-lite/wpforms.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-wpforms.png', + __( + 'The best drag & drop WordPress form builder. Easily create beautiful contact forms, surveys, payment ' . + 'forms, and more with our 100+ form templates. Trusted by over 4 million websites as the best forms plugin.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/wpforms-lite.zip', + 'https://wordpress.org/plugins/wpforms-lite/' + ); + $item->setPro( + __('WPForms Pro', 'duplicator'), + 'wpforms/wpforms.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-wpforms.png', + __( + 'The easiest drag & drop WordPress form builder plugin to create beautiful contact forms, subscription ' . + 'forms, payment forms, and more in minutes. No coding skills required.', + 'duplicator' + ), + 'https://wpforms.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('WP Mail SMTP', 'duplicator'), + 'wp-mail-smtp/wp_mail_smtp.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-smtp.png', + __( + 'Improve your WordPress email deliverability and make sure that your website emails reach user\'s inbox ' . + 'with the #1 SMTP plugin for WordPress. Over 3 million websites use it to fix WordPress email issues.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/wp-mail-smtp.zip', + 'https://wordpress.org/plugins/wp-mail-smtp/' + ); + $item->setPro( + __('WP Mail SMTP Pro', 'duplicator'), + 'wp-mail-smtp-pro/wp_mail_smtp.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-smtp.png', + __( + 'Improve your WordPress email deliverability and make sure that your website emails reach user\'s inbox ' . + 'with the #1 SMTP plugin for WordPress. Over 3 million websites use it to fix WordPress email issues.', + 'duplicator' + ), + 'https://wpmailsmtp.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('AIOSEO', 'duplicator'), + 'all-in-one-seo-pack/all_in_one_seo_pack.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-aioseo.png', + __( + 'The original WordPress SEO plugin and toolkit that improves your website\'s search rankings. Comes with ' . + 'all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/all-in-one-seo-pack.zip', + 'https://wordpress.org/plugins/all-in-one-seo-pack/' + ); + $item->setPro( + __('AIOSEO Pro', 'duplicator'), + 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-aioseo.png', + __( + 'The original WordPress SEO plugin and toolkit that improves your website\'s search rankings. Comes ' . + 'with all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more.', + 'duplicator' + ), + 'https://aioseo.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('SeedProd', 'duplicator'), + 'coming-soon/coming-soon.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-seedprod.png', + __('The best WordPress coming soon page plugin to create a beautiful coming soon page, maintenance mode page, ' . + 'or landing page. No coding skills required.', 'duplicator'), + 'https://downloads.wordpress.org/plugin/coming-soon.zip', + 'https://wordpress.org/plugins/coming-soon/' + ); + $item->setPro( + __('SeedProd Pro', 'duplicator'), + 'seedprod-coming-soon-pro-5/seedprod-coming-soon-pro-5.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-seedprod.png', + __('The best WordPress coming soon page plugin to create a beautiful coming soon page, maintenance mode ' . + 'page, or landing page. No coding skills required.', 'duplicator'), + 'https://www.seedprod.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('RafflePress', 'duplicator'), + 'rafflepress/rafflepress.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-rp.png', + __( + 'Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and social ' . + 'media followers with the most powerful giveaways & contests plugin for WordPress.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/rafflepress.zip', + 'https://wordpress.org/plugins/rafflepress/' + ); + $item->setPro( + __('RafflePress Pro', 'duplicator'), + 'rafflepress-pro/rafflepress-pro.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-rp.png', + __( + 'Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and ' . + 'social media followers with the most powerful giveaways & contests plugin for WordPress.', + 'duplicator' + ), + 'https://rafflepress.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('PushEngage', 'duplicator'), + 'pushengage/main.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-pushengage.png', + __( + 'Connect with your visitors after they leave your website with the leading web push notification software. ' . + 'Over 10,000+ businesses worldwide use PushEngage to send 9 billion notifications each month.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/pushengage.zip', + 'https://wordpress.org/plugins/pushengage/' + ); + + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('Smash Balloon Instagram Feeds', 'duplicator'), + 'instagram-feed/instagram-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-instagram.png', + __( + 'Easily display Instagram content on your WordPress site without writing any code. Comes with multiple templates, ' . + 'ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/instagram-feed.zip', + 'https://wordpress.org/plugins/instagram-feed/' + ); + $item->setPro( + __('Smash Balloon Instagram Feeds Pro', 'duplicator'), + 'instagram-feed-pro/instagram-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-instagram.png', + __( + 'Easily display Instagram content on your WordPress site without writing any code. Comes with multiple ' . + 'templates, ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites.', + 'duplicator' + ), + 'https://smashballoon.com/instagram-feed/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('Smash Balloon Facebook Feeds', 'duplicator'), + 'custom-facebook-feed/custom-facebook-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-fb.png', + __( + 'Easily display Facebook content on your WordPress site without writing any code. Comes with multiple templates, ' . + 'ability to embed albums, group content, reviews, live videos, comments, and reactions.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/custom-facebook-feed.zip', + 'https://wordpress.org/plugins/custom-facebook-feed/' + ); + $item->setPro( + __('Smash Balloon Facebook Feeds Pro', 'duplicator'), + 'custom-facebook-feed-pro/custom-facebook-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-fb.png', + __( + 'Easily display Facebook content on your WordPress site without writing any code. Comes with multiple templates, ' . + 'ability to embed albums, group content, reviews, live videos, comments, and reactions.', + 'duplicator' + ), + 'https://smashballoon.com/custom-facebook-feed/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('Smash Balloon Twitter Feeds', 'duplicator'), + 'custom-twitter-feeds/custom-twitter-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-twitter.png', + __( + 'Easily display Twitter content in WordPress without writing any code. Comes with multiple layouts, ability ' . + 'to combine multiple Twitter feeds, Twitter card support, tweet moderation, and more.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/custom-twitter-feeds.zip', + 'https://wordpress.org/plugins/custom-twitter-feeds/' + ); + $item->setPro( + __('Smash Balloon Twitter Feeds Pro', 'duplicator'), + 'custom-twitter-feeds-pro/custom-twitter-feeds.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-twitter.png', + __( + 'Easily display Twitter content in WordPress without writing any code. Comes with multiple layouts, ' . + 'ability to combine multiple Twitter feeds, Twitter card support, tweet moderation, and more.', + 'duplicator' + ), + 'https://smashballoon.com/custom-twitter-feeds/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('Smash Balloon YouTube Feeds', 'duplicator'), + 'feeds-for-youtube/youtube-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-youtube.png', + __( + 'Easily display YouTube videos on your WordPress site without writing any code. Comes with multiple layouts, ' . + 'ability to embed live streams, video filtering, ability to combine multiple channel videos, and more.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/feeds-for-youtube.zip', + 'https://wordpress.org/plugins/feeds-for-youtube/' + ); + $item->setPro( + __('Smash Balloon YouTube Feeds Pro', 'duplicator'), + 'youtube-feed-pro/youtube-feed.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sb-youtube.png', + __( + 'Easily display YouTube videos on your WordPress site without writing any code. Comes with multiple ' . + 'layouts, ability to embed live streams, video filtering, ability to combine multiple channel videos, and more.', + 'duplicator' + ), + 'https://smashballoon.com/youtube-feed/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('TrustPulse', 'duplicator'), + 'trustpulse-api/trustpulse.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-trustpulse.png', + __( + 'Boost your sales and conversions by up to 15% with real-time social proof notifications. TrustPulse helps ' . + 'you show live user activity and purchases to help convince other users to purchase.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/trustpulse-api.zip', + 'https://wordpress.org/plugins/trustpulse-api/' + ); + + $result[$item->getSlug()] = $item; + + + $item = new ExtraItem( + __('SearchWP', 'duplicator'), + 'searchwp/index.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-searchwp.png', + __( + 'The most advanced WordPress search plugin. Customize your WordPress search algorithm, reorder search results, ' . + 'track search metrics, and everything you need to leverage search to grow your business.', + 'duplicator' + ), + 'https://searchwp.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('AffiliateWP', 'duplicator'), + 'affiliate-wp/affiliate-wp.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-affwp.png', + __( + 'The #1 affiliate management plugin for WordPress. Easily create an affiliate program for your eCommerce ' . + 'store or membership site within minutes and start growing your sales with the power of referral marketing.', + 'duplicator' + ), + 'https://affiliatewp.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator', + false + ); + + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('WP Simple Pay', 'duplicator'), + 'stripe/stripe-checkout.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-wp-simple-pay.png', + __( + 'The #1 Stripe payments plugin for WordPress. Start accepting one-time and recurring payments on your ' . + 'WordPress site without setting up a shopping cart. No code required.', + 'duplicator' + ), + 'https://downloads.wordpress.org/plugin/stripe.zip', + 'https://wordpress.org/plugins/stripe/' + ); + $item->setPro( + __('WP Simple Pay Pro', 'duplicator'), + 'wp-simple-pay-pro-3/simple-pay.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-wp-simple-pay.png', + __( + 'The #1 Stripe payments plugin for WordPress. Start accepting one-time and recurring payments on your ' . + 'WordPress site without setting up a shopping cart. No code required.', + 'duplicator' + ), + 'https://wpsimplepay.com/lite-upgrade/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('Easy Digital Downloads', 'duplicator'), + 'easy-digital-downloads/easy-digital-downloads.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-edd.png', + __('The best WordPress eCommerce plugin for selling digital downloads. Start selling eBooks, software, music, ' . + 'digital art, and more within minutes. Accept payments, manage subscriptions, advanced access control, and more.', 'duplicator'), + 'https://downloads.wordpress.org/plugin/easy-digital-downloads.zip', + 'https://wordpress.org/plugins/easy-digital-downloads/' + ); + + $result[$item->getSlug()] = $item; + + $item = new ExtraItem( + __('Sugar Calendar', 'duplicator'), + 'sugar-calendar-lite/sugar-calendar-lite.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sugarcalendar.png', + __('A simple & powerful event calendar plugin for WordPress that comes with all the event management features ' . + 'including payments, scheduling, timezones, ticketing, recurring events, and more.', 'duplicator'), + 'https://downloads.wordpress.org/plugin/sugar-calendar-lite.zip', + 'https://wordpress.org/plugins/sugar-calendar-lite/' + ); + $item->setPro( + __('Sugar Calendar Pro', 'duplicator'), + 'sugar-calendar/sugar-calendar.php', + DUPLICATOR_PLUGIN_URL . 'assets/img/about/plugin-sugarcalendar.png', + __('A simple & powerful event calendar plugin for WordPress that comes with all the event management features ' . + 'including payments, scheduling, timezones, ticketing, recurring events, and more.', 'duplicator'), + 'https://sugarcalendar.com/?utm_source=duplicatorplugin&utm_medium=link&utm_campaign=About%20Duplicator' + ); + $result[$item->getSlug()] = $item; + + return $result; + } +} diff --git a/src/Utils/Upsell.php b/src/Utils/Upsell.php new file mode 100644 index 00000000..78cc252c --- /dev/null +++ b/src/Utils/Upsell.php @@ -0,0 +1,85 @@ +getDataToSend(); + + if (self::request(self::END_POINT_PLUGIN_STATS, $data)) { + PluginData::getInstance()->updateLastSendTime(); + return true; + } else { + return false; + } + } + + /** + * Disabled usage tracking + * + * @return bool true if data was sent successfully, false otherwise + */ + public static function disableUsageTracking() + { + if (DUPLICATOR_USTATS_DISALLOW) { // @phpstan-ignore-line + // Don't use StatsBootstrap::isTrackingAllowed beacause on disalbe usage tracking i necessary disable the tracking on server + return false; + } + + // Remove usage tracking data on server + $data = PluginData::getInstance()->getDisableDataToSend(); + return self::request(self::END_POINT_DISABLE, $data, 'Disable usage tracking error'); + } + + /** + * Sent installer statistics + * + * @return bool true if data was sent successfully, false otherwise + */ + public static function installerSend() + { + if (!StatsBootstrap::isTrackingAllowed()) { + return false; + } + + $data = InstallerData::getInstance()->getDataToSend(); + return self::request(self::END_POINT_INSTALLER, $data, 'Installer usage tracking error'); + } + + /** + * Request to usage tracking server + * + * @param string $endPoint end point + * @param array $data data to send + * @param string $traceMessagePerefix trace message prefix + * + * @return bool true if data was sent successfully, false otherwise + */ + protected static function request($endPoint, $data, $traceMessagePerefix = 'Error sending usage tracking') + { + try { + global $wp_version; + + $agent_string = "WordPress/" . $wp_version; + $postParams = array( + 'method' => 'POST', + 'timeout' => 10, + 'redirection' => 5, + 'sslverify' => false, + 'httpversion' => '1.1', + //'blocking' => false, + 'user-agent' => $agent_string, + 'body' => $data, + ); + + $url = self::getRemoteHost() . $endPoint . '/'; + $response = wp_remote_post($url, $postParams); + + if (is_wp_error($response)) { + /** @var WP_Error $response */ + DUP_Log::trace('URL Request: ' . $url); + DUP_Log::trace($traceMessagePerefix . ' code: ' . $response->get_error_code()); + DUP_Log::trace('Error message: ' . $response->get_error_message()); + return false; + } elseif ($response['response']['code'] < 200 || $response['response']['code'] >= 300) { + DUP_Log::trace('URL Request: ' . $url); + DUP_Log::trace($traceMessagePerefix . ' code: ' . $response['response']['code']); + DUP_Log::trace('Error message: ' . $response['response']['message']); + DUP_Log::traceObject('Data', $data); + return false; + } else { + DUP_Log::trace('Usage tracking updated successfully'); + return true; + } + } catch (Exception $e) { + DUP_Log::trace($traceMessagePerefix . ' trace msg: ' . $e->getMessage() . "\n" . SnapLog::getTextException($e, false)); + return false; + } catch (Error $e) { + DUP_Log::trace($traceMessagePerefix . ' trace msg: ' . $e->getMessage() . "\n" . SnapLog::getTextException($e, false)); + return false; + } + } + + /** + * Get remote host + * + * @return string + */ + public static function getRemoteHost() + { + if (DUPLICATOR_CUSTOM_STATS_REMOTE_HOST != '') { // @phpstan-ignore-line + return DUPLICATOR_CUSTOM_STATS_REMOTE_HOST; + } else { + return self::DEFAULT_REMOTE_HOST; + } + } +} diff --git a/src/Utils/UsageStatistics/InstallerData.php b/src/Utils/UsageStatistics/InstallerData.php new file mode 100644 index 00000000..808d6400 --- /dev/null +++ b/src/Utils/UsageStatistics/InstallerData.php @@ -0,0 +1,88 @@ + + */ + public function getDataToSend() + { + /** @var wpdb $wpdb */ + global $wpdb; + + $data = (object) MigrationMng::getMigrationData(); + + $result = array( + 'api_version' => CommStats::API_VERSION, + 'plugin' => $data->plugin, + 'plugin_version' => $data->installerVersion, + 'install_type' => StatsUtil::getInstallType($data->installType), + 'logic_modes' => StatsUtil::getLogicModes($data->logicModes), + 'template' => StatsUtil::getTemplate($data->template), + 'wp_version' => get_bloginfo('version'), + 'db_engine' => SnapDB::getDBEngine($wpdb->dbh), // @phpstan-ignore-line + 'db_version' => DUP_DB::getVersion(), + // SOURCE SITE INFO + 'source_phpv' => SnapUtil::getVersion($data->phpVersion, 3), + // TARGET SITE INFO + 'target_phpv' => SnapUtil::getVersion(phpversion(), 3), + // PACKAGE INFO + 'license_type' => StatsUtil::getLicenseType($data->licenseType), + 'archive_type' => $data->archiveType, + 'site_size_mb' => round(((int) $data->siteSize) / 1024 / 1024, 2), + 'site_num_files' => $data->siteNumFiles, + 'site_db_size_mb' => round(((int) $data->siteDbSize) / 1024 / 1024, 2), + 'site_db_num_tbl' => $data->siteDBNumTables, + 'components' => StatsUtil::getStatsComponents($data->components), + ); + + $rules = array( + 'api_version' => 'string|max:7', // 1.0 + 'plugin_version' => 'string|max:25', + 'wp_version' => 'string|max:25', + 'db_engine' => 'string|max:25', + 'db_version' => 'string|max:25', + // SOURCE SERVER INFO + 'source_phpv' => 'string|max:25', + // TARGET SERVER INFO + 'target_phpv' => 'string|max:25', + ); + return StatsUtil::sanitizeFields($result, $rules); + } +} diff --git a/src/Utils/UsageStatistics/PluginData.php b/src/Utils/UsageStatistics/PluginData.php new file mode 100644 index 00000000..9e216124 --- /dev/null +++ b/src/Utils/UsageStatistics/PluginData.php @@ -0,0 +1,434 @@ +getProperties(); + foreach ($props as $prop) { + if (isset($data[$prop->getName()])) { + $prop->setAccessible(true); + $prop->setValue($this, $data[$prop->getName()]); + } + } + } else { + $this->identifier = self::generateIdentifier(); + $this->save(); + } + } + + /** + * Get instance + * + * @return self + */ + public static function getInstance() + { + if (self::$instance === null) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Save plugin data + * + * @return bool True if data has been saved, false otherwise + */ + public function save() + { + $values = get_object_vars($this); + return update_option(self::PLUGIN_DATA_OPTION_KEY, SnapJson::jsonEncodePPrint($values)); + } + + /** + * Get identifier + * + * @return string + */ + public function getIdentifier() + { + return $this->identifier; + } + + /** + * Update from migrate data + * + * @param StdClass $data Migration data + * + * @return bool + */ + public function updateFromMigrateData(stdClass $data) + { + $save = false; + if ( + isset($data->ustatIdentifier) && + strlen($data->ustatIdentifier) > 0 && + $data->ustatIdentifier !== $this->identifier + ) { + $this->identifier = $data->ustatIdentifier; + $save = true; + } + + return ($save ? $this->save() : true); + } + + /** + * Return usage tracking data + * + * @return array + */ + public function getDataToSend() + { + $result = $this->getBasicInfos(); + $result = array_merge($result, $this->getPluginInfos()); + $result = array_merge($result, $this->getSiteInfos()); + $result = array_merge($result, $this->getManualPackageInfos()); + $result = array_merge($result, $this->getSettingsInfos()); + + $rules = array( + 'api_version' => 'string|max:7', // 1.0 + 'identifier' => 'string|max:44', + // BASIC INFO + 'plugin_version' => 'string|max:25', + 'php_version' => 'string|max:25', + 'wp_version' => 'string|max:25', + // PLUGIN INFO + 'pinstall_version' => '?string|max:25', + // SITE INFO + 'servertype' => 'string|max:25', + 'db_engine' => 'string|max:25', + 'db_version' => 'string|max:25', + 'timezoneoffset' => 'string|max:10', + 'locale' => 'string|max:10', + 'themename' => 'string|max:255', + 'themeversion' => 'string|max:25', + ); + + return StatsUtil::sanitizeFields($result, $rules); + } + + /** + * Get disable tracking data + * + * @return array + */ + public function getDisableDataToSend() + { + $result = $this->getBasicInfos(); + + $rules = array( + 'api_version' => 'string|max:7', // 1.0 + 'identifier' => 'string|max:44', + // BASIC INFO + 'plugin_version' => 'string|max:25', + 'php_version' => 'string|max:25', + 'wp_version' => 'string|max:25', + ); + + return StatsUtil::sanitizeFields($result, $rules); + } + + /** + * Set status + * + * @param string $status Status: active, inactive or uninstalled + * + * @return void + */ + public function setStatus($status) + { + if ($this->pluginStatus === $status) { + return; + } + + switch ($status) { + case self::PLUGIN_STATUS_ACTIVE: + case self::PLUGIN_STATUS_INACTIVE: + $this->pluginStatus = $status; + $this->save(); + break; + } + } + + /** + * Get status + * + * @return string Enum: self::PLUGIN_STATUS_ACTIVE, self::PLUGIN_STATUS_INACTIVE or self::PLUGIN_STATUS_UNINSTALLED + */ + public function getStatus() + { + return $this->pluginStatus; + } + + /** + * Add paackage build count and date for manual and schedule build + * + * @param DUP_Package $package Package + * + * @return void + */ + public function addPackageBuild(DUP_Package $package) + { + if ($package->Status == DUP_PackageStatus::COMPLETE) { + $this->buildCount++; + $this->buildLastDate = time(); + } else { + $this->buildFailedCount++; + $this->buildFailedLastDate = time(); + } + + $this->save(); + } + + /** + * Set site size + * + * @param int $size Site size in bytes + * @param int $numFiles Number of files + * @param int $dbSize Database size in bytes + * @param int $numTables Number of tables + * + * @return void + */ + public function setSiteSize($size, $numFiles, $dbSize, $numTables) + { + $this->siteSizeMB = round(((int) $size) / 1024 / 1024, 2); + $this->siteNumFiles = (int) $numFiles; + $this->siteDbSizeMB = round(((int) $dbSize) / 1024 / 1024, 2); + $this->siteDbNumTables = (int) $numTables; + $this->save(); + } + + /** + * Update last send time + * + * @return void + */ + public function updateLastSendTime() + { + $this->lastSendTime = time(); + $this->save(); + } + + /** + * Get last send time + * + * @return int + */ + public function getLastSendTime() + { + return $this->lastSendTime; + } + + /** + * Get basic infos + * + * @return array + */ + protected function getBasicInfos() + { + return array( + 'api_version' => CommStats::API_VERSION, + 'identifier' => $this->identifier, + 'plugin' => $this->plugin, + 'plugin_status' => $this->pluginStatus, + 'plugin_version' => DUPLICATOR_VERSION, + 'php_version' => SnapUtil::getVersion(phpversion(), 3), + 'wp_version' => get_bloginfo('version'), + ); + } + + /** + * Return plugin infos + * + * @return array + */ + protected function getPluginInfos() + { + if (($installInfo = DUP_LITE_Plugin_Upgrade::getNewInstallInfo()) === false) { + $installInfo = array( + 'version' => null, + 'time' => null, + ); + } + + return array( + 'pinstall_date' => ($installInfo['time'] == null ? null : date('Y-m-d H:i:s', $installInfo['time'])), + 'pinstall_version' => ($installInfo['version'] == null ? null : $installInfo['version']), + 'license_type' => StatsUtil::getLicenseType(), + 'license_status' => StatsUtil::getLicenseStatus(), + ); + } + + /** + * Return site infos + * + * @return array + */ + protected function getSiteInfos() + { + /** @var wpdb $wpdb */ + global $wpdb; + + $theme_data = wp_get_theme(); + + return array( + 'servertype' => StatsUtil::getServerType(), + 'db_engine' => SnapDB::getDBEngine($wpdb->dbh), // @phpstan-ignore-line + 'db_version' => DUP_DB::getVersion(), + 'is_multisite' => is_multisite(), + 'sites_count' => count(SnapWP::getSitesIds()), + 'user_count' => SnapWp::getUsersCount(), + 'timezoneoffset' => get_option('gmt_offset'), /** @todo evaluate use wp or server timezone offset */ + 'locale' => get_locale(), + 'am_family' => StatsUtil::getAmFamily(), + 'themename' => $theme_data->get('Name'), + 'themeversion' => $theme_data->get('Version'), + 'site_size_mb' => ($this->siteSizeMB == 0 ? null : $this->siteSizeMB), + 'site_num_files' => ($this->siteNumFiles == 0 ? null : $this->siteNumFiles), + 'site_db_size_mb' => ($this->siteDbSizeMB == 0 ? null : $this->siteDbSizeMB), + 'site_db_num_tbl' => ($this->siteDbNumTables == 0 ? null : $this->siteDbNumTables), + ); + } + + /** + * Return manal package infos + * + * @return array + */ + protected function getManualPackageInfos() + { + return array( + 'packages_build_count' => $this->buildCount, + 'packages_build_last_date' => ($this->buildLastDate == 0 ? null : date('Y-m-d H:i:s', $this->buildLastDate)), + 'packages_build_failed_count' => $this->buildFailedCount, + 'packages_build_failed_last_date' => ($this->buildFailedLastDate == 0 ? null : date('Y-m-d H:i:s', $this->buildFailedLastDate)), + 'packages_count' => DUP_Package::getNumCompletePackages(), + ); + } + + /** + * Return granular permissions infos + * + * @return array + */ + protected function getSettingsInfos() + { + return array( + 'settings_archive_build_mode' => StatsUtil::getArchiveBuildMode(), + 'settings_db_build_mode' => StatsUtil::getDbBuildMode(), + 'settings_usage_enabled' => StatsBootstrap::isTrackingAllowed(), + ); + } + + /** + * Return unique identifier + * + * @return string + */ + protected static function generateIdentifier() + { + $maxRand = strlen(self::IDENTIFIER_CHARS) - 1; + + $result = ''; + for ($i = 0; $i < 44; $i++) { + $result .= substr(self::IDENTIFIER_CHARS, wp_rand(0, $maxRand), 1); + } + + return $result; + } +} diff --git a/src/Utils/UsageStatistics/StatsBootstrap.php b/src/Utils/UsageStatistics/StatsBootstrap.php new file mode 100644 index 00000000..c3dced01 --- /dev/null +++ b/src/Utils/UsageStatistics/StatsBootstrap.php @@ -0,0 +1,136 @@ +getStatus() !== PluginData::PLUGIN_STATUS_ACTIVE) { + PluginData::getInstance()->setStatus(PluginData::PLUGIN_STATUS_ACTIVE); + CommStats::pluginSend(); + } + } + + /** + * Deactivation action + * + * @return void + */ + public static function deactivationAction() + { + // Unschedule custom cron event for cleanup if it's scheduled + if (wp_next_scheduled(self::USAGE_TRACKING_CRON_HOOK)) { + $timestamp = wp_next_scheduled(self::USAGE_TRACKING_CRON_HOOK); + wp_unschedule_event($timestamp, self::USAGE_TRACKING_CRON_HOOK); + } + + PluginData::getInstance()->setStatus(PluginData::PLUGIN_STATUS_INACTIVE); + CommStats::pluginSend(); + } + + /** + * Add package build, + * don't use PluginData::getInstance()->addPackageBuild() directly in hook to avoid useless init + * + * @param DUP_Package $package Package + * @param int $status Status DUP_PRO_PackageStatus Enum + * + * @return void + */ + public static function addPackageBuild(DUP_Package $package, $status) + { + if ($status >= DUP_PackageStatus::CREATED && $status < DUP_PackageStatus::COMPLETE) { + return; + } + PluginData::getInstance()->addPackageBuild($package); + } + + /** + * Add site size statistics + * + * @param DUP_Package $package Package + * @param array $report Scan report + * + * @return void + */ + public static function addSiteSizes(DUP_Package $package, $report) + { + if ($package->Archive->ExportOnlyDB) { + return; + } + + PluginData::getInstance()->setSiteSize( + $report['ARC']['USize'], + $report['ARC']['UFullCount'], + $report['DB']['RawSize'], + $report['DB']['TableCount'] + ); + } + + /** + * Is tracking allowed + * + * @return bool + */ + public static function isTrackingAllowed() + { + if (DUPLICATOR_USTATS_DISALLOW) { // @phpstan-ignore-line + return false; + } + + return DUP_Settings::Get('usage_tracking', false); + } + + /** + * Send plugin statistics + * + * @return void + */ + public static function sendPluginStatCron() + { + if (!self::isTrackingAllowed()) { + return; + } + + DUP_Log::trace("CRON: Sending plugin statistics"); + CommStats::pluginSend(); + } +} diff --git a/src/Utils/UsageStatistics/StatsUtil.php b/src/Utils/UsageStatistics/StatsUtil.php new file mode 100644 index 00000000..ff81ec46 --- /dev/null +++ b/src/Utils/UsageStatistics/StatsUtil.php @@ -0,0 +1,261 @@ + $data Data + * @param array $rules Rules + * + * @return array + */ + public static function sanitizeFields($data, $rules) + { + foreach ($data as $key => $val) { + if (!isset($rules[$key])) { + continue; + } + + $matches = null; + if (preg_match('/(\??)(int|float|bool|string)(?:\|max:(\d+))?/', $rules[$key], $matches) !== 1) { + throw new Exception("Invalid sanitize rule: {$rules[$key]}"); + } + + $nullable = $matches[1] === '?'; + $type = $matches[2]; + $max = isset($matches[3]) ? (int) $matches[3] : PHP_INT_MAX; + + if ($nullable && $val === null) { + continue; + } + + switch ($type) { + case 'int': + $data[$key] = (int) $val; + break; + case 'float': + $data[$key] = (float) $val; + break; + case 'bool': + $data[$key] = (bool) $val; + break; + case 'string': + $data[$key] = substr((string) $val, 0, $max); + break; + default: + throw new Exception("Unknown sanitize rule: {$rules[$key]}"); + } + } + + return $data; + } +} diff --git a/src/Views/AdminNotices.php b/src/Views/AdminNotices.php new file mode 100644 index 00000000..a2fecfaf --- /dev/null +++ b/src/Views/AdminNotices.php @@ -0,0 +1,500 @@ +roles) && !current_user_can('export'); + } + + if ($noCapabilitiesNotice) { + $notices[] = array(__CLASS__, 'showNoExportCapabilityNotice'); + } + + if (is_multisite()) { + $displayNotices = is_super_admin() && current_user_can('export'); + } else { + $displayNotices = current_user_can('export'); + } + + if ($displayNotices) { + $notices[] = array(__CLASS__, 'clearInstallerFilesAction'); // BEFORE MIGRATION SUCCESS NOTICE + $notices[] = array(__CLASS__, 'migrationSuccessNotice'); + $notices[] = array(__CLASS__, 'installAutoDeactivatePlugins'); + } + + $action = is_multisite() ? 'network_admin_notices' : 'admin_notices'; + foreach ($notices as $notice) { + add_action($action, $notice); + } + } + + /** + * Remove all notices coming from other plugins + * + * @param string $hook Hook string + * + * @return void + */ + public static function unhookThirdPartyNotices($hook) + { + if (!ControllersManager::isDuplicatorPage()) { + return; + } + + global $wp_filter; + $filterHooks = array('user_admin_notices', 'admin_notices', 'all_admin_notices', 'network_admin_notices'); + foreach ($filterHooks as $filterHook) { + if (empty($wp_filter[$filterHook]->callbacks) || !is_array($wp_filter[$filterHook]->callbacks)) { + continue; + } + + foreach ($wp_filter[$filterHook]->callbacks as $priority => $hooks) { + foreach ($hooks as $name => $arr) { + if (is_object($arr['function']) && $arr['function'] instanceof Closure) { + unset($wp_filter[$filterHook]->callbacks[$priority][$name]); + continue; + } + if ( + !empty($arr['function'][0]) && + is_object($arr['function'][0]) && + strpos(get_class($arr['function'][0]), Autoloader::ROOT_NAMESPACE) === 0 + ) { + continue; + } + if (!empty($name) && strpos($name, Autoloader::ROOT_NAMESPACE) !== 0) { + unset($wp_filter[$filterHook]->callbacks[$priority][$name]); + } + } + } + } + } + + /** + * Clear installer file action + * + * @return void + */ + public static function clearInstallerFilesAction() + { + + if (!\DUP_CTRL_Tools::isDiagnosticPage() || get_option(self::OPTION_KEY_MIGRATION_SUCCESS_NOTICE) == true) { + return; + } + + + if (SnapUtil::filterInputRequest('action', FILTER_DEFAULT) === 'installer') { + if (! wp_verify_nonce($_REQUEST['_wpnonce'], 'duplicator_cleanup_page')) { + echo '

                        ' . __('Security issue', 'duplicator') . '

                        '; + exit; // Get out of here bad nounce! + } + + ?> +
                        + +
                        + id == 'duplicator_page_duplicator-tools' && isset($_GET['action']) && $_GET['action'] == 'installer'); + if (DUP_Server::hasInstallerFiles() && !$is_installer_cleanup_req) { + MigrationMng::renameInstallersPhpFiles(); + + $on_active_tab = isset($_GET['section']) ? $_GET['section'] : ''; + echo '

                        '; + + //Safe Mode Notice + $safe_html = ''; + if (get_option("duplicator_exe_safe_mode", 0) > 0) { + $safe_msg1 = __('Safe Mode:', 'duplicator'); + $safe_msg2 = __('During the install safe mode was enabled deactivating all plugins.
                        Please be sure to ', 'duplicator'); + $safe_msg3 = __('re-activate the plugins', 'duplicator'); + $safe_html = "

                        {$safe_msg1}
                        {$safe_msg2} {$safe_msg3}!

                        "; + } + + //On Tools > Cleanup Page + if ($screen->id == 'duplicator_page_duplicator-tools' && ($on_active_tab == "info" || $on_active_tab == '')) { + $title = __('This site has been successfully migrated!', 'duplicator'); + $msg1 = __('Final step(s):', 'duplicator'); + $msg2 = __('This message will be removed after all installer files are removed. Installer files must be removed to maintain a secure site. ' + . 'Click the link above or button below to remove all installer files and complete the migration.', 'duplicator'); + + echo " " . esc_html($title) . + "
                        {$safe_html} " . esc_html($msg1) . "
                        "; + printf( + "1. %s
                        ", + esc_html__('Remove Installation Files Now!', 'duplicator') + ); + printf( + "2. %s
                        ", + esc_html__('Optionally, Review Duplicator at WordPress.org...', 'duplicator') + ); + echo "
                        " . esc_html($msg2) . "
                        "; + + //All other Pages + } else { + $title = __('Migration Almost Complete!', 'duplicator'); + $msg = __( + 'Reserved Duplicator installation files have been detected in the root directory. Please delete these installation files to ' + . 'avoid security issues.
                        Go to:Duplicator > Tools > Information >Stored Data and click the "Remove Installation Files" button', + 'duplicator' + ); + + $nonce = wp_create_nonce('duplicator_cleanup_page'); + $url = self_admin_url('admin.php?page=duplicator-tools&tab=diagnostics§ion=info&_wpnonce=' . $nonce); + echo "{$title}
                        {$safe_html} {$msg}"; + @printf("
                        %s", __('Take me there now!', 'duplicator')); + } + echo "

                        "; + } + } + + /** + * Shows a message for redirecting a page + * + * @param string $location The location to redirect to + * + * @return never + */ + public static function redirect($location) + { + echo '
                        '; + esc_html__('Redirecting Please Wait...', 'duplicator'); + echo '
                        '; + echo ""; + die(esc_html__('Invalid token permissions to perform this request.', 'duplicator')); + } + + /** + * Shows install deactivated function + * + * @return void + */ + public static function installAutoDeactivatePlugins() + { + $reactivatePluginsAfterInstallation = get_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL, false); + + $pluginsToActive = get_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL, false); + if (!is_array($pluginsToActive) || empty($pluginsToActive)) { + return false; + } + + $shouldBeActivated = array(); + $allPlugins = get_plugins(); + foreach ($pluginsToActive as $index => $pluginSlug) { + if (!isset($allPlugins[$pluginSlug])) { + unset($pluginsToActive[$index]); + continue; + } + + $isActive = is_plugin_active($pluginSlug); + + if (!$isActive && isset($allPlugins[$pluginSlug])) { + $shouldBeActivated[$pluginSlug] = $allPlugins[$pluginSlug]['Name']; + } else { + unset($pluginsToActive[$index]); + } + } + + if (empty($shouldBeActivated)) { + delete_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL); + return; + } else { + update_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL, $pluginsToActive); + } + + $activatePluginsAnchors = array(); + foreach ($shouldBeActivated as $slug => $title) { + $activateURL = wp_nonce_url(admin_url('plugins.php?action=activate&plugin=' . $slug), 'activate-plugin_' . $slug); + $anchorTitle = sprintf(esc_html__('Activate %s', 'duplicator'), $title); + $activatePluginsAnchors[] = '' . + $title . ''; + } + ?> +
                        +

                        + " . esc_html__("Warning!", "duplicator") . " " . esc_html__("Migration Almost Complete!", "duplicator") . "
                        "; + echo esc_html__( + "Plugin(s) listed here have been deactivated during installation to help prevent issues. Please activate them to finish this migration: ", + "duplicator" + ) . "
                        "; + echo implode(' ,', $activatePluginsAnchors); + ?> +

                        +
                        + id, $duplicator_pages) || (isset($notices[$notice_id]) && 'true' === $notices[$notice_id])) { + return; + } + + // not using DUP_Util::getTablePrefix() in place of $tablePrefix because AdminNotices included initially (Duplicator\Lite\Requirement + // is depended on the AdminNotices) + $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? + $GLOBALS['wpdb']->base_prefix : + $GLOBALS['wpdb']->prefix; + $packagesCount = $GLOBALS['wpdb']->get_var('SELECT count(id) FROM ' . $tablePrefix . 'duplicator_packages WHERE status=100'); + + if ($packagesCount < DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE) { + return; + } + + $notices[$notice_id] = 'false'; + update_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, $notices); + $dismiss_url = wp_nonce_url( + add_query_arg(array( + 'action' => 'duplicator_set_admin_notice_viewed', + 'notice_id' => esc_attr($notice_id), + ), admin_url('admin-post.php')), + 'duplicator_set_admin_notice_viewed', + 'nonce' + ); + ?> +
                        +
                        +
                        + " + style="text-align:top; margin:0; height:60px; width:60px;" alt="Duplicator"> +
                        +
                        +

                        + + + + +

                        +

                        + + + + + + +

                        +
                        +
                        +
                        + roles) && !current_user_can('export')) { + $faqUrl = esc_url(LinkManager::getDocUrl( + 'how-to-resolve-duplicator-plugin-user-interface-ui-issues', + 'admin_notice', + 'duplicator menu missing' + )); + $errorMessage = __( + 'Duplicator
                        Your logged-in user role does not have export + capability so you don\'t have access to Duplicator functionality.', + 'duplicator' + ) . + "
                        " . + sprintf( + _x( + 'RECOMMENDATION: Add export capability to your role. See FAQ: ' . + '%1$sWhy is the Duplicator/Packages menu missing from my admin menu?%2$s', + '%1$s and %2$s are tags', + 'duplicator' + ), + '', + '' + ); + self::displayGeneralAdminNotice($errorMessage, self::GEN_ERROR_NOTICE, true); + } + } + + /** + * display genral admin notice by printing it + * + * @param string $htmlMsg html code to be printed + * @param integer $noticeType constant value of SELF::GEN_ + * @param boolean $isDismissible whether the notice is dismissable or not. Default is true + * @param array|string $extraClasses add more classes to the notice div + * + * @return void + */ + public static function displayGeneralAdminNotice($htmlMsg, $noticeType, $isDismissible = true, $extraClasses = array()) + { + if (empty($extraClasses)) { + $classes = array(); + } elseif (is_array($extraClasses)) { + $classes = $extraClasses; + } else { + $classes = array($extraClasses); + } + + $classes[] = 'notice'; + + switch ($noticeType) { + case self::GEN_INFO_NOTICE: + $classes[] = 'notice-info'; + break; + case self::GEN_SUCCESS_NOTICE: + $classes[] = 'notice-success'; + break; + case self::GEN_WARNING_NOTICE: + $classes[] = 'notice-warning'; + break; + case self::GEN_ERROR_NOTICE: + $classes[] = 'notice-error'; + break; + default: + throw new Exception('Invalid Admin notice type!'); + } + + if ($isDismissible) { + $classes[] = 'is-dismissible'; + } + + $classesStr = implode(' ', $classes); + ?> +
                        +

                        + + + + +

                        +
                        + setStripSpaces(true); + ?> +
                        + +
                        + +
                        + +
                        + render( + 'parts/DashboardWidget/package-create-section', + array ( + 'lastBackupString' => self::getLastBackupString() + ) + ); + } + + /** + * Render the last packages + * + * @return void + */ + protected static function renderRecentlyPackages() + { + /** @var DUP_Package[] */ + $packages = DUP_Package::get_packages_by_status( + array( + array( + 'op' => '>=', + 'status' => DUP_PackageStatus::COMPLETE + ) + ), + self::LAST_PACKAGES_LIMIT, + 0, + 'created DESC' + ); + + $totalsIds = DUP_Package::get_ids_by_status( + array( + array( + 'op' => '>=', + 'status' => DUP_PackageStatus::COMPLETE + ) + ) + ); + + $failuresIds = DUP_Package::get_ids_by_status( + array( + array( + 'op' => '<', + 'status' => 0 + ) + ) + ); + + TplMng::getInstance()->render( + 'parts/DashboardWidget/recently-packages', + array( + 'packages' => $packages, + 'totalPackages' => count($totalsIds), + 'totalFailures' => count($failuresIds) + ) + ); + } + + /** + * Render Duplicate sections + * + * @return void + */ + protected static function renderSections() + { + TplMng::getInstance()->render( + 'parts/DashboardWidget/sections-section', + array( + 'numSchedules' => 0, + 'numSchedulesEnabled' => 0, + 'numTemplates' => 1, + 'numStorages' => 1, + 'nextScheduleString' => '', + 'recoverDateString' => '' + ) + ); + } + + /** + * Get the last backup string + * + * @return string HTML string + */ + public static function getLastBackupString() + { + if (DUP_Package::isPackageRunning()) { + return ' ' . esc_html__('A package is currently running.', 'duplicator') . ''; + } + + /** @var DUP_Package[] */ + $lastPackage = DUP_Package::get_packages_by_status( + array( + array( + 'op' => '>=', + 'status' => DUP_PackageStatus::COMPLETE + ) + ), + 1, + 0, + 'created DESC' + ); + + if (empty($lastPackage)) { + return '' . esc_html__('No packages have been created yet.', 'duplicator') . ''; + } + + $createdTime = date(get_option('date_format'), strtotime($lastPackage[0]->Created)); + + if ($lastPackage[0]->getPackageLife() > self::LAST_PACKAGE_TIME_WARNING) { + $timeDiffClass = 'maroon'; + } else { + $timeDiffClass = 'green'; + } + + $timeDiff = sprintf( + _x('%s ago', '%s represents the time diff, eg. 2 days', 'duplicator'), + $lastPackage[0]->getPackageLife('human') + ); + + return '' . $createdTime . ' ' . + " (" . '' . + $timeDiff . + '' . ")"; + } + + /** + * Return randomly chosen one of recommended plugins. + * + * @return false|array{name: string,slug: string,more: string,pro: array{file: string}} + */ + protected static function getRecommendedPluginData() + { + $plugins = array( + 'google-analytics-for-wordpress/googleanalytics.php' => array( + 'name' => __('MonsterInsights', 'duplicator'), + 'slug' => 'google-analytics-for-wordpress', + 'more' => 'https://www.monsterinsights.com/', + 'pro' => array( + 'file' => 'google-analytics-premium/googleanalytics-premium.php', + ), + ), + 'all-in-one-seo-pack/all_in_one_seo_pack.php' => array( + 'name' => __('AIOSEO', 'duplicator'), + 'slug' => 'all-in-one-seo-pack', + 'more' => 'https://aioseo.com/', + 'pro' => array( + 'file' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', + ), + ), + 'coming-soon/coming-soon.php' => array( + 'name' => __('SeedProd', 'duplicator'), + 'slug' => 'coming-soon', + 'more' => 'https://www.seedprod.com/', + 'pro' => array( + 'file' => 'seedprod-coming-soon-pro-5/seedprod-coming-soon-pro-5.php', + ), + ), + 'wp-mail-smtp/wp_mail_smtp.php' => array( + 'name' => __('WP Mail SMTP', 'duplicator'), + 'slug' => 'wp-mail-smtp', + 'more' => 'https://wpmailsmtp.com/', + 'pro' => array( + 'file' => 'wp-mail-smtp-pro/wp_mail_smtp.php', + ), + ), + ); + + $installed = get_plugins(); + + foreach ($plugins as $id => $plugin) { + if (isset($installed[$id])) { + unset($plugins[$id]); + } + + if (isset($installed[$plugin['pro']['file']])) { + unset($plugins[$id]); + } + } + return ($plugins ? $plugins[ array_rand($plugins) ] : false); + } + + /** + * Recommended plugin block HTML. + * + * @return void + */ + public static function renderRecommendedPluginSection() + { + if (get_user_meta(get_current_user_id(), self::RECOMMENDED_PLUGIN_DISMISSED_OPT_KEY, true) != false) { + return; + } + + $plugin = self::getRecommendedPluginData(); + + if (empty($plugin)) { + return; + } + + $installUrl = wp_nonce_url( + self_admin_url('update.php?action=install-plugin&plugin=' . rawurlencode($plugin['slug'])), + 'install-plugin_' . $plugin['slug'] + ); + + TplMng::getInstance()->render( + 'parts/DashboardWidget/recommended-section', + array( + 'plugin' => $plugin, + 'installUrl' => $installUrl, + ) + ); + } +} diff --git a/src/Views/EducationElements.php b/src/Views/EducationElements.php new file mode 100644 index 00000000..47c9e5c0 --- /dev/null +++ b/src/Views/EducationElements.php @@ -0,0 +1,134 @@ +render('parts/Education/callout-cta'); + } + + /** + * Display did you know + * + * @return void + */ + public static function didYouKnow() + { + $features = Upsell::getProFeatureList(); + TplMng::getInstance()->render('parts/Education/did-you-know-blurb', array( + 'feature' => $features[array_rand($features)] + )); + } + + /** + * Display email form + * + * @return void + */ + public static function emailForm() + { + if (self::userIsSubscribed()) { + return; + } + + TplMng::getInstance()->render('parts/Education/subscribe-form'); + } + + /** + * Display did you know + * + * @return void + */ + public static function bottomBar() + { + if (get_user_meta(get_current_user_id(), self::DUP_PACKAGES_BOTTOM_BAR_DISMISSED, false) == true) { + return; + } + + $numberOfPackages = \DUP_Package::count_by_status(array( + array('op' => '=' , 'status' => \DUP_PackageStatus::COMPLETE ) + )); + + if ($numberOfPackages < 1) { + return; + } + + $features = self::getBottomBarFeatures(); + TplMng::getInstance()->render('parts/Education/packages-bottom-bar', array( + 'feature' => $features[array_rand($features)] + )); + } + + /** + * Get packages bottom bar feature list + * + * @return string[] + */ + private static function getBottomBarFeatures() + { + return array( + __('Scheduled Backups - Ensure that important data is regularly and consistently backed up, allowing for quick ' . + 'and efficient recovery in case of data loss.', 'duplicator'), + __('Cloud Backups - Back up to Dropbox, FTP, Google Drive, OneDrive, or Amazon S3 and more for safe storage.', 'duplicator'), + __('Recovery Points - Recovery Points provides protection against mistakes and bad updates by letting you ' . + 'quickly rollback your system to a known, good state.', 'duplicator'), + __('Secure File Encryption - Protect and secure the archive file with industry-standard AES-256 encryption', 'duplicator'), + __('Server to Server Import - Direct package import from source server or cloud storage using URL. No need ' . + 'to download the package to your desktop machine first.', 'duplicator'), + __('File & Database Table Filters - Use file and database filters to pick and choose exactly what you want to ' . + 'backup or transfer. No bloat!', 'duplicator'), + __('Large Site Support - Duplicator Pro has developed a new way to package backups especially tailored for ' . + 'larger site. No server timeouts or other restrictions.', 'duplicator'), + __('Mulstisite Support - Duplicator Pro supports multisite network backup & migration. You can even install ' . + 'a subsite as a standalone site.', 'duplicator'), + ); + } + + /** + * True if user is subscribed + * + * @return bool + */ + public static function userIsSubscribed() + { + return get_user_meta(get_current_user_id(), self::DUP_EMAIL_SUBSCRIBED_OPT_KEY, false); + } +} diff --git a/src/Views/ViewHelper.php b/src/Views/ViewHelper.php new file mode 100644 index 00000000..7f31e769 --- /dev/null +++ b/src/Views/ViewHelper.php @@ -0,0 +1,26 @@ +render('parts/admin-logo-header'); + } +} diff --git a/template/admin_pages/about_us/about_us/extra_plugin_item.php b/template/admin_pages/about_us/about_us/extra_plugin_item.php new file mode 100644 index 00000000..df985372 --- /dev/null +++ b/template/admin_pages/about_us/about_us/extra_plugin_item.php @@ -0,0 +1,69 @@ + $tplData + * @var ExtraItem $plugin + */ + +$plugin = $tplData['plugin']; + +switch ($plugin->getStatus()) { + case ExtraItem::STATUS_ACTIVE: + $buttonLabel = __('Activated', 'duplicator'); + $buttonClass = 'disabled'; + $statusClass = 'status-active'; + break; + case ExtraItem::STATUS_INSTALLED: + $buttonLabel = __('Activate', 'duplicator'); + $buttonClass = 'button-secondary'; + $statusClass = 'status-installed'; + break; + case ExtraItem::STATUS_NOT_INSTALLED: + default: + $buttonLabel = __('Install Plugin', 'duplicator'); + $buttonClass = 'button-primary'; + $statusClass = 'status-missing'; + break; +} + +?> +
                        +
                        +
                        + <?php echo $plugin->name; ?> logo +
                        + name; ?> +
                        +

                        desc; ?>

                        +
                        +
                        +
                        + + + getStatusText(); ?> + + +
                        +
                        + getURLType() === ExtraItem::URL_TYPE_GENERIC) { ?> + + + + + + +
                        +
                        +
                        +
                        diff --git a/template/admin_pages/about_us/about_us/extra_plugins.php b/template/admin_pages/about_us/about_us/extra_plugins.php new file mode 100644 index 00000000..499a3ba4 --- /dev/null +++ b/template/admin_pages/about_us/about_us/extra_plugins.php @@ -0,0 +1,32 @@ + $tplData + */ + +defined('ABSPATH') || die(); + +if (!current_user_can('install_plugins')) { + return; +} +?> +
                        +
                        +
                        + foreachCallback(function (ExtraItem $plugin) use ($tplMng) { + $tplMng->render( + 'admin_pages/about_us/about_us/extra_plugin_item', + array('plugin' => $plugin->skipLite() ? $plugin->getPro() : $plugin) + ); + }); + ?> +
                        +
                        +
                        diff --git a/template/admin_pages/about_us/about_us/info.php b/template/admin_pages/about_us/about_us/info.php new file mode 100644 index 00000000..151b85a4 --- /dev/null +++ b/template/admin_pages/about_us/about_us/info.php @@ -0,0 +1,55 @@ +
                        +
                        +

                        + +

                        +

                        + +

                        +

                        + +

                        +

                        + WPBeginner, the most popular ' . + 'lead-generation software, OptinMonster, ' . + 'the best WordPress analytics plugin, MonsterInsights, and more!', + 'duplicator' + ), + array( + 'a' => array( + 'href' => array(), + 'rel' => array(), + 'target' => array(), + ), + ) + ), + 'https://www.wpbeginner.com/?utm_source=duplicatorplugin&utm_medium=pluginaboutpage&utm_campaign=aboutduplicator', + 'https://optinmonster.com/?utm_source=duplicatorplugin&utm_medium=pluginaboutpage&utm_campaign=aboutduplicator', + 'https://www.monsterinsights.com/?utm_source=duplicatorplugin&utm_medium=pluginaboutpage&utm_campaign=aboutduplicator' + ); + ?> +

                        +

                        + +

                        +
                        + +
                        +
                        + <?php esc_attr_e('The Awesome Motive Team photo', 'duplicator'); ?> +
                        +
                        +
                        +
                        +
                        +
                        \ No newline at end of file diff --git a/template/admin_pages/about_us/about_us/main.php b/template/admin_pages/about_us/about_us/main.php new file mode 100644 index 00000000..571b5aa2 --- /dev/null +++ b/template/admin_pages/about_us/about_us/main.php @@ -0,0 +1,25 @@ + $tplData + */ +?> + +
                        +render('admin_pages/about_us/about_us/info'); +$tplMng->render('admin_pages/about_us/about_us/extra_plugins'); +?> +
                        diff --git a/template/admin_pages/about_us/getting_started/first_package.php b/template/admin_pages/about_us/getting_started/first_package.php new file mode 100644 index 00000000..0b46f11d --- /dev/null +++ b/template/admin_pages/about_us/getting_started/first_package.php @@ -0,0 +1,72 @@ + $tplData + */ +?> +
                        + +
                        + +

                        + +

                        + +

                        +

                        + +

                        +

                        + +

                        + + + +
                        + +
                        diff --git a/template/admin_pages/about_us/getting_started/get_pro.php b/template/admin_pages/about_us/getting_started/get_pro.php new file mode 100644 index 00000000..63d104c2 --- /dev/null +++ b/template/admin_pages/about_us/getting_started/get_pro.php @@ -0,0 +1,112 @@ + $tplData + */ +?> +
                        + +
                        +

                        + +

                        + +

                        + Upgrade to Duplicator Pro to unlock ' . + 'all the awesome features and experience
                        why Duplicator is consistently rated the best WordPress migration plugin.', + 'duplicator' + ), + array( + 'br' => array(), + 'strong' => array(), + ) + ); + ?> +

                        + +

                        + 4000+ five star ratings ' . + '(%s) and is active on over 1 million websites.', + 'duplicator' + ), + array( + 'strong' => array(), + ) + ), + '' . + '' . + '' . + '' . + '' + ); + ?> +

                        +
                        + +
                        +
                        +
                          + +
                        • + + + +
                        • + +
                        +
                        + +
                        + +

                        + ', + esc_url(Upsell::getCampaignUrl('duplicator-about_getting-started', 'Get Duplicator Pro Today')) + ); + + _e('Get Duplicator Pro Today and Unlock all the Powerful Features', 'duplicator'); + ?> + +

                        + +

                        + %1$d%% off regular price, ' . + 'automatically applied at checkout.', + 'duplicator' + ), + DUP_Constants::UPSELL_DEFAULT_DISCOUNT + ); + ?> +

                        +
                        + +
                        \ No newline at end of file diff --git a/template/admin_pages/about_us/getting_started/main.php b/template/admin_pages/about_us/getting_started/main.php new file mode 100644 index 00000000..cbaf9ce0 --- /dev/null +++ b/template/admin_pages/about_us/getting_started/main.php @@ -0,0 +1,28 @@ + $tplData + */ + +?> + +
                        +render('admin_pages/about_us/getting_started/first_package'); + +TplMng::getInstance()->render('admin_pages/about_us/getting_started/get_pro'); diff --git a/template/admin_pages/about_us/lite_vs_pro/main.php b/template/admin_pages/about_us/lite_vs_pro/main.php new file mode 100644 index 00000000..a4e5391d --- /dev/null +++ b/template/admin_pages/about_us/lite_vs_pro/main.php @@ -0,0 +1,113 @@ + $tplData + */ +?> +
                        +
                        +

                        + Lite vs Pro +

                        + +

                        + +

                        +
                        + +
                        + +
                        +
                        +

                        + +

                        +
                        +
                        +

                        + +

                        +
                        +
                        +

                        + +

                        +
                        +
                        +
                        + + + + + + + + + +
                        +

                        +
                        +

                        + + + +

                        +
                        +

                        + + + +

                        +
                        +
                        +
                        +
                        +
                        +

                        + ', + esc_url(Upsell::getCampaignUrl('about_duplicator_lite_vs_pro', 'Get Duplicator Pro Today')) + ); + _e('Get Duplicator Pro Today and Unlock all the Powerful Features', 'duplicator') + ?> + +

                        + +

                        + %1$d%% off regular price, ' . + 'automatically applied at checkout.', + 'duplicator' + ), + DUP_Constants::UPSELL_DEFAULT_DISCOUNT + ); + ?> +

                        +
                        +
                        +
                        diff --git a/template/admin_pages/about_us/tabs.php b/template/admin_pages/about_us/tabs.php new file mode 100644 index 00000000..b32b173d --- /dev/null +++ b/template/admin_pages/about_us/tabs.php @@ -0,0 +1,27 @@ + $tplData + */ +?> + + diff --git a/template/admin_pages/packages/setup/archive-filter-files-tab.php b/template/admin_pages/packages/setup/archive-filter-files-tab.php new file mode 100644 index 00000000..0b87db93 --- /dev/null +++ b/template/admin_pages/packages/setup/archive-filter-files-tab.php @@ -0,0 +1,23 @@ + $tplData + */ +?> +
                        + render('parts/filters/package_components', array( + 'package' => $tplData['package'], + )); ?> +
                        diff --git a/template/admin_pages/settings/general/email_summary.php b/template/admin_pages/settings/general/email_summary.php new file mode 100644 index 00000000..fcdd579b --- /dev/null +++ b/template/admin_pages/settings/general/email_summary.php @@ -0,0 +1,47 @@ + $tplData + */ + +use Duplicator\Utils\Email\EmailSummary; + +defined('ABSPATH') || exit; + +$frequency = DUP_Settings::Get('email_summary_frequency'); +?> + +

                        +
                        + + + + + +
                        + +

                        + tags to the summary preview link', + 'duplicator-pro' + ), + '', + '' + ); + ?> +

                        +
                        diff --git a/template/admin_pages/settings/general/general.php b/template/admin_pages/settings/general/general.php new file mode 100644 index 00000000..4226d1fa --- /dev/null +++ b/template/admin_pages/settings/general/general.php @@ -0,0 +1,395 @@ + $tplData + */ + +use Duplicator\Installer\Utils\LinkManager; +use Duplicator\Libs\Snap\SnapUtil; +use Duplicator\Core\Views\TplMng; + +global $wp_version; +global $wpdb; + +$action_updated = null; +$action_response = __("General Settings Saved", 'duplicator'); + +//SAVE RESULTS +if (isset($_POST['action']) && $_POST['action'] == 'save') { + //Nonce Check + if (!isset($_POST['dup_settings_save_nonce_field']) || !wp_verify_nonce($_POST['dup_settings_save_nonce_field'], 'dup_settings_save')) { + die('Invalid token permissions to perform this request.'); + } + + DUP_Settings::Set('uninstall_settings', isset($_POST['uninstall_settings']) ? "1" : "0"); + DUP_Settings::Set('uninstall_files', isset($_POST['uninstall_files']) ? "1" : "0"); + + DUP_Settings::Set('wpfront_integrate', isset($_POST['wpfront_integrate']) ? "1" : "0"); + DUP_Settings::Set('package_debug', isset($_POST['package_debug']) ? "1" : "0"); + + $skip_archive_scan = filter_input(INPUT_POST, 'skip_archive_scan', FILTER_VALIDATE_BOOLEAN); + DUP_Settings::Set('skip_archive_scan', $skip_archive_scan); + + $unhook_third_party_js = filter_input(INPUT_POST, 'unhook_third_party_js', FILTER_VALIDATE_BOOLEAN); + DUP_Settings::Set('unhook_third_party_js', $unhook_third_party_js); + + $unhook_third_party_css = filter_input(INPUT_POST, 'unhook_third_party_css', FILTER_VALIDATE_BOOLEAN); + DUP_Settings::Set('unhook_third_party_css', $unhook_third_party_css); + + $email_summary_frequency = SnapUtil::sanitizeStrictInput(INPUT_POST, 'email_summary_frequency'); + DUP_Settings::setEmailSummaryFrequency($email_summary_frequency); + + $usage_tracking = filter_input(INPUT_POST, 'usage_tracking', FILTER_VALIDATE_BOOLEAN); + DUP_Settings::setUsageTracking($usage_tracking); + + $amNotices = !SnapUtil::sanitizeBoolInput(INPUT_POST, 'dup_am_notices'); + DUP_Settings::Set('amNotices', $amNotices); + + if (isset($_REQUEST['trace_log_enabled'])) { + dup_log::trace("#### trace log enabled"); + // Trace on + + if (DUP_Settings::Get('trace_log_enabled') == 0) { + DUP_Log::DeleteTraceLog(); + } + + DUP_Settings::Set('trace_log_enabled', 1); + } else { + dup_log::trace("#### trace log disabled"); + + // Trace off + DUP_Settings::Set('trace_log_enabled', 0); + } + + DUP_Settings::Save(); + $action_updated = true; + DUP_Util::initSnapshotDirectory(); +} + +$trace_log_enabled = DUP_Settings::Get('trace_log_enabled'); +$uninstall_settings = DUP_Settings::Get('uninstall_settings'); +$uninstall_files = DUP_Settings::Get('uninstall_files'); +$wpfront_integrate = DUP_Settings::Get('wpfront_integrate'); +$wpfront_ready = apply_filters('wpfront_user_role_editor_duplicator_integration_ready', false); +$package_debug = DUP_Settings::Get('package_debug'); +$skip_archive_scan = DUP_Settings::Get('skip_archive_scan'); +$unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js'); +$unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css'); +?> + + + +
                        + + + + + + +

                        + + + +

                        +
                        + + + + + + + + + + + + + + + + + +
                        + +
                        +

                        + /> + +

                        +

                        + /> +
                        +

                        +
                        + + + + + + + > + + " + data-tooltip="render('admin_pages/settings/general/usage_tracking_tooltip', array(), false)); ?>" + data-tooltip-width="600" + > + + +
                        + + /> + +
                        + + render('admin_pages/settings/general/email_summary'); ?> + +

                        +
                        + + + + + + + + + +
                        + /> + +
                        + /> +
                        +

                        + '); + esc_html_e('WARNING: Only turn on this setting when asked to by support as tracing will impact performance.', 'duplicator'); + ?> +


                        + +

                        + + +

                        +
                        + + + + + + + + + + + + + + + + + +
                        + +

                        + + " + data-tooltip=""> + +

                        +
                        + value="1" /> +
                        +

                        + +

                        +
                        + value="1"/> +
                        +

                        + '; + esc_html_e("Do not modify this setting unless you know the expected result or have talked to support.", 'duplicator'); + ?> +

                        +
                        + value="1"/> +
                        +

                        + '; + esc_html_e("Do not modify this setting unless you know the expected result or have talked to support.", 'duplicator'); + ?> +

                        +
                        + +

                        +
                        + " + style="display: inline-block;" + /> +

                        + +
                        + + +title = __('Reset Packages ?', 'duplicator'); +$reset_confirm->message = __('This will clear and reset all of the current temporary packages. Would you like to continue?', 'duplicator'); +$reset_confirm->progressText = __('Resetting settings, Please Wait...', 'duplicator'); +$reset_confirm->jscallback = 'Duplicator.Pack.ResetAll()'; +$reset_confirm->progressOn = false; +$reset_confirm->okText = __('Yes', 'duplicator'); +$reset_confirm->cancelText = __('No', 'duplicator'); +$reset_confirm->closeOnConfirm = true; +$reset_confirm->initConfirm(); + +$faqUrl = esc_url(LinkManager::getDocUrl('how-to-resolve-duplicator-plugin-user-interface-ui-issues', 'settings-admin_notice')); +$msg_ajax_error = new DUP_UI_Messages( + __('AJAX Call Error!', 'duplicator') . '
                        ' . + sprintf( + _x( + 'AJAX error encountered when resetting packages. Please see %1$sthis FAQ entry%2$s for possible resolutions.', + '1 and 2 are opening and closing tags', + 'duplicator' + ), + '', + '' + ), + DUP_UI_Messages::ERROR +); + +$msg_ajax_error->hide_on_init = true; +$msg_ajax_error->is_dismissible = true; +$msg_ajax_error->initMessage(); + +$msg_response_error = new DUP_UI_Messages(__('RESPONSE ERROR!', 'duplicator'), DUP_UI_Messages::ERROR); +$msg_response_error->hide_on_init = true; +$msg_response_error->is_dismissible = true; +$msg_response_error->initMessage(); + +$msg_response_success = new DUP_UI_Messages('', DUP_UI_Messages::NOTICE); +$msg_response_success->hide_on_init = true; +$msg_response_success->is_dismissible = true; +$msg_response_success->initMessage(); +?> + diff --git a/template/admin_pages/settings/general/usage_tracking_tooltip.php b/template/admin_pages/settings/general/usage_tracking_tooltip.php new file mode 100644 index 00000000..1ef316cf --- /dev/null +++ b/template/admin_pages/settings/general/usage_tracking_tooltip.php @@ -0,0 +1,96 @@ + $tplData + */ +?> +
                        + +
                        + +
                        +
                        +
                        +
                        + + + + + +
                        +
                          +
                        • + PHP Version: so we know which PHP versions we have to test against (no one likes whitescreens or log files full of errors).', + 'duplicator' + ); + ?> +
                        • +
                        • + WordPress Version: so we know which WordPress versions to support and test against.', + 'duplicator' + ); + ?> +
                        • +
                        • + MySQL Version: so we know which versions of MySQL to support and test against for our custom tables.', + 'duplicator' + ); + ?> +
                        • +
                        • + Duplicator Version: so we know which versions of Duplicator are potentially responsible for issues when we get bug reports, + allowing us to identify issues and release solutions much faster.', + 'duplicator' + ); + ?> +
                        • +
                        • + Plugins and Themes infos: so we can figure out which ones I can generate compatibility errors with Duplicator.', + 'duplicator' + ); + ?> +
                        • +
                        • + Site info: General information about the site such as database, file size, number of users, and sites in case it is a multisite. + This is useful for us to understand the critical issues of package creation.', + 'duplicator' + ); + ?> +
                        • +
                        • + Packages infos: Information about the packages created and the type of components included.', + 'duplicator' + ); + ?> +
                        • +
                        \ No newline at end of file diff --git a/template/admin_pages/welcome/features.php b/template/admin_pages/welcome/features.php new file mode 100644 index 00000000..5e23c048 --- /dev/null +++ b/template/admin_pages/welcome/features.php @@ -0,0 +1,105 @@ + $tplData + */ +?> + +
                        +
                        +

                        +
                        + +
                        +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        + +
                        + +
                        +

                        + +

                        +
                        +
                        + +
                        + + + +
                        +
                        +
                        \ No newline at end of file diff --git a/template/admin_pages/welcome/footer.php b/template/admin_pages/welcome/footer.php new file mode 100644 index 00000000..2f90e7b1 --- /dev/null +++ b/template/admin_pages/welcome/footer.php @@ -0,0 +1,41 @@ + $tplData + */ +?> + + \ No newline at end of file diff --git a/template/admin_pages/welcome/intro.php b/template/admin_pages/welcome/intro.php new file mode 100644 index 00000000..d61e2a16 --- /dev/null +++ b/template/admin_pages/welcome/intro.php @@ -0,0 +1,56 @@ + $tplData +*/ +?> + +
                        +
                        + <?php esc_attr_e('Willie the Duplicator mascot', 'duplicator'); ?> +
                        +
                        +

                        +
                        +
                        + +
                        +
                        +
                        +
                        + + + +
                        +
                        + + + +
                        +
                        +
                        +
                        diff --git a/template/admin_pages/welcome/testimonials.php b/template/admin_pages/welcome/testimonials.php new file mode 100644 index 00000000..c4cd0b57 --- /dev/null +++ b/template/admin_pages/welcome/testimonials.php @@ -0,0 +1,56 @@ + $tplData + */ +?> +
                        +
                        +

                        + +
                        + +

                        + WP migration, I very much recommend this plugin!', + 'duplicator' + ), + array('b' => array()) + ); + ?> +

                        +

                        Karina Caidez, Website Designer

                        +
                        + +
                        + +

                        + WordPress migration & backup plugin I have ever used. I will be ' . + 'recommending this plugin to everyone I can.', + 'duplicator' + ), + array('b' => array()) + ); + ?> +

                        +

                        Blake Stiller, Website Development Instructor

                        +
                        +
                        +
                        \ No newline at end of file diff --git a/template/admin_pages/welcome/upgrade-cta.php b/template/admin_pages/welcome/upgrade-cta.php new file mode 100644 index 00000000..bbd72f97 --- /dev/null +++ b/template/admin_pages/welcome/upgrade-cta.php @@ -0,0 +1,40 @@ + $tplData + */ +?> +
                        +
                        +
                        +

                        +
                          + +
                        • + +
                        • + +
                        +
                        + +
                        + + + +
                        +
                        +
                        \ No newline at end of file diff --git a/template/admin_pages/welcome/welcome.php b/template/admin_pages/welcome/welcome.php new file mode 100644 index 00000000..3ff958d2 --- /dev/null +++ b/template/admin_pages/welcome/welcome.php @@ -0,0 +1,45 @@ + $tplData + */ +?> + +
                        +
                        + render( + 'admin_pages/welcome/intro', + array( + 'packageNonceUrl' => wp_nonce_url(admin_url('admin.php?page=duplicator&tab=new1'), 'new1-package'), + ) + ); + + TplMng::getInstance()->render('admin_pages/welcome/features'); + + TplMng::getInstance()->render('admin_pages/welcome/upgrade-cta'); + + TplMng::getInstance()->render('admin_pages/welcome/testimonials'); + + TplMng::getInstance()->render( + 'admin_pages/welcome/footer', + array( + 'packageNonceUrl' => wp_nonce_url(admin_url('admin.php?page=duplicator&tab=new1'), 'new1-package'), + ) + ); + ?> +
                        +
                        \ No newline at end of file diff --git a/template/mail/email_summary.php b/template/mail/email_summary.php new file mode 100644 index 00000000..9a70b267 --- /dev/null +++ b/template/mail/email_summary.php @@ -0,0 +1,196 @@ + $tplData + */ + +?> + + + + + + <?php _e('Duplicator', 'duplicator'); ?> + + + > + > + > + + +
                        > + > + > + + + > + + + + + +
                        > + logo + > +
                        > + > + > + + +
                        > +
                        >Hi there!
                        +

                        > + +

                        +

                        > + + + +
                        + +

                        +

                        > + ', + '' + ); + ?> +

                        + 0) : ?> +

                        > + +

                        + > + > + + + + $packageInfo) : ?> + > + + + + +
                        > + + > + +
                        > + + > + + > + + + + + +
                        + +

                        > + +

                        + +
                        +
                        > + tag with a link to the current website.', + 'wpforms-lite' + ), + '' + . wp_specialchars_decode(get_bloginfo('name')) . '' + ); + ?> + + ', + '' + ); + ?> +
                        +
                        + + + diff --git a/template/mocks/import/content-popup.php b/template/mocks/import/content-popup.php new file mode 100644 index 00000000..bd59adb2 --- /dev/null +++ b/template/mocks/import/content-popup.php @@ -0,0 +1,35 @@ + $tplData + */ +?> +

                        + classic installer method ' . + 'on an empty site, Duplicator Pro now supports Drag and Drop migrations and site restores! Simply drag ' . + 'the bundled site archive to the site you wish to overwrite.', + 'duplicator' + ), + array( + 'a' => array( + 'href' => array(), + 'rel' => array(), + 'target' => array(), + ) + ) + ), + LinkManager::getPostUrl('how-to-move-a-wordpress-website-to-a-new-host', 'import_popup', 'classic installer method') + ); + ?> +

                        diff --git a/template/mocks/import/import.php b/template/mocks/import/import.php new file mode 100644 index 00000000..ecf21271 --- /dev/null +++ b/template/mocks/import/import.php @@ -0,0 +1,207 @@ + $tplData + */ +?> +
                        +

                        + Import +

                        +
                        +
                        +
                        +

                        + + Step1 of 2: Upload Archive +

                        +
                        +
                        + + +
                        + + +
                        +
                        +render( + 'parts/Education/static-popup', + array( + 'title' => __('Overwrite a WordPress site with Drag and Drop Import!', 'duplicator'), + 'warning-text' => __('Drag and Drop Import is not available in Duplicator Lite!', 'duplicator'), + 'content-tpl' => 'mocks/import/content-popup', + 'upsell-url' => Upsell::getCampaignUrl('blurred-mocks', 'Import') + ), + true +); ?> diff --git a/template/mocks/recovery/content-popup.php b/template/mocks/recovery/content-popup.php new file mode 100644 index 00000000..76f5b52f --- /dev/null +++ b/template/mocks/recovery/content-popup.php @@ -0,0 +1,19 @@ + $tplData + */ +?> +

                        + +

                        \ No newline at end of file diff --git a/template/mocks/recovery/recovery.php b/template/mocks/recovery/recovery.php new file mode 100644 index 00000000..a0e219d2 --- /dev/null +++ b/template/mocks/recovery/recovery.php @@ -0,0 +1,122 @@ + $tplData + */ +?> + + +render( + 'parts/Education/static-popup', + array( + 'title' => __('Rollback your sites with Recovery Points!', 'duplicator'), + 'warning-text' => __('Recovery Points are not supported in Duplicator Lite!', 'duplicator'), + 'content-tpl' => 'mocks/recovery/content-popup', + 'upsell-url' => Upsell::getCampaignUrl('blurred-mocks', 'Recovery') + ), + true +); ?> \ No newline at end of file diff --git a/template/mocks/schedule/content-popup.php b/template/mocks/schedule/content-popup.php new file mode 100644 index 00000000..fd14c530 --- /dev/null +++ b/template/mocks/schedule/content-popup.php @@ -0,0 +1,28 @@ + $tplData + */ +?> +

                        + +

                        +

                        + +

                        \ No newline at end of file diff --git a/template/mocks/schedule/schedules.php b/template/mocks/schedule/schedules.php new file mode 100644 index 00000000..07f8450d --- /dev/null +++ b/template/mocks/schedule/schedules.php @@ -0,0 +1,285 @@ + $tplData + */ +?> +
                        +

                        Schedules

                        +
                        + + + + + + + + +
                        + + + + + + +
                        + Add New +
                        +
                        + +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        NameStorageRuns NextLast RanActiveRecovery
                        + + + Daily Schedule - Default Local + DefaultJanuary 1, 2023 0:00 - Daily + December 31, 2022 0:00 + Yes + Available +
                        + + + Weekly Schedule - DropBox + DropBoxJanuary 8, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Monthly Schedule - GDrive + Google DriveFebruary 1, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Monthly Schedule - All Storages + Local, Google Drive, FTP, SFTP,
                        S3, OneDrive, DropBox
                        February 1, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Daily Schedule - Default Local + DefaultJanuary 1, 2023 0:00 - Daily + December 31, 2022 0:00 + Yes + Available +
                        + + + Weekly Schedule - DropBox + DropBoxJanuary 8, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Monthly Schedule - GDrive + Google DriveFebruary 1, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Monthly Schedule - All Storages + Local, Google Drive, FTP, SFTP,
                        S3, OneDrive, DropBox
                        February 1, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Daily Schedule - Default Local + DefaultJanuary 1, 2023 0:00 - Daily + December 31, 2022 0:00 + Yes + Available +
                        + + + Weekly Schedule - DropBox + DropBoxJanuary 8, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Monthly Schedule - GDrive + Google DriveFebruary 1, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + + + Monthly Schedule - All Storages + Local, Google Drive, FTP, SFTP,
                        S3, OneDrive, DropBox
                        February 1, 2023 0:00 - Weekly + January 1, 2023 0:00 + Yes + Available +
                        + Total: 12 | Active: 12 | Time: 00:00:01
                        +
                        +
                        +
                        +render( + 'parts/Education/static-popup', + array( + 'title' => __('Automate your workflow with scheduled backups!', 'duplicator'), + 'warning-text' => __('Duplicator Lite does not support scheduled backups!', 'duplicator'), + 'content-tpl' => 'mocks/schedule/content-popup', + 'upsell-url' => Upsell::getCampaignUrl('blurred-mocks', 'Schedules') + ) +); +?> diff --git a/template/mocks/settings/access/capabilities.php b/template/mocks/settings/access/capabilities.php new file mode 100644 index 00000000..d47a8f01 --- /dev/null +++ b/template/mocks/settings/access/capabilities.php @@ -0,0 +1,129 @@ + $tplData + */ +?> +

                        +
                        +
                        +

                        +
                        +
                        +
                        + +

                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +render( + 'parts/Education/static-popup', + array( + 'title' => __('Advanced Backup Permissions', 'duplicator'), + 'warning-text' => __('Advanced Backup Permissions are not available in Duplicator Lite!', 'duplicator'), + 'content-tpl' => 'mocks/settings/access/content-popup', + 'upsell-url' => Upsell::getCampaignUrl('blurred-mocks', 'Settings Access Tab') + ), + true +); ?> diff --git a/template/mocks/settings/access/content-popup.php b/template/mocks/settings/access/content-popup.php new file mode 100644 index 00000000..d4879819 --- /dev/null +++ b/template/mocks/settings/access/content-popup.php @@ -0,0 +1,23 @@ + $tplData + */ +?> +

                        + +

                        diff --git a/template/mocks/storage/popup.php b/template/mocks/storage/popup.php new file mode 100644 index 00000000..d37e1fbc --- /dev/null +++ b/template/mocks/storage/popup.php @@ -0,0 +1,41 @@ + $tplData + */ +?> + +
                        + " /> + +
                          + +
                        • + + + +   + +
                        • + +
                        + +
                        +
                        +

                        + + + +

                        +
                        + diff --git a/template/mocks/storage/storage.php b/template/mocks/storage/storage.php new file mode 100644 index 00000000..c584c816 --- /dev/null +++ b/template/mocks/storage/storage.php @@ -0,0 +1,172 @@ + $tplData + */ +?> + +

                        +
                        +

                        +

                        +

                        + + + +

                        +
                        + + + + + + + + +
                        + + + + + + + +
                        + +
                        +
                        + +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        + + + Default + +  Local +
                        + + + + + + + + <?php echo $storage['label']; ?> + + +
                        +
                        +
                        + + diff --git a/template/mocks/templates/content-popup.php b/template/mocks/templates/content-popup.php new file mode 100644 index 00000000..eef582ad --- /dev/null +++ b/template/mocks/templates/content-popup.php @@ -0,0 +1,28 @@ + $tplData + */ +?> +

                        + +

                        +

                        + +

                        \ No newline at end of file diff --git a/template/mocks/templates/templates.php b/template/mocks/templates/templates.php new file mode 100644 index 00000000..818c0c46 --- /dev/null +++ b/template/mocks/templates/templates.php @@ -0,0 +1,200 @@ + $tplData + */ +?> +
                        + + + + + + + + +
                        + + + +
                        + Add New +
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        NameRecovery
                        + + + Default + + + Available + +  
                        + + + Full site backup + + + Available + +  
                        + + + Database only backup + + + Disabled + +  
                        + + + Uploads folder filtered + + + Available + +  
                        + + + Non-WP tables filtered + + + Disabled + +  
                        + + + Full site backup + + + Available + +  
                        + + + Database only backup + + + Disabled + +  
                        + + + Uploads folder filtered + + + Available + +  
                        + + + Non-WP tables filtered + + + Disabled + +  
                        + Total: 2 +
                        +
                        +render( + 'parts/Education/static-popup', + array( + 'title' => __('Easily customize your backups with templates!', 'duplicator'), + 'warning-text' => __('Templates are not available in Duplicator Lite!', 'duplicator'), + 'content-tpl' => 'mocks/templates/content-popup', + 'upsell-url' => Upsell::getCampaignUrl('blurred-mocks', 'Templates') + ), + true +); ?> \ No newline at end of file diff --git a/template/mocks/transfer/content-popup.php b/template/mocks/transfer/content-popup.php new file mode 100644 index 00000000..1e224166 --- /dev/null +++ b/template/mocks/transfer/content-popup.php @@ -0,0 +1,19 @@ + $tplData + */ +?> +

                        + +

                        \ No newline at end of file diff --git a/template/mocks/transfer/transfer.php b/template/mocks/transfer/transfer.php new file mode 100644 index 00000000..877d4d25 --- /dev/null +++ b/template/mocks/transfer/transfer.php @@ -0,0 +1,236 @@ + $tplData + */ +?> + +
                        + +
                        +

                        + Manual Transfer +

                        +
                        +
                        + +
                        +
                        +

                        Step 1: Choose Location

                        + + + + +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        TypeNameLocation
                        + + + + + + +  DropBox + + https://dropbox.com/home
                        + + + + + + +  Google Drive + + google://Duplicator Backups/duplicator.com
                        + + + + + + +  OneDrive + + Not Authenticated
                        + + + + + + +  FTP + + ftp://duplicator.com:21/duplicator.com
                        + + + + + + +  SFTP + + duplicator.com:22
                        + + [Create New Storage] + +
                        + +
                        + + +
                        +

                        + Step 2: Transfer Files + +

                        + + + +
                        + +
                        +
                        + + +
                        +
                        + + Transfer Log +
                        +
                        + + + + + + + + + + + + + + + + + + + + + + +
                        StartedStoppedStatusTypeDescription
                        Sun, 01 Jan 00:00:00Sun, 01 Jan 00:01:00SucceededDropboxTransferred package to Dropbox folder duplicator.com
                        Log Items: 1
                        +
                        +
                        +
                        +render( + 'parts/Education/static-popup', + array( + 'title' => __('Manually transfer backups to remote storages!', 'duplicator'), + 'warning-text' => __('Remote storages are not available in Duplicator Lite!', 'duplicator'), + 'content-tpl' => 'mocks/transfer/content-popup', + 'upsell-url' => Upsell::getCampaignUrl('blurred-mocks', 'Details Transfer') + ), + true +); ?> diff --git a/template/parts/DashboardWidget/package-create-section.php b/template/parts/DashboardWidget/package-create-section.php new file mode 100644 index 00000000..0695b0c4 --- /dev/null +++ b/template/parts/DashboardWidget/package-create-section.php @@ -0,0 +1,49 @@ + $tplData + */ + +$tooltipTitle = esc_attr__('Package creation', 'duplicator'); +$tooltipContent = esc_attr__( + 'This will create a new package. If a package is currently running then this button will be disabled.', + 'duplicator' +); + +?> +
                        + + + + + + + + + + + +
                        diff --git a/template/parts/DashboardWidget/recently-packages.php b/template/parts/DashboardWidget/recently-packages.php new file mode 100644 index 00000000..5f9bcef7 --- /dev/null +++ b/template/parts/DashboardWidget/recently-packages.php @@ -0,0 +1,49 @@ + $tplData + * @var DUP_Package[] $packages + */ +$packages = $tplData['packages']; + +?> +
                        +

                        + +

                        + 0) { ?> +
                          + Created); + $createdDate = date(get_option('date_format'), $createdTime); + $createdHours = date(get_option('time_format'), $createdTime); + + ?> +
                        • + + Name); ?> + - +
                        • + +
                        + +

                        + +

                        +
                        diff --git a/template/parts/DashboardWidget/recommended-section.php b/template/parts/DashboardWidget/recommended-section.php new file mode 100644 index 00000000..941e2e09 --- /dev/null +++ b/template/parts/DashboardWidget/recommended-section.php @@ -0,0 +1,55 @@ + $tplData + * @var array{name: string,slug: string,more: string,pro: array{file: string}} $plugin + */ +$plugin = $tplData['plugin']; + +/** @var string */ +$installUrl = $tplData['installUrl']; +$moreUrl = $plugin['more'] . '?' . http_build_query(array( + 'utm_medium' => 'link', + 'utm_source' => 'duplicatorplugin', + 'utm_campaign' => 'duplicatordashboardwidget' +)); + +?> + diff --git a/template/parts/DashboardWidget/sections-section.php b/template/parts/DashboardWidget/sections-section.php new file mode 100644 index 00000000..b45370e5 --- /dev/null +++ b/template/parts/DashboardWidget/sections-section.php @@ -0,0 +1,107 @@ + $tplData + */ + +$templatesURL = ControllersManager::getMenuLink( + ControllersManager::TOOLS_SUBMENU_SLUG, + 'templates' +); +$recoveryURl = ControllersManager::getMenuLink( + ControllersManager::TOOLS_SUBMENU_SLUG, + 'recovery' +); + +?> +
                        +
                          +
                        • + + + : + + + + + - : + + +
                        • +
                        • + +
                        • +
                        • + +
                        • +
                        • + + + + +
                        • +
                        +
                        diff --git a/template/parts/Education/callout-cta.php b/template/parts/Education/callout-cta.php new file mode 100644 index 00000000..ebbebced --- /dev/null +++ b/template/parts/Education/callout-cta.php @@ -0,0 +1,81 @@ + $tplData + */ +?> +
                        + +
                        +

                        + +

                        +

                        + array( + 'class' => array(), + 'aria-hidden' => array(), + ), + ) + ), + str_repeat('', 5) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ); + ?> +

                        +
                        +
                          + +
                        • + + + +
                        • + +
                        +

                        + + + +

                        +

                        + Bonus: Duplicator Lite users get %1$d%% off regular price,' . + 'automatically applied at checkout.', + 'duplicator' + ), + DUP_Constants::UPSELL_DEFAULT_DISCOUNT + ); + ?> +

                        +
                        \ No newline at end of file diff --git a/template/parts/Education/did-you-know-blurb.php b/template/parts/Education/did-you-know-blurb.php new file mode 100644 index 00000000..24e7aa9b --- /dev/null +++ b/template/parts/Education/did-you-know-blurb.php @@ -0,0 +1,26 @@ + $tplData + */ +?> +
                        + + + + + +
                        \ No newline at end of file diff --git a/template/parts/Education/packages-bottom-bar.php b/template/parts/Education/packages-bottom-bar.php new file mode 100644 index 00000000..28aaa8f6 --- /dev/null +++ b/template/parts/Education/packages-bottom-bar.php @@ -0,0 +1,46 @@ + $tplData + */ +?> + + +
                        +
                        + +
                        +
                        +

                        +

                        + +

                        +
                        +
                        + + + +
                        +
                        + +
                        +
                        + + diff --git a/template/parts/Education/static-popup.php b/template/parts/Education/static-popup.php new file mode 100644 index 00000000..956c6dfb --- /dev/null +++ b/template/parts/Education/static-popup.php @@ -0,0 +1,34 @@ + $tplData + */ +?> +
                        +
                        + +
                        +
                        +

                        + +

                        + render($tplData['content-tpl']); ?> +
                        +
                        + + + +
                        +
                        diff --git a/template/parts/Education/subscribe-form.php b/template/parts/Education/subscribe-form.php new file mode 100644 index 00000000..75392799 --- /dev/null +++ b/template/parts/Education/subscribe-form.php @@ -0,0 +1,31 @@ + $tplData + */ +?> +
                        +
                        + +
                        +
                        + +
                        +
                        diff --git a/template/parts/Notifications/main.php b/template/parts/Notifications/main.php new file mode 100644 index 00000000..453b1c66 --- /dev/null +++ b/template/parts/Notifications/main.php @@ -0,0 +1,45 @@ + $tplData + */ + +defined('ABSPATH') || exit; + +?> +
                        +
                        +
                        + + +
                        +
                        +
                        + +
                        + + + 1) : ?> + + + +
                        + render('parts/Notifications/single-message', $notification); + } ?> +
                        +
                        +
                        diff --git a/template/parts/Notifications/single-message.php b/template/parts/Notifications/single-message.php new file mode 100644 index 00000000..4ed84655 --- /dev/null +++ b/template/parts/Notifications/single-message.php @@ -0,0 +1,36 @@ + $tplData + */ + +defined('ABSPATH') || exit; +?> +
                        +

                        + + + > + + + +

                        +
                        + +
                        + + > + + + +
                        diff --git a/template/parts/admin-logo-header.php b/template/parts/admin-logo-header.php new file mode 100644 index 00000000..5591a7b9 --- /dev/null +++ b/template/parts/admin-logo-header.php @@ -0,0 +1,19 @@ + $tplData + */ +?> +
                        +
                        + Duplicator Logo +
                        \ No newline at end of file diff --git a/template/parts/filters/package_components.php b/template/parts/filters/package_components.php new file mode 100644 index 00000000..42e1b5f2 --- /dev/null +++ b/template/parts/filters/package_components.php @@ -0,0 +1,344 @@ + $tplData + */ + +$archiveFilterPaths = trim($tplData['package']->Archive->FilterDirs . ";" . $tplData['package']->Archive->FilterFiles, ";"); +$archiveFilterPaths = str_replace(';', ";\n", $archiveFilterPaths); +$archiveFilterExtensions = $tplData['package']->Archive->FilterExts; +$packageComponentsTooltip = wp_kses( + __("Package components allow you to include/exclude differents part of your WordPress installation in the package.

                        " . + "Database: Include the database in the package.
                        " . + "Plugins: Include the plugins in the package. With the 'active only' option enabled, only active plugins will be included in the package.
                        " . + "Themes: Include the themes in the package. With the 'active only' option enabled, only active themes will be included in the package.
                        " . + "Media: Include the 'uploads' folder.
                        " . + "Other: Include non-WordPress files and folders in the root directory.
                        ", 'duplicator'), + array( + 'br' => array(), + 'b' => array(), + ) +); +$pathFiltersTooltip = __("File filters allow you to exclude files and folders from the package. To enable path and extension filters check the " . + "checkbox. Enter the full path of the files and folders you want to exclude from the package as a semicolon (;) seperated list."); +$extensionFilterTooltip = __("File extension filters allow you to exclude files with certain file extensions from the package e.g. zip;rar;pdf etc. " . + "Enter the file extensions you want to exclude from the package as a semicolon (;) seperated list."); +?> + +
                        +
                        +
                        + + + + +
                        +
                        +
                        + Archive->ExportOnlyDB); ?> + > + + Archive->ExportOnlyDB); ?> + data-parsley-multiple="auto-select-components" + > + + + +
                        +
                        +
                          +
                        • + +
                        • +
                        • + +
                        • +
                        • + +
                        • +
                        • + +
                        • +
                        • + +
                        • +
                        • + +
                        • +
                        • + +
                        • +
                        +
                        +
                        +
                        +
                        + () + + + +
                        + +
                        + + + + + +
                        + +
                        +
                        + Overview:
                        This advanced option excludes all files from the archive. Only the database and a copy of the installer.php " + . "will be included in the archive.zip file. The option can be used for backing up and moving only the database.", + 'duplicator' + ), + array( + 'b' => array(), + 'br' => array(), + ) + ); + echo '

                        '; + + echo wp_kses( + __( + " Notice:
                        " + . "Installing only the database over an existing site may have unintended consequences. " + . "Be sure to know the state of your system before installing the database without the associated files. ", + 'duplicator' + ), + array( + 'b' => array(), + 'i' => array('class'), + 'br' => array() + ) + ); + + esc_html_e( + "For example, if you have WordPress 5.6 on this site and you copy this site's database to a host that has WordPress 5.8 files " + . "then the source code of the files will not be in sync with the database causing possible errors. " + . "This can also be true of plugins and themes. " + . "When moving only the database be sure to know the database will be compatible with " + . "ALL source code files. Please use this advanced feature with caution!", + 'duplicator' + ); + + echo '

                        '; + + echo wp_kses( + __("Install Time:
                        When installing a database only package please visit the ", 'duplicator'), + array( + 'b' => array(), + 'br' => array(), + ) + ); + ?> + + + +
                        +
                        +
                        +
                        + + Media Only and Custom options are not included in Duplicator Lite. ' . + 'To enable advanced options please %1$supgrade to Pro%2$s.', + '%1$s and %2$s represents the opening and closing HTML tags for an anchor or link.', + 'duplicator' + ), + '', + '' + ); + ?> + +
                        + diff --git a/template/parts/notice-bar.php b/template/parts/notice-bar.php new file mode 100644 index 00000000..710d6d95 --- /dev/null +++ b/template/parts/notice-bar.php @@ -0,0 +1,67 @@ + $tplData + */ +?> + +
                        + + You\'re using Duplicator Lite. To unlock more features consider ' . + 'upgrading to Pro', + 'duplicator' + ), + array( + 'a' => array( + 'href' => array(), + 'rel' => array(), + 'target' => array(), + ), + 'strong' => array(), + ) + ), + esc_url(Upsell::getCampaignUrl('lite-upgrade-bar', $tplData['utm_content'])) + ); + ?> + + + +
                        diff --git a/uninstall.php b/uninstall.php index 5dc4eed4..08b9135c 100644 --- a/uninstall.php +++ b/uninstall.php @@ -1,86 +1,160 @@ -prefix . "duplicator_packages"; -$wpdb->query("DROP TABLE `{$table_name}`"); - -delete_option('duplicator_version_plugin'); - -//Remvoe entire wp-snapshots directory -if (DUP_Settings::Get('uninstall_files')) { - - $ssdir = DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH); - $ssdir_tmp = DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP); - - //Sanity check for strange setup - $check = glob("{$ssdir}/wp-config.php"); - if (count($check) == 0) { - - //PHP sanity check - foreach (glob("{$ssdir}/*_database.sql") as $file) { - if (strstr($file, '_database.sql')) - @unlink("{$file}"); - } - foreach (glob("{$ssdir}/*_installer.php") as $file) { - if (strstr($file, '_installer.php')) - @unlink("{$file}"); - } - foreach (glob("{$ssdir}/*_archive.zip") as $file) { - if (strstr($file, '_archive.zip')) - @unlink("{$file}"); - } - foreach (glob("{$ssdir}/*_scan.json") as $file) { - if (strstr($file, '_scan.json')) - @unlink("{$file}"); - } - foreach (glob("{$ssdir}/*.log") as $file) { - if (strstr($file, '.log')) - @unlink("{$file}"); - } - - //Check for core files and only continue removing data if the snapshots directory - //has not been edited by 3rd party sources, this helps to keep the system stable - $files = glob("{$ssdir}/*"); - if (is_array($files) && count($files) < 6) { - $defaults = array("{$ssdir}/index.php", "{$ssdir}/robots.txt", "{$ssdir}/dtoken.php"); - $compare = array_diff($defaults, $files); - - //There might be a .htaccess file or index.php/html etc. - if (count($compare) < 3) { - foreach ($defaults as $file) { - @unlink("{$file}"); - } - @unlink("{$ssdir}/.htaccess"); - @rmdir($ssdir_tmp); - @rmdir($ssdir); - } - } - } -} - -//Remove all Settings -if (DUP_Settings::Get('uninstall_settings')) { - DUP_Settings::Delete(); - delete_option('duplicator_ui_view_state'); - delete_option('duplicator_package_active'); -} -?> \ No newline at end of file +base_prefix . self::PACKAGES_TABLE_NAME; + $GLOBALS['wpdb']->query('DROP TABLE IF EXISTS ' . $tableName); + + $fsystem = new WP_Filesystem_Direct(true); + $fsystem->rmdir(self::getSsdirPathWpCont(), true); + $fsystem->rmdir(self::getSsdirPathLegacy(), true); + } + + /** + * Remove plugins settings + * + * @return void + */ + private static function removeSettings() + { + if (get_option(self::UNINSTALL_SETTINGS_OPTION_KEY) != true) { + return; + } + + self::deleteUserMetaKeys(); + self::deleteOptions(); + self::deleteTransients(); + } + + /** + * Delete all users meta key + * + * @return void + */ + private static function deleteUserMetaKeys() + { + /** @var wpdb */ + global $wpdb; + + $wpdb->query("DELETE FROM " . $wpdb->usermeta . " WHERE meta_key REGEXP '^duplicator_(?!pro_)'"); + } + + /** + * Delete all options + * + * @return void + */ + private static function deleteOptions() + { + $optionsTableName = $GLOBALS['wpdb']->base_prefix . "options"; + $dupOptionNames = $GLOBALS['wpdb']->get_col( + "SELECT `option_name` FROM `{$optionsTableName}` WHERE `option_name` REGEXP '^duplicator_(?!pro_|expire_)'" + ); + + foreach ($dupOptionNames as $dupOptionName) { + delete_option($dupOptionName); + } + } + + /** + * Delete all transients + * + * @return void + */ + private static function deleteTransients() + { + $optionsTableName = $GLOBALS['wpdb']->base_prefix . "options"; + $dupOptionTransientNames = $GLOBALS['wpdb']->get_col( + "SELECT `option_name` FROM `{$optionsTableName}` WHERE `option_name` REGEXP '^_transient_duplicator_(?!pro_)'" + ); + + foreach ($dupOptionTransientNames as $dupOptionTransientName) { + delete_transient(str_replace("_transient_", "", $dupOptionTransientName)); + } + } +} + +DuplicatorLiteUninstall::uninstall(); diff --git a/vendor/requests/LICENSE b/vendor/requests/LICENSE new file mode 100644 index 00000000..d61ae7b1 --- /dev/null +++ b/vendor/requests/LICENSE @@ -0,0 +1,49 @@ +Requests +======== + +Copyright (c) 2010-2012 Ryan McCue and contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +ComplexPie IRI Parser +===================== + +Copyright (c) 2007-2010, Geoffrey Sneddon and Steve Minutillo. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the SimplePie Team nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/requests/library/Requests.php b/vendor/requests/library/Requests.php new file mode 100644 index 00000000..bb266189 --- /dev/null +++ b/vendor/requests/library/Requests.php @@ -0,0 +1,980 @@ +dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options)); + + if (!empty($options['transport'])) { + $transport = $options['transport']; + + if (is_string($options['transport'])) { + $transport = new $transport(); + } + } + else { + $need_ssl = (0 === stripos($url, 'https://')); + $capabilities = array('ssl' => $need_ssl); + $transport = self::get_transport($capabilities); + } + $response = $transport->request($url, $headers, $data, $options); + + $options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options)); + + return self::parse_response($response, $url, $headers, $data, $options); + } + + /** + * Send multiple HTTP requests simultaneously + * + * The `$requests` parameter takes an associative or indexed array of + * request fields. The key of each request can be used to match up the + * request with the returned data, or with the request passed into your + * `multiple.request.complete` callback. + * + * The request fields value is an associative array with the following keys: + * + * - `url`: Request URL Same as the `$url` parameter to + * {@see Requests::request} + * (string, required) + * - `headers`: Associative array of header fields. Same as the `$headers` + * parameter to {@see Requests::request} + * (array, default: `array()`) + * - `data`: Associative array of data fields or a string. Same as the + * `$data` parameter to {@see Requests::request} + * (array|string, default: `array()`) + * - `type`: HTTP request type (use Requests constants). Same as the `$type` + * parameter to {@see Requests::request} + * (string, default: `Requests::GET`) + * - `cookies`: Associative array of cookie name to value, or cookie jar. + * (array|Requests_Cookie_Jar) + * + * If the `$options` parameter is specified, individual requests will + * inherit options from it. This can be used to use a single hooking system, + * or set all the types to `Requests::POST`, for example. + * + * In addition, the `$options` parameter takes the following global options: + * + * - `complete`: A callback for when a request is complete. Takes two + * parameters, a Requests_Response/Requests_Exception reference, and the + * ID from the request array (Note: this can also be overridden on a + * per-request basis, although that's a little silly) + * (callback) + * + * @param array $requests Requests data (see description for more information) + * @param array $options Global and default options (see {@see Requests::request}) + * @return array Responses (either Requests_Response or a Requests_Exception object) + */ + public static function request_multiple($requests, $options = array()) { + $options = array_merge(self::get_default_options(true), $options); + + if (!empty($options['hooks'])) { + $options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple')); + if (!empty($options['complete'])) { + $options['hooks']->register('multiple.request.complete', $options['complete']); + } + } + + foreach ($requests as $id => &$request) { + if (!isset($request['headers'])) { + $request['headers'] = array(); + } + if (!isset($request['data'])) { + $request['data'] = array(); + } + if (!isset($request['type'])) { + $request['type'] = self::GET; + } + if (!isset($request['options'])) { + $request['options'] = $options; + $request['options']['type'] = $request['type']; + } + else { + if (empty($request['options']['type'])) { + $request['options']['type'] = $request['type']; + } + $request['options'] = array_merge($options, $request['options']); + } + + self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']); + + // Ensure we only hook in once + if ($request['options']['hooks'] !== $options['hooks']) { + $request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple')); + if (!empty($request['options']['complete'])) { + $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']); + } + } + } + unset($request); + + if (!empty($options['transport'])) { + $transport = $options['transport']; + + if (is_string($options['transport'])) { + $transport = new $transport(); + } + } + else { + $transport = self::get_transport(); + } + $responses = $transport->request_multiple($requests, $options); + + foreach ($responses as $id => &$response) { + // If our hook got messed with somehow, ensure we end up with the + // correct response + if (is_string($response)) { + $request = $requests[$id]; + self::parse_multiple($response, $request); + $request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id)); + } + } + + return $responses; + } + + /** + * Get the default options + * + * @see Requests::request() for values returned by this method + * @param boolean $multirequest Is this a multirequest? + * @return array Default option values + */ + protected static function get_default_options($multirequest = false) { + $defaults = array( + 'timeout' => 10, + 'connect_timeout' => 10, + 'useragent' => 'php-requests/' . self::VERSION, + 'protocol_version' => 1.1, + 'redirected' => 0, + 'redirects' => 10, + 'follow_redirects' => true, + 'blocking' => true, + 'type' => self::GET, + 'filename' => false, + 'auth' => false, + 'proxy' => false, + 'cookies' => false, + 'max_bytes' => false, + 'idn' => true, + 'hooks' => null, + 'transport' => null, + 'verify' => Requests::get_certificate_path(), + 'verifyname' => true, + ); + if ($multirequest !== false) { + $defaults['complete'] = null; + } + return $defaults; + } + + /** + * Get default certificate path. + * + * @return string Default certificate path. + */ + public static function get_certificate_path() { + if ( ! empty( Requests::$certificate_path ) ) { + return Requests::$certificate_path; + } + + return dirname(__FILE__) . '/Requests/Transport/cacert.pem'; + } + + /** + * Set default certificate path. + * + * @param string $path Certificate path, pointing to a PEM file. + */ + public static function set_certificate_path( $path ) { + Requests::$certificate_path = $path; + } + + /** + * Set the default values + * + * @param string $url URL to request + * @param array $headers Extra headers to send with the request + * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests + * @param string $type HTTP request type + * @param array $options Options for the request + * @return array $options + */ + protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) { + if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) { + throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url); + } + + if (empty($options['hooks'])) { + $options['hooks'] = new Requests_Hooks(); + } + + if (is_array($options['auth'])) { + $options['auth'] = new Requests_Auth_Basic($options['auth']); + } + if ($options['auth'] !== false) { + $options['auth']->register($options['hooks']); + } + + if (is_string($options['proxy']) || is_array($options['proxy'])) { + $options['proxy'] = new Requests_Proxy_HTTP($options['proxy']); + } + if ($options['proxy'] !== false) { + $options['proxy']->register($options['hooks']); + } + + if (is_array($options['cookies'])) { + $options['cookies'] = new Requests_Cookie_Jar($options['cookies']); + } + elseif (empty($options['cookies'])) { + $options['cookies'] = new Requests_Cookie_Jar(); + } + if ($options['cookies'] !== false) { + $options['cookies']->register($options['hooks']); + } + + if ($options['idn'] !== false) { + $iri = new Requests_IRI($url); + $iri->host = Requests_IDNAEncoder::encode($iri->ihost); + $url = $iri->uri; + } + + // Massage the type to ensure we support it. + $type = strtoupper($type); + + if (!isset($options['data_format'])) { + if (in_array($type, array(self::HEAD, self::GET, self::DELETE))) { + $options['data_format'] = 'query'; + } + else { + $options['data_format'] = 'body'; + } + } + } + + /** + * HTTP response parser + * + * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`) + * @throws Requests_Exception On missing head/body separator (`noversion`) + * @throws Requests_Exception On missing head/body separator (`toomanyredirects`) + * + * @param string $headers Full response text including headers and body + * @param string $url Original request URL + * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects + * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects + * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects + * @return Requests_Response + */ + protected static function parse_response($headers, $url, $req_headers, $req_data, $options) { + $return = new Requests_Response(); + if (!$options['blocking']) { + return $return; + } + + $return->raw = $headers; + $return->url = $url; + + if (!$options['filename']) { + if (($pos = strpos($headers, "\r\n\r\n")) === false) { + // Crap! + throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator'); + } + + $headers = substr($return->raw, 0, $pos); + $return->body = substr($return->raw, $pos + strlen("\n\r\n\r")); + } + else { + $return->body = ''; + } + // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3) + $headers = str_replace("\r\n", "\n", $headers); + // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2) + $headers = preg_replace('/\n[ \t]/', ' ', $headers); + $headers = explode("\n", $headers); + preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches); + if (empty($matches)) { + throw new Requests_Exception('Response could not be parsed', 'noversion', $headers); + } + $return->protocol_version = (float) $matches[1]; + $return->status_code = (int) $matches[2]; + if ($return->status_code >= 200 && $return->status_code < 300) { + $return->success = true; + } + + foreach ($headers as $header) { + list($key, $value) = explode(':', $header, 2); + $value = trim($value); + preg_replace('#(\s+)#i', ' ', $value); + $return->headers[$key] = $value; + } + if (isset($return->headers['transfer-encoding'])) { + $return->body = self::decode_chunked($return->body); + unset($return->headers['transfer-encoding']); + } + if (isset($return->headers['content-encoding'])) { + $return->body = self::decompress($return->body); + } + + //fsockopen and cURL compatibility + if (isset($return->headers['connection'])) { + unset($return->headers['connection']); + } + + $options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options)); + + if ($return->is_redirect() && $options['follow_redirects'] === true) { + if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) { + if ($return->status_code === 303) { + $options['type'] = self::GET; + } + $options['redirected']++; + $location = $return->headers['location']; + if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) { + // relative redirect, for compatibility make it absolute + $location = Requests_IRI::absolutize($url, $location); + $location = $location->uri; + } + + $hook_args = array( + &$location, + &$req_headers, + &$req_data, + &$options, + $return + ); + $options['hooks']->dispatch('requests.before_redirect', $hook_args); + $redirected = self::request($location, $req_headers, $req_data, $options['type'], $options); + $redirected->history[] = $return; + return $redirected; + } + elseif ($options['redirected'] >= $options['redirects']) { + throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return); + } + } + + $return->redirects = $options['redirected']; + + $options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options)); + return $return; + } + + /** + * Callback for `transport.internal.parse_response` + * + * Internal use only. Converts a raw HTTP response to a Requests_Response + * while still executing a multiple request. + * + * @param string $response Full response text including headers and body (will be overwritten with Response instance) + * @param array $request Request data as passed into {@see Requests::request_multiple()} + * @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object + */ + public static function parse_multiple(&$response, $request) { + try { + $url = $request['url']; + $headers = $request['headers']; + $data = $request['data']; + $options = $request['options']; + $response = self::parse_response($response, $url, $headers, $data, $options); + } + catch (Requests_Exception $e) { + $response = $e; + } + } + + /** + * Decoded a chunked body as per RFC 2616 + * + * @see https://tools.ietf.org/html/rfc2616#section-3.6.1 + * @param string $data Chunked body + * @return string Decoded body + */ + protected static function decode_chunked($data) { + if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) { + return $data; + } + + + + $decoded = ''; + $encoded = $data; + + while (true) { + $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches); + if (!$is_chunked) { + // Looks like it's not chunked after all + return $data; + } + + $length = hexdec(trim($matches[1])); + if ($length === 0) { + // Ignore trailer headers + return $decoded; + } + + $chunk_length = strlen($matches[0]); + $decoded .= substr($encoded, $chunk_length, $length); + $encoded = substr($encoded, $chunk_length + $length + 2); + + if (trim($encoded) === '0' || empty($encoded)) { + return $decoded; + } + } + + // We'll never actually get down here + // @codeCoverageIgnoreStart + } + // @codeCoverageIgnoreEnd + + /** + * Convert a key => value array to a 'key: value' array for headers + * + * @param array $array Dictionary of header values + * @return array List of headers + */ + public static function flatten($array) { + $return = array(); + foreach ($array as $key => $value) { + $return[] = sprintf('%s: %s', $key, $value); + } + return $return; + } + + /** + * Convert a key => value array to a 'key: value' array for headers + * + * @codeCoverageIgnore + * @deprecated Misspelling of {@see Requests::flatten} + * @param array $array Dictionary of header values + * @return array List of headers + */ + public static function flattern($array) { + return self::flatten($array); + } + + /** + * Decompress an encoded body + * + * Implements gzip, compress and deflate. Guesses which it is by attempting + * to decode. + * + * @param string $data Compressed data in one of the above formats + * @return string Decompressed string + */ + public static function decompress($data) { + if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") { + // Not actually compressed. Probably cURL ruining this for us. + return $data; + } + + if (function_exists('gzdecode') && ($decoded = @gzdecode($data)) !== false) { + return $decoded; + } + elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) { + return $decoded; + } + elseif (($decoded = self::compatible_gzinflate($data)) !== false) { + return $decoded; + } + elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) { + return $decoded; + } + + return $data; + } + + /** + * Decompression of deflated string while staying compatible with the majority of servers. + * + * Certain Servers will return deflated data with headers which PHP's gzinflate() + * function cannot handle out of the box. The following function has been created from + * various snippets on the gzinflate() PHP documentation. + * + * Warning: Magic numbers within. Due to the potential different formats that the compressed + * data may be returned in, some "magic offsets" are needed to ensure proper decompression + * takes place. For a simple progmatic way to determine the magic offset in use, see: + * https://core.trac.wordpress.org/ticket/18273 + * + * @since 2.8.1 + * @link https://core.trac.wordpress.org/ticket/18273 + * @link https://secure.php.net/manual/en/function.gzinflate.php#70875 + * @link https://secure.php.net/manual/en/function.gzinflate.php#77336 + * + * @param string $gzData String to decompress. + * @return string|bool False on failure. + */ + public static function compatible_gzinflate($gzData) { + // Compressed data might contain a full zlib header, if so strip it for + // gzinflate() + if (substr($gzData, 0, 3) == "\x1f\x8b\x08") { + $i = 10; + $flg = ord(substr($gzData, 3, 1)); + if ($flg > 0) { + if ($flg & 4) { + list($xlen) = unpack('v', substr($gzData, $i, 2)); + $i = $i + 2 + $xlen; + } + if ($flg & 8) { + $i = strpos($gzData, "\0", $i) + 1; + } + if ($flg & 16) { + $i = strpos($gzData, "\0", $i) + 1; + } + if ($flg & 2) { + $i = $i + 2; + } + } + $decompressed = self::compatible_gzinflate(substr($gzData, $i)); + if (false !== $decompressed) { + return $decompressed; + } + } + + // If the data is Huffman Encoded, we must first strip the leading 2 + // byte Huffman marker for gzinflate() + // The response is Huffman coded by many compressors such as + // java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's + // System.IO.Compression.DeflateStream. + // + // See https://decompres.blogspot.com/ for a quick explanation of this + // data type + $huffman_encoded = false; + + // low nibble of first byte should be 0x08 + list(, $first_nibble) = unpack('h', $gzData); + + // First 2 bytes should be divisible by 0x1F + list(, $first_two_bytes) = unpack('n', $gzData); + + if (0x08 == $first_nibble && 0 == ($first_two_bytes % 0x1F)) { + $huffman_encoded = true; + } + + if ($huffman_encoded) { + if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) { + return $decompressed; + } + } + + if ("\x50\x4b\x03\x04" == substr($gzData, 0, 4)) { + // ZIP file format header + // Offset 6: 2 bytes, General-purpose field + // Offset 26: 2 bytes, filename length + // Offset 28: 2 bytes, optional field length + // Offset 30: Filename field, followed by optional field, followed + // immediately by data + list(, $general_purpose_flag) = unpack('v', substr($gzData, 6, 2)); + + // If the file has been compressed on the fly, 0x08 bit is set of + // the general purpose field. We can use this to differentiate + // between a compressed document, and a ZIP file + $zip_compressed_on_the_fly = (0x08 == (0x08 & $general_purpose_flag)); + + if (!$zip_compressed_on_the_fly) { + // Don't attempt to decode a compressed zip file + return $gzData; + } + + // Determine the first byte of data, based on the above ZIP header + // offsets: + $first_file_start = array_sum(unpack('v2', substr($gzData, 26, 4))); + if (false !== ($decompressed = @gzinflate(substr($gzData, 30 + $first_file_start)))) { + return $decompressed; + } + return false; + } + + // Finally fall back to straight gzinflate + if (false !== ($decompressed = @gzinflate($gzData))) { + return $decompressed; + } + + // Fallback for all above failing, not expected, but included for + // debugging and preventing regressions and to track stats + if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) { + return $decompressed; + } + + return false; + } + + public static function match_domain($host, $reference) { + // Check for a direct match + if ($host === $reference) { + return true; + } + + // Calculate the valid wildcard match if the host is not an IP address + // Also validates that the host has 3 parts or more, as per Firefox's + // ruleset. + $parts = explode('.', $host); + if (ip2long($host) === false && count($parts) >= 3) { + $parts[0] = '*'; + $wildcard = implode('.', $parts); + if ($wildcard === $reference) { + return true; + } + } + + return false; + } +} diff --git a/vendor/requests/library/Requests/Auth.php b/vendor/requests/library/Requests/Auth.php new file mode 100644 index 00000000..bca41092 --- /dev/null +++ b/vendor/requests/library/Requests/Auth.php @@ -0,0 +1,33 @@ +user, $this->pass) = $args; + } + } + + /** + * Register the necessary callbacks + * + * @see curl_before_send + * @see fsockopen_header + * @param Requests_Hooks $hooks Hook system + */ + public function register(Requests_Hooks &$hooks) { + $hooks->register('curl.before_send', array(&$this, 'curl_before_send')); + $hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header')); + } + + /** + * Set cURL parameters before the data is sent + * + * @param resource $handle cURL resource + */ + public function curl_before_send(&$handle) { + curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString()); + } + + /** + * Add extra headers to the request before sending + * + * @param string $out HTTP header string + */ + public function fsockopen_header(&$out) { + $out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString())); + } + + /** + * Get the authentication string (user:pass) + * + * @return string + */ + public function getAuthString() { + return $this->user . ':' . $this->pass; + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Cookie.php b/vendor/requests/library/Requests/Cookie.php new file mode 100644 index 00000000..00fbbc73 --- /dev/null +++ b/vendor/requests/library/Requests/Cookie.php @@ -0,0 +1,500 @@ +name = $name; + $this->value = $value; + $this->attributes = $attributes; + $default_flags = array( + 'creation' => time(), + 'last-access' => time(), + 'persistent' => false, + 'host-only' => true, + ); + $this->flags = array_merge($default_flags, $flags); + + $this->reference_time = time(); + if ($reference_time !== null) { + $this->reference_time = $reference_time; + } + + $this->normalize(); + } + + /** + * Check if a cookie is expired. + * + * Checks the age against $this->reference_time to determine if the cookie + * is expired. + * + * @return boolean True if expired, false if time is valid. + */ + public function is_expired() { + // RFC6265, s. 4.1.2.2: + // If a cookie has both the Max-Age and the Expires attribute, the Max- + // Age attribute has precedence and controls the expiration date of the + // cookie. + if (isset($this->attributes['max-age'])) { + $max_age = $this->attributes['max-age']; + return $max_age < $this->reference_time; + } + + if (isset($this->attributes['expires'])) { + $expires = $this->attributes['expires']; + return $expires < $this->reference_time; + } + + return false; + } + + /** + * Check if a cookie is valid for a given URI + * + * @param Requests_IRI $uri URI to check + * @return boolean Whether the cookie is valid for the given URI + */ + public function uri_matches(Requests_IRI $uri) { + if (!$this->domain_matches($uri->host)) { + return false; + } + + if (!$this->path_matches($uri->path)) { + return false; + } + + return empty($this->attributes['secure']) || $uri->scheme === 'https'; + } + + /** + * Check if a cookie is valid for a given domain + * + * @param string $string Domain to check + * @return boolean Whether the cookie is valid for the given domain + */ + public function domain_matches($string) { + if (!isset($this->attributes['domain'])) { + // Cookies created manually; cookies created by Requests will set + // the domain to the requested domain + return true; + } + + $domain_string = $this->attributes['domain']; + if ($domain_string === $string) { + // The domain string and the string are identical. + return true; + } + + // If the cookie is marked as host-only and we don't have an exact + // match, reject the cookie + if ($this->flags['host-only'] === true) { + return false; + } + + if (strlen($string) <= strlen($domain_string)) { + // For obvious reasons, the string cannot be a suffix if the domain + // is shorter than the domain string + return false; + } + + if (substr($string, -1 * strlen($domain_string)) !== $domain_string) { + // The domain string should be a suffix of the string. + return false; + } + + $prefix = substr($string, 0, strlen($string) - strlen($domain_string)); + if (substr($prefix, -1) !== '.') { + // The last character of the string that is not included in the + // domain string should be a %x2E (".") character. + return false; + } + + // The string should be a host name (i.e., not an IP address). + return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $string); + } + + /** + * Check if a cookie is valid for a given path + * + * From the path-match check in RFC 6265 section 5.1.4 + * + * @param string $request_path Path to check + * @return boolean Whether the cookie is valid for the given path + */ + public function path_matches($request_path) { + if (empty($request_path)) { + // Normalize empty path to root + $request_path = '/'; + } + + if (!isset($this->attributes['path'])) { + // Cookies created manually; cookies created by Requests will set + // the path to the requested path + return true; + } + + $cookie_path = $this->attributes['path']; + + if ($cookie_path === $request_path) { + // The cookie-path and the request-path are identical. + return true; + } + + if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) { + if (substr($cookie_path, -1) === '/') { + // The cookie-path is a prefix of the request-path, and the last + // character of the cookie-path is %x2F ("/"). + return true; + } + + if (substr($request_path, strlen($cookie_path), 1) === '/') { + // The cookie-path is a prefix of the request-path, and the + // first character of the request-path that is not included in + // the cookie-path is a %x2F ("/") character. + return true; + } + } + + return false; + } + + /** + * Normalize cookie and attributes + * + * @return boolean Whether the cookie was successfully normalized + */ + public function normalize() { + foreach ($this->attributes as $key => $value) { + $orig_value = $value; + $value = $this->normalize_attribute($key, $value); + if ($value === null) { + unset($this->attributes[$key]); + continue; + } + + if ($value !== $orig_value) { + $this->attributes[$key] = $value; + } + } + + return true; + } + + /** + * Parse an individual cookie attribute + * + * Handles parsing individual attributes from the cookie values. + * + * @param string $name Attribute name + * @param string|boolean $value Attribute value (string value, or true if empty/flag) + * @return mixed Value if available, or null if the attribute value is invalid (and should be skipped) + */ + protected function normalize_attribute($name, $value) { + switch (strtolower($name)) { + case 'expires': + // Expiration parsing, as per RFC 6265 section 5.2.1 + if (is_int($value)) { + return $value; + } + + $expiry_time = strtotime($value); + if ($expiry_time === false) { + return null; + } + + return $expiry_time; + + case 'max-age': + // Expiration parsing, as per RFC 6265 section 5.2.2 + if (is_int($value)) { + return $value; + } + + // Check that we have a valid age + if (!preg_match('/^-?\d+$/', $value)) { + return null; + } + + $delta_seconds = (int) $value; + if ($delta_seconds <= 0) { + $expiry_time = 0; + } + else { + $expiry_time = $this->reference_time + $delta_seconds; + } + + return $expiry_time; + + case 'domain': + // Domain normalization, as per RFC 6265 section 5.2.3 + if ($value[0] === '.') { + $value = substr($value, 1); + } + + return $value; + + default: + return $value; + } + } + + /** + * Format a cookie for a Cookie header + * + * This is used when sending cookies to a server. + * + * @return string Cookie formatted for Cookie header + */ + public function format_for_header() { + return sprintf('%s=%s', $this->name, $this->value); + } + + /** + * Format a cookie for a Cookie header + * + * @codeCoverageIgnore + * @deprecated Use {@see Requests_Cookie::format_for_header} + * @return string + */ + public function formatForHeader() { + return $this->format_for_header(); + } + + /** + * Format a cookie for a Set-Cookie header + * + * This is used when sending cookies to clients. This isn't really + * applicable to client-side usage, but might be handy for debugging. + * + * @return string Cookie formatted for Set-Cookie header + */ + public function format_for_set_cookie() { + $header_value = $this->format_for_header(); + if (!empty($this->attributes)) { + $parts = array(); + foreach ($this->attributes as $key => $value) { + // Ignore non-associative attributes + if (is_numeric($key)) { + $parts[] = $value; + } + else { + $parts[] = sprintf('%s=%s', $key, $value); + } + } + + $header_value .= '; ' . implode('; ', $parts); + } + return $header_value; + } + + /** + * Format a cookie for a Set-Cookie header + * + * @codeCoverageIgnore + * @deprecated Use {@see Requests_Cookie::format_for_set_cookie} + * @return string + */ + public function formatForSetCookie() { + return $this->format_for_set_cookie(); + } + + /** + * Get the cookie value + * + * Attributes and other data can be accessed via methods. + */ + public function __toString() { + return $this->value; + } + + /** + * Parse a cookie string into a cookie object + * + * Based on Mozilla's parsing code in Firefox and related projects, which + * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265 + * specifies some of this handling, but not in a thorough manner. + * + * @param string Cookie header value (from a Set-Cookie header) + * @return Requests_Cookie Parsed cookie object + */ + public static function parse($string, $name = '', $reference_time = null) { + $parts = explode(';', $string); + $kvparts = array_shift($parts); + + if (!empty($name)) { + $value = $string; + } + elseif (strpos($kvparts, '=') === false) { + // Some sites might only have a value without the equals separator. + // Deviate from RFC 6265 and pretend it was actually a blank name + // (`=foo`) + // + // https://bugzilla.mozilla.org/show_bug.cgi?id=169091 + $name = ''; + $value = $kvparts; + } + else { + list($name, $value) = explode('=', $kvparts, 2); + } + $name = trim($name); + $value = trim($value); + + // Attribute key are handled case-insensitively + $attributes = new Requests_Utility_CaseInsensitiveDictionary(); + + if (!empty($parts)) { + foreach ($parts as $part) { + if (strpos($part, '=') === false) { + $part_key = $part; + $part_value = true; + } + else { + list($part_key, $part_value) = explode('=', $part, 2); + $part_value = trim($part_value); + } + + $part_key = trim($part_key); + $attributes[$part_key] = $part_value; + } + } + + return new Requests_Cookie($name, $value, $attributes, array(), $reference_time); + } + + /** + * Parse all Set-Cookie headers from request headers + * + * @param Requests_Response_Headers $headers Headers to parse from + * @param Requests_IRI|null $origin URI for comparing cookie origins + * @param int|null $time Reference time for expiration calculation + * @return array + */ + public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) { + $cookie_headers = $headers->getValues('Set-Cookie'); + if (empty($cookie_headers)) { + return array(); + } + + $cookies = array(); + foreach ($cookie_headers as $header) { + $parsed = self::parse($header, '', $time); + + // Default domain/path attributes + if (empty($parsed->attributes['domain']) && !empty($origin)) { + $parsed->attributes['domain'] = $origin->host; + $parsed->flags['host-only'] = true; + } + else { + $parsed->flags['host-only'] = false; + } + + $path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/'); + if (!$path_is_valid && !empty($origin)) { + $path = $origin->path; + + // Default path normalization as per RFC 6265 section 5.1.4 + if (substr($path, 0, 1) !== '/') { + // If the uri-path is empty or if the first character of + // the uri-path is not a %x2F ("/") character, output + // %x2F ("/") and skip the remaining steps. + $path = '/'; + } + elseif (substr_count($path, '/') === 1) { + // If the uri-path contains no more than one %x2F ("/") + // character, output %x2F ("/") and skip the remaining + // step. + $path = '/'; + } + else { + // Output the characters of the uri-path from the first + // character up to, but not including, the right-most + // %x2F ("/"). + $path = substr($path, 0, strrpos($path, '/')); + } + $parsed->attributes['path'] = $path; + } + + // Reject invalid cookie domains + if (!empty($origin) && !$parsed->domain_matches($origin->host)) { + continue; + } + + $cookies[$parsed->name] = $parsed; + } + + return $cookies; + } + + /** + * Parse all Set-Cookie headers from request headers + * + * @codeCoverageIgnore + * @deprecated Use {@see Requests_Cookie::parse_from_headers} + * @return string + */ + public static function parseFromHeaders(Requests_Response_Headers $headers) { + return self::parse_from_headers($headers); + } +} diff --git a/vendor/requests/library/Requests/Cookie/Jar.php b/vendor/requests/library/Requests/Cookie/Jar.php new file mode 100644 index 00000000..69be0fb5 --- /dev/null +++ b/vendor/requests/library/Requests/Cookie/Jar.php @@ -0,0 +1,175 @@ +cookies = $cookies; + } + + /** + * Normalise cookie data into a Requests_Cookie + * + * @param string|Requests_Cookie $cookie + * @return Requests_Cookie + */ + public function normalize_cookie($cookie, $key = null) { + if ($cookie instanceof Requests_Cookie) { + return $cookie; + } + + return Requests_Cookie::parse($cookie, $key); + } + + /** + * Normalise cookie data into a Requests_Cookie + * + * @codeCoverageIgnore + * @deprecated Use {@see Requests_Cookie_Jar::normalize_cookie} + * @return Requests_Cookie + */ + public function normalizeCookie($cookie, $key = null) { + return $this->normalize_cookie($cookie, $key); + } + + /** + * Check if the given item exists + * + * @param string $key Item key + * @return boolean Does the item exist? + */ + public function offsetExists($key) { + return isset($this->cookies[$key]); + } + + /** + * Get the value for the item + * + * @param string $key Item key + * @return string Item value + */ + public function offsetGet($key) { + if (!isset($this->cookies[$key])) { + return null; + } + + return $this->cookies[$key]; + } + + /** + * Set the given item + * + * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) + * + * @param string $key Item name + * @param string $value Item value + */ + public function offsetSet($key, $value) { + if ($key === null) { + throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); + } + + $this->cookies[$key] = $value; + } + + /** + * Unset the given header + * + * @param string $key + */ + public function offsetUnset($key) { + unset($this->cookies[$key]); + } + + /** + * Get an iterator for the data + * + * @return ArrayIterator + */ + public function getIterator() { + return new ArrayIterator($this->cookies); + } + + /** + * Register the cookie handler with the request's hooking system + * + * @param Requests_Hooker $hooks Hooking system + */ + public function register(Requests_Hooker $hooks) { + $hooks->register('requests.before_request', array($this, 'before_request')); + $hooks->register('requests.before_redirect_check', array($this, 'before_redirect_check')); + } + + /** + * Add Cookie header to a request if we have any + * + * As per RFC 6265, cookies are separated by '; ' + * + * @param string $url + * @param array $headers + * @param array $data + * @param string $type + * @param array $options + */ + public function before_request($url, &$headers, &$data, &$type, &$options) { + if (!$url instanceof Requests_IRI) { + $url = new Requests_IRI($url); + } + + if (!empty($this->cookies)) { + $cookies = array(); + foreach ($this->cookies as $key => $cookie) { + $cookie = $this->normalize_cookie($cookie, $key); + + // Skip expired cookies + if ($cookie->is_expired()) { + continue; + } + + if ($cookie->domain_matches($url->host)) { + $cookies[] = $cookie->format_for_header(); + } + } + + $headers['Cookie'] = implode('; ', $cookies); + } + } + + /** + * Parse all cookies from a response and attach them to the response + * + * @var Requests_Response $response + */ + public function before_redirect_check(Requests_Response &$return) { + $url = $return->url; + if (!$url instanceof Requests_IRI) { + $url = new Requests_IRI($url); + } + + $cookies = Requests_Cookie::parse_from_headers($return->headers, $url); + $this->cookies = array_merge($this->cookies, $cookies); + $return->cookies = $this; + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Exception.php b/vendor/requests/library/Requests/Exception.php new file mode 100644 index 00000000..37d4711c --- /dev/null +++ b/vendor/requests/library/Requests/Exception.php @@ -0,0 +1,62 @@ +type = $type; + $this->data = $data; + } + + /** + * Like {@see getCode()}, but a string code. + * + * @codeCoverageIgnore + * @return string + */ + public function getType() { + return $this->type; + } + + /** + * Gives any relevant data + * + * @codeCoverageIgnore + * @return mixed + */ + public function getData() { + return $this->data; + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Exception/HTTP.php b/vendor/requests/library/Requests/Exception/HTTP.php new file mode 100644 index 00000000..9ac6a873 --- /dev/null +++ b/vendor/requests/library/Requests/Exception/HTTP.php @@ -0,0 +1,71 @@ +reason = $reason; + } + + $message = sprintf('%d %s', $this->code, $this->reason); + parent::__construct($message, 'httpresponse', $data, $this->code); + } + + /** + * Get the status message + */ + public function getReason() { + return $this->reason; + } + + /** + * Get the correct exception class for a given error code + * + * @param int|bool $code HTTP status code, or false if unavailable + * @return string Exception class name to use + */ + public static function get_class($code) { + if (!$code) { + return 'Requests_Exception_HTTP_Unknown'; + } + + $class = sprintf('Requests_Exception_HTTP_%d', $code); + if (class_exists($class)) { + return $class; + } + + return 'Requests_Exception_HTTP_Unknown'; + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Exception/HTTP/304.php b/vendor/requests/library/Requests/Exception/HTTP/304.php new file mode 100644 index 00000000..67990335 --- /dev/null +++ b/vendor/requests/library/Requests/Exception/HTTP/304.php @@ -0,0 +1,27 @@ +code = $data->status_code; + } + + parent::__construct($reason, $data); + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Exception/Transport.php b/vendor/requests/library/Requests/Exception/Transport.php new file mode 100644 index 00000000..e60b4884 --- /dev/null +++ b/vendor/requests/library/Requests/Exception/Transport.php @@ -0,0 +1,5 @@ +type = $type; + } + + if ($code !== null) { + $this->code = $code; + } + + if ($message !== null) { + $this->reason = $message; + } + + $message = sprintf('%d %s', $this->code, $this->reason); + parent::__construct($message, $this->type, $data, $this->code); + } + + /** + * Get the error message + */ + public function getReason() { + return $this->reason; + } + +} diff --git a/vendor/requests/library/Requests/Hooker.php b/vendor/requests/library/Requests/Hooker.php new file mode 100644 index 00000000..f667ae9c --- /dev/null +++ b/vendor/requests/library/Requests/Hooker.php @@ -0,0 +1,33 @@ +0 is executed later + */ + public function register($hook, $callback, $priority = 0); + + /** + * Dispatch a message + * + * @param string $hook Hook name + * @param array $parameters Parameters to pass to callbacks + * @return boolean Successfulness + */ + public function dispatch($hook, $parameters = array()); +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Hooks.php b/vendor/requests/library/Requests/Hooks.php new file mode 100644 index 00000000..2e61c734 --- /dev/null +++ b/vendor/requests/library/Requests/Hooks.php @@ -0,0 +1,68 @@ +0 is executed later + */ + public function register($hook, $callback, $priority = 0) { + if (!isset($this->hooks[$hook])) { + $this->hooks[$hook] = array(); + } + if (!isset($this->hooks[$hook][$priority])) { + $this->hooks[$hook][$priority] = array(); + } + + $this->hooks[$hook][$priority][] = $callback; + } + + /** + * Dispatch a message + * + * @param string $hook Hook name + * @param array $parameters Parameters to pass to callbacks + * @return boolean Successfulness + */ + public function dispatch($hook, $parameters = array()) { + if (empty($this->hooks[$hook])) { + return false; + } + + foreach ($this->hooks[$hook] as $priority => $hooked) { + foreach ($hooked as $callback) { + call_user_func_array($callback, $parameters); + } + } + + return true; + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/IDNAEncoder.php b/vendor/requests/library/Requests/IDNAEncoder.php new file mode 100644 index 00000000..ebbe2111 --- /dev/null +++ b/vendor/requests/library/Requests/IDNAEncoder.php @@ -0,0 +1,388 @@ + 0) { + if ($position + $length > $strlen) { + throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); + } + for ($position++; $remaining > 0; $position++) { + $value = ord($input[$position]); + + // If it is invalid, count the sequence as invalid and reprocess the current byte: + if (($value & 0xC0) !== 0x80) { + throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); + } + + $character |= ($value & 0x3F) << (--$remaining * 6); + } + $position--; + } + + if ( + // Non-shortest form sequences are invalid + $length > 1 && $character <= 0x7F + || $length > 2 && $character <= 0x7FF + || $length > 3 && $character <= 0xFFFF + // Outside of range of ucschar codepoints + // Noncharacters + || ($character & 0xFFFE) === 0xFFFE + || $character >= 0xFDD0 && $character <= 0xFDEF + || ( + // Everything else not in ucschar + $character > 0xD7FF && $character < 0xF900 + || $character < 0x20 + || $character > 0x7E && $character < 0xA0 + || $character > 0xEFFFD + ) + ) { + throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); + } + + $codepoints[] = $character; + } + + return $codepoints; + } + + /** + * RFC3492-compliant encoder + * + * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code + * @throws Requests_Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`) + * + * @param string $input UTF-8 encoded string to encode + * @return string Punycode-encoded string + */ + public static function punycode_encode($input) { + $output = ''; +# let n = initial_n + $n = self::BOOTSTRAP_INITIAL_N; +# let delta = 0 + $delta = 0; +# let bias = initial_bias + $bias = self::BOOTSTRAP_INITIAL_BIAS; +# let h = b = the number of basic code points in the input + $h = $b = 0; // see loop +# copy them to the output in order + $codepoints = self::utf8_to_codepoints($input); + $extended = array(); + + foreach ($codepoints as $char) { + if ($char < 128) { + // Character is valid ASCII + // TODO: this should also check if it's valid for a URL + $output .= chr($char); + $h++; + } + // Check if the character is non-ASCII, but below initial n + // This never occurs for Punycode, so ignore in coverage + // @codeCoverageIgnoreStart + elseif ($char < $n) { + throw new Requests_Exception('Invalid character', 'idna.character_outside_domain', $char); + } + // @codeCoverageIgnoreEnd + else { + $extended[$char] = true; + } + } + $extended = array_keys($extended); + sort($extended); + $b = $h; +# [copy them] followed by a delimiter if b > 0 + if (strlen($output) > 0) { + $output .= '-'; + } +# {if the input contains a non-basic code point < n then fail} +# while h < length(input) do begin + while ($h < count($codepoints)) { +# let m = the minimum code point >= n in the input + $m = array_shift($extended); + //printf('next code point to insert is %s' . PHP_EOL, dechex($m)); +# let delta = delta + (m - n) * (h + 1), fail on overflow + $delta += ($m - $n) * ($h + 1); +# let n = m + $n = $m; +# for each code point c in the input (in order) do begin + for ($num = 0; $num < count($codepoints); $num++) { + $c = $codepoints[$num]; +# if c < n then increment delta, fail on overflow + if ($c < $n) { + $delta++; + } +# if c == n then begin + elseif ($c === $n) { +# let q = delta + $q = $delta; +# for k = base to infinity in steps of base do begin + for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) { +# let t = tmin if k <= bias {+ tmin}, or +# tmax if k >= bias + tmax, or k - bias otherwise + if ($k <= ($bias + self::BOOTSTRAP_TMIN)) { + $t = self::BOOTSTRAP_TMIN; + } + elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) { + $t = self::BOOTSTRAP_TMAX; + } + else { + $t = $k - $bias; + } +# if q < t then break + if ($q < $t) { + break; + } +# output the code point for digit t + ((q - t) mod (base - t)) + $digit = $t + (($q - $t) % (self::BOOTSTRAP_BASE - $t)); + $output .= self::digit_to_char($digit); +# let q = (q - t) div (base - t) + $q = floor(($q - $t) / (self::BOOTSTRAP_BASE - $t)); +# end + } +# output the code point for digit q + $output .= self::digit_to_char($q); +# let bias = adapt(delta, h + 1, test h equals b?) + $bias = self::adapt($delta, $h + 1, $h === $b); +# let delta = 0 + $delta = 0; +# increment h + $h++; +# end + } +# end + } +# increment delta and n + $delta++; + $n++; +# end + } + + return $output; + } + + /** + * Convert a digit to its respective character + * + * @see https://tools.ietf.org/html/rfc3492#section-5 + * @throws Requests_Exception On invalid digit (`idna.invalid_digit`) + * + * @param int $digit Digit in the range 0-35 + * @return string Single character corresponding to digit + */ + protected static function digit_to_char($digit) { + // @codeCoverageIgnoreStart + // As far as I know, this never happens, but still good to be sure. + if ($digit < 0 || $digit > 35) { + throw new Requests_Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit); + } + // @codeCoverageIgnoreEnd + $digits = 'abcdefghijklmnopqrstuvwxyz0123456789'; + return substr($digits, $digit, 1); + } + + /** + * Adapt the bias + * + * @see https://tools.ietf.org/html/rfc3492#section-6.1 + * @param int $delta + * @param int $numpoints + * @param bool $firsttime + * @return int New bias + */ + protected static function adapt($delta, $numpoints, $firsttime) { +# function adapt(delta,numpoints,firsttime): +# if firsttime then let delta = delta div damp + if ($firsttime) { + $delta = floor($delta / self::BOOTSTRAP_DAMP); + } +# else let delta = delta div 2 + else { + $delta = floor($delta / 2); + } +# let delta = delta + (delta div numpoints) + $delta += floor($delta / $numpoints); +# let k = 0 + $k = 0; +# while delta > ((base - tmin) * tmax) div 2 do begin + $max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2); + while ($delta > $max) { +# let delta = delta div (base - tmin) + $delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN)); +# let k = k + base + $k += self::BOOTSTRAP_BASE; +# end + } +# return k + (((base - tmin + 1) * delta) div (delta + skew)) + return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW)); + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/IPv6.php b/vendor/requests/library/Requests/IPv6.php new file mode 100644 index 00000000..204dbd7e --- /dev/null +++ b/vendor/requests/library/Requests/IPv6.php @@ -0,0 +1,190 @@ + FF01:0:0:0:0:0:0:101 + * ::1 -> 0:0:0:0:0:0:0:1 + * + * @author Alexander Merz + * @author elfrink at introweb dot nl + * @author Josh Peck + * @copyright 2003-2005 The PHP Group + * @license http://www.opensource.org/licenses/bsd-license.php + * @param string $ip An IPv6 address + * @return string The uncompressed IPv6 address + */ + public static function uncompress($ip) { + if (substr_count($ip, '::') !== 1) { + return $ip; + } + + list($ip1, $ip2) = explode('::', $ip); + $c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':'); + $c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':'); + + if (strpos($ip2, '.') !== false) { + $c2++; + } + // :: + if ($c1 === -1 && $c2 === -1) { + $ip = '0:0:0:0:0:0:0:0'; + } + // ::xxx + else if ($c1 === -1) { + $fill = str_repeat('0:', 7 - $c2); + $ip = str_replace('::', $fill, $ip); + } + // xxx:: + else if ($c2 === -1) { + $fill = str_repeat(':0', 7 - $c1); + $ip = str_replace('::', $fill, $ip); + } + // xxx::xxx + else { + $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); + $ip = str_replace('::', $fill, $ip); + } + return $ip; + } + + /** + * Compresses an IPv6 address + * + * RFC 4291 allows you to compress consecutive zero pieces in an address to + * '::'. This method expects a valid IPv6 address and compresses consecutive + * zero pieces to '::'. + * + * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 + * 0:0:0:0:0:0:0:1 -> ::1 + * + * @see uncompress() + * @param string $ip An IPv6 address + * @return string The compressed IPv6 address + */ + public static function compress($ip) { + // Prepare the IP to be compressed + $ip = self::uncompress($ip); + $ip_parts = self::split_v6_v4($ip); + + // Replace all leading zeros + $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]); + + // Find bunches of zeros + if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) { + $max = 0; + $pos = null; + foreach ($matches[0] as $match) { + if (strlen($match[0]) > $max) { + $max = strlen($match[0]); + $pos = $match[1]; + } + } + + $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max); + } + + if ($ip_parts[1] !== '') { + return implode(':', $ip_parts); + } + else { + return $ip_parts[0]; + } + } + + /** + * Splits an IPv6 address into the IPv6 and IPv4 representation parts + * + * RFC 4291 allows you to represent the last two parts of an IPv6 address + * using the standard IPv4 representation + * + * Example: 0:0:0:0:0:0:13.1.68.3 + * 0:0:0:0:0:FFFF:129.144.52.38 + * + * @param string $ip An IPv6 address + * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part + */ + protected static function split_v6_v4($ip) { + if (strpos($ip, '.') !== false) { + $pos = strrpos($ip, ':'); + $ipv6_part = substr($ip, 0, $pos); + $ipv4_part = substr($ip, $pos + 1); + return array($ipv6_part, $ipv4_part); + } + else { + return array($ip, ''); + } + } + + /** + * Checks an IPv6 address + * + * Checks if the given IP is a valid IPv6 address + * + * @param string $ip An IPv6 address + * @return bool true if $ip is a valid IPv6 address + */ + public static function check_ipv6($ip) { + $ip = self::uncompress($ip); + list($ipv6, $ipv4) = self::split_v6_v4($ip); + $ipv6 = explode(':', $ipv6); + $ipv4 = explode('.', $ipv4); + if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) { + foreach ($ipv6 as $ipv6_part) { + // The section can't be empty + if ($ipv6_part === '') { + return false; + } + + // Nor can it be over four characters + if (strlen($ipv6_part) > 4) { + return false; + } + + // Remove leading zeros (this is safe because of the above) + $ipv6_part = ltrim($ipv6_part, '0'); + if ($ipv6_part === '') { + $ipv6_part = '0'; + } + + // Check the value is valid + $value = hexdec($ipv6_part); + if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) { + return false; + } + } + if (count($ipv4) === 4) { + foreach ($ipv4 as $ipv4_part) { + $value = (int) $ipv4_part; + if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) { + return false; + } + } + } + return true; + } + else { + return false; + } + } +} diff --git a/vendor/requests/library/Requests/IRI.php b/vendor/requests/library/Requests/IRI.php new file mode 100644 index 00000000..8dc2fa28 --- /dev/null +++ b/vendor/requests/library/Requests/IRI.php @@ -0,0 +1,1084 @@ + array( + 'port' => 674 + ), + 'dict' => array( + 'port' => 2628 + ), + 'file' => array( + 'ihost' => 'localhost' + ), + 'http' => array( + 'port' => 80, + ), + 'https' => array( + 'port' => 443, + ), + ); + + /** + * Return the entire IRI when you try and read the object as a string + * + * @return string + */ + public function __toString() { + return $this->get_iri(); + } + + /** + * Overload __set() to provide access via properties + * + * @param string $name Property name + * @param mixed $value Property value + */ + public function __set($name, $value) { + if (method_exists($this, 'set_' . $name)) { + call_user_func(array($this, 'set_' . $name), $value); + } + elseif ( + $name === 'iauthority' + || $name === 'iuserinfo' + || $name === 'ihost' + || $name === 'ipath' + || $name === 'iquery' + || $name === 'ifragment' + ) { + call_user_func(array($this, 'set_' . substr($name, 1)), $value); + } + } + + /** + * Overload __get() to provide access via properties + * + * @param string $name Property name + * @return mixed + */ + public function __get($name) { + // isset() returns false for null, we don't want to do that + // Also why we use array_key_exists below instead of isset() + $props = get_object_vars($this); + + if ( + $name === 'iri' || + $name === 'uri' || + $name === 'iauthority' || + $name === 'authority' + ) { + $method = 'get_' . $name; + $return = $this->$method(); + } + elseif (array_key_exists($name, $props)) { + $return = $this->$name; + } + // host -> ihost + elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) { + $name = $prop; + $return = $this->$prop; + } + // ischeme -> scheme + elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) { + $name = $prop; + $return = $this->$prop; + } + else { + trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); + $return = null; + } + + if ($return === null && isset($this->normalization[$this->scheme][$name])) { + return $this->normalization[$this->scheme][$name]; + } + else { + return $return; + } + } + + /** + * Overload __isset() to provide access via properties + * + * @param string $name Property name + * @return bool + */ + public function __isset($name) { + return (method_exists($this, 'get_' . $name) || isset($this->$name)); + } + + /** + * Overload __unset() to provide access via properties + * + * @param string $name Property name + */ + public function __unset($name) { + if (method_exists($this, 'set_' . $name)) { + call_user_func(array($this, 'set_' . $name), ''); + } + } + + /** + * Create a new IRI object, from a specified string + * + * @param string|null $iri + */ + public function __construct($iri = null) { + $this->set_iri($iri); + } + + /** + * Create a new IRI object by resolving a relative IRI + * + * Returns false if $base is not absolute, otherwise an IRI. + * + * @param IRI|string $base (Absolute) Base IRI + * @param IRI|string $relative Relative IRI + * @return IRI|false + */ + public static function absolutize($base, $relative) { + if (!($relative instanceof Requests_IRI)) { + $relative = new Requests_IRI($relative); + } + if (!$relative->is_valid()) { + return false; + } + elseif ($relative->scheme !== null) { + return clone $relative; + } + + if (!($base instanceof Requests_IRI)) { + $base = new Requests_IRI($base); + } + if ($base->scheme === null || !$base->is_valid()) { + return false; + } + + if ($relative->get_iri() !== '') { + if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) { + $target = clone $relative; + $target->scheme = $base->scheme; + } + else { + $target = new Requests_IRI; + $target->scheme = $base->scheme; + $target->iuserinfo = $base->iuserinfo; + $target->ihost = $base->ihost; + $target->port = $base->port; + if ($relative->ipath !== '') { + if ($relative->ipath[0] === '/') { + $target->ipath = $relative->ipath; + } + elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') { + $target->ipath = '/' . $relative->ipath; + } + elseif (($last_segment = strrpos($base->ipath, '/')) !== false) { + $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; + } + else { + $target->ipath = $relative->ipath; + } + $target->ipath = $target->remove_dot_segments($target->ipath); + $target->iquery = $relative->iquery; + } + else { + $target->ipath = $base->ipath; + if ($relative->iquery !== null) { + $target->iquery = $relative->iquery; + } + elseif ($base->iquery !== null) { + $target->iquery = $base->iquery; + } + } + $target->ifragment = $relative->ifragment; + } + } + else { + $target = clone $base; + $target->ifragment = null; + } + $target->scheme_normalization(); + return $target; + } + + /** + * Parse an IRI into scheme/authority/path/query/fragment segments + * + * @param string $iri + * @return array + */ + protected function parse_iri($iri) { + $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); + $has_match = preg_match('/^((?P[^:\/?#]+):)?(\/\/(?P[^\/?#]*))?(?P[^?#]*)(\?(?P[^#]*))?(#(?P.*))?$/', $iri, $match); + if (!$has_match) { + throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri); + } + + if ($match[1] === '') { + $match['scheme'] = null; + } + if (!isset($match[3]) || $match[3] === '') { + $match['authority'] = null; + } + if (!isset($match[5])) { + $match['path'] = ''; + } + if (!isset($match[6]) || $match[6] === '') { + $match['query'] = null; + } + if (!isset($match[8]) || $match[8] === '') { + $match['fragment'] = null; + } + return $match; + } + + /** + * Remove dot segments from a path + * + * @param string $input + * @return string + */ + protected function remove_dot_segments($input) { + $output = ''; + while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') { + // A: If the input buffer begins with a prefix of "../" or "./", + // then remove that prefix from the input buffer; otherwise, + if (strpos($input, '../') === 0) { + $input = substr($input, 3); + } + elseif (strpos($input, './') === 0) { + $input = substr($input, 2); + } + // B: if the input buffer begins with a prefix of "/./" or "/.", + // where "." is a complete path segment, then replace that prefix + // with "/" in the input buffer; otherwise, + elseif (strpos($input, '/./') === 0) { + $input = substr($input, 2); + } + elseif ($input === '/.') { + $input = '/'; + } + // C: if the input buffer begins with a prefix of "/../" or "/..", + // where ".." is a complete path segment, then replace that prefix + // with "/" in the input buffer and remove the last segment and its + // preceding "/" (if any) from the output buffer; otherwise, + elseif (strpos($input, '/../') === 0) { + $input = substr($input, 3); + $output = substr_replace($output, '', strrpos($output, '/')); + } + elseif ($input === '/..') { + $input = '/'; + $output = substr_replace($output, '', strrpos($output, '/')); + } + // D: if the input buffer consists only of "." or "..", then remove + // that from the input buffer; otherwise, + elseif ($input === '.' || $input === '..') { + $input = ''; + } + // E: move the first path segment in the input buffer to the end of + // the output buffer, including the initial "/" character (if any) + // and any subsequent characters up to, but not including, the next + // "/" character or the end of the input buffer + elseif (($pos = strpos($input, '/', 1)) !== false) { + $output .= substr($input, 0, $pos); + $input = substr_replace($input, '', 0, $pos); + } + else { + $output .= $input; + $input = ''; + } + } + return $output . $input; + } + + /** + * Replace invalid character with percent encoding + * + * @param string $string Input string + * @param string $extra_chars Valid characters not in iunreserved or + * iprivate (this is ASCII-only) + * @param bool $iprivate Allow iprivate + * @return string + */ + protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) { + // Normalize as many pct-encoded sections as possible + $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string); + + // Replace invalid percent characters + $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); + + // Add unreserved and % to $extra_chars (the latter is safe because all + // pct-encoded sections are now valid). + $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; + + // Now replace any bytes that aren't allowed with their pct-encoded versions + $position = 0; + $strlen = strlen($string); + while (($position += strspn($string, $extra_chars, $position)) < $strlen) { + $value = ord($string[$position]); + + // Start position + $start = $position; + + // By default we are valid + $valid = true; + + // No one byte sequences are valid due to the while. + // Two byte sequence: + if (($value & 0xE0) === 0xC0) { + $character = ($value & 0x1F) << 6; + $length = 2; + $remaining = 1; + } + // Three byte sequence: + elseif (($value & 0xF0) === 0xE0) { + $character = ($value & 0x0F) << 12; + $length = 3; + $remaining = 2; + } + // Four byte sequence: + elseif (($value & 0xF8) === 0xF0) { + $character = ($value & 0x07) << 18; + $length = 4; + $remaining = 3; + } + // Invalid byte: + else { + $valid = false; + $length = 1; + $remaining = 0; + } + + if ($remaining) { + if ($position + $length <= $strlen) { + for ($position++; $remaining; $position++) { + $value = ord($string[$position]); + + // Check that the byte is valid, then add it to the character: + if (($value & 0xC0) === 0x80) { + $character |= ($value & 0x3F) << (--$remaining * 6); + } + // If it is invalid, count the sequence as invalid and reprocess the current byte: + else { + $valid = false; + $position--; + break; + } + } + } + else { + $position = $strlen - 1; + $valid = false; + } + } + + // Percent encode anything invalid or not in ucschar + if ( + // Invalid sequences + !$valid + // Non-shortest form sequences are invalid + || $length > 1 && $character <= 0x7F + || $length > 2 && $character <= 0x7FF + || $length > 3 && $character <= 0xFFFF + // Outside of range of ucschar codepoints + // Noncharacters + || ($character & 0xFFFE) === 0xFFFE + || $character >= 0xFDD0 && $character <= 0xFDEF + || ( + // Everything else not in ucschar + $character > 0xD7FF && $character < 0xF900 + || $character < 0xA0 + || $character > 0xEFFFD + ) + && ( + // Everything not in iprivate, if it applies + !$iprivate + || $character < 0xE000 + || $character > 0x10FFFD + ) + ) { + // If we were a character, pretend we weren't, but rather an error. + if ($valid) { + $position--; + } + + for ($j = $start; $j <= $position; $j++) { + $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); + $j += 2; + $position += 2; + $strlen += 2; + } + } + } + + return $string; + } + + /** + * Callback function for preg_replace_callback. + * + * Removes sequences of percent encoded bytes that represent UTF-8 + * encoded characters in iunreserved + * + * @param array $match PCRE match + * @return string Replacement + */ + protected function remove_iunreserved_percent_encoded($match) { + // As we just have valid percent encoded sequences we can just explode + // and ignore the first member of the returned array (an empty string). + $bytes = explode('%', $match[0]); + + // Initialize the new string (this is what will be returned) and that + // there are no bytes remaining in the current sequence (unsurprising + // at the first byte!). + $string = ''; + $remaining = 0; + + // Loop over each and every byte, and set $value to its value + for ($i = 1, $len = count($bytes); $i < $len; $i++) { + $value = hexdec($bytes[$i]); + + // If we're the first byte of sequence: + if (!$remaining) { + // Start position + $start = $i; + + // By default we are valid + $valid = true; + + // One byte sequence: + if ($value <= 0x7F) { + $character = $value; + $length = 1; + } + // Two byte sequence: + elseif (($value & 0xE0) === 0xC0) { + $character = ($value & 0x1F) << 6; + $length = 2; + $remaining = 1; + } + // Three byte sequence: + elseif (($value & 0xF0) === 0xE0) { + $character = ($value & 0x0F) << 12; + $length = 3; + $remaining = 2; + } + // Four byte sequence: + elseif (($value & 0xF8) === 0xF0) { + $character = ($value & 0x07) << 18; + $length = 4; + $remaining = 3; + } + // Invalid byte: + else { + $valid = false; + $remaining = 0; + } + } + // Continuation byte: + else { + // Check that the byte is valid, then add it to the character: + if (($value & 0xC0) === 0x80) { + $remaining--; + $character |= ($value & 0x3F) << ($remaining * 6); + } + // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: + else { + $valid = false; + $remaining = 0; + $i--; + } + } + + // If we've reached the end of the current byte sequence, append it to Unicode::$data + if (!$remaining) { + // Percent encode anything invalid or not in iunreserved + if ( + // Invalid sequences + !$valid + // Non-shortest form sequences are invalid + || $length > 1 && $character <= 0x7F + || $length > 2 && $character <= 0x7FF + || $length > 3 && $character <= 0xFFFF + // Outside of range of iunreserved codepoints + || $character < 0x2D + || $character > 0xEFFFD + // Noncharacters + || ($character & 0xFFFE) === 0xFFFE + || $character >= 0xFDD0 && $character <= 0xFDEF + // Everything else not in iunreserved (this is all BMP) + || $character === 0x2F + || $character > 0x39 && $character < 0x41 + || $character > 0x5A && $character < 0x61 + || $character > 0x7A && $character < 0x7E + || $character > 0x7E && $character < 0xA0 + || $character > 0xD7FF && $character < 0xF900 + ) { + for ($j = $start; $j <= $i; $j++) { + $string .= '%' . strtoupper($bytes[$j]); + } + } + else { + for ($j = $start; $j <= $i; $j++) { + $string .= chr(hexdec($bytes[$j])); + } + } + } + } + + // If we have any bytes left over they are invalid (i.e., we are + // mid-way through a multi-byte sequence) + if ($remaining) { + for ($j = $start; $j < $len; $j++) { + $string .= '%' . strtoupper($bytes[$j]); + } + } + + return $string; + } + + protected function scheme_normalization() { + if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) { + $this->iuserinfo = null; + } + if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) { + $this->ihost = null; + } + if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) { + $this->port = null; + } + if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) { + $this->ipath = ''; + } + if (isset($this->ihost) && empty($this->ipath)) { + $this->ipath = '/'; + } + if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) { + $this->iquery = null; + } + if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) { + $this->ifragment = null; + } + } + + /** + * Check if the object represents a valid IRI. This needs to be done on each + * call as some things change depending on another part of the IRI. + * + * @return bool + */ + public function is_valid() { + $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; + if ($this->ipath !== '' && + ( + $isauthority && $this->ipath[0] !== '/' || + ( + $this->scheme === null && + !$isauthority && + strpos($this->ipath, ':') !== false && + (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) + ) + ) + ) { + return false; + } + + return true; + } + + /** + * Set the entire IRI. Returns true on success, false on failure (if there + * are any invalid characters). + * + * @param string $iri + * @return bool + */ + protected function set_iri($iri) { + static $cache; + if (!$cache) { + $cache = array(); + } + + if ($iri === null) { + return true; + } + if (isset($cache[$iri])) { + list($this->scheme, + $this->iuserinfo, + $this->ihost, + $this->port, + $this->ipath, + $this->iquery, + $this->ifragment, + $return) = $cache[$iri]; + return $return; + } + + $parsed = $this->parse_iri((string) $iri); + + $return = $this->set_scheme($parsed['scheme']) + && $this->set_authority($parsed['authority']) + && $this->set_path($parsed['path']) + && $this->set_query($parsed['query']) + && $this->set_fragment($parsed['fragment']); + + $cache[$iri] = array($this->scheme, + $this->iuserinfo, + $this->ihost, + $this->port, + $this->ipath, + $this->iquery, + $this->ifragment, + $return); + return $return; + } + + /** + * Set the scheme. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $scheme + * @return bool + */ + protected function set_scheme($scheme) { + if ($scheme === null) { + $this->scheme = null; + } + elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) { + $this->scheme = null; + return false; + } + else { + $this->scheme = strtolower($scheme); + } + return true; + } + + /** + * Set the authority. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $authority + * @return bool + */ + protected function set_authority($authority) { + static $cache; + if (!$cache) { + $cache = array(); + } + + if ($authority === null) { + $this->iuserinfo = null; + $this->ihost = null; + $this->port = null; + return true; + } + if (isset($cache[$authority])) { + list($this->iuserinfo, + $this->ihost, + $this->port, + $return) = $cache[$authority]; + + return $return; + } + + $remaining = $authority; + if (($iuserinfo_end = strrpos($remaining, '@')) !== false) { + $iuserinfo = substr($remaining, 0, $iuserinfo_end); + $remaining = substr($remaining, $iuserinfo_end + 1); + } + else { + $iuserinfo = null; + } + if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) { + $port = substr($remaining, $port_start + 1); + if ($port === false || $port === '') { + $port = null; + } + $remaining = substr($remaining, 0, $port_start); + } + else { + $port = null; + } + + $return = $this->set_userinfo($iuserinfo) && + $this->set_host($remaining) && + $this->set_port($port); + + $cache[$authority] = array($this->iuserinfo, + $this->ihost, + $this->port, + $return); + + return $return; + } + + /** + * Set the iuserinfo. + * + * @param string $iuserinfo + * @return bool + */ + protected function set_userinfo($iuserinfo) { + if ($iuserinfo === null) { + $this->iuserinfo = null; + } + else { + $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:'); + $this->scheme_normalization(); + } + + return true; + } + + /** + * Set the ihost. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $ihost + * @return bool + */ + protected function set_host($ihost) { + if ($ihost === null) { + $this->ihost = null; + return true; + } + if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') { + if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) { + $this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']'; + } + else { + $this->ihost = null; + return false; + } + } + else { + $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;='); + + // Lowercase, but ignore pct-encoded sections (as they should + // remain uppercase). This must be done after the previous step + // as that can add unescaped characters. + $position = 0; + $strlen = strlen($ihost); + while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) { + if ($ihost[$position] === '%') { + $position += 3; + } + else { + $ihost[$position] = strtolower($ihost[$position]); + $position++; + } + } + + $this->ihost = $ihost; + } + + $this->scheme_normalization(); + + return true; + } + + /** + * Set the port. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $port + * @return bool + */ + protected function set_port($port) { + if ($port === null) { + $this->port = null; + return true; + } + + if (strspn($port, '0123456789') === strlen($port)) { + $this->port = (int) $port; + $this->scheme_normalization(); + return true; + } + + $this->port = null; + return false; + } + + /** + * Set the ipath. + * + * @param string $ipath + * @return bool + */ + protected function set_path($ipath) { + static $cache; + if (!$cache) { + $cache = array(); + } + + $ipath = (string) $ipath; + + if (isset($cache[$ipath])) { + $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; + } + else { + $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/'); + $removed = $this->remove_dot_segments($valid); + + $cache[$ipath] = array($valid, $removed); + $this->ipath = ($this->scheme !== null) ? $removed : $valid; + } + $this->scheme_normalization(); + return true; + } + + /** + * Set the iquery. + * + * @param string $iquery + * @return bool + */ + protected function set_query($iquery) { + if ($iquery === null) { + $this->iquery = null; + } + else { + $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true); + $this->scheme_normalization(); + } + return true; + } + + /** + * Set the ifragment. + * + * @param string $ifragment + * @return bool + */ + protected function set_fragment($ifragment) { + if ($ifragment === null) { + $this->ifragment = null; + } + else { + $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?'); + $this->scheme_normalization(); + } + return true; + } + + /** + * Convert an IRI to a URI (or parts thereof) + * + * @param string|bool IRI to convert (or false from {@see get_iri}) + * @return string|false URI if IRI is valid, false otherwise. + */ + protected function to_uri($string) { + if (!is_string($string)) { + return false; + } + + static $non_ascii; + if (!$non_ascii) { + $non_ascii = implode('', range("\x80", "\xFF")); + } + + $position = 0; + $strlen = strlen($string); + while (($position += strcspn($string, $non_ascii, $position)) < $strlen) { + $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); + $position += 3; + $strlen += 2; + } + + return $string; + } + + /** + * Get the complete IRI + * + * @return string + */ + protected function get_iri() { + if (!$this->is_valid()) { + return false; + } + + $iri = ''; + if ($this->scheme !== null) { + $iri .= $this->scheme . ':'; + } + if (($iauthority = $this->get_iauthority()) !== null) { + $iri .= '//' . $iauthority; + } + $iri .= $this->ipath; + if ($this->iquery !== null) { + $iri .= '?' . $this->iquery; + } + if ($this->ifragment !== null) { + $iri .= '#' . $this->ifragment; + } + + return $iri; + } + + /** + * Get the complete URI + * + * @return string + */ + protected function get_uri() { + return $this->to_uri($this->get_iri()); + } + + /** + * Get the complete iauthority + * + * @return string + */ + protected function get_iauthority() { + if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) { + return null; + } + + $iauthority = ''; + if ($this->iuserinfo !== null) { + $iauthority .= $this->iuserinfo . '@'; + } + if ($this->ihost !== null) { + $iauthority .= $this->ihost; + } + if ($this->port !== null) { + $iauthority .= ':' . $this->port; + } + return $iauthority; + } + + /** + * Get the complete authority + * + * @return string + */ + protected function get_authority() { + $iauthority = $this->get_iauthority(); + if (is_string($iauthority)) { + return $this->to_uri($iauthority); + } + else { + return $iauthority; + } + } +} diff --git a/vendor/requests/library/Requests/Proxy.php b/vendor/requests/library/Requests/Proxy.php new file mode 100644 index 00000000..ac7c1d6b --- /dev/null +++ b/vendor/requests/library/Requests/Proxy.php @@ -0,0 +1,35 @@ +proxy = $args; + } + elseif (is_array($args)) { + if (count($args) == 1) { + list($this->proxy) = $args; + } + elseif (count($args) == 3) { + list($this->proxy, $this->user, $this->pass) = $args; + $this->use_authentication = true; + } + else { + throw new Requests_Exception('Invalid number of arguments', 'proxyhttpbadargs'); + } + } + } + + /** + * Register the necessary callbacks + * + * @since 1.6 + * @see curl_before_send + * @see fsockopen_remote_socket + * @see fsockopen_remote_host_path + * @see fsockopen_header + * @param Requests_Hooks $hooks Hook system + */ + public function register(Requests_Hooks &$hooks) { + $hooks->register('curl.before_send', array(&$this, 'curl_before_send')); + + $hooks->register('fsockopen.remote_socket', array(&$this, 'fsockopen_remote_socket')); + $hooks->register('fsockopen.remote_host_path', array(&$this, 'fsockopen_remote_host_path')); + if ($this->use_authentication) { + $hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header')); + } + } + + /** + * Set cURL parameters before the data is sent + * + * @since 1.6 + * @param resource $handle cURL resource + */ + public function curl_before_send(&$handle) { + curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + curl_setopt($handle, CURLOPT_PROXY, $this->proxy); + + if ($this->use_authentication) { + curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string()); + } + } + + /** + * Alter remote socket information before opening socket connection + * + * @since 1.6 + * @param string $remote_socket Socket connection string + */ + public function fsockopen_remote_socket(&$remote_socket) { + $remote_socket = $this->proxy; + } + + /** + * Alter remote path before getting stream data + * + * @since 1.6 + * @param string $path Path to send in HTTP request string ("GET ...") + * @param string $url Full URL we're requesting + */ + public function fsockopen_remote_host_path(&$path, $url) { + $path = $url; + } + + /** + * Add extra headers to the request before sending + * + * @since 1.6 + * @param string $out HTTP header string + */ + public function fsockopen_header(&$out) { + $out .= sprintf("Proxy-Authorization: Basic %s\r\n", base64_encode($this->get_auth_string())); + } + + /** + * Get the authentication string (user:pass) + * + * @since 1.6 + * @return string + */ + public function get_auth_string() { + return $this->user . ':' . $this->pass; + } +} \ No newline at end of file diff --git a/vendor/requests/library/Requests/Response.php b/vendor/requests/library/Requests/Response.php new file mode 100644 index 00000000..3152fb6d --- /dev/null +++ b/vendor/requests/library/Requests/Response.php @@ -0,0 +1,121 @@ +headers = new Requests_Response_Headers(); + $this->cookies = new Requests_Cookie_Jar(); + } + + /** + * Response body + * + * @var string + */ + public $body = ''; + + /** + * Raw HTTP data from the transport + * + * @var string + */ + public $raw = ''; + + /** + * Headers, as an associative array + * + * @var Requests_Response_Headers Array-like object representing headers + */ + public $headers = array(); + + /** + * Status code, false if non-blocking + * + * @var integer|boolean + */ + public $status_code = false; + + /** + * Protocol version, false if non-blocking + * @var float|boolean + */ + public $protocol_version = false; + + /** + * Whether the request succeeded or not + * + * @var boolean + */ + public $success = false; + + /** + * Number of redirects the request used + * + * @var integer + */ + public $redirects = 0; + + /** + * URL requested + * + * @var string + */ + public $url = ''; + + /** + * Previous requests (from redirects) + * + * @var array Array of Requests_Response objects + */ + public $history = array(); + + /** + * Cookies from the request + * + * @var Requests_Cookie_Jar Array-like object representing a cookie jar + */ + public $cookies = array(); + + /** + * Is the response a redirect? + * + * @return boolean True if redirect (3xx status), false if not. + */ + public function is_redirect() { + $code = $this->status_code; + return in_array($code, array(300, 301, 302, 303, 307)) || $code > 307 && $code < 400; + } + + /** + * Throws an exception if the request was not successful + * + * @throws Requests_Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`) + * @throws Requests_Exception_HTTP On non-successful status code. Exception class corresponds to code (e.g. {@see Requests_Exception_HTTP_404}) + * @param boolean $allow_redirects Set to false to throw on a 3xx as well + */ + public function throw_for_status($allow_redirects = true) { + if ($this->is_redirect()) { + if (!$allow_redirects) { + throw new Requests_Exception('Redirection not allowed', 'response.no_redirects', $this); + } + } + elseif (!$this->success) { + $exception = Requests_Exception_HTTP::get_class($this->status_code); + throw new $exception(null, $this); + } + } +} diff --git a/vendor/requests/library/Requests/Response/Headers.php b/vendor/requests/library/Requests/Response/Headers.php new file mode 100644 index 00000000..cc6a2087 --- /dev/null +++ b/vendor/requests/library/Requests/Response/Headers.php @@ -0,0 +1,98 @@ +data[$key])) { + return null; + } + + return $this->flatten($this->data[$key]); + } + + /** + * Set the given item + * + * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) + * + * @param string $key Item name + * @param string $value Item value + */ + public function offsetSet($key, $value) { + if ($key === null) { + throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); + } + + $key = strtolower($key); + + if (!isset($this->data[$key])) { + $this->data[$key] = array(); + } + + $this->data[$key][] = $value; + } + + /** + * Get all values for a given header + * + * @param string $key + * @return array Header values + */ + public function getValues($key) { + $key = strtolower($key); + if (!isset($this->data[$key])) { + return null; + } + + return $this->data[$key]; + } + + /** + * Flattens a value into a string + * + * Converts an array into a string by imploding values with a comma, as per + * RFC2616's rules for folding headers. + * + * @param string|array $value Value to flatten + * @return string Flattened value + */ + public function flatten($value) { + if (is_array($value)) { + $value = implode(',', $value); + } + + return $value; + } + + /** + * Get an iterator for the data + * + * Converts the internal + * @return ArrayIterator + */ + public function getIterator() { + return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten')); + } +} diff --git a/vendor/requests/library/Requests/SSL.php b/vendor/requests/library/Requests/SSL.php new file mode 100644 index 00000000..2b037685 --- /dev/null +++ b/vendor/requests/library/Requests/SSL.php @@ -0,0 +1,152 @@ +useragent = 'X';` + * + * @var array + */ + public $options = array(); + + /** + * Create a new session + * + * @param string|null $url Base URL for requests + * @param array $headers Default headers for requests + * @param array $data Default data for requests + * @param array $options Default options for requests + */ + public function __construct($url = null, $headers = array(), $data = array(), $options = array()) { + $this->url = $url; + $this->headers = $headers; + $this->data = $data; + $this->options = $options; + + if (empty($this->options['cookies'])) { + $this->options['cookies'] = new Requests_Cookie_Jar(); + } + } + + /** + * Get a property's value + * + * @param string $key Property key + * @return mixed|null Property value, null if none found + */ + public function __get($key) { + if (isset($this->options[$key])) { + return $this->options[$key]; + } + + return null; + } + + /** + * Set a property's value + * + * @param string $key Property key + * @param mixed $value Property value + */ + public function __set($key, $value) { + $this->options[$key] = $value; + } + + /** + * Remove a property's value + * + * @param string $key Property key + */ + public function __isset($key) { + return isset($this->options[$key]); + } + + /** + * Remove a property's value + * + * @param string $key Property key + */ + public function __unset($key) { + if (isset($this->options[$key])) { + unset($this->options[$key]); + } + } + + /**#@+ + * @see request() + * @param string $url + * @param array $headers + * @param array $options + * @return Requests_Response + */ + /** + * Send a GET request + */ + public function get($url, $headers = array(), $options = array()) { + return $this->request($url, $headers, null, Requests::GET, $options); + } + + /** + * Send a HEAD request + */ + public function head($url, $headers = array(), $options = array()) { + return $this->request($url, $headers, null, Requests::HEAD, $options); + } + + /** + * Send a DELETE request + */ + public function delete($url, $headers = array(), $options = array()) { + return $this->request($url, $headers, null, Requests::DELETE, $options); + } + /**#@-*/ + + /**#@+ + * @see request() + * @param string $url + * @param array $headers + * @param array $data + * @param array $options + * @return Requests_Response + */ + /** + * Send a POST request + */ + public function post($url, $headers = array(), $data = array(), $options = array()) { + return $this->request($url, $headers, $data, Requests::POST, $options); + } + + /** + * Send a PUT request + */ + public function put($url, $headers = array(), $data = array(), $options = array()) { + return $this->request($url, $headers, $data, Requests::PUT, $options); + } + + /** + * Send a PATCH request + * + * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the + * specification recommends that should send an ETag + * + * @link https://tools.ietf.org/html/rfc5789 + */ + public function patch($url, $headers, $data = array(), $options = array()) { + return $this->request($url, $headers, $data, Requests::PATCH, $options); + } + /**#@-*/ + + /** + * Main interface for HTTP requests + * + * This method initiates a request and sends it via a transport before + * parsing. + * + * @see Requests::request() + * + * @throws Requests_Exception On invalid URLs (`nonhttp`) + * + * @param string $url URL to request + * @param array $headers Extra headers to send with the request + * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests + * @param string $type HTTP request type (use Requests constants) + * @param array $options Options for the request (see {@see Requests::request}) + * @return Requests_Response + */ + public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) { + $request = $this->merge_request(compact('url', 'headers', 'data', 'options')); + + return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']); + } + + /** + * Send multiple HTTP requests simultaneously + * + * @see Requests::request_multiple() + * + * @param array $requests Requests data (see {@see Requests::request_multiple}) + * @param array $options Global and default options (see {@see Requests::request}) + * @return array Responses (either Requests_Response or a Requests_Exception object) + */ + public function request_multiple($requests, $options = array()) { + foreach ($requests as $key => $request) { + $requests[$key] = $this->merge_request($request, false); + } + + $options = array_merge($this->options, $options); + + // Disallow forcing the type, as that's a per request setting + unset($options['type']); + + return Requests::request_multiple($requests, $options); + } + + /** + * Merge a request's data with the default data + * + * @param array $request Request data (same form as {@see request_multiple}) + * @param boolean $merge_options Should we merge options as well? + * @return array Request data + */ + protected function merge_request($request, $merge_options = true) { + if ($this->url !== null) { + $request['url'] = Requests_IRI::absolutize($this->url, $request['url']); + $request['url'] = $request['url']->uri; + } + + if (empty($request['headers'])) { + $request['headers'] = array(); + } + $request['headers'] = array_merge($this->headers, $request['headers']); + + if (empty($request['data'])) { + if (is_array($this->data)) { + $request['data'] = $this->data; + } + } + elseif (is_array($request['data']) && is_array($this->data)) { + $request['data'] = array_merge($this->data, $request['data']); + } + + if ($merge_options !== false) { + $request['options'] = array_merge($this->options, $request['options']); + + // Disallow forcing the type, as that's a per request setting + unset($request['options']['type']); + } + + return $request; + } +} diff --git a/vendor/requests/library/Requests/Transport.php b/vendor/requests/library/Requests/Transport.php new file mode 100644 index 00000000..7e4a2629 --- /dev/null +++ b/vendor/requests/library/Requests/Transport.php @@ -0,0 +1,41 @@ +version = $curl['version_number']; + $this->handle = curl_init(); + + curl_setopt($this->handle, CURLOPT_HEADER, false); + curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1); + if ($this->version >= self::CURL_7_10_5) { + curl_setopt($this->handle, CURLOPT_ENCODING, ''); + } + if (defined('CURLOPT_PROTOCOLS')) { + curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + } + if (defined('CURLOPT_REDIR_PROTOCOLS')) { + curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + } + } + + /** + * Destructor + */ + public function __destruct() { + if (is_resource($this->handle)) { + curl_close($this->handle); + } + } + + /** + * Perform a request + * + * @throws Requests_Exception On a cURL error (`curlerror`) + * + * @param string $url URL to request + * @param array $headers Associative array of request headers + * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD + * @param array $options Request options, see {@see Requests::response()} for documentation + * @return string Raw HTTP result + */ + public function request($url, $headers = array(), $data = array(), $options = array()) { + $this->hooks = $options['hooks']; + + $this->setup_handle($url, $headers, $data, $options); + + $options['hooks']->dispatch('curl.before_send', array(&$this->handle)); + + if ($options['filename'] !== false) { + $this->stream_handle = fopen($options['filename'], 'wb'); + } + + $this->response_data = ''; + $this->response_bytes = 0; + $this->response_byte_limit = false; + if ($options['max_bytes'] !== false) { + $this->response_byte_limit = $options['max_bytes']; + } + + if (isset($options['verify'])) { + if ($options['verify'] === false) { + curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0); + } + elseif (is_string($options['verify'])) { + curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']); + } + } + + if (isset($options['verifyname']) && $options['verifyname'] === false) { + curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0); + } + + curl_exec($this->handle); + $response = $this->response_data; + + $options['hooks']->dispatch('curl.after_send', array()); + + if (curl_errno($this->handle) === 23 || curl_errno($this->handle) === 61) { + // Reset encoding and try again + curl_setopt($this->handle, CURLOPT_ENCODING, 'none'); + + $this->response_data = ''; + $this->response_bytes = 0; + curl_exec($this->handle); + $response = $this->response_data; + } + + $this->process_response($response, $options); + + // Need to remove the $this reference from the curl handle. + // Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called. + curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null); + curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null); + + return $this->headers; + } + + /** + * Send multiple requests simultaneously + * + * @param array $requests Request data + * @param array $options Global options + * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well) + */ + public function request_multiple($requests, $options) { + // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯ + if (empty($requests)) { + return array(); + } + + $multihandle = curl_multi_init(); + $subrequests = array(); + $subhandles = array(); + + $class = get_class($this); + foreach ($requests as $id => $request) { + $subrequests[$id] = new $class(); + $subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']); + $request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id])); + curl_multi_add_handle($multihandle, $subhandles[$id]); + } + + $completed = 0; + $responses = array(); + + $request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle)); + + do { + $active = false; + + do { + $status = curl_multi_exec($multihandle, $active); + } + while ($status === CURLM_CALL_MULTI_PERFORM); + + $to_process = array(); + + // Read the information as needed + while ($done = curl_multi_info_read($multihandle)) { + $key = array_search($done['handle'], $subhandles, true); + if (!isset($to_process[$key])) { + $to_process[$key] = $done; + } + } + + // Parse the finished requests before we start getting the new ones + foreach ($to_process as $key => $done) { + $options = $requests[$key]['options']; + if (CURLE_OK !== $done['result']) { + //get error string for handle. + $reason = curl_error($done['handle']); + $exception = new Requests_Exception_Transport_cURL( + $reason, + Requests_Exception_Transport_cURL::EASY, + $done['handle'], + $done['result'] + ); + $responses[$key] = $exception; + $options['hooks']->dispatch('transport.internal.parse_error', array(&$responses[$key], $requests[$key])); + } + else { + $responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options); + + $options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key])); + } + + curl_multi_remove_handle($multihandle, $done['handle']); + curl_close($done['handle']); + + if (!is_string($responses[$key])) { + $options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key)); + } + $completed++; + } + } + while ($active || $completed < count($subrequests)); + + $request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle)); + + curl_multi_close($multihandle); + + return $responses; + } + + /** + * Get the cURL handle for use in a multi-request + * + * @param string $url URL to request + * @param array $headers Associative array of request headers + * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD + * @param array $options Request options, see {@see Requests::response()} for documentation + * @return resource Subrequest's cURL handle + */ + public function &get_subrequest_handle($url, $headers, $data, $options) { + $this->setup_handle($url, $headers, $data, $options); + + if ($options['filename'] !== false) { + $this->stream_handle = fopen($options['filename'], 'wb'); + } + + $this->response_data = ''; + $this->response_bytes = 0; + $this->response_byte_limit = false; + if ($options['max_bytes'] !== false) { + $this->response_byte_limit = $options['max_bytes']; + } + $this->hooks = $options['hooks']; + + return $this->handle; + } + + /** + * Setup the cURL handle for the given data + * + * @param string $url URL to request + * @param array $headers Associative array of request headers + * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD + * @param array $options Request options, see {@see Requests::response()} for documentation + */ + protected function setup_handle($url, $headers, $data, $options) { + $options['hooks']->dispatch('curl.before_request', array(&$this->handle)); + + // Force closing the connection for old versions of cURL (<7.22). + if ( ! isset( $headers['Connection'] ) ) { + $headers['Connection'] = 'close'; + } + + $headers = Requests::flatten($headers); + + if (!empty($data)) { + $data_format = $options['data_format']; + + if ($data_format === 'query') { + $url = self::format_get($url, $data); + $data = ''; + } + elseif (!is_string($data)) { + $data = http_build_query($data, null, '&'); + } + } + + switch ($options['type']) { + case Requests::POST: + curl_setopt($this->handle, CURLOPT_POST, true); + curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data); + break; + case Requests::HEAD: + curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); + curl_setopt($this->handle, CURLOPT_NOBODY, true); + break; + case Requests::TRACE: + curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); + break; + case Requests::PATCH: + case Requests::PUT: + case Requests::DELETE: + case Requests::OPTIONS: + default: + curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); + if (!empty($data)) { + curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data); + } + } + + // cURL requires a minimum timeout of 1 second when using the system + // DNS resolver, as it uses `alarm()`, which is second resolution only. + // There's no way to detect which DNS resolver is being used from our + // end, so we need to round up regardless of the supplied timeout. + // + // https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609 + $timeout = max($options['timeout'], 1); + + if (is_int($timeout) || $this->version < self::CURL_7_16_2) { + curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout)); + } + else { + curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000)); + } + + if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) { + curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout'])); + } + else { + curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000)); + } + curl_setopt($this->handle, CURLOPT_URL, $url); + curl_setopt($this->handle, CURLOPT_REFERER, $url); + curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']); + if (!empty($headers)) { + curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers); + } + if ($options['protocol_version'] === 1.1) { + curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + } + else { + curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + } + + if (true === $options['blocking']) { + curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers')); + curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array(&$this, 'stream_body')); + curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE); + } + } + + /** + * Process a response + * + * @param string $response Response data from the body + * @param array $options Request options + * @return string HTTP response data including headers + */ + public function process_response($response, $options) { + if ($options['blocking'] === false) { + $fake_headers = ''; + $options['hooks']->dispatch('curl.after_request', array(&$fake_headers)); + return false; + } + if ($options['filename'] !== false) { + fclose($this->stream_handle); + $this->headers = trim($this->headers); + } + else { + $this->headers .= $response; + } + + if (curl_errno($this->handle)) { + $error = sprintf( + 'cURL error %s: %s', + curl_errno($this->handle), + curl_error($this->handle) + ); + throw new Requests_Exception($error, 'curlerror', $this->handle); + } + $this->info = curl_getinfo($this->handle); + + $options['hooks']->dispatch('curl.after_request', array(&$this->headers, &$this->info)); + return $this->headers; + } + + /** + * Collect the headers as they are received + * + * @param resource $handle cURL resource + * @param string $headers Header string + * @return integer Length of provided header + */ + public function stream_headers($handle, $headers) { + // Why do we do this? cURL will send both the final response and any + // interim responses, such as a 100 Continue. We don't need that. + // (We may want to keep this somewhere just in case) + if ($this->done_headers) { + $this->headers = ''; + $this->done_headers = false; + } + $this->headers .= $headers; + + if ($headers === "\r\n") { + $this->done_headers = true; + } + return strlen($headers); + } + + /** + * Collect data as it's received + * + * @since 1.6.1 + * + * @param resource $handle cURL resource + * @param string $data Body data + * @return integer Length of provided data + */ + public function stream_body($handle, $data) { + $this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit)); + $data_length = strlen($data); + + // Are we limiting the response size? + if ($this->response_byte_limit) { + if ($this->response_bytes === $this->response_byte_limit) { + // Already at maximum, move on + return $data_length; + } + + if (($this->response_bytes + $data_length) > $this->response_byte_limit) { + // Limit the length + $limited_length = ($this->response_byte_limit - $this->response_bytes); + $data = substr($data, 0, $limited_length); + } + } + + if ($this->stream_handle) { + fwrite($this->stream_handle, $data); + } + else { + $this->response_data .= $data; + } + + $this->response_bytes += strlen($data); + return $data_length; + } + + /** + * Format a URL given GET data + * + * @param string $url + * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query} + * @return string URL with data + */ + protected static function format_get($url, $data) { + if (!empty($data)) { + $url_parts = parse_url($url); + if (empty($url_parts['query'])) { + $query = $url_parts['query'] = ''; + } + else { + $query = $url_parts['query']; + } + + $query .= '&' . http_build_query($data, null, '&'); + $query = trim($query, '&'); + + if (empty($url_parts['query'])) { + $url .= '?' . $query; + } + else { + $url = str_replace($url_parts['query'], $query, $url); + } + } + return $url; + } + + /** + * Whether this transport is valid + * + * @codeCoverageIgnore + * @return boolean True if the transport is valid, false otherwise. + */ + public static function test($capabilities = array()) { + if (!function_exists('curl_init') || !function_exists('curl_exec')) { + return false; + } + + // If needed, check that our installed curl version supports SSL + if (isset($capabilities['ssl']) && $capabilities['ssl']) { + $curl_version = curl_version(); + if (!(CURL_VERSION_SSL & $curl_version['features'])) { + return false; + } + } + + return true; + } +} diff --git a/vendor/requests/library/Requests/Transport/cacert.pem b/vendor/requests/library/Requests/Transport/cacert.pem new file mode 100644 index 00000000..56ece1a0 --- /dev/null +++ b/vendor/requests/library/Requests/Transport/cacert.pem @@ -0,0 +1,3554 @@ +## +## ca-bundle.crt -- Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Sat Dec 29 20:03:40 2012 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## + +# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $ + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 1 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy +MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE +NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i +o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq +kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 +RbyhkwS7hp86W0N6w4pl +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 3 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy +MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD +VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS +xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi +up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 +mPnHfxsb1gYgAlihw6ID +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC +AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER +gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B +AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS +o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z +2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX +OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 2 +============================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE +ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y +MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT +DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn +2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 +BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx +JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e +uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 +jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia +78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm +V+GRMOrN +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +TDC Internet Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE +ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx +NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu +ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j +xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL +znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc +5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 +otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI +AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM +VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM +MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe +UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G +CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb +O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU +Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Firmaprofesional Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT +GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp +Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA +ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL +MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT +OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 +ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V +j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH +lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf +3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 +NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww +KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG +AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD +ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq +u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf +wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm +7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG +VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= +-----END CERTIFICATE----- + +Wells Fargo Root CA +=================== +-----BEGIN CERTIFICATE----- +MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl +bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv +MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX +x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 +E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 +OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j +sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj +YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF +BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD +ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv +m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R +OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx +x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 +tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 +MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM +MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF +NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe +AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC +b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn +7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN +cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp +WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 +haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY +MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 +MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn +jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ +MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H +VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl +vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl +OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 +1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq +nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy +x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg +QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe +Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt +IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by +X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b +gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr +eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ +TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy +Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn +uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI +qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm +ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 +Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW +Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t +FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm +zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k +XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT +bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU +RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK +1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt +2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ +Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 +AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) FÅ‘tanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ +5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn +vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj +CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil +e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR +OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI +CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 +48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi +trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 +qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB +AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC +ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA +A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz ++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj +f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN +kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk +CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF +URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb +CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h +oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV +IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD +T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 +MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG +A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk +WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD +YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew +MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb +m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk +HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT +xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 +3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 +2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq +TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz +4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU +9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv +bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg +aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP +eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk +zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 +ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI +KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq +nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE +I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp +MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o +tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +TC TrustCenter Universal CA III +=============================== +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe +Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU +QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex +KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt +QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO +juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut +CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 +M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G +A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA +g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ +KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK +BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV +CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq +woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ +Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 +dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu +c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv +bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 +aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 +fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm +N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN +Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T +tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX +e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA +2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs +HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib +D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +StartCom Certification Authority G2 +=================================== +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE +ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O +o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG +4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi +Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul +Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs +O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H +vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L +nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS +FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa +z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ +KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk +J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ +JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG +/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc +nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld +blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc +l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm +7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm +obp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- diff --git a/vendor/requests/library/Requests/Transport/fsockopen.php b/vendor/requests/library/Requests/Transport/fsockopen.php new file mode 100644 index 00000000..21cb56d5 --- /dev/null +++ b/vendor/requests/library/Requests/Transport/fsockopen.php @@ -0,0 +1,444 @@ +dispatch('fsockopen.before_request'); + + $url_parts = parse_url($url); + if (empty($url_parts)) { + throw new Requests_Exception('Invalid URL.', 'invalidurl', $url); + } + $host = $url_parts['host']; + $context = stream_context_create(); + $verifyname = false; + $case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers); + + // HTTPS support + if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') { + $remote_socket = 'ssl://' . $host; + if (!isset($url_parts['port'])) { + $url_parts['port'] = 443; + } + + $context_options = array( + 'verify_peer' => true, + // 'CN_match' => $host, + 'capture_peer_cert' => true + ); + $verifyname = true; + + // SNI, if enabled (OpenSSL >=0.9.8j) + if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) { + $context_options['SNI_enabled'] = true; + if (isset($options['verifyname']) && $options['verifyname'] === false) { + $context_options['SNI_enabled'] = false; + } + } + + if (isset($options['verify'])) { + if ($options['verify'] === false) { + $context_options['verify_peer'] = false; + } + elseif (is_string($options['verify'])) { + $context_options['cafile'] = $options['verify']; + } + } + + if (isset($options['verifyname']) && $options['verifyname'] === false) { + $context_options['verify_peer_name'] = false; + $verifyname = false; + } + + stream_context_set_option($context, array('ssl' => $context_options)); + } + else { + $remote_socket = 'tcp://' . $host; + } + + $this->max_bytes = $options['max_bytes']; + + if (!isset($url_parts['port'])) { + $url_parts['port'] = 80; + } + $remote_socket .= ':' . $url_parts['port']; + + set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE); + + $options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket)); + + $socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context); + + restore_error_handler(); + + if ($verifyname && !$this->verify_certificate_from_context($host, $context)) { + throw new Requests_Exception('SSL certificate did not match the requested domain name', 'ssl.no_match'); + } + + if (!$socket) { + if ($errno === 0) { + // Connection issue + throw new Requests_Exception(rtrim($this->connect_error), 'fsockopen.connect_error'); + } + + throw new Requests_Exception($errstr, 'fsockopenerror', null, $errno); + } + + $data_format = $options['data_format']; + + if ($data_format === 'query') { + $path = self::format_get($url_parts, $data); + $data = ''; + } + else { + $path = self::format_get($url_parts, array()); + } + + $options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url)); + + $request_body = ''; + $out = sprintf("%s %s HTTP/%.1f\r\n", $options['type'], $path, $options['protocol_version']); + + if ($options['type'] !== Requests::TRACE) { + if (is_array($data)) { + $request_body = http_build_query($data, null, '&'); + } + else { + $request_body = $data; + } + + if (!empty($data)) { + if (!isset($case_insensitive_headers['Content-Length'])) { + $headers['Content-Length'] = strlen($request_body); + } + + if (!isset($case_insensitive_headers['Content-Type'])) { + $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + } + } + } + + if (!isset($case_insensitive_headers['Host'])) { + $out .= sprintf('Host: %s', $url_parts['host']); + + if (( 'http' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 80 ) || ( 'https' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 443 )) { + $out .= ':' . $url_parts['port']; + } + $out .= "\r\n"; + } + + if (!isset($case_insensitive_headers['User-Agent'])) { + $out .= sprintf("User-Agent: %s\r\n", $options['useragent']); + } + + $accept_encoding = $this->accept_encoding(); + if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) { + $out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding); + } + + $headers = Requests::flatten($headers); + + if (!empty($headers)) { + $out .= implode($headers, "\r\n") . "\r\n"; + } + + $options['hooks']->dispatch('fsockopen.after_headers', array(&$out)); + + if (substr($out, -2) !== "\r\n") { + $out .= "\r\n"; + } + + if (!isset($case_insensitive_headers['Connection'])) { + $out .= "Connection: Close\r\n"; + } + + $out .= "\r\n" . $request_body; + + $options['hooks']->dispatch('fsockopen.before_send', array(&$out)); + + fwrite($socket, $out); + $options['hooks']->dispatch('fsockopen.after_send', array($out)); + + if (!$options['blocking']) { + fclose($socket); + $fake_headers = ''; + $options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers)); + return ''; + } + + $timeout_sec = (int) floor($options['timeout']); + if ($timeout_sec == $options['timeout']) { + $timeout_msec = 0; + } + else { + $timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS; + } + stream_set_timeout($socket, $timeout_sec, $timeout_msec); + + $response = $body = $headers = ''; + $this->info = stream_get_meta_data($socket); + $size = 0; + $doingbody = false; + $download = false; + if ($options['filename']) { + $download = fopen($options['filename'], 'wb'); + } + + while (!feof($socket)) { + $this->info = stream_get_meta_data($socket); + if ($this->info['timed_out']) { + throw new Requests_Exception('fsocket timed out', 'timeout'); + } + + $block = fread($socket, Requests::BUFFER_SIZE); + if (!$doingbody) { + $response .= $block; + if (strpos($response, "\r\n\r\n")) { + list($headers, $block) = explode("\r\n\r\n", $response, 2); + $doingbody = true; + } + } + + // Are we in body mode now? + if ($doingbody) { + $options['hooks']->dispatch('request.progress', array($block, $size, $this->max_bytes)); + $data_length = strlen($block); + if ($this->max_bytes) { + // Have we already hit a limit? + if ($size === $this->max_bytes) { + continue; + } + if (($size + $data_length) > $this->max_bytes) { + // Limit the length + $limited_length = ($this->max_bytes - $size); + $block = substr($block, 0, $limited_length); + } + } + + $size += strlen($block); + if ($download) { + fwrite($download, $block); + } + else { + $body .= $block; + } + } + } + $this->headers = $headers; + + if ($download) { + fclose($download); + } + else { + $this->headers .= "\r\n\r\n" . $body; + } + fclose($socket); + + $options['hooks']->dispatch('fsockopen.after_request', array(&$this->headers, &$this->info)); + return $this->headers; + } + + /** + * Send multiple requests simultaneously + * + * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request} + * @param array $options Global options, see {@see Requests::response()} for documentation + * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well) + */ + public function request_multiple($requests, $options) { + $responses = array(); + $class = get_class($this); + foreach ($requests as $id => $request) { + try { + $handler = new $class(); + $responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']); + + $request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request)); + } + catch (Requests_Exception $e) { + $responses[$id] = $e; + } + + if (!is_string($responses[$id])) { + $request['options']['hooks']->dispatch('multiple.request.complete', array(&$responses[$id], $id)); + } + } + + return $responses; + } + + /** + * Retrieve the encodings we can accept + * + * @return string Accept-Encoding header value + */ + protected static function accept_encoding() { + $type = array(); + if (function_exists('gzinflate')) { + $type[] = 'deflate;q=1.0'; + } + + if (function_exists('gzuncompress')) { + $type[] = 'compress;q=0.5'; + } + + $type[] = 'gzip;q=0.5'; + + return implode(', ', $type); + } + + /** + * Format a URL given GET data + * + * @param array $url_parts + * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query} + * @return string URL with data + */ + protected static function format_get($url_parts, $data) { + if (!empty($data)) { + if (empty($url_parts['query'])) { + $url_parts['query'] = ''; + } + + $url_parts['query'] .= '&' . http_build_query($data, null, '&'); + $url_parts['query'] = trim($url_parts['query'], '&'); + } + if (isset($url_parts['path'])) { + if (isset($url_parts['query'])) { + $get = $url_parts['path'] . '?' . $url_parts['query']; + } + else { + $get = $url_parts['path']; + } + } + else { + $get = '/'; + } + return $get; + } + + /** + * Error handler for stream_socket_client() + * + * @param int $errno Error number (e.g. E_WARNING) + * @param string $errstr Error message + */ + public function connect_error_handler($errno, $errstr) { + // Double-check we can handle it + if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) { + // Return false to indicate the default error handler should engage + return false; + } + + $this->connect_error .= $errstr . "\n"; + return true; + } + + /** + * Verify the certificate against common name and subject alternative names + * + * Unfortunately, PHP doesn't check the certificate against the alternative + * names, leading things like 'https://www.github.com/' to be invalid. + * Instead + * + * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1 + * + * @throws Requests_Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`) + * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`) + * @param string $host Host name to verify against + * @param resource $context Stream context + * @return bool + */ + public function verify_certificate_from_context($host, $context) { + $meta = stream_context_get_options($context); + + // If we don't have SSL options, then we couldn't make the connection at + // all + if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) { + throw new Requests_Exception(rtrim($this->connect_error), 'ssl.connect_error'); + } + + $cert = openssl_x509_parse($meta['ssl']['peer_certificate']); + + return Requests_SSL::verify_certificate($host, $cert); + } + + /** + * Whether this transport is valid + * + * @codeCoverageIgnore + * @return boolean True if the transport is valid, false otherwise. + */ + public static function test($capabilities = array()) { + if (!function_exists('fsockopen')) { + return false; + } + + // If needed, check that streams support SSL + if (isset($capabilities['ssl']) && $capabilities['ssl']) { + if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) { + return false; + } + + // Currently broken, thanks to https://github.com/facebook/hhvm/issues/2156 + if (defined('HHVM_VERSION')) { + return false; + } + } + + return true; + } +} diff --git a/vendor/requests/library/Requests/Utility/CaseInsensitiveDictionary.php b/vendor/requests/library/Requests/Utility/CaseInsensitiveDictionary.php new file mode 100644 index 00000000..2c97893a --- /dev/null +++ b/vendor/requests/library/Requests/Utility/CaseInsensitiveDictionary.php @@ -0,0 +1,103 @@ + $value) { + $this->offsetSet($key, $value); + } + } + + /** + * Check if the given item exists + * + * @param string $key Item key + * @return boolean Does the item exist? + */ + public function offsetExists($key) { + $key = strtolower($key); + return isset($this->data[$key]); + } + + /** + * Get the value for the item + * + * @param string $key Item key + * @return string Item value + */ + public function offsetGet($key) { + $key = strtolower($key); + if (!isset($this->data[$key])) { + return null; + } + + return $this->data[$key]; + } + + /** + * Set the given item + * + * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) + * + * @param string $key Item name + * @param string $value Item value + */ + public function offsetSet($key, $value) { + if ($key === null) { + throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); + } + + $key = strtolower($key); + $this->data[$key] = $value; + } + + /** + * Unset the given header + * + * @param string $key + */ + public function offsetUnset($key) { + unset($this->data[strtolower($key)]); + } + + /** + * Get an iterator for the data + * + * @return ArrayIterator + */ + public function getIterator() { + return new ArrayIterator($this->data); + } + + /** + * Get the headers as an array + * + * @return array Header data + */ + public function getAll() { + return $this->data; + } +} diff --git a/vendor/requests/library/Requests/Utility/FilteredIterator.php b/vendor/requests/library/Requests/Utility/FilteredIterator.php new file mode 100644 index 00000000..76a29e72 --- /dev/null +++ b/vendor/requests/library/Requests/Utility/FilteredIterator.php @@ -0,0 +1,45 @@ +callback = $callback; + } + + /** + * Get the current item's value after filtering + * + * @return string + */ + public function current() { + $value = parent::current(); + $value = call_user_func($this->callback, $value); + return $value; + } +} diff --git a/views/actions.php b/views/actions.php deleted file mode 100644 index 45817c07..00000000 --- a/views/actions.php +++ /dev/null @@ -1,152 +0,0 @@ -Scan(); - - $Package->SaveActiveItem('ScanFile', $Package->ScanFile); - $json_response = json_encode($report); - - DUP_Package::TmpCleanup(); - error_reporting($errLevel); - die($json_response); -} - -/** - * duplicator_package_build - * Returns the package result status - * - * @return json json object of package results - */ -function duplicator_package_build() { - - header('Content-Type: application/json'); - DUP_Util::CheckPermissions('export'); - - @set_time_limit(0); - $errLevel = error_reporting(); - error_reporting(E_ERROR); - DUP_Util::InitSnapshotDirectory(); - - $Package = DUP_Package::GetActive(); - - if (!is_readable(DUPLICATOR_SSDIR_PATH_TMP . "/{$Package->ScanFile}")) { - die("The scan result file was not found. Please run the scan step before building the package."); - } - - $Package->Build(); - - //JSON:Debug Response - //Pass = 1, Warn = 2, Fail = 3 - $json = array(); - $json['Status'] = 1; - $json['Package'] = $Package; - $json['Runtime'] = $Package->Runtime; - $json['ExeSize'] = $Package->ExeSize; - $json['ZipSize'] = $Package->ZipSize; - $json_response = json_encode($json); - - error_reporting($errLevel); - die($json_response); -} - - -function duplicator_package_report() { - - DUP_Util::CheckPermissions('export'); - - $scanReport = $_GET['scanfile']; - header('Content-Type: application/json'); - header("Location: " . DUPLICATOR_SSDIR_URL . "/tmp/" . $scanReport); - echo DUPLICATOR_SSDIR_URL . "/tmp/" . $scanReport; - - die(); -} - -/** - * DUPLICATOR_PACKAGE_DELETE - * Deletes the files and database record entries - * - * @return json A json message about the action. - * Use console.log to debug from client - */ -function duplicator_package_delete() { - - DUP_Util::CheckPermissions('export'); - check_ajax_referer( 'package_list', 'nonce' ); - - try { - global $wpdb; - $json = array(); - $post = stripslashes_deep($_POST); - $tblName = $wpdb->prefix . 'duplicator_packages'; - $postIDs = isset($post['duplicator_delid']) ? $post['duplicator_delid'] : null; - $list = explode(",", $postIDs); - $delCount = 0; - - if ($postIDs != null) { - - foreach ($list as $id) { - - $getResult = $wpdb->get_results($wpdb->prepare("SELECT name, hash FROM `{$tblName}` WHERE id = %d", $id), ARRAY_A); - if ($getResult) { - $row = $getResult[0]; - $nameHash = "{$row['name']}_{$row['hash']}"; - $delResult = $wpdb->query($wpdb->prepare( "DELETE FROM `{$tblName}` WHERE id = %d", $id )); - if ($delResult != 0) { - //Perms - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_archive.zip"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_database.sql"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_installer.php"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_archive.zip"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_database.sql"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_installer.php"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_scan.json"), 0644); - @chmod(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}.log"), 0644); - //Remove - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_archive.zip")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_database.sql")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_installer.php")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_archive.zip")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_database.sql")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_installer.php")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_scan.json")); - @unlink(DUP_Util::SafePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}.log")); - //Unfinished Zip files - $tmpZip = DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_archive.zip.*"; - array_map('unlink', glob($tmpZip)); - @unlink(DUP_Util::SafePath()); - $delCount++; - } - } - } - } - - } catch (Exception $e) { - $json['error'] = "{$e}"; - die(json_encode($json)); - } - - $json['ids'] = "{$postIDs}"; - $json['removed'] = $delCount; - die(json_encode($json)); -} - -//DO NOT ADD A CARRIAGE RETURN BEYOND THIS POINT (headers issue)!! -?> \ No newline at end of file diff --git a/views/help/about.php b/views/help/about.php deleted file mode 100644 index 71de4006..00000000 --- a/views/help/about.php +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - -
                        - - -
                        - -
                        - - - - - -
                        - - - - - -

                        - - - -

                        - - -
                        - - - - -
                        - -
                        - - - - - - - - -
                        -
                        -
                        - - - -
                        - -
                        -
                        -
                        - -
                        -
                        - -
                        -
                        - - - -
                        - - - - -
                        - -
                        -
                        - -
                        - > - > - > - > - > -

                        -
                        -
                        -

                        - - - - -
                        -




                        \ No newline at end of file diff --git a/views/help/gopro.php b/views/help/gopro.php deleted file mode 100644 index b84230e1..00000000 --- a/views/help/gopro.php +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - -
                        - - -
                        - -
                        - -
                        - -

                        - - -

                        -

                        - - -

                        -
                        - - -
                        -
                        - -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        -
                        -
                        -
                        -
                        -
                        - -
                        - - -
                        -
                        - -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        -
                        - -
                        -
                        - -
                        -
                        -

                        - - - -

                        -
                        -




                        - - \ No newline at end of file diff --git a/views/help/help.php b/views/help/help.php deleted file mode 100644 index c665120b..00000000 --- a/views/help/help.php +++ /dev/null @@ -1,135 +0,0 @@ - - - - -
                        - - -
                        - -
                        - - - - - - -
                        - -
                        -

                        - - -
                        -
                        - -
                        -
                        -
                        -
                        - -
                        -
                        - - -
                        -
                        - -
                        -
                        -
                        - -

                        - -
                        -
                        -


                        - - - -
                        - -
                        - -
                        -
                        -
                        - -

                        - -
                        -
                        - - -
                        - -
                        - -
                        -
                        -
                        - -

                        - -
                        -
                        - - - -
                        -




                        - - \ No newline at end of file diff --git a/views/inc.header.php b/views/inc.header.php index 15434c08..6578ffe1 100644 --- a/views/inc.header.php +++ b/views/inc.header.php @@ -1,14 +1,13 @@ - - - - -
                        -

                        Duplicator »

                        -
                        - - - - - +" . esc_html($title) . ""; +} diff --git a/views/index.php b/views/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/views/index.php @@ -0,0 +1,3 @@ + -/* DESCRIPTION: Methods and Objects in this file are global and common in - * nature use this file to place all shared methods and varibles */ - -//UNIQUE NAMESPACE -Duplicator = new Object(); -Duplicator.UI = new Object(); -Duplicator.Pack = new Object(); -Duplicator.Settings = new Object(); -Duplicator.Tools = new Object(); -Duplicator.Tasks = new Object(); - -//GLOBAL CONSTANTS -Duplicator.DEBUG_AJAX_RESPONSE = false; -Duplicator.AJAX_TIMER = null; - - -/* ============================================================================ -* BASE NAMESPACE: All methods at the top of the Duplicator Namespace -* ============================================================================ */ - -/* ---------------------------------------- -* METHOD: Starts a timer for Ajax calls */ -Duplicator.StartAjaxTimer = function() { - Duplicator.AJAX_TIMER = new Date(); -}; - -/* ---------------------------------------- -* METHOD: Ends a timer for Ajax calls */ -Duplicator.EndAjaxTimer = function() { - var endTime = new Date(); - Duplicator.AJAX_TIMER = (endTime.getTime() - Duplicator.AJAX_TIMER) /1000; -}; - -/* ---------------------------------------- -* METHOD: Reloads the current window -* @param data An xhr object */ -Duplicator.ReloadWindow = function(data) { - if (Duplicator.DEBUG_AJAX_RESPONSE) { - Duplicator.Pack.ShowError('debug on', data); - } else { - window.location.reload(true); - } -}; - -//Basic Util Methods here: -Duplicator.OpenLogWindow = function(log) { - var logFile = log || null; - if (logFile == null) { - window.open('?page=duplicator-tools', 'Log Window'); - } else { - window.open('' + '/' + log) - } -}; - - -/* ============================================================================ -* UI NAMESPACE: All methods at the top of the Duplicator Namespace -* ============================================================================ */ - -/* ---------------------------------------- - * METHOD: */ -Duplicator.UI.SaveViewStateByPost = function (key, value) { - if (key != undefined && value != undefined ) { - jQuery.ajax({ - type: "POST", - url: ajaxurl, - dataType: "json", - data: {action : 'DUP_UI_SaveViewStateByPost', key: key, value: value}, - success: function(data) {}, - error: function(data) {} - }); - } -} - -/* ---------------------------------------- - * METHOD: */ -Duplicator.UI.AnimateProgressBar = function(id) { - //Create Progress Bar - var $mainbar = jQuery("#" + id); - $mainbar.progressbar({ value: 100 }); - $mainbar.height(25); - runAnimation($mainbar); - - function runAnimation($pb) { - $pb.css({ "padding-left": "0%", "padding-right": "90%" }); - $pb.progressbar("option", "value", 100); - $pb.animate({ paddingLeft: "90%", paddingRight: "0%" }, 3500, "linear", function () { runAnimation($pb); }); - } -} - - -/* ---------------------------------------- -* METHOD: Toggle MetaBoxes */ -Duplicator.UI.ToggleMetaBox = function() { - var $title = jQuery(this); - var $panel = $title.parent().find('.dup-box-panel'); - var $arrow = $title.parent().find('.dup-box-arrow i'); - var key = $panel.attr('id'); - var value = $panel.is(":visible") ? 0 : 1; - $panel.toggle(); - Duplicator.UI.SaveViewStateByPost(key, value); - (value) - ? $arrow.removeClass().addClass('fa fa-caret-up') - : $arrow.removeClass().addClass('fa fa-caret-down'); - -} - - -jQuery(document).ready(function($) { - //Init: Toggle MetaBoxes - $('div.dup-box div.dup-box-title').each(function() { - var $title = $(this); - var $panel = $title.parent().find('.dup-box-panel'); - var $arrow = $title.find('.dup-box-arrow'); - $title.click(Duplicator.UI.ToggleMetaBox); - ($panel.is(":visible")) - ? $arrow.html('') - : $arrow.html(''); - }); -}); - - \ No newline at end of file diff --git a/views/packages/controller.php b/views/packages/controller.php index dc10ff4f..f9204d50 100644 --- a/views/packages/controller.php +++ b/views/packages/controller.php @@ -1,89 +1,80 @@ - - - - - - -
                        - -
                        \ No newline at end of file + + + +
                        + +
                        diff --git a/views/packages/details/controller.php b/views/packages/details/controller.php new file mode 100644 index 00000000..4495f534 --- /dev/null +++ b/views/packages/details/controller.php @@ -0,0 +1,80 @@ +Status < 100); +?> + + + +
                        + Name}", 'duplicator')); + ?> + + +
                        +

                        + and respectively', + 'duplicator' + ), + '', + '' + ); + ?> + and respectively', + 'duplicator' + ), + '', + '', + '', + '' + ); + ?> +

                        +
                        + + + + + + render('mocks/transfer/transfer', array(), true); + break; + } + ?> +
                        diff --git a/views/packages/details/detail.php b/views/packages/details/detail.php new file mode 100644 index 00000000..048508d4 --- /dev/null +++ b/views/packages/details/detail.php @@ -0,0 +1,610 @@ +getPackageFileDownloadInfo(DUP_PackageFileType::Archive); +$logDownloadInfo = $package->getPackageFileDownloadInfo(DUP_PackageFileType::Log); +$installerDownloadInfo = $package->getInstallerDownloadInfo(); +$archiveDownloadInfoJson = SnapJson::jsonEncodeEscAttr($archiveDownloadInfo); +$logDownloadInfoJson = SnapJson::jsonEncodeEscAttr($logDownloadInfo); +$installerDownloadInfoJson = SnapJson::jsonEncodeEscAttr($installerDownloadInfo); +$showLinksDialogJson = SnapJson::jsonEncodeEscAttr(array( + "archive" => $archiveDownloadInfo["url"], + "log" => $logDownloadInfo["url"], +)); + +$debug_on = DUP_Settings::Get('package_debug'); +$mysqldump_on = DUP_Settings::Get('package_mysqldump') && DUP_DB::getMySqlDumpPath(); +$mysqlcompat_on = isset($Package->Database->Compatible) && strlen($Package->Database->Compatible); +$mysqlcompat_on = ($mysqldump_on && $mysqlcompat_on) ? true : false; +$dbbuild_mode = ($mysqldump_on) ? 'mysqldump' : 'PHP'; +$archive_build_mode = ($package->Archive->Format === 'ZIP') ? 'ZipArchive (zip)' : 'DupArchive (daf)'; +$dup_install_secure_on = isset($package->Installer->OptsSecureOn) ? $package->Installer->OptsSecureOn : 0; +$dup_install_secure_pass = isset($package->Installer->OptsSecurePass) ? DUP_Util::installerUnscramble($package->Installer->OptsSecurePass) : ''; +$installerNameMode = DUP_Settings::Get('installer_name_mode'); + +$currentStoreURLPath = DUP_Settings::getSsdirUrl(); +$installerSecureName = $package->getInstDownloadName(true); +$installerDirectLink = "{$currentStoreURLPath}/" . pathinfo($installerSecureName, PATHINFO_FILENAME) . DUP_Installer::INSTALLER_SERVER_EXTENSION; +?> + + + + +

                        + + +
                        + [open all]   + [close all] +
                        + + +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        + + Name); ?> + +
                        + + + + + + + + + + + + + +
                        ID); ?>
                        Hash); ?>
                        NameHash); ?>
                        +
                        +
                        Notes) ? $package->Notes : esc_html__('- no notes -', 'duplicator') ?>
                        Created) ?>
                        + + Version); ?> + +
                        + + + + + + + + + + + + + +
                        VersionWP) ? esc_html($package->VersionWP) : esc_html__('- unknown -', 'duplicator') ?>
                        VersionPHP) ? esc_html($package->VersionPHP) : esc_html__('- unknown -', 'duplicator') ?>
                        + VersionDB) ? esc_html($package->VersionDB) : esc_html__('- unknown -', 'duplicator') ?> | + Database->Comments) ? esc_html($package->Database->Comments) : esc_html__('- unknown -', 'duplicator') ?> +
                        +
                        +
                        Runtime) ? esc_html($package->Runtime) : esc_html__("error running", 'duplicator'); ?>
                        Status >= 100) ? esc_html__('completed', 'duplicator') : esc_html__('in-complete', 'duplicator') ?>
                        WPUser) ? esc_html($package->WPUser) : esc_html__('- unknown -', 'duplicator') ?>
                        +
                        + + '; + } else { + $installBtnTooltip = __('Download basic installer (installer.php)', 'duplicator'); + $installBtnIcon = ''; + } + ?> +
                        + + +

                        +
                        + + + + + + +
                        + + + + + + + + + + + + + + + + + +
                        + " class="link-style"> + Archive->File); ?> + +
                        + " target="file_results" class="link-style"> + + +
                        + +
                        + +
                        +
                        +
                        + + + + + + +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + + + + + + + + +
                        + + + + + + + + + '; + echo DUP_Settings:: getSsdirUrl(); + ?> +
                        +
                        + +  ' . 'Amazon', + ' ' . 'Dropbox', + ' ' . 'Google Drive', + ' ' . 'OneDrive', + ' ' . 'FTP/SFTP' + ); ?> + + + + " + data-tooltip=""> + + +
                        +
                        + +
                        +
                        + + +
                        +
                        + +
                        +
                        +
                        + + +
                        + + +
                        + + + + + + + + Archive->ExportOnlyDB) : ?> + + + + + + + + + + +
                        + Archive->FilterOn == 1 ? 'On' : 'Off'; ?> +
                        +
                        + Archive->FilterDirs) + ? str_replace(';', ";\n", $package->Archive->FilterDirs) + : esc_html__('- no filters -', 'duplicator'); + ?> + +
                        + +
                        +
                        + Archive->FilterExts) && strlen($package->Archive->FilterExts) + ? esc_html($package->Archive->FilterExts) + : esc_html__('- no filters -', 'duplicator'); + ?> +
                        + +
                        +
                        + Archive->FilterFiles) + ? str_replace(';', ";\n", $package->Archive->FilterFiles) + : esc_html__('- no filters -', 'duplicator'); + ?> + +
                        +
                        +

                        + + +
                        + + +
                        + + + + + + + + + + + + + + + + + + + + + +
                        Database->info->name); ?>
                        Database->Type); ?>
                        + + +
                        + + + [] + + +
                        Database->FilterOn == 1 ? 'On' : 'Off'; ?>
                          +
                        + Database->FilterTables) && strlen($package->Database->FilterTables) + ? str_replace(',', "
                        \n", $package->Database->FilterTables) + : esc_html__('- no filters -', 'duplicator'); + ?> +
                        +
                        +
                        + + + +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + + + + + + + +
                        +
                        +
                        + + + +
                        +
                        + + +
                        +
                        +

                        + + + + + + + + + + + + + + + + + +
                        +
                        +
                        Installer->OptsDBHost) ? esc_html($package->Installer->OptsDBHost) : esc_html__('- not set -', 'duplicator') ?>
                        Installer->OptsDBName) ? esc_html($package->Installer->OptsDBName) : esc_html__('- not set -', 'duplicator') ?>
                        Installer->OptsDBUser) ? esc_html($package->Installer->OptsDBUser) : esc_html__('- not set -', 'duplicator') ?>
                        +
                        +
                        + + +
                        + []
                        + +
                        + + + + diff --git a/views/packages/details/index.php b/views/packages/details/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/views/packages/details/index.php @@ -0,0 +1,3 @@ + - -
                        - -
                        -

                        - - - %s %s", - __("Please visit the", 'wpduplicator'), - __("help page", 'wpduplicator'), - __("for additional support", 'wpduplicator')); - ?> - - - - -
                        - - %s %s", - __("To get an older package please visit the", 'wpduplicator'), - __("help page", 'wpduplicator'), - __("and look for the Change Log link for additional instructions.", 'wpduplicator')); - ?>
                        - -


                        - -
                         
                        - -
                        - - - diff --git a/views/packages/list.base.php b/views/packages/list.base.php deleted file mode 100644 index 70baf302..00000000 --- a/views/packages/list.base.php +++ /dev/null @@ -1,353 +0,0 @@ -get_results("SELECT * FROM `{$wpdb->prefix}duplicator_packages` ORDER BY id DESC", ARRAY_A); - $qryStatus = $wpdb->get_results("SELECT status FROM `{$wpdb->prefix}duplicator_packages` WHERE status >= 100", ARRAY_A); - $totalElements = count($qryResult); - $statusCount = count($qryStatus); - $package_debug = DUP_Settings::Get('package_debug'); - - $ajax_nonce = wp_create_nonce('package_list'); -?> - - - -
                        - -= 3) : ?> -
                        - -
                        - - - - - - - - - -
                        -
                        - - " onclick="Duplicator.Pack.Delete()"> -
                        -
                        -
                        - ..."> - -   - -
                        - - - - - - - - - -
                         
                         
                        - - - - - - - - - - - - - - - - - - Name; - $pack_archive_size = $Package->Archive->Size; - $pack_version = $Package->Version; - $pack_notes = $Package->Notes; - $pack_storeurl = $Package->StoreURL; - $pack_namehash = $Package->NameHash; - } else { - $pack_archive_size = 0; - $pack_version = 'unknown'; - $pack_notes = 'unknown'; - $pack_storeurl = 'unknown'; - $pack_name = 'unknown'; - $pack_namehash = 'unknown'; - } - - $detail_id = "duplicator-detail-row-{$rowCount}"; - $plugin_version = empty($pack_version) ? 'unknown' : $pack_version; - $plugin_compat = version_compare($plugin_version, '0.5.0'); - $notes = empty($pack_notes) ? __("(No Notes Taken)", 'wpduplicator') : $pack_notes; - - //Links - $uniqueid = "{$row['name']}_{$row['hash']}"; - $sqlfilelink = $pack_storeurl . "{$uniqueid}_database.sql"; - $packagepath = $pack_storeurl . "{$uniqueid}_archive.zip"; - $installerpath = $pack_storeurl . "{$uniqueid}_installer.php"; - $logfilelink = $pack_storeurl . "{$uniqueid}.log"; - $reportfilelink = $pack_storeurl . "{$uniqueid}_scan.json"; - $installfilelink = "{$installerpath}?get=1&file={$uniqueid}_installer.php"; - $logfilename = "{$uniqueid}.log"; - $css_alt = ($rowCount % 2 != 0) ? '' : 'alternate'; - ?> - - - = 100) : ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        " style="margin-left:15px" onclick="Duplicator.Pack.SetDeleteAll()" /> - -
                        [] -   - - -
                        - :   |   - :   |   - :
                        - : -
                         
                        -   -   - - -
                        - ); return false;">[]   - []
                        - -
                        - -
                        [] - - ... - -
                        -
                        - :   |   - :   |   - :
                        - - -
                        - - :
                        - %s", - __("This package has encountered errors. Click 'View Log' for more details. For additional support see the ", 'wpduplicator'), - __("online knowledgebase", 'wpduplicator')); - ?>
                         
                        - - -
                        - [View Package Object]
                        - -
                        - - - - -
                        -
                        - | - -
                        - -
                        - - - - - - - - - - - diff --git a/views/packages/main/controller.php b/views/packages/main/controller.php new file mode 100644 index 00000000..856f5872 --- /dev/null +++ b/views/packages/main/controller.php @@ -0,0 +1,75 @@ +%s %s.", $txt_invalid_msg1, $txt_invalid_msg2, $txt_invalid_lnk)); + } + break; + case 'new2': + if (!wp_verify_nonce($_GET['_wpnonce'], 'new2-package')) { + die(printf("%s
                        %s %s.", $txt_invalid_msg1, $txt_invalid_msg2, $txt_invalid_lnk)); + } + break; + case 'new3': + if (!wp_verify_nonce($_GET['_wpnonce'], 'new3-package')) { + die(printf("%s
                        %s %s.", $txt_invalid_msg1, $txt_invalid_msg2, $txt_invalid_lnk)); + } + break; +} +?> + + + + diff --git a/views/packages/main/index.php b/views/packages/main/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/views/packages/main/index.php @@ -0,0 +1,3 @@ + '>=', 'status' => DUP_PackageStatus::COMPLETE))); // total packages completed +$active_package_present = DUP_Package::isPackageRunning(); +$is_mu = is_multisite(); + +$package_running = false; +global $packageTablerowCount; +$packageTablerowCount = 0; + +if (DUP_Settings::Get('installer_name_mode') == DUP_Settings::INSTALLER_NAME_MODE_SIMPLE) { + $packageExeNameModeMsg = __("When clicking the Installer download button, the 'Save as' dialog is currently defaulting the name to 'installer.php'. " + . "To improve the security and get more information, go to: Settings > Packages Tab > Installer > Name option or click on the gear icon at the top of this page.", 'duplicator'); +} else { + $packageExeNameModeMsg = __("When clicking the Installer download button, the 'Save as' dialog is defaulting the name to '[name]_[hash]_[time]_installer.php'. " + . "This is the secure and recommended option. For more information, go to: Settings > Packages Tab > Installer > Name or click on the gear icon at the top of this page.

                        " + . "To quickly copy the hashed installer name, to your clipboard use the copy icon link or click the installer name and manually copy the selected text.", 'duplicator'); +} +?> + + + +
                        + + + + + + + +
                        + + " + onclick="Duplicator.Pack.ConfirmDelete()" + > + + " onclick="Duplicator.Pack.showHelp()"> + + + " + > + + + " + > + + + + " + > + + + "> + + + + + + + +
                        + + + + + + + + + + + +
                         
                        +
                        + +
                        +
                        +
                        > +
                        + + + +
                        + '; + echo ' '; + esc_html_e('Duplicator Lite does not officially support WordPress multisite.', 'duplicator'); + echo "
                        "; + esc_html_e('We strongly recommend upgrading to ', 'duplicator'); + echo " [" . esc_html__('Duplicator Pro', 'duplicator') . "]."; + echo '
                        '; + } + ?> +
                         
                        + +
                         
                        + + + + + + + + + + + + + + + + + isRunning(); + $pack_name = $Package->Name; + $pack_archive_size = $Package->getArchiveSize(); + $pack_perc = $Package->Status; + $pack_dbonly = $Package->Archive->ExportOnlyDB; + $pack_build_mode = ($Package->Archive->Format === 'ZIP') ? true : false; + + //Links + $uniqueid = $Package->NameHash; + $packagepath = DUP_Settings::getSsdirUrl() . '/' . $Package->Archive->File; + + $css_alt = ($packageTablerowCount % 2 != 0) ? '' : 'alternate'; + + if ($Package->Status >= 100 || $is_running_package) : + ?> + + + + + + + + + ID}"; + ?> + + + + + + + + + + + + + + + + +
                        + " style="margin-left:12px" onclick="Duplicator.Pack.SetDeleteAll()" /> + + + " + data-tooltip="" > + + + +
                        +
                        + +
                        +
                        +
                        +
                        + + + +
                        +
                         
                        +
                        +
                        + Created, DUP_Settings::get_create_date_format()); + echo ' ' . ($pack_build_mode ? + "zip" : + "daf"); + ?> + + DB" : esc_html($pack_name); ?>
                        + + Building Package % +   " + data-tooltip=" Advanced > Reset Packages', 'duplicator'); ?>"> + +
                        + getInstDownloadName(); + ?> + "> + + + + + + + + +
                        Created, DUP_Settings::get_create_date_format()); ?>  + + +
                        + + + +
                        + +
                        + +
                        + + +
                        + + +title = __('Bulk Action Required', 'duplicator'); +$alert1->message = ' '; +$alert1->message .= __('No selections made! Please select an action from the "Bulk Actions" drop down menu.', 'duplicator'); +$alert1->initAlert(); + +$alert2 = new DUP_UI_Dialog(); +$alert2->title = __('Selection Required', 'duplicator', 'duplicator'); +$alert2->message = ' '; +$alert2->message .= __('No selections made! Please select at least one package to delete.', 'duplicator'); +$alert2->initAlert(); + +$confirm1 = new DUP_UI_Dialog(); +$confirm1->title = __('Delete Packages?', 'duplicator'); +$confirm1->message = __('Are you sure you want to delete the selected package(s)?', 'duplicator'); +$confirm1->progressText = __('Removing Packages, Please Wait...', 'duplicator'); +$confirm1->jscallback = 'Duplicator.Pack.Delete()'; +$confirm1->initConfirm(); + +$alert3 = new DUP_UI_Dialog(); +$alert3->height = 400; +$alert3->width = 450; +$alert3->title = __('Duplicator Help', 'duplicator'); +$alert3->message = "
                        "; +$alert3->initAlert(); + +$alertPackRunning = new DUP_UI_Dialog(); +$alertPackRunning->title = __('Alert!', 'duplicator'); +$alertPackRunning->message = __('A package is being processed. Retry later.', 'duplicator'); +$alertPackRunning->initAlert(); +?> + + + + + diff --git a/views/packages/main/s1.setup1.php b/views/packages/main/s1.setup1.php new file mode 100644 index 00000000..83ad6f1e --- /dev/null +++ b/views/packages/main/s1.setup1.php @@ -0,0 +1,310 @@ +setResponseType('PHP'); +$data = $ctrl_ui->GetViewStateList(); + +$ui_css_storage = (isset($data->payload['dup-pack-storage-panel']) && !$data->payload['dup-pack-storage-panel']) ? 'display:none' : 'display:block'; +$ui_css_archive = (isset($data->payload['dup-pack-archive-panel']) && $data->payload['dup-pack-archive-panel']) ? 'display:block' : 'display:none'; +$ui_css_installer = (isset($data->payload['dup-pack-installer-panel']) && $data->payload['dup-pack-installer-panel']) ? 'display:block' : 'display:none'; +$dup_intaller_files = implode(", ", array_keys(DUP_Server::getInstallerFiles())); +$dbbuild_mode = (DUP_Settings::Get('package_mysqldump') && DUP_DB::getMySqlDumpPath()) ? 'mysqldump' : 'PHP'; +$archive_build_mode = DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::ZipArchive ? 'zip' : 'daf'; + +//="No Selection", 1="Try Again", 2="Two-Part Install" +$retry_state = isset($_GET['retry']) ? $_GET['retry'] : 0; +?> + + + + + + + + + + +
                        +
                        +
                        + + + +
                        +
                        +
                        + + +
                        +
                         
                        +
                        + + +

                        + + + + + +
                        +
                        + Pass
                        ' : '
                        Fail
                        '; + ?> +
                        +
                        + +
                        + +
                        + +
                        + + +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        + %s %s", + esc_html__("ZipArchive extension is required or", 'duplicator'), + esc_html__("Switch to DupArchive", 'duplicator'), + esc_html__("to by-pass this requirement.", 'duplicator') + ); + ?> +
                        file_get_contents
                        file_put_contents
                        mb_strlen
                        + + + +
                        +
                        + + +
                        +
                        + +
                        + +
                        +
                        +
                        + %s   [%s]
                        ", $dup_tests['IO']['SSDIR'], DUP_Settings::getSsdirPath()); + printf("%s   [%s]
                        ", $dup_tests['IO']['SSTMP'], DUP_Settings::getSsdirTmpPath()); + printf("%s   [%s]
                        ", $dup_tests['IO']['WPROOT'], $abs_path); + ?> +
                        + '; + } + esc_html_e("If Duplicator does not have enough permissions then you will need to manually create the paths above.   ", 'duplicator'); + ?> +
                        +
                        +
                        + + +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + +
                        + + [" . esc_html__('more info', 'duplicator') . "]"; + ?> + +
                        + + + + + +
                        mysqli_real_escape_string
                        + + + +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        + + + +
                        + +
                        + +
                        ' style='font-size:10px; margin-top:5px;' /> +
                        + +
                        +
                        + +
                        +

                        + + + + +
                        + +
                        + + +
                        + +
                        + + diff --git a/views/packages/main/s1.setup2.php b/views/packages/main/s1.setup2.php new file mode 100644 index 00000000..68c7b934 --- /dev/null +++ b/views/packages/main/s1.setup2.php @@ -0,0 +1,679 @@ + + + +
                        + + + +
                        + + +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + +
                        +
                        + + +
                        +
                        +
                        +
                        + + + +
                        + +
                        +
                        + + + + + + + + + + + + + + + + + + + + + +
                        + + + + + + + + + +
                        +
                        + +  ' . 'Amazon', + ' ' . 'Dropbox', + ' ' . 'Google Drive', + ' ' . 'OneDrive', + ' ' . 'FTP/SFTP' + ); + ?> + + + + " + data-tooltip=""> + + +
                        +
                        +
                        +

                        + + + +
                        +
                        +
                        + + {$archive_build_mode}"; + ?>     +
                        +
                        + + + + + + + + + + +   + +
                        +
                        +
                        +
                        + + + +
                        +
                          +
                        • +
                        • +
                        • +
                        + + + render('admin_pages/packages/setup/archive-filter-files-tab', array ( + 'package' => $Package + )); ?> + + +
                        +
                        + +
                        + + + + + + +
                        Database->FilterOn) ? "checked='checked'" : ""; ?> /> + + " + data-tooltip=""> + +
                        +
                        +
                        +   + +
                        +
                        + get_results("SHOW FULL TABLES FROM `" . DB_NAME . "` WHERE Table_Type = 'BASE TABLE' ", ARRAY_N); + $num_rows = count($tables); + $next_row = round($num_rows / 4, 0); + $counter = 0; + $tableList = explode(',', $Package->Database->FilterTables); + + echo '
                        '; + foreach ($tables as $table) { + if (DUP_Util::isTableExists($table[0])) { + if (DUP_Util::isWPCoreTable($table[0])) { + $core_css = 'core-table'; + $core_note = '*'; + } else { + $core_css = 'non-core-table'; + $core_note = ''; + } + + if (in_array($table[0], $tableList)) { + $checked = 'checked="checked"'; + $css = 'text-decoration:line-through'; + } else { + $checked = ''; + $css = ''; + } + echo "
                        "; + $counter++; + if ($next_row <= $counter) { + echo '
                        '; + $counter = 0; + } + } + } + echo '
                        '; + ?> +
                        +
                        + +
                        + excluded from the database script. ", 'duplicator'); + _e("Excluding certain tables can cause your site or plugins to not work correctly after install!
                        ", 'duplicator'); + _e(" Use caution when excluding tables! It is highly recommended to not exclude WordPress core tables*, unless you know the impact.", 'duplicator'); + ?> +
                        +
                        + +
                        + +
                        + +
                        + + :  + + +
                        + :  + " + data-tooltip=""> +   + + [] + + + + Database->Compatible); + $is_mysql40 = in_array('mysql40', $modes); + $is_no_table = in_array('no_table_options', $modes); + $is_no_key = in_array('no_key_options', $modes); + $is_no_field = in_array('no_field_options', $modes); + ?> + + + + + + + +
                        + > + + + > + + + > + + + > + +
                        + + + +
                        +
                        + + +
                        +

                        + +

                        + + + +
                        +
                        +
                        +

                        + + +
                        +
                        +
                        +   +
                        +
                        + + + + + + +
                        +
                        +
                        + +
                        + +
                        + + +
                        + + " + data-tooltip=""> + +
                        + + + + + + + + + + + + + +
                        + + + :" + data-tooltip=""> +

                        +
                        + Installer->OptsSecureOn) ? $Package->Installer->OptsSecureOn : 0; + $dup_install_secure_pass = isset($Package->Installer->OptsSecurePass) ? DUP_Util::installerUnscramble($Package->Installer->OptsSecurePass) : ''; + ?> + /> + + " + data-tooltip=""> + +
                        + + +
                        +
                        +
                        + + + + + +
                        + + +
                        +
                          +
                        • +
                        • +
                        + + +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        + +
                        + +
                        + +
                        + +
                        + +
                        + +

                        +
                        + + +
                        +
                        + " style="width:16px; height:12px" /> +
                        + + + +
                        + +
                        +
                        + +
                        + + +
                        +

                        + + + + +
                        + + +title = __('Reset Package Settings?', 'duplicator'); + $confirm1->message = __('This will clear and reset all of the current package settings. Would you like to continue?', 'duplicator'); + $confirm1->jscallback = 'Duplicator.Pack.ResetSettings()'; + $confirm1->initConfirm(); + + $default_name1 = DUP_Package::getDefaultName(); + $default_name2 = DUP_Package::getDefaultName(false); +?> + diff --git a/views/packages/main/s2.scan1.php b/views/packages/main/s2.scan1.php new file mode 100644 index 00000000..c93e6b6c --- /dev/null +++ b/views/packages/main/s2.scan1.php @@ -0,0 +1,460 @@ +window.location.href = '{$reredirect_nonce_url}'"); +} + + $Package = new DUP_Package(); + $Package->saveActive($_POST); + + DUP_Settings::Set('active_package_id', -1); + DUP_Settings::Save(); + + $Package = DUP_Package::getActive(); + + $mysqldump_on = DUP_Settings::Get('package_mysqldump') && DUP_DB::getMySqlDumpPath(); + $mysqlcompat_on = isset($Package->Database->Compatible) && strlen($Package->Database->Compatible); + $mysqlcompat_on = ($mysqldump_on && $mysqlcompat_on) ? true : false; + $dbbuild_mode = ($mysqldump_on) ? 'mysqldump' : 'PHP'; + $zip_check = DUP_Util::getZipPath(); + + $action_url = admin_url('admin.php?page=duplicator&tab=new3'); + $action_nonce_url = wp_nonce_url($action_url, 'new3-package'); +?> + + + +validateInputs(); +if (!$validator->isSuccess()) { + ?> +
                        + +
                        +
                        +
                        +
                        + +
                        +
                          + getErrorsFormat("
                        • %s
                        • "); + ?> +
                        +
                        +
                        +
                        + " onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=')" class="button button-large" /> +
                        + + + + + + + + +
                        +
                        +
                        + + + +
                        +
                        + + +
                        +
                        +
                         
                        +
                        + +
                        + + + +
                        + +
                        +
                        +
                        +

                        +
                        +
                        +
                        + +
                        + + + + + + + + +
                        + + \ No newline at end of file diff --git a/views/packages/main/s2.scan2.php b/views/packages/main/s2.scan2.php new file mode 100644 index 00000000..e078316b --- /dev/null +++ b/views/packages/main/s2.scan2.php @@ -0,0 +1,245 @@ + + +
                        + +
                        +   + +
                        +
                        + + +
                        + + Archive->FilterDirs); + $filterFiles = explode(';', $Package->Archive->FilterFiles); + + if (!$Package->Archive->ExportOnlyDB && $Package->Archive->FilterOn) { + $core_dir_included = array_intersect($filterDirs, DUP_Util::getWPCoreDirs()); + if (count($core_dir_included)) { + $core_dir_notice = true; + } + + $core_files_included = array_intersect($filterFiles, DUP_Util::getWPCoreFiles()); + if (count($core_files_included)) { + $core_file_notice = true; + } + } + ?> +
                        +
                        +
                        +
                        +
                        +  ' . esc_html__('Web Server', 'duplicator') . ":  '" . esc_attr($_SERVER['SERVER_SOFTWARE']) . "'
                        "; + _e("Supported web servers: ", 'duplicator'); + echo "" . esc_html($web_servers) . ""; + + //PHP VERSION + echo '
                         ' . esc_html__('PHP Version', 'duplicator') . "
                        "; + _e('The minimum PHP version supported by Duplicator is 5.2.9. It is highly recommended to use PHP 5.3+ for improved stability. For international language support please use PHP 7.0+.', 'duplicator'); + + //OPEN_BASEDIR + $test = ini_get("open_basedir"); + $test = ($test) ? 'ON' : 'OFF'; + echo '
                         ' . esc_html__('PHP Open Base Dir', 'duplicator') . ":  '{$test}'
                        "; + _e('Issues might occur when [open_basedir] is enabled. Work with your server admin to disable this value in the php.ini file if you’re having issues building a package.', 'duplicator'); + echo " [" . esc_html__('details', 'duplicator') . "]
                        "; + + //MAX_EXECUTION_TIME + $test = (@set_time_limit(0)) ? 0 : ini_get("max_execution_time"); + echo '
                         ' . esc_html__('PHP Max Execution Time', 'duplicator') . ":  '{$test}'
                        "; + _e('Timeouts may occur for larger packages when [max_execution_time] time in the php.ini is too low. A value of 0 (recommended) indicates that PHP has no time limits. ' + . 'An attempt is made to override this value if the server allows it.', 'duplicator'); + echo '

                        '; + _e('Note: Timeouts can also be set at the web server layer, so if the PHP max timeout passes and you still see a build timeout messages, then your web server could be killing ' + . 'the process. If you are on a budget host and limited on processing time, consider using the database or file filters to shrink the size of your overall package. ' + . 'However use caution as excluding the wrong resources can cause your install to not work properly.', 'duplicator'); + echo " [" . esc_html__('details', 'duplicator') . "]"; + if ($zip_check != null) { + echo '

                        '; + echo ''; + _e('Get faster builds with Duplicator Pro with access to shell_exec zip.', 'duplicator'); + echo ''; + echo " [" . esc_html__('details', 'duplicator') . "]"; + } + + //MANAGED HOST + $test = DUP_Custom_Host_Manager::getInstance()->isManaged() ? "true" : "false"; + echo '
                         ' . esc_html__('Managed Host', 'duplicator') . ":  '{$test}'
                        "; + _e('A managed host is a WordPress host that tightly controls the server environment so that the software running on it can be closely ‘managed’ by the hosting company. ' + . 'Managed hosts typically have constraints imposed to facilitate this management, including the locking down of certain files and directories as well as non-standard configurations.', 'duplicator'); + echo '

                        '; + _e('Duplicator Lite allows users to build a package on managed hosts, however, the installer may not properly install packages created on managed hosts due to the non-standard configurations of managed hosts. ' + . 'It is also possible the package engine of Duplicator Lite won’t be able to capture all of the necessary data of a site running on a managed host.', 'duplicator'); + echo '

                        '; + _e('Due to these constraints Lite does not officially support the migration of managed hosts. ' + . 'It’s possible one could get the package to install but it may require custom manual effort. ' + . 'To get support and the advanced installer processing required for managed host support we encourage users to ' + . 'upgrade to Duplicator Pro. ' + . 'Pro has more sophisticated package and installer logic and accounts for odd configurations associated with managed hosts.', 'duplicator'); + echo '

                        '; + + ?> +
                        +
                        + + +
                        + +
                        +
                        +
                        +
                        +
                        +  ' . esc_html__('WordPress Version', 'duplicator') . ":  '{$wp_version}'
                        "; + printf(__('It is recommended to have a version of WordPress that is greater than %1$s. Older version of WordPress can lead to migration issues and are a security risk. ' + . 'If possible please update your WordPress site to the latest version.', 'duplicator'), DUPLICATOR_SCAN_MIN_WP); + + //CORE FILES + echo '
                         ' . esc_html__('Core Files', 'duplicator') . "
                        "; + + + $filter_text = ""; + if ($core_dir_notice) { + echo ''; + esc_html_e("The core WordPress paths below will NOT be included in the archive. These paths are required for WordPress to function!", 'duplicator'); + echo "
                        "; + foreach ($core_dir_included as $core_dir) { + echo '     ' . $core_dir . '
                        '; + } + echo '

                        '; + $filter_text = "directories"; + } + + if ($core_file_notice) { + echo ''; + esc_html_e("The core WordPress file below will NOT be included in the archive. This file is required for WordPress to function!", 'duplicator'); + echo "
                        "; + foreach ($core_files_included as $core_file) { + echo '     ' . $core_file . '
                        '; + } + echo '

                        '; + $filter_text .= (strlen($filter_text) > 0) ? " and file" : "files"; + } + + if (strlen($filter_text) > 0) { + echo ''; + esc_html_e("Note: Please change the {$filter_text} filters if you wish to include the WordPress core files otherwise the data will have to be manually copied" + . " to the new location for the site to function properly.", 'duplicator'); + echo ''; + } + + + if (!$core_dir_notice && !$core_file_notice) : + esc_html_e("If the scanner is unable to locate the wp-config.php file in the root directory, then you will need to manually copy it to its new location. " + . "This check will also look for core WordPress paths that should be included in the archive for WordPress to work correctly.", 'duplicator'); + endif; + + + + //CACHE DIR + /* + $cache_path = DUP_Util::safePath(WP_CONTENT_DIR) . '/cache'; + $cache_size = DUP_Util::byteSize(DUP_Util::getDirectorySize($cache_path)); + echo '
                         ' . esc_html__('Cache Path', 'duplicator') . ":  '".esc_html($cache_path)."' (".esc_html($cache_size).")
                        "; + _e("Cached data will lead to issues at install time and increases your archive size. Empty your cache directory before building the package by using " + . "your cache plugins clear cache feature. Use caution if manually removing files the cache folder. The cache " + . "size minimum threshold that triggers this warning is currently set at ", 'duplicator'); + echo esc_html(DUP_Util::byteSize(DUPLICATOR_SCAN_CACHESIZE)) . '.'; + */ + + //MU SITE + if (is_multisite()) { + echo '
                         ' . esc_html__('Multisite: Unsupported', 'duplicator') . "
                        "; + esc_html_e('Duplicator does not support WordPress multisite migrations. We strongly recommend using Duplicator Pro which currently supports full multisite migrations and various other ' + . 'subsite scenarios.', 'duplicator'); + echo '

                        '; + + esc_html_e('While it is not recommended you can still continue with the build of this package. At install time additional manual custom configurations will ' + . 'need to be made to finalize this multisite migration. Please note that any support requests for mulitsite with Duplicator Lite will not be supported.', 'duplicator'); + echo " [" . esc_html__('upgrade to pro', 'duplicator') . "]"; + } else { + echo '
                         ' . esc_html__('Multisite: N/A', 'duplicator') . "
                        "; + esc_html_e('This is not a multisite install so duplication will proceed without issue. Duplicator does not officially support multisite. However, Duplicator Pro supports ' + . 'duplication of a full multisite network and also has the ability to install a multisite subsite as a standalone site.', 'duplicator'); + echo " [" . esc_html__('upgrade to pro', 'duplicator') . "]"; + } + ?> +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + diff --git a/views/packages/main/s2.scan3.php b/views/packages/main/s2.scan3.php new file mode 100644 index 00000000..7cf8eb5b --- /dev/null +++ b/views/packages/main/s2.scan3.php @@ -0,0 +1,1169 @@ + 50 ? substr($root, 0, 50) . '...' : $root; + echo "
                        {$sroot}
                        "; +} + +$archive_type_label = DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::ZipArchive ? "ZipArchive" : "DupArchive"; +$archive_type_extension = DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::ZipArchive ? "zip" : "daf"; +$duparchive_max_limit = DUP_Util::readableByteSize(DUPLICATOR_MAX_DUPARCHIVE_SIZE); +$skip_archive_scan = DUP_Settings::Get('skip_archive_scan'); +$dbbuild_mode = DUP_DB::getBuildMode(); +?> + + +
                        +   + +
                        +
                        + +
                        + + + +
                        +
                        + Archive->ExportOnlyDB) { + echo ' '; + esc_html_e('Database Only', 'duplicator'); + } elseif ($Package->Archive->FilterOn) { + echo ' '; + esc_html_e('Enabled', 'duplicator'); + } + ?> +
                        +
                        + + +
                        +
                        +
                        + +Archive->ExportOnlyDB) { ?> +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        + +

                        + +
                        +
                        + + + +
                        +
                        +
                        +
                        +
                        +
                        + :   |   + :   |   + :
                        + some budget hosts may cause timeouts. ', 'duplicator'); + echo "  [" . esc_html__('more details...', 'duplicator') . "]"; + ?> +
                        + ' . DUP_Util::byteSize(DUPLICATOR_SCAN_SIZE_DEFAULT) . '' + ); + ?> +

                        + ": +
                        +
                          +
                        • +
                        • + tags', + 'duplicator' + ), + '', + '' + ); + ?> +
                        • +
                        • + tags', + 'duplicator' + ), + '', + '' + ); + ?> +
                        • +
                        +
                        + + +
                        +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        + +
                        + +
                        +
                        +
                        + + + +
                        +
                        +
                        +
                        +
                        +
                        + <:/\|", can be problematic on some hosts.', 'duplicator'); + esc_html_e(' Only consider using this filter if the package build is failing. Select files that are not important to your site or you can migrate manually.', 'duplicator'); + $txt = __('If this environment/system and the system where it will be installed are set up to support Unicode and long paths then these filters can be ignored. ' + . 'If you run into issues with creating or installing a package, then is recommended to filter these paths.', 'duplicator'); + ?> + +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + +
                        +
                        + + +
                        +
                        + Database->FilterOn) { + echo ' '; + esc_html_e('Enabled', 'duplicator'); + } + ?> +
                        +
                        + " + data-tooltip=""> + +
                        + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        + ' . esc_html__('TOTAL SIZE', 'duplicator') . '   ⇛   '; ?> + :   |   + :   |   + :
                        +
                        '; + + //TABLE DETAILS + echo '' . __('TABLE DETAILS:', 'duplicator') . '
                        '; + $dup_scan_tbl_trigger_size = DUP_Util::byteSize(DUPLICATOR_SCAN_DB_TBL_SIZE) . ', ' . number_format(DUPLICATOR_SCAN_DB_TBL_ROWS); + printf(esc_html__('The notices for tables are %1$s records or names with upper-case characters. Individual tables will not trigger ' + . 'a notice message, but can help narrow down issues if they occur later on.', 'duplicator'), $dup_scan_tbl_trigger_size); + + echo '
                        '; + + //RECOMMENDATIONS + echo '

                        '; + echo '' . esc_html__('RECOMMENDATIONS:', 'duplicator') . '
                        '; + + echo '
                        '; + $lnk = '' . esc_html__('repair and optimization', 'duplicator') . ''; + printf(__('1. Run a %1$s on the table to improve the overall size and performance.', 'duplicator'), $lnk); + echo '

                        '; + _e('2. Remove post revisions and stale data from tables. Tables such as logs, statistical or other non-critical data should be cleared.', 'duplicator'); + echo '

                        '; + $lnk = '' . esc_html__('Enable mysqldump', 'duplicator') . ''; + printf(__('3. %1$s if this host supports the option.', 'duplicator'), $lnk); + echo '

                        '; + $lnk = '' . esc_html__('lower_case_table_names', 'duplicator') . ''; + printf(__('4. For table name case sensitivity issues either rename the table with lower case characters or be prepared to work with the %1$s system variable setting.', 'duplicator'), $lnk); + echo '
                        '; + + ?> +
                        +
                        + get_col("SHOW TRIGGERS", 1); + if (count($triggers)) { ?> +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + get_col("SHOW PROCEDURE STATUS WHERE `Db` = '{$GLOBALS['wpdb']->dbname}'", 1); + $functions = $GLOBALS['wpdb']->get_col("SHOW FUNCTION STATUS WHERE `Db` = '{$GLOBALS['wpdb']->dbname}'", 1); + if (count($procedures) || count($functions)) { ?> +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + + + + + + +
                        + + + +  '; + esc_html_e('Migrate large, multi-gig sites with', 'duplicator'); + echo ' ' . esc_html__('Duplicator Pro', 'duplicator') . '!'; + echo '
                        '; + ?> +
                    +

                    + + + +height = 600; + $alert1->width = 600; + $alert1->title = __('Scan Details', 'duplicator'); + $alert1->message = "
                    "; + $alert1->initAlert(); + + $alert2 = new DUP_UI_Dialog(); + $alert2->height = 450; + $alert2->width = 650; + $alert2->title = __('Copy Quick Filter Paths', 'duplicator'); + $alert2->message = "
                    "; + $alert2->initAlert(); +?> + + + + + + + + + diff --git a/views/packages/main/s3.build.php b/views/packages/main/s3.build.php new file mode 100644 index 00000000..38722ca7 --- /dev/null +++ b/views/packages/main/s3.build.php @@ -0,0 +1,859 @@ + + + + + + + + + + +
                    +
                    +
                    + + + +
                    +
                    + + +
                    +
                    +
                    + + + + + + + + + +
                    +
                    + + +
                    + + + +
                    + +
                    +
                    0%
                    +
                    +

                    +
                    +
                    +
                    + +
                    + + +
                    + + + diff --git a/views/packages/new1.base.php b/views/packages/new1.base.php deleted file mode 100644 index 9d4d3c7e..00000000 --- a/views/packages/new1.base.php +++ /dev/null @@ -1,325 +0,0 @@ -MakeHash(); - -$dup_tests = array(); -$dup_tests = DUP_Server::GetRequirements(); -$default_name = DUP_Package::GetDefaultName(); - -$view_state = DUP_UI::GetViewStateArray(); -$ui_css_storage = (isset($view_state['dup-pack-storage-panel']) && $view_state['dup-pack-storage-panel']) ? 'display:block' : 'display:none'; -$ui_css_archive = (isset($view_state['dup-pack-archive-panel']) && $view_state['dup-pack-archive-panel']) ? 'display:block' : 'display:none'; -$ui_css_installer = (isset($view_state['dup-pack-installer-panel']) && $view_state['dup-pack-installer-panel']) ? 'display:block' : 'display:none'; -?> - - - - - - - - - -
                    -
                    -
                    - - - -
                    -
                    - -
                    -
                    -
                    -   - -
                    -
                    - - - - -

                    - - - -
                    -
                    - - Pass
                    ' : '
                    Fail
                    '; - ?> -
                    -
                    - -
                    - -
                    - -
                    - - -
                    -
                    - -
                    -
                    -
                    - - - - - - - - - - - - - - - - - - - - - - - - - -
                    file_get_contents
                    file_put_contents
                    mb_strlen
                    - - - -
                    -
                    - - -
                    -
                    -
                    -
                    -
                    - -
                    - %s   [%s]
                    ", $dup_tests['IO']['WPROOT'], DUPLICATOR_WPROOTPATH); - printf("%s   [%s]
                    ", $dup_tests['IO']['SSDIR'], DUPLICATOR_SSDIR_PATH); - printf("%s   [%s]
                    ", $dup_tests['IO']['SSTMP'], DUPLICATOR_SSDIR_PATH_TMP); - //printf("%s: [%s]
                    ", __('PHP Script Owner', 'wpduplicator'), DUP_Util::GetCurrentUser()); - //printf("%s: [%s]
                    ", __('PHP Process Owner', 'wpduplicator'), DUP_Util::GetProcessOwner()); - ?> -
                    - - - -
                    -
                    - - -
                    -
                    - -
                    -
                    -
                    - - - - - - - - - -
                    db_version()); ?>
                    - - [" . __('more info', 'wpduplicator') . "]"; - ?> - -
                    -
                    - - -
                    -
                    -
                    -
                    -
                    - - - -
                    - -
                    ' style='font-size:10px; margin-top:5px;' /> -
                    - -
                    -
                    - - -
                    - %s [%s]", __("For additional help please see the ", 'wpduplicator'), __("help page", 'wpduplicator')); - ?> -
                    - -
                    -

                    - - - -
                    - -
                    - - \ No newline at end of file diff --git a/views/packages/new1.inc.form.php b/views/packages/new1.inc.form.php deleted file mode 100644 index 1d77ecb7..00000000 --- a/views/packages/new1.inc.form.php +++ /dev/null @@ -1,292 +0,0 @@ - -
                    - - -
                    - -
                    - -
                    -
                    -
                    -
                    -
                    - -
                    -
                    -
                    - - -
                    -
                    -   -
                    -
                    - -
                    - - - - - - - - - - - - - - - - - - -
                     
                    - -

                    - - - - Duplicator Pro - -

                    -
                    -
                    -

                    - - - -
                    -
                    -   - -    - - -
                    -
                    -
                    - - -
                    -
                      -
                    • -
                    • -
                    - - -
                    - - -
                    - Archive->FilterOn) ? "checked='checked'" : ""; ?> /> - -
                    - -
                    - - -
                    - - - - -
                    -
                    - -
                    -
                    -
                    - - - -
                    -
                    -

                    - - - - -
                    -
                    - -
                    -
                    - -
                    -

                    - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    - - - - - - - - - - - -
                    - Installer->OptsSSLAdmin) ? "checked='checked'" : ""; ?> /> - - - Installer->OptsSSLLogin) ? "checked='checked'" : ""; ?> /> - -
                    - Installer->OptsCacheWP) ? "checked='checked'" : ""; ?> /> - - - Installer->OptsCachePath) ? "checked='checked'" : ""; ?> /> - -
                    -

                    - -
                    - - - - - - -
                    - -
                    - -
                    - -
                    -

                    - - - - - -
                    - - diff --git a/views/packages/new2.base.php b/views/packages/new2.base.php deleted file mode 100644 index 19d9b7b9..00000000 --- a/views/packages/new2.base.php +++ /dev/null @@ -1,617 +0,0 @@ -SaveActive($_POST); - $Package = DUP_Package::GetActive(); - - $package_mysqldump = DUP_Settings::Get('package_mysqldump'); - $mysqlDumpPath = DUP_Database::GetMySqlDumpPath(); - $build_mode = ($mysqlDumpPath && $package_mysqldump) ? 'mysqldump (fast)' : 'PHP (slow)'; - - $zip_check = DUP_Util::GetZipPath(); -?> - - - - - - - - - -
                    -
                    -
                    - - - -
                    -
                    - -
                    -
                    -
                    -   - -
                    -
                    - - -
                    -
                    - -
                    -

                    -
                    - -
                    - - - - - - - - -
                    - - -
                    - - \ No newline at end of file diff --git a/views/packages/new3.base.php b/views/packages/new3.base.php deleted file mode 100644 index 7337af4f..00000000 --- a/views/packages/new3.base.php +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - - -
                    -
                    -
                    - - - -
                    -
                    - -
                    -
                    -
                    -   - -
                    -
                    - - -
                    - - -
                    -

                    -
                    -

                    -
                    -
                    -
                    - - -
                    - - \ No newline at end of file diff --git a/views/packages/screen.php b/views/packages/screen.php new file mode 100644 index 00000000..979038f6 --- /dev/null +++ b/views/packages/screen.php @@ -0,0 +1,154 @@ +screen = get_current_screen(); + + switch (strtoupper($active_tab)) { + case 'LIST': + $content = $this->get_list_help(); + break; + case 'NEW1': + $content = $this->get_step1_help(); + break; + case 'NEW2': + $content = $this->get_step2_help(); + break; + case 'NEW3': + $content = $this->get_step3_help(); + break; + case 'DETAIL': + $content = $this->get_details_help(); + break; + default: + $content = $this->get_list_help(); + break; + } + + $guide = '#guide-packs'; + $faq = '#faq-package'; + $content .= "References:
                    " + . "User Guide | " + . "FAQs | " + . "Quick Start"; + + $this->screen->add_help_tab(array( + 'id' => 'dup_help_package_overview', + 'title' => esc_html__('Overview', 'duplicator'), + 'content' => "

                    {$content}

                    " + )); + + $this->getSupportTab($guide, $faq); + $this->getHelpSidbar(); + } + + public function get_list_help() + { + return __( + " Packages » All
                    The 'Packages' section is the main interface for managing all the packages that have been created. " + . "A Package consists of two core files, the 'archive.zip' and the 'installer.php' file. The archive file is a zip file containing all your WordPress files and a " + . "copy of your WordPress database. The installer file is a php file that when browsed to via a web browser presents a wizard that redeploys/installs the website " + . "by extracting the archive file and installing the database. To create a package, click the 'Create New' button and follow the prompts.

                    " + + . " Downloads
                    " + . "To download the package files click on the Installer and Archive buttons after creating a package. The archive file will have a copy of the installer inside of it named " + . "installer-backup.php in case the original installer file is lost. To see the details of a package click on the details button.

                    " + + . " Archive Types
                    " + . "An archive file can be saved as either a .zip file or .daf file. A zip file is a common archive format used to compress and group files. The daf file short for " + . "'Duplicator Archive Format' is a custom format used specifically for working with larger packages and scale-ability issues on many shared hosting platforms. Both " + . "formats work very similar. The main difference is that the daf file can only be extracted using the installer.php file or the " + . "DAF extraction tool. The zip file can be used by the installer.php " + . "or other zip tools like winrar/7-Zip/winzip or other client-side tools.

                    ", + 'duplicator' + ); + } + + + public function get_step1_help() + { + return __("Packages New » 1 Setup
                    " + . "The setup step allows for optional filtered directory paths, files, file extensions and database tables. To filter specific system files, click the 'Enable File Filters' " + . "checkbox and add the full path of the file or directory, followed by a semicolon. For a file extension add the name (i.e. 'zip') followed by a semicolon.

                    " + + . "To exclude a database table, check the box labeled 'Enable Table Filters' and check the table name to exclude. To include only a copy of your database in the " + . "archive file check the box labeled 'Archive Only the Database'. The installer.php file can optionally be pre-filled with data at install time but is not " + . "required.

                    ", 'duplicator'); + } + + + public function get_step2_help() + { + $status1 = sprintf('%1$s Good %2$s', '', ''); + $status2 = sprintf('%1$s Notice %2$s', '', ''); + + //TITLE + $msg = sprintf('%1$s Packages » 2 Scan %2$s', '', '
                    '); + + //MESSAGE + $msg .= sprintf( + 'In Step-2 of the build process Duplicator scans your WordPress site files and database for any possible issues. Each section is expandable ' + . 'and will show more details regarding the parameters of that section. The following indicators will be present for each section: %3$s' + . '%1$s Indicates that no issues were detected. It is best to try and get all the values to display this status if possible, but not required. %3$s' + . '%2$s Indicates a possible issue. A notice will not prevent the build from running however, if you do have issues then the section should be observed. %4$s', + $status1, + $status2, + '
                    ', + '

                    ' + ); + return $msg; + } + + public function get_step3_help() + { + return __("Packages » 3 Build
                    " + . "The final step in the build process where the installer script and archive of the website can be downloaded. To start the install process follow these steps: " + . "
                      " + . "
                    1. Download the installer.php and archive.zip files to your local computer.
                    2. " + . "
                    3. For localhost installs be sure you have PHP, Apache & MySQL installed on your local computer with software such as XAMPP, Instant WordPress or MAMP for MAC. " + . "Place the package.zip and installer.php into any empty directory under your webroot then browse to the installer.php via your web browser to launch the install wizard.
                    4. " + . "
                    5. For remote installs use FTP or cPanel to upload both the archive.zip and installer.php to your hosting provider. Place the files in a new empty directory under " + . "your host's webroot accessible from a valid URL such as http://your-domain/your-wp-directory/installer.php to launch the install wizard. On some hosts the root directory " + . "will be a something like public_html -or- www. If your're not sure contact your hosting provider.
                    6. " + . "
                    " + . "For complete instructions see:
                    " + . "How do I install this Package?

                    ", 'duplicator'); + } + + public function get_details_help() + { + return __("Packages » Details
                    " + . "The details view will give you a full break-down of the package including any errors that may have occured during the install.

                    ", 'duplicator'); + } +} diff --git a/views/parts/migration-almost-complete.php b/views/parts/migration-almost-complete.php new file mode 100644 index 00000000..a947eca6 --- /dev/null +++ b/views/parts/migration-almost-complete.php @@ -0,0 +1,53 @@ + +
                    +

                    + +

                    +

                    + +
                    + General > Information > Stored Data > and click the "Remove Installation Files" button', 'duplicator'); ?>
                    + + + +

                    + 0) { ?> +
                    + +
                    + +

                    + + +

                    + + +
                    \ No newline at end of file diff --git a/views/parts/migration-clean-installation-files.php b/views/parts/migration-clean-installation-files.php new file mode 100644 index 00000000..454d6123 --- /dev/null +++ b/views/parts/migration-clean-installation-files.php @@ -0,0 +1,95 @@ + +
                    +

                    + +

                    + +

                    + +

                    $success) { + if ($success) { + ?>
                    + - +
                    + - +
                    + +
                    + +

                    + + + +
                    + +

                    + +
                    +

                    + : +
                    + tags', + 'duplicator' + ), + '', + '' + ); + ?> +

                    +

                    + : + '; + _e( + 'Show your support with a ' + . '5 star review! We would be thrilled if you could!', + 'duplicator' + ); + ?> +

                    +
                    +
                    diff --git a/views/parts/migration-message.php b/views/parts/migration-message.php new file mode 100644 index 00000000..6ec77925 --- /dev/null +++ b/views/parts/migration-message.php @@ -0,0 +1,85 @@ + +
                    +
                    + +
                    +

                    + %s', 'duplicator'), DUP_Settings::getSsdirPath()); ?> +

                    +
                      + $label) { ?> +
                    • + - +
                    • + +
                    + + 0) { ?> +

                    + +

                    +
                      + +
                    • + +
                    • + +
                    + +

                    +
                    + + + +

                    + 0) { ?> +
                    + +
                    + + +

                    +
                    + + +
                    +

                    + +
                    diff --git a/views/settings/about-info.php b/views/settings/about-info.php new file mode 100644 index 00000000..b2cc76ce --- /dev/null +++ b/views/settings/about-info.php @@ -0,0 +1,125 @@ + + + + +
                    +
                    + + + + + +
                    + " style='margin-top:-60px; height:176px; width:176px' /> + + +

                    + + + + + +
                    + + + + +
                    + +
                    +
                    +
                    + +
                    +
                    +

                    +
                    + +
                    +




                    + diff --git a/views/settings/controller.php b/views/settings/controller.php index 4a1f1103..64a710a4 100644 --- a/views/settings/controller.php +++ b/views/settings/controller.php @@ -1,31 +1,80 @@ - - - - -
                    - - - - - - -
                    + + +
                    + + + + + render("admin_pages/settings/general/general"); + break; + case 'package': + include(DUPLICATOR_PLUGIN_PATH . "views/settings/packages.php"); + break; + case 'storage': + include(DUPLICATOR_PLUGIN_PATH . "views/settings/storage.php"); + break; + case 'access': + Bootstrap::mocksStyles(); + TplMng::getInstance()->render("mocks/settings/access/capabilities"); + break; + case 'license': + include(DUPLICATOR_PLUGIN_PATH . "views/settings/license.php"); + break; + } + do_action('duplicator_settings_page_footer'); + ?> +
                    diff --git a/views/settings/general.php b/views/settings/general.php deleted file mode 100644 index 93876736..00000000 --- a/views/settings/general.php +++ /dev/null @@ -1,237 +0,0 @@ - - - - -
                    - - - - - - -

                    - - - - -

                    -
                    - - - - - - - - - - - - - -
                    - /> -
                    - - /> -
                    - -
                    - : -

                    - /> - -

                    - -

                    -
                    - - - -

                    -
                    - - - - - - - - - - - - - - -
                    - /> - - () -

                    - -

                    -
                    - /> -   - -
                    -   - - () - -

                    - - -

                    - '; - _e("Please contact the server administrator to enable this feature.", 'wpduplicator'); - ?> -

                    - - /> -   - ()

                    - -
                    - -
                    -   - -

                    - -
                    - -

                    - - -
                    - -

                    - -

                    -
                    - - -
                    - /> - -
                    - - -

                    -
                    - - - - - - - -
                    - /> - - -
                    -

                    - %s %s' - . ' %s %s ' - . ' %s', - __('The User Role Editor Plugin', 'wpduplicator'), - __('Free', 'wpduplicator'), - __('or', 'wpduplicator'), - __('Professional', 'wpduplicator'), - __('must be installed to use', 'wpduplicator'), - __('this feature.', 'wpduplicator') - ); - ?> -

                    -
                    -

                    - -

                    -
                    - " style="display: inline-block;" /> -

                    - -
                    \ No newline at end of file diff --git a/views/settings/index.php b/views/settings/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/views/settings/index.php @@ -0,0 +1,3 @@ + +

                    +
                    + + + + + + + + + + + + + +
                    + ', + '' + ); + ?> +
                    + +
                    +
                    + + + +
                    +
                    +
                    +
                    +

                    🙂

                    +

                    + upgrading to PRO.', 'duplicator'), + array( + 'a' => array( + 'href' => array(), + 'class' => array(), + 'target' => array(), + 'rel' => array(), + ), + 'strong' => array(), + ) + ), + esc_url(Upsell::getCampaignUrl('license-tab', 'upgrading to PRO')) + ); ?> +

                    +

                    + %1$d%% off, automatically applied at checkout!', + 'duplicator' + ), + DUP_Constants::UPSELL_DEFAULT_DISCOUNT + ); + ?> +

                    +
                    +

                    + Duplicator PRO!', 'duplicator'); ?>

                    +

                    + + +

                    +
                    +
                    + + +
                    + + + + + + + + +
                    + diff --git a/views/settings/packages.php b/views/settings/packages.php new file mode 100644 index 00000000..66968007 --- /dev/null +++ b/views/settings/packages.php @@ -0,0 +1,477 @@ + + + + +
                    + + + + + +

                    + + + +

                    +
                    + + + + + +
                    +
                    + /> + +
                    + +
                    + + + + + /> + + +
                    + +

                    + + + + + + +
                    + + +

                    +
                    + + + + + + + + + +
                    +
                    + /> + +
                    + +
                    + /> +     +
                    + +
                    + + + + + + +
                    + /> + + () +

                    + +

                    +

                    + +

                    +
                    + + + + + +
                    +
                    + +
                    + +

                    + + . +

                    +
                    +

                    +
                    + : my-name_64fc6df76c17f2023225_20220815053010_installer.php +

                    +

                    + +

                    +

                    + +

                    +

                    + + + + +

                    +
                    +
                    + +

                    +
                    + + + + + +
                    + +

                    +
                    + +

                    +

                    + + +

                    +
                    + " style="display: inline-block;" /> +

                    +
                    + + diff --git a/views/settings/storage.php b/views/settings/storage.php new file mode 100644 index 00000000..1064f3e8 --- /dev/null +++ b/views/settings/storage.php @@ -0,0 +1,134 @@ + + + +
                    + +
                    +

                    + +

                    +

                    + %s', 'duplicator'), esc_html($targetFolder)); ?>
                    + %s )', 'duplicator'), esc_html(dirname($targetFolder))); ?> +

                    +
                    + + + +
                    + + + + + +

                    + + + + + + + + + + + +
                    +

                    + +

                    +

                    + +

                    +

                    +
                    + +   + [] +

                    +
                    + /> + +

                    + +

                    +
                    +

                    +
                    + " style="display: inline-block;" /> +

                    +
                    +
                    +
                    + + + diff --git a/views/tools/cleanup.php b/views/tools/cleanup.php deleted file mode 100644 index 561aae7a..00000000 --- a/views/tools/cleanup.php +++ /dev/null @@ -1,148 +0,0 @@ - - - - - -
                    - - -
                    -

                    - - - Successfully removed {$installer_file}
                    " : "
                    Does not exist or unable to remove file: {$installer_file}
                    "; - $html .= (@unlink($installer_bak)) ? "
                    Successfully removed {$installer_bak}
                    " : "
                    Does not exist or unable to remove file: {$installer_bak}
                    "; - $html .= (@unlink($installer_sql)) ? "
                    Successfully removed {$installer_sql}
                    " : "
                    Does not exist or unable to remove file: {$installer_sql}
                    "; - $html .= (@unlink($installer_log)) ? "
                    Successfully removed {$installer_log}
                    " : "
                    Does not exist or unable to remove file: {$installer_log}
                    "; - - //No way to know exact name of archive file except from installer. - //The only place where the package can be remove is from installer - //So just show a message if removing from plugin. - if (! empty($package_name) ){ - $path_parts = pathinfo($package_name); - $path_parts = (isset($path_parts['extension'])) ? $path_parts['extension'] : ''; - if ($path_parts == "zip" && ! is_dir($package_name)) { - $html .= (@unlink($package_name)) - ? "
                    Successfully removed {$package_name}
                    " - : "
                    Does not exist or unable to remove archive file.
                    "; - } else { - $html .= "
                    Does not exist or unable to remove archive file. Please validate that an archive file exists.
                    "; - } - } else { - $html .= '
                    It is recommended to remove your archive file from the root of your WordPress install. This will need to be done manually.
                    '; - } - - echo $html; - ?> - -
                    - .
                    - .

                    -
                    - - -
                    - - - -


                    - - - - - - - - - - - - - -
                    [].
                    [].
                    - - - - - - diff --git a/views/tools/controller.php b/views/tools/controller.php index d89329a1..fcb306df 100644 --- a/views/tools/controller.php +++ b/views/tools/controller.php @@ -1,31 +1,43 @@ - -
                    - - - - - -
                    + + +
                    + + + + + render('mocks/templates/templates', array(), true); + break; + case 'recovery': + TplMng::getInstance()->render('mocks/recovery/recovery', array(), true); + break; + } + ?> +
                    diff --git a/views/tools/diagnostics.php b/views/tools/diagnostics.php deleted file mode 100644 index 670cc78c..00000000 --- a/views/tools/diagnostics.php +++ /dev/null @@ -1,313 +0,0 @@ -(.*).*$%ms', '$1', $serverinfo); - $serverinfo = preg_replace( '%^.*(.*).*$%ms','$1', $serverinfo); - $action_response = null; - $dbvar_maxtime = DUP_Util::MysqlVariableValue('wait_timeout'); - $dbvar_maxpacks = DUP_Util::MysqlVariableValue('max_allowed_packet'); - $dbvar_maxtime = is_null($dbvar_maxtime) ? __("unknow", 'wpduplicator') : $dbvar_maxtime; - $dbvar_maxpacks = is_null($dbvar_maxpacks) ? __("unknow", 'wpduplicator') : $dbvar_maxpacks; - - $space = @disk_total_space(DUPLICATOR_WPROOTPATH); - $space_free = @disk_free_space(DUPLICATOR_WPROOTPATH); - $perc = @round((100/$space)*$space_free,2); - $mysqldumpPath = DUP_Database::GetMySqlDumpPath(); - $mysqlDumpSupport = ($mysqldumpPath) ? $mysqldumpPath : 'Path Not Found'; - - $view_state = DUP_UI::GetViewStateArray(); - $ui_css_srv_panel = (isset($view_state['dup-settings-diag-srv-panel']) && $view_state['dup-settings-diag-srv-panel']) ? 'display:block' : 'display:none'; - $ui_css_opts_panel = (isset($view_state['dup-settings-diag-opts-panel']) && $view_state['dup-settings-diag-opts-panel']) ? 'display:block' : 'display:none'; - - - $client_ip_address = DUP_Server::GetClientIP(); - - //POST BACK - $action_updated = null; - if (isset($_POST['action'])) { - $action_result = DUP_Settings::DeleteWPOption($_POST['action']); - switch ($_POST['action']) { - case 'duplicator_settings' : $action_response = __('Plugin settings reset.', 'wpduplicator'); break; - case 'duplicator_ui_view_state' : $action_response = __('View state settings reset.', 'wpduplicator'); break; - case 'duplicator_package_active' : $action_response = __('Active package settings reset.', 'wpduplicator'); break; - case 'clear_legacy_data': - DUP_Settings::LegacyClean(); - $action_response = __('Legacy data removed.', 'wpduplicator'); - break; - } - } -?> - - - -
                    - - -
                    - - -

                    - - - -
                    -
                    - - -
                    -
                    -
                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      This is a WordPress setting
                    WordPress
                    ()
                    PHP
                    SAPI
                    - -
                    MySQL
                    db_version() ?>
                    % -- from
                    - -
                    - -
                    -

                    - -
                    -
                    -
                    - - -
                    -
                    - - -
                    -
                    -
                    -
                    -

                    - - - - - - - prefix}options` WHERE `option_name` LIKE '%duplicator_%' ORDER BY option_name"; - foreach( $wpdb->get_results("{$sql}") as $key => $row) { ?> - - - - - -
                    KeyValue
                    - option_name, $GLOBALS['DUPLICATOR_OPTS_DELETE'])) - ? "{$row->option_name}" - : $row->option_name; - ?> -
                    -
                    - -
                    -
                    -
                    - - -
                    -
                    - - -
                    -
                    -
                    - -
                    -
                    - - - - - diff --git a/views/tools/diagnostics/inc.data.php b/views/tools/diagnostics/inc.data.php new file mode 100644 index 00000000..904ca37a --- /dev/null +++ b/views/tools/diagnostics/inc.data.php @@ -0,0 +1,137 @@ +prefix}options` WHERE `option_name` LIKE '%duplicator_%' AND `option_name` NOT LIKE '%duplicator_pro%' ORDER BY option_name"; +?> + + +
                    +
                    + + +
                    +
                    +
                    +
                    +

                    + + + + + + + + + +
                    + + + + []
                    + +
                    +
                    "; + + $installer_files = array_keys($installer_files); + array_push($installer_files, '[HASH]_archive.zip/daf'); + echo '' . implode('
                    ', $installer_files) . '
                    '; + echo "

                    "; + ?> +
                    +
                    + + [].
                    +
                    +
                    +

                    + + + + + + + + + get_results("{$sql}") as $key => $row) { ?> + + + + + + +
                    KeyValue
                    + option_name, $GLOBALS['DUPLICATOR_OPTS_DELETE'])) + ? "" . esc_html($row->option_name) . "" + : $row->option_name; + ?> +
                    +
                    + +
                    +
                    +
                    + + +title = __('Delete Option?', 'duplicator'); + $confirm1->message = __('Delete the option value just selected?', 'duplicator'); + $confirm1->progressText = __('Removing Option, Please Wait...', 'duplicator'); + $confirm1->jscallback = 'Duplicator.Settings.DeleteOption()'; + $confirm1->initConfirm(); + + $confirm2 = new DUP_UI_Dialog(); + $confirm2->title = __('Clear Build Cache?', 'duplicator'); + $confirm2->message = __('This process will remove all build cache files. Be sure no packages are currently building or else they will be cancelled.', 'duplicator'); + $confirm2->jscallback = 'Duplicator.Tools.ClearBuildCache()'; + $confirm2->initConfirm(); +?> + + diff --git a/views/tools/diagnostics/inc.phpinfo.php b/views/tools/diagnostics/inc.phpinfo.php new file mode 100644 index 00000000..76dafe77 --- /dev/null +++ b/views/tools/diagnostics/inc.phpinfo.php @@ -0,0 +1,38 @@ +phpinfo function is not supported on this server, ' + . 'for more details contact your hosting provider.'; +} else { + $serverinfo = preg_replace('%^.*(.*).*$%ms', '$1', $serverinfo); + $serverinfo = preg_replace('%^.*(.*).*$%ms', '$1', $serverinfo); +} +?> + + +
                    +
                    + + +
                    +
                    +
                    +
                    +
                    +
                    diff --git a/views/tools/diagnostics/inc.settings.php b/views/tools/diagnostics/inc.settings.php new file mode 100644 index 00000000..d918785a --- /dev/null +++ b/views/tools/diagnostics/inc.settings.php @@ -0,0 +1,241 @@ + + + +
                    +
                    + + +
                    +
                    +
                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    + +
                      This is a WordPress setting
                    WordPress
                    ()
                    PHP
                    SAPI
                    + +
                    + + " + data-tooltip=""> +
                    + +
                    MySQL
                    + + +

                    + + % -- + from
                    + +
                    + +
                    + +

                    + +
                    +
                    +
                    diff --git a/views/tools/diagnostics/inc.validator.php b/views/tools/diagnostics/inc.validator.php new file mode 100644 index 00000000..3655807a --- /dev/null +++ b/views/tools/diagnostics/inc.validator.php @@ -0,0 +1,161 @@ + + + + + +title = __('Run Validator', 'duplicator'); + $confirm1->message = __('This will run the scan validation check. This may take several minutes. Do you want to Continue?', 'duplicator'); + $confirm1->progressOn = false; + $confirm1->jscallback = 'Duplicator.Tools.runScanValidator()'; + $confirm1->initConfirm(); +?> + + +
                    +
                    + + +
                    +
                    +
                    + +

                    + + + + + +
                    + +
                    +
                    +
                    + + + diff --git a/views/tools/diagnostics/information.php b/views/tools/diagnostics/information.php new file mode 100644 index 00000000..e4ad067f --- /dev/null +++ b/views/tools/diagnostics/information.php @@ -0,0 +1,82 @@ + +
                    +

                    +
                    + + + +
                    + + + +

                    " . esc_html($remove_response) . "

                    "; + } + + include_once 'inc.data.php'; + include_once 'inc.settings.php'; + include_once 'inc.validator.php'; + include_once 'inc.phpinfo.php'; + ?> + diff --git a/views/tools/diagnostics/logging.php b/views/tools/diagnostics/logging.php new file mode 100644 index 00000000..46a62e79 --- /dev/null +++ b/views/tools/diagnostics/logging.php @@ -0,0 +1,241 @@ + 0) { + unset($logname); + } + unset($validFiles); +} + +if (!isset($logname) || !$logname) { + $logname = (count($logs) > 0) ? basename($logs[0]) : ""; +} + +$logurl = DUP_Settings::getSsdirUrl() . '/' . $logname; +$logfound = (strlen($logname) > 0) ? true : false; +?> + + + + + +
                    + + + + +
                    +

                    .

                    + .

                    + :
                    + - .
                    + - .
                    + - .
                    +
                    + + + + + + +
                    +
                    +   |   + " + data-tooltip=""> + + tags', + 'duplicator' + ), + '', + '' + ); + ?> + +
                    +
                     
                    +
                    +
                    
                    +            
                    +

                    +
                    + " />   + + +
                    + +
                    + + +
                    + +
                    + " . esc_html($time) . "-" . esc_html($name) . "" + : "" . esc_html($time) . "-" . esc_html($name) . ""; + if ($count > 20) { + break; + } + } + ?> +
                    +
                    + +
                    diff --git a/views/tools/diagnostics/main.php b/views/tools/diagnostics/main.php new file mode 100644 index 00000000..a959ae21 --- /dev/null +++ b/views/tools/diagnostics/main.php @@ -0,0 +1,80 @@ + + + + +setResponseType('PHP'); +$data = $ctrl_ui->GetViewStateList(); + +$ui_css_srv_panel = (isset($data->payload['dup-settings-diag-srv-panel']) && $data->payload['dup-settings-diag-srv-panel']) ? 'display:block' : 'display:none'; +$ui_css_opts_panel = (isset($data->payload['dup-settings-diag-opts-panel']) && $data->payload['dup-settings-diag-opts-panel']) ? 'display:block' : 'display:none'; + +$section = isset($_GET['section']) ? $_GET['section'] : 'info'; +$txt_diagnostic = __('Information', 'duplicator'); +$txt_log = __('Logs', 'duplicator'); +$txt_support = __('Support', 'duplicator'); +; +$tools_url = 'admin.php?page=duplicator-tools&tab=diagnostics'; + +switch ($section) { + case 'info': + echo "
                    " . + esc_html($txt_diagnostic) . + "  |  " . + esc_html($txt_log) . "  |  " . + esc_html($txt_support) . "
                    "; + include(dirname(__FILE__) . '/information.php'); + break; + + case 'log': + echo ""; + include(dirname(__FILE__) . '/logging.php'); + break; + + case 'support': + echo "
                    " . + esc_html($txt_diagnostic) . "  |  " . + esc_html($txt_log) . "  |  " . + esc_html($txt_support) . "
                    "; + include(dirname(__FILE__) . '/support.php'); + break; +} +?> diff --git a/views/tools/diagnostics/support.php b/views/tools/diagnostics/support.php new file mode 100644 index 00000000..867a998a --- /dev/null +++ b/views/tools/diagnostics/support.php @@ -0,0 +1,108 @@ + + + + +
                    + +
                    + + + + + +
                    + +
                    +

                    + + +
                    +
                    + +
                    +
                    +
                    + +
                    + +
                    +
                    + + +
                    +
                    + +
                    +
                    +
                    + +
                    + + Free Users Support Forum +
                    +
                    +
                    +
                    + diff --git a/views/tools/index.php b/views/tools/index.php new file mode 100644 index 00000000..c9199655 --- /dev/null +++ b/views/tools/index.php @@ -0,0 +1,3 @@ + 0) { - unset($logname); - } - unset($validFiles); - } - - if (!isset($logname) || !$logname) { - $logname = (count($logs) > 0) ? basename($logs[0]) : ""; - } - - $logurl = get_site_url(null, '', is_ssl() ? 'https' : 'http') . '/' . DUPLICATOR_SSDIR_NAME . '/' . $logname; - $logfound = (strlen($logname) > 0) ? true :false; - -?> - - - - - -
                    - - - -
                    -

                    .

                    - - .

                    - - :
                    - - .
                    - - .
                    - - .
                    -
                    - - - - - - - - -
                    -
                    -
                     
                    -
                    - -
                    -

                    -
                    - " />   -
                    - - -
                    -
                    - -
                    - -
                    - {$time} - {$name}
                    " - : "{$time} - {$name}
                    "; - if ($count > 20) break; - } - ?> -
                    -
                    - - -
                    - \ No newline at end of file