async function onReadyAsync(optionalWidth, optionalHeight) {
    // this function is run when the DOM for the page has loaded
    // summary
    //  if the current protocol is http rather than https, redirect to https
    //  if login features are enabled, show login and logout buttons as appropriate
    //      otherwise hide login and logout buttons
    //  assign click handlers to buttons

    const logHdr = 'Lenses.onReadyAsync: ';
    log(logHdr + 'enter');
    log(logHdr + 'optionalWidth=' + optionalWidth);
    log(logHdr + 'optionalHeight=' + optionalHeight);

    const PAGE_URL = urlUtils.getUrl('/lenses.html');
    // get a URL for this page, to use for redirects

    log(logHdr + 'PAGE_URL=' + PAGE_URL);

    const BUY_NOW_URL = 'https://www.invisiblesolutionstools.com/buy-it';

    var authenticated = false;
    var auth0Client = null;

    var theProtocol = location.protocol;
    // get the protocol (http or https) for the current URL

    log(logHdr + 'theProtocol=' + theProtocol);

    // if the current protocol is http, redirect to https
    // most mobile browsers will not allow access to location services without https
    if (theProtocol === 'http:') {

        log(logHdr + 'protocal is http, so we will set location.href to redirect to https');
        log(logHdr + 'about to set location.href');

        location.href = location.href.replace(/^http:/, 'https:');
        // we need HTTPS for the gelocation call
        // yes, it's safer to handle this server-side, but we may use Azure static websites
        // to host this site.  these web sites do not have a redirect feature.
        // they do have a "require https" feature, but if that is enabled the user gets an error
        // and we don't get a chance to redirect.

        log(logHdr + 'back from setting location.href');
        log(logHdr + 'leave');

        return;
    }

    const urlParams = new URLSearchParams(window.location.search);
    // parse the query string

    var idProvided = securityStateUtils.getAllowed();
    // has the user already provided the id?

    idProvided = true;
    // for production

    log(logHdr + 'idProvided=' + idProvided);

    if (!idProvided) {
        // if not

        log(logHdr + 'id not provided previously, so we check the query string');

        var hasId = urlParams.has(QUERY_STRING_KEY_ID);
        // does the query string have an id value?

        log(logHdr + 'hasId=' + hasId);

        if (!hasId) {
            // if not, redirect

            location.href = SECURITY_REDIRECT_URL;
            // redirect

            return;
        }

        log(logHdr + 'the query string has an id value');

        const qsId = urlParams.get(QUERY_STRING_KEY_ID);
        // get the id from the query string

        log(logHdr + 'qsId=' + qsId);

        if (qsId === QUERY_STRING_ID_VALUE) {
            // if the id is correct

            log(logHdr + 'storing the allowed flag, for next time');

            securityStateUtils.setAllowed(true);
            // set the value, for next time
        }
        else {
            // if the id is NOT correct

            location.href = SECURITY_REDIRECT_URL;
            // redirect

            return;
        }
    }

    var hasClear = urlParams.has(QUERY_STRING_KEY_CLEAR_STORAGE);
    // does the query string have a clear storage value?

    if (hasClear) {
        // if so

        const clearValue = urlParams.get(QUERY_STRING_KEY_CLEAR_STORAGE);

        if (clearValue === 'true') {
            log('we received a clear storage command in the query string, so we will clear all local storage');

            globalStateUtils.clearAll();
        }
    }

    // for this function (unlike some others in the app) we need the screen dimensions info here, not later

    viewWidth = document.documentElement.clientWidth;
    viewHeight = document.documentElement.clientHeight;
    // store view width and height

    log(logHdr + 'view width=' + viewWidth + ', viewHeight=' + viewHeight);

    const widthDefined = typeof optionalWidth !== 'undefined';
    const heightDefined = typeof optionalHeight !== 'undefined';
    // did the caller pass these values?

    if (widthDefined && heightDefined) {
        // if the caller passed width and height values

        log(logHdr + 'the caller passed width (' + optionalWidth + ') and height (' + optionalHeight + ') values so we will use them');

        viewWidth = optionalWidth;
        viewHeight = optionalHeight;
        // use the parameter values
    }

    // alert('view width=' + viewWidth + ', viewHeight=' + viewHeight);

    viewWide = (viewWidth > 1049);
    // is the view wide enough that we want to show more than one column?

    // the previous value we used here was 693.
    // the idea behind this value was that 694 can show two columns of lens cards.
    // however, on iPhone 6, for example, if the user rotates the phone from portrait to landscape
    // it's more helpful to show them more info about one card than to show two cards
    // and force them to click something to expand a card to see more info
    // iPhone 6 height in portrait mode is 667, which becomes width in landscape mode

    log(logHdr + 'viewWide=' + viewWide);

    $('#btnDebugger').click(function () { debugger; });

    $('#btnBuySmScrn').click(function handleBuySmScreen() { location.href = BUY_NOW_URL; });
    $('#btnBuyLgScrn').click(function handleBuyLgScreen() { location.href = BUY_NOW_URL; });
    // subscribe to buy button click handlers

    if (enableLoginFeatures) {
        // if login features are enabled

        $('#aLogin').click(async function () { await authUtils.doLoginAsync(PAGE_URL); });
        $('#btnLogout').click(async function () { await authUtils.doLogoutAsync(); });

        $('#btnLoginSmScrn').click(async function () { await authUtils.doLoginAsync(PAGE_URL); });
        $('#btnLoginLgScrn').click(async function () { await authUtils.doLoginAsync(PAGE_URL); });

        auth0Client = authUtils._auth0Client;
        // read the Auth0 client, or null

        if (auth0Client === null) {
            // if we haven't yet stored in Auth0 client object

            const tmrCreateAuth = tmrUtils.newTimer('createAuth0Client').start();

            auth0Client = await createAuth0Client({ domain: authUtils.AUTH0_DOMAIN, client_id: authUtils.AUTH0_CLIENT_ID });
            // allocate an Auth0 object
            // if the user has already authenticated, the auth0 object will be populated with an access token and user profile

            tmrCreateAuth.stop();
            log(logHdr + 'TIME: ' + tmrCreateAuth);

            authUtils.setAuth0Client(auth0Client);
            // store the client in our auth utilities object
        }

        authenticated = await authUtils.isUserAuthenticatedAsync();
        // is the current user authenticated?
        // use var here because we may set the variable again below

        log(logHdr + 'authenticated=' + authenticated);

        if (!authenticated) {
            // if the user is not authenticated

            log(logHdr + 'user is NOT authenticated');

            var authCode = '';
            var authState = '';

            var hasCode = urlParams.has(QUERY_STRING_KEY_AUTH_CODE);
            var hasState = urlParams.has(QUERY_STRING_KEY_AUTH_STATE);
            // are the Auth0 values present in the query string?
            // if so, Auth0 put them there before it redirected to this page

            log(logHdr + 'hasCode=' + hasCode + ' (in query string)');
            log(logHdr + 'hasState=' + hasState + ' (in query string)');

            if (hasCode && hasState) {
                // if both values are in the query string

                log(logHdr + 'the query string has values for auth values state and code, so we will store those values in cookies');

                authCode = urlParams.get(QUERY_STRING_KEY_AUTH_CODE);
                authState = urlParams.get(QUERY_STRING_KEY_AUTH_STATE);

                authUtils.setAuthCode(authCode);
                authUtils.setAuthState(authState);
                // store auth code and auth state in cookies

                hasCode = true;
                hasState = true;
                // we have them now

                log(logHdr + 'atc auth0Client.handleRedirectCallback');

                await auth0Client.handleRedirectCallback();
                // process this data to get a token and store the token in auth0Client

                log(logHdr + 'bf auth0Client.handleRedirectCallback');
                log(logHdr + 'atc auth0Client.isAuthenticated');

                authenticated = await auth0Client.isAuthenticated();
                // read the authenticated value again

                log(logHdr + 'bf auth0.isAuthenticated');
                log(logHdr + 'authenticated=' + authenticated + ' (after call to handleRedirectCallback)');

                window.history.replaceState({}, document.title, PAGE_URL);
                // remove the querystring parameters
            }
        }

        if (authenticated) {
            // if the user is authenticated now

            log(logHdr + 'atc licenseUIUtils.updtTrialMenuAsync');

            await licenseUIUtils.updtTrialMenuAsync(auth0Client);
            // update the Trial menu

            log(logHdr + 'bf licenseUIUtils.updtTrialMenuAsync');

            const userAccount = await licenseUtils.getUserAccountAsync(auth0Client);
            // get the user account data

            if (userAccount === null) {
                // if failure

                log(logHdr + 'getUserAccountAsync returned NULL.  Should NOT happen.  Leaving early');
                log(logHdr + 'leave');
                return;
            }

            const userStatus = userAccount.userStatus;
            // get the user status
            // possible values:
            //  trial
            //  registered
            //  complimentary

            if (userStatus === "trial") {
                // if user has trial account

                const startDateStr = userAccount.startDate;
                // get the date the user's trial started as a string

                const startDate = new Date(startDateStr);
                // convert the string to a date

                log(logHdr + 'startDate=' + startDate);

                const expired = licenseUtils.hasTrialExpiredByStartDate(startDate);
                // given the start date, has the trial expired?

                log(logHdr + 'expired=' + expired);

                if (expired) {
                    // if the trial has expired

                    log(logHdr + 'trial has expired, so we hide the lenses content');

                    $('#divRegistered').hide();
                    $('#divBuyNow').show();
                    // hide the lenses content and show the buy now content

                    if (viewWide) {
                        // if larger screen

                        log(logHdr + 'showing the large screen buy now content');

                        $('#divBuyNowLgScrn').show();
                        $('#divBuyNowSmScrn').hide();
                        // show the large screen buy now content

                    }
                    else {
                        // if smaller screen

                        log(logHdr + 'showing the small screen buy now content');

                        $('#divBuyNowSmScrn').show();
                        $('#divBuyNowLgScrn').hide();
                        // show the small screen buy now content
                    }
                }
                else {
                    // otherwise

                    log(logHdr + 'trial has NOT expired, so we show the lenses content');

                    $('#divRegistered').show();
                    $('#divBuyNow').hide();
                    // show the lenses content and hide the buy now content
                }
            } else {
                // if user has paid or has free account

                log(logHdr + 'user status is ' + userStatus + ' so we show the lenses content');

                $('#divRegistered').show();
                $('#divBuyNow').hide();
                // show the lenses content and hide the buy now content
            }
        }
        else {
            // otherwise, hide the trial menu

            $('#divTrial').hide();
        }

        // NOTE: we need viewWidth set by the time we run the code below to decide whether to show mobile or desktop
        // version of content for unauthorized user.



        if (authenticated) {
            // if the user is logged in

            log(logHdr + 'the user is logged in');

            const user = await authUtils.logUserAsync();

            $('#divLogin').hide();

            log(logHdr + 'hid the Login button');

            if (user !== null) {
                authUIUtils.updateUIForUser(user.given_name, user.picture);
                // update the Login menu with the user's name and picture
            }

            $('#divAccount').show();
            // show the account menu

            log(logHdr + 'showed the Account menu');

            $('#divUnauth').hide();
            $('#divAuth').show();
            // show the lenses content and hide the login prompt
        }
        else {
            // if the user is NOT logged in

            log(logHdr + 'the user is NOT logged in');
            log(logHdr + 'hide the Logout button');

            $('#divAccount').hide();
            // hide the account menu

            $('#divUnauth').show();
            $('#divAuth').hide();
            // show the login prompt and hide the lenses content

            const unAuthTabs = lensHtmlUtils.showTabsOrNot();
            // should we show tabs? (i.e. is the screen wide?)

            log(logHdr + 'unAuthTabs=' + unAuthTabs);

            if (unAuthTabs) {
                // if user not authorized and screen is large

                $('#divUnauthSmScrn').hide();
                $('#divUnauthLgScrn').show();
                // hide small screen content and show large screen content
            }
            else {
                // if user is not authorized and screen is small

                $('#divUnauthSmScrn').show();
                $('#divUnauthLgScrn').hide();
                // show small screen content and hide large screen content
            }

            $('#divParent').show();
            $('#divFooter').show();
            // show the site

            return;
        }
    }
    else {
        // if login features are disabled

        $('#divLogin').hide();
        $('#divAccount').hide();
        // hide login and account menus

        $('#divUnauth').hide();
        $('#divAuth').show();
        // hide login prompt and show lenses content
    }

    log(logHdr + 'lensDTOS.length=' + lensDTOs.length);
    // make sure this code loaded

    lensUtils = new LensUtils(categoryDTOs, lensDTOs);
    // allocate and store lens utilities

    const dropDownSource = lensUtils.getLensNames();
    // get the names of all the lenses

    var defaultLensName = '';
    // the lens name to display in the combo box when it's created

    const findCount = lensesToFindStorageUtils.count();
    // how many lenses has the user specified to find?

    log(logHdr + 'findCount=' + findCount);

    if (findCount > 0) {
        // if the user specified a lens to find
        // NOTE: for now, the feature can find only one lens

        const findIds = lensesToFindStorageUtils.getLensIds();

        if (findIds.length > 0) {
            const findLensId = findIds[0];

            defaultLensName = lensUtils.getLensName(findLensId);

            log(logHdr + 'defaultLensName=' + defaultLensName);
        }
        // if the user has specified finding a lens, show its name in the find lens drop down
    }

    var placeholder = '';

    const findLensRowJQ = $('#divTopBtnsRow');
    // get a jQuery object for the row

    var centerTopBtns = false;

    if (viewWidth <= 320) {
        // we have a media query that hides the "Find Lens" caption at this width
        // without the caption, the combo box may confuse the user, so we set a placeholder here.
        // the combo box displays the placeholder when no item is selected in the combo box

        placeholder = '(find a lens)';

        if (findCount < 1) {
            // if the screen is narrow and the user hasn't found any lenses

            centerTopBtns = true;
        }
    }

    log(logHdr + 'centerTopBtns=' + centerTopBtns);

    if (centerTopBtns) {
        findLensRowJQ.removeClass('justify-content-left');
        findLensRowJQ.addClass('justify-content-center');

        $('#divColFindLens').css('margin-left', '');
        $('#divColShowHidden').css('margin-left', '');
        // when the buttons are centered, remove these left margins
    }
    else {
        findLensRowJQ.removeClass('justify-content-center');
        findLensRowJQ.addClass('justify-content-left');

        $('#divColFindLens').css('margin-left', '10px');
        $('#divColShowHidden').css('margin-left', '10px');
        // when the buttons are left-justified, set these left margins
    }

    findLensRowJQ.addClass('justify-content-');
    // center justify the contents of the row

    if (findLensComponent === null) {
        // if the combo has not already been allocated

        log(logHdr + '** findLensComponent is NULL, so we will allocate the combo');

        const dxdParams = {
            dataSource: dropDownSource,

            placeholder: placeholder,

            onInitialized: function onInitialized(e) {
                // when the combo box has been created

                const logHeader = 'onInitialized: ';
                log(logHeader + 'enter');

                findLensComponent = e.component;
                // store a reference to the component

                log(logHeader + '** set findLensComponent');

                if (defaultLensName.length > 0) {
                    e.component.option("value", defaultLensName);
                    // display the lens name in the drop down

                    prevNextLensUIUtils.show();
                }

                log(logHeader + 'leave');
            },

            contentTemplate: function contentTemplate(e) {
                log('contentTemplate: enter');

                findLensList = $("<div>").dxList({
                    dataSource: e.component.option("dataSource"),

                    selectionMode: "single",

                    onSelectionChanged: async function onSelectionChanged(arg) {
                        log('onSelectionChanged: enter');

                        const itemsAdded = arg.addedItems;
                        // get the array of items added by the user

                        const addedCount = itemsAdded.length;

                        log('onSelectionChanged: addedCount=' + addedCount);

                        if (addedCount < 1) {
                            log('onSelectionChanged: no item selected');

                            e.component.option("value", '');
                            // clear the lens name in the drop down's text area

                            log('onSelectionChanged: leave');
                            return;
                        }

                        const selItem = itemsAdded[0];

                        log('onSelectionChanged: selItem=' + selItem);

                        e.component.option("value", selItem);
                        // display the lens name in the drop down's text area

                        e.component.close();
                        // close the editor

                        const lensId = lensUtils.getLensIdByName(selItem);

                        log('onSelectionChanged: lensId=' + lensId);

                        if (lensId < 0) {
                            log('onSelectionChanged: leave');
                            return;
                        }

                        prevNextLensUIUtils.show();

                        lensesToFindStorageUtils.clear();
                        // for now, every lens the user finds clears any previous one

                        lensesToFindStorageUtils.addToLensIds(lensId);

                        tabsCardExpStorageUtils.addToLensIds(lensId);
                        noTabsCardExpStorageUtils.addToLensIds(lensId);
                        // add the lens to the list of expanded lenses for both displays: tabs and no tabs

                        prevNextLensUIUtils.showHideClearBtn();
                        // show the Clear button

                        await lensUIUtils.displayCurrentLensesAsync();
                        // display the current set of lenses

                        await uiUtils.handleLensCountChangedAsync();

                        expandCollapseBtnUtils.showHideExpandCollapseBtnsAndCol();
                        // show or hide the expand and collapse all buttons and their parent column as necessary

                        log('onSelectionChanged: leave');
                    }
                });

                log('contentTemplate: leave');

                return findLensList;
            }
        };

        $('#divDxDropDown').dxDropDownBox(dxdParams);
    }
    else {
        // otherwise

        log(logHdr + 'findLensComponent is NOT NULL, so we will NOT allocate the combo');
    }

    $('#divParent').show();
    $('#divFooter').show();
    // show the site

    if (enableLoginFeatures) {
        // if login features are enabled

        const tmrIsAuth = tmrUtils.newTimer('isUserAuthenticatedAsync').start();

        authenticated = await authUtils.isUserAuthenticatedAsync();
        // is the current user authenticated?

        tmrIsAuth.stop();
        log(logHdr + 'TIME: ' + tmrIsAuth);

        log(logHdr + 'authenticated=' + authenticated);

        if (!authenticated) {
            // if the user is not authenticated

            log(logHdr + 'user is NOT authenticated');

            authCode = '';
            authState = '';

            hasCode = urlParams.has(QUERY_STRING_KEY_AUTH_CODE);
            hasState = urlParams.has(QUERY_STRING_KEY_AUTH_STATE);
            // are the Auth0 values present in the query string?
            // if so, Auth0 put them there

            log(logHdr + 'hasCode=' + hasCode);
            log(logHdr + 'hasState=' + hasState);

            if (hasCode && hasState) {
                // if both values are in the query string

                log(logHdr + 'the query string has values for auth values state and code, so we will store those values in cookies');

                authCode = urlParams.get(QUERY_STRING_KEY_AUTH_CODE);
                authState = urlParams.get(QUERY_STRING_KEY_AUTH_STATE);

                authUtils.setAuthCode(authCode);
                authUtils.setAuthState(authState);
                // store auth code and auth state in cookies

                hasCode = true;
                hasState = true;
                // we have them now
            }

            if (hasCode && hasState) {
                // if the user has both of these query string parameters, we have data we can convert to tokens

                const tmrCreateAuth = tmrUtils.newTimer('createAuth0Client').start();

                const auth0 = await createAuth0Client({ domain: authUtils.AUTH0_DOMAIN, client_id: authUtils.AUTH0_CLIENT_ID });
                // allocate an Auth0 object
                // if the user has already authenticated, the auth0 object will be populated with info about the user

                tmrCreateAuth.stop();
                log(logHdr + 'TIME: ' + tmrCreateAuth);

                log(logHdr + 'atc auth0.handleRedirectCallback');

                await auth0.handleRedirectCallback();
                // process this data

                log(logHdr + 'bf auth0.handleRedirectCallback');
                log(logHdr + 'atc auth0.isAuthenticated');

                authenticated = await auth0.isAuthenticated();
                // read the authenticated value again

                log(logHdr + 'bf auth0.isAuthenticated');
                log(logHdr + 'authenticated=' + authenticated + '(after call to handleRedirectCallback)');

                window.history.replaceState({}, document.title, PAGE_URL);
                // remove the querystring parameters
            }
        }

        log(logHdr + 'after if (!authenticated) block');

        if (authenticated) {
            // if the user is logged in

            log(logHdr + 'the user is logged in');

            const user = await authUtils.logUserAsync();

            $('#divLogin').hide();

            log(logHdr + 'hid the Login button');

            if (user !== null) {
                authUIUtils.updateUIForUser(user.given_name, user.picture);
                // update the Login menu with the user's name and picture
            }

            $('#divAccount').show();
            // show the account menu

            log(logHdr + 'showed the Account menu');
        }
        else {
            // if the user is NOT logged in

            log(logHdr + 'the user is NOT logged in');
            log(logHdr + 'hide the Logout button');

            $('#divAccount').hide();
            // hide the account menu
        }
    }
    else {
        // if login features are disabled

        $('#divLogin').hide();
        $('#divAccount').hide();
        // hide login and account menus
    }

    // mutation-summary
    //$domObserver = $(document);
    //// get a jQuery object for the document
    //$domObserver.mutationSummary("connect", msCallback, [{ element: "div" }]);
    //// subscribe changes in the DOM relating to a div

    topBtnsUIUtils.showHideTopBtnsHR();
    // show or hide the top buttons horizontal rule
    // we do this here because the show/hide calls below may not change the state of the UI objects
    // but the state of the horizontal rule may need to change

    lensExampleUtils = new LensExampleUtils(lensExamplesDict);
    // allocate and store a utilities object for lens examples

    findWhichGroupUtils.showGroupIfNec();
    // show or hide the "which to find" button group as necessary

    findWhichGroupUtils.updateBtns();
    // update buttons to indicate which is selected

    displayByUtils.showHideDisplayByAsNec();
    // show or hide the "display by" button group as necessary

    var hasDisplayByValue = displayByStateUtils.hasValue();
    // has a display by value been stored?

    if (!hasDisplayByValue) {
        // if no "display by" value has been stored

        displayByStateUtils.setDisplayAlpha(true);
        // display lens cards alphabetically
        // which takes up less horizontal space than display by group and is simpler
    }

    displayByUtils.updateBtns();
    // update buttons to indicate which is selected

    prevNextLensUIUtils.showHideClearBtn();
    // show or hide the Clear button

    await uiUtils.handleLensCountChangedAsync();

    // NOTE: this function, onReadyAsync is called in the jQuery on ready handler
    // but also it the window's on resize handler.
    // not sure why, but on iPhone 6 device we are sometimes getting wrong results
    // when the user clicks the next image.  lens selected is too far forward in the list.
    // logs show the click handler is being called more than once.
    // for the reason, we remove handlers before assigning them in the code below.

    const btnExpandJQ = $('#btnExpandAll');
    btnExpandJQ.off('click');
    btnExpandJQ.click(expandCollapseUtils.expandAll);

    const btnCollapseJQ = $('#btnCollapseAll');
    btnCollapseJQ.off('click');
    btnCollapseJQ.click(expandCollapseUtils.collapseAll);

    const imgPrevJQ = $('#imgPrevLens');
    imgPrevJQ.off('click'); // remove any previous subscriptions
    imgPrevJQ.click(prevNextLensUIUtils.handlePrevClickAsync);

    const imgNextJQ = $('#imgNextLens');
    imgNextJQ.off('click'); // remove any previous subscriptions
    imgNextJQ.click(prevNextLensUIUtils.handleNextClickAsync);

    const findWhichJQ = $('#divFindWhichParent :input');
    findWhichJQ.off('change');
    findWhichJQ.change(function () { const elemId = this.id; findWhichGroupUtils.handleFindWhichGroupClickAsync(elemId); });
    // subscribe to the change handler for the "find which" button group

    const groupByJQ = $('#divGroupByParent :input');
    groupByJQ.off('change');
    groupByJQ.change(function () { const elemId = this.id; topBtnsUIUtils.handleGroupByGroupClickAsync(elemId); });
    // subscribe to the change handler for the "group by" button group

    const hiddenJQ = $('#btnShowHidden');
    hiddenJQ.off('click');
    hiddenJQ.click(function () { showHiddenBtnUtils.handleShowHiddenBtnClickAsync(); });
    // subscribe to click in "Show Hidden Lenses" button
    // NOTE: handleShowHiddenBtnClickAsync is an async function, but adding "await" before the function call breaks the page

    const btnClearJQ = $('#btnClearFind');
    btnClearJQ.off('click');
    btnClearJQ.click(function () { prevNextLensUIUtils.handleClearClickAsync(); });
    // subscribe to the click event for the Clear found lens button
    // NOTE: handleClearClickAsync is an async function, but adding "await" before the function call breaks the page

    const topBtnParents = $('.div-top-btns-nav');

    if (viewWide) {
        // if we will show more than one column of lenses

        topBtnParents.removeClass('justify-content-center');
        topBtnParents.addClass('justify-content-left');
        // left justify the buttons
    }
    else {
        // if we will show one column of lenses

        topBtnParents.removeClass('justify-content-left');
        topBtnParents.addClass('justify-content-center');
        // center the buttons
    }

    log(logHdr + 'atc displayCurrentLensesAsync');

    await lensUIUtils.displayCurrentLensesAsync();
    // display the current set of lenses

    log(logHdr + 'bf displayCurrentLensesAsync');

    expandCollapseBtnUtils.showHideExpandCollapseBtnsAndCol();
    // show or hide the expand all and collapse all buttons
    // and their parent column as necessary

    log(logHdr + 'leave');
}