def walkProd():
    global driver, prevTrail
    try:
        # click overlay advertisement popup left button "No Thanks"
        try:
            driver.find_element_by_css_selector("a.btn.close.fl-left").\
                    click()
        except (NoSuchElementException):
            pass

        zpath = ('#ctl00_ctl00_ctl00_mainContent_localizedContent_bodyCenter'+
                 '_adsPanel_lbProduct')
        waitTextChanged(zpath)
        curSel = Select(css(zpath))
        numProds = len(curSel.options)
        ulog("numProds=%d"%numProds)

        startIdx = getStartIdx()
        for idx in range(startIdx, numProds):
            curSel = Select(css(zpath))
            ulog("idx=%s"%idx)
            ulog('select "%s"'%curSel.options[idx].text)
            curSel.select_by_index(idx)
            prevTrail+=[idx]
            while True:
                ret = walkFile()
                if ret != TRY_AGAIN:
                    break
            if ret== PROC_GIVE_UP:
                ulog('"%s" is GIVE UP'% curSel.options[idx].text)
            prevTrail.pop()
        return PROC_OK
    except Exception as ex:
        traceback.print_exc(); ipdb.set_trace()
        driver.save_screenshot('netgear_exc.png')
 def run(self):
     while True:
         try:
             driver.find_element_by_css_selector("a.btn.close.fl-left").\
                     click()
             print('overlay terminated')
             return
         except:
             print('no overlay, sleep 1 seconds')
             time.sleep(1)
def css(path) -> WebElement:
    global driver
    return driver.find_element_by_css_selector(path)
def walkFile():
    global driver, prevTrail
    try:
        try:
            modelName = waitTextChanged('h2#searchResults', None, 5, 1)
        except TimeoutException:
            try:
                modelName = waitText('h2#searchResults', 5, 1)
            except TimeoutException:
                return PROC_GIVE_UP
        ulog('modelName="%s"'%modelName)

        resultsCount = waitText('#LargeFirmware>p')
        # try:
        #     resultsCount = waitTextChanged('#LargeFirmware>p', None, 0.5, 0.25)
        #     ulog('waitTextChanged #LargeFirmware>p')
        # except TimeoutException:
        #     ulog('TimeoutException: #LargeFirmware>p')
        #     resultsCount = waitText('#LargeFirmware>p')
        # except NoSuchElementException:
        #     ulog('NoSuchElementException: #LargeFirmware>p')
        #     resultsCount = waitText('#LargeFirmware>p')
        ulog('resutlsCount=%s'%resultsCount)
        if resultsCount.startswith('No matching'):
            return

        numFiles = int(re.search(r'\d+', resultsCount).group(0))
        ulog('numFiles=%d'%numFiles)

        try:
            waitTextChanged('#LargeFirmware a.navlistsearch',
                            None, 1, 0.5)
            ulog('waitTextChanged #LargeFirmware a.navlistsearch')
        except TimeoutException:
            ulog('TimeoutException: #LargeFirmware a.navlistsearch')
            pass
        except NoSuchElementException:
            ulog('NoSuchElementException #LargeFirmware a.navlistsearch')
            return

        if numFiles > 10:
            ulog('click moreResults because numFiles=%d>10'%numFiles)
            bMoreResultsClicked=False
            for _i in range(10):
                moreResults = waitClickable('#lnkAllDownloadMore')
                try:
                    moreResults.click()
                    ulog('moreResults.click()')
                    bMoreResultsClicked=True
                    break
                except WebDriverException:
                    time.sleep(0.5)
            if not bMoreResultsClicked:
                raise StaleElementReferenceException()

        lastFile = driver.find_element_by_css_selector('#LargeFirmware li:nth-child(%d) a.navlistsearch'%numFiles)
        for _i in range(10):
            if lastFile.is_displayed():
                break
            time.sleep(0.5)

        # try:
        #     waitTextChanged('#LargeFirmware li:nth-child(%d)'%numFiles,
        #                     None, 1, 0.5)
        #     ulog('waitTextChanged #LargeFirmware li:nth-child(%d)'%numFiles)
        # except TimeoutException:
        #     ulog('TimeoutException: #LargeFirmware li:nth-child(%d)'%numFiles)
        #     pass
        # except NoSuchElementException:
        #     ulog('NoSuchElementException #LargeFirmware li:nth-child(%d)'%numFiles)
        #     return
        # waitClickable('#LargeFirmware li:nth-child(%d) a.navlistsearch'
        #               %numFiles)

        files = getElems('#LargeFirmware a.navlistsearch')
        startIdx = getStartIdx()
        # get firmware download URL
        for idx in range(startIdx, numFiles):
            assert files[idx].is_displayed()
            fileName = files[idx].text
            ulog('idx=%d, fileName="%s"'%(idx, fileName))
            if 'firmware' not in fileName.lower():
                continue
            prevTrail+=[idx]
            storeFile(modelName, files[idx])
            prevTrail.pop()
        return PROC_OK
    except (StaleElementReferenceException):
        try:
            driver.find_element_by_css_selector("a.btn.close.fl-left").\
                    click()
            return TRY_AGAIN
        except (NoSuchElementException):
            return TRY_AGAIN
    except TimeoutException as ex:
        raise ex
    except Exception as ex:
        traceback.print_exc(); ipdb.set_trace()
        driver.save_screenshot('netgear_exc.png')
def tableRowWalker(fwVer:str):
    global startTrail,prevTrail,driver
    try:
        try:
            cells = getElems('table#imageTableContainer tr td')
        except TimeoutException:
            ulog("Timeout at getElems('table#imageTableContainer tr td'); bypass!")
            return
        assert len(cells)%4==0
        numFiles=int(len(cells)/4)
        cellTxt = [getElemText(_) for _ in cells]

        try:
            carts = getElems('table#imageTableContainer tr td input', 10)
            cartsTxt = [getElemAttr(_,'title').lower().strip() for _ in carts]
            # https://software.cisco.com/download/release.html?mdfid=282822110&flowid=266&softwareid=280805680&release=15.0.2-SE8&relind=AVAILABLE&rellifecycle=MD&reltype=latest
            # fwVer='15.0.2-SE1(ED)' has len(cells)==6 and numFiles==4
            cartsTxt = flatCarts(cartsTxt)
            assert len(cartsTxt)==numFiles
            needContracts=[ int('cart' in _) for _ in cartsTxt]
            # needContract=int(int(len(cells2)/numFiles)==2)
        except TimeoutException:
            ulog('needContract= "Deferral"')
            needContracts= [-1]*numFiles # Deferral
        ulog('needContracts=%s'%needContracts)

        quats = combinePerFour(cellTxt)
        assert len(quats)==len(needContracts)
        quats = list(zip(quats, needContracts))
        fileDescs=[]
        for quat,needContract in quats:
            fileTitle=quat[0].split('\n')[0].strip()
            fileName=quat[0].split('\n')[1].strip()
            relDate=guessDate(quat[1])
            fileSize=guessFileSize(quat[2])
            fileDescs.append((fileTitle,fileName,relDate,fileSize, needContract))

        model = waitText('td.SDPBannerTitle')
        ulog('model="%s"'%model)
        pageUrl=driver.current_url

        if startTrail:
            startIdx=startTrail.pop(0)
        else:
            startIdx=0
        ulog('startIdx=%d'%startIdx)

        try:
            imageRhSide=driver.find_element_by_css_selector('div#imageRhSide')
            driver.execute_script(
                "arguments[0].scroll(0,%d);"%(62*startIdx),
                imageRhSide)
        except:
            pass

        spans=getElems('#imageTableContainer tr td span.overlay_img')
        assert len(spans)==numFiles
        for idx in range(startIdx, numFiles):
            ulog('getSha512 Trail=%s'%(prevTrail+[idx]))
            infos = getSha512(spans[idx])
            if infos:
                infos.update(dict(needContract=needContracts[idx], model=model,
                    pageUrl=pageUrl,treeTrail=str(prevTrail+[idx])))
            else:
                fileTitle,fileName,relDate,fileSize,needContract=fileDescs[idx]
                infos=dict(fileTitle=fileTitle,fileName=fileName,relDate=relDate,
                        fileSize=fileSize,needContract=needContract,
                        pageUrl=pageUrl,treeTrail=str(prevTrail+[idx]),
                        md5=None,sha512=None,model=model,fwVer=fwVer)
            sql("INSERT OR REPLACE INTO TFiles(model,"
                " fw_date,fw_ver,file_title,file_name,file_size,"
                " need_contract, page_url, tree_trail, md5, sha512) "
                "VALUES (:model,"
                " :relDate,:fwVer,:fileTitle,:fileName,:fileSize,"
                " :needContract, :pageUrl, :treeTrail, :md5, :sha512)",
                infos)
            ulog('UPSERT "%(model)s", "%(relDate)s", "%(fwVer)s", '
                '"%(fileTitle)s", "%(fileName)s", %(needContract)d,'
                ' "%(treeTrail)s", %(pageUrl)s, "%(md5)s", "%(sha512)s"'
                %infos)
    except Exception as ex:
        ipdb.set_trace()
        print(ex); traceback.print_exc()
        driver.save_screenshot('cisco_tableRowWalker.png')