/* Ċ Ġ* ĠCopyright Ġ 2 0 1 8 - 2 0 2 1 ĠSIP 3 . IO , ĠCorp . Ċ Ġ* Ċ Ġ* Ġ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 Ġio . sip 3 . sal to . ce . socket Ċ Ċ import Ġio . sip 3 . commons . domain . media . Media Control Ċ import Ġio . sip 3 . commons . vertx . annotations . Conditional On Property Ċ import Ġio . sip 3 . commons . vertx . annotations . Instance Ċ import Ġio . sip 3 . sal to . ce . Mongo Client Ċ import Ġio . sip 3 . sal to . ce . Routes CE Ċ import Ġio . sip 3 . sal to . ce . host . Host Registry Ċ import Ġio . vertx . core . Abstract Vert icle Ċ import Ġio . vertx . core . buffer . Buffer Ċ import Ġio . vertx . core . data gram . Data gram Socket Ċ import Ġio . vertx . core . data gram . Data gram Socket Options Ċ import Ġio . vertx . core . json . JsonObject Ċ import Ġio . vertx . core . net . SocketAddress Ċ import Ġmu . Kotlin Logging Ċ import Ġjava . net . URI Ċ Ċ /** Ċ Ġ* ĠManagement Ġsocket Ċ Ġ*/ Ċ @ Instance ( singleton Ġ= Ġtrue ) Ċ @ Conditional On Property ("/ management ") Ċ open Ġclass ĠManagement Socket Ġ: ĠAbstract Vert icle () Ġ{ ĊĊĠĠĠ Ġprivate Ġval Ġlogger Ġ= ĠKotlin Logging . logger Ġ{} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠTYPE _ SHUT DOWN Ġ= Ġ" shutdown " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠTYPE _ REGISTER Ġ= Ġ" register " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠTYPE _ MEDIA _ CONTROL Ġ= Ġ" media _ control " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠTYPE _ MEDIA _ RECORD ING _ RESET Ġ= Ġ" media _ recording _ reset " ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġvar Ġclient : Ġio . vertx . ext . mongo . Mongo Client ? Ġ= Ġnull ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġhost Registry : ĠHost Registry ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġuri : ĠURI ĊĠĠĠ Ġprivate Ġvar Ġexpiration Delay : ĠLong Ġ= Ġ 6 0 0 0 0 ĊĠĠĠ Ġprivate Ġvar Ġexpiration Timeout : ĠLong Ġ= Ġ 1 2 0 0 0 0 ĊĠĠĠ Ġprivate Ġvar Ġpublish Media Control Mode Ġ= Ġ 0 ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġsocket : ĠData gram Socket ĊĊĠĠĠ Ġprivate Ġval Ġremote Hosts Ġ= Ġmutable Map Of < String , ĠRemote Host >() ĊĠĠĠ Ġprivate Ġvar Ġsend S dp Sessions Ġ= Ġfalse ĊĊĠĠĠ Ġoverride Ġfun Ġstart () Ġ{ ĊĠĠĠĠĠĠĠ Ġconfig (). get JsonObject (" mongo ") ?. let Ġ{ Ġconfig Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclient Ġ= ĠMongo Client . create Shared ( vertx , Ġconfig ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġhost Registry Ġ= ĠHost Registry . getInstance ( vertx , Ġconfig ()) ĊĊĠĠĠĠĠĠĠ Ġconfig (). get JsonObject (" management "). let Ġ{ Ġconfig Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuri Ġ= ĠURI ( config . getString (" uri ") Ġ?: Ġthrow ĠIllegalArgumentException (" uri ")) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġconfig . getLong (" expiration - delay ") ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpiration Delay Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconfig . getLong (" expiration - timeout ") ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpiration Timeout Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconfig . getInteger (" publish - media - control - mode ") ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpublish Media Control Mode Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġstart Udp Server () ĊĊĠĠĠĠĠĠĠ Ġvert x . set Periodic ( expiration Delay ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnow Ġ= ĠSystem . currentTimeMillis () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts . filter Values Ġ{ Ġit . last Update Ġ+ Ġexpiration Timeout Ġ< Ġnow Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. forEach Ġ{ Ġ( name , Ġremote Host ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" Expired : Ġ$ remote Host " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts . remove ( name ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsend S dp Sessions Ġ= Ġremote Hosts . any Ġ{ Ġ(_, Ġhost ) Ġ-> Ġhost . media Enabled Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġvert x . event Bus (). local Consumer < Media Control >( Routes CE . media Ġ+ Ġ"_ control ") Ġ{ Ġevent Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmedia Control Ġ= Ġevent . body () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpublish Media Control ( media Control ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( e ) Ġ{ Ġ" Management Socket Ġ' publish Media Control ()' Ġfailed ." Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġvert x . event Bus (). local Consumer < JsonObject >( Routes CE . media Ġ+ Ġ"_ recording _ reset ") Ġ{ Ġevent Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpayload Ġ= Ġevent . body () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpublish Media Recording Reset ( payload ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( e ) Ġ{ Ġ" Management Socket Ġ' publish Media Recording Reset ()' Ġfailed ." Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġopen Ġfun Ġstart Udp Server () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġoptions Ġ= ĠData gram Socket Options (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis Ip V 6 Ġ= Ġuri . host . matches ( Regex ("\\ [ .* ] ")) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsocket Ġ= Ġvert x . create Data gram Socket ( options ) ĊĊĠĠĠĠĠĠĠ Ġsocket . handler Ġ{ Ġpacket Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsocket Address Ġ= Ġpacket . sender () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuffer Ġ= Ġpacket . data () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= Ġbuffer . to JsonObject () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle ( socket Address , Ġmessage ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( e ) Ġ{ Ġ" Management Socket Ġ' handle ()' Ġfailed ." Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsocket . listen ( uri . port , Ġuri . host ) Ġ{ Ġconnection Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( connection . failed ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( connection . cause ()) Ġ{ Ġ" UDP Ġconnection Ġfailed . ĠURI : Ġ$ uri " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġconnection . cause () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" Listening Ġon Ġ$ uri " Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġopen Ġfun Ġhandle ( socket Address : ĠSocket Address , Ġmessage : ĠJsonObject ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġtype Ġ= Ġmessage . getString (" type ") ĊĠĠĠĠĠĠĠ Ġval Ġpayload Ġ= Ġmessage . get JsonObject (" payload ") ĊĊĠĠĠĠĠĠĠ Ġwhen Ġ( type ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTYPE _ REGISTER Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġconfig Ġ= Ġpayload . get JsonObject (" config ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġscheme Ġ= Ġuri . scheme ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts . compute If Absent ( config ?. get JsonObject (" host ") ?. getString (" name ") Ġ?: Ġpayload . getString (" name ")) Ġ{ Ġname Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" Registered : Ġ$ payload " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ compute If Absent ĠRemote Host ( name ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġhost Ġ= Ġsocket Address . host () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġport Ġ= Ġsocket Address . port () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġuri Ġ= ĠURI ("$ scheme :// $ host :$ port ") ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġconfig ?. get JsonObject (" host ") ?. let Ġ{ Ġhost Registry . save ( it ) Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġr tp Enabled Ġ= Ġconfig ?. get JsonObject (" rtp ") ?. getBoolean (" enabled ") Ġ?: Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġr tcp Enabled Ġ= Ġconfig ?. get JsonObject (" rt cp ") ?. getBoolean (" enabled ") Ġ?: Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmedia Enabled Ġ= Ġr tp Enabled Ġ|| Ġr tcp Enabled ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsend S dp Sessions Ġ= Ġsend S dp Sessions Ġ|| Ġmedia Enabled ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlast Update Ġ= ĠSystem . currentTimeMillis () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTYPE _ SHUT DOWN Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġname Ġ= Ġpayload . getString (" name ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" Handling Ġ` shutdown ` Ġcommand Ġreceived Ġvia Ġmanagement Ġsocket : Ġ$ message " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts [ name ]?. apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" Shut ting Ġdown Ġthe Ġ`$ name ` Ġvia Ġmanagement Ġsocket ..." Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsocket . send ( message . to Buffer (), Ġuri . port , Ġuri . host ) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġlogger . error Ġ{ Ġ" Unknown Ġmessage Ġtype . ĠMessage : Ġ${ message . encode P ret til y () }" Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġopen Ġfun Ġpublish Media Control ( media Control : ĠMedia Control ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! send S dp Sessions ) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= ĠJsonObject (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput (" type ", ĠTYPE _ MEDIA _ CONTROL ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput (" payload ", ĠJsonObject . map From ( media Control )) ĊĠĠĠĠĠĠĠ Ġ}. to Buffer () ĊĊĠĠĠĠĠĠĠ Ġwhen Ġ( publish Media Control Mode ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠMode Ġ 0 : ĠSend Ġto Ġall Ġhosts ĊĠĠĠĠĠĠĠĠĠĠĠĠ 0 Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts . forEach Ġ{ Ġ(_, Ġhost ) Ġ-> Ġsend Media Control IfNeeded ( host , Ġmessage ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠMode Ġ 1 : ĠSend Ġto Ġmedia Ġparticipants Ġonly ĊĠĠĠĠĠĠĠĠĠĠĠĠ 1 Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmedia Control . sdp Session . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts [ host Registry . get HostName ( src . addr )] ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsend Media Control IfNeeded ( it , Ġmessage ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremote Hosts [ host Registry . get HostName ( dst . addr )] ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsend Media Control IfNeeded ( it , Ġmessage ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġopen Ġfun Ġpublish Media Recording Reset ( payload : ĠJsonObject ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= ĠJsonObject (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput (" type ", ĠTYPE _ MEDIA _ RECORD ING _ RESET ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput (" payload ", Ġpayload ) ĊĠĠĠĠĠĠĠ Ġ}. to Buffer () ĊĊĠĠĠĠĠĠĠ Ġremote Hosts . forEach Ġ{ Ġ(_, Ġhost ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsocket . send ( message , Ġhost . uri . port , Ġhost . uri . host ) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( e ) Ġ{ Ġ" Socket Ġ' send ()' Ġfailed . ĠURI : Ġ${ host . uri }" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġsend Media Control IfNeeded ( host : ĠRemote Host , Ġmessage : ĠBuffer ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( host . media Enabled ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsocket . send ( message , Ġhost . uri . port , Ġhost . uri . host ) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( e ) Ġ{ Ġ" Socket Ġ' send ()' Ġfailed . ĠURI : Ġ${ host . uri }" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġclass ĠRemote Host ( val Ġname : ĠString ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġvar Ġlast Update : ĠLong Ġ= ĠSystem . currentTimeMillis () ĊĠĠĠĠĠĠĠ Ġlateinit Ġvar Ġuri : ĠURI ĊĠĠĠĠĠĠĠ Ġvar Ġmedia Enabled Ġ= Ġfalse ĊĠĠĠ Ġ} Ċ }