CINXE.COM
Modifying Dependency Metadata
<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="Asciidoctor 2.0.23"> <title>Modifying Dependency Metadata</title> <style> /* * Copyright 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Custom Admonition Blocks */ body { --gradle-blue: #209BC4; --gradle-bg-dark: #010002; --gradle-bg-gray: #F8F8F8; --gradle-bg-white: #FFFFFF; --gradle-blue: #209BC4; --gradle-blue-lite: #4DC9C0; --gradle-blue-dark: #1b3262; --gradle-blue-darker: #19274f; --button-gradient-angle: 160deg; --caution-color: #e40046; --caution-on-color: #fff; --important-color: #802392; --important-on-color: #fff; --note-color: #2d7dd2; --note-on-color: #fff; --tip-color: #43b929; --tip-on-color: #fff; --warning-color: #f70; --warning-on-color: #fff; --admonition-background: #fafafa; --doc-icon-filter: invert(14.5%); --rem-base: 18; --black-color: #000; --white-color: #fff; --text-color: #02303A; --title-color: #02303A; --header-color: rgba(0, 0, 0, 0.85); --footer-color: #fff; --footer-other-text-color: #02303; --footer-form-color: #1BA8CB; --code-color: #f7f7f8; --code-text-color: rgba(0, 0, 0, 0.9); --code-link-color: #021274; --num-color: rgba(0, 0, 0, 0.8); --nav-color: #f8f8f7; --table-color: #f7f8f7; --box-shadow-color: rgba(0, 0, 0, .15); --top-header-color: #fff; --footer-white-color: #fff; --footer-text-color: #fff; --quoteblock-color: #7a2518; --menu-burger-color: #fff; --various-border-color: #e7e7e9; } body.dark-theme { --admonition-background: #2a2929; --black-color: #fff; --white-color: #121212; --text-color: #aaa; --title-color: #fff; --header-color: rgba(255, 255, 255, 0.85); --footer-color: #121212; --footer-other-text-color: #ddd; --code-color: #1f1f1f; --code-text-color: rgba(255, 255, 255, 0.9); --code-link-color: #1fafcc; --num-color: #fff; --nav-color: #121212; --table-color: #121212; --box-shadow-color: rgba(255, 255, 255, .15); --top-header-color: #242526; --footer-white-color: #242526; --footer-text-color: #aaa; --footer-form-color: #1BA8CB; --quoteblock-color: #1DA2BD; --menu-burger-color: #242526; --various-border-color: #242526; } @media (prefers-color-scheme: dark) { /* defaults to dark theme */ body { --admonition-background: #2a2929; --black-color: #fff; --white-color: #121212; --text-color: #aaa; --title-color: #fff; --header-color: rgba(255, 255, 255, 0.85); --footer-color: #121212; --footer-other-text-color: #ddd; --code-color: #1f1f1f; --code-text-color: rgba(255, 255, 255, 0.9); --code-link-color: #1fafcc; --num-color: #fff; --nav-color: #121212; --table-color: #121212; --box-shadow-color: rgba(255, 255, 255, .15); --top-header-color: #242526; --footer-white-color: #242526; --footer-text-color: #aaa; --footer-form-color: #1BA8CB; --quoteblock-color: #1DA2BD; --menu-burger-color: #242526; --various-border-color: #242526; } body.light-theme { --gradle-blue: #209BC4; --gradle-bg-dark: #010002; --gradle-bg-gray: #F8F8F8; --gradle-bg-white: #FFFFFF; --gradle-blue: #209BC4; --gradle-blue-lite: #4DC9C0; --gradle-blue-dark: #1b3262; --gradle-blue-darker: #19274f; --button-gradient-angle: 160deg; --caution-color: #e40046; --caution-on-color: #fff; --important-color: #802392; --important-on-color: #fff; --note-color: #2d7dd2; --note-on-color: #fff; --tip-color: #43b929; --tip-on-color: #fff; --warning-color: #f70; --warning-on-color: #fff; --admonition-background: #fafafa; --doc-icon-filter: invert(14.5%); --rem-base: 18; --black-color: #000; --white-color: #fff; --text-color: #02303A; --title-color: #02303A; --header-color: rgba(0, 0, 0, 0.85); --footer-color: #fff; --footer-other-text-color: #02303; --code-color: #f7f7f8; --code-text-color: rgba(0, 0, 0, 0.9); --code-link-color: #021274; --num-color: rgba(0, 0, 0, 0.8); --nav-color: #f8f8f7; --table-color: #f7f8f7; --box-shadow-color: rgba(0, 0, 0, .15); --top-header-color: #fff; --footer-white-color: #fff; --footer-text-color: #fff; --footer-form-color: #1BA8CB; --quoteblock-color: #7a2518; --menu-burger-color: #fff; --various-border-color: #e7e7e9; } } .cls-1 { fill: #02303a; } body.dark-theme { .cls-1 { fill: #fff; } } @media (prefers-color-scheme: dark) { .cls-1 { fill: #fff; } body.light-theme { .cls-1 { fill: #02303a; } } } /* Lato (normal, regular) */ @font-face { font-family: Lato; font-weight: 400; font-style: normal; src: url("https://assets.gradle.com/lato/fonts/lato-normal/lato-normal.woff2") format("woff2"), url("https://assets.gradle.com/lato/fonts/lato-normal/lato-normal.woff") format("woff"); } /* Lato (normal, italic) */ @font-face { font-display: swap; font-family: Lato; font-weight: 400; font-style: italic; src: url("https://assets.gradle.com/lato/fonts/lato-normal-italic/lato-normal-italic.woff2") format("woff2"), url("https://assets.gradle.com/lato/fonts/lato-normal-italic/lato-normal-italic.woff") format("woff"); } /* Lato (bold, regular) */ @font-face { font-display: swap; font-family: Lato; font-weight: 500; font-style: normal; src: url("https://assets.gradle.com/lato/fonts/lato-semibold/lato-semibold.woff2") format("woff2"), url("https://assets.gradle.com/lato/fonts/lato-semibold/lato-semibold.woff") format("woff"); } /* Lato (bold, regular) */ @font-face { font-display: swap; font-family: Lato; font-weight: 800; font-style: normal; src: url("https://assets.gradle.com/lato/fonts/lato-heavy/lato-heavy.woff2") format("woff2"), url("https://assets.gradle.com/lato/fonts/lato-heavy/lato-heavy.woff") format("woff"); } /* BEGIN asciidoc.css */ /*! normalize.css v2.1.2 | MIT License | git.io/normalize */ /* ========================================================================== HTML5 display definitions ========================================================================== */ /** Correct `block` display not defined in IE 8/9. */ article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } /** Correct `inline-block` display not defined in IE 8/9. */ audio, canvas, video { display: inline-block; } /** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */ [hidden], template { display: none; } script { display: none !important; } /* ========================================================================== Base ========================================================================== */ /** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */ html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /** Remove default margin. */ body { margin: 0; } /* ========================================================================== Links ========================================================================== */ /** Remove the gray background color from active links in IE 10. */ a { background: transparent; } /** Address `outline` inconsistency between Chrome and other browsers. */ a:focus { outline: thin dotted; } /** Improve readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* ========================================================================== Typography ========================================================================== */ /** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */ h1 { font-size: 2em; margin: 0.67em 0; } /** Address styling not present in IE 8/9, Safari 5, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */ b, strong { font-weight: bold; } /** Address styling not present in Safari 5 and Chrome. */ dfn { font-style: italic; } /** Address differences between Firefox and other browsers. */ hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } /** Address styling not present in IE 8/9. */ mark { background: #ff0; color: var(--black-color); } /** Correct font family set oddly in Safari 5 and Chrome. */ code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } /** Improve readability of pre-formatted text in all browsers. */ pre { white-space: pre-wrap; } /** Set consistent quote types. */ q { quotes: "\201C""\201D""\2018""\2019"; } /** Address inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /** Prevent `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* ========================================================================== Embedded content ========================================================================== */ /** Remove border when inside `a` element in IE 8/9. */ img { border: 0; } /** Correct overflow displayed oddly in IE 9. */ svg:not(:root) { overflow: hidden; } /* ========================================================================== Figures ========================================================================== */ /** Address margin not present in IE 8/9 and Safari 5. */ figure { margin: 0; } /* ========================================================================== Forms ========================================================================== */ /** Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */ button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ } /** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */ button, input { line-height: normal; } /** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */ button, select { text-transform: none; } /** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */ button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /** Re-set default cursor for disabled elements. */ button[disabled], html input[disabled] { cursor: default; } /** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** Remove inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */ textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ } /* ========================================================================== Tables ========================================================================== */ /** Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; } meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; } meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; } meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; } *, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } html, body { font-size: 100%; } body { background: var(--white-color); color: var(--num-color); padding: 0; margin: 0; font-family: "Noto Serif", "DejaVu Serif", serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; } a:hover { cursor: pointer; } img, object, embed { max-width: 100%; height: auto; } object, embed { height: 100%; } img { -ms-interpolation-mode: bicubic; } #map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; } .left { float: left !important; } .right { float: right !important; } .text-left { text-align: left !important; } .text-right { text-align: right !important; } .text-center { text-align: center !important; } .text-justify { text-align: justify !important; } .hide { display: none; } .antialiased { -webkit-font-smoothing: antialiased; } img { display: inline-block; vertical-align: middle; } textarea { height: auto; min-height: 50px; } select { width: 100%; } object, svg { display: inline-block; vertical-align: middle; } .center { margin-left: auto; margin-right: auto; } .spread { width: 100%; } p.lead, .paragraph.lead>p, #preamble>.sectionbody>.paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; } .subheader, .admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title { line-height: 1.45; color: #7a2518; font-weight: normal; margin-top: 0; margin-bottom: 0.25em; } /* Typography resets */ div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock>.content>.title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; } /* Default Link Styles */ a { color: #2156a5; text-decoration: underline; line-height: inherit; } a:hover, a:focus { color: #1d4b8f; } a img { border: none; } /* Default paragraph styles */ p { font-family: inherit; font-weight: normal; font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; text-rendering: optimizeLegibility; } p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; } /* Default header styles */ h1, h2, h3, #toctitle, .sidebarblock>.content>.title, h4, h5, h6 { font-family: "Open Sans", "DejaVu Sans", sans-serif; font-weight: 300; font-style: normal; color: #ba3925; text-rendering: optimizeLegibility; margin-top: 1em; margin-bottom: 0.5em; line-height: 1.0125em; } h1 small, h2 small, h3 small, #toctitle small, .sidebarblock>.content>.title small, h4 small, h5 small, h6 small { font-size: 60%; color: #e99b8f; line-height: 0; } h1 { font-size: 2.125em; } h2 { font-size: 1.6875em; } h3, #toctitle, .sidebarblock>.content>.title { font-size: 1.375em; } h4 { font-size: 1.125em; } h5 { font-size: 1.125em; } h6 { font-size: 1em; } hr { border: solid #ddddd8; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; } /* Helpful Typography Defaults */ em, i { font-style: italic; line-height: inherit; } strong, b { font-weight: bold; line-height: inherit; } small { font-size: 60%; line-height: inherit; } code { font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; font-weight: normal; color: var(--code-text-color); } a code { color: var(--code-link-color); } /* Lists */ ul, ol, dl { font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; list-style-position: outside; font-family: inherit; } ul, ol { margin-left: 1.5em; } ul.no-bullet, ol.no-bullet { margin-left: 1.5em; } /* Unordered Lists */ ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ } ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; } ul.square { list-style-type: square; } ul.circle { list-style-type: circle; } ul.disc { list-style-type: disc; } ul.no-bullet { list-style: none; } /* Ordered Lists */ ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; } /* Definition Lists */ dl dt { margin-bottom: 0.3125em; font-weight: bold; } dl dd { margin-bottom: 1.25em; } /* Abbreviations */ abbr, acronym { text-transform: uppercase; font-size: 90%; color: var(--num-color); border-bottom: 1px dotted #dddddd; cursor: help; } abbr { text-transform: none; } /* Blockquotes */ blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; } blockquote cite { display: block; font-size: 0.9375em; color: rgba(0, 0, 0, 0.6); } blockquote cite:before { content: "\2014 \0020"; } blockquote cite a, blockquote cite a:visited { color: rgba(0, 0, 0, 0.6); } blockquote, blockquote p { line-height: 1.6; color: var(--header-color); } /* Microformats */ .vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; } .vcard li { margin: 0; display: block; } .vcard .fn { font-weight: bold; font-size: 0.9375em; } .vevent .summary { font-weight: bold; } .vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; } @media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock>.content>.title, h4, h5, h6 { line-height: 1.2; } h1 { font-size: 2.75em; } h2 { font-size: 2.3125em; } h3, #toctitle, .sidebarblock>.content>.title { font-size: 1.6875em; } h4 { font-size: 1.4375em; } } /* Tables */ table { background: var(--white-color); margin-bottom: 1.25em; border: solid 1px #dedede; } table thead, table tfoot { background: var(--table-color); font-weight: bold; } table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: var(--num-color); text-align: left; } table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: var(--num-color); } table tr.even, table tr.alt, table tr:nth-of-type(even) { background: var(--nav-color); } table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.6; } body { tab-size: 4; } h1, h2, h3, #toctitle, .sidebarblock>.content>.title, h4, h5, h6 { line-height: 1.2; word-spacing: -0.05em; } h1 strong, h2 strong, h3 strong, #toctitle strong, .sidebarblock>.content>.title strong, h4 strong, h5 strong, h6 strong { font-weight: 400; } .clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; } .clearfix:after, .float-group:after { clear: both; } *:not(pre)>code { font-size: 0.9375em; font-style: normal !important; letter-spacing: 0; padding: 0.1em 0.5ex; word-spacing: -0.15em; background-color: var(--code-color); -webkit-border-radius: 4px; border-radius: 4px; line-height: 1.45; text-rendering: optimizeSpeed; word-wrap: break-word; } *:not(pre)>code.nobreak { word-wrap: normal; } *:not(pre)>code.nowrap { white-space: nowrap; } pre, pre>code { line-height: 1.45; color: var(--code-text-color); font-family: "Droid Sans Mono", "DejaVu Sans Mono", "Monospace", monospace; font-weight: normal; text-rendering: optimizeSpeed; } em em { font-style: normal; } strong strong { font-weight: normal; } .keyseq { color: rgba(51, 51, 51, 0.8); } kbd { font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; display: inline-block; color: var(--num-color); font-size: 0.65em; line-height: 1.45; background-color: #f7f7f7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; margin: 0 0.15em; padding: 0.2em 0.5em; vertical-align: middle; position: relative; top: -0.1em; white-space: nowrap; } .keyseq kbd:first-child { margin-left: 0; } .keyseq kbd:last-child { margin-right: 0; } .menuseq, .menu { color: var(--num-color); } b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; } b.button:before { content: "["; padding: 0 3px 0 2px; } b.button:after { content: "]"; padding: 0 2px 0 3px; } p a>code:hover { color: var(--code-text-color); } #header, #content, #footnotes, #footer { width: 100%; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: 0; max-width: 62.5em; *zoom: 1; position: relative; padding-left: 0.9375em; padding-right: 0.9375em; } #header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; } #header:after, #content:after, #footnotes:after, #footer:after { clear: both; } #content { margin-top: 1.25em; } #content:before { content: none; } #header>h1:first-child { color: var(--header-color); margin-top: 2.25rem; margin-bottom: 0; } #header>h1:first-child+#toc { margin-top: 8px; border-top: 1px solid #ddddd8; } #header>h1:only-child, body.toc2 #header>h1:nth-last-child(2) { border-bottom: 1px solid #ddddd8; padding-bottom: 8px; } #header .details { border-bottom: 1px solid #ddddd8; line-height: 1.45; padding-top: 0.25em; padding-bottom: 0.25em; padding-left: 0.25em; color: rgba(0, 0, 0, 0.6); display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; } #header .details span:first-child { margin-left: -0.125em; } #header .details span.email a { color: var(--header-color); } #header .details br { display: none; } #header .details br+span:before { content: "\00a0\2013\00a0"; } #header .details br+span.author:before { content: "\00a0\22c5\00a0"; color: var(--header-color); } #header .details br+span#revremark:before { content: "\00a0|\00a0"; } #header #revnumber { text-transform: capitalize; } #header #revnumber:after { content: "\00a0"; } #content>h1:first-child:not([class]) { color: var(--header-color); border-bottom: 1px solid #ddddd8; padding-bottom: 8px; margin-top: 0; padding-top: 1rem; margin-bottom: 1.25rem; } #toc { border-bottom: 1px solid #efefed; padding-bottom: 0.5em; } #toc>ul { margin-left: 0.125em; } #toc ul.sectlevel0>li>a { font-style: italic; } #toc ul.sectlevel0 ul.sectlevel1 { margin: 0.5em 0; } #toc ul { font-family: "Open Sans", "DejaVu Sans", sans-serif; list-style-type: none; } #toc li { line-height: 1.3334; margin-top: 0.3334em; } #toc a { text-decoration: none; } #toc a:active { text-decoration: underline; } #toctitle { color: #7a2518; font-size: 1.2em; } @media only screen and (min-width: 768px) { #toctitle { font-size: 1.375em; } body.toc2 { padding-left: 15em; padding-right: 0; } #toc.toc2 { margin-top: 0 !important; background-color: var(--nav-color); position: fixed; width: 15em; left: 0; top: 0; border-right: 1px solid #efefed; border-top-width: 0 !important; border-bottom-width: 0 !important; z-index: 1000; padding: 1.25em 1em; height: 100%; overflow: auto; } #toc.toc2 #toctitle { margin-top: 0; margin-bottom: 0.8rem; font-size: 1.2em; } #toc.toc2>ul { font-size: 0.9em; margin-bottom: 0; } #toc.toc2 ul ul { margin-left: 0; padding-left: 1em; } #toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; } body.toc2.toc-right { padding-left: 0; padding-right: 15em; } body.toc2.toc-right #toc.toc2 { border-right-width: 0; border-left: 1px solid #efefed; left: auto; right: 0; } } @media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; padding-right: 0; } #toc.toc2 { width: 20em; } #toc.toc2 #toctitle { font-size: 1.375em; } #toc.toc2>ul { font-size: 0.95em; } #toc.toc2 ul ul { padding-left: 1.25em; } body.toc2.toc-right { padding-left: 0; padding-right: 20em; } } #content #toc { border-style: solid; border-width: 1px; border-color: #e0e0dc; margin-bottom: 1.25em; padding: 1.25em; background: var(--nav-color); -webkit-border-radius: 4px; border-radius: 4px; } #content #toc> :first-child { margin-top: 0; } #content #toc> :last-child { margin-bottom: 0; } #footer { max-width: 100%; background-color: var(--num-color); padding: 1.25em; } #footer-text { color: rgba(255, 255, 255, 0.8); line-height: 1.44; } .sect1 { padding-bottom: 0.625em; } @media only screen and (min-width: 768px) { .sect1 { padding-bottom: 1.25em; } } .sect1+.sect1 { border-top: 1px solid #efefed; } #content h1>a.anchor, h2>a.anchor, h3>a.anchor, #toctitle>a.anchor, .sidebarblock>.content>.title>a.anchor, h4>a.anchor, h5>a.anchor, h6>a.anchor { position: absolute; z-index: 1001; width: 1.5ex; margin-left: -1.5ex; display: block; text-decoration: none !important; visibility: hidden; text-align: center; font-weight: normal; } #content h1>a.anchor:before, h2>a.anchor:before, h3>a.anchor:before, #toctitle>a.anchor:before, .sidebarblock>.content>.title>a.anchor:before, h4>a.anchor:before, h5>a.anchor:before, h6>a.anchor:before { content: "\00A7"; font-size: 0.85em; display: block; padding-top: 0.1em; } #content h1:hover>a.anchor, #content h1>a.anchor:hover, h2:hover>a.anchor, h2>a.anchor:hover, h3:hover>a.anchor, #toctitle:hover>a.anchor, .sidebarblock>.content>.title:hover>a.anchor, h3>a.anchor:hover, #toctitle>a.anchor:hover, .sidebarblock>.content>.title>a.anchor:hover, h4:hover>a.anchor, h4>a.anchor:hover, h5:hover>a.anchor, h5>a.anchor:hover, h6:hover>a.anchor, h6>a.anchor:hover { visibility: visible; } #content h1>a.link, h2>a.link, h3>a.link, #toctitle>a.link, .sidebarblock>.content>.title>a.link, h4>a.link, h5>a.link, h6>a.link { color: #ba3925; text-decoration: none; } #content h1>a.link:hover, h2>a.link:hover, h3>a.link:hover, #toctitle>a.link:hover, .sidebarblock>.content>.title>a.link:hover, h4>a.link:hover, h5>a.link:hover, h6>a.link:hover { color: #a53221; } .audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { margin-bottom: 1.25em; } .admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title { text-rendering: optimizeLegibility; text-align: left; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 1rem; font-style: italic; } table.tableblock>caption.title { white-space: nowrap; overflow: visible; max-width: 0; } .paragraph.lead>p, #preamble>.sectionbody>.paragraph:first-of-type p { color: var(--header-color); } table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p { font-size: inherit; } /* Custom SVG logos coloring */ path { fill: #02303A; } body.dark-theme { path { fill: white; } } @media (prefers-color-scheme: dark) { path { fill: white; } body.light-theme { path { fill: #02303A; } } } /* Custom scroll bar */ /* Works on Firefox */ .docs-navigation { scrollbar-width: auto; scrollbar-color: #686868 #e7e7e9; } /* Works on Chrome, Edge, and Safari */ .docs-navigation::-webkit-scrollbar { width: 12px; } .docs-navigation::-webkit-scrollbar-track { background: #e7e7e9; } .docs-navigation::-webkit-scrollbar-thumb { background-color: #686868; border-radius: 20px; border: 3px #686868; } body.dark-theme { /* Works on Firefox */ * { scrollbar-width: auto; scrollbar-color: #686868 #242526; } /* Works on Chrome, Edge, and Safari */ *::-webkit-scrollbar { width: auto; } *::-webkit-scrollbar-track { background: #242526; } *::-webkit-scrollbar-thumb { background-color: #686868; border-radius: 20px; border: 3px #686868; } } @media (prefers-color-scheme: dark) { /* Works on Firefox */ * { scrollbar-width: auto; scrollbar-color: #686868 #242526; } /* Works on Chrome, Edge, and Safari */ *::-webkit-scrollbar { width: auto; } *::-webkit-scrollbar-track { background: #242526; } *::-webkit-scrollbar-thumb { background-color: #686868; border-radius: 20px; border: 3px #686868; } body.light-theme { .docs-navigation { scrollbar-width: auto; scrollbar-color: #686868 #e7e7e9; } /* Works on Chrome, Edge, and Safari */ .docs-navigation::-webkit-scrollbar { width: 12px; } .docs-navigation::-webkit-scrollbar-track { background: #e7e7e9; } .docs-navigation::-webkit-scrollbar-thumb { background-color: #686868; border-radius: 20px; border: 3px #686868; } } } /* Custom Admonition Blocks - Icons from https://github.com/primer/octicons */ .admonitionblock td div:last-of-type p { margin-bottom: 0em !important; } .admonitionblock { margin: 1.4rem 0 0 } .admonitionblock i { font-family: inherit; } .admonitionblock i.fa { background: no-repeat 50%/1em 1em; display: inline-block; filter: var(--doc-icon-filter); font-style: normal; height: 1em; -webkit-hyphens: none; hyphens: none; vertical-align: -.125em; width: 1em } .admonitionblock p, .admonitionblock td.content { font-size: 1rem; } .admonitionblock td.content>.title+*, .admonitionblock td.content>:not(.title):first-child { margin-top: 0 } .admonitionblock pre { font-size: calc(15/var(--rem-base)*1rem) } .admonitionblock>table { position: relative; table-layout: fixed; border: none; width: 100% } .admonitionblock td.content { word-wrap: anywhere; background: var(--admonition-background); padding: 1rem 1rem 1rem 1rem; width: 100%; border-radius: 4px; } .admonitionblock td.icon { background: linear-gradient(90deg, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .2)) no-repeat 0 /2.075em 100%; border-radius: .5em; font-size: calc(15/var(--rem-base)*1rem); left: 0; line-height: 1; padding: .25em .075em; position: absolute; top: 0; transform: translate(-.5rem, -50%) } .admonitionblock td.icon i { align-items: center; background-position-x: .5em; display: inline-flex; filter: invert(100%); padding-left: 2em; vertical-align: initial; width: auto } .admonitionblock td.icon i::after { content: attr(title); filter: invert(100%); font-style: normal; font-weight: bold; margin: -.05em; padding: 0 .5em; text-transform: uppercase } .admonitionblock.caution td.icon { background-color: var(--caution-color); color: var(--caution-on-color) } .admonitionblock.caution td.icon i { background-image: url(./img/octicons-16.svg#view-flame) } .admonitionblock.important td.icon { background-color: var(--important-color); color: var(--important-on-color) } .admonitionblock.important td.icon i { background-image: url(./img/octicons-16.svg#view-stop) } .admonitionblock.note td.icon { background-color: var(--note-color); color: var(--note-on-color) } .admonitionblock.note td.icon i { background-image: url(./img/octicons-16.svg#view-info) } .admonitionblock.tip td.icon { background-color: var(--tip-color); color: var(--tip-on-color) } .admonitionblock.tip td.icon i { background-image: url(./img/octicons-16.svg#view-light-bulb) } .admonitionblock.warning td.icon { background-color: var(--warning-color); color: var(--warning-on-color) } .admonitionblock.warning td.icon i { background-image: url(./img/octicons-16.svg#view-alert) } /* Custom collapsible block */ details summary { width: 100%; padding: 1rem 0; border-top: 1px solid gray; position: relative; cursor: pointer; list-style: none; } details summary:after { content: "+"; color: var(--black-color); position: absolute; font-size: 1.75rem; line-height: 0; margin-top: 0.3rem; right: 0; font-weight: 400; transform-origin: center; transition: 200ms linear; } details[open] summary:after { transform: rotate(45deg); font-size: 2rem; } details summary { outline: 0; } details p { font-size: 0.95rem; margin: 0 0 1rem; padding-top: 1rem; } .exampleblock>.content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: var(--white-color); -webkit-border-radius: 4px; border-radius: 4px; } .exampleblock>.content> :first-child { margin-top: 0; } .exampleblock>.content> :last-child { margin-bottom: 0; } .sidebarblock { border-style: solid; border-width: 1px; border-color: #e0e0dc; margin-bottom: 1.25em; padding: 1.25em; background: var(--nav-color); -webkit-border-radius: 4px; border-radius: 4px; } .sidebarblock> :first-child { margin-top: 0; } .sidebarblock> :last-child { margin-bottom: 0; } .sidebarblock>.content>.title { color: #7a2518; margin-top: 0; text-align: center; } .exampleblock>.content> :last-child> :last-child, .exampleblock>.content .olist>ol>li:last-child> :last-child, .exampleblock>.content .ulist>ul>li:last-child> :last-child, .exampleblock>.content .qlist>ol>li:last-child> :last-child, .sidebarblock>.content> :last-child> :last-child, .sidebarblock>.content .olist>ol>li:last-child> :last-child, .sidebarblock>.content .ulist>ul>li:last-child> :last-child, .sidebarblock>.content .qlist>ol>li:last-child> :last-child { margin-bottom: 0; } .literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { background: var(--code-color); } .sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { background: #f2f1f1; } .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { -webkit-border-radius: 4px; border-radius: 4px; word-wrap: break-word; padding: 1em; font-size: 0.8125em; } .literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; } @media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.90625em; } } @media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 1em; } } .literalblock.output pre { color: var(--code-color); background-color: var(--code-text-color); } .listingblock pre.highlightjs { padding: 0; } .listingblock pre.highlightjs>code { padding: 1em; -webkit-border-radius: 4px; border-radius: 4px; } .listingblock pre.prettyprint { border-width: 0; } .listingblock>.content { position: relative; } .listingblock code[data-lang]:before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; right: 0.5rem; line-height: 1; text-transform: uppercase; color: #999; } .listingblock:hover code[data-lang]:before { display: block; } .listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; } .listingblock.terminal pre .command:not([data-prompt]):before { content: "$"; } table.pyhltable { border-collapse: separate; border: 0; margin-bottom: 0; background: none; } table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; line-height: 1.45; } table.pyhltable td.code { padding-left: .75em; padding-right: 0; } pre.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #ddddd8; } pre.pygments .lineno { display: inline-block; margin-right: .25em; } table.pyhltable .linenodiv { background: none !important; padding-right: 0 !important; } .quoteblock { margin: 0 1em 1.25em 1.5em; display: table; } .quoteblock>.title { margin-left: -1.5em; margin-bottom: 0.75em; } .quoteblock blockquote, .quoteblock blockquote p { color: var(--header-color); font-size: 1.15rem; line-height: 1.75; word-spacing: 0.1em; letter-spacing: 0; font-style: italic; text-align: justify; } .quoteblock blockquote { margin: 0; padding: 0; border: 0; } .quoteblock blockquote:before { content: "\201c"; float: left; font-size: 2.75em; font-weight: bold; line-height: 0.6em; margin-left: -0.6em; color: var(--quoteblock-color); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .quoteblock blockquote>.paragraph:last-child p { margin-bottom: 0; } .quoteblock .attribution { margin-top: 0.5em; margin-right: 0.5ex; text-align: right; } .quoteblock .quoteblock { margin-left: 0; margin-right: 0; padding: 0.5em 0; border-left: 3px solid rgba(0, 0, 0, 0.6); } .quoteblock .quoteblock blockquote { padding: 0 0 0 0.75em; } .quoteblock .quoteblock blockquote:before { display: none; } .verseblock { margin: 0 1em 1.25em 1em; } .verseblock pre { font-family: "Open Sans", "DejaVu Sans", sans; font-size: 1.15rem; color: var(--header-color); font-weight: 300; text-rendering: optimizeLegibility; } .verseblock pre strong { font-weight: 400; } .verseblock .attribution { margin-top: 1.25rem; margin-left: 0.5ex; } .quoteblock .attribution, .verseblock .attribution { font-size: 0.9375em; line-height: 1.45; font-style: italic; } .quoteblock .attribution br, .verseblock .attribution br { display: none; } .quoteblock .attribution cite, .verseblock .attribution cite { display: block; letter-spacing: -0.025em; color: rgba(0, 0, 0, 0.6); } .quoteblock.abstract { margin: 0 0 1.25em 0; display: block; } .quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { text-align: left; word-spacing: 0; } .quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { display: none; } table.tableblock { max-width: 100%; border-collapse: separate; } table.tableblock td>.paragraph:last-child p>p:last-child, table.tableblock th>p:last-child, table.tableblock td>p:last-child { margin-bottom: 0; } table.tableblock, th.tableblock, td.tableblock { border: 0 solid #dedede; } table.grid-all th.tableblock, table.grid-all td.tableblock { border-width: 0 1px 1px 0; } table.grid-all tfoot>tr>th.tableblock, table.grid-all tfoot>tr>td.tableblock { border-width: 1px 1px 0 0; } table.grid-cols th.tableblock, table.grid-cols td.tableblock { border-width: 0 1px 0 0; } table.grid-all *>tr>.tableblock:last-child, table.grid-cols *>tr>.tableblock:last-child { border-right-width: 0; } table.grid-rows th.tableblock, table.grid-rows td.tableblock { border-width: 0 0 1px 0; } table.grid-all tbody>tr:last-child>th.tableblock, table.grid-all tbody>tr:last-child>td.tableblock, table.grid-all thead:last-child>tr>th.tableblock, table.grid-rows tbody>tr:last-child>th.tableblock, table.grid-rows tbody>tr:last-child>td.tableblock, table.grid-rows thead:last-child>tr>th.tableblock { border-bottom-width: 0; } table.grid-rows tfoot>tr>th.tableblock, table.grid-rows tfoot>tr>td.tableblock { border-width: 1px 0 0 0; } table.frame-all { border-width: 1px; } table.frame-sides { border-width: 0 1px; } table.frame-topbot { border-width: 1px 0; } th.halign-left, td.halign-left { text-align: left; } th.halign-right, td.halign-right { text-align: right; } th.halign-center, td.halign-center { text-align: center; } th.valign-top, td.valign-top { vertical-align: top; } th.valign-bottom, td.valign-bottom { vertical-align: bottom; } th.valign-middle, td.valign-middle { vertical-align: middle; } table thead th, table tfoot th { font-weight: bold; } tbody tr th { display: table-cell; line-height: 1.6; background: var(--table-color); } tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: var(--num-color); font-weight: bold; } p.tableblock>code:only-child { background: none; padding: 0; } p.tableblock { font-size: 1em; } td>div.verse { white-space: pre; } ol { margin-left: 1.75em; } ul li ol { margin-left: 1.5em; } dl dd { margin-left: 1.125em; } dl dd:last-child, dl dd:last-child> :last-child { margin-bottom: 0; } ol>li p, ul>li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.625em; } ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; } ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; } ul.checklist li>p:first-child>.fa-square-o:first-child, ul.checklist li>p:first-child>.fa-check-square-o:first-child { width: 1em; font-size: 0.85em; } ul.checklist li>p:first-child>input[type="checkbox"]:first-child { width: 1em; position: relative; top: 1px; } ul.inline { margin: 0 auto 0.625em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; } ul.inline>li { list-style: none; float: left; margin-left: 1.375em; display: block; } ul.inline>li>* { display: block; } .unstyled dl dt { font-weight: normal; font-style: normal; } ol.arabic { list-style-type: decimal; } ol.decimal { list-style-type: decimal-leading-zero; } ol.loweralpha { list-style-type: lower-alpha; } ol.upperalpha { list-style-type: upper-alpha; } ol.lowerroman { list-style-type: lower-roman; } ol.upperroman { list-style-type: upper-roman; } ol.lowergreek { list-style-type: lower-greek; } .hdlist>table, .colist>table { border: 0; background: none; } .hdlist>table>tbody>tr, .colist>table>tbody>tr { background: none; } td.hdlist1, td.hdlist2 { vertical-align: top; padding: 0 0.625em; } td.hdlist1 { font-weight: bold; padding-bottom: 1.25em; } .literalblock+.colist { margin-top: -0.5em; } .colist>table tr>td:first-of-type { padding: 0 0.75em; line-height: 1; } .colist>table tr>td:first-of-type img { max-width: initial; } .colist>table tr>td:last-of-type { padding: 0.25em 0; } .thumb, .th { line-height: 0; display: inline-block; border: solid 4px var(--white-color); -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; } .imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; } .imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; } .imageblock>.title { margin-bottom: 0; } .imageblock.thumb, .imageblock.th { border-width: 6px; } .imageblock.thumb>.title, .imageblock.th>.title { padding: 0 0.125em; } .image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; } .image.left { margin-right: 0.625em; } .image.right { margin-left: 0.625em; } a.image { text-decoration: none; display: inline-block; } a.image object { pointer-events: none; } sup.footnote, sup.footnoteref { font-size: 0.875em; position: static; vertical-align: super; } sup.footnote a, sup.footnoteref a { text-decoration: none; } sup.footnote a:active, sup.footnoteref a:active { text-decoration: underline; } #footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; } #footnotes hr { width: 20%; min-width: 6.25em; margin: -0.25em 0 0.75em 0; border-width: 1px 0 0 0; } #footnotes .footnote { padding: 0 0.375em 0 0.225em; line-height: 1.3334; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.05em; margin-bottom: 0.2em; } #footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; } #footnotes .footnote:last-of-type { margin-bottom: 0; } #content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; } .gist .file-data>table { border: 0; background: var(--white-color); width: 100%; margin-bottom: 0; } .gist .file-data>table td.line-data { width: 99%; } div.unbreakable { page-break-inside: avoid; } .big { font-size: larger; } .small { font-size: smaller; } .underline { text-decoration: underline; } .overline { text-decoration: overline; } .line-through { text-decoration: line-through; } .green { color: #006000; } .red { color: #bf0000; } .yellow { color: #bfbf00; } span.icon>.fa { cursor: default; } .conum[data-value] { display: inline-block; color: var(--white-color) !important; background-color: var(--num-color); -webkit-border-radius: 100px; border-radius: 100px; text-align: center; font-size: 0.75em; width: 1.67em; height: 1.67em; line-height: 1.67em; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-style: normal; font-weight: bold; } .conum[data-value] * { color: var(--white-color) !important; } .conum[data-value]+b { display: none; } .conum[data-value]:after { content: attr(data-value); } pre .conum[data-value] { position: relative; top: -0.125em; } b.conum * { color: inherit !important; } .conum:not([data-value]):empty { display: none; } dt, th.tableblock, td.content, div.footnote { text-rendering: optimizeLegibility; } h1, h2, p, td.content, span.alt { letter-spacing: -0.01em; } p strong, td.content strong, div.footnote strong { letter-spacing: -0.005em; } p, blockquote, dt, td.content, span.alt { font-size: 1.0625rem; } p { margin-bottom: 1.25rem; } .sidebarblock p, .sidebarblock dt, .sidebarblock td.content, p.tableblock { font-size: 1em; } .exampleblock>.content { background-color: #fffef7; border-color: #e0e0dc; -webkit-box-shadow: 0 1px 4px #e0e0dc; box-shadow: 0 1px 4px #e0e0dc; } .print-only { display: none !important; } @media print { @page { margin: 1.25cm 0.75cm; } * { -webkit-box-shadow: none !important; box-shadow: none !important; text-shadow: none !important; } a { color: inherit !important; text-decoration: underline !important; } a.bare, a[href^="#"], a[href^="mailto:"] { text-decoration: none !important; } a[href^="http:"]:not(.bare):after, a[href^="https:"]:not(.bare):after { content: "(" attr(href) ")"; display: inline-block; font-size: 0.875em; padding-left: 0.25em; } abbr[title]:after { content: " (" attr(title) ")"; } pre, blockquote, tr, img, object, svg { page-break-inside: avoid; } thead { display: table-header-group; } svg { max-width: 100%; } p, blockquote, dt, td.content { font-size: 1em; orphans: 3; widows: 3; } h2, h3, #toctitle, .sidebarblock>.content>.title, #toctitle, .sidebarblock>.content>.title { page-break-after: avoid; } #toc, .sidebarblock, .exampleblock>.content { background: none !important; } #toc { border-bottom: 1px solid #ddddd8 !important; padding-bottom: 0 !important; } .sect1 { padding-bottom: 0 !important; } .sect1+.sect1 { border: 0 !important; } #header>h1:first-child { margin-top: 1.25rem; } body.book #header { text-align: center; } body.book #header>h1:first-child { border: 0 !important; margin: 2.5em 0 1em 0; } body.book #header .details { border: 0 !important; display: block; padding: 0 !important; } body.book #header .details span:first-child { margin-left: 0 !important; } body.book #header .details br { display: block; } body.book #header .details br+span:before { content: none !important; } body.book #toc { border: 0 !important; text-align: left !important; padding: 0 !important; margin: 0 !important; } body.book #toc, body.book #preamble, body.book h1.sect0, body.book .sect1>h2 { page-break-before: always; } .listingblock code[data-lang]:before { display: block; } #footer { background: none !important; padding: 0 0.9375em; } #footer-text { color: rgba(0, 0, 0, 0.6) !important; font-size: 0.9em; } .hide-on-print { display: none !important; } .print-only { display: block !important; } .hide-for-print { display: none !important; } .show-for-print { display: inherit !important; } } /* END asciidoc.css */ html, body { margin: 0; padding: 0; } html { font-size: 16px; font-weight: 400; line-height: 1.5; } body { color: var(--text-color); background-color: var(--white-color); font-family: "Lato", "Helvetica Neue", Arial, sans-serif; line-height: 1.5; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } /* Links */ a { color: #1DA2BD; text-decoration: none; } a:hover, a:focus { text-decoration: underline; } #content a[href^='../dsl/'], #content a[href^='../kotlin-dsl/'], #content a[href^='../javadoc/'] { font-family: 'Inconsolata', monospace; font-style: normal; border-bottom: 1px dotted rgba(29, 162, 189, 0.5); padding: 0 1px; } #content a[href^='../dsl/']:hover, #content a[href^='../dsl/']:focus, #content a[href^='../kotlin-dsl/']:hover, #content a[href^='../kotlin-dsl/']:focus, #content a[href^='../javadoc/']:hover, #content a[href^='../javadoc/']:focus { text-decoration: none; } /* Copy */ p { font-size: 1rem; } pre, pre>code, code { font-family: 'Inconsolata', monospace; } h1, h2, h3, h4, h5, h6, #toctitle, .sidebarblock>.content>.title { font-family: inherit; font-weight: 500; color: inherit; } h1 { font-size: 2rem; } h2 { font-size: 1.5rem; } h3 { font-size: 1.125rem; } h4 { font-size: 1.0625rem; } h5, h6 { font-size: 1rem; } b, strong { font-weight: 500; } dl { margin: 0 0 1.25rem 1.5rem; } .dlist dt code { color: var(--text-color); font-size: 1em; font-weight: bold; } .dlist p { margin-bottom: 0.625rem; } .sr-only { border: 0; clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } /* Layout */ .main-content>.appendix, .main-content>.book, .main-content>.chapter, .main-content>.footer { background-color: var(--white-color); border-radius: 5px; max-width: 45rem; padding: 1.5rem; } @media screen and (max-width: 45em) { .footer { max-width: 100%; } .main-content>.appendix, .main-content>.book, .main-content>.chapter { margin-top: 0; margin-bottom: 0; } } /* Override asciidoc styles */ #header { position: static; } #header, #content { padding: 0; } #header .details { /* TODO: Pretty sure there's a way to avoid Asciidoc generating details */ display: none; } p { color: var(--text-color); } h1, h2, p, p strong, td.content, td.content strong, div.footnote strong, span.alt { letter-spacing: normal; } .subheader, .admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title { color: inherit; font-family: inherit; } .listingblock .title, .listingblock .title code { font-style: normal; font-weight: bold; } .imageblock, .videoblock { padding: 0.25em; } p.lead, .paragraph.lead>p, #preamble>.sectionbody>.paragraph:first-of-type p { font-size: 1.0625rem; } .paragraph.lead>p, #preamble>.sectionbody>.paragraph:first-of-type p { color: inherit; } .sect1 { padding-bottom: 0; } .sect1+.sect1 { border: 0 none; } .verseblock pre { font-family: "Lato", Arial, sans-serif; } td.hdlist1 { padding-bottom: 0.625rem; } td.hdlist2 p { margin-bottom: 0.625rem; } body.book #header>h1 { border: 0; } #header>h1:first-child { margin-top: 0; } #content a.link { color: var(--title-color); } .highlight .com { color: #777; } .listingblock pre.highlightjs>code { overflow-x: auto; } .listingblock pre.highlight { overflow-x: auto; } .listingblock pre.highlight>code { white-space: pre; } .conum[data-value] { font-family: "Lato", Arial, sans-serif; } .colist>table tr>td:first-of-type { padding-top: 0.25em; padding-bottom: 0.25em; line-height: 1.4; vertical-align: baseline; } /* * Samples */ .exampleblock>.content { background-color: inherit; border: 0 none; box-shadow: none; padding: 0; padding-bottom: 0.7rem; margin-bottom: 0; } .exampleblock>.content .title { background-color: var(--code-color); border-top: 1px solid #ccc; font-family: 'Inconsolata', monospace; margin: 0; padding: 1em 1em 0; } .exampleblock>.title>a { text-decoration: none; color: var(--num-color); } .exampleblock .listingblock { margin: 0; } /* * Ensure that blocks of code do not wrap by applying the behavior of `[listing%nowrap]` by default. * * These styles are copied from a CSS ruleset in asciidoctor.css that has the same group of * selectors except that they end with `.nowrap`. */ .openblock .content { background: var(--admonition-background); margin-bottom: 1.25em; padding: 1em 1em 0em 1em; border-radius: 4px; overflow: auto !important; } .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { overflow-x: auto; white-space: pre; word-wrap: normal; } /* * This CSS ruleset solves: https://github.com/gradle/guides/issues/113#issuecomment-314826749. */ .literalblock pre::after, .literalblock pre[class]::after, .listingblock pre::after, .listingblock pre[class]::after { content: ""; } .quoteblock blockquote, .quoteblock blockquote p { text-align: left; text-align: start; } div.screenshot { box-shadow: 0 0 20px 1px rgba(0, 0, 0, 0.2); margin-left: auto; margin-right: auto; width: 90%; } .inset { box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1); padding: 1em; } .image.inline-icon img { vertical-align: sub; } /* TOC */ #header>h1:first-child+#toc { background: none; border: 0 none; margin-top: 0; } #toc, #content #toc { border: 0 none; } #toc>ul { margin-left: 0; font-family: inherit; } #toc>ul>li { line-height: 1.25; margin-top: 0; padding-bottom: 0.5rem; } #toc>ul>li:last-of-type { padding-bottom: 0; } #toc a { font-style: normal; } #toc a:hover, #toc a:focus, #toc a:hover code, #toc a:focus code { color: #1DA2BD; } #toc a:active { text-decoration: none; } /* Site header specific styles */ .hamburger { background-color: transparent; background-image: none; border: none; border-radius: 4px; cursor: pointer; margin-left: auto; padding: 11px 10px; } .hamburger:focus { outline: 0; } .hamburger__bar { display: block; width: 22px; height: 2px; background-color: var(--black-color); border-radius: 1px; } .hamburger__bar+.hamburger__bar { margin-top: 4px; } .site-header { background-color: var(--top-header-color); } /* Override javadoc styles */ .site-header div { font-family: 'Lato', Arial, sans-serif; } .site-header__navigation-header a { align-self: center; border-bottom: 0 none; height: 36px; } .site-header .site-header-version { align-self: center; color: #1da2bd; font-size: 20px; padding-left: 1px; margin-top: 22px; } .site-header__navigation { z-index: 2; display: flex; flex-direction: column; } .site-header__navigation-header { display: flex; flex: 0 0 auto; margin-left: 12px; } .site-header__navigation-collapsible { flex: 1 1 auto; height: 210px; overflow: visible; transition: height 0.3s ease; } .site-header__navigation-items { display: flex; flex-direction: column; flex-wrap: wrap; align-items: flex-start; max-height: 210px; /* This matches the collapsible height above */ margin: 0 20px; padding-top: 12px; padding-left: 0; list-style-type: none; } .site-header__navigation-item { flex: 0 1 auto; font-size: 16px; width: 250px; } .site-header__navigation-item .site-header__navigation-link { position: relative; display: inline-block; cursor: pointer; width: 100%; padding: 5px; line-height: 20px; border: 0 none; color: var(--text-color); text-decoration: none; transition: none; -o-transition: none; -moz-transition: none; -webkit-transition: none; } .site-header__navigation-item .site-header__navigation-link:hover { color: #1DA2BD; } .site-header__navigation-item .site-header__navigation-link.active { font-weight: 500; } /* Navigation submenu styles */ .site-header__navigation-submenu-section { position: relative; } .site-header__navigation-submenu-section .site-header__down-arrow { width: 8px; height: 8px; margin-left: 2px; margin-top: 0; } .site-header__navigation-submenu-section .site-header__navigation-link:hover path { fill: none; } .site-header__navigation-submenu-section .site-header__navigation-submenu .site-header__navigation-submenu-item-link:hover { color: #1DA2BD; } .site-header__navigation-submenu-section .site-header__navigation-submenu { display: none; width: 170px; background-color: var(--menu-burger-color); top: 40px; left: 7px; /* NOTE: This must match the padding of .site-header__navigation-link */ padding: 3px 10px 6px 10px; z-index: 100; } .site-header__navigation-submenu-section .site-header__navigation-submenu .site-header__navigation-submenu-item-link { width: 100%; color: var(--text-color); white-space: nowrap; display: inline-block; padding-top: 3px; border: 0 none; transition: none; -o-transition: none; -moz-transition: none; -webkit-transition: none; } .site-header__navigation-submenu-section .site-header__navigation-submenu .site-header__navigation-submenu-item-link .site-header__navigation-submenu-item-link-text { display: inline-block; font-size: 16px; } .site-header__navigation-submenu-section.open .site-header__navigation-submenu { display: block; } /* Top navigation mobile styles */ @media (max-width: 1023px) { .site-header__navigation-collapsible--collapse { height: 0; overflow-y: hidden; } .site-header__navigation-submenu-section .site-header__navigation-submenu { padding: 0 1rem 0.5rem 1.5rem; display: block; top: 30px !important; left: 0 !important; } .site-header__navigation-item, .site-header__navigation-submenu-section .site-header__navigation-submenu .site-header__navigation-submenu-item-link .site-header__navigation-submenu-item-link-text { font-size: 18px; } .site-header { padding: 5px 12px; } .site-header-version { display: none; } .site-footer__navigation { flex-direction: column; } .site-footer__links { flex-wrap: wrap; } .site-footer__link-group { margin-bottom: 1rem; } } /* Top navigation desktop styles */ @media (min-width: 1024px) { .site-header { -webkit-box-shadow: 0 2px 4px 0 var(--box-shadow-color); -moz-box-shadow: 0 2px 4px 0 var(--box-shadow-color); box-shadow: 0 2px 4px 0 var(--box-shadow-color); z-index: 2; } body.dark-theme { .site-header { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; z-index: 2; } } @media (prefers-color-scheme: dark) { .site-header { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; z-index: 2; } body.light-theme { .site-header { -webkit-box-shadow: 0 2px 4px 0 var(--box-shadow-color); -moz-box-shadow: 0 2px 4px 0 var(--box-shadow-color); box-shadow: 0 2px 4px 0 var(--box-shadow-color); z-index: 2; } } } /* Pushes the section headings to just below the top nav bar when a user navigates directly to section anchors. */ #content h2[id], #content h3[id], #content h4[id], #content h5[id] { padding-top: 60px; } #content h2[id] { /* Little extra room above h2s */ margin-top: -1em; } #content h3[id], #content h4[id], #content h5[id] { margin-top: -60px; } .site-header__navigation { flex-direction: row; } .site-header__navigation-button { display: none; } .site-header__navigation-items { flex-direction: row; align-items: center; float: right; width: auto; padding-top: 0; } .site-header__navigation-item { width: auto; } .site-header__navigation-item .site-header__navigation-link { padding: 15px 18px; } .site-header__navigation-item:last-of-type .site-header__navigation-link { padding-right: 0; } .site-header__navigation-link--button { padding: 6px 12px; } .site-header__navigation-collapsible { height: auto; } .site-header__navigation-submenu-section .site-header__navigation-submenu { position: absolute; border: 1px solid #9a9a9a; border-radius: 3px; } .site-header__navigation-submenu-section:hover .site-header__navigation-submenu { display: block; } /* Pushes the section headings to just below the top nav bar when a user navigates directly to section anchors. It doesn't work if you try to apply the padding and margin to the `h` elements directly. */ .chapter a[name], .chapter .anchor { padding-top: 60px; margin-top: -60px; text-decoration: none; border: none; display: inline-block; } } /* Side Navigation styles */ /* Docs Navigation */ .docs-navigation { border-right: 1px solid var(--various-border-color); } .docs-navigation .search-container { display: none; margin-bottom: 1rem; } .docs-navigation a { color: var(--text-color); display: block; font-size: .95rem; position: relative; } .docs-navigation a:focus { outline: none; } .docs-navigation a:hover { color: #35c1e4; text-decoration: none; } .docs-navigation a code { color: var(--text-color); overflow-wrap: break-word; padding: 0; word-break: break-all; } .docs-navigation a.active { color: #06A0CE; outline: 0; border: none; -moz-outline-style: none; } .docs-navigation a.active:hover { color: #35c1e4; text-decoration: underline; } .docs-navigation ul { list-style-type: none; margin: 0; padding: 0; } .docs-navigation li>ul>li a { font-size: 14px; color: #7d7d7d; } .docs-navigation ul:last-of-type { margin-bottom: 0; } .docs-navigation li { margin-top: 0.3334em; line-height: 1.3334; } .docs-navigation li:last-of-type { margin-bottom: 0; } .docs-navigation .nav-dropdown:before { content: '\2023'; font-size: 28px; position: absolute; margin-left: -14px; margin-top: -8px; } .docs-navigation .nav-dropdown.expanded:before { transform: rotate(90deg); } .docs-navigation>ul ul, .docs-navigation>ul ul ul { display: none; height: 0; margin-left: 1rem; } .docs-navigation>ul ul:target, .docs-navigation>ul ul:target ul, .docs-navigation>ul .nav-dropdown.expanded~ul { display: block; height: auto; } .docs-navigation h3 { font-size: .95rem; font-weight: 600; line-height: 1.5; margin: 1.5em 0 0; } .docs-navigation .docs-home-link { position: relative; } @media screen and (min-width: 45rem) { .main-content { display: flex; } } /* User guide navigation appears for desktops */ @media screen and (min-width: 64rem) { .docs-navigation { flex: 0 0 auto; width: 13.75rem; } .main-content>.appendix, .main-content>.book, .main-content>.chapter { flex: 0 0 auto; margin: 0 auto; } } /** * For mobile devices, we show navigation at bottom of page. * * This is the simplest solution to this issue. */ @media not screen and (min-width: 64rem) { /* Repeat the class twice to prioritize our mobile classes! */ .content.content { /* Make the height equal to the real height of content */ overflow: visible; } .main-content { /* Main content show first */ flex-direction: column-reverse; } .docs-navigation.docs-navigation { /* Fill the main container */ width: 100%; /* Don't clip the navigation container */ overflow: visible; } } /* Userguide Meta */ .chapter-meta { float: right; text-align: right; } .chapter-meta .edit-link { color: #999; font-size: 0.9em; padding-right: 3px; } .chapter-meta .edit-link svg { margin-right: 1px; } /* Clever use of RTL to fill in all stars to left of hover position */ .rating { direction: rtl; } .rating>.star { cursor: pointer; display: table-cell; padding: 3px; } .rating>.star:hover>svg>g, .rating>.star:hover~.star>svg>g, .rating>.star.selected>svg>g, .rating>.star.selected~.star>svg>g { fill: #999; } /* Footer styles */ .site-footer {} .site-footer__navigation { display: flex; padding: 30px 12px; max-width: 62.5rem; margin: 0 auto; padding-left: 5rem; } @media not screen and (min-width: 64rem) { .site-footer__navigation { /* same to nav.docs-navigation for mobiles */ padding: 20px 20px 20px 26px; } } .site-footer__links { display: flex; flex: 1 1 auto; } .site-footer__links .site-footer__links-list { list-style-type: none; margin: 0; } .site-footer__links .site-footer__links-list a { color: var(--footer-other-text-color); } .site-footer__link-group { flex: 1 1 auto; flex-basis: 175px; } .site-footer__link-group header { color: var(--text-color); } .site-footer__subscribe-newsletter .newsletter-form__header h5 { color: var(--text-color); margin-top: 0; } .site-footer__subscribe-newsletter p { font-size: 0.875rem; margin: 2px 0 0 2px; opacity: 0.7; } .site-footer__subscribe-newsletter .disclaimer { color: var(--footer-other-text-color); font-size: 0.75rem; opacity: 0.55; } .site-footer__subscribe-newsletter .newsletter-form { padding-top: 6px; display: flex; justify-content: flex-start; } .site-footer__subscribe-newsletter .email, .site-footer__subscribe-newsletter .submit { height: 40px; } .site-footer__subscribe-newsletter .email { line-height: 40px; width: 250px; color: #1DA2BD; font-size: 16px; padding-left: 20px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; border: 1px solid var(--footer-form-color); } .site-footer__subscribe-newsletter .submit { font-family: inherit; font-size: inherit; line-height: inherit; width: 100px; background-color: #1BA8CB; color: #fff; font-weight: 500; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-style: none; cursor: pointer; transition: all .3s ease; } /* Secondary footer (below) */ .site-footer-secondary { background-color: var(--footer-white-color); border-top: 1px solid var(--various-border-color); width: 100%; z-index: 1; } body.dark-theme { .site-footer-secondary { background-color: var(--footer-white-color); border-top: none; width: 100%; z-index: 1; } } @media (prefers-color-scheme: dark) { .site-footer-secondary { background-color: var(--footer-white-color); border-top: none; width: 100%; z-index: 1; } body.light-theme { .site-footer-secondary { background-color: var(--footer-white-color); border-top: 1px solid var(--various-border-color); width: 100%; z-index: 1; } } } .site-footer-secondary__contents { display: flex; align-items: center; justify-content: space-between; max-width: 75rem; margin-left: auto; margin-right: auto; font-size: 0.875rem; padding: 0.5rem 0.75rem; } /* * 1. Value is the largest computed width among 'site-footer__copy' and 'site-footer__links'. */ .site-footer__copy, .site-footer__secondary-links { flex-grow: 0; flex-basis: 280px; /* 1. */ } /* * 1. 'flex-shrink: 1' is applied to the element with the smallest computed width among * 'site-footer__copy' and 'site-footer__links'. */ .site-footer__copy { flex-shrink: 1; /* 1. */ } .site-footer__logo { flex: 0 0 auto; margin-right: 10px; margin-left: 10px; } .site-footer__logo svg { width: 35px; height: 35px; } /* * 1. 'flex-shrink: 0' is applied to the element with the largest computed width among * 'site-footer__copy' and 'site-footer__links'. */ .site-footer__secondary-links { flex-shrink: 0; /* 1 */ text-align: right; white-space: nowrap; } .site-footer-secondary a { color: #999; } .site-footer-secondary__links a:not(:last-child) { padding-right: 10px; } .site-footer-secondary__links a:not(:first-child) { padding-left: 10px; } @media all and (max-width: 29.99rem) { .site-footer__rights, .site-footer-secondary__links { display: none; } .site-footer__logo { order: 1; text-align: left; } .site-footer__copy { order: 2; text-align: right; } } /* Avoid the footer taking up much of the screen on short displays */ @media all and (max-height: 56.25rem) { .site-footer__navigation { margin: 1.5rem auto 0 auto; padding-top: 0; padding-bottom: 0; } } @media screen and (min-width: 84.375rem) { .ui-logos .ui-logo { box-shadow: 0 6px 15px 1px rgba(0, 0, 0, 0.56); } } /* User Manual Home */ .technology-logos, .ui-logos { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-around; } .technology-logo, .ui-logo { flex: 0 1 auto; } .ui-logo { width: 224px; height: 135px; margin: 12px; } /* Samples download button */ .download { display: flex; } .download a { border-style: solid; border-width: 1px; text-decoration: none; padding: 5px; display: block; width: 10em; margin: 5px; } .download ul { list-style: none; list-style-type: none; } .download li { float: right; } .docs-navigation { width: 18rem; padding: 20px 20px 20px 26px; background: var(--nav-color); overflow-y: scroll; overflow-x: auto; } .layout { display: flex; flex-direction: column; overflow: hidden; height: 100vh; } .main-content { overflow-y: auto; overflow-x: auto; display: flex; } .content { flex: 1 1 auto; overflow: auto; padding-left: 0; padding-right: 0; } .content .chapter { padding: 2rem 2.4rem; } #toc a:active { font-weight: 500; } .site-header { margin-bottom: 1rem; } .site-header__navigation-submenu-item { padding: 2px 0; } .site-footer { background-color: var(--footer-color); padding: 20px 0 40px 0; border-top: 1px solid var(--various-border-color); } #header { margin-left: 0; } #header>h1:first-child { margin-bottom: 40px; } @media screen and (min-width: 64rem) { #header { margin-bottom: 20px; } .site-header { margin-bottom: 0; z-index: 2; } .site-header__navigation-header { margin-top: -7px; } .site-header__navigation-submenu-section:after { content: '\2023'; font-size: 28px; position: absolute; transform: rotate(90deg); margin-right: 10px; top: 5px; right: -7px; } .site-footer__navigation { flex-wrap: wrap; } .site-footer__link-group { flex: 1 1 auto; } .site-footer__links { margin-bottom: 1rem; } } @media screen and (min-width: 75rem) { .content .chapter { box-sizing: content-box; } #content { padding-right: 260px; margin: 0; } /* #toc here must be referenced as #header #toc since we don't want to change single page #toc */ #header #toc { position: fixed; margin: 0 auto; padding-bottom: 0; right: 0; top: 65px; width: 260px; z-index: 1; overflow: auto; border-radius: 0 0 5px 0; max-height: calc(100% - 118px); margin-right: 15px; } #header #toctitle { margin-top: 1.3em; } #header #toc>ul { /* margin-left have to increase if you change border thickness of active toc item */ margin-left: 1px; border-left: 1px solid #666; margin-bottom: 0; padding-right: 10px; padding-bottom: 0.5rem; background-color: var(--white-color); } #header #toc>ul>li, #toc>ul>li:last-of-type { padding: 0.5rem 0; margin: 0; } #header #toc a { padding-left: 10px; font-weight: 400; color: var(--text-color); font-size: .95rem; display: inline-block; } #header #toc a.active { font-weight: 500; border-left: 3px solid #01303a; margin-left: -2px; padding-left: 9px; } .site-footer__navigation { flex-wrap: wrap; margin-left: auto; padding-left: 3rem; } .site-footer__link-group { flex: 0.15 1 auto; } .site-footer__subscribe-newsletter { /* A fix so subscribe disclaimer does not go under long ToC */ max-width: calc(100% - 17rem); } } @media screen and (min-width: 80rem) { .site-footer__subscribe-newsletter { max-height: none; } } @media screen and (min-width: 100rem) { .content .chapter { max-width: 60.5rem; } #header { margin: 0 auto; } #content { padding-right: 0; margin: 0 auto; } #header #toc { right: initial; margin-left: 62.5rem; } .site-footer__navigation { padding-left: 0; } .site-footer__link-group { flex: 0.2 1 auto; } } @media screen and (min-width: 112rem) { .content .chapter { max-width: 62.5rem; margin: 0 auto; padding-right: 3.5rem; position: relative; left: -130px; } #header #toc { right: initial; margin-left: 64.5rem; } .site-footer__link-group { flex: 0.2 1 auto; } } @supports (-moz-appearance:meterbar) and (background-blend-mode:difference, normal) { /* Firefox only */ .site-header__navigation-submenu-section:after { top: 2px; right: -4px; } } /* Added dark mode and other items for outdated Prettify.css */ code[data-lang="text"] .pln, code[data-lang="text"] .str, code[data-lang="text"] .kwd, code[data-lang="text"] .com, code[data-lang="text"] .typ, code[data-lang="text"] .lit, code[data-lang="text"] .pun, code[data-lang="text"] .opn, code[data-lang="text"] .clo, code[data-lang="text"] .tag, code[data-lang="text"] .atn, code[data-lang="text"] .atv, code[data-lang="text"] .dec, code[data-lang="text"] .var, code[data-lang="text"] .fun { color: #000; } body.dark-theme { code[data-lang="text"] .pln, code[data-lang="text"] .str, code[data-lang="text"] .kwd, code[data-lang="text"] .com, code[data-lang="text"] .typ, code[data-lang="text"] .lit, code[data-lang="text"] .pun, code[data-lang="text"] .opn, code[data-lang="text"] .clo, code[data-lang="text"] .tag, code[data-lang="text"] .atn, code[data-lang="text"] .atv, code[data-lang="text"] .dec, code[data-lang="text"] .var, code[data-lang="text"] .fun { color: #fff !important; } .com { color: #909090 !important; } .str, .tag { color: #90a959 !important; } .kwd, .atv { color: #d28445 !important; } .typ { color: #f4bf75 !important; } .lit, .atn { color: #6a9fb5 !important; } .pun, .pln, .opn, .clo { color: #d0d0d0 !important; } .dec, .var { color: #aa759f !important; } li.L1, li.L3, li.L5, li.L7, li.L9 { background: #111 !important; } } @media (prefers-color-scheme: dark) { code[data-lang="text"] .pln, code[data-lang="text"] .str, code[data-lang="text"] .kwd, code[data-lang="text"] .com, code[data-lang="text"] .typ, code[data-lang="text"] .lit, code[data-lang="text"] .pun, code[data-lang="text"] .opn, code[data-lang="text"] .clo, code[data-lang="text"] .tag, code[data-lang="text"] .atn, code[data-lang="text"] .atv, code[data-lang="text"] .dec, code[data-lang="text"] .var, code[data-lang="text"] .fun { color: #fff !important; } .com { color: #909090 !important; } .str, .tag { color: #90a959 !important; } .kwd, .atv { color: #d28445 !important; } .typ { color: #f4bf75 !important; } .lit, .atn { color: #6a9fb5 !important; } .pun, .pln, .opn, .clo { color: #d0d0d0 !important; } .dec, .var { color: #aa759f !important; } li.L1, li.L3, li.L5, li.L7, li.L9 { background: #111 !important; } body.light-theme { code[data-lang="text"] .pln, code[data-lang="text"] .str, code[data-lang="text"] .kwd, code[data-lang="text"] .com, code[data-lang="text"] .typ, code[data-lang="text"] .lit, code[data-lang="text"] .pun, code[data-lang="text"] .opn, code[data-lang="text"] .clo, code[data-lang="text"] .tag, code[data-lang="text"] .atn, code[data-lang="text"] .atv, code[data-lang="text"] .dec, code[data-lang="text"] .var, code[data-lang="text"] .fun { color: #000; } .pln { color: #000 !important;; } .com { color: #800 !important;; } .str, .tag { color: #080 !important;; } .kwd, .atv { color: #008 !important;; } .typ { color: #606 !important;; } .lit, .atn { color: #066 !important;; } .pun, .opn, .clo { color: #660 !important;; } .dec, .var { color: #606 !important;; } li.L1, li.L3, li.L5, li.L7, li.L9 { background: #eee; } } } /* DPE University button*/ /* CSS */ .badge-wrapper { padding-top: 0px; padding-bottom: 20px; a { text-decoration: none; } a:link { text-decoration: none; } a:visited { text-decoration: none; } a:hover { text-decoration: none; } a:active { text-decoration: none; } } .badge { background-color: var(--black-color); height: 24px; border-radius: 12px; border-color: var(--black-color); border-style: solid; border-width: 1px; padding: 5px; a { color: var(--gradle-blue); } } .badge-type { border-radius: 8px; margin-right: 10px; padding-left: 10px; padding-right: 10px; } .badge-text { color: var(--white-color); } .button--blue { color: white; border-color: transparent; &:hover { color: white; } } .button--blue { background: var(--gradle-blue); background: linear-gradient(var(--button-gradient-angle), var(--gradle-blue) 0%, var(--gradle-blue-lite) 100%); &:hover { background: var(--gradle-blue-lite); } } /* Custom Download button*/ /* CSS */ .button-9 { appearance: button; backface-visibility: hidden; background-color: #209BC4; border-radius: 6px; border-width: 0; box-shadow: rgba(50, 50, 93, .1) 0 0 0 1px inset, rgba(50, 50, 93, .1) 0 2px 5px 0, rgba(0, 0, 0, .07) 0 1px 1px 0; box-sizing: border-box; color: #fff; cursor: pointer; font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Ubuntu, sans-serif; font-size: 100%; height: 44px; line-height: 1.15; margin: 12px 12px 12px 0px; outline: none; overflow: hidden; padding: 0 25px; position: relative; text-align: center; text-transform: none; transform: translateZ(0); transition: all .2s, box-shadow .08s ease-in; user-select: none; -webkit-user-select: none; touch-action: manipulation; width: 25%; } .button-9:disabled { cursor: default; } .button-9:focus { box-shadow: rgba(50, 50, 93, .1) 0 0 0 1px inset, rgba(50, 50, 93, .2) 0 6px 15px 0, rgba(0, 0, 0, .1) 0 2px 2px 0, rgba(50, 151, 211, .3) 0 0 0 4px; } .button-9-sect { padding-bottom: 1.25em; } /* Theme toggle switch button */ /* Switch */ .switch { position: relative; display: inline-block; width: 60px; height: 34px; align-self: center; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: 0.4s; transition: 0.4s; } .slider:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: white; -webkit-transition: 0.4s; transition: 0.4s; } input:checked+.slider { background-color: #2196f3; } input:checked+.slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); } /* Rounded sliders */ .slider { border-radius: 30px; } .slider:before { border-radius: 50%; } </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css"> <meta name="adoc-src-path" content="dep-man/dependency-management/component_metadata_rules.adoc"> <link crossorigin href="//assets.gradle.com" rel="preconnect"> <link href="https://fonts.googleapis.com/css?family=Inconsolata:400,700" rel="stylesheet"/> <style type="text/css">.multi-language-selector .language-option[data-lang='groovy'], .exampleblock[data-lang=groovy] > .content .title { background-image: url('data:image/svg+xml;base64,PHN2Zw0KICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIg0KICAgd2lkdGg9IjYxNC4wNjA4NSINCiAgIGhlaWdodD0iMzAzLjU5ODYiDQogICB2ZXJzaW9uPSIxLjEiPg0KICA8Zw0KICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzUuMzk2NTk5LC0zMC41NTgxOTYpIj4NCiAgICA8cGF0aA0KICAgICAgIGQ9Im0gMTU0Ljk3Njg3LDMzMi42OTE2MiBjIDAsLTAuODA1ODcgMTAuODMxMjMsLTE4LjYyMTcyIDI0LjA2OTQsLTM5LjU5MDc2IDEzLjIzODE5LC0yMC45NjkwNSAyMi42NjA1NywtMzguNjIwNjYgMjAuOTM4NjcsLTM5LjIyNTc3IC0xLjcyMTkxLC0wLjYwNTEgLTcuNjc5OTIsMC40ODU2NyAtMTMuMjQwMDIsMi40MjM5MyAtMTYuNzQ1MjQsNS44Mzc0MyAtMjAuMTg2MDUsNC4yOTAxNiAtMzIuNjkzMDgsLTE0LjcwMTU1IC0xMy41MzI2NSwtMjAuNTQ5MDYgLTE0LjAxNzI0LC0yMi42Njk4MyAtNi45NjE1OCwtMzAuNDY2MjQgNC42MDg3NiwtNS4wOTI1NiA0LjMzMTU5LC02LjI3OTY3IC0zLjIzMTksLTEzLjg0MzE2IC00LjU1MDA5LC00LjU1MDEgLTguMjcyODksLTkuNjQzMDkgLTguMjcyODksLTExLjMxNzc2IDAsLTIuODE2NzkgLTMwLjk5MTQ1LC0xNS41ODkzMyAtNzkuOTg5NDk2LC0zMi45NjYxNSAtMTEuMTA5NjYsLTMuOTM5OTcgLTIwLjE5OTM3NSwtNy44MjkyOCAtMjAuMTk5Mzc1LC04LjY0MjkxIDAsLTAuODEzNjYgMjMuNDcwNzM4LC0xLjAwNDc2IDUyLjE1NzE5MSwtMC40MjQ2OSBsIDUyLjE1NzIxLDEuMDU0NjYgNS4wOTEyNywtOC4wMzAwMSBjIDIxLjUxNjQ0LC0zMy45MzU5MiA1NC4wMDk1MiwtNjQuNTg4MjEyIDY4LjQ2NzA1LC02NC41ODgyMTIgMy4wMTA2LDAgOS4xMjE0MSwyLjg2OTE4IDEzLjU3OTUzLDYuMzc1OTQ1IDcuMjU5NDYsNS43MTAyODMgOC4yNTY1LDkuMjQ4NjMyIDkuNTQ5OTQsMzMuODkxOTY3IDAuNzk0MywxNS4xMzM4MiAyLjQyNDIyLDI4LjQ5NjAxIDMuNjIxOTgsMjkuNjkzNzkgMS4xOTc3NSwxLjE5Nzc2IDQuOTk3NjksLTAuMzc0MjUgOC40NDQzMSwtMy40OTMzOSA0LjQwMTQsLTMuOTgzMjMgOS4wMzQ4NCwtNS4wNjMxMyAxNS41Njc2MSwtMy42MjgzIDYuNzY3NTYsMS40ODY0MSAxMC42MjcxLDAuNDY4OTUgMTQuMTY5MzgsLTMuNzM1NDMgNS4zMTM2LC02LjMwNjY2IDMxLjkwNTk2LC00OC45MzcyMDEgMzEuOTA1OTYsLTUxLjE0ODc0NCAwLC0wLjc1MTU4OCA1LjI2NTA5LC05Ljc1NzMwNiAxMS43MDAyMywtMjAuMDEyNzAzIDYuNDM1MDksLTEwLjI1NTM5NyAxMy44NDY2NCwtMjIuMDgwNjMxIDE2LjQ3MDA3LC0yNi4yNzgyODMgNC42NjU1OCwtNy40NjUyMDEgNS4zOTY2LC02LjU4MTczNSAzMy40MjY5Miw0MC4zOTg3MzYgMjguOTQxMjEsNDguNTA3MTY0IDQ0LjUxNzY3LDY2LjQwNjU1NCA1Mi4zMTU3LDYwLjExNzYzNCA1LjQ0MiwtNC4zODg4OSAzNC4wMDA1NSwtNC42Mzc5NCA0MS45ODI0NiwtMC4zNjYxNCA0LjUzNjY1LDIuNDI3OTMgNy40MTkxNiwyLjM5NjEgOS45MjQ4NCwtMC4xMDk2MiA1LjIwMDA3LC01LjIwMDA2IDE3LjY0OTgyLC00LjI5NDM3IDIwLjkwNDEyLDEuNTIwNzggMi41NjM5Myw0LjU4MTQ2IDMuMjE3ODQsNC41ODE0NiA3LjAyMDE0LDAgMi4zMDYwNiwtMi43Nzg2NyA5LjEzNjE5LC01LjA1MjA4IDE1LjE3ODAzLC01LjA1MjA4IDguNTM4ODQsMCAxMS43OTMzNiwxLjc3MzY3IDE0LjYxNDAzLDcuOTY0MzcgbCAzLjYyODgxLDcuOTY0MzYgNTYuMDkyMDMsLTEuOTg1OCBjIDMwLjg1MDYyLC0xLjA5MjIyIDU2LjA5MjA0LC0xLjI4Njg4IDU2LjA5MjA0LC0wLjQzMjU1IDAsMC44NTQyNyAtMjIuOTA2MDgsMTAuMDcxOTUgLTUwLjkwMjQxLDIwLjQ4MzcxIC0yNy45OTYzMiwxMC40MTE3MiAtNTEuMzY3LDE5LjI0MzA1IC01MS45MzQ4NCwxOS42MjUxMiAtMC41Njc4NSwwLjM4MjA3IDAuNjk4NDcsOS40OTI3MyAyLjgxNDA1LDIwLjI0NTg4IDUuNTA0NTcsMjcuOTc5MTcgMS45MTQ1OCw0Ni42MjU4OSAtMTEuOTI2MjksNjEuOTQ2MDQgLTYuMjA5LDYuODcyNjMgLTE2LjI4MzM4LDE0LjE0Mzk1IC0yMi4zODc1MywxNi4xNTg0OSAtNi4xMDQxNSwyLjAxNDU0IC0xMS4wOTg0NCw0LjM4NjE0IC0xMS4wOTg0NCw1LjI3MDE5IDAsMC44ODQwNiA2LjUxNTI1LDExLjY3ODkzIDE0LjQ3ODM1LDIzLjk4ODU5IDcuOTYzMDksMTIuMzA5NjkgMTMuMjgyOCwyMi4zODEyNSAxMS44MjE1MiwyMi4zODEyNSAtMi4zODUwNCwwIC02MC40Njk4NywtMjIuNDQyMzggLTE1MC43ODg5OCwtNTguMjYwNyAtMTcuODA5LC03LjA2MjU4IC0zNC4wMjY4MywtMTIuODQxMDkgLTM2LjAzOTYxLC0xMi44NDEwOSAtMy43NTM2MywwIC0zNi4xNjY5LDEyLjI4NjYyIC0xMzEuMjI0MjMsNDkuNzQyMDYgLTU1LjEyNTI1LDIxLjcyMTAzIC01Ny4yOTIxNywyMi40NzM0OCAtNTcuMjkyMTcsMTkuODk0NTEgeiBtIDExMy4xMTY0OCwtNTEuMjUyNjUgYyAyOS4zMjk0OSwtMTEuMzk1MDYgNTguNDE2NTcsLTIyLjUzMDggNjQuNjM3OTgsLTI0Ljc0NjA3IDEwLjcwMDY4LC0zLjgxMDE5IDE0LjI3OTE4LC0yLjg1NDkzIDY2LjI1Mzk0LDE3LjY4NjM0IDMwLjIxODI1LDExLjk0Mjc0IDYwLjAzMjUyLDIzLjU3NTg3IDY2LjI1MzkyLDI1Ljg1MTM0IDYuMjIxNDEsMi4yNzU1MiAxOS4wNDMxNyw3LjIyMDU5IDI4LjQ5Mjc1LDEwLjk4OTA4IDEwLjc3NTAzLDQuMjk3MDQgMTYuMjgyNTEsNS4zMzE2NiAxNC43NzEwOCwyLjc3NDg0IC0xNi44ODM3LC0yOC41NjExMyAtMTcuMzk5OCwtMjkuMDM3MTYgLTI5LjEwMDgzLC0yNi44NDIwNSAtMTQuMTEzNjEsMi42NDc3MiAtMjIuODc4OTcsLTAuMDY4NSAtMjcuMzgzNjksLTguNDg1NTQgLTIuOTIxMTIsLTUuNDU4MTYgLTIuMDI5NDQsLTguMTI3NTkgNS4yNTQ0MiwtMTUuNzMwMzEgMTAuODQ4ODcsLTExLjMyMzc3IDkuMTQ0NTcsLTIxLjc0MTQ0IC00Ljg0NDI5LC0yOS42MTA5OSAtNS4zNjc2NCwtMy4wMTk1OSAtMTIuMTQwNTksLTEwLjQ4MzcyIC0xNS4wNTEwMiwtMTYuNTg2OTcgbCAtNS4yOTE2OSwtMTEuMDk2ODIgLTExLjM0NTUxLDcuNjk5MjggYyAtMTMuOTQ0NTgsOS40NjMwNCAtMzAuOTUwNjIsOS45NTA2MyAtNDUuMTQ3NjQsMS4yOTQ0OCBsIC0xMC40NjQ4OCwtNi4zODA2NSAtMTIuMTU4NDEsOC4yNjI4NCBjIC0xMi4xNzQ2Miw4LjI3Mzg2IC0yNi4xOTEwOCw5LjM0MjggLTQwLjQzNzUyLDMuMDgzOTIgLTMuOTI0OTgsLTEuNzI0MzkgLTUuNjU1ODMsLTEuMDU0MTUgLTUuNjU1ODMsMi4xOTAwOCAwLDIuNTcxMTggLTMuNzA0MjksNi4zNjI2NSAtOC4yMzE4MSw4LjQyNTUzIC0xMy41NzQyLDYuMTg0NzkgLTI2LjgyMTA3LDQuNTQyNDcgLTM1LjgwMjI5LC00LjQzODc1IGwgLTguMTg5NDQsLTguMTg5NDQgLTYuNjA5ODIsOC40MDMwMyBjIC0zLjYzNTM5LDQuNjIxNjYgLTEyLjA0OTUyLDExLjgzNjk4IC0xOC42OTgwNSwxNi4wMzM5OCAtOC4yMjk2NSw1LjE5NTE4IC0xOC40MTc0MSwxNy44NzE4MiAtMzEuOTE2NCwzOS43MTM2MSAtMTAuOTA1NDksMTcuNjQ1NDYgLTE5LjgyODE2LDMyLjk4MDQyIC0xOS44MjgxNiwzNC4wNzc3NiAwLDEuMDk3MyA4LjM2MjU1LC0xLjUyNzM2IDE4LjU4MzQyLC01LjgzMjU5IDEwLjIyMDg5LC00LjMwNTIxIDQyLjU4MDI4LC0xNy4xNTA4NyA3MS45MDk3NywtMjguNTQ1OTMgeiBtIDI0OC43NjcyOSwtMTIuMjU4NDYgYyAyMi4yNTU1NywtMTIuNTA4MzMgMjcuNDE0MjQsLTM1LjY0ODA4IDE3LjU3Njg1LC03OC44NDMxOCAtOC4yMjE0LC0zNi4wOTk2MSAtMTIuMzI1NSwtNDcuOTEzMjcgLTE3LjE5NDk0LC00OS40OTU5NyAtMy4zNjkwMiwtMS4wOTUwMyAtMy44ODY3NCwwLjEwNjk5IC0xLjk4ODU4LDQuNjE2MzUgMTIuMzE1MTYsMjkuMjU3NzEgMTIuOTk5NjMsNDMuOTQ2NjIgMi4yNDAyMiw0OC4wNzU0MSAtNy4zOTE1MSwyLjgzNjQyIC0xNS4yMzIzOSwtNy43OTA3NSAtMjEuMzk5MDIsLTI5LjAwMzI2IC00Ljc3NTEyLC0xNi40MjU4NyAtOS43Njg2MSwtMjMuODI4MzcgLTEzLjUzMzg3LC0yMC4wNjMxMSAtMC45MDE1NywwLjkwMTYgMC42Nzg0OCw2LjEyMTE3IDMuNTExMjQsMTEuNTk5MTMgMi44MzI3Myw1LjQ3NzkgNi43MTcyMSwyMS45NzQ1NSA4LjYzMjE3LDM2LjY1OTIgMS45MTQ5NywxNC42ODQ2MiA1LjYxMzg1LDMwLjA2MDczIDguMjE5NzMsMzQuMTY5MTIgNi43NzE5OCwxMC42NzY2MSAxNy41NTEyOCw4LjEwMzYgMjQuNTIzODIsLTUuODUzODQgNi44OTM3MywtMTMuNzk5NzUgNy42NzI4NCwtNC42MDc4MSAwLjk2OTMsMTEuNDM2MDIgLTYuOTYwNzQsMTYuNjU5MzcgLTI3LjYzNDQyLDIxLjY1NDgxIC01MS41ODQxOCwxMi40NjQ0MiAtMy44MzMzLC0xLjQ3MDk2IC01LjEzMDM5LDAuMDUxNSAtNS4xMzAzOSw2LjAyMDk3IDAsNC4zOTQzMSAtMi45MzYxOCwxMS43MjI0NSAtNi41MjQ4OCwxNi4yODQ3IGwgLTYuNTI0ODgsOC4yOTUwNiA4Ljk0ODgxLDEuNTExMjMgYyAxNS40NDk0NSwyLjYwOTA5IDM2LjYzMzI4LC0wLjc3NjQyIDQ5LjI1ODYsLTcuODcyMjUgeiBtIC0zMjAuMzY2NSwtMjcuNTM3MzMgYyA0Ni40NTk2NSwtMTMuMzU0NSA1NC43NjE4OCwtMjguOTMwOTMgMzkuMzI4ODUsLTczLjc4NzgyIC0zLjU4MTg1LC0xMC40MTA3OSAtNi41MTI0MywtMjEuNjA5NzEgLTYuNTEyNDMsLTI0Ljg4NjU0IDAsLTExLjE1NzEyIC01LjYxMTUyLC02LjAwMTYxIC05LjgxNzEzLDkuMDE5NDMgLTUuNTYyMDMsMTkuODY1NjEgLTIyLjI5MTE1LDM2Ljc1MDUzIC0zNi4zNDUxNiwzNi42ODM2NCAtMTIuMjA1NDcsLTAuMDU4MiAtMTYuMTgyNTEsLTIuMjgwMDggLTIxLjIyMzc4LC0xMS44NTc2OCAtOS4wNDc0OCwtMTcuMTg4ODIgMC44MTQ2OSwtNDMuNTY3OTcgMjUuOTY5NTQsLTY5LjQ2MjcyIDE4LjQyNDMxLC0xOC45NjYzMDQgMjguNDg4OTMsLTIwLjY4Mzk2NSAyOC40ODg5MywtNC44NjIwNSAwLDI0LjY3MzIgLTE3LjAxMTM0LDYwLjk5NDcgLTI1Ljk3MzA5LDU1LjQ1NjA0IC00LjM4MjA1LC0yLjcwODI2IC0zLjY3MTM4LC0xNC42Njc1MiAxLjQxNzIyLC0yMy44NTAwOSA0LjMyNzM1LC03LjgwODgyIDMuNDQ4MTQsLTE5LjcwNzcxIC0xLjQ1NjIsLTE5LjcwNzcxIC01LjY4Njg5LDAgLTE2Ljk0NTQ3LDIwLjcxMTk2IC0xOC40MzMxOCwzMy45MTA3NCAtMS4zMTUxNSwxMS42NjgyNiAtMC40OTI4NiwxNC41MDU0NSA1LjA2NjUyLDE3LjQ4MDcyIDE5LjQ4MjQ0LDEwLjQyNjcgNDUuMDA1MzEsLTIxLjM5NTQ1IDQ2LjI5MDgzLC01Ny43MTU4NCAwLjY3NTA0LC0xOS4wNzMxODEgLTMuMDE2NzYsLTI0LjQ0MTEwNSAtMTQuNzc5MDYsLTIxLjQ4ODk1MSAtMTcuMTE4NzksNC4yOTY1NDMgLTYzLjIzNDgzLDYzLjc4NjY0MSAtNjMuMjM0ODMsODEuNTczNDYxIDAsMTMuOTEyOCA2Ljk4NzM3LDIzLjY5NzI4IDE5LjI4ODI3LDI3LjAwOTYgMjAuOTE0MTksNS42MzE2MiA0MS4xMzUzOSwtNC4zNzM4OSA1NS40NjMzLC0yNy40NDMzOCBsIDYuMDIxNzUsLTkuNjk1NzEgMC4wMTMyLDEzLjE3MjIzIGMgMC4wMTYyLDE5LjA3MzggLTEyLjQyNjE5LDI5LjEyNzQgLTUxLjY5ODE3LDQxLjc2NzkzIC05Ljc3NjQ5LDMuMTQ2OCAtMTguMTgzMzIsNi4wNTQ0MSAtMTguNjgxOCw2LjQ2MTM3IC0xLjgyMDU2LDEuNDg2MzIgMTYuNjg3MzksMjcuNDc1NzEgMTkuNTY2NDQsMjcuNDc1NzEgMS42MzI2MiwwIDExLjE5MTE1LC0yLjM2MzU5IDIxLjI0MTIzLC01LjI1MjM4IHogTSA0NzYuNDExLDIxNy45NjMwMSBjIDQuNjYzNDcsLTUuMTUzMSA1LjQ4NTUxLC0xMC43NTEwMyA0LjQ4NTc5LC0zMC41NDgyMyAtMS4wODczOSwtMjEuNTMzMzEgLTIuMjc3NDYsLTI1LjMzODUxIC0xMC42NjE0MywtMzQuMDg5NDkgLTE1LjE0ODgyLC0xNS44MTE5NCAtMzMuODYxMjMsLTExLjc3ODI4IC0yMi45MDgxOSw0LjkzODE0IDUuODIyNTYsOC44ODYzNyAxMi45MjU0LDcuMzY4NjQgMTAuNDE2NDEsLTIuMjI1ODEgLTEuOTk4NjQsLTcuNjQyNzYgMS43Mjk5OCwtNy44NDM1OCA4LjIyODM5LC0wLjQ0MzIyIDEyLjE5MzAxLDEzLjg4NTM3IDkuMTE1MzQsMzMuMTI2OTggLTUuMjk4NiwzMy4xMjY5OCAtOS44NjcxNiwwIC0xMi45NDE5NSwtNC4yMzE3NiAtMTkuMzczNTMsLTI2LjY2MzE4IC0yLjkzMDU5LC0xMC4yMjA4NyAtNi40OTk2NCwtMTguNTgzNDMgLTcuOTMxMjcsLTE4LjU4MzQzIC00Ljc2ODk5LDAgLTYuODkyODcsNC4yMDg3OCAtMy45MjcyMSw3Ljc4MjQgMS42MTA4OCwxLjk0MTEgNi4wNzIxOCwxNS44OTEyNyA5LjkxNDA0LDMxLjAwMDQxIDkuNjY5MDMsMzguMDI1OTYgMjMuMTc2NjYsNTEuMDQxNDUgMzcuMDU1NiwzNS43MDU0MyB6IG0gLTE4My43NzEyNSwwLjYwMzk1IGMgMS45ODk3OCwtMS4zMzUgMi44OTk3NSwtNy42NDg5MyAyLjA3ODY1LC0xNC40MjMgLTEuMzI0NDksLTEwLjkyNzAyIC0yLjA2NjYyLC0xMS43MjQxIC03Ljk3MjcsLTguNTYzMjcgLTguNDg3MzMsNC41NDIyNyAtMTcuNjA4MzksLTQuMDYzNTEgLTIwLjcwMjIyLC0xOS41MzI2IC0yLjM0NzA3LC0xMS43MzUzOCAtMy4wNjUyNiwtMTEuNTA0ODkgMTQuMDI1NzYsLTQuNTAxNDkgMi4xNDI4OCwwLjg3ODA4IDcuNTk2NzEsLTIuMTA0MDIgMTIuMTE5NjMsLTYuNjI2OTQgOC4yNzQwOCwtOC4yNzQwOCAxMC45OTgwMiwtMTguMjEyOTkgNC45OTE1NiwtMTguMjEyOTkgLTEuNzc3NTQsMCAtMy4yMzE5LDEuNDU0MzYgLTMuMjMxOSwzLjIzMTkgMCw0LjY0OTIzIC04Ljg0MjMxLDMuOTg5ODIgLTEwLjgzNDY1LC0wLjgwNzk3IC0xLjE2MjI0LC0yLjc5ODc5IC0zLjYzODA3LC0xLjgwNTkxIC04LjA1OTE1LDMuMjMxOSAtMy41MDk4NSwzLjk5OTQ4IC03Ljc5NjczLDcuMjcxNzggLTkuNTI2NDEsNy4yNzE3OCAtMS43Mjk2OSwwIC00LjA2NTYsLTMuMjcyMyAtNS4xOTA4OCwtNy4yNzE3OCAtMS45NzE5NSwtNy4wMDg1NiAtMi4yMTM2NiwtNy4wNTI3NyAtNi42NzczNywtMS4yMjE2OSAtMy45MTA2LDUuMTA4NTQgLTMuOTQ1NTcsNi43MzU4MyAtMC4yMjQ2MSwxMC40NTY2MSAzLjk0MDYyLDMuOTQwNjQgMTEuNDI2MTUsMzAuODcxMDIgMTEuNDI2MTUsNDEuMTA3NDQgMCwxMi43Mjg2NyAxNy41MjkzMywyMi43MzgzMiAyNy43NzgzLDE1Ljg2MjEgeiBtIDU4Ljk0MzA5LC0xNi44NzUzMSBjIDEyLjE0NTY3LC0xMi4xNDU2NyAxNS43NDQ1MiwtMzAuMzUxNDMgOS4xMjk0MywtNDYuMTgzNTcgLTUuMTcwMTYsLTEyLjM3Mzk3IC0xNC4xNDQ2NiwtMTcuMDA1MTYgLTI2Ljc5ODc4LC0xMy44MjkxOCAtOS40MDI2MywyLjM1OTkxIC0yMy43MjMxMSwyOS43NzY1OSAtMjMuNzczODcsNDUuNTE1MzYgLTAuMDc5MiwyNC41MjkwMiAyMy4yNTA1MywzMi42OTAwNSA0MS40NDMyMiwxNC40OTczOSB6IG0gLTIyLjA4MzQxLC0xOS40MzQwNyBjIC0zLjU1NTEsLTMuNTU1MSAtNi40MTc1NSwtMTAuNDYzMjggLTYuMzYxMDIsLTE1LjM1MTUzIDAuMDkzNCwtOC4wNzk2NSAwLjQ5MzE1LC04LjM3MzUgNC4zOTYxOSwtMy4yMzE5IDQuODI0NjQsNi4zNTU2OSAxMy4zOTc5Nyw3LjQ1NjY2IDE2LjY4MjQxLDIuMTQyMzIgMS4xOTQzMiwtMS45MzI0MSAwLjU1Mjk1LC01LjEzMjAyIC0xLjQyNTIsLTcuMTEwMTcgLTUuMDgxMzIsLTUuMDgxMzIgLTQuNDY1NjEsLTExLjk5OTYzIDEuMDY3OTIsLTExLjk5OTYzIDYuMTUxMzcsMCAxNC43MjY3OSwxMi41MTQ3NyAxNC43MjY3OSwyMS40OTE5MSAwLDYuNjA2NzQgLTEzLjQ0NDQsMjAuNTIyOCAtMTkuODI3MjQsMjAuNTIyOCAtMS41Mzc4NSwwIC01LjcwNDc2LC0yLjkwODcyIC05LjI1OTg1LC02LjQ2MzggeiBtIDg2LjM0ODk3LDE4LjU4MzQxIGMgMTMuNDEwNzQsLTE0LjYwMjYzIDEyLjEwMzc2LC0zNy4wOTggLTMuMDk4MjUsLTUzLjMyNjM0IC03Ljg1MDU3LC04LjM4MDYgLTI1LjI5Mjk4LC05LjgyNTUyIC0zMi40MzE4NSwtMi42ODY2NCAtNi41ODc2MSw2LjU4NzYxIC0xMy4xNjQ2NSwzMi40OTMwMyAtMTAuNzIxMjIsNDIuMjI4NDEgNS4yMTEyMiwyMC43NjMxOCAzMi40MDA0MSwyOC44NjY1MiA0Ni4yNTEzMiwxMy43ODQ1NyB6IG0gLTI3LjQ1NTY1LC0yMy42MTQ1MiBjIC01LjMwNjIzLC0zLjcxNjY0IC03LjEyOTQxLC04LjE0OTc0IC02Ljk3ODA2LC0xNi45Njc0NyAwLjE2OTM1LC05Ljg2MDMzIDAuNjg0MywtMTAuNzQ5ODEgMi45NjE0NSwtNS4xMTQxNSAzLjM0NTczLDguMjgwMzIgMTAuMzYyOTIsMTEuNDA3MzQgMTYuNTE4MTQsNy4zNjA5IDMuODE3NTMsLTIuNTA5NjMgMy42MzkyOSwtMy42OTU5NyAtMS4xMDEwNCwtNy4zMjkwNyAtNi4zMjE4OSwtNC44NDUyMyAtNy41NTUwOCwtMTEuNzAxOTEgLTIuMTA0NjUsLTExLjcwMTkxIDQuODczNjQsMCAyMi4zMDQwMiwxOS4wNjY2NiAyMi4zMDQwMiwyNC4zOTc3OCAwLDUuMjAzMTYgLTEyLjM3NzM5LDE0LjM4NTAzIC0xOS4zOTEzOSwxNC4zODUwMyAtMi43NjQwNSwwIC04LjI1NzksLTIuMjY0MDIgLTEyLjIwODQ3LC01LjAzMTExIHogbSAxODkuOTYyOTIsLTE0LjI4ODg3IDMzLjkzNDk1LC0xMi43MzY4MiAtMzYuMzU4ODgsLTAuMTMxMjUgYyAtMzIuNTM5MiwtMC4xMTczNiAtMzYuMzU0MjQsMC40NjMwNyAtMzYuMzE0NzUsNS41MjQ3NSAwLjA0MDEsNS4xMjc1NyAzLjMzMDczLDIwLjI4Mzk1IDQuMzcyNywyMC4xMzk2NyAwLjIzNzIyLC0wLjAzMjkgMTUuNzAxNzcsLTUuNzkxMjQgMzQuMzY1OTgsLTEyLjc5NjQ4IHogbSAtNDQzLjQ5MzQzLC0yLjI3OTMgMy40NjgyNSwtMTAuMjg3NjEgLTMwLjQ2Njg2LC0xLjAyNDA0IGMgLTE2Ljc1Njc0NCwtMC41NjMyMiAtMzAuNDYzNTg0LC0wLjEzMjEzIC0zMC40NTk1OCwwLjk1ODA0IDAuMDA1OCwxLjU5NTEzIDUyLjUwNjU3LDIyLjEwNzA3IDUzLjY2MTc0LDIwLjk2NTUyIDAuMTgwMzUsLTAuMTc4NCAxLjg4ODkyLC00Ljk1MzcyIDMuNzk2NDUsLTEwLjYxMTkxIHogbSAyMDguOTA5MiwtMzEuODg2OTUgYyA3LjE2NjY3LDEuMTQ2IDE1LjI0OTgxLDQuMDc5MjQgMTcuOTYyNTYsNi41MTgzNSA0LjIxMjc5LDMuNzg3ODMgNi4wNDUyOCwzLjUyOTY2IDEyLjU2MjA3LC0xLjc2OTg1IDQuMTk2NDMsLTMuNDEyNSA5LjY1MDI2LC02LjIwNDU3IDEyLjExOTYzLC02LjIwNDU3IDIuNDY5MzksMCA0LjQ4OTgyLC0wLjcxMzA4IDQuNDg5ODIsLTEuNTg0NjcgMCwtMy4wMDkxOCAtNDYuNTM5NTQsLTc5LjIxMjUyIC00OC4zMTQ0NywtNzkuMTA5NjEgLTIuMDg1LDAuMTIwODcyIC00OS43ODYwMyw4MC4wODc5OCAtNTEuMjU0NjQsODUuOTI0MzcgLTAuNjE2MzQsMi40NDk1MiAxLjMxODA0LDMuMzUzNzEgNS4wNzM2NCwyLjM3MTYgMy4zMzgzNiwtMC44NzMgNy45NTQxNiwwLjY4MzI2IDEwLjI1NzI3LDMuNDU4MzYgMy43MzU0LDQuNTAwODcgNS4yNjEwOCw0LjE0MjI5IDE0LjEzMDY4LC0zLjMyMDk3IDguNDI2NDcsLTcuMDkwNDEgMTEuOTMwOCwtOC4wNDg4IDIyLjk3MzQ0LC02LjI4MzAxIHoiDQogICAgICAgc3R5bGU9ImZpbGw6IzMzMzMzMztmaWxsLW9wYWNpdHk6MSIgLz4NCiAgICA8cGF0aA0KICAgICAgIHN0eWxlPSJmaWxsOiM2Mzk4YWE7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiDQogICAgICAgZD0ibSAzMDkuNTQ1NzksMTQwLjg3OTIyIGMgLTAuNTAwNzUsLTAuMjMzMTEgLTEuMTE4MDQsLTAuNzY3OTkgLTIuNTI3OCwtMi4xOTAzNSAtMS45MTE4OCwtMS45Mjg5NyAtMi42NzE4OCwtMi40OTAxMyAtNC4yNjEwOCwtMy4xNDYyOCAtMi4wODc5MSwtMC44NjIwNCAtNC4zNTQ5LC0xLjA5NDIzIC02LjQ4MjMxLC0wLjY2MzkxIC0xLjg5ODA4LDAuMzgzOTMgLTIuNDI0MzUsMC40MjUyNyAtMy4yODI0MiwwLjI1NzggLTEuNDMyMjQsLTAuMjc5NTMgLTEuOTQxNTcsLTEuMTQ5MjkgLTEuNTM1ODMsLTIuNjIyNzIgMC41MDU3MywtMS44MzY1NyA0LjMzNjkzLC04Ljk0MjU1IDEyLjAwODk5LC0yMi4yNzM4NyAxNS41ODM3LC0yNy4wNzg5ODggMzYuNTM2MjQsLTYxLjIyMDk2OCAzOC44NTA1NiwtNjMuMzA2NjYyIDAuMjU2MzEsLTAuMjMwOTk0IDAuMjY1LC0wLjIzMDk5NCAwLjUyMjQ4LDAgMS4zNzc2OCwxLjIzNTk3NiA5LjQ3NjIsMTMuNzI1ODg5IDIwLjU0MDM2LDMxLjY3ODI5OCAxNC45NjY5NiwyNC4yODUwMDQgMjcuNDExMDIsNDUuNjQzNzE0IDI3LjQxMTAyLDQ3LjA0NzcwNCAwLDAuODU3MjkgLTEuMzE2MDgsMS4zNzIxNSAtNC4wODU5MSwxLjU5ODQ1IC0zLjQ0MjI2LDAuMjgxMjQgLTcuNDI0NzgsMi4zMDE4OCAtMTIuODY4ODcsNi41MjkzNiAtMi41ODcxMiwyLjAwODk4IC0zLjY5MTI2LDIuNzU5MzMgLTQuOTUwNjIsMy4zNjQzOCAtMS4wNDkyOCwwLjUwNDExIC0xLjEzNjkyLDAuNTI0MzcgLTIuMjY4NTQsMC41MjQzNyAtMS4xMTM2OCwwIC0xLjIyNjYxLC0wLjAyNDkgLTIuMDk2MjMsLTAuNDYxMjggLTAuNTEyMTMsLTAuMjU3MDIgLTEuNTA0NjksLTAuOTQ5MyAtMi4yNDE1NSwtMS41NjM0MiAtMi4xNzg0OCwtMS44MTU2MSAtNC43OTkxOCwtMy4xMzYxNCAtOS4wNzE5NywtNC41NzEyNCAtNS40Mjk5NywtMS44MjM3NiAtMTEuMjQ0NTQsLTIuOTE4NCAtMTYuMTk1NTEsLTMuMDQ4OTYgLTMuOTA5MzQsLTAuMTAzMDggLTUuNzEyMDEsMC4yNDc5OCAtOC42NzYwMiwxLjY4OTYzIC0yLjQxOTg4LDEuMTc2OTggLTMuNTg2MjEsMi4wMTMxMSAtOS4xMjQ3NSw2LjU0MTQ1IC01LjYzMzc2LDQuNjA2MTcgLTcuNjM0NDIsNS41NjIwNSAtOS42NjQsNC42MTcyNSB6IiAvPg0KICAgIDxwYXRoDQogICAgICAgc3R5bGU9ImZpbGw6IzYzOThhYTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSINCiAgICAgICBkPSJtIDEyOC42Mzc4NiwxNzAuNzM5IGMgLTEwLjE1OSwtMi45NjA3IC00NS41MDMxNzEsLTE2LjkxOTYyIC01MC40NTA5MjQsLTE5LjkyNTIzIC0wLjY4MjkxNiwtMC40MTQ4NCAtMC43MzgwOTgsLTAuNDc3ODcgLTAuNTQzMjA3LC0wLjYyMDM4IDEuMTMxNTYzLC0wLjgyNzQxIDEyLjMzNzk4MywtMS4yMzkwMSAyNS4wMDQwMzEsLTAuOTE4MzYgNS4wNTEzMSwwLjEyNzg4IDM1LjUwMTMyLDEuMTMzMjMgMzUuNTUwOSwxLjE3Mzc3IDAuMDk5NywwLjA4MTUgLTYuNTIxNjQsMTkuMjg4OCAtNy4wMzA1MSwyMC4zOTQzMyAtMC4yMTI1MSwwLjQ2MTcgLTAuNjUwNjMsMC40NDM2NyAtMi41MzAyOSwtMC4xMDQxMyB6IiAvPg0KICAgIDxwYXRoDQogICAgICAgc3R5bGU9ImZpbGw6IzYzOThhYTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSINCiAgICAgICBkPSJtIDU0My42OTQxMywxNzUuMzEwNTUgYyAtMS4zODYyLC0yLjcxMjg3IC0zLjg4NzY5LC0xNC45NzA2NyAtMy45NjA3OCwtMTkuNDA4NTggLTAuMDI4NCwtMS43MjQyNCAwLjE4NjY3LC0yLjQyNzQxIDAuOTYwNiwtMy4xNDA4IDEuNzczNzgsLTEuNjM1MDEgNS4zNzkzOCwtMi4yMjMyIDE1LjI5MDE3LC0yLjQ5NDM0IDUuMDAzNDcsLTAuMTM2ODkgMjguMTAxOSwtMC4xNTc5NiA0NC40MTEyNywtMC4wNDA1IGwgMTEuNDI4NTksMC4wODIzIC0yNy41MTc3LDEwLjMxNDI3IGMgLTI1LjA5MjkyLDkuNDA1NCAtMzkuNjg0NzMsMTQuODQxMjYgLTQwLjIyNDkxLDE0Ljk4NDkgLTAuMTM1MTcsMC4wMzYgLTAuMjY5ODEsLTAuMDY3NCAtMC4zODcyNCwtMC4yOTcyMyBsIDAsMCB6IiAvPg0KICAgIDxwYXRoDQogICAgICAgc3R5bGU9ImZpbGw6IzYzOThhYTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSINCiAgICAgICBkPSJtIDE3OC4wODgzNSwzMTUuNTE0MzMgYyAwLC0wLjc3MDc4IDMuMjY4OSwtNi41MzMxIDExLjU1Mzk1LC0yMC4zNjY5OCAxOS44NTExOCwtMzMuMTQ2MzEgMjguOTI3MTUsLTQ1LjE2MDEyIDQwLjA3MjkyLC01My4wNDQyOSA5Ljk3MTI3LC03LjA1MzM3IDE1LjMwMjc5LC0xMS45Mjk0IDIxLjI0NTM5LC0xOS40MzAzMyBsIDMuNjY0MDksLTQuNjI0OTIgNC45Mzk5LDQuODU2NTIgYyA4LjY0Nzg0LDguNTAxODkgMTMuODYxMywxMC45NjY2OCAyMy4yOTcxNywxMS4wMTQzMiAxMS41NDA1OCwwLjA1ODMgMjQuMTc4NDksLTYuMzg4MSAyNC4xNzg0OSwtMTIuMzMyOTkgMCwtMS4zMzk4IDAuOTU0MDQsLTIuNzIyMzYgMS44Nzg1NywtMi43MjIzNiAwLjM5MTMyLDAgMi42MTY4NiwwLjY4MzY1IDQuOTQ1NjUsMS41MTkyMyA2LjA2OTkyLDIuMTc3OSA5LjYzMDI4LDIuOTY1NDggMTQuNjA5MTIsMy4yMzE2NSA0LjkzOTk4LDAuMjY0MDkgOC41NDg0OCwtMC4xNzA0IDEzLjM1ODE3LC0xLjYwODQxIDQuNzI1NjEsLTEuNDEyODggNy40NDcwOSwtMi44NTkwNSAxNS41OTgzMywtOC4yODg4MiA0LjEwNzYsLTIuNzM2MTggNy41OTk1NCwtNC45NzQ4NyA3Ljc1OTg4LC00Ljk3NDg3IDAuMTYwMzMsMCAzLjEyNTM0LDEuNzE4OTYgNi41ODg5LDMuODE5OTEgMy40NjM1NiwyLjEwMDk1IDcuNjI1NDIsNC4zODEzMyA5LjI0ODU5LDUuMDY3NTEgMTEuMDY4NjIsNC42NzkxOCAyMy4wMjQ0NSw0LjM3MzkgMzMuOTcxMjYsLTAuODY3NDEgMS45NTc5NSwtMC45Mzc0NyA2LjU2NzkzLC0zLjczMDc0IDEwLjI0NDQsLTYuMjA3MjcgMy42NzY0OCwtMi40NzY1MyA2LjczNjEzLC00LjQ0NTc2IDYuNzk5MjMsLTQuMzc2MDYgMC4wNjMxLDAuMDY5NyAxLjQ1NjA1LDIuOTIwOCAzLjA5NTQ0LDYuMzM1NzggMS42Mzk0LDMuNDE0OTggMy42OTg5NSw3LjI2NjcgNC41NzY3OSw4LjU1OTM3IDMuODAwMDEsNS41OTU3OCA4LjE3NTg4LDkuNzUxNDEgMTQuMDgzNDMsMTMuMzc0NjQgNi4wODEyMiwzLjcyOTc1IDkuODMyMDYsOC42ODY4IDEwLjIxODgyLDEzLjUwNTA3IDAuMzgzNjcsNC43Nzk2OCAtMS43MDMyOSw5LjAxOTM5IC03LjcyMTg5LDE1LjY4NzIxIC00LjY5NzQ3LDUuMjA0MTkgLTUuODczMyw3LjIzNTQgLTUuODYxMTMsMTAuMTI0OTEgMC4wMTIyLDIuODkyNjIgMS43MDEwMyw2LjIyODU0IDQuNjY5NjQsOS4yMjM3OSA0LjgwNTMzLDQuODQ4NDQgMTIuMzQ2MDUsNi4yODc3NyAyMy40MzUzNCw0LjQ3MzE5IDIuNDc0MDgsLTAuNDA0ODQgNS41OTQ3OSwtMC43Mzc1NyA2LjkzNDkxLC0wLjczOTM4IDQuMjg1NTEsLTAuMDA2IDYuOTAzMTksMi4wOTU5NSAxMS44OTI1MSw5LjU0ODU5IDMuNDQzNTEsNS4xNDM2NSAxMC45NzM5NiwxNy43NTUwOCAxMC45NzM5NiwxOC4zNzgzNiAwLDAuMzI0MDcgLTAuMzUxNDUsMC41NTIwOCAtMC44NTA5NywwLjU1MjA4IC0xLjA1MTA5LDAgLTUuNjIzMTQsLTEuMjQzOCAtOC45MzIxNCwtMi40Mjk5NCAtNC4zNDg1LC0xLjU1ODc1IC01Ny4yNzIzOCwtMjIuMDA1MjYgLTc0Ljc0Nzg2LC0yOC44Nzc5NSAtNDYuNjYzNSwtMTguMzUxNjIgLTYyLjAyODA1LC0yNC4yMTI0NiAtNjkuNTM2NTcsLTI2LjUyNDg5IC04LjExNDE3LC0yLjQ5ODk1IC0xMy42NDAyOSwtMy4wODUyMiAtMTguMTI2NjEsLTEuOTIzMDYgLTUuNTc5OTYsMS40NDU0NiAtODEuNzIwNjcsMzAuODY4ODggLTEyNi4xMzI0NSw0OC43NDE5NSAtMjEuOTMxMTksOC44MjYgLTI0LjY3NzQ5LDkuODc1NzcgLTI4Ljc4MTE2LDExLjAwMTU5IC0zLjI2MzAzLDAuODk1MjEgLTMuMTQ0MDcsMC44ODI5NCAtMy4xNDQwNywwLjMyNDI2IHoiIC8+DQogIDwvZz4NCjwvc3ZnPg=='); background-position: 16px 80%; background-repeat: no-repeat; background-size: 20px 12px; padding-left: 2.5em; } .multi-language-selector .language-option[data-lang='kotlin'], .exampleblock[data-lang=kotlin] > .content .title { background-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 8 8' xmlns='http://www.w3.org/2000/svg'><linearGradient id='g' gradientUnits='userSpaceOnUse' x1='8' y1='0' x2='0' y2='8'><stop offset='0' stop-color='%23e44857'/><stop offset='.4689' stop-color='%23c711e1'/><stop offset='1' stop-color='%237f52ff'/></linearGradient><polygon fill='url(%23g)' points='8 8 0 8 0 0 8 0 4 4'/></svg>"); background-position: 17px 80%; background-repeat: no-repeat; background-size: 11px 11px; padding-left: 2.3em; } .multi-language-selector { display: block; } .multi-language-selector .language-option[data-lang='groovy'] { background-position: 20px center; padding-left: 32px; } .multi-language-selector .language-option[data-lang='kotlin'] { background-position: 30px center; padding-left: 27px; } .multi-language-selector .language-option { background-color: white; border: 1px solid #f7f7f8; border-radius: 4px 4px 0 0; cursor: pointer; display: inline-block; font-weight: normal; font-family: 'Lato', Arial, sans-serif; margin: 0; padding: 4px 20px; min-width: 130px; max-width: 320px; text-align: center; filter: grayscale(1); -webkit-filter: grayscale(1); opacity: 0.7; } .multi-language-selector .language-option.selected { background-color: #f7f7f8; color: #02303a; filter: none; -webkit-filter: none; opacity: 1; } .multi-language-text.hidden, .multi-language-selector ~ .multi-language-sample.hidden { display: none; } .multi-language-sample { border-radius: 0 0 4px 4px; } body.dark-theme { .multi-language-selector .language-option { background-color: #1f1f1f; border: 1px solid #1e1e22; } .multi-language-selector .language-option.selected { background-color: #2c2c2c; color: white; } } @media (prefers-color-scheme: dark) { .multi-language-selector .language-option { background-color: #1f1f1f; border: 1px solid #1e1e22; } .multi-language-selector .language-option.selected { background-color: #2c2c2c; color: white; } body.light-theme { .multi-language-selector .language-option { background-color: #white; border: 1px solid #f7f7f8; } .multi-language-selector .language-option.selected { background-color: #f7f7f8; color: #02303a; } } } </style><script type="text/javascript">function postProcessCodeBlocks() { // Assumptions: // 1) All siblings that are marked with class="multi-language-sample" should be grouped // 2) Only one language can be selected per domain (to allow selection to persist across all docs pages) // 3) There is exactly 1 small set of languages to choose from. This does not allow for multiple language preferences. For example, users cannot prefer both Kotlin and ZSH. // 4) Only 1 sample of each language can exist in the same collection. var GRADLE_DSLs = ["kotlin", "groovy"]; var preferredBuildScriptLanguage = initPreferredBuildScriptLanguage(); // Ensure preferred DSL is valid, defaulting to Kotlin DSL function initPreferredBuildScriptLanguage() { var lang = window.localStorage.getItem("preferred-gradle-dsl"); if (GRADLE_DSLs.indexOf(lang) === -1) { window.localStorage.setItem("preferred-gradle-dsl", "kotlin"); lang = "kotlin"; } return lang; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function processSampleEl(sampleEl, prefLangId) { var codeEl = sampleEl.querySelector("code[data-lang]"); if (codeEl != null) { sampleEl.setAttribute("data-lang", codeEl.getAttribute("data-lang")); if (codeEl.getAttribute("data-lang") !== prefLangId) { sampleEl.classList.add("hidden"); } else { sampleEl.classList.remove("hidden"); } } } function switchSampleLanguage(languageId) { var multiLanguageSampleElements = [].slice.call( document.querySelectorAll(".multi-language-sample") ); // Array of Arrays, each top-level array representing a single collection of samples var multiLanguageSets = []; for (var i = 0; i < multiLanguageSampleElements.length; i++) { var currentCollection = [multiLanguageSampleElements[i]]; var currentSampleElement = multiLanguageSampleElements[i]; processSampleEl(currentSampleElement, languageId); while ( currentSampleElement.nextElementSibling != null && currentSampleElement.nextElementSibling.classList.contains( "multi-language-sample" ) ) { currentCollection.push(currentSampleElement.nextElementSibling); currentSampleElement = currentSampleElement.nextElementSibling; processSampleEl(currentSampleElement, languageId); i++; } multiLanguageSets.push(currentCollection); } multiLanguageSets.forEach(function (sampleCollection) { // Create selector element if not existing if ( sampleCollection.length > 1 && (sampleCollection[0].previousElementSibling == null || !sampleCollection[0].previousElementSibling.classList.contains( "multi-language-selector" )) ) { var languageSelectorFragment = document.createDocumentFragment(); var multiLanguageSelectorElement = document.createElement("div"); multiLanguageSelectorElement.classList.add("multi-language-selector"); languageSelectorFragment.appendChild(multiLanguageSelectorElement); sampleCollection.forEach(function (sampleEl) { var optionEl = document.createElement("code"); var sampleLanguage = sampleEl.getAttribute("data-lang"); optionEl.setAttribute("data-lang", sampleLanguage); optionEl.setAttribute("role", "button"); optionEl.classList.add("language-option"); optionEl.innerText = capitalizeFirstLetter(sampleLanguage); optionEl.addEventListener( "click", function updatePreferredLanguage(evt) { var preferredLanguageId = optionEl.getAttribute("data-lang"); window.localStorage.setItem( "preferred-gradle-dsl", preferredLanguageId ); // Record how far down the page the clicked element is before switching all samples var beforeOffset = evt.target.offsetTop; switchSampleLanguage(preferredLanguageId); // Scroll the window to account for content height differences between different sample languages window.scrollBy(0, evt.target.offsetTop - beforeOffset); } ); multiLanguageSelectorElement.appendChild(optionEl); }); sampleCollection[0].parentNode.insertBefore( languageSelectorFragment, sampleCollection[0] ); } }); [].slice .call( document.querySelectorAll(".multi-language-selector .language-option") ) .forEach(function (optionEl) { if (optionEl.getAttribute("data-lang") === languageId) { optionEl.classList.add("selected"); } else { optionEl.classList.remove("selected"); } }); [].slice .call(document.querySelectorAll(".multi-language-text")) .forEach(function (el) { if (!el.classList.contains("lang-" + languageId)) { el.classList.add("hidden"); } else { el.classList.remove("hidden"); } }); } switchSampleLanguage(preferredBuildScriptLanguage); } document.addEventListener("DOMContentLoaded", function () { postProcessCodeBlocks(); }); </script> <!-- Prefetch header and footer if on Gradle 4.4 and lower only --> <!-- Load build-tool.css if on Gradle<=4.4 or release notes --> <!-- Load build-tool.css if on Gradle<8.0 and javadoc --> <!-- Load build-tool-modern.css if on Gradle>=8.0 and javadoc --> <!-- Load decorate.css if on Gradle<=4.3 for user manual, Gradle<=4.4 for DSL Reference, or Gradle<=4.5 for Javadoc --> <style type="text/css"> cloudflare-app[app="cookiless"] cookiless-div { font-family: "Lato","Helvetica Neue",Arial,sans-serif; font-weight: 300; background-color: #02303A !important; opacity: 1 !important; } cloudflare-app[app="cookiless"] cookiless-div .iAccept { font-weight: 400; } @media (max-width: 1023px) { .notification { display: none; } } @media (min-width: 1024px) { cloudflare-app[app="cookiless"] { position: fixed !important; width: 400px !important; left: auto !important; right: 0 !important; bottom: 0 !important; } /* Overrides for banner */ .notification { height: 44px; line-height: 44px; vertical-align: middle; background-color: #02303A; text-align: center; color: white; z-index: 1; } .notification a { color: white; text-decoration: underline; } .notification ~ .main-content #header #toc, .notification ~ .main-content .toc { top: 98px; } } </style> <!-- Load common JS for all Gradle versions --> <script src="/build-tool.js" type="text/javascript" defer></script> <!-- Google Tag Manager --> <script> (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-WRTQKGT'); </script> <!-- End Google Tag Manager --> <!-- Inject new header and footer for Gradle<=4.4 or release notes--> <script type="text/javascript" defer> window.siteDecorateVersion = "8.11.1"; </script> <!-- Load DocSearch assets if on current manual, dsl, or samples --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-theme-classic"> <script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.23.3/dist/algoliasearch-lite.umd.js"></script> <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.69.0/dist/instantsearch.production.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-js"></script> <script src="/build-tool-search.js" type="text/javascript" defer></script> <link rel="stylesheet" href="/build-tool-search.css"> <!--Load ratings css and js if on current user manual --> <link rel="stylesheet" href="/build-tool-rating.css"> <script src="/build-tool-rating.js" type="text/javascript" defer></script> <!--Load banner css, html and js if on current user manual --> <link rel="stylesheet" href="/build-tool-banner.css"> <script src="/build-tool-banner.js" type="text/javascript" defer></script> <!-- Canonical Link and Structured Data for SEO --> <link rel="canonical" href="https://docs.gradle.org/current/userguide/component_metadata_rules.html" /> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "WebPage", "name": "Gradle Documentation", "url": "https://docs.gradle.org/current/userguide/component_metadata_rules.html" } </script> <meta name="google-site-verification" content="kCnBfMu0lbnMpfg3t1-ZgJHbSOSYRSquWsxQ4HgqLkA" /></head> <body id="component-metadata-rules" class="book"><!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-WRTQKGT" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) --> <div class="layout"> <header class="site-layout__header site-header" itemscope="itemscope" itemtype="https://schema.org/WPHeader"> <nav class="site-header__navigation" itemscope="itemscope" itemtype="https://schema.org/SiteNavigationElement"> <div class="site-header__navigation-header"> <a target="_top" class="logo" href="https://docs.gradle.org" title="Gradle Docs"> <svg width="139px" height="43px" viewBox="0 0 278 86" version="1.1" xmlns="http://www.w3.org/2000/svg"> <title>Gradle</title> <path class="cls-1" d="M155,56.32V70.27a18.32,18.32,0,0,1-5.59,2.83,21.82,21.82,0,0,1-6.36.89,21.08,21.08,0,0,1-7.64-1.31A17.12,17.12,0,0,1,129.59,69a16.14,16.14,0,0,1-3.73-5.58,18.78,18.78,0,0,1-1.31-7.08,19.58,19.58,0,0,1,1.26-7.14A15.68,15.68,0,0,1,135,40a20.39,20.39,0,0,1,7.45-1.29,22,22,0,0,1,3.92.33,20.43,20.43,0,0,1,3.39.92,15.16,15.16,0,0,1,2.85,1.42A17.3,17.3,0,0,1,155,43.25l-1.84,2.91a1.72,1.72,0,0,1-1.12.84,2,2,0,0,1-1.5-.34L149,45.75a10.49,10.49,0,0,0-1.75-.79,14.33,14.33,0,0,0-2.17-.54,15.29,15.29,0,0,0-2.78-.22,11.91,11.91,0,0,0-4.61.86,9.66,9.66,0,0,0-3.52,2.46,10.9,10.9,0,0,0-2.24,3.84,14.88,14.88,0,0,0-.79,5,15.23,15.23,0,0,0,.85,5.28,11.06,11.06,0,0,0,2.38,3.94A10.15,10.15,0,0,0,138.05,68a14.28,14.28,0,0,0,8.25.44,17.1,17.1,0,0,0,2.94-1.09V61.14h-4.35a1.3,1.3,0,0,1-1-.35,1.15,1.15,0,0,1-.35-.85V56.32Zm10.47-2.93a10.53,10.53,0,0,1,2.72-3.45,5.77,5.77,0,0,1,3.72-1.25,4.5,4.5,0,0,1,2.72.74l-.38,4.41a1.18,1.18,0,0,1-.34.61,1,1,0,0,1-.61.18,6.76,6.76,0,0,1-1.06-.12,8.22,8.22,0,0,0-1.38-.12,5,5,0,0,0-1.74.28,4.37,4.37,0,0,0-1.37.83,5.55,5.55,0,0,0-1.07,1.3,12.26,12.26,0,0,0-.87,1.74V73.61H160V49.14h3.45a1.94,1.94,0,0,1,1.27.32,1.9,1.9,0,0,1,.48,1.16Zm11.36-.84A14.49,14.49,0,0,1,187,48.69a9.92,9.92,0,0,1,3.84.7,8.06,8.06,0,0,1,2.86,2,8.38,8.38,0,0,1,1.78,3,11.64,11.64,0,0,1,.61,3.82V73.61h-2.68a2.64,2.64,0,0,1-1.28-.25,1.72,1.72,0,0,1-.72-1l-.52-1.77a20.25,20.25,0,0,1-1.82,1.47,10.86,10.86,0,0,1-1.83,1.06,10.36,10.36,0,0,1-2,.66,12,12,0,0,1-2.4.22,9.64,9.64,0,0,1-2.86-.41,6.28,6.28,0,0,1-2.27-1.26,5.6,5.6,0,0,1-1.48-2.07,7.38,7.38,0,0,1-.52-2.89,5.7,5.7,0,0,1,.31-1.85,5.3,5.3,0,0,1,1-1.75,8.25,8.25,0,0,1,1.83-1.57,11.17,11.17,0,0,1,2.75-1.29,23.28,23.28,0,0,1,3.81-.9,36.77,36.77,0,0,1,5-.41V58.16a5.35,5.35,0,0,0-1.05-3.64,3.83,3.83,0,0,0-3-1.18,7.3,7.3,0,0,0-2.38.33,9.39,9.39,0,0,0-1.65.75l-1.3.75a2.52,2.52,0,0,1-1.3.34,1.7,1.7,0,0,1-1.05-.32,2.61,2.61,0,0,1-.69-.76Zm13.5,10.61a31.66,31.66,0,0,0-4.3.45,11,11,0,0,0-2.79.82,3.57,3.57,0,0,0-1.5,1.17,2.89,2.89,0,0,0,.47,3.67,3.93,3.93,0,0,0,2.39.67,7,7,0,0,0,3.14-.66,9.52,9.52,0,0,0,2.59-2Zm32.53-25V73.61h-3.6a1.39,1.39,0,0,1-1.48-1.07l-.5-2.36a12.4,12.4,0,0,1-3.4,2.74,9.17,9.17,0,0,1-4.47,1,7.95,7.95,0,0,1-6.55-3.26A11.61,11.61,0,0,1,201,66.79a19.71,19.71,0,0,1-.66-5.34,16.77,16.77,0,0,1,.74-5.06,12.21,12.21,0,0,1,2.13-4,9.88,9.88,0,0,1,3.31-2.69,9.64,9.64,0,0,1,4.34-1,8.63,8.63,0,0,1,3.51.64,9,9,0,0,1,2.6,1.74V38.17ZM217,55.39a5.94,5.94,0,0,0-2.18-1.72,6.54,6.54,0,0,0-2.54-.5,5.68,5.68,0,0,0-2.41.5A4.87,4.87,0,0,0,208,55.19a7.19,7.19,0,0,0-1.17,2.57,14.83,14.83,0,0,0-.4,3.69,16.34,16.34,0,0,0,.34,3.63,7.14,7.14,0,0,0,1,2.44,3.79,3.79,0,0,0,1.58,1.36,5,5,0,0,0,2.07.41,6,6,0,0,0,3.13-.76A9.19,9.19,0,0,0,217,66.36Zm17.67-17.22V73.61h-5.89V38.17ZM245.1,62.11a11.37,11.37,0,0,0,.67,3.26,6.54,6.54,0,0,0,1.38,2.27,5.39,5.39,0,0,0,2,1.33,7.26,7.26,0,0,0,2.61.44,8.21,8.21,0,0,0,2.47-.33,11.51,11.51,0,0,0,1.81-.74c.52-.27,1-.52,1.36-.74a2.31,2.31,0,0,1,1.13-.33,1.21,1.21,0,0,1,1.1.55L261.36,70a9.45,9.45,0,0,1-2.19,1.92,12.18,12.18,0,0,1-2.54,1.24,14,14,0,0,1-2.7.66,18.78,18.78,0,0,1-2.65.19,12.93,12.93,0,0,1-4.75-.85,10.65,10.65,0,0,1-3.82-2.5,11.8,11.8,0,0,1-2.55-4.1,15.9,15.9,0,0,1-.93-5.67,13.55,13.55,0,0,1,.81-4.71,11.34,11.34,0,0,1,2.33-3.84,11,11,0,0,1,3.69-2.59,12.31,12.31,0,0,1,4.93-1,11.86,11.86,0,0,1,4.27.74,9.25,9.25,0,0,1,3.36,2.16,9.84,9.84,0,0,1,2.21,3.48,13,13,0,0,1,.8,4.71,3.82,3.82,0,0,1-.29,1.8,1.19,1.19,0,0,1-1.1.46Zm11.23-3.55A7.28,7.28,0,0,0,256,56.4a5.16,5.16,0,0,0-1-1.77,4.44,4.44,0,0,0-1.63-1.21,5.68,5.68,0,0,0-2.3-.44,5.46,5.46,0,0,0-4,1.45,7.13,7.13,0,0,0-1.87,4.13ZM112.26,14a13.72,13.72,0,0,0-19.08-.32,1.27,1.27,0,0,0-.41.93,1.31,1.31,0,0,0,.38.95l1.73,1.73a1.31,1.31,0,0,0,1.71.12,7.78,7.78,0,0,1,4.71-1.57,7.87,7.87,0,0,1,5.57,13.43C96,40.2,81.41,9.66,48.4,25.37a4.48,4.48,0,0,0-2,6.29l5.66,9.79a4.49,4.49,0,0,0,6.07,1.67l.14-.08-.11.08,2.51-1.41a57.72,57.72,0,0,0,7.91-5.89,1.37,1.37,0,0,1,1.8-.06h0a1.29,1.29,0,0,1,0,2A59.79,59.79,0,0,1,62.11,44l-.09.05-2.51,1.4a7,7,0,0,1-3.47.91,7.19,7.19,0,0,1-6.23-3.57l-5.36-9.24C34.17,40.81,27.93,54.8,31.28,72.5a1.31,1.31,0,0,0,1.29,1.06h6.09A1.3,1.3,0,0,0,40,72.42a8.94,8.94,0,0,1,17.73,0A1.3,1.3,0,0,0,59,73.56h5.94a1.31,1.31,0,0,0,1.3-1.14,8.93,8.93,0,0,1,17.72,0,1.3,1.3,0,0,0,1.29,1.14h5.87a1.3,1.3,0,0,0,1.3-1.28c.14-8.28,2.37-17.79,8.74-22.55C123.15,33.25,117.36,19.12,112.26,14ZM89.79,38.92l-4.2-2.11h0a2.64,2.64,0,1,1,4.2,2.12Z"/> </svg> </a> <div class="site-header__doc-type sr-only">User Manual</div> <div class="site-header-version"></div> <button type="button" aria-label="Navigation Menu" class="site-header__navigation-button hamburger"> <span class="hamburger__bar"></span> <span class="hamburger__bar"></span> <span class="hamburger__bar"></span> </button> </div> <div class="site-header__navigation-collapsible site-header__navigation-collapsible--collapse"> <ul class="site-header__navigation-items"> <li id="theme-toggle" class="site-header__navigation-item"> <a class="site-header__navigation-link theme-toggle" title="Theme"> <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <title>Theme</title> <path d="m12 22c5.5228475 0 10-4.4771525 10-10s-4.4771525-10-10-10-10 4.4771525-10 10 4.4771525 10 10 10zm0-1.5v-17c4.6944204 0 8.5 3.80557963 8.5 8.5 0 4.6944204-3.8055796 8.5-8.5 8.5z"/> </svg> </a> <script type="text/javascript"> const btn = document.querySelector(".theme-toggle"); const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); const currentTheme = localStorage.getItem("theme"); if (currentTheme == "dark") { document.body.classList.toggle("dark-theme"); } else if (currentTheme == "light") { document.body.classList.toggle("light-theme"); } btn.addEventListener("click", function () { if (prefersDarkScheme.matches) { document.body.classList.toggle("light-theme"); var theme = document.body.classList.contains("light-theme")? "light" : "dark"; } else { document.body.classList.toggle("dark-theme"); var theme = document.body.classList.contains("dark-theme")? "dark" : "light"; } localStorage.setItem("theme", theme); }); </script> </li> <li class="site-header__navigation-item site-header__navigation-submenu-section" tabindex="0"> <span class="site-header__navigation-link"> Community </span> <div class="site-header__navigation-submenu"> <div class="site-header__navigation-submenu-item" itemprop="name"> <a target="_top" class="site-header__navigation-submenu-item-link" href="https://gradle.org/" itemprop="url"> <span class="site-header__navigation-submenu-item-link-text">Community Home</span> </a> </div> <div class="site-header__navigation-submenu-item" itemprop="name"> <a target="_top" class="site-header__navigation-submenu-item-link" href="https://discuss.gradle.org/" itemprop="url"> <span class="site-header__navigation-submenu-item-link-text">Community Forums</span> </a> </div> <div class="site-header__navigation-submenu-item" itemprop="name"> <a target="_top" class="site-header__navigation-submenu-item-link" href="https://plugins.gradle.org" itemprop="url"> <span class="site-header__navigation-submenu-item-link-text">Community Plugins</span> </a> </div> </div> </li> <li class="site-header__navigation-item" itemprop="name"> <a target="_top" class="site-header__navigation-link" href="https://dpeuniversity.gradle.com/" itemprop="url">DPE University</a> </li> <li class="site-header__navigation-item" itemprop="name"> <a target="_top" class="site-header__navigation-link" href="https://gradle.org/training/" itemprop="url">Events</a> </li> <li class="site-header__navigation-item site-header__navigation-submenu-section" tabindex="0"> <span class="site-header__navigation-link"> News </span> <div class="site-header__navigation-submenu"> <div class="site-header__navigation-submenu-item" itemprop="name"> <a class="site-header__navigation-submenu-item-link" href="https://newsletter.gradle.org" itemprop="url"> <span class="site-header__navigation-submenu-item-link-text">Newsletter</span> </a> </div> <div class="site-header__navigation-submenu-item" itemprop="name"> <a class="site-header__navigation-submenu-item-link" href="https://blog.gradle.org" itemprop="url"> <span class="site-header__navigation-submenu-item-link-text">Blog</span> </a> </div> <div class="site-header__navigation-submenu-item"> <a class="site-header__navigation-submenu-item-link" href="https://twitter.com/gradle"> <span class="site-header__navigation-submenu-item-link-text">Twitter</span> </a> </div> </div> </li> <li class="site-header__navigation-item" itemprop="name"> <a target="_top" class="site-header__navigation-link" href="https://gradle.com/develocity" itemprop="url">Develocity</a> </li> <li class="site-header__navigation-item"> <a class="site-header__navigation-link" title="Gradle on GitHub" href="https://github.com/gradle/gradle"> <svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <title>Github</title> <path d="M10 0C4.477 0 0 4.477 0 10c0 4.418 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.462-1.11-1.462-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.268 2.75 1.026A9.578 9.578 0 0 1 10 4.836c.85.004 1.705.114 2.504.337 1.909-1.294 2.747-1.026 2.747-1.026.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.579.688.481C17.137 18.163 20 14.418 20 10c0-5.523-4.478-10-10-10" fill-rule="evenodd";/> </svg> </a> </li> </ul> </div> </nav> </header> <main class="main-content"> <!-- Primary Navigation --> <nav class="docs-navigation"> <div class="search-container"></div> <h3 id="overview">Overview</h3> <ul> <li><a href="../userguide/userguide.html">What is Gradle?</a></li> <li><a href="../userguide/quick_start.html">Quick Start</a></li> </ul> <h3 id="what-is-new">Releases</h3> <ul> <li><a href="https://gradle.org/releases/">All Releases</a></li> <li><a href="../release-notes.html">Release Notes</a></li> <li><a href="../userguide/installation.html">Installing Gradle</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#upgrading-gradle" aria-expanded="false" aria-controls="upgrading-gradle">Upgrading Gradle</a> <ul id="upgrading-gradle"> <li><a href="../userguide/upgrading_version_8.html">version 8.X to latest</a></li> <li><a href="../userguide/upgrading_version_7.html">version 7.X to 8.0</a></li> <li><a href="../userguide/upgrading_version_6.html">version 6.X to 7.0</a></li> <li><a href="../userguide/upgrading_version_5.html">version 5.X to 6.0</a></li> <li><a href="../userguide/upgrading_version_4.html">version 4.X to 5.0</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#migrating-to-gradle" aria-expanded="false" aria-controls="migrating-to-gradle">Migrating to Gradle</a> <ul id="migrating-to-gradle"> <li><a href="../userguide/migrating_from_maven.html">from Maven</a></li> <li><a href="../userguide/migrating_from_ant.html">from Ant</a></li> </ul> </li> <li><a href="../userguide/troubleshooting.html">Troubleshooting</a></li> <li><a href="../userguide/compatibility.html">Compatibility Notes</a></li> <li><a href="../userguide/feature_lifecycle.html">Gradle's Feature Lifecycle</a></li> </ul> <h3 id="running-gradle-builds">Running Gradle Builds</h3> <ul> <li><a href="../userguide/getting_started_eng.html">Getting Started</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#running-introduction" aria-expanded="false" aria-controls="introduction">Core Concepts</a> <ul id="running-introduction"> <li><a href="../userguide/gradle_basics.html">1. Gradle Basics</a></li> <li><a href="../userguide/gradle_wrapper_basics.html">2. Gradle Wrapper Basics</a></li> <li><a href="../userguide/command_line_interface_basics.html">3. Command-Line Interface Basics</a></li> <li><a href="../userguide/settings_file_basics.html">4. Settings File Basics</a></li> <li><a href="../userguide/build_file_basics.html">5. Build File Basics</a></li> <li><a href="../userguide/dependency_management_basics.html">6. Dependency Management Basics</a></li> <li><a href="../userguide/task_basics.html">7. Task Basics</a></li> <li><a href="../userguide/plugin_basics.html">8. Plugins Basics</a></li> <li><a href="../userguide/gradle_optimizations.html">9. Incremental Builds + Caching</a></li> <li><a href="../userguide/build_scans.html">10. Build Scans</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" aria-expanded="false">Tutorial</a> <ul id="running-tutorial"> <li><a href="../userguide/part1_gradle_init.html">1. Initializing the Project</a></li> <li><a href="../userguide/part2_gradle_tasks.html">2. Running Tasks</a></li> <li><a href="../userguide/part3_gradle_dep_man.html">3. Understanding Dependencies</a></li> <li><a href="../userguide/part4_gradle_plugins.html">4. Applying Plugins</a></li> <li><a href="../userguide/part5_gradle_inc_builds.html">5. Exploring Incremental Builds</a></li> <li><a href="../userguide/part6_gradle_caching.html">6. Enabling the Build Cache</a></li> <li><a href="../userguide/part7_gradle_refs.html">7. Using Reference Materials</a></li> </ul> </li> <li><a href="../userguide/gradle_ides.html">Gradle in the IDE</a></li> <li><a href="../userguide/continuous_builds.html">Continuous Build</a></li> </ul> <h3 id="authoring-gradle-builds">Authoring Gradle Builds</h3> <ul> <li><a href="../userguide/getting_started_dev.html">Getting Started</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#learning-the-basics" aria-expanded="false" aria-controls="learning-the-basics">Learning the Basics</a> <ul id="authoring-introduction"> <li><a href="../userguide/gradle_directories.html">1. Gradle Directories</a></li> <li><a href="../userguide/intro_multi_project_builds.html">2. Multi-Project Builds</a></li> <li><a href="../userguide/build_lifecycle.html">3. Gradle Build Lifecycle</a></li> <li><a href="../userguide/writing_settings_files.html">4. Writing Settings Files</a></li> <li><a href="../userguide/writing_build_scripts.html">5. Writing Build Scripts</a></li> <li><a href="../userguide/tutorial_using_tasks.html">6. Using Tasks</a></li> <li><a href="../userguide/writing_tasks.html">7. Writing Tasks</a></li> <li><a href="../userguide/plugins.html">8. Using Plugins</a></li> <li><a href="../userguide/writing_plugins.html">9. Writing Plugins</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" aria-expanded="false">Tutorial</a> <ul id="authoring-tutorial"> <li><a href="../userguide/partr1_gradle_init.html">1. Initializing the Project</a></li> <li><a href="../userguide/partr2_build_lifecycle.html">2. Understanding the Build Lifecycle</a></li> <li><a href="../userguide/partr3_multi_project_builds.html">3. Multi-Project Builds</a></li> <li><a href="../userguide/partr4_settings_file.html">4. Writing the Settings File</a></li> <li><a href="../userguide/partr5_build_scripts.html">5. Writing a Build Script</a></li> <li><a href="../userguide/partr6_writing_tasks.html">6. Writing Tasks</a></li> <li><a href="../userguide/partr7_writing_plugins.html">7. Writing Plugins</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#authoring-multi-project-builds" aria-expanded="false" aria-controls="authoring-multi-project-builds">Structuring Builds</a> <ul id="authoring-multi-project-builds"> <li><a href="../userguide/multi_project_builds.html">Structuring Projects with Gradle</a></li> <li><a href="../userguide/declaring_dependencies_between_subprojects.html">Declaring Dependencies between Subprojects</a></li> <li><a href="../userguide/sharing_build_logic_between_subprojects.html">Sharing Build Logic between Subprojects</a></li> <li><a href="../userguide/composite_builds.html">Composite Builds</a></li> <li><a href="../userguide/multi_project_configuration_and_execution.html">Configuration on Demand</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#developing-tasks" aria-expanded="false" aria-controls="developing-tasks">Developing Tasks</a> <ul id="developing-tasks"> <li><a href="../userguide/more_about_tasks.html">Understanding Tasks</a></li> <li><a href="../userguide/controlling_task_execution.html">Controlling Task Execution</a></li> <li><a href="../userguide/organizing_tasks.html">Organizing Tasks</a></li> <li><a href="../userguide/implementing_custom_tasks.html">Implementing Custom Tasks</a></li> <li><a href="../userguide/lazy_configuration.html">Configuring Tasks Lazily</a></li> <li><a href="../userguide/worker_api.html">Developing Parallel Tasks</a></li> <li><a href="../userguide/custom_tasks.html">Developing Advanced Tasks</a></li> <li><a href="../userguide/build_services.html">Using Shared Build Services</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#developing-plugins" aria-expanded="false" aria-controls="developing-plugins">Developing Plugins</a> <ul id="developing-plugins"> <li><a href="../userguide/custom_plugins.html">Understanding Plugins</a></li> <li><a href="../userguide/implementing_gradle_plugins.html">Understanding Implementation Options</a></li> <li><a href="../userguide/implementing_gradle_plugins_precompiled.html">Implementing Pre-compiled Script Plugins</a></li> <li><a href="../userguide/implementing_gradle_plugins_binary.html">Implementing Binary Plugins</a></li> <li><a href="../userguide/testing_gradle_plugins.html">Testing Plugins</a></li> <li><a href="../userguide/publishing_gradle_plugins.html">Publishing Plugins</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#gradle-properties" aria-expanded="false" aria-controls="gradle-properties">Understanding Gradle Types</a> <ul id="gradle-properties-topics"> <li><a href="../userguide/properties_providers.html">Understanding Properties and Providers</a></li> <li><a href="../userguide/collections.html">Understanding Collections</a></li> <li><a href="../userguide/service_injection.html">Understanding Services and Service Injection</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#other-developing-topics" aria-expanded="false" aria-controls="other-developing-topics">Other Topics</a> <ul id="other-developing-topics"> <li><a href="../userguide/working_with_files.html">Working with Files</a></li> <li><a href="../userguide/init_scripts.html">Initialization Scripts</a></li> <li><a href="../userguide/dataflow_actions.html">Dataflow Actions</a></li> <li><a href="../userguide/test_kit.html">Testing with TestKit</a></li> <li><a href="../userguide/ant.html">Using Ant from Gradle</a></li> </ul> </li> <li><a href="../userguide/directory_layout.html">Gradle-managed Directories</a></li> <li><a href="../userguide/build_environment.html">Configuring the Build Environment</a></li> <li><a href="../userguide/logging.html">Logging with Gradle</a></li> </ul> <h3 id="managing-dependencies">Dependency Management</h3> <ul> <li><a href="../userguide/getting_started_dep_man.html">Getting Started</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#learning-the-basics-dependency-management" aria-expanded="false" aria-controls="learning-the-basics-dependency-management">Learning the Basics</a> <ul id="learning-the-basics-dependency-management"> <li><a href="../userguide/declaring_dependencies.html">1. Declaring Dependencies</a></li> <li><a href="../userguide/dependency_configurations.html">2. Dependency Configurations</a></li> <li><a href="../userguide/declaring_repositories.html">3. Declaring Repositories</a></li> <li><a href="../userguide/centralizing_dependencies.html">4. Centralizing Dependencies</a></li> <li><a href="../userguide/dependency_constraints_conflicts.html">5. Dependency Constraints and Conflict Resolution</a></li> <li><a href="../userguide/dependency_resolution.html">6. Dependency Resolution</a></li> <li><a href="../userguide/variant_aware_resolution.html">7. Variant Aware Dependency Resolution</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#declaring-dependencies" aria-expanded="false" aria-controls="declaring-dependencies">Declaring Dependencies</a> <ul id="declaring-dependencies"> <li><a href="../userguide/declaring_dependencies_basics.html">Declaring Dependencies Basics</a></li> <li><a href="../userguide/viewing_debugging_dependencies.html">Viewing Dependencies</a></li> <li><a href="../userguide/dependency_versions.html">Declaring Versions and Ranges</a></li> <li><a href="../userguide/dependency_constraints.html">Declaring Dependency Constraints</a></li> <li><a href="../userguide/declaring_configurations.html">Creating Dependency Configurations</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#declaring-repositories" aria-expanded="false" aria-controls="declaring-repositories">Declaring Repositories</a> <ul id="declaring-repositories"> <li><a href="../userguide/declaring_repositories_basics.html">Declaring Repositories Basics</a></li> <li><a href="../userguide/centralizing_repositories.html">Centralizing Repository Declarations</a></li> <li><a href="../userguide/supported_repository_types.html">Repository Types</a></li> <li><a href="../userguide/supported_metadata_formats.html">Metadata Formats</a></li> <li><a href="../userguide/supported_repository_protocols.html">Supported Protocols</a></li> <li><a href="../userguide/filtering_repository_content.html">Filtering Repository Content</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#centralizing-dependencies" aria-expanded="false" aria-controls="centralizing-dependencies">Centralizing Dependencies</a> <ul id="centralizing-dependencies"> <li><a href="../userguide/platforms.html">Creating Platforms</a></li> <li><a href="../userguide/version_catalogs.html">Creating Version Catalogs</a></li> <li><a href="../userguide/centralizing_catalog_platform.html">Using Catalogs with Platforms</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#dependency-management" aria-expanded="false" aria-controls="dependency-management">Managing Dependencies</a> <ul id="dependency-management"> <li><a href="../userguide/dependency_locking.html">Locking Versions</a></li> <li><a href="../userguide/resolution_rules.html">Using Resolution Rules</a></li> <li><a href="../userguide/component_metadata_rules.html">Modifying Dependency Metadata</a></li> <li><a href="../userguide/dependency_caching.html">Caching Dependencies</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#understanding_dep_res" aria-expanded="false" aria-controls="understanding_dep_res">Understanding Dependency Resolution</a> <ul id="understanding_dep_res"> <li><a href="../userguide/variant_model.html">Understanding The Model</a></li> <li><a href="../userguide/component_capabilities.html">Capabilities</a></li> <li><a href="../userguide/variant_attributes.html">Variants and Attributes</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#dependency-resolution" aria-expanded="false" aria-controls="dependency-resolution">Controlling Dependency Resolution</a> <ul id="dependency-resolution"> <li><a href="../userguide/dependency_resolution_basics.html">Dependency Resolution Basics</a></li> <li><a href="../userguide/dependency_graph_resolution.html">Graph Resolution</a></li> <li><a href="../userguide/artifact_resolution.html">Artifact Resolution</a></li> <li><a href="../userguide/artifact_transforms.html">Artifact Transforms</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#publishing" aria-expanded="false" aria-controls="publishing">Publishing Libraries</a> <ul id="publishing"> <li><a href="../userguide/publishing_setup.html">Setting up Publishing</a></li> <li><a href="../userguide/publishing_gradle_module_metadata.html">Understanding Gradle Module Metadata</a></li> <li><a href="../userguide/publishing_signing.html">Signing Artifacts</a></li> <li><a href="../userguide/publishing_customization.html">Customizing Publishing</a></li> <li><a href="../userguide/publishing_maven.html">Maven Publish Plugin</a></li> <li><a href="../userguide/publishing_ivy.html">Ivy Publish Plugin</a></li> </ul> </li> <li><a class="nav-dropdown" data-toggle="collapse" href="#other" aria-expanded="false" aria-controls="other">Other Topics</a> <ul id="other"> <li><a href="../userguide/dependency_verification.html">Verifying Dependencies</a></li> <li><a href="../userguide/dependency_version_alignment.html">Aligning Dependencies</a></li> <li><a href="../userguide/feature_variants.html">Modeling Feature Variants and Optional Dependencies</a></li> </ul> </li> </ul> <h3 id="authoring-gradle-builds-java">Authoring JVM Builds</h3> <ul> <li><a href="../userguide/building_java_projects.html">Building Java & JVM projects</a></li> <li><a href="../userguide/java_testing.html">Testing Java & JVM projects</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#java-toolchains" aria-expanded="false" aria-controls="java-toolchains">Java Toolchains</a> <ul id="java-toolchains"> <li><a href="../userguide/toolchains.html">Toolchains for JVM projects</a></li> <li><a href="../userguide/toolchain_plugins.html">Toolchain Resolver Plugins</a></li> </ul> </li> <li><a href="../userguide/dependency_management_for_java_projects.html">Managing Dependencies</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#jvm-plugins" aria-expanded="false" aria-controls="jvm-plugins">JVM Plugins</a> <ul id="jvm-plugins"> <li><a href="../userguide/java_library_plugin.html">Java Library Plugin</a></li> <li><a href="../userguide/application_plugin.html">Java Application Plugin</a></li> <li><a href="../userguide/java_platform_plugin.html">Java Platform Plugin</a></li> <li><a href="../userguide/groovy_plugin.html">Groovy Plugin</a></li> <li><a href="../userguide/scala_plugin.html">Scala Plugin</a></li> </ul> </li> </ul> <h3 id="optimizing-build-performance">Optimizing Build Performance</h3> <ul> <li><a href="../userguide/performance.html">Improving Performance of Gradle Builds</a></li> <li><a href="../userguide/gradle_daemon.html">Gradle Daemon</a></li> <li><a href="../userguide/file_system_watching.html">File System Watching</a></li> <li><a href="../userguide/incremental_build.html">Incremental Build</a></li> <li><a class="nav-dropdown" data-toggle="collapse" href="#build-cache" aria-expanded="false" aria-controls="optimizing-build-performance">Using the Build Cache</a> <ul id="build-cache"> <li><a href="../userguide/build_cache.html">Enabling and Configuring</a></li> <li><a href="../userguide/build_cache_use_cases.html">Why use the Build Cache?</a></li> <li><a href="../userguide/build_cache_performance.html">Understanding the Impact</a></li> <li><a href="../userguide/build_cache_concepts.html">Learning Basic Concepts</a></li> <li><a href="../userguide/caching_java_projects.html">Caching Java Project</a></li> <li><a href="../userguide/caching_android_projects.html">Caching Android Project</a></li> <li><a href="../userguide/build_cache_debugging.html">Debugging Caching Issues</a></li> <li><a href="../userguide/common_caching_problems.html">Troubleshooting</a></li> </ul> </li> <li><a href="../userguide/configuration_cache.html">Using the Configuration Cache</a></li> <li><a href="../userguide/inspect.html">Inspecting Gradle Builds</a></li> <li><a href="../userguide/config_gradle.html">Configuring Gradle</a></li> <li><a href="../userguide/project_properties.html">Project Properties</a></li> <li><a href="../userguide/networking.html">Gradle Networking</a></li> </ul> <h3 id="authoring-gradle-builds-native">Authoring C++/Swift Builds</h3> <ul> <li><a href="../userguide/building_cpp_projects.html">Building C++ projects</a></li> <li><a href="../userguide/cpp_testing.html">Testing C++ projects</a></li> <li><a href="../userguide/building_swift_projects.html">Building Swift projects</a></li> <li><a href="../userguide/swift_testing.html">Testing Swift projects</a></li> </ul> <h3 id="reference">Reference</h3> <ul> <li><a class="nav-dropdown" data-toggle="collapse" href="#gradle-api" aria-expanded="false" aria-controls="gradle-api">Gradle DSLs and API</a> <ul id="gradle-api"> <li><a href="../javadoc/index.html?overview-summary.html">Javadoc</a></li> <li><a href="../userguide/groovy_build_script_primer.html">Groovy DSL Primer</a></li> <li><a href="../dsl/index.html">Groovy DSL Reference</a></li> <li><a href="../userguide/kotlin_dsl.html">Kotlin DSL Primer</a></li> <li><a href="../kotlin-dsl/index.html" target="_blank">Kotlin DSL API</a></li> <li><a href="../userguide/migrating_from_groovy_to_kotlin_dsl.html">Groovy to Kotlin DSL Migration</a></li> <li><a href="../samples/index.html">Samples</a></li> <li><a href="../userguide/glossary.html">Glossary</a></li> </ul> </li> <li><a href="https://community.gradle.org/cookbook/">Gradle Cookbook</a></li> <li><a href="../userguide/command_line_interface.html">Command-Line Interface</a></li> <li><a href="../userguide/gradle_wrapper.html">Gradle Wrapper</a></li> <li><a href="../userguide/plugin_reference.html">Core Plugins</a></li> <li id="third-party-integration"><a href="../userguide/third_party_integration.html">Gradle & Third-party Tools</a></li> <li><a href="../userguide/userguide_single.html">User Manual Single Page</a></li> <li><a href="../userguide/userguide.pdf">User Manual PDF</a></li> </ul> </nav> <!-- End Primary Navigation --> <div class="content"> <div class="chapter"> <div id="header"> <h1>Modifying Dependency Metadata</h1> <div class="details"> <span id="revnumber">version 8.11.1</span> </div> <div id="toc" class="toc"> <div id="toctitle">Contents</div> <ul class="sectlevel1"> <li><a href="#sec:writing-metadata-rule">Writing a component metadata rule</a></li> <li><a href="#sec:component-metadata-rules-details">Which parts of metadata can be modified?</a></li> <li><a href="#sec:fixing-dependency-details">Fixing incorrect dependency details</a></li> <li><a href="#sec:publish-variants-explicit-jars">Making variants published as classified jars explicit</a></li> <li><a href="#sec:encoded-variants-explicit">Making variants encoded in versions explicit</a></li> <li><a href="#sec:adding-variants-jars">Adding variants for native jars</a></li> <li><a href="#sec:making-library-flavors">Making different flavors of a library available through capabilities</a></li> <li><a href="#sec:adding-missing-capabilities">Adding missing capabilities to detect conflicts</a></li> <li><a href="#sec:making-ivy-modules-variant-aware">Making Ivy modules variant-aware</a></li> <li><a href="#sec:filter-maven-metadata">Filter using Maven metadata</a></li> <li><a href="#sec:modifying-metadata">Modifying metadata on the component level for alignment</a></li> <li><a href="#sec:custom-status-scheme">Modifying metadata on the component level for version selection based on status</a></li> </ul> </div> </div> <div id="content"> <div id="preamble"> <div class="sectionbody"> <div class="paragraph"> <p>Each component pulled from a repository includes metadata, such as its group, name, version, and the various variants it provides along with their artifacts and dependencies.</p> </div> <div class="paragraph"> <p>Occasionally, this metadata might be incomplete or incorrect.</p> </div> <div class="paragraph"> <p>Gradle offers an API to address this issue, allowing you to write <strong>component metadata rules</strong> directly within the build script. These rules are applied after a module’s metadata is downloaded, but before it’s used in dependency resolution.</p> </div> </div> </div> <div class="sect1"> <h2 id="sec:writing-metadata-rule"><a class="anchor" href="#sec:writing-metadata-rule"></a><a class="link" href="#sec:writing-metadata-rule">Writing a component metadata rule</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Component metadata rules are applied within the <a href="../dsl/org.gradle.api.artifacts.dsl.ComponentMetadataHandler.html"><code>components</code></a> section of the <a href="../dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html"><code>dependencies</code></a> block in a build script or in the settings script.</p> </div> <div class="paragraph"> <p>These rules can be defined in two ways:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p><strong>Inline as an Action:</strong> Directly within the <code>components</code> section.</p> </li> <li> <p><strong>As a Separate Class:</strong> Implementing the <a href="../javadoc/org/gradle/api/artifacts/ComponentMetadataRule.html"><code>ComponentMetadataRule</code></a> interface.</p> </li> </ol> </div> <div class="paragraph"> <p>While inline actions are convenient for quick experimentation, it’s generally recommended to define rules as separate classes.</p> </div> <div class="paragraph"> <p>Rules written as isolated classes can be annotated with <code>@CacheableRule</code>, allowing their results to be cached and avoiding re-execution each time dependencies are resolved.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> A rule should always be cacheable to avoid major impacts on build performance and ensure faster build times. </td> </tr> </table> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class TargetJvmVersionRule @Inject constructor(val jvmVersion: Int) : ComponentMetadataRule { @get:Inject abstract val objects: ObjectFactory override fun execute(context: ComponentMetadataContext) { context.details.withVariant("compile") { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, jvmVersion) attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API)) } } } } dependencies { components { withModule<TargetJvmVersionRule>("commons-io:commons-io") { params(7) } withModule<TargetJvmVersionRule>("commons-collections:commons-collections") { params(8) } } implementation("commons-io:commons-io:2.6") implementation("commons-collections:commons-collections:3.2.2") }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class TargetJvmVersionRule implements ComponentMetadataRule { final Integer jvmVersion @Inject TargetJvmVersionRule(Integer jvmVersion) { this.jvmVersion = jvmVersion } @Inject abstract ObjectFactory getObjects() void execute(ComponentMetadataContext context) { context.details.withVariant("compile") { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, jvmVersion) attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_API)) } } } } dependencies { components { withModule("commons-io:commons-io", TargetJvmVersionRule) { params(7) } withModule("commons-collections:commons-collections", TargetJvmVersionRule) { params(8) } } implementation("commons-io:commons-io:2.6") implementation("commons-collections:commons-collections:3.2.2") }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>In this example, the <code>TargetJvmVersionRule</code> class implements <a href="../javadoc/org/gradle/api/artifacts/ComponentMetadataRule.html"><code>ComponentMetadataRule</code></a> and is further configured using <a href="../javadoc/org/gradle/api/ActionConfiguration.html"><code>ActionConfiguration</code></a>.</p> </div> <div class="paragraph"> <p>Gradle enforces isolation of instances of <code>ComponentMetadataRule</code>, requiring that all parameters must be <code>Serializable</code> or recognized Gradle types.</p> </div> <div class="paragraph"> <p>Additionally, services like <a href="../javadoc/org/gradle/api/model/ObjectFactory.html"><code>ObjectFactory</code></a> can be injected into your rule’s constructor using <code>@Inject</code>.</p> </div> <div class="paragraph"> <p>A component metadata rule can be applied to all modules using <code>all(rule)</code> or to a specific module using <code>withModule(groupAndName, rule)</code>. Typically, a rule is tailored to enrich the metadata of a specific module, so the <code>withModule</code> API is preferred.</p> </div> <div class="sect2"> <h3 id="sec:rules-in-settings"><a class="anchor" href="#sec:rules-in-settings"></a><a class="link" href="#sec:rules-in-settings">Declaring rules in a central place</a></h3> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Declaring component metadata rules in settings is an incubating feature </td> </tr> </table> </div> <div class="paragraph"> <p>Component metadata rules can be declared in the <code>settings.gradle(.kts)</code> file for the entire build, rather than in each subproject individually. Rules declared in settings are applied to all projects by default unless overridden by project-specific rules.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">dependencyResolutionManagement { components { withModule<GuavaRule>("com.google.guava:guava") } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">dependencyResolutionManagement { components { withModule("com.google.guava:guava", GuavaRule) } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>By default, project-specific rules take precedence over settings rules. However, this behavior can be adjusted:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">dependencyResolutionManagement { rulesMode = RulesMode.PREFER_SETTINGS }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">dependencyResolutionManagement { rulesMode = RulesMode.PREFER_SETTINGS }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>If this method is called and that a project or plugin declares rules, a warning will be issued. You can make this a failure instead by using this alternative:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">dependencyResolutionManagement { rulesMode = RulesMode.FAIL_ON_PROJECT_RULES }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">dependencyResolutionManagement { rulesMode = RulesMode.FAIL_ON_PROJECT_RULES }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>The default behavior is equivalent to calling this method:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">dependencyResolutionManagement { rulesMode = RulesMode.PREFER_PROJECT }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">settings.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">dependencyResolutionManagement { rulesMode = RulesMode.PREFER_PROJECT }</code></pre> </div> </div> </div> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="sec:component-metadata-rules-details"><a class="anchor" href="#sec:component-metadata-rules-details"></a><a class="link" href="#sec:component-metadata-rules-details">Which parts of metadata can be modified?</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>The Component Metadata Rules API focuses on the features supported by Gradle Module Metadata and the dependencies API. The key difference between using metadata rules and defining dependencies/artifacts in a build script is that component metadata rules operate directly on <a href="variant_model.html#sec:understanding-variant-selection">variants</a>, whereas build scripts often affect multiple variants at once (e.g., an <code>api</code> dependency is applied to both <code>api</code> and <code>runtime</code> variants of a Java library).</p> </div> <div class="paragraph"> <p>Variants can be modified through the following methods:</p> </div> <div class="ulist"> <ul> <li> <p><strong><code>allVariants</code></strong>: Modify all variants of a component.</p> </li> <li> <p><strong><code>withVariant(name)</code></strong>: Modify a specific variant identified by its name.</p> </li> <li> <p><strong><code>addVariant(name)</code> or <code>addVariant(name, base)</code></strong>: Add a new variant from scratch or copy details from an existing variant (<code>base</code>).</p> </li> </ul> </div> <div class="paragraph"> <p>The following variant details can be modified:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Attributes</strong>: Use the <code>attributes {}</code> block to adjust <a href="variant_model.html#sec:abm-configuration-attributes">attributes</a> that identify the variant.</p> </li> <li> <p><strong>Capabilities</strong>: Use the <code>withCapabilities {}</code> block to define the <a href="component_capabilities.html#sec:declaring-component-capabilities">capabilities</a> the variant provides.</p> </li> <li> <p><strong>Dependencies</strong>: Use the <code>withDependencies {}</code> block to manage the variant’s dependencies, including <a href="dependency_versions.html#sec:rich-version-constraints">rich version</a> constraints.</p> </li> <li> <p><strong>Dependency Constraints</strong>: Use the <code>withDependencyConstraints {}</code> block to define the variant’s <a href="dependency_constraints.html#sec:adding-constraints-transitive-deps">dependency constraints</a>, including rich versions.</p> </li> <li> <p><strong>Published Files</strong>: Use the <code>withFiles {}</code> block to specify the location of the files that make up the variant’s content.</p> </li> </ul> </div> <div class="paragraph"> <p>Additionally, several component-level properties can be changed:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Component Attributes</strong>: The only <a href="#sec:custom-status-scheme">meaningful attribute</a> here is <code>org.gradle.status</code>.</p> </li> <li> <p><strong>Status Scheme</strong>: Influence how the <code>org.gradle.status</code> attribute is interpreted during version selection.</p> </li> <li> <p><strong>BelongsTo Property</strong>: Used for <component_capabilities.adoc#sec:declaring-capabilities-external-modules,version alignment>> via virtual platforms.</p> </li> </ul> </div> <div class="paragraph"> <p>The format of a module’s metadata affects how it maps to the variant-centric representation:</p> </div> <div class="ulist"> <ul> <li> <p><strong>Gradle Module Metadata</strong>: The data structure is similar to the module’s <code>.module</code> file.</p> </li> <li> <p><strong>POM Metadata</strong>: For modules published with <code>.pom</code> metadata, fixed variants are derived as explained in the <a href="variant_model.html#sec:maven-mapping-to-variants">"Mapping POM Files to Variants"</a>, section.</p> </li> <li> <p><strong>Ivy Metadata</strong>: If a module was published with an <code>ivy.xml</code> file, Ivy configurations can be accessed in place of variants. Their dependencies, constraints, and files can be modified. You can also use <code>addVariant(name, baseVariantOrConfiguration)</code> to derive variants from Ivy configurations, such as defining <a href="variant_model.html#sec:ivy-mapping-to-variants"><code>compile</code> and <code>runtime</code> variants for the Java library plugin</a>.</p> </li> </ul> </div> <div class="paragraph"> <p>Before using component metadata rules to adjust a module’s metadata, determine whether the module was published with <strong>Gradle Module Metadata</strong> (<code>.module</code> file) or <strong>traditional metadata</strong> (<code>.pom</code> or <code>ivy.xml</code>):</p> </div> <div class="ulist"> <ul> <li> <p><strong>Modules with Gradle Module Metadata</strong>: These typically have complete metadata, but issues can still occur. Only apply component metadata rules if you’ve clearly identified a problem with the metadata. For dependency resolution issues, first consider using <a href="dependency_versions.html#sec:rich-version-constraints">dependency constraints with rich versions</a>. If you’re developing a library, note that dependency constraints are published as part of your own library’s metadata, making it easier to share the solution with consumers. In contrast, component metadata rules apply only within your own build.</p> </li> <li> <p><strong>Modules with Traditional Metadata</strong> (<code>.pom</code> or <code>ivy.xml</code>): These are more likely to have incomplete metadata since features like variants and dependency constraints aren’t supported in these formats. Such modules might have variants or constraints that were omitted or incorrectly defined as dependencies. In the following sections, we explore examples of OSS modules with incomplete metadata and the rules to add missing information.</p> </li> </ul> </div> <div class="paragraph"> <p>As a rule of thumb, you should contemplate if the rule you are writing also works out of context of your build. That is, does the rule still produce a correct and useful result if applied in any other build that uses the module(s) it affects?</p> </div> </div> </div> <div class="sect1"> <h2 id="sec:fixing-dependency-details"><a class="anchor" href="#sec:fixing-dependency-details"></a><a class="link" href="#sec:fixing-dependency-details">Fixing incorrect dependency details</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Consider the Jaxen XPath Engine (version <code>1.1.3</code>) published on Maven Central. Its <code>pom</code> file declares several unnecessary dependencies in the <code>compile</code> scope, which were later removed in version <code>1.1.4</code>. If you need to work with version <code>1.1.3</code>, you can fix the metadata using the following rule:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class JaxenDependenciesRule: ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { context.details.allVariants { withDependencies { removeAll { it.group in listOf("dom4j", "jdom", "xerces", "maven-plugins", "xml-apis", "xom") } } } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class JaxenDependenciesRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { context.details.allVariants { withDependencies { removeAll { it.group in ["dom4j", "jdom", "xerces", "maven-plugins", "xml-apis", "xom"] } } } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>In the <code>withDependencies</code> block, you have access to the full list of dependencies and can use Java collection methods to inspect and modify that list. You can also add dependencies using the <code>add(notation, configureAction)</code> method. Similarly, you can inspect and modify dependency constraints within the <code>withDependencyConstraints</code> block.</p> </div> <div class="paragraph"> <p>In Jaxen version <code>1.1.4</code>, the <code>dom4j</code>, <code>jdom</code>, and <code>xerces</code> dependencies are still present but marked as <strong>optional</strong>. Optional dependencies are not processed automatically by Gradle or Maven, as they indicate <a href="feature_variants.html#feature_variants">feature variants</a> that require additional dependencies. However, the <code>pom</code> file lacks information about these features and their corresponding dependencies. This can be represented in Gradle Module Metadata through variants and <a href="component_capabilities.html#sec:declaring-component-capabilities">capabilities</a>, which we can add via a component metadata rule.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class JaxenCapabilitiesRule: ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { context.details.addVariant("runtime-dom4j", "runtime") { withCapabilities { removeCapability("jaxen", "jaxen") addCapability("jaxen", "jaxen-dom4j", context.details.id.version) } withDependencies { add("dom4j:dom4j:1.6.1") } } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class JaxenCapabilitiesRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { context.details.addVariant("runtime-dom4j", "runtime") { withCapabilities { removeCapability("jaxen", "jaxen") addCapability("jaxen", "jaxen-dom4j", context.details.id.version) } withDependencies { add("dom4j:dom4j:1.6.1") } } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>In this example, we create a new variant called <code>runtime-dom4j</code> using the <code>addVariant(name, baseVariant)</code> method. This variant represents an optional feature, defined by the capability <code>jaxen-dom4j</code>. We then add the required dependency <code>dom4j:dom4j:1.6.1</code> to this feature.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">dependencies { components { withModule<JaxenDependenciesRule>("jaxen:jaxen") withModule<JaxenCapabilitiesRule>("jaxen:jaxen") } implementation("jaxen:jaxen:1.1.3") runtimeOnly("jaxen:jaxen:1.1.3") { capabilities { requireCapability("jaxen:jaxen-dom4j") } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">dependencies { components { withModule("jaxen:jaxen", JaxenDependenciesRule) withModule("jaxen:jaxen", JaxenCapabilitiesRule) } implementation("jaxen:jaxen:1.1.3") runtimeOnly("jaxen:jaxen:1.1.3") { capabilities { requireCapability("jaxen:jaxen-dom4j") } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>By applying these rules, Gradle uses the enriched metadata to correctly resolve the optional dependencies when the <code>jaxen-dom4j</code> feature is required.</p> </div> </div> </div> <div class="sect1"> <h2 id="sec:publish-variants-explicit-jars"><a class="anchor" href="#sec:publish-variants-explicit-jars"></a><a class="link" href="#sec:publish-variants-explicit-jars">Making variants published as classified jars explicit</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>In modern builds, variants are often published as separate artifacts, each represented by its own jar file. For example, libraries may provide distinct jars for different Java versions, ensuring that the correct version is used at runtime or compile time based on the environment.</p> </div> <div class="paragraph"> <p>For instance, version <code>0.7.9</code> of the asynchronous programming library Quasar, published on <a href="https://repo1.maven.org/maven2/co/paralleluniverse/quasar-core/0.7.9">Maven Central</a>, includes both <code>quasar-core-0.7.9.jar</code> and <code>quasar-core-0.7.9-jdk8.jar</code>. Publishing jars with a classifier, such as <code>jdk8</code>, is common practice in Maven repositories. However, neither Maven nor Gradle metadata provides information about these classified jars. As a result, there is no clear way to determine their existence or any differences, such as dependencies, between the variants.</p> </div> <div class="paragraph"> <p>In Gradle Module Metadata, variant information would be present. For the already published Quasar library, we can add this information using the following rule:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class QuasarRule: ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { listOf("compile", "runtime").forEach { base -> context.details.addVariant("jdk8${base.capitalize()}", base) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) } withFiles { removeAllFiles() addFile("${context.details.id.name}-${context.details.id.version}-jdk8.jar") } } context.details.withVariant(base) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 7) } } } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class QuasarRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { ["compile", "runtime"].each { base -> context.details.addVariant("jdk8${base.capitalize()}", base) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) } withFiles { removeAllFiles() addFile("${context.details.id.name}-${context.details.id.version}-jdk8.jar") } } context.details.withVariant(base) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 7) } } } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>In this case, the <code>jdk8</code> classifier clearly indicates the target Java version, which corresponds to a known attribute in the Java ecosystem. Since we need both compile and runtime variants for Java 8, we create two new variants using the existing compile and runtime variants as a base. This ensures that all other Java ecosystem attributes are set correctly, and dependencies are carried over.</p> </div> <div class="paragraph"> <p>We assign the <code>TARGET_JVM_VERSION_ATTRIBUTE</code> to <code>8</code> for both new variants, remove any existing files with <code>removeAllFiles()</code>, and then add the <code>jdk8</code> jar using <code>addFile()</code>. Removing the files is necessary because the reference to the main jar <code>quasar-core-0.7.9.jar</code> is copied from the base variant.</p> </div> <div class="paragraph"> <p>Finally, we enrich the existing compile and runtime variants with the information that they target Java 7 using <code>attribute(TARGET_JVM_VERSION_ATTRIBUTE, 7)</code>.</p> </div> <div class="paragraph"> <p>With these changes, you can now request Java 8 versions for all dependencies on the compile classpath, and Gradle will automatically select the best-fitting variant. In the case of Quasar, this will be the <code>jdk8Compile</code> variant, which exposes the <code>quasar-core-0.7.9-jdk8.jar</code>.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">configurations["compileClasspath"].attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) } dependencies { components { withModule<QuasarRule>("co.paralleluniverse:quasar-core") } implementation("co.paralleluniverse:quasar-core:0.7.9") }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">configurations.compileClasspath.attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) } dependencies { components { withModule("co.paralleluniverse:quasar-core", QuasarRule) } implementation("co.paralleluniverse:quasar-core:0.7.9") }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>With this configuration, Gradle will select the Java 8 variant of Quasar for the compile classpath.</p> </div> </div> </div> <div class="sect1"> <h2 id="sec:encoded-variants-explicit"><a class="anchor" href="#sec:encoded-variants-explicit"></a><a class="link" href="#sec:encoded-variants-explicit">Making variants encoded in versions explicit</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Another solution to publish multiple alternatives for the same library is the usage of a versioning pattern as done by the popular Guava library. Here, each new version is published twice by appending the classifier to the version instead of the jar artifact. In the case of Guava 28 for example, we can find a <em>28.0-jre</em> (Java 8) and <em>28.0-android</em> (Java 6) version on <a href="https://repo1.maven.org/maven2/com/google/guava/guava">Maven central</a>. The advantage of using this pattern when working only with pom metadata is that both variants are discoverable through the version. The disadvantage is that there is no information as to what the different version suffixes mean semantically. So in the case of conflict, Gradle would just pick the highest version when comparing the version strings.</p> </div> <div class="paragraph"> <p>Turning this into proper variants is a bit more tricky, as Gradle first selects a version of a module and then selects the best fitting variant. So the concept that variants are encoded as versions is not supported directly. However, since both variants are always published together we can assume that the files are physically located in the same repository. And since they are published with Maven repository conventions, we know the location of each file if we know module name and version. We can write the following rule:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class GuavaRule: ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { val variantVersion = context.details.id.version val version = variantVersion.substring(0, variantVersion.indexOf("-")) listOf("compile", "runtime").forEach { base -> mapOf(6 to "android", 8 to "jre").forEach { (targetJvmVersion, jarName) -> context.details.addVariant("jdk$targetJvmVersion${base.capitalize()}", base) { attributes { attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, targetJvmVersion) } withFiles { removeAllFiles() addFile("guava-$version-$jarName.jar", "../$version-$jarName/guava-$version-$jarName.jar") } } } } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class GuavaRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { def variantVersion = context.details.id.version def version = variantVersion.substring(0, variantVersion.indexOf("-")) ["compile", "runtime"].each { base -> [6: "android", 8: "jre"].each { targetJvmVersion, jarName -> context.details.addVariant("jdk$targetJvmVersion${base.capitalize()}", base) { attributes { attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, targetJvmVersion) } withFiles { removeAllFiles() addFile("guava-$version-${jarName}.jar", "../$version-$jarName/guava-$version-${jarName}.jar") } } } } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>Similar to the previous example, we add runtime and compile variants for both Java versions. In the <code>withFiles</code> block however, we now also specify a relative path for the corresponding jar file which allows Gradle to find the file no matter if it has selected a <em>-jre</em> or <em>-android</em> version. The path is always relative to the location of the metadata (in this case <code>pom</code>) file of the selection module version. So with this rules, both Guava 28 "versions" carry both the <em>jdk6</em> and <em>jdk8</em> variants. So it does not matter to which one Gradle resolves. The variant, and with it the correct jar file, is determined based on the requested <code>TARGET_JVM_VERSION_ATTRIBUTE</code> value.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">configurations["compileClasspath"].attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 6) } dependencies { components { withModule<GuavaRule>("com.google.guava:guava") } // '23.3-android' and '23.3-jre' are now the same as both offer both variants implementation("com.google.guava:guava:23.3+") }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">configurations.compileClasspath.attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 6) } dependencies { components { withModule("com.google.guava:guava", GuavaRule) } // '23.3-android' and '23.3-jre' are now the same as both offer both variants implementation("com.google.guava:guava:23.3+") }</code></pre> </div> </div> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="sec:adding-variants-jars"><a class="anchor" href="#sec:adding-variants-jars"></a><a class="link" href="#sec:adding-variants-jars">Adding variants for native jars</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Jars with classifiers are also used to separate parts of a library for which multiple alternatives exists, for example native code, from the main artifact. This is for example done by the Lightweight Java Game Library (LWGJ), which publishes several platform specific jars to <a href="https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.2.3">Maven central</a> from which always one is needed, in addition to the main jar, at runtime. It is not possible to convey this information in pom metadata as there is no concept of putting multiple artifacts in relation through the metadata. In Gradle Module Metadata, each variant can have arbitrary many files and we can leverage that by writing the following rule:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class LwjglRule: ComponentMetadataRule { data class NativeVariant(val os: String, val arch: String, val classifier: String) private val nativeVariants = listOf( NativeVariant(OperatingSystemFamily.LINUX, "arm32", "natives-linux-arm32"), NativeVariant(OperatingSystemFamily.LINUX, "arm64", "natives-linux-arm64"), NativeVariant(OperatingSystemFamily.WINDOWS, "x86", "natives-windows-x86"), NativeVariant(OperatingSystemFamily.WINDOWS, "x86-64", "natives-windows"), NativeVariant(OperatingSystemFamily.MACOS, "x86-64", "natives-macos") ) @get:Inject abstract val objects: ObjectFactory override fun execute(context: ComponentMetadataContext) { context.details.withVariant("runtime") { attributes { attributes.attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named("none")) attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named("none")) } } nativeVariants.forEach { variantDefinition -> context.details.addVariant("${variantDefinition.classifier}-runtime", "runtime") { attributes { attributes.attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(variantDefinition.os)) attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(variantDefinition.arch)) } withFiles { addFile("${context.details.id.name}-${context.details.id.version}-${variantDefinition.classifier}.jar") } } } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class LwjglRule implements ComponentMetadataRule { //val os: String, val arch: String, val classifier: String) private def nativeVariants = [ [os: OperatingSystemFamily.LINUX, arch: "arm32", classifier: "natives-linux-arm32"], [os: OperatingSystemFamily.LINUX, arch: "arm64", classifier: "natives-linux-arm64"], [os: OperatingSystemFamily.WINDOWS, arch: "x86", classifier: "natives-windows-x86"], [os: OperatingSystemFamily.WINDOWS, arch: "x86-64", classifier: "natives-windows"], [os: OperatingSystemFamily.MACOS, arch: "x86-64", classifier: "natives-macos"] ] @Inject abstract ObjectFactory getObjects() void execute(ComponentMetadataContext context) { context.details.withVariant("runtime") { attributes { attributes.attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, "none")) attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(MachineArchitecture, "none")) } } nativeVariants.each { variantDefinition -> context.details.addVariant("${variantDefinition.classifier}-runtime", "runtime") { attributes { attributes.attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, variantDefinition.os)) attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(MachineArchitecture, variantDefinition.arch)) } withFiles { addFile("${context.details.id.name}-${context.details.id.version}-${variantDefinition.classifier}.jar") } } } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>This rule is quite similar to the Quasar library example above. Only this time we have five different runtime variants we add and nothing we need to change for the compile variant. The runtime variants are all based on the existing <em>runtime</em> variant and we do not change any existing information. All Java ecosystem attributes, the dependencies and the main jar file stay part of each of the runtime variants. We only set the additional attributes <code>OPERATING_SYSTEM_ATTRIBUTE</code> and <code>ARCHITECTURE_ATTRIBUTE</code> which are defined as part of Gradle’s <a href="building_cpp_projects.html#building_cpp_projects">native support</a>. And we add the corresponding native jar file so that each runtime variant now carries two files: the main jar and the native jar.</p> </div> <div class="paragraph"> <p>In the build script, we can now request a specific variant and Gradle will fail with a selection error if more information is needed to make a decision.</p> </div> <div class="paragraph"> <p>Gradle is able to understand the common case where a single attribute is missing that would have removed the ambiguity. In this case, rather than listing information about all attributes on all available variants, Gradle helpfully lists only possible values for that attribute along with the variants each value would select.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">configurations["runtimeClasspath"].attributes { attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named("windows")) } dependencies { components { withModule<LwjglRule>("org.lwjgl:lwjgl") } implementation("org.lwjgl:lwjgl:3.2.3") }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">configurations["runtimeClasspath"].attributes { attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, "windows")) } dependencies { components { withModule("org.lwjgl:lwjgl", LwjglRule) } implementation("org.lwjgl:lwjgl:3.2.3") }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>Gradle fails to select a variant because a machine architecture needs to be chosen:</p> </div> <div class="listingblock"> <div class="content"> <pre>> Could not resolve all files for configuration ':runtimeClasspath'. > Could not resolve org.lwjgl:lwjgl:3.2.3. Required by: project : > The consumer was configured to find a library for use during runtime, compatible with Java 11, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.gradle.native.operatingSystem' with value 'windows'. There are several available matching variants of org.lwjgl:lwjgl:3.2.3 The only attribute distinguishing these variants is 'org.gradle.native.architecture'. Add this attribute to the consumer's configuration to resolve the ambiguity: - Value: 'x86-64' selects variant: 'natives-windows-runtime' - Value: 'x86' selects variant: 'natives-windows-x86-runtime'</pre> </div> </div> </div> </div> <div class="sect1"> <h2 id="sec:making-library-flavors"><a class="anchor" href="#sec:making-library-flavors"></a><a class="link" href="#sec:making-library-flavors">Making different flavors of a library available through capabilities</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Because it is difficult to model <a href="feature_variants.html#feature_variants">optional feature variants</a> as separate jars with pom metadata, libraries sometimes comprise different jars with different feature sets. That is, instead of composing your flavor of the library from different feature variants, you select one of the pre-composed variants (offering everything in one jar). One such library is the well-known dependency injection framework Guice, published on <a href="https://repo1.maven.org/maven2/com/google/inject/guice/4.2.2">Maven central</a>, which offers a complete flavor (the main jar) and a reduced variant without aspect-oriented programming support (<code>guice-4.2.2-no_aop.jar</code>). That second variant with a classifier is not mentioned in the pom metadata. With the following rule, we create compile and runtime variants based on that file and make it selectable through a capability named <code>com.google.inject:guice-no_aop</code>.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class GuiceRule: ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { listOf("compile", "runtime").forEach { base -> context.details.addVariant("noAop${base.capitalize()}", base) { withCapabilities { addCapability("com.google.inject", "guice-no_aop", context.details.id.version) } withFiles { removeAllFiles() addFile("guice-${context.details.id.version}-no_aop.jar") } withDependencies { removeAll { it.group == "aopalliance" } } } } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class GuiceRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { ["compile", "runtime"].each { base -> context.details.addVariant("noAop${base.capitalize()}", base) { withCapabilities { addCapability("com.google.inject", "guice-no_aop", context.details.id.version) } withFiles { removeAllFiles() addFile("guice-${context.details.id.version}-no_aop.jar") } withDependencies { removeAll { it.group == "aopalliance" } } } } } }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>The new variants also have the dependency on the standardized aop interfaces library <code>aopalliance:aopalliance</code> removed, as this is clearly not needed by these variants. Again, this is information that cannot be expressed in pom metadata. We can now select a <code>guice-no_aop</code> variant and will get the correct jar file <strong>and</strong> the correct dependencies.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">dependencies { components { withModule<GuiceRule>("com.google.inject:guice") } implementation("com.google.inject:guice:4.2.2") { capabilities { requireCapability("com.google.inject:guice-no_aop") } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">dependencies { components { withModule("com.google.inject:guice", GuiceRule) } implementation("com.google.inject:guice:4.2.2") { capabilities { requireCapability("com.google.inject:guice-no_aop") } } }</code></pre> </div> </div> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="sec:adding-missing-capabilities"><a class="anchor" href="#sec:adding-missing-capabilities"></a><a class="link" href="#sec:adding-missing-capabilities">Adding missing capabilities to detect conflicts</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Another usage of capabilities is to express that two different modules, for example <code>log4j</code> and <code>log4j-over-slf4j</code>, provide alternative implementations of the same thing. By declaring that both provide the same capability, Gradle only accepts one of them in a dependency graph. This example, and how it can be tackled with a component metadata rule, is described in detail in the <a href="component_capabilities.html#sec:declaring-capabilities-external-modules">feature modelling</a> section.</p> </div> </div> </div> <div class="sect1"> <h2 id="sec:making-ivy-modules-variant-aware"><a class="anchor" href="#sec:making-ivy-modules-variant-aware"></a><a class="link" href="#sec:making-ivy-modules-variant-aware">Making Ivy modules variant-aware</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Modules published using Ivy do not have variants available by default.</p> </div> <div class="paragraph"> <p>However, <em>Ivy configurations</em> can be mapped to variants as the <code>addVariant(name, baseVariantOrConfiguration)</code> accepts any Ivy configuration that was published as base. This can be used, for example, to define runtime and compile variants. An example of a corresponding rule can be found <a href="variant_model.html#sec:ivy-mapping-to-variants">here</a>. Ivy details of Ivy configurations (e.g. dependencies and files) can also be modified using the <code>withVariant(configurationName)</code> API. However, modifying attributes or capabilities on Ivy configurations has no effect.</p> </div> <div class="paragraph"> <p>For very Ivy specific use cases, the component metadata rules API also offers access to other details only found in Ivy metadata. These are available through the <a href="../javadoc/org/gradle/api/artifacts/ivy/IvyModuleDescriptor.html">IvyModuleDescriptor</a> interface and can be accessed using <code>getDescriptor(IvyModuleDescriptor)</code> on the <a href="../javadoc/org/gradle/api/artifacts/ComponentMetadataContext.html">ComponentMetadataContext</a>.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class IvyComponentRule : ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { val descriptor = context.getDescriptor(IvyModuleDescriptor::class) if (descriptor != null && descriptor.branch == "testing") { context.details.status = "rc" } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class IvyComponentRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { def descriptor = context.getDescriptor(IvyModuleDescriptor) if (descriptor != null && descriptor.branch == "testing") { context.details.status = "rc" } } }</code></pre> </div> </div> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="sec:filter-maven-metadata"><a class="anchor" href="#sec:filter-maven-metadata"></a><a class="link" href="#sec:filter-maven-metadata">Filter using Maven metadata</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>For Maven specific use cases, the component metadata rules API also offers access to other details only found in POM metadata. These are available through the <a href="../javadoc/org/gradle/api/artifacts/maven/PomModuleDescriptor.html">PomModuleDescriptor</a> interface and can be accessed using <code>getDescriptor(PomModuleDescriptor)</code> on the <a href="../javadoc/org/gradle/api/artifacts/ComponentMetadataContext.html">ComponentMetadataContext</a>.</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class MavenComponentRule : ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { val descriptor = context.getDescriptor(PomModuleDescriptor::class) if (descriptor != null && descriptor.packaging == "war") { // ... } } }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class MavenComponentRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { def descriptor = context.getDescriptor(PomModuleDescriptor) if (descriptor != null && descriptor.packaging == "war") { // ... } } }</code></pre> </div> </div> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="sec:modifying-metadata"><a class="anchor" href="#sec:modifying-metadata"></a><a class="link" href="#sec:modifying-metadata">Modifying metadata on the component level for alignment</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>While all the examples above made modifications to variants of a component, there is also a limited set of modifications that can be done to the metadata of the component itself. This information can influence the <a href="variant_model.html#understanding_dependency_resolution_model">version selection</a> process for a module during dependency resolution, which is performed <em>before</em> one or multiple variants of a component are selected.</p> </div> <div class="paragraph"> <p>The first API available on the component is <code>belongsTo()</code> to create virtual platforms for aligning versions of multiple modules without Gradle Module Metadata. It is explained in detail in the section on <a href="dependency_version_alignment.html#sec:align-versions-unpublished">aligning versions of modules not published with Gradle</a>.</p> </div> </div> </div> <div class="sect1"> <h2 id="sec:custom-status-scheme"><a class="anchor" href="#sec:custom-status-scheme"></a><a class="link" href="#sec:custom-status-scheme">Modifying metadata on the component level for version selection based on status</a></h2> <div class="sectionbody"> <div class="paragraph"> <p>Gradle and Gradle Module Metadata also allow attributes to be set on the whole component instead of a single variant. Each of these attributes carries special semantics as they influence version selection which is done <em>before</em> variant selection. While variant selection can handle <a href="variant_attributes.html#sec:declaring-attributes">any custom attribute</a>, version selection only considers attributes for which specific semantics are implemented. At the moment, the only attribute with meaning here is <code>org.gradle.status</code>.</p> </div> <div class="openblock"> <div class="content"> <div class="paragraph"> <p>The <code>org.gradle.status</code> module attribute indicates the lifecycle status or maturity level of a module or library:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p><strong><code>integration</code></strong>: This indicates that the module is under active development and may not be stable.</p> </li> <li> <p><strong><code>milestone</code></strong>: A module with this status is more mature than one marked as <code>integration</code>.</p> </li> <li> <p><strong><code>release</code></strong>: This status signifies that the module is stable and officially released.</p> </li> </ol> </div> </div> </div> <div class="paragraph"> <p>It is therefore recommended to only modify this attribute, if any, on the component level. A dedicated API <code>setStatus(value)</code> is available for this. To modify another attribute for all variants of a component <code>withAllVariants { attributes {} }</code> should be utilised instead.</p> </div> <div class="paragraph"> <p>A module’s status is taken into consideration when a <a href="dependency_versions.html#sec:single-version-declarations"><em>latest</em> version selector</a> is resolved. Specifically, <code>latest.someStatus</code> will resolve to the highest module version that has status <code>someStatus</code> or a more mature status. For example, <code>latest.integration</code> will select the highest module version regardless of its status (because <code>integration</code> is the least mature status as explained below), whereas <code>latest.release</code> will select the highest module version with status <code>release</code>.</p> </div> <div class="paragraph"> <p>The interpretation of the status can be influenced by changing a module’s <em>status scheme</em> through the <code>setStatusScheme(valueList)</code> API. This concept models the different levels of maturity that a module transitions through over time with different publications. The default status scheme, ordered from least to most mature status, is <code>integration</code>, <code>milestone</code>, <code>release</code>. The <code>org.gradle.status</code> attribute must be set, to one of the values in the component’s status scheme. Thus each component always has a status which is determined from the metadata as follows:</p> </div> <div class="ulist"> <ul> <li> <p>Gradle Module Metadata: the value that was published for the <code>org.gradle.status</code> attribute on the component</p> </li> <li> <p>Ivy metadata: <code>status</code> defined in the ivy.xml, defaults to <code>integration</code> if missing</p> </li> <li> <p>Pom metadata: <code>integration</code> for modules with a SNAPSHOT version, <code>release</code> for all others</p> </li> </ul> </div> <div class="paragraph"> <p>The following example demonstrates <code>latest</code> selectors based on a custom status scheme declared in a component metadata rule that applies to all modules:</p> </div> <div class="exampleblock"> <div class="content"> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle.kts</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="kotlin">@CacheableRule abstract class CustomStatusRule : ComponentMetadataRule { override fun execute(context: ComponentMetadataContext) { context.details.statusScheme = listOf("nightly", "milestone", "rc", "release") if (context.details.status == "integration") { context.details.status = "nightly" } } } dependencies { components { all<CustomStatusRule>() } implementation("org.apache.commons:commons-lang3:latest.rc") }</code></pre> </div> </div> </div> </div> <div class="exampleblock testable-sample multi-language-sample"> <div class="content"> <div class="listingblock"> <div class="title">build.gradle</div> <div class="content"> <pre class="prettyprint highlight"><code data-lang="groovy">@CacheableRule abstract class CustomStatusRule implements ComponentMetadataRule { void execute(ComponentMetadataContext context) { context.details.statusScheme = ["nightly", "milestone", "rc", "release"] if (context.details.status == "integration") { context.details.status = "nightly" } } } dependencies { components { all(CustomStatusRule) } implementation("org.apache.commons:commons-lang3:latest.rc") }</code></pre> </div> </div> </div> </div> </div> </div> <div class="paragraph"> <p>Compared to the default scheme, the rule inserts a new status <code>rc</code> and replaces <code>integration</code> with <code>nightly</code>. Existing modules with the status <code>integration</code> are mapped to <code>nightly</code>.</p> </div> </div> </div> </div> <div id="feedback-container" class="feedback-container"> <div class="feedback-buttons"> <label id="feedback-container-label"> Was this page helpful?</label> <button id="thumbs-up" onclick="showFeedbackForm(true)"> <!-- Thumbs Up SVG --> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1"> <g id="surface1"> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.588235%,65.882353%,79.607843%);fill-opacity:1;" d="M 3 21.375 C 3 21.582031 2.832031 21.75 2.625 21.75 C 2.417969 21.75 2.25 21.582031 2.25 21.375 C 2.25 21.167969 2.417969 21 2.625 21 C 2.832031 21 3 21.167969 3 21.375 Z M 3 21.375 "/> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.588235%,65.882353%,79.607843%);fill-opacity:1;" d="M 5.25 9.75 C 5.25 8.921875 4.578125 8.25 3.75 8.25 L 1.5 8.25 C 0.671875 8.25 0 8.921875 0 9.75 L 0 22.5 C 0 23.328125 0.671875 24 1.5 24 L 3.75 24 C 4.578125 24 5.25 23.328125 5.25 22.5 Z M 2.625 22.5 C 2.003906 22.5 1.5 21.996094 1.5 21.375 C 1.5 20.753906 2.003906 20.25 2.625 20.25 C 3.246094 20.25 3.75 20.753906 3.75 21.375 C 3.75 21.996094 3.246094 22.5 2.625 22.5 Z M 2.625 22.5 "/> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.588235%,65.882353%,79.607843%);fill-opacity:1;" d="M 24 10.5 C 24 9.257812 22.992188 8.25 21.75 8.25 L 15.367188 8.25 L 15.375 8.25 L 16.125 1.5 C 16.203125 0.679688 15.640625 0 14.8125 0 L 13.3125 0 C 12.375 0 11.984375 0.65625 11.625 1.5 L 8.625 8.25 C 7.816406 10.1875 6.75 10.5 6 10.5 L 6 21.832031 C 6.449219 21.9375 7.019531 22.1875 7.578125 22.761719 C 8.746094 23.960938 10.140625 24 10.875 24 L 19.5 24 C 20.742188 24 21.75 22.992188 21.75 21.75 C 21.75 21.101562 21.472656 20.515625 21.035156 20.105469 C 21.890625 19.789062 22.5 18.964844 22.5 18 C 22.5 17.351562 22.222656 16.765625 21.785156 16.355469 C 22.640625 16.039062 23.25 15.214844 23.25 14.25 C 23.25 13.601562 22.972656 13.015625 22.535156 12.605469 C 23.390625 12.289062 24 11.464844 24 10.5 Z M 24 10.5 "/> </g> </svg> </button> <button id="thumbs-down" onclick="showFeedbackForm(false)"> <!-- Thumbs Down SVG --> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1"> <g id="surface1"> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.588235%,65.882353%,79.607843%);fill-opacity:1;" d="M 3 13.125 C 3 13.332031 2.832031 13.5 2.625 13.5 C 2.417969 13.5 2.25 13.332031 2.25 13.125 C 2.25 12.917969 2.417969 12.75 2.625 12.75 C 2.832031 12.75 3 12.917969 3 13.125 Z M 3 13.125 "/> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.588235%,65.882353%,79.607843%);fill-opacity:1;" d="M 0 1.5 C 0 0.671875 0.671875 0 1.5 0 L 3.75 0 C 4.578125 0 5.25 0.671875 5.25 1.5 L 5.25 14.25 C 5.25 15.078125 4.578125 15.75 3.75 15.75 L 1.5 15.75 C 0.671875 15.75 0 15.078125 0 14.25 Z M 2.625 14.25 C 3.246094 14.25 3.75 13.746094 3.75 13.125 C 3.75 12.503906 3.246094 12 2.625 12 C 2.003906 12 1.5 12.503906 1.5 13.125 C 1.5 13.746094 2.003906 14.25 2.625 14.25 Z M 2.625 14.25 "/> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.588235%,65.882353%,79.607843%);fill-opacity:1;" d="M 24 13.5 C 24 14.742188 22.992188 15.75 21.75 15.75 L 15.367188 15.75 L 15.375 15.75 L 16.125 22.5 C 16.203125 23.320312 15.640625 24 14.8125 24 L 13.3125 24 C 12.375 24 11.984375 23.34375 11.625 22.5 L 8.625 15.75 C 7.816406 13.8125 6.75 13.5 6 13.5 L 6 2.167969 C 6.449219 2.0625 7.019531 1.8125 7.578125 1.238281 C 8.746094 0.0390625 10.140625 0 10.875 0 L 19.5 0 C 20.742188 0 21.75 1.007812 21.75 2.25 C 21.75 2.898438 21.472656 3.484375 21.035156 3.894531 C 21.890625 4.210938 22.5 5.035156 22.5 6 C 22.5 6.648438 22.222656 7.234375 21.785156 7.644531 C 22.640625 7.960938 23.25 8.785156 23.25 9.75 C 23.25 10.398438 22.972656 10.984375 22.535156 11.394531 C 23.390625 11.710938 24 12.535156 24 13.5 Z M 24 13.5 "/> </g> </svg> </button> </div> <div id="feedback-form" class="hidden-feedback-form"> <form> <label for="feedback">Additional Feedback:</label> <textarea id="feedback" name="feedback" rows="4" cols="50" placeholder="Tell us more about your experience."></textarea> <div>You can <a href="https://github.com/gradle/gradle/issues/new?assignees=&labels=a%3Adocumentation%2Cto-triage&projects=&template=40_contributor_documentation.yml"> submit issues</a> directly on Github.</div> <button id="feedback-button" type="button" onclick="submitAdditionalFeedback()" disabled> Submit Feedback <div class="animate-flicker"></div> </button> </form> </div> </div><script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/run_prettify.min.js"></script> </div> <!-- end div class="chapter" --> <footer class="site-layout__footer site-footer" itemscope="itemscope" itemtype="https://schema.org/WPFooter"> <nav class="site-footer__navigation" itemtype="https://schema.org/SiteNavigationElement"> <section class="site-footer__links"> <div class="site-footer__link-group"> <header><strong>Docs</strong></header> <ul class="site-footer__links-list"> <li itemprop="name"><a href="/release-notes.html" itemprop="url">Release Notes</a></li> <li itemprop="name"><a href="/dsl/" itemprop="url">Groovy DSL</a></li> <li itemprop="name"><a href="/kotlin-dsl/" itemprop="url">Kotlin DSL</a></li> <li itemprop="name"><a href="/javadoc/" itemprop="url">Javadoc</a></li> </ul> </div> <div class="site-footer__link-group"> <header><strong>News</strong></header> <ul class="site-footer__links-list"> <li itemprop="name"><a href="https://blog.gradle.org/" itemprop="url">Blog</a></li> <li itemprop="name"><a href="https://newsletter.gradle.org/" itemprop="url">Newsletter</a></li> <li itemprop="name"><a href="https://twitter.com/gradle" itemprop="url">Twitter</a></li> <li itemprop="name"><a href="https://status.gradle.com/" itemprop="url">Status</a></li> </ul> </div> <div class="site-footer__link-group"> <header><strong>Products</strong></header> <ul class="site-footer__links-list"> <li itemprop="name"><a href="https://gradle.com/develocity/" itemprop="url">Develocity</a></li> <li itemprop="name"><a href="https://gradle.com/build-scans/" itemprop="url">Build Scan™</a></li> <li itemprop="name"><a href="https://gradle.com/build-cache/" itemprop="url">Build Cache</a></li> <li itemprop="name"><a href="https://gradle.org/services/" itemprop="url">Services</a></li> </ul> </div> <div class="site-footer__link-group"> <header><strong>Get Help</strong></header> <ul class="site-footer__links-list"> <li itemprop="name"><a href="https://discuss.gradle.org/c/help-discuss" itemprop="url">Forums</a></li> <li itemprop="name"><a href="https://github.com/gradle/" itemprop="url">GitHub</a></li> <li itemprop="name"><a href="https://gradle.org/training/" itemprop="url">Events</a></li> <li itemprop="name"><a href="https://dpeuniversity.gradle.com/" itemprop="url">DPE University</a></li> </ul> </div> </section> <section class="site-footer__subscribe-newsletter" id="newsletter-form-container"> <header class="newsletter-form__header"><h5>Stay <code>UP-TO-DATE</code> on new features and news</h5></header> <p class="disclaimer">By entering your email, you agree to our <a href="https://gradle.com/legal/terms-of-service/">Terms</a> and <a href="https://gradle.com/legal/privacy/">Privacy Policy</a>, including receipt of emails. You can unsubscribe at any time.</p> <div class="newsletter-form__container"> <form id="newsletter-form" class="newsletter-form" action="https://go.gradle.com/l/68052/2018-09-07/bk6wml" method="post"> <input id="email" class="email" name="email" type="email" placeholder="name@email.com" pattern="[^@\s]+@[^@\s]+\.[^@\s]+" maxlength="255" required=""/> <button id="submit" class="submit" type="submit">Subscribe</button> </form> </div> </section> </nav> </footer> </div> <!-- end div class="content" --> </main> <div class="site-footer-secondary"> <div class="site-footer-secondary__contents"> <div class="site-footer__copy">© <a href="https://gradle.com">Gradle Inc.</a> <time>2023</time> All rights reserved. </div> <div class="site-footer__logo"><a href="/"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 66.06"> <title>Gradle</title> <path class="cls-1" d="M85.11,4.18a14.27,14.27,0,0,0-19.83-.34,1.38,1.38,0,0,0,0,2L67,7.6a1.36,1.36,0,0,0,1.78.12A8.18,8.18,0,0,1,79.5,20.06C68.17,31.38,53.05-.36,18.73,16a4.65,4.65,0,0,0-2,6.54l5.89,10.17a4.64,4.64,0,0,0,6.3,1.73l.14-.08-.11.08L31.53,33a60.29,60.29,0,0,0,8.22-6.13,1.44,1.44,0,0,1,1.87-.06h0a1.34,1.34,0,0,1,.06,2A61.61,61.61,0,0,1,33,35.34l-.09,0-2.61,1.46a7.34,7.34,0,0,1-3.61.94,7.45,7.45,0,0,1-6.47-3.71l-5.57-9.61C4,32-2.54,46.56,1,65a1.36,1.36,0,0,0,1.33,1.11H8.61A1.36,1.36,0,0,0,10,64.87a9.29,9.29,0,0,1,18.42,0,1.35,1.35,0,0,0,1.34,1.19H35.9a1.36,1.36,0,0,0,1.34-1.19,9.29,9.29,0,0,1,18.42,0A1.36,1.36,0,0,0,57,66.06H63.1a1.36,1.36,0,0,0,1.36-1.34c.14-8.6,2.46-18.48,9.07-23.43C96.43,24.16,90.41,9.48,85.11,4.18ZM61.76,30.05l-4.37-2.19h0a2.74,2.74,0,1,1,4.37,2.2Z"/> </svg> </a></div> <div class="site-footer-secondary__links"> <a href="https://gradle.com/careers/">Careers</a> | <a href="https://gradle.com/legal/privacy/">Privacy</a> | <a href="https://gradle.com/legal/terms-of-service/">Terms of Service</a> | <a href="https://gradle.org/contact/">Contact</a> </div> </div> </div> </div> <!-- end div class="layout" --> <script type="text/javascript"> // Polyfill Element.matches() if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; } // Polyfill Element.closest() if (!Element.prototype.closest) { Element.prototype.closest = function (s) { var el = this; if (!document.documentElement.contains(el)) return null; do { if (typeof el.matches === "function" && el.matches(s)) return el; el = el.parentElement || el.parentNode; } while (el !== null); return null; }; } function getCurrentChapterFileName(givenUrl) { var currentChapterFileName = givenUrl.substr(givenUrl.lastIndexOf("/") + 1); if (currentChapterFileName === "index.html" || currentChapterFileName === "") { currentChapterFileName = givenUrl.substr(0, givenUrl.lastIndexOf("/")); currentChapterFileName = currentChapterFileName.substr(currentChapterFileName.lastIndexOf("/") + 1) + "/index.html"; } return currentChapterFileName; } // The media query indicating that a device is a desktop. // The `min-width: 64rem` definition should be aligned to // the one of `css/manual.css`. const desktopMediaQuery = window.matchMedia("screen and (min-width: 64rem)"); [].forEach.call(document.querySelectorAll(".docs-navigation a[href$='/" + getCurrentChapterFileName(window.location.pathname) + "']"), function (link) { // Add "active" to all links same as current URL link.classList.add("active"); // Expand all parent navigation var parentListEl = link.closest("li"); while (parentListEl !== null) { var dropDownEl = parentListEl.querySelector(".nav-dropdown"); if (dropDownEl !== null) { dropDownEl.classList.add("expanded"); } parentListEl = parentListEl.parentNode.closest("li"); } // Only scroll if the device is a desktop. // // Mobile's `docs-navigation` is always at bottom of `content`, // so we should not slide down to where `docs-navigation` lays. if (desktopMediaQuery.matches) { // Scroll to center of the page link.scrollIntoView({behavior: 'auto', block: 'center', inline: 'center'}) } }); // Expand/contract multi-level side navigation [].forEach.call(document.querySelectorAll(".docs-navigation .nav-dropdown"), function registerSideNavActions(collapsibleElement) { collapsibleElement.addEventListener("click", function toggleExpandedSideNav(evt) { evt.preventDefault(); evt.target.classList.toggle("expanded"); evt.target.setAttribute("aria-expanded", evt.target.classList.contains("expanded").toString()); return false; }, false); }); // Fix a weird issue making the initial screen always at the bottom. document.querySelector(".content").scrollIntoView(true); </script> </body> </html>