package Ġgov . cdc . prime . router . cli Ċ Ċ import Ġcom . fasterxml . jackson . databind . JsonNode Ċ import Ġcom . fasterxml . jackson . module . kotlin . jackson ObjectMapper Ċ import Ġcom . github . aj alt . cli kt . core . Print Message Ċ import Ġcom . github . kit tin un f . fuel . Fuel Ċ import Ġcom . github . kit tin un f . fuel . core . extensions . authentication Ċ import Ġcom . github . kit tin un f . result . Result Ċ import Ġgov . cdc . prime . router . common . Environment Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlinx . coroutines . run Blocking Ċ import Ġjava . io . IOException Ċ import Ġjava . net . URL Ċ Ċ /** Ċ Ġ* ĠUtilities Ġfor Ġcommands . Ċ Ġ*/ Ċ class ĠCommand Utilities Ġ{ ĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠThe ĠAPI Ġendpoint Ġto Ġcheck Ġfor . Ġ ĠThis Ġneeds Ġto Ġbe Ġa Ġsimple Ġoperation . ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠwaitFor Api Endpoint Path Ġ= Ġ" api / look upt ables / list " ĊĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠW aits Ġfor Ġthe Ġendpoint Ġat Ġ[ environment ] Ġto Ġbecome Ġavailable . ĠThis Ġfunction Ġwill Ġretry Ġ[ retries ] Ġnumber Ġof ĊĠĠĠĠĠĠĠĠ Ġ* Ġtimes Ġwaiting Ġ[ poll Interval Secs ] Ġseconds Ġbetween Ġretries . ĊĠĠĠĠĠĠĠĠ Ġ* Ġ@ throws ĠIOException Ġif Ġa Ġconnection Ġwas Ġnot Ġmade ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġinternal Ġfun ĠwaitFor Api ( environment : ĠEnvironment , Ġretries : ĠInt Ġ= Ġ 3 0 , Ġpoll Interval Secs : ĠLong Ġ= Ġ 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġurl Ġ= Ġenvironment . form Url ( waitFor Api Endpoint Path ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠaccessToken Ġ= ĠOk ta Command . fetch AccessToken ( environment . ok ta App ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġerror (" Unable Ġto Ġobtain ĠOk ta Ġaccess Ġtoken Ġfor Ġenvironment Ġ$ environment ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġretry Count Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ(! is Endpoint Available ( url , ĠaccessToken )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġretry Count ++ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( retry Count Ġ> Ġretries ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIOException (" Unable Ġto Ġconnect Ġto Ġthe ĠAPI Ġat Ġ$ url ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrun Blocking Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( poll Interval Secs Ġ* Ġ 1 0 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠIs Ġthe Ġservice Ġrunning Ġthe Ġenvironment ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġinternal Ġfun Ġis Api Available ( environment : ĠEnvironment ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġurl Ġ= Ġenvironment . form Url ( waitFor Api Endpoint Path ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠaccessToken Ġ= ĠOk ta Command . fetch AccessToken ( environment . ok ta App ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġerror (" Unable Ġto Ġobtain ĠOk ta Ġaccess Ġtoken Ġfor Ġenvironment Ġ$ environment ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġis Endpoint Available ( url , ĠaccessToken ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠChecks Ġif Ġthe ĠAPI Ġcan Ġbe Ġconnected Ġto . ĊĠĠĠĠĠĠĠĠ Ġ* Ġ@ return Ġtrue Ġis Ġthe ĠAPI Ġis Ġavailable , Ġfalse Ġotherwise ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġis Endpoint Available ( url : ĠURL , ĠaccessToken : ĠString ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ(_, Ġ_, Ġresult ) Ġ= ĠF uel . head ( url . toString ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. authentication () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. bearer ( accessToken ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. response () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġwhen Ġ( result ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠResult . Success Ġ-> Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġjson Mapper Ġ= Ġj ack son ObjectMapper () ĊĊĠĠĠĠĠĠĠ Ġdata Ġclass ĠDiff Row ( val Ġname : ĠString , Ġval Ġbase Value : ĠString , Ġval Ġto Value : ĠString ) ĊĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠCreate Ġa Ġlist Ġof Ġdifferences Ġbetween Ġtwo ĠJSON Ġstrings . ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġfun Ġdiff Json ( base : ĠString , Ġcompare To : ĠString ): ĠList < Diff Row > Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠĠĠĠĠ Ġ* ĠGiven Ġthe Ġ[ node ] Ġcall Ġ[ visitor ] Ġall Ġdesc endant Ġvalue Ġnodes ĊĠĠĠĠĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfun Ġwalk Tree ( node : ĠJsonNode , Ġpath : ĠString Ġ= Ġ"", Ġvisitor : Ġ( name : ĠString , Ġvalue : ĠString ) Ġ-> ĠUnit ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . isNull Ġ-> Ġvisitor ( path , Ġ" null ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . is Text ual Ġ-> Ġvisitor ( path , Ġ"\" ${ node . text Value ()} \" ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . is Boolean Ġ-> Ġvisitor ( path , Ġnode . as Text ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . isNumber Ġ-> Ġvisitor ( path , Ġnode . as Text ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . isArray Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . iterator (). as Sequence (). forEach Indexed Ġ{ Ġindex , Ġelement Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwalk Tree ( element , Ġ"$ path [$ index ]", Ġvisitor ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . isObject Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġparent Path Ġ= Ġif Ġ( path . isBlank ()) Ġ"" Ġelse Ġ"$ path ." ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . fields (). forEach Ġ{ Ġentry Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwalk Tree ( entry . value , Ġ"$ parent Path ${ entry . key }", Ġvisitor ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠĠĠĠĠ Ġ* ĠFlat ten Ġthe Ġ[ json ] Ġstructure Ġand Ġcreate Ġa Ġmap Ġof Ġname - value Ġpairs ĊĠĠĠĠĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfun Ġcreate Maps ( json : ĠString ): ĠMap < String , ĠString > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtree : ĠJsonNode Ġ= Ġjson Mapper . read Tree ( json ) Ġ?: Ġreturn Ġempty Map () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresult Map Ġ= Ġmutable Map Of < String , ĠString >() ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwalk Tree ( tree ) Ġ{ Ġname , Ġvalue Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresult Map [ name ] Ġ= Ġvalue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġresult Map ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠĠĠĠĠ Ġ* ĠMerge Ġthe Ġ[ base ] Ġand Ġ[ compareTo ] Ġmaps Ġtogether Ġto Ġcreate Ġa Ġlist Ġof Ġ[ Diff Row ] ĊĠĠĠĠĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfun Ġmerge Maps ( base : ĠMap < String , ĠString >, Ġcompare To : ĠMap < String , ĠString >): ĠList < Diff Row > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcommon Rows Ġ= Ġbase ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġ( name , Ġ_) Ġ-> Ġcompare To . containsKey ( name ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( name , Ġbase Value ) Ġ-> ĠDiff Row ( name , Ġbase Value , Ġcompare To [ name ] !! ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġextra Base Rows Ġ= Ġbase ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġ( name , Ġ_) Ġ-> Ġ! compareTo . containsKey ( name ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( name , Ġbase Value ) Ġ-> ĠDiff Row ( name , Ġbase Value , Ġ"") Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġextra CompareTo Rows Ġ= Ġcompare To ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġ( name , Ġ_) Ġ-> Ġ! base . containsKey ( name ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( name , Ġcompare To Value ) Ġ-> ĠDiff Row ( name , Ġ"", Ġcompare To Value ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġcommon Rows Ġ+ Ġextra Base Rows Ġ+ Ġextra CompareTo Rows ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbase Map Ġ= Ġcreate Maps ( base ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcompare ToMap Ġ= Ġcreate Maps ( compareTo ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmerged Rows Ġ= Ġmerge Maps ( base Map , Ġcompare ToMap ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġmerged Rows . filter Ġ{ Ġit . base Value Ġ!= Ġit . to Value Ġ}. sorted By Ġ{ Ġit . name Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠNice Ġway Ġto Ġabort Ġa Ġcommand ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġfun Ġabort ( message : ĠString ): ĠNothing Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠPrint Message ( message , Ġerror Ġ= Ġtrue ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ }