text: 'use strict';(function(){const indexCfg={cache:true};indexCfg.doc={id:'id',field:['title','content'],store:['title','href'],};const index=FlexSearch.create('balance',indexCfg);window.bookSearchIndex=index;index.add({'id':0,'href':'/keycloakmigration/migrations/requiredactions/','title':"Required Actions",'content':"Required Actions\r#\r\rAll migrations referring to the Required Actions resource in Authentication.\nAddRequiredAction\r#\r\rAdds a required action.\nParameters\r#\r\r realm: String, optional providerId: String, mandatory alias: String, mandatory name: String, mandatory config: Map\u0026lt;String,String\u0026gt;, optional, default = emptyMap defaultAction: Boolean, optional, default = false enabled: Boolean, optional, default = true priority: Boolean, optional, default = preset through keycloak  Example\r#\r\rid:add-required-actionauthor:klg71realm:integ-testchanges:- addRequiredAction:providerId:verify-emailalias:VERIFY_EMAILname:VerifyEmaildefaultAction:trueenabled:trueUpdateRequiredAction\r#\r\rUpdates a required action. Only updates provided values. For an update of the required action alias use the oldAlias as alias and the newAlias in newAlias.\nParameters\r#\r\r realm: String, optional providerId: String, optional, default = no update, alias: String, mandatory newAlias: String, optional, default = no update name: String, optional, default = no update config: Map\u0026lt;String,String\u0026gt;, optional, default = no update defaultAction: Boolean, optional, default = no update enabled: Boolean, optional, default = no update priority: Boolean, optional, default = no update  Example\r#\r\rid:add-required-actionauthor:klg71realm:integ-testchanges:- addRequiredAction:providerId:verify-emailalias:VERIFY_EMAILname:VerifyEmaildefaultAction:trueenabled:true- updateRequiredAction:providerId:verify-emailalias:VERIFY_EMAILname:VerifyEmail2DeleteRequiredAction\r#\r\rDeletes a required action, if one with this alias exists\nParameters\r#\r\r realm: String, optional alias: String, mandatory  Example\r#\r\rid:delete-required-actionauthor:klg71realm:integ-testchanges:- addRequiredAction:providerId:verify-emailalias:VERIFY_EMAILname:VerifyEmaildefaultAction:trueenabled:true- deleteRequiredAction:alias:VERIFY_EMAIL"});index.add({'id':1,'href':'/keycloakmigration/migrations/','title':"Available Actions",'content':"Supported migrations\r#\r\rCurrently we implemented migration actions for the following resources:\n User Group Role Realm Client UserFederation  For more examples see src/test/resources/changesets.\nTechnical Hints\r#\r\rThe migration hashes are stored in the attribute named \u0026lsquo;migration\u0026rsquo; in the migration user.\nThere are no transactions in keycloak though if the rollback fails there might be a non deterministic state! If it fails I would like to receive a bug report for this.\nIf you struggle with invalid hashes on a linux-windows setup check the line endings of the json-import files as git might check them out as LF where on windows its CRLF and thus producing the error in hashing.\nIf you are using git you can place the following file into the dir with the json-import-files to reassure that the line ending is always LF.\n.gitattributes:\n** text eol=lf\r Hacking\r#\r\rTo start developing on this project you can use the gradle tasks.\nTo start the local development keycloak you can just use the task startLocalKeycloak\nTested with OpenJdk 12 and Keycloak 8.0.2\nUse keycloakmigration through maven dependency\r#\r\rGradle dependency\r#\r\r // https://mvnrepository.com/artifact/de.klg71.keycloakmigration/keycloakmigration\rcompile group: 'de.klg71.keycloakmigration', name: 'keycloakmigration', version: 'x.x.x'\r Usage\r#\r\rKotlin\nclass MyMigrationArgs(private val adminUser: String,\rprivate val adminPassword: String,\rprivate val migrationFile: String,\rprivate val baseUrl: String,\rprivate val realm: String,\rprivate val clientId: String,\rprivate val correctHashes: Boolean,\rprivate val parameters: Map\u0026lt;String, String\u0026gt;) : MigrationArgs {\roverride fun adminUser() = adminUser\roverride fun adminPassword() = adminPassword\roverride fun baseUrl() = baseUrl\roverride fun migrationFile() = migrationFile\roverride fun realm() = realm\roverride fun clientId() = clientId\roverride fun correctHashes() = correctHashes\roverride fun parameters() = parameters\r}\rclass KeycloakMigrationExecution {\rfun migrate() {\rMyMigrationArgs(\u0026quot;admin\u0026quot;, \u0026quot;adminPass\u0026quot;, \u0026quot;keycloak-changelog.yml\u0026quot;,\r\u0026quot;https://myauthserver\u0026quot;, \u0026quot;master\u0026quot;,\r\u0026quot;admin-cli\u0026quot;, false, emptyMap())\r.let {\rde.klg71.keycloakmigration.migrate(it)\r}\r}\r}\r TODOS\r#\r\r Add more commands Add sophisticated unit and integration Tests batch updates for users  "});index.add({'id':2,'href':'/keycloakmigration/migrations/client/','title':"Client Migrations",'content':"Client Migrations\r#\r\rAll migrations referring to the client resource.\naddSimpleClient\r#\r\rSimple command to add a client to keycloak, TODO: add more fields\nParameter\r#\r\r realm: String, optional clientId: String, not optional, enabled: Boolean, optional, default=true attributes: Map\u0026lt; String, String\u0026gt;, optional, default = empty protocol: String, optional, default=\u0026quot;openid-connect\u0026rdquo; secret: String, optional publicClient: Boolean, optional, default=true redirectUris: List\u0026lt; String\u0026gt;, optional, default=empty  Example\r#\r\rid: add-simple-client\rauthor: klg71\rchanges:\r- addSimpleClient:\rrealm: master\rclientId: test\r deleteClient\r#\r\rDelete a client in keycloak\nParameter\r#\r\r realm: String, optional clientId: String, not optional,  Example\r#\r\rid: delete-client\rauthor: klg71\rchanges:\r- deleteClient:\rrealm: master\rclientId: test\r importClient\r#\r\rImports a client using the json representation.\nParameters\r#\r\r realm: String, optional clientRepresentationJsonFilename: String, not optional relativeToFile: Boolean, optional, default=true  Example\r#\r\rid: import-client\rauthor: klg71\rchanges:\r- importClient:\rrealm: master\rclientRepresentationJsonFilename: client.json\rrelativeToFile: true\r updateClient\r#\r\rUpdate a client\nParameters\r#\r\r realm: String, optional clientId: String, not optional name: String, optional, default=no change description: String, optional, default=no change enabled: Boolean, optional, default=no change attributes: Map\u0026lt;String, String\u0026gt;, optional, default=no change protocol: String, optional, default=no change redirectUris: List\u0026lt; String\u0026gt;, optional, default=no change bearerOnly: Boolean, optional, default=no change directAccessGrantEnabled: Boolean, optional, default=no change implicitFlowEnabled: Boolean, optional, default=no change standardFlowEnabled: Boolean, optional, default=no change adminUrl: String, optional, default=no change baseUrl: String, optional, default=no change rootUrl: String, optional, default=no change publicClient: Boolean, optional, default=no change serviceAccountsEnabled: Boolean, optional, default=no change webOrigins: List\u0026lt; String\u0026gt;, optional, default=no change fullScopeAllowed: Boolean, optional, default=no change  Example\r#\r\rid: update-client\rauthor: klg71\rchanges:\r- updateClient:\rrealm: master\rclientId: testClient\rredirectUris: - http://localhost:8080\r- https://www.example.com\r assignRoleToClient\r#\r\rAssigns a realm- or client-role(if roleClientId is set) to a service account of a client.\nParameters\r#\r\r realm: String, optional clientId: String, not optional role: String, not optional roleClientId: String, optional, default = realmRole  Example\r#\r\rid: add-client-roles\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testClientRoles\r- updateClient:\rclientId: testClientRoles\rserviceAccountsEnabled: true\rpublicClient: false\r- assignRoleToClient:\rclientId: testClientRoles\rrole: query-users\rroleClientId: realm-management\r addRoleScopeMapping\r#\r\rAdds a realm- or client-role(if roleClientId is set) to the cope mappings of a client.\nSee https://www.keycloak.org/docs/latest/server_admin/#_role_scope_mappings\nParameters\r#\r\r realm: String, optional clientId: String, not optional role: String, not optional roleClientId: String, optional, default = realmRole  Example\r#\r\rid: add-client-role-mapping\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testClientRoleScopeMappings\r- addRole:\rname: scope-mapping-role\r- updateClient:\rclientId: testClientRoleScopeMappings\rfullScopeAllowed: false\r- addRoleScopeMapping:\rclientId: testClientRoleScopeMappings\rrole: scope-mapping-role\r- addRoleScopeMapping:\rclientId: testClientRoleScopeMappings\rrole: query-users\rroleClientId: realm-management\r addClientMapper\r#\r\radds a full configurable clientmapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\n Only use this action if you can\u0026rsquo;t find a convenient method to add the mapper below\n Parameters\r#\r\r realm: String, optional clientId: String, not optional name: String, not optional config: Map\u0026lt;String,String\u0026gt;, not optional protocolMapper: String, not optional protocol: String, optional, default=\u0026quot;openid-connect\u0026rdquo;  Example:\r#\r\rid: add-client-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testMappers\r- addClientMapper:\rclientId: testMappers\rname: testPropertyMapper\rprotocolMapper: oidc-usermodel-property-mapper\rconfig:\raccess.token.claim: true\rid.token.claim: false\ruserinfo.token.claim: false\rclaim.name: customPropertyMapper\rjsonType.label: String\ruser.attribute: UserModel.getEmail()\r deleteClientMapper\r#\r\rdeletes a client mapper\nParameters\r#\r\r realm: String, optional clientId: String, not optional name: String, not optional  Example:\r#\r\rid: add-client-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testMappers\r- addClientMapper:\rclientId: testMappers\rname: testPropertyMapper\rprotocolMapper: oidc-usermodel-property-mapper\rconfig:\raccess.token.claim: true\rid.token.claim: false\ruserinfo.token.claim: false\rclaim.name: customPropertyMapper\rjsonType.label: String\ruser.attribute: UserModel.getEmail()\r- deleteClientMapper:\rclientId: testMappers\rname: testPropertyMapper\r addClientAudienceMapper\r#\r\radds a audience clientmapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientId: String, not optional name: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, clientAudience: String, optional, default = \u0026ldquo;\u0026rdquo;, customAudience: String, optional, default = \u0026quot;\u0026rdquo;  Example:\r#\r\rid: add-client-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testMappers\r- addClientAudienceMapper:\rclientId: testMappers\rname: audienceMapper\raddToIdToken: false\rclientAudience: testMappers\rcustomAudience: completlyCustom\r addClientGroupMembershipMapper\r#\r\radds a group-membership clientmapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientId: String, not optional name: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, addToUserInfo: Boolean, optional, default = true, fullGroupPath: Boolean, optional, default = true, claimName: String?, optional, default = \u0026laquo; name parameter\u0026raquo;  Example:\r#\r\rid: add-client-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testMappers\r- addClientGroupMembershipMapper:\rclientId: testMappers\rname: groupMembership\raddToAccessToken: false\rclaimName: groupClaim\r addClientUserAttributeMapper\r#\r\radds a user-attribute clientmapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientId: String, not optional name: String, not optional userAttribute: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, addToUserInfo: Boolean, optional, default = true, claimName: String?, optional, default = \u0026laquo; name parameter\u0026raquo; multivalued: Boolean, optional, default = false, aggregateAttributeValues: Boolean, optional, default = true  Example:\r#\r\rid: add-client-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testMappers\r- addClientUserAttributeMapper:\rclientId: testMappers\rname: userAttribute\ruserAttribute: testAttribute\raddToUserInfo: false\r addClientUserRealmRoleMapper\r#\r\radds a user-realm-role clientmapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientId: String, not optional name: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, addToUserInfo: Boolean, optional, default = true, claimName: String?, optional, default = \u0026laquo; name parameter\u0026raquo; prefix: String, optional, default = \u0026quot;\u0026rdquo;  Example:\r#\r\rid: add-client-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addSimpleClient:\rclientId: testMappers\r- addClientUserRealmRoleMapper:\rclientId: testMappers\rname: userRealmRole\rprefix: rolePrefix\r "});index.add({'id':3,'href':'/keycloakmigration/migrations/scopes/','title':"ClientScope Migrations",'content':"ClientScope Migrations\r#\r\rAll migrations referring to the ClientScope resource.\naddClientScope\r#\r\rAdds a clientScope to keycloak, fails if a clientScope with that name already exists\nParameter\r#\r\r realm: String, optional name: String, not optional description: String, optional, default = null protocol: String, optional, default = \u0026ldquo;openid-connect\u0026rdquo; protocolMappers: List\u0026lt; ProtocolMapper \u0026gt;, optional, default = empty list consentScreenText: String, optional, default = null displayOnConsentScreen: Boolean, optional, default = false guiOrder: Int, optional, default = null includeInTokenScope: Boolean, optional, default = true  subclass ProtocolMapper\r#\r\r name: String, mandatory protocol: String, mandatory, default = null protocolMapper: String, mandatory consentRequired: Boolean, optional config: Map\u0026lt;String, String\u0026gt;, optional, default = empty  Example\r#\r\rid:add-client-scopesauthor:klg71realm:integ-testchanges:- addClientScope:name:apiassignDefaultClientScope\r#\r\rAssigns a default clientScope to a client, fails if the client or scope doesn\u0026rsquo;t exist.\nParameter\r#\r\r realm: String, optional clientScopeName: String clientId: String  Example\r#\r\rid:add-client-scopesauthor:klg71realm:integ-testchanges:- addSimpleClient:clientId:testClientScope- addClientScope:name:api- assignDefaultClientScope:clientId:testClientScopeclientScopeName:apiaddClientScopeMapper\r#\r\radds a full configurable client scope mapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\n Only use this action if you can\u0026rsquo;t find a convenient method to add the mapper below\n Parameters\r#\r\r realm: String, optional clientScopeName: String, not optional name: String, not optional config: Map\u0026lt;String,String\u0026gt;, not optional protocolMapper: String, not optional protocol: String, optional, default=\u0026quot;openid-connect\u0026rdquo;  Example:\r#\r\rid: add-client-scope-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addClientScope:\rname: testMappers\r- addClientScopeMapper:\rclientScopeName: testMappers\rname: testPropertyMapper\rprotocolMapper: oidc-usermodel-property-mapper\rconfig:\raccess.token.claim: true\rid.token.claim: false\ruserinfo.token.claim: false\rclaim.name: customPropertyMapper\rjsonType.label: String\ruser.attribute: UserModel.getEmail()\r deleteClientScopeMapper\r#\r\rdeletes a client scope mapper\nParameters\r#\r\r realm: String, optional clientScopeName: String, not optional name: String, not optional  Example:\r#\r\rid: add-client-scope-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addClientScope:\rname: testMappers\r- addClientScopeMapper:\rclientScopeName: testMappers\rname: testPropertyMapper\rprotocolMapper: oidc-usermodel-property-mapper\rconfig:\raccess.token.claim: true\rid.token.claim: false\ruserinfo.token.claim: false\rclaim.name: customPropertyMapper\rjsonType.label: String\ruser.attribute: UserModel.getEmail()\r- deleteClientScopeMapper:\rclientScopeName: testMappers\rname: testPropertyMapper\r addClientScopeAudienceMapper\r#\r\radds an audience client scope mapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientScopeName: String, not optional name: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, clientAudience: String, optional, default = \u0026ldquo;\u0026rdquo;, customAudience: String, optional, default = \u0026quot;\u0026rdquo;  Example:\r#\r\rid: add-client-scope-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addClientScope:\rname: testMappers\r- addClientScopeAudienceMapper:\rclientScopeName: testMappers\rname: audienceMapper\raddToIdToken: false\rclientAudience: testMappers\rcustomAudience: completlyCustom\r addClientScopeGroupMembershipMapper\r#\r\radds a group-membership client scope mapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientScopeName: String, not optional name: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, addToUserInfo: Boolean, optional, default = true, fullGroupPath: Boolean, optional, default = true, claimName: String?, optional, default = \u0026laquo; name parameter\u0026raquo;  Example:\r#\r\rid: add-client-scope-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addClientScope:\rname: testMappers\r- addClientScopeGroupMembershipMapper:\rclientScopeName: testMappers\rname: groupMembership\raddToAccessToken: false\rclaimName: groupClaim\r addClientScopeUserAttributeMapper\r#\r\radds a user-attribute client scope mapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientScopeName: String, not optional name: String, not optional userAttribute: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, addToUserInfo: Boolean, optional, default = true, claimName: String?, optional, default = \u0026laquo; name parameter\u0026raquo; multivalued: Boolean, optional, default = false, aggregateAttributeValues: Boolean, optional, default = true  Example:\r#\r\rid: add-client-scope-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addClientScope:\rname: testMappers\r- addClientScopeUserAttributeMapper:\rclientScopeName: testMappers\rname: userAttribute\ruserAttribute: testAttribute\raddToUserInfo: false\r addClientScopeUserRealmRoleMapper\r#\r\radds a user-realm-role client scope mapper, throws error if client or realm doesn\u0026rsquo;t exist or mapper with same name already exists\nParameters\r#\r\r realm: String, optional clientScopeName: String, not optional name: String, not optional addToIdToken: Boolean , optional, default = true, addToAccessToken: Boolean, optional, default = true, addToUserInfo: Boolean, optional, default = true, claimName: String?, optional, default = \u0026laquo; name parameter\u0026raquo; prefix: String, optional, default = \u0026quot;\u0026rdquo;  Example:\r#\r\rid: add-client-scope-mappers\rauthor: klg71\rrealm: integ-test\rchanges:\r- addClientScope:\rname: testMappers\r- addClientScopeUserRealmRoleMapper:\rclientScopeName: testMappers\rname: userRealmRole\rprefix: rolePrefix\r "});index.add({'id':4,'href':'/keycloakmigration/migrations/flow/','title':"Flow Migrations",'content':"Flow Migrations\r#\r\rAll migrations referring to the Authentication Flow resource.\nAddFlow\r#\r\rAdds an authentication flow.\nParameters\r#\r\r realm: String, optional alias: String, not optional description: String, optional, default = \u0026ldquo;\u0026rdquo;, buildIn: Boolean, optional, default = false, providerId: String, optional, default = \u0026ldquo;basic-flow\u0026rdquo;, topLevel: Boolean, optional, default = true, executions: List\u0026lt; AuthenticationExecutionImport \u0026gt;, default = emptyList()  subclass AuthenticationExecutionImport\r#\r\r requirement: Flow.Requirement = \u0026ldquo;ALTERNATIVE\u0026rdquo; | \u0026ldquo;DISABLED\u0026rdquo; | \u0026ldquo;REQUIRED\u0026rdquo; | \u0026ldquo;CONDITIONAL\u0026rdquo; | \u0026ldquo;OPTIONAL\u0026rdquo; providerId: String = see providers in next point level: Int index: Int config: Map\u0026lt;String, String\u0026gt;, optional, default = empty  Known Flow providers on Release (09.04.2021)\r#\r\r no-cookie-redirect,Browser Redirect/Refresh,Perform a 302 redirect to get user agent\u0026rsquo;s current URI on authenticate path with an auth_session_id query parameter. This is for client\u0026rsquo;s that do not support cookies. auth-cookie,Cookie,Validates the SSO cookie set by the auth server. console-username-password,Username Password Challenge,Proprietary challenge protocol for CLI clients that queries for username password reset-credentials-choose-user,Choose User,Choose a user to reset credentials for direct-grant-validate-password,Password,Validates the password supplied as a \u0026lsquo;password\u0026rsquo; form parameter in direct grant request webauthn-authenticator,WebAuthn Authenticator,Authenticator for WebAuthn. Usually used for WebAuthn two-factor authentication auth-spnego,Kerberos,Initiates the SPNEGO protocol. Most often used with Kerberos. reset-password,Reset Password,Sets the Update Password required action if execution is REQUIRED. Will also set it if execution is OPTIONAL and the password is currently configured for it. direct-grant-auth-x509-username,X509/Validate Username,Validates username and password from X509 client certificate received as a part of mutual SSL handshake. auth-password-form,Password Form,Validates a password from login form. docker-http-basic-authenticator,Docker Authenticator,Uses HTTP Basic authentication to validate docker users, returning a docker error token on auth failure idp-username-password-form,Username Password Form for identity provider reauthentication,Validates a password from login form. Username may be already known from identity provider authentication idp-email-verification,Verify existing account by Email,Email verification of existing Keycloak user, that wants to link his user account with identity provider idp-auto-link,Automatically set existing user,Automatically set existing user to authentication context without any verification auth-x509-client-username-form,X509/Validate Username Form,Validates username and password from X509 client certificate received as a part of mutual SSL handshake. conditional-user-role,Condition - user role,Flow is executed only if user has the given role. basic-auth,Basic Auth Challenge,Challenge-response authentication using HTTP BASIC scheme. identity-provider-redirector,Identity Provider Redirector,Redirects to default Identity Provider or Identity Provider specified with kc_idp_hint query parameter direct-grant-validate-username,Username Validation,Validates the username supplied as a \u0026lsquo;username\u0026rsquo; form parameter in direct grant request reset-otp,Reset OTP,Sets the Configure OTP required action. conditional-user-configured,Condition - user configured,Executes the current flow only if authenticators are configured webauthn-authenticator-passwordless,WebAuthn Passwordless Authenticator,Authenticator for Passwordless WebAuthn authentication basic-auth-otp,Basic Auth Password+OTP,Challenge-response authentication using HTTP BASIC scheme. Password param should contain a combination of password + otp. Realm\u0026rsquo;s OTP policy is used to determine how to parse this. This SHOULD NOT BE USED in conjection with regular basic auth provider. idp-review-profile,Review Profile,User reviews and updates profile data retrieved from Identity Provider in the displayed form idp-confirm-link,Confirm link existing account,Show the form where user confirms if he wants to link identity provider with existing account or rather edit user profile data retrieved from identity provider to avoid conflict auth-conditional-otp-form,Conditional OTP Form,Validates a OTP on a separate OTP form. Only shown if required based on the configured conditions. auth-username-password-form,Username Password Form,Validates a username and password from login form. reset-credential-email,Send Reset Email,Send email to user and wait for response. auth-username-form,Username Form,Selects a user from his username. http-basic-authenticator,HTTP Basic Authentication,Validates username and password from Authorization HTTP header auth-otp-form,OTP Form,Validates a OTP on a separate OTP form. direct-grant-validate-otp,OTP,Validates the one time password supplied as a \u0026lsquo;totp\u0026rsquo; form parameter in direct grant request idp-create-user-if-unique,Create User If Unique,Detect if there is existing Keycloak account with same email like identity provider. If no, create new user  Example\r#\r\rid:add-flowauthor:klg71realm:integ-testchanges:- addFlow:alias:trust-foreign-idpexecutions:- requirement:ALTERNATIVEproviderId:idp-create-user-if-unique- requirement:ALTERNATIVEproviderId:idp-auto-linkUpdateFlow\r#\r\rUpdates an authentication flow in place. Only updates provided values. For an update of the flow alias use the oldAlias as alias and the newAlias in newAlias.\nParameters\r#\r\r realm: String, optional alias: String, not optional newAlias: String, optional, default = no update description: String, default = no update buildIn: Boolean, optional, default = no update, providerId: String, optional, default = no update, topLevel: Boolean, optional, default = no update, executions: List\u0026lt; AuthenticationExecutionImport \u0026gt;, default = no update  subclass AuthenticationExecutionImport\r#\r\r requirement: Flow.Requirement = \u0026ldquo;ALTERNATIVE\u0026rdquo; | \u0026ldquo;DISABLED\u0026rdquo; | \u0026ldquo;REQUIRED\u0026rdquo; | \u0026ldquo;CONDITIONAL\u0026rdquo; | \u0026ldquo;OPTIONAL\u0026rdquo; providerId: String = see providers in AddFlow action level: Int index: Int config: Map\u0026lt;String, String\u0026gt;, optional, default = empty  Example\r#\r\rid:update-flowauthor:klg71realm:integ-testchanges:- addFlow:alias:trust-foreign-idpexecutions:- requirement:ALTERNATIVEproviderId:idp-create-user-if-unique- requirement:ALTERNATIVEproviderId:idp-auto-link- updateFlow:alias:trust-foreign-idpnewAlias:trust-foreign-idp-updatedescription:new-descriptionexecutions:- requirement:ALTERNATIVEproviderId:idp-create-user-if-unique- requirement:REQUIREDproviderId:console-username-passwordDeleteFlow\r#\r\rDeletes a flow, if one with this alias exists\nParameters\r#\r\r realm: String, optional alias: String, not optional  Example\r#\r\rid:delete-flowauthor:klg71realm:integ-testchanges:- addFlow:alias:trust-foreign-idpexecutions:- requirement:ALTERNATIVEproviderId:idp-create-user-if-unique- requirement:ALTERNATIVEproviderId:idp-auto-link- deleteFlow:alias:trust-foreign-idp"});index.add({'id':5,'href':'/keycloakmigration/migrations/group/','title':"Group Migrations",'content':"Group Migrations\r#\r\rAll migrations referring to the group resource.\naddGroup\r#\r\rAdds a new group to keycloak. Fails if the group already exists.\nParameters\r#\r\r realm: String, optional name: String, not optional parent: String, default=empty  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- addGroup:\rrealm: master\rname: testGroup\r deleteGroup\r#\r\rRemoves a group from keycloak. Fails if the group does not exist.\nParameters\r#\r\r realm: String, optional name: String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- deleteGroup:\rrealm: master\rname: testUser\r updateGroup\r#\r\rUpdates a group from keycloak. Fails if the group does not exist.\nParameters\r#\r\r realm: String, optional name: String, not optional attributes: Map\u0026lt; String,List\u0026lt; String\u0026raquo;, optional, default=existing attributes realmRoles: List\u0026lt; String\u0026gt;, optional, default=existing realm roles clientRoles: Map\u0026lt; String,List\u0026lt; String\u0026raquo;, optional, default=existing client roles, Key of the map is the clientId and the value is a List of roleNames to attach  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- updateGroup:\rrealm: master\rname: child1\rattributes:\rlkz:\r- \u0026quot;1234\u0026quot;\r assignRoleToGroup\r#\r\rAssigns a role to a group in keycloak. Fails if the group or the role does not exist.\nParameters\r#\r\r realm: String, optional role: String, not optional group: String, not optional clientId: String, optional, default=realmRole  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- assignRoleToGroup:\rrealm: integ-test\rrole: parent\rgroup: test3\r revokeRoleFromGroup\r#\r\rRevokes a role from a group in keycloak. Fails if the group or the role does not exist or the role is not assigned to the group.\nParameters\r#\r\r realm: String, optional role: String, not optional group: String, not optional clientId: String, optional, default=realmRole  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- revokeRoleFromGroup:\rrealm: integ-test\rgroup: parent\rrole: test3\r "});index.add({'id':6,'href':'/keycloakmigration/migrations/realm/','title':"Realm Migrations",'content':"Realm Migrations\r#\r\rAll migrations referring to the realm resource.\naddRealm\r#\r\radds a Realm, throws error if realm with that id already exists\nParameters\r#\r\r name: String, not optional enabled: Boolean, optional, default=true id: String, optional, default=name  Example\r#\r\rid: add-realm\rauthor: klg71\rchanges:\r- addRealm:\rname: integ-test\r deleteRealm\r#\r\rdeletes a Realm, throws error if realm with that id does not exists\nParameters\r#\r\r id: String, not optional  Example\r#\r\rid: add-realm\rauthor: klg71\rchanges:\r- deleteRealm:\rid: integ-test\r updateRealm\r#\r\rupdates a Realm, throws error if realm with that id does not exists\nParameters\r#\r\r id: String, not optional realmName: String, optional displayName:String, optional displayNameHtml:String, optional revokeRefreshToken:Boolean, optional refreshTokenMaxReuse:Int, optional accessTokenLifespan:Int, optional accessTokenLifespanForImplicitFlow:Int, optional ssoSessionIdleTimeout:Int, optional ssoSessionMaxLifespan:Int, optional ssoSessionIdleTimeoutRememberMe:Int, optional ssoSessionMaxLifespanRememberMe:Int, optional offlineSessionIdleTimeout:Int, optional offlineSessionMaxLifespanEnabled:Boolean, optional offlineSessionMaxLifespan:Int, optional accessCodeLifespan:Int, optional accessCodeLifespanUserAction:Int, optional accessCodeLifespanLogin:Int, optional actionTokenGeneratedByAdminLifespan:Int, optional actionTokenGeneratedByUserLifespan:Int, optional enabled:Boolean, optional sslRequired:String, optional registrationAllowed:Boolean, optional registrationEmailAsUsername:Boolean, optional rememberMe:Boolean, optional verifyEmail:Boolean, optional loginWithEmailAllowed:Boolean, optional duplicateEmailsAllowed:Boolean, optional resetPasswordAllowed:Boolean, optional editUsernameAllowed:Boolean, optional bruteForceProtected:Boolean, optional permanentLockout:Boolean, optional maxFailureWaitSeconds:Int, optional minimumQuickLoginWaitSeconds:Int, optional waitIncrementSeconds:Int, optional quickLoginCheckMilliSeconds:Int, optional maxDeltaTimeSeconds:Int, optional failureFactor:Int, optional requiredCredentials:List\u0026lt; String\u0026gt;, optional otpPolicyType:String, optional otpPolicyAlgorithm:String, optional otpPolicyInitialCounter:Int, optional otpPolicyDigits:Int, optional otpPolicyLookAheadWindow:Int, optional otpPolicyPeriod:Int, optional otpSupportedApplications:List\u0026lt; String\u0026gt;, optional webAuthnPolicyRpEntityName:String, optional webAuthnPolicySignatureAlgorithms:List\u0026lt; String\u0026gt;, optional webAuthnPolicyRpId:String, optional webAuthnPolicyAttestationConveyancePreference:String, optional webAuthnPolicyAuthenticatorAttachment:String, optional webAuthnPolicyRequireResidentKey:String, optional webAuthnPolicyUserVerificationRequirement:String, optional webAuthnPolicyCreateTimeout:Int, optional webAuthnPolicyAvoidSameAuthenticatorRegister:Boolean, optional webAuthnPolicyAcceptableAaguids:List\u0026lt; String\u0026gt;, browserSecurityHeaders:Map\u0026lt;String,String\u0026gt;, optional smtpServer:Map\u0026lt;String,String\u0026gt;, optional eventsEnabled:Boolean, optional eventsListeners:List\u0026lt; String\u0026gt;, optional enabledEventTypes:List\u0026lt; String\u0026gt;, optional adminEventsEnabled:Boolean, optional adminEventsDetailsEnabled:Boolean, optional internationalizationEnabled:Boolean, optional supportedLocales:List\u0026lt; String\u0026gt;, optional browserFlow:String, optional registrationFlow:String, optional directGrantFlow:String, optional resetCredentialsFlow:String, optional clientAuthenticationFlow:String, optional dockerAuthenticationFlow:String, optional attributes:Map\u0026lt;String,String\u0026gt;, optional (Map gets merged if attributes are not present in yaml). Following keys are supported in keycloak 8.0.1:  webAuthnPolicyAuthenticatorAttachment _browser_header.xRobotsTag webAuthnPolicyRpEntityName failureFactor actionTokenGeneratedByUserLifespan maxDeltaTimeSeconds webAuthnPolicySignatureAlgorithms frontendUrl offlineSessionMaxLifespan _browser_header.contentSecurityPolicyReportOnly bruteForceProtected _browser_header.contentSecurityPolicy _browser_header.xXSSProtection _browser_header.xFrameOptions _browser_header.strictTransportSecurity webAuthnPolicyUserVerificationRequirement permanentLockout quickLoginCheckMilliSeconds webAuthnPolicyCreateTimeout webAuthnPolicyRequireResidentKey webAuthnPolicyRpId webAuthnPolicyAttestationConveyancePreference maxFailureWaitSeconds minimumQuickLoginWaitSeconds webAuthnPolicyAvoidSameAuthenticatorRegister _browser_header.xContentTypeOptions actionTokenGeneratedByAdminLifespan waitIncrementSeconds offlineSessionMaxLifespanEnabled   userManagedAccessAllowed:Boolean, optional accountTheme:String, optional adminTheme:String, optional emailTheme:String, optional loginTheme:String, optional  Example\r#\r\rid: update-realm\rauthor: klg71\rchanges:\r- updateRealm:\rid: integ-test\rdisplayName: UpdatedRealm\r "});index.add({'id':7,'href':'/keycloakmigration/migrations/role/','title':"Role Migrations",'content':"Role Migrations\r#\r\rAll migrations referring to the role resource.\naddRole\r#\r\rAdd a role to keycloak, fails if the role already exists\nParameter\r#\r\r realm: String, optional name: String, not optional, clientId: String, optional, default=realmRole, description: String, optional, default=\u0026rdquo;\u0026rdquo; attributes: Map\u0026lt; String,List\u0026lt; String\u0026raquo;, optional, default=empty composite: Boolean, optional, default=false, must be true if compositeChildRoles is specified clientRole: Boolean, optional, default=false, containerId: String, optional, default=not set compositeChildRoles: List, optional, default=not set  subclass RoleSelector\r#\r\r name: String, mandatory clientId: String, optional  Example\r#\r\rid: add-role\rauthor: klg71\rchanges:\r- addRole:\rrealm: master\rname: test3\rattributes:\rrole:\r- value1\r- value2\r deleteRole\r#\r\rDelete a role from keycloak, fails if the role does not exist\nParameter\r#\r\r realm: String, optional name: String, not optional, clientId: String, optional, default=realmRole  Example\r#\r\rid: delete-role\rauthor: klg71\rchanges:\r- deleteRole:\rrealm: master\rname: test4\rclientId: test\r "});index.add({'id':8,'href':'/keycloakmigration/migrations/identityprovider/','title':"User Federation Migrations",'content':"IdentityProvider Migrations\r#\r\rAll migrations referring to the identityprovider resource.\nAddKeycloakIdentityProvider\r#\r\rAdds a keycloak identity provider.\nParameters\r#\r\r realm: String, optional alias: String, not optional authorizationUrl: String, not optional tokenUrl: String, not optional clientId: String, not optional clientSecret: String, not optional clientAuthMethod: String = \u0026ldquo;client_secret_post\u0026rdquo;, logoutUrl: String, optional default = \u0026ldquo;\u0026rdquo;, userInfoUrl: String, optional default = \u0026ldquo;\u0026rdquo;, issuer: String, optional default = \u0026ldquo;\u0026rdquo;, displayName: String, optional default = \u0026ldquo;\u0026rdquo;, defaultScopes: List\u0026lt; String\u0026gt;, optional default = emptyList(), validateSignature: String, optional default = \u0026ldquo;\u0026rdquo;, forwardParameters: List, optional default = emptyList(), loginHint: Boolean, optional default = false, disableUserInfo: Boolean, optional default = false, hideOnLoginPage: Boolean, optional default = false, backchannelSupported: Boolean, optional default = false, syncMode: String, optional default = \u0026ldquo;IMPORT\u0026rdquo;, acceptsPromptsNoneForwardFromClient: String, optional default = \u0026ldquo;\u0026rdquo;, uiLocales: Boolean, optional default = true, guiOrder: String, optional default = \u0026ldquo;\u0026rdquo;, useJwksUrl: Boolean, optional default = false, enabled: Boolean, optional default = true, trustEmail: Boolean, optional default = false, storeToken: Boolean, optional default = false, linkOnly: Boolean, optional default = false, firstBrokerLoginFlowAlias: String, optional default = \u0026ldquo;first broker login\u0026rdquo;, postBrokerLoginFlowAlias: String, optional default = \u0026ldquo;\u0026rdquo;, updateProfileFirstLoginMode: String, optional default = \u0026ldquo;on\u0026rdquo;,  Example\r#\r\rid:add-keycloak-identity-providerauthor:klg71realm:integ-testchanges:- addKeycloakIdentityProvider:alias:testAliasauthorizationUrl:https://authUrltokenUrl:https://tokenUrlclientId:clientIdclientSecret:clientSecrethideOnLoginPage:truebackchannelSupported:truetrustEmail:truestoreToken:trueDeleteIdentityProvider\r#\r\rDeletes an identity provider, if one with this alias exists\nParameters\r#\r\r realm: String, optional alias: String, not optional  Example\r#\r\rid:delete-identity-providerauthor:klg71realm:integ-testchanges:- addIdentityProvider:alias:testAlias1providerId:keycloak-oidctrustEmail:truestoreToken:trueconfig:hideOnLoginPage:truebackchannelSupported:trueauthorizationUrl:https://authUrltokenUrl:https://tokenUrlclientId:clientIdclientSecret:clientSecret- deleteIdentityProvider:alias:testAlias1AddIdentityProvider\r#\r\rAdds a generic identity provider, exact configuration has to be reverse engineered through the keycloak web frontent. If you need an identity provider please open an issue or file a pull request.\nSpecific IdentityProvider actions (e.g. for Keycloak) are listed below\nParameters\r#\r\r  realm: String, optional\n  alias: String, not optional\n  providerId: String,\n  config: Map\u0026lt;String, String\u0026gt; not optional,\nconfiguration properties include for example:\n acceptsPromptNoneForwardFromClient authorizationUrl backchannelSupported clientAuthMethod clientId clientSecret defaultScope disableUserInfo forwardParameters guiOrder hideOnLoginPage issuer loginHint logoutUrl syncMode tokenUrl uiLocales useJwksUrl userInfoUrl validateSignature    displayName: String optional, default=\u0026rdquo;,\n  enabled: Boolean, optional, default = true,\n  trustEmail: Boolean, optional, default = false,\n  storeToken: Boolean, optional, default = false,\n  linkOnly: Boolean, optional, default = false,\n  firstBrokerLoginFlowAlias: String, optional, default = \u0026ldquo;first broker login\u0026rdquo;,\n  postBrokerLoginFlowAlias: String, optional, default = \u0026ldquo;\u0026rdquo;,\n  Example\r#\r\rid:add-identity-providerauthor:klg71realm:integ-testchanges:- addIdentityProvider:alias:testAlias1providerId:keycloak-oidctrustEmail:truestoreToken:trueconfig:hideOnLoginPage:truebackchannelSupported:trueauthorizationUrl:https://authUrltokenUrl:https://tokenUrlclientId:clientIdclientSecret:clientSecret"});index.add({'id':9,'href':'/keycloakmigration/migrations/userfederation/','title':"User Federation Migrations",'content':"UserFederation Migrations\r#\r\rAll migrations referring to the userfederation resource.\nAddAdLdap\r#\r\rAdds an active directory to the realm\nParameters\r#\r\r realm: String, optional name: String, not optional config: Map \u0026lt;String, String\u0026gt; values:  connectionUrl, not optional usersDn, not optional bindCredential, not optional bindDn, not optional changedSyncPeriod, optional, default:\u0026ldquo;86400\u0026rdquo; fullSyncPeriod, optional, default:\u0026ldquo;604800\u0026rdquo; useKerberosAuthentication, optional, default: \u0026ldquo;false\u0026rdquo; allowKerberosAuthentication, optional, default: \u0026ldquo;false\u0026rdquo; pagination, optional, default: \u0026ldquo;true\u0026rdquo; readTimeout, optional, default: \u0026quot;\u0026rdquo; connectionTimeout, optional, default: \u0026quot;\u0026rdquo; connectionPooling, optional, default: \u0026ldquo;true\u0026rdquo; useTruststoreSPI, optional, default: \u0026ldquo;ldapsOnly\u0026rdquo; validatePasswordPolicy, optional, default: \u0026ldquo;false\u0026rdquo; searchScope, optional, default: \u0026ldquo;1\u0026rdquo; ldapFilter, optional, default: \u0026quot;\u0026rdquo; authenticationType, optional, default: \u0026ldquo;simple\u0026rdquo; userObjectClasses, optional, default: \u0026ldquo;person, organizationalPerson, user\u0026rdquo; uuidLdapAttribute, optional, default: \u0026ldquo;cn\u0026rdquo; rdnLdapAttribute, optional, default: \u0026ldquo;cn\u0026rdquo; usernameLdapAttribute, optional, default: \u0026ldquo;cn\u0026rdquo; importUsers, optional, default: \u0026ldquo;true\u0026rdquo; editMode, optional, default: \u0026ldquo;READ_ONLY\u0026rdquo; batchSize, optional, default: \u0026ldquo;1000\u0026rdquo; cachePolicy, optional, default: \u0026ldquo;DEFAULT\u0026rdquo; periodicChangedUsersSync, optional, default: \u0026ldquo;false\u0026rdquo; priority, optional, default: \u0026ldquo;0\u0026rdquo;    Example\r#\r\rid:add-ad-ldapauthor:klg71changes:- addAdLdap:realm:mastername:testLdapconfig:connectionUrl:https://testldapusersDN:usersTestDnbindCredential:testPasswordbindDN:testBindDnAddAdLdapFullNameMapper\r#\r\rAdds a full name mapper to an active directory ldap, throws an error if the ad doesn\u0026rsquo;t exists or if a mapper with this name already exists in this ad\nParameters\r#\r\r realm: String, optional name: String, not optional adName: String, not optional ldapFullNameAttribute: String, not optional readOnly: Boolean, optional, default = true writeOnly: Boolean, optional, default = false  Example\r#\r\rid: add-ad-ldap-full-name-mapper\rauthor: klg71\rrealm: integ-test\rchanges:\r- addAdLdapFullNameMapper:\rname: testFullNamemapper\radName: testLdap\rldapFullNameAttribute: fullName\r AddAdLdapGroupMapper\r#\r\rAdds a group mapper to an active directory ldap, throws an error if the ad doesn\u0026rsquo;t exists or if a mapper with this name already exists in this ad\nParameters\r#\r\r realm: String, optional name: String, not optional adName: String, not optional groupsDn: String, not optional groupObjectClasses: List\u0026lt; String \u0026gt;, optional, default = emptyList() groupNameLdapAttribute: String, optional, default = \u0026ldquo;cn\u0026rdquo; preserveGroupInheritance: Boolean, optional, default = true, membershipLdapAttribute: String, optional, default = \u0026ldquo;member\u0026rdquo;, membershipAttributeType: String, optional, default = \u0026ldquo;DN\u0026rdquo;, membershipUserLdapAttribute: String, optional, default = \u0026ldquo;cn\u0026rdquo;, filter: String, optional, default = \u0026ldquo;\u0026rdquo;, mode: String, optional, default = \u0026ldquo;READ_ONLY\u0026rdquo;, ignoreMissingGroups: Boolean, optional, default = false, userRolesRetrieveStrategy: String, optional, default = \u0026ldquo;LOAD_GROUPS_BY_MEMBER_ATTRIBUTE\u0026rdquo;, mappedGroupAttributes: List\u0026lt; String \u0026gt;, optional, default = emptyList(), memberofLdapAttribute: String, optional, default = \u0026ldquo;memberOf\u0026rdquo;, dropNonExistingGroupsDuringSync: Boolean, optional, default = false  Example\r#\r\rid: add-ad-ldap-group-mapper\rauthor: klg71\rrealm: integ-test\rchanges:\r- addAdLdapGroupMapper:\rname: testGroupMapper\radName: testLdap\rgroupsDn: groupsDn\r AddAdLdapHardcodedRoleMapper\r#\r\rAdds a hardcoded role mapper to an active directory ldap, throws an error if the ad doesn\u0026rsquo;t exists or if a mapper with this name already exists in this ad. If the given role doesn\u0026rsquo;t exists this command throws an exception.\nParameters\r#\r\r realm: String, optional name: String, not optional adName: String, not optional role: String, not optional  Example\r#\r\rid: add-ad-ldap-hardcoded-role-mapper\rauthor: klg71\rrealm: integ-test\rchanges:\r- addRole:\rname: testMapperRole\r- addAdLdapHardcodedRoleMapper:\rname: testHardcodedRoleMapper\radName: testLdap\rrole: testMapperRole\r AddAdLdapUserControlMapperMapper\r#\r\rAdds a user account control mapper to an active directory ldap, throws an error if the ad doesn\u0026rsquo;t exists or if a mapper with this name already exists in this ad.\nParameters\r#\r\r realm: String, optional name: String, not optional adName: String, not optional  Example\r#\r\rid: add-ad-ldap-user-account-control-mapper\rauthor: klg71\rrealm: integ-test\rchanges:\r- addAdLdapUserAccountControlMapper:\rname: testUserAccountControl\radName: testLdap\r AddAdLdapUserAttributeMapperMapper\r#\r\rAdds a user account attribute mapper to an active directory ldap, throws an error if the ad doesn\u0026rsquo;t exists or if a mapper with this name already exists in this ad.\nParameters\r#\r\r realm: String, optional name: String, not optional adName: String, not optional userModelAttribute: String, not optional ldapAttribute: String, not optional readOnly: Boolean, optional, default = false, alwaysReadFromLdap: Boolean, optional, default = false, isMandatoryInLdap: Boolean, optional, default = false  Example\r#\r\rid: add-ad-ldap-user-attribute-mapper\rauthor: klg71\rrealm: integ-test\rchanges:\r- addAdLdapUserAttributeMapper:\rname: testUserAttributeMapper\radName: testLdap\ruserModelAttribute: userModelAttribute\rldapAttribute: ldapAttribute\r AddAdLdapMapperMapper\r#\r\rAdds a custom mapper to an active directory ldap, throws an error if the ad doesn\u0026rsquo;t exists or if a mapper with this name already exists in this ad.\n Only use this action if you can\u0026rsquo;t find a convenient method to add the mapper above. You can find the correct parameters by using the network debugging tool in chrome/firefox to inspect the requests in the keycloak gui.\n Parameters\r#\r\r realm: String, optional name: String, not optional adName: String, not optional providerId: String, not optional config: Map\u0026lt;String,String\u0026gt;, not optional  Example\r#\r\rid: add-ad-ldap-user-attribute-mapper\rauthor: klg71\rrealm: integ-test\rchanges:\r- addAdLdapMapper:\rname: testRoleMapper\radName: testLdap\rproviderId: role-ldap-mapper\rconfig:\rmemberof.ldap.attribute: \u0026quot;memberOf\u0026quot;\rmembership.attribute.type: \u0026quot;DN\u0026quot;\rmembership.ldap.attribute: \u0026quot;member\u0026quot;\rmembership.user.ldap.attribute: \u0026quot;cn\u0026quot;\rmode: \u0026quot;READ_ONLY\u0026quot;\rrole.name.ldap.attribute: \u0026quot;cn\u0026quot;\rrole.object.classes: \u0026quot;group\u0026quot;\rroles.dn: \u0026quot;rolesDn\u0026quot;\ruse.realm.roles.mapping: \u0026quot;true\u0026quot;\ruser.roles.retrieve.strategy: \u0026quot;LOAD_ROLES_BY_MEMBERSHIP_ATTRIBUTE\u0026quot;\r AddUserFederation\r#\r\rAdds a user federation to the realm\nParameters\r#\r\r realm: String, optional name: String, mandatory providerId: String, mandatory providerType: String, optional, default = \u0026ldquo;org.keycloak.storage.UserStorageProvider\u0026rdquo; config: Map \u0026lt;String, String\u0026gt;, optional  Example\r#\r\rid:add-user-federationauthor:klg71changes:- addUserFederation:realm:mastername:testUserFederationproviderId:my-user-storage-providerDeleteUserFederation\r#\r\rDeletes an userFederation from the realm, throws an exception if it doesn\u0026rsquo;t exist.\nParameters\r#\r\r realm: String, optional name: String, not optional  Example\r#\r\rid: delete-ad-ldap\rauthor: klg71\rchanges:\r- deleteUserFederation:\rrealm: integ-test\rname: testLdap\r "});index.add({'id':10,'href':'/keycloakmigration/migrations/user/','title':"User Migrations",'content':"User Migrations\r#\r\rAll migrations referring to the user resource.\naddUser\r#\r\rAdds a user to keycloak. Fails if a user with that name already exists.\nParameters\r#\r\r realm: String, optional name: String, not optional enabled: Boolean, default=true emailVerified: Boolean, default=true attributes: Map with Layout Map\u0026lt;String, List\u0026lt; String \u0026raquo;, default=empty groups: List of groupnames to attach, List\u0026lt; String \u0026gt;, optional, default=empty realmRoles: List of realmroles to attach, List\u0026lt; String \u0026gt;, optional, default=empty clientRoles: List of ClientRoles to attach, List\u0026lt; ClientRole \u0026gt;, optional, default=empty email: String, optional, default=\u0026rdquo;\u0026rdquo; firstName: String, optional, default=\u0026rdquo;\u0026rdquo; lastName: String, optional, default=\u0026rdquo;\u0026rdquo;  ClientRole Parameters:\n client: ClientId, String, not optional role: Rolename, String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- addUser:\rrealm: master\rname: test\renabled: true\remail: test@example.de\remailVerified: true\rattributes:\rtest:\r- test\r- test2\rgroups:\r- testGroup\rrealmRoles:\r- testRealmRole\rclientRoles:\r- client: testClient\rrole: testClientRole\r deleteUser\r#\r\rRemoves a user from keycloak. Fails if a user with that name does not exists.\nParameters\r#\r\r realm: String, optional name: String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- deleteUser:\rrealm: master\rname: test\r updateUser\r#\r\rUpdates an exiting user in keycloak. Fails if no user with given name exists.\nParameters\r#\r\r realm: String, optional name: String, not optional enabled: Boolean, default=no change emailVerified: Boolean, default=no change access: String, default=no change notBefore: Long, default=no change totp: Boolean, default=no change disableableCredentialTypes: List\u0026lt; String \u0026gt;, default=no change requiredActions: List\u0026lt; String \u0026gt;, default=no change email: String, default=no change firstName: String, default=no change lastName: String, default=no change credentials: Map\u0026lt;String,String\u0026gt; (see example below)  hashedSaltedValue: String, not optional salt: String, not optional algorithm: String, optional, default = \u0026ldquo;pbkdf2-sha256\u0026rdquo; counter: Int, optional, default = 0, createdDate: Long, optional, default = Date().time, digits: Int, optional, default = 0, hashIterations: Int, optional, default = 27500, period: Int, optional, default = 0, type: String, optional, default = \u0026ldquo;password\u0026rdquo;, config1: Map\u0026lt;String, String\u0026gt;, optional, default = emptyMap() (See keycloak documentation)    Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- updateUser:\rrealm: master\rname: test\renabled: false\rlastName: Lukas\r Example to update Password\r#\r\r If you don\u0026rsquo;t want to hash and generate the salt by youself you can use the updateUserPassword method listed below.\nThis method gives more control over the credential entry in keycloak including hashIterations, algorithms used, digits and additional configs.\nUpdating the credential can not be rolled back!\n id: update-password\rauthor: klg71\rchanges:\r- updateUser:\rrealm: integ-test\rname: test\rcredentials:\r- hashedSaltedValue: 1tWf95Drz6t8/9kKE3tiJXPywCzG/C0KDnmCIFXEDdFQMPB6iVWWxjLO9HJI3YwTfWZa78N+hcmYHcT1tkavcA==\rsalt: dGVzdB==\r Script to generate salt and hash:\r#\r\rimport org.apache.commons.codec.Charsets.UTF_8 import java.util.* import javax.crypto.SecretKeyFactory import javax.crypto.spec.PBEKeySpec fun generatePassword(){ println(\u0026#34;Keycloak password hash helper\u0026#34;) val scanner = Scanner(System.`in`, UTF_8) println(\u0026#34;Enter password:\u0026#34;) val password = scanner.nextLine() println(\u0026#34;Enter salt:\u0026#34;) val salt = scanner.nextLine() val hashIterations = 27500 val keyByteLength = 64 val pass = getEncryptedPassword(password, salt.toByteArray(UTF_8), hashIterations, keyByteLength) println(\u0026#34;Password: $pass\u0026#34;) println(\u0026#34;Salt: \u0026#34; + Base64.getEncoder().encodeToString(salt.toByteArray(UTF_8))) } fun getEncryptedPassword(password: String, salt: ByteArray, iterations: Int, derivedKeyLength: Int): String { return SecretKeyFactory.getInstance(\u0026#34;PBKDF2WithHmacSHA256\u0026#34;).run { generateSecret(PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength * 8) ) }.run { @Suppress(\u0026#34;UsePropertyAccessSyntax\u0026#34;) getEncoded() }.let { Base64.getEncoder().encodeToString(it) } } updateUserPassword\r#\r\rUpdates the passwords of a user\n WARNING: This action can not be rolled back!\n The password is hashed with 27500 hash_iterations and a key_byte_length of 64 bytes.\nParameters\r#\r\r realm: String, optional name: String, not optional password: String, not optional salt: String, optional, default = Random 15 letter alphanumeric String  Example\r#\r\rid: test\rauthor: klg71\rrealm: integ-test\rchanges:\r- addUser:\rname: testPasswordUser\r- updateUserPassword:\rname: testPasswordUser\rpassword: \u0026quot;testPassword\u0026quot;\r addUserAttribute\r#\r\rAdds an attribute to an existing user. Throws an error if the user does not exist.\nUser attributes can\u0026rsquo;t be set deterministic with the updateUser action.\nParameters\r#\r\r realm: String, optional name: String, not optional attributeName: String, not optional attributeValues: List\u0026lt; String\u0026gt;, not optional override: Boolean, default=false  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- addUserAttribute:\rrealm: master\rname: test\rattributeName: test1\rattributeValues:\r- value1\r- value2\r deleteUserAttribute\r#\r\rDeletes an attribute to an existing user. Throws an error if the user does not exist.\nParameters\r#\r\r realm: String, optional name: String, not optional attributeName: String, not optional failOnMissing: Boolean, default=true  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- deleteUserAttribute:\rrealm: master\rname: test\rattributeName: test1\r assignRole\r#\r\rAssigns a role to the given user. Fails if the user or the role doesn\u0026rsquo;t exist.\nParameters\r#\r\r realm: String, optional user: String, not optional role: String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- assignRole:\rrealm: master\ruser: testUser\rrole: testRole\r revokeRole\r#\r\rRevokes a role from the given user. Fails if the user or the role doesn\u0026rsquo;t exist or the user does not have the role assigned.\nParameters\r#\r\r realm: String, optional user: String, not optional role: String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- revokeRole:\rrealm: master\ruser: testUser\rrole: testRole\r assignGroup\r#\r\rAssigns a group to the given user. Fails if the user or the group doesn\u0026rsquo;t exist.\nParameters\r#\r\r realm: String, optional user: String, not optional group: String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- assignGroup:\rrealm: master\ruser: testUser\rgroup: testGroup\r revokeGroup\r#\r\rRevokes a group from the given user. Fails if the user or the group doesn\u0026rsquo;t exist or the user doesnt have the group assigned .\nParameters\r#\r\r realm: String, optional user: String, not optional group: String, not optional  Example\r#\r\rid: test\rauthor: klg71\rchanges:\r- revokeGroup:\rrealm: master\ruser: testUser\rgroup: testGroup\r "});index.add({'id':11,'href':'/keycloakmigration/about/','title':"About Me",'content':"Software Engineer located in Dresden Germany.\nCurrently working at OSP.\nSome of my other Projects:\n Android App for tree management baum.watch Migrations in Keycloak like liquibase: keycloakmigration  Contact me for talks or courses about Java and Kotlin.\n"});index.add({'id':12,'href':'/keycloakmigration/contributing/','title':"Contributing",'content':"Contributing\r#\r\rTo start developing on this project you can use the gradle tasks.\nTo start the local development keycloak you can just use the task startLocalKeycloak\nTested with OpenJdk 12 and Keycloak 10.0.2\nIf you want to contribute to this project please visit the issues page and maybe you can find something interesting :)\nUse keycloakmigration through maven dependency\r#\r\rGradle dependency\r#\r\r // https://mvnrepository.com/artifact/de.klg71.keycloakmigration/keycloakmigration\rcompile group: 'de.klg71.keycloakmigration', name: 'keycloakmigration', version: 'x.x.x'\r Usage\r#\r\rKotlin\nclass MyMigrationArgs(private val adminUser: String,\rprivate val adminPassword: String,\rprivate val migrationFile: String,\rprivate val baseUrl: String,\rprivate val realm: String,\rprivate val clientId: String,\rprivate val correctHashes: Boolean,\rprivate val parameters: Map\u0026lt;String, String\u0026gt;) : MigrationArgs {\roverride fun adminUser() = adminUser\roverride fun adminPassword() = adminPassword\roverride fun baseUrl() = baseUrl\roverride fun migrationFile() = migrationFile\roverride fun realm() = realm\roverride fun clientId() = clientId\roverride fun correctHashes() = correctHashes\roverride fun parameters() = parameters\r}\rclass KeycloakMigrationExecution {\rfun migrate() {\rMyMigrationArgs(\u0026quot;admin\u0026quot;, \u0026quot;adminPass\u0026quot;, \u0026quot;keycloak-changelog.yml\u0026quot;,\r\u0026quot;https://myauthserver\u0026quot;, \u0026quot;master\u0026quot;,\r\u0026quot;admin-cli\u0026quot;, false, emptyMap())\r.let {\rde.klg71.keycloakmigration.migrate(it)\r}\r}\r}\r "});index.add({'id':13,'href':'/keycloakmigration/quickstart/groovy/','title':"Gradle Groovy DSL",'content':"Gradle Groovy DSL\r#\r\rFiletree:\r#\r\r build.gradle settings.gradle keycloak-changelog.yml 01_create_realm.yml  build.gradle\nplugins { id \u0026#34;de.klg71.keycloakmigrationplugin\u0026#34; version \u0026#34;x.x.x\u0026#34; } repositories { jcenter() } task keycloakMigrateLocal(type: KeycloakMigrationTask) { group = \u0026#34;keycloak\u0026#34; description = \u0026#34;Migrate the keycloak instance\u0026#34; migrationFile = \u0026#34;migration/keycloak-changelog.yml\u0026#34; adminUser = \u0026#34;admin\u0026#34; adminPassword = \u0026#34;admin\u0026#34; baseUrl = \u0026#34;http://localhost:8080\u0026#34; realm = \u0026#34;master\u0026#34; waitForKeycloak = false waitForKeycloakTimeout = 0L // infinit wait time  parameters = [USERNAME: \u0026#34;testUser\u0026#34;, PASSWORD: \u0026#34;testPassword\u0026#34;] } settings.gradle\nrootProject.name = \u0026#34;keycloak-migration\u0026#34; keycloak-changelog.yml\nincludes:- path:01_create_realm.yml01_create_realm.yml\nid:create-realmauthor:lmeisegechanges:- addRealm:name:kubernetes- updateRealm:id:kubernetesrememberMe:truessoSessionIdleTimeout:36000Execute\r#\r\rgradle keycloakMigrateLocal Available migrations are listed here: Migrations\n"});index.add({'id':14,'href':'/keycloakmigration/quickstart/kotlin/','title':"Gradle Kotlin DSL",'content':"Gradle Kotlin DSL\r#\r\rFiletree:\r#\r\r build.gradle.kts settings.gradle.kts keycloak-changelog.yml 01_create_realm.yml  build.gradle.kts\nplugins { id(\u0026#34;de.klg71.keycloakmigrationplugin\u0026#34;) version \u0026#34;x.x.x\u0026#34; } repositories { jcenter() } tasks { register\u0026lt;KeycloakMigrationTask\u0026gt;(\u0026#34;keycloakMigrateLocal\u0026#34;) { migrationFile = \u0026#34;keycloak-changelog.yml\u0026#34; adminUser = \u0026#34;admin\u0026#34; adminPassword = \u0026#34;adminPassword\u0026#34; baseUrl = \u0026#34;http://localhost:8080\u0026#34; realm = \u0026#34;master\u0026#34; waitForKeycloak(keycloakBaseUrl) parameters = mapOf( \u0026#34;USER_NAME\u0026#34; to \u0026#34;testUser\u0026#34;, \u0026#34;PASSWORD\u0026#34; to \u0026#34;password\u0026#34; ) waitForKeycloak = false waitForKeycloakTimeout = 0L // infinit wait time  } } settings.gradle.kts\nrootProject.name = \u0026#34;keycloak-migration\u0026#34; keycloak-changelog.yml\nincludes:- path:01_create_realm.yml01_create_realm.yml\nid:create-realmauthor:lmeisegechanges:- addRealm:name:kubernetes- updateRealm:id:kubernetesrememberMe:truessoSessionIdleTimeout:36000Execute\r#\r\rgradle keycloakMigrateLocal Available migrations are listed here: Migrations\n"});index.add({'id':15,'href':'/keycloakmigration/implementation_details/','title':"Implementation Substitution",'content':"Implementation Details\r#\r\rThe migration hashes are stored in the attribute named \u0026lsquo;migration\u0026rsquo; in the migration user.\nThere are no transactions in keycloak though if the rollback fails there might be a non deterministic state! If it fails I would like to receive a bug report for this.\nIf you struggle with invalid hashes on a linux-windows setup check the line endings of the json-import files as git might check them out as LF where on windows its CRLF and thus producing the error in hashing.\nIf you are using git you can place the following file into the dir with the json-import-files to reassure that the line ending is always LF.\n.gitattributes:\n** text eol=lf\r "});index.add({'id':16,'href':'/keycloakmigration/migration_files/','title':"Parameter Substitution",'content':"Migration Files\r#\r\rThere are two types of files to control migrations in keycloak. ChangeLog and ChangeSet (may sound similar in liquibase). The Changelog references all changeSets to apply and the ChangeSets contain the actual changes.\nChangelog\r#\r\rMigrations are controlled through the changelog. It contains the changeSets used to execute the migration.\nParameters\r#\r\r includes: List of changesets to apply consisting of:  path: String, not optional, path to changeset relativeToFile: Boolean, optional, default=true, whether the file should be searched from the working dir or relative to the keycloak changelog file.    Example\r#\r\rincludes:\r- path: 01_initial.yml\r- path: 02_second.yml\r- path: changes/03_third.yml\rrelativeToFile: true\r ChangeSet\r#\r\rThe changeSet contains the actual changes as a list of migrations (see Supported Migrations)\nParameters\r#\r\r id: String, not optional, describe the change author: String, not optional, author of the changeset realm: String, optional, preset realm for actions   Please note that you must either provide a realm in the ChangeSet or in each action! Even though both parameters are optional one must be set!\n   enabled: Boolean, optional, default=true, can be set through environment variable substitution to enable dynamic changesets see: https://github.com/klg71/keycloakmigration/issues/9\n  changes: List of Migrations\n  Example\r#\r\rid:initial-keycloakauthor:klg71realm:masterchanges:- addUser:name:testenabled:trueemailVerified:trueattributes:test:- test- test2- updateUser:realm:otherRealmname:testenabled:falselastName:LukasParameter substitution\r#\r\rThis format supports substitution of environment variables for dynamic content. The hash however will not include the resolved variable and just encode the file as a hash.\nExample\r#\r\rid:initial-keycloakauthor:klg71realm:masterchanges:- addUser:name:testenabled:trueemailVerified:trueattributes:test:- ${JAVA_HOME}- test2This will replace ${JAVA_HOME} with the system variable JAVA_HOME present at runtime\nParameter substitution is implemented through apache-common-text StringSubstitutor.\nYou can also provide default values through the ${UNDEFINED_NUMBER:-1234} (default value is after the :- separator).\nYou may also use the string interpolation features provided by StringSubstitutor but be careful to don\u0026rsquo;t hurt the readability by doing so.\nMissing parameters\r#\r\rMissing parameter can lead to unexpected behaviour of the changelog parser and you may want to report them.\nTo fail on missing parameters you can use the option failOnUndefinedVariables(default = false) and to warn warnOnUndefinedVariable(default = true)\n"});index.add({'id':17,'href':'/keycloakmigration/quickstart/','title':"Quickstart",'content':"Quickstart\r#\r\rPlease choose a quickstart guide according to your deployment:\n Kotlin Gradle DSL Groovy Gradle DSL Jar  "});index.add({'id':18,'href':'/keycloakmigration/hashmigration/','title':"Troubleshooting migration Hashes",'content':"Troubleshooting migration hashes\r#\r\rThe hash implementation from 0.0.12 to 0.1.0 has changed so the old hashes will always throw an error.\nAn hash error may also occur if you did make a syntactic but not semantic change to the changelog.\nYou can however call the migration script with the --correct-hashes switch and it will just replace the failing hashes. Alternatively you can execute the KeycloakMigrationCorrectHashesTask in gradle.\nThis will skip any control mechanism and you must to make sure that you have the same changelog that you migrated before. It will only check for the number of hashes to skip or execute migrations!\n Dont use the --correct-hashes switch in build pipelines!\n "});index.add({'id':19,'href':'/keycloakmigration/quickstart/jar/','title':"Usage trough fatjar",'content':"Usage through fatjar\r#\r\rFiletree:\r#\r\r keycloakmigration-x.x.x-fat.jar (download on github releases) keycloak-changelog.yml 01_create_realm.yml  Execute\r#\r\rjava -jar keycloakmigration-x.x.x-fat.jar Arguments\r#\r\rjava -jar keycloakmigration.jar --help\rusage: [-h] [-u USER] [-p PASSWORD] [-b BASEURL] [MIGRATION-FILE] [-r REALM]\r[-c CLIENT] [--correct-hashes] [-k PARAMETER]... [--wait-for-keycloak]\r[--wait-for-keycloak-timeout WAIT_FOR_KEYCLOAK_TIMEOUT]\roptional arguments:\r-h, --help show this help message and exit\r-u USER, --user USER Username for the migration user, defaulting to admin.\r-p PASSWORD, --password PASSWORD Password for the migration user, defaulting to admin.\r-b BASEURL, --baseurl BASEURL Base url of keycloak server, defaulting to\rhttp://localhost:18080/auth.\r-r REALM, --realm REALM Realm to use for migration, defaulting to master\r-c CLIENT, --client CLIENT Client to use for\rmigration,\rdefaulting to master\r--correct-hashes Correct hashes to most recent version, defaulting to false\rJust choose this option if you didn't change anything in\rthe changelog since the last migration!\rThis will replace all old hashes with the new hash version\rand can be omitted next time the migration is run.\rSee README.md for further explanation!\r-k PARAMETER, --parameter PARAMETER Parameters to substitute in changelog, syntax is:\r-k param1=value1\rwill replace\r${param1} with\rvalue1 in changelog\r--wait-for-keycloak Wait for Keycloak to become ready.\r--wait-for-keycloak-timeout WAIT_FOR_KEYCLOAK_TIMEOUT Wait for Keycloak to become ready timeout in seconds (defaulting to 0=infinit).\r--fail-on-undefined-variables Fail if variables could not be replaced, defaulting to false.\r--warn-on-undefined-variables warn if variables could not bereplaced, defaulting to true. positional arguments:\rMIGRATION-FILE File to migrate, defaulting to keycloak-changelog.yml\r Available migrations are listed here: Migrations\n"});index.add({'id':20,'href':'/keycloakmigration/quickstart/docker/','title':"Usage with Docker",'content':"Usage with docker\r#\r\ryou can also use keycloakmigraiton with docker. The migrations are then controlled trough environment variables and mounted volumes.\nUsage\r#\r\rdocker run --env BASEURL=http://localhost:8080 klg71/keycloakmigration Environment variables\r#\r\r  KEYCLOAK_CHANGELOG migration changelog, should be mounted\ndefault: /migration/keycloak-changelog.yml\n  ADMIN_USER user to execute migration\ndefault: admin\n  ADMIN_PASSWORD password of user to execute migration\ndefault: admin\n  ADMIN_CLIENT client to use for admin login\ndefault: admin-cli\n  LOGIN_REALM realm to use for admin login\ndefault: master\n  BASEURL Baseurl for the keycloak instance\ndefault: http://localhost:8080/auth\n  WAIT_FOR_KEYCLOAK(flag) If keycloakmigration should wait for the keycloak instance\ndefault: unset\n  WAIT_FOR_KEYCLOAK_TIMEOUT Wait time till keycloak migration fails if keycloak is not ready (only if WAIT_FOR_KEYCLOAK is set)\ndefault: 0(infinit)\n  FAIL_ON_UNDEFINED_VARIABLES(flag) If keycloakmigration should fail if undefined template variables occur\ndefault: unset=false\n  DISABLE_WARN_ON_UNDEFINED_VARIABLES(flag) If keycloakmigration should not warn if undefined template variables occur\ndefault: unset=false\n  CORRECT_HASHES(flag) If keycloakmigration should migrate not matching hashes (see Hash Troubleshooting )\ndefault: unset=false\n  STAY_IDLE(flag) Don\u0026rsquo;t kill container when migration is finished (useful for k8s deployment)\ndefault: unset=false\n  "});index.add({'id':21,'href':'/keycloakmigration/keycloak_api/','title':"Using the Keycloak Api",'content':"Using the Keycloak Api\r#\r\rFor the migrations to work I had to implement a keycloak administration api.\nThis api provides a KeycloakClient which connects to the keycloak instance. This client has methods to manage user, group, role, client, realms and userfederation resources.\nTo use it you can simply the maven dependency or download the keycloakapi-jar from the releases page.\nGradle Groovy DSL\r#\r\r// https://mvnrepository.com/artifact/de.klg71.keycloakmigration/keycloakmigration compile group: \u0026#39;de.klg71.keycloakmigration\u0026#39;, name: \u0026#39;keycloakmapi\u0026#39;, version: \u0026#39;x.x.x\u0026#39; Gradle Kotlin DSL\r#\r\r// https://mvnrepository.com/artifact/de.klg71.keycloakmigration/keycloakmigration compile(\u0026#34;de.klg71.keycloakmigration:keycloakapi:x.x.x\u0026#34;) Maven\r#\r\r\u0026lt;!-- https://mvnrepository.com/artifact/de.klg71.keycloakmigration/keycloakmigration --\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;de.klg71.keycloakmigration\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;keycloakapi\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;x.x.x\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; The keycloakapi uses OpenFeign to connect to the keycloak instance.\nFull documentation is available here: Documentation\n"});})();