
    ic                       d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ dZdZdZdZdZdZej>                  jA                   ejB                         d      Z"dZ# e$ejJ                  jM                  dd            Z'da( e$ejJ                  jM                  dd            Z) e$ejJ                  jM                  dd            Z*d/dZ+d0dZ,d1dZ-d2dZ.d2dZ/d3dZ0d4d Z1d5d!Z2d5d"Z3d3d#Z4d3d$Z5d6d%Z6d3d&Z7d5d'Z8d7d(Z9e'fd8d)Z:d9d:d*Z;d9d:d+Z<d/d,Z=d/d-Z>e?d.k(  r e>        yy);a  
Open_PowerBi.py

Purpose
-------
Launch a *private* (incognito) Firefox window, navigate to Power BI, and perform
Microsoft login if prompted.

This script ALSO writes out a small session-info JSON file so other scripts can
attach to the already-open browser session (without reopening/logging in again).

Key fix (Jan 2026)
------------------
When this script is launched *from another process* (like Enter_PowerBi_Selector),
stdin is often NOT an interactive TTY. In that case, calling input() raises EOFError
immediately, which causes this script to exit and kills the geckodriver port before
your attach scripts can connect.

So: if stdin is not a TTY (or input() hits EOF), we keep the session alive by
sleeping until we receive SIGTERM/SIGINT (the selector will terminate us when
"Keep Power BI open" is unchecked).

Session handoff file
--------------------
By default, this script writes:  config/powerbi_session.json
to BOTH:
  1) the folder containing this script
  2) the current working directory (if different)

You can override the path with:
  - env var POWERBI_SESSION_FILE=/full/path/to/powerbi_session.json

The JSON contains:
  {
    "executor_url": "http://127.0.0.1:PORT",
    "session_id": "...",
    "download_dir": "/abs/path/to/downloads"
  }

Dependencies
------------
- Python 3.9+
- Selenium 4.x
- Firefox installed
- geckodriver available on PATH (recommended) or set GECKODRIVER_PATH

Usage
-----
  python Open_PowerBi.py
  python Open_PowerBi.py --headless
    )annotationsN)Path)	webdriver)By)WebDriverWait)expected_conditions)Service)Optionszhttps://app.powerbi.com/groups/me/apps/e65cf9b1-6444-4b63-8a86-b94e47839c83/rdlreports/c98f4a29-f532-4bf7-929d-4328ef57a6c2?experience=power-bi
Dealershipz614-WALDORF, MDFootwearzjusstin@rwsext.netzFluppyNupps49!	downloadszconfig/powerbi_session.jsonPOWERBI_READY_TIMEOUT240        #POWERBI_MFA_ACTION_COOLDOWN_SECONDS30%POWERBI_MFA_POST_TRIGGER_WAIT_SECONDS35c                    t         j                  j                  dd      j                         } | rt	        |       j                         nt	        j                         dz  }|j                         }|j                  dd       dD ]u  }t         j                  j                  |d      j                         }|r'|dv s#|j                  d      s|j                  d	      sZt        |      t         j                  |<   w y
)a  Force Selenium temp files under $HOME (avoid /tmp issues on snap/locked-down Firefox).

    On some server installs (notably snap-packaged Firefox), the browser process cannot
    access host paths like /tmp created by Selenium for its temporary Firefox profile.
    That can cause geckodriver to hang during NEW_SESSION until Selenium times out.

    We avoid that by pointing TMPDIR/TMP/TEMP to a normal, user-writable folder.
    You can override the base folder with POWERBI_TMPDIR.
    POWERBI_TMPDIR zselenium-tmpTparentsexist_ok)TMPDIRTMPTEMP)z/tmpz/var/tmpz/tmp/z	/var/tmp/N)osenvirongetstripr   
expanduserhomeresolvemkdir
startswithstr)	preferredbasekeycurs       l/home/justin/Documents/My_Sync/Shared/60_RedWing_Notes/PowerBi_Automation/Powerbi_Background/Open_PowerBi.py_ensure_selenium_tempdirr-   f   s     

/4::<I+44	?%%'499;;WD<<>DJJtdJ+( (jjnnS"%++-33s~~g7NRUR`R`alRm!$iBJJsO	(    c                 T   t         j                  j                  dd      j                         } g }| r(|j	                  t        |       j                                t         j                  j                  dd      j                         }|r)|j                  dt        |      j                                |j                  t        j                         dz  dz  dz  t        j                         dz  d	z  g       |D ]  }	 |j                  d
d
       t        j                  |d       |j                         r^t        j                  |t         j                  t         j                  z        r)t!        |      t         j                  d<   t!        |      c S  | S # t"        $ r Y w xY w)z<Provide a private runtime dir when cron does not export one.XDG_RUNTIME_DIRr   POWERBI_XDG_RUNTIME_DIRr   z.localrunpowerbiz.cachezpowerbi-xdg-runtimeTr   i  )r   r   r    r!   appendr   r"   insertextendr#   r%   chmodis_diraccessW_OKX_OKr'   	Exception)current
candidatesoverride	candidates       r,   _ensure_xdg_runtime_dirrA   |   sS   jjnn.399;GJ$w-2245zz~~7<BBDH!T(^6689		h&2		h!66 
   		OOD4O8HHY&!bii	277RWW;L&M03I

,-9~% N  		s    BF	F'&F'c                2    t        j                  | d       y)z%Ensure the download directory exists.T)r   N)r   makedirs)paths    r,   ensure_download_directoryrE      s    KKt$r.   c                 6   g } t         j                  j                  dd      j                         }|r| j	                  |       dD ]  }| j	                  |        dD ]+  }t        j                  |      }|s| j	                  |       - t               }| D ]  }|r||v r
|j                  |       t         j                  j                  |      s;t        j                  |t         j                        s`t         j                  j                  |      c S  y)z7Resolve Firefox even when cron provides a reduced PATH.FIREFOX_BINARYr   )z-/snap/firefox/current/usr/lib/firefox/firefoxz/snap/bin/firefoxz/usr/bin/firefoxz/usr/bin/firefox-esrz/usr/local/bin/firefoxz/usr/local/bin/firefox-esrz/usr/lib/firefox/firefoxz/usr/lib64/firefox/firefox)firefoxzfirefox-esrN)r   r   r    r!   r4   shutilwhichsetaddrD   isfiler9   r;   abspath)r>   env_pathfixedname
which_pathseenr@   s          r,   _resolve_firefox_binaryrT      s    Jzz~~.399;H(#	 
! 	% 
! + *\\$'
j)*
 UD .	I-77>>)$9bgg)F77??9--. r.   c                    t         j                  j                  dd      j                         } | rt         j                  j                  |       rst         j                  j                  | t         j                  dk(  rdnd      }t         j                  j                  |      rt         j                  j                  |      S t         j                  j                  |       rt         j                  j                  |       S g }dD ]+  }t        j                  |      }|s|j                  |       - |j                  t        t        j                          dz  dz        dd	d
g       t#               }|D ]  }|r||v r
|j%                  |       t         j                  j                  |      s;t        j&                  |t         j(                        s`t         j                  j                  |      c S  y)z
    Resolve geckodriver path cross-platform.
    Priority:
      1) GECKODRIVER_PATH env var
      2) PATH (shutil.which)

    Returns an absolute path string, or None to let Selenium try defaults.
    GECKODRIVER_PATHr   ntgeckodriver.exegeckodriver)rY   rX   binz/snap/bin/geckodriverz/usr/bin/geckodriverz/usr/local/bin/geckodriverN)r   r   r    r!   rD   isdirjoinrQ   rM   rN   rI   rJ   r4   r6   r'   r   r#   rK   rL   r9   r;   )rO   candr>   rQ   rR   rS   r@   s          r,   _resolve_geckodriverr^      su    zz~~0"5;;=H77=="77<<%'WW_!-D ww~~d#wwt,,77>>(#77??8,,J2 *\\$'
j)*
 DIIK%-/0$	  UD .	I-77>>)$9bgg)F77??9--. r.   c                ~   t        | dd      }|4t        |dd      }|rt        |      S t        |dd      }|rt        |      S t        | dd      }|	 t        |dd      }|rt        |      S 	 |4t        |dd      }|rt        |      S t        |dd      }|rt        |      S t        d	      # t        $ r Y Lw xY w)
z?
    Determine the running WebDriver command executor URL.
    command_executorN_urlurlserviceservice_urladdressremote_server_addrzCould not determine executor URL from WebDriver. Please ensure that your version of Selenium exposes either 'command_executor._url', 'command_executor.url' or that the driver service provides 'service_url'.)getattrr'   r<   RuntimeError)drivercerb   rc   s       r,   _get_executor_urlrk      s     
+T	2B	~b&$'s8Ob%&s8Ofi.G	'=$7C3x 
 
~b)T*s8Ob.5s8O
	=   		s   B0 0	B<;B<c                   t        |       }| j                  }||t        t        |      j	                         j                               d}t        j                  j                  dd      j                         }g }|rt        |      j	                         j                         }|j                  j                  dd       |j                  t        j                  |d      d	       |j                  |       |S t        t               j                         j                  }t        j"                         j                         }	||	hD ]b  }
|
t$        z  }	 |j                  j                  dd       |j                  t        j                  |d      d	       |j                  |       d |st)        d
      |S # t&        $ r Y w xY w)zn
    Write session info to a JSON file so other scripts can attach.

    Returns a list of paths written.
    )executor_url
session_iddownload_dirPOWERBI_SESSION_FILEr   Tr      )indentutf-8encodingz?Failed to write session file anywhere (permissions/path issue).)rk   rn   r'   r   r"   r$   r   r   r    r!   parentr%   
write_textjsondumpsr4   __file__cwdSESSION_FILENAMEr<   rh   )ri   ro   rm   rn   payloadr?   writtenp
script_dircwd_dirr)   s              r,   write_session_filer     s    %V,L""J % D.99;CCEFG zz~~4b9??AHGN%%'//1	td3	TZZ2WEqh'')00Jhhj  "GW% ##	HHNN4$N7LLGA6LINN1 \]]N  		s   AF>>	G
	G
c                    t         j                  j                  dt              }t         j                  j                  dt              }|r|syt        | d      }d}t        j                  dft        j                  dft        j                  dft        j                  dffD ]+  }	 |j                  t        j                  |            }| n- |	 |j                          	 |j                  |       t!        d	       t        j                  d
ft        j                  dft        j"                  dft        j"                  dffD ].  }	  | j$                  | }|j'                          t!        d        n d}t        j                  dft        j                  dft        j                  dffD ]+  }	 |j                  t        j                  |            }| n- |	 |j                          	 |j                  |       t!        d       t        j                  dft        j"                  dft        j"                  dffD ].  }	  | j$                  | }|j'                          t!        d        n 	 | j%                  t        j                  d      }|j'                          t!        d       t)        j(                         }	t+        dt,              }
|	t.        z
  |
k  ryd}t        j                  dft        j"                  dft        j                  dffD ]4  }	  | j$                  | j0                  xs dj3                         }|r|} n6 |rt!        d|        d}|rt        j                  dft        j                  dft        j                  dffD ]d  }	 t        | d      j                  t        j4                  |            }|j'                          d }t!        d!       t)        j6                  d"        n d}t        j                  d#ft        j                  d$ft        j                  d%ffD ]O  }	 t        | d      j                  t        j4                  |            }|j'                          d }t!        d&        n d}|s|rt        j                  d'ft        j                  d(ft        j                  d)ffD ]O  }	 t        | d      j                  t        j4                  |            }|j'                          d }t!        d*        n |s|s|r&|	at)        j6                  t+        d+t8                     yy# t        $ r Y w xY w# t        $ r Y yw xY w# t        $ r Y lw xY w# t        $ r Y 6w xY w# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y {w xY w# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y Vw xY w# t        $ r Y w xY w# t        $ r Y Kw xY w),zO
    Perform a two-step login into the Microsoft account used by Power BI.
    POWERBI_USERNAMEPOWERBI_PASSWORDN   emaili0116loginfmtz\//input[@type='email' or contains(@placeholder, 'Email') or contains(@placeholder, 'email')]zEntered Microsoft username.	submitBtnidSIButton9zinput[type='submit']zbutton[type='submit']zSubmitted username step.i0118passwdz//input[@type='password']zEntered Microsoft password.zSubmitted password step.z Confirmed stay signed in prompt.   r   idSpan_SAOTCC_Error_OTCz#idDiv_SAOTCC_ErrorMsg_OTCz?//*[contains(@class,'alert-error') or contains(@id,'ErrorMsg')]zMFA notice: Fz}//input[@type='button' and contains(translate(@value,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'try again')]zw//button[contains(translate(normalize-space(.),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'try again')]zr//a[contains(translate(normalize-space(.),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'try again')]rq   TzClicked MFA 'Try again'.      ?z>//div[@data-value='TwoWayVoiceOffice' and contains(., 'Call')]z//*[self::div or self::button][contains(translate(normalize-space(.), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'call me')]z//*[self::div or self::button][contains(translate(normalize-space(.), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'call')]zClicked the 'Call me' option.idSubmit_SAOTCC_Continuezz//input[@type='submit' and contains(translate(@value,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'verify')]zt//button[contains(translate(normalize-space(.),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'verify')]z Triggered MFA verification call.
   )r   r   r    HARDCODED_USERNAMEHARDCODED_PASSWORDr   r   IDNAMEXPATHuntilECpresence_of_element_locatedr<   clear	send_keysprintCSS_SELECTORfind_elementclicktimemaxMFA_ACTION_COOLDOWN_SECONDS_LAST_MFA_ACTION_TStextr!   element_to_be_clickablesleepMFA_POST_TRIGGER_WAIT_SECONDS)ri   usernamepasswordwaitemail_inputlocatorbtnpassword_inputstay_btnnowcooldownmfa_error_texttxtretry_clickedcall_clickedvoice_call_tileverify_clickeds                    r,   login_if_requiredr   @  s*    zz~~02DEHzz~~02DEH#D K			*	qr	 	**R%C%CG%LMK& ' 		!!(+/0
 UUK UUM"__45__56	
 	G)f))73		01	 N		(	./ 

	!ZZ(F(Fw(OPN) *
 !	  "	$$X./0
 UUM"__45__56
 	G
)f))73		01	&&ruum<01 ))+C112H
  8+N	)*	67	TU 
	&6&&055;BBDC!$  ^,-.MXX  W  XXX  Q  RXX  L  M
 	G
#FA.44R5O5OPW5XY		 $01

3	 L	ST	  d  	e	  a  	b 
	+FA6<<R=W=WX_=`aO!!#L12 N}UU./XX  T  UXX  N  O
 	G
#FA.44R5O5OPW5XY		!%89	 }!

3r89: )7e  		  		
  		    		  		
  		    *  		(    		   s   &&U U $U  
*U02&V V 0V  *V03;W  /WA W 8AW0AX  	UU	UU 	U-,U-0	U=<U= 	VV	VV 	V-,V-0	V=<V= 	WW	WW 	W-,W-0	W=<W= 	XXc                    t        |        y N)r   ri   s    r,   login_microsoft_if_promptedr     s
    fr.   c                ^    	 | j                   xs dj                         S # t        $ r Y yw xY wNr   )current_urlr!   r<   r   s    r,   _safe_current_urlr     s3    ""(b//11      	,,c                ^    	 | j                   xs dj                         S # t        $ r Y yw xY wr   )titler!   r<   r   s    r,   _safe_titler     s1    "))++ r   c                n    | j                         }|j                         }d|v xs d|v xs
 d|v xs d|v S )Nzlogin.microsoftonline.comz/singlesignonz/signinzsign in)lower)rb   r   uts       r,   _is_auth_or_sso_pager      sL    		AA#q( 	a	>	 >	r.   c                J   g }t         j                  dft         j                  dft         j                  dft         j                  dft         j                  dft         j                  dft         j                  dffD ]I  }	  | j                  | D ]4  }|j
                  xs dj                         }|s$|j                  |       6 K t               }g }|D ])  }||vs|j                  |       |j                  |       + d	j                  |d
d       S # t        $ r Y w xY w)zDBest-effort capture of visible Microsoft login error/challenge text.usernameErrorpasswordError
i0116Error
i0118Errorz[role='alert']z".error, .error-msg, .error-messagez6//*[contains(@class,'error') or contains(@id,'error')]r   z | N   )r   r   r   r   find_elementsr   r!   r4   r<   rK   rL   r\   )ri   r>   r   elr   rS   outs          r,   _extract_login_error_textr     s   J	 	 			*+	>?	KL 	*f**G4 +ww}"++-%%c*+  5DC d?HHSMJJsO ::c"1g  		s    2D3D	D"!D"c                   t        j                         j                         dz  }|j                  dd       t	        t        t        j                                     }|d| dz  }|d| dz  }	 | j                  t	        |             t        d|        	 |j                  | j                  xs dd	
       t        d|        y # t        $ r Y <w xY w# t        $ r Y y w xY w)Npowerbi_login_debugTr   login_timeout_z.pngz.htmlzSaved login debug screenshot: r   rs   rt   zSaved login debug HTML: )r   r{   r$   r%   r'   intr   save_screenshotr   r<   rw   page_source)ri   out_dirstamppnghtmls        r,   _dump_login_debugr   '  s    hhj  "%::GMM$M.DIIK !E
nUG40
0C~eWE22Ds3x(.se45**0b7C(/0	  
  s$   2(C /C 	CC	C&%C&c                   t        |       }t        |       }|syt        ||      ryd|j                         vry|j                         }d|v rd|v rydD ]%  }	 | j	                  t
        j                  |      r y' y# t        $ r Y 4w xY w)z>True when authenticated and on a report-capable Power BI page.Fapp.powerbi.com/rdlreports/z/groups/T)z,iframe[src*='paginated-reports.powerbi.com']ziframe[src*='/rdlreports/']ziframe[src*='rdlembed'])r   r   r   r   r   r   r   r<   )ri   rb   r   lowsels        r,   _is_report_readyr   9  s    
F
#CEC'		+ ))+Cs!2 	
	##BOOS9 :	   		s    A>>	B
	B
c                   t        j                          |z   }d}d}t        j                          |k  rt        |        t        |       ryt        j                          }||z
  dk\  rZd}t        t	        |       t        |             rt        |       }t        ddt	        |       dt        |       |rd|nd       |}t	        |       j                         }||z
  d	k\  r5d
|v r1t        |t        |             sd|vr	 | j                  t               |}t        j                  d       t        j                          |k  rt        |        t        dt	        |       dt        |             # t        $ r Y iw xY w)zCWait until login is truly complete and report context is available.r   Nr   r   z(Waiting for authenticated report page...zurl=ztitle=zlogin_error=   r   r   r   zDTimed out waiting for authenticated Power BI report page. Last URL: z	; title: )r   r   r   r   r   r   r   r   r   r    POWERBI_REPORT_URLr<   r   r   TimeoutError)ri   timeoutdeadlinelast_loglast_navr   	login_errr+   s           r,   wait_for_authenticated_reportr   X  s|   yy{W$HHH
))+
 #F+F#iik>QI#$5f$={6?RS5f=	:(034V,/01:<	}-	 H  '--/(Nb !S((k&.ABc)

-. H

3C ))+
 F f
	&v.1;v;N:Q	S   s    E3 3	E?>E?c                   t                t               }t        j                  j	                  dd       | r t        j                  j	                  dd       t               }t               }|r||_        |j                  dd       t        j                  j                  dt              }t        t        |      j                         j                               }t        |       |j                  dd       |j                  d	|       |j                  d
d       |j                  dd       |j                  dd       |j                  dd       |j                  dd       dj!                  g d      }|j                  d|       |j                  d|       |j                  dd       |j                  dd       | r|j#                  d       t%               }t'        d|xs d        t'        d|xs d        t'        dt        j                  j                  dd              t'        d|xs  t        j                  j                  dd              |rt)        |      n	t)               }t+        j,                  ||       |fS )!NNO_AT_BRIDGE1MOZ_HEADLESSz!browser.privatebrowsing.autostartTPOWERBI_DOWNLOAD_DIRzbrowser.download.folderListrq   zbrowser.download.dirzbrowser.download.useDownloadDirz)browser.download.manager.showWhenStartingFz*browser.download.manager.focusWhenStartingz browser.download.alwaysOpenPanelz'browser.download.manager.alertOnEXEOpen,)zapplication/octet-streamzbinary/octet-streamzapplication/downloadzapplication/x-downloadzapplication/pdfztext/csvzapplication/csvzapplication/vnd.ms-excelzAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetzapplication/zipzapplication/x-zip-compressedz
text/plainz&browser.helperApps.neverAsk.saveToDiskz$browser.helperApps.neverAsk.openFilez"browser.helperApps.alwaysAsk.forcezpdfjs.disabled	-headlesszFirefox binary: zdefault lookupzGeckodriver: zTMPDIR: r   r   zXDG_RUNTIME_DIR: r0   )executable_path)rc   options)r-   rA   r   r   
setdefaultFirefoxOptionsrT   binary_locationset_preferencer    DOWNLOAD_DIRr'   r   r"   r$   rE   r\   add_argumentr^   r   FirefoxServicer   Firefox)headlessruntime_diroptsfirefox_binaryro   	never_askrY   rc   s           r,   build_driverr    s-   )+KJJ.#.


nc2D,.N- 	;TB ::>>"8,GLtL)446>>@ALl+5q9.=94@CUKDeL:EBA5I  I 	@)L>	J<eD($/+&&(K	^?/?@
AB	M+9)9:
;<	HRZZ^^Hb12
34	kRRZZ^^<Mr-RS
TU=Hn[9nN^GWd;\IIr.   c                   t        |       \  }}	 |j                          |j                  t               t        |       t        |t               	 t        d|j                         ||fS # t        $ r Y Ww xY w# t        $ r Y ||fS w xY w)Nr  )r   z Current URL after login attempt:)
r  maximize_windowr<   r    r   r   r   READY_TIMEOUT_SECONDSr   r   )r  ri   ro   s      r,   open_powerbi_sessionr    s    ':FL  JJ!"'!&2GH0&2D2DE <    <s#   A- A< -	A98A9<	B
Bc                 0    	 t        j                  d       )Ni  )r   r    r.   r,   _keep_alive_loopr    s    


4 r.   c                    t        d dD              } t        |       \  }}	 t        ||      }t        d       |D ]  }t        d|         t        d       t        d	       t        d
       t        d       	 t
        j                  Ct        t
        j                  d      r)t
        j                  j                         rt                n
t                	 |j                          y # t        $ r}t        d| d       Y d }~d }~ww xY w# t        t        f$ r Y Hw xY w# t        $ r Y y w xY w# 	 |j                          w # t        $ r Y w w xY wxY w)Nc              3  @   K   | ]  }|t         j                  v   y wr   )sysargv).0as     r,   	<genexpr>z$keep_open_forever.<locals>.<genexpr>  s     FQ1=Fs   )r   z
--headlessr  z
Wrote session file(s):z  - z.Other scripts can now attach using this file.
z(
WARNING: Could not write session file: 
zPower BI window is open.z6Leave this terminal running to keep the session alive.z@Press ENTER to close the browser (TTY only), or Ctrl+C to stop.
isatty)anyr  r   r   r<   r  stdinhasattrr  inputr  KeyboardInterruptEOFErrorquit)r  ri   ro   written_pathsr   es         r,   keep_open_foreverr!    s8   F*EFFH/BFLA*6<@() 	AD*	?@ 

$%	
BC	
MN99 WSYY%AciiFVFVFXG
	KKM%  A9!B?@@A x(   			KKM 		sr   7C+ <AD D% +	D4DDD"D4 !D""D4 %	D10D14E6EE	EEEE__main__)returnNone)r#  r'   )rD   r'   r#  r$  )r#  z
str | None)ri   webdriver.Firefoxr#  r'   )ri   r%  ro   r'   r#  z
list[Path])ri   r%  r#  r$  )rb   r'   r   r'   r#  bool)ri   r%  r#  r&  )ri   r%  r   r   r#  r$  )F)r  r&  r#  ztuple[webdriver.Firefox, str])@__doc__
__future__r   rx   r   r  r   rI   pathlibr   seleniumr   selenium.webdriver.common.byr   selenium.webdriver.support.uir   selenium.webdriver.supportr   r   "selenium.webdriver.firefox.servicer	   r   "selenium.webdriver.firefox.optionsr
   r   r   
STORE_TYPESTORE_NOCATEGORYr   r   rD   r\   getcwdr   r|   r   r   r    r
  r   r   r   r-   rA   rE   rT   r^   rk   r   r   r   r   r   r   r   r   r   r   r  r  r  r!  __name__r  r.   r,   <module>r5     sk  2h #  	 
     + 7 @ H H
 V 
 
 * %  ww||IBIIK5 1  BJJNN+BEJK   !"**..1VX\"]^  #BJJNN3Z\`$a b (,:%
!H+\"J(Vk;\8$> Mb -`:Jz (B z r.   