/* Ċ Ġ* ĠCopyright Ġ( C ) Ġ 2 0 1 7 / 2 0 2 0 Ġe - voy age urs Ġtechnologies Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġai . to ck . bot . connector . ga Ċ Ċ import Ġai . to ck . bot . connector . Connector Base Ċ import Ġai . to ck . bot . connector . Connector Callback Ċ import Ġai . to ck . bot . connector . Connector Callback Base Ċ import Ġai . to ck . bot . connector . Connector Data Ċ import Ġai . to ck . bot . connector . Connector Message Ċ import Ġai . to ck . bot . connector . ga . GA Account Link ing . Companion . getUserId Ċ import Ġai . to ck . bot . connector . ga . GA Account Link ing . Companion . is User Authenticated Ċ import Ġai . to ck . bot . connector . ga . GA Account Link ing . Companion . switch Time Line Ċ import Ġai . to ck . bot . connector . ga . model . request . GA Request Ċ import Ġai . to ck . bot . connector . ga . model . response . G AC ar ousel Item Ċ import Ġai . to ck . bot . connector . ga . model . response . GA Item Ċ import Ġai . to ck . bot . connector . ga . model . response . GA Option Info Ċ import Ġai . to ck . bot . connector . ga . model . response . G AS imple Response Ċ import Ġai . to ck . bot . connector . media . Media Card Ċ import Ġai . to ck . bot . connector . media . Media Carousel Ċ import Ġai . to ck . bot . connector . media . Media Message Ċ import Ġai . to ck . bot . engine . Bot Bus Ċ import Ġai . to ck . bot . engine . Bot Repository Ċ import Ġai . to ck . bot . engine . Connector Controller Ċ import Ġai . to ck . bot . engine . action . Action Ċ import Ġai . to ck . bot . engine . action . Send Attachment . Attachment Type . image Ċ import Ġai . to ck . bot . engine . action . Send Choice Ċ import Ġai . to ck . bot . engine . event . Event Ċ import Ġai . to ck . bot . engine . event . Login Event Ċ import Ġai . to ck . bot . engine . user . Player Id Ċ import Ġai . to ck . bot . engine . user . Player Type Ċ import Ġai . to ck . bot . engine . user . User Preferences Ċ import Ġai . to ck . shared . Executor Ċ import Ġai . to ck . shared . injector Ċ import Ġai . to ck . shared . jackson . mapper Ċ import Ġai . to ck . shared . provide Ċ import Ġcom . fasterxml . jackson . module . kotlin . readValue Ċ import Ġcom . google . api . client . auth . openid connect . Id Token Ċ import Ġcom . google . api . client . auth . openid connect . Id Token Verifier Ċ import Ġcom . google . api . client . json . jackson 2 . Jack son Factory Ċ import Ġio . vertx . ext . web . Routing Context Ċ import Ġmu . Kotlin Logging Ċ import Ġkotlin . Lazy Thread Safety Mode . PUBLIC ATION ĊĊ Ċ /** Ċ Ġ* Ċ Ġ*/ Ċ class ĠGA Connector Ġinternal Ġconstructor ( ĊĠĠĠ Ġval Ġapplication Id : ĠString , ĊĠĠĠ Ġval Ġpath : ĠString , ĊĠĠĠ Ġval Ġallowed Project Ids : ĠSet < String > Ċ ) Ġ: ĠConnector Base ( GA Connector Provider . connector Type ) Ġ{ ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġlogger Ġ= ĠKotlin Logging . logger Ġ{} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġexecutor : ĠExecutor Ġget () Ġ= Ġinjector . provide () ĊĊĠĠĠ Ġprivate Ġval Ġverifier : ĠId Token Verifier Ġby Ġlazy ( PUBLIC ATION ) Ġ{ ĠId Token Verifier . Builder (). build () Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġregister ( controller : ĠConnector Controller ) Ġ{ ĊĠĠĠĠĠĠĠ Ġcontroller . register Services ( path ) Ġ{ Ġrouter Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info (" deploy Ġrest Ġgoogle Ġassistant Ġservices Ġfor Ġroot Ġpath Ġ$ path Ġ") ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġrouter . post ( path ). handler Ġ{ Ġcontext Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( isValid Token ( context )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexecutor . execute Blocking Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Request ( controller , Ġcontext , Ġcontext . body AsString ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . fail ( 4 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . fail ( e ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// internal Ġfor Ġtests ĊĠĠĠ Ġinternal Ġfun Ġhandle Request ( ĊĠĠĠĠĠĠĠ Ġcontroller : ĠConnector Controller , ĊĠĠĠĠĠĠĠ Ġcontext : ĠRouting Context , ĊĠĠĠĠĠĠĠ Ġbody : ĠString ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġtimer Data Ġ= ĠBot Repository . request Timer . start (" ga _ webhook ") ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" Google ĠAssistant Ġrequest Ġinput Ġ: Ġ$ body " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrequest : ĠGA Request Ġ= Ġmapper . readValue ( body ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcallback Ġ= ĠGA Connector Callback ( application Id , Ġcontroller , Ġcontext , Ġrequest ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġevent Ġ= ĠWeb hook Action Converter . to Event ( request , Ġapplication Id ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfun Ġsend Request () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontroller . handle ( event , ĠConnector Data ( callback , Ġsave Timeline Ġ= Ġ! request . health check )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevent Ġis ĠLogin Event Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġswitch Time Line ( event . userId , Ġevent . previous UserId , Ġcontroller ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsend Request () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis User Authenticated ( request ) Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" Google ĠAssistant Ġrefresh Ġtoken Ġbefore Ġstory Ġexecution " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontroller . handle ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLogin Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠPlayer Id ( getUserId ( request ), ĠPlayer Type . user ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠPlayer Id ( application Id , ĠPlayer Type . bot ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequest . user . accessToken Ġ?: Ġerror (" Access Ġtoken Ġcan 't Ġbe Ġnull "), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġapplication Id , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcheck Login Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠConnector Data ( object Ġ: ĠConnector Callback Base ( application Id , Ġga Connector Type ) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġsend Ġ 4 0 1 Ġfor Ġre voke Ġtoken Ġand Ġlogout Ġgoogle Ġassistant Ġuser ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġevent Skipped ( event : ĠEvent ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . fail ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġevent Answer ed ( event : ĠEvent ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsend Request () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġsend Request () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( t : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠBot Repository . request Timer . throwable ( t , Ġtimer Data ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcallback . send Technical Error ( t , Ġbody , Ġrequest ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( t : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠBot Repository . request Timer . throwable ( t , Ġtimer Data ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . fail ( t ) ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠBot Repository . request Timer . end ( timer Data ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠisValid Token ( context : ĠRouting Context ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġif Ġ( allowed Project Ids . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġjwt Ġ= Ġcontext . request (). getHeader (" authorization ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠId Token . parse ( Jack son Factory . getDefaultInstance (), Ġjwt ). let Ġ{ Ġtoken Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġverifier . verify ( token ) Ġ&& Ġallowed Project Ids . any Ġ{ Ġtoken . verify Audience ( listOf ( it )) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn Ġ{ Ġ" invalid Ġsignature " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġoverride Ġfun Ġsend ( event : ĠEvent , Ġcallback : ĠConnector Callback , Ġdelay In Ms : ĠLong ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġc Ġ= Ġcallback Ġas ? ĠGA Connector Callback ĊĠĠĠĠĠĠĠ Ġc ?. addAction ( event , Ġdelay In Ms ) ĊĠĠĠĠĠĠĠ Ġif Ġ( event Ġis ĠAction ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( event . metadata . last Answer ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġc ?. send Response () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . trace Ġ{ Ġ" unsupported Ġevent : Ġ$ event " Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġoverride Ġfun Ġload Profile ( callback : ĠConnector Callback , ĠuserId : ĠPlayer Id ): ĠUser Preferences ? Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġc Ġ= Ġcallback Ġas ? ĠGA Connector Callback ĊĠĠĠĠĠĠĠ Ġreturn Ġc ?. request ?. user ?. profile ?. run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( given Name Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠUser Preferences ( given Name , Ġfamily Name ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġadd Suggestions ( text : ĠCharSequence , Ġsuggestions : ĠList < CharSequence >): ĠBot Bus . () Ġ-> ĠConnector Message ? Ġ= Ġ{ ĊĠĠĠĠĠĠĠ Ġga Message ( rich Response ( text , Ġsuggestions )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġadd Suggestions ( ĊĠĠĠĠĠĠĠ Ġmessage : ĠConnector Message , ĊĠĠĠĠĠĠĠ Ġsuggestions : ĠList < CharSequence > ĊĠĠĠ Ġ): ĠBot Bus . () Ġ-> ĠConnector Message ? Ġ= Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( message Ġis ĠGA Response Connector Message ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġm Ġ= Ġmessage . expected Inputs . last OrNull ()?. input Prompt ?. rich Initial Prompt ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( m Ġ!= Ġnull Ġ&& Ġm . suggestions . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage . copy ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpected Inputs Ġ= Ġmessage . expected Inputs . take ( message . expected Inputs . size Ġ- Ġ 1 ) Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage . expected Inputs . last (). copy ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinput Prompt Ġ= Ġmessage . expected Inputs . last (). input Prompt . copy ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrich Initial Prompt Ġ= Ġm . copy ( suggestions Ġ= Ġsuggestions . map Ġ{ Ġsuggestion ( it ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġto Connector Message ( message : ĠMedia Message ): ĠBot Bus . () Ġ-> ĠList < Connector Message > Ġ= Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( message Ġis ĠMedia Card ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtitle Ġ= Ġmessage . title ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsub Title Ġ= Ġmessage . sub Title ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġimage Ġ= Ġmessage . file ?. take If Ġ{ Ġit . type Ġ== Ġimage Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcard Ġ= Ġif Ġ( image Ġ!= Ġnull ) Ġbasic Card ( title , Ġnull , Ġsub Title , Ġga Image ( image . url , Ġimage . name )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġif Ġ( title Ġ!= Ġnull ) Ġif Ġ( sub Title Ġ== Ġnull ) Ġbasic Card ( formatted Text Ġ= Ġtitle ) Ġelse Ġbasic Card ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtitle , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġformatted Text Ġ= Ġsub Title ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġif Ġ( sub Title Ġ!= Ġnull ) Ġbasic Card ( formatted Text Ġ= Ġsub Title ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġnull ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrequired Text ToS peech Ġ= Ġtitle Ġ?: Ġsub Title Ġ?: Ġ" default _ ga _ card _ title " ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( card Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġactions Ġ= Ġmessage . actions ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsuggestions Ġ= Ġactions . filter Ġ{ Ġit . url Ġ== Ġnull Ġ}. map Ġ{ Ġit . title Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġredirect Ġ= Ġactions . first OrNull Ġ{ Ġit . url Ġ!= Ġnull Ġ} ?. let Ġ{ Ġga Button ( it . title , Ġit . url !! ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠlistOf ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġga Message ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrich Response ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġi 1 8 n Key (" default _ ga _ card _ title ", Ġrequired Text ToS peech ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcard . copy ( buttons Ġ= ĠlistOf NotNull ( redirect )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuggestions ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġempty List () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( message Ġis ĠMedia Carousel ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage . cards . size Ġ> Ġ 1 Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsuggestions Ġ= ĠArrayList < String >() ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġitems Ġ= Ġmessage . cards . map Ġ{ Ġcard Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtitle Ġ= Ġtranslate ( card . title ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsub Title Ġ= Ġtranslate ( card . sub Title ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuggestions . addAll ( card . actions . filter Ġ{ Ġit . url Ġ== Ġnull Ġ}. map Ġ{ Ġit . title . toString () Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠG AC ar ousel Item ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoption Info Ġ= ĠGA Option Info ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġkey Ġ= ĠSend Choice . encode N lp Choice Id ( title . toString ()), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsyn onyms Ġ= Ġempty List () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtitle Ġ= Ġtitle . toString (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdescription Ġ= Ġsub Title . toString (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġimage Ġ= Ġcard . file ?. take If Ġ{ Ġit . type Ġ== Ġimage Ġ} ?. let Ġ{ Ġga Image ( it . url , Ġit . name ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcarousel Message Ġ= Ġga Message ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinput Prompt Ġ= Ġinput Prompt ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrich Response ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġitems Ġ= ĠlistOf ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠGA Item ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠG AS imple Response ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtranslate (" default _ ga _ carousel _ title "). toString () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuggestions Ġ= Ġsuggestions ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpossible Intent s Ġ= ĠlistOf ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpected Text Intent (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpected Intent For Carousel ( items ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠlistOf ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcarousel Message ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage . cards . size Ġ== Ġ 1 Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġto Connector Message ( message . cards . first ()). invoke ( this ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġempty List () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġempty List () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ }