/** Ċ Ġ* ĠĠ ĠCopyright Ġ 2 0 1 9 Ġch ris fang 6 Ċ Ġ* Ċ Ġ* ĠĠ Ġ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 Ġnet . chr is . news . f ond ue . repository Ċ Ċ import Ġio . reactivex . Observable Ċ import Ġio . reactivex . Single Ċ import Ġio . reactivex . schedul ers . Schedulers Ċ import Ġnet . chr is . news . f ond ue . repository . Constant . MAX _ TRY Ċ import Ġnet . chr is . news . f ond ue . repository . Constant . SIZE _ PER _ REQUEST Ċ import Ġnet . chr is . news . f ond ue . repository . converter . News DO 2 PO Converter Ċ import Ġnet . chr is . news . f ond ue . repository . converter . News PO 2 BO Converter Ċ import Ġnet . chr is . news . f ond ue . repository . database . News Database Handler Ċ import Ġnet . chr is . news . f ond ue . repository . network . News WebService Ċ import Ġnet . chr is . news . f ond ue . repository . po . Head lines PO Ċ import Ġnet . chr is . news . f ond ue . repository . po . News PO Ċ import Ġnet . chr is . news . f ond ue . use case . News Type Ċ import Ġnet . chr is . news . f ond ue . use case . News Type . HEAD LINES Ċ import Ġnet . chr is . news . f ond ue . use case . bo . News BO Ċ import Ġnet . chr is . news . f ond ue . use case . repo . News List Repository Ċ import Ġtim ber . log . Tim ber Ċ import Ġjavax . inject . Inject Ċ import Ġkotlin . math . ceil Ċ Ċ class ĠNews List Repository Impl Ġ@ Inject Ġconstructor ( ĊĠĠĠ Ġprivate Ġval Ġnews WebService : ĠNews WebService , ĊĠĠĠ Ġprivate Ġval Ġnews DO 2 PO Converter : ĠNews DO 2 PO Converter , ĊĠĠĠ Ġprivate Ġval Ġnews PO 2 BO Converter : ĠNews PO 2 BO Converter , ĊĠĠĠ Ġprivate Ġval Ġnews Database Handler : ĠNews Database Handler Ċ ) Ġ: ĠNews List Repository Ġ{ ĊĊĠĠĠ Ġprivate Ġvar Ġfrom Index For After Ġ= Ġ 0 ĊĊĠĠĠ Ġoverride Ġfun Ġget News List ( ĊĠĠĠĠĠĠĠ Ġcategory : ĠString , ĊĠĠĠĠĠĠĠ Ġtype : ĠNews Type , ĊĠĠĠĠĠĠĠ Ġrequested Load Size : ĠInt ĊĠĠĠ Ġ): ĠSingle < List < News BO >> Ġ= Ġget News List After ( category , Ġnull , Ġtype , Ġrequested Load Size ) ĊĊĠĠĠ Ġoverride Ġfun Ġget News List After ( ĊĠĠĠĠĠĠĠ Ġcategory : ĠString , ĊĠĠĠĠĠĠĠ Ġafter Doc Id : ĠString ?, ĊĠĠĠĠĠĠĠ Ġtype : ĠNews Type , ĊĠĠĠĠĠĠĠ Ġrequested Load Size : ĠInt ĊĠĠĠ Ġ): ĠSingle < List < News BO >> Ġ= Ġwhen Ġ( type ) Ġ{ ĊĠĠĠĠĠĠĠ ĠHEAD LINES Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" ######## ## ") ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d ( after Doc Id ?. let Ġ{ Ġ"# ĠTo Ġget Ġ$ requested Load Size Ġnews ĠAFTER Ġ$ after Doc Id " Ġ} Ġ?: Ġ"# ĠGet Ġ$ requested Load Size ĠTOP Ġnews ") ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" ######## ## ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTry Ġso Ġmany Ġtimes , Ġthen Ġfor Ġthe Ġefficiency Ġwe Ġwould Ġgive Ġup Ġeven Ġif Ġwe Ġcan 't Ġget Ġthe Ġenough Ġnews . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġshould Try Ġ= ĠMAX _ TRY . coerce At Least ( ceil ( requested Load Size . toDouble () Ġ/ ĠSIZE _ PER _ REQUEST ). toInt ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġtried Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġfrom Index Ġ= Ġfrom Index For After ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfetch Local News After ( after Doc Id , Ġrequested Load Size , Ġtype ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Observable Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . size Ġ< Ġrequested Load Size Ġ&& Ġtried Ġ< Ġshould Try Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d ("# ĠGot Ġ${ it . size } Ġrecords Ġfrom Ġdatabase Ġless Ġthan Ġrequested Ġnumber Ġof Ġ$ requested Load Size ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠObservable . error ( Exception (" Not Ġso Ġmany Ġlocal Ġrecords ")) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠObservable . just ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. retry When Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . flatMap Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfetch Network News Single ( from Index , Ġcategory ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Observable Ġ{ Ġhead lines Ġ-> Ġsave News Observable ( head lines , Ġtype ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Next Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfrom Index Ġ+= ĠSIZE _ PER _ REQUEST ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfrom Index For After Ġ= Ġfrom Index ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtried Ġ+= Ġ 1 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ ĠObservable . from Iterable ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġnews PO 2 BO Converter . apply ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toList () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠSingle . error < List < News BO >>( IllegalArgumentException (" unknown Ġnews Ġtype ")) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġget News List Before ( ĊĠĠĠĠĠĠĠ Ġcategory : ĠString , ĊĠĠĠĠĠĠĠ Ġbefore Doc Id : ĠString , ĊĠĠĠĠĠĠĠ Ġtype : ĠNews Type , ĊĠĠĠĠĠĠĠ Ġrequested Load Size : ĠInt ĊĠĠĠ Ġ): ĠSingle < List < News BO >> Ġ= Ġwhen Ġ( type ) Ġ{ ĊĠĠĠĠĠĠĠ ĠHEAD LINES Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" ######## ## ") ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d ("# ĠTo Ġget Ġnews Ġ$ requested Load Size ĠBE FORE Ġ$ before Doc Id ") ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" ######## ## ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTry ĠMAX _ TRY Ġtimes Ġrequests , Ġand Ġthen Ġfor Ġthe Ġefficiency Ġwe Ġwould Ġgive Ġup Ġeven Ġif Ġwe Ġcan 't Ġtouch Ġthe Ġtop Ġnews Ġof Ġcurrent Ġlist . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġshould Try Ġ= ĠMAX _ TRY ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġtried Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġtouched Ġ= Ġfalse Ġ// ĠIf Ġit Ġhas Ġgot Ġthe Ġnews Ġincluding Ġthe Ġtop Ġnews Ġof Ġcurrent Ġlist . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġfrom Index Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfetch Local News Before ( before Doc Id , Ġrequested Load Size , Ġtype ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Observable Ġ{ Ġlist Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d ("# Ġ${ list . size } Ġlocal Ġnews Ġbefore Ġ$ before Doc Id , Ġtried Ġ$ tri ed Ġtimes , Ġand Ġ${ if Ġ(! touched ) Ġ" no " Ġelse Ġ"" } Ġtouched ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠMat ched Ġnews Ġitems Ġare Ġalready Ġin Ġlocal Ġstorage . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠOnly Ġfor Ġthe Ġfirst Ġtime Ġwithout Ġretry ing . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ( list . size Ġ== Ġrequested Load Size Ġ&& Ġtried Ġ== Ġ 0 ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTouch Ġthe Ġtop Ġnews Ġof Ġcurrent Ġlist Ġfrom Ġnetwork , Ġno Ġmatter Ġhow Ġmany Ġtimes Ġit Ġhas Ġtried . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtouched Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠT ried Ġtoo Ġmany Ġtimes ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtried Ġ>= Ġshould Try Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠObservable . just ( list ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> ĠObservable . error ( Exception (" No Ġenough Ġlocal Ġrecords Ġgot ")) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. retry When Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . flatMap Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfetch Network News Single ( from Index , Ġcategory ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Observable Ġ{ Ġhead lines Ġ-> Ġsave News Observable ( head lines , Ġtype ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Next Ġ{ Ġhead lines Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhead lines . find Ġ{ Ġitem Ġ-> Ġitem . doc Id Ġ== Ġbefore Doc Id Ġ} ?. let Ġ{ Ġtouched Ġ= Ġtrue Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfrom Index Ġ+= ĠSIZE _ PER _ REQUEST ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtried Ġ+= Ġ 1 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ ĠObservable . from Iterable ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġnews PO 2 BO Converter . apply ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toList () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠSingle . error < List < News BO >>( IllegalArgumentException (" unknown Ġnews Ġtype ")) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġfetch Local News Before ( ĊĠĠĠĠĠĠĠ Ġbefore Doc Id : ĠString , ĊĠĠĠĠĠĠĠ Ġrequested Load Size : ĠInt , ĊĠĠĠĠĠĠĠ Ġtype : ĠNews Type ĊĠĠĠ Ġ) Ġ= ĠSingle . from Callable < List < News PO >> Ġ{ ĊĠĠĠĠĠĠĠ Ġnews Database Handler . getAll News Before ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtype . name , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbefore Doc Id , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrequested Load Size ĊĠĠĠĠĠĠĠ Ġ) ?. reversed () Ġ?: ĠlistOf () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġfetch Local News After ( ĊĠĠĠĠĠĠĠ Ġafter Doc Id : ĠString ?, ĊĠĠĠĠĠĠĠ Ġrequested Load Size : ĠInt , ĊĠĠĠĠĠĠĠ Ġtype : ĠNews Type ĊĠĠĠ Ġ) Ġ= ĠSingle . from Callable < List < News PO >> Ġ{ ĊĠĠĠĠĠĠĠ Ġ( after Doc Id ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnews Database Handler . getAll News After ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtype . name , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġafter Doc Id , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequested Load Size ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} Ġ?: Ġnews Database Handler . getAll News ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtype . name , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrequested Load Size ĊĠĠĠĠĠĠĠ Ġ)) Ġ?: ĠlistOf () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġsave News Observable ( ĊĠĠĠĠĠĠĠ Ġhead lines PO : ĠHead lines PO , ĊĠĠĠĠĠĠĠ Ġtype : ĠNews Type ĊĠĠĠ Ġ): ĠObservable < out ĠList < News PO >> Ġ= ĠSingle . just ( head lines PO ) ĊĠĠĠĠĠĠĠ Ġ. flatMap Observable Ġ{ ĠObservable . from Iterable ( it . list ) Ġ} ĊĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . doc id ?. isNotBlank () Ġ== Ġtrue Ġ|| Ġit . title ?. isNotBlank () Ġ== Ġtrue Ġ|| Ġit . ptime ?. isNotBlank () Ġ== Ġtrue Ġ} ĊĠĠĠĠĠĠĠ Ġ. do On Next Ġ{ Ġit . t name Ġ= ĠNews Type . convert ( type . name ). toString () Ġ} Ġ// ĠFix Ġthe Ġnull Ġvalue Ġbug Ġof Ġthe Ġapi . ĊĠĠĠĠĠĠĠ Ġ. map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d ("# ĠNews DO : Ġ$ it ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnews DO 2 PO Converter . apply ( it ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ. toList () ĊĠĠĠĠĠĠĠ Ġ. to Observable () ĊĠĠĠĠĠĠĠ Ġ. do On Next Ġ{ Ġnews Database Handler . insert All (* it . to Typed Array ()) Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġfetch Network News Single ( ĊĠĠĠĠĠĠĠ Ġfrom Index : ĠInt , ĊĠĠĠĠĠĠĠ Ġcategory : ĠString ĊĠĠĠ Ġ) Ġ= Ġnews WebService . fetch Head lines ( category , Ġfrom Index ) Ċ } Ċ