diff --git a/.all-contributorsrc b/.all-contributorsrc index ce485028d8..21a93ff2c9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7145,6 +7145,34 @@ "bug", "code" ] + }, + { + "login": "nwcm", + "name": "nwcm", + "avatar_url": "https://avatars.githubusercontent.com/u/111259588?v=4", + "profile": "https://github.com/nwcm", + "contributions": [ + "doc" + ] + }, + { + "login": "PimvanderLoos", + "name": "Pim van der Loos", + "avatar_url": "https://avatars.githubusercontent.com/u/3114723?v=4", + "profile": "https://github.com/PimvanderLoos", + "contributions": [ + "code", + "test" + ] + }, + { + "login": "joaodinissf", + "name": "João Dinis Ferreira", + "avatar_url": "https://avatars.githubusercontent.com/u/6786818?v=4", + "profile": "https://github.com/joaodinissf", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/.ci/README.md b/.ci/README.md index 87250d6ba7..6286fd14b4 100644 --- a/.ci/README.md +++ b/.ci/README.md @@ -138,7 +138,7 @@ f=check-environment.sh; \ Calling `.ci/build.sh` directly would re-release the tag $TAG_NAME - that's why it is commented out. All the side-effects of a release would be carried out like creating and publishing a release on github, -uploading the release to sourceforge, uploading the docs to pmd.github.io/docs.pmd-code.org, uploading a +uploading the release to sourceforge, uploading the docs to docs.pmd-code.org, uploading a new baseline for the regression tester and so on. While the release should be reproducible and therefore should produce exactly the same artifacts, re-uploading artifacts is not desired just for testing. diff --git a/.ci/build.sh b/.ci/build.sh index 5f4d321698..ac5986007b 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -55,6 +55,13 @@ function build() { # stop early for invalid maven version and branch/tag combination pmd_ci_maven_verify_version || exit 0 + # skip tests when doing a release build - this makes the process faster + # it's a manual task now to verify that a release is only started, when the main branch + # was green before. This is usually checked via a local build, see ./do-release.sh + if pmd_ci_maven_isReleaseBuild; then + PMD_MAVEN_EXTRA_OPTS+=(-DskipTests=true) + fi + if [ "$(pmd_ci_utils_get_os)" != "linux" ]; then pmd_ci_log_group_start "Build with mvnw" ./mvnw clean verify --show-version --errors --batch-mode --no-transfer-progress "${PMD_MAVEN_EXTRA_OPTS[@]}" @@ -179,6 +186,11 @@ function pmd_ci_deploy_build_artifacts() { # Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/ pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-bin-${PMD_CI_MAVEN_PROJECT_VERSION}.zip" pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-src-${PMD_CI_MAVEN_PROJECT_VERSION}.zip" + # Deploy SBOM + cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml" + cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json" + pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml" + pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json" if pmd_ci_maven_isReleaseBuild; then # create a draft github release @@ -188,6 +200,9 @@ function pmd_ci_deploy_build_artifacts() { # Deploy to github releases pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "pmd-dist/target/pmd-bin-${PMD_CI_MAVEN_PROJECT_VERSION}.zip" pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "pmd-dist/target/pmd-src-${PMD_CI_MAVEN_PROJECT_VERSION}.zip" + # Deploy SBOM + pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml" + pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json" fi } @@ -224,7 +239,7 @@ function pmd_ci_build_and_upload_doc() { pmd_ci_sourceforge_uploadReleaseNotes "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "${rendered_release_notes}" if pmd_ci_maven_isSnapshotBuild && [ "${PMD_CI_BRANCH}" = "master" ]; then - # only for snapshot builds from branch master + # only for snapshot builds from branch master: https://docs.pmd-code.org/snapshot -> pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION} pmd_code_createSymlink "${PMD_CI_MAVEN_PROJECT_VERSION}" "snapshot" # update github pages https://pmd.github.io/pmd/ @@ -249,14 +264,12 @@ function pmd_ci_build_and_upload_doc() { local rendered_release_notes_with_links rendered_release_notes_with_links=" * Downloads: https://github.com/pmd/pmd/releases/tag/pmd_releases%2F${PMD_CI_MAVEN_PROJECT_VERSION} -* Documentation: https://pmd.github.io/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}/ +* Documentation: https://docs.pmd-code.org/pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}/ ${rendered_release_notes}" pmd_ci_sourceforge_createDraftBlogPost "${release_name} released" "${rendered_release_notes_with_links}" "pmd,release" SF_BLOG_URL="${RESULT}" - # updates https://pmd.github.io/latest/ and https://pmd.github.io/pmd-${PMD_CI_MAVEN_PROJECT_VERSION} - publish_release_documentation_github # rsync site to https://pmd.sourceforge.io/pmd-${PMD_CI_MAVEN_PROJECT_VERSION} pmd_ci_sourceforge_rsyncSnapshotDocumentation "${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-${PMD_CI_MAVEN_PROJECT_VERSION}" fi diff --git a/.ci/inc/pmd-doc.inc b/.ci/inc/pmd-doc.inc index 4a6d5acc14..8969f8a4d8 100644 --- a/.ci/inc/pmd-doc.inc +++ b/.ci/inc/pmd-doc.inc @@ -42,55 +42,7 @@ function pmd_doc_create_archive() { } # -# Publishes the site to https://pmd.github.io/pmd-${PMD_CI_MAVEN_PROJECT_VERSION} and -# https://pmd.github.io/latest/ -# -function publish_release_documentation_github() { - echo -e "\n\n" - pmd_ci_log_info "Adding the new doc to pmd.github.io..." - # clone pmd.github.io. Note: This uses the ssh key setup earlier - # In order to speed things up, we use a sparse checkout - no need to checkout all directories here - mkdir pmd.github.io - ( - cd pmd.github.io || { echo "Directory 'pmd.github.io' doesn't exist"; exit 1; } - git init - git config user.name "PMD CI (pmd-bot)" - git config user.email "pmd-bot@users.noreply.github.com" - git config core.sparsecheckout true - git remote add origin git@github.com-pmd.github.io:pmd/pmd.github.io.git - echo "/latest/" > .git/info/sparse-checkout - echo "/sitemap.xml" >> .git/info/sparse-checkout - git pull --depth=1 origin master - pmd_ci_log_info "Copying documentation from ../docs/pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}/ to pmd-${PMD_CI_MAVEN_PROJECT_VERSION}/ ..." - rsync -ah --stats "../docs/pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}/" "pmd-${PMD_CI_MAVEN_PROJECT_VERSION}/" - git status - pmd_ci_log_debug "Executing: git add pmd-${PMD_CI_MAVEN_PROJECT_VERSION}" - git add --sparse "pmd-${PMD_CI_MAVEN_PROJECT_VERSION}" - pmd_ci_log_debug "Executing: git commit..." - git commit -q -m "Added pmd-${PMD_CI_MAVEN_PROJECT_VERSION}" - - pmd_ci_log_info "Copying pmd-${PMD_CI_MAVEN_PROJECT_VERSION} to latest ..." - git rm -qr latest - cp -a "pmd-${PMD_CI_MAVEN_PROJECT_VERSION}" latest - pmd_ci_log_debug "Executing: git add latest" - git add latest - pmd_ci_log_debug "Executing: git commit..." - git commit -q -m "Copying pmd-${PMD_CI_MAVEN_PROJECT_VERSION} to latest" - - pmd_ci_log_info "Generating sitemap.xml" - ../docs/sitemap_generator.sh > sitemap.xml - pmd_ci_log_debug "Executing: git add sitemap.xml" - git add sitemap.xml - pmd_ci_log_debug "Executing: git commit..." - git commit -q -m "Generated sitemap.xml" - - pmd_ci_log_info "Executing: git push origin master" - git push origin master - ) -} - -# -# Updates github pages of the main repository, +# Updates github pages branch "gh-pages" of the main repository, # so that https://pmd.github.io/pmd/ has the latest (snapshot) content # function pmd_doc_publish_to_github_pages() { diff --git a/.github/ISSUE_TEMPLATE/0rule_violation_false-positive.md b/.github/ISSUE_TEMPLATE/0rule_violation_false-positive.md index 8faed7c14a..9daab4f380 100644 --- a/.github/ISSUE_TEMPLATE/0rule_violation_false-positive.md +++ b/.github/ISSUE_TEMPLATE/0rule_violation_false-positive.md @@ -13,7 +13,7 @@ assignees: '' **Rule:** Please provide the rule name and a link to the rule documentation: - + **Description:** diff --git a/.github/ISSUE_TEMPLATE/1rule_violation_false-negative.md b/.github/ISSUE_TEMPLATE/1rule_violation_false-negative.md index 51702e0038..d6ae5c5d0d 100644 --- a/.github/ISSUE_TEMPLATE/1rule_violation_false-negative.md +++ b/.github/ISSUE_TEMPLATE/1rule_violation_false-negative.md @@ -13,7 +13,7 @@ assignees: '' **Rule:** Please provide the rule name and a link to the rule documentation: - + **Description:** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed97a2878b..b4fe5f9d27 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,11 +33,11 @@ When filing a bug report, please provide as much information as possible, so tha ## Documentation -There is some documentation available under . Feel free to create a bug report if +There is some documentation available under . Feel free to create a bug report if documentation is missing, incomplete or outdated. See [Bug reports](#bug-reports). The documentation is generated as a Jekyll site, the source is available at: . You can find build instructions there. -For more on contributing documentation check +For more on contributing documentation check ## Questions diff --git a/Gemfile.lock b/Gemfile.lock index aa09f3659b..d96519a4e1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.8.1) + addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) claide (1.1.0) claide-plugins (0.9.2) @@ -31,13 +31,13 @@ GEM faraday (2.7.4) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-http-cache (2.4.1) + faraday-http-cache (2.5.0) faraday (>= 0.8) faraday-net_http (3.0.2) fugit (1.8.1) et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) - git (1.17.2) + git (1.18.0) addressable (~> 2.8) rchardet (~> 1.8) kramdown (2.4.0) @@ -49,7 +49,7 @@ GEM mini_portile2 (2.8.1) nap (1.1.0) no_proxy_fix (0.1.2) - nokogiri (1.14.2) + nokogiri (1.14.3) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (5.6.1) diff --git a/README.md b/README.md index 5fe24a5db5..382eb8ca61 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Coverage Status](https://coveralls.io/repos/github/pmd/pmd/badge.svg)](https://coveralls.io/github/pmd/pmd) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/ea550046a02344ec850553476c4aa2ca)](https://www.codacy.com/gh/pmd/pmd/dashboard?utm_source=github.com&utm_medium=referral&utm_content=pmd/pmd&utm_campaign=Badge_Grade) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](code_of_conduct.md) -[![Documentation (latest)](https://img.shields.io/badge/docs-latest-green)](https://pmd.github.io/latest/) +[![Documentation (latest)](https://img.shields.io/badge/docs-latest-green)](https://docs.pmd-code.org/latest/) **PMD** is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It supports many languages. It can be extended with custom rules. @@ -32,9 +32,9 @@ it makes sense. Download the latest binary zip from the [releases](https://github.com/pmd/pmd/releases/latest) and extract it somewhere. -Execute `bin/run.sh pmd` or `bin\pmd.bat`. +Execute `bin/pmd check` or `bin\pmd.bat check`. -See also [Getting Started](https://pmd.github.io/latest/pmd_userdocs_installation.html) +See also [Getting Started](https://docs.pmd-code.org/latest/pmd_userdocs_installation.html) **Demo:** @@ -43,7 +43,7 @@ This shows how PMD can detect for loops, that can be replaced by for-each loops. ![Demo](docs/images/userdocs/pmd-demo.gif) There are plugins for Maven and Gradle as well as for various IDEs. -See [Tools / Integrations](https://pmd.github.io/latest/pmd_userdocs_tools.html) +See [Tools / Integrations](https://docs.pmd-code.org/latest/pmd_userdocs_tools.html) ## ℹ️ How to get support? @@ -54,7 +54,7 @@ See [Tools / Integrations](https://pmd.github.io/latest/pmd_userdocs_tools.html) * I got this error and I'm sure it's a bug -- file an [issue](https://github.com/pmd/pmd/issues). * I have an idea/request/question -- create a new [discussion](https://github.com/pmd/pmd/discussions). * I have a quick question -- ask in our [Gitter room](https://app.gitter.im/#/room/#pmd_pmd:gitter.im). -* Where's your documentation? -- +* Where's your documentation? -- ## 🤝 Contributing diff --git a/do-release.sh b/do-release.sh index 7a42d9be4e..60d060c944 100755 --- a/do-release.sh +++ b/do-release.sh @@ -165,26 +165,13 @@ git commit -a -m "Prepare pmd release ${RELEASE_VERSION}" fi ) -# for release candidates, allow snapshot dependencies -if [[ "${RELEASE_VERSION}" == *-rc* ]]; then - ./mvnw versions:set -DnewVersion="${RELEASE_VERSION}" -DgenerateBackupPoms=false - git commit -S -a -m "[release] prepare release pmd_releases/${RELEASE_VERSION}" - git tag -a -s -m "[release] tag pmd_releases/${RELEASE_VERSION}" "pmd_releases/${RELEASE_VERSION}" - # test build - ./mvnw clean verify -Denforcer.skip=true - ./mvnw versions:set -DnewVersion="${DEVELOPMENT_VERSION}" -DgenerateBackupPoms=false - git commit -S -a -m "[release] prepare for next development iteration" - # push - git push origin - git push origin tag "pmd_releases/${RELEASE_VERSION}" -else - ./mvnw -B release:clean release:prepare \ - -Dtag="pmd_releases/${RELEASE_VERSION}" \ - -DreleaseVersion="${RELEASE_VERSION}" \ - -DdevelopmentVersion="${DEVELOPMENT_VERSION}" \ - -DscmCommentPrefix="[release] " \ - -Pgenerate-rule-docs -fi +./mvnw -B release:clean release:prepare \ + -Dtag="pmd_releases/${RELEASE_VERSION}" \ + -DreleaseVersion="${RELEASE_VERSION}" \ + -DdevelopmentVersion="${DEVELOPMENT_VERSION}" \ + -DscmCommentPrefix="[release] " \ + -Pgenerate-rule-docs + echo echo "Tag has been pushed.... now check github actions: " diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 0a0f1cccb1..661669d561 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -6,17 +6,17 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.1) + addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.23.8) + commonmarker (0.23.9) concurrent-ruby (1.2.2) - dnsruby (1.61.9) - simpleidn (~> 0.1) + dnsruby (1.70.0) + simpleidn (~> 0.2.1) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) @@ -86,7 +86,7 @@ GEM activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.8.0) - i18n (1.12.0) + i18n (1.13.0) concurrent-ruby (~> 1.0) jekyll (3.9.3) addressable (~> 2.4) @@ -211,7 +211,7 @@ GEM jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) minitest (5.18.0) - nokogiri (1.14.2) + nokogiri (1.14.3) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (4.25.1) diff --git a/docs/README.md b/docs/README.md index d0aef2914f..71c8eaf911 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,10 @@ # PMD Documentation -The documentation is available at: +The snapshot documentation (build by github pages) is available at: . -The documentation for the latest release is at: +The same documentation (build with our own scripts) is available at: . + +The documentation for the latest release is at: ## Site Theme diff --git a/docs/_config.yml b/docs/_config.yml index 920e5d9a1c..4dc5eee07d 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -44,7 +44,6 @@ exclude: - pdf-*.sh - pdfconfigs/ - pdf/ - - sitemap_generator.sh - render_release_notes.rb feedback_subject_line: PMD Source Code Analyzer @@ -117,7 +116,7 @@ description: "Intended as a documentation theme based on Jekyll for technical wr # the description is used in the feed.xml file # needed for sitemap.xml file only -url: https://pmd.github.io/pmd +url: https://docs.pmd-code.org/latest baseurl: "" # used by javadoc_tag.rb diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 6ca086dc8f..cb0a560ccb 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -409,6 +409,9 @@ entries: - title: Java url: /pmd_languages_java.html output: web, pdf + - title: JavaScript / TypeScript + url: /pmd_languages_js_ts.html + output: web, pdf - title: JSP url: /pmd_languages_jsp.html output: web, pdf @@ -430,6 +433,9 @@ entries: - title: Gherkin url: /pmd_languages_gherkin.html output: web, pdf + - title: Julia + url: /pmd_languages_julia.html + output: web, pdf - title: Developer Documentation output: web, pdf folderitems: @@ -469,7 +475,7 @@ entries: - title: Adding a new language (JavaCC) url: /pmd_devdocs_major_adding_new_language_javacc.html output: web, pdf - - title: Adding a new language (Antlr) + - title: Adding a new language (ANTLR) url: /pmd_devdocs_major_adding_new_language_antlr.html output: web, pdf - title: Adding a new CPD language diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html index e8e3c871f4..46187408cf 100755 --- a/docs/_includes/footer.html +++ b/docs/_includes/footer.html @@ -9,7 +9,7 @@ target="_blank" href="https://github.com/{{site.github_editme_path}}{{editmepath}}" role="button" - > Edit on GitHub Edit on GitHub {% endif %} diff --git a/docs/_includes/head.html b/docs/_includes/head.html index 806206b577..a81e15c796 100644 --- a/docs/_includes/head.html +++ b/docs/_includes/head.html @@ -6,7 +6,7 @@ {{ page.title }} | {{ site.site_title }} - + @@ -15,7 +15,7 @@ - - + + diff --git a/docs/_plugins/rule_tag.rb b/docs/_plugins/rule_tag.rb index 36eeb12032..7b5aa3ee13 100644 --- a/docs/_plugins/rule_tag.rb +++ b/docs/_plugins/rule_tag.rb @@ -53,7 +53,7 @@ class RuleTag < Liquid::Tag # This is passed from the release notes processing script # When generating links for the release notes, the links should be absolute if context["is_release_notes_processor"] - url_prefix = "https://pmd.github.io/pmd-#{context["site.pmd.version"]}/" + url_prefix = "https://docs.pmd-code.org/pmd-doc-#{context["site.pmd.version"]}/" end if @was_removed diff --git a/docs/assets/README.md b/docs/assets/README.md index 947fb59af0..48125954f8 100644 --- a/docs/assets/README.md +++ b/docs/assets/README.md @@ -4,7 +4,7 @@ Doc: https://fontawesome.com/how-to-use/on-the-web/setup/hosting-font-awesome-yourself -Download: https://use.fontawesome.com/releases/v5.14.0/fontawesome-free-5.14.0-web.zip +Download: https://use.fontawesome.com/releases/v5.15.4/fontawesome-free-5.15.4-web.zip ## Bootstrap diff --git a/docs/assets/fontawesome-free-5.14.0-web/css/all.min.css b/docs/assets/fontawesome-free-5.14.0-web/css/all.min.css deleted file mode 100644 index f7eacc802d..0000000000 --- a/docs/assets/fontawesome-free-5.14.0-web/css/all.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Font Awesome Free 5.14.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - */ -.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.eot b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.eot deleted file mode 100644 index 54ad8d72dc..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.eot and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.ttf b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.ttf deleted file mode 100644 index 16852bfd05..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.ttf and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.woff b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.woff deleted file mode 100644 index 6cf6fb3870..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.woff and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.woff2 b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.woff2 deleted file mode 100644 index f2a4e36f18..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.woff2 and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.eot b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.eot deleted file mode 100644 index 479b32cecc..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.eot and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.ttf b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.ttf deleted file mode 100644 index 42a04fde4e..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.ttf and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.woff b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.woff deleted file mode 100644 index c390c60e2b..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.woff and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.woff2 b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.woff2 deleted file mode 100644 index 11c71d28cf..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-regular-400.woff2 and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.eot b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.eot deleted file mode 100644 index 52883b93c8..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.eot and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.ttf b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.ttf deleted file mode 100644 index 7c59512f3c..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.ttf and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.woff b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.woff deleted file mode 100644 index aff125d658..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.woff and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.woff2 b/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.woff2 deleted file mode 100644 index aa2b79109e..0000000000 Binary files a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-solid-900.woff2 and /dev/null differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/LICENSE.txt b/docs/assets/fontawesome-free-5.15.4-web/LICENSE.txt similarity index 100% rename from docs/assets/fontawesome-free-5.14.0-web/LICENSE.txt rename to docs/assets/fontawesome-free-5.15.4-web/LICENSE.txt diff --git a/docs/assets/fontawesome-free-5.15.4-web/css/all.min.css b/docs/assets/fontawesome-free-5.15.4-web/css/all.min.css new file mode 100644 index 0000000000..ac76ff191e --- /dev/null +++ b/docs/assets/fontawesome-free-5.15.4-web/css/all.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/docs/assets/fontawesome-free-5.15.4-web/webfonts/fa-brands-400.eot b/docs/assets/fontawesome-free-5.15.4-web/webfonts/fa-brands-400.eot new file mode 100644 index 0000000000..cba6c6cce8 Binary files /dev/null and b/docs/assets/fontawesome-free-5.15.4-web/webfonts/fa-brands-400.eot differ diff --git a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.svg b/docs/assets/fontawesome-free-5.15.4-web/webfonts/fa-brands-400.svg similarity index 95% rename from docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.svg rename to docs/assets/fontawesome-free-5.15.4-web/webfonts/fa-brands-400.svg index 2c8659c12b..b9881a43b7 100644 --- a/docs/assets/fontawesome-free-5.14.0-web/webfonts/fa-brands-400.svg +++ b/docs/assets/fontawesome-free-5.15.4-web/webfonts/fa-brands-400.svg @@ -1,16 +1,12 @@ - -Created by FontForge 20200314 at Wed Jul 15 11:59:41 2020 +Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021 By Robert Madole Copyright (c) Font Awesome - + + + + + + + + + + + - +d="M400 416c26.4922 0 48 -21.5078 48 -48v-352c0 -26.4922 -21.5078 -48 -48 -48h-352c-26.4922 0 -48 21.5078 -48 48v352c0 26.4922 21.5078 48 48 48h352zM336 136v160c-31.5996 -11.2002 -41.2002 -16 -59.7998 -16c-31.4004 0 -43.4004 16 -74.6006 16 +c-25.3994 0 -37.3994 -10.4004 -57.5996 -14.4004v6.40039c0 8.83105 -7.16895 16 -16 16s-16 -7.16895 -16 -16v-192c0 -8.83105 7.16895 -16 16 -16s16 7.16895 16 16v153.6c20.2002 4 32.2002 14.4004 57.5996 14.4004c31.4004 0 43.2002 -16 74.6006 -16 +c10.2002 0 17.7998 1.40039 27.7998 4.59961v-96c-10 -3.19922 -17.5996 -4.59961 -27.7998 -4.59961c-31.4004 0 -43.4004 16 -74.6006 16c-8.91309 -0.0322266 -17.5195 -1.44336 -25.5996 -4v-32c7.86035 2.58398 16.2559 4.00195 24.9756 4.00195 +c0.208008 0 0.416016 0 0.624023 -0.00195312c31.4004 0 43.2002 -16 74.6006 -16c18.5996 0 28.2002 4.7998 59.7998 16z" /> +d="M498.252 213.777c0.129883 -0.613281 0.322266 -1.21777 0.561523 -1.78223v-37.0557c-0.194336 -0.300781 -0.516602 -0.583008 -0.552734 -0.900391c-0.619141 -5.36426 -0.837891 -10.8076 -1.87012 -16.0869c-2.06934 -10.6074 -4.15723 -21.2393 -7.0166 -31.6523 +c-4.94531 -18.0205 -12.7578 -34.8809 -22.2998 -50.9258c-8.94336 -15.126 -19.4043 -28.9668 -31.4268 -41.6387c-3.74609 -3.92188 -7.54688 -7.80078 -11.5107 -11.5c-5.31152 -4.95703 -10.5146 -10.1094 -16.2998 -14.457 +c-9.3418 -7.02344 -18.9883 -13.6533 -28.7373 -20.1006c-15.083 -9.81543 -31.6211 -17.9053 -48.9512 -23.8174c-15.3828 -5.38281 -31.1533 -9.38574 -47.4893 -10.7178c-2.52734 -0.206055 -5.02051 -0.753906 -7.52734 -1.14258h-32.2891 +c-0.358398 0.245117 -0.762695 0.436523 -1.18945 0.55957c-6.1377 0.620117 -12.3418 0.863281 -18.4121 1.87305c-13.8301 2.22949 -27.5977 5.58398 -40.6416 9.83496c-19.5498 6.43359 -38.4463 15.0176 -55.8994 25.2773 +c-15.0488 8.79004 -28.9365 18.9688 -41.7871 30.5859c-9.6875 8.70605 -18.3936 18.0898 -26.3584 28.416c-9.38184 12.1963 -17.4385 25.4316 -24 39.5283c-7.5918 16.6592 -13.3467 34.7812 -16.7295 53.2998c-2.35547 13.1611 -3.85059 26.5459 -4.4248 40.2402 +c-0.136719 3.0332 -0.209961 5.74121 -0.209961 8.80859c0 9.05566 0.599609 17.9717 1.76172 26.7119c1.52637 11.874 4.15625 23.6367 7.69043 34.7588c5.05762 15.7021 12.0283 30.7871 20.4941 44.6006c9.58203 15.9961 20.7793 30.6025 33.6484 43.9502 +c9.55469 9.83496 19.7539 19.0605 29.9268 28.2676c5.70605 5.1582 11.8066 9.9082 17.9736 14.5186c12.0029 9.04004 24.6963 17.1025 38.0801 24.1572c12.5137 6.63281 25.9795 12.1963 39.7686 16.3555c10.9453 3.41016 22.5254 5.84375 34.2559 7.09961 +c2.42773 0.225586 4.82617 0.761719 7.23633 1.15039c10.7627 -0.00195312 21.5254 0 32.2881 0.00585938c0.299805 -0.195312 0.583984 -0.516602 0.899414 -0.552734c6.87793 -0.81543 13.8467 -1.16797 20.627 -2.48242 +c11.2432 -2.18359 22.4971 -4.51465 33.5156 -7.61523c19.999 -5.78125 39.2266 -14.2031 56.7227 -24.668c17.2832 -10.0947 32.9639 -22.1357 47.1133 -36.1152c6.71973 -6.90527 12.9209 -14.0508 18.8174 -21.6895c13.4639 -16.959 24.0283 -36.4561 30.874 -57.5 +c3.88867 -11.8086 7.16211 -24.2148 9.62207 -36.5996c2.0459 -10.1748 2.53809 -20.6602 3.74609 -31zM337.135 214.927l0.00488281 67.2695c-35.2686 0 -53.1152 -9.36719 -62.04 -36.1895v31.9316h-73.5176v-190.738h73.5127v93.667 +c0 22.1396 6.37012 37.04 33.5703 37.04c11.8984 0 28.4697 -2.98047 28.4697 -2.98047z" /> +d="M400 416c26.4922 0 48 -21.5078 48 -48v-352c0 -26.4922 -21.5078 -48 -48 -48h-352c-26.4922 0 -48 21.5078 -48 48v352c0 26.4922 21.5078 48 48 48h352zM416 16v352c0 8.83105 -7.16895 16 -16 16h-352c-8.83105 0 -16 -7.16895 -16 -16v-352 +c0 -8.83105 7.16895 -16 16 -16h352c8.83105 0 16 7.16895 16 16zM201.6 296c31.2002 0 43.2002 -16 74.6006 -16c18.5996 0 28.2002 4.7998 59.7998 16v-160c-31.5996 -11.2002 -41.2002 -16 -59.7998 -16c-31.4004 0 -43.2002 16 -74.6006 16 +c-0.208008 0.00195312 -0.415039 -0.0175781 -0.623047 -0.0175781c-8.7207 0 -17.1162 -1.39844 -24.9766 -3.98242v32c8.08008 2.55664 16.6865 3.96777 25.5996 4c31.2002 0 43.2002 -16 74.6006 -16c10.2002 0 17.7998 1.40039 27.7998 4.59961v96 +c-10 -3.19922 -17.5996 -4.59961 -27.7998 -4.59961c-31.4004 0 -43.2002 16 -74.6006 16c-25.3994 0 -37.3994 -10.4004 -57.5996 -14.4004v-153.6c0 -8.83105 -7.16895 -16 -16 -16s-16 7.16895 -16 16v192c0 8.83105 7.16895 16 16 16s16 -7.16895 16 -16v-6.40039 +c20.2002 4 32.2002 14.4004 57.5996 14.4004z" /> d="M87 -33.7998v73.5996h73.7002v-73.5996h-73.7002zM25.4004 101.4h61.5996v-61.6006h-61.5996v61.6006zM491.6 271.1c53.2002 -170.3 -73 -327.1 -235.6 -327.1v95.7998h0.299805v0.299805c101.7 0.200195 180.5 101 141.4 208 c-14.2998 39.6006 -46.1006 71.4004 -85.7998 85.7002c-107.101 38.7998 -208.101 -39.8994 -208.101 -141.7h-95.7998c0 162.2 156.9 288.7 327 235.601c74.2002 -23.2998 133.6 -82.4004 156.6 -156.601zM256.3 40.0996h-0.299805v-0.299805h-95.2998v95.6006h95.5996 v-95.3008z" /> - + @@ -1917,13 +1982,21 @@ c-42.5 0 -47.3994 -14.8008 -47.3994 -25.9004c0 -13.4004 5.7998 -17.2998 63.2002 +d="M104.324 178.828v26.1777h26.0664v-26.1777h-26.0664zM156.79 205.006h-26.3428v26.1777c-0.124023 7.05762 -5.8916 12.748 -12.9785 12.748c-7.08594 0 -12.8535 -5.69043 -12.9775 -12.748v-0.166016h-26.4004v0.166016 +c-0.000976562 0.119141 -0.000976562 0.220703 -0.000976562 0.339844c0 21.7041 17.6211 39.3242 39.3242 39.3242c21.5039 0 38.999 -17.2959 39.3213 -38.7227v-0.941406zM209.146 179.16v26.0117h26.3438v-26.0117 +c0 -0.0371094 -0.000976562 -0.0722656 -0.000976562 -0.109375c0 -64.7373 -52.5439 -117.3 -117.274 -117.331h-0.774414c-0.0380859 0 -0.0732422 0.000976562 -0.110352 0.000976562c-64.7373 0 -117.299 52.543 -117.33 117.273v0.166016h26.3369 +c0 -50.2793 40.8203 -91.1006 91.0996 -91.1006h0.609375c50.2793 0 91.1006 40.8213 91.1006 91.1006zM51.9131 179.16v25.96h-26.291v25.3994c0 50.6445 41.1162 91.7617 91.7607 91.7617s91.7607 -41.1172 91.7607 -91.7617v-25.293h-26.3438v25.293v0.200195 +c0 36.1055 -29.3135 65.4199 -65.4199 65.4199c-35.7656 0 -64.8672 -28.7646 -65.4121 -64.4023v-26.6201h26.2891v-25.957c0.356445 -21.2305 17.7031 -38.3564 39.0176 -38.3564s38.6611 17.126 39.0176 38.3564h26.3438 +c-0.140625 -35.9551 -29.374 -65.1016 -65.3613 -65.1016s-65.2207 29.1465 -65.3613 65.1016zM470.313 250.333c-11.3467 0 -20.8633 -4.75977 -24.2402 -12.1172v-8.41211c2.21875 -4.53809 6.30859 -7.69238 12.6191 -9.62988 +c4.75879 -1.37891 9.76562 -2.3623 14.832 -2.87793c6.36426 -0.827148 13.0068 -1.71484 20.6992 -4.42676c13.7256 -4.59375 24.0742 -13.2275 28.9443 -24.2412l0.166016 -0.664062l-0.166016 -25.8994c-7.69238 -17.0479 -28.668 -28.4473 -52.2998 -28.4473 +c-25.6797 0 -47.374 12.6182 -55.2891 32.0439l-0.552734 1.43848l23.0205 11.5078l0.719727 -1.49414c5.97754 -12.1211 17.5996 -19.0391 31.9336 -19.0391c12.0098 0 22.083 4.81445 25.791 12.3418v9.85059c-2.37988 4.59473 -6.47656 7.75098 -12.8398 9.85156 +c-5.20312 1.71582 -10.3506 2.37988 -15.8291 3.09961c-6.78809 0.675781 -13.4814 2.04199 -19.8135 3.98438c-14.1123 4.87109 -23.9678 13.2275 -28.668 24.2412c-0.158203 0.949219 -0.123047 -2.02637 0 24.8496c7.36133 17.0469 27.8379 28.4473 50.9727 28.4473 +c24.9062 0 45.3818 -12.0098 53.4062 -31.2705l0.609375 -1.43848l-23.2451 -11.5117l-0.71875 1.5498c-5.47949 11.6221 -16.3818 18.2637 -30.0518 18.2637zM287.568 136.656v68.3994h26.0664v-68.3994h-26.0664zM639.834 189.956l0.166016 -0.722656l-0.166016 -28.8906 +c-7.52734 -15.9941 -27.8916 -26.7305 -50.584 -26.7305s-43.0029 10.7363 -50.585 26.7305l-0.166016 0.720703l0.166016 28.8887c2.93262 6.25391 8.24121 12.0137 15.4414 16.7139c-5.57422 3.90332 -10.0391 9.14453 -13.0068 15.3311l-0.166016 0.664062 +l0.166016 25.3467c7.36133 15.9922 26.7334 26.7324 48.1504 26.7324s40.7881 -10.7402 48.1504 -26.7295l0.166016 -0.664062l-0.166016 -25.3467c-2.90137 -6.22852 -7.38379 -11.4873 -13.0078 -15.3301c7.1416 -4.7041 12.5088 -10.46 15.4414 -16.7139z +M566.614 240.762v-13.7246c3.48535 -6.19922 12.5068 -10.3486 22.5801 -10.3486c10.0723 0 19.0938 4.14844 22.6357 10.3486v13.7246c-3.59766 6.31055 -12.6191 10.5166 -22.6357 10.5166c-10.0176 0 -18.9805 -4.20605 -22.5801 -10.5166zM613.933 168.593v16.1572 +c-3.76367 6.36523 -13.3379 10.5146 -24.6826 10.5146c-11.1836 0 -20.9756 -4.20605 -24.6836 -10.5146v-16.1572c3.70801 -6.52734 13.5586 -10.8994 24.6836 -10.8994c11.3447 0 20.9189 4.25879 24.6826 10.8994zM376.4 182.038v89.7129h25.8994v-135.095h-25.6777 +l-62.5391 94.085v0.386719h-26.5098v40.623h29z" /> +d="M284.046 223.2c0.0341797 0 0.0664062 -0.00195312 0.100586 -0.00195312c18.8496 0 34.1592 -15.2754 34.2168 -34.1113c0 -18.8281 -15.2822 -34.1143 -34.1104 -34.1143s-34.1143 15.2861 -34.1143 34.1143c0 18.7588 15.1748 34.002 33.9072 34.1133zM173.596 223.2 +c0.0332031 0 0.0673828 -0.00195312 0.100586 -0.00195312c18.8496 0 34.1592 -15.2754 34.2168 -34.1113c0 -18.8281 -15.2822 -34.1143 -34.1104 -34.1143s-34.1143 15.2861 -34.1143 34.1143c0 18.7588 15.1748 34.002 33.9072 34.1133zM394.519 223.2 +c0.0351562 0 0.0683594 -0.00195312 0.102539 -0.00195312c18.8496 0 34.1592 -15.2754 34.2148 -34.1113c0 -18.8281 -15.2822 -34.1143 -34.1104 -34.1143s-34.1133 15.2861 -34.1133 34.1143c0 18.7588 15.1738 34.002 33.9062 34.1133zM548.326 278.519 +c17.3076 -26.9443 26.0674 -55.9189 26.0898 -86.9395c0 -30.209 -8.76074 -59.2021 -26.0703 -86.125c-15.5342 -24.1934 -37.3076 -45.5703 -64.6787 -63.6191c-52.8672 -34.8164 -122.354 -53.9746 -195.667 -53.9746 +c-0.150391 -0.000976562 0.0664062 -0.00585938 -0.0830078 -0.00585938c-24.5488 0 -48.5908 2.18359 -71.9443 6.36621c-14.8564 -14.2842 -31.3604 -26.5059 -49.5098 -36.5889c-66.7744 -33.3467 -125.6 -20.9092 -155.324 -10.2002 +c-5.54492 1.96289 -9.51758 7.25488 -9.51758 13.4697c0 3.82715 1.50879 7.30469 3.96289 9.87109c20.9619 21.6748 55.6416 64.5342 47.1162 103.49c-33.1426 33.9004 -51.1123 74.7764 -51.1123 118.148c0 42.5605 17.9697 83.4365 51.1123 117.337 +c8.52148 38.9521 -26.1582 81.7939 -47.1201 103.47c-2.45996 2.56738 -3.97656 6.0498 -3.97656 9.88281c0 6.21973 3.98047 11.5156 9.53125 13.4785c29.7246 10.71 88.5488 23.1211 155.302 -10.2109c18.1504 -10.0811 34.6553 -22.3027 49.5107 -36.5879 +c23.3457 4.18066 47.0137 6.35742 71.5547 6.35742c0.15918 0 0.318359 -0.000976562 0.476562 -0.000976562c73.293 0 142.78 -19.1826 195.666 -54c27.3711 -18.0479 49.1465 -39.4453 64.6816 -63.6182zM284.987 38.0996c128.612 0 232.866 67.376 232.866 150.487 +c0 83.0957 -104.274 150.469 -232.866 150.469c-128.593 0 -232.847 -67.3691 -232.847 -150.469c0 -36.2002 19.7861 -69.4375 52.7783 -95.4004c9.28809 -29.5986 3.84668 -62.958 -16.3252 -100.078c-0.960938 -1.79297 -1.8584 -3.58496 -2.8418 -5.35645 +c18.6367 1.63574 36.5557 6.875 52.5225 14.8701c13.5889 7.65625 25.9609 16.8633 37.1377 27.585l20.1289 19.3926c28.2617 -7.47852 57.8037 -11.501 88.4033 -11.501c0.347656 0 0.695312 0 1.04297 0.000976562z" /> @@ -2379,10 +2455,11 @@ c13.7002 9.39941 16.4004 24.3994 9.10059 31.3994c-7.2002 6.90039 -28.2002 -7 -29 c12.5996 33.0996 -3.59961 45.5 -3.59961 45.5s-23.4004 12.9004 -33.3008 -20.2002c-9.89941 -33.0996 -6.39941 -44.8994 -6.39941 -44.8994s30.7002 -13.4004 43.2998 19.5996zM442.1 188.1c0 0 15.7002 -1.09961 26.4004 14.2002s1.2998 25.5 1.2998 25.5 s-8.59961 11.1006 -19.5996 -9.09961c-11.1006 -20.1006 -8.10059 -30.6006 -8.10059 -30.6006z" /> +d="M448 400v-336c-63 -23 -82 -32 -119 -32c-63 0 -87 32 -150 32c-20 0 -36 -4 -51 -8v64c15 4 31 8 51 8c63 0 87 -32 150 -32c20 0 35 3 55 9v208c-20 -6 -35 -9 -55 -9c-63 0 -87 32 -150 32c-51 0 -75 -21 -115 -29v-307 +c0.00195312 -0.136719 0.00292969 -0.273438 0.00292969 -0.410156c0 -17.4404 -14.1602 -31.5996 -31.6006 -31.5996c-0.136719 0 -0.265625 0.0078125 -0.402344 0.00976562c-0.136719 -0.00195312 -0.273438 -0.00292969 -0.410156 -0.00292969 +c-17.4404 0 -31.5996 14.1602 -31.5996 31.6006c0 0.136719 0.0078125 0.265625 0.00976562 0.402344v384c-0.00195312 0.136719 -0.00292969 0.273438 -0.00292969 0.410156c0 17.4404 14.1602 31.5996 31.6006 31.5996 +c0.136719 0 0.265625 -0.0078125 0.402344 -0.00976562c0.136719 0.00195312 0.273438 0.00292969 0.410156 0.00292969c17.4404 0 31.5996 -14.1602 31.5996 -31.6006c0 -0.136719 -0.0078125 -0.265625 -0.00976562 -0.402344v-13c40 8 64 29 115 29c63 0 87 -32 150 -32 +c37 0 56 9 119 32z" /> - @@ -3345,9 +3420,13 @@ M353.9 173.3c3.55273 2.83594 6.87891 5.7998 10.0996 9l-34.9004 35c-3.18457 -3.22 c2.53027 3.79688 4.77832 7.81738 6.7002 12l-39.5 39.7998c-0.374023 -5.3252 -1.63574 -10.4893 -3.59961 -15.2002zM391.6 230.8l-53.0996 53.4004c4.25977 -7.79688 6.82422 -16.7627 7.09961 -26.2002l41.3008 -41.5c1.7959 4.61523 3.39258 9.46387 4.69922 14.2998z M392.6 236.4c1.25586 5.3623 2.04199 10.9189 2.30078 16.5996l-64.3008 64.7002c-2.61426 -3.74805 -5.95898 -6.85938 -9.89941 -9.2002z" /> +d="M14 352.208c0 52.9043 42.8877 95.792 95.793 95.792h164.368c52.9053 0 95.793 -42.8877 95.793 -95.792c0 -33.5 -17.1963 -62.9844 -43.2432 -80.1055c26.0469 -17.1211 43.2432 -46.6045 43.2432 -80.1045c0 -52.9053 -42.8877 -95.793 -95.793 -95.793h-2.08008 +c-24.8018 0 -47.4033 9.42578 -64.415 24.8906v-88.2627c0 -53.6104 -44.0088 -96.833 -97.3574 -96.833c-52.7725 0 -96.3086 42.7568 -96.3086 95.793c0 33.498 17.1943 62.9805 43.2393 80.1016c-26.0449 17.1221 -43.2393 46.6055 -43.2393 80.1035 +c0 33.5 17.1963 62.9834 43.2422 80.1045c-26.0459 17.1211 -43.2422 46.6055 -43.2422 80.1055zM176.288 256.413h-66.4951c-35.5762 0 -64.415 -28.8398 -64.415 -64.415c0 -35.4385 28.6172 -64.1924 64.0029 -64.4141 +c0.136719 0.000976562 0.274414 0.000976562 0.412109 0.000976562h66.4951v128.828zM207.666 191.998c0 -35.5752 28.8389 -64.415 64.415 -64.415h2.08008c35.5762 0 64.415 28.8398 64.415 64.415s-28.8389 64.415 -64.415 64.415h-2.08008 +c-35.5762 0 -64.415 -28.8398 -64.415 -64.415zM109.793 96.2051c-0.137695 0 -0.275391 0.000976562 -0.412109 0.000976562c-35.3857 -0.220703 -64.0029 -28.9746 -64.0029 -64.4131c0 -35.4453 29.2246 -64.415 64.9307 -64.415 +c36.2822 0 65.9795 29.4365 65.9795 65.4551v63.3721h-66.4951zM109.793 416.622c-35.5762 0 -64.415 -28.8398 -64.415 -64.4141c0 -35.5762 28.8389 -64.415 64.415 -64.415h66.4951v128.829h-66.4951zM207.666 287.793h66.4951c35.5762 0 64.415 28.8389 64.415 64.415 +c0 35.5742 -28.8389 64.4141 -64.415 64.4141h-66.4951v-128.829z" /> - + - -Created by FontForge 20200314 at Wed Jul 15 11:59:40 2020 +Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021 By Robert Madole Copyright (c) Font Awesome - + - -Created by FontForge 20200314 at Wed Jul 15 11:59:41 2020 +Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021 By Robert Madole Copyright (c) Font Awesome - + + + @@ -3707,11 +3720,17 @@ c0 53.0195 42.9805 96 96 96c53.0205 0 96 -42.9805 96 -96c0 -11.2803 -2.30957 -21 - + + + + + PMD + + + + image/svg+xml + + PMD + + + http://www.bijzonderbezig.nl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md index 4ee9585405..473648ea00 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md @@ -3,15 +3,10 @@ title: Adding PMD support for a new ANTLR grammar based language short_title: Adding a new language with ANTLR tags: [devdocs, extending] summary: "How to add a new language to PMD using ANTLR grammar." -last_updated: February 2023 (7.0.0) +last_updated: April 2023 (7.0.0) sidebar: pmd_sidebar permalink: pmd_devdocs_major_adding_new_language_antlr.html folder: pmd/devdocs - -# -# needs to be changed to branch master instead of pmd/7.0.x once pmd7 is released -# https://github.com/pmd/pmd/blob/pmd/7.0.x -> https://github.com/pmd/pmd/blob/master -# --- {% include callout.html type="warning" content=" @@ -21,27 +16,33 @@ folder: pmd/devdocs This is really a big contribution and can't be done with a drive by contribution. It requires dedicated passion and long commitment to implement support for a new language.

-This step-by-step guide is just a small intro to get the basics started and it's also not necessarily up-to-date -or complete and you have to be able to fill in the blanks.

+This step-by-step guide is just a small intro to get the basics started, and it's also not necessarily up-to-date +or complete. You have to be able to fill in the blanks.

-Currently the Antlr integration has some basic limitations compared to JavaCC: The output of the -Antlr parser generator is not an abstract syntax tree (AST) but a parse tree. As such, a parse tree is -much more fine-grained than what a typical JavaCC grammar will produce. This means that the +Currently, the Antlr integration has some basic **limitations** compared to JavaCC: The output of the +Antlr parser generator is not an abstract syntax tree (AST) but a parse tree (also known as CST, concrete syntax tree). +As such, a parse tree is much more fine-grained than what a typical JavaCC grammar will produce. This means that the parse tree is much deeper and contains nodes down to the different token types.

-The Antlr nodes themselves don't have any attributes because they are on the wrong abstraction level. -As they don't have attributes, there are no attributes that can be used in XPath based rules.

+The Antlr nodes are context objects and serve a different abstraction than nodes in an AST. These context objects +themselves don't have any attributes because they themselves represent the attributes (as nodes or leaves in the +parse tree). As they don't have attributes, there are no attributes that can be used in XPath based rules.

+ +The current implementation of the languages using ANTLR use these context objects as nodes in PMD's AST +representation.

In order to overcome these limitations, one would need to implement a post-processing step that transforms -a parse tree into an abstract syntax tree and introducing real nodes on a higher abstraction level. This -step is **not** described in this guide.

+a parse tree into an abstract syntax tree and introducing real nodes on a higher abstraction level. These +real nodes can then have attributes which are available in XPath based rules. The transformation can happen +with a visitor, but the implementation of the AST is a manual step. This step is **not** described +in this guide.

After the basic support for a language is there, there are lots of missing features left. Typical features that can greatly improve rule writing are: symbol table, type resolution, call/data flow analysis.

Symbol table keeps track of variables and their usages. Type resolution tries to find the actual class type of each used type, following along method calls (including overloaded and overwritten methods), allowing -to query sub types and type hierarchy. This requires additional configuration of an auxiliary classpath. +to query subtypes and type hierarchy. This requires additional configuration of an auxiliary classpath. Call and data flow analysis keep track of the data as it is moving through different execution paths a program has.

@@ -52,37 +53,57 @@ definitely don't come for free. It is much effort and requires perseverance to i ## 1. Start with a new sub-module * See pmd-swift for examples. +* Make sure to add your new module to PMD's parent pom as `` entry, so that it is built alongside the + other languages. +* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language + is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion + in the pmd-cli module. + ## 2. Implement an AST parser for your language * ANTLR will generate the parser for you based on the grammar file. The grammar file needs to be placed in the folder `src/main/antlr4` in the appropriate sub package `ast` of the language. E.g. for swift, the grammar - file is [Swift.g4](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4) + file is [Swift.g4](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4) and is placed in the package `net.sourceforge.pmd.lang.swift.ast`. +* Configure the options "superClass" and "contextSuperClass". These are the base classes for the generated + classes. ## 3. Create AST node classes * The individual AST nodes are generated, but you need to define the common interface for them. * You need to define the supertype interface for all nodes of the language. For that, we provide - [`AntlrNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNode.java). -* See [`SwiftNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNode.java) + [`AntlrNode`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNode.java). +* See [`SwiftNode`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNode.java) as an example. * Additionally, you need several base classes: * a language specific inner node - these nodes represent the production rules from the grammar. In Antlr, they are called "ParserRuleContext". We call them "InnerNode". Use the base class from pmd-core - [`BaseAntlrInnerNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java) - . And example is [`SwiftInnerNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java). + [`BaseAntlrInnerNode`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java) + . And example is [`SwiftInnerNode`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java). + Note that this language specific inner node is package-private, as it is only the base class for the concrete + nodes generated by ANLTR. * a language specific root node - this provides the root of the AST and our parser will return subtypes of this node. The root node itself is a "InnerNode". - See [`SwiftRootNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftRootNode.java). + See [`SwiftRootNode`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftRootNode.java). + Note that this language specific root node is package-private, as it is only the base class for the concrete + node generated by ANLTR. * a language specific terminal node. - See [`SwiftTerminalNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftTerminalNode.java). + See [`SwiftTerminalNode`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftTerminalNode.java). * a language specific error node. - See [`SwiftErrorNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftErrorNode.java). + See [`SwiftErrorNode`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftErrorNode.java). + * a language name dictionary. This is used to convert ANTLR node names to useful XPath node names. + See [`SwiftNameDictionary'](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNameDictionary.java). +* Once these base classes exist, you need to change the ANTLR grammar to add additional members via `@parser::members` + * Define a package private field `DICO` which creates a new instance of your language name dictionary using the + vocabulary from the generated parser (`VOCABULARY`). + * Define two additional methods to help converting the ANTLR context objects into PMD AST nodes. + The methods are abstract in [`AntlrGeneratedParserBase`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrGeneratedParserBase.java) + and need to be implemented here for the concrete language: `createPmdTerminal()` and `createPmdError()`. * In order for the generated code to match and use our custom classes, we have a common ant script, that fiddles with - the generated code. The ant script is [`antlr4-wrapper.xml`](https://github.com/pmd/pmd/blob/pmd/7.0.x/antlr4-wrapper.xml) and - does not need to be adjusted - it has plenty of parameters to set. The ant script is added in the - language module's `pom.xml` where the parameters are set (e.g. name of root name class). Have a look at - Swift's example: [`pmd-swift/pom.xml`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/pom.xml). + the generated code. The ant script is [`antlr4-wrapper.xml`](https://github.com/pmd/pmd/blob/master/antlr4-wrapper.xml) + and does not need to be adjusted - it has plenty of parameters that can be configured. + The ant script is added in the language module's `pom.xml` where the parameters are set (e.g. name of root name + class). Have a look at Swift's example: [`pmd-swift/pom.xml`](https://github.com/pmd/pmd/blob/master/pmd-swift/pom.xml). * You can add additional methods in your "InnerNode" (e.g. `SwiftInnerNode`) that are available on all nodes. But on most cases you won't need to do anything. @@ -93,31 +114,31 @@ definitely don't come for free. It is much effort and requires perseverance to i have the parser generated. * The generated code will be placed under `target/generated-sources/antlr4` and will not be committed to source control. -* You should review the [swift pom](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/pom.xml). +* You should review [`pmd-swift/pom.xml`](https://github.com/pmd/pmd/blob/master/pmd-swift/pom.xml). ## 5. Create a TokenManager * This is needed to support CPD (copy paste detection) -* We provide a default implementation using [`AntlrTokenManager`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java). +* We provide a default implementation using [`AntlrTokenManager`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java). * You must create your own "AntlrTokenizer" such as we do with - [`SwiftTokenizer`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java). + [`SwiftTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java). * If you wish to filter specific tokens (e.g. comments to support CPD suppression via "CPD-OFF" and "CPD-ON") you can create your own implementation of - [`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java). + [`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java). You'll need to override then the protected method `getTokenFilter(AntlrTokenManager)` and return your custom filter. See the tokenizer for C# as an exmaple: - [`CsTokenizer`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java). + [`CsTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java). If you don't need a custom token filter, you don't need to override the method. It returns the default `AntlrTokenFilter` which doesn't filter anything. ## 6. Create a PMD parser “adapter” * Create your own parser, that adapts the ANLTR interface to PMD's parser interface. -* We provide a [`AntlrBaseParser`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java) +* We provide a [`AntlrBaseParser`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java) implementation that you need to extend to create your own adapter as we do with - [`PmdSwiftParser`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java). + [`PmdSwiftParser`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java). ## 7. Create a language version handler -* Now you need to create your version handler, as we did with [`SwiftHandler`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftHandler.java). +* Now you need to create your version handler, as we did with [`SwiftHandler`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftHandler.java). * This class is sort of a gateway between PMD and all parsing logic specific to your language. * For a minimal implementation, it just needs to return a parser *(see step #6)*. * It can be used to provide other features for your language like @@ -130,15 +151,15 @@ definitely don't come for free. It is much effort and requires perseverance to i * A parser visitor adapter is not needed anymore with PMD 7. The visitor interface now provides a default implementation. * The visitor for ANTLR based AST is generated along the parser from the ANTLR grammar file. The - base interface for a visitor is [`AstVisitor`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitor.java). + base interface for a visitor is [`AstVisitor`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitor.java). * The generated visitor class for Swift is called `SwiftVisitor`. * In order to help use this visitor later on, a base visitor class should be created. - See [`SwiftVisitorBase`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftVisitorBase.java) + See [`SwiftVisitorBase`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftVisitorBase.java) as an example. ## 9. Make PMD recognize your language * Create your own subclass of `net.sourceforge.pmd.lang.impl.SimpleLanguageModuleBase`, see Swift as an example: - [`SwiftLanguageModule`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java). + [`SwiftLanguageModule`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java). * Add for each version of your language a call to `addVersion` in your language module’s constructor. Use `addDefaultVersion` for defining the default version. * You’ll need to refer the language version handler created in step #7. @@ -146,15 +167,21 @@ definitely don't come for free. It is much effort and requires perseverance to i Add your fully qualified class name as a single line into it. ## 10. Create an abstract rule class for the language -* You need to create your own `AbstractRule` in order to interface your language with PMD's generic rule +* You need to create your own abstract rule class in order to interface your language with PMD's generic rule execution. -* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java) as an example. -* While the rule basically just extends - [`AntlrBaseRule`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseRule.java) without adding anything, every language should have its own base class for rule. +* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java) as an example. +* The rule basically just extends + [`AbstractVisitorRule`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractVisitorRule.java) + and only redefines the abstract `buildVisitor()` method to return our own type of visitor. + In this case our `SwiftVisitor` is used. + While there is no real functionality added, every language should have its own base class for rules. This helps to organize the code. * All other rules for your language should extend this class. The purpose of this class is to provide a visitor via the method `buildVisitor()` for analyzing the AST. The provided visitor only implements the visit methods - for specific AST nodes. The other node types use the default behavior and you don't need to care about them. + for specific AST nodes. The other node types use the default behavior, and you don't need to care about them. +* Note: This is different from how it was in PMD 6: Each rule in PMD 6 was itself a visitor (implementing the visitor + interface of the specific language). Now the rule just provides a visitor, which can be hidden and potentially + shared between rules. ## 11. Create rules * Creating rules is already pretty well documented in PMD - and it’s no different for a new language, except you @@ -162,20 +189,38 @@ definitely don't come for free. It is much effort and requires perseverance to i * PMD supports 2 types of rules, through visitors or XPath. * To add a visitor rule: * You need to extend the abstract rule you created on the previous step, you can use the swift - rule [UnavailableFunctionRule](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java) + rule [UnavailableFunctionRule](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java) as an example. Note, that all rule classes should be suffixed with `Rule` and should be placed in a package the corresponds to their category. * To add an XPath rule you can follow our guide [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html). +* When creating the category ruleset XML file, the XML can reference build properties that are replaced + during the build. This is used for the `externalInfoUrl` attribute of a rule. E.g. we use `${pmd.website.baseurl}` + to point to the correct webpage (depending on the PMD version). In order for this to work, you need to add a + resource filtering configuration in the language module's `pom.xml`. Under `` add the following lines: + ```xml + + + ${project.basedir}/src/main/resources + true + + + ``` ## 14. Test the rules * Testing rules is described in depth in [Testing your rules](pmd_userdocs_extending_testing.html). * Each rule has its own test class: Create a test class for your rule extending `PmdRuleTst` - *(see UnavailableFunctionTest for example)* - * Create a category rule set for your language *(see pmd-swift/src/main/resources/bestpractices.xml for example)* + *(see + [`UnavailableFunctionTest`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionTest.java) + for example)* + * Create a category rule set for your language *(see + [`pmd-swift/src/main/resources/bestpractices.xml`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/resources/category/swift/bestpractices.xml) + for example)* * Place the test XML file with the test cases in the correct location * When executing the test class * this triggers the unit test to read the corresponding XML file with the rule test data - *(see `UnavailableFunction.xml` for example)* + *(see + [`UnavailableFunction.xml`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/UnavailableFunction.xml) + for example)* * This test XML file contains sample pieces of code which should trigger a specified number of violations of this rule. The unit test will execute the rule on this piece of code, and verify that the number of violations matches. diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md index 1e4e523b1c..0501ec73b8 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md @@ -16,15 +16,15 @@ folder: pmd/devdocs This is really a big contribution and can't be done with a drive by contribution. It requires dedicated passion and long commitment to implement support for a new language.

-This step-by-step guide is just a small intro to get the basics started and it's also not necessarily up-to-date -or complete and you have to be able to fill in the blanks.

+This step-by-step guide is just a small intro to get the basics started, and it's also not necessarily up-to-date +or complete. You have to be able to fill in the blanks.

After the basic support for a language is there, there are lots of missing features left. Typical features that can greatly improve rule writing are: symbol table, type resolution, call/data flow analysis.

Symbol table keeps track of variables and their usages. Type resolution tries to find the actual class type of each used type, following along method calls (including overloaded and overwritten methods), allowing -to query sub types and type hierarchy. This requires additional configuration of an auxiliary classpath. +to query subtypes and type hierarchy. This requires additional configuration of an auxiliary classpath. Call and data flow analysis keep track of the data as it is moving through different execution paths a program has.

@@ -35,7 +35,12 @@ definitely don't come for free. It is much effort and requires perseverance to i ## 1. Start with a new sub-module -* See pmd-java or pmd-vm for examples. +* See pmd-java or pmd-vm for examples. +* Make sure to add your new module to PMD's parent pom as `` entry, so that it is built alongside the + other languages. +* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language + is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion + in the pmd-cli module. ## 2. Implement an AST parser for your language * Ideally an AST parser should be implemented as a JJT file *(see VmParser.jjt or Java.jjt for example)* diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_new_cpd_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_new_cpd_language.md index 4590867fa8..52ffb4bbec 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_new_cpd_language.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_new_cpd_language.md @@ -17,10 +17,17 @@ Happily for you, to add CPD support for a new language is now easier than ever! All you need to do is follow this few steps: 1. Create a new module for your language, you can take [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go) as an example + * Make sure to add your new module to the parent pom as `` entry, so that it is built alongside the + other languages. + * Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language + is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion + in the pmd-cli module. + 2. Create a Tokenizer - - For Antlr grammars you can take the grammar from [here](https://github.com/antlr/grammars-v4) and extend [AntlrTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java) taking Go as an example - + - For Antlr grammars you can take the grammar from [here](https://github.com/antlr/grammars-v4) and + extend [AntlrTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java) + taking Go as an example ```java public class GoTokenizer extends AntlrTokenizer { @@ -32,7 +39,9 @@ All you need to do is follow this few steps: } ``` - - For JavaCC grammars you should subclass [JavaCCTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java) which has many examples you could follow, you should also take the [Python implementation](https://github.com/pmd/pmd/blob/master/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java) as reference + - For JavaCC grammars you should subclass [JavaCCTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/JavaCCTokenizer.java) + which has many examples you could follow, you should also take the + [Python implementation](https://github.com/pmd/pmd/blob/master/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java) as reference - For any other scenario you can use [AnyTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AnyTokenizer.java) If you're using Antlr or JavaCC, update the pom.xml of your submodule to use the appropriate ant wrapper. See `pmd-go/pom.xml` and `pmd-python/pom.xml` for examples. diff --git a/docs/pages/pmd/languages/js_ts.md b/docs/pages/pmd/languages/js_ts.md new file mode 100644 index 0000000000..7633105a2d --- /dev/null +++ b/docs/pages/pmd/languages/js_ts.md @@ -0,0 +1,16 @@ +--- +title: JavaScript and TypeScript +permalink: pmd_languages_js_ts.html +tags: [languages] +summary: "JavaScript and TypeScript infos" +--- + +**JavaScript** support is using [Rhino](https://github.com/mozilla/rhino) for parsing and supports CPD as well as +PMD with rules. + +See [Compatibility Table](https://mozilla.github.io/rhino/compat/engines.html) for supported language features. + + +**TypeScript** is supported for Copy-Paste-Detection only and uses the ANTLR grammar from +[antlr/grammars-v4](https://github.com/antlr/grammars-v4/tree/master/javascript/typescript). +This grammar is published under the [MIT](https://opensource.org/licenses/MIT) license. diff --git a/docs/pages/pmd/languages/julia.md b/docs/pages/pmd/languages/julia.md new file mode 100644 index 0000000000..de36f3e9ea --- /dev/null +++ b/docs/pages/pmd/languages/julia.md @@ -0,0 +1,15 @@ +--- +title: Julia +permalink: pmd_languages_julia.html +--- + +The [Julia](https://julialang.org/) is dynamically typed, like a scripting language, +and has good support for interactive use. +Julia was designed from the beginning for high performance. +Julia programs compile to efficient native code for multiple platforms via LLVM. + +## Support in PMD +Starting from version 7.0.0, Julia support was added to CPD. + +### Limitations +- Support for Julia only extends to CPD to detect code duplication in Julia source files. diff --git a/docs/pages/pmd/projectdocs/committers/main_landing_page.md b/docs/pages/pmd/projectdocs/committers/main_landing_page.md index a0f2515068..8ad63c686f 100644 --- a/docs/pages/pmd/projectdocs/committers/main_landing_page.md +++ b/docs/pages/pmd/projectdocs/committers/main_landing_page.md @@ -27,12 +27,6 @@ It usually takes 15 minutes. * There is also a sub page "news" which lists all news. * Layout: [_layouts/news.html](https://github.com/pmd/pmd.github.io/blob/master/_layouts/news.html) * Page (which is pretty empty): [news.html](https://github.com/pmd/pmd.github.io/blob/master/news.html) -* Documentation for the latest release: - * The PMD documentation of the latest release is simply copied as static html into the folder [latest/](https://github.com/pmd/pmd.github.io/tree/master/latest). - This makes the latest release documentation available under the stable URL - . This URL is also used for the [sitemap.xml](https://github.com/pmd/pmd.github.io/blob/master/sitemap.xml). -* Documentation for previous releases are still being kept under the folders `pmd-/`. - ## Building the page locally diff --git a/docs/pages/pmd/projectdocs/committers/releasing.md b/docs/pages/pmd/projectdocs/committers/releasing.md index d41605db65..92ddf8035c 100644 --- a/docs/pages/pmd/projectdocs/committers/releasing.md +++ b/docs/pages/pmd/projectdocs/committers/releasing.md @@ -45,7 +45,7 @@ e.g. it requires that the repo `pmd.github.io` is checked out aside the main pmd The script `do-release.sh` is called in the directory `/home/joe/source/pmd` and searches for `../pmd.github.io`. -Also make sure, that the repo "pmd.github.io" is locally up to date and has no local changes. +Also make sure, that the repo "pmd.github.io" is locally up-to-date and has no local changes. ### The Release Notes and docs @@ -183,11 +183,8 @@ Here is, what happens: * Remove old javadoc for the SNAPSHOT version, e.g. delete . * Create a draft news post on for the new release. This contains the rendered release notes. -* Add the documentation of the new release to a subfolder on , also make - this folder available as `latest`, so that shows the new - version and is the URL for the specific release. -* Also copy the documentation to sourceforge's web space, so that it is available as - . All previously copied version are listed +* Copy the documentation to sourceforge's web space, so that it is available as + . All previously copied versions are listed under . * After all this is done, the release on github () is published and the news post on sourceforge (https://sourceforge.net/p/pmd/news/> is publishes as well. @@ -206,7 +203,7 @@ news: * Downloads: https://github.com/pmd/pmd/releases/tag/pmd_releases%2F - * Documentation: https://pmd.github.io/pmd-/ + * Documentation: https://docs.pmd-code.org/pmd-doc-/ And Copy-Paste the release notes @@ -219,20 +216,21 @@ Tweet on , eg.: ### Checklist -| Task | Description | URL | ☐ / ✔ | -|------|-------------|-----|-------| -| maven central | The new version of all artifacts are available in maven central | | | -| github releases | A new release with 3 assets (bin, src, doc) is created | | | -| sourceforge files | The 3 assets (bin, src, doc) are uploaded, the new version is pre-selected as latest | | | -| homepage | Main landing page points to new version, doc for new version is available | | | -| homepage2 | New blogpost for the new release is posted | | | -| docs | New docs are uploaded | | | -| docs-archive | New docs are also on archive site | | | -| javadoc | New javadocs are uploaded | | | -| news | New blogpost on sourceforge is posted | | | -| regression-tester | New release baseline is uploaded | | | -| mailing list | announcement on mailing list is sent | | | -| twitter | tweet about the new release | | | +| Task | Description | URL | ☐ / ✔ | +|-------------------|--------------------------------------------------------------------------------------|-----------------------------------------------------------------|-------------------------| +| maven central | The new version of all artifacts are available in maven central | | | +| github releases | A new release with 3 assets (bin, src, doc) is created | | | +| sourceforge files | The 3 assets (bin, src, doc) are uploaded, the new version is pre-selected as latest | | | +| homepage | Main landing page points to new version, doc for new version is available | | | +| homepage2 | New blogpost for the new release is posted | | | +| docs | New docs are uploaded | | | +| docs2 | New version in the docs is listed under "Version specific documentation" | | | +| docs-archive | New docs are also on archive site | | | +| javadoc | New javadocs are uploaded | | | +| news | New blogpost on sourceforge is posted | | | +| regression-tester | New release baseline is uploaded | | | +| mailing list | announcement on mailing list is sent | | | +| twitter | tweet about the new release | | | ## Prepare the next release @@ -309,7 +307,7 @@ In theory, the fixes should already be there, but you never now. If releases from multiple branches are being done, the order matters. You should start from the "oldest" branch, e.g. `pmd/5.4.x`, release from there. Then merge (see above) into the next branch, e.g. `pmd/5.5.x` and release from there. Then merge into the `master` branch and release from there. This way, the last release done, becomes -automatically the latest release on and on sourceforge. +automatically the latest release on and on sourceforge. ### (Optional) Create a new release branch diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 7c364b7d02..95a5fff653 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -379,640 +379,643 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Josh Feingold

💻 🐛
Josh Holthaus

🐛
Joshua S Arquilevich

🐛 +
João Dinis Ferreira

📖
João Ferreira

💻 🐛 -
João Pedro Schmitt

🐛 +
João Pedro Schmitt

🐛
Juan Martín Sotuyo Dodero

💻 📖 🐛 🚧
Juan Pablo Civile

🐛
Julian Voronetsky

🐛
Julien

🐛
Julius

🐛
JustPRV

🐛 -
Jörn Huxhorn

🐛 +
Jörn Huxhorn

🐛
KThompso

🐛
Kai Amundsen

🐛
Karel Vervaeke

🐛
Karl-Andero Mere

🐛
Karl-Philipp Richter

🐛
Karsten Silz

🐛 -
Kazuma Watanabe

🐛 +
Kazuma Watanabe

🐛
Kev

🐛
Keve Müller

🐛
Kevin Guerra

💻
Kevin Jones

🐛
Kevin Wayne

🐛
Kieran Black

🐛 -
Kirill Zubov

🐛 +
Kirill Zubov

🐛
Kirk Clemens

💻 🐛
Klaus Hartl

🐛
Koen Van Looveren

🐛
Kris Scheibe

💻 🐛
Kunal Thanki

🐛
LaLucid

💻 -
Larry Diamond

💻 🐛 +
Larry Diamond

💻 🐛
Lars Knickrehm

🐛
Leo Gutierrez

🐛
LiGaOg

💻
Liam Sharp

🐛
Lintsi

🐛
Linus Fernandes

🐛 -
Lixon Lookose

🐛 +
Lixon Lookose

🐛
Logesh

🐛
Lorenzo Gabriele

🐛
Loïc Ledoyen

🐛
Lucas Silva

🐛
Lucas Soncini

💻 🐛
Luis Alcantar

💻 -
Lukasz Slonina

🐛 +
Lukasz Slonina

🐛
Lukebray

🐛
Lynn

💻 🐛
Lyor Goldstein

🐛
MCMicS

🐛
Macarse

🐛
Machine account for PMD

💻 -
Maciek Siemczyk

🐛 +
Maciek Siemczyk

🐛
Maikel Steneker

💻 🐛
Maksim Moiseikin

🐛
Manfred Koch

🐛
Manuel Moya Ferrer

💻 🐛
Manuel Ryan

🐛
Marat Vyshegorodtsev

🐛 -
Marcel Härle

🐛 +
Marcel Härle

🐛
Marcello Fialho

🐛
Marcin Rataj

🐛
Mark Adamcin

🐛
Mark Hall

💻 🐛
Mark Kolich

🐛
Mark Pritchard

🐛 -
Markus Rathgeb

🐛 +
Markus Rathgeb

🐛
Marquis Wang

🐛
MartGit

🐛
Martin Feldsztejn

🐛
Martin Lehmann

🐛
Martin Spamer

🐛
Martin Tarjányi

🐛 -
MatFl

🐛 +
MatFl

🐛
Mateusz Stefanski

🐛
Mathieu Gouin

🐛
MatiasComercio

💻 🐛
Matt Benson

🐛
Matt De Poorter

🐛
Matt Hargett

💻 💵 -
Matt Harrah

🐛 +
Matt Harrah

🐛
Matt Nelson

🐛
Matthew Amos

🐛
Matthew Duggan

🐛
Matthew Hall

🐛
Matías Fraga

💻 🐛
Maxime Robert

💻 🐛 -
MetaBF

🐛 +
MetaBF

🐛
Michael

🐛
Michael Bell

🐛
Michael Bernstein

🐛
Michael Clay

🐛
Michael Dombrowski

🐛
Michael Hausegger

🐛 -
Michael Hoefer

🐛 +
Michael Hoefer

🐛
Michael Möbius

🐛
Michael N. Lipp

🐛
Michael Pellegrini

🐛
Michal Kordas

🐛
Michał Borek

🐛
Michał Kuliński

🐛 -
Miguel Núñez Díaz-Montes

🐛 +
Miguel Núñez Díaz-Montes

🐛
Mihai Ionut

🐛
Mirek Hankus

🐛
Mladjan Gadzic

🐛
MrAngry52

🐛
Muminur Choudhury

🐛
Mykhailo Palahuta

💻 🐛 -
Nagendra Kumar Singh

🐛 +
Nagendra Kumar Singh

🐛
Nahuel Barrios

🐛
Nathan Braun

🐛
Nathan Reynolds

🐛
Nathan Reynolds

🐛
Nathanaël

🐛
Naveen

💻 -
Nazdravi

🐛 +
Nazdravi

🐛
Neha-Dhonde

🐛
Nicholas Doyle

🐛
Nick Butcher

🐛
Nico Gallinal

🐛
Nicola Dal Maso

🐛
Nicolas Filotto

💻 -
Nicolas Vervelle

🐛 +
Nicolas Vervelle

🐛
Nicolas Vuillamy

📖
Nikita Chursin

🐛
Niklas Baudy

🐛
Nikolas Havrikov

🐛
Nilesh Virkar

🐛
Nimit Patel

🐛 -
Niranjan Harpale

🐛 +
Niranjan Harpale

🐛
Nirvik Patel

💻
Noah Sussman

🐛
Noah0120

🐛
Noam Tamim

🐛
Noel Grandin

🐛
Olaf Haalstra

🐛 -
Oleg Andreych

💻 🐛 +
Oleg Andreych

💻 🐛
Oleg Pavlenko

🐛
Oleksii Dykov

💻 🐛
Oliver Eikemeier

🐛
Oliver Siegmar

💵
Olivier Parent

💻 🐛
Ollie Abbey

💻 🐛 -
OverDrone

🐛 +
OverDrone

🐛
Ozan Gulle

💻 🐛
PUNEET JAIN

🐛
Parbati Bose

🐛
Paul Berg

🐛
Paul Guyot

💻
Pavel Bludov

🐛 -
Pavel Mička

🐛 +
Pavel Mička

🐛
Pedro Nuno Santos

🐛
Pedro Rijo

🐛
Pelisse Romain

💻 📖 🐛
Per Abich

💻
Pete Davids

🐛
Peter Bruin

🐛 -
Peter Chittum

💻 🐛 +
Peter Chittum

💻 🐛
Peter Cudmore

🐛
Peter Kasson

🐛
Peter Kofler

🐛
Peter Paul Bakker

💻
Pham Hai Trung

🐛
Philip Graf

💻 🐛 -
Philip Hachey

🐛 +
Philip Hachey

🐛
Philippe Ozil

🐛
Phinehas Artemix

🐛
Phokham Nonava

🐛 +
Pim van der Loos

💻 ⚠️
Piotr Szymański

🐛
Piotrek Żygieło

💻 🐛 📖 -
Pranay Jaiswal

🐛 -
Prasad Kamath

🐛 +
Pranay Jaiswal

🐛 +
Prasad Kamath

🐛
Prasanna

🐛
Presh-AR

🐛
Puneet1726

🐛
Rafael Cortês

🐛
RaheemShaik999

🐛 -
RajeshR

💻 🐛 -
Ramachandra Mohan

🐛 +
RajeshR

💻 🐛 +
Ramachandra Mohan

🐛
Ramel0921

🐛
Raquel Pau

🐛
Ravikiran Janardhana

🐛
Reda Benhemmouche

🐛
Renato Oliveira

💻 🐛 -
Rich DiCroce

🐛 -
Riot R1cket

🐛 +
Rich DiCroce

🐛 +
Riot R1cket

🐛
Rishabh Jain

🐛
RishabhDeep Singh

🐛
Robbie Martinus

💻 🐛
Robert Henry

🐛
Robert Mihaly

🐛 -
Robert Painsi

🐛 -
Robert Russell

🐛 +
Robert Painsi

🐛 +
Robert Russell

🐛
Robert Sösemann

💻 📖 📢 🐛
Robert Whitebit

🐛
Robin Richtsfeld

🐛
Robin Stocker

💻 🐛
Robin Wils

🐛 -
RochusOest

🐛 -
Rodolfo Noviski

🐛 +
RochusOest

🐛 +
Rodolfo Noviski

🐛
Rodrigo Casara

🐛
Rodrigo Fernandes

🐛
Roman Salvador

💻 🐛
Ronald Blaschke

🐛
Róbert Papp

🐛 -
Saikat Sengupta

🐛 -
Saksham Handu

🐛 +
Saikat Sengupta

🐛 +
Saksham Handu

🐛
Saladoc

🐛
Salesforce Bob Lightning

🐛
Sam Carlberg

🐛
Satoshi Kubo

🐛
Scott Kennedy

🐛 -
Scott Wells

🐛 💻 -
Scrsloota

💻 +
Scott Wells

🐛 💻 +
Scrsloota

💻
Sebastian Bögl

🐛
Sebastian Schuberth

🐛
Sebastian Schwarz

🐛
Seren

🐛 💻
Sergey Gorbaty

🐛 -
Sergey Kozlov

🐛 -
Sergey Yanzin

💻 🐛 +
Sergey Kozlov

🐛 +
Sergey Yanzin

💻 🐛
Seth Wilcox

💻
Shubham

💻 🐛
Simon Abykov

💻 🐛
Simon Xiao

🐛
Srinivasan Venkatachalam

🐛 -
Stanislav Gromov

🐛 -
Stanislav Myachenkov

💻 +
Stanislav Gromov

🐛 +
Stanislav Myachenkov

💻
Stefan Birkner

🐛
Stefan Bohn

🐛
Stefan Endrullis

🐛
Stefan Klöss-Schuster

🐛
Stefan Wolf

🐛 -
Stephan H. Wissel

🐛 -
Stephen

🐛 +
Stephan H. Wissel

🐛 +
Stephen

🐛
Stephen Friedrich

🐛
Steve Babula

💻
Steven Stearns

🐛 💻
Stexxe

🐛
Stian Lågstad

🐛 -
StuartClayton5

🐛 -
Supun Arunoda

🐛 +
StuartClayton5

🐛 +
Supun Arunoda

🐛
Suren Abrahamyan

🐛
Suvashri

📖
SwatiBGupta1110

🐛
SyedThoufich

🐛
Szymon Sasin

🐛 -
T-chuangxin

🐛 -
TERAI Atsuhiro

🐛 +
T-chuangxin

🐛 +
TERAI Atsuhiro

🐛
TIOBE Software

💻 🐛
Tarush Singh

💻
Taylor Smock

🐛
Techeira Damián

💻 🐛
Ted Husted

🐛 -
TehBakker

🐛 -
The Gitter Badger

🐛 +
TehBakker

🐛 +
The Gitter Badger

🐛
Theodoor

🐛
Thiago Henrique Hüpner

🐛
Thibault Meyer

🐛
Thomas Güttler

🐛
Thomas Jones-Low

🐛 -
Thomas Smith

💻 🐛 -
ThrawnCA

🐛 +
Thomas Smith

💻 🐛 +
ThrawnCA

🐛
Thunderforge

💻 🐛
Tim van der Lippe

🐛
Tobias Weimer

💻 🐛
Tom Copeland

🐛 💻 📖
Tom Daly

🐛 -
Tomer Figenblat

🐛 -
Tomi De Lucca

💻 🐛 +
Tomer Figenblat

🐛 +
Tomi De Lucca

💻 🐛
Torsten Kleiber

🐛
TrackerSB

🐛
Tyson Stewart

🐛
Ullrich Hafner

🐛
Utku Cuhadaroglu

💻 🐛 -
Valentin Brandl

🐛 -
Valeria

🐛 +
Valentin Brandl

🐛 +
Valeria

🐛
Valery Yatsynovich

📖
Vasily Anisimov

🐛
Vibhor Goyal

🐛
Vickenty Fesunov

🐛
Victor Noël

🐛 -
Vincent Galloy

💻 -
Vincent HUYNH

🐛 +
Vincent Galloy

💻 +
Vincent HUYNH

🐛
Vincent Maurin

🐛
Vincent Privat

🐛
Vishhwas

🐛
Vitaly

🐛
Vitaly Polonetsky

🐛 -
Vojtech Polivka

🐛 -
Vsevolod Zholobov

🐛 +
Vojtech Polivka

🐛 +
Vsevolod Zholobov

🐛
Vyom Yadav

💻
Wang Shidong

🐛
Waqas Ahmed

🐛
Wayne J. Earl

🐛
Wchenghui

🐛 -
Will Winder

🐛 -
William Brockhus

💻 🐛 +
Will Winder

🐛 +
William Brockhus

💻 🐛
Wilson Kurniawan

🐛
Wim Deblauwe

🐛
Woongsik Choi

🐛
XenoAmess

💻 🐛
Yang

💻 -
YaroslavTER

🐛 -
Yasar Shaikh

💻 +
YaroslavTER

🐛 +
Yasar Shaikh

💻
Young Chan

💻 🐛
YuJin Kim

🐛
Yuri Dolzhenko

🐛
Yurii Dubinka

🐛
Zoltan Farkas

🐛 -
Zustin

🐛 -
aaronhurst-google

🐛 💻 +
Zustin

🐛 +
aaronhurst-google

🐛 💻
alexmodis

🐛
andreoss

🐛
andrey81inmd

💻 🐛
anicoara

🐛
arunprasathav

🐛 -
asiercamara

🐛 -
astillich-igniti

💻 +
asiercamara

🐛 +
astillich-igniti

💻
avesolovksyy

🐛
avishvat

🐛
avivmu

🐛
axelbarfod1

🐛
b-3-n

🐛 -
balbhadra9

🐛 -
base23de

🐛 +
balbhadra9

🐛 +
base23de

🐛
bergander

🐛
berkam

💻 🐛
breizh31

🐛
caesarkim

🐛
carolyujing

🐛 -
cbfiddle

🐛 -
cesares-basilico

🐛 +
cbfiddle

🐛 +
cesares-basilico

🐛
chrite

🐛
cobratbq

🐛
coladict

🐛
cosmoJFH

🐛
cristalp

🐛 -
crunsk

🐛 -
cwholmes

🐛 +
crunsk

🐛 +
cwholmes

🐛
cyberjj999

🐛
cyw3

🐛
d1ss0nanz

🐛
dague1

📖
dalizi007

💻 -
danbrycefairsailcom

🐛 -
dariansanity

🐛 +
danbrycefairsailcom

🐛 +
dariansanity

🐛
darrenmiliband

🐛
davidburstrom

🐛
dbirkman-paloalto

🐛
deepak-patra

🐛
dependabot[bot]

💻 🐛 -
dinesh150

🐛 -
diziaq

🐛 +
dinesh150

🐛 +
diziaq

🐛
dreaminpast123

🐛
duanyanan

🐛
dutt-sanjay

🐛
dylanleung

🐛
dzeigler

🐛 -
ekkirala

🐛 -
emersonmoura

🐛 +
ekkirala

🐛 +
emersonmoura

🐛
fairy

🐛
filiprafalowicz

💻
foxmason

🐛
frankegabor

🐛
frankl

🐛 -
freafrea

🐛 -
fsapatin

🐛 +
freafrea

🐛 +
fsapatin

🐛
gracia19

🐛
guo fei

🐛
gurmsc5

🐛
gwilymatgearset

💻 🐛
haigsn

🐛 -
hemanshu070

🐛 -
henrik242

🐛 +
hemanshu070

🐛 +
henrik242

🐛
hongpuwu

🐛
hvbtup

💻 🐛
igniti GmbH

🐛
ilovezfs

🐛
itaigilo

🐛 -
jakivey32

🐛 -
jbennett2091

🐛 +
jakivey32

🐛 +
jbennett2091

🐛
jcamerin

🐛
jkeener1

🐛
jmetertea

🐛
johnra2

💻
josemanuelrolon

💻 🐛 -
kabroxiko

💻 🐛 -
karwer

🐛 +
kabroxiko

💻 🐛 +
karwer

🐛
kaulonline

🐛
kdaemonv

🐛
kdebski85

🐛 💻
kenji21

💻 🐛
kfranic

🐛 -
khalidkh

🐛 -
koalalam

🐛 +
khalidkh

🐛 +
koalalam

🐛
krzyk

🐛
lasselindqvist

🐛
lgemeinhardt

🐛
lihuaib

🐛
lonelyma1021

🐛 -
lpeddy

🐛 -
lujiefsi

💻 +
lpeddy

🐛 +
lujiefsi

💻
lukelukes

💻
lyriccoder

🐛
marcelmore

🐛
matchbox

🐛
matthiaskraaz

🐛 -
meandonlyme

🐛 -
mikesive

🐛 +
meandonlyme

🐛 +
mikesive

🐛
milossesic

🐛
mluckam

💻
mohan-chinnappan-n

💻
mriddell95

🐛
mrlzh

🐛 -
msloan

🐛 -
mucharlaravalika

🐛 +
msloan

🐛 +
mucharlaravalika

🐛
mvenneman

🐛
nareshl119

🐛
nicolas-harraudeau-sonarsource

🐛
noerremark

🐛
novsirion

🐛 -
oggboy

🐛 -
oinume

🐛 +
nwcm

📖 +
oggboy

🐛 +
oinume

🐛
orimarko

💻 🐛
pacvz

💻
pallavi agarwal

🐛
parksungrin

🐛 + +
patpatpat123

🐛
patriksevallius

🐛
pbrajesh1

🐛 - -
phoenix384

🐛
piotrszymanski-sc

💻
plan3d

🐛
poojasix

🐛 + +
prabhushrikant

🐛
pujitha8783

🐛
r-r-a-j

🐛 - -
raghujayjunk

🐛
rajeshveera

🐛
rajeswarreddy88

🐛
recdevs

🐛 + +
reudismam

💻 🐛
rijkt

🐛
rillig-tk

🐛 - -
rmohan20

💻 🐛
rnveach

🐛
rxmicro

🐛
ryan-gustafson

💻 🐛 + +
sabi0

🐛
scais

🐛
sebbASF

🐛 - -
sergeygorbaty

💻
shilko2013

🐛
shiomiyan

📖
simeonKondr

🐛 + +
snajberk

🐛
sniperrifle2004

🐛
snuyanzin

🐛 💻 - -
sratz

🐛
stonio

🐛
sturton

💻 🐛
sudharmohan

🐛 + +
suruchidawar

🐛
svenfinitiv

🐛
tashiscool

🐛 - -
test-git-hook

🐛
testation21

💻 🐛
thanosa

🐛
tiandiyixian

🐛 + +
tobwoerk

🐛
tprouvot

🐛 💻
trentchilders

🐛 - -
triandicAnt

🐛
trishul14

🐛
tsui

🐛
winhkey

🐛 + +
witherspore

🐛
wjljack

🐛
wuchiuwong

🐛 - -
xingsong

🐛
xioayuge

🐛
xnYi9wRezm

💻 🐛
xuanuy

🐛 + +
xyf0921

🐛
yalechen-cyw3

🐛
yasuharu-sato

🐛 - -
zenglian

🐛
zgrzyt93

💻 🐛
zh3ng

🐛
zt_soft

🐛 + +
ztt79

🐛
zzzzfeng

🐛
Árpád Magosányi

🐛 - -
任贵杰

🐛
茅延安

💻 diff --git a/docs/pages/pmd/projectdocs/logo.md b/docs/pages/pmd/projectdocs/logo.md index 17a94f01e9..3838039f8e 100644 --- a/docs/pages/pmd/projectdocs/logo.md +++ b/docs/pages/pmd/projectdocs/logo.md @@ -10,11 +10,26 @@ folder: pmd/projectdocs The following PMD Logos and Icons are licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/): -* [PMD.svg](images/logo/PMD.svg) +* [PMD.svg](images/logo/PMD.svg) - main logo source file. All other sizes/images are derived from that. * [PMD.png](images/logo/PMD.png) +* [Logo (70px, transparent)](images/logo/pmd-logo-70px.png) +* [Logo (70px, transparent, square shape)](images/logo/pmd-logo-70px-squared.png) * [Logo (300px, transparent)](images/logo/pmd-logo-300px.png) +* [Logo (300px, transparent, square shape)](images/logo/pmd-logo-300px-squared.png) * [Logo (300px, white)](images/logo/pmd-logo-white-300px.png) +* [Logo (300px, white, square shape)](images/logo/pmd-logo-white-300px-squared.png) +* [Logo (400x165px, white)](images/logo/pmd-logo-white-400x165px.png) * [Logo (600px, transparent)](images/logo/pmd-logo-600px.png) +* [Logo (600px, transparent, square shape)](images/logo/pmd-logo-600px-squared.png) * [Logo (600px, white)](images/logo/pmd-logo-white-600px.png) +* [Logo (600px, white, suqare shape)](images/logo/pmd-logo-white-600px-squared.png) * [Favicon (16x16)](images/logo/favicon.ico) + +This new greenish logo was introduced with PMD 7. + +Before that, PMD used the following logo with the tagline "Don't shoot the messenger". +These old logos are provided here only as reference for historical reasons and shouldn't be used anymore. + +* [Old logo - pmd-old.svg](images/logo/pmd-old.svg) +* [Old logo (600x440px, white)](images/logo/pmd-old-logo-white-600x440px.png) diff --git a/docs/pages/pmd/userdocs/cpd/cpd.md b/docs/pages/pmd/userdocs/cpd/cpd.md index a8719c55b9..fc93959c4d 100644 --- a/docs/pages/pmd/userdocs/cpd/cpd.md +++ b/docs/pages/pmd/userdocs/cpd/cpd.md @@ -457,7 +457,7 @@ public Object someParameterizedFactoryMethod(int x) throws Exception { // any code here will be ignored for the duplication detection } //disable suppression -@SuppressWarnings("CPD-END) +@SuppressWarnings("CPD-END") public void nextMethod() { } ``` diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b875222f4d..a3c12dd7d9 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -5,7 +5,7 @@ keywords: changelog, release notes --- {% if is_release_notes_processor %} -{% capture baseurl %}https://pmd.github.io/pmd-{{ site.pmd.version }}/{% endcapture %} +{% capture baseurl %}https://docs.pmd-code.org/pmd-doc-{{ site.pmd.version }}/{% endcapture %} {% else %} {% assign baseurl = "" %} {% endif %} @@ -39,11 +39,59 @@ for all.

This section lists the most important changes from the last release candidate. The remaining section describe the complete release notes for 7.0.0. -Fixed Issues: +#### API Changes +* Moved the two classes {% jdoc core::cpd.impl.AntlrTokenizer %} and {% jdoc core::cpd.impl.JavaCCTokenizer %} from + `internal` package into package {% jdoc_package core::cpd.impl %}. These two classes are part of the API and + are base classes for CPD language implementations. +* `AntlrBaseRule` is gone in favor of {% jdoc core::lang.rule.AbstractVisitorRule %}. +* The classes {% jdoc kotlin::lang.kotlin.ast.KotlinInnerNode %} and {% jdoc swift::lang.swift.ast.SwiftInnerNode %} + are package-private now. +* The parameter order of {% jdoc core::lang.document.FileCollector#addSourceFile(String, String) %} has been swapped + in order to have the same meaning as in 6.55.0. That will make it easier if you upgrade from 6.55.0 to 7.0.0. + However, that means, that you need to change these method calls if you have migrated to 7.0.0-rc1 already. + +#### Updated PMD Designer +This PMD release ships a new version of the pmd-designer. +For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/7.0.0-rc1). + +#### Rule Changes +* {% rule "java/design/ImmutableField" %}: the property `ignoredAnnotations` has been removed. The property was + deprecated since PMD 6.52.0. + +#### Fixed Issues +* cli + * [#4482](https://github.com/pmd/pmd/issues/4482): \[cli] pmd.bat can only be executed once + * [#4484](https://github.com/pmd/pmd/issues/4484): \[cli] ast-dump with no properties produce an NPE +* core + * [#2500](https://github.com/pmd/pmd/issues/2500): \[core] Clarify API for ANTLR based languages +* doc + * [#2501](https://github.com/pmd/pmd/issues/2501): \[doc] Verify ANTLR Documentation + * [#4438](https://github.com/pmd/pmd/issues/4438): \[doc] Documentation links in VS Code are outdated * java-codestyle * [#4273](https://github.com/pmd/pmd/issues/4273): \[java] CommentDefaultAccessModifier ignoredAnnotations should include "org.junit.jupiter.api.extension.RegisterExtension" by default + * [#4487](https://github.com/pmd/pmd/issues/4487): \[java] UnnecessaryConstructor: false-positive with @Inject and @Autowired +* java-design + * [#4254](https://github.com/pmd/pmd/issues/4254): \[java] ImmutableField - false positive with Lombok @Setter + * [#4477](https://github.com/pmd/pmd/issues/4477): \[java] SignatureDeclareThrowsException: false-positive with TestNG annotations + * [#4490](https://github.com/pmd/pmd/issues/4490): \[java] ImmutableField - false negative with Lombok @Getter * java-errorprone * [#4449](https://github.com/pmd/pmd/issues/4449): \[java] AvoidAccessibilityAlteration: Possible false positive in AvoidAccessibilityAlteration rule when using Lambda expression + * [#4493](https://github.com/pmd/pmd/issues/4493): \[java] MissingStaticMethodInNonInstantiatableClass: false-positive about @Inject + * [#4505](https://github.com/pmd/pmd/issues/4505): \[java] ImplicitSwitchFallThrough NPE in PMD 7.0.0-rc1 +* java-multithreading + * [#4483](https://github.com/pmd/pmd/issues/4483): \[java] NonThreadSafeSingleton false positive with double-checked locking +* miscellaneous + * [#4462](https://github.com/pmd/pmd/issues/4462): Provide Software Bill of Materials (SBOM) + +#### External contributions +* [#4444](https://github.com/pmd/pmd/pull/4444): \[java] CommentDefaultAccessModifier - ignore org.junit.jupiter.api.extension.RegisterExtension by default - [Nirvik Patel](https://github.com/nirvikpatel) (@nirvikpatel) +* [#4450](https://github.com/pmd/pmd/pull/4450): \[java] Fix #4449 AvoidAccessibilityAlteration: Correctly handle Lambda expressions in PrivilegedAction scenarios - [Seren](https://github.com/mohui1999) (@mohui1999) +* [#4452](https://github.com/pmd/pmd/pull/4452): \[doc] Update PMD_APEX_ROOT_DIRECTORY documentation reference - [nwcm](https://github.com/nwcm) (@nwcm) +* [#4474](https://github.com/pmd/pmd/pull/4474): \[java] ImmutableField: False positive with lombok (fixes #4254) - [Pim van der Loos](https://github.com/PimvanderLoos) (@PimvanderLoos) +* [#4488](https://github.com/pmd/pmd/pull/4488): \[java] Fix #4477: A false-positive about SignatureDeclareThrowsException - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe) +* [#4494](https://github.com/pmd/pmd/pull/4494): \[java] Fix #4487: A false-positive about UnnecessaryConstructor and @Inject and @Autowired - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe) +* [#4495](https://github.com/pmd/pmd/pull/4495): \[java] Fix #4493: false-positive about MissingStaticMethodInNonInstantiatableClass and @Inject - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe) +* [#4520](https://github.com/pmd/pmd/pull/4520): \[doc] Fix typo: missing closing quotation mark after CPD-END - [João Dinis Ferreira](https://github.com/joaodinissf) (@joaodinissf) ### 🚀 Major Features and Enhancements @@ -60,7 +108,7 @@ The new official logo of PMD: * Rewritten type resolution framework and symbol table correctly implements the JLS * AST exposes more semantic information (method calls, field accesses) -For more information, see the [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). +For more information, see the [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html). Contributors: [Clément Fournier](https://github.com/oowekyala) (@oowekyala), [Andreas Dangel](https://github.com/adangel) (@adangel), @@ -78,7 +126,7 @@ Contributors: [Clément Fournier](https://github.com/oowekyala) (@oowekyala), ![Demo]({{ baseurl }}images/userdocs/pmd-demo.gif) -For more information, see the [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). +For more information, see the [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html). Contributors: [Juan Martín Sotuyo Dodero](https://github.com/jsotuyod) (@jsotuyod) @@ -88,16 +136,21 @@ Contributors: [Juan Martín Sotuyo Dodero](https://github.com/jsotuyod) (@jsotuy * Previously, Antlr grammar could only be used for CPD * New supported languages: Swift and Kotlin -For more information, see the [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). +For more information, see the [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html). Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), [Matías Fraga](https://github.com/matifraga) (@matifraga), [Tomás De Lucca](https://github.com/tomidelucca) (@tomidelucca) +#### Updated PMD Designer + +This PMD release ships a new version of the pmd-designer. +For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/7.0.0-rc1). + ### 🎉 Language Related Changes Note that this is just a concise listing of the highlight. -For more information on the languages, see the [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). +For more information on the languages, see the [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html). #### New: Swift support @@ -114,6 +167,20 @@ Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), * Support for Kotlin 1.8 grammar * initially 2 built-in rules +#### New: CPD support for TypeScript + +Thanks to a contribution, CPD now supports the TypeScript language. It is shipped +with the rest of the JavaScript support in the module `pmd-javascript`. + +Contributors: [Paul Guyot](https://github.com/pguyot) (@pguyot) + +#### New: CPD support for Julia + +Thanks to a contribution, CPD now supports the Julia language. It is shipped +in the new module `pmd-julia`. + +Contributors: [Wener](https://github.com/wener-tiobe) (@wener-tiobe) + #### Changed: JavaScript support * latest version supports ES6 and also some new constructs (see [Rhino](https://github.com/mozilla/rhino)]) @@ -172,11 +239,13 @@ Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), * {% rule "java/documentation/CommentContent" %}: The properties `caseSensitive` and `disallowedTerms` are removed. The new property `fobiddenRegex` can be used now to define the disallowed terms with a single regular expression. +* {% rule "java/design/ImmutableField" %}: the property `ignoredAnnotations` has been removed. The property was + deprecated since PMD 6.52.0. #### Removed Rules Many rules, that were previously deprecated have been finally removed. -See [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html) for the complete list. +See [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html) for the complete list. ### 🚨 API @@ -185,7 +254,7 @@ have a clear separation between a well-defined API and the implementation, which This should help us in future development. Also, there are some improvement and changes in different areas. For the detailed description -of the changes listed here, see [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). +of the changes listed here, see [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html). * Miscellaneous smaller changes and cleanups * XPath 3.1 support for XPath-based rules @@ -195,7 +264,7 @@ of the changes listed here, see [Detailed Release Notes for PMD 7](pmd_release_n * Language Lifecycle and Language Properties ### 💥 Compatibility and migration notes -See [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). +See [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html). ### 🐛 Fixed Issues @@ -208,6 +277,7 @@ See [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). * [#2497](https://github.com/pmd/pmd/issues/2497): PMD 7 Logo page * [#2498](https://github.com/pmd/pmd/issues/2498): Update PMD 7 Logo in documentation * [#3797](https://github.com/pmd/pmd/issues/3797): \[all] Use JUnit5 + * [#4462](https://github.com/pmd/pmd/issues/4462): Provide Software Bill of Materials (SBOM) * ant * [#4080](https://github.com/pmd/pmd/issues/4080): \[ant] Split off Ant integration into a new submodule * core @@ -220,6 +290,7 @@ See [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). * [#2218](https://github.com/pmd/pmd/issues/2218): \[core] `isFindBoundary` should not be an attribute * [#2234](https://github.com/pmd/pmd/issues/2234): \[core] Consolidate PMD CLI into a single command * [#2239](https://github.com/pmd/pmd/issues/2239): \[core] Merging Javacc build scripts + * [#2500](https://github.com/pmd/pmd/issues/2500): \[core] Clarify API for ANTLR based languages * [#2518](https://github.com/pmd/pmd/issues/2518): \[core] Language properties * [#2602](https://github.com/pmd/pmd/issues/2602): \[core] Remove ParserOptions * [#2614](https://github.com/pmd/pmd/pull/2614): \[core] Upgrade Saxon, add XPath 3.1, remove Jaxen @@ -244,6 +315,11 @@ See [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). * [#2234](https://github.com/pmd/pmd/issues/2234): \[core] Consolidate PMD CLI into a single command * [#3828](https://github.com/pmd/pmd/issues/3828): \[core] Progress reporting * [#4079](https://github.com/pmd/pmd/issues/4079): \[cli] Split off CLI implementation into a pmd-cli submodule + * [#4482](https://github.com/pmd/pmd/issues/4482): \[cli] pmd.bat can only be executed once + * [#4484](https://github.com/pmd/pmd/issues/4484): \[cli] ast-dump with no properties produce an NPE +* doc + * [#2501](https://github.com/pmd/pmd/issues/2501): \[doc] Verify ANTLR Documentation + * [#4438](https://github.com/pmd/pmd/issues/4438): \[doc] Documentation links in VS Code are outdated * testing * [#2435](https://github.com/pmd/pmd/issues/2435): \[test] Remove duplicated Dummy language module * [#4234](https://github.com/pmd/pmd/issues/4234): \[test] Tests that change the logging level do not work @@ -274,6 +350,7 @@ Language specific fixes: * [#1661](https://github.com/pmd/pmd/issues/1661): \[java] About operator nodes * [#2366](https://github.com/pmd/pmd/pull/2366): \[java] Remove qualified names * [#2819](https://github.com/pmd/pmd/issues/2819): \[java] GLB bugs in pmd 7 + * [#3642](https://github.com/pmd/pmd/issues/3642): \[java] Parse error on rare extra dimensions on method return type on annotation methods * [#3763](https://github.com/pmd/pmd/issues/3763): \[java] Ambiguous reference error in valid code * [#3749](https://github.com/pmd/pmd/issues/3749): \[java] Improve `isOverridden` in ASTMethodDeclaration * [#3750](https://github.com/pmd/pmd/issues/3750): \[java] Make symbol table support instanceof pattern bindings @@ -291,7 +368,9 @@ Language specific fixes: * [#1189](https://github.com/pmd/pmd/issues/1189): \[java] UnusedPrivateMethod false positive from inner class via external class * [#1205](https://github.com/pmd/pmd/issues/1205): \[java] Improve ConstantsInInterface message to mention alternatives * [#1212](https://github.com/pmd/pmd/issues/1212): \[java] Don't raise JUnitTestContainsTooManyAsserts on JUnit 5's assertAll - * [#1422](https://github.com/pmd/pmd/issues/1422): \[java] JUnitTestsShouldIncludeAssert false positive with inherited @Rule field + * [#1422](https://github.com/pmd/pmd/issues/1422): \[java] JUnitTestsShouldIncludeAssert false positive with inherited @Rule field + * [#1455](https://github.com/pmd/pmd/issues/1455): \[java] JUnitTestsShouldIncludeAssert: False positives for assert methods named "check" and "verify" + * [#1563](https://github.com/pmd/pmd/issues/1563): \[java] False positive ForLoopCanBeForeach * [#1565](https://github.com/pmd/pmd/issues/1565): \[java] JUnitAssertionsShouldIncludeMessage false positive with AssertJ * [#1747](https://github.com/pmd/pmd/issues/1747): \[java] PreserveStackTrace false-positive * [#1969](https://github.com/pmd/pmd/issues/1969): \[java] MissingOverride false-positive triggered by package-private method overwritten in another package by extending class @@ -312,9 +391,11 @@ Language specific fixes: * [#2946](https://github.com/pmd/pmd/issues/2946): \[java] SwitchStmtsShouldHaveDefault false positive on enum inside enums * [#3672](https://github.com/pmd/pmd/pull/3672): \[java] LooseCoupling - fix false positive with generics * [#3675](https://github.com/pmd/pmd/pull/3675): \[java] MissingOverride - fix false positive with mixing type vars + * [#3858](https://github.com/pmd/pmd/issues/3858): \[java] UseCollectionIsEmpty should infer local variable type from method invocation * java-codestyle * [#1208](https://github.com/pmd/pmd/issues/1208): \[java] PrematureDeclaration rule false-positive on variable declared to measure time * [#1429](https://github.com/pmd/pmd/issues/1429): \[java] PrematureDeclaration as result of method call (false positive) + * [#1480](https://github.com/pmd/pmd/issues/1480): \[java] IdenticalCatchBranches false positive * [#1673](https://github.com/pmd/pmd/issues/1673): \[java] UselessParentheses false positive with conditional operator * [#1790](https://github.com/pmd/pmd/issues/1790): \[java] UnnecessaryFullyQualifiedName false positive with enum constant * [#1918](https://github.com/pmd/pmd/issues/1918): \[java] UselessParentheses false positive with boolean operators @@ -332,9 +413,11 @@ Language specific fixes: * [#3500](https://github.com/pmd/pmd/pull/3500): \[java] UnnecessaryBoxing - check for Integer.valueOf(String) calls * [#4273](https://github.com/pmd/pmd/issues/4273): \[java] CommentDefaultAccessModifier ignoredAnnotations should include "org.junit.jupiter.api.extension.RegisterExtension" by default * [#4357](https://github.com/pmd/pmd/pull/4357): \[java] Fix IllegalStateException in UseDiamondOperator rule + * [#4487](https://github.com/pmd/pmd/issues/4487): \[java] UnnecessaryConstructor: false-positive with @Inject and @Autowired * java-design * [#1014](https://github.com/pmd/pmd/issues/1014): \[java] LawOfDemeter: False positive with lambda expression * [#1605](https://github.com/pmd/pmd/issues/1605): \[java] LawOfDemeter: False positive for standard UTF-8 charset name + * [#2160](https://github.com/pmd/pmd/issues/2160): \[java] Issues with Law of Demeter * [#2175](https://github.com/pmd/pmd/issues/2175): \[java] LawOfDemeter: False positive for chained methods with generic method call * [#2179](https://github.com/pmd/pmd/issues/2179): \[java] LawOfDemeter: False positive with static property access - should treat class-level property as global object, not dot-accessed property * [#2180](https://github.com/pmd/pmd/issues/2180): \[java] LawOfDemeter: False positive with Thread and ThreadLocalRandom @@ -345,6 +428,9 @@ Language specific fixes: * [#3754](https://github.com/pmd/pmd/issues/3754): \[java] SingularField false positive with read in while condition * [#3786](https://github.com/pmd/pmd/issues/3786): \[java] SimplifyBooleanReturns should consider operator precedence * [#4238](https://github.com/pmd/pmd/pull/4238): \[java] Make LawOfDemeter not use the rulechain + * [#4254](https://github.com/pmd/pmd/issues/4254): \[java] ImmutableField - false positive with Lombok @Setter + * [#4477](https://github.com/pmd/pmd/issues/4477): \[java] SignatureDeclareThrowsException: false-positive with TestNG annotations + * [#4490](https://github.com/pmd/pmd/issues/4490): \[java] ImmutableField - false negative with Lombok @Getter * java-documentation * [#4369](https://github.com/pmd/pmd/pull/4369): \[java] Improve CommentSize * [#4416](https://github.com/pmd/pmd/pull/4416): \[java] Fix reported line number in CommentContentRule @@ -352,7 +438,7 @@ Language specific fixes: * [#659](https://github.com/pmd/pmd/issues/659): \[java] MissingBreakInSwitch - last default case does not contain a break * [#1005](https://github.com/pmd/pmd/issues/1005): \[java] CloneMethodMustImplementCloneable triggers for interfaces * [#1669](https://github.com/pmd/pmd/issues/1669): \[java] NullAssignment - FP with ternay and null as constructor argument - * [#1899](https://github.com/pmd/pmd/issues/1899): \[java] Recognize @SuppressWanings("fallthrough") for MissingBreakInSwitch + * [#1899](https://github.com/pmd/pmd/issues/1899): \[java] Recognize @SuppressWanings("fallthrough") for MissingBreakInSwitch * [#2320](https://github.com/pmd/pmd/issues/2320): \[java] NullAssignment - FP with ternary and null as method argument * [#2532](https://github.com/pmd/pmd/issues/2532): \[java] AvoidDecimalLiteralsInBigDecimalConstructor can not detect the case `new BigDecimal(Expression)` * [#2579](https://github.com/pmd/pmd/issues/2579): \[java] MissingBreakInSwitch detects the lack of break in the last case @@ -365,17 +451,22 @@ Language specific fixes: * [#3173](https://github.com/pmd/pmd/issues/3173): \[java] UseProperClassLoader false positive * [#3351](https://github.com/pmd/pmd/issues/3351): \[java] ConstructorCallsOverridableMethod ignores abstract methods * [#3400](https://github.com/pmd/pmd/issues/3400): \[java] AvoidUsingOctalValues FN with underscores + * [#3843](https://github.com/pmd/pmd/issues/3843): \[java] UseEqualsToCompareStrings should consider return type * [#4356](https://github.com/pmd/pmd/pull/4356): \[java] Fix NPE in CloseResourceRule * [#4449](https://github.com/pmd/pmd/issues/4449): \[java] AvoidAccessibilityAlteration: Possible false positive in AvoidAccessibilityAlteration rule when using Lambda expression + * [#4493](https://github.com/pmd/pmd/issues/4493): \[java] MissingStaticMethodInNonInstantiatableClass: false-positive about @Inject + * [#4505](https://github.com/pmd/pmd/issues/4505): \[java] ImplicitSwitchFallThrough NPE in PMD 7.0.0-rc1 * java-multithreading * [#2537](https://github.com/pmd/pmd/issues/2537): \[java] DontCallThreadRun can't detect the case that call run() in `this.run()` * [#2538](https://github.com/pmd/pmd/issues/2538): \[java] DontCallThreadRun can't detect the case that call run() in `foo.bar.run()` * [#2577](https://github.com/pmd/pmd/issues/2577): \[java] UseNotifyAllInsteadOfNotify falsely detect a special case with argument: `foo.notify(bar)` + * [#4483](https://github.com/pmd/pmd/issues/4483): \[java] NonThreadSafeSingleton false positive with double-checked locking * java-performance * [#1224](https://github.com/pmd/pmd/issues/1224): \[java] InefficientEmptyStringCheck false negative in anonymous class * [#2587](https://github.com/pmd/pmd/issues/2587): \[java] AvoidArrayLoops could also check for list copy through iterated List.add() * [#2712](https://github.com/pmd/pmd/issues/2712): \[java] SimplifyStartsWith false-positive with AssertJ * [#3486](https://github.com/pmd/pmd/pull/3486): \[java] InsufficientStringBufferDeclaration: Fix NPE + * [#3848](https://github.com/pmd/pmd/issues/3848): \[java] StringInstantiation: false negative when using method result * kotlin * [#419](https://github.com/pmd/pmd/issues/419): \[kotlin] Add support for Kotlin * [#4389](https://github.com/pmd/pmd/pull/4389): \[kotlin] Update grammar to version 1.8 @@ -395,10 +486,18 @@ Language specific fixes: * [#1882](https://github.com/pmd/pmd/pull/1882): \[swift] UnavailableFunction Swift rule - [Tomás de Lucca](https://github.com/tomidelucca) (@tomidelucca) * [#2830](https://github.com/pmd/pmd/pull/2830): \[apex] Apexlink POC - [Kevin Jones](https://github.com/nawforce) (@nawforce) * [#3866](https://github.com/pmd/pmd/pull/3866): \[core] Add CLI Progress Bar - [@JerritEic](https://github.com/JerritEic) (@JerritEic) +* [#4402](https://github.com/pmd/pmd/pull/4402): \[javascript] CPD: add support for Typescript using antlr4 grammar - [Paul Guyot](https://github.com/pguyot) (@pguyot) +* [#4403](https://github.com/pmd/pmd/pull/4403): \[julia] CPD: Add support for Julia code duplication - [Wener](https://github.com/wener-tiobe) (@wener-tiobe) * [#4412](https://github.com/pmd/pmd/pull/4412): \[doc] Added new error msg to ConstantsInInterface - [David Ljunggren](https://github.com/dague1) (@dague1) * [#4428](https://github.com/pmd/pmd/pull/4428): \[apex] ApexBadCrypto bug fix for #4427 - inline detection of hard coded values - [Steven Stearns](https://github.com/sfdcsteve) (@sfdcsteve) * [#4444](https://github.com/pmd/pmd/pull/4444): \[java] CommentDefaultAccessModifier - ignore org.junit.jupiter.api.extension.RegisterExtension by default - [Nirvik Patel](https://github.com/nirvikpatel) (@nirvikpatel) * [#4450](https://github.com/pmd/pmd/pull/4450): \[java] Fix #4449 AvoidAccessibilityAlteration: Correctly handle Lambda expressions in PrivilegedAction scenarios - [Seren](https://github.com/mohui1999) (@mohui1999) +* [#4452](https://github.com/pmd/pmd/pull/4452): \[doc] Update PMD_APEX_ROOT_DIRECTORY documentation reference - [nwcm](https://github.com/nwcm) (@nwcm) +* [#4474](https://github.com/pmd/pmd/pull/4474): \[java] ImmutableField: False positive with lombok (fixes #4254) - [Pim van der Loos](https://github.com/PimvanderLoos) (@PimvanderLoos) +* [#4488](https://github.com/pmd/pmd/pull/4488): \[java] Fix #4477: A false-positive about SignatureDeclareThrowsException - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe) +* [#4494](https://github.com/pmd/pmd/pull/4494): \[java] Fix #4487: A false-positive about UnnecessaryConstructor and @Inject and @Autowired - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe) +* [#4495](https://github.com/pmd/pmd/pull/4495): \[java] Fix #4493: false-positive about MissingStaticMethodInNonInstantiatableClass and @Inject - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe) +* [#4520](https://github.com/pmd/pmd/pull/4520): \[doc] Fix typo: missing closing quotation mark after CPD-END - [João Dinis Ferreira](https://github.com/joaodinissf) (@joaodinissf) ### 📈 Stats * 4416 commits diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 7b05d6ff5b..acece18793 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -12,7 +12,7 @@ Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/rele We're excited to bring you the next major version of PMD! Since this is a big release, we provide here only a concise version of the release notes. We prepared a separate -page with the full [Detailed Release Notes for PMD 7.0.0](https://pmd.github.io/pmd-7.0.0-rc1/pmd_release_notes_pmd7.html). +page with the full [Detailed Release Notes for PMD 7.0.0](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_release_notes_pmd7.html).
ℹ️ Release Candidates @@ -57,7 +57,7 @@ for all.

The new official logo of PMD: -![New PMD Logo](https://pmd.github.io/pmd-7.0.0-rc1/images/logo/pmd-logo-300px.png) +![New PMD Logo](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/images/logo/pmd-logo-300px.png) #### Revamped Java module @@ -82,7 +82,7 @@ Contributors: [Clément Fournier](https://github.com/oowekyala) (@oowekyala), * progress bar support for `pmd check` * shell completion -![Demo](https://pmd.github.io/pmd-7.0.0-rc1/images/userdocs/pmd-demo.gif) +![Demo](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/images/userdocs/pmd-demo.gif) For more information, see the [Detailed Release Notes for PMD 7](pmd_release_notes_pmd7.html). @@ -136,46 +136,46 @@ Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), #### New Rules **Apex** -* [`UnusedMethod`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_apex_design.html#unusedmethod) finds unused methods in your code. +* [`UnusedMethod`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_apex_design.html#unusedmethod) finds unused methods in your code. **Java** -* [`UnnecessaryBoxing`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_codestyle.html#unnecessaryboxing) reports boxing and unboxing conversions that may be made implicit. +* [`UnnecessaryBoxing`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_codestyle.html#unnecessaryboxing) reports boxing and unboxing conversions that may be made implicit. **Kotlin** -* [`FunctionNameTooShort`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_kotlin_bestpractices.html#functionnametooshort) -* [`OverrideBothEqualsAndHashcode`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_kotlin_errorprone.html#overridebothequalsandhashcode) +* [`FunctionNameTooShort`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_kotlin_bestpractices.html#functionnametooshort) +* [`OverrideBothEqualsAndHashcode`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_kotlin_errorprone.html#overridebothequalsandhashcode) **Swift** -* [`ProhibitedInterfaceBuilder`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_swift_bestpractices.html#prohibitedinterfacebuilder) -* [`UnavailableFunction`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_swift_bestpractices.html#unavailablefunction) -* [`ForceCast`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_swift_errorprone.html#forcecast) -* [`ForceTry`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_swift_errorprone.html#forcetry) +* [`ProhibitedInterfaceBuilder`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_swift_bestpractices.html#prohibitedinterfacebuilder) +* [`UnavailableFunction`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_swift_bestpractices.html#unavailablefunction) +* [`ForceCast`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_swift_errorprone.html#forcecast) +* [`ForceTry`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_swift_errorprone.html#forcetry) #### Changed Rules **Java** -* [`UnnecessaryFullyQualifiedName`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_codestyle.html#unnecessaryfullyqualifiedname): the rule has two new properties, +* [`UnnecessaryFullyQualifiedName`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_codestyle.html#unnecessaryfullyqualifiedname): the rule has two new properties, to selectively disable reporting on static field and method qualifiers. The rule also has been improved to be more precise. -* [`UselessParentheses`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_codestyle.html#uselessparentheses): the rule has two new properties which control how strict +* [`UselessParentheses`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_codestyle.html#uselessparentheses): the rule has two new properties which control how strict the rule should be applied. With `ignoreClarifying` (default: true) parentheses that are strictly speaking not necessary are allowed, if they separate expressions of different precedence. The other property `ignoreBalancing` (default: true) is similar, in that it allows parentheses that help reading and understanding the expressions. -* [`LooseCoupling`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_bestpractices.html#loosecoupling): the rule has a new property to allow some types to be coupled +* [`LooseCoupling`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_bestpractices.html#loosecoupling): the rule has a new property to allow some types to be coupled to (`allowedTypes`). -* [`EmptyCatchBlock`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_errorprone.html#emptycatchblock): `CloneNotSupportedException` and `InterruptedException` are not +* [`EmptyCatchBlock`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_errorprone.html#emptycatchblock): `CloneNotSupportedException` and `InterruptedException` are not special-cased anymore. Rename the exception parameter to `ignored` to ignore them. -* [`DontImportSun`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_errorprone.html#dontimportsun): `sun.misc.Signal` is not special-cased anymore. -* [`UseDiamondOperator`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_codestyle.html#usediamondoperator): the property `java7Compatibility` is removed. The rule now +* [`DontImportSun`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_errorprone.html#dontimportsun): `sun.misc.Signal` is not special-cased anymore. +* [`UseDiamondOperator`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_codestyle.html#usediamondoperator): the property `java7Compatibility` is removed. The rule now handles Java 7 properly without a property. -* [`SingularField`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_design.html#singularfield): Properties `checkInnerClasses` and `disallowNotAssignment` are removed. +* [`SingularField`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_design.html#singularfield): Properties `checkInnerClasses` and `disallowNotAssignment` are removed. The rule is now more precise and will check these cases properly. -* [`UseUtilityClass`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_design.html#useutilityclass): The property `ignoredAnnotations` has been removed. -* [`LawOfDemeter`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_design.html#lawofdemeter): the rule has a new property `trustRadius`. This defines the maximum degree +* [`UseUtilityClass`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_design.html#useutilityclass): The property `ignoredAnnotations` has been removed. +* [`LawOfDemeter`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_design.html#lawofdemeter): the rule has a new property `trustRadius`. This defines the maximum degree of trusted data. The default of 1 is the most restrictive. -* [`CommentContent`](https://pmd.github.io/pmd-7.0.0-rc1/pmd_rules_java_documentation.html#commentcontent): The properties `caseSensitive` and `disallowedTerms` are removed. The +* [`CommentContent`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc1/pmd_rules_java_documentation.html#commentcontent): The properties `caseSensitive` and `disallowedTerms` are removed. The new property `fobiddenRegex` can be used now to define the disallowed terms with a single regular expression. @@ -453,6 +453,7 @@ version `20-preview`: ./run.sh pmd --use-version java-20-preview ... #### T-SQL support + Thanks to the contribution from [Paul Guyot](https://github.com/pguyot) PMD now has CPD support for T-SQL (Transact-SQL). diff --git a/docs/pages/release_notes_pmd7.md b/docs/pages/release_notes_pmd7.md index 9f74c26e59..08f285d210 100644 --- a/docs/pages/release_notes_pmd7.md +++ b/docs/pages/release_notes_pmd7.md @@ -441,6 +441,11 @@ Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), [Matías Fraga](https://github.com/matifraga) (@matifraga), [Tomás De Lucca](https://github.com/tomidelucca) (@tomidelucca) +### Updated PMD Designer + +This PMD release ships a new version of the pmd-designer. +For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/7.0.0-rc1). + ## 🎉 Language Related Changes ### New: Swift support @@ -550,6 +555,8 @@ Related issue: [[core] Explicitly name all language versions (#4120)](https://gi * {% rule "java/documentation/CommentContent" %}: The properties `caseSensitive` and `disallowedTerms` are removed. The new property `fobiddenRegex` can be used now to define the disallowed terms with a single regular expression. +* {% rule "java/design/ImmutableField" %}: the property `ignoredAnnotations` has been removed. The property was + deprecated since PMD 6.52.0. ### Deprecated Rules @@ -750,6 +757,13 @@ until the next major release, but it is recommended to stop using them. * {% jdoc core::util.IteratorUtil %} * {% jdoc core::util.StringUtil %} +* Moved the two classes {% jdoc core::cpd.impl.AntlrTokenizer %} and {% jdoc core::cpd.impl.JavaCCTokenizer %} from + `internal` package into package {% jdoc_package core::cpd.impl %}. These two classes are part of the API and + are base classes for CPD language implementations. Since 7.0.0-rc2. +* `AntlrBaseRule` is gone in favor of {% jdoc core::lang.rule.AbstractVisitorRule %}. Since 7.0.0-rc2. +* The classes {% jdoc kotlin::lang.kotlin.ast.KotlinInnerNode %} and {% jdoc swift::lang.swift.ast.SwiftInnerNode %} + are package-private now. Since 7.0.0-rc2. + ### XPath 3.1 support Support for XPath versions 1.0, 1.0-compatibility was removed, support for XPath 2.0 is deprecated. The default diff --git a/docs/report-examples/pmd-report.sarif.json b/docs/report-examples/pmd-report.sarif.json index e785af258d..005c000c90 100644 --- a/docs/report-examples/pmd-report.sarif.json +++ b/docs/report-examples/pmd-report.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [ { "id": "ApexSharingViolations", @@ -17,7 +17,7 @@ "fullDescription": { "text": "Detect classes declared without explicit sharing mode if DML methods are used. This forces the developer to take access restrictions into account before modifying objects." }, - "helpUri": "https://pmd.github.io/pmd/pmd_rules_apex_security.html#apexsharingviolations", + "helpUri": "https://docs.pmd-code.org/latest/pmd_rules_apex_security.html#apexsharingviolations", "help": { "text": "Detect classes declared without explicit sharing mode if DML methods are used. This forces the developer to take access restrictions into account before modifying objects." }, @@ -37,7 +37,7 @@ "fullDescription": { "text": "This rule validates that: ApexDoc comments are present for classes, methods, and properties that are public or global, excluding overrides and test classes (as well as the contents of test classes)." }, - "helpUri": "https://pmd.github.io/pmd/pmd_rules_apex_documentation.html#apexdoc", + "helpUri": "https://docs.pmd-code.org/latest/pmd_rules_apex_documentation.html#apexdoc", "help": { "text": "This rule validates that: ApexDoc comments are present for classes, methods, and properties that are public or global, excluding overrides and test classes (as well as the contents of test classes)." }, @@ -152,4 +152,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 38a04d6c4e..5a1d7dc52e 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -1,24 +1,42 @@ --- layout: none search: exclude +# https://www.sitemaps.org/protocol.html +# Priority is relative to the website, can be chosen in {0.1, 0.2, ..., 1} +# Default priority is 0.5 +latestPriority: 0.8 --- + + {{site.url}}/index.html + 0.9 + monthly + {{ site.time | date: "%Y-%m-%d" }} + + + {% for post in site.posts %} {% unless post.search == "exclude" %} {{site.url}}{{post.url}} + {{page.latestPriority}} + monthly + {{ site.time | date: "%Y-%m-%d" }} {% endunless %} {% endfor %} - {% for page in site.pages %} - {% unless page.search == "exclude" %} + {% for p in site.pages %} + {% unless p.search == "exclude" %} - {{site.url}}{{ page.url}} + {{site.url}}{{ p.url}} + {{page.latestPriority}} + monthly + {{ site.time | date: "%Y-%m-%d" }} {% endunless %} {% endfor %} - \ No newline at end of file + diff --git a/docs/sitemap_generator.sh b/docs/sitemap_generator.sh deleted file mode 100755 index 03e25a0bcf..0000000000 --- a/docs/sitemap_generator.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -# Sitemap generator for pmd.github.io main landing page. -# Assumes we have the latest version of the site under "latest" -# https://www.sitemaps.org/protocol.html - -WEBSITE_PREFIX="https://pmd.github.io/" -DOC_PREFIX="latest/" -DATE=`date +%Y-%m-%d` -# Priority is relative to the website, can be chosen in {0.1, 0.2, ..., 1} -# Default priority is 0.5 -LATEST_PRIORITY=0.8 - - -# Writes to standard output - -cat << HEADER_END - - - - - ${WEBSITE_PREFIX}index.html - 1 - monthly - $DATE - - - - ${WEBSITE_PREFIX}${DOC_PREFIX}index.html - 0.9 - monthly - $DATE - - - - -HEADER_END - - -for page in ${DOC_PREFIX}pmd_*.html -do - - cat << ENTRY_END - - ${WEBSITE_PREFIX}$page - $LATEST_PRIORITY - monthly - $DATE - - -ENTRY_END - -done - -echo "" - diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java index a9aebddf01..335fb06084 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java @@ -71,7 +71,16 @@ public final class ApexMultifileAnalysis { // FIXME: Syntax & Semantic errors found during Org loading are not currently being reported. These // should be routed to the new SemanticErrorReporter but that is not available for use just yet. } - } catch (Exception e) { + } catch (Exception | ExceptionInInitializerError | NoClassDefFoundError e) { + // Note: Org.newOrg() will try to find the base Apex Types through the current classloader + // in package "com.nawforce.runforce". This requires, that directory listings can be retrievied + // on the URL that the classloader returns from getResource("/com/nawforce/runforce"): + // https://github.com/nawforce/apex-link/blob/7688adcb7a2d7f8aa28d0618ffb2a3aa81151858/apexlink/src/main/scala/com/nawforce/apexlink/types/platform/PlatformTypeDeclaration.scala#L260-L273 + // However, when running as an Eclipse plugin, we have a special bundle classloader, that returns + // URIs in the form "bundleresource://...". For the schema "bundleresource", no FileSystemProvider can be + // found, so we get a java.nio.file.ProviderNotFoundException. Since all this happens during initialization of the class + // com.nawforce.apexlink.types.platform.PlatformTypeDeclaration we get a ExceptionInInitializerError + // and later NoClassDefFoundErrors, because PlatformTypeDeclaration couldn't be loaded. LOG.error("Exception while initializing Apexlink ({})", e.getMessage(), e); LOG.error("PMD will not attempt to initialize Apexlink further, this can cause rules like UnusedMethod to be dysfunctional"); org = null; diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/ExcessivePublicCountRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/ExcessivePublicCountRule.java index 5be16d0783..b833424ced 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/ExcessivePublicCountRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/ExcessivePublicCountRule.java @@ -52,4 +52,8 @@ public class ExcessivePublicCountRule extends AbstractCounterCheckRule { protected boolean isIgnored(ASTMethod node) { return node.isConstructor(); } + + @Override + protected Object[] getViolationParameters(ASTMethod node, int metric, int limit) { + return new Object[]{ node.getImage(), metric, limit }; + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/internal/AbstractCounterCheckRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/internal/AbstractCounterCheckRule.java index 8e4ff77025..3879f3fd07 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/internal/AbstractCounterCheckRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/internal/AbstractCounterCheckRule.java @@ -48,9 +48,8 @@ public abstract class AbstractCounterCheckRule> extends Ab protected abstract int defaultReportLevel(); - - protected Object[] getViolationParameters(T node, int metric) { - return new Object[] {metric}; + protected Object[] getViolationParameters(T node, int metric, int limit) { + return new Object[] {metric, limit}; } @@ -70,8 +69,9 @@ public abstract class AbstractCounterCheckRule> extends Ab if (!isIgnored(t)) { int metric = getMetric(t); - if (metric >= getProperty(reportLevel)) { - addViolation(data, node, getViolationParameters(t, metric)); + int limit = getProperty(reportLevel); + if (metric >= limit) { + addViolation(data, node, getViolationParameters(t, metric, limit)); } } diff --git a/pmd-apex/src/main/resources/category/apex/design.xml b/pmd-apex/src/main/resources/category/apex/design.xml index 6f34471e41..808ceb08b7 100644 --- a/pmd-apex/src/main/resources/category/apex/design.xml +++ b/pmd-apex/src/main/resources/category/apex/design.xml @@ -48,13 +48,13 @@ Avoid having unused methods since they make understanding and maintaining code h This rule finds not only unused private methods, but public methods as well. [ApexLink](https://github.com/nawforce/ApexLink) is used to make this possible and this needs -additional configuration. The environment variable `PMD_APEX_ROOTDIRECTORY` needs to be set prior to executing +additional configuration. The environment variable `PMD_APEX_ROOT_DIRECTORY` needs to be set prior to executing PMD. With this variable the root directory of the Salesforce metadata, where `sfdx-project.json` resides, is specified. ApexLink can then load all the classes in the project and figure out, whether a method is used or not. -For an accurate analysis it is important that the `PMD_APEX_ROOTDIRECTORY` contains a complete set of metadata that +For an accurate analysis it is important that the `PMD_APEX_ROOT_DIRECTORY` contains a complete set of metadata that may be referenced from the Apex source code, such as Custom Objects, Visualforce Pages, Flows and Labels. The -`PMD_APEX_ROOTDIRECTORY` directory must contain a `sfdx-project.json`, but metadata may be either in the +`PMD_APEX_ROOT_DIRECTORY` directory must contain a `sfdx-project.json`, but metadata may be either in the [SFDX Source format](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_source_file_format.htm) or the older MDAPI format. The `packageDirectories` entries in `sfdx-project.json` are used to determine which directories to search for metadata, if a `.forceignore` file is present it will be respected. @@ -281,7 +281,7 @@ public void addPerson(Date birthdate, BodyMeasurements measurements, int ssn) { @@ -340,7 +340,7 @@ public class Foo extends Bar { diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml index 45e7fe4a93..b424122e23 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml @@ -113,4 +113,29 @@ public class SomeClass { } ]]> + + + class with inner classes + 1 + 2 + 1,5 + + The class OuterClass has 2 public methods and attributes (limit: 1) + The class InnerClass has 4 public methods and attributes (limit: 1) + + + diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml index 6562dcb876..b278b7299b 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml @@ -70,6 +70,9 @@ public class Foo { long method 13 1 + + The method 'foo()' has an NCSS line count of 13 (limit: 13) + diff --git a/pmd-cli/pom.xml b/pmd-cli/pom.xml index 5d65824a77..a144afdd06 100644 --- a/pmd-cli/pom.xml +++ b/pmd-cli/pom.xml @@ -78,168 +78,15 @@ ${project.version} - - + net.sourceforge.pmd - pmd-apex - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-cpp - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-cs - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-dart - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-fortran - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-gherkin - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-go - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-groovy - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-html - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-lua - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-java - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-javascript - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-jsp - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-kotlin - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-matlab - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-modelica - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-perl - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-objectivec - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-php - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-plsql - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-python - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-ruby - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-scala_2.13 - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-swift - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-visualforce - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-vm - ${project.version} - runtime - - - net.sourceforge.pmd - pmd-xml + pmd-languages-deps ${project.version} + pom runtime diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java index c034682f07..452d1410fd 100644 --- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java +++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java @@ -75,7 +75,7 @@ public class TreeExportCommand extends AbstractPmdSubcommand { @Option(names = "-P", description = "Key-value pair defining a property for the report format.%n" + "Supported values for each report format:%n${sys:pmd-cli.tree-export.report.properties.help}", completionCandidates = TreeExportReportPropertiesCandidates.class) - private Properties properties; + private Properties properties = new Properties(); @Option(names = "--file", description = "The file to parse and dump.") private Path file; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index 1d94f97c0c..1bf5e9a584 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -558,9 +558,9 @@ public final class PmdAnalysis implements AutoCloseable { && configuration.getAnalysisCache() instanceof NoopAnalysisCache && reporter.isLoggable(Level.WARN)) { final String version = - PMDVersion.isUnknown() || PMDVersion.isSnapshot() ? "latest" : "pmd-" + PMDVersion.VERSION; + PMDVersion.isUnknown() || PMDVersion.isSnapshot() ? "latest" : "pmd-doc-" + PMDVersion.VERSION; reporter.warn("This analysis could be faster, please consider using Incremental Analysis: " - + "https://pmd.github.io/{0}/pmd_userdocs_incremental_analysis.html", version); + + "https://docs.pmd-code.org/{0}/pmd_userdocs_incremental_analysis.html", version); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java similarity index 98% rename from pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java rename to pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java index 23235df0e0..af3d43dbf8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.cpd.internal; +package net.sourceforge.pmd.cpd.impl; import java.io.IOException; import java.io.UncheckedIOException; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/JavaCCTokenizer.java similarity index 98% rename from pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java rename to pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/JavaCCTokenizer.java index 083780a33a..99d44fde32 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/JavaCCTokenizer.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.cpd.internal; +package net.sourceforge.pmd.cpd.impl; import java.io.IOException; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrGeneratedParserBase.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrGeneratedParserBase.java index edf18dbedb..6f2750966a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrGeneratedParserBase.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrGeneratedParserBase.java @@ -31,7 +31,8 @@ import net.sourceforge.pmd.lang.ast.Node; * which stores the XPath names of the generated nodes (and terminals). * *

Additional members can be added to a parser with {@code @parser::members { ... }} - * in the g4 file. + * in the g4 file. That's how the implementations for {@link #createPmdTerminal(ParserRuleContext, Token)} + * and {@link #createPmdError(ParserRuleContext, Token)} can be added. */ public abstract class AntlrGeneratedParserBase> extends Parser { @@ -52,9 +53,9 @@ public abstract class AntlrGeneratedParserBase> extends P // Those two need to return a node that implements eg SwiftNode - public abstract BaseAntlrTerminalNode createPmdTerminal(ParserRuleContext parent, Token t); + protected abstract BaseAntlrTerminalNode createPmdTerminal(ParserRuleContext parent, Token t); - public abstract BaseAntlrErrorNode createPmdError(ParserRuleContext parent, Token t); + protected abstract BaseAntlrErrorNode createPmdError(ParserRuleContext parent, Token t); protected Node asPmdNode(RuleContext ctx) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java index 6b13d723d4..5887805ec4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java @@ -10,7 +10,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.ast.impl.TokenDocument; import net.sourceforge.pmd.lang.document.TextDocument; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractVisitorRule.java similarity index 63% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseRule.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractVisitorRule.java index bc56f0084d..9ef6e4a472 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractVisitorRule.java @@ -2,38 +2,31 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.impl.antlr4; +package net.sourceforge.pmd.lang.rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.AbstractRule; - -/** - * Base implementation of an antlr rule. - */ -public abstract class AntlrBaseRule extends AbstractRule { - - protected AntlrBaseRule() { - // inheritance constructor - } +public abstract class AbstractVisitorRule extends AbstractRule { @Override public void apply(Node target, RuleContext ctx) { AstVisitor visitor = buildVisitor(); assert visitor != null : "Rule should provide a non-null visitor"; - assert target instanceof AntlrNode : "Incorrect node type " + target + " passed to " + this; - ((AntlrNode) target).acceptVisitor(visitor, ctx); + target.acceptVisitor(visitor, ctx); } /** * Returns a rule visitor that can visit nodes for the given rule context. * This visitor should explore the nodes it's interested in and report * violations on the given rule context. + *

+ * Language specific subclasses should redefine the return type to use + * a language specific visitor interface. + *

* * @return A visitor bound to the given rule context */ public abstract AstVisitor buildVisitor(); - } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java index 0f886bbabb..3af680f3f8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java @@ -39,12 +39,10 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { } private static String getPmdPropertiesURL() { + final String BASE_URL = "https://docs.pmd-code.org/"; final String PAGE = "/pmd_userdocs_configuring_rules.html#rule-properties"; - String url = "https://pmd.github.io/pmd-" + PMDVersion.VERSION + PAGE; - if (PMDVersion.isSnapshot() || PMDVersion.isUnknown()) { - url = "https://pmd.github.io/latest" + PAGE; - } - return url; + final String VERSION_PART = PMDVersion.isUnknown() || PMDVersion.isSnapshot() ? "latest" : "pmd-doc-" + PMDVersion.VERSION; + return BASE_URL + VERSION_PART + PAGE; } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/SarifRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/SarifRenderer.java index f4052818d0..39cb54baf6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/SarifRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/SarifRenderer.java @@ -71,6 +71,7 @@ public class SarifRenderer extends AbstractIncrementingRenderer { final SarifLog sarifLog = sarifLogBuilder.build(); final String json = gson.toJson(sarifLog); writer.write(json); + writer.println(); } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/internal/sarif/SarifLogBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/internal/sarif/SarifLogBuilder.java index 1367412578..8994dfcd33 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/internal/sarif/SarifLogBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/internal/sarif/SarifLogBuilder.java @@ -190,7 +190,7 @@ public class SarifLogBuilder { return Component.builder() .name("PMD") .version(PMDVersion.VERSION) - .informationUri("https://pmd.github.io/pmd/") + .informationUri("https://docs.pmd-code.org/latest/") .build(); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index 283f39f6c3..0a0b87b385 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -27,7 +27,7 @@ class CodeClimateRendererTest extends AbstractRendererTest { + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" + "[Remediation Points](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#remediation-points): 50000\\n\\n" + "Description with Unicode Character U+2013: – .\\n\\n" - + "### [PMD properties](https://pmd.github.io/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + + "### [PMD properties](https://docs.pmd-code.org/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + "Name | Value | Description\\n" + "--- | --- | ---\\n" + "violationSuppressRegex | | Suppress violations with messages matching a regular expression\\n" + "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n" @@ -42,7 +42,7 @@ class CodeClimateRendererTest extends AbstractRendererTest { + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" + "[Remediation Points](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#remediation-points): 50000\\n\\n" + "Description with Unicode Character U+2013: – .\\n\\n" - + "### [PMD properties](https://pmd.github.io/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + + "### [PMD properties](https://docs.pmd-code.org/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + "Name | Value | Description\\n" + "--- | --- | ---\\n" + "violationSuppressRegex | | Suppress violations with messages matching a regular expression\\n" + "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n" @@ -64,7 +64,7 @@ class CodeClimateRendererTest extends AbstractRendererTest { + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" + "[Remediation Points](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#remediation-points): 50000\\n\\n" + "Description with Unicode Character U+2013: – .\\n\\n" - + "### [PMD properties](https://pmd.github.io/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + + "### [PMD properties](https://docs.pmd-code.org/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + "Name | Value | Description\\n" + "--- | --- | ---\\n" + "violationSuppressRegex | | Suppress violations with messages matching a regular expression\\n" + "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n" @@ -74,7 +74,7 @@ class CodeClimateRendererTest extends AbstractRendererTest { + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" + "[Remediation Points](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#remediation-points): 50000\\n\\n" + "desc\\n\\n" - + "### [PMD properties](https://pmd.github.io/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + + "### [PMD properties](https://docs.pmd-code.org/latest/pmd_userdocs_configuring_rules.html#rule-properties)\\n\\n" + "Name | Value | Description\\n" + "--- | --- | ---\\n" + "violationSuppressRegex | | Suppress violations with messages matching a regular expression\\n" + "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n" diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/empty.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/empty.sarif.json index 91178676f0..43307fcb5f 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/empty.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/empty.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [] } }, @@ -21,4 +21,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-configerror.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-configerror.sarif.json index 16adc0caf0..7f467c9aab 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-configerror.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-configerror.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [] } }, @@ -30,4 +30,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error-nomessage.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error-nomessage.sarif.json index 820c78a15d..92d233a33a 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error-nomessage.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error-nomessage.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [] } }, diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error.sarif.json index 35155a5aac..3715a32406 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-error.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [] } }, diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple-locations.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple-locations.sarif.json index fc2061b4e0..ca0b13614b 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple-locations.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple-locations.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [ { "id": "Foo", diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple.sarif.json index 06f5a29a7d..b2108169d2 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [ { "id": "Foo", diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected.sarif.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected.sarif.json index 3d82f299ac..a387dc1f75 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected.sarif.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected.sarif.json @@ -7,7 +7,7 @@ "driver": { "name": "PMD", "version": "unknown", - "informationUri": "https://pmd.github.io/pmd/", + "informationUri": "https://docs.pmd-code.org/latest/", "rules": [ { "id": "Foo", diff --git a/pmd-cpp/src/main/java/net/sourceforge/pmd/cpd/CPPTokenizer.java b/pmd-cpp/src/main/java/net/sourceforge/pmd/cpd/CPPTokenizer.java index 0728e9afbf..ccfd511bdb 100644 --- a/pmd-cpp/src/main/java/net/sourceforge/pmd/cpd/CPPTokenizer.java +++ b/pmd-cpp/src/main/java/net/sourceforge/pmd/cpd/CPPTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.cpd; import java.util.Properties; import java.util.regex.Pattern; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.cpd.token.JavaCCTokenFilter; import net.sourceforge.pmd.cpd.token.TokenFilter; import net.sourceforge.pmd.lang.TokenManager; diff --git a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java index 64822f1a38..712fae22c3 100644 --- a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java +++ b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java @@ -9,7 +9,7 @@ import java.util.Properties; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrToken; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTokenManager; diff --git a/pmd-dart/src/main/java/net/sourceforge/pmd/cpd/DartTokenizer.java b/pmd-dart/src/main/java/net/sourceforge/pmd/cpd/DartTokenizer.java index 6c847754a2..048a0a3a6f 100644 --- a/pmd-dart/src/main/java/net/sourceforge/pmd/cpd/DartTokenizer.java +++ b/pmd-dart/src/main/java/net/sourceforge/pmd/cpd/DartTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrToken; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTokenManager; diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 554b2cb809..43bc6c06d8 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -126,7 +126,7 @@ net.sourceforge.pmd - pmd-apex + pmd-core ${project.version} @@ -142,136 +142,11 @@ sh completion - - net.sourceforge.pmd - pmd-core - ${project.version} - net.sourceforge.pmd pmd-ant ${project.version} - - net.sourceforge.pmd - pmd-cpp - ${project.version} - - - net.sourceforge.pmd - pmd-cs - ${project.version} - - - net.sourceforge.pmd - pmd-dart - ${project.version} - - - net.sourceforge.pmd - pmd-fortran - ${project.version} - - - net.sourceforge.pmd - pmd-gherkin - ${project.version} - - - net.sourceforge.pmd - pmd-go - ${project.version} - - - net.sourceforge.pmd - pmd-groovy - ${project.version} - - - net.sourceforge.pmd - pmd-html - ${project.version} - - - net.sourceforge.pmd - pmd-lua - ${project.version} - - - net.sourceforge.pmd - pmd-java - ${project.version} - - - net.sourceforge.pmd - pmd-javascript - ${project.version} - - - net.sourceforge.pmd - pmd-jsp - ${project.version} - - - net.sourceforge.pmd - pmd-kotlin - ${project.version} - - - net.sourceforge.pmd - pmd-matlab - ${project.version} - - - net.sourceforge.pmd - pmd-modelica - ${project.version} - - - net.sourceforge.pmd - pmd-perl - ${project.version} - - - net.sourceforge.pmd - pmd-objectivec - ${project.version} - - - net.sourceforge.pmd - pmd-php - ${project.version} - - - net.sourceforge.pmd - pmd-plsql - ${project.version} - - - net.sourceforge.pmd - pmd-python - ${project.version} - - - net.sourceforge.pmd - pmd-ruby - ${project.version} - - - net.sourceforge.pmd - pmd-scala_2.13 - ${project.version} - - - net.sourceforge.pmd - pmd-swift - ${project.version} - - - net.sourceforge.pmd - pmd-tsql - ${project.version} - net.sourceforge.pmd pmd-ui @@ -279,20 +154,11 @@ net.sourceforge.pmd - pmd-visualforce + pmd-languages-deps ${project.version} + pom + runtime - - net.sourceforge.pmd - pmd-vm - ${project.version} - - - net.sourceforge.pmd - pmd-xml - ${project.version} - - org.slf4j diff --git a/pmd-dist/src/main/resources/assemblies/pmd-bin.xml b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml index 2215aa3265..8d67eb9662 100644 --- a/pmd-dist/src/main/resources/assemblies/pmd-bin.xml +++ b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml @@ -53,6 +53,19 @@ + + + target/bom.xml + sbom + pmd-${project.version}-cyclonedx.xml + + + target/bom.json + sbom + pmd-${project.version}-cyclonedx.json + + + @@ -71,7 +84,9 @@ runtime + net.sourceforge.pmd:pmd-apex-jorje:pom net.sourceforge.pmd:pmd-cli:sh:completion:* + net.sourceforge.pmd:pmd-languages-deps:pom lib 0755 diff --git a/pmd-dist/src/main/resources/scripts/pmd b/pmd-dist/src/main/resources/scripts/pmd index 6407edb1e0..926238f9da 100755 --- a/pmd-dist/src/main/resources/scripts/pmd +++ b/pmd-dist/src/main/resources/scripts/pmd @@ -95,6 +95,13 @@ function script_exit() { exit 1 } +function check_java() { + java -version >/dev/null 2>&1 + if [ $? -ne 0 ]; then + script_exit "No java executable found in PATH" + fi +} + determine_java_version() { local full_ver=$(java -version 2>&1) # java_ver is eg "80" for java 1.8, "90" for java 9.0, "100" for java 10.0.x @@ -183,6 +190,8 @@ readonly APPNAME="${1}" is_cygwin +check_java + set_lib_dir check_lib_dir set_conf_dir diff --git a/pmd-dist/src/main/resources/scripts/pmd.bat b/pmd-dist/src/main/resources/scripts/pmd.bat index f7d3fe9474..c4dc049770 100644 --- a/pmd-dist/src/main/resources/scripts/pmd.bat +++ b/pmd-dist/src/main/resources/scripts/pmd.bat @@ -1,19 +1,26 @@ @echo off +rem make all variables local to not add new global environment variables to the current cmd session +setlocal set TOPDIR="%~dp0.." set OPTS= set COMMAND=%1 set MAIN_CLASS=net.sourceforge.pmd.cli.PmdCli +rem check whether java is available at all +java -version > nul 2>&1 || ( + echo No java executable found in PATH + exit /b 1 +) -:: sets the jver variable to the java version, eg 90 for 9.0.1+x or 80 for 1.8.0_171-b11 or 110 for 11.0.6.1 -:: sets the jvendor variable to either java (oracle) or openjdk +rem sets the jver variable to the java version, eg 90 for 9.0.1+x or 80 for 1.8.0_171-b11 or 110 for 11.0.6.1 +rem sets the jvendor variable to either java (oracle) or openjdk for /f tokens^=1^,3^,4^,5^ delims^=.-_+^"^ %%j in ('java -version 2^>^&1 ^| findstr /c:"version"') do ( set jvendor=%%j if %%l EQU ea ( set /A "jver=%%k0" ) else ( if %%k EQU 1 ( - :: for java version 1.7.x, 1.8.x, ignore the first 1. + rem for java version 1.7.x, 1.8.x, ignore the first 1. set /A "jver=%%l%%m" ) else ( set /A "jver=%%k%%l" @@ -22,11 +29,11 @@ for /f tokens^=1^,3^,4^,5^ delims^=.-_+^"^ %%j in ('java -version 2^>^&1 ^| fin ) Set "jreopts=" -:: oracle java 9 and 10 has javafx included as a module +rem oracle java 9 and 10 has javafx included as a module if /I %jvendor% == java ( if %jver% GEQ 90 ( if %jver% LSS 110 ( - :: enable reflection + rem enable reflection SETLOCAL EnableDelayedExpansion rem java9 and java10 from oracle contain javafx as a module rem open internal module of javafx to reflection (for our TreeViewWrapper) @@ -38,7 +45,6 @@ if /I %jvendor% == java ( set "jreopts=!jreopts! --add-opens javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED" rem Warn of remaining illegal accesses set "jreopts=!jreopts! --illegal-access=warn" - ) ) ) @@ -53,25 +59,21 @@ if [%COMMAND%] == [designer] ( if %_needjfxlib% EQU 1 ( if %jver% LSS 100 ( echo For openjfx at least java 10 is required. - pause - exit + exit /b 1 ) - if [%JAVAFX_HOME%] EQU [] ( + if not defined JAVAFX_HOME ( echo The environment variable JAVAFX_HOME is missing. - pause - exit + exit /b 1 ) - :: The wildcard will include only jar files, but we need to access also - :: property files such as javafx.properties that lay bare in the dir + rem The wildcard will include only jar files, but we need to access also + rem property files such as javafx.properties that lay bare in the dir set pmd_classpath=%TOPDIR%\conf;%TOPDIR%\lib\*;%JAVAFX_HOME%\lib\*;%JAVAFX_HOME%\lib\ ) else ( set pmd_classpath=%TOPDIR%\conf;%TOPDIR%\lib\* ) -if [%CLASSPATH%] NEQ [] ( - set classpath=%CLASSPATH%;%pmd_classpath% -) else ( - set classpath=%pmd_classpath% +if defined CLASSPATH ( + set pmd_classpath=%CLASSPATH%;%pmd_classpath% ) java %PMD_JAVA_OPTS% %jreopts% -classpath %pmd_classpath% %OPTS% %MAIN_CLASS% %* diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java index c1331cbd67..25f9a8503d 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java @@ -31,9 +31,10 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest { private static final List SUPPORTED_LANGUAGES_CPD = listOf( "apex", "cpp", "cs", "dart", "ecmascript", "fortran", "gherkin", "go", "groovy", "html", "java", "jsp", + "julia", "kotlin", "lua", "matlab", "modelica", "objectivec", "perl", "php", "plsql", "python", "ruby", "scala", "swift", "tsql", - "vf", "xml" + "typescript", "vf", "xml" ); private static final List SUPPORTED_LANGUAGES_PMD = listOf( @@ -87,6 +88,8 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest { result.add(basedir + "shell/pmd-completion.sh"); result.add(basedir + "lib/pmd-core-" + PMDVersion.VERSION + ".jar"); result.add(basedir + "lib/pmd-java-" + PMDVersion.VERSION + ".jar"); + result.add(basedir + "sbom/pmd-" + PMDVersion.VERSION + "-cyclonedx.xml"); + result.add(basedir + "sbom/pmd-" + PMDVersion.VERSION + "-cyclonedx.json"); return result; } @@ -218,4 +221,13 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest { result = CpdExecutor.runCpd(tempDir, "--minimum-tokens", "1000", "--format", "text", "--dir", srcDir); result.assertExitCode(0); } + + @Test + void runAstDump() throws Exception { + File jumbledIncrementerSrc = new File(srcDir, "JumbledIncrementer.java"); + List args = listOf("--format", "xml", "--language", "java", "--file", jumbledIncrementerSrc.toString()); + ExecutionResult result = PMDExecutor.runCommand(tempDir, "ast-dump", args); + result.assertExitCode(0); + } + } diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/CpdExecutor.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/CpdExecutor.java index 0948d9ff28..4875c560d5 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/CpdExecutor.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/CpdExecutor.java @@ -4,14 +4,8 @@ package net.sourceforge.pmd.it; -import static net.sourceforge.pmd.util.CollectionUtil.listOf; - import java.nio.file.Path; -import java.util.List; - -import org.apache.commons.lang3.SystemUtils; - -import net.sourceforge.pmd.PMDVersion; +import java.util.Arrays; /** * Executes CPD from command line. Deals with the differences, when CPD is run on Windows or on Linux. @@ -19,8 +13,6 @@ import net.sourceforge.pmd.PMDVersion; * @author Andreas Dangel */ public class CpdExecutor { - private static final String PMD_BIN_PREFIX = "pmd-bin-"; - private CpdExecutor() { // this is a helper class only } @@ -33,15 +25,6 @@ public class CpdExecutor { * @throws Exception if the execution fails for any reason (executable not found, ...) */ public static ExecutionResult runCpd(Path tempDir, String... arguments) throws Exception { - String cmd; - List args; - if (SystemUtils.IS_OS_WINDOWS) { - cmd = "/bin/pmd.bat"; - } else { - cmd = "/bin/pmd"; - } - args = listOf("cpd", arguments); - cmd = tempDir.resolve(PMD_BIN_PREFIX + PMDVersion.VERSION + cmd).toAbsolutePath().toString(); - return PMDExecutor.runCommand(cmd, args, null); + return PMDExecutor.runCommand(tempDir, "cpd", Arrays.asList(arguments)); } } diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java index ccc151ddc3..22357c3eba 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java @@ -36,31 +36,21 @@ public class PMDExecutor { // this is a helper class only } - private static ExecutionResult runPMDUnix(Path tempDir, Path reportFile, String... arguments) throws Exception { - String cmd = tempDir.resolve(AbstractBinaryDistributionTest.PMD_BIN_PREFIX + PMDVersion.VERSION + "/bin/pmd").toAbsolutePath().toString(); - List args = new ArrayList<>(); - args.add("check"); - args.addAll(Arrays.asList(arguments)); - return runCommand(cmd, args, reportFile); + static ExecutionResult runCommand(Path tempDir, String cmd, List arguments) throws Exception { + return runCommand(tempDir, cmd, arguments, null); } - private static ExecutionResult runPMDWindows(Path tempDir, Path reportFile, String... arguments) throws Exception { - String cmd = tempDir.resolve(AbstractBinaryDistributionTest.PMD_BIN_PREFIX + PMDVersion.VERSION + "/bin/pmd.bat").toAbsolutePath().toString(); - List args = new ArrayList<>(); - args.add("check"); - args.addAll(Arrays.asList(arguments)); - return runCommand(cmd, args, reportFile); - } - - static ExecutionResult runCommand(String cmd, List arguments, Path reportFile) throws Exception { - ProcessBuilder pb = new ProcessBuilder(cmd); - - if (reportFile != null) { - arguments.add(REPORTFILE_FLAG); - arguments.add(reportFile.toString()); + static ExecutionResult runCommand(Path tempDir, String cmd, List arguments, Path reportFile) throws Exception { + final String pmdScript; + if (SystemUtils.IS_OS_WINDOWS) { + pmdScript = tempDir.resolve(AbstractBinaryDistributionTest.PMD_BIN_PREFIX + PMDVersion.VERSION + "/bin/pmd.bat").toAbsolutePath().toString(); + } else { + pmdScript = tempDir.resolve(AbstractBinaryDistributionTest.PMD_BIN_PREFIX + PMDVersion.VERSION + "/bin/pmd").toAbsolutePath().toString(); } - + ProcessBuilder pb = new ProcessBuilder(pmdScript); + pb.command().add(cmd); pb.command().addAll(arguments); + pb.redirectErrorStream(false); // Ensure no ANSI output so tests can properly look at it @@ -137,10 +127,13 @@ public class PMDExecutor { * @throws Exception if the execution fails for any reason (executable not found, ...) */ public static ExecutionResult runPMD(Path reportFile, Path tempDir, String... arguments) throws Exception { - if (SystemUtils.IS_OS_WINDOWS) { - return runPMDWindows(tempDir, reportFile, arguments); - } else { - return runPMDUnix(tempDir, reportFile, arguments); + List args = new ArrayList<>(); + if (reportFile != null) { + args.add(REPORTFILE_FLAG); + args.add(reportFile.toString()); } + args.addAll(Arrays.asList(arguments)); + + return runCommand(tempDir, "check", args, reportFile); } } diff --git a/pmd-dist/src/test/resources/scripts/designertest.bat b/pmd-dist/src/test/resources/scripts/pmdtest.bat similarity index 73% rename from pmd-dist/src/test/resources/scripts/designertest.bat rename to pmd-dist/src/test/resources/scripts/pmdtest.bat index d43a5ff146..40f189ce7a 100644 --- a/pmd-dist/src/test/resources/scripts/designertest.bat +++ b/pmd-dist/src/test/resources/scripts/pmdtest.bat @@ -1,27 +1,27 @@ @echo off -:: BSD-style license; for more info see http://pmd.sourceforge.net/license.html +rem BSD-style license; for more info see http://pmd.sourceforge.net/license.html -:: -:: Simple manual test script -:: - code is copied from designer.bat to be tested here (so please check, it might be out of sync) -:: - mostly the function "determine_java_version" is tested here -:: - just run it with "designertest.bat" and look at the output -:: - test cases are at the end of this script -:: +rem +rem Simple manual test script +rem - code is copied from pmd.bat to be tested here (so please check, it might be out of sync) +rem - mostly the function "determine_java_version" is tested here +rem - just run it with "pmd.bat" and look at the output +rem - test cases are at the end of this script +rem GOTO :main :determine_java_version -:: sets the jver variable to the java version, eg 90 for 9.0.1+x or 80 for 1.8.0_171-b11 or 110 for 11.0.6.1 -:: sets the jvendor variable to either java (oracle) or openjdk +rem sets the jver variable to the java version, eg 90 for 9.0.1+x or 80 for 1.8.0_171-b11 or 110 for 11.0.6.1 +rem sets the jvendor variable to either java (oracle) or openjdk for /f tokens^=1^,3^,4^,5^ delims^=.-_+^"^ %%j in (%full_version%) do ( set jvendor=%%j if %%l EQU ea ( set /A "jver=%%k0" ) else ( if %%k EQU 1 ( - :: for java version 1.7.x, 1.8.x, ignore the first 1. + rem for java version 1.7.x, 1.8.x, ignore the first 1. set /A "jver=%%l%%m" ) else ( set /A "jver=%%k%%l" @@ -67,6 +67,24 @@ if [%detection%] == [] ( EXIT /B +:check_for_java_command +set cmd=%1 +echo cmd=%1 +%cmd% -version > nul 2>&1 || ( + echo No java executable not found in PATH + EXIT /B 1 +) +EXIT /B 0 + +:check_classpath_extension +setlocal +set cp=%1 +echo testing cp=%1 +if defined cp ( + echo classpath is not empty +) +endlocal +EXIT /B :run_test set full_version=%1 @@ -86,6 +104,16 @@ EXIT /B :main +CALL :check_for_java_command javanotfound +echo errorlevel: %ERRORLEVEL% + +CALL :check_classpath_extension +CALL :check_classpath_extension a\b.jar +CALL :check_classpath_extension "a\b.jar;c\d.jar" +CALL :check_classpath_extension "a\b.jar" +CALL :check_classpath_extension "a"\b.jar +CALL :check_classpath_extension "a"\b.jar;"c"\d.jar + CALL :run_test "java version ""1.7.0_80""" java 70 "detected java 7" CALL :run_test "openjdk version ""1.7.0_352""" openjdk 70 "detected java 7" CALL :run_test "java version ""1.8.0_271""" java 80 "detected java 8" diff --git a/pmd-gherkin/src/main/java/net/sourceforge/pmd/lang/gherkin/cpd/GherkinTokenizer.java b/pmd-gherkin/src/main/java/net/sourceforge/pmd/lang/gherkin/cpd/GherkinTokenizer.java index fd9d03a244..1bbe22cf51 100644 --- a/pmd-gherkin/src/main/java/net/sourceforge/pmd/lang/gherkin/cpd/GherkinTokenizer.java +++ b/pmd-gherkin/src/main/java/net/sourceforge/pmd/lang/gherkin/cpd/GherkinTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.lang.gherkin.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.lang.gherkin.ast.GherkinLexer; /** diff --git a/pmd-go/src/main/java/net/sourceforge/pmd/cpd/GoTokenizer.java b/pmd-go/src/main/java/net/sourceforge/pmd/cpd/GoTokenizer.java index 98d2653f85..d46d4827ed 100644 --- a/pmd-go/src/main/java/net/sourceforge/pmd/cpd/GoTokenizer.java +++ b/pmd-go/src/main/java/net/sourceforge/pmd/cpd/GoTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.lang.go.ast.GolangLexer; public class GoTokenizer extends AntlrTokenizer { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java b/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java index 525d1731b2..a1ac11bfc8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java @@ -9,7 +9,7 @@ import java.util.Deque; import java.util.LinkedList; import java.util.Properties; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.cpd.token.JavaCCTokenFilter; import net.sourceforge.pmd.cpd.token.TokenFilter; import net.sourceforge.pmd.lang.TokenManager; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java index f3e9e4a253..6eafbbb05a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java @@ -4,8 +4,8 @@ package net.sourceforge.pmd.lang.java.rule.codestyle; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; import org.checkerframework.checker.nullness.qual.NonNull; @@ -35,7 +35,9 @@ public class UnnecessaryConstructorRule extends AbstractIgnoredAnnotationRule { @Override protected Collection defaultSuppressionAnnotations() { - return Collections.singletonList("javax.inject.Inject"); + return Arrays.asList("javax.inject.Inject", + "com.google.inject.Inject", + "org.springframework.beans.factory.annotation.Autowired"); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java index ecd65ef8b6..759032dc0f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design; import static net.sourceforge.pmd.util.CollectionUtil.setOf; -import java.util.List; import java.util.Set; import net.sourceforge.pmd.lang.ast.NodeStream; @@ -25,27 +24,25 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule; import net.sourceforge.pmd.lang.java.rule.internal.DataflowPass; import net.sourceforge.pmd.lang.java.rule.internal.DataflowPass.AssignmentEntry; import net.sourceforge.pmd.lang.java.rule.internal.DataflowPass.DataflowResult; -import net.sourceforge.pmd.lang.java.rule.internal.JavaPropertyUtil; -import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.util.CollectionUtil; public class ImmutableFieldRule extends AbstractJavaRulechainRule { - private static final PropertyDescriptor> IGNORED_ANNOTS = - JavaPropertyUtil.ignoredAnnotationsDescriptor(); - private static final Set INVALIDATING_CLASS_ANNOT = setOf( "lombok.Builder", "lombok.Data", - "lombok.Getter", "lombok.Setter", "lombok.Value" ); + private static final Set INVALIDATING_FIELD_ANNOT = + setOf( + "lombok.Setter" + ); + public ImmutableFieldRule() { super(ASTFieldDeclaration.class); - definePropertyDescriptor(IGNORED_ANNOTS); } @@ -55,7 +52,7 @@ public class ImmutableFieldRule extends AbstractJavaRulechainRule { if (field.getEffectiveVisibility().isAtMost(Visibility.V_PRIVATE) && !field.getModifiers().hasAny(JModifier.VOLATILE, JModifier.STATIC, JModifier.FINAL) && !JavaAstUtils.hasAnyAnnotation(enclosingType, INVALIDATING_CLASS_ANNOT) - && !JavaAstUtils.hasAnyAnnotation(field, getProperty(IGNORED_ANNOTS))) { + && !JavaAstUtils.hasAnyAnnotation(field, INVALIDATING_FIELD_ANNOT)) { DataflowResult dataflow = DataflowPass.getDataflowResult(field.getRoot()); @@ -82,9 +79,9 @@ public class ImmutableFieldRule extends AbstractJavaRulechainRule { if (!hasWrite && !isBlank) { //todo this case may also handle static fields easily. - addViolation(data, varId, varId.getName()); + asCtx(data).addViolation(varId, varId.getName()); } else if (hasWrite && defaultValueDoesNotReachEndOfCtor(dataflow, varId)) { - addViolation(data, varId, varId.getName()); + asCtx(data).addViolation(varId, varId.getName()); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java index c5c070249a..66741473a1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java @@ -36,6 +36,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement; import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; +import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant; import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTFieldAccess; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; @@ -954,6 +955,7 @@ public final class DataflowPass { @Override public SpanInfo visitTypeDecl(ASTAnyTypeDeclaration node, SpanInfo data) { + // process initializers and ctors first processInitializers(node.getDeclarations(), data, node.getSymbol()); for (ASTBodyDeclaration decl : node.getDeclarations()) { @@ -989,12 +991,14 @@ public final class DataflowPass { for (ASTBodyDeclaration declaration : declarations) { final boolean isStatic; - if (declaration instanceof ASTFieldDeclaration) { + if (declaration instanceof ASTEnumConstant) { + isStatic = true; + } else if (declaration instanceof ASTFieldDeclaration) { isStatic = ((ASTFieldDeclaration) declaration).isStatic(); } else if (declaration instanceof ASTInitializer) { isStatic = ((ASTInitializer) declaration).isStatic(); } else if (declaration instanceof ASTConstructorDeclaration - || declaration instanceof ASTCompactConstructorDeclaration) { + || declaration instanceof ASTCompactConstructorDeclaration) { ctors.add(declaration); continue; } else { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/TestFrameworksUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/TestFrameworksUtil.java index d8ccc72e28..f3a35f4361 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/TestFrameworksUtil.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/TestFrameworksUtil.java @@ -46,6 +46,23 @@ public final class TestFrameworksUtil { "junit.framework.Assert", "junit.framework.TestCase"); + private static final Set TEST_CONFIGURATION_ANNOTATIONS = + setOf("org.junit.Before", + "org.junit.BeforeClass", + "org.junit.After", + "org.junit.AfterClass", + "org.testng.annotations.AfterClass", + "org.testng.annotations.AfterGroups", + "org.testng.annotations.AfterMethod", + "org.testng.annotations.AfterSuite", + "org.testng.annotations.AfterTest", + "org.testng.annotations.BeforeClass", + "org.testng.annotations.BeforeGroups", + "org.testng.annotations.BeforeMethod", + "org.testng.annotations.BeforeSuite", + "org.testng.annotations.BeforeTest" + ); + private TestFrameworksUtil() { // utility class } @@ -75,10 +92,7 @@ public final class TestFrameworksUtil { * Returns true if this is a Before/setUp method or After/tearDown. */ public static boolean isTestConfigurationMethod(ASTMethodDeclaration method) { - return method.isAnnotationPresent("org.junit.Before") - || method.isAnnotationPresent("org.junit.BeforeClass") - || method.isAnnotationPresent("org.junit.After") - || method.isAnnotationPresent("org.junit.AfterClass") + return TEST_CONFIGURATION_ANNOTATIONS.stream().anyMatch(method::isAnnotationPresent) || isJUnit3Class(method.getEnclosingType()) && ("setUp".equals(method.getName()) || "tearDown".equals(method.getName())); diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index c888a021ff..ac2a1558e0 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -2349,7 +2349,7 @@ See the property `annotations`.
3 - + + + #1563 FP with ForLoopCanBeForeach + 0 + mList) { + for (int i = 0; i < mList.size(); i++) { + mList.get(i).setIndex(i); + } + } + interface Foo { + void setIndex(int i); + } + } + ]]> + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml index 649bebe0c0..3e7662a85f 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml @@ -653,7 +653,7 @@ public class FooTest extends TestCase { - AssertJ and JUnit5 + AssertJ and JUnit5 #3339 0 - JUnit5 + JUnit5 #3339 0 + + + [java] JUnitTestsShouldIncludeAssert: False positives for assert methods named "check" and "verify" #1455 + 0 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseCollectionIsEmpty.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseCollectionIsEmpty.xml index fd77707ff7..c3c449ea2f 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseCollectionIsEmpty.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseCollectionIsEmpty.xml @@ -543,4 +543,29 @@ public record Record(Set stringSet) { } } ]]> + + + [java] UseCollectionIsEmpty should infer local variable type from method invocation #3858 + 1 + 8 + 0) { // point 1: false negative + System.out.println("!list.isEmpty() is better!"); + // ... + } + } + + private List getList() { // mock + return new ArrayList<>(); + } +} +]]> + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IdenticalCatchBranches.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IdenticalCatchBranches.xml index 44f66afec7..82a3c4d246 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IdenticalCatchBranches.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IdenticalCatchBranches.xml @@ -126,4 +126,23 @@ class Foo { } ]]> + + [java] IdenticalCatchBranches false positive #1480 + 0 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryConstructor.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryConstructor.xml index 1754836837..a656bfd98c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryConstructor.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryConstructor.xml @@ -209,6 +209,26 @@ public class Foo { @Deprecated public Foo() { } +} + ]]> + + + + Issue #4487: [java]A false-positive about UnnecessaryConstructor and @Inject + 0 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml index 3c6dd6a849..069561592a 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml @@ -415,15 +415,31 @@ public class CombinersTest { - #410 [java] ImmutableField: False positive with lombok + #410 [java] ImmutableField: False positive with lombok on class + 0 + + + + + #4254 [java] ImmutableField: False positive with lombok on field 0 - - #1056 [java] Property ignoredAnnotations does not work for SingularField and ImmutableField - java.lang.Deprecated - 0 - - - #1792 Immutable field should still be detected with @Delegate 1 @@ -809,6 +808,25 @@ public class MyTable implements Serializable return m_id; } } +]]> + + + + #4490 False negative with Lombok @Getter only + 1 + 6 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SignatureDeclareThrowsException.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SignatureDeclareThrowsException.xml index fab1305cfa..cfe692eaa2 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SignatureDeclareThrowsException.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SignatureDeclareThrowsException.xml @@ -256,6 +256,18 @@ public final class Namespace { public class WeirdException extends @Weird Exception { } +} + ]]> + + + + #4477:[java] SignatureDeclareThrowsException: false-positive with TestNG annotations + 0 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml index 15895fdede..16afc0e794 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml @@ -400,4 +400,25 @@ record MyRecord(boolean b) { } ]]> + + + #4505 NPE with Switch in enum constant body + 1 + 7 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml index c5d70fcb8f..3f5498f250 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml @@ -576,4 +576,21 @@ public final class TestPrivateClassWithFactory implements GenericTest { } ]]> + + + #4493:[java]false-positive about MissingStaticMethodInNonInstantiatableClass and @Inject + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml index d535631744..61eec5bccf 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml @@ -194,4 +194,20 @@ public class Foo {{ }} ]]> + + + [java] UseEqualsToCompareStrings should consider return type #3843 + 1 + 6 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/NonThreadSafeSingleton.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/NonThreadSafeSingleton.xml index 23a897b482..9a177239f3 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/NonThreadSafeSingleton.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/NonThreadSafeSingleton.xml @@ -176,7 +176,7 @@ class A extends B { - False positive with correct double checked pattern + False positive with correct double-checked pattern #4483 0 + + + [java] StringInstantiation: false negative when using method result #3848 + 1 + 6 + + diff --git a/pmd-javascript/pmd-javascript-checkstyle-suppressions.xml b/pmd-javascript/pmd-javascript-checkstyle-suppressions.xml new file mode 100644 index 0000000000..24e5d8c32f --- /dev/null +++ b/pmd-javascript/pmd-javascript-checkstyle-suppressions.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index bca334d6fa..e5cdefc231 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -23,6 +23,10 @@ + + org.antlr + antlr4-maven-plugin + maven-resources-plugin @@ -74,6 +78,14 @@ + + + org.apache.maven.plugins + maven-checkstyle-plugin + + pmd-javascript-checkstyle-suppressions.xml + + @@ -81,6 +93,10 @@ net.sourceforge.pmd pmd-core + + org.antlr + antlr4-runtime + org.mozilla rhino diff --git a/pmd-javascript/src/main/antlr4/net/sourceforge/pmd/lang/typescript/ast/TypeScriptLexer.g4 b/pmd-javascript/src/main/antlr4/net/sourceforge/pmd/lang/typescript/ast/TypeScriptLexer.g4 new file mode 100644 index 0000000000..3d71fe675a --- /dev/null +++ b/pmd-javascript/src/main/antlr4/net/sourceforge/pmd/lang/typescript/ast/TypeScriptLexer.g4 @@ -0,0 +1,308 @@ +lexer grammar TypeScriptLexer; + +channels { ERROR } + +options { + superClass=TypeScriptLexerBase; +} + + +MultiLineComment: '/*' .*? '*/' -> channel(HIDDEN); +SingleLineComment: '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN); +RegularExpressionLiteral: '/' RegularExpressionFirstChar RegularExpressionChar* {this.IsRegexPossible()}? '/' IdentifierPart*; + +OpenBracket: '['; +CloseBracket: ']'; +OpenParen: '('; +CloseParen: ')'; +OpenBrace: '{' {this.ProcessOpenBrace();}; +TemplateCloseBrace: {this.IsInTemplateString()}? '}' -> popMode; +CloseBrace: '}' {this.ProcessCloseBrace();}; +SemiColon: ';'; +Comma: ','; +Assign: '='; +QuestionMark: '?'; +Colon: ':'; +Ellipsis: '...'; +Dot: '.'; +PlusPlus: '++'; +MinusMinus: '--'; +Plus: '+'; +Minus: '-'; +BitNot: '~'; +Not: '!'; +Multiply: '*'; +Divide: '/'; +Modulus: '%'; +RightShiftArithmetic: '>>'; +LeftShiftArithmetic: '<<'; +RightShiftLogical: '>>>'; +LessThan: '<'; +MoreThan: '>'; +LessThanEquals: '<='; +GreaterThanEquals: '>='; +Equals_: '=='; +NotEquals: '!='; +IdentityEquals: '==='; +IdentityNotEquals: '!=='; +BitAnd: '&'; +BitXOr: '^'; +BitOr: '|'; +And: '&&'; +Or: '||'; +MultiplyAssign: '*='; +DivideAssign: '/='; +ModulusAssign: '%='; +PlusAssign: '+='; +MinusAssign: '-='; +LeftShiftArithmeticAssign: '<<='; +RightShiftArithmeticAssign: '>>='; +RightShiftLogicalAssign: '>>>='; +BitAndAssign: '&='; +BitXorAssign: '^='; +BitOrAssign: '|='; +ARROW: '=>'; + +/// Null Literals + +NullLiteral: 'null'; + +/// Boolean Literals + +BooleanLiteral: 'true' + | 'false'; + +/// Numeric Literals + +DecimalLiteral: DecimalIntegerLiteral '.' [0-9]* ExponentPart? + | '.' [0-9]+ ExponentPart? + | DecimalIntegerLiteral ExponentPart? + ; + +/// Numeric Literals + +HexIntegerLiteral: '0' [xX] HexDigit+; +OctalIntegerLiteral: '0' [0-7]+ {!this.IsStrictMode()}?; +OctalIntegerLiteral2: '0' [oO] [0-7]+; +BinaryIntegerLiteral: '0' [bB] [01]+; + +/// Keywords + +Break: 'break'; +Do: 'do'; +Instanceof: 'instanceof'; +Typeof: 'typeof'; +Case: 'case'; +Else: 'else'; +New: 'new'; +Var: 'var'; +Catch: 'catch'; +Finally: 'finally'; +Return: 'return'; +Void: 'void'; +Continue: 'continue'; +For: 'for'; +Switch: 'switch'; +While: 'while'; +Debugger: 'debugger'; +Function_: 'function'; +This: 'this'; +With: 'with'; +Default: 'default'; +If: 'if'; +Throw: 'throw'; +Delete: 'delete'; +In: 'in'; +Try: 'try'; +As: 'as'; +From: 'from'; +ReadOnly: 'readonly'; +Async: 'async'; + +/// Future Reserved Words + +Class: 'class'; +Enum: 'enum'; +Extends: 'extends'; +Super: 'super'; +Const: 'const'; +Export: 'export'; +Import: 'import'; + +/// The following tokens are also considered to be FutureReservedWords +/// when parsing strict mode + +Implements: 'implements' ; +Let: 'let' ; +Private: 'private' ; +Public: 'public' ; +Interface: 'interface' ; +Package: 'package' ; +Protected: 'protected' ; +Static: 'static' ; +Yield: 'yield' ; + +//keywords: + +Any : 'any'; +Number: 'number'; +Boolean: 'boolean'; +String: 'string'; +Symbol: 'symbol'; + + +TypeAlias : 'type'; + +Get: 'get'; +Set: 'set'; + +Constructor: 'constructor'; +Namespace: 'namespace'; +Require: 'require'; +Module: 'module'; +Declare: 'declare'; + +Abstract: 'abstract'; + +Is: 'is'; + +// +// Ext.2 Additions to 1.8: Decorators +// +At: '@'; + +/// Identifier Names and Identifiers + +Identifier: IdentifierStart IdentifierPart*; + +/// String Literals +StringLiteral: ('"' DoubleStringCharacter* '"' + | '\'' SingleStringCharacter* '\'') {this.ProcessStringLiteral();} + ; + +BackTick: '`' {this.IncreaseTemplateDepth();} -> pushMode(TEMPLATE); + +WhiteSpaces: [\t\u000B\u000C\u0020\u00A0]+ -> channel(HIDDEN); + +LineTerminator: [\r\n\u2028\u2029] -> channel(HIDDEN); + +/// Comments + + +HtmlComment: '' -> channel(HIDDEN); +CDataComment: '' -> channel(HIDDEN); +UnexpectedCharacter: . -> channel(ERROR); + +mode TEMPLATE; + +TemplateStringEscapeAtom: '\\' .; +BackTickInside: '`' {this.DecreaseTemplateDepth();} -> type(BackTick), popMode; +TemplateStringStartExpression: '${' {this.StartTemplateString();} -> pushMode(DEFAULT_MODE); +TemplateStringAtom: ~[`\\]; + +// Fragment rules + +fragment DoubleStringCharacter + : ~["\\\r\n] + | '\\' EscapeSequence + | LineContinuation + ; + +fragment SingleStringCharacter + : ~['\\\r\n] + | '\\' EscapeSequence + | LineContinuation + ; + +fragment EscapeSequence + : CharacterEscapeSequence + | '0' // no digit ahead! TODO + | HexEscapeSequence + | UnicodeEscapeSequence + | ExtendedUnicodeEscapeSequence + ; + +fragment CharacterEscapeSequence + : SingleEscapeCharacter + | NonEscapeCharacter + ; + +fragment HexEscapeSequence + : 'x' HexDigit HexDigit + ; + +fragment UnicodeEscapeSequence + : 'u' HexDigit HexDigit HexDigit HexDigit + ; + +fragment ExtendedUnicodeEscapeSequence + : 'u' '{' HexDigit+ '}' + ; + +fragment SingleEscapeCharacter + : ['"\\bfnrtv] + ; + +fragment NonEscapeCharacter + : ~['"\\bfnrtv0-9xu\r\n] + ; + +fragment EscapeCharacter + : SingleEscapeCharacter + | [0-9] + | [xu] + ; + +fragment LineContinuation + : '\\' [\r\n\u2028\u2029] + ; + +fragment HexDigit + : [0-9a-fA-F] + ; + +fragment DecimalIntegerLiteral + : '0' + | [1-9] [0-9]* + ; + +fragment ExponentPart + : [eE] [+-]? [0-9]+ + ; + +fragment IdentifierPart + : IdentifierStart + | [\p{Mn}] + | [\p{Nd}] + | [\p{Pc}] + | '\u200C' + | '\u200D' + ; + +fragment IdentifierStart + : [\p{L}] + | [$_] + | '\\' UnicodeEscapeSequence + ; + +fragment RegularExpressionFirstChar + : ~[*\r\n\u2028\u2029\\/[] + | RegularExpressionBackslashSequence + | '[' RegularExpressionClassChar* ']' + ; + +fragment RegularExpressionChar + : ~[\r\n\u2028\u2029\\/[] + | RegularExpressionBackslashSequence + | '[' RegularExpressionClassChar* ']' + ; + +fragment RegularExpressionClassChar + : ~[\r\n\u2028\u2029\]\\] + | RegularExpressionBackslashSequence + ; + +fragment RegularExpressionBackslashSequence + : '\\' ~[\r\n\u2028\u2029] + ; + diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/cpd/EcmascriptTokenizer.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/cpd/EcmascriptTokenizer.java index d66d74949f..2d52fa0896 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/cpd/EcmascriptTokenizer.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/cpd/EcmascriptTokenizer.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/ast/TypeScriptLexerBase.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/ast/TypeScriptLexerBase.java new file mode 100644 index 0000000000..7492de1e88 --- /dev/null +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/ast/TypeScriptLexerBase.java @@ -0,0 +1,173 @@ +/** + * Source: https://github.com/antlr/grammars-v4/tree/master/javascript/typescript + * License: MIT + * + * Slightly modified to adapt to pmd's style. + */ + +package net.sourceforge.pmd.lang.typescript.ast; + +import org.antlr.v4.runtime.*; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * All lexer methods that used in grammar (IsStrictMode) + * should start with Upper Case Char similar to Lexer rules. + */ +abstract class TypeScriptLexerBase extends Lexer +{ + /** + * Stores values of nested modes. By default mode is strict or + * defined externally (useStrictDefault) + */ + private Deque scopeStrictModes = new ArrayDeque<>(); + + private Token lastToken = null; + /** + * Default value of strict mode + * Can be defined externally by setUseStrictDefault + */ + private boolean useStrictDefault = false; + /** + * Current value of strict mode + * Can be defined during parsing, see StringFunctions.js and StringGlobal.js samples + */ + private boolean useStrictCurrent = false; + /** + * Keeps track of the current depth of nested template string backticks. + * E.g. after the X in: + * + * `${a ? `${X + * + * templateDepth will be 2. This variable is needed to determine if a `}` is a + * plain CloseBrace, or one that closes an expression inside a template string. + */ + private int templateDepth = 0; + + /** + * Keeps track of the depth of open- and close-braces. Used for expressions like: + * + * `${[1, 2, 3].map(x => { return x * 2;}).join("")}` + * + * where the '}' from `return x * 2;}` should not become a `TemplateCloseBrace` + * token but rather a `CloseBrace` token. + */ + private int bracesDepth = 0; + + TypeScriptLexerBase(CharStream input) { + super(input); + } + + public boolean getStrictDefault() { + return useStrictDefault; + } + + public void setUseStrictDefault(boolean value) { + useStrictDefault = value; + useStrictCurrent = value; + } + + public boolean IsStrictMode() { + return useStrictCurrent; + } + + public void StartTemplateString() { + this.bracesDepth = 0; + } + + public boolean IsInTemplateString() { + return this.templateDepth > 0 && this.bracesDepth == 0; + } + + /** + * Return the next token from the character stream and records this last + * token in case it resides on the default channel. This recorded token + * is used to determine when the lexer could possibly match a regex + * literal. Also changes scopeStrictModes stack if tokenize special + * string 'use strict'; + * + * @return the next token from the character stream. + */ + @Override + public Token nextToken() { + Token next = super.nextToken(); + + if (next.getChannel() == Token.DEFAULT_CHANNEL) { + // Keep track of the last token on the default channel. + this.lastToken = next; + } + + return next; + } + + protected void ProcessOpenBrace() + { + bracesDepth++; + useStrictCurrent = !scopeStrictModes.isEmpty() && scopeStrictModes.peek() || useStrictDefault; + scopeStrictModes.push(useStrictCurrent); + } + + protected void ProcessCloseBrace() + { + bracesDepth--; + useStrictCurrent = !scopeStrictModes.isEmpty() ? scopeStrictModes.pop() : useStrictDefault; + } + + protected void ProcessStringLiteral() + { + if (lastToken == null || lastToken.getType() == TypeScriptLexer.OpenBrace) + { + String text = getText(); + if ("\"use strict\"".equals(text) || "'use strict'".equals(text)) + { + if (!scopeStrictModes.isEmpty()) { + scopeStrictModes.pop(); + } + useStrictCurrent = true; + scopeStrictModes.push(useStrictCurrent); + } + } + } + + protected void IncreaseTemplateDepth() { + this.templateDepth++; + } + + protected void DecreaseTemplateDepth() { + this.templateDepth--; + } + + /** + * Returns {@code true} if the lexer can match a regex literal. + */ + protected boolean IsRegexPossible() { + + if (this.lastToken == null) { + // No token has been produced yet: at the start of the input, + // no division is possible, so a regex literal _is_ possible. + return true; + } + + switch (this.lastToken.getType()) { + case TypeScriptLexer.Identifier: + case TypeScriptLexer.NullLiteral: + case TypeScriptLexer.BooleanLiteral: + case TypeScriptLexer.This: + case TypeScriptLexer.CloseBracket: + case TypeScriptLexer.CloseParen: + case TypeScriptLexer.OctalIntegerLiteral: + case TypeScriptLexer.DecimalLiteral: + case TypeScriptLexer.HexIntegerLiteral: + case TypeScriptLexer.StringLiteral: + case TypeScriptLexer.PlusPlus: + case TypeScriptLexer.MinusMinus: + // After any of the tokens above, no regex literal can follow. + return false; + default: + // In all other cases, a regex literal _is_ possible. + return true; + } + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/ast/package-info.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/ast/package-info.java new file mode 100644 index 0000000000..423b55603f --- /dev/null +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/ast/package-info.java @@ -0,0 +1,5 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.typescript.ast; diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptLanguage.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptLanguage.java new file mode 100644 index 0000000000..9191e65cc2 --- /dev/null +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptLanguage.java @@ -0,0 +1,17 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.typescript.cpd; + +import net.sourceforge.pmd.cpd.AbstractLanguage; + +/** + * @author pguyot@kallisys.net + */ +public class TypeScriptLanguage extends AbstractLanguage { + + public TypeScriptLanguage() { + super("TypeScript", "typescript", new TypeScriptTokenizer(), ".ts"); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptTokenizer.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptTokenizer.java new file mode 100644 index 0000000000..f38c7f9509 --- /dev/null +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptTokenizer.java @@ -0,0 +1,18 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.typescript.cpd; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Lexer; + +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; +import net.sourceforge.pmd.lang.typescript.ast.TypeScriptLexer; + +public class TypeScriptTokenizer extends AntlrTokenizer { + @Override + protected Lexer getLexerForSource(CharStream charStream) { + return new TypeScriptLexer(charStream); + } +} diff --git a/pmd-javascript/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language b/pmd-javascript/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language index 7019119daf..a6868c8c36 100644 --- a/pmd-javascript/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language +++ b/pmd-javascript/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language @@ -1 +1,2 @@ net.sourceforge.pmd.cpd.EcmascriptLanguage +net.sourceforge.pmd.lang.typescript.cpd.TypeScriptLanguage diff --git a/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptTokenizerTest.java b/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptTokenizerTest.java new file mode 100644 index 0000000000..96c7e660ac --- /dev/null +++ b/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/typescript/cpd/TypeScriptTokenizerTest.java @@ -0,0 +1,39 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.typescript.cpd; + +import java.util.Properties; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.cpd.Tokenizer; +import net.sourceforge.pmd.cpd.test.CpdTextComparisonTest; + +class TypeScriptTokenizerTest extends CpdTextComparisonTest { + + TypeScriptTokenizerTest() { + super(".ts"); + } + + @Override + public Tokenizer newTokenizer(Properties properties) { + return new TypeScriptTokenizer(); + } + + @Override + protected String getResourcePrefix() { + return "../cpd/testdata"; + } + + @Test + void greeterTest() { + doTest("greeter"); + } + + @Test + void apiSampleWatchTest() { + doTest("APISample_Watch"); + } +} diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/APISample_Watch.ts b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/APISample_Watch.ts new file mode 100644 index 0000000000..e41fe8f5d2 --- /dev/null +++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/APISample_Watch.ts @@ -0,0 +1,89 @@ +// https://github.com/microsoft/TypeScript/blob/main/tests/cases/compiler/APISample_Watch.ts + +// @module: commonjs +// @skipLibCheck: true +// @noImplicitAny:true +// @strictNullChecks:true + +// @filename: node_modules/typescript/package.json +{ + "name": "typescript", + "types": "/.ts/typescript.d.ts" +} + +// @filename: APISample_Watch.ts +/* + * Note: This test is a public API sample. The sample sources can be found + * at: https://github.com/Microsoft/TypeScript-wiki/blob/master/Using-the-Compiler-API.md#writing-an-incremental-program-watcher + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var process: any; +declare var console: any; +declare var os: any; + +import ts = require("typescript"); + +const formatHost: ts.FormatDiagnosticsHost = { + getCanonicalFileName: path => path, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, +} + +function watchMain() { + const configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + const host = ts.createWatchCompilerHost(configPath, {}, ts.sys, + ts.createSemanticDiagnosticsBuilderProgram, + reportDiagnostic, + reportWatchStatusChanged, + ); + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames: ReadonlyArray, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +function reportDiagnostic(diagnostic: ts.Diagnostic) { + console.error("Error", diagnostic.code, ":", + ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine()) + ); +} + +/** + * Prints a diagnostic every time the watch status changes. + * This is mainly for messages like "Starting compilation" or "Compilation completed". + */ +function reportWatchStatusChanged(diagnostic: ts.Diagnostic) { + console.info(ts.formatDiagnostic(diagnostic, formatHost)); +} + +watchMain(); + diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/APISample_Watch.txt b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/APISample_Watch.txt new file mode 100644 index 0000000000..5043121523 --- /dev/null +++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/APISample_Watch.txt @@ -0,0 +1,330 @@ + [Image] or [Truncated image[ Bcol Ecol +L9 + [{] 1 2 +L10 + ["name"] 5 11 + [:] 11 12 + ["typescript"] 13 25 + [,] 25 26 +L11 + ["types"] 5 12 + [:] 12 13 + ["/.ts/typescript.d.ts"] 14 36 +L12 + [}] 1 2 +L21 + [declare] 1 8 + [var] 9 12 + [process] 13 20 + [:] 20 21 + [any] 22 25 + [;] 25 26 +L22 + [declare] 1 8 + [var] 9 12 + [console] 13 20 + [:] 20 21 + [any] 22 25 + [;] 25 26 +L23 + [declare] 1 8 + [var] 9 12 + [os] 13 15 + [:] 15 16 + [any] 17 20 + [;] 20 21 +L25 + [import] 1 7 + [ts] 8 10 + [=] 11 12 + [require] 13 20 + [(] 20 21 + ["typescript"] 21 33 + [)] 33 34 + [;] 34 35 +L27 + [const] 1 6 + [formatHost] 7 17 + [:] 17 18 + [ts] 19 21 + [.] 21 22 + [FormatDiagnosticsHost] 22 43 + [=] 44 45 + [{] 46 47 +L28 + [getCanonicalFileName] 5 25 + [:] 25 26 + [path] 27 31 + [=>] 32 34 + [path] 35 39 + [,] 39 40 +L29 + [getCurrentDirectory] 5 24 + [:] 24 25 + [ts] 26 28 + [.] 28 29 + [sys] 29 32 + [.] 32 33 + [getCurrentDirectory] 33 52 + [,] 52 53 +L30 + [getNewLine] 5 15 + [:] 15 16 + [(] 17 18 + [)] 18 19 + [=>] 20 22 + [ts] 23 25 + [.] 25 26 + [sys] 26 29 + [.] 29 30 + [newLine] 30 37 + [,] 37 38 +L31 + [}] 1 2 +L33 + [function] 1 9 + [watchMain] 10 19 + [(] 19 20 + [)] 20 21 + [{] 22 23 +L34 + [const] 5 10 + [configPath] 11 21 + [=] 22 23 + [ts] 24 26 + [.] 26 27 + [findConfigFile] 27 41 + [(] 41 42 + ["./"] 57 61 + [,] 61 62 + [ts] 63 65 + [.] 65 66 + [sys] 66 69 + [.] 69 70 + [fileExists] 70 80 + [,] 80 81 + ["tsconfig.json"] 82 97 + [)] 97 98 + [;] 98 99 +L35 + [if] 5 7 + [(] 8 9 + [!] 9 10 + [configPath] 10 20 + [)] 20 21 + [{] 22 23 +L36 + [throw] 9 14 + [new] 15 18 + [Error] 19 24 + [(] 24 25 + ["Could not find a valid 'tsconfig.[ 25 66 + [)] 66 67 + [;] 67 68 +L37 + [}] 5 6 +L50 + [const] 5 10 + [host] 11 15 + [=] 16 17 + [ts] 18 20 + [.] 20 21 + [createWatchCompilerHost] 21 44 + [(] 44 45 + [configPath] 45 55 + [,] 55 56 + [{] 57 58 + [}] 58 59 + [,] 59 60 + [ts] 61 63 + [.] 63 64 + [sys] 64 67 + [,] 67 68 +L51 + [ts] 9 11 + [.] 11 12 + [createSemanticDiagnosticsBuilderPr[ 12 51 + [,] 51 52 +L52 + [reportDiagnostic] 9 25 + [,] 25 26 +L53 + [reportWatchStatusChanged] 9 33 + [,] 33 34 +L54 + [)] 5 6 + [;] 6 7 +L58 + [const] 5 10 + [origCreateProgram] 11 28 + [=] 29 30 + [host] 31 35 + [.] 35 36 + [createProgram] 36 49 + [;] 49 50 +L59 + [host] 5 9 + [.] 9 10 + [createProgram] 10 23 + [=] 24 25 + [(] 26 27 + [rootNames] 27 36 + [:] 36 37 + [ReadonlyArray] 38 51 + [<] 51 52 + [string] 52 58 + [>] 58 59 + [,] 59 60 + [options] 61 68 + [,] 68 69 + [host] 70 74 + [,] 74 75 + [oldProgram] 76 86 + [)] 86 87 + [=>] 88 90 + [{] 91 92 +L60 + [console] 9 16 + [.] 16 17 + [log] 17 20 + [(] 20 21 + ["** We're about to create the prog[ 21 63 + [)] 63 64 + [;] 64 65 +L61 + [return] 9 15 + [origCreateProgram] 16 33 + [(] 33 34 + [rootNames] 34 43 + [,] 43 44 + [options] 45 52 + [,] 52 53 + [host] 54 58 + [,] 58 59 + [oldProgram] 60 70 + [)] 70 71 + [;] 71 72 +L62 + [}] 5 6 +L63 + [const] 5 10 + [origPostProgramCreate] 11 32 + [=] 33 34 + [host] 35 39 + [.] 39 40 + [afterProgramCreate] 40 58 + [;] 58 59 +L65 + [host] 5 9 + [.] 9 10 + [afterProgramCreate] 10 28 + [=] 29 30 + [program] 31 38 + [=>] 39 41 + [{] 42 43 +L66 + [console] 9 16 + [.] 16 17 + [log] 17 20 + [(] 20 21 + ["** We finished making the program[ 21 60 + [)] 60 61 + [;] 61 62 +L67 + [origPostProgramCreate] 9 30 + [!] 30 31 + [(] 31 32 + [program] 32 39 + [)] 39 40 + [;] 40 41 +L68 + [}] 5 6 + [;] 6 7 +L71 + [ts] 5 7 + [.] 7 8 + [createWatchProgram] 8 26 + [(] 26 27 + [host] 27 31 + [)] 31 32 + [;] 32 33 +L72 + [}] 1 2 +L74 + [function] 1 9 + [reportDiagnostic] 10 26 + [(] 26 27 + [diagnostic] 27 37 + [:] 37 38 + [ts] 39 41 + [.] 41 42 + [Diagnostic] 42 52 + [)] 52 53 + [{] 54 55 +L75 + [console] 5 12 + [.] 12 13 + [error] 13 18 + [(] 18 19 + ["Error"] 19 26 + [,] 26 27 + [diagnostic] 28 38 + [.] 38 39 + [code] 39 43 + [,] 43 44 + [":"] 45 48 + [,] 48 49 +L76 + [ts] 9 11 + [.] 11 12 + [flattenDiagnosticMessageText] 12 40 + [(] 40 41 + [diagnostic] 41 51 + [.] 51 52 + [messageText] 52 63 + [,] 63 64 + [formatHost] 65 75 + [.] 75 76 + [getNewLine] 76 86 + [(] 86 87 + [)] 87 88 + [)] 88 89 +L77 + [)] 5 6 + [;] 6 7 +L78 + [}] 1 2 +L84 + [function] 1 9 + [reportWatchStatusChanged] 10 34 + [(] 34 35 + [diagnostic] 35 45 + [:] 45 46 + [ts] 47 49 + [.] 49 50 + [Diagnostic] 50 60 + [)] 60 61 + [{] 62 63 +L85 + [console] 5 12 + [.] 12 13 + [info] 13 17 + [(] 17 18 + [ts] 18 20 + [.] 20 21 + [formatDiagnostic] 21 37 + [(] 37 38 + [diagnostic] 38 48 + [,] 48 49 + [formatHost] 50 60 + [)] 60 61 + [)] 61 62 + [;] 62 63 +L86 + [}] 1 2 +L88 + [watchMain] 1 10 + [(] 10 11 + [)] 11 12 + [;] 12 13 +EOF diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/greeter.ts b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/greeter.ts new file mode 100644 index 0000000000..18c3b1867d --- /dev/null +++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/greeter.ts @@ -0,0 +1,9 @@ +// https://www.typescriptlang.org/docs/handbook/typescript-tooling-in-5-minutes.html + +function greeter(person) { + return "Hello, " + person; +} + +let user = "Jane User"; + +document.body.textContent = greeter(user); diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/greeter.txt b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/greeter.txt new file mode 100644 index 0000000000..f3ca6d0d75 --- /dev/null +++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/typescript/cpd/testdata/greeter.txt @@ -0,0 +1,35 @@ + [Image] or [Truncated image[ Bcol Ecol +L3 + [function] 1 9 + [greeter] 10 17 + [(] 17 18 + [person] 18 24 + [)] 24 25 + [{] 26 27 +L4 + [return] 3 9 + ["Hello, "] 10 19 + [+] 20 21 + [person] 22 28 + [;] 28 29 +L5 + [}] 1 2 +L7 + [let] 1 4 + [user] 5 9 + [=] 10 11 + ["Jane User"] 12 23 + [;] 23 24 +L9 + [document] 1 9 + [.] 9 10 + [body] 10 14 + [.] 14 15 + [textContent] 15 26 + [=] 27 28 + [greeter] 29 36 + [(] 36 37 + [user] 37 41 + [)] 41 42 + [;] 42 43 +EOF diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/cpd/JSPTokenizer.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/cpd/JSPTokenizer.java index 5617484d1b..bc5858dc05 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/cpd/JSPTokenizer.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/cpd/JSPTokenizer.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; diff --git a/pmd-julia/pom.xml b/pmd-julia/pom.xml new file mode 100644 index 0000000000..dea11351dc --- /dev/null +++ b/pmd-julia/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + pmd-julia + PMD Julia + + + net.sourceforge.pmd + pmd + 7.0.0-SNAPSHOT + ../pom.xml + + + + + + org.antlr + antlr4-maven-plugin + + + + maven-resources-plugin + + false + + ${*} + + + + + + + + + net.sourceforge.pmd + pmd-core + + + org.antlr + antlr4-runtime + + + + org.junit.jupiter + junit-jupiter-api + test + + + net.sourceforge.pmd + pmd-test + test + + + net.sourceforge.pmd + pmd-lang-test + test + + + diff --git a/pmd-julia/src/main/antlr4/net/sourceforge/pmd/lang/julia/ast/Julia.g4 b/pmd-julia/src/main/antlr4/net/sourceforge/pmd/lang/julia/ast/Julia.g4 new file mode 100644 index 0000000000..dbaddc8fd4 --- /dev/null +++ b/pmd-julia/src/main/antlr4/net/sourceforge/pmd/lang/julia/ast/Julia.g4 @@ -0,0 +1,270 @@ +grammar Julia; + +// Parser + +main + : functionBody (functionDefinition functionBody)* END? EOF + ; + +functionDefinition + : functionDefinition1 + | functionDefinition2 + ; + +functionDefinition1 + : FUNCTION IDENTIFIER? anyToken*? ('(' anyToken*? ')' whereClause*? functionBody)? END + ; + +functionDefinition2 + : functionIdentifier '(' anyToken*? ')' whereClause*? '=' functionBody + ; + +functionIdentifier + : IDENTIFIER + | '(' anyToken*? ')' // Operator + ; + +whereClause + : WHERE anyToken*? + ; + +functionBody + : anyToken*? (statement anyToken*?)*? + ; + +statement + : beginStatement + | doStatement + | forStatement + | functionDefinition1 + | ifStatement + | letStatement + | macroStatement + | structStatement + | tryCatchStatement + | typeStatement + | whileStatement + ; + +beginStatement + : BEGIN functionBody END + ; + +doStatement + : DO functionBody END + ; + +forStatement + : FOR functionBody END + ; + +ifStatement + : IF functionBody (ELSIF functionBody)* (ELSE functionBody)? END + ; + +letStatement + : LET functionBody END + ; + +macroStatement + : MACRO functionBody END + ; + +structStatement + : STRUCT functionBody END + ; + +tryCatchStatement + : TRY functionBody (CATCH functionBody)? (FINALLY functionBody)? END + ; + +typeStatement + : TYPE functionBody END + ; + +whileStatement + : WHILE functionBody END + ; + +anyToken + : ABSTRACT + | ANY + | ARROWOPERATOR + | ASSIGNMENTOPERATOR + | BAREMODULE + | BEGIN + | BITSHIFTOPERATOR + | BITSTYPE + | BREAK + | CATCH + | CCALL + | CHAR + | CONST + | CONTINUE + | DO + | ELSE + | ELSIF + | END + | EXPORT + | EXTERNALCOMMAND + | FINALLY + | FOR + | FUNCTION + | GLOBAL + | IDENTIFIER + | IF + | IMMUTABLE + | IMPORT + | IMPORTALL + | INSTANCEOF + | LET + | LOCAL + | MACRO + | MODULE + | NUMERICAL + | PIPEOPERATOR + | QUOTE + | RETURN + | STAGED_FUNCTION + | STRING + | STRUCT + | TRY + | TYPE + | TYPEALIAS + | USING + | WHERE + | WHILE + | '(' anyToken*? ')' + | '[' anyToken*? ']' + | '{' anyToken*? '}' + | '=' + | '=>' + | '&&' // short-circuit + | '||' // short-circuit + | '==' // to disambiguate from "=" + | '>=' + | '<=' + | '<' + | '<:' + | '>' + | '...' + ; + +// Lexer + +COMMENTS : '#' (~[=\r\n]~[\r\n]*)? -> skip; // skip #= because otherwise multiline comments are not recognized, see next line +MULTILINECOMMENTS1 : '#=' .*? '=#' -> skip; +MULTILINECOMMENTS2 : '```' .*? '```' -> skip; +MULTILINESTRING : '"""' ('\\"'|.)*? '"""' -> skip; +NL : '\r'? '\n' -> skip ; +WHITESPACE : [ \t]+ -> skip ; + +ABSTRACT : 'abstract' ; + +ARROWOPERATOR + : '--' + | '-->' + ; + +ASSIGNMENTOPERATOR + : ':=' | '+=' | '-=' | '*=' | '/=' | '//=' | './/=' + | '.*=' | './=' | '\\=' | '.\\=' | '^=' | '.^=' | '%=' | '.%=' + | '|=' | '&=' | '$=' | '=>' | '<<=' | '>>=' | '>>>=' + | '.+=' | '.-=' + ; + +BAREMODULE : 'baremodule' ; +BEGIN : 'begin' ; +BITSHIFTOPERATOR : '<<' | '>>' | '>>>' | '.<<' | '.>>' | '.>>>'; +BITSTYPE : 'bitstype' ; +BREAK : 'break' ; +CATCH : 'catch' ; +CCALL : 'ccall' ; +CHAR : '\'' '\\'? .? '\'' ; +CONST : 'const' ; +CONTINUE : 'continue' ; +DO : 'do' ; +ELSE : 'else' ; +ELSIF : 'elsif' ; +END : 'end' ; +EXPORT : 'export' ; +EXTERNALCOMMAND : '`' .*? '`' ; +FINALLY : 'finally' ; +FOR : 'for' ; +FUNCTION : 'function' ; +GLOBAL : 'global' ; +IF : 'if' ; +IMMUTABLE : 'immutable' ; +IMPORT : 'import' ; +IMPORTALL : 'importall' ; +INSTANCEOF : '::' ; +LET : 'let' ; +LOCAL : 'local' ; +MACRO : 'macro' ; +MODULE : 'module' ; +PIPEOPERATOR : '|>'| '<|' ; +QUOTE : 'quote' ; +RETURN : 'return' ; +STAGEDFUNCTION : 'stagedfunction' ; +STRING : '"' ('\\\\'|'\\"'|'$(' ('$(' .*? ')'|'"' .*? '"'|.)*? ')'|.)*? '"' ; +STRUCT : 'struct' ; +TRY : 'try' ; +TYPE : 'type' ; +TYPEALIAS : 'typealias' ; +USING : 'using' ; +WHERE : 'where' ; +WHILE : 'while' ; + +NUMERICAL + : INT_LITERAL + | BINARY + | OCTAL + | HEX + | FLOAT32_LITERAL + | FLOAT64_LITERAL + | HEX_FLOAT + ; + +INT_LITERAL : DEC_DGT+; +BINARY : '0b'BIN_DGT+; +OCTAL : '0o'OCT_DGT+; +HEX : '0x'HEX_DGT+; + +FLOAT32_LITERAL + : DEC_DGT+ '.'? DEC_DGT* EXP32? + | '.' DEC_DGT* EXP32? + ; + +FLOAT64_LITERAL + : DEC_DGT+ '.'? DEC_DGT* EXP64? + | '.' DEC_DGT* EXP64? + ; + +HEX_FLOAT : '0x' HEX_DGT? ('.' HEX_DGT*)? ( 'p' | 'P' ) ( '+' | '-' )? DEC_DGT+; + +fragment EXP32 : [f] [+\-]? DEC_DGT+; +fragment EXP64 : [e] [+\-]? DEC_DGT+; + +IDENTIFIER : ('_'|UNi) ('_'|UNi|DEC_DGT)* '!'?; +fragment DEC_DGT : [0-9_]; +fragment BIN_DGT : [0-1_]; +fragment OCT_DGT : [0-7_]; +fragment HEX_DGT : [0-9A-Fa-f_]; + +fragment UNi + : 'A'..'Z' + | 'a'..'z' + | '\u00C0'..'\u00D6' + | '\u00D8'..'\u00F6' + | '\u00F8'..'\u02FF' + | '\u0370'..'\u037D' + | '\u037F'..'\u1FFF' + | '\u200C'..'\u200D' + | '\u2070'..'\u218F' + | '\u2C00'..'\u2FEF' + | '\u3001'..'\uD7FF' + | '\uF900'..'\uFDCF' + | '\uFDF0'..'\uFFFD' + ; + +ANY : . ; \ No newline at end of file diff --git a/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/ast/package-info.java b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/ast/package-info.java new file mode 100644 index 0000000000..f72bcf2f32 --- /dev/null +++ b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/ast/package-info.java @@ -0,0 +1,8 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * Contains the Antlr grammar for Julia. + */ +package net.sourceforge.pmd.lang.julia.ast; diff --git a/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/JuliaLanguage.java b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/JuliaLanguage.java new file mode 100644 index 0000000000..d6bd001607 --- /dev/null +++ b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/JuliaLanguage.java @@ -0,0 +1,20 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.julia.cpd; + +import net.sourceforge.pmd.cpd.AbstractLanguage; + +/** + * Language implementation for Julia. + */ +public class JuliaLanguage extends AbstractLanguage { + + /** + * Creates a new Julia Language instance. + */ + public JuliaLanguage() { + super("Julia", "julia", new JuliaTokenizer(), ".jl"); + } +} diff --git a/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/JuliaTokenizer.java b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/JuliaTokenizer.java new file mode 100644 index 0000000000..9a38293d5e --- /dev/null +++ b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/JuliaTokenizer.java @@ -0,0 +1,21 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.julia.cpd; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Lexer; + +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; +import net.sourceforge.pmd.lang.julia.ast.JuliaLexer; + +/** + * The Julia Tokenizer. + */ +public class JuliaTokenizer extends AntlrTokenizer { + @Override + protected Lexer getLexerForSource(CharStream charStream) { + return new JuliaLexer(charStream); + } +} diff --git a/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/package-info.java b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/package-info.java new file mode 100644 index 0000000000..e052fae87a --- /dev/null +++ b/pmd-julia/src/main/java/net/sourceforge/pmd/lang/julia/cpd/package-info.java @@ -0,0 +1,8 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * Contains Julia tokenizer and language classes. + */ +package net.sourceforge.pmd.lang.julia.cpd; diff --git a/pmd-julia/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language b/pmd-julia/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language new file mode 100644 index 0000000000..bd23fbae93 --- /dev/null +++ b/pmd-julia/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language @@ -0,0 +1 @@ +net.sourceforge.pmd.lang.julia.cpd.JuliaLanguage diff --git a/pmd-julia/src/test/java/net/sourceforge/pmd/cpd/JuliaTokenizerTest.java b/pmd-julia/src/test/java/net/sourceforge/pmd/cpd/JuliaTokenizerTest.java new file mode 100644 index 0000000000..e09f2f12f3 --- /dev/null +++ b/pmd-julia/src/test/java/net/sourceforge/pmd/cpd/JuliaTokenizerTest.java @@ -0,0 +1,34 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +import java.util.Properties; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.cpd.test.CpdTextComparisonTest; +import net.sourceforge.pmd.lang.julia.cpd.JuliaTokenizer; + +class JuliaTokenizerTest extends CpdTextComparisonTest { + JuliaTokenizerTest() { + super(".jl"); + } + + @Override + protected String getResourcePrefix() { + return "../lang/julia/cpd/testdata"; + } + + @Override + public Tokenizer newTokenizer(Properties properties) { + JuliaTokenizer tok = new JuliaTokenizer(); + return tok; + } + + @Test + void testMathExample() { + doTest("mathExample"); + } +} diff --git a/pmd-julia/src/test/resources/net/sourceforge/pmd/lang/julia/cpd/testdata/mathExample.jl b/pmd-julia/src/test/resources/net/sourceforge/pmd/lang/julia/cpd/testdata/mathExample.jl new file mode 100644 index 0000000000..8c70fdef3e --- /dev/null +++ b/pmd-julia/src/test/resources/net/sourceforge/pmd/lang/julia/cpd/testdata/mathExample.jl @@ -0,0 +1,33 @@ +# function to calculate the volume of a sphere +function sphere_vol(r) + # julia allows Unicode names (in UTF-8 encoding) + # so either "pi" or the symbol π can be used + return 4/3*pi*r^3 +end + +# functions can also be defined more succinctly +quadratic(a, sqr_term, b) = (-b + sqr_term) / 2a + +# calculates x for 0 = a*x^2+b*x+c, arguments types can be defined in function definitions +function quadratic2(a::Float64, b::Float64, c::Float64) + # unlike other languages 2a is equivalent to 2*a + # a^2 is used instead of a**2 or pow(a,2) + sqr_term = sqrt(b^2-4a*c) + r1 = quadratic(a, sqr_term, b) + r2 = quadratic(a, -sqr_term, b) + # multiple values can be returned from a function using tuples + # if the return keyword is omitted, the last term is returned + r1, r2 +end + +vol = sphere_vol(3) +# @printf allows number formatting but does not automatically append the \n to statements, see below +using Printf +@printf "volume = %0.3f\n" vol +#> volume = 113.097 + +quad1, quad2 = quadratic2(2.0, -2.0, -12.0) +println("result 1: ", quad1) +#> result 1: 3.0 +println("result 2: ", quad2) +#> result 2: -2.0 \ No newline at end of file diff --git a/pmd-julia/src/test/resources/net/sourceforge/pmd/lang/julia/cpd/testdata/mathExample.txt b/pmd-julia/src/test/resources/net/sourceforge/pmd/lang/julia/cpd/testdata/mathExample.txt new file mode 100644 index 0000000000..4413565ff3 --- /dev/null +++ b/pmd-julia/src/test/resources/net/sourceforge/pmd/lang/julia/cpd/testdata/mathExample.txt @@ -0,0 +1,143 @@ + [Image] or [Truncated image[ Bcol Ecol +L2 + [function] 1 9 + [sphere_vol] 10 20 + [(] 20 21 + [r] 21 22 + [)] 22 23 +L5 + [return] 3 9 + [4] 10 11 + [/] 11 12 + [3] 12 13 + [*] 13 14 + [pi] 14 16 + [*] 16 17 + [r] 17 18 + [^] 18 19 + [3] 19 20 +L6 + [end] 1 4 +L9 + [quadratic] 1 10 + [(] 10 11 + [a] 11 12 + [,] 12 13 + [sqr_term] 14 22 + [,] 22 23 + [b] 24 25 + [)] 25 26 + [=] 27 28 + [(] 29 30 + [-] 30 31 + [b] 31 32 + [+] 33 34 + [sqr_term] 35 43 + [)] 43 44 + [/] 45 46 + [2] 47 48 + [a] 48 49 +L12 + [function] 1 9 + [quadratic2] 10 20 + [(] 20 21 + [a] 21 22 + [::] 22 24 + [Float64] 24 31 + [,] 31 32 + [b] 33 34 + [::] 34 36 + [Float64] 36 43 + [,] 43 44 + [c] 45 46 + [::] 46 48 + [Float64] 48 55 + [)] 55 56 +L15 + [sqr_term] 3 11 + [=] 12 13 + [sqrt] 14 18 + [(] 18 19 + [b] 19 20 + [^] 20 21 + [2] 21 22 + [-] 22 23 + [4] 23 24 + [a] 24 25 + [*] 25 26 + [c] 26 27 + [)] 27 28 +L16 + [r1] 3 5 + [=] 6 7 + [quadratic] 8 17 + [(] 17 18 + [a] 18 19 + [,] 19 20 + [sqr_term] 21 29 + [,] 29 30 + [b] 31 32 + [)] 32 33 +L17 + [r2] 3 5 + [=] 6 7 + [quadratic] 8 17 + [(] 17 18 + [a] 18 19 + [,] 19 20 + [-] 21 22 + [sqr_term] 22 30 + [,] 30 31 + [b] 32 33 + [)] 33 34 +L20 + [r1] 3 5 + [,] 5 6 + [r2] 7 9 +L21 + [end] 1 4 +L23 + [vol] 1 4 + [=] 5 6 + [sphere_vol] 7 17 + [(] 17 18 + [3] 18 19 + [)] 19 20 +L25 + [using] 1 6 + [Printf] 7 13 +L26 + [@] 1 2 + [printf] 2 8 + ["volume = %0.3f\\n"] 9 27 + [vol] 28 31 +L29 + [quad1] 1 6 + [,] 6 7 + [quad2] 8 13 + [=] 14 15 + [quadratic2] 16 26 + [(] 26 27 + [2.0] 27 30 + [,] 30 31 + [-] 32 33 + [2.0] 33 36 + [,] 36 37 + [-] 38 39 + [12.0] 39 43 + [)] 43 44 +L30 + [println] 1 8 + [(] 8 9 + ["result 1: "] 9 21 + [,] 21 22 + [quad1] 23 28 + [)] 28 29 +L32 + [println] 1 8 + [(] 8 9 + ["result 2: "] 9 21 + [,] 21 22 + [quad2] 23 28 + [)] 28 29 +EOF diff --git a/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/Kotlin.g4 b/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/Kotlin.g4 index 282b737351..16e602e2cc 100644 --- a/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/Kotlin.g4 +++ b/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/Kotlin.g4 @@ -15,12 +15,12 @@ import net.sourceforge.pmd.lang.ast.AstVisitor; static final AntlrNameDictionary DICO = new KotlinNameDictionary(VOCABULARY, ruleNames); @Override - public KotlinTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { + protected KotlinTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { return new KotlinTerminalNode(t); } @Override - public KotlinErrorNode createPmdError(ParserRuleContext parent, Token t) { + protected KotlinErrorNode createPmdError(ParserRuleContext parent, Token t) { return new KotlinErrorNode(t); } } diff --git a/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/README.md b/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/README.md index 20361f9a64..0bce081a13 100644 --- a/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/README.md +++ b/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/ast/README.md @@ -50,12 +50,12 @@ import net.sourceforge.pmd.lang.ast.AstVisitor; static final AntlrNameDictionary DICO = new KotlinNameDictionary(VOCABULARY, ruleNames); @Override - public KotlinTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { + protected KotlinTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { return new KotlinTerminalNode(t); } @Override - public KotlinErrorNode createPmdError(ParserRuleContext parent, Token t) { + protected KotlinErrorNode createPmdError(ParserRuleContext parent, Token t) { return new KotlinErrorNode(t); } } diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java index 143c1f5f06..b2512fb67b 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrToken; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTokenManager; diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/AbstractKotlinRule.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/AbstractKotlinRule.java index 31262b1473..7c13206023 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/AbstractKotlinRule.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/AbstractKotlinRule.java @@ -5,10 +5,10 @@ package net.sourceforge.pmd.lang.kotlin; import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrBaseRule; import net.sourceforge.pmd.lang.kotlin.ast.KotlinVisitor; +import net.sourceforge.pmd.lang.rule.AbstractVisitorRule; -public abstract class AbstractKotlinRule extends AntlrBaseRule { +public abstract class AbstractKotlinRule extends AbstractVisitorRule { protected AbstractKotlinRule() { // inheritance constructor diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/ast/KotlinInnerNode.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/ast/KotlinInnerNode.java index a6d58699ae..683f78b4de 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/ast/KotlinInnerNode.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/ast/KotlinInnerNode.java @@ -9,8 +9,7 @@ import org.antlr.v4.runtime.ParserRuleContext; import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.impl.antlr4.BaseAntlrInnerNode; -public abstract class KotlinInnerNode - extends BaseAntlrInnerNode implements KotlinNode { +abstract class KotlinInnerNode extends BaseAntlrInnerNode implements KotlinNode { KotlinInnerNode(ParserRuleContext parent, int invokingStateNumber) { super(parent, invokingStateNumber); diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt index a9d789d0c7..fa812f1f7b 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt @@ -243,7 +243,7 @@ abstract class BaseParsingHelper, T : RootNode return PmdAnalysis.create(config).use { pmd -> pmd.addListener(GlobalAnalysisListener.exceptionThrower()) pmd.addRuleSet(RuleSet.forSingleRule(rule)) - pmd.files().addSourceFile(fileName, code) + pmd.files().addSourceFile(code, fileName) pmd.performAnalysisAndCollectReport() } } diff --git a/pmd-languages-deps/pom.xml b/pmd-languages-deps/pom.xml new file mode 100644 index 0000000000..296b354747 --- /dev/null +++ b/pmd-languages-deps/pom.xml @@ -0,0 +1,163 @@ + + + 4.0.0 + + net.sourceforge.pmd + pmd + 7.0.0-SNAPSHOT + + + pmd-languages-deps + pom + PMD Languages Dependencies + + + + net.sourceforge.pmd + pmd-apex + ${project.version} + + + net.sourceforge.pmd + pmd-cpp + ${project.version} + + + net.sourceforge.pmd + pmd-cs + ${project.version} + + + net.sourceforge.pmd + pmd-dart + ${project.version} + + + net.sourceforge.pmd + pmd-fortran + ${project.version} + + + net.sourceforge.pmd + pmd-gherkin + ${project.version} + + + net.sourceforge.pmd + pmd-go + ${project.version} + + + net.sourceforge.pmd + pmd-groovy + ${project.version} + + + net.sourceforge.pmd + pmd-html + ${project.version} + + + net.sourceforge.pmd + pmd-java + ${project.version} + + + net.sourceforge.pmd + pmd-javascript + ${project.version} + + + net.sourceforge.pmd + pmd-jsp + ${project.version} + + + net.sourceforge.pmd + pmd-julia + ${project.version} + + + net.sourceforge.pmd + pmd-kotlin + ${project.version} + + + net.sourceforge.pmd + pmd-lua + ${project.version} + + + net.sourceforge.pmd + pmd-matlab + ${project.version} + + + net.sourceforge.pmd + pmd-modelica + ${project.version} + + + net.sourceforge.pmd + pmd-objectivec + ${project.version} + + + net.sourceforge.pmd + pmd-perl + ${project.version} + + + net.sourceforge.pmd + pmd-php + ${project.version} + + + net.sourceforge.pmd + pmd-plsql + ${project.version} + + + net.sourceforge.pmd + pmd-python + ${project.version} + + + net.sourceforge.pmd + pmd-ruby + ${project.version} + + + net.sourceforge.pmd + pmd-scala_2.13 + ${project.version} + + + net.sourceforge.pmd + pmd-swift + ${project.version} + + + net.sourceforge.pmd + pmd-tsql + ${project.version} + + + net.sourceforge.pmd + pmd-visualforce + ${project.version} + + + net.sourceforge.pmd + pmd-vm + ${project.version} + + + net.sourceforge.pmd + pmd-xml + ${project.version} + + + diff --git a/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java b/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java index 509a7803c6..aa5288deec 100644 --- a/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java +++ b/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java @@ -9,7 +9,7 @@ import java.util.Properties; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrToken; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTokenManager; diff --git a/pmd-matlab/src/main/java/net/sourceforge/pmd/cpd/MatlabTokenizer.java b/pmd-matlab/src/main/java/net/sourceforge/pmd/cpd/MatlabTokenizer.java index 9459c44696..002e40c081 100644 --- a/pmd-matlab/src/main/java/net/sourceforge/pmd/cpd/MatlabTokenizer.java +++ b/pmd-matlab/src/main/java/net/sourceforge/pmd/cpd/MatlabTokenizer.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/cpd/ModelicaTokenizer.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/cpd/ModelicaTokenizer.java index 3258a3cda7..fb22a555d3 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/cpd/ModelicaTokenizer.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/cpd/ModelicaTokenizer.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.cpd.token.JavaCCTokenFilter; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; diff --git a/pmd-objectivec/src/main/java/net/sourceforge/pmd/cpd/ObjectiveCTokenizer.java b/pmd-objectivec/src/main/java/net/sourceforge/pmd/cpd/ObjectiveCTokenizer.java index acccfcd24a..236eea59a3 100644 --- a/pmd-objectivec/src/main/java/net/sourceforge/pmd/cpd/ObjectiveCTokenizer.java +++ b/pmd-objectivec/src/main/java/net/sourceforge/pmd/cpd/ObjectiveCTokenizer.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java index 77abbf8794..8a7a153c3f 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.cpd; import java.util.Properties; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; diff --git a/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java b/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java index c80d572f67..82720a8ea1 100644 --- a/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java +++ b/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.cpd; import java.util.regex.Pattern; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index cd7697bdbf..9f008e7e3f 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -16,6 +16,12 @@ + + + ${project.basedir}/src/main/resources + true + + diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 index 7d9bd13ff6..17c2e3f934 100644 --- a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 +++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 @@ -44,12 +44,12 @@ import net.sourceforge.pmd.lang.ast.AstVisitor; static final AntlrNameDictionary DICO = new SwiftNameDictionary(VOCABULARY, ruleNames); @Override - public SwiftTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { + protected SwiftTerminalNode createPmdTerminal(ParserRuleContext parent, Token t) { return new SwiftTerminalNode(t); } @Override - public SwiftErrorNode createPmdError(ParserRuleContext parent, Token t) { + protected SwiftErrorNode createPmdError(ParserRuleContext parent, Token t) { return new SwiftErrorNode(t); } } diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java b/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java index 41d7c28d36..8153ba4455 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.lang.swift.ast.SwiftLexer; /** diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java index 11199a0239..a4a11d3ad2 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java @@ -5,15 +5,15 @@ package net.sourceforge.pmd.lang.swift; import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.AstVisitor; -import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrBaseRule; +import net.sourceforge.pmd.lang.rule.AbstractVisitorRule; +import net.sourceforge.pmd.lang.swift.ast.SwiftVisitor; -public abstract class AbstractSwiftRule extends AntlrBaseRule { +public abstract class AbstractSwiftRule extends AbstractVisitorRule { protected AbstractSwiftRule() { // inheritance constructor } @Override - public abstract AstVisitor buildVisitor(); + public abstract SwiftVisitor buildVisitor(); } diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java index ea082bfbdc..48c5de1aeb 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java @@ -9,7 +9,8 @@ import org.antlr.v4.runtime.ParserRuleContext; import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.impl.antlr4.BaseAntlrInnerNode; -public abstract class SwiftInnerNode +// package private base class +abstract class SwiftInnerNode extends BaseAntlrInnerNode implements SwiftNode { SwiftInnerNode() { diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java index 5c49fb5669..1c1c0da91b 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java @@ -7,7 +7,6 @@ package net.sourceforge.pmd.lang.swift.rule.bestpractices; import java.util.List; import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.swift.AbstractSwiftRule; import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwAttribute; import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwAttributes; @@ -15,6 +14,7 @@ import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwCodeBlock; import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwFunctionDeclaration; import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwInitializerDeclaration; import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwStatement; +import net.sourceforge.pmd.lang.swift.ast.SwiftVisitor; import net.sourceforge.pmd.lang.swift.ast.SwiftVisitorBase; public class UnavailableFunctionRule extends AbstractSwiftRule { @@ -29,7 +29,7 @@ public class UnavailableFunctionRule extends AbstractSwiftRule { } @Override - public AstVisitor buildVisitor() { + public SwiftVisitor buildVisitor() { return new SwiftVisitorBase() { @Override diff --git a/pmd-swift/src/main/resources/category/swift/bestpractices.xml b/pmd-swift/src/main/resources/category/swift/bestpractices.xml index 6bf75958e6..cab248b276 100644 --- a/pmd-swift/src/main/resources/category/swift/bestpractices.xml +++ b/pmd-swift/src/main/resources/category/swift/bestpractices.xml @@ -10,11 +10,11 @@ Rules which enforce generally accepted best practices.
+ externalInfoUrl="${pmd.website.baseurl}/pmd_rules_swift_bestpractices.html#prohibitedinterfacebuilder"> Creating views using Interface Builder should be avoided. Defining views by code allows the compiler to detect issues that otherwise will be runtime errors. @@ -45,11 +45,11 @@ class ViewController: UIViewController { + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_swift_bestpractices.html#unavailablefunction"> Due to Objective-C and Swift interoperability some functions are often required to be implemented but aren't really needed. It is extremely common that the sole implementation of the functions consist of throwing diff --git a/pmd-swift/src/main/resources/category/swift/errorprone.xml b/pmd-swift/src/main/resources/category/swift/errorprone.xml index 1a64a50b85..e4dab5022d 100644 --- a/pmd-swift/src/main/resources/category/swift/errorprone.xml +++ b/pmd-swift/src/main/resources/category/swift/errorprone.xml @@ -11,10 +11,10 @@ + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_swift_errorprone.html#forcecast"> Force casts should be avoided. This may lead to a crash if it's not used carefully. For example assuming a JSON property has a given type, or your reused Cell has a certain contract. @@ -41,10 +41,10 @@ NSNumber() as? Int // no violation + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_swift_errorprone.html#forcetry"> Force tries should be avoided. If the code being wrapped happens to raise and exception, our application will crash. Consider using a conditional try and handling the resulting optional, or wrapping the try statement in a do-catch block. diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java b/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java index 372e55b422..c4f8c22a46 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java @@ -147,7 +147,7 @@ public abstract class AbstractRuleSetFactoryTest { .append(rule.getName()) .append(" is missing 'externalInfoURL' attribute\n"); } else { - String expectedExternalInfoURL = "https?://pmd.(sourceforge.net|github.io)/.+/pmd_rules_" + String expectedExternalInfoURL = "https://docs.pmd-code.org/.+/pmd_rules_" + language.getTerseName() + "_" + IOUtil.getFilenameBase(fileName) + ".html#" diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index d944cce12f..6de91feef6 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -202,8 +202,9 @@ public abstract class RuleTst { System.out.println(" -> Expected messages: " + test.getExpectedMessages()); System.out.println(" -> Expected line numbers: " + test.getExpectedLineNumbers()); System.out.println(); + StringWriter reportOutput = new StringWriter(); TextRenderer renderer = new TextRenderer(); - renderer.setWriter(new StringWriter()); + renderer.setWriter(reportOutput); try { renderer.start(); renderer.renderFileReport(report); @@ -211,7 +212,7 @@ public abstract class RuleTst { } catch (IOException e) { throw new RuntimeException(e); } - System.out.println(renderer.getWriter().toString()); + System.out.println(reportOutput); System.out.println("--------------------------------------------------------------"); } diff --git a/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/cpd/TSqlTokenizer.java b/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/cpd/TSqlTokenizer.java index 6274dbf6da..9676b37f7c 100644 --- a/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/cpd/TSqlTokenizer.java +++ b/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/cpd/TSqlTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.lang.tsql.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.lang.tsql.ast.TSqlLexer; public class TSqlTokenizer extends AntlrTokenizer { diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java index 17926160b0..d0baf84e24 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer; +import net.sourceforge.pmd.cpd.impl.JavaCCTokenizer; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaEscapeTranslator; diff --git a/pmd-xml/src/main/java/net/sourceforge/pmd/xml/cpd/XmlTokenizer.java b/pmd-xml/src/main/java/net/sourceforge/pmd/xml/cpd/XmlTokenizer.java index 278e8463eb..120b448d09 100644 --- a/pmd-xml/src/main/java/net/sourceforge/pmd/xml/cpd/XmlTokenizer.java +++ b/pmd-xml/src/main/java/net/sourceforge/pmd/xml/cpd/XmlTokenizer.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.xml.cpd; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; +import net.sourceforge.pmd.cpd.impl.AntlrTokenizer; import net.sourceforge.pmd.lang.xml.antlr4.XMLLexer; public class XmlTokenizer extends AntlrTokenizer { diff --git a/pom.xml b/pom.xml index a2b90df0c5..5e4d08f020 100644 --- a/pom.xml +++ b/pom.xml @@ -108,14 +108,14 @@ UTF-8 UTF-8 - https://pmd.github.io/pmd + https://docs.pmd-code.org/snapshot -Xmx512m -Dfile.encoding=${project.build.sourceEncoding} ${extraArgLine} 21 - 7.0.0-SNAPSHOT + 7.0.0-rc1 ${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar ${project.build.directory}/generated-sources/javacc ${project.basedir}/../javacc-wrapper.xml @@ -436,7 +436,7 @@ - true + false 100 1.${java.version} @@ -503,6 +503,11 @@ jacoco-maven-plugin 0.8.8 + + org.cyclonedx + cyclonedx-maven-plugin + 2.7.6 + @@ -624,6 +629,26 @@ https://oss.sonatype.org/ + + org.cyclonedx + cyclonedx-maven-plugin + + + package + + makeAggregateBom + + + + + + + org.ow2.asm + asm + 9.5 + + + @@ -1031,7 +1056,7 @@ pmd-release - https://pmd.github.io/pmd-${project.version} + https://docs.pmd-code.org/pmd-doc-${project.version} @@ -1163,6 +1188,7 @@ pmd-java pmd-javascript pmd-jsp + pmd-julia pmd-kotlin pmd-lang-test pmd-matlab @@ -1185,5 +1211,6 @@ pmd-vm pmd-xml pmd-ant + pmd-languages-deps