package Ġorg . simple . clin ic . activity Ċ Ċ import Ġcom . f 2 pr ate ek . rx . preferences 2 . Preference Ċ import Ġcom . google . common . truth . Truth . assertThat Ċ import Ġcom . n ha ar man . mockito _ kotlin . any Ċ import Ġcom . n ha ar man . mockito _ kotlin . check Ċ import Ġcom . n ha ar man . mockito _ kotlin . mock Ċ import Ġcom . n ha ar man . mockito _ kotlin . never Ċ import Ġcom . n ha ar man . mockito _ kotlin . times Ċ import Ġcom . n ha ar man . mockito _ kotlin . verify Ċ import Ġcom . n ha ar man . mockito _ kotlin . verify No More Interactions Ċ import Ġcom . n ha ar man . mockito _ kotlin . wh enever Ċ import Ġio . reactivex . Observable Ċ import Ġio . reactivex . Single Ċ import Ġio . reactivex . subjects . Publish Subject Ċ import Ġjunit params . JUnit Params Runner Ċ import Ġjunit params . Parameters Ċ import Ġorg . junit . Before Ċ import Ġorg . junit . Rule Ċ import Ġorg . junit . Test Ċ import Ġorg . junit . runner . RunWith Ċ import Ġorg . simple . clin ic . activity . Activity Lifecycle . Started Ċ import Ġorg . simple . clin ic . activity . Activity Lifecycle . Stopped Ċ import Ġorg . simple . clin ic . forgot pin . cre aten ew pin . Forgot Pin Create New Pin Screen Key Ċ import Ġorg . simple . clin ic . home . Home Screen Key Ċ import Ġorg . simple . clin ic . login . app lock . App Lock Config Ċ import Ġorg . simple . clin ic . main . The Activity Ċ import Ġorg . simple . clin ic . main . The Activity Controller Ċ import Ġorg . simple . clin ic . patient . Patient M ocker Ċ import Ġorg . simple . clin ic . registration . phone . Registration Phone Screen Key Ċ import Ġorg . simple . clin ic . router . screen . FullScreen Key Ċ import Ġorg . simple . clin ic . user . User Ċ import Ġorg . simple . clin ic . user . User . LoggedIn Status . LOG GED _ IN Ċ import Ġorg . simple . clin ic . user . User . LoggedIn Status . NOT _ LOG GED _ IN Ċ import Ġorg . simple . clin ic . user . User . LoggedIn Status . OTP _ REQUEST ED Ċ import Ġorg . simple . clin ic . user . User . LoggedIn Status . RESET TING _ PIN Ċ import Ġorg . simple . clin ic . user . User . LoggedIn Status . RESET _ PIN _ REQUEST ED Ċ import Ġorg . simple . clin ic . user . User . LoggedIn Status . UN AUTHORIZ ED Ċ import Ġorg . simple . clin ic . user . User Session Ċ import Ġorg . simple . clin ic . user . User Status Ċ import Ġorg . simple . clin ic . util . Just Ċ import Ġorg . simple . clin ic . util . None Ċ import Ġorg . simple . clin ic . util . Optional Ċ import Ġorg . simple . clin ic . util . Rx Errors Rule Ċ import Ġorg . simple . clin ic . widgets . Ui Event Ċ import Ġorg . th reet en . bp . Instant Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ @ RunWith ( JUnit Params Runner :: class ) Ċ class ĠThe Activity Controller Test Ġ{ ĊĊĠ Ġ@ get : Rule ĊĠ Ġval Ġrx Errors Rule Ġ= ĠRx Errors Rule () ĊĊĠ Ġprivate Ġval Ġlock In Minutes Ġ= Ġ 1 5 L ĊĊĠ Ġprivate Ġval Ġactivity Ġ= Ġmock < The Activity >() ĊĠ Ġprivate Ġval Ġuser Session Ġ= Ġmock < User Session >() ĊĠ Ġprivate Ġval Ġlock After Timestamp Ġ= Ġmock < Preference < Instant >>() ĊĠ Ġprivate Ġval Ġui Events Ġ= ĠPublish Subject . create < Ui Event >() ĊĠ Ġprivate Ġval Ġuser Subject Ġ= ĠPublish Subject . create < Optional < User >>() ĊĠ Ġprivate Ġval Ġuser Unauthorized Subject Ġ= ĠPublish Subject . create < Boolean >() ĊĊĠ Ġprivate Ġval Ġcontroller Ġ= ĠThe Activity Controller ( ĊĠĠĠĠĠ Ġuser Session Ġ= Ġuser Session , ĊĠĠĠĠĠ Ġapp Lock Config Ġ= ĠSingle . just ( App Lock Config ( lock After Time Millis Ġ= ĠTimeUnit . MIN UTES . to Millis ( lock In Minutes ))), ĊĠĠĠĠĠ Ġlock After Timestamp Ġ= Ġlock After Timestamp ĊĠ Ġ) ĊĊĠ Ġ@ Before ĊĠ Ġfun ĠsetUp () Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User Unauthorized ()). thenReturn ( user Unauthorized Subject ) ĊĠĠĠ Ġwhenever ( user Session . logged In User ()). thenReturn ( user Subject ) ĊĊĠĠĠ Ġui Events ĊĠĠĠĠĠĠĠ Ġ. compose ( controller ) ĊĠĠĠĠĠĠĠ Ġ. subscribe Ġ{ Ġui Change Ġ-> Ġui Change ( activity ) Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` when Ġactivity Ġis Ġstarted Ġand Ġuser Ġis Ġlogged Ġout Ġthen Ġapp Ġlock Ġshouldn 't Ġbe Ġshown `() Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User LoggedIn ()). thenReturn ( false ) ĊĊĠĠĠ Ġui Events . onNext ( Started ( null )) ĊĊĠĠĠ Ġverify ( activity , Ġnever ()). show App Lock Screen () ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġ@ Parameters ( value Ġ= Ġ[ ĊĠĠĠ Ġ" NOT _ LOG GED _ IN | false ", ĊĠĠĠ Ġ" OTP _ REQUEST ED | true ", ĊĠĠĠ Ġ" LOG GED _ IN | true ", ĊĠĠĠ Ġ" RESET TING _ PIN | false ", ĊĠĠĠ Ġ" RESET _ PIN _ REQUEST ED | true " ĊĠ Ġ]) ĊĠ Ġfun Ġ` when Ġactivity Ġis Ġstarted , Ġuser Ġis Ġlogged Ġin Ġand Ġuser Ġwas Ġinactive Ġthen Ġapp Ġlock Ġshould Ġbe Ġshown `( ĊĠĠĠĠĠ Ġlogged In Status : ĠUser . LoggedIn Status , ĊĠĠĠĠĠ Ġshould Show App Lock : ĠBoolean ĊĠ Ġ) Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User LoggedIn ()). thenReturn ( true ) ĊĠĠĠ Ġwhenever ( user Session . logged In User ()). thenReturn ( Observable . just ( Just ( Patient M ocker . logged In User ( logged In Status Ġ= Ġlogged In Status )))) ĊĊĠĠĠ Ġval Ġlock After Time Ġ= ĠInstant . now (). minus Seconds ( TimeUnit . MIN UTES . to Seconds ( 1 )) ĊĠĠĠ Ġwhenever ( lock After Timestamp . get ()). thenReturn ( lock After Time ) ĊĊĠĠĠ Ġui Events . onNext ( Started ( null )) ĊĊĠĠĠ Ġif Ġ( should Show App Lock ) Ġ{ ĊĠĠĠĠĠ Ġverify ( activity ). show App Lock Screen () ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠ Ġverify ( activity , Ġnever ()). show App Lock Screen () ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` when Ġapp Ġis Ġstopped Ġand Ġlock Ġtimer Ġis Ġunset Ġthen Ġthe Ġtimer Ġshould Ġbe Ġupdated `() Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User LoggedIn ()). thenReturn ( true ) ĊĠĠĠ Ġwhenever ( lock After Timestamp . get ()). thenReturn ( Instant . MAX ) ĊĠĠĠ Ġwhenever ( lock After Timestamp . isSet ). thenReturn ( false ) ĊĊĠĠĠ Ġui Events . onNext ( Stopped ( null )) ĊĊĠĠĠ Ġverify ( lock After Timestamp ). set ( check Ġ{ ĊĠĠĠĠĠ Ġ// ĠNot Ġthe Ġbest Ġway , Ġbut Ġworks . ĊĠĠĠĠĠ Ġit Ġ> ĠInstant . now (). minus Seconds ( 1 ) ĊĠĠĠ Ġ}) ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` when Ġapp Ġis Ġstopped Ġand Ġlock Ġtimer Ġis Ġset Ġthen Ġthe Ġtimer Ġshould Ġnot Ġbe Ġupdated `() Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User LoggedIn ()). thenReturn ( true ) ĊĠĠĠ Ġwhenever ( lock After Timestamp . isSet ). thenReturn ( true ) ĊĠĠĠ Ġwhenever ( lock After Timestamp . get ()). thenReturn ( Instant . now ()) ĊĊĠĠĠ Ġui Events . onNext ( Stopped ( null )) ĊĊĠĠĠ Ġverify ( lock After Timestamp , Ġnever ()). set ( any ()) ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` when Ġapp Ġis Ġstarted Ġun locked Ġand Ġlock Ġtimer Ġhasn 't Ġexpired Ġyet Ġthen Ġthe Ġtimer Ġshould Ġbe Ġunset `() Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User LoggedIn ()). thenReturn ( true ) ĊĠĠĠ Ġwhenever ( user Session . logged In User ()) ĊĠĠĠĠĠĠĠ Ġ. thenReturn ( Observable . just ( Just ( Patient M ocker . logged In User ( logged In Status Ġ= ĠLOG GED _ IN )))) ĊĊĠĠĠ Ġval Ġlock After Time Ġ= ĠInstant . now (). plus Seconds ( TimeUnit . MIN UTES . to Seconds ( 1 0 )) ĊĠĠĠ Ġwhenever ( lock After Timestamp . get ()). thenReturn ( lock After Time ) ĊĊĠĠĠ Ġui Events . onNext ( Started ( null )) ĊĊĠĠĠ Ġverify ( lock After Timestamp ). delete () ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` when Ġapp Ġis Ġstarted Ġlocked Ġand Ġlock Ġtimer Ġhasn 't Ġexpired Ġyet Ġthen Ġthe Ġtimer Ġshould Ġnot Ġbe Ġunset `() Ġ{ ĊĠĠĠ Ġwhenever ( user Session . is User LoggedIn ()). thenReturn ( true ) ĊĊĠĠĠ Ġval Ġlock After Time Ġ= ĠInstant . now (). minus Seconds ( TimeUnit . MIN UTES . to Seconds ( 5 )) ĊĠĠĠ Ġwhenever ( lock After Timestamp . get ()). thenReturn ( lock After Time ) ĊĊĠĠĠ Ġui Events . onNext ( Started ( null )) ĊĊĠĠĠ Ġverify ( lock After Timestamp , Ġnever ()). delete () ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġ@ Parameters ( ĊĠĠĠĠĠ Ġ" OTP _ REQUEST ED | LOG GED _ IN | LOG GED _ IN | true ", ĊĠĠĠĠĠ Ġ" LOG GED _ IN | LOG GED _ IN | LOG GED _ IN | false " ĊĠ Ġ) ĊĠ Ġfun Ġ` when Ġa Ġuser Ġis Ġverified Ġfor Ġlogin , Ġthe Ġlogged Ġout Ġalert Ġmust Ġbe Ġshown `( ĊĠĠĠĠĠ Ġprev logged In Status : ĠUser . LoggedIn Status , ĊĠĠĠĠĠ Ġcur LoggedIn Status : ĠUser . LoggedIn Status , ĊĠĠĠĠĠ Ġnext LoggedIn Status : ĠUser . LoggedIn Status , ĊĠĠĠĠĠ Ġshould Show Logged Out Alert : ĠBoolean ĊĠ Ġ) Ġ{ ĊĠĠĠ Ġval Ġuser Ġ= ĠPatient M ocker . logged In User ( status Ġ= ĠUser Status . Approved For Sync ing , Ġlogged In Status Ġ= Ġprev logged In Status ) ĊĠĠĠ Ġwhenever ( lock After Timestamp . get ()). thenReturn ( Instant . MAX ) ĊĠĠĠ Ġwhenever ( user Session . logged In User ()). thenReturn ( ĊĠĠĠĠĠĠĠ ĠObservable . just ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠJust ( user ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠJust ( user . copy ( logged In Status Ġ= Ġcur LoggedIn Status )), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠJust ( user . copy ( logged In Status Ġ= Ġnext LoggedIn Status ))) ĊĠĠĠ Ġ) ĊĊĠĠĠ Ġui Events . onNext ( Started ( null )) ĊĊĠĠĠ Ġif Ġ( should Show Logged Out Alert ) Ġ{ ĊĠĠĠĠĠ Ġverify ( activity ). show User Logged Out On Other Device Alert () ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠ Ġverify ( activity , Ġnever ()). show User Logged Out On Other Device Alert () ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġ@ Parameters ( method Ġ= Ġ" params Ġfor Ġlocal Ġuser Ġinitial Ġscreen Ġkey ") ĊĠ Ġfun Ġ` when Ġa Ġlocal Ġuser Ġexists , Ġthe Ġappropriate Ġinitial Ġkey Ġmust Ġbe Ġreturned Ġbased Ġon Ġthe Ġlogged Ġin Ġstatus `( ĊĠĠĠĠĠ Ġlogged In Status : ĠUser . LoggedIn Status , ĊĠĠĠĠĠ Ġexpected KeyType : ĠClass < FullScreen Key > ĊĠ Ġ) Ġ{ ĊĠĠĠ Ġval Ġuser Ġ= ĠPatient M ocker . logged In User ( logged In Status Ġ= Ġlogged In Status ) ĊĠĠĠ Ġwhenever ( user Session . logged In User ()). thenReturn ( Observable . just ( Just ( user ))) ĊĊĠĠĠ ĠassertThat ( controller . initial Screen Key ()). isInstanceOf ( expected KeyType ) ĊĠ Ġ} ĊĊĠ Ġ@ Suppress (" Unused ") ĊĠ Ġprivate Ġfun Ġ` params Ġfor Ġlocal Ġuser Ġinitial Ġscreen Ġkey ` (): ĠArray < Array < Any >> Ġ{ ĊĠĠĠ Ġfun ĠtestCase ( ĊĠĠĠĠĠĠĠ Ġlogged In Status : ĠUser . LoggedIn Status , ĊĠĠĠĠĠĠĠ Ġexpected KeyType : ĠClass < *> ĊĠĠĠ Ġ): ĠArray < Any > Ġ{ ĊĠĠĠĠĠ Ġreturn ĠarrayOf ( logged In Status , Ġexpected KeyType ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġreturn ĠarrayOf ( ĊĠĠĠĠĠĠĠ ĠtestCase ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogged In Status Ġ= ĠNOT _ LOG GED _ IN , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected KeyType Ġ= ĠRegistration Phone Screen Key :: class . java ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠtestCase ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogged In Status Ġ= ĠO TP _ REQUEST ED , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected KeyType Ġ= ĠHome Screen Key :: class . java ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠtestCase ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogged In Status Ġ= ĠRESET _ PIN _ REQUEST ED , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected KeyType Ġ= ĠHome Screen Key :: class . java ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠtestCase ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogged In Status Ġ= ĠRE SETTING _ PIN , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected KeyType Ġ= ĠF orgot Pin Create New Pin Screen Key :: class . java ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠtestCase ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogged In Status Ġ= ĠLOG GED _ IN , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected KeyType Ġ= ĠHome Screen Key :: class . java ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠtestCase ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogged In Status Ġ= ĠU NA UTH ORIZ ED , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected KeyType Ġ= ĠRegistration Phone Screen Key :: class . java ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ) ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` when Ġa Ġlocal Ġuser Ġdoes Ġnot Ġexist , Ġthe Ġregistration Ġscreen Ġmust Ġbe Ġopened `() Ġ{ ĊĠĠĠ Ġwhenever ( user Session . logged In User ()). thenReturn ( Observable . just ( None )) ĊĊĠĠĠ ĠassertThat ( controller . initial Screen Key ()). isInstanceOf ( Registration Phone Screen Key :: class . java ) ĊĠ Ġ} ĊĊĠ Ġdata Ġclass ĠRedirect To SignIn Params ( ĊĠĠĠĠĠ Ġval Ġuser Unauthorized Values : ĠList < Boolean >, ĊĠĠĠĠĠ Ġval ĠnumberOf Times Should Redirect To SignIn : ĠInt ĊĠ Ġ) ĊĊĠ Ġ@ Test ĊĠ Ġ@ Parameters ( method Ġ= Ġ" params Ġfor Ġredirect ing Ġto Ġsign Ġin ") ĊĠ Ġfun Ġ` wh enever Ġthe Ġuser Ġlogged Ġin Ġstatus Ġbecomes Ġun authorized , Ġthe Ġsign Ġin Ġscreen Ġmust Ġbe Ġshown `( testCase : ĠRedirect To SignIn Params ) Ġ{ ĊĠĠĠ Ġval Ġ( user Unauthorized Values , ĠnumberOf Times Should Redirect To SignIn ) Ġ= ĠtestCase ĊĠĠĠ Ġuser Unauthorized Values . forEach ( user Unauthorized Subject :: onNext ) ĊĊĠĠĠ Ġif Ġ( numberOf Times Should Redirect To SignIn Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠ Ġverify ( activity , Ġtimes ( numberOf Times Should Redirect To SignIn )). redirectTo Login () ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠ Ġverify ( activity , Ġnever ()). redirectTo Login () ĊĠĠĠ Ġ} ĊĠĠĠ Ġverify No More Interactions ( activity ) ĊĠ Ġ} ĊĊĠ Ġ@ Suppress (" Unused ") ĊĠ Ġprivate Ġfun Ġ` params Ġfor Ġredirect ing Ġto Ġsign Ġin ` (): ĠList < Redirect To SignIn Params > Ġ{ ĊĠĠĠ Ġreturn ĠlistOf ( ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( true ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 1 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( false ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( true , Ġtrue ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 1 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( true , Ġfalse , Ġtrue ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 2 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( false , Ġtrue , Ġtrue , Ġfalse , Ġtrue ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 2 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( false , Ġfalse , Ġfalse , Ġfalse ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( true , Ġtrue , Ġtrue , Ġtrue ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 1 ĊĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠ ĠRedirect To SignIn Params ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Unauthorized Values Ġ= ĠlistOf ( true , Ġfalse , Ġtrue , Ġfalse , Ġtrue , Ġfalse ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠnumberOf Times Should Redirect To SignIn Ġ= Ġ 3 ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ) ĊĠ Ġ} Ċ } Ċ