.author{grid-column:1;grid-row:3;align-content:flex-start}.Metadata_root__oCstk>.description,.Metadata_root__oCstk>.pills-list,.Metadata_root__oCstk>.stats,.Metadata_root__oCstk>.title{grid-column:1/span 2}.Metadata_root__oCstk>.title{margin-bottom:8px}.Metadata_root__oCstk>.stats{margin-bottom:12px}.Metadata_root__oCstk>.description{margin-top:12px}.Metadata_root__oCstk>.pills-list{margin-block-start:20px;margin-block-end:18px}.Metadata_root__oCstk>.actions{display:none}@media screen and (max-width:928px){.Metadata_root__oCstk{margin-block:8px 20px}.Metadata_root__oCstk>.stats{margin-bottom:16px}.Metadata_root__oCstk>.description{margin-top:0}.Metadata_root__oCstk>.author{grid-column:2;grid-row:5;margin-block-start:12px;margin-block-end:6px;justify-content:end}.Metadata_root__oCstk>.actions{display:flex;margin-top:16px;grid-column:1;grid-row:5}.Metadata_root__oCstk>.pills-list{margin-block-start:16px;margin-block-end:0}}.Metadata_root__oCstk .metadata-recs{grid-column:1/-1}.Heading_heading__3MAvZ{color:var(--blue-gray-900)}.Heading_h1__3k7S2{font-size:32px;font-weight:700}.Heading_h2__f9yvs{font-size:28px;font-weight:600}.Heading_h3__f1djd{font-size:24px}.Heading_h4__7tfLE{font-size:20px}.Heading_h5__jVM0l{font-size:16px;font-weight:400}.Heading_h6__uUTrd{font-size:14px;font-weight:400}.Title_root__svkHQ{color:var(--blue-gray-900);font-size:clamp(26px,1vw + 1rem,28px);font-weight:600;line-height:1.25;min-width:0;word-break:break-word}.Stats_root__p_BoZ{flex-wrap:wrap;display:flex;align-items:center;-moz-column-gap:6px;column-gap:6px;color:var(--blue-gray-600);white-space:nowrap;font-size:16px}.Stats_leftContent__588PR,.Stats_rightContent__8d0AF{display:flex;gap:6px}.Stats_root__p_BoZ span{font-size:16px}.Stats_root__p_BoZ .Stats_aiTag__zTzW8{margin-left:10px}@media screen and (max-width:928px){.Stats_root__p_BoZ span{line-height:1.5}.Stats_root__p_BoZ.Stats_extendedMetadata__wb62p .Stats_leftContent__588PR{width:100%}.Stats_root__p_BoZ .Stats_aiTag__zTzW8{margin:8px 0 0}.Stats_root__p_BoZ.Stats_extendedMetadata__wb62p .Stats_formatTypesBullet__xDv0L{display:none}}.Likes_root__WVQ1_{cursor:pointer;transition:color .2s ease-in-out;border-radius:4px}.Likes_root__WVQ1_:hover{color:var(--blue-gray-700)}.Tooltip_root__7FS0Y{background:var(--midnight-green-dark);border-radius:4px;box-shadow:0 .5px 5px rgba(0,0,0,.04),0 4px 11px rgba(0,0,0,.2);color:var(--white);font-weight:400;font-size:12px;line-height:15px;padding:6px 8px;opacity:0;visibility:hidden;animation:Tooltip_show__qVG5k .2s ease-in-out forwards;z-index:var(--popup-index)}.Tooltip_triggerWrapper___S2HG{flex-shrink:0;position:relative;align-items:center;justify-content:center}@keyframes Tooltip_show__qVG5k{to{opacity:1;visibility:visible}}.Tooltip_large__J4Fvl{padding:16px;display:flex;flex-direction:column;background:#fff;color:var(--black)}.AITag_tag__Xx37c{padding:0 12px;height:25px;border-radius:16px;background-color:#f0f2f9;color:#16171b;display:inline-flex;gap:8px;font-size:14px;line-height:1.5;font-weight:600}.AITag_tooltipContent__7JZR_{width:332px}.Author_root___6Bx5{--link-color:var(--blue-gray-800);position:relative;display:flex;align-items:center;gap:8px}.Author_link___lVxw{z-index:1;color:var(--link-color);font-weight:600;display:block}.Author_link___lVxw:before{content:"";position:absolute;inset:0}.Author_follow__Lw4TS{z-index:1}@media screen and (max-width:928px){.Author_link___lVxw:hover{color:var(--blue-gray-800)}}.Avatar_root__GNWHY{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;background-color:var(--white);color:var(--blue-gray-300);border-radius:50%;font-size:16px;font-weight:600;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none;overflow:hidden}.Avatar_initials__EJfVt{color:var(--white);transition:background-color .2s ease-in-out}.Avatar_initials__EJfVt,.Avatar_initials__EJfVt:hover{background-color:var(--blue-gray-600)}.Avatar_image__Bbtll{width:100%;height:100%;-o-object-fit:cover;object-fit:cover}.FollowButton_root__FxpBi{display:inline-flex;background-color:transparent;border:1px solid transparent;border-radius:4px;font-size:12px;padding:1px 6px;transition:background-color .2s ease-in-out,border-color .2s ease-in-out;cursor:pointer}.FollowButton_following__xKCww{border-color:#bf5905;color:#bf5905}.FollowButton_following__xKCww:hover{background-color:#ffead7;border-color:rgba(191,89,5,.5)}.FollowButton_follow__d_6u5{border-color:var(--celadon-blue-dark);color:var(--celadon-blue-dark)}.FollowButton_follow__d_6u5:hover{background-color:#eaf7ff;border-color:rgba(2,126,176,.5)}@media screen and (max-width:928px){.FollowButton_root__FxpBi{display:none}}.Description_root__kt4uq{--line-height:26px;position:relative}.Description_root__kt4uq.Description_clamped__PaV_1{padding-bottom:25px}.Description_root__kt4uq.Description_clamped__PaV_1 .Description_wrapper__hYE9_{mask-image:linear-gradient(to bottom,var(--white),transparent);-webkit-mask-image:linear-gradient(to bottom,var(--white),transparent)}.Description_wrapper__hYE9_{min-height:var(--line-height);display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:2}.Description_noClamp__1z7c5,.Description_wrapper__hYE9_.Description_expanded__lRamt{-webkit-line-clamp:unset;-webkit-mask-image:none;mask-image:none}.Description_wrapper__hYE9_.Description_expanded__lRamt{height:auto}.Description_wrapper__hYE9_ p{color:var(--blue-gray-600);font-size:18px;line-height:var(--line-height);white-space:pre-wrap;word-break:break-word}.Description_more__ChrRK{position:absolute;padding:0;bottom:0;height:26px}.Description_less__BvWbY{padding:0}.Description_hidden__a9QZJ{display:none}@media screen and (max-width:928px){.Description_more__ChrRK{right:0;background-color:#fff}.Description_root__kt4uq.Description_clamped__PaV_1{padding-bottom:0}.Description_less__BvWbY,.Description_more__ChrRK{height:var(--line-height)}}.PillsList_root__2EydN{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.Pill_root__IqOYH{--bg:color-mix(in srgb,var(--celadon-blue-dark),90% transparent);--color:var(--blue-gray-800);height:40px;display:inline-flex;align-items:center;gap:6px;background-color:var(--bg);border-radius:100vmax;color:var(--color);font-size:16px;font-weight:600;padding-inline:16px;transition:color .2s ease-in-out,background-color .2s ease-in-out,filter .2s ease-in-out;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;text-decoration:none;white-space:nowrap}.Pill_root__IqOYH:not(.Pill_selected__VPtHm):hover{filter:brightness(.6)}.Pill_root__IqOYH.Pill_selected__VPtHm{--bg:var(--blue-gray-900);--color:var(--white)}@media screen and (max-width:520px){.Pill_root__IqOYH{height:28px;padding-inline:12px;gap:4px;font-size:12px}.Pill_icon__xE_Cg{--size:18px!important}}.Actions_root__00yIC{display:flex;align-items:baseline;gap:6px}.ReadingModeTooltip_root__laf5h{width:277px}.ToggleButtonGroup_root__vtGE_{display:inline-flex;gap:4px;padding:5px 8px;border-radius:4px;background-color:var(--white);border:1px solid var(--blue-gray-200)}.ToggleButton_root__jGx6U{border-radius:4px;background-color:var(--white);color:var(--blue-gray-700);border:none;width:44px;height:34px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.ToggleButton_selected__51g6d{background-color:var(--blue-gray-200)}.SaveLoggedIn_icon__lk74r{color:var(--blue-gray-700)}.PopoverMenuContent_root__MsRtR{background:var(--white);box-shadow:0 .5px 5px rgba(0,0,0,.04),0 4px 11px rgba(0,0,0,.2);border-radius:4px;opacity:0;visibility:hidden;transition:opacity .2s ease-in-out,visibility .2s ease-in-out;z-index:1000;overflow-y:auto}.PopoverMenuContent_root__MsRtR.PopoverMenuContent_visible__O86I_{opacity:1;visibility:visible;transition-delay:0s}.PopoverMenuItem_item__iazpP{width:100%;display:flex;align-items:center;background-color:transparent;color:inherit;cursor:pointer;font-size:inherit;line-height:24px;padding:12px 16px;white-space:nowrap}.PopoverMenuItem_item__iazpP.PopoverMenuItem_highlight__inbqK,.PopoverMenuItem_item__iazpP:hover{background-color:var(--blue-gray-100)}.PopoverMenuSeparator_separator__UpSGw{width:calc(100% - 32px);height:1px;background-color:var(--blue-gray-300);margin:8px 16px}.SavePopover_popover__mZhIY{width:290px;max-height:220px;color:var(--blue-gray-800);font-weight:400;padding:6px 8px;font-size:12px;line-height:15px;overflow:hidden}.SavePopover_saveToNewList__MVBSu{display:flex;align-items:center;gap:6px;color:var(--midnight-green-dark);font-weight:600;font-size:18px;line-height:24px;padding:10px;width:100%}.SavePopover_addIcon__aJLJ3{color:var(--blue-gray-800)}.SavePopover_horizontalSeparator__bsI6Y{border:none;border-bottom:1px solid var(--blue-gray-300);margin:8px 0}.SavePopover_listsContainer__tGGtp{height:100%;max-height:144px;display:flex;flex-direction:column;align-items:center;overflow-y:auto}.SavePopover_saveToList__Fsfl9{color:var(--blue-gray-800);font-weight:400;font-size:16px;justify-content:space-between;line-height:24px;padding:12px 14px 12px 16px;width:100%}.SavePopover_saveToList__Fsfl9 span:not(.SavePopover_clampLines__Blxtm){display:flex;flex-direction:row;gap:35px;justify-content:space-between}.SavePopover_saveToList__Fsfl9 span.SavePopover_clampLines__Blxtm{display:inline-block;overflow:hidden;text-align:left;text-overflow:ellipsis;white-space:nowrap;width:180px}.SavePopover_listIcon__OVsXv{color:var(--blue-gray-900)}.SavePopover_noSavedLists__0Mh_H{color:var(--blue-gray-600);font-weight:400;font-size:16px;line-height:24px;padding:12px 16px;text-align:center}.SaveOptionsDrawer_drawerTrigger__Gb7nK{box-shadow:none;border:none;border-radius:4px;position:relative;z-index:7}.SaveOptionsDrawer_drawerTrigger__Gb7nK:active,.SaveOptionsDrawer_drawerTrigger__Gb7nK:active:focus,.SaveOptionsDrawer_drawerTrigger__Gb7nK:hover{border:none;box-shadow:none;background-color:transparent}.SaveOptionsDrawer_drawerTrigger__Gb7nK:focus{background:transparent}.SaveOptionsDrawerContent_drawerContent__J5JTL{margin:16px}.SaveOptionsDrawerContent_separator__UW5Rz{margin:8px 0}.SaveOptionsDrawerContent_itemsContainer__tCXw5{display:flex;flex-direction:column;margin-top:0;max-height:144px;overflow-y:auto}.SaveOptionsDrawerContent_drawerActionSecondary__7cq8j{font-weight:400;line-height:24px;padding:0 8px;margin:8px 0;width:100%}.SaveOptionsDrawerContent_drawerActionSecondary__7cq8j span{color:var(--blue-gray-800);justify-content:space-between;gap:30px}.SaveOptionsDrawerContent_drawerActionPrimary____QuR span{gap:14px}.SaveOptionsDrawerContent_drawerActionPrimary____QuR{color:var(--blue-gray-800);display:flex;font-weight:400;line-height:24px;align-items:center;justify-content:flex-start;padding:8px 4px;margin:14px 0}.SaveOptionsDrawerContent_drawerActionPrimary____QuR.SaveOptionsDrawerContent_newListButton__VzhfD{font-size:16px;font-weight:600}.SaveOptionsDrawerContent_addIcon__Wb2cq{color:var(--blue-gray-800)}.SaveOptionsDrawerContent_drawerActionSecondary__7cq8j span.SaveOptionsDrawerContent_clampLines__zfkfI{display:inline-block;overflow:hidden;text-align:left;text-overflow:ellipsis;white-space:nowrap;width:calc(100vw - 115px)}.SaveOptionsDrawerContent_listIcon__5dcfC{color:var(--blue-gray-900)}.SaveOptionsDrawerContent_noSavedLists__cpUBY{color:var(--blue-gray-600);font-weight:400;font-size:16px;line-height:24px;padding:12px 16px;text-align:center}.Separator_root__70Ime{--orientationMargin:0;background-color:var(--blue-gray-200);flex-shrink:0}.Separator_horizontal__czVEa{width:calc(100% - var(--orientationMargin) * 2);height:1px}.Separator_vertical__JYCCK{width:1px;height:calc(100% - var(--orientationMargin) * 2)}.SaveLoggedOut_icon__ny9X2{color:var(--blue-gray-700)}.Dropdown_root__Z78h8{display:inline-block;position:relative;color:inherit}.DropdownTrigger_trigger__SzsBj{display:flex;align-items:center;justify-content:center;background:transparent;border:none;font-size:inherit;padding:0;margin:0;cursor:pointer}.DropdownTrigger_trigger__SzsBj:active,.DropdownTrigger_trigger__SzsBj:focus,.DropdownTrigger_trigger__SzsBj:hover{background:transparent}.DropdownContent_content__3daFs{position:absolute;display:flex;flex-direction:column;align-items:flex-start;padding:8px 0;background-color:#fff;box-shadow:0 .5px 5px rgba(0,0,0,.039),0 3.75px 11px rgba(0,0,0,.19);border-radius:4px;color:var(--blue-gray-800);opacity:0;visibility:hidden;transition:transform .15s,opacity .15s,visibility 0s linear .15s;transform:scale(.95);z-index:var(--dropdown-index)}.DropdownContent_bottom-left__gioqM{top:calc(100% + 6px);left:0;transform-origin:top left}.DropdownContent_bottom-right__QJ94h{top:calc(100% + 6px);right:0;transform-origin:top right}.DropdownContent_top-left__O3Ryp{bottom:calc(100% + 6px);left:0;transform-origin:bottom left}.DropdownContent_top-right___Qe45{bottom:calc(100% + 6px);right:0;transform-origin:bottom right}.DropdownContent_content__3daFs.DropdownContent_open__6VoiP{visibility:visible;opacity:1;transform:none;transition-delay:0s}.DropdownItem_item__Sv0GT{width:100%;display:flex;align-items:center;background-color:transparent;color:inherit;cursor:pointer;font-size:inherit;line-height:24px;padding:12px 16px;white-space:nowrap}.DropdownItem_highlight__jO3zg,.DropdownItem_item__Sv0GT:hover{background-color:var(--blue-gray-100)}.DropdownSeparator_separator__EN82n{width:calc(100% - 32px);height:1px;background-color:var(--blue-gray-300);margin:8px 16px}.MoreDropdownButton_moreOptionsDropdown__GK_Uw{display:flex;align-items:center;justify-content:center;width:32px;height:32px}.MoreDropdownButton_item__t4HmI{gap:12px}.MoreDropdownButton_moreOptionsIcon__TpJLA{color:var(--blue-gray-700)}.MoreDropdownButton_icon__DxfY4{color:var(--blue-gray-800)}.MoreDropdownButton_tooltip__az4od{white-space:nowrap}.MetadataToolbar_root__c03ao{--shadow-opacity:0;display:grid;height:var(--metadata-toolbar-height);background-color:var(--white);z-index:var(--header-index)}.MetadataToolbar_wrapper__r7XEc{position:relative;display:grid;grid-template-columns:minmax(0,1fr) max-content 1fr;align-items:center;padding-inline-end:20px;padding-block:16px}.MetadataToolbar_underline__QQn0C{grid-column:1/-1;grid-row:2;height:1px;position:absolute;bottom:0;right:-20px;left:-30vw;background-color:var(--blue-gray-200);box-shadow:0 2px 4px 0 rgba(0 0 0/var(--shadow-opacity));animation:MetadataToolbar_reveal-shadow__5yBxP linear both;animation-timeline:scroll(block);animation-range:150px 450px}.MetadataToolbar_verticalMode__Bh759{position:sticky}.MetadataToolbar_title__jfTWv{font-size:18px;font-weight:600}.MetadataToolbar_actions__FB33C{width:-moz-max-content;width:max-content;justify-self:flex-end;display:flex;grid-column-end:-1}.MetadataToolbar_pageNumber__i6Bhj{display:inline-flex;align-items:center;margin-inline:1em;height:44px}.MetadataToolbar_isInReadingModeVariant__XMDcr{align-items:flex-start}.MetadataToolbar_isInReadingModeVariant__XMDcr .MetadataToolbar_downloadButton__ncS7o>button{padding:0 15px}@media screen and (max-width:928px){.MetadataToolbar_root__c03ao{display:none}}@media screen and (min-width:929px) and (max-width:1249px){.MetadataToolbar_isInReadingModeVariant__XMDcr .MetadataToolbar_pageNumber__i6Bhj{display:none}}@keyframes MetadataToolbar_reveal-shadow__5yBxP{to{--shadow-opacity:0.122}}.DownloadButton_root__adY00{margin-left:auto;display:inline-grid;gap:6px;justify-items:center;flex-shrink:0}.DownloadButton_savedStyling__k18od{font-weight:600;font-size:18px}.DownloadMultipleFormatDrawer_root__CWFxX{width:100%;padding:0 24px}.DownloadMultipleFormatDrawer_drawerHeading__8LnFw{margin:16px 0}.DownloadMultipleFormatDrawer_drawerContent__y815X{width:100%;padding:24px 0}.DownloadMultipleFormatDrawer_drawerRadioButtons__I_lQ4 label{margin-bottom:20px}.DownloadMultipleFormatDrawer_drawerRadioButtons__I_lQ4{margin-bottom:4px}.Fieldset_root__L2NQU{display:grid;padding:0;border:0}.Fieldset_root__L2NQU legend{display:none}.DownloadMultipleFormatPopover_popoverContent__IJudF{min-width:185px}.FadeInOut_root__v7Efq{position:relative;min-width:0;background-color:var(--snow-gray);padding:20px}.FadeInOut_root__v7Efq.FadeInOut_isInfographic__PdX2K{background-color:unset;padding-inline-start:0;padding-inline-end:20px}@media (max-width:928px){.FadeInOut_root__v7Efq,.FadeInOut_root__v7Efq.FadeInOut_isInfographic__PdX2K{background-color:unset;padding-inline:2px}}.FadeInOut_in__9dYWz{animation:FadeInOut_fadeIn__14JD0 .5s}.FadeInOut_out___eDZk{animation:FadeInOut_fadeOut__ILQaD .4s}@keyframes FadeInOut_fadeIn__14JD0{0%{opacity:0}to{opacity:1}}@keyframes FadeInOut_fadeOut__ILQaD{0%{opacity:1}to{opacity:0}}.VerticalSlideOverlayed_root__9Thd4{position:relative}.VerticalSlideOverlayed_root__9Thd4 .vertical-slide-image{position:absolute;inset:0}.VerticalSlideOverlayed_active___p5f2 .vertical-slide-image{opacity:.4}.VerticalSlideOverlayed_active___p5f2{background-color:#000}.VerticalSlideImage_image__VtE4p{width:100%;height:100%;-o-object-fit:contain;object-fit:contain;box-shadow:0 0 0 1px var(--blue-gray-200);border-radius:8px;transition:opacity .3s cubic-bezier(.2,0,0,1);opacity:.9;overflow:clip;background-color:var(--blue-gray-600);animation-name:VerticalSlideImage_pulse__OPBSn;animation-direction:alternate;animation-duration:1s;animation-iteration-count:infinite;animation-timing-function:ease-in-out}.VerticalSlideImage_image__VtE4p.VerticalSlideImage_isLoaded__r4xAa{opacity:1;animation:none;background-color:unset}@keyframes VerticalSlideImage_pulse__OPBSn{0%{opacity:.09}to{opacity:.15}}.SlideScrollDetector_root__AIK38{position:relative;height:100%;width:100%;pointer-events:none}.SlideScrollDetector_detector__rhkyk{position:absolute;top:0;left:0;height:1px;width:100%}.SlideScrollDetector_detector1__NmF8s{top:25%}.SlideScrollDetector_detector2__32XWr{top:75%}.SlideActions_root__fB9Q4{position:absolute;right:0;top:0;display:grid;grid-template-columns:40px;grid-template-rows:40px 40px;grid-column-gap:12px;-moz-column-gap:12px;column-gap:12px;grid-row-gap:12px;row-gap:12px;padding:12px;justify-content:flex-end;align-items:center;text-align:end}.SlideActions_active__aD_e1{grid-template-columns:max-content 40px}.SlideActions_button__o8UXk{background-color:var(--blue-gray-100);color:var(--blue-gray-700)}.VerticalSlide_infographic__ij1FA,.VerticalSlide_root__jU_9r{position:relative}.VerticalSlide_root__jU_9r .vertical-slide-image{position:absolute;inset:0}.VerticalSlide_infographic__ij1FA .vertical-slide-image{position:unset}.VerticalPlayer_root__K8_YS{position:relative;display:grid;grid-template-columns:minmax(0,1fr);grid-gap:24px;gap:24px}@media screen and (max-width:928px){.VerticalPlayer_root__K8_YS{gap:8px}}.FreestarVideoAd_root__KDWgl{min-width:0;flex-shrink:0;aspect-ratio:16/9}.VerticalInterstitialAdWrapper_root__LxQh8{container-type:inline-size;position:relative;display:grid;min-height:280px;overflow-x:clip}.VerticalInterstitialAdWrapper_root__LxQh8:has(.interstitial-ad-container.has-fetched):not(:has(.interstitial-ad-container.has-fetched .freestar-ad-container:not(.unfilled))){display:none}.VerticalInterstitialAdWrapper_root__LxQh8:has(div.interstitial-ad-container.has-fetched div.freestar-ad-container.filled div),.VerticalInterstitialAdWrapper_root__LxQh8:has(div.interstitial-ad-container.has-fetched div.freestar-ad-container.unfilled iframe){display:block!important}.VerticalInterstitial_root__Dunl7{display:none}@media (max-width:520px){.VerticalInterstitial_root__Dunl7:not(.VerticalInterstitial_inVariant__xB9lL){display:block}}@container (max-width: 480px){.VerticalInterstitial_root__Dunl7.VerticalInterstitial_inVariant__xB9lL{display:block}}.FreestarAdContainer_root__qPPC_{position:relative;display:grid;place-content:center}.FreestarAdContainer_root__qPPC_.FreestarAdContainer_withFallback__A4lgm{aspect-ratio:var(--fallback-aspect-ratio)}.FreestarAdContainer_fallback__WreT9{position:absolute;inset:0;grid-template-columns:unset;place-content:center}.AdFallback_root__uAXsl{display:grid;justify-items:center;grid-template-columns:1fr;z-index:0}.MultipleIncontentSmall_root__x58Hs{display:none;grid-template-columns:repeat(auto-fit,minmax(max-content,300px));place-content:center;gap:16px}@media (min-width:521px){.MultipleIncontentSmall_root__x58Hs:not(.MultipleIncontentSmall_inVariant__uf1S8){display:grid}}@container (max-width: 616px){.MultipleIncontentSmall_root__x58Hs:not(.MultipleIncontentSmall_inVariant__uf1S8) .freestar-ad-container:nth-of-type(2){display:none}}@container (min-width: 616px) and (max-width: 688px){.MultipleIncontentSmall_root__x58Hs.MultipleIncontentSmall_inVariant__uf1S8{display:grid}}.MultipleIncontentWide_root__4WD8U{display:none;place-content:center}@container (min-width: 480px) and (max-width: 616px){.MultipleIncontentWide_root__4WD8U{display:grid}}.MultipleIncontentLarge_root__pGIAn{display:none;grid-template-columns:repeat(auto-fit,minmax(max-content,336px));place-content:center;gap:16px}@container (min-width: 688px){.MultipleIncontentLarge_root__pGIAn{display:grid}}.SlideRecs_root__likA5{--card-hover-background:var(--blue-gray-200);display:flex;flex-direction:column;gap:20px}.SlideRecs_root__likA5 h2{font-size:24px;font-weight:600}@media (max-width:1050px){.SlideRecs_root__likA5{display:none}}.SlideRecs_root__likA5 .SlideRecs_cards__Lbxtt{display:grid;grid-gap:16px;gap:16px}.SlideRecs_root__likA5 .SlideRecs_card__txc2D{position:relative;grid-template-columns:180px 1fr;grid-template-rows:auto;gap:16px}.SlideRecs_root__likA5 .slideshow-thumbnail{box-shadow:0 0 0 1px var(--blue-gray-200)}.SlideRecs_root__likA5 .slideshow-card-content{padding-block:0;padding-inline-end:36px;gap:8px}.SlideRecs_root__likA5 .slideshow-title{line-height:1;margin-block-end:0}.SlideRecs_root__likA5 .SlideRecs_wrapper__21j_w{display:flex;gap:8px;align-items:center}.SlideRecs_root__likA5 .SlideRecs_wrapper__21j_w a,.SlideRecs_root__likA5 .SlideRecs_wrapper__21j_w span{font-size:12px}.SlideRecs_root__likA5 .SlideRecs_save__RR8dD{position:absolute;top:8px;right:8px}.SlideRecs_root__likA5 .SlideRecs_author__zlhWO{color:var(--blue-gray-700);font-weight:600;text-decoration:none;z-index:2}.SlideRecs_root__likA5 .SlideRecs_author__zlhWO:first-letter{text-transform:uppercase}.SlideRecs_root__likA5 .SlideRecs_card__txc2D .slideshow-title{font-size:16px}.SlideRecs_root__likA5 .SlideRecs_description__0bGsx{color:var(--blue-gray-700);font-size:14px;display:-webkit-box;overflow:hidden;line-clamp:1;-webkit-line-clamp:1;-webkit-box-orient:vertical}.SlideRecs_root__likA5 .SlideRecs_dot__Db7HR{font-size:16px}.SlideRecs_root__likA5 .SlideRecs_tags__RCA1q{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.SlideRecs_root__likA5 .SlideRecs_tags__RCA1q span{display:grid;place-content:center;height:20px;background-color:var(--alice-blue-600);border-radius:100vmax;color:var(--blue-gray-700);font-size:11px;font-weight:600;padding-inline:12px;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap;text-transform:capitalize;z-index:2}.RecWithPopover_root__iNXfW{width:330px;display:flex;flex-direction:column;gap:8px}.RecWithPopover_root__iNXfW>*{line-height:18px}.RecWithPopover_root__iNXfW h3{font-size:16px;font-weight:600}.RecWithPopover_root__iNXfW p{flex:1 1;color:var(--blue-gray-600);font-size:14px;max-width:100%;display:-webkit-box;line-clamp:5;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow-y:hidden}.RecWithPopover_hasSiblingsWithPopover__dlaxN{border-radius:4px;padding:12px}.RecWithPopover_hasPopover__G8_rr:hover:not(:has(:is(.save:hover,.author:hover))){background-color:var(--card-hover-background)}.SlideshowCard_root__pD8t4{position:relative;display:grid;grid-template-rows:max-content minmax(0,1fr);grid-template-columns:minmax(0,1fr);align-content:flex-start;color:var(--blue-gray-600)}.SlideshowCard_root__pD8t4:hover .SlideshowCard_thumb__86aJk{scale:1.02}.SlideshowCard_content__xh7kV{display:flex;flex-direction:column;-moz-column-gap:8px;column-gap:8px;padding:16px 0}.SlideshowCardLink_root__p8KI7{position:absolute;inset:0;z-index:1;margin:4px}.Thumbnail_root__qLW0K{--ease:cubic-bezier(0.2,0,0,1);position:relative;background-color:var(--blue-gray-100);border:1px solid var(--blue-gray-100);border-radius:8px;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);scale:1;transition:scale .2s var(--ease);overflow:hidden}.Thumbnail_thumb__UXO3a{--reveal-delay:calc(30ms * var(--index));position:absolute;inset:0;width:100%;height:100%;opacity:0;transition:opacity .3s var(--ease);transition-delay:var(--reveal-delay)}.Thumbnail_loaded__XOJ5p{opacity:1}.Thumbnail_blur__opK6A{filter:blur(8px)}.Thumbnail_cover__1zsIi{-o-object-fit:cover;object-fit:cover}.Thumbnail_contain__K6M0d{-o-object-fit:contain;object-fit:contain}.SlideshowTitle_root__2VccW{display:-webkit-box;color:var(--blue-gray-900);font-size:18px;font-weight:600;line-height:1.2;margin-bottom:8px;white-space:break-spaces;word-break:break-word;-webkit-box-orient:vertical}.RecSaveButton_root__0CS9m{grid-area:d}.RecSaveButton_icon__btwCp{fill:currentColor;z-index:2}@media (max-width:928px){.RecSaveButton_root__0CS9m{display:none}}.SlideshowAuthor_root__IkT1_{color:var(--celadon-blue);font-weight:600;text-decoration:underline;-webkit-text-decoration-color:transparent;text-decoration-color:transparent;text-decoration-thickness:1.5px;text-underline-offset:2px;transition:-webkit-text-decoration-color .2s ease-out;transition:text-decoration-color .2s ease-out;transition:text-decoration-color .2s ease-out,-webkit-text-decoration-color .2s ease-out;z-index:2}.SlideshowAuthor_root__IkT1_:hover{-webkit-text-decoration-color:var(--celadon-blue);text-decoration-color:var(--celadon-blue)}.CountTag_root__y1hE1,.SplitDot_root__lTZDc{color:var(--blue-gray-600);font-weight:400}.SlideshowStats_root__EQOR1{display:flex;align-items:center;gap:6px}.SlideshowStats_text___WD7l{color:var(--blue-gray-600)}.BelowReaderAd_root__NKeGg{margin-top:16px;margin-bottom:60px}.BelowReaderAd_root__NKeGg.BelowReaderAd_desktop__7_JN7{display:block;justify-items:flex-start}.BelowReaderAd_root__NKeGg.BelowReaderAd_mobile__08T3d{display:none}.BelowReaderAd_root__NKeGg .fallback-ad{justify-self:flex-start}@media screen and (max-width:928px){.BelowReaderAd_root__NKeGg.BelowReaderAd_desktop__7_JN7{display:none}.BelowReaderAd_root__NKeGg.BelowReaderAd_mobile__08T3d{display:block;justify-items:center}}.Sidebar_root__1BbNu{width:var(--sidebar-size);max-height:100dvh;overflow:clip scroll;position:sticky;top:var(--metadata-toolbar-offset,0);display:flex;flex-direction:column;padding-inline-start:28px;padding-block-start:32px;padding-block-end:430px}.Sidebar_root__1BbNu.Sidebar_withSidebarAds__0w0dT{max-height:unset;overflow:unset;position:static;top:unset;display:grid;grid-template-rows:repeat(var(--slots),1fr);padding-inline:28px}@media (max-width:1050px){.Sidebar_root__1BbNu,.Sidebar_root__1BbNu.Sidebar_withSidebarAds__0w0dT{display:none}}.AboveRecsAd_root__iTmTR{min-height:280px;margin-block-end:32px}.AboveRecsAd_root__iTmTR .freestar-ad-container{place-content:flex-start}@media (max-width:1050px){.AboveRecsAd_root__iTmTR .freestar-ad-container{place-content:center}}.AboveRecsAd_mobileAd__LYgqf{display:none}.AboveRecsAd_desktopAd__ymykj{display:block}@media (max-width:1050px){.AboveRecsAd_mobileAd__LYgqf{display:block}.AboveRecsAd_desktopAd__ymykj{display:none}}.RailRecommendations_root__zqtZQ{display:flex;flex-direction:column;gap:8px;padding-block-end:24px}.RailRecommendations_title__kt1D2{font-size:24px;color:var(--blue-gray-900);font-weight:600;margin-block-end:20px}@media only screen and (min-width:929px){.RailRecommendations_hidden__7Ct2B{display:none}}.RailCard_root__rZUGY{--card-hover-background:var(--blue-gray-100);width:100%;position:relative;border-radius:8px;padding-block:12px;padding-inline:8px}.RailCard_root__rZUGY.slideshow-card{grid-template-columns:160px minmax(0,1fr);grid-template-rows:auto;gap:12px}.RailCard_root__rZUGY .slideshow-card-content{padding:0}.RailCard_actionContainer__eXUHT{display:grid;grid-template-columns:minmax(0,1fr) 28px;grid-column-gap:8px;-moz-column-gap:8px;column-gap:8px}.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-author,.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-stats,.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-title{grid-area:unset}.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-author,.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-stats{grid-column:1/-1}.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-author{grid-row:2}.RailCard_root__rZUGY .RailCard_actionContainer__eXUHT .slideshow-stats{grid-row:3}.RailCard_link__d3BBm{z-index:1}.RailCard_info__Oqm6G{min-width:0;display:flex;flex-direction:column;justify-content:center;word-break:break-word}.RailCard_root__rZUGY .RailCard_title__Tvfiv{font-size:16px;margin-bottom:0;grid-area:a;word-break:break-word}.RailCard_root__rZUGY .RailCard_stats__ZvZms{margin-top:12px}.RailCard_stats__ZvZms .text{font-size:12px}.RailCard_root__rZUGY .RailCard_author__JYeYZ{color:var(--blue-gray-700);margin-top:8px;text-decoration:none}@media screen and (min-width:929px){.RailCard_root__rZUGY:hover{background-color:var(--blue-gray-100)}}.RelatedContent_root__29Np1{background-color:var(--blue-gray-100);border-top:1px solid var(--blue-gray-200);border-bottom:1px solid var(--blue-gray-200);padding-block:32px;position:relative}.RelatedContent_wrapper__riU7l{display:grid;grid-template-columns:minmax(0,1fr);grid-gap:32px;gap:32px;max-width:var(--max-content-width);margin-inline:auto}.RelatedContent_title__QUhpL{text-align:center;font-size:32px;font-weight:700}.RelatedContent_root__29Np1 .bottom-recs{display:grid}.RelatedContent_root__29Np1 .rail-recs{display:none}@media screen and (max-width:520px){.RelatedContent_root__29Np1 .bottom-recs{display:none}.RelatedContent_root__29Np1 .rail-recs{display:flex}.RelatedContent_wrapper__riU7l{padding-inline:16px}}.BottomRecommendation_root__7aU9w{display:grid;grid-gap:4px;gap:4px;padding-inline:24px}.BottomRecommendation_title__SRj68{font-size:22px;font-weight:600}.BottomRecommendation_count__4HpLo{color:var(--blue-gray-600);font-size:16px;font-weight:400}.Slider_root__c0Jo8{position:relative;display:grid}.Slider_scroller__KHjw4{display:flex;gap:20px;overflow:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;max-inline-size:100%;min-block-size:100%;touch-action:pan-x;-ms-overflow-style:none;scrollbar-width:none}.Slider_scroller__KHjw4::-webkit-scrollbar{display:none}.Slider_scroller__KHjw4>*{flex-grow:1;flex-shrink:0;scroll-snap-align:start}.Slider_scroller__KHjw4>:last-child{scroll-snap-align:end}.Slider_arrow__8LCca{display:grid;place-content:center;width:36px;height:36px;position:absolute;top:50%;background:var(--white);border:1px solid var(--blue-gray-200);border-radius:100vmax;box-shadow:0 2px 4px 0 rgba(0,0,0,.25);color:var(--blue-gray-800);padding:0;opacity:1;visibility:visible;pointer-events:all;transition:opacity .2s ease-in-out,visibility .2s ease-in-out;transition-delay:0s;cursor:pointer;z-index:1}.Slider_prev__YMssa{left:0;translate:-50% -50%}.Slider_next__fa9IO{right:0;translate:50% -50%}.Slider_hidden__rs7nK{opacity:0;visibility:hidden;pointer-events:none}.BottomRecommendationCard_root__gffTk{inline-size:clamp(220px,12.63rem + 3.45vw,260px);position:relative;border-radius:8px;background-color:#fff;border:1px solid var(--blue-gray-200)}.BottomRecommendationCard_root__gffTk .slideshow-thumbnail{border-radius:0;border-top-left-radius:8px;border-top-right-radius:8px}.BottomRecommendationCard_root__gffTk .slideshow-card-content{padding:16px}.BottomRecommendationCard_root__gffTk .slideshow-author{max-width:50%;word-break:break-all;white-space:break-spaces;-webkit-line-clamp:1;display:-webkit-box;-webkit-box-orient:vertical}.BottomRecommendationCard_root__gffTk .slideshow-stats{margin-block-start:auto}.BottomRecommendationCard_root__gffTk:focus,.BottomRecommendationCard_root__gffTk:focus-visible{outline:none;border-color:var(--celadon-blue);border-width:1px}.BottomRecommendationCard_root__gffTk .BottomRecommendationCard_text__5jKNE{display:-webkit-box;-webkit-box-orient:vertical;white-space:break-spaces;word-break:break-word;-webkit-line-clamp:1}.BottomRecommendationCard_link__pHORq:before{content:"";position:absolute;inset:0;z-index:1}.BottomRecommendationCard_metaLine__shwPk{display:flex;gap:8px;align-items:center;white-space:nowrap;grid-area:c}.ScribdRecommendation_root__t3ezS{display:grid;grid-gap:16px;gap:16px;padding:0 24px}.ScribdRecommendation_header__Jw_M1{display:grid;grid-template-columns:1fr max-content}.ScribdRecommendation_title__JZ5p7{font-size:22px;font-weight:600}.ScribdRecommendation_link__4DVQz{align-self:end;grid-column:2;grid-row:1/span 2;color:var(--celadon-blue-dark)}.ScribdRecommendation_link__4DVQz:hover{color:var(--celadon-blue)}.ScribdRecommendationCard_root__ef2Y_{--ease:cubic-bezier(0.2,0,0,1);--rec-bg-1:#f1e3e3;--rec-bg-2:#f6f4e3;--rec-bg-3:#e1eaec;--rec-bg-4:#efebef;--rec-bg-5:#f1f0f0;--rec-bg-6:#f4eadb;--rec-bg-7:#eaeee7;--rec-bg-8:#e3e8ef;--rec-bg-9:#f1eee6;max-width:172px;position:relative;height:100%;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:max-content minmax(0,1fr);align-content:flex-start;background-color:var(--white);border:1px solid var(--blue-gray-200);box-shadow:none;transition:box-shadow .2s ease-in-out;text-decoration:none}.ScribdRecommendationCard_root__ef2Y_:hover{box-shadow:0 2px 10px rgba(0,0,0,.1)}.ScribdRecommendationCard_thumb__5VVNh{position:relative;display:flex;background-color:var(--blue-gray-200);margin-block-start:24px;margin-inline:20px}.ScribdRecommendationCard_root__ef2Y_:before{position:absolute;inset:0;aspect-ratio:19/16;content:"";background-color:var(--block-color)}.ScribdRecommendationCard_thumb__5VVNh img{--reveal-delay:calc(30ms * var(--card-index));aspect-ratio:inherit;box-shadow:0 4px 6px rgba(0,0,0,.2);-o-object-fit:cover;object-fit:cover;opacity:0;visibility:hidden;transition:opacity .3s var(--ease);transition-delay:var(--reveal-delay)}.ScribdRecommendationCard_loaded__FTN_f img{opacity:1;visibility:visible}.ScribdRecommendationCard_content__ObcvL{display:flex;flex-direction:column;padding-block:20px;padding-inline:16px}.ScribdRecommendationCard_content__ObcvL .rating{padding-block-start:8px;margin-block-start:auto}@media (max-width:928px){.ScribdRecommendationCard_content__ObcvL .rating{flex-direction:column;align-items:flex-start}}.Rating_root__fgZQJ{display:flex;align-items:center;-moz-column-gap:6px;column-gap:6px;white-space:nowrap}.Rating_root__fgZQJ :first-child{color:#e47b01;font-size:16px;line-height:1}.Rating_root__fgZQJ :last-child{color:var(--blue-gray-600);font-size:14px;letter-spacing:-.25px}.Transcript_root__Vrf6Q{width:100%;max-width:var(--max-content-width);display:grid;grid-gap:8px;gap:8px;padding:32px 16px;margin-inline:auto;position:relative;background:#fff}.Transcript_title__YgAka{display:flex;align-items:center;gap:4px;font-weight:300;word-break:break-word}.Transcript_list__faItj{list-style-type:none;padding-inline-start:0;word-break:break-word}.Transcript_link__MLbGS{color:var(--celadon-blue);font-weight:700;line-height:22px;text-decoration:none;cursor:pointer}.EditorsNotes_root__3PcDF{padding:32px 16px;margin:0 auto}.EditorsNotes_heading__XR9E6{font-weight:700;font-size:22px}.EditorsNotes_list__NcG5Y{padding-left:30px;font-size:18px;font-style:italic;color:var(--blue-gray-600)}.EditorsNotes_item__ebBbj{word-break:break-word}@media screen and (min-width:1696px){.EditorsNotes_root__3PcDF{max-width:1688px}}.FixedDownloadButton_root__14xtQ{display:none}@media screen and (max-width:928px){.FixedDownloadButton_root__14xtQ{position:sticky;bottom:0;display:flex;justify-content:right;z-index:3;padding:16px}}.Modal_root__TYkzh[open]{opacity:1;animation:Modal_slide-in__GHXut .3s ease-out}.Modal_root__TYkzh{--max-height:calc(100dvb - var(--header-height));--slide-from:calc(-50% + 8px);--slide-to:-50%;--title-size:80px;max-width:100%;max-height:var(--max-height);top:50%;left:50%;translate:-50% -50%;box-shadow:0 0 0 1px rgba(9,30,66,.08),0 2px 1px rgba(9,30,66,.08),0 0 20px -6px rgba(9,30,66,.3);border:0;border-radius:var(--border-radius);padding:0;opacity:0;animation:Modal_slide-out__m_Ov2 .2s ease-in;transition:display allow-discrete .3s,overlay allow-discrete .3s;overflow:clip}@starting-style{.Modal_root__TYkzh[open]{opacity:0}}.Modal_root__TYkzh.Modal_small__hupRE{width:400px}.Modal_root__TYkzh.Modal_medium__j8NOV{width:600px}.Modal_root__TYkzh.Modal_large__ygVmr{width:800px}.Modal_root__TYkzh.Modal_xlarge__HeXWk{width:960px}.Modal_wrapper__4UTGq{position:relative;display:flex;flex-direction:column}.Modal_wrapper__4UTGq>h1+*{flex:1 1;max-height:calc(var(--max-height) - var(--title-size));overflow:clip auto}@media screen and (max-width:520px){.Modal_root__TYkzh,.Modal_root__TYkzh.Modal_large__ygVmr,.Modal_root__TYkzh.Modal_medium__j8NOV,.Modal_root__TYkzh.Modal_small__hupRE,.Modal_root__TYkzh.Modal_xlarge__HeXWk{width:100vw}}@media screen and (max-width:928px){.Modal_root__TYkzh.Modal_bottomPlacement__BUbfp{--slide-from:8px;--slide-to:0;width:100vw;top:unset;bottom:0;translate:-50% 0;border-bottom-left-radius:0;border-bottom-right-radius:0}}@keyframes Modal_slide-in__GHXut{0%{translate:-50% var(--slide-from);opacity:0}to{translate:-50% var(--slide-to);opacity:1}}@keyframes Modal_slide-out__m_Ov2{0%{translate:-50% var(--slide-to);opacity:1}to{translate:-50% var(--slide-from);opacity:0}}.Modal_root__TYkzh::backdrop{background-color:transparent;transition:display allow-discrete .3s,overlay allow-discrete .3s,background-color .3s}.Modal_root__TYkzh[open]::backdrop{background-color:rgba(0,0,0,.6)}@starting-style{.Modal_root__TYkzh[open]::backdrop{background-color:transparent}}.Modal_title__xhSfl{height:var(--title-size);display:flex;align-items:center;color:var(--blue-gray-900);font-size:20px;font-weight:600;border-bottom:1px solid var(--blue-gray-200);padding-inline-start:20px;padding-inline-end:60px}.Modal_title__xhSfl:first-letter{text-transform:capitalize}.Modal_content__R1F4d{padding-inline:20px;padding-block:24px}.Modal_actions__t63hZ{display:flex;align-items:center;justify-content:flex-end;gap:24px;padding-inline:20px;padding-block:16px}.CloseButton_root__JCTRm{position:absolute;right:16px;top:16px;width:40px;height:40px;display:grid;place-content:center;color:var(--blue-gray-600);border-radius:100vmax;background-color:transparent;border:0;padding:0;margin:0;transition:background-color .2s ease-in-out;cursor:pointer}.CloseButton_root__JCTRm:hover{background-color:rgba(var(--blue-gray-600-rgb),.05)}.ReportForm_root__RNqAc{display:grid;grid-gap:10px;gap:10px}.ReportForm_selectField__Kyyaj{max-width:unset!important}.LikeModal_more__R9uAk{justify-self:center;color:var(--celadon-blue);font-weight:500;opacity:0;visibility:hidden;transition:opacity .2s ease-in-out,visibility .2s ease-in-out}.LikeModal_more__R9uAk.LikeModal_visible__t1vr4{opacity:1;visibility:visible;transition-delay:0s}.LikesUserList_root__RMFUk{list-style:none;padding:0 0 16px;margin:0}.LikesUserList_root__RMFUk>li{display:grid}.LikesUserList_root__RMFUk>li:last-child .LikesUserList_link__NeMA0{border-bottom:none}.LikesUserList_link__NeMA0{display:grid;grid-template-columns:repeat(2,max-content) 1fr;grid-template-rows:repeat(2,min-content);grid-template-areas:"avatar username summary" "avatar title title";grid-column-gap:12px;-moz-column-gap:12px;column-gap:12px;grid-row-gap:0;row-gap:0;border-bottom:1px solid var(--blue-gray-200);padding:8px 0;text-decoration:none}.LikesUserList_avatar__VRXz2{grid-area:avatar}.LikesUserList_username__c84om{grid-area:username}.LikesUserList_summary___gbSG{grid-area:summary}.LikesUserList_title__UF0V6{grid-area:title}.ViewModal_content__GPKXy{padding-block:0}.ViewModal_row__xLxnz{display:flex;justify-content:space-between;border-bottom:1px dashed var(--blue-gray-300);color:var(--blue-gray-800);padding:16px 0}.ViewModal_row__xLxnz:last-child{border-bottom:none}.ConfirmRemoveSavedModal_description__2EAEu{color:var(--blue-gray-800);font-weight:400;font-size:16px;line-height:20px;padding:24px 0}div.SaveToNewListModal_input__Fi90k{max-width:unset;margin-bottom:24px}.SaveToNewListModal_checkboxWrapper__y_w0m .SaveToNewListModal_checkboxLabel__lMiU9:hover,.SaveToNewListModal_checkboxWrapper__y_w0m:hover .SaveToNewListModal_checkboxLabel__lMiU9,.SaveToNewListModal_checkboxWrapper__y_w0m:hover .SaveToNewListModal_input__Fi90k{color:var(--blue-gray-800)}.SaveToNewListModal_checkboxWrapper__y_w0m .SaveToNewListModal_checkboxLabel__lMiU9{color:var(--blue-gray-800);font-weight:400;font-size:14px;flex-direction:column;display:flex;line-height:18px}.SaveToNewListModal_imageContainer__Dx4nD{display:flex;flex-direction:column;justify-content:center;align-items:center;width:178px;margin:0 auto 24px}.SaveToNewListModal_imageContainer__Dx4nD img{height:100px}.SaveToNewListModal_errorContainer__FBZPH{margin:16px 0}
Svoboda | Graniru | BBC Russia | Golosameriki | Facebook
SlideShare a Scribd company logo
Advanced Appium Tips & Tricks
Jonathan Lipps • Founding Principal • Cloud Grey


@AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com
Perfecto Mobile Webinar · The Internet
April 24, 2018
© 2015, Perfecto Mobile Ltd. All Rights Reserved.
Housekeeping
• Please participate in our live poll and end-of-webinar survey
• Ask us questions in the QA panel
• We will send you the recording and slides
4/21/2018 2
Founding Principal
Architect, Maintainer
Jonathan Lipps • Founding Principal • Cloud Grey


@AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com
Appium Update
AppiumConf!
@jlipps · cloudgrey.io
Watch the videos at
appiumconf.com
Stay tuned for next year.
Thanks for sponsoring,
Perfecto!
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
Auxiliary app support via otherApps capability
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
Auxiliary app support via otherApps capability
iOS Screen Recording
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
Auxiliary app support via otherApps capability
iOS Screen Recording
iOS Performance data gathering via Instruments
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
Auxiliary app support via otherApps capability
iOS Screen Recording
iOS Performance data gathering via Instruments
Android Broadcast device logs for log streaming
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
Auxiliary app support via otherApps capability
iOS Screen Recording
iOS Performance data gathering via Instruments
Android Broadcast device logs for log streaming
Android Support ‘Instant Apps’
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
W3C WebDriver spec support
App management features
Improved screen-related primitives
Clipboard management features
Auxiliary app support via otherApps capability
iOS Screen Recording
iOS Performance data gathering via Instruments
Android Broadcast device logs for log streaming
Android Support ‘Instant Apps’
Many, many bugfixes and performance/stability improvements
What’s new in Appium 1.8?
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
npm install -g appium
© 2015, Perfecto Mobile Ltd. All Rights Reserved.
Poll Question
What feature would you most want to see Implemented in
Appium?
• Support for network virtualization (3G, 4G, packet loss %, etc.)
• Support for visual testing (barcode scanning, check deposit use
cases)
• Support for gesture like Face ID, Finger Print, and more
• Better Cross platform automation for all platforms including
smartwatch, iOS, Android
• Support for audio and video testing (chatbots, MOS, 

etc.)
• Other
4/21/2018 8
Today’s tips: recent selections from appiumpro.com
@jlipps · cloudgrey.io
Finding elements with greater speed and stability
Today’s tips: recent selections from appiumpro.com
@jlipps · cloudgrey.io
Finding elements with greater speed and stability
Using deep links to speed up tests and reduce flakiness
Today’s tips: recent selections from appiumpro.com
@jlipps · cloudgrey.io
Finding elements with greater speed and stability
Using deep links to speed up tests and reduce flakiness
Testing app upgrade scenarios
Today’s tips: recent selections from appiumpro.com
@jlipps · cloudgrey.io
Finding elements with greater speed and stability
Using deep links to speed up tests and reduce flakiness
Testing app upgrade scenarios
Cross-platform testing best practices
Today’s tips: recent selections from appiumpro.com
@jlipps · cloudgrey.io
Element Locators
@jlipps · cloudgrey.io
driver.findElement(By.className(“Button”));
@jlipps · cloudgrey.io
driver.findElement(By.className(“Button”));
locator strategy
@jlipps · cloudgrey.io
driver.findElement(By.className(“Button”));
locator strategy selector
Locator Strategy From Support in Appium
class name Selenium Yes
id Selenium Yes
name Selenium Yes
xpath Selenium Yes
accessibility id Appium Yes
-ios predicate string Appium Yes
-ios class chain Appium Yes
-android uiautomator Appium Yes
-ios uiautomation Appium Deprecated
css selector Selenium No
link text Selenium No
partial link text Selenium No
tag name Selenium No
@jlipps · cloudgrey.io
Why use XPath?
@jlipps · cloudgrey.io
It allows for the formulation of complex queries (for example, using the @contains
function)
Why use XPath?
@jlipps · cloudgrey.io
It allows for the formulation of complex queries (for example, using the @contains
function)
It can identify any element in the UI hierarchy available to Appium
Why use XPath?
@jlipps · cloudgrey.io
It allows for the formulation of complex queries (for example, using the @contains
function)
It can identify any element in the UI hierarchy available to Appium
…
Why use XPath?
@jlipps · cloudgrey.io
It allows for the formulation of complex queries (for example, using the @contains
function)
It can identify any element in the UI hierarchy available to Appium
…
that’s about it
Why use XPath?
@jlipps · cloudgrey.io
Why not to use XPath
@jlipps · cloudgrey.io
Why not to use XPath
@jlipps · cloudgrey.io
Path-based selectors are brittle
Why not to use XPath
@jlipps · cloudgrey.io
Path-based selectors are brittle
It is often expensive to generate an XML representation of the UI
Why not to use XPath
@jlipps · cloudgrey.io
Path-based selectors are brittle
It is often expensive to generate an XML representation of the UI
It is often expensive to map XML elements found by XPath to native element objects
Why not to use XPath
@jlipps · cloudgrey.io
Path-based selectors are brittle
It is often expensive to generate an XML representation of the UI
It is often expensive to map XML elements found by XPath to native element objects
XPath selectors are not cross-platform
Preferred locator strategies
@jlipps · cloudgrey.io
Preferred locator strategies
@jlipps · cloudgrey.io
MobileBy.AccessibilityId
Cross-platform locator strategy, will find
elements by Accessibility Id (or Name) on
iOS, and Content Description on Android
Preferred locator strategies
@jlipps · cloudgrey.io
MobileBy.AccessibilityId
Cross-platform locator strategy, will find
elements by Accessibility Id (or Name) on
iOS, and Content Description on Android
By.id
Cross-platform locator strategy, will find
elements by Id (and a set of other unique
identifiers) on iOS, and android:id on
Android
“Advanced” locator strategies
@jlipps · cloudgrey.io
“Advanced” locator strategies
@jlipps · cloudgrey.io
MobileBy.iOSNsPredicateString
iOS-only locator strategy that allows complex
element lookups based on attributes
“Advanced” locator strategies
@jlipps · cloudgrey.io
MobileBy.iOSNsPredicateString
iOS-only locator strategy that allows complex
element lookups based on attributes
MobileBy.iOSClassChain
iOS-only locator strategy that allows complex
element lookups based on attributes and
hierarchy
“Advanced” locator strategies
@jlipps · cloudgrey.io
MobileBy.iOSNsPredicateString
iOS-only locator strategy that allows complex
element lookups based on attributes
MobileBy.iOSClassChain
iOS-only locator strategy that allows complex
element lookups based on attributes and
hierarchy
MobileBy.AndroidUIAutomator
Android-only locator strategy that allows use
the UiSelector API to chain element
finding restrictions
iOS Predicate String example
@jlipps · cloudgrey.io
MobileBy.iOSNsPredicateString(
"type == 'XCUIElementTypeButton' AND value BEGINSWITH[c] 'foo' AND visible == 1"
);
iOS Class Chain example
@jlipps · cloudgrey.io
MobileBy.iOSClassChain(
"**/XCUIElementTypeCell[`name BEGINSWITH “C"`]/XCUIElementTypeButton[10]"
);
Android UiAutomator example
@jlipps · cloudgrey.io
MobileBy.AndroidUIAutomator(
'new UiSelector().className("ScrollView").getChildByText(new
UiSelector().className("android.widget.TextView"), "Tabs")'
);
Deep Links
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
~30 seconds
@jlipps · cloudgrey.io
30 seconds x 50 tests = 25 minutes
Strategies to set up app state instantly
@jlipps · cloudgrey.io
Android Start the test with custom intents
to navigate directly to the right place
Use intentAction and
optionalIntentArguments parameters
to driver.startActivity
Strategies to set up app state instantly
@jlipps · cloudgrey.io
Android Start the test with custom intents
to navigate directly to the right place
Use intentAction and
optionalIntentArguments parameters
to driver.startActivity
iOS Start the app with custom arguments
using Appium capabilities
Use the processArguments capability
when starting a session
Strategies to set up app state instantly
@jlipps · cloudgrey.io
Android Start the test with custom intents
to navigate directly to the right place
Use intentAction and
optionalIntentArguments parameters
to driver.startActivity
iOS Start the app with custom arguments
using Appium capabilities
Use the processArguments capability
when starting a session
Cross-platform Use deep linking
Implement a custom url scheme in your app,
then simply use driver.get
Strategies to set up app state instantly
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
yourapp://test/login/:username/:password
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
~5 seconds
@jlipps · cloudgrey.io
5 seconds x 50 tests = ~4 minutes
Testing App Upgrades
App upgrades on Android
@jlipps · cloudgrey.io
Get paths to two versions of your app
App upgrades on Android
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
App upgrades on Android
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
Install the new app using driver.installApp
App upgrades on Android
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
Install the new app using driver.installApp
Trigger the new app to relaunch by using driver.startActivity
App upgrades on Android
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
App upgrades on iOS
@jlipps · cloudgrey.io
Get paths to two versions of your app
App upgrades on iOS
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
App upgrades on iOS
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
Stop the current app using mobile: terminateApp
App upgrades on iOS
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
Stop the current app using mobile: terminateApp
Install the new app using mobile: installApp
App upgrades on iOS
@jlipps · cloudgrey.io
Get paths to two versions of your app
Start an Appium session using the older version of the app (via the app capability)
Stop the current app using mobile: terminateApp
Install the new app using mobile: installApp
Trigger the new app to relaunch by using mobile: launchApp
App upgrades on iOS
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
Cross-platform Tips
Tips for app development
@jlipps · cloudgrey.io
Add labels to any element that might be used in testing (i.e., pretty much every
element)
Tips for app development
@jlipps · cloudgrey.io
Add labels to any element that might be used in testing (i.e., pretty much every
element)
Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make
them the same!
Tips for app development
@jlipps · cloudgrey.io
Add labels to any element that might be used in testing (i.e., pretty much every
element)
Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make
them the same!
As much as possible within the product design requirements, keep user flows the same
across apps
Tips for app development
@jlipps · cloudgrey.io
Add labels to any element that might be used in testing (i.e., pretty much every
element)
Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make
them the same!
As much as possible within the product design requirements, keep user flows the same
across apps
Build a test version of your app that has all kinds of state set-up goodies
Tips for app development
@jlipps · cloudgrey.io
Add labels to any element that might be used in testing (i.e., pretty much every
element)
Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make
them the same!
As much as possible within the product design requirements, keep user flows the same
across apps
Build a test version of your app that has all kinds of state set-up goodies
Make debug versions of builds
Tips for app development
@jlipps · cloudgrey.io
Add labels to any element that might be used in testing (i.e., pretty much every
element)
Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make
them the same!
As much as possible within the product design requirements, keep user flows the same
across apps
Build a test version of your app that has all kinds of state set-up goodies
Make debug versions of builds
iOS Use Wildcard App IDs in Provisioning Profiles (so WebDriverAgent can be built
using a custom Bundle ID that works with the profile)
Tips for app development
@jlipps · cloudgrey.io
Tips for the testsuite
@jlipps · cloudgrey.io
Use a Page Object Model strategy (or similar), to keep differences between platforms
encapsulated
Tips for the testsuite
@jlipps · cloudgrey.io
Use a Page Object Model strategy (or similar), to keep differences between platforms
encapsulated
Test step code should be totally platform-agnostic. Only your runner and your object
model should know about platform
Tips for the testsuite
@jlipps · cloudgrey.io
Use a Page Object Model strategy (or similar), to keep differences between platforms
encapsulated
Test step code should be totally platform-agnostic. Only your runner and your object
model should know about platform
Avoid XPath in favor of cross-platform locator strategies
Tips for the testsuite
@jlipps · cloudgrey.io
Use a Page Object Model strategy (or similar), to keep differences between platforms
encapsulated
Test step code should be totally platform-agnostic. Only your runner and your object
model should know about platform
Avoid XPath in favor of cross-platform locator strategies
Dynamically update test name for reports to include platform name or other details, for
easier debugging
Tips for the testsuite
@jlipps · cloudgrey.io
@jlipps · cloudgrey.io
More tips like these sent by e-mail every week
Subscribe at appiumpro.com
Thank You!
Your free weekly Appium newsletter:
appiumpro.com
Jonathan Lipps • Founding Principal • Cloud Grey


@AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com
Questions?
Your free weekly Appium newsletter:
appiumpro.com
Jonathan Lipps • Founding Principal • Cloud Grey


@AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com

More Related Content

Advanced Appium Tips & Tricks with Jonathan Lipps

  • 1. Advanced Appium Tips & Tricks Jonathan Lipps • Founding Principal • Cloud Grey 
 @AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com Perfecto Mobile Webinar · The Internet April 24, 2018
  • 2. © 2015, Perfecto Mobile Ltd. All Rights Reserved. Housekeeping • Please participate in our live poll and end-of-webinar survey • Ask us questions in the QA panel • We will send you the recording and slides 4/21/2018 2
  • 3. Founding Principal Architect, Maintainer Jonathan Lipps • Founding Principal • Cloud Grey 
 @AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com
  • 5. AppiumConf! @jlipps · cloudgrey.io Watch the videos at appiumconf.com Stay tuned for next year. Thanks for sponsoring, Perfecto!
  • 6. What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 7. W3C WebDriver spec support What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 8. W3C WebDriver spec support App management features What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 9. W3C WebDriver spec support App management features Improved screen-related primitives What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 10. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 11. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features Auxiliary app support via otherApps capability What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 12. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features Auxiliary app support via otherApps capability iOS Screen Recording What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 13. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features Auxiliary app support via otherApps capability iOS Screen Recording iOS Performance data gathering via Instruments What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 14. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features Auxiliary app support via otherApps capability iOS Screen Recording iOS Performance data gathering via Instruments Android Broadcast device logs for log streaming What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 15. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features Auxiliary app support via otherApps capability iOS Screen Recording iOS Performance data gathering via Instruments Android Broadcast device logs for log streaming Android Support ‘Instant Apps’ What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 16. W3C WebDriver spec support App management features Improved screen-related primitives Clipboard management features Auxiliary app support via otherApps capability iOS Screen Recording iOS Performance data gathering via Instruments Android Broadcast device logs for log streaming Android Support ‘Instant Apps’ Many, many bugfixes and performance/stability improvements What’s new in Appium 1.8? @jlipps · cloudgrey.io
  • 17. @jlipps · cloudgrey.io npm install -g appium
  • 18. © 2015, Perfecto Mobile Ltd. All Rights Reserved. Poll Question What feature would you most want to see Implemented in Appium? • Support for network virtualization (3G, 4G, packet loss %, etc.) • Support for visual testing (barcode scanning, check deposit use cases) • Support for gesture like Face ID, Finger Print, and more • Better Cross platform automation for all platforms including smartwatch, iOS, Android • Support for audio and video testing (chatbots, MOS, 
 etc.) • Other 4/21/2018 8
  • 19. Today’s tips: recent selections from appiumpro.com @jlipps · cloudgrey.io
  • 20. Finding elements with greater speed and stability Today’s tips: recent selections from appiumpro.com @jlipps · cloudgrey.io
  • 21. Finding elements with greater speed and stability Using deep links to speed up tests and reduce flakiness Today’s tips: recent selections from appiumpro.com @jlipps · cloudgrey.io
  • 22. Finding elements with greater speed and stability Using deep links to speed up tests and reduce flakiness Testing app upgrade scenarios Today’s tips: recent selections from appiumpro.com @jlipps · cloudgrey.io
  • 23. Finding elements with greater speed and stability Using deep links to speed up tests and reduce flakiness Testing app upgrade scenarios Cross-platform testing best practices Today’s tips: recent selections from appiumpro.com @jlipps · cloudgrey.io
  • 28. Locator Strategy From Support in Appium class name Selenium Yes id Selenium Yes name Selenium Yes xpath Selenium Yes accessibility id Appium Yes -ios predicate string Appium Yes -ios class chain Appium Yes -android uiautomator Appium Yes -ios uiautomation Appium Deprecated css selector Selenium No link text Selenium No partial link text Selenium No tag name Selenium No @jlipps · cloudgrey.io
  • 29. Why use XPath? @jlipps · cloudgrey.io
  • 30. It allows for the formulation of complex queries (for example, using the @contains function) Why use XPath? @jlipps · cloudgrey.io
  • 31. It allows for the formulation of complex queries (for example, using the @contains function) It can identify any element in the UI hierarchy available to Appium Why use XPath? @jlipps · cloudgrey.io
  • 32. It allows for the formulation of complex queries (for example, using the @contains function) It can identify any element in the UI hierarchy available to Appium … Why use XPath? @jlipps · cloudgrey.io
  • 33. It allows for the formulation of complex queries (for example, using the @contains function) It can identify any element in the UI hierarchy available to Appium … that’s about it Why use XPath? @jlipps · cloudgrey.io
  • 34. Why not to use XPath @jlipps · cloudgrey.io
  • 35. Why not to use XPath @jlipps · cloudgrey.io Path-based selectors are brittle
  • 36. Why not to use XPath @jlipps · cloudgrey.io Path-based selectors are brittle It is often expensive to generate an XML representation of the UI
  • 37. Why not to use XPath @jlipps · cloudgrey.io Path-based selectors are brittle It is often expensive to generate an XML representation of the UI It is often expensive to map XML elements found by XPath to native element objects
  • 38. Why not to use XPath @jlipps · cloudgrey.io Path-based selectors are brittle It is often expensive to generate an XML representation of the UI It is often expensive to map XML elements found by XPath to native element objects XPath selectors are not cross-platform
  • 40. Preferred locator strategies @jlipps · cloudgrey.io MobileBy.AccessibilityId Cross-platform locator strategy, will find elements by Accessibility Id (or Name) on iOS, and Content Description on Android
  • 41. Preferred locator strategies @jlipps · cloudgrey.io MobileBy.AccessibilityId Cross-platform locator strategy, will find elements by Accessibility Id (or Name) on iOS, and Content Description on Android By.id Cross-platform locator strategy, will find elements by Id (and a set of other unique identifiers) on iOS, and android:id on Android
  • 43. “Advanced” locator strategies @jlipps · cloudgrey.io MobileBy.iOSNsPredicateString iOS-only locator strategy that allows complex element lookups based on attributes
  • 44. “Advanced” locator strategies @jlipps · cloudgrey.io MobileBy.iOSNsPredicateString iOS-only locator strategy that allows complex element lookups based on attributes MobileBy.iOSClassChain iOS-only locator strategy that allows complex element lookups based on attributes and hierarchy
  • 45. “Advanced” locator strategies @jlipps · cloudgrey.io MobileBy.iOSNsPredicateString iOS-only locator strategy that allows complex element lookups based on attributes MobileBy.iOSClassChain iOS-only locator strategy that allows complex element lookups based on attributes and hierarchy MobileBy.AndroidUIAutomator Android-only locator strategy that allows use the UiSelector API to chain element finding restrictions
  • 46. iOS Predicate String example @jlipps · cloudgrey.io MobileBy.iOSNsPredicateString( "type == 'XCUIElementTypeButton' AND value BEGINSWITH[c] 'foo' AND visible == 1" );
  • 47. iOS Class Chain example @jlipps · cloudgrey.io MobileBy.iOSClassChain( "**/XCUIElementTypeCell[`name BEGINSWITH “C"`]/XCUIElementTypeButton[10]" );
  • 48. Android UiAutomator example @jlipps · cloudgrey.io MobileBy.AndroidUIAutomator( 'new UiSelector().className("ScrollView").getChildByText(new UiSelector().className("android.widget.TextView"), "Tabs")' );
  • 52. @jlipps · cloudgrey.io 30 seconds x 50 tests = 25 minutes
  • 53. Strategies to set up app state instantly @jlipps · cloudgrey.io
  • 54. Android Start the test with custom intents to navigate directly to the right place Use intentAction and optionalIntentArguments parameters to driver.startActivity Strategies to set up app state instantly @jlipps · cloudgrey.io
  • 55. Android Start the test with custom intents to navigate directly to the right place Use intentAction and optionalIntentArguments parameters to driver.startActivity iOS Start the app with custom arguments using Appium capabilities Use the processArguments capability when starting a session Strategies to set up app state instantly @jlipps · cloudgrey.io
  • 56. Android Start the test with custom intents to navigate directly to the right place Use intentAction and optionalIntentArguments parameters to driver.startActivity iOS Start the app with custom arguments using Appium capabilities Use the processArguments capability when starting a session Cross-platform Use deep linking Implement a custom url scheme in your app, then simply use driver.get Strategies to set up app state instantly @jlipps · cloudgrey.io
  • 60. @jlipps · cloudgrey.io 5 seconds x 50 tests = ~4 minutes
  • 62. App upgrades on Android @jlipps · cloudgrey.io
  • 63. Get paths to two versions of your app App upgrades on Android @jlipps · cloudgrey.io
  • 64. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) App upgrades on Android @jlipps · cloudgrey.io
  • 65. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) Install the new app using driver.installApp App upgrades on Android @jlipps · cloudgrey.io
  • 66. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) Install the new app using driver.installApp Trigger the new app to relaunch by using driver.startActivity App upgrades on Android @jlipps · cloudgrey.io
  • 68. App upgrades on iOS @jlipps · cloudgrey.io
  • 69. Get paths to two versions of your app App upgrades on iOS @jlipps · cloudgrey.io
  • 70. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) App upgrades on iOS @jlipps · cloudgrey.io
  • 71. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) Stop the current app using mobile: terminateApp App upgrades on iOS @jlipps · cloudgrey.io
  • 72. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) Stop the current app using mobile: terminateApp Install the new app using mobile: installApp App upgrades on iOS @jlipps · cloudgrey.io
  • 73. Get paths to two versions of your app Start an Appium session using the older version of the app (via the app capability) Stop the current app using mobile: terminateApp Install the new app using mobile: installApp Trigger the new app to relaunch by using mobile: launchApp App upgrades on iOS @jlipps · cloudgrey.io
  • 76. Tips for app development @jlipps · cloudgrey.io
  • 77. Add labels to any element that might be used in testing (i.e., pretty much every element) Tips for app development @jlipps · cloudgrey.io
  • 78. Add labels to any element that might be used in testing (i.e., pretty much every element) Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make them the same! Tips for app development @jlipps · cloudgrey.io
  • 79. Add labels to any element that might be used in testing (i.e., pretty much every element) Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make them the same! As much as possible within the product design requirements, keep user flows the same across apps Tips for app development @jlipps · cloudgrey.io
  • 80. Add labels to any element that might be used in testing (i.e., pretty much every element) Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make them the same! As much as possible within the product design requirements, keep user flows the same across apps Build a test version of your app that has all kinds of state set-up goodies Tips for app development @jlipps · cloudgrey.io
  • 81. Add labels to any element that might be used in testing (i.e., pretty much every element) Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make them the same! As much as possible within the product design requirements, keep user flows the same across apps Build a test version of your app that has all kinds of state set-up goodies Make debug versions of builds Tips for app development @jlipps · cloudgrey.io
  • 82. Add labels to any element that might be used in testing (i.e., pretty much every element) Add labels as “Accessibility ID” on iOS and “Content Description” on Android—and make them the same! As much as possible within the product design requirements, keep user flows the same across apps Build a test version of your app that has all kinds of state set-up goodies Make debug versions of builds iOS Use Wildcard App IDs in Provisioning Profiles (so WebDriverAgent can be built using a custom Bundle ID that works with the profile) Tips for app development @jlipps · cloudgrey.io
  • 83. Tips for the testsuite @jlipps · cloudgrey.io
  • 84. Use a Page Object Model strategy (or similar), to keep differences between platforms encapsulated Tips for the testsuite @jlipps · cloudgrey.io
  • 85. Use a Page Object Model strategy (or similar), to keep differences between platforms encapsulated Test step code should be totally platform-agnostic. Only your runner and your object model should know about platform Tips for the testsuite @jlipps · cloudgrey.io
  • 86. Use a Page Object Model strategy (or similar), to keep differences between platforms encapsulated Test step code should be totally platform-agnostic. Only your runner and your object model should know about platform Avoid XPath in favor of cross-platform locator strategies Tips for the testsuite @jlipps · cloudgrey.io
  • 87. Use a Page Object Model strategy (or similar), to keep differences between platforms encapsulated Test step code should be totally platform-agnostic. Only your runner and your object model should know about platform Avoid XPath in favor of cross-platform locator strategies Dynamically update test name for reports to include platform name or other details, for easier debugging Tips for the testsuite @jlipps · cloudgrey.io
  • 88. @jlipps · cloudgrey.io More tips like these sent by e-mail every week Subscribe at appiumpro.com
  • 89. Thank You! Your free weekly Appium newsletter: appiumpro.com Jonathan Lipps • Founding Principal • Cloud Grey 
 @AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com
  • 90. Questions? Your free weekly Appium newsletter: appiumpro.com Jonathan Lipps • Founding Principal • Cloud Grey 
 @AppiumDevs • @cloudgrey_io • @jlipps • appiumpro.com