diff --git a/applications/spring-shell/src/test/java/org/springframework/sbm/BootUpgrade_27_30_MultiModule_IntegrationTest.java b/applications/spring-shell/src/test/java/org/springframework/sbm/BootUpgrade_27_30_MultiModule_IntegrationTest.java index 204f8c62d..980fa1537 100644 --- a/applications/spring-shell/src/test/java/org/springframework/sbm/BootUpgrade_27_30_MultiModule_IntegrationTest.java +++ b/applications/spring-shell/src/test/java/org/springframework/sbm/BootUpgrade_27_30_MultiModule_IntegrationTest.java @@ -153,7 +153,8 @@ private void verifyPropertyConfigurationUpdate() { "spring.datasource.driverClassName=org.h2.Driver\n" + "spring.datasource.username=sa\n" + "spring.datasource.password=password\n" + - "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect\n"); + "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect\n" + + "logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS\n"); } private void verifyEhCacheVersionIsUpgraded() { diff --git a/ci/images/ci-image/Dockerfile b/ci/images/ci-image/Dockerfile index ef560c712..852b4fa1c 100644 --- a/ci/images/ci-image/Dockerfile +++ b/ci/images/ci-image/Dockerfile @@ -15,6 +15,7 @@ ENV JAVA_HOME /opt/openjdk ENV PATH $PATH:$JAVA_HOME/bin ENV MAVEN_HOME /usr/share/maven ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2" +ENV JAVA_TOOL_OPTIONS "-Dfile.encoding=\"UTF-8\"" ADD docker-lib.sh /docker-lib.sh diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/engine/git/GitSupport.java b/components/sbm-core/src/main/java/org/springframework/sbm/engine/git/GitSupport.java index 3f3c92d14..440fb8231 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/engine/git/GitSupport.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/engine/git/GitSupport.java @@ -59,9 +59,8 @@ public static Optional findRepository(File repo) { Optional repository = Optional.empty(); try { repository = Optional.of(new FileRepositoryBuilder().findGitDir(repo).setMustExist(true).build()); - } catch (IllegalArgumentException | IOException e) { - log.error("Could not find .git in the given directory '{}' or any of it's parents", repo, e); + log.debug("Could not find .git in the given directory '{}' or any of it's parents", repo, e); } return repository; } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/properties/api/PropertiesSource.java b/components/sbm-core/src/main/java/org/springframework/sbm/properties/api/PropertiesSource.java index a3d76cc05..c11cb1d37 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/properties/api/PropertiesSource.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/properties/api/PropertiesSource.java @@ -28,10 +28,14 @@ import org.openrewrite.properties.tree.Properties.Entry; import org.openrewrite.properties.tree.Properties.File; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; // TODO: fcoi RewriteSourceFileHolder as member ?! @Slf4j @@ -79,6 +83,17 @@ public Optional getProperty(String key) { } + public java.util.Properties getProperties() { + String collect = getSourceFile().printAll(); + try { + java.util.Properties properties = new java.util.Properties(collect.length()); + properties.load(new ByteArrayInputStream(collect.getBytes(StandardCharsets.UTF_8))); + return properties; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + private void apply(Recipe r) { File rewriteResource = getSourceFile(); List results = r.run(List.of(rewriteResource), executionContext).getResults(); diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/engine/git/GitSupportTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/engine/git/GitSupportTest.java index 47a02f44d..9fa6589bf 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/engine/git/GitSupportTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/engine/git/GitSupportTest.java @@ -53,7 +53,7 @@ void findRepository_withoutGit_shouldLogErrorAndReturnEmpty(@TempDir Path tmpDir Optional repository = GitSupport.findRepository(tmpDir.toFile()); assertThat(repository).isEmpty(); - assertThat(sysOutBuffer.toString()).matches("[\\d\\: \\. ]*\\[main\\] ERROR o\\.s\\.sbm\\.engine\\.git\\.GitSupport - Could not find \\.git in the given directory '"+tmpDir.toString().replace("/", "\\/")+"' or any of it's parents(?s).*"); + assertThat(sysOutBuffer.toString()).matches("[\\d\\: \\. ]*\\[main\\] DEBUG o\\.s\\.sbm\\.engine\\.git\\.GitSupport - Could not find \\.git in the given directory '"+tmpDir.toString().replace("/", "\\/")+"' or any of it's parents(?s).*"); System.setOut(realSysOut); } diff --git a/components/sbm-recipes-boot-upgrade/css/asciidoctor.css b/components/sbm-recipes-boot-upgrade/css/asciidoctor.css new file mode 100644 index 000000000..9021c39f5 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/asciidoctor.css @@ -0,0 +1,956 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +/* Asciidoctor styling based on https://gitlab.com/antora/antora-ui-default/-/blob/8751b86b76d6779fbbcf0fccd58fafcf73c49260/src/css/doc.css */ + +/* Container element styling */ + +.doc { + color: var(--asciidoctor-font-color); + hyphens: none; + line-height: 1.6; + letter-spacing: -0.0027777778rem; + margin: 0; +} + +/* Gutter and margins */ + +.doc #content, +.doc #footer { + margin: 0 2rem; +} + +.doc #header > *:not(#toc) { + /* Gutter is not applied directly to #header of toc positioning */ + margin-left: 2rem; + margin-right: 2rem; +} + +.doc #content { + padding-bottom: 4rem; +} + +/* Doc background embellishment */ + +#doc { + background: no-repeat top right / 305px 147px; + background-image: url("../img/doc-background.svg"); +} + +.doc #header { + margin-right: var(--asciidoctor-doc-embellishment-margin-width); +} + +/* Header Details */ + +.doc #header .details { + background: var(--asciidoctor-details-background); + color: var(--asciidoctor-details-font-color); + padding: 1rem 1.5rem; + font-weight: 600; + font-size: 0.8em; +} + +.doc #header div.details { + display: flex; + flex-wrap: wrap; +} + +#header .details br { + display: none; +} + +.doc #header .details span.author:not(:last-of-type)::after { + content: "\2022"; + font-weight: 400; + margin: 0.4em; + color: var(--asciidoctor-author-separator-color); +} + +.doc #header .details span.last-author::after { + display: none; +} + +.doc #header .details #revnumber { + flex-basis: 100%; + margin-top: 0.5rem; + text-transform: capitalize; + font-weight: 200; +} + +/* Section setup */ + +.doc #preamble + .sect1, +.doc .sect1 + .sect1 { + margin-top: 2rem; +} + +.doc .sect1 + .sect1 { + border-top: 1px solid var(--asciidoctor-section-divider-color); +} + +/* Headings */ + +.doc h1 { + font-size: 2.3em; +} + +.doc h2 { + font-size: 2em; +} + +.doc h3 { + font-size: 1.7em; +} + +.doc h4 { + font-size: 1.6em; +} + +.doc h5 { + font-size: 1.4em; +} + +.doc h6 { + font-size: 1.3em; +} + +.doc h1, +.doc h2, +.doc h3, +.doc h4, +.doc h5, +.doc h6 { + color: var(--asciidoctor-heading-font-color); + font-weight: var(--asciidoctor-heading-font-weight); + hyphens: none; + line-height: 1.3; + margin: 1.3rem 0 0; + padding-top: 1.8rem; +} + +.doc h1.sect0 { + background: var(--asciidoctor-abstract-background); + font-size: 1.8em; + margin: 1.5rem -1rem 0; + padding: 0.5rem 1rem; +} + +.doc h1:first-child { + margin: 1.3rem 0; +} + +.doc h2:not(.discrete) { + margin-left: -1rem; + margin-right: -1rem; + padding: 1.8rem 1rem 0.1rem; +} + +.doc h3:not(.discrete) { + font-weight: var(--asciidoctor-alt-heading-font-weight); +} + +/* Header hover anchors */ + +.doc h1 .anchor, +.doc h2 .anchor, +.doc h3 .anchor, +.doc h4 .anchor, +.doc h5 .anchor, +.doc h6 .anchor { + position: absolute; + text-decoration: none; + width: 2.25ex; + margin-left: -2ex; + padding-left: 0.5ex; + visibility: hidden; + font-weight: normal; +} + +.doc h1 .anchor::before, +.doc h2 .anchor::before, +.doc h3 .anchor::before, +.doc h4 .anchor::before, +.doc h5 .anchor::before, +.doc h6 .anchor::before { + content: "\0023"; +} + +.doc h1:hover .anchor, +.doc h2:hover .anchor, +.doc h3:hover .anchor, +.doc h4:hover .anchor, +.doc h5:hover .anchor, +.doc h6:hover .anchor { + visibility: visible; +} + +.doc p, +.doc dl { + margin: 0; +} + +/* General anchors */ + +.doc a.bare { + hyphens: none; +} + +.doc a { + color: var(--asciidoctor-link-font-color); +} + +.doc a:hover { + color: var(--asciidoctor-hover-link-font-color); +} + +.doc a.unresolved { + color: var(--asciidoctor-unresolved-link-font-color); +} + +/* Code and Pre */ + +.doc p code, +.doc thead code, +.doc .admonitionblock code { + color: var(--asciidoctor-code-font-color); + background: var(--asciidoctor-code-background); + border-radius: 0.25em; + font-size: 0.95em; + padding: 0.125em 0.25em; +} + +.doc p a code, +.doc thead a code, +.doc .admonitionblock a code { + color: var(--asciidoctor-code-link-font-color); +} + +.doc code, +.doc pre { + hyphens: none; +} + +.doc pre { + font-size: calc(14 / var(--pixel-to-rem)); + line-height: 1.3; + margin: 0; +} + +.doc pre.highlight code, +.doc .listingblock pre:not(.highlight), +.doc .literalblock pre { + background: var(--asciidoctor-pre-background); + box-shadow: inset 0 0 1.75px var(--asciidoctor-pre-border-color); + display: block; + overflow-x: auto; + padding: 0.95rem; + border-radius: 4px; +} + +.doc pre.highlight code[data-lang]:before { + content: attr(data-lang); + text-transform: uppercase; + display: block; + position: absolute; + top: 0.3rem; + right: 0.3rem; + line-height: 1; + font-size: 0.65em; + color: var(--asciidoctor-code-data-lang-color); +} + +.doc pre.highlight { + position: relative; +} + +.doc table pre.highlight code[data-lang]:before { + display: none; +} + +/* General margin and fonts sizing */ + +.doc blockquote { + margin: 0; +} + +.doc .paragraph.lead > p { + font-size: calc(18 / var(--pixel-to-rem)); +} + +.doc .paragraph, +.doc .dlist, +.doc .hdlist, +.doc .olist, +.doc .ulist, +.doc .exampleblock, +.doc .imageblock, +.doc .listingblock, +.doc .literalblock, +.doc .sidebarblock, +.doc .verseblock, +.doc .quoteblock, +.doc .partintro, +.doc details, +.doc hr { + margin: 1rem 0 0; +} + +/* Tables */ + +.doc table.tableblock { + display: block; + width: 100%; + overflow-x: auto; +} + +.doc table.tableblock td { + min-width: 6rem; +} + +.doc table.tableblock { + font-size: calc(15 / var(--pixel-to-rem)); + margin: 1.5rem 0 0; +} + +.doc table.tableblock + * { + margin-top: 2rem; +} + +.doc td.tableblock > .content > :first-child { + margin-top: 0; +} + +.doc table.tableblock th, +.doc table.tableblock td { + padding: 0.5rem; +} + +.doc table.tableblock thead th { + border-bottom: 2.5px solid var(--asciidoctor-table-border-color); +} + +.doc table.tableblock td, +.doc table.tableblock > :not(thead) th { + border-top: 1px solid var(--asciidoctor-table-border-color); + border-bottom: 1px solid var(--asciidoctor-table-border-color); +} + +.doc table.stripes-all > tbody > tr, +.doc table.stripes-odd > tbody > tr:nth-of-type(odd), +.doc table.stripes-even > tbody > tr:nth-of-type(even), +.doc table.stripes-hover > tbody > tr:hover { + background: var(--asciidoctor-table-stripe-background); +} + +.doc table.tableblock > tfoot { + background: var(--asciidoctor-table-footer-background); +} + +.doc .tableblock pre, +.doc .tableblock code, +.doc .listingblock.wrap pre { + white-space: pre-wrap; +} + +.doc td:nth-child(1) .tableblock pre, +.doc td:nth-child(1) .tableblock code, +.doc td:nth-child(1) .listingblock.wrap pre { + white-space: nowrap; +} + +/* Admonition blocks */ + +.doc .admonitionblock { + margin: 2.5rem 0; +} + +.doc .admonitionblock p, +.doc .admonitionblock td.content { + font-size: calc(16 / var(--pixel-to-rem)); +} + +.doc .admonitionblock td.content > :not(.title):first-child, +.doc .admonitionblock td.content > .title + * { + margin-top: 0; +} + +.doc .admonitionblock pre { + font-size: calc(14 / var(--pixel-to-rem)); + border: none; +} + +.doc .admonitionblock > table { + table-layout: fixed; + position: relative; + width: 100%; +} + +.doc .admonitionblock td.content { + padding: 1rem 1rem 0.75rem; + background: var(--asciidoctor-admonition-background); + width: 100%; + word-wrap: anywhere; +} + +.doc .admonitionblock td.icon { + position: absolute; + top: 0; + left: 0; + font-size: calc(16 / var(--pixel-to-rem)); + line-height: 1; + transform: translate(-0.5rem, -50%); + border-radius: 0.45rem; + padding: 0.25em 0.075em; +} + +.doc .admonitionblock .icon i { + display: inline-flex; + align-items: center; + width: auto; + height: 16px; + background-repeat: no-repeat; + background-position: 0.5em 0; + filter: invert(100%); + padding-left: 2em; + vertical-align: initial; +} + +.doc .admonitionblock .icon i::after { + border-left: 1px solid rgba(255, 255, 255, 0.3); + content: attr(title); + text-transform: capitalize; + filter: invert(100%); + font-weight: var(--asciidoctor-admonition-label-font-weight); + color: var(--asciidoctor-admonition-font-color); + font-style: normal; + hyphens: none; + padding: 0 0.5em; + margin: -0.05em; +} + +i.fa { + background-size: 16px 16px; +} + +i.fa.icon-caution { + background-image: url("../img/octicons-16.svg#view-flame"); +} + +i.fa.icon-important { + background-image: url("../img/octicons-16.svg#view-stop"); +} + +i.fa.icon-note { + background-image: url("../img/octicons-16.svg#view-info"); +} + +i.fa.icon-tip { + background-image: url("../img/octicons-16.svg#view-light-bulb"); +} + +i.fa.icon-warning { + background-image: url("../img/octicons-16.svg#view-alert"); +} + +.doc .admonitionblock.caution td.icon { + background: var(--asciidoctor-admonition-caution-background); +} + +.doc .admonitionblock.important td.icon { + background: var(--asciidoctor-admonition-important-background); +} + +.doc .admonitionblock.note .icon { + background: var(--asciidoctor-admonition-note-background); +} + +.doc .admonitionblock.tip .icon { + background: var(--asciidoctor-admonition-tip-background); +} + +.doc .admonitionblock.warning .icon { + background-color: var(--asciidoctor-admonition-warning-background); +} + +/* Images and image blocks */ + +.doc .imageblock { + display: flex; + flex-direction: column; + align-items: center; +} + +.doc .imageblock img, +.doc .image > img { + display: inline-block; + height: auto; + max-width: 100%; + vertical-align: middle; +} + +.doc .image:not(.left):not(.right) > img { + margin-top: -0.2em; +} + +/* Quote blocks */ + +.doc #preamble .abstract blockquote { + background: var(--asciidoctor-abstract-background); + border-left: 5px solid var(--asciidoctor-abstract-border-color); + font-size: calc(16 / var(--pixel-to-rem)); + padding: 0.75em 1em; +} + +.doc .quoteblock, +.doc .verseblock { + background: var(--asciidoctor-quote-background); + border-left: 5px solid var(--asciidoctor-quote-border-color); +} + +.doc .quoteblock { + padding: 0.25rem 2rem 1.25rem; +} + +.doc .quoteblock .attribution { + color: var(--asciidoctor-quote-attribution-font-color); + font-size: calc(15 / var(--pixel-to-rem)); + margin-top: 0.75rem; +} + +.doc .quoteblock blockquote { + margin-top: 1rem; +} + +.doc .quoteblock .paragraph { + font-style: italic; +} + +.doc .quoteblock cite { + padding-left: 1em; +} + +/* Verse blocks */ + +.doc .verseblock { + font-size: 1.15em; + padding: 1rem 2rem; +} + +.doc .verseblock pre { + font-family: inherit; + font-size: inherit; +} + +/* Lists */ + +.doc ol, +.doc ul { + margin: 0; + padding: 0 0 0 2rem; +} + +.doc ul.checklist, +.doc ul.none, +.doc ol.none, +.doc ul.no-bullet, +.doc ol.unnumbered, +.doc ul.unstyled, +.doc ol.unstyled { + list-style-type: none; +} + +.doc ul.no-bullet, +.doc ol.unnumbered { + padding-left: 1.25rem; +} + +.doc ul.unstyled, +.doc ol.unstyled { + padding-left: 0; +} + +.doc ul.circle { + list-style-type: square; +} + +.doc ul.disc { + list-style-type: square; +} + +.doc ul.square { + list-style-type: square; +} + +.doc ol.arabic { + list-style-type: decimal; +} + +.doc ol.decimal { + list-style-type: decimal-leading-zero; +} + +.doc ol.loweralpha { + list-style-type: lower-alpha; +} + +.doc ol.upperalpha { + list-style-type: upper-alpha; +} + +.doc ol.lowerroman { + list-style-type: lower-roman; +} + +.doc ol.upperroman { + list-style-type: upper-roman; +} + +.doc ol.lowergreek { + list-style-type: lower-greek; +} + +.doc ul.checklist { + padding-left: 0.5rem; +} + +.doc ul.checklist p > i.fa-check-square-o:first-child, +.doc ul.checklist p > i.fa-square-o:first-child { + display: inline-flex; + justify-content: center; + width: 1.25rem; +} + +.doc ul.checklist i.fa-check-square-o::before { + content: "\2713"; +} + +.doc ul.checklist i.fa-square-o::before { + content: "\274f"; +} + +.doc .dlist .dlist, +.doc .dlist .olist, +.doc .dlist .ulist, +.doc .olist .dlist, +.doc .olist .olist, +.doc .olist .ulist, +.doc .ulist .dlist, +.doc .ulist .olist, +.doc .ulist .ulist { + margin-top: 0.5rem; +} + +.doc .olist li, +.doc .ulist li { + margin-bottom: 0.3rem; +} + +.doc .ulist .listingblock, +.doc .olist .listingblock, +.doc .admonitionblock .listingblock { + padding: 0; +} + +/* Block Titles */ + +.doc .admonitionblock .title, +.doc .exampleblock .title, +.doc .imageblock .title, +.doc .literalblock .title, +.doc .listingblock .title, +.doc .openblock .title, +.doc .tableblock caption { + color: var(--asciidoctor-caption-font-color); + font-size: calc(14 / var(--pixel-to-rem)); + font-weight: var(--asciidoctor-caption-font-weight); + font-style: italic; + hyphens: none; + letter-spacing: 0.01em; + padding-bottom: 0.075rem; + text-align: left; +} + +.doc .imageblock .title { + margin-top: 0.5rem; + padding-bottom: 0; +} + +/* Block content */ + +.doc .exampleblock > .content { + background: var(--asciidoctor-example-background); + border: 1px solid var(--asciidoctor-example-border-color); + border-radius: 4px; + padding: 0.75rem; +} + +.doc .exampleblock > .content > :first-child { + margin-top: 0; +} + +/* Sidebars */ + +.doc .sidebarblock { + background: var(--asciidoctor-sidebar-background); + padding: 2.2rem 2.2rem; +} + +.doc .sidebarblock > .content > .title { + font-size: calc(23 / var(--pixel-to-rem)); + font-weight: var(--asciidoctor-alt-heading-font-weight); + line-height: 1.3; + margin-bottom: 1.2rem; +} + +.doc .sidebarblock > .content > :not(.title):first-child { + margin-top: 0; +} + +/* Buttons (https://docs.asciidoctor.org/asciidoc/latest/macros/ui-macros/#button-macro-syntax) */ + +.doc b.button { + white-space: nowrap; +} + +.doc b.button::before { + content: "["; + padding-right: 0.25em; +} + +.doc b.button::after { + content: "]"; + padding-left: 0.25em; +} + +/* Menu (https://docs.asciidoctor.org/asciidoc/latest/macros/ui-macros/#menu-macro-syntax) */ + +.doc .menuseq, +.doc .path { + hyphens: none; +} + +.doc .menuseq i.caret::before { + content: "\203a"; + font-size: 1.1em; + font-weight: var(--asciidoctor-body-font-weight-bold); + line-height: calc(1 / 1.1); +} + +/* Keyboard (https://docs.asciidoctor.org/asciidoc/latest/macros/keyboard-macro/) */ + +.doc kbd { + display: inline-block; + font-size: calc(12 / var(--pixel-to-rem)); + background: var(--asciidoctor-kbd-background); + border: 1px solid var(--asciidoctor-kbd-border-color); + border-radius: 0.25em; + box-shadow: 0 1px 0 var(--asciidoctor-kbd-border-color), + 0 0 0 0.1em var(--body-background) inset; + padding: 0.25em 0.5em; + vertical-align: text-bottom; + white-space: nowrap; +} + +.doc kbd, +.doc .keyseq { + line-height: 1; +} + +.doc .keyseq { + font-size: calc(16 / var(--pixel-to-rem)); +} + +.doc .keyseq kbd { + margin: 0 0.125em; +} + +.doc .keyseq kbd:first-child { + margin-left: 0; +} + +.doc .keyseq kbd:last-child { + margin-right: 0; +} + +/* Misc */ + +.doc i.fa { + hyphens: none; + font-style: normal; +} + +.doc .language-console .hljs-meta { + user-select: none; +} + +.doc .dlist dt { + font-style: italic; +} + +.doc .dlist dd { + margin: 0 0 0.25rem 1.5rem; +} + +.doc .dlist dd:last-of-type { + margin-bottom: 0; +} + +.doc td.hdlist1, +.doc td.hdlist2 { + padding: 0.5rem 0 0; + vertical-align: top; +} + +.doc tr:first-child > .hdlist1, +.doc tr:first-child > .hdlist2 { + padding-top: 0; +} + +.doc td.hdlist1 { + font-weight: var(--body-font-weight-bold); + padding-right: 0.25rem; +} + +.doc td.hdlist2 { + padding-left: 0.25rem; +} + +.doc .colist { + font-size: calc(16 / var(--pixel-to-rem)); + margin: 0.25rem 0 -0.25rem; +} + +.doc .colist > table > tr > :first-child, +.doc .colist > table > tbody > tr > :first-child { + padding: 0.25em 0.5rem 0; + vertical-align: top; +} + +.doc .colist > table > tr > :last-child, +.doc .colist > table > tbody > tr > :last-child { + padding: 0.25rem 0; +} + +.doc .conum[data-value] { + /* border: 1px solid currentColor; */ + font-family: var(--monospace-font-family); + border-radius: 100%; + display: inline-block; + font-size: calc(12.5 / var(--pixel-to-rem)); + font-style: normal; + line-height: 1.2; + text-align: center; + width: 1.25em; + height: 1.25em; + letter-spacing: -0.25ex; + text-indent: -0.25ex; + background: var(--asciidoctor-callout-background); + color: var(--asciidoctor-callout-font-color); +} + +.doc .conum[data-value]::after { + content: attr(data-value); +} + +.doc .conum[data-value] + b { + display: none; +} + +.doc hr { + border: solid var(--asciidoctor-section-divider-color); + border-width: 2px 0 0; + height: 0; +} + +/* Pass-though Classes */ + +.doc :not(pre).nowrap { + white-space: nowrap; +} + +.doc .nobreak { + hyphens: none; + word-wrap: normal; +} + +.doc .right { + float: right; +} + +.doc .left { + float: left; +} + +.doc .stretch { + width: 100%; +} + +.doc .underline { + text-decoration: underline; +} + +.doc .line-through { + text-decoration: line-through; +} + +.doc .halign-left { + text-align: left; +} + +.doc .halign-right { + text-align: right; +} + +.doc .halign-center { + text-align: center; +} + +.doc .valign-top { + vertical-align: top; +} + +.doc .valign-bottom { + vertical-align: bottom; +} + +.doc .valign-middle { + vertical-align: middle; +} + +/* Footer */ + +#footer #footer-text { + font-size: calc(14 / var(--pixel-to-rem)); + color: var(--asciidoctor-footer-font-color); + padding: 2rem 0; + border-top: 1px solid var(--asciidoctor-section-divider-color); +} + +/* Responsive and Dark Theme Overrides */ + +html.dark-theme #doc { + background: no-repeat top right / 305px 147px; + background-image: url("../img/doc-background-dark.svg"); +} + +@media screen and (max-width: 1024px) { + #doc { + background: no-repeat top right / 203px 95px; + background-image: url("../img/doc-background.svg"); + } + html.dark-theme #doc { + background: no-repeat top right / 203px 95px; + background-image: url("../img/doc-background-dark.svg"); + } +} + +@media screen and (max-width: 800px) { + html.dark-theme #doc, + #doc { + background: none; + } +} diff --git a/components/sbm-recipes-boot-upgrade/css/codetools.css b/components/sbm-recipes-boot-upgrade/css/codetools.css new file mode 100644 index 000000000..6e4992964 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/codetools.css @@ -0,0 +1,171 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +div.codetools { + --button-width: 28px; + --button-height: 24px; + --arrow-size: 5px; + display: flex; + position: absolute; + bottom: 9px; + right: 8px; + background: var(--codetools-background-color); + padding: 0; + border-radius: 2px; + border: 1px solid var(--codetools-border-color); + opacity: 0; + transition: opacity 150ms ease-in-out; +} + +.doc pre.highlight:hover div.codetools { + opacity: 1; +} + +div.codetools button { + width: var(--button-width); + height: var(--button-height); + filter: var(--codetools-button-filter); + background: no-repeat center / 16px 16px; + border: none; + padding: 0; + outline: none; +} + +div.codetools button:not(:last-child) { + border-right: 1px solid var(--codetools-divider-color); +} + +div.codetools button:hover { + background-color: var(--codetools-hover-background-color); + transition: filter 300ms; +} + +div.codetools button:active { + filter: var(--codetools-button-active-filter); + transition: filter none; +} + +div.codetools button span.label { + display: none; +} + +div.codetools button.copy-button { + background-image: url("../img/octicons-16.svg#view-clippy"); +} + +div.codetools button.unfold-button { + background-image: url("../img/octicons-16.svg#view-unfold"); +} + +div.codetools button.fold-button { + background-image: url("../img/octicons-16.svg#view-fold"); +} + +div.codetools span.copied { + opacity: 0; + display: block; + content: ""; + position: relative; + width: var(--button-width); + height: var(--button-height); + z-index: 1000000; + transition: opacity 500ms; +} + +div.codetools button:active span.copied { + filter: invert(); + transition: filter none; +} + +div.codetools span.copied:before { + position: absolute; + bottom: calc(var(--arrow-size) * -1); + left: 50%; + margin-left: calc(var(--arrow-size) / -2); + content: ""; + border: var(--arrow-size) solid var(--codetools-popup-background-color); + border-color: transparent transparent var(--codetools-popup-background-color) + transparent; +} + +div.codetools span.copied:after { + content: "Copied to clipboard!"; + position: absolute; + top: calc(var(--button-height) + var(--arrow-size)); + right: 100%; + margin-right: calc(var(--button-width) * -1); + background-color: var(--codetools-popup-background-color); + color: var(--codetools-popup-font-color); + padding: 5px 8px; + border-radius: 3px; + font-weight: bold; +} + +div.codetools button.clicked span.copied { + opacity: 1; +} + +span.fold-block { + position: relative; + float: left; + clear: left; + padding-right: 0.75rem; + overflow: hidden; +} + +code.unfolded span.fold-block.hide-when-folded, +code:not(.unfolded) span.fold-block.hide-when-unfolded { + max-height: 99999px; + opacity: 1; +} + +code.unfolded span.fold-block.hide-when-unfolded, +code:not(.unfolded) span.fold-block.hide-when-folded { + max-height: 0px; + opacity: 0; +} + +code.unfolding span.fold-block.hide-when-folded { + max-height: 600px; + opacity: 1; +} + +code.folding span.fold-block.hide-when-unfolded { + max-height: 400px; + opacity: 1; +} + +code.unfolding span.fold-block.hide-when-unfolded, +code.folding span.fold-block.hide-when-folded { + max-height: 0; + opacity: 0; +} + +code.unfolding span.fold-block.hide-when-unfolded { + transition: max-height 200ms cubic-bezier(0, 1, 0, 1), opacity 200ms linear; +} + +code.folding span.fold-block.hide-when-unfolded { + transition: max-height 200ms cubic-bezier(1, 0, 1, 0), opacity 200ms linear; +} + +code.unfolding span.fold-block.hide-when-folded { + transition: max-height 200ms cubic-bezier(1, 0, 1, 0), opacity 200ms linear; +} + +code.folding span.fold-block.hide-when-folded { + transition: max-height 200ms cubic-bezier(0, 1, 0, 1), opacity 200ms linear; +} diff --git a/components/sbm-recipes-boot-upgrade/css/components.css b/components/sbm-recipes-boot-upgrade/css/components.css new file mode 100644 index 000000000..f9b74af16 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/components.css @@ -0,0 +1,22 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "layout.css"; +@import "asciidoctor.css"; +@import "highlight.css"; +@import "tabs.css"; +@import "toc.css"; +@import "codetools.css"; diff --git a/components/sbm-recipes-boot-upgrade/css/elements.css b/components/sbm-recipes-boot-upgrade/css/elements.css new file mode 100644 index 000000000..29ccd7719 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/elements.css @@ -0,0 +1,66 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +html { + height: 100%; + font-size: var(--html-font-size); + scroll-behavior: smooth; + min-width: 340px; +} + +body { + margin: 0; + overflow-wrap: anywhere; + overscroll-behavior: none; + font-family: var(--font-family); + font-weight: var(--font-weight); + color: var(--body-font-color); + background-color: var(--body-background-color); +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:active { + background-color: none; +} + +code, +kbd, +pre { + font-family: var(--monospace-font-family); +} + +@supports (scrollbar-width: thin) { + body * { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thumb-color) transparent; + } +} + +table { + border-collapse: collapse; + word-wrap: normal; +} + +mark { + background: var(--mark-background-color); +} diff --git a/components/sbm-recipes-boot-upgrade/css/generic.css b/components/sbm-recipes-boot-upgrade/css/generic.css new file mode 100644 index 000000000..77467aad3 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/generic.css @@ -0,0 +1,29 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +html { + box-sizing: border-box; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body { + text-size-adjust: none; +} diff --git a/components/sbm-recipes-boot-upgrade/css/highlight.css b/components/sbm-recipes-boot-upgrade/css/highlight.css new file mode 100644 index 000000000..1092da866 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/highlight.css @@ -0,0 +1,105 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: var(--highlight-background-color); + color: var(--highlight-font-color); +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { + color: var(--highlight-keyword-font-color); +} + +.hljs-comment, +.hljs-quote { + color: var(--highlight-comment-font-color); +} + +.hljs-string, +.hljs-doctag { + color: var(--highlight-string-font-color); +} + +.hljs-meta { + color: var(--highlight-meta-font-color); +} + +.hljs-built_in, +.hljs-builtin-name, +.hljs-number, +.hljs-symbol, +.hljs-literal { + color: var(--highlight-constant-font-color); +} + +.hljs-variable, +.hljs-template-variable { + color: var(--highlight-variable-font-color); +} + +.hljs-tag, +.hljs-name, +.hljs-attribute { + color: var(--highlight-tag-font-color); +} + +.hljs-tag .hljs-attr { + color: var(--highlight-tag-attribute-font-color); +} + +.hljs-type, +.hljs-class .hljs-title { + color: var(--highlight-type-font-color); +} + +.hljs-regexp { + color: var(--highlight-regex-font-color); +} + +.hljs-link { + text-decoration: underline; + color: var(--highlight-link-font-color); +} + +.hljs-addition { + color: var(--highlight-addition-font-color); +} + +.hljs-deletion { + color: var(--highlight-deletion-font-color); +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.language-json .hljs-number, +.language-json .hljs-literal { + color: var(--highlight-variable-font-color); +} + +.language-json .hljs-attr { + color: var(--highlight-string-font-color); +} diff --git a/components/sbm-recipes-boot-upgrade/css/layout.css b/components/sbm-recipes-boot-upgrade/css/layout.css new file mode 100644 index 000000000..8622d1e39 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/layout.css @@ -0,0 +1,83 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#banner-container { + height: var(--layout-banner-height); + overflow: hidden; + border-bottom: 1px solid var(--layout-border-color); +} + +#banner { + height: 100%; + background: no-repeat top var(--layout-banner-logo-offset) left + var(--layout-banner-logo-offset) / auto var(--layout-banner-logo-height); + background-image: url("../img/banner-logo.svg"); +} + +#doc { + overflow: auto; +} + +.contained { + max-width: var(--layout-max-width); + margin: 0 auto; +} + +div#switch-theme, +#switch-theme label { + display: none; +} + +html.js div#switch-theme { + display: block; + float: right; + margin: 8px 6px 0 0; +} + +#switch-theme input { + appearance: none; + position: relative; + width: 40px; + height: 22px; + filter: var(--layout-switchtheme-invert-filter); + background: no-repeat url("../img/octicons-16.svg#view-sun") 90% 50% / 16px + 16px, + no-repeat url("../img/octicons-16.svg#view-moon") 10% 50% / 16px 16px; + background-color: var(--layout-switchtheme-background-color); + border-radius: 25px; + outline: none; +} + +#switch-theme input::before { + filter: var(--layout-switchtheme-invert-filter); + content: ""; + position: absolute; + left: 2px; + top: 2px; + height: 18px; + width: 18px; + border-radius: 25px; + background-color: var(--layout-switchtheme-button-color); + transition: transform 200ms; +} + +#switch-theme:hover input::before { + background-color: var(--layout-switchtheme-button-hover-color); +} + +#switch-theme input:checked::before { + transform: translateX(18px); +} diff --git a/components/sbm-recipes-boot-upgrade/css/settings-dark.css b/components/sbm-recipes-boot-upgrade/css/settings-dark.css new file mode 100644 index 000000000..8623cd06b --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/settings-dark.css @@ -0,0 +1,63 @@ +html.dark-theme { + /* General */ + --font-weight: 300; + --body-background-color: #1b1f23; + --panel-background-color: #262a2d; + --panel-group-background-color: #303741; + --panel-border-color: #2c3135; + --color-accent-1: #272c33; + --color-accent-1-invert: #d8d3cc; + --color-accent-2: #2d333a; + --color-accent-3: #6db33f; + --body-font-color: #bbbcbe; + --body-font-light-color: #abacaf; + --body-font-dark-color: #cecfd1; + --link-font-color: #086dc3; + --hover-link-font-color: #107ddd; + --scrollbar-thumb-color: #5f5f5f; + --mark-background-color: #2eca12; + --selected-background-color: #8d8d8d; + + /* Layout */ + --layout-switchtheme-invert-filter: none; + --layout-switchtheme-background-color: var(--selected-background-color); + + /* Asciidoctor */ + --asciidoctor-code-background: rgba(177, 209, 241, 0.15); + --asciidoctor-code-data-lang-color: #6e6e6e; + --asciidoctor-admonition-font-color: #f0f0f0; + --asciidoctor-admonition-caution-background: #603668; + --asciidoctor-admonition-important-background: #924040; + --asciidoctor-admonition-note-background: #355463; + --asciidoctor-admonition-tip-background: #4d6340; + --asciidoctor-admonition-warning-background: #967745; + --asciidoctor-footer-font-color: #5e5e5e; + + /* Highlight JS (colors based on https://github.com/primer/github-syntax-dark) */ + --highlight-background-color: var(--asciidoctor-pre-background); + --highlight-font-color: #f6f8fa; + --highlight-keyword-font-color: #ea4a5a; + --highlight-comment-font-color: #959da5; + --highlight-string-font-color: #79b8ff; + --highlight-meta-font-color: #959da5; + --highlight-constant-font-color: #79b8ff; + --highlight-variable-font-color: #c8e1ff; + --highlight-tag-font-color: #7bcc72; + --highlight-tag-attribute-font-color: #b392f0; + --highlight-type-font-color: #b392f0; + --highlight-link-font-color: #1565c0; + --highlight-addition-font-color: #7bcc72; + --highlight-deletion-font-color: #f6f8fa; + --highlight-regex-font-color: #79b8ff; + + /* TOC */ + --toc-back-to-index-filter: invert(); + --toc-bar-button-filter: invert(); + + /* Code Tools */ + --codetools-button-filter: invert(); + --codetools-button-active-filter: none; + --codetools-hover-background-color: var(--color-accent-1-invert); + --codetools-border-color: rgba(255, 255, 255, 0.274); + --codetools-divider-color: rgba(44, 44, 44, 0.274); +} diff --git a/components/sbm-recipes-boot-upgrade/css/settings.css b/components/sbm-recipes-boot-upgrade/css/settings.css new file mode 100644 index 000000000..8ee936c07 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/settings.css @@ -0,0 +1,180 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +:root { + /* NOTE: Don't use relative `url()` values in here. Safari load them properly */ + + /* General */ + --html-font-size: 1em; + --pixel-to-rem: 16 * 1rem; + --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol"; + --font-weight: 400; + --monospace-font-family: "SFMono-Regular", "Consolas", "Liberation Mono", + "Menlo", monospace; + --body-background-color: white; + --panel-background-color: #f6f8fa; + --panel-group-background-color: #e1e8e8; + --panel-border-color: #eaedf0; + --color-accent-1: #ebf2f2; + --color-accent-2: #d7e7e7; + --color-accent-3: #6db33f; + --body-font-color: #191e1e; + --body-font-light-color: #273030; + --body-font-dark-color: #141818; + --link-font-color: #1565c0; + --hover-link-font-color: #104d92; + --scrollbar-thumb-color: silver; + --mark-background-color: #39ff14; + --selected-background-color: #191e1e; + + /* Layout */ + --layout-banner-logo-offset: 18px; + --layout-banner-logo-height: 50px; + --layout-max-width: 1400px; + --layout-banner-height: 80px; + --layout-border-color: var(--color-accent-1); + --layout-switchtheme-invert-filter: invert(); + --layout-switchtheme-background-color: var(--body-background-color); + --layout-switchtheme-button-color: var(--body-background-color); + --layout-switchtheme-button-hover-color: var(--color-accent-1); + + /* Asciidoctor */ + --asciidoctor-doc-embellishment-margin-width: 250px; + --asciidoctor-doc-background-embellishment-height: 147px; + --asciidoctor-details-background: var(--color-accent-1); + --asciidoctor-details-font-color: var(--body-font-light-color); + --asciidoctor-author-separator-color: var(--color-accent-3); + --asciidoctor-panel-background: var(--panel-background-color); + --asciidoctor-panel-border-color: var(--panel-border-color); + --asciidoctor-font-color: var(--body-font-color); + --asciidoctor-heading-font-color: var(--body-font-dark-color); + --asciidoctor-heading-font-weight: 600; + --asciidoctor-alt-heading-font-weight: 600; + --asciidoctor-section-divider-color: var(--color-accent-1); + --asciidoctor-link-font-color: var(--link-font-color); + --asciidoctor-hover-link-font-color: var(--hover-link-font-color); + --asciidoctor-unresolved-link-font-color: #d32f2f; + --asciidoctor-code-font-color: var(--asciidoctor-font-color); + --asciidoctor-code-link-font-color: var(--link-font-color); + --asciidoctor-code-background: rgba(27, 31, 35, 0.05); + --asciidoctor-code-data-lang-color: #999; + --asciidoctor-table-border-color: var(--asciidoctor-panel-border-color); + --asciidoctor-table-header-footer-background: var(--color-accent-1); + --asciidoctor-table-stripe-background: var(--color-accent-1); + --asciidoctor-table-footer-background: linear-gradient( + to bottom, + var(--color-accent-1) 0%, + var(--body-background-color) 100% + ); + --asciidoctor-admonition-background: var(--color-accent-1); + --asciidoctor-admonition-pre-background: var(--color-accent-2); + --asciidoctor-admonition-label-font-weight: 500; + --asciidoctor-admonition-font-color: #f0f0f0; + --asciidoctor-admonition-caution-background: #561164; + --asciidoctor-admonition-important-background: #960000; + --asciidoctor-admonition-note-background: #015785; + --asciidoctor-admonition-tip-background: #3e6b1f; + --asciidoctor-admonition-warning-background: #bd7400; + --asciidoctor-abstract-background: var(--asciidoctor-panel-background); + --asciidoctor-abstract-border-color: var(--asciidoctor-panel-border-color); + --asciidoctor-quote-background: var(--color-accent-1); + --asciidoctor-quote-border-color: var(--color-accent-3); + --asciidoctor-quote-attribution-font-color: var(--color-accent-3); + --asciidoctor-caption-font-color: var(--body-font-light-color); + --asciidoctor-caption-font-weight: 400; + --asciidoctor-example-background: var(--asciidoctor-panel-background); + --asciidoctor-example-border-color: var(--asciidoctor-panel-border-color); + --asciidoctor-sidebar-background: var(--color-accent-1); + --asciidoctor-pre-background: var(--asciidoctor-panel-background); + --asciidoctor-pre-border-color: var(--asciidoctor-panel-border-color); + --asciidoctor-callout-background: var(--body-font-dark-color); + --asciidoctor-callout-font-color: var(--body-background-color); + --asciidoctor-footer-font-color: #b6b6b6; + + /* Highlight JS (colors based on https://github.com/primer/github-syntax-light) */ + --highlight-background-color: var(--asciidoctor-pre-background); + --highlight-font-color: #24292e; + --highlight-keyword-font-color: #d73a49; + --highlight-comment-font-color: #6a737d; + --highlight-string-font-color: #032f62; + --highlight-meta-font-color: #6a737d; + --highlight-constant-font-color: #032f62; + --highlight-variable-font-color: #005cc5; + --highlight-tag-font-color: #22863a; + --highlight-tag-attribute-font-color: #6f42c1; + --highlight-type-font-color: #6f42c1; + --highlight-link-font-color: var(--link-font-color); + --highlight-addition-font-color: #22863a; + --highlight-deletion-font-color: #24292e; + --highlight-regex-font-color: #032f62; + + /* Tabs */ + --tabs-border-color: var(--selected-background-color); + --tabs-background-color: var(--body-background-color); + --tabs-font-color: var(--body-font-color); + --tabs-selected-background-color: var(--selected-background-color); + --tabs-selected-font-color: var(--body-background-color); + --tabs-hover-font-color: var(--hover-link-font-color); + --tabs-hover-background: var(--color-accent-1); + --tabs-group-background-color: var(--panel-group-background-color); + + /* TOC */ + --toc-width: 24rem; + --toc-display: block; + --toc-font-color: var(--body-font-color); + --toc-hover-background-color: var(--color-accent-1); + --toc-active-background-color: var(--selected-background-color); + --toc-active-font-color: var(--body-background-color); + --toc-back-to-index-filter: none; + --toc-bar-display: none; + --toc-bar-height: 0; + --toc-bar-button-filter: none; + + /* Code Tools */ + --codetools-button-filter: none; + --codetools-button-active-filter: invert(); + --codetools-background-color: var(--body-background-color); + --codetools-border-color: rgba(0, 0, 0, 0.3); + --codetools-hover-background-color: var(--color-accent-1); + --codetools-divider-color: var(--codetools-border-color); + --codetools-popup-background-color: var(--selected-background-color); + --codetools-popup-font-color: var(--body-background-color); +} + +/* Responsive Overrides */ + +@media screen and (max-width: 1024px) { + :root { + --toc-width: 16rem; + --asciidoctor-doc-embellishment-margin-width: 140px; + } +} + +@media screen and (max-width: 800px) { + :root { + --layout-banner-height: 51px; + --layout-banner-logo-height: 30px; + --layout-banner-logo-offset: 10px; + --layout-border-color: var(--body-background-color); + --toc-bar-display: block; + --toc-bar-height: 24px; + --toc-width: 0; + --toc-display: none; + --asciidoctor-doc-embellishment-margin-width: 0; + } +} diff --git a/components/sbm-recipes-boot-upgrade/css/site.css b/components/sbm-recipes-boot-upgrade/css/site.css new file mode 100644 index 000000000..fbbbf60aa --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/site.css @@ -0,0 +1,21 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "settings.css"; +@import "settings-dark.css"; +@import "generic.css"; +@import "elements.css"; +@import "components.css"; diff --git a/components/sbm-recipes-boot-upgrade/css/tabs.css b/components/sbm-recipes-boot-upgrade/css/tabs.css new file mode 100644 index 000000000..539458281 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/tabs.css @@ -0,0 +1,70 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Block Switching */ + +.hidden { + display: none; +} + +.doc .tabs { + font-weight: bold; + font-size: calc(12 / var(--pixel-to-rem)); + border-style: none; + display: inline-block; + position: relative; + bottom: 0; + margin-top: 0.5rem; + margin-bottom: calc(2 / var(--pixel-to-rem)); +} + +.doc .tab:not(:first-child) { + border: 1px solid var(--tabs-border-color); +} + +.doc .tab { + padding: 0.3rem 0.6rem; + background-color: var(--tabs-background-color); + color: var(--tabs-font-color); + display: inline-block; + cursor: pointer; + border: 1px solid var(--tabs-border-color); + margin-bottom: calc(2 / var(--pixel-to-rem)); + border-radius: 0; + transition: background-color 200ms; +} + +.doc .tab:hover { + color: var(--tabs-hover-font-color); + background-color: var(--tabs-hover-background); + text-decoration: underline; +} + +.doc .tab.selected { + background-color: var(--tabs-selected-background-color); + border-color: var(--tabs-selected-background-color); + color: var(--tabs-selected-font-color); +} + +.doc .tab.selected:hover { + color: var(--tabs-selected-font-color); + text-decoration: none; +} + +.doc div.openblock.tabs-content > .content { + padding: 1rem; + background-color: var(--tabs-group-background-color); +} diff --git a/components/sbm-recipes-boot-upgrade/css/toc.css b/components/sbm-recipes-boot-upgrade/css/toc.css new file mode 100644 index 000000000..c76e49565 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/css/toc.css @@ -0,0 +1,169 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +body.toc-left #doc { + border-left: 1px solid var(--layout-border-color); + overflow: auto; + margin-left: var(--toc-width); +} + +#toc { + display: var(--toc-display); + position: absolute; + top: var(--layout-banner-height); + width: var(--toc-width); + margin-left: calc(var(--toc-width) * -1); + border-right: 1px solid var(--layout-border-color); + padding: 1.7rem 1rem 0 1rem; + font-size: 0.95rem; + line-height: 1.1; +} + +#toctitle { + display: none; +} + +#toc ul, +#toc ol { + padding: 0; +} + +#toc ul ul, +#toc ul ol { + padding-left: 0.8rem; +} + +#toc li { + display: block; + list-style: none; +} + +#toc a { + display: block; + text-decoration: none; + color: var(--toc-font-color); + padding: 0.4rem 0.6rem; + border-radius: 4px; +} + +#toc a:hover { + background-color: var(--toc-hover-background-color); +} + +body.fixed-toc #toc { + position: fixed; + top: 0; + overflow-x: hidden; + height: 100%; +} + +#toc li.active > a { + background-color: var(--toc-active-background-color); + color: var(--toc-active-font-color); +} + +#toc > ul ul, +#toc > ol ol { + display: none; +} + +#toc li.active > ul, +#toc li.active > ol, +#toc ul.expanded, +#toc ol.expanded { + display: block; +} + +#back-to-index { + display: block; + margin-bottom: 0.6rem; +} + +#back-to-index a { + padding-left: 1.6rem; + margin-bottom: 0.6rem; + margin-top: -0.9rem; +} + +#back-to-index a::before { + content: ""; + filter: var(--toc-back-to-index-filter); + background: no-repeat center / 16px 16px; + background-image: url("../img/octicons-16.svg#view-chevron-left"); + display: block; + position: absolute; + min-width: 16px; + min-height: 16px; + left: 1.4rem; +} + +#tocbar-container { + display: var(--toc-bar-display); + width: 100%; +} + +#tocbar-container { + height: var(--tocbar-height); + background-color: var(--body-background-color); + border-bottom: 1px solid var(--panel-border-color); + z-index: 10000; +} + +#tocbar { + width: 100%; + height: 100%; + padding-left: 6px; +} + +body.fixed-toc #tocbar-container { + position: fixed; + top: 0; +} + +button#toggle-toc { + width: var(--toc-bar-height); + height: var(--toc-bar-height); + filter: var(--toc-bar-button-filter); + background: no-repeat center / 16px 16px; + background-image: url("../img/octicons-16.svg#view-three-bars"); + border: none; + outline: none; + padding: 0; + display: block; +} + +body.show-toc button#toggle-toc { + background-image: url("../img/octicons-16.svg#view-x"); +} + +@media screen and (max-width: 800px) { + body.fixed-toc #toc { + top: var(--toc-bar-height); + } + + #toc { + top: calc(var(--layout-banner-height) + var(--toc-bar-height)); + width: 100%; + height: 100%; + left: 0; + background-color: var(--body-background-color); + z-index: 10000; + } + + body.show-toc #toc { + display: block; + } +} diff --git a/components/sbm-recipes-boot-upgrade/img/banner-logo.svg b/components/sbm-recipes-boot-upgrade/img/banner-logo.svg new file mode 100644 index 000000000..23e7e980c --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/img/banner-logo.svg @@ -0,0 +1,16 @@ + + + Spring Logos and Graphics + + + + + + + + + + + + + diff --git a/components/sbm-recipes-boot-upgrade/img/doc-background-dark.svg b/components/sbm-recipes-boot-upgrade/img/doc-background-dark.svg new file mode 100644 index 000000000..3e7b63c3e --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/img/doc-background-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/components/sbm-recipes-boot-upgrade/img/doc-background.svg b/components/sbm-recipes-boot-upgrade/img/doc-background.svg new file mode 100644 index 000000000..301ff34f1 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/img/doc-background.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/components/sbm-recipes-boot-upgrade/img/octicons-16.svg b/components/sbm-recipes-boot-upgrade/img/octicons-16.svg new file mode 100644 index 000000000..9e8fe2847 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/img/octicons-16.svg @@ -0,0 +1,109 @@ + + Octicons (24px subset) + Octicons v12.1.0 by GitHub - https://primer.style/octicons/ - License: MIT + + + + @primer/octicons + 12.1.0 + A scalable set of icons handcrafted with <3 by GitHub + image/svg+xml + + + GitHub + + + + + Copyright (c) 2020 GitHub Inc. + + + + https://primer.style/octicons/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/sbm-recipes-boot-upgrade/js/setup.js b/components/sbm-recipes-boot-upgrade/js/setup.js new file mode 100644 index 000000000..ae5b1b7bd --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/js/setup.js @@ -0,0 +1,3 @@ +!function(){"use strict";document.getElementsByTagName("html")[0].classList.add("js")}(); +!function(){var t=function(t,n,e){if("function"!=typeof t)throw new TypeError("Expected a function");return setTimeout((function(){t.apply(void 0,e)}),n)};var n=function(t){return t};var e=function(t,n,e){switch(e.length){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)},r=Math.max;var o=function(t,n,o){return n=r(void 0===n?t.length-1:n,0),function(){for(var c=arguments,u=-1,i=r(c.length-n,0),a=Array(i);++u0){if(++n>=800)return arguments[0]}else n=0;return t.apply(void 0,arguments)}},D=C(R);var G=/\s/;var U=function(t){for(var n=t.length;n--&&G.test(t.charAt(n)););return n},z=/^\s+/;var B=function(t){return t?t.slice(0,U(t)+1).replace(z,""):t};var H=function(t){return null!=t&&"object"==typeof t};var J=function(t){return"symbol"==typeof t||H(t)&&"[object Symbol]"==g(t)},K=/^[-+]0x[0-9a-f]+$/i,Q=/^0b[01]+$/i,V=/^0o[0-7]+$/i,W=parseInt;var X=function(t){if("number"==typeof t)return t;if(J(t))return NaN;if(m(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=m(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=B(t);var e=Q.test(t);return e||V.test(t)?W(t.slice(2),e?2:8):K.test(t)?NaN:+t},Y=function(t,e){return D(o(t,e,n),t+"")}((function(n,e,r){return t(n,X(e)||0,r)}));!function(){"use strict";const t=window.localStorage,n=document.documentElement,e=window.matchMedia("(prefers-color-scheme: dark)");function r(){const n=null!==t?t.getItem("theme"):null;return n?"dark"===n:e.matches}function o(){this.checked?(Y((function(){n.classList.add("dark-theme")}),100),c("dark")):(Y((function(){n.classList.remove("dark-theme")}),100),c("light"))}function c(n){t&&t.setItem("theme",n)}r()&&n.classList.add("dark-theme"),window.addEventListener("load",(function(){const t=document.querySelector("#switch-theme-checkbox");t.checked=r(),t.addEventListener("change",o.bind(t))}))}()}(); +//# sourceMappingURL=setup.js.map diff --git a/components/sbm-recipes-boot-upgrade/js/site.js b/components/sbm-recipes-boot-upgrade/js/site.js new file mode 100644 index 000000000..e4fc71fe8 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/js/site.js @@ -0,0 +1,7 @@ +!function(){"use strict";function n(){const n=document.getElementById("anchor-rewrite"),o=window.location.hash.substr(1);n&&o&&function(n,o){const e=[n];for(console.debug(n);o[n];){if(n=o[n],e.includes(n))return void console.error("Skipping circular anchor update");e.push(n)}window.location.hash=n}(o,JSON.parse(n.innerHTML))}window.addEventListener("load",n),window.addEventListener("hashchange",n)}(); +!function(){"use strict";!function(){let t=document.getElementById("author"),n=t;for(;t;)t.classList.contains("author")&&(n=t),t=t.nextElementSibling;n&&n.classList.add("last-author")}()}(); +!function(){var t=function(t,n,e){if("function"!=typeof t)throw new TypeError("Expected a function");return setTimeout((function(){t.apply(void 0,e)}),n)};var n=function(t){return t};var e=function(t,n,e){switch(e.length){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)},r=Math.max;var o=function(t,n,o){return n=r(void 0===n?t.length-1:n,0),function(){for(var c=arguments,i=-1,u=r(c.length-n,0),a=Array(u);++i0){if(++n>=800)return arguments[0]}else n=0;return t.apply(void 0,arguments)}},G=D(I);var M=/\s/;var U=function(t){for(var n=t.length;n--&&M.test(t.charAt(n)););return n},z=/^\s+/;var B=function(t){return t?t.slice(0,U(t)+1).replace(z,""):t};var H=function(t){return null!=t&&"object"==typeof t};var J=function(t){return"symbol"==typeof t||H(t)&&"[object Symbol]"==g(t)},K=/^[-+]0x[0-9a-f]+$/i,Q=/^0b[01]+$/i,V=/^0o[0-7]+$/i,W=parseInt;var X=function(t){if("number"==typeof t)return t;if(J(t))return NaN;if(m(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=m(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=B(t);var e=Q.test(t);return e||V.test(t)?W(t.slice(2),e?2:8):K.test(t)?NaN:+t},Y=function(t,e){return G(o(t,e,n),t+"")}((function(n,e,r){return t(n,X(e)||0,r)}));!function(){"use strict";function t(t){const e=t.querySelector("code").cloneNode(!0);for(const t of e.querySelectorAll(".hide-when-unfolded"))t.parentNode.removeChild(t);const r=e.innerText;r&&window.navigator.clipboard.writeText(r+"\n").then(n.bind(this))}function n(){this.classList.add("clicked")}function e(){this.classList.remove("clicked")}function r(t){const n=t.querySelector("code"),e=!n.classList.contains("unfolded");n.classList.remove(e?"folding":"unfolding"),n.classList.add(e?"unfolding":"folding"),Y((function(){n.classList.remove(e?"unfolding":"folding"),n.classList.toggle("unfolded")}),1100),o(this,!e)}function o(t,n){const e=n?"Expanded folded text":"Collapse foldable text";t.classList.remove(n?"fold-button":"unfold-button"),t.classList.add(n?"unfold-button":"fold-button"),t.querySelector("span.label").innerText=e,t.title=e}!function(){for(const t of document.querySelectorAll(".doc pre.highlight")){const e=document.createElement("div");e.className="codetools",n(t,e)&&t.appendChild(e)}function n(n,i){let u=0;return function(t){return!!t.querySelector("span.hide-when-folded")}(n)&&(!function(t,n){const e=c();o(e,!0),e.addEventListener("click",r.bind(e,t)),n.appendChild(e)}(n,i),u++),window.navigator.clipboard&&(!function(n,r){const o=c("Copy to clipboard","copy-button");o.addEventListener("click",t.bind(o,n)),o.addEventListener("mouseleave",e.bind(o)),o.addEventListener("blur",e.bind(o));const i=document.createElement("span");o.appendChild(i),i.className="copied",r.appendChild(o)}(n,i),u++),u>0}function c(t,n){const e=document.createElement("button");e.className=n,e.title=t,e.type="button";const r=document.createElement("span");return r.appendChild(document.createTextNode(t)),r.className="label",e.appendChild(r),e}}()}()}(); +!function(){function e(n){return n instanceof Map?n.clear=n.delete=n.set=function(){throw new Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=function(){throw new Error("set is read-only")}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((function(t){var a=n[t];"object"!=typeof a||Object.isFrozen(a)||e(a)})),n}var n=e,t=e;n.default=t;class a{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function i(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}const s=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=i(e)}openNode(e){if(!s(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){this.buffer+=``}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){return!0}}function g(e){return e?"string"==typeof e?e:e.source:null}const d=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;const u="[a-zA-Z]\\w*",b="[a-zA-Z_]\\w*",m="\\b\\d+(\\.\\d+)?",h="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",f="\\b(0b[01]+)",p={begin:"\\\\[\\s\\S]",relevance:0},_={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[p]},E={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[p]},v={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},N=function(e,n,t={}){const a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(v),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},y=N("//","$"),w=N("/\\*","\\*/"),x=N("#","$"),O={className:"number",begin:m,relevance:0},M={className:"number",begin:h,relevance:0},k={className:"number",begin:f,relevance:0},R={className:"number",begin:m+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},A={begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[p,{begin:/\[/,end:/\]/,relevance:0,contains:[p]}]}]},S={className:"title",begin:u,relevance:0},T={className:"title",begin:b,relevance:0},C={begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0};var D=Object.freeze({__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:u,UNDERSCORE_IDENT_RE:b,NUMBER_RE:m,C_NUMBER_RE:h,BINARY_NUMBER_RE:f,RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map((e=>g(e))).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:p,APOS_STRING_MODE:_,QUOTE_STRING_MODE:E,PHRASAL_WORDS_MODE:v,COMMENT:N,C_LINE_COMMENT_MODE:y,C_BLOCK_COMMENT_MODE:w,HASH_COMMENT_MODE:x,NUMBER_MODE:O,C_NUMBER_MODE:M,BINARY_NUMBER_MODE:k,CSS_NUMBER_MODE:R,REGEXP_MODE:A,TITLE_MODE:S,UNDERSCORE_TITLE_MODE:T,METHOD_GUARD:C,END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}});function L(e,n){"."===e.input[e.index-1]&&n.ignoreMatch()}function B(e,n){n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=L,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,void 0===e.relevance&&(e.relevance=0))}function $(e,n){Array.isArray(e.illegal)&&(e.illegal=function(...e){return"("+e.map((e=>g(e))).join("|")+")"}(...e.illegal))}function I(e,n){if(e.match){if(e.begin||e.end)throw new Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function j(e,n){void 0===e.relevance&&(e.relevance=1)}const z=["of","and","for","in","not","or","if","then","parent","list","value"];function P(e,n,t="keyword"){const a={};return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((function(t){Object.assign(a,P(e[t],n,t))})),a;function i(e,t){n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((function(n){const t=n.split("|");a[t[0]]=[e,U(t[0],t[1])]}))}}function U(e,n){return n?Number(n):function(e){return z.includes(e.toLowerCase())}(e)?0:1}function K(e,{plugins:n}){function t(n,t){return new RegExp(g(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class a{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return new RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map((e=>e[1]));this.matcherRe=t(function(e,n="|"){let t=0;return e.map((e=>{t+=1;const n=t;let a=g(e),i="";for(;a.length>0;){const e=d.exec(a);if(!e){i+=a;break}i+=a.substring(0,e.index),a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+String(Number(e[1])+n):(i+=e[0],"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new a;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))),n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&this.considerAll()),t}}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=r(e.classNameAliases||{}),function n(a,s){const o=a;if(a.isCompiled)return o;[I].forEach((e=>e(a,s))),e.compilerExtensions.forEach((e=>e(a,s))),a.__beforeBegin=null,[B,$,j].forEach((e=>e(a,s))),a.isCompiled=!0;let l=null;if("object"==typeof a.keywords&&(l=a.keywords.$pattern,delete a.keywords.$pattern),a.keywords&&(a.keywords=P(a.keywords,e.case_insensitive)),a.lexemes&&l)throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l=l||a.lexemes||/\w+/,o.keywordPatternRe=t(l,!0),s&&(a.begin||(a.begin=/\B|\b/),o.beginRe=t(a.begin),a.endSameAsBegin&&(a.end=a.begin),a.end||a.endsWithParent||(a.end=/\B|\b/),a.end&&(o.endRe=t(a.end)),o.terminatorEnd=g(a.end)||"",a.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(a.end?"|":"")+s.terminatorEnd)),a.illegal&&(o.illegalRe=t(a.illegal)),a.contains||(a.contains=[]),a.contains=[].concat(...a.contains.map((function(e){return function(e){e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((function(n){return r(e,{variants:null},n)})));if(e.cachedVariants)return e.cachedVariants;if(H(e))return r(e,{starts:e.starts?r(e.starts):null});if(Object.isFrozen(e))return r(e);return e}("self"===e?a:e)}))),a.contains.forEach((function(e){n(e,o)})),a.starts&&n(a.starts,s),o.matcher=function(e){const n=new i;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin"}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(o),o}(e)}function H(e){return!!e&&(e.endsWithParent||H(e.starts))}function Z(e){const n={props:["language","code","autodetect"],data:function(){return{detectedLanguage:"",unknownLanguage:!1}},computed:{className(){return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){if(!this.autoDetect&&!e.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`),this.unknownLanguage=!0,i(this.code);let n={};return this.autoDetect?(n=e.highlightAuto(this.code),this.detectedLanguage=n.language):(n=e.highlight(this.language,this.code,this.ignoreIllegals),this.detectedLanguage=this.language),n.value},autoDetect(){return!this.language||(e=this.autodetect,Boolean(e||""===e));var e},ignoreIllegals:()=>!0},render(e){return e("pre",{},[e("code",{class:this.className,domProps:{innerHTML:this.highlighted}})])}};return{Component:n,VuePlugin:{install(e){e.component("highlightjs",n)}}}}const G={"after:highlightElement":({el:e,result:n,text:t})=>{const a=q(e);if(!a.length)return;const r=document.createElement("div");r.innerHTML=n.value,n.value=function(e,n,t){let a=0,r="";const s=[];function o(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function c(e){r+=""}function g(e){("start"===e.event?l:c)(e.node)}for(;e.length||n.length;){let n=o();if(r+=i(t.substring(a,n[0].offset)),a=n[0].offset,n===e){s.reverse().forEach(c);do{g(n.splice(0,1)[0]),n=o()}while(n===e&&n.length&&n[0].offset===a);s.reverse().forEach(l)}else"start"===n[0].event?s.push(n[0].node):s.pop(),g(n.splice(0,1)[0])}return r+i(t.substr(a))}(a,q(r),t)}};function F(e){return e.nodeName.toLowerCase()}function q(e){const n=[];return function e(t,a){for(let i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=e(i,a),F(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}const W={},Q=e=>{console.error(e)},X=(e,...n)=>{console.log(`WARN: ${e}`,...n)},V=(e,n)=>{W[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),W[`${e}/${n}`]=!0)},J=i,Y=r,ee=Symbol("nomatch");var ne=function(e){const t=Object.create(null),i=Object.create(null),r=[];let s=!0;const o=/(^(<[^>]+>|\t|)+|\n)/gm,l="Could not find the language '{}', did you forget to load/include a language module?",g={disableAutodetect:!0,name:"Plain text",contains:[]};let d={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:c};function u(e){return d.noHighlightRe.test(e)}function b(e,n,t,a){let i="",r="";"object"==typeof n?(i=e,t=n.ignoreIllegals,r=n.language,a=void 0):(V("10.7.0","highlight(lang, code, ...args) has been deprecated."),V("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),r=e,i=n);const s={code:i,language:r};M("before:highlight",s);const o=s.result?s.result:m(s.language,s.code,t,a);return o.code=s.code,M("after:highlight",o),o}function m(e,n,i,o){function c(e,n){const t=N.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function g(){null!=O.subLanguage?function(){if(""===R)return;let e=null;if("string"==typeof O.subLanguage){if(!t[O.subLanguage])return void k.addText(R);e=m(O.subLanguage,R,!0,M[O.subLanguage]),M[O.subLanguage]=e.top}else e=h(R,O.subLanguage.length?O.subLanguage:null);O.relevance>0&&(A+=e.relevance),k.addSublanguage(e.emitter,e.language)}():function(){if(!O.keywords)return void k.addText(R);let e=0;O.keywordPatternRe.lastIndex=0;let n=O.keywordPatternRe.exec(R),t="";for(;n;){t+=R.substring(e,n.index);const a=c(O,n);if(a){const[e,i]=a;if(k.addText(t),t="",A+=i,e.startsWith("_"))t+=n[0];else{const t=N.classNameAliases[e]||e;k.addKeyword(n[0],t)}}else t+=n[0];e=O.keywordPatternRe.lastIndex,n=O.keywordPatternRe.exec(R)}t+=R.substr(e),k.addText(t)}(),R=""}function u(e){return e.className&&k.openNode(N.classNameAliases[e.className]||e.className),O=Object.create(e,{parent:{value:O}}),O}function b(e,n,t){let i=function(e,n){const t=e&&e.exec(n);return t&&0===t.index}(e.endRe,t);if(i){if(e["on:end"]){const t=new a(e);e["on:end"](n,t),t.isMatchIgnored&&(i=!1)}if(i){for(;e.endsParent&&e.parent;)e=e.parent;return e}}if(e.endsWithParent)return b(e.parent,n,t)}function f(e){return 0===O.matcher.regexIndex?(R+=e[0],1):(C=!0,0)}function p(e){const n=e[0],t=e.rule,i=new a(t),r=[t.__beforeBegin,t["on:begin"]];for(const t of r)if(t&&(t(e,i),i.isMatchIgnored))return f(n);return t&&t.endSameAsBegin&&(t.endRe=new RegExp(n.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),t.skip?R+=n:(t.excludeBegin&&(R+=n),g(),t.returnBegin||t.excludeBegin||(R=n)),u(t),t.returnBegin?0:n.length}function _(e){const t=e[0],a=n.substr(e.index),i=b(O,e,a);if(!i)return ee;const r=O;r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t),g(),r.excludeEnd&&(R=t));do{O.className&&k.closeNode(),O.skip||O.subLanguage||(A+=O.relevance),O=O.parent}while(O!==i.parent);return i.starts&&(i.endSameAsBegin&&(i.starts.endRe=i.endRe),u(i.starts)),r.returnEnd?0:t.length}let E={};function v(t,a){const r=a&&a[0];if(R+=t,null==r)return g(),0;if("begin"===E.type&&"end"===a.type&&E.index===a.index&&""===r){if(R+=n.slice(a.index,a.index+1),!s){const n=new Error("0 width match regex");throw n.languageName=e,n.badRule=E.rule,n}return 1}if(E=a,"begin"===a.type)return p(a);if("illegal"===a.type&&!i){const e=new Error('Illegal lexeme "'+r+'" for mode "'+(O.className||"")+'"');throw e.mode=O,e}if("end"===a.type){const e=_(a);if(e!==ee)return e}if("illegal"===a.type&&""===r)return 1;if(T>1e5&&T>3*a.index){throw new Error("potential infinite loop, way more iterations than matches")}return R+=r,r.length}const N=w(e);if(!N)throw Q(l.replace("{}",e)),new Error('Unknown language: "'+e+'"');const y=K(N,{plugins:r});let x="",O=o||y;const M={},k=new d.__emitter(d);!function(){const e=[];for(let n=O;n!==N;n=n.parent)n.className&&e.unshift(n.className);e.forEach((e=>k.openNode(e)))}();let R="",A=0,S=0,T=0,C=!1;try{for(O.matcher.considerAll();;){T++,C?C=!1:O.matcher.considerAll(),O.matcher.lastIndex=S;const e=O.matcher.exec(n);if(!e)break;const t=v(n.substring(S,e.index),e);S=e.index+t}return v(n.substr(S)),k.closeAllNodes(),k.finalize(),x=k.toHTML(),{relevance:Math.floor(A),value:x,language:e,illegal:!1,emitter:k,top:O}}catch(t){if(t.message&&t.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:t.message,context:n.slice(S-100,S+100),mode:t.mode},sofar:x,relevance:0,value:J(n),emitter:k};if(s)return{illegal:!1,relevance:0,value:J(n),emitter:k,language:e,top:O,errorRaised:t};throw t}}function h(e,n){n=n||d.languages||Object.keys(t);const a=function(e){const n={relevance:0,emitter:new d.__emitter(d),value:J(e),illegal:!1,top:g};return n.emitter.addText(e),n}(e),i=n.filter(w).filter(O).map((n=>m(n,e,!1)));i.unshift(a);const r=i.sort(((e,n)=>{if(e.relevance!==n.relevance)return n.relevance-e.relevance;if(e.language&&n.language){if(w(e.language).supersetOf===n.language)return 1;if(w(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s;return l.second_best=o,l}const f={"before:highlightElement":({el:e})=>{d.useBR&&(e.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"))},"after:highlightElement":({result:e})=>{d.useBR&&(e.value=e.value.replace(/\n/g,"
"))}},p=/^(<[^>]+>|\t)+/gm,_={"after:highlightElement":({result:e})=>{d.tabReplace&&(e.value=e.value.replace(p,(e=>e.replace(/\t/g,d.tabReplace))))}};function E(e){let n=null;const t=function(e){let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=d.languageDetectRe.exec(n);if(t){const n=w(t[1]);return n||(X(l.replace("{}",t[1])),X("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}return n.split(/\s+/).find((e=>u(e)||w(e)))}(e);if(u(t))return;M("before:highlightElement",{el:e,language:t}),n=e;const a=n.textContent,r=t?b(a,{language:t,ignoreIllegals:!0}):h(a);M("after:highlightElement",{el:e,result:r,text:a}),e.innerHTML=r.value,function(e,n,t){const a=n?i[n]:t;e.classList.add("hljs"),a&&e.classList.add(a)}(e,t,r.language),e.result={language:r.language,re:r.relevance,relavance:r.relevance},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.relevance,relavance:r.second_best.relevance})}const v=()=>{if(v.called)return;v.called=!0,V("10.6.0","initHighlighting() is deprecated. Use highlightAll() instead.");document.querySelectorAll("pre code").forEach(E)};let N=!1;function y(){if("loading"===document.readyState)return void(N=!0);document.querySelectorAll("pre code").forEach(E)}function w(e){return e=(e||"").toLowerCase(),t[e]||t[i[e]]}function x(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{i[e.toLowerCase()]=n}))}function O(e){const n=w(e);return n&&!n.disableAutodetect}function M(e,n){const t=e;r.forEach((function(e){e[t]&&e[t](n)}))}"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(function(){N&&y()}),!1),Object.assign(e,{highlight:b,highlightAuto:h,highlightAll:y,fixMarkup:function(e){return V("10.2.0","fixMarkup will be removed entirely in v11.0"),V("10.2.0","Please see https://github.com/highlightjs/highlight.js/issues/2534"),n=e,d.tabReplace||d.useBR?n.replace(o,(e=>"\n"===e?d.useBR?"
":e:d.tabReplace?e.replace(/\t/g,d.tabReplace):e)):n;var n},highlightElement:E,highlightBlock:function(e){return V("10.7.0","highlightBlock will be removed entirely in v12.0"),V("10.7.0","Please use highlightElement now."),E(e)},configure:function(e){e.useBR&&(V("10.3.0","'useBR' will be removed entirely in v11.0"),V("10.3.0","Please see https://github.com/highlightjs/highlight.js/issues/2559")),d=Y(d,e)},initHighlighting:v,initHighlightingOnLoad:function(){V("10.6.0","initHighlightingOnLoad() is deprecated. Use highlightAll() instead."),N=!0},registerLanguage:function(n,a){let i=null;try{i=a(e)}catch(e){if(Q("Language definition for '{}' could not be registered.".replace("{}",n)),!s)throw e;Q(e),i=g}i.name||(i.name=n),t[n]=i,i.rawDefinition=a.bind(null,e),i.aliases&&x(i.aliases,{languageName:n})},unregisterLanguage:function(e){delete t[e];for(const n of Object.keys(i))i[n]===e&&delete i[n]},listLanguages:function(){return Object.keys(t)},getLanguage:w,registerAliases:x,requireLanguage:function(e){V("10.4.0","requireLanguage will be removed entirely in v11."),V("10.4.0","Please see https://github.com/highlightjs/highlight.js/pull/2844");const n=w(e);if(n)return n;throw new Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:O,inherit:Y,addPlugin:function(e){!function(e){e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{e["before:highlightBlock"](Object.assign({block:n.el},n))}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{e["after:highlightBlock"](Object.assign({block:n.el},n))})}(e),r.push(e)},vuePlugin:Z(e).VuePlugin}),e.debugMode=function(){s=!1},e.safeMode=function(){s=!0},e.versionString="10.7.3";for(const e in D)"object"==typeof D[e]&&n(D[e]);return Object.assign(e,D),e.addPlugin(f),e.addPlugin(G),e.addPlugin(_),e}({});function te(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var ae=function(e){const n=[{className:"strong",begin:/\*{2}([^\n]+?)\*{2}/},{className:"strong",begin:te(/\*\*/,/((\*(?!\*)|\\[^\n]|[^*\n\\])+\n)+/,/(\*(?!\*)|\\[^\n]|[^*\n\\])*/,/\*\*/),relevance:0},{className:"strong",begin:/\B\*(\S|\S[^\n]*?\S)\*(?!\w)/},{className:"strong",begin:/\*[^\s]([^\n]+\n)+([^\n]+)\*/}],t=[{className:"emphasis",begin:/_{2}([^\n]+?)_{2}/},{className:"emphasis",begin:te(/__/,/((_(?!_)|\\[^\n]|[^_\n\\])+\n)+/,/(_(?!_)|\\[^\n]|[^_\n\\])*/,/__/),relevance:0},{className:"emphasis",begin:/\b_(\S|\S[^\n]*?\S)_(?!\w)/},{className:"emphasis",begin:/_[^\s]([^\n]+\n)+([^\n]+)_/},{className:"emphasis",begin:"\\B'(?!['\\s])",end:"(\\n{2}|')",contains:[{begin:"\\\\'\\w",relevance:0}],relevance:0}];return{name:"AsciiDoc",aliases:["adoc"],contains:[e.COMMENT("^/{4,}\\n","\\n/{4,}$",{relevance:10}),e.COMMENT("^//","$",{relevance:0}),{className:"title",begin:"^\\.\\w.*$"},{begin:"^[=\\*]{4,}\\n",end:"\\n^[=\\*]{4,}$",relevance:10},{className:"section",relevance:10,variants:[{begin:"^(={1,6})[ \t].+?([ \t]\\1)?$"},{begin:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$"}]},{className:"meta",begin:"^:.+?:",end:"\\s",excludeEnd:!0,relevance:10},{className:"meta",begin:"^\\[.+?\\]$",relevance:0},{className:"quote",begin:"^_{4,}\\n",end:"\\n_{4,}$",relevance:10},{className:"code",begin:"^[\\-\\.]{4,}\\n",end:"\\n[\\-\\.]{4,}$",relevance:10},{begin:"^\\+{4,}\\n",end:"\\n\\+{4,}$",contains:[{begin:"<",end:">",subLanguage:"xml",relevance:0}],relevance:10},{className:"bullet",begin:"^(\\*+|-+|\\.+|[^\\n]+?::)\\s+"},{className:"symbol",begin:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",relevance:10},{begin:/\\[*_`]/},{begin:/\\\\\*{2}[^\n]*?\*{2}/},{begin:/\\\\_{2}[^\n]*_{2}/},{begin:/\\\\`{2}[^\n]*`{2}/},{begin:/[:;}][*_`](?![*_`])/},...n,...t,{className:"string",variants:[{begin:"``.+?''"},{begin:"`.+?'"}]},{className:"code",begin:/`{2}/,end:/(\n{2}|`{2})/},{className:"code",begin:"(`.+?`|\\+.+?\\+)",relevance:0},{className:"code",begin:"^[ \\t]",end:"$",relevance:0},{begin:"^'{3,}[ \\t]*$",relevance:10},{begin:"(link:)?(http|https|ftp|file|irc|image:?):\\S+?\\[[^[]*?\\]",returnBegin:!0,contains:[{begin:"(link|image:?):",relevance:0},{className:"link",begin:"\\w",end:"[^\\[]+",relevance:0},{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0,relevance:0}],relevance:10}]}};function ie(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var re=function(e){const n={},t={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[n]}]};Object.assign(n,{className:"variable",variants:[{begin:ie(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},t]});const a={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},r={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,n,a]};a.contains.push(r);const s={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,n]},o=e.SHEBANG({binary:`(${["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"].join("|")})`,relevance:10}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp"},contains:[o,e.SHEBANG(),l,s,e.HASH_COMMENT_MODE,i,r,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},n]}};const se=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],oe=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],le=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],ce=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ge=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-variant","font-variant-ligatures","font-variation-settings","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","src","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"].reverse();function de(e){return function(...e){return e.map((e=>function(e){return e?"string"==typeof e?e:e.source:null}(e))).join("")}("(?=",e,")")}var ue=function(e){const n=(e=>({IMPORTANT:{className:"meta",begin:"!important"},HEXCOLOR:{className:"number",begin:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"},ATTRIBUTE_SELECTOR_MODE:{className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]}}))(e),t=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},contains:[e.C_BLOCK_COMMENT_MODE,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/},e.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{begin:":("+le.join("|")+")"},{begin:"::("+ce.join("|")+")"}]},{className:"attribute",begin:"\\b("+ge.join("|")+")\\b"},{begin:":",end:"[;}]",contains:[n.HEXCOLOR,n.IMPORTANT,e.CSS_NUMBER_MODE,...t,{begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]},{className:"built_in",begin:/[\w-]+(?=\()/}]},{begin:de(/@/),end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only",attribute:oe.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute"},...t,e.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"\\b("+se.join("|")+")\\b"}]}};var be=function(e){return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,variants:[{begin:/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/},{begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^--- +\d+,\d+ +----$/}]},{className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/^index/,end:/$/},{begin:/={3,}/,end:/$/},{begin:/^-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{begin:/^\*{15}$/},{begin:/^diff --git/,end:/$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}};var me=function(e){return{name:"Dockerfile",aliases:["docker"],case_insensitive:!0,keywords:"from maintainer expose env arg user onbuild stopsignal",contains:[e.HASH_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{beginKeywords:"run cmd entrypoint volume add copy workdir label healthcheck shell",starts:{end:/[^\\]$/,subLanguage:"bash"}}],illegal:"function(e){return e?"string"==typeof e?e:e.source:null}(e))).join("")}("(?=",e,")")}function pe(e,n={}){return n.variants=e,n}var _e=function(e){const n="[A-Za-z0-9_$]+",t=pe([e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]})]),a={className:"regexp",begin:/~?\/[^\/\n]+\//,contains:[e.BACKSLASH_ESCAPE]},i=pe([e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]),r=pe([{begin:/"""/,end:/"""/},{begin:/'''/,end:/'''/},{begin:"\\$/",end:"/\\$",relevance:10},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE],{className:"string"});return{name:"Groovy",keywords:{built_in:"this super",literal:"true false null",keyword:"byte short char int long boolean float double void def as in assert trait abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},contains:[e.SHEBANG({binary:"groovy",relevance:10}),t,r,a,i,{className:"class",beginKeywords:"class interface trait enum",end:/\{/,illegal:":",contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{className:"meta",begin:"@[A-Za-z]+",relevance:0},{className:"attr",begin:n+"[ \t]*:",relevance:0},{begin:/\?/,end:/:/,relevance:0,contains:[t,r,a,i,"self"]},{className:"symbol",begin:"^[ \t]*"+fe(n+":"),excludeBegin:!0,end:n+":",relevance:0}],illegal:/#|<\//}};function Ee(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var ve=function(e){const n="HTTP/(2|1\\.[01])",t={className:"attribute",begin:Ee("^",/[A-Za-z][A-Za-z0-9-]*/,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},a=[t,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+n+" \\d{3})",end:/$/,contains:[{className:"meta",begin:n},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:a}},{begin:"(?=^[A-Z]+ (.*?) "+n+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:n},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:a}},e.inherit(t,{relevance:0})]}},Ne="\\.([0-9](_*[0-9])*)",ye="[0-9a-fA-F](_*[0-9a-fA-F])*",we={className:"number",variants:[{begin:`(\\b([0-9](_*[0-9])*)((${Ne})|\\.)?|(${Ne}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:`\\b([0-9](_*[0-9])*)((${Ne})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${Ne})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{begin:`\\b0[xX]((${ye})\\.?|(${ye})?\\.(${ye}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${ye})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};var xe=function(e){var n="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",a={className:"meta",begin:"@"+n,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]};const i=we;return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface enum",end:/[{;=]/,excludeEnd:!0,relevance:1,keywords:"class interface enum",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"class",begin:"record\\s+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,excludeEnd:!0,end:/[{;=]/,keywords:t,contains:[{beginKeywords:"record"},{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[a,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},i,a]}};const Oe="[A-Za-z$_][0-9A-Za-z$_]*",Me=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],ke=["true","false","null","undefined","NaN","Infinity"],Re=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function Ae(e){return Se("(?=",e,")")}function Se(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var Te=function(e){const n=Oe,t="<>",a="",i={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{const t=e[0].length+e.index,a=e.input[t];"<"!==a?">"===a&&(((e,{after:n})=>{const t="",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:r,contains:f}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:t,end:a},{begin:i.begin,"on:begin":i.isTrulyOpeningTag,end:i.end}],subLanguage:"xml",contains:[{begin:i.begin,end:i.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/,excludeEnd:!0,keywords:r,contains:["self",e.inherit(e.TITLE_MODE,{begin:n}),p],illegal:/%/},{beginKeywords:"while if switch catch for"},{className:"function",begin:e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,contains:[p,e.inherit(e.TITLE_MODE,{begin:n})]},{variants:[{begin:"\\."+n},{begin:"\\$"+n}],relevance:0},{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/,end:/[{;]/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:n}),"self",p]},{begin:"(get|set)\\s+(?="+n+"\\()",end:/\{/,keywords:"get set",contains:[e.inherit(e.TITLE_MODE,{begin:n}),{begin:/\(\)/},p]},{begin:/\$[(.]/}]}};var Ce=function(e){const n={literal:"true false null"},t=[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],a=[e.QUOTE_STRING_MODE,e.C_NUMBER_MODE],i={end:",",endsWithParent:!0,excludeEnd:!0,contains:a,keywords:n},r={begin:/\{/,end:/\}/,contains:[{className:"attr",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE],illegal:"\\n"},e.inherit(i,{begin:/:/})].concat(t),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[e.inherit(i)],illegal:"\\S"};return a.push(r,s),t.forEach((function(e){a.push(e)})),{name:"JSON",contains:a,keywords:n,illegal:"\\S"}},De="\\.([0-9](_*[0-9])*)",Le="[0-9a-fA-F](_*[0-9a-fA-F])*",Be={className:"number",variants:[{begin:`(\\b([0-9](_*[0-9])*)((${De})|\\.)?|(${De}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:`\\b([0-9](_*[0-9])*)((${De})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${De})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{begin:`\\b0[xX]((${Le})\\.?|(${Le})?\\.(${Le}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${Le})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};var $e=function(e){const n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(r,{className:"meta-string"})]}]},l=Be,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),g={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=g;return d.variants[1].contains=[g],g.variants[1].contains=[d],{name:"Kotlin",aliases:["kt","kts"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[g,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},l]}};function Ie(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var je=function(e){const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:Ie(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.+?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};a.contains.push(i),i.contains.push(a);let r=[n,t];return a.contains=a.contains.concat(r),i.contains=i.contains.concat(r),r=r.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:r},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:r}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:r,end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}};var ze=function(e){const n={keyword:"rec with let in inherit assert if else then",literal:"true false or and null",built_in:"import abort baseNameOf dirOf isNull builtins map removeAttrs throw toString derivation"},t={className:"subst",begin:/\$\{/,end:/\}/,keywords:n},a={className:"string",contains:[t],variants:[{begin:"''",end:"''"},{begin:'"',end:'"'}]},i=[e.NUMBER_MODE,e.HASH_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{begin:/[a-zA-Z0-9-_]+(\s*=)/,returnBegin:!0,relevance:0,contains:[{className:"attr",begin:/\S+/}]}];return t.contains=i,{name:"Nix",aliases:["nixos"],keywords:n,contains:i}};var Pe=function(e){var n="[ \\t\\f]*",t=n+"[:=]"+n,a="[ \\t\\f]+",i="("+t+"|"+"[ \\t\\f]+)",r="([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",s="([^\\\\:= \\t\\f\\n]|\\\\.)+",o={end:i,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\\\"},{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{returnBegin:!0,variants:[{begin:r+t,relevance:1},{begin:r+a,relevance:0}],contains:[{className:"attr",begin:r,endsParent:!0,relevance:0}],starts:o},{begin:s+i,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:s,endsParent:!0,relevance:0}],starts:o},{className:"attr",relevance:0,begin:s+n+"$"}]}};function Ue(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var Ke=function(e){const n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",t={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",built_in:"proc lambda",literal:"true false nil"},a={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[a]}),e.COMMENT("^=begin","^=end",{contains:[a],relevance:10}),e.COMMENT("^__END__","\\n$")],s={className:"subst",begin:/#\{/,end:/\}/,keywords:t},o={className:"string",contains:[e.BACKSLASH_ESCAPE,s],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:/<<[-~]?'?(\w+)\n(?:[^\n]*\n)*?\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,s]})]}]},l="[0-9](_?[0-9])*",c={className:"number",relevance:0,variants:[{begin:`\\b([1-9](_?[0-9])*|0)(\\.(${l}))?([eE][+-]?(${l})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},g={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:t},d=[o,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(r)},{className:"function",begin:Ue(/def\s+/,(u=n+"\\s*(\\(|;|$)",Ue("(?=",u,")"))),relevance:0,keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),g].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[o,{begin:n}],relevance:0},c,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:t},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,s],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(i,r),relevance:0}].concat(i,r);var u;s.contains=d,g.contains=d;const b=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",starts:{end:"$",contains:d}}];return r.unshift(i),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:t,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(b).concat(r).concat(d)}};var He=function(e){const n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:/\$\{/,end:/\}/}]},t={className:"string",variants:[{begin:'"""',end:'"""'},{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},a={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},i={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},r={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[a]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[a]},i]},s={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[i]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},a,s,r,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}};var Ze=function(e){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#]/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}};function Ge(e){return e?"string"==typeof e?e:e.source:null}function Fe(...e){return e.map((e=>Ge(e))).join("")}function qe(...e){return"("+e.map((e=>Ge(e))).join("|")+")"}var We=function(e){const n=e.COMMENT("--","$"),t=["true","false","unknown"],a=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],i=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],r=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],s=i,o=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update ","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!i.includes(e))),l={begin:Fe(/\b/,qe(...s),/\s*\(/),keywords:{built_in:s}};return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{$pattern:/\b[\w\.]+/,keyword:function(e,{exceptions:n,when:t}={}){const a=t;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?`${e}|0`:e))}(o,{when:e=>e.length<3}),literal:t,type:a,built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]},contains:[{begin:qe(...r),keywords:{$pattern:/[\w\.]+/,keyword:o.concat(r),literal:t,type:a}},{className:"type",begin:qe("double precision","large object","with timezone","without timezone")},l,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,n,{className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}};function Qe(e){return e?"string"==typeof e?e:e.source:null}function Xe(e){return Ve("(?=",e,")")}function Ve(...e){return e.map((e=>Qe(e))).join("")}function Je(...e){return"("+e.map((e=>Qe(e))).join("|")+")"}var Ye=function(e){const n=Ve(/[A-Z_]/,Ve("(",/[A-Z0-9_.-]*:/,")?"),/[A-Z0-9_.-]*/),t={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},a={begin:/\s/,contains:[{className:"meta-keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},i=e.inherit(a,{begin:/\(/,end:/\)/}),r=e.inherit(e.APOS_STRING_MODE,{className:"meta-string"}),s=e.inherit(e.QUOTE_STRING_MODE,{className:"meta-string"}),o={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[a,s,r,i,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[a,i,s,r]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},t,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[o],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[o],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:Ve(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:n,relevance:0,starts:o}]},{className:"tag",begin:Ve(/<\//,Xe(Ve(n,/>/))),contains:[{className:"name",begin:n,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}};var en=function(e){var n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},s={end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},o={begin:/\{/,end:/\}/,contains:[s],illegal:"\\n",relevance:0},l={begin:"\\[",end:"\\]",contains:[s],illegal:"\\n",relevance:0},c=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",relevance:10},{className:"string",begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type",begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},r,{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},o,l,a],g=[...c];return g.pop(),g.push(i),s.contains=g,{name:"YAML",case_insensitive:!0,aliases:["yml"],contains:c}};!function(){"use strict";ne.registerLanguage("asciidoc",ae),ne.registerLanguage("bash",re),ne.registerLanguage("css",ue),ne.registerLanguage("diff",be),ne.registerLanguage("dockerfile",me),ne.registerLanguage("gradle",he),ne.registerLanguage("groovy",_e),ne.registerLanguage("http",ve),ne.registerLanguage("java",xe),ne.registerLanguage("javascript",Te),ne.registerLanguage("json",Ce),ne.registerLanguage("kotlin",$e),ne.registerLanguage("markdown",je),ne.registerLanguage("nix",ze),ne.registerLanguage("properties",Pe),ne.registerLanguage("ruby",Ke),ne.registerLanguage("scala",He),ne.registerLanguage("shell",Ze),ne.registerLanguage("bash",Ze),ne.registerLanguage("sql",We),ne.registerLanguage("xml",Ye),ne.registerLanguage("yaml",en),ne.configure({ignoreUnescapedHTML:!0});for(const e of document.querySelectorAll("pre.highlight > code"))ne.highlightBlock(e)}()}(); +!function(){"use strict";function t(t){const e=n('
');return t.prepend(e),e}function e(t,e){const o=t.querySelector(".title").textContent,c=t.querySelectorAll(".content").item(0),s=function(t,e){let n=t.nextElementSibling;for(;n;){if(n.matches(e))return n;n=n.nextElementSibling}}(t,".colist");s&&c.append(s);const r=n('
'+o+"
");return r.dataset.blockName=o,c.dataset.blockName=o,e.append(r),{tabElement:r,content:c}}function n(t){const e=document.createElement("template");return e.innerHTML=t,e.content.firstChild}function o(t){let e=t.previousElementSibling;for(;e&&!e.classList.contains("primary");)e=e.previousElementSibling;return e}function c(t){const e=this.textContent;window.localStorage.setItem(t,e);for(const n of document.querySelectorAll(".tab"))r(n)===t&&n.textContent===e&&s(n)}function s(t){for(const e of t.parentNode.children)e.classList.remove("selected");t.classList.add("selected");for(const e of t.parentNode.parentNode.children)e.classList.contains("content")&&(t.dataset.blockName===e.dataset.blockName?e.classList.remove("hidden"):e.classList.add("hidden"))}function r(t){const e=[];for(t of t.parentNode.querySelectorAll(".tab"))e.push(t.textContent.toLowerCase());return e.sort().join("-")}window.addEventListener("load",(function(){(function(){for(const n of document.querySelectorAll(".primary")){if(n.querySelector("div.switch"))return void console.debug("Skipping tabs due to existing blockswitches");e(n,t(n)).tabElement.classList.add("selected"),n.querySelector(".title").remove(),n.classList.add("tabs-content")}for(const t of document.querySelectorAll(".secondary")){const n=o(t);if(n){const o=e(t,n.querySelector(".tabs"));o.content.classList.add("hidden"),n.append(o.content),t.remove()}else console.error("Found secondary block with no primary sibling")}})(),function(){for(const t of document.querySelectorAll(".tab")){const e=r(t);t.addEventListener("click",c.bind(t,e)),t.textContent===window.localStorage.getItem(e)&&s(t)}}()}))}(); +!function(){var t=function(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)},e={};(function(t){(function(){var n="object"==typeof t&&t&&t.Object===Object&&t;e=n}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{});var n="object"==typeof self&&self&&self.Object===Object&&self,o=e||n||Function("return this")(),r=function(){return o.Date.now()},i=/\s/;var c=function(t){for(var e=t.length;e--&&i.test(t.charAt(e)););return e},u=/^\s+/;var a=function(t){return t?t.slice(0,c(t)+1).replace(u,""):t},l=o.Symbol,f=Object.prototype,d=f.hasOwnProperty,s=f.toString,m=l?l.toStringTag:void 0;var v=function(t){var e=d.call(t,m),n=t[m];try{t[m]=void 0;var o=!0}catch(t){}var r=s.call(t);return o&&(e?t[m]=n:delete t[m]),r},p=Object.prototype.toString;var g=function(t){return p.call(t)},h=l?l.toStringTag:void 0;var y=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":h&&h in Object(t)?v(t):g(t)};var w=function(t){return null!=t&&"object"==typeof t};var E=function(t){return"symbol"==typeof t||w(t)&&"[object Symbol]"==y(t)},b=/^[-+]0x[0-9a-f]+$/i,L=/^0b[01]+$/i,j=/^0o[0-7]+$/i,x=parseInt;var S=function(e){if("number"==typeof e)return e;if(E(e))return NaN;if(t(e)){var n="function"==typeof e.valueOf?e.valueOf():e;e=t(n)?n+"":n}if("string"!=typeof e)return 0===e?e:+e;e=a(e);var o=L.test(e);return o||j.test(e)?x(e.slice(2),o?2:8):b.test(e)?NaN:+e},T=Math.max,O=Math.min;var N=function(e,n,o){var i,c,u,a,l,f,d=0,s=!1,m=!1,v=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function p(t){var n=i,o=c;return i=c=void 0,d=t,a=e.apply(o,n)}function g(t){return d=t,l=setTimeout(y,n),s?p(t):a}function h(t){var e=t-f;return void 0===f||e>=n||e<0||m&&t-d>=u}function y(){var t=r();if(h(t))return w(t);l=setTimeout(y,function(t){var e=n-(t-f);return m?O(e,u-(t-d)):e}(t))}function w(t){return l=void 0,v&&i?p(t):(i=c=void 0,a)}function E(){var t=r(),e=h(t);if(i=arguments,c=this,f=t,e){if(void 0===l)return g(f);if(m)return clearTimeout(l),l=setTimeout(y,n),p(f)}return void 0===l&&(l=setTimeout(y,n)),a}return n=S(n)||0,t(o)&&(s=!!o.leading,u=(m="maxWait"in o)?T(S(o.maxWait)||0,n):u,v="trailing"in o?!!o.trailing:v),E.cancel=function(){void 0!==l&&clearTimeout(l),d=0,i=f=c=l=void 0},E.flush=function(){return void 0===l?a:w(r())},E};var q=function(e,n,o){var r=!0,i=!0;if("function"!=typeof e)throw new TypeError("Expected a function");return t(o)&&(r="leading"in o?!!o.leading:r,i="trailing"in o?!!o.trailing:i),N(e,n,{leading:r,maxWait:n,trailing:i})};!function(){"use strict";let t,e,n,o,r,i,c=null,u=!1;function a(){v();const t=r.get(window.location.hash),e=g(window.location.hash);t&&E(e)&&(u=!0,b("activating window location hash"),y(t.parentElement)),f()}window.addEventListener("load",(function(){if(t=document.querySelector("#toc"),e=document.querySelector("#toggle-toc"),n=document.querySelector("#content"),!t||!n)return;o=function(){const e=r(),o=[];for(let t=0;t<=e;t++)o.push("h"+(t+1)+"[id]");return n.querySelectorAll(o);function r(){let e=1;for(const n of t.querySelectorAll("ul","ol"))e=Math.max(e,i(n));return e}function i(e){let n=0;for(;e&&e!==t;)n+="UL"===e.nodeName||"OL"===e.nodeName?1:0,e=e.parentElement;return e?n:-1}}(),r=function(){const e=new Map;for(const n of t.querySelectorAll("li > a")){const t=n.getAttribute("href");t&&e.set(t,n)}return e}(),i=function(){const t=new Map;for(const e of o){const n=h(e);if(n){const o=r.get(n);if(o){const n=o.parentElement;t.set(e,n)}}}return t}(),a(),window.addEventListener("hashchange",a),window.addEventListener("scroll",l),window.addEventListener("scroll",f),window.addEventListener("resize",d),t.addEventListener("click",s),e.addEventListener("click",m)}));const l=q((function(){v(),u||p()}),50,{leading:!0}),f=N((function(){if(b("scrolling ended"),v(),u=!1,c){E(g(h(c)))||p()}else p()}),50),d=q((function(){v()}),50,{leading:!0});function s(t){if("A"===t.target.nodeName){const e=t.target.parentElement;if(e&&"back-to-index"===e.id)return;u=!0,b("activating clicked toc element"),y(t.target.parentElement)}}function m(t){t.stopPropagation();document.body.classList.toggle("show-toc")?document.documentElement.addEventListener("click",m):document.documentElement.removeEventListener("click",m)}function v(){const t=window.getComputedStyle(document.documentElement),e=parseInt(t.getPropertyValue("--layout-banner-height"),10);w()>=e?document.body.classList.add("fixed-toc"):document.body.classList.remove("fixed-toc")}function p(){b("activating top header element");const t=function(){const t=w()+45;for(let e=0;et)return o[e-1>=0?e-1:0];return o[o.length-1]}();y(i.get(t))}function g(t){for(let e=0;e=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)}function b(t){false}}()}(); +//# sourceMappingURL=site.js.map diff --git a/components/sbm-recipes-boot-upgrade/pom.xml b/components/sbm-recipes-boot-upgrade/pom.xml index 377432283..3477156d0 100644 --- a/components/sbm-recipes-boot-upgrade/pom.xml +++ b/components/sbm-recipes-boot-upgrade/pom.xml @@ -27,8 +27,11 @@ sbm-recipes-boot-upgrade + UTF-8 + UTF-8 11 11 + 0.0.3 @@ -76,5 +79,22 @@ ${openrewrite.version} test + + + io.spring.asciidoctor.backends + spring-asciidoctor-backends + ${spring-asciidoctor-backends.version} + + + + + spring-release + Spring Releases + https://repo.spring.io/release + + false + + + \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/report.html b/components/sbm-recipes-boot-upgrade/report.html new file mode 100644 index 000000000..f9d54f44f --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/report.html @@ -0,0 +1,174 @@ + + + + + + + + +Spring Boot 3 Upgrade Report + + + + + + +
+
+
+ +
+
+

1. Introduction

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

Scanned dir

/Users/fkrueger/projects/spring-boot-migrator/components/sbm-recipes-boot-upgrade/target/dummy-test-path

Revision

Scanned project not under Git

Coordinate

com.example:dummy-root:0.1.0-SNAPSHOT

Boot version

2.7.3

Changes

1

+
+

The application was scanned and matched against the changes listed in the +Spring Boot 2.5 Release Notes +as well as from Spring Framework 5.x Release Notes.

+
+
+

The Relevant Changes section lists all potentially required changes to upgrade the scanned application to Spring Boot 2.5.6.

+
+
+ + + + + +
+ + +JDK 17 is required for Spring Boot 3 +
+
+
+
+
+

2. Relevant Changes

+
+
+

This section lists the changes SBM found to be applicable to upgrade the scanned application to Spring Boot 3.0.0.

+
+
+

2.1. Changes to Data Properties

+
+

Issue: #123, Contributors: @fabapp2

+
+
+

What Changed

+
+

The data prefix has been reserved for Spring Data and any properties under the data prefix imply that Spring +Data is required on the classpath.

+
+
+
+

Why is the application affected

+
+

The scan found properties with spring.data prefix but no dependency matching org.springframework.data:.*.

+
+
+ +
+
+
+

Remediation

+
+

Either add spring-data dependency, rename the property or remove it in case it’s not required anymore.

+
+
+

We want to say thank you to all Contributors:

+
+
+

Generated by Spring Boot Migrator (experimental)

+
+
+
+
+
+
+ +
+
+
+ + \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade/common/UpgradeReportUtil.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade/common/UpgradeReportUtil.java index 9fbe8ea89..84e4dd2b1 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade/common/UpgradeReportUtil.java +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade/common/UpgradeReportUtil.java @@ -18,9 +18,7 @@ import freemarker.template.Configuration; import freemarker.template.Template; -import org.asciidoctor.Asciidoctor; -import org.asciidoctor.Options; -import org.asciidoctor.SafeMode; +import org.asciidoctor.*; import java.io.StringWriter; import java.util.Map; @@ -39,14 +37,18 @@ public static String renderMarkdown(Map params, Configuration co public static String renderHtml(String markdown) { + return renderHtml(markdown, "spring-html"); + } + + public static String renderHtml(String markdown, String backend) { Asciidoctor asciidoctor = Asciidoctor.Factory.create(); String html = asciidoctor.convert(markdown, - Options.builder() - .toFile(true) - .backend("html5") - .headerFooter(true) - .safe(SafeMode.UNSAFE) - .build()); + Options.builder() + .toFile(true) + .backend(backend) + .headerFooter(true) + .safe(SafeMode.SERVER) + .build()); return html; } } diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/report/Boot_24_25_Introduction.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/report/Boot_24_25_Introduction.java index 6983984a5..075947ef0 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/report/Boot_24_25_Introduction.java +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/report/Boot_24_25_Introduction.java @@ -16,8 +16,8 @@ package org.springframework.sbm.boot.upgrade_24_25.report; import org.springframework.sbm.boot.UpgradeSectionBuilder; -import org.springframework.sbm.boot.asciidoctor.IntroductionSection; import org.springframework.sbm.boot.asciidoctor.Section; +import org.springframework.sbm.boot.asciidoctor.IntroductionSection; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.build.api.BuildFile; diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/SpringBoot30UpgradeReport.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/SpringBoot30UpgradeReport.java index 1c4e6e6ac..cf16b5d26 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/SpringBoot30UpgradeReport.java +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/SpringBoot30UpgradeReport.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import freemarker.template.Configuration; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.sbm.boot.UpgradeSectionBuilder; import org.springframework.sbm.boot.asciidoctor.Section; import org.springframework.sbm.boot.upgrade.common.UpgradeReportUtil; import org.springframework.sbm.boot.upgrade_24_25.report.Boot_24_25_Introduction; diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportAction.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportAction.java new file mode 100644 index 000000000..fba62771e --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportAction.java @@ -0,0 +1,186 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.Action; +import org.springframework.sbm.engine.recipe.Condition; +import org.springframework.sbm.project.resource.StringProjectResource; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Special Action generates a Spring Boot Upgrade report. + * + * After being deserialized from {@code YAML}, the Action renders the {@link SpringBootUpgradeReportSection}s + * as Asciidoctor and adds it into an Asciidoctor report template. + * The Asciidoctor report is then rendered to HTML and written to {@code filename}.html in the project directory. + * + * @author Fabian Krüger + */ +@Setter +@Getter +@SuperBuilder +@NoArgsConstructor +public class SpringBootUpgradeReportAction implements Action { + + /** + * Provides data to render header and footer. + */ + public interface DataProvider { + Map getData(ProjectContext context, @Valid List sections); + } + + @NotNull + private Condition condition; + + /** + * The filename of the generated report, {@code .html} will be appended. + */ + @NotEmpty + private String file; + /** + * The header of the report + */ + private String header; + /** + * The footer of the report + */ + private String footer; + @JsonIgnore + @Autowired + private SpringBootUpgradeReportRenderer upgradeReportRenderer; + + @JsonIgnore + @Autowired + private SpringBootUpgradeReportFreemarkerSupport freemarkerSupport; + + @JsonIgnore + @Autowired + private DataProvider dataProvider = new DataProvider() { + @Override + public Map getData(ProjectContext context, @Valid List sections) { + return Map.of(); + } + }; + + @Valid + List sections; + + @Override + public String getDescription() { + return "Creates a Upgrade report for Spring Boot 3."; + } + + @Override + public String getDetailedDescription() { + return "Creates a Upgrade report for Spring Boot 3."; + } + + @Override + public Condition getCondition() { + return condition; + } + + @Override + public void apply(ProjectContext context) { + + + List renderedSections = new ArrayList<>(); + sections.stream() + .filter(s -> s.shouldRender(context)) + .forEach(section -> { + renderedSections.add(section.render(context)); + }); + + Map data = dataProvider.getData(context, sections); + String renderedHeader = renderTemplate("header", header, data); + + String renderedFooter = renderTemplate("footer", footer, data); + + String report = renderReport(renderedHeader, renderedSections, renderedFooter); + String filename = file + ".html"; + context.getProjectResources().add(new StringProjectResource(context.getProjectRootDirectory(), context.getProjectRootDirectory().resolve(filename), report)); + } + + private String renderReport(String renderedHeader, List sections, String renderedFooter) { + String key = "report"; + String content = """ + ${header} + + <#list sections as changeSection> + ${changeSection} + + + ${footer} + """; + + Map data = Map.of( + "header", renderedHeader, + "sections", sections, + "footer", renderedFooter + ); + + String renderedTemplate = renderTemplate(key, content, data); + String renderedReport = upgradeReportRenderer.renderReport(renderedTemplate); + return renderedReport; + } + + private String renderTemplate(String key, String content, Map data) { + + try (StringWriter writer = new StringWriter()) { + freemarkerSupport.getStringLoader().putTemplate(key, content); + Template report = freemarkerSupport.getConfiguration().getTemplate(key); + report.process(data, writer); + return writer.toString(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (TemplateException e) { + throw new RuntimeException(e); + } + } + + @Override + public void applyInternal(ProjectContext context) { + apply(context); + } + + @Override + public ApplicationEventPublisher getEventPublisher() { + return null; + } + + @Override + public boolean isAutomated() { + return false; + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportActionDeserializer.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportActionDeserializer.java new file mode 100644 index 000000000..97b0eca43 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportActionDeserializer.java @@ -0,0 +1,90 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.sbm.engine.recipe.Action; +import org.springframework.sbm.engine.recipe.ActionDeserializer; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * @author Fabian Krüger + */ +@Component +public class SpringBootUpgradeReportActionDeserializer implements ActionDeserializer { + @Override + public Action deserialize(ObjectMapper tolerantObjectMapper, Class actionClass, JsonNode node, AutowireCapableBeanFactory beanFactory) { + try { + SpringBootUpgradeReportAction action = (SpringBootUpgradeReportAction) tolerantObjectMapper.convertValue(node, actionClass); + + JsonNode dataProviderNode = node.get("dataProvider"); + if(dataProviderNode != null) { + String className = dataProviderNode.textValue(); + if(className == null || className.isEmpty()) { + throw new IllegalArgumentException("dataProvider for Action '"+action.getDescription()+"' was found but no fully qualified classname was provided."); + } + Class aClass = Class.forName(className); + Constructor constructor = aClass.getConstructor(null); + Object o = constructor.newInstance(); + SpringBootUpgradeReportAction.DataProvider dataProvider = (SpringBootUpgradeReportAction.DataProvider) o; + action.setDataProvider(dataProvider); + } + + JsonNode sections = node.get("sections"); + if (sections != null) { + if(ArrayNode.class.isInstance(sections)) { + ArrayNode arrayNode = (ArrayNode) sections; + for(int i=0; i < arrayNode.size(); i++) { + JsonNode helper = arrayNode.get(i).get("helper"); + String type = helper.textValue(); + Class aClass = Class.forName(type); + Constructor constructor = aClass.getConstructor(null); + Object o = constructor.newInstance(); + SpringBootUpgradeReportSection.Helper cast = (SpringBootUpgradeReportSection.Helper) aClass.cast(o); + SpringBootUpgradeReportSection section = action.getSections().get(i); + section.setHelper(cast); + beanFactory.autowireBean(section); + } + } + } else { + throw new IllegalArgumentException("Could not find required field 'sections' for SpringBootUpgradeReportAction with description '"+action.getDescription()+"'."); + } + beanFactory.autowireBean(action); + return action; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean canHandle(Class key) { + return SpringBootUpgradeReportAction.class.isAssignableFrom(key); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java new file mode 100644 index 000000000..72f2d78f3 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java @@ -0,0 +1,63 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.stereotype.Component; + +import javax.validation.Valid; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Fabian Krüger + */ +@Component +public class SpringBootUpgradeReportDataProvider implements SpringBootUpgradeReportAction.DataProvider { + @Override + public Map getData(ProjectContext context, @Valid List sections) { + Map data = new HashMap<>(); + + data.put("timestamp", Instant.now().toString()); + Set authors = sections + .stream() + .flatMap(s -> s.getAuthors().stream()) + .collect(Collectors.toSet()); + data.put("contributors", authors); + + String scannedCoordinate = context.getApplicationModules().getRootModule().getBuildFile().getCoordinates(); + data.put("scannedCoordinate", scannedCoordinate); + + data.put("scannedProjectRoot", context.getProjectRootDirectory()); + + data.put("revision", context.getRevision()); + + if(context.getBuildFile().getName().isPresent()) { + data.put("projectName", context.getBuildFile().getName().get()); + } + + data.put("numberOfChanges", sections.size()); + + // FIXME: Retrieve Boot version from Finder + data.put("bootVersion", "2.7.3"); + + return data; + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportFreemarkerSupport.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportFreemarkerSupport.java new file mode 100644 index 000000000..d60147616 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportFreemarkerSupport.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import freemarker.cache.StringTemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.Version; +import lombok.Getter; +import org.springframework.stereotype.Component; + +/** + * @author Fabian Krüger + */ +@Component +@Getter +class SpringBootUpgradeReportFreemarkerSupport { + + private final Configuration configuration; + private final StringTemplateLoader stringLoader; + + public SpringBootUpgradeReportFreemarkerSupport() { + + Version version = new Version("2.3.0"); + configuration = new Configuration(version); + stringLoader = new StringTemplateLoader(); + configuration.setTemplateLoader(stringLoader); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportRenderer.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportRenderer.java new file mode 100644 index 000000000..9bfd76247 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportRenderer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import org.springframework.sbm.boot.upgrade.common.UpgradeReportUtil; +import org.springframework.stereotype.Component; + +/** + * @author Fabian Krüger + */ +@Component +public class SpringBootUpgradeReportRenderer { + public String renderReport(String s) { + String html = UpgradeReportUtil.renderHtml(s, "html5"); + return html; + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java new file mode 100644 index 000000000..f4b001850 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java @@ -0,0 +1,203 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import freemarker.core.ParseException; +import freemarker.template.*; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.Condition; + +import javax.validation.constraints.NotEmpty; +import java.io.IOException; +import java.io.StringWriter; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * A section in a generated report for Spring Boot 3 upgrade, rendered as Asciidoc from a freemarker template string. + * The {@link Helper} is condition and evaluates if the section should be rendered. + * If the section should be rendered, the {@link Helper} provides the data extracted from {@link ProjectContext} to render the template. + * + * @author Fabian Krüger + */ +@Getter +@Setter +public class SpringBootUpgradeReportSection { + + public static final String CHANGE = "What Changed"; + public static final String AFFECTED = "Why is the application affected"; + public static final String REMEDIATION = "Remediation"; + + public boolean shouldRender(ProjectContext context) { + return helper.evaluate(context); + } + + /** + * Helper acting as {@link Condition} and data provide for a {@link SpringBootUpgradeReportSection}. + */ + public interface Helper extends Condition { + /** + * @return {@code Map} the model data for the template. + */ + Map getData(ProjectContext context); + } + + /** + * Section title + */ + @NotEmpty + private String title; + /** + * Describes the change, e.g a section from Release Notes. + */ + @NotEmpty + private String change; + /** + * Describes why the scanned application is affected by this change. + */ + @NotEmpty + private String affected; + /** + * Describes required changes to the scanned application. + */ + @NotEmpty + private String remediation; + /** + * The id of the GitHub issue to this report section. + */ + @NotNull + private Integer gitHubIssue; + /** + * Contributors with pattern {@code Given Name[@githubHandle]}. + */ + @NotNull + private Set contributors; + /** + * The name of the recipe for automated migration or {@code null} of none exist. + */ + @Nullable + private String recipe; + + @JsonIgnore + private Helper helper; + @JsonIgnore + @Autowired + private SpringBootUpgradeReportFreemarkerSupport freemarkerSupport; + + public List getAuthors() { + return contributors.stream() + .map(c -> { + Matcher matcher = Pattern.compile("(.*)\\[(.*)\\]").matcher(c); + if(matcher.find()) { + String name = matcher.group(1); + String handle = matcher.group(2).replace("@", ""); + return new Author(name, handle); + } else { + return null; + } + }) + .collect(Collectors.toList()); + } + + public String render(ProjectContext context) { + if (getHelper().evaluate(context)) { + Map params = new HashMap<>(); + params = getHelper().getData(context); + + try (StringWriter writer = new StringWriter()) { + String templateContent = buildTemplate(); + String templateName = getTitle().replace(" ", "") + UUID.randomUUID(); + freemarkerSupport.getStringLoader().putTemplate(templateName, templateContent); + Template t = freemarkerSupport.getConfiguration().getTemplate(templateName); + t.process(params, writer); + return writer.toString(); + } catch (TemplateException e) { + throw new RuntimeException(e); + } catch (TemplateNotFoundException e) { + throw new RuntimeException(e); + } catch (ParseException e) { + throw new RuntimeException(e); + } catch (MalformedTemplateNameException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + throw new IllegalArgumentException("Could not render Sectipn '"+ getTitle()+"', evaluating the context returned false"); + } + + @NotNull + private String buildTemplate() { + StringBuilder sb = new StringBuilder(); + + String ls = System.lineSeparator(); + + sb.append("=== ").append(getTitle()).append(ls); + if(gitHubIssue != null) { + sb.append("Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/").append(gitHubIssue).append("[#").append(gitHubIssue).append("]"); + } + if(contributors != null && gitHubIssue != null) { + sb.append(", "); + } else { + sb.append(ls); + } + if(contributors != null) { + List authors = getAuthors(); + sb.append("Contributors: "); + authors.stream() + .forEach(a -> { + sb.append("https://github.com/").append(a.getHandle()).append("[@").append(a.getHandle()).append("^, role=\"ext-link\"]"); + }); + sb.append(ls); + } + sb.append(ls) + .append("==== " + CHANGE).append(ls) + .append(getChange()).append(ls) + .append(ls) + .append("==== " + AFFECTED).append(ls) + .append(getAffected()).append(ls) + .append(ls) + .append("==== " + REMEDIATION).append(ls) + .append(getRemediation()).append(ls) + .append(ls); + + + + + String templateContent = sb.toString(); + + return templateContent; + } + + + @Getter + @RequiredArgsConstructor + @EqualsAndHashCode + public class Author { + private final String name; + private final String handle; + } +} \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesHelper.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesHelper.java new file mode 100644 index 000000000..252cff578 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesHelper.java @@ -0,0 +1,90 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report.helper; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.sbm.boot.properties.api.SpringBootApplicationProperties; +import org.springframework.sbm.boot.properties.search.SpringBootApplicationPropertiesResourceListFilter; +import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportAction; +import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportSection; +import org.springframework.sbm.build.migration.conditions.NoDependencyExistMatchingRegex; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.Condition; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Fabian Krüger + */ +public class ChangesToDataPropertiesHelper implements SpringBootUpgradeReportSection.Helper> { + + private Map> data = new HashMap<>(); + + @Override + public String getDescription() { + return ""; + } + + @Override + public boolean evaluate(ProjectContext context) { + boolean noDepExists = new NoDependencyExistMatchingRegex(List.of("org\\.springframework\\.data\\:.*")).evaluate( + context); + List search = context + .search(new SpringBootApplicationPropertiesResourceListFilter()); + + data = new HashMap<>(); + + search.forEach(p -> { + Path absolutePath = p.getAbsolutePath(); + List propertiesFound = p + .getProperties() + .keySet() + .stream() + .filter(k -> k.toString().startsWith("spring.data.")) + .collect(Collectors.toList()); + if (!propertiesFound.isEmpty()) { + if (data.containsKey("matches")) { + data.get("matches").add(new Match(absolutePath.toString(), p.getSourcePath().toString(), propertiesFound)); + } else { + List matches = new ArrayList<>(); + matches.add(new Match(absolutePath.toString(), p.getSourcePath().toString(), propertiesFound)); + data.put("matches", matches); + } + } + + }); + return noDepExists && !data.isEmpty(); + } + + @Override + public Map> getData(ProjectContext context) { + return data; + } + + @RequiredArgsConstructor + @Getter + public class Match { + private final String absolutePath; + private final String relativePath; + private final List propertiesFound; + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatHelper.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatHelper.java new file mode 100644 index 000000000..5f56b8735 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatHelper.java @@ -0,0 +1,48 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report.helper; + +import org.springframework.sbm.boot.upgrade_27_30.filter.LoggingDateFormatPropertyFinder; +import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportSection; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.properties.api.PropertiesSource; + +import java.util.List; +import java.util.Map; + +/** + * @author Fabian Krüger + */ +public class LoggingDateFormatHelper implements SpringBootUpgradeReportSection.Helper { + + private List propertiesSources; + + @Override + public String getDescription() { + return ""; + } + + @Override + public boolean evaluate(ProjectContext context) { + propertiesSources = context.search(new LoggingDateFormatPropertyFinder()); + return propertiesSources.isEmpty(); + } + + @Override + public Map getData(ProjectContext context) { + return Map.of("properties", propertiesSources); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml index c88830911..6a1d8982c 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml +++ b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml @@ -620,3 +620,15 @@ - org.openrewrite.properties.DeleteProperty: propertyKey: spring.jta.log-dir + - type: org.springframework.sbm.boot.properties.actions.AddSpringBootApplicationPropertiesAction + description: "Adds default spring boot properties to project. For multi-module project, adds default spring boot properties to every module with jar packaging" + condition: + type: org.springframework.sbm.boot.upgrade_27_30.conditions.LoggingDateFormatCondition + addDefaultPropertiesFileToTopModules: true + - type: org.springframework.sbm.boot.upgrade_27_30.actions.Boot_27_30_AddLoggingDateFormat + + description: "Sets logging date format to yyyy-MM-dd HH:mm:ss.SSS" + condition: + type: org.springframework.sbm.boot.upgrade_27_30.conditions.LoggingDateFormatCondition + + diff --git a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml new file mode 100644 index 000000000..fc6309836 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml @@ -0,0 +1,119 @@ +- name: boot-2.7-3.0-upgrade-report2 + description: Create a report for Spring Boot Upgrade from 2.7.x to 3.0.x + condition: + type: org.springframework.sbm.boot.common.conditions.IsSpringBootProject + versionPattern: "2\\.4\\..*|2\\.5\\..*" + + actions: + + - type: org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportAction + file: report + condition: + type: org.springframework.sbm.common.migration.conditions.TrueCondition + + dataProvider: org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportDataProvider + + header: |- + [[index]] + = Spring Boot 3 Upgrade Report + <#if contributors?has_content> + <#list contributors as contributor> + ${contributor.name}<#sep>, + + + :source-highlighter: highlight.js + :highlightjs-languages: java + :linkcss: + :doctype: book + :idprefix: + :idseparator: - + :toc: left + :sectnumlevels: 2 + :toclevels: 2 + :tabsize: 4 + :numbered: + :sectanchors: + :sectnums: + :hide-uri-scheme: + :docinfo: shared,private + :attribute-missing: warn + :chomp: default headers packages + :spring-boot-artifactory-repo: snapshot + :github-tag: main + :spring-boot-version: current + + == Introduction + <#assign coordinates>${scannedCoordinate} + [cols="1h,3"] + |=== + | Scanned dir | `${scannedProjectRoot}` + | Revision | <#if revision?has_content>`${revision}`<#else>Scanned project not under Git + <#if projectName?has_content> + | Project name | ${projectName} + + | Coordinate | `${scannedCoordinate}` + | Boot version | `${bootVersion}` + <#if numberOfChanges?has_content> + | Changes | ${numberOfChanges} + + |=== + + The application was scanned and matched against the changes listed in the + https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes[Spring Boot 2.5 Release Notes] + as well as from https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x[Spring Framework 5.x Release Notes]. + + The Relevant Changes section lists all potentially required changes to upgrade the scanned application to Spring Boot 2.5.6. + + NOTE: JDK 17 is required for Spring Boot 3 + + == Relevant Changes + + This section lists the changes SBM found to be applicable to upgrade the scanned application to Spring Boot 3.0.0. + + sections: + + - title: Changes to Data Properties + helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ChangesToDataPropertiesHelper + change: |- + The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring + Data is required on the classpath. + affected: |- + The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`. + + <#list matches as match> + * file://${match.absolutePath}[`${match.relativePath}`] + <#list match.propertiesFound as property> + ** `${property}` + + + + remediation: |- + Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore. + gitHubIssue: 123 + recipe: boot-2.7-3.0-upgrade-report + contributors: + - "Fabian Krüger[@fabapp2]" + + + + - title: Logging Date Format + helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.LoggingDateFormatHelper + change: |- + The default format for the date and time component of log messages for Logback and Log4j2 has changed to + align with the ISO-8601 standard. The new default format `yyyy-MM-dd’T’HH:mm:ss.SSSXXX` uses a `T` to + separate the date and time instead of a space character and adds the timezone offset to the end. + The `LOG_DATEFORMAT_PATTERN` environment variable or `logging.pattern.dateformat` property can be used to + restore the previous default value of `yyyy-MM-dd HH:mm:ss.SSS`. + affected: |- + The scan found no property `logging.pattern.dateformat`. + remediation: |- + Set logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS to fall back to the previous log format. + gitHubIssue: 489 + recipe: boot-2.7-3.0-upgrade-report + contributors: + - "Fabian Krüger[@fabapp2]" + + footer: |- + We want to say thank you to all Contributors: + + Generated by Spring Boot Migrator (experimental) \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/confitions/LoggingDateFormatConditionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/conditions/LoggingDateFormatConditionTest.java similarity index 94% rename from components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/confitions/LoggingDateFormatConditionTest.java rename to components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/conditions/LoggingDateFormatConditionTest.java index 6d795e6a7..f7dfed982 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/confitions/LoggingDateFormatConditionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/conditions/LoggingDateFormatConditionTest.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package org.springframework.sbm.boot.upgrade_27_30.confitions; +package org.springframework.sbm.boot.upgrade_27_30.conditions; import org.junit.jupiter.api.Test; import org.springframework.sbm.boot.properties.SpringApplicationPropertiesPathMatcher; import org.springframework.sbm.boot.properties.SpringBootApplicationPropertiesRegistrar; -import org.springframework.sbm.boot.upgrade_27_30.conditions.LoggingDateFormatCondition; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.project.resource.TestProjectContext; diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java new file mode 100644 index 000000000..b9bf7bf7c --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.sbm.boot.properties.SpringApplicationPropertiesPathMatcher; +import org.springframework.sbm.boot.properties.SpringBootApplicationPropertiesRegistrar; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +import java.nio.file.Path; +import java.util.Map; + +/** + * @author Fabian Krüger + */ +public class ChangesToDataPropertiesReportTest { + + @Test + @DisplayName("Changes to Data Properties") + void changesToDataPropertiesSection() { + ProjectContext context = TestProjectContext.buildProjectContext() + .addRegistrar(new SpringBootApplicationPropertiesRegistrar(new SpringApplicationPropertiesPathMatcher())) + .addProjectResource("src/main/resources/application.properties", "spring.data.foo=bar") + .addProjectResource("src/main/resources/application-another.properties", "spring.data.here=there") + .build(); + + SpringBootUpgradeReportTestSupport.generatedSection("Changes to Data Properties") + .fromProjectContext(context) + .shouldRenderAs( + """ + === Changes to Data Properties + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/123[#123], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + + ==== What Changed + The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring + Data is required on the classpath. + + ==== Why is the application affected + The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`. + + * file:///src/main/resources/application.properties[`src/main/resources/application.properties`] + ** `spring.data.foo` + * file:///src/main/resources/application-another.properties[`src/main/resources/application-another.properties`] + ** `spring.data.here` + + ==== Remediation + Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore. + + """, Map.of("PATH", Path + .of(".").toAbsolutePath().resolve(TestProjectContext.getDefaultProjectRoot()).toString())); + } + +} diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportActionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportActionTest.java new file mode 100644 index 000000000..78fefb055 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportActionTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.sbm.boot.properties.SpringApplicationPropertiesPathMatcher; +import org.springframework.sbm.boot.properties.SpringBootApplicationPropertiesRegistrar; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Map; + +/** + * @author Fabian Krüger + */ +class SpringBootUpgradeReportActionTest { + + @Test + void renderReport() throws IOException { + ProjectContext context = TestProjectContext.buildProjectContext() + .addRegistrar(new SpringBootApplicationPropertiesRegistrar(new SpringApplicationPropertiesPathMatcher())) + .addProjectResource("src/main/resources/application.properties", "spring.data.foo=bar") + .addProjectResource("src/main/resources/application-another.properties", "spring.data.here=there") + .build(); + + @Language("adoc") + String expectedOutput = """ + [[index]] + = Spring Boot 3 Upgrade Report + Fabian Krüger + :source-highlighter: highlight.js + :highlightjs-languages: java + :linkcss: + :doctype: book + :idprefix: + :idseparator: - + :toc: left + :sectnumlevels: 2 + :toclevels: 2 + :tabsize: 4 + :numbered: + :sectanchors: + :sectnums: + :hide-uri-scheme: + :docinfo: shared,private + :attribute-missing: warn + :chomp: default headers packages + :spring-boot-artifactory-repo: snapshot + :github-tag: main + :spring-boot-version: current + + == Introduction + [cols="1h,3"] + |=== + | Scanned dir | `` + | Revision | Scanned project not under Git + | Coordinate | `com.example:dummy-root:0.1.0-SNAPSHOT` + | Boot version | `2.7.3` + | Changes | 2 + |=== + + The application was scanned and matched against the changes listed in the + https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes[Spring Boot 2.5 Release Notes] + as well as from https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x[Spring Framework 5.x Release Notes]. + + The Relevant Changes section lists all potentially required changes to upgrade the scanned application to Spring Boot 2.5.6. + + NOTE: JDK 17 is required for Spring Boot 3 + + == Relevant Changes + + This section lists the changes SBM found to be applicable to upgrade the scanned application to Spring Boot 3.0.0.\s + + === Changes to Data Properties + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/123[#123], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + + ==== What Changed + The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring + Data is required on the classpath. + + ==== Why is the application affected + The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`. + + * file:///src/main/resources/application.properties[`src/main/resources/application.properties`] + ** `spring.data.foo` + * file:///src/main/resources/application-another.properties[`src/main/resources/application-another.properties`] + ** `spring.data.here` + + ==== Remediation + Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore. + + + === Logging Date Format + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/489[#489], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + + ==== What Changed + The default format for the date and time component of log messages for Logback and Log4j2 has changed to\s + align with the ISO-8601 standard. The new default format `yyyy-MM-dd’T’HH:mm:ss.SSSXXX` uses a `T` to\s + separate the date and time instead of a space character and adds the timezone offset to the end.\s + The `LOG_DATEFORMAT_PATTERN` environment variable or `logging.pattern.dateformat` property can be used to\s + restore the previous default value of `yyyy-MM-dd HH:mm:ss.SSS`. + + ==== Why is the application affected + The scan found no property `logging.pattern.dateformat`. + + ==== Remediation + Set logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS to fall back to the previous log format. + + + + We want to say thank you to all Contributors: + + Generated by Spring Boot Migrator (experimental) + """; + SpringBootUpgradeReportTestSupport.generatedReport() + .fromProjectContext(context) + .shouldRenderAs(expectedOutput, Map.of("PATH", Path.of(".").toAbsolutePath().resolve(TestProjectContext.getDefaultProjectRoot()).toString())); + + Files.deleteIfExists(Path.of(".").toAbsolutePath().resolve("report.html")); + Files.createFile(Path.of(".").toAbsolutePath().resolve("report.html")); + Files.writeString(Path.of(".").toAbsolutePath().resolve("report.html"), context.getProjectResources().get(3).print(), StandardOpenOption.TRUNCATE_EXISTING); + } + +} \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java new file mode 100644 index 000000000..d4091c83f --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java @@ -0,0 +1,164 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.sbm.boot.upgrade_27_30.report; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.Recipe; +import org.springframework.sbm.engine.recipe.Recipes; +import org.springframework.sbm.test.RecipeTestSupport; +import org.springframework.sbm.testhelper.common.utils.TestDiff; +import org.springframework.test.util.ReflectionTestUtils; +import org.stringtemplate.v4.ST; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Fabian Krüger + */ +public class SpringBootUpgradeReportTestSupport { + + public static SectionProjectContext generatedSection(String title) { + SectionBuilderData builderData = new SectionBuilderData(); + builderData.setTitle(title); + return new SectionProjectContext(builderData); + } + + public static SectionProjectContext generatedReport() { + BuilderData builderData = new ReportBuilderData(); + return new SectionProjectContext(builderData); + } + + public static class SectionProjectContext { + private BuilderData builderData; + + public SectionProjectContext(BuilderData builderData) { + this.builderData = builderData; + } + + public Assertion fromProjectContext(ProjectContext context) { + builderData.setContext(context); + return new Assertion(builderData); + } + + } + + public static class Assertion { + private BuilderData builderData; + + public Assertion(BuilderData builderData) { + this.builderData = builderData; + } + + + public void shouldRenderAs(String expectedOutput) { + shouldRenderAs(expectedOutput, Map.of()); + } + + public void shouldRenderAs(String expectedOutput, Map templateVariables) { + String expectedOutputRendered = replacePlaceHolders(expectedOutput, templateVariables); + Consumer assertion = (s) -> assertThat(s).isEqualTo(expectedOutputRendered); + verify(assertion); + } + + public void shouldStartWith(String expectedOutput) { + shouldStartWith(expectedOutput, Map.of()); + } + + public void shouldStartWith(String expectedOutput, Map templateVariables) { + String expectedOutputRendered = replacePlaceHolders(expectedOutput, templateVariables); + Consumer assertion = (s) -> assertThat(s).as(TestDiff.of(s, expectedOutputRendered)).startsWith(expectedOutputRendered); + verify(assertion); + } + + private void verify(Consumer assertion) { + if(ReportBuilderData.class.isInstance(builderData)) { + ReportBuilderData reportBuilderData = ReportBuilderData.class.cast(builderData); + verify2(recipes -> { + Recipe recipe = recipes.getRecipeByName("boot-2.7-3.0-upgrade-report2").get(); + SpringBootUpgradeReportAction action = (SpringBootUpgradeReportAction) recipe.getActions().get(0); + ReflectionTestUtils.setField(action, "upgradeReportRenderer", + new SpringBootUpgradeReportRenderer() { + @Override + public String renderReport(String s) { + assertion.accept(s); + return super.renderReport(s); + } + }); + action.apply(reportBuilderData.getContext()); + }); + } else if(SectionBuilderData.class.isInstance(builderData)) { + SectionBuilderData sectionBuilderData = SectionBuilderData.class.cast(builderData); + verify2(recipes -> { + Recipe recipe = recipes.getRecipeByName("boot-2.7-3.0-upgrade-report2").get(); + SpringBootUpgradeReportAction action = (SpringBootUpgradeReportAction) recipe.getActions().get(0); + List sections = (List) ReflectionTestUtils.getField(recipe.getActions().get(0), "sections"); + List matchingSections = sections + .stream() + .filter(s -> s.getTitle().equals(builderData.getTitle())) + .collect(Collectors.toList()); + + if(matchingSections.size() != 1) { + fail("Found " + matchingSections.size() + " Sections with title '" + builderData.getTitle() + "'."); + } + + SpringBootUpgradeReportSection sectionUnderTest = matchingSections.get(0); + + + action.apply(builderData.getContext()); + String renderedSection = sectionUnderTest.render(builderData.getContext()); + assertion.accept(renderedSection); + }); + } + } + + private void verify2(Consumer recipesConsumer) { + RecipeTestSupport.testRecipe( + Path.of("recipes/boot-new-report.yaml"), recipesConsumer, + SpringBootUpgradeReportActionDeserializer.class, + SpringBootUpgradeReportFreemarkerSupport.class, + SpringBootUpgradeReportRenderer.class, + SpringBootUpgradeReportDataProvider.class + ); + } + + private String replacePlaceHolders(String expectedOutput, Map templateVariables) { + ST st = new ST(expectedOutput); + templateVariables.entrySet().stream().forEach(e -> st.add(e.getKey(), e.getValue())); + return st.render(); + } + } + + @Getter + @Setter + private static class BuilderData { + private ProjectContext context; + private String title; + } + private static class SectionBuilderData extends BuilderData { + } + + private static class ReportBuilderData extends BuilderData { + } +} diff --git a/docs/boot-3.0.0-M3-upgrade.adoc b/docs/boot-3.0.0-M3-upgrade.adoc index c7979bb9c..8cafac6f0 100644 --- a/docs/boot-3.0.0-M3-upgrade.adoc +++ b/docs/boot-3.0.0-M3-upgrade.adoc @@ -1,47 +1,276 @@ -[plantuml,modules,png] += Spring Boot 3.0 Upgrade Report +:report-recipe-file: https://github.com/spring-projects-experimental/spring-boot-migrator/blob/68f9c138d0a2bc138f5c9eb712559bb9a4b04578/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml[boot-new-report.yaml] + +== Upgrade Report + +The report is declared in `{report-recipe-file}` + +=== Change Sections + +Every change after 2.7.x should be covered in a section in the "Spring Boot 3 Upgrade Report". + +Every change section has these parts + +. A title +. The description of the change +. The description of why the scanned application is/might be affected +. How to remediate + +Every section is declared in YAML + +==== The title +[source,yaml] +.... + sections: + + - title: The title of the change in the Release Notes or GitHub issue +.... + +==== The Helper + +The `Helper` is condition and data provider for the template. +It must implement `ìsApplicable` and `getData` from `SpringBootUpgradeReportSection.Helper`. +All variables used in the template must be provided by `getData`. + +[source,java] +.... + public interface Helper extends Condition { + Map getData(ProjectContext context); + } +.... + +[source,yaml] +.... + helper: o.s.sbm.boot.upgrade_27_30.report.helper.ChangesToDataPropertiesHelper <1> +.... + +==== The Change + +[source,yaml] +.... + info: |- + Describes the change, e.g a section from Release Notes. + Links to the Release Note or other resources can be added here. +.... + +==== The Reason + +[source,yaml] +.... + reason: |- + The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`. + + <#list matches as match> <2> + * file://${match.absolutePath}[`${match.relativePath}`] + <#list match.propertiesFound as property> + ** `${property}` + + +.... + +==== Remediation + +[source,yaml] +.... + remediation: |- + Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore. + gitHubIssue: 123 + recipe: upgrade-to-spring-boot-3 + contributor: "Fabian Krüger[@fabapp2]" + +.... + +==== GitHubIssue + +[source,yaml] +.... + gitHubIssue: 123 + contributor: "Fabian Krüger[@fabapp2]" + recipe: upgrade-to-spring-boot-3 .... -component rewrite { -} -component "rewrite-spring" { -} -component "sbm-openrewrite-boot-upgrade" { -} -component "sbm-recipes-boot-upgrade" { -} -component "sbm-support-boot" { -} -component "sbm-openrewrite" { -} -component "sbm-core" { -} -note left of sbm-openrewrite - Only Helpers, Recipes and Visitors -end note -note top of sbm-recipes-boot-upgrade - Automated and manual SBM recipes - for Spring Boot upgrades -end note +<2> The template for the section can contain freemarker syntax, the data must be provided by the `Helper` + +=== Testing + +[source,java] +.... +<1> + ProjectContext context = TestProjectContext.buildProjectContext() + .addRegistrar(new SpringBootApplicationPropertiesRegistrar(new SpringApplicationPropertiesPathMatcher())) + .addProjectResource("src/main/resources/application.properties", "spring.data.foo=bar") + .addProjectResource("src/main/resources/application-another.properties", "spring.data.here=there") + .build(); + + SpringBootUpgradeReportTestSupport.generatedSection("Changes to Data Properties") <2> + .fromProjectContext(context) <3> + .shouldRenderAs( <4> + """ + == Changes to Data Properties + + === Description + The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring\s + Data is required on the classpath. + + === Why it needs to be changed + The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.* `. + + * file:///src/main/resources/application.properties[`src/main/resources/application.properties`] <5> + ** `spring.data.foo` + * file:///src/main/resources/application-another.properties[`src/main/resources/application-another.properties`] + ** `spring.data.here` + + === How to Resolve + Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore. + + GitHub-issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/123[=123] + """, + Map.of("PATH", Path.of(".").toAbsolutePath().resolve(TestProjectContext.getDefaultProjectRoot()).toString()) <6> + ); +.... + +<1> create the `ProjectContext` +<2> use `SpringBootUpgradeReportTestSupport` to test the section with given title +<3> pass in the `ProjectContext` +<4> provide the expected output +<5> `` will be replaced with the values from map +<6> provide values for replacement + + +==== The YAML + +https://www.tablesgenerator.com/markdown_tables[Markdown Table Generator] + +https://github.com/Buzzardo/spring-style-guide/blob/master/spring-style-guide.adoc[Spring Style Guide] + +[source,yaml] +.... +- name: boot-2.7-3.0-upgrade-report2 + description: Create a report for Spring Boot Upgrade from 2.7.x to 3.0.x + condition: + type: org.springframework.sbm.boot.common.conditions.IsSpringBootProject + versionPattern: "2\\.7\\..*|3\\.0\\..*" + + actions: + + - type: org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportAction + file: report + condition: + type: org.springframework.sbm.common.migration.conditions.TrueCondition + + dataProvider: org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportDataProvider + + header: |- + [[index]] + = Spring Boot 3 Upgrade Report + <#if contributors?has_content> + <#list contributors as contributor> + ${contributor.name}<#sep>, + + + :source-highlighter: highlight.js + :highlightjs-languages: java + :linkcss: + :doctype: book + :idprefix: + :idseparator: - + :toc: left + :sectnumlevels: 2 + :toclevels: 2 + :tabsize: 4 + :numbered: + :sectanchors: + :sectnums: + :hide-uri-scheme: + :docinfo: shared,private + :attribute-missing: warn + :chomp: default headers packages + :spring-boot-artifactory-repo: snapshot + :github-tag: main + :spring-boot-version: current + + == Introduction + <#assign coordinates>${scannedCoordinate} + [cols="1h,3"] + |=== + | Scanned dir | `${scannedProjectRoot}` + | Revision | <#if revision?has_content>`${revision}`<#else>Scanned project not under Git + <#if projectName?has_content> + | Project name | ${projectName} + + | Coordinate | `${scannedCoordinate}` + | Boot version | `${bootVersion}` + <#if numberOfChanges?has_content> + | Changes | ${numberOfChanges} + + |=== + + The application was scanned and matched against the changes listed in the + https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes[Spring Boot 2.5 Release Notes] + as well as from https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x[Spring Framework 5.x Release Notes]. + + The Relevant Changes section lists all potentially required changes to upgrade the scanned application to Spring Boot 2.5.6. + + NOTE: JDK 17 is required for Spring Boot 3 + + == Relevant Changes + + This section lists the changes SBM found to be applicable to upgrade the scanned application to Spring Boot 3.0.0. + + sections: + + - title: The title + helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ChangesToDataPropertiesHelper + info: |- + The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring + Data is required on the classpath. + reason: |- + The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`. + + <#list matches as match> + * file://${match.absolutePath}[`${match.relativePath}`] + <#list match.propertiesFound as property> + ** `${property}` + + + + todos: |- + Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore. + gitHubIssue: 123 + recipe: upgrade-to-spring-boot-3 + contributor: "Fabian Krüger[@fabapp2]" + + footer: |- + Generated by Spring Boot Migrator (experimental) +.... + +|=== +|Field |Description + +|title +|The title of the change in the Release Notes or GitHub issue. https://github.com/Buzzardo/spring-style-guide/blob/master/spring-style-guide.adoc#titles-and-subtitles[Headings] -note top of sbm-openrewrite-boot-upgrade - No dependency on SBM, - contains OpenRewrite Recipes and Visitors -end note +|change +|Describes the change, e.g a section from Release Notes. +Links to the Release Note or other resources can be added here. +|affected +|Describes why the scanned application is affected by this change. -"sbm-support-boot" --> "sbm-core" -"sbm-recipes-boot-upgrade" --> "sbm-support-boot" -"sbm-recipes-boot-upgrade" --> "sbm-openrewrite-boot-upgrade" -"sbm-recipes-boot-upgrade" --> "rewrite-spring" -"sbm-core" --> "sbm-openrewrite" -"sbm-openrewrite" --> rewrite -"sbm-openrewrite-boot-upgrade" --> "sbm-openrewrite" -"rewrite-spring" -> "rewrite" +|remediation +|Describes required changes to the scanned application. +A https://docs.asciidoctor.org/asciidoc/latest/lists/checklist/[checklist] can be used here. +|gitHubIssue +|The id (int) of the GitHub issue to this report section. +|contributors +|List of contributors with pattern `Given Name[@githubHandle]`. +|=== -.... \ No newline at end of file +==== The Helper +Helper acting as `Condition` and data provider for a `SpringBootUpgradeReportSection`. It provides the model data for the template. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 26e18939e..ff309c930 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,8 @@ pom + UTF-8 + UTF-8 spring-boot-migrator 2.5.0 17