"}},"componentScriptGroups({\"componentId\":\"custom.widget.MicrosoftFooter\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageListTabs\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageListTabs-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageView/MessageViewInline\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/Pager/PagerLoadMore\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/Pager/PagerLoadMore-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/OverflowNav\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageUnreadCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageViewCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageViewCount-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/kudos/KudosCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/kudos/KudosCount-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRepliesCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1745505307000"}],"cachedText({\"lastModified\":\"1745505307000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1745505307000"}]},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Deleted","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"MMM dd yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":null,"possibleValues":["en-US","es-ES"]},"repliesSortOrder":{"__typename":"InheritableStringSettingWithPossibleValues","key":"config.user_replies_sort_order","value":"DEFAULT","localValue":"DEFAULT","possibleValues":["DEFAULT","LIKES","PUBLISH_TIME","REVERSE_PUBLISH_TIME"]}},"deleted":false},"CachedAsset:pages-1746563185879":{"__typename":"CachedAsset","id":"pages-1746563185879","value":[{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"UserBlogPermissions.Page","type":"COMMUNITY","urlPath":"/c/user-blog-permissions/page","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"AllEvents","type":"CUSTOM","urlPath":"/Events","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"CommunityHub.Page","type":"CUSTOM","urlPath":"/Directory","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"AllBlogs.Page","type":"CUSTOM","urlPath":"/blogs","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"HealthCheckPage","type":"COMMUNITY","urlPath":"/health","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1746563185879,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}","userBanned":"We're sorry, but you have been banned from using this site.","userBannedReason":"You have been banned for the following reason: {reason}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:theme:customTheme1-1746563185305":{"__typename":"CachedAsset","id":"theme:customTheme1-1746563185305","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["default"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"favicon-1730836283320.png","imageLastModified":"1730836286415","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"favicon-1730836271365.png","imageLastModified":"1730836274203","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1300px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_BROWSER","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"3px","borderRadius":"3px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"16px","paddingXHero":"60px","fontStyle":"NORMAL","fontWeight":"700","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-200)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-200)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"LIGHT","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.16)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.12)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-link-color)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","defaultMessageFontFamily":"var(--lia-bs-font-family-base)","forumColor":"#4099E2","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#148563","blogColor":"#1CBAA0","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#4C6B90","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#FF8000","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#D13A1F","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#333333","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#717171","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0069D4","secondary":"#333333","bodyText":"#1E1E1E","bodyBg":"#FFFFFF","info":"#409AE2","success":"#41C5AE","warning":"#FCC844","danger":"#BC341B","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#D3F5A4","#243A5E"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Segoe UI","fontStyle":"NORMAL","fontWeight":"400","h1FontSize":"34px","h2FontSize":"32px","h3FontSize":"28px","h4FontSize":"24px","h5FontSize":"20px","h6FontSize":"16px","lineHeight":"1.3","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":"var(--lia-bs-headings-font-weight)","h2FontWeight":"var(--lia-bs-headings-font-weight)","h3FontWeight":"var(--lia-bs-headings-font-weight)","h4FontWeight":"var(--lia-bs-headings-font-weight)","h5FontWeight":"var(--lia-bs-headings-font-weight)","h6FontWeight":"var(--lia-bs-headings-font-weight)","__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":"","imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"40px","defaultMessageHeaderMarginBottom":"20px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"40px","specialMessageHeaderMarginBottom":"20px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Segoe UI","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.5","fontSizeBase":"16px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"14px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[{"source":"SERVER","name":"Segoe UI","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"},{"style":"NORMAL","weight":"300","__typename":"FontStyleData"},{"style":"NORMAL","weight":"600","__typename":"FontStyleData"},{"style":"NORMAL","weight":"700","__typename":"FontStyleData"},{"style":"ITALIC","weight":"400","__typename":"FontStyleData"}],"assetNames":["SegoeUI-normal-400.woff2","SegoeUI-normal-300.woff2","SegoeUI-normal-600.woff2","SegoeUI-normal-700.woff2","SegoeUI-italic-400.woff2"],"__typename":"CustomFont"},{"source":"SERVER","name":"MWF Fluent Icons","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"}],"assetNames":["MWFFluentIcons-normal-400.woff2"],"__typename":"CustomFont"}],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1745505307000","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1745505307000","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-pages/tags/TagPage-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-pages/tags/TagPage-1745505307000","value":{"tagPageTitle":"Tag:\"{tagName}\" | {communityTitle}","tagPageForNodeTitle":"Tag:\"{tagName}\" in \"{title}\" | {communityTitle}","name":"Tags Page","tag":"Tag: {tagName}"},"localOverride":false},"Category:category:solutions":{"__typename":"Category","id":"category:solutions","entityType":"CATEGORY","displayId":"solutions","nodeType":"category","depth":2,"title":"Topics","shortTitle":"Topics","parent":{"__ref":"Category:category:communities"}},"Category:category:top":{"__typename":"Category","id":"category:top","displayId":"top","nodeType":"category","depth":0,"title":"Top"},"Category:category:communities":{"__typename":"Category","id":"category:communities","displayId":"communities","nodeType":"category","depth":1,"parent":{"__ref":"Category:category:top"},"title":"Communities"},"Category:category:HealthcareAndLifeSciences":{"__typename":"Category","id":"category:HealthcareAndLifeSciences","entityType":"CATEGORY","displayId":"HealthcareAndLifeSciences","nodeType":"category","depth":3,"title":"Healthcare and Life Sciences","description":"","avatar":null,"profileSettings":{"__typename":"ProfileSettings","language":null},"parent":{"__ref":"Category:category:solutions"},"ancestors":{"__typename":"CoreNodeConnection","edges":[{"__typename":"CoreNodeEdge","node":{"__ref":"Community:community:gxcuf89792"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:communities"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:solutions"}}]},"userContext":{"__typename":"NodeUserContext","canAddAttachments":false,"canUpdateNode":false,"canPostMessages":false,"isSubscribed":false},"theme":{"__ref":"Theme:customTheme1"},"categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"tagPolicies":{"__typename":"TagPolicies","canSubscribeTagOnNode":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.labels.action.corenode.subscribe_labels.allow.accessDenied","key":"error.lithium.policies.labels.action.corenode.subscribe_labels.allow.accessDenied","args":[]}},"canManageTagDashboard":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.labels.action.corenode.admin_labels.allow.accessDenied","key":"error.lithium.policies.labels.action.corenode.admin_labels.allow.accessDenied","args":[]}}}},"CachedAsset:quilt:o365.prod:pages/tags/TagPage:category:HealthcareAndLifeSciences-1746740537378":{"__typename":"CachedAsset","id":"quilt:o365.prod:pages/tags/TagPage:category:HealthcareAndLifeSciences-1746740537378","value":{"id":"TagPage","container":{"id":"Common","headerProps":{"removeComponents":["community.widget.bannerWidget"],"__typename":"QuiltContainerSectionProps"},"items":[{"id":"tag-header-widget","layout":"ONE_COLUMN","bgColor":"var(--lia-bs-white)","showBorder":"BOTTOM","sectionEditLevel":"LOCKED","columnMap":{"main":[{"id":"tags.widget.TagsHeaderWidget","__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"},{"id":"messages-list-for-tag-widget","layout":"ONE_COLUMN","columnMap":{"main":[{"id":"messages.widget.messageListForNodeByRecentActivityWidget","props":{"viewVariant":{"type":"inline","props":{"useUnreadCount":true,"useViewCount":true,"useAuthorLogin":true,"clampBodyLines":3,"useAvatar":true,"useBoardIcon":false,"useKudosCount":true,"usePreviewMedia":true,"useTags":false,"useNode":true,"useNodeLink":true,"useTextBody":true,"truncateBodyLength":-1,"useBody":true,"useRepliesCount":true,"useSolvedBadge":true,"timeStampType":"conversation.lastPostingActivityTime","useMessageTimeLink":true,"clampSubjectLines":2}},"panelType":"divider","useTitle":false,"hideIfEmpty":false,"pagerVariant":{"type":"loadMore"},"style":"list","showTabs":true,"tabItemMap":{"default":{"mostRecent":true,"mostRecentUserContent":false,"newest":false},"additional":{"mostKudoed":true,"mostViewed":true,"mostReplies":false,"noReplies":false,"noSolutions":false,"solutions":false}}},"__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"}],"__typename":"QuiltContainer"},"__typename":"Quilt"},"localOverride":false},"CachedAsset:quiltWrapper:o365.prod:Common:1746797691674":{"__typename":"CachedAsset","id":"quiltWrapper:o365.prod:Common:1746797691674","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"community.widget.navbarWidget","props":{"showUserName":true,"showRegisterLink":true,"useIconLanguagePicker":true,"useLabelLanguagePicker":true,"className":"QuiltComponent_lia-component-edit-mode__0nCcm","links":{"sideLinks":[],"mainLinks":[{"children":[],"linkType":"INTERNAL","id":"gxcuf89792","params":{},"routeName":"CommunityPage"},{"children":[],"linkType":"EXTERNAL","id":"external-link","url":"/Directory","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft365","params":{"categoryId":"microsoft365"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows","params":{"categoryId":"Windows"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"Common-microsoft365-copilot-link","params":{"categoryId":"Microsoft365Copilot"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-teams","params":{"categoryId":"MicrosoftTeams"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-securityand-compliance","params":{"categoryId":"microsoft-security"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"azure","params":{"categoryId":"Azure"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"Common-content_management-link","params":{"categoryId":"Content_Management"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"exchange","params":{"categoryId":"Exchange"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows-server","params":{"categoryId":"Windows-Server"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"outlook","params":{"categoryId":"Outlook"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-endpoint-manager","params":{"categoryId":"microsoftintune"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-2","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities","url":"/","target":"BLANK"},{"children":[{"linkType":"INTERNAL","id":"a-i","params":{"categoryId":"AI"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"education-sector","params":{"categoryId":"EducationSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"partner-community","params":{"categoryId":"PartnerCommunity"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"i-t-ops-talk","params":{"categoryId":"ITOpsTalk"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"healthcare-and-life-sciences","params":{"categoryId":"HealthcareAndLifeSciences"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-mechanics","params":{"categoryId":"MicrosoftMechanics"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"public-sector","params":{"categoryId":"PublicSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"s-m-b","params":{"categoryId":"MicrosoftforNonprofits"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"io-t","params":{"categoryId":"IoT"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"startupsat-microsoft","params":{"categoryId":"StartupsatMicrosoft"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"driving-adoption","params":{"categoryId":"DrivingAdoption"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-1","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities-1","url":"/","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external","url":"/Blogs","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external-1","url":"/Events","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft-learn-1","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-learn-blog","params":{"boardId":"MicrosoftLearnBlog","categoryId":"MicrosoftLearn"},"routeName":"BlogBoardPage"},{"linkType":"EXTERNAL","id":"external-10","url":"https://learningroomdirectory.microsoft.com/","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-3","url":"https://docs.microsoft.com/learn/dynamics365/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-4","url":"https://docs.microsoft.com/learn/m365/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-5","url":"https://docs.microsoft.com/learn/topics/sci/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-6","url":"https://docs.microsoft.com/learn/powerplatform/?wt.mc_id=techcom_header-webpage-powerplatform","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-7","url":"https://docs.microsoft.com/learn/github/?wt.mc_id=techcom_header-webpage-github","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-8","url":"https://docs.microsoft.com/learn/teams/?wt.mc_id=techcom_header-webpage-teams","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-9","url":"https://docs.microsoft.com/learn/dotnet/?wt.mc_id=techcom_header-webpage-dotnet","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-2","url":"https://docs.microsoft.com/learn/azure/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"}],"linkType":"INTERNAL","id":"microsoft-learn","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"community-info-center","params":{"categoryId":"Community-Info-Center"},"routeName":"CategoryPage"}]},"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","controllerHighlightColor":"hsla(30, 100%, 50%)","linkFontWeight":"400","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkBoxShadowHover":"none","linkFontSize":"14px","backgroundOpacity":0.8,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","hamburgerColor":"var(--lia-nav-controller-icon-color)","linkTextBorderBottom":"none","brandLogoHeight":"30px","linkBgHoverColor":"transparent","linkLetterSpacing":"normal","collapseMenuDividerOpacity":0.16,"dropdownPaddingBottom":"15px","paddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"1px solid var(--lia-bs-border-color)","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","collapseMenuDividerBg":"var(--lia-nav-link-color)","linkColor":"var(--lia-bs-body-color)","linkJustifyContent":"flex-start","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","controllerTextColor":"var(--lia-nav-controller-icon-color)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-body-color)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid var(--lia-bs-body-color)","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","linkPaddingX":"10px","linkPaddingY":"5px","paddingTop":"15px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkBgColor":"transparent","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkDropdownPaddingY":"9px","controllerIconColor":"var(--lia-bs-body-color)","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"var(--lia-bs-body-color)"},"showSearchIcon":false,"languagePickerStyle":"iconAndLabel"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"transparent","linkHighlightColor":"var(--lia-bs-primary)","visualEffects":{"showBottomBorder":true},"linkTextColor":"var(--lia-bs-gray-700)"},"__typename":"QuiltComponent"},{"id":"custom.widget.community_banner","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"usePageWidth":false,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.HeroBanner","props":{"widgetVisibility":"signedInOrAnonymous","usePageWidth":false,"useTitle":true,"cMax_items":3,"useBackground":false,"title":"","lazyLoad":false,"widgetChooser":"custom.widget.HeroBanner"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.MicrosoftFooter","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1745505307000","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.community_banner-en-us-1746740526290":{"__typename":"CachedAsset","id":"component:custom.widget.community_banner-en-us-1746740526290","value":{"component":{"id":"custom.widget.community_banner","template":{"id":"community_banner","markupLanguage":"HANDLEBARS","style":".community-banner {\n a.top-bar.btn {\n top: 0px;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0px;\n background: #0068b8;\n color: white;\n padding: 10px 0px;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0px !important;\n font-size: 14px;\n }\n}\n","texts":{},"defaults":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.community_banner","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_community_banner_community-banner_1x9u2_1 {\n a.custom_widget_community_banner_top-bar_1x9u2_2.custom_widget_community_banner_btn_1x9u2_2 {\n top: 0;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0;\n background: #0068b8;\n color: white;\n padding: 0.625rem 0;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0 !important;\n font-size: 0.875rem;\n }\n}\n","tokens":{"community-banner":"custom_widget_community_banner_community-banner_1x9u2_1","top-bar":"custom_widget_community_banner_top-bar_1x9u2_2","btn":"custom_widget_community_banner_btn_1x9u2_2"}},"form":null},"localOverride":false},"CachedAsset:component:custom.widget.HeroBanner-en-us-1746740526290":{"__typename":"CachedAsset","id":"component:custom.widget.HeroBanner-en-us-1746740526290","value":{"component":{"id":"custom.widget.HeroBanner","template":{"id":"HeroBanner","markupLanguage":"REACT","style":null,"texts":{"searchPlaceholderText":"Search this community","followActionText":"Follow","unfollowActionText":"Following","searchOnHoverText":"Please enter your search term(s) and then press return key to complete a search.","blogs.sidebar.pagetitle":"Latest Blogs | Microsoft Tech Community","followThisNode":"Follow this node","unfollowThisNode":"Unfollow this node"},"defaults":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.HeroBanner","form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"__typename":"Component","localOverride":false},"globalCss":null,"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"}},"localOverride":false},"CachedAsset:component:custom.widget.MicrosoftFooter-en-us-1746740526290":{"__typename":"CachedAsset","id":"component:custom.widget.MicrosoftFooter-en-us-1746740526290","value":{"component":{"id":"custom.widget.MicrosoftFooter","template":{"id":"MicrosoftFooter","markupLanguage":"HANDLEBARS","style":".context-uhf {\n min-width: 280px;\n font-size: 15px;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.c-uhff-link {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.c-uhff {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.c-uhff-nav {\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n .c-heading-4 {\n color: #616161;\n word-break: break-word;\n font-size: 15px;\n line-height: 20px;\n padding: 36px 0 4px;\n font-weight: 600;\n }\n .c-uhff-nav-row {\n .c-uhff-nav-group {\n display: block;\n float: left;\n min-height: 1px;\n vertical-align: text-top;\n padding: 0 12px;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.c-list.f-bare {\n font-size: 11px;\n line-height: 16px;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 8px 0;\n margin: 0;\n }\n }\n }\n }\n}\n.c-uhff-base {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 30px 5% 16px;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.c-uhff-ccpa {\n font-size: 11px;\n line-height: 16px;\n float: left;\n margin: 3px 0;\n }\n a.c-uhff-ccpa:hover {\n text-decoration: underline;\n }\n ul.c-list {\n font-size: 11px;\n line-height: 16px;\n float: right;\n margin: 3px 0;\n color: #616161;\n li {\n padding: 0 24px 4px 0;\n display: inline-block;\n }\n }\n .c-list.f-bare {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 30px 24px 16px;\n }\n}\n\n.social-share {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n\n.sharing-options {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 43px;\n border-radius: 0px 7px 7px 0px;\n}\n.linkedin-icon {\n border-top-right-radius: 7px;\n}\n.linkedin-icon:hover {\n border-radius: 0;\n}\n.social-share-rss-image {\n border-bottom-right-radius: 7px;\n}\n.social-share-rss-image:hover {\n border-radius: 0;\n}\n\n.social-link-footer {\n position: relative;\n display: block;\n margin: -2px 0;\n transition: all 0.2s ease;\n}\n.social-link-footer:hover .linkedin-icon {\n border-radius: 0;\n}\n.social-link-footer:hover .social-share-rss-image {\n border-radius: 0;\n}\n\n.social-link-footer img {\n width: 40px;\n height: auto;\n transition: filter 0.3s ease;\n}\n\n.social-share-list {\n width: 40px;\n}\n.social-share-rss-image {\n width: 40px;\n}\n\n.share-icon {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n\n.share-icon:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n\n.share-icon:hover .label {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n\n.label {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 10px;\n top: 50%;\n transform: translateY(-50%);\n height: 40px;\n border-radius: 0 6px 6px 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px 5px 20px 8px;\n margin-left: -1px;\n}\n.linkedin {\n background-color: #0474b4;\n}\n.facebook {\n background-color: #3c5c9c;\n}\n.twitter {\n background-color: white;\n color: black;\n}\n.reddit {\n background-color: #fc4404;\n}\n.mail {\n background-color: #848484;\n}\n.bluesky {\n background-color: white;\n color: black;\n}\n.rss {\n background-color: #ec7b1c;\n}\n#RSS {\n width: 40px;\n height: 40px;\n}\n\n@media (max-width: 991px) {\n .social-share {\n display: none;\n }\n}\n","texts":{"New tab":"What's New","New 1":"Surface Laptop Studio 2","New 2":"Surface Laptop Go 3","New 3":"Surface Pro 9","New 4":"Surface Laptop 5","New 5":"Surface Studio 2+","New 6":"Copilot in Windows","New 7":"Microsoft 365","New 8":"Windows 11 apps","Store tab":"Microsoft Store","Store 1":"Account Profile","Store 2":"Download Center","Store 3":"Microsoft Store Support","Store 4":"Returns","Store 5":"Order tracking","Store 6":"Certified Refurbished","Store 7":"Microsoft Store Promise","Store 8":"Flexible Payments","Education tab":"Education","Edu 1":"Microsoft in education","Edu 2":"Devices for education","Edu 3":"Microsoft Teams for Education","Edu 4":"Microsoft 365 Education","Edu 5":"How to buy for your school","Edu 6":"Educator Training and development","Edu 7":"Deals for students and parents","Edu 8":"Azure for students","Business tab":"Business","Bus 1":"Microsoft Cloud","Bus 2":"Microsoft Security","Bus 3":"Dynamics 365","Bus 4":"Microsoft 365","Bus 5":"Microsoft Power Platform","Bus 6":"Microsoft Teams","Bus 7":"Microsoft Industry","Bus 8":"Small Business","Developer tab":"Developer & IT","Dev 1":"Azure","Dev 2":"Developer Center","Dev 3":"Documentation","Dev 4":"Microsoft Learn","Dev 5":"Microsoft Tech Community","Dev 6":"Azure Marketplace","Dev 7":"AppSource","Dev 8":"Visual Studio","Company tab":"Company","Com 1":"Careers","Com 2":"About Microsoft","Com 3":"Company News","Com 4":"Privacy at Microsoft","Com 5":"Investors","Com 6":"Diversity and inclusion","Com 7":"Accessiblity","Com 8":"Sustainibility"},"defaults":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.MicrosoftFooter","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_MicrosoftFooter_context-uhf_105bp_1 {\n min-width: 17.5rem;\n font-size: 0.9375rem;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-link_105bp_12 {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff_105bp_12 {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35 {\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n .custom_widget_MicrosoftFooter_c-heading-4_105bp_49 {\n color: #616161;\n word-break: break-word;\n font-size: 0.9375rem;\n line-height: 1.25rem;\n padding: 2.25rem 0 0.25rem;\n font-weight: 600;\n }\n .custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57 {\n .custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58 {\n display: block;\n float: left;\n min-height: 0.0625rem;\n vertical-align: text-top;\n padding: 0 0.75rem;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 0.5rem 0;\n margin: 0;\n }\n }\n }\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff-base_105bp_94 {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 1.875rem 5% 1rem;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: left;\n margin: 0.1875rem 0;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107:hover {\n text-decoration: underline;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: right;\n margin: 0.1875rem 0;\n color: #616161;\n li {\n padding: 0 1.5rem 0.25rem 0;\n display: inline-block;\n }\n }\n .custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 1.875rem 1.5rem 1rem;\n }\n}\n.custom_widget_MicrosoftFooter_social-share_105bp_138 {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n.custom_widget_MicrosoftFooter_sharing-options_105bp_146 {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 2.6875rem;\n border-radius: 0 0.4375rem 0.4375rem 0;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-top-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-bottom-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 {\n position: relative;\n display: block;\n margin: -0.125rem 0;\n transition: all 0.2s ease;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 img {\n width: 2.5rem;\n height: auto;\n transition: filter 0.3s ease;\n}\n.custom_widget_MicrosoftFooter_social-share-list_105bp_188 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195 {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover .custom_widget_MicrosoftFooter_label_105bp_207 {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n.custom_widget_MicrosoftFooter_label_105bp_207 {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 0.625rem;\n top: 50%;\n transform: translateY(-50%);\n height: 2.5rem;\n border-radius: 0 0.375rem 0.375rem 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1.25rem 0.3125rem 1.25rem 0.5rem;\n margin-left: -0.0625rem;\n}\n.custom_widget_MicrosoftFooter_linkedin_105bp_156 {\n background-color: #0474b4;\n}\n.custom_widget_MicrosoftFooter_facebook_105bp_237 {\n background-color: #3c5c9c;\n}\n.custom_widget_MicrosoftFooter_twitter_105bp_240 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_reddit_105bp_244 {\n background-color: #fc4404;\n}\n.custom_widget_MicrosoftFooter_mail_105bp_247 {\n background-color: #848484;\n}\n.custom_widget_MicrosoftFooter_bluesky_105bp_250 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_rss_105bp_254 {\n background-color: #ec7b1c;\n}\n#custom_widget_MicrosoftFooter_RSS_105bp_1 {\n width: 2.5rem;\n height: 2.5rem;\n}\n@media (max-width: 991px) {\n .custom_widget_MicrosoftFooter_social-share_105bp_138 {\n display: none;\n }\n}\n","tokens":{"context-uhf":"custom_widget_MicrosoftFooter_context-uhf_105bp_1","c-uhff-link":"custom_widget_MicrosoftFooter_c-uhff-link_105bp_12","c-uhff":"custom_widget_MicrosoftFooter_c-uhff_105bp_12","c-uhff-nav":"custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35","c-heading-4":"custom_widget_MicrosoftFooter_c-heading-4_105bp_49","c-uhff-nav-row":"custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57","c-uhff-nav-group":"custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58","c-list":"custom_widget_MicrosoftFooter_c-list_105bp_78","f-bare":"custom_widget_MicrosoftFooter_f-bare_105bp_78","c-uhff-base":"custom_widget_MicrosoftFooter_c-uhff-base_105bp_94","c-uhff-ccpa":"custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107","social-share":"custom_widget_MicrosoftFooter_social-share_105bp_138","sharing-options":"custom_widget_MicrosoftFooter_sharing-options_105bp_146","linkedin-icon":"custom_widget_MicrosoftFooter_linkedin-icon_105bp_156","social-share-rss-image":"custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162","social-link-footer":"custom_widget_MicrosoftFooter_social-link-footer_105bp_169","social-share-list":"custom_widget_MicrosoftFooter_social-share-list_105bp_188","share-icon":"custom_widget_MicrosoftFooter_share-icon_105bp_195","label":"custom_widget_MicrosoftFooter_label_105bp_207","linkedin":"custom_widget_MicrosoftFooter_linkedin_105bp_156","facebook":"custom_widget_MicrosoftFooter_facebook_105bp_237","twitter":"custom_widget_MicrosoftFooter_twitter_105bp_240","reddit":"custom_widget_MicrosoftFooter_reddit_105bp_244","mail":"custom_widget_MicrosoftFooter_mail_105bp_247","bluesky":"custom_widget_MicrosoftFooter_bluesky_105bp_250","rss":"custom_widget_MicrosoftFooter_rss_105bp_254","RSS":"custom_widget_MicrosoftFooter_RSS_105bp_1"}},"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1745505307000","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagsHeaderWidget-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagsHeaderWidget-1745505307000","value":{"tag":"{tagName}","topicsCount":"{count} {count, plural, one {Topic} other {Topics}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1745505307000","value":{"title@userScope:other":"Recent Content","title@userScope:self":"Contributions","title@board:FORUM@userScope:other":"Recent Discussions","title@board:BLOG@userScope:other":"Recent Blogs","emptyDescription":"No content to show","MessageListForNodeByRecentActivityWidgetEditor.nodeScope.label":"Scope","title@instance:1722894000155":"Recent Discussions","title@instance:1727367112619":"Recent Blog Articles","title@instance:1727367069748":"Recent Discussions","title@instance:1727366213114":"Latest Discussions","title@instance:1727899609720":"","title@instance:1727363308925":"Latest Discussions","title@instance:1737115580352":"Latest Articles","title@instance:1720453418992":"Recent Discssions","title@instance:1727365950181":"Latest Blog Articles","title@instance:bmDPnI":"Latest Blog Articles","title@instance:IiDDJZ":"Latest Blog Articles","title@instance:1721244347979":"Latest blog posts","title@instance:1728383752171":"Related Content","title@instance:1722893956545":"Latest Skilling Resources","title@instance:dhcgCU":"Latest Discussions"},"localOverride":false},"Category:category:Exchange":{"__typename":"Category","id":"category:Exchange","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Outlook":{"__typename":"Category","id":"category:Outlook","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Community-Info-Center":{"__typename":"Category","id":"category:Community-Info-Center","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:EducationSector":{"__typename":"Category","id":"category:EducationSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:DrivingAdoption":{"__typename":"Category","id":"category:DrivingAdoption","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Azure":{"__typename":"Category","id":"category:Azure","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows-Server":{"__typename":"Category","id":"category:Windows-Server","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftTeams":{"__typename":"Category","id":"category:MicrosoftTeams","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PublicSector":{"__typename":"Category","id":"category:PublicSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft365":{"__typename":"Category","id":"category:microsoft365","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:IoT":{"__typename":"Category","id":"category:IoT","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:ITOpsTalk":{"__typename":"Category","id":"category:ITOpsTalk","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftLearn":{"__typename":"Category","id":"category:MicrosoftLearn","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Blog:board:MicrosoftLearnBlog":{"__typename":"Blog","id":"board:MicrosoftLearnBlog","blogPolicies":{"__typename":"BlogPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:AI":{"__typename":"Category","id":"category:AI","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftMechanics":{"__typename":"Category","id":"category:MicrosoftMechanics","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftforNonprofits":{"__typename":"Category","id":"category:MicrosoftforNonprofits","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:StartupsatMicrosoft":{"__typename":"Category","id":"category:StartupsatMicrosoft","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PartnerCommunity":{"__typename":"Category","id":"category:PartnerCommunity","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Microsoft365Copilot":{"__typename":"Category","id":"category:Microsoft365Copilot","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows":{"__typename":"Category","id":"category:Windows","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Content_Management":{"__typename":"Category","id":"category:Content_Management","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft-security":{"__typename":"Category","id":"category:microsoft-security","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoftintune":{"__typename":"Category","id":"category:microsoftintune","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Conversation:conversation:3707414":{"__typename":"Conversation","id":"conversation:3707414","topic":{"__typename":"BlogTopicMessage","uid":3707414},"lastPostingActivityTime":"2023-12-05T18:03:30.924-08:00","solved":false},"Blog:board:HealthcareAndLifeSciencesBlog":{"__typename":"Blog","id":"board:HealthcareAndLifeSciencesBlog","displayId":"HealthcareAndLifeSciencesBlog","nodeType":"board","conversationStyle":"BLOG","title":"Healthcare and Life Sciences Blog","shortTitle":"Healthcare and Life Sciences Blog","parent":{"__ref":"Category:category:HealthcareAndLifeSciences"}},"User:user:1484035":{"__typename":"User","uid":1484035,"login":"j_folberth","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0xNDg0MDM1LTVjQjEyOQ?image-coordinates=0%2C155%2C2069%2C2224"},"id":"user:1484035"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=9","title":"azure_pipelines.jpg","associationType":"BODY","width":474,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwMmk0NTU0RTFDRDk3NTQ1MUNF?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwMmk0NTU0RTFDRDk3NTQ1MUNF?revision=9","title":"j_folberth_0-1672755058438.png","associationType":"BODY","width":271,"height":320,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwM2lBOTQ4OTlCMkVGOTZGQTVB?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwM2lBOTQ4OTlCMkVGOTZGQTVB?revision=9","title":"j_folberth_1-1672755058441.png","associationType":"BODY","width":760,"height":885,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwNGk2MzQ4Nzg0MDNCQUYzQzZB?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwNGk2MzQ4Nzg0MDNCQUYzQzZB?revision=9","title":"j_folberth_2-1672755058443.png","associationType":"BODY","width":498,"height":696,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwNWlBNkIxMTA5NkQ1QTA4OERD?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwNWlBNkIxMTA5NkQ1QTA4OERD?revision=9","title":"j_folberth_3-1672755058444.png","associationType":"BODY","width":668,"height":307,"altText":null},"BlogTopicMessage:message:3707414":{"__typename":"BlogTopicMessage","subject":"Azure DevOps Pipelines: Environments and Variables","conversation":{"__ref":"Conversation:conversation:3707414"},"id":"message:3707414","revisionNum":9,"uid":3707414,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484035"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Environments and variables are two key components when it comes to Azure DevOps pipelines security and governance. Additionally, if done right they assist with reusability of your pipelines. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":66701},"postTime":"2023-01-03T06:53:12.555-08:00","lastPublishTime":"2023-12-05T18:03:30.924-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n Introduction \n This is part of a series on Azure DevOps pipelines, previously we discussed Azure DevOps Pipelines: tasks, jobs, and stages. \n \n At this point you are familiar with core components of Azure DevOps pipelines (tasks, jobs, and stages) and are looking how to best leverage some additional components such as environments and variables. \n \n Environments and variables are two key components when it comes to Azure DevOps pipelines security and governance. Additionally, if done right they assist with reusability of your pipelines. \n \n Environments \n Azure DevOps environments are defined as “a collection of resources that you can target with deployments from a pipeline” \n They are much more than that though. Environments provide the ability to monitor deployments that are occurring, provide an additional level of security, and assist in tracking the state of work items in terms of where they have been deployed to. \n Environments, like a lot of things withing Azure, is a very generic term. \n \n These environments are accessed under the pipelines blade: \n \n \n \n \n These environments do not necessarily equivocate to a traditional dev, tst, prd model. Don’t get me wrong, they certainly could, and I usually suggest doing so as a start. When and how to create an environment goes back to how the environment will be deployed and managed. \n \n Before diving into this with more detail, it’s important to understand the environment is associated with a deployment job, which is a subtype of an Azure DevOps job. Deployment jobs, in themselves, could be an additional topic; however, for this purpose the deployment job is the mechanism that registers the activity with the Azure DevOps target environment. \n An environment gives users of Azure DevOps a clear prospective on what jobs have been deployed to a specific environment. \n \n Observe below the list of jobs that have been deployed to the “dev” environment. \n \n \n \n One can see here all the jobs and respective pipelines that have been deployed to a specified environment. This perspective gives an admin the ability to see what has been deployed in Azure DevOps to a specified scope. Which, as any administrator can attest, is a key in understanding what may have changed in an environment over a given point of time. Additionally, one can drill into the pipeline associated with the job and easily see the commits, work items, and any additional details that were included as part of the deployment. \n The next key piece to leveraging environments is the ability to set gates for the environments. \n \n A gate is a pre-approval or check before the job is dispatched to an agent(s). There are multiple options as to what could be considered a gate or approval. Traditionally manual approval is one most organization look for when going to a production environment. Alternatively, and additionally a gate could consist of invoking an Azure Function, confined to a time window, invoke a rest API, etc.. \n \n \n \n \n This ability provides the opportunity to enforce quality control and security around any deployments being sent out to an environment. \n So, a couple guidelines when creating environments: \n \n All deployment jobs in the same stage should go to the same environment. This helps when rerunning and organizing approvals/gates \n Think of environments based on the audience who would be controlling gates and/or viewing jobs. Maybe a combination of app + environment makes the most sense. \n If redeploying a stage w/ environment or approval the gate or approval will be re evaluated \n \n Variables \n Azure DevOps Variables are the key when trying to optimize reuse across stages and jobs. First and foremost, variables are attached to a scope. This is the key concept when trying to best leverage them across a multi-stage and multi-environment pipeline. \n A variable can be scoped at the pipeline, stage, and job level. When thinking about this a job is the sequence of tasks being dispatched to an agent, as such any variables being scoped to a job will not be inherently available to subsequent jobs since they could be running on completely different agents. Again, this is true for any variables scoped at the stage level. The same variable defined in multiple places could have different values depending on how the variable has been scoped. \n \n Variables can be read in from: \n \n User Defined \n A template file \n A variable group \n System Defined \n \n It is my experience that when creating user defined variables that there should be thought in how they will be used. Realistically user defined variables should only be leveraged if there is no potential to be reused outside of the current scope. Variables should be architected in such a fashion that they can be reused across multiple jobs, stages, and pipelines. Explicitly defining them to a set value tends to limit this and introduce more manual maintenance. \n \n The first place I defined variables is in a template file. There will be a follow up post more focused on templates; however, not mentioning them, as an option for variables is leaving out huge functionality that is easy to add. Think of a template file as comprable to an aasettings.json, azuredeploy.parameters.json, or terraform.var file. This file SHOULD NOT CONTAIN SECRETS OR SENSITVE INFORMATION. Remeber this YAML will be stored in source control which is different than classic releases. \n Defining a variable template file is easy. \n \n All that is required is a `variable` block and the rest is key value mapping: \n \n \n \n variables: \n AzureSubscriptionServiceConnectionName: Example - Dev \n TerraformDirectory: Infrastructure \n TerraformStateStorageAccountContainerName: terraform-state \n TerraformStateStorageAccountName: satfdeveus \n TerraformStateStorageAccountResourceGroupName: rg-terraformState-dev-eus \n \n \n \n Example is taken from TheYAMLPipelineOne repo. \n \n Referencing these values can be done so via: \n \n \n ${{variables.TerraformDirectory}} \n \n \n The important thing when using a YAML variable template is the name. I highly recommend the name of the variable file matches the target environment as described above. This means for a dev environment perhaps the YAML variable file name will be `dev_variables.yml`. \n Using this pattern, the variable file should be called within a job responsible for deploying to dev. \n \n Here is an example of such a practice: \n \n \n jobs: \n- deployment: terraformApply${{ parameters.environmentName }} \n displayName: Terraform Apply ${{ parameters.environmentName }} \n environment: ${{ parameters.environmentName }} \n variables: \n - template: ../variables/${{ parameters.environmentName }}_variables.yml \n \n \n This will mean we can call the appropriate variable template corresponding to the target environment reusing the same parameter. \n If needing to store a secret, then I would suggest leveraging Azure DevOps Variable Groups. Variable groups will have the added security having to explicitly grant pipelines access to them, the inability to retrieve secrets after they are stored, and Azure DevOps itself has another layer of security as to whom can edit or add variables. \n \n Referencing a variable group in YAML is also straightforward by leveraging the ‘group’ keyword. I would also recommend the practice of appending or prefixing the variable group with environment name. This will give you the flexibility to load the associated variable group and variables at the requested scope: \n \n \n variables: \n- group: my-variable-group_${{ parameters.environmentName }} \n \n \n Once loaded then the individual properties can be accessed as `$(variableName)`. Notice the difference in syntax that the variable is $() format. This means the variable will be accessed at macro level right before runtime. This is a preferred way if storing secrets as variables. More on that below. \n \n Sometimes the need may arise to evaluate one of the built in Azure DevOps variables. A common request I come across is determining if the pipeline is executing against the trunk or release branch of the repository. This can be accommodate leveraging the ‘Build.SourceBranch’ variable. \n \n This would be accomplished with: \n \n \n - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main')}}: \n \n \n Here we will do the next steps if the value in the `Build.SourceBranch` variable is the main branch. \n Variable Syntax \n This is one of the most common items we run into when helping customers is how and when to define variables as `$(variableName)`, `${{variables.variableName}}`, or `$[variables.variableName]`. \n \n Personally, I recommend defaulting to ${{variables.variableName}}. This will make the variable insert at compilation time. Compilation time is when the pipeline execution instance is created. I find this easy to debug if a variable is incorrectly passed since the variable will be populated in the log files. Another added benefit is when authoring pipelines can quickly tell if the referenced value name is a variable and not a parameter. \n Now $(variableName) is the next type I typically use. This is used for secrets as discussed above. Additionally, since this variable will expand at task execution runtime, it will be used for all built in variables. Since we typically won’t know these variable values until the pipeline executes. \n \n For summary here is a chart from Microsoft docs: \n \n \n \n Conclusion \n The combination of Azure DevOps target environments and variables can be a powerful tool to yield when expanding and creating Azure DevOps Pipelines. Having their names align can lead to properly scoping variables to jobs associated with the corresponding environments. Furthermore, environments add an additional level of control via gates and approvals. While variables add the extra functional of being user defined, defined in a template file, variable group, and expose built in variables from Azure DevOps itself. In a future post we will dive deeper into how to stitch together templates together to really accelerate your Azure Pipeline creation and maintenance. In the meantime, if you are interested in learning and seeing examples of YAML Pipelines check out my GitHub repository on YAMLTemplates. \n \n Additionally feel free to check out a follow up piece on templating Azure DevOps Pipelines: Templates Tasks and Jobs (microsoft.com) Furthermore here is a post on how to template stages and leverage YAML Objects. \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"11149","kudosSumWeight":6,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwMmk0NTU0RTFDRDk3NTQ1MUNF?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwM2lBOTQ4OTlCMkVGOTZGQTVB?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwNGk2MzQ4Nzg0MDNCQUYzQzZB?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzA3NDE0LTQyOTYwNWlBNkIxMTA5NkQ1QTA4OERD?revision=9\"}"}}],"totalCount":5,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3851470":{"__typename":"Conversation","id":"conversation:3851470","topic":{"__typename":"BlogTopicMessage","uid":3851470},"lastPostingActivityTime":"2024-07-30T23:14:27.801-07:00","solved":false},"User:user:1676800":{"__typename":"User","uid":1676800,"login":"VinodSoni","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0xNjc2ODAwLTU0NzMzMGlFNkI4OEIzMEFBOEEyNzNF"},"id":"user:1676800"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM4OWkwRjBCNUQxMUE0QTkyNDEw?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM4OWkwRjBCNUQxMUE0QTkyNDEw?revision=1","title":"VinodSoni_0-1687202692697.png","associationType":"BODY","width":1862,"height":439,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MWk0RjJERkNFQ0UxNEIwNTND?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MWk0RjJERkNFQ0UxNEIwNTND?revision=1","title":"VinodSoni_1-1687202692704.png","associationType":"BODY","width":1862,"height":883,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5N2k2OTk2QTMxMUFBODFERkQw?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5N2k2OTk2QTMxMUFBODFERkQw?revision=1","title":"VinodSoni_4-1687203166840.png","associationType":"BODY","width":1338,"height":710,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MGk5QTUxNDhDOTgwOEUwOUM4?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MGk5QTUxNDhDOTgwOEUwOUM4?revision=1","title":"VinodSoni_2-1687202692705.png","associationType":"BODY","width":492,"height":203,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MmlDQjY4QkEwRjhDNTc1NkRB?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MmlDQjY4QkEwRjhDNTc1NkRB?revision=1","title":"VinodSoni_3-1687202692706.png","associationType":"BODY","width":1001,"height":180,"altText":null},"BlogTopicMessage:message:3851470":{"__typename":"BlogTopicMessage","subject":"Azure OpenAI GPT model to review Pull Requests for Azure DevOps","conversation":{"__ref":"Conversation:conversation:3851470"},"id":"message:3851470","revisionNum":1,"uid":3851470,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1676800"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" In recent months, the use of Generative Pre-trained Transformer (GPT) models for natural language processing (NLP) has gained significant traction. GPT models, which are based on the Transformer architecture, can generate text from arbitrary sources of input data and can be trained to identify errors and detect anomalies in text. As such, GPT models are increasingly being used for a variety of applications, ranging from natural language understanding to text summarization and question-answering. \n \n In the software development world, developers use pull requests to submit proposed changes to a codebase. However, reviews by other developers can sometimes take a long time and not accurate, and in some cases, these reviews can introduce new bugs and issues. In order to reduce this risk, During my research I found the integration of GPT models is possible and we can add Azure OpenAI service as pull request reviewers for Azure Pipelines service. \n \n The GPT models are trained on developer codebases and are able to detect potential coding issues such as typos, syntax errors, style inconsistencies and code smells. In addition, they can also assess code structure and suggest improvements to the overall code quality. \n \n Once the GPT models have been trained, they can be integrated into the Azure Pipelines service so that they can automatically review pull requests and provide feedback. This helps to reduce the time taken for code reviews, as well as reduce the likelihood of introducing bugs and issues. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":38302},"postTime":"2023-06-19T12:35:27.843-07:00","lastPublishTime":"2023-06-19T12:35:27.843-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" In recent months, the use of Generative Pre-trained Transformer (GPT) models for natural language processing (NLP) has gained significant traction. GPT models, which are based on the Transformer architecture, can generate text from arbitrary sources of input data and can be trained to identify errors and detect anomalies in text. As such, GPT models are increasingly being used for a variety of applications, ranging from natural language understanding to text summarization and question-answering. \n \n In the software development world, developers use pull requests to submit proposed changes to a codebase. However, reviews by other developers can sometimes take a long time and not accurate, and in some cases, these reviews can introduce new bugs and issues. In order to reduce this risk, During my research I found the integration of GPT models is possible and we can add Azure OpenAI service as pull request reviewers for Azure Pipelines service. \n \n The GPT models are trained on developer codebases and are able to detect potential coding issues such as typos, syntax errors, style inconsistencies and code smells. In addition, they can also assess code structure and suggest improvements to the overall code quality. \n \n Once the GPT models have been trained, they can be integrated into the Azure Pipelines service so that they can automatically review pull requests and provide feedback. This helps to reduce the time taken for code reviews, as well as reduce the likelihood of introducing bugs and issues. \n \n How to use it \n \n 1. Create Azure OpenAI instance \n Azure OpenAI Service provides REST API access to OpenAI's powerful language models including the GPT-3, Codex and Embeddings model series. In addition, the new GPT-4 and ChatGPT (gpt-35-turbo) model series have now reached general availability. These models can be easily adapted to your specific task including but not limited to content generation, summarization, semantic search, and natural language to code translation. Users can access the service through REST APIs, Python SDK, or our web-based interface in the Azure OpenAI Studio. \n \n Use this article to get started making your first calls to Azure OpenAI - How-to - Create a resource and deploy a model using Azure OpenAI Service - Azure OpenAI | Microsoft Learn \n \n \n \n 2. Deploy Model \n Set up a deployment to make API calls against a provided base model or a custom model in Azure OpenAI Studio. \n \n \n 3. Install the extension \n To use the GPT Pull Request Review Task, first install the extension in your Azure DevOps organization. Click on the \"Get it free\" button and follow the prompts to install it. You may need to authorize the extension to access your Azure DevOps account. \n \n GitHub Repository Link - mlarhrouch/azure-pipeline-gpt-pr-review: Azure DevOps extension adding tools to review Pull Requets using Azure Pipelines (github.com) \n \n Visual Studio Marketplace - GPT Pull Request Review - Visual Studio Marketplace \n \n 4. Add the task to the build pipeline \n After installing the extension, add the task to your build pipeline. Go to your build pipeline, click on the \"+\" icon to add a new task, and search for \"Review PullRequest by GPT\". Select it and add it to your pipeline. \n \n 5. Configure the task \n Once you have added the task to your pipeline, configure it. In the task configuration, provide your API key for OpenAI API. To create an API key, go to Azure OpenAI instance > Key and Endpoints as shown in below screenshot. \n \n Notes: These keys are used to access your Cognitive Service API. Do not share your keys. Store them securely– for example, using Azure Key Vault. We also recommend regenerating these keys regularly. Only one key is necessary to make an API call. When regenerating the first key, you can use the second key for continued access to the service. \n \n \n \n \n 6. Review Pull Requests \n When the build is triggered from a Pull Request, the task will review it. If there is feedback on the changed code, the task will add comments to the Pull Request. If the build is triggered manually, the task will be skipped. \n \n 7. Permission Setup \n Before using this task, ensure that the build service has permissions to contribute to Pull Requests in your repository, and allow the task to access the system token. \n 8. Give permission to the build service agent \n \n \n 9. Allow Task to access the system token \n Depending on the type of pipeline you are using, follow one of the two steps below: \n \n 10. Yaml pipelines \n Add a checkout section with persistCredentials set to true. \n steps:- checkout: self persistCredentials: true \n \n 11. Classic editors \n Enable the option \"Allow scripts to access the OAuth token\" in the \"Agent job\" properties. \n \n \n Overall, the integration of GPT models as pull request reviewers for Azure Pipelines can help to reduce the time taken for code reviews and improve the overall quality of code. This is a great step forward for the development process and can help to make the process of software development much more efficient and secure. \n \n Feel free to provide your feedback and any suggestions advice on this topic. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"5352","kudosSumWeight":3,"repliesCount":12,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM4OWkwRjBCNUQxMUE0QTkyNDEw?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MWk0RjJERkNFQ0UxNEIwNTND?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5N2k2OTk2QTMxMUFBODFERkQw?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MGk5QTUxNDhDOTgwOEUwOUM4?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODUxNDcwLTQ4MTM5MmlDQjY4QkEwRjhDNTc1NkRB?revision=1\"}"}}],"totalCount":5,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3694772":{"__typename":"Conversation","id":"conversation:3694772","topic":{"__typename":"BlogTopicMessage","uid":3694772},"lastPostingActivityTime":"2024-02-16T04:36:21.030-08:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=13\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=13","title":"azure_pipelines.jpg","associationType":"BODY","width":474,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNTIzNWk5MTEwRjQ4MTY4RkJEMzIw?revision=13\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNTIzNWk5MTEwRjQ4MTY4RkJEMzIw?revision=13","title":"j_folberth_1-1670813477021.png","associationType":"BODY","width":910,"height":351,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNTIzM2k3MDgwQzMyNjk5RTlBNjRB?revision=13\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNTIzM2k3MDgwQzMyNjk5RTlBNjRB?revision=13","title":"j_folberth_0-1670812073275.png","associationType":"BODY","width":263,"height":303,"altText":null},"BlogTopicMessage:message:3694772":{"__typename":"BlogTopicMessage","subject":"Azure DevOps Pipelines: Tasks, Jobs, Stages","conversation":{"__ref":"Conversation:conversation:3694772"},"id":"message:3694772","revisionNum":13,"uid":3694772,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484035"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Introduction into the basic terminology around Azure DevOps Pipelines. This post will cover the role of a task, job, and stage in addition to illustrating how they interact with each other. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":36800},"postTime":"2022-12-14T09:54:45.955-08:00","lastPublishTime":"2023-04-10T19:54:52.106-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n \n Introduction \n When starting in Azure DevOps Pipelines one can immediately become inundated with terminology that may seem foreign or question what pipeline structure will lead to the most flexibility and streamlining of their build/deployment process. This post will focus on the hierarchy of Tasks->Jobs-Stages. My intent will be to cover Environments and Variables in a follow up post and then templating in one after that. \n \n What is a Pipeline? \n An Azure DevOps Pipeline is the next generation of what is today referred to as Classic Build and Releases. I have heard them called YAML Pipelines, Multi-Stage Pipelines, and just Pipelines. They have been around now for a few years; however, with the maturity and introduction of new features coming from the product team the general direction seems to be towards adopting pipelines. Perhaps none more telling than the option to \"disable classic pipelines\" in an Azure Devops Organization. \n \n At the end of the day a pipeline is defined in YAML and used to build and/or deploy your code. Some of the features of YAML pipelines are: \n \n Defined in Source Control via YAML Files \n Can be templated \n Reference resource in other repositories (even GitHub) \n Easily run jobs in parallel \n Self-Hosted or MS Hosted Agents (Machines) for execution \n \n For more information feel free to check out Microsoft's official documentation. \n \n If coming from a GitHub background this may sound familiar to you as it is comparable to GitHub Actions. Here is a breakdown of terminology between the two. For more feel free to check out this comparison document from GitHub \n \n \n \n \n Azure DevOps Pipeline \n \n \n GitHub Action \n \n \n \n \n pipeline \n \n \n workflow \n \n \n \n \n stages \n \n \n stages (separate workflow files) \n \n \n \n \n jobs \n \n \n jobs \n \n \n \n \n tasks \n \n \n uses \n \n \n \n \n \n Here is an example of how one environment could utilize stages, jobs, tasks: \n \n \n Tasks \n Sometimes referred to as \"steps\", tasks are the basic building block to any pipeline. A task is the individual utility/method/execution that is being ran. One cannot have a pipeline without a task. A pipeline needs to run something. For some examples feel free to check out the complete list of Pipeline tasks available from Microsoft. Still can't find what you need? The Azure DevOps Marketplace provide plenty of other tasks which have been created and published from the open-source community. One word of advice if looking to download and install a task from the Marketplace is to ensure the extension is still being actively maintained. An easy way to check this would be click on the project details like the one below: \n Can see here that this particular task, Replace Tokens, was last updated 2 months ago from this writing. \n \n When designing tasks, order matters. Tasks should be constructed so that they are ran in sequential order. In other words, one shouldn't be running an MSBuild task before installing any needed DotnetSDKs. \n \n The majority of the time if the pipeline involves building an application there should be a PublishPipelineArtifact. In general, this task will upload an artifact (code, package, zip file) to the pipeline. This will not only ensure continuity for deployments across environments; however, it will also provide an audit trail and ability to roll back. There is no storage cost associated with this, just double check your artifact retention policies. \n \n Jobs \n The next step in the Pipeline hierarchy is the Job. The job is a grouping of tasks. A job may or may not be dependent on other jobs. This is a key concept to understand as it easily allows you to run jobs in parallel to significantly increase your pipeline efficiency. \n \n This is achieved by the job being dispatched to an agent (machine) to run the tasks. Thus, it is important to scope jobs such that they are can be ran in parallel. Going back to my earlier example I may have a job that is building a dotnet code containing the tasks required to package and publish the code and a second job responsible for copying my Infrastructure as Code (IaC) components as pipeline artifacts. Splitting the jobs in this away ensures that agent time is maximized. \n \n Another item to note is the job will download the artifact(s) produced in the build stage of the pipeline. This helps to understand how future jobs retrieve the artifact to be deployed. \n \n A few key considerations when we are talking about jobs: \n \n Job names must be unique in a given stage....more on that in a minute \n Variables can be loaded to the scope of the job \n Every pipeline must have at least one job \n The agent OS can be defined at the job level \n By default, jobs are run in parallel. Can override by dependsOn[ job name] \n Must have at least one job with no dependencies \n Deployment jobs are a key concept \n Azure DevOps Environments are a deployment job property. Next post forthcoming. \n \n \n Stages \n Next on the hierarchal chain is stages. Stages are the level above jobs. A stage is required; however, there is a default if one is not provided. A stage can contain one to many jobs and acts as a logical grouping of related jobs. \n \n An important component to understand is that Azure DevOps, out of the box, provide an easy way to rerun Pipelines at the stage level. This means our stages should be constructed with jobs that make sense to re-run together. Usually, customers want to naturally associate a stage with a customer environment. I'd advise fighting this temptation. \n \n It may make sense at first to do this; however, it can break down and isn't a one size fits all approach. If dealing with the cloud, I usually advise to start with a combination of customer environment/region. Think if my application spans three Azure regions and those are all in the same stage when clicking redeploy stage am I always going to want to redeploy across all three of my regions? Maybe not all the time and if so, we can click redeploy on all the individual stages. An additional scenario could be pipelines that deploy to both on prem and the cloud. Perhaps we'd like to split that as two different stages? \n \n Some other notes on stages: \n \n Variables can be scoped at the stage level \n Can have dependencies \n Stage names must be unique to the pipeline \n \n \n Conclusion \n The architecture and thought process behind designing and developing tasks, jobs, and stages for your Azure Pipelines are paramount to be successful in a highly mature environment. Hopefully this post did a good job outlining some of the key pieces of each. For additional reading check out Azure DevOps Pipelines: Environments and Variables. If wanting to check jump to templating can check out a follow blog on Azure DevOps Pipelines: Templates Tasks and Jobs (microsoft.com) , Azure DevOps Pipelines: Stages and YAML Objects, or check out my GitHub repository on YAMLTemplates. \n \n \n \n \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7149","kudosSumWeight":9,"repliesCount":4,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=13\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNTIzNWk5MTEwRjQ4MTY4RkJEMzIw?revision=13\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjk0NzcyLTQyNTIzM2k3MDgwQzMyNjk5RTlBNjRB?revision=13\"}"}}],"totalCount":3,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3750154":{"__typename":"Conversation","id":"conversation:3750154","topic":{"__typename":"BlogTopicMessage","uid":3750154},"lastPostingActivityTime":"2023-10-16T06:57:57.693-07:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzUwMTU0LTQ0NDUxMGlDNzBBRjdERTgzMTg5MDJC?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzUwMTU0LTQ0NDUxMGlDNzBBRjdERTgzMTg5MDJC?revision=2","title":"VinodSoni_0-1677095782892.png","associationType":"BODY","width":717,"height":408,"altText":null},"BlogTopicMessage:message:3750154":{"__typename":"BlogTopicMessage","subject":"Setup Azure DevOps Self Hosted Agent On-Premise & Troubleshooting Guidelines","conversation":{"__ref":"Conversation:conversation:3750154"},"id":"message:3750154","revisionNum":2,"uid":3750154,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1676800"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Azure DevOps supports the deployment of the builds from release pipelines to the on-premise environments using self-hosted pipeline agents. This article describes creating an Azure DevOps self-hosted agent in an on-premise Windows machine and some standard troubleshooting steps in case any issue. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":30099},"postTime":"2023-02-22T11:59:24.735-08:00","lastPublishTime":"2023-10-16T06:30:20.963-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Azure DevOps supports the deployment of the builds from release pipelines to the on-premise environments using self-hosted pipeline agents. This article describes creating an Azure DevOps self-hosted agent in an on-premise Windows machine and some standard troubleshooting steps in case any issue. \n \n \n Process \n \n Microsoft made creating Azure DevOps self-hosted agents easy in an on-premise environment. This section describes how to do it. \n \n Create an Agent pool and download the agent \n Follow the below steps to create an agent pool in Azure DevOps and download the agent. \n Open Azure DevOps portal and navigate to the organization where you want to add the agent. \n Click on Organization settings. \n Click on Agent pools under the pipelines. \n Click on Add pool. \n Select Pool type as Self-hosted and provide a suitable name (say MyAgentPool). And click Create. \n Click on the newly created Agent pool (MyAgentPool) and the New agent button. \n Click the Download button to download the agent pool zip file under the Windows tab. This is the server where you want to create an on-premise Agent pool. \n \n \n Configure Azure DevOps agent \n \n \n Once you have downloaded the zip file, follow the below instruction to configure the Azure DevOps agent in an on-premise machine. \n Navigate to the organization in the DevOps portal and click on the user settings icon at the top-right corner of the page. Click on Personal access tokens from the drop-down menu. Click on New Token. Select Agent Pools (read, manage) for the scope and ensure all the other boxes are unchecked. Once the token is created, copy and store the token for future use. \n The on-premise Azure DevOps agent will use this token to communicate with Azure DevOps organization. \n Open PowerShell ISE on the Windows machine and execute the below command. \n cd C:\\ #base location for the agent folder. \n \n You can set it as per your needs. \n \n \n mkdir agent \n\ncd agent \n\nAdd-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory(\"$HOME\\Downloads\\vsts-agent-win-x64-2.217.2.zip\", \"$PWD\") \n \n \n \n Navigate to the folder path C:\\agent. \n Double-click on config.cmd file. This will open a cmd prompt with the below questionnaire. \n Enter server URL > https://dev.azure.com/<organisation name>/ \n Enter authentication type (press enter for PAT) > <Press enter> \n Enter personal access token > <Enter access token generated in step 1> If the connection is successful, it will ask you to register an agent. \n Enter agent pool (press enter for default)> <Name of the agent pool created earlier (MyAgentPool)> \n Enter agent name (press enter for <servername>) > <Provide any suitable name for the agent. The default is Server name> \n It will connect and test the agent connection. If it is successful, \n Enter work folder (press enter for _work) > <press enter> \n Enter run agent as service? (Y/N) (press enter for N) > (Enter Y if you want to run this as a service) \n Enter configure autologon and run agent on startup? (Y/N) (press enter for N) > (Enter Y if you want to start the service on startup) \n \n \n Start and Verify the Azure DevOps self-hosted agent. \n \n \n Navigate to the folder path C:\\agent. \n Double-click on the run.cmd file. This will open a cmd prompt and connect to the server. After the successful connection, it will start listening for jobs. \n You can return to the Agent pools in Azure DevOps organization and see your agent status online. \n Azure DevOps self-hosted agent is now ready to use in Release pipelines for on-premise deployments. \n \n \n Troubleshooting the agent for connectivity issue \n \n Sometime self-hosted build agent lost connection to the DevOps Services. We may notice error while running build/release pipelines. To provide some context, the azure pipelines agent is composed of two processes: agent.listener and agent.worker (one of these per step in the job). The listener is responsible for reporting that workers are still making progress. If the agent.listener is unable to communicate with the server for 10 minutes (we attempt to communicate every minute), we assume something has Gone Wrong and abandon the job. \n We can perform several troubleshooting steps based on the error we face. Below are some common steps I recommend to follow. \n \n Examples of error: - \n \n \n ERR Agent] System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. \n \n \n \n Re-Start the running Agent service – We can go to task management or services section and kill the running service and restart it from installation folder. \n Re-Installation of Agent - We can stop the running services and remove the contents from installation folder (e.g config.cmd). Follow the steps listed here - Deploy an Azure Pipelines agent on Windows - Azure Pipelines | Microsoft Learn \n \n \n Note: We can also try installing the agent again in a separate folder from the old agent. The issue might be related to that the old agent installed with the URL [org.name].visualstudio.com I guess there is now some SSL certificate issue with the old URL. We can try new agent with the dev.azure.com/[org.name] URL and this may solve the issues. \n \n \n TLS2 Configuration – Look this article (Azure DevOps TLS 1.2 transition readiness checker) and verify TLS configuration - Source and script - microsoft/azure-devops-tls12: Azure DevOps TLS 1.2 transition readiness checker (github.com) \n Check if anti-virus programs identifying it as a threat \n Check if local proxies acting up in various ways \n Physical machine running out of memory or disk space (quite common). \n Check if the machine rebooting unexpectedly for any scheduled maintenance window e.g. OS updates etc. \n Sometime work payload being run at a way higher priority than the listener (thus \"starving\" the listener out). \n Unit tests shutting down network adapters (quite common). \n Having too many agents at normal priority on the same machine so they starve each other out, etc. \n If you think you're seeing an issue that cannot be explained by any of the above (and nothing jumps out at you from the _diag logs folder), please file an issue at Azure DevOps Support | Microsoft Azure \n Run a self-hosted agent behind a web proxy – To enable the agent to run behind a web proxy, pass --proxyurl, --proxyusername and --proxypassword. You can refer this document for more information - Run the agent behind a web proxy - Azure Pipelines | Microsoft Learn \n Stop going Agent going into idle and sleep state– Sometime agents goes into sleep state if there is no activity on agent and remains idle for specific period of time. We can configure the agent machine not to go into sleep mode. \n \n If everything seems to be perfectly alright with your agent and none of the steps mentioned in the Pipeline troubleshooting guide help, please report it on Developer Community where the Azure DevOps Team and DevOps community are actively answering questions. \n \n Continue Part 2 - Setup Azure DevOps Self Hosted Agent On-Premise & Troubleshooting Guidelines (microsoft.com) ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"8064","kudosSumWeight":0,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzUwMTU0LTQ0NDUxMGlDNzBBRjdERTgzMTg5MDJC?revision=2\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3712459":{"__typename":"Conversation","id":"conversation:3712459","topic":{"__typename":"BlogTopicMessage","uid":3712459},"lastPostingActivityTime":"2023-02-08T06:32:08.448-08:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=7","title":"azure_pipelines.jpg","associationType":"BODY","width":474,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMGkyNDdCMkU0MjZCOEYzODMz?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMGkyNDdCMkU0MjZCOEYzODMz?revision=7","title":"j_folberth_0-1673361392398.png","associationType":"BODY","width":902,"height":145,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMmk5RDY2NDI0RDI0MUI5RTk5?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMmk5RDY2NDI0RDI0MUI5RTk5?revision=7","title":"j_folberth_1-1673361392399.png","associationType":"BODY","width":963,"height":104,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMWk3OTE2MzAzRkFDQUIxQ0M1?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMWk3OTE2MzAzRkFDQUIxQ0M1?revision=7","title":"j_folberth_2-1673361392400.png","associationType":"BODY","width":464,"height":283,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwM2kxMjY0Njc5NzVFQzNDQ0RG?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwM2kxMjY0Njc5NzVFQzNDQ0RG?revision=7","title":"j_folberth_3-1673361392402.png","associationType":"BODY","width":468,"height":209,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNGk5RUIwMkZEODREODdBRDg1?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNGk5RUIwMkZEODREODdBRDg1?revision=7","title":"j_folberth_4-1673361392402.png","associationType":"BODY","width":395,"height":211,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNWk0N0NBOEY3NkFBQ0I4Q0VD?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNWk0N0NBOEY3NkFBQ0I4Q0VD?revision=7","title":"j_folberth_5-1673361392404.png","associationType":"BODY","width":1257,"height":678,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNmlBQjBCRDY3QzBEMzJBQjU1?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNmlBQjBCRDY3QzBEMzJBQjU1?revision=7","title":"j_folberth_6-1673361392405.png","associationType":"BODY","width":136,"height":218,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwN2k5QTg3RTZGMDgzODU5QTM3?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwN2k5QTg3RTZGMDgzODU5QTM3?revision=7","title":"j_folberth_7-1673361392406.png","associationType":"BODY","width":225,"height":293,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwOGk4OEQzOEY1MkFCQzI1RjFB?revision=7\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwOGk4OEQzOEY1MkFCQzI1RjFB?revision=7","title":"j_folberth_8-1673361392407.png","associationType":"BODY","width":254,"height":324,"altText":null},"BlogTopicMessage:message:3712459":{"__typename":"BlogTopicMessage","subject":"Azure DevOps Pipelines: Templates Tasks and Jobs","conversation":{"__ref":"Conversation:conversation:3712459"},"id":"message:3712459","revisionNum":7,"uid":3712459,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484035"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Fully leveraging the power of Azure DevOps (ADO) one should evaluate how to best use templates. This post focuses on using templates for tasks and jobs. Previous posts on Azure DevOps Pipelines: Environments and Variables (microsoft.com) and Azure DevOps Pipelines: Tasks, Jobs, Stages (microsoft.com) ","introduction":"","metrics":{"__typename":"MessageMetrics","views":27399},"postTime":"2023-01-10T06:57:20.941-08:00","lastPublishTime":"2023-02-08T06:32:08.448-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n \n Introduction \n By now if you have been following this series then you have learned about tasks, jobs, and stages in addition to variables and environments. This post will start to tie these together with templates. \n \n YAML templates provide Azure DevOps customers with the capabilities to quickly scale and deploy artifacts while following their organizations required steps securely and quickly. Templates are the ultimate goal in any DRY (Don’t Repeat Yourself) implementation of Azure DevOps Pipelines. \n \n In an effort not to overwhelm this post will cover task and job template design. To unlock how to use stage templates I have found it helpful to pair with YAML Object parameters. This will be a follow up post in this series as it can be a lot to take in. \n \n What Are Templates? \n Azure DevOps YAML templates are YAML files that can be reused including stages, jobs, tasks, and variables. If it helps think of a simple task, perhaps the DotNetCoreCLI task. For those unaware, this task can be used to build and publish a DotNetCore project, among other things. In this example we are going to use it to publish an artifact. \n \n Now a given code deployment may involve multiple projects. Without templates we’d have to code this task repeatedly for each project in the codebase. This provides a prime opportunity to use a template. We can define this task once and resue it by passing in various parameters for each project we would like to publish. \n \n In addition to increasing the readability of our pipeline YAML file, templates also help improve long term maintainability of our pipelines. Notice that this specific task is currently on version 2, this is evident with the @2 on the end of the task. Now whenever @3 is released, we need to only update the template file as opposed to manually updating each instance of the task across every repository that uses this task. \n \n To help illustrate this here is an example of leveraging the DotNetCoreCLI task both with and without templates: \n Without: \n \n \n With: \n Calling task within the job: \n \n \n Dotnetcore_cli_publish_task.yml \n \n \n The `../tasks/dotnetcore_cli_publish_task.yml` points to the location of the YAML template file. \n \n Design for Templating Up \n “Templating Up” is the methodology I use when designing and creating templates. The thought is to create a template on each basic step or task. Once all the task templates have been created, then create a job template calling all those tasks. Lastly create stage templates that will call the desired job templates. \n \n Tasks \n To illustrate this let’s build on the previous step where we have a task for publishing a dotnet project. What if we also require a specific version of the dotnet SDK to be installed on the agent? \n \n Similarly, we’d create a new file for the dotnet sdk task template. Perhaps it would look something like: \n \n dotnet_sdk_task.yml \n \n \n Let’s also do the same for a dotnet build task since publishing projects that don’t compile is something we usually try to avoid. \n \n dotnetcore_cli_task.yml \n \n \n The final step of a build process should be the publication of the artifacts to the ADO pipeline. This will ensure our tasks will produce a deployable artifact for future pipeline stages and jobs to consume. \n So now, if keeping track, we have the following steps to publish our project: \n \n Install required SDK \n Build Project via DotNetCoreCLI \n Publish Project via DotNetCoreCLI \n Publish Pipeline Artifact \n \n \n Jobs \n What we have here is a series of steps that can apply to any number of DotNetCore projects we have in our organization. As such the next step in templating up is to create a job template using these task templates. \n \n If you read my previous post on jobs, then we realize that the job is dispatched to an agent so if building and publishing multiple projects we can build/publish projects simultaneously on different agents all using the same template: \n \n dotnetcore_build_publish_job.yml \n \n \n \n This agent separation is key to understanding as it provides the opportunity to load a variable template scoped to the job. In this example we are not using them; however, the next post on YAML Objects with stages will heavily use these. \n \n If you haven’t noticed the solution specific arguments for these tasks have been abstracted as parameters, which provide flexibility. Things like the sdkversion and project name have been pulled out and made parameters, with defaulted values. This follows an 80/20 rule. The value for the parameter that is used 80% of the time should be the default. \n \n This allows future developers not to require all the inputs. If a parameter is required, I tend to default to ‘’. This will allow templates to expand and compile and if missing could create an error at task execution or produce an empty string. This is opposed to templates throwing errors on required parameters at pipeline compilation time. This then leads to trouble shooting through layers of templates. \n \n Storing and Naming Templates \n When dealing with YAML Templates an important question probably arises around where to store them and how to maintain them. This question isn’t that hard if we ask how we should store something that multiple repositories can use, has version control, and ability to be easily maintained. Microsoft recommends the answer to this being its own git repository. \n Pipelines can reference a repository like: \n \n \n \n \n repositories: \n - repository: templates \n type: git \n name: TheYAMLPipelineOne.git \n \n \n \n \n This reads as: \n \n repository: name of the repository local to the job \n type: what kind of repository is it \n name: what the name of the repository is, if in a different project provide project name in addition \n \n So then if we want to leverage a template in the repository it would look like: \n \n \n \n \n - template: jobs/dotnetcore_build_publish_job.yml@templates \n \n \n \n \n The @ sign is only required if referencing a file in a remote repository. If nesting templates in the same repository, a job that reference task template, do not use this as it will inadvertently build a name dependency since the template will attempt to resolve the repository at the named reference. \n \n So how to name them? Personally, I always adhere to a folder structure similar to: \n \n \n \n This ensures clear separation of what each template is scoped to. As for individual file names I usually go with something like technology_verb_templateType. So, in above dotnetcore(technology)_build_publish(verbs as to what it will do)_job(templateType). This again allows for quick identification of what the template is for and how to use it. \n \n Maintaining \n If we store these templates in a separate repository, then we need the ability to maintain changes in our deployment/build processes and tasks. This would best be accomplished via a branching strategy and testing with specifying which template repository branch to use. \n If interested check out my post on Selecting Source Branches for Pipelines which was featured in Top Stories from the Microsoft DevOps Community. \n \n Debugging \n When working with templates a common question is “How can I see my Pipeline YAML?”. It’s important to understand that the templates will expand at compilation time and ADO will create one YAML pipeline file with all the tasks, jobs, stages, and variables fully expanded. \n This can be downloaded by selecting the pipeline and “Download logs” \n \n \n \n This will download all your pipeline logs as a zip file. Once downloaded select “azure-pipelines-expanded.yml” file. \n \n \n \n This will load up the pipeline with all templates and variables expanded. For additional help in troubleshooting working with templates can check out my personal blog on What to do when Azure DevOps YAML Pipelines Fail. \n \n Conclusion \n At this point we have covered how to start designing and implementing Azure DevOps templates for tasks and jobs. This should be enough to get started; however, there is still a lot to master when keeping your pipelines DRY. Here is a follow up post with more information on how to template stages and leverage YAML objects. \n \n All artifacts that were shown here are available on GitHub TheYAMLPipelineOne ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"8987","kudosSumWeight":6,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMGkyNDdCMkU0MjZCOEYzODMz?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMmk5RDY2NDI0RDI0MUI5RTk5?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwMWk3OTE2MzAzRkFDQUIxQ0M1?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwM2kxMjY0Njc5NzVFQzNDQ0RG?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNGk5RUIwMkZEODREODdBRDg1?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNWk0N0NBOEY3NkFBQ0I4Q0VD?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwNmlBQjBCRDY3QzBEMzJBQjU1?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwN2k5QTg3RTZGMDgzODU5QTM3?revision=7\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDEw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzEyNDU5LTQzMTUwOGk4OEQzOEY1MkFCQzI1RjFB?revision=7\"}"}}],"totalCount":10,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3855524":{"__typename":"Conversation","id":"conversation:3855524","topic":{"__typename":"BlogTopicMessage","uid":3855524},"lastPostingActivityTime":"2024-02-21T02:26:18.182-08:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=11\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=11","title":"azure_pipelines.jpg","associationType":"BODY","width":474,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4MjY5MWkwMzgzRUVBNTBDOTRBRTA5?revision=11\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4MjY5MWkwMzgzRUVBNTBDOTRBRTA5?revision=11","title":"j_folberth_0-1687541015046.png","associationType":"BODY","width":224,"height":135,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4MjczOWlGMzIwRDhGOEUzN0RDNEE0?revision=11\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4MjczOWlGMzIwRDhGOEUzN0RDNEE0?revision=11","title":"j_folberth_0-1687550394168.png","associationType":"BODY","width":475,"height":458,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4Mjc0MGkwN0RBNDJFREU1Q0ZFRUFD?revision=11\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4Mjc0MGkwN0RBNDJFREU1Q0ZFRUFD?revision=11","title":"j_folberth_1-1687550449473.png","associationType":"BODY","width":506,"height":981,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4Mjc0MWlDOTM4NTU0MkFCOUUzQjI1?revision=11\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4Mjc0MWlDOTM4NTU0MkFCOUUzQjI1?revision=11","title":"j_folberth_2-1687550491032.png","associationType":"BODY","width":1615,"height":465,"altText":null},"BlogTopicMessage:message:3855524":{"__typename":"BlogTopicMessage","subject":"Azure DevOps Pipelines: Practices for Scaling Templates","conversation":{"__ref":"Conversation:conversation:3855524"},"id":"message:3855524","revisionNum":11,"uid":3855524,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484035"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" When starting to leverage YAML Pipelines at scale you are most likely going to gravitate towards a solution that leverages a consolidated template repository. Since we will have multiple pipelines calling the same repository it's important we get guidance on how to start and structure this new repository, so it scales with our organization and their pipeline adoption. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":20020},"postTime":"2023-07-17T09:02:00.178-07:00","lastPublishTime":"2023-07-24T06:40:54.738-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n Introduction \n This article is part of a larger series on Azure DevOps Pipelines regarding leveraging YAML templating. As part of this series, I have had numerous requests or questions around what is considered \"good practices\" when looking to leverage one repository consisting of YAML templates. \n \n Objective \n The objective on what we are trying to achieve is create a structure by which we can create a task, job, stage, or variable template once and let all of our pipelines reuse the code. The intent is to achieve the following outcome: \n \n Reduce pipeline creation time \n Ease maintenance of pipelines \n Provide an extra layer of security on who can create pipelines \n Consistently be able to deploy various apps in a similar fashion \n \n \n Template Expansion \n To best understand and architect a YAML pipeline via templates have to understand how the template expansion process works. When we go to run our Azure DevOps Pipeline it will collect all the YAML templates and associated files, variables, etc... and expand it into ONE file. This is the azure-pipeline-expanded.yml file which can be downloaded post a job completion. This is important to understand from architecture and troubleshooting perspective that we can see that one file is submitted to Azure DevOps. All parameters being passed in must be available at the pipeline compilation time. Runtime variables can be runtime variables and will be retrieved at pipeline execution. \n \n One Repository \n In order to help achieve these goals it is recommended to store of the templates in a dedicated Git repository. Azure DevOps pipelines support this functionality via the resources block. By doing this all of our pipelines can retrieve their templates from one consolidate location. In addition, by putting these in a separate repository we can introduce another layer of security on who can update this repo. \n \n Connecting to Single Replository \n When connecting to a single YAML repository one just needs to declare the repository reference like: \n \n \n \n \n \n \n resources:\n repositories:\n - repository: templates\n type: github\n name: JFolberth/TheYAMLPipelineOne\n endpoint: JFolberth \n \n \n \n \n \n \n Let's break down what each one of these actually means. \n \n \n \n \n \n \n resources:\n repositories:\n - repository: string # Required as first property. Alias for the repository.\n endpoint: string # ID of the service endpoint connecting to this repository.\n trigger: none | trigger | [ string ] # CI trigger for this repository, no CI trigger if skipped (only works for Azure Repos).\n name: string # repository name (format depends on 'type'; does not accept variables).\n ref: string # ref name to checkout; defaults to 'refs/heads/main'. The branch checked out by default whenever the resource trigger fires.\n type: string # Type of repository: git, github, githubenterprise, and bitbucket. \n \n \n \n \n \n \n Template Scope \n When creating templates for reuse one of the first thing one must decide is what is the scope of the template file? It is recommended that a template have a predefined scope and designed for one activity. At the most rudimental level a task template will consist on one task. No more. This ensures each individual component can be separately maintained and used when needed. When needing to do more then one task then we create a template for one job. One job will call one or multiple tasks. This ensures we wrap related tasks together. If multiple jobs are required, then we create a template for one stage that calls multiple job templates. \n \n Let's walk through a practical example of this leveraging the common steps of creating a build stage for a building a dotnet app: \n \n ensure proper dotnet SDK \n build dotnet app via DotNeCoreCLI \n publish dotnet app via DotNetCLICLI \n publish dotnet code via PublishPipelineArtifact \n \n These tasks would be chained together via a job and that job then would be contained in a stage. I recommend a separate file for each. That means if you are keeping count, we'd have one stage template file calling one job template file which calls four individual task template files. \n \n If your deployment footprint is small this may seem like a decent amount of overhead. However, I implore you to focus on just the PublishPipelineArtifact. This one task really is critical to any pipeline to publish an artifact as part of the pipeline execution. By templating it we can now insert this task into anyone pipeline. Even better say Microsoft updates the version of the task from v1 to v2. We can now change it in one file via one Pull Request and instantly all of our consuming pipelines get the updated. \n \n File Structure \n It is recommended that there is a folder per template type. This means that a consolidate repository for YAML templates would most likely look something like: \n \n If leveraging the intent that each template contains one instance of a stage, job, task, variable file this quickly becomes organized. \n \n Naming Convention \n Each organization may adopt this differently and this is just the pattern I have found to be successful. I typically name my YAML templates some format of technology_verb_scope.yml. \n \n I have found this helps with quickly identifying what technology the template is for, what it does, and lastly what it should be used for. \n Here is a quick example of some: \n adf_build_job.yml = Azure Data Factor Build Job Template \n zip_publish_job.yml = Zip files and publish them as an ADO Artifact Job Template \n bicep_deploy_stage.yml = Deploy Bicep files Stage Template \n azpwsh_file_execute_task.yml = Azure Power Shell execute a file Task Template \n node_install_template_task.yml = Install Node on the server Task Template \n azure_dev_variable.yml = Variables to be used for an Azure Dev Environment Template \n \n One thing I have learned the hard way is the file names are case sensitive. This is important and due to this I recommend just leaving them a lower case to avoid any confusion. \n \n Calling a template in a remote repository \n Once we have the connection to the remote repository defined, we need to be able to tell Azure DevOps what file to connect to. \n \n Here is an example where information is being passed into a bicep build stage template: \n \n \n \n \n \n \n parameters:\n- name: environmentObjects\n type: object\n default:\n - environmentName: 'dev'\n regionAbrvs: ['eus']\n - environmentName: 'tst'\n regionAbrvs: ['eus']\n- name: templateFileName\n type: string\n default: 'main'\n- name: templateDirectory\n type: string \n default: 'Infrastructure'\n- name: serviceName\n type: string\n default: 'adfdemo'\n\nstages:\n- template: stages/bicep_build_stage.yml@templates\n parameters:\n environmentObjects: ${{ parameters.environmentObjects }}\n templateFileName: ${{ parameters.templateFileName }}\n serviceName: ${{ parameters.serviceName }}\n templateDirectory: ${{ parameters.templateDirectory }} \n \n \n \n \n \n \n Notice that we tell Azure DevOps we want the stages/bicep_build_stage.yml file located in what we have called @templates. This is what we put in for the 'repository' value when defining the reference. This is an alias that only our local pipeline is aware of. \n \n Calling templates within templates \n When opening up the bicep_build_stage.yml file the template above is using we can see it will call a job template: \n \n \n \n \n \n \n parameters:\n- name: environmentObjects\n type: object\n default:\n - environmentName: 'dev'\n regionAbrvs: ['cus']\n- name: templateFileName\n type: string\n default: 'main'\n- name: templateDirectory\n type: string \n default: 'Infrastructure'\n- name: serviceName\n type: string\n default: 'SampleApp'\n\nstages:\n- stage: '${{ parameters.serviceName }}_build'\n jobs:\n - template: ../jobs/infrastructure_publish_job.yml\n parameters:\n targetPath: ${{ parameters.templateDirectory }}\n - ${{ each environmentObject in parameters.environmentObjects }} :\n - ${{ each regionAbrv in environmentObject.regionAbrvs }} :\n - template: ../jobs/bicep_whatif_env_job.yml\n parameters:\n environmentName: ${{ environmentObject.environmentName }}\n templateFileName: ${{ parameters.templateFileName }}\n templateDirectory: ${{ parameters.templateDirectory }}\n serviceName: ${{ parameters.serviceName }}\n regionAbrv: ${{ regionAbrv }}\n \n\n \n \n \n \n \n \n \n First notice when calling a nested template, we don't need the @templates. This is important as if we include this reference in here then our pipeline is dependent on finding that repository alias...even if we named it something different in our calling pipeline. The second thing to note here is we are calling the RELATIVE PATH of the YAML template repository. In our case this means up a folder from the stage folder and then locate the bicep_whatif_env_job.yml file under the jobs folder. \n \n Running Different Template Versions \n Perhaps you are making some changes and updates to the master template repository and need to test them out without impacting your production version. To accomplish this Azure DevOps let's you chose an easy way to change the branch version of your required resource templates. \n \n Within Azure DevOps select the pipeline to run and select Resources: \n \n This will load the repository resources in our resource block. Select the one your templates are located in. From there we can select which branch to use: \n \n \n When our pipeline runs, we can confirm the branch that is being used. \n \n \n Alternatively, we could also update the repository reference in our calling pipeline to point to a specific branch if it is more than a few minor changes. \n \n When to use Conditions and When to use Expressions \n This is from Azure DevOps Pipelines: If Expressions and Conditions and I am including here for consolidation of practices. \n \n Conditions should be leveraged when requiring to evaluate the status of something that has been ran or loaded into the template. Remember that if expressions will dynamically insert templates or variables into a pipeline. \n This means if expressions can only evaluate information that is static and available at time of task/job/stage execution. They will not know about which jobs have succeeded, failed or unaware of any variables that may have been created as part of a proceeding task/job/stage. \n \n My own personal pattern is to default leveraging if expressions first. This allows for a cleaner UI and a simpler approach when managing pipelines. This is due to only loading the necessary information into the pipeline vs load everything and evaluate as it goes. The flipside; however, is more complicated pipelines may require additional conditional operators and thus the condition attribute is more appropriate. \n \n Running Jobs in Parallel \n By default, Azure DevOps Pipeline jobs will run in parallel. This is extremely powerful and significantly impacts how jobs are structured. Think of a job as an isolated list of related steps to accomplish an end goal. There are times where we want to leverage parallel activities in the hopes of speeding up our CI/CD pipelines. \n \n One such example I commonly recommend is around Terraform. When running a Continuous Integration (CI) build against Terraform I recommend running a Terraform plan against all environments upon check in. For those unaware Terraform plan will output the list of changes Terraform will execute. When doing this in this matter each Terraform plan can be ran in a parallel against individual environments. This means we have one job running a Terraform plan against dev, one in uat, and one in production all simultaneously. The alternative is to run each sequentially which is only adds to our pipeline duration. And on that note.... \n \n Naming Stages and Jobs \n Stages and Jobs must have unique names. This is an important factor when scaling out your pipelines. As such I always recommend that the name of the stage or job has information that differentiates it from each other and is something that is calculated. Environment name is a good one to use. The environment name not only is a property of the job itself; however, can be used as part of the stage and job name. This creates a uniqueness for the job. To further emphasize this, I also leverage Azure region, if applicable. \n \n Here is an example of one such job name: \n \n \n \n \n \n \n \n jobs:\n- deployment: '${{ parameters.serviceName }}_app_${{ parameters.environmentName }}_${{ parameters.regionAbrv }}'\n environment: ${{ parameters.environmentName }} \n \n \n \n \n \n \n \n This is taken from an webapp deployment template. The fun thing is that these parameters can be reused in other jobs within the same stage or can even be used to create the dependent jobs name. \n \n Variable Scoping \n Coping variables is a big thing to consider as well when we talk through templating pipelines. A variable can be scoped at the root, stage, or job level. It is important to understand the variables value needs to either be set to runtime or be known prior to pipeline compilation. Again think of the pipeline expansion process. \n \n It is considered a good practice to scope the variables at the lowest level needed. This really is key when we are talking about reusing a deployment stage/job across multiple environments. Typically, this setup would be the same YAML is being ran with different variables being passed in. These variables can be loaded at the appropriate scope. \n \n Here is a piece of a Terraform apply job which is reusable and is dynamically loading in the variable information: \n \n \n \n \n \n \n \n jobs:\n- deployment: terraformApply${{ parameters.environmentName }}\n displayName: Terraform Apply ${{ parameters.environmentName }}\n variables: \n - template: ../variables/azure_terraform_${{ parameters.environmentName }}_variables.yml\n - name: commandOptions\n value: ''\n environment: ${{ parameters.environmentName }} \n \n \n \n \n \n \n \n For context we can have multiple environment files for terraform configuration information. Such as azure_terraform_dev_variables.yml and azure_terraform_tst_variables.yml. \n \n Both of these files could contain: \n \n \n \n \n \n \n \n variables:\n AzureSubscriptionServiceConnectionName: Example - Dev\n TerraformDirectory: Infrastructure\n TerraformStateStorageAccountContainerName: terraform-state\n TerraformStateStorageAccountName: satfdeveus \n TerraformStateStorageAccountResourceGroupName: rg-terraformState-dev-eus \n \n \n \n \n \n \n \n With the appropriate Azure environment information for each. We then could reference and pass this information on to a dependent task like: \n \n \n \n \n \n \n \n - template: ../tasks/terraform_init_task.yml\n parameters:\n serviceName: ${{ parameters.serviceName }}\n TerraformDirectory: $(Pipeline.Workspace)/${{ variables.TerraformDirectory }}\n AzureSubscriptionServiceConnectionName: ${{ variables.AzureSubscriptionServiceConnectionName }}\n TerraformStateStorageAccountResourceGroupName: ${{ variables.TerraformStateStorageAccountResourceGroupName }}\n TerraformStateStorageAccountName: ${{ variables.TerraformStateStorageAccountName }}\n TerraformStateStorageAccountContainerName: ${{ variables.TerraformStateStorageAccountContainerName }} \n \n \n \n \n \n \n Dependencies \n By it is important to understand that jobs by default will run in parallel and stages do not. A practice I have learned to assist in scaling and reusing jobs across stage templates is to provide the default value for this. The default is an empty string to denote no dependencies, one dependency is accepted as a string, and multiple dependencies is passed in as an object of strings. Since an object with one string has the same behavior and expansion behavior as an object with multiple strings, I would recommend defaulting the dependsOn object value to an empty object. \n \n This would look something like: \n \n \n \n \n \n \n \n parameters:\n- name: serviceName\n type: string\n default: ''\n- name: environmentName\n type: string\n- name: regionAbrv\n type: string\n default: ''\n- name: dependsOn\n type: object\n default: []\n\njobs:\n- deployment: 'docker_${{ parameters.serviceName }}_${{parameters.environmentName }}_${{ parameters.regionAbrv }}_buildandpush'\n environment: ${{ parameters.environmentName }}\n dependsOn: ${{ parameters.dependsOn }} \n \n \n \n \n \n \n \n This will allow this specific job to be reused by both stages that will require the job to have a dependency and ones that do not. And the best part is we won't have to go back and make a code change for this functionality since we already provided it in. \n \n Pipeline Decorators \n For those who could be wondering how to universally enforce and run a set of steps prior to pipeline execution that please check out pipeline decorators. \n \n When to use a decorator vs a template is going to vary based on use case; however, Microsoft documentation describes the following scenario: \n Pipeline decorators let you add steps to the beginning and end of every job. The process of authoring a pipeline decorator is different than adding steps to a single definition because it applies to all pipelines in an organization. \n \n Suppose your organization requires running a virus scanner on all build outputs that could be released. Pipeline authors don't need to remember to add that step. We create a decorator that automatically injects the step. Our pipeline decorator injects a custom task that does virus scanning at the end of every pipeline job \n \n If you or your organization curious on pipeline decorator's I'd encourage you to check out JinL99 post on \"Azure DevOps - Leveraging Pipeline Decorators for Custom Process Automation\" \n \n Conclusion \n When starting to leverage YAML Pipelines at scale you are most likely going to gravitate towards a solution that leverages a consolidated template repository. Since we will have multiple pipelines calling the same repository it's important we get guidance on how to start and structure this new repository, so it scales with our organization and their pipeline adoption. \n \n This post has covered how pipeline templates expand, the importance of understanding scope, provided a basic file structure and naming standard for organizational purposes, how to write, nest, maintain templates, scale jobs and stages, leverage variable templates, and when to use pipeline decorators. For additional resources check out additional HLS blog articles on YAML Pipeline Series , resources on my personal blog, and my GitHub TheYAMLPipelineOne which contains working template examples. \n \n This post help cover some important topics and practices that I have implemented as well as lessons learned in the hopes that they can help inspire and grow your organization's use of YAML pipelines. If you'd like to see how we use this approach in practice keep an eye out in the coming weeks on the series \"Unlock the Power of Azure Data Factory: A Guide to Boosting Your Data Ingestion Process\" by Joe_Fitzgerald and myself. \n \n If you have any feedback or questions, feel free to reach out or drop it in the comments. \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"20394","kudosSumWeight":6,"repliesCount":6,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=11\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4MjY5MWkwMzgzRUVBNTBDOTRBRTA5?revision=11\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4MjczOWlGMzIwRDhGOEUzN0RDNEE0?revision=11\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4Mjc0MGkwN0RBNDJFREU1Q0ZFRUFD?revision=11\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODU1NTI0LTQ4Mjc0MWlDOTM4NTU0MkFCOUUzQjI1?revision=11\"}"}}],"totalCount":5,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3737159":{"__typename":"Conversation","id":"conversation:3737159","topic":{"__typename":"BlogTopicMessage","uid":3737159},"lastPostingActivityTime":"2023-03-24T23:34:30.573-07:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=1","title":"azure_pipelines.jpg","associationType":"BODY","width":474,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQzOTg5Mmk5MzQxRjE2QjQ2MkZERjg0?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQzOTg5Mmk5MzQxRjE2QjQ2MkZERjg0?revision=1","title":"j_folberth_0-1675866908232.png","associationType":"BODY","width":1024,"height":152,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQzOTg5MWk0NEU1NTNBQ0M1QTJDRUE2?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQzOTg5MWk0NEU1NTNBQ0M1QTJDRUE2?revision=1","title":"j_folberth_1-1675866908233.png","associationType":"BODY","width":1087,"height":275,"altText":null},"BlogTopicMessage:message:3737159":{"__typename":"BlogTopicMessage","subject":"Azure DevOps Pipelines: If Expressions and Conditions","conversation":{"__ref":"Conversation:conversation:3737159"},"id":"message:3737159","revisionNum":1,"uid":3737159,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484035"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Within Azure DevOps there are multiple ways to run tasks/jobs/stages based on dynamic criteria. This article will compare and contrast leveraging if expressions and condition properties. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":19815},"postTime":"2023-02-08T06:48:05.047-08:00","lastPublishTime":"2023-02-08T06:48:05.047-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n \n Introduction \n At this stage in the series we’ve talked about tasks, jobs, stages, how to template them, and how to leverage environments in variables. This post will attempt to cover some basics around using if and conditions in your YAML Pipelines. \n \n For the full series check out the series on the Microsoft Health and Life Sciences Blog. \n \n If Expressions \n If expressions are simple and easy enough in YAML pipelines, they are a powerful tool. In my experience I have leveraged if expressions to: \n \n Conditionally load templates \n Dynamically load variables \n Enable same pipeline for CI/CD \n \n The key to unlocking their power is the understanding that an if expression will evaluate at pipeline compilation. This means the pipeline has to leverage known values to apply the logic within. We should not use an if expression when relying on the output of another task/job, the status of another job, or a variable that is updated during pipeline execution. \n \n The other side of this, since the statement is evaluated at pipeline compilation time, is that we will not load any unnecessary templates into our pipelines. As opposed to conditions, which will we cover next, templates will not appear in the expanded pipeline YAML file. This leads to a cleaner and more secure experience since only what will be executed will appear in the pipeline logs. \n \n One common scenario I leverage if statements in my YAML pipelines is for CI builds. Typically, I like to leverage the same pipeline for my CI as my CD. This means one pipeline that will only load deployment stages if the source branch is main. Feel free to switch this branch name for any condition your organization may like to use. The if expression for the outlined activity will leverage the built in variable ‘Build.SourceBranch’. \n \n stages: \n- template: stages/terraform_build_stage.yml@templates \n parameters: \n environmentObjects: ${{ parameters.environmentObjects }} \n templateFileName: ${{ parameters.templateFileName }} \n serviceName: ${{ parameters.serviceName }} \n- ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main')}}: \n - template: stages/terraform_apply_stage.yml@templates \n \n Here you can see we load a template for the Terraform Build stage every time the pipeline is triggered. However, only if the source branch is main will a deployment occur. This is opposed to a PR build whose source branch will be the branch the PR is based off of, thus only running the CI pieces. \n \n Here is an example illustrating the visual difference between a CI and a CD pipeline execution using the same definition that includes the if expression \n \n \n \n Conditions \n A condition is actually a key word defined in the schema of any stage, job, or step. It’s not always documented; however, it is available. \n \n Microsoft defines conditions as: \n You can specify the conditions under which each stage, job, or step runs. By default, a job or stage runs if it doesn't depend on any other job or stage, or if all of the jobs or stages it depends on have completed and succeeded. This includes not only direct dependencies, but their dependencies as well, computed recursively. By default, a step runs if nothing in its job has failed yet and the step immediately preceding it has finished. You can customize this behavior by forcing a stage, job, or step to run even if a previous dependency fails or by specifying a custom condition. \n \n An important piece to understand is that every stage, job, step has the condition field defaulted to succeeded(). This default condition is configured to be in place and references to the preceding stage/job/task. \n \n This is important to understand as any attempt override this condition, say add a condition to only run a task if the branch has a specific name pattern, will replace the succeeded() default. This would most likely have unintended consequences, so as a good practices if overwriting the condition one should include succeeded() to ensure the previous stage/job/task ran successfully prior to execution. \n \n I have an example of this that was featured in the Microsoft DevOps Community updates on Dynamically Retain Azure DevOps Pipelines. Essentially an optional stage that would run, if the pipeline went to the production stage, and attach a retention to the pipeline for auditing and rollback purposes. \n \n For visual purposes let’s look at the CI/CD pipeline and instead of using the if statement, let’s use a condition and see what happens: \n \n \n \n Since the stages loaded into the pipeline and the condition will be evaluated at pipeline execution, the condition wasn’t met, so the stages were skipped. Personally, I find this a bit of a headache, visually, to keep track of. I prefer not loading the stages/jobs/tasks if they won’t be needed. Additionally, one can download the pipeline logs and see what all was skipped. Again, this could lead to confusion. \n \n When to use each \n Conditions should be leveraged when requiring to evaluate the status of something that has been ran or loaded into the template. Remember that if expressions will dynamically insert templates or variables into a pipeline. \n This means if expressions can only evaluate information that is static and available at time of task/job/stage execution. They will not know about which jobs have succeeded, failed or unaware of any variables that may have been created as part of a proceeding task/job/stage. \n \n My own personal pattern is to default leveraging if expressions first. This allows for a cleaner UI and a simpler approach when managing pipelines. This is due to only loading the necessary information into the pipeline vs load everything and evaluate as it goes. The flipside; however, is more complicated pipelines may require additional conditional operators and thus the condition attribute is more appropriate. \n \n Conclusion \n Leveraging both if expressions and YAML conditions each have their place and benefit within Azure DevOps. They both can offer the ability to run/load a task/job/stage based on a given criteria. Thus, better utilizing pipelines in an organization's environment. \n \n For more information be sure to check out the rest of the series of blog posts. Also be sure to check out additional YAML code snippets on my GitHub TheYAMLPipelineOne ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"6672","kudosSumWeight":1,"repliesCount":1,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQzOTg5Mmk5MzQxRjE2QjQ2MkZERjg0?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM3MTU5LTQzOTg5MWk0NEU1NTNBQ0M1QTJDRUE2?revision=1\"}"}}],"totalCount":3,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3604759":{"__typename":"Conversation","id":"conversation:3604759","topic":{"__typename":"BlogTopicMessage","uid":3604759},"lastPostingActivityTime":"2025-02-24T07:42:22.081-08:00","solved":false},"User:user:1484034":{"__typename":"User","uid":1484034,"login":"Andrew_Redman","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0xNDg0MDM0LTM5NzQ2N2k4RERDOTBGQjIwRkQ0ODBE"},"id":"user:1484034"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1MmlCRjQ0QUVFMTIzMjQzRjE0?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1MmlCRjQ0QUVFMTIzMjQzRjE0?revision=6","title":"KeyVaultADOBlogImage.png","associationType":"TEASER","width":720,"height":405,"altText":"KeyVaultADOBlogImage.png"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1M2lDQjFCNDhGMzgwMTA3MTBB?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1M2lDQjFCNDhGMzgwMTA3MTBB?revision=6","title":"Andrew_Redman_0-1660940381688.png","associationType":"BODY","width":674,"height":392,"altText":"Andrew_Redman_0-1660940381688.png"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NGlGNUVFMkE1NkEwNzI2MkFE?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NGlGNUVFMkE1NkEwNzI2MkFE?revision=6","title":"Andrew_Redman_1-1660940381698.png","associationType":"BODY","width":1184,"height":346,"altText":"Andrew_Redman_1-1660940381698.png"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NWk2QjlBODk1NDExNUQ0Q0RD?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NWk2QjlBODk1NDExNUQ0Q0RD?revision=6","title":"Andrew_Redman_2-1660940381708.png","associationType":"BODY","width":1382,"height":462,"altText":"Andrew_Redman_2-1660940381708.png"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1OGkyMEEwQkU0MzUwNzAwNDc0?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1OGkyMEEwQkU0MzUwNzAwNDc0?revision=6","title":"Andrew_Redman_3-1660940381720.png","associationType":"BODY","width":1648,"height":144,"altText":"Andrew_Redman_3-1660940381720.png"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1N2k4QkZGODNEQjZGMEI5QzlE?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1N2k4QkZGODNEQjZGMEI5QzlE?revision=6","title":"Andrew_Redman_4-1660940381725.png","associationType":"BODY","width":878,"height":464,"altText":"Andrew_Redman_4-1660940381725.png"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NmlDNTE4NjlENUU5MkJGMjIy?revision=6\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NmlDNTE4NjlENUU5MkJGMjIy?revision=6","title":"Andrew_Redman_5-1660940381727.png","associationType":"BODY","width":1816,"height":148,"altText":"Andrew_Redman_5-1660940381727.png"},"BlogTopicMessage:message:3604759":{"__typename":"BlogTopicMessage","subject":"Getting secrets from Key Vault in YAML pipeline","conversation":{"__ref":"Conversation:conversation:3604759"},"id":"message:3604759","revisionNum":6,"uid":3604759,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484034"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" \n If you have ever created an Azure App Service or Azure Function App that uses app settings, then you have dealt with the problem of how you are going to get those settings secure and updated correctly in each environment. You need a secure location to store this information and then be able to access it during your deployment process. Azure Key Vault and using the Azure Key Vault task inside a deployment pipeline in Azure DevOps can solve this problem for you. If you prefer video, then have a look at this as it will walk you through the steps of getting this setup. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":15824},"postTime":"2022-08-19T14:02:24.643-07:00","lastPublishTime":"2025-02-24T07:42:22.081-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Keeping your connection strings and secrets secure is not necessarily only a concern of just one type of industry. The best practice would be to keep security at the top of your mind regardless of if you are working on an app for a company in the Healthcare space or Finance, Retail, etc….Azure Key Vault can help in doing just that. \n If you have ever created an Azure App Service or Azure Function App that uses app settings, then you have dealt with the problem of how you are going to get those settings secure and updated correctly in each environment. You need a secure location to store this information and then be able to access it during your deployment process. Azure Key Vault and using the Azure Key Vault task inside a deployment pipeline in Azure DevOps can solve this problem for you. If you prefer video, then have a look at this as it will walk you through the steps of getting this setup. \n \n What’s the problem? \n You want your code ‘bits’ to not have to worry about the configuration items that might change from environment to environment, so being a good developer, you have created variables to protect you from these changing values. Now how do you automate your deployment to consider these changing values? I’d like to suggest using the Azure Key Vault task yaml snippet as part of your yaml pipeline in Azure DevOps and here’s how you can use it. \n The Setup \n We have the following resources that we are using to demonstrate this setup. \n \n Azure Function (python, but can be any language) \n Key Vault \n YAML pipeline \n \n This GitHub repo is what we are going to be using as our example: \n If you look at the README.md it will give you a good feel for what the repo is doing, but we are going to zoom in to the Key Vault integration. \n Azure Function App \n You will need to make sure you have a function app created that you can use. There isn’t any special setup you need to do here other than to take note of the app settings that you want to set in your pipeline. \n Key Vault \n Again, you will need to make sure you have a key vault created in Azure to use and it will need to have at least one secret that you want to set as the app setting. You will also need to make sure that the service connection has Get and List permission in the Key Vaults Access policies. \n \n This is a good place to point out that an Azure Key Vault currently has 2 permission models: Vault access policy and Azure role-based access control (RBAC). The model used in this blog post and video is the Vault access policy, but it could also be accomplished with the RBAC approach. If you are interested in following the RBAC approach, please refer to this document. \n Azure-pipelines.yml pipeline \n All of the code is located in the GitHub repo listed above, but this pipeline file will need to be used in an Azure DevOps pipeline so you can kick it off to test this process. If you take a look at this file, you can see Azure Key Vault snippet and the parameters use. \n \n Here is a link to the document for the key vault yaml snippet. This code downloads all the secrets from the key vault that you specify. Once you have downloaded all the secrets you can use them throughout the pipeline as you would a typical variable using the key vault secret name as the variable name. See below we are using `blob-storage-connection-secret`. \n \n How to test \n To test this, you will just need to run the Azure DevOps pipeline that you created using the `azure-pipelines.yml` file. When that run completes, we can take a look at the output from the `Deploy Function App` step and you will see the following: \n \n The log confirms that your setting was updated and notice that the actual value it’s using to replace is obfuscated from the log to keep your secrets…well secret! Just to double check you can go out to the Azure portal, to the Function App and confirm the setting there. In our case we are looking for this key vault value to be put in the app settings: \n \n Key Vault -> Secret -> blob-storage-connection-secret \n \n \n Function App Service \n \n \n That’s it! Thanks for reading and/or watching. Please comment with any questions. \n \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"4378","kudosSumWeight":6,"repliesCount":4,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1MmlCRjQ0QUVFMTIzMjQzRjE0?revision=6\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1M2lDQjFCNDhGMzgwMTA3MTBB?revision=6\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NGlGNUVFMkE1NkEwNzI2MkFE?revision=6\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NWk2QjlBODk1NDExNUQ0Q0RD?revision=6\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1OGkyMEEwQkU0MzUwNzAwNDc0?revision=6\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1N2k4QkZGODNEQjZGMEI5QzlE?revision=6\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNjA0NzU5LTM5NzQ1NmlDNTE4NjlENUU5MkJGMjIy?revision=6\"}"}}],"totalCount":7,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[{"__typename":"VideoEdge","cursor":"MHxodHRwczovL3lvdXR1LmJlLy1nR3owWGh5S3pRfDB8MjU7MjV8fA","node":{"__typename":"AssociatedVideo","videoTag":{"__typename":"VideoTag","vid":"https://youtu.be/-gGz0XhyKzQ","thumbnail":"https://i.ytimg.com/vi/-gGz0XhyKzQ/hqdefault.jpg","uploading":false,"height":240,"width":320,"title":null},"videoAssociationType":"INLINE_BODY"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3719136":{"__typename":"Conversation","id":"conversation:3719136","topic":{"__typename":"BlogTopicMessage","uid":3719136},"lastPostingActivityTime":"2023-06-07T08:22:48.258-07:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=5","title":"azure_pipelines.jpg","associationType":"TEASER","width":474,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1OGlENUM0QjcyMTEyOTUyMEJG?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1OGlENUM0QjcyMTEyOTUyMEJG?revision=5","title":"j_folberth_0-1674058201941.png","associationType":"BODY","width":310,"height":134,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1Nmk4N0FCQkY2MTBDMEMxMkMw?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1Nmk4N0FCQkY2MTBDMEMxMkMw?revision=5","title":"j_folberth_1-1674058201942.png","associationType":"BODY","width":255,"height":193,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1N2lGRjEwN0NDQTBFODkxQ0NC?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1N2lGRjEwN0NDQTBFODkxQ0NC?revision=5","title":"j_folberth_2-1674058201943.png","associationType":"BODY","width":443,"height":59,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY2MGlBMTIwRTU4RUNBNTQzOTE0?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY2MGlBMTIwRTU4RUNBNTQzOTE0?revision=5","title":"j_folberth_3-1674058201944.png","associationType":"BODY","width":976,"height":263,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1OWkxOEUxRDg4MzAzQ0E3MTE3?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1OWkxOEUxRDg4MzAzQ0E3MTE3?revision=5","title":"j_folberth_4-1674058201945.png","associationType":"BODY","width":1000,"height":421,"altText":null},"BlogTopicMessage:message:3719136":{"__typename":"BlogTopicMessage","subject":"Azure DevOps Pipelines: Leveraging Stages with YAML Objects","conversation":{"__ref":"Conversation:conversation:3719136"},"id":"message:3719136","revisionNum":5,"uid":3719136,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1484035"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Post covers how to create YAML pipeline stage templates as well as an example on how to use Objects to unlock advanced functionality ","introduction":"","metrics":{"__typename":"MessageMetrics","views":13439},"postTime":"2023-01-24T06:43:37.864-08:00","lastPublishTime":"2023-02-08T06:31:21.497-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Introduction \n By now we’ve covered the basics on tasks, jobs, stages, environments, variables and templates for jobs and tasks. It is now time to move towards stage templates. Additionally, to assist with templating we will cover one way to leverage YAML objects which is a key tool when templating up and keeping your pipelines DRY (Don’t Repeat Yourself). \n \n To follow along I am leveraging non-ADO code in from Azure IaC Flavors and YAML templates from TheYAMLPipelineOne \n \n Stages \n Recapping from a pervious post, a stage is: \n Stages are the level above jobs. A stage is required; however, there is a default if one is not provided. A stage can contain one to many jobs and acts as a logical grouping of related jobs. \n \n An important component to understand is that Azure DevOps, out of the box, provide an easy way to rerun Pipelines at the stage level. This means our stages should be constructed with jobs that make sense to re-run together. Usually, customers want to naturally associate a stage with a customer environment. I'd advise fighting this temptation. \n \n Picking up on this notion, I tend to recommend a stage can be combination of app components (data, front end, infrastructure, etc..) and deployment target (region, virtual machine, etc..). By making this distinction it helps keep our stages scoped to an easily and targeted deployment path. \n \n When stopping to think about this our stages, specifically between a test and production environment, should be exactly the same minus the deployment target information and environment settings. Thus, they are a great candidate for templates. \n \n So why weren’t these covered in jobs and task templates in the previous article? Stages are the container that houses all of the deployment jobs. As such extra thought should be placed into how to architect these to scale out infinitely. It shouldn’t matter if I am deploying to one or twenty locations. They all should contain the same jobs, tasks, and appropriate variables. Deploying to one stage or two stages with the same template is easy....but how to do it for infinite possibilities? Enter YAML Objects. \n \n YAML Objects \n To Clarify YAML Objects can be used with more than just stages. Previously I have used YAML Objects to pass project specific configuration into a stage deploying multiple projects as one such example. Where each project has it's own specific information and the object is passed into a subsequent job. If you read through Azure DevOps documentation, there is mention of YAML Objects; which now includes an example. If wanting more focused on the topic check out my personal blog post on YAML Objects and Looping. \n \n For the purposes of this article, I am going to keep this as simple as I can. We will deal with just deploying Terraform to multiple environments and multiple regions. My warning is a better practice would be to deploy Infrastructure as Code and any application code together. There are strong opinions of this; however, I am of the camp you shouldn’t have one without the other so they should be stored, managed and deployed together. \n \n Here is my parameter which will be passed into the stage template: \n \n \n Essentially, we have an environment, this will match the environment name defined in Azure DevOps. I can’t state this enough that a consistent naming pattern across all aspects gives you the freedom to define one variable and build the rest. \n \n I even take this down to the Terraform variable file names: \n \n \n A quick disclaimer as someone keen would say why you need region-specific parameters? Good question, in this case assume you may have a primary region that has different load requirements than a secondary. \n \n The important concept here with working with templates is passing in the YAML Object to the stage template. The logic for looping and creating all the individual stages is actually handled by the template. Remember that the YAML pipeline will fully expand when submitted to Azure DevOps for execution. \n \n To call the stage template will look like: \n \n \n serviceName name is used to help define the Terraform state file as well as provide names to the stages and jobs. The key thing to recognize here is the passing of the entire environmentObjects block. This will include the configuration for all the environments and regions. The next step is to take that information and loop through the environmentObjects data creating the appropriate stages. For this purpose, keep in mind we need to loop not only for environments; however, regions as well. \n \n \n \n Something to consider is the `stages` keyword appears in both the template and the calling pipeline. This true of any templates and I link to think of it as the key word marker that the template will load into. \n \n The first loop here is to go through all the environmentObjects, in this case ‘dev’ and ‘tst’. Once inside the instance of the object need to loop through all the regionAbrv values in the regionAbrv array. Notice though that these each loops are being called prior to the actual stage creation. This is the key to making the number of stages dynamic. Since YAML will fully expand at execution it will determine and pull in the appropriate stages at that time. \n \n Something to consider when dealing with any type of dynamic template insertion is the stage name must be unique across the pipeline and the jobs must be unique in the same stage. Because of this it is important to build a name that relies on the individual components of the loop. This ensures that there is no class of two stages or jobs having the same name. \n \n The next step here is using logic to determine variable assignment. I realize this is a bit tricky and honestly probably one of the more confusing parts on this post. The thought process behind this is if we are fanning out to x number of stages then we need to be able to track dependencies. By default, stages are dependent on each other in sequential order. \n \n Well in this scenario I’d like all the tst jobs depend on completion of all the dev jobs. Jobs in dev should realistically be dependent on the build stage, which in this case due to a strict naming convention we know what the name of that build stage will be. As such if no dependency is being passed in then we will assign the build stage as the dependency. There will be a follow up post on using if statements in YAML pipelines later in the series. \n \n Once we get through this our pipeline execution plan will look like: \n \n \n Conclusion \n This is not an easy topic and deals with a lot of advanced concepts when not only creating your pipelines; however, even more when starting to think how templatize them. If done properly the possibilities of scale can be limitless. \n \n Hopefully this post provided just one-use case on how to leverage YAML templates at the stage level coupled with using YAML Objects. For recap of material feel free to check out Templates Tasks and Jobs, Environments and Variables, or Tasks, Jobs, Stages. \n \n Also, some other resources to check out are these repos on Azure IaC Flavors and TheYamlPipelineOne ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7499","kudosSumWeight":2,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQyNjEyOGk2MEEyMUQzMURGQTM1M0Uy?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1OGlENUM0QjcyMTEyOTUyMEJG?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1Nmk4N0FCQkY2MTBDMEMxMkMw?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1N2lGRjEwN0NDQTBFODkxQ0NC?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY2MGlBMTIwRTU4RUNBNTQzOTE0?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzE5MTM2LTQzMzY1OWkxOEUxRDg4MzAzQ0E3MTE3?revision=5\"}"}}],"totalCount":6,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3738791":{"__typename":"Conversation","id":"conversation:3738791","topic":{"__typename":"BlogTopicMessage","uid":3738791},"lastPostingActivityTime":"2025-03-24T03:11:50.343-07:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4MWlENDAwNjRFRDExNTYxM0ZD?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4MWlENDAwNjRFRDExNTYxM0ZD?revision=3","title":"1P.png","associationType":"BODY","width":780,"height":264,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4MmkwRUUxNkRFQkMwMjFDOTg2?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4MmkwRUUxNkRFQkMwMjFDOTg2?revision=3","title":"2P.png","associationType":"BODY","width":780,"height":537,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NGkwMkU1RDA1MzI5NTVCOTUx?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NGkwMkU1RDA1MzI5NTVCOTUx?revision=3","title":"3P.png","associationType":"BODY","width":780,"height":297,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NWk5QjBCMjk1NTUzOUEyMjEw?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NWk5QjBCMjk1NTUzOUEyMjEw?revision=3","title":"4P.png","associationType":"BODY","width":780,"height":362,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NmkwNTc3NkZDNUE5NTE5RTQ1?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NmkwNTc3NkZDNUE5NTE5RTQ1?revision=3","title":"5P.png","associationType":"BODY","width":780,"height":422,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4N2kwMEU0OUU2MjFEQTUyOTdC?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4N2kwMEU0OUU2MjFEQTUyOTdC?revision=3","title":"6P.png","associationType":"BODY","width":780,"height":757,"altText":null},"BlogTopicMessage:message:3738791":{"__typename":"BlogTopicMessage","subject":"Repository graphs in Azure DevOps","conversation":{"__ref":"Conversation:conversation:3738791"},"id":"message:3738791","revisionNum":3,"uid":3738791,"depth":0,"board":{"__ref":"Blog:board:HealthcareAndLifeSciencesBlog"},"author":{"__ref":"User:user:1676800"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" If you working with GitHub, you must be aware that repository insights graph is available in public & private repositories and if you are looking for similar feature under Azure DevOps. This article will help you to achive the same functionality in Azure DevOps. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":13122},"postTime":"2023-02-09T15:10:24.349-08:00","lastPublishTime":"2023-02-09T15:45:01.480-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" If you working with GitHub, you must be aware that repository insights graph is available in public repositories (as shown below) with GitHub Free and GitHub Free for organizations, and in public and private repositories with GitHub Pro, GitHub Team, GitHub Enterprise Cloud, and GitHub Enterprise Server. \n \n \n \n Basically repository's graphs give you information on traffic, projects that depend on the repository, contributors and commits to the repository, and a repository's forks and network. If you maintain a repository, you can use this data to get a better understanding of who's using your repository and why they're using it. But unfortunately this features not available in Azure DevOps and developer community looking the same feature under Azure DevOps. Lets begin with following customer scenario. \n \n Suppose you have several repositories in Azure DevOps. In my dashboard, in the project stats I can see that there were X commits by Y authors (for the last 7 days), but, I cannot click on this to get more details. How can I get the list or overview of who committed what on the repos for the last X days? \n \n If above ask were about for single repository we can simply use following command at CLI. \n \n git shortlog --since=\"7 days ago\" \n It would output a list sorted by author, like this \n \n Vinod Soni (3):\n Commit message foo\n Commit message bar\n Commit message baz\n \nMahima Soni (1):\n Commit message abc\n \n Of course, above is only the default format, but you could as well use --format=<format> to specify how each commit should be displayed. \n \n We can also use the Git UI to visualize the history (as shown in below screenshot) but our customer ask is for multiple repositories in the Azure DevOps project. In other words they wanted to see over all repos in one request. \n \n \n \n \n \n \n \n \n \n \n \n I found the Contributions Graph extension for Azure DevOps which allows you to see who did what for different repositories. Works really nice! We can install it from Visual Studio marketplace or above link. It’s free to use and we don’t have to pay anything additional. Below are some standard steps to configure it for our Azure DevOps organization. \n \n Step 1: Go to Link Contributions Graph \n \n \n \n \n \n \n \n \n \n \n \n Step 2: Click on Get it free option and select your target Azure DevOps organization then select Download. It may take few minutes to install. \n \n \n \n \n \n \n \n \n \n \n \n Step 3: Login to Azure DevOps then go to your organization. Go to Boards and you will find the Contribution graph is installed (as shown in below screenshot). \n \n \n \n \n \n \n \n \n \n \n You can apply filer as per your requirement and include multiple repositories, authors in filter criteria as shown in below screenshot. \n \n \n \n \n \n \n \n \n \n \n If you have any question answer and look any issue please visit publisher's GitHub repository for extension related questions. You can view the GitHub repository readme file for more information and detailed documentation. \n \n Hope this will help you to achieve the similar functionality available in GitHub. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"3402","kudosSumWeight":3,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4MWlENDAwNjRFRDExNTYxM0ZD?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4MmkwRUUxNkRFQkMwMjFDOTg2?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NGkwMkU1RDA1MzI5NTVCOTUx?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NWk5QjBCMjk1NTUzOUEyMjEw?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4NmkwNTc3NkZDNUE5NTE5RTQ1?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuM3wyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zNzM4NzkxLTQ0MDQ4N2kwMEU0OUU2MjFEQTUyOTdC?revision=3\"}"}}],"totalCount":6,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"CachedAsset:text:en_US-components/community/Navbar-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1745505307000","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","gxcuf89792":"Tech Community","external-1":"Events","s-m-b":"Nonprofit Community","windows-server":"Windows Server","education-sector":"Education Sector","driving-adoption":"Driving Adoption","Common-content_management-link":"Content Management","microsoft-learn":"Microsoft Learn","s-q-l-server":"Content Management","partner-community":"Microsoft Partner Community","microsoft365":"Microsoft 365","external-9":".NET","external-8":"Teams","external-7":"Github","products-services":"Products","external-6":"Power Platform","communities-1":"Topics","external-5":"Microsoft Security","planner":"Outlook","external-4":"Microsoft 365","external-3":"Dynamics 365","azure":"Azure","healthcare-and-life-sciences":"Healthcare and Life Sciences","external-2":"Azure","microsoft-mechanics":"Microsoft Mechanics","microsoft-learn-1":"Community","external-10":"Learning Room Directory","microsoft-learn-blog":"Blog","windows":"Windows","i-t-ops-talk":"ITOps Talk","external-link-1":"View All","microsoft-securityand-compliance":"Microsoft Security","public-sector":"Public Sector","community-info-center":"Lounge","external-link-2":"View All","microsoft-teams":"Microsoft Teams","external":"Blogs","microsoft-endpoint-manager":"Microsoft Intune","startupsat-microsoft":"Startups at Microsoft","exchange":"Exchange","a-i":"AI and Machine Learning","io-t":"Internet of Things (IoT)","Common-microsoft365-copilot-link":"Microsoft 365 Copilot","outlook":"Microsoft 365 Copilot","external-link":"Community Hubs","communities":"Products"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1745505307000","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1745505307000","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1745505307000","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1745505307000","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1745505307000","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagSubscriptionAction-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagSubscriptionAction-1745505307000","value":{"success.follow.title":"Following Tag","success.unfollow.title":"Unfollowed Tag","success.follow.message.followAcrossCommunity":"You will be notified when this tag is used anywhere across the community","success.unfollowtag.message":"You will no longer be notified when this tag is used anywhere in this place","success.unfollowtagAcrossCommunity.message":"You will no longer be notified when this tag is used anywhere across the community","unexpected.error.title":"Error - Action Failed","unexpected.error.message":"An unidentified problem occurred during the action you took. Please try again later.","buttonTitle":"{isSubscribed, select, true {Unfollow} false {Follow} other{}}","unfollow":"Unfollow"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1745505307000","value":{"title":"Query Handler"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1745505307000","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListTabs-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListTabs-1745505307000","value":{"mostKudoed":"{value, select, IDEA {Most Votes} other {Most Likes}}","mostReplies":"Most Replies","mostViewed":"Most Viewed","newest":"{value, select, IDEA {Newest Ideas} OCCASION {Newest Events} other {Newest Topics}}","newestOccasions":"Newest Events","mostRecent":"Most Recent","noReplies":"No Replies Yet","noSolutions":"No Solutions Yet","solutions":"Solutions","mostRecentUserContent":"Most Recent","trending":"Trending","draft":"Drafts","spam":"Spam","abuse":"Abuse","moderation":"Moderation","tags":"Tags","PAST":"Past","UPCOMING":"Upcoming","sortBymostRecent":"Sort By Most Recent","sortBymostRecentUserContent":"Sort By Most Recent","sortBymostKudoed":"Sort By Most Likes","sortBymostReplies":"Sort By Most Replies","sortBymostViewed":"Sort By Most Viewed","sortBynewest":"Sort By Newest Topics","sortBynewestOccasions":"Sort By Newest Events","otherTabs":" Messages list in the {tab} for {conversationStyle}","guides":"Guides","archives":"Archives"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewInline-1745505307000","value":{"bylineAuthor":"{bylineAuthor}","bylineBoard":"{bylineBoard}","anonymous":"Anonymous","place":"Place {bylineBoard}","gotoParent":"Go to parent {name}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Pager/PagerLoadMore-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Pager/PagerLoadMore-1745505307000","value":{"loadMore":"Show More"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/OverflowNav-1745505307000","value":{"toggleText":"More"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1745505307000","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1745505307000","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1745505307000","value":{"postTime":"Published: {time}","lastPublishTime":"Last Update: {time}","conversation.lastPostingActivityTime":"Last posting activity time: {time}","conversation.lastPostTime":"Last post time: {time}","moderationData.rejectTime":"Rejected time: {time}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1745505307000","value":{"contentType":"Content Type {style, select, FORUM {Forum} BLOG {Blog} TKB {Knowledge Base} IDEA {Ideas} OCCASION {Events} other {}} icon"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageUnreadCount-1745505307000","value":{"unread":"{count} unread","comments":"{count, plural, one { unread comment} other{ unread comments}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageViewCount-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageViewCount-1745505307000","value":{"textTitle":"{count, plural,one {View} other{Views}}","views":"{count, plural, one{View} other{Views}}"},"localOverride":false},"CachedAsset:text:en_US-components/kudos/KudosCount-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/kudos/KudosCount-1745505307000","value":{"textTitle":"{count, plural,one {{messageType, select, IDEA{Vote} other{Like}}} other{{messageType, select, IDEA{Votes} other{Likes}}}}","likes":"{count, plural, one{like} other{likes}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRepliesCount-1745505307000","value":{"textTitle":"{count, plural,one {{conversationStyle, select, IDEA{Comment} OCCASION{Comment} other{Reply}}} other{{conversationStyle, select, IDEA{Comments} OCCASION{Comments} other{Replies}}}}","comments":"{count, plural, one{Comment} other{Comments}}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1745505307000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1745505307000","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false}}}},"page":"/tags/TagPage/TagPage","query":{"messages.widget.messagelistfornodebyrecentactivitywidget-tab-main-messages-list-for-tag-widget-0":"mostViewed","nodeId":"category:HealthcareAndLifeSciences","tagName":"Azure DevOps"},"buildId":"-gVUpXaWnPcjlrLJZ92B7","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"o365","openTelemetryServiceVersion":"25.3.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false,"inboxMuteWipFeatureEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/customComponent/CustomComponent/CustomComponent.tsx","./components/tags/TagsHeaderWidget/TagsHeaderWidget.tsx","./components/messages/MessageListForNodeByRecentActivityWidget/MessageListForNodeByRecentActivityWidget.tsx","./components/tags/TagSubscriptionAction/TagSubscriptionAction.tsx","./components/external/components/ExternalComponent.tsx","./components/customComponent/CustomComponentContent/TemplateContent.tsx","../shared/client/components/common/List/ListGroup/ListGroup.tsx","./components/messages/MessageView/MessageView.tsx","./components/messages/MessageView/MessageViewInline/MessageViewInline.tsx","../shared/client/components/common/Pager/PagerLoadMore/PagerLoadMore.tsx"],"appGip":true,"scriptLoader":[{"id":"analytics","src":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/pagescripts/1730819800000/analytics.js?page.id=TagPage","strategy":"afterInteractive"}]}