DIRECTORY BasicTime USING [ GMT, Unpacked, Unpack, Now, Period, Pack], Calendar USING [ Date, Days, Months, Years, ZoomLevel], CalStorage USING [ protData, ProtectedData, YearNode, DayNode, MonthNode], CalSupport USING [ GetTimeInterval, GetMonthInfo, ExtractDate], Hickory USING [ Event, EventTuple, RestoreEvents, EventList, All, ExpandRepetitions, Options, NoOptions, Reason, OrderEventList, SameEvent], RopeSets USING [ RopeSet], Tempus USING [ Adjust], ViewerClasses USING [ Viewer], ViewerOps USING [ DestroyViewer] ; CalStorageImpl: CEDAR MONITOR LOCKS CalStorage.protData IMPORTS BasicTime, Hickory, CalStorage, CalSupport, ViewerOps, Tempus EXPORTS CalStorage SHARES CalSupport = BEGIN OPEN Calendar, CalStorage, CalSupport, CalStorage.protData; FirstMonth: INTEGER = -6; -- the nbr of month before today that we prefetch events. LastMonth: INTEGER = + 8; protData: PUBLIC ProtectedData; NewYearNode: PROCEDURE [ date: Date] RETURNS [ tree: REF YearNode] = INLINE BEGIN tree _ NEW[ YearNode]; tree.Year _ date.Year; FOR m: Months IN [ January..December] DO tree.MonthNodes[ m].Month_ m; FOR d: Days IN [ 1..31] DO tree.MonthNodes[ m].DayNodes[ d].Day _ d; ENDLOOP; ENDLOOP; END; -- NewYearNode InsertYearTree: INTERNAL PROCEDURE [ tree: REF YearNode] = BEGIN prev, cur: REF YearNode; IF yearTrees = NIL THEN BEGIN yearTrees _ tree; RETURN; END; prev _ NIL; cur _ yearTrees; DO IF cur = NIL THEN EXIT; IF cur.Year >= tree.Year THEN EXIT; prev _ cur; cur _ cur.Next; ENDLOOP; IF cur = NIL THEN -- we have at least made one step! prev.Next _ tree ELSE IF cur.Year > tree.Year THEN IF prev = NIL THEN BEGIN -- insert at head of list tree.Next _ yearTrees; yearTrees _ tree; END ELSE BEGIN -- insert in middle of list tree.Next _ cur; prev.Next _ tree; END; END; -- InsertYearTree FindYearTree: INTERNAL PROCEDURE [ yr: Years] RETURNS [ tree: REF YearNode] = BEGIN yp: REF YearNode _ yearTrees; DO IF yp = NIL THEN RETURN[ yp]; IF yp.Year = yr THEN RETURN[ yp]; yp _ yp.Next; ENDLOOP; END; -- FindYearTree GetEventsOfDay: PUBLIC INTERNAL PROCEDURE [ date: Date, zoomLevel: ZoomLevel] RETURNS [ evl: LIST OF Hickory.EventTuple] = BEGIN thisYear: REF YearNode _ FindYearTree[ date.Year]; IF thisYear = NIL THEN BEGIN thisYear _ NewYearNode[ date]; InsertYearTree[ thisYear]; END; BEGIN OPEN thisYear.MonthNodes[ date.Month].DayNodes[ date.Day]; IF Initialized THEN RETURN[ EvList] ELSE BEGIN -- go and get it from hickory SELECT zoomLevel FROM Day => FetchADay[ date, thisYear]; Month => [] _ FetchAMonth[ date, thisYear, NIL]; Year => FetchAYear[ date, thisYear]; ENDCASE; RETURN[ EvList]; END; -- IF initialized... END; -- OPEN END; -- GetEventsOfDay FetchADay: INTERNAL PROCEDURE [ date: Date, thisYear: REF YearNode] = BEGIN OPEN thisYear.MonthNodes[ date.Month].DayNodes[ date.Day]; from, to: BasicTime.GMT; options: Hickory.Options _ Hickory.NoOptions; options[ Hickory.ExpandRepetitions] _ TRUE; options[ Hickory.All] _ FALSE; [ from, to] _ GetTimeInterval[ date, Day]; EvList _ Hickory.RestoreEvents[ from, to, options]; Initialized _ TRUE; END; -- FetchADay FetchAMonth: INTERNAL PROCEDURE [ date: Date, thisYear: REF YearNode, evl: Hickory.EventList _ NIL, query: BOOLEAN _ TRUE] RETURNS [ truncatedEvl: Hickory.EventList] = BEGIN options: Hickory.Options _ Hickory.NoOptions; options[ Hickory.ExpandRepetitions] _ TRUE; options[ Hickory.All] _ FALSE; IF evl = NIL AND query THEN BEGIN -- must access Hickory from, to: BasicTime.GMT; [ from, to] _ GetTimeInterval[ date, Month]; evl _ Hickory.RestoreEvents[ from, to, options]; END; BEGIN OPEN thisYear.MonthNodes[ date.Month]; FOR d: Days IN [ 1..GetMonthInfo[ date.Month, date.Year].nbrOfDays] DO dayList: Hickory.EventList; [ dayList, evl] _ GetDayList[ evl, [ d, date.Month, date.Year]]; DayNodes[ d].EvList _ dayList; DayNodes[ d].Initialized _ TRUE; ENDLOOP; Initialized _ TRUE; RETURN[ evl]; END; END; -- FetchAMonth GetDayList: INTERNAL PROCEDURE [ evl: Hickory.EventList, date: Date] RETURNS [ dayList, remainder: Hickory.EventList] = BEGIN from, to: BasicTime.GMT; cur, prev, head: Hickory.EventList; IF evl = NIL THEN RETURN[ NIL, NIL]; [ from, to] _ GetTimeInterval[ date, Day]; IF BasicTime.Period[ to, evl.first.EventTime] > 0 THEN RETURN[ NIL, evl]; cur _ evl; prev _ NIL; WHILE cur # NIL AND BasicTime.Period[ cur.first.EventTime, from] > 0 DO prev _ cur; cur _ cur.rest; ENDLOOP; head _ cur; WHILE cur # NIL AND BasicTime.Period[ cur.first.EventTime, to] >= 0 DO prev _ cur; cur _ cur.rest; ENDLOOP; evl _ prev.rest; prev.rest _ NIL; RETURN[ head, evl]; END; -- GetDayList FetchMonths: INTERNAL PROCEDURE [ m1, m2: Months, year: Years] RETURNS [ evl: Hickory.EventList] = BEGIN from, to: BasicTime.GMT; options: Hickory.Options _ Hickory.NoOptions; options[ Hickory.ExpandRepetitions] _ TRUE; options[ Hickory.All] _ FALSE; [ from, ] _ GetTimeInterval[ [ 1, m1, year], Month]; [ , to] _ GetTimeInterval[ [ 1, m2, year], Month]; evl _ Hickory.RestoreEvents[ from, to, options]; END; -- FetchMonths FetchAYear: INTERNAL PROCEDURE [ date: Date, thisYear: REF YearNode] = BEGIN month1, month2: Months; evl1, evl2, cur: Hickory.EventList; options: Hickory.Options _ Hickory.NoOptions; GetInitializedMonths: INTERNAL PROCEDURE [ thisYear: REF YearNode] RETURNS [ from, to: Months] = BEGIN OPEN thisYear; m: Months; from _ unspecified; to _ unspecified; FOR m _ January, SUCC[ m] UNTIL m = unspecified OR MonthNodes[ m].Initialized DO NULL; ENDLOOP; IF m # unspecified THEN from _ m ELSE RETURN[ from, to]; FOR m _ m, SUCC[ m] UNTIL m = unspecified OR NOT MonthNodes[ m].Initialized DO NULL; ENDLOOP; IF m = unspecified THEN RETURN [ from, December] ELSE RETURN[ from, PRED[ m]]; END; -- GetInitializedMonths options[ Hickory.ExpandRepetitions] _ TRUE; options[ Hickory.All] _ FALSE; [ month1, month2] _ GetInitializedMonths[ thisYear]; IF month1 = January AND month2 = December THEN BEGIN thisYear.Initialized _ TRUE; RETURN; END; IF month1 # unspecified THEN BEGIN -- there is at least one initialized month IF month1 # January THEN evl1 _ FetchMonths[ January, PRED[ month1], date.Year] -- not inclusive initialized months... ELSE evl1 _ NIL; IF month2 # December THEN evl2 _ FetchMonths[ SUCC[ month2], December, date.Year] ELSE evl2 _ NIL; IF evl2 # NIL THEN IF evl1 # NIL THEN BEGIN -- concatenate both lists. cur _ evl1; DO IF cur.rest = NIL THEN EXIT; cur _ cur.rest; ENDLOOP; cur.rest _ evl2; END ELSE evl1 _ evl2; -- evl1 was empty END ELSE BEGIN -- get the entire year from, to: BasicTime.GMT; [ from, to] _ GetTimeInterval[ date, Year]; evl1 _ Hickory.RestoreEvents[ from, to, options]; END; FOR m: Months IN [ January..December] DO IF NOT thisYear.MonthNodes[ m].Initialized THEN evl1 _ FetchAMonth[ [ 1, m, date.Year], thisYear, evl1, FALSE]; ENDLOOP; thisYear.Initialized _ TRUE; END; -- FetchAYear RetrieveViewer: PUBLIC INTERNAL PROCEDURE [ date: Date, zoom: ZoomLevel] RETURNS [ viewer: ViewerClasses.Viewer] = BEGIN thisYear: REF YearNode; IF zoom = Day THEN RETURN[ NIL]; thisYear _ FindYearTree[ date.Year]; IF thisYear = NIL THEN RETURN[ NIL]; IF zoom = Month THEN RETURN[ thisYear.MonthNodes[ date.Month].Viewer] ELSE RETURN[ thisYear.Viewer]; END; -- RetrieveViewer StoreViewer: PUBLIC INTERNAL PROCEDURE [ date: Date, zoom: ZoomLevel, viewer: ViewerClasses.Viewer] = BEGIN thisYear: REF YearNode; IF zoom = Day THEN RETURN; -- day viewers not stored! thisYear _ FindYearTree[ date.Year]; IF thisYear = NIL THEN RETURN; IF zoom = Month THEN thisYear.MonthNodes[ date.Month].Viewer _ viewer ELSE thisYear.Viewer _ viewer; END; -- StoreViewer DestroyAllViewers: PUBLIC INTERNAL PROCEDURE = BEGIN FOR years: REF YearNode _ yearTrees, years.Next UNTIL years = NIL DO IF years.Viewer # NIL THEN BEGIN ViewerOps.DestroyViewer[ years.Viewer]; years.Viewer _ NIL; END; FOR mo: Months IN [ January..December] DO OPEN years; IF MonthNodes[ mo].Viewer # NIL THEN BEGIN ViewerOps.DestroyViewer[ MonthNodes[ mo].Viewer]; MonthNodes[mo].Viewer _ NIL; END; ENDLOOP; ENDLOOP; END; -- DestroyAllViewers FindEvent: PUBLIC INTERNAL PROCEDURE [ date: Date, key: Hickory.Event] RETURNS [ ev: REF Hickory.EventTuple] = BEGIN cur: Hickory.EventList; IF key = NIL THEN RETURN[ NIL]; cur _ GetEventsOfDay[ date, Day]; WHILE cur # NIL DO IF Hickory.SameEvent[ key, cur.first.Key] THEN BEGIN new: REF Hickory.EventTuple _ NEW[ Hickory.EventTuple _ cur.first]; RETURN [ new]; END; cur _ cur.rest; ENDLOOP; RETURN[ NIL]; END; -- FindEvent InitStorage: ENTRY PROCEDURE = BEGIN now, from, to: BasicTime.GMT _ BasicTime.Now[]; time: BasicTime.Unpacked _ BasicTime.Unpack[ now]; evl: Hickory.EventList; options: Hickory.Options _ Hickory.NoOptions; date: Date; curDate.Year _ time.year; curDate.Month _ time.month; curDate.Day _ time.day; curMode _ Initial; yearTrees _ NewYearNode[ curDate]; -- we need at least one! options[ Hickory.All] _ FALSE; options[ Hickory.ExpandRepetitions] _ TRUE; from _ Tempus.Adjust[ months: FirstMonth, baseTime: now, precisionOfResult: days].time; date _ CalSupport.ExtractDate[ from]; time.hour _ 0; time.minute _ 0; time.second _ 0; time.day _ 1; time.month _ date.Month; time.year _ date.Year; from _ BasicTime.Pack[ time]; to _ Tempus.Adjust[ months: LastMonth, baseTime: now, precisionOfResult: days].time; date _ CalSupport.ExtractDate[ to]; time.hour _ 23; time.minute _ 59; time.second _ 59; time.month _ date.Month; time.year _ date.Year; time.day _ CalSupport.GetMonthInfo[ date.Month, date.Year].nbrOfDays; to _ BasicTime.Pack[ time]; evl _ Hickory.RestoreEvents[ from: from, to: to, options: options]; FOR i: INT IN [ FirstMonth..LastMonth] DO -- preload cache date: Date _ CalSupport.ExtractDate[ Tempus.Adjust[ months: i, baseTime: now, precisionOfResult: days].time]; thisYear: REF YearNode _ FindYearTree[ date.Year]; IF thisYear = NIL THEN BEGIN thisYear _ NewYearNode[ date]; InsertYearTree[ thisYear]; END; date.Day _ 1; evl _ FetchAMonth[ date, thisYear, evl, FALSE]; ENDLOOP; END; --InitStorage; HickoryChange: PUBLIC INTERNAL PROCEDURE [ reason: Hickory.Reason, ev: Hickory.Event, data: RopeSets.RopeSet] RETURNS [ oldEvl, newEvl: Hickory.EventList] = BEGIN options: Hickory.Options _ Hickory.NoOptions; from, to: BasicTime.GMT; options[ Hickory.ExpandRepetitions] _ TRUE; options[ Hickory.All] _ FALSE; [ from, to] _ MinMaxCalDates[]; oldEvl _ NIL; newEvl _ NIL; SELECT reason FROM NewEvent, UnForget => BEGIN -- assume forgotten events are not in CalStorage newEvl _ Hickory.RestoreEvents[ from: from, to: to, options: options, key: ev]; UpdateStorage[ reason, newEvl]; END; Edit => BEGIN oldEvl _ RemoveFromStorage[ ev]; -- because of those bloody repetitions... newEvl _ Hickory.RestoreEvents[ from: from, to: to, options: options, key: ev]; UpdateStorage[ reason, newEvl]; END; Forget => BEGIN -- retrieve the events that are now forgotten in db... options[ Hickory.ExpandRepetitions] _ TRUE; options[ Hickory.All] _ TRUE; oldEvl _ Hickory.RestoreEvents[ from: from, to: to, options: options, key: ev]; UpdateStorage[ reason, oldEvl]; END; Destroy => BEGIN oldEvl _ RemoveFromStorage[ ev]; END; ENDCASE; RETURN[oldEvl, newEvl]; END; -- HickoryChange MinMaxCalDates: INTERNAL PROCEDURE RETURNS [ t1, t2: BasicTime.GMT] = BEGIN time: BasicTime.Unpacked; yp: REF YearNode; time.year _ yearTrees.Year; time.month _ January; time.day _ 1; time.hour _ 0; time.minute _ 0; time.second _ 0; t1 _ BasicTime.Pack[ time]; yp _ yearTrees; WHILE yp.Next # NIL DO yp _ yp.Next; ENDLOOP; time.year _ yp.Year; time.month _ December; time.day _ 31; -- again: Anne's birthday time.hour _ 23; time.minute _ 59; time.second _ 59; t2 _ BasicTime.Pack[ time]; RETURN[ t1, t2]; END; -- MinMaxCalDates UpdateStorage: INTERNAL PROCEDURE [ reason: Hickory.Reason, evl: Hickory.EventList] = BEGIN FOR l: Hickory.EventList _ evl, l.rest UNTIL l = NIL DO SELECT reason FROM Edit, NewEvent, UnForget => InsertEvent[ l.first, CalSupport.ExtractDate[ l.first.EventTime]]; Forget => ForgetEvent[ l.first, CalSupport.ExtractDate[ l.first.EventTime]]; ENDCASE; ENDLOOP; END; -- UpdateStorage InsertEvent: INTERNAL PROCEDURE [ evt: Hickory.EventTuple, date: Date] = BEGIN thisYear: REF YearNode _ FindYearTree[ date.Year]; IF thisYear = NIL THEN RETURN; -- this shouldn't really happen.. BEGIN OPEN thisYear.MonthNodes[ date.Month].DayNodes[ date.Day]; IF NOT Initialized THEN RETURN; -- well, since our min,max dates migh be wrong... IF EvList = NIL THEN EvList _ CONS[ evt, NIL] ELSE BEGIN evl: Hickory.EventList _ CONS[ evt, EvList]; EvList _ Hickory.OrderEventList[ evl]; END; END; -- OPEN END; -- InsertEvent ForgetEvent: INTERNAL PROCEDURE [ evt: Hickory.EventTuple, date: Date] = BEGIN thisYear: REF YearNode _ FindYearTree[ date.Year]; IF thisYear = NIL THEN RETURN; -- this shouldn't really happen.. BEGIN OPEN thisYear.MonthNodes[ date.Month].DayNodes[ date.Day]; IF NOT Initialized THEN RETURN; -- well, since our min,max dates migh be wrong... IF EvList = NIL THEN RETURN ELSE BEGIN prev: Hickory.EventList _ NIL; cur: Hickory.EventList _ EvList; WHILE cur # NIL DO -- in case several repetitions on same date ( day) WHILE cur # NIL AND NOT Hickory.SameEvent[ evt.Key, cur.first.Key] DO prev _ cur; cur _ cur.rest; ENDLOOP; IF cur = NIL THEN RETURN; -- not found ?! IF prev # NIL THEN BEGIN -- delete in middle prev.rest _ cur.rest; cur.rest _ NIL; -- and GC takes care of the rest cur _ prev.rest; END ELSE BEGIN -- prev = NIL -> delete at head EvList _ cur.rest; cur.rest _ NIL; IF EvList # NIL THEN cur _ EvList.rest ELSE cur _ NIL; END ENDLOOP; END; END; -- OPEN END; -- ForgetEvent RemoveFromStorage: INTERNAL PROCEDURE [ ev: Hickory.Event] RETURNS [ evl: Hickory.EventList] = BEGIN yp: REF YearNode _ yearTrees; evl _ NIL; WHILE yp # NIL DO FOR m: Months IN [ January..December] DO FOR d: Days IN [ 1..31] DO OPEN yp^.MonthNodes[ m].DayNodes[ d]; IF NOT Initialized THEN LOOP ELSE IF EvList = NIL THEN LOOP ELSE BEGIN prev: Hickory.EventList _ NIL; cur: Hickory.EventList _ EvList; WHILE cur # NIL DO IF Hickory.SameEvent[ cur.first.Key, ev] THEN BEGIN -- delete the sucker IF prev # NIL THEN BEGIN prev.rest _ cur.rest; cur.rest _ evl; evl _ cur; -- insert in front of evl cur _ prev.rest; -- next elm. END ELSE BEGIN -- delete cur at head of EvList EvList _ cur.rest; cur.rest _ evl; evl _ cur; -- insert in front of evl IF EvList # NIL THEN cur _ EvList.rest ELSE cur _ NIL; END END ELSE BEGIN prev _ cur; cur _ cur.rest; END; ENDLOOP; END; -- If not initialized ENDLOOP; -- for all days ENDLOOP; -- for all months yp _ yp.Next; -- next year ENDLOOP; -- for all years RETURN[ evl]; END; -- CalStorageImpl InitStorage[]; END. N/ivy/binding/calendar/calStorageImpl.mesa providing the storage for calendar data, i.e. mainly caching the Hickory events but also keeping the viewers we create for browsers... Last edited by: Binding, August 16, 1984 2:50:59 pm PDT to initialize a year tree properly to insert a new tree into the list of year nodes pointed to by yearTrees returns nil if year not in list of yearnodes first look into year tree on the given date, if node not initialized query Hickory and initialize node here we access Hickory for just one day. here we try to get back the month's events. If evl non NIL then we use the supplied list, else we call Hickory, if query is set. truncate the dayList off from evl, which is ordered... make at least one step... to get a period of several months.. fetch a whole year, taking in account possibly initialized months.. returns the months within a year that are initialized [ inclusive]! evl1 is valid list.. to go through all years and throw away the browsing viewers that we have kept around. To be called when top level viewer was destroyed. return the pointer onto the event in storage. and make a copy..! to initialize all global variables maintaining the storage ( except viewers) when hickory is updated... here we update hickory storage and return the list of events that have indeed changed to find out what are the extreme points in calendar. We make a rough estimate.. here we traverse the storage and update the event lists elements it's easy to find the right spot since we can find out about the date.. in case a new event appeared in Hickory... This is also the case when editing an event, since we have previously deleted all occurrences of the old unedited event. Reason is repeated events...! if an event was forgotten. It's still in data base, but we must remove it here. it's easier than destroy since we know the exact dates where event occurred here we must traverse all the trees and figure out where the events to be deleted are hidden. Since db no longer has the events, we can't get at the dates.. evl is the list of events that we found and have deleted from storage ÊĘJšœ)™)J™OJ™6Jšœ7™7J˜šÏk ˜ Jšœ œœ'˜˜EJšœ ˜Jšœ ˜—J˜šœœœ7˜CJ˜Jšœ œÏc9˜TJšœ œ˜Jšœ œ˜J˜š Ïn œ œœ œ œ˜QJšœ"™"Jšœœ ˜J˜šœ œ˜(J˜šœ œ ˜J˜)—Jšœ˜—Jšœ˜Jšœž˜J˜—š Ÿœœ œ œ œ˜AJšœH™HJšœ œ ˜J˜šœ œœ˜J˜Jšœ˜Jšœ˜—Jšœœ˜š˜Jšœœœœ˜Jšœœœ˜#J˜ J˜Jšœ˜—šœœœž"˜5Jšœ˜—šœœ˜!š œœœœž˜2J˜J˜Jš˜—šœœž˜&J˜J˜Jšœ˜——Jšœž˜—J˜š Ÿ œœ œœ œ ˜SJšœ,™,Jšœœ˜J˜š˜Jšœœœœ˜Jšœœœ˜!J˜ Jšœ˜—Jšœž˜—J˜šŸœœœ œ%œœœœ˜JšœV™VJšœ™Jšœ œ%˜2J˜šœ œœœ˜Jšœ˜J˜Jšœ˜—šœœ6˜@Jšœ œœ ˜#šœœž˜*šœ ˜J˜"Jšœ+œ˜0J˜$Jšœ˜—Jšœ ˜Jšœž˜—Jšœž˜ —Jšœž˜—J˜š Ÿ œœ œœ ˜KJšœ(™(Jšœ6˜:Jšœœ˜J˜-J˜Jšœ&œ˜+Jšœœ˜J˜*J˜3Jšœœ˜Jšœž ˜J˜—šŸ œœ œœ$œ œœœ&˜­JšœS™SJšœ,™,J˜-J˜Jšœ&œ˜+Jšœœ˜š œœœœœž˜9Jšœœ˜J˜,J˜0Jšœ˜—šœœ"˜,šœ œ6˜FJ˜J˜@J˜Jšœœ˜ Jšœ˜—Jšœœ˜Jšœ˜ Jšœ˜—šœž˜J˜——š Ÿ œœ œ'œ,˜}Jšœ6™6Jšœœ˜J˜#J˜Jš œœœœœœ˜$J˜*Jšœ0œœœ˜IJšœ™Jšœœ˜šœœœ2˜GJ˜Jšœ˜—J˜ šœœœ1˜FJ˜Jšœ˜—J˜Jšœ œ˜Jšœ ˜Jšœž ˜J˜—š Ÿ œœ œ œ˜hJšœ#™#Jšœœ˜J˜-J˜Jšœ&œ˜+Jšœœ˜J˜4J˜2J˜0Jšœž˜J˜—š Ÿ œœ œœ ˜LJšœC™CJ˜J˜#J˜-J˜š Ÿœœ œ œ œœ˜gJšœC™CJšœ ˜J˜ J˜J˜J˜š œœœœœ˜QJšœ˜Jšœ˜—Jšœœ œœ ˜8š œœœœœ˜NJšœ˜Jšœ˜—Jšœœœ˜0Jšœœœ˜Jšœž˜J˜—Jšœ&œ˜+Jšœœ˜J˜4šœœœ˜4Jšœœœ˜$Jšœ˜—šœœœž*˜Mšœœ˜Jšœœž&˜]—Jšœœ˜šœœ˜Jšœœ˜7—Jšœœ˜šœœ˜š œœœž˜4J˜ šœ˜Jšœ œœœ˜J˜Jšœ˜—J˜Jš˜—Jšœž˜#—Jš˜—šœœž˜"Jšœœ˜J˜+J˜1Jšœ˜—Jšœ™šœ œ˜(šœœ%˜/Jšœ8œ˜?—Jšœ˜—Jšœœ˜Jšœž ˜J˜—š Ÿœœœ œ œ#˜xJšœ œ ˜J˜Jšœ œœœ˜ J˜$Jš œ œœœœ˜$Jšœœœ*˜EJšœœ˜Jšœž˜J˜—š Ÿ œœœ œ@˜kJšœ œ ˜J˜Jšœ œœž˜5J˜$Jšœ œœœ˜Jšœœ1˜EJšœ˜Jšœž˜J˜—š Ÿœœœ œ˜4JšœH™HJšœ>™>š œœ#œ œ˜Ešœœœ˜ J˜'Jšœœ˜Jšœ˜—šœ œ˜)Jšœ˜ šœœœ˜+J˜1Jšœœ˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœž˜J˜—š Ÿ œœœ œ#œœ˜tJšœ@™@Jšœ˜J˜Jš œœœœœ˜J˜!šœœ˜šœ(œ˜4Jšœœœ"˜CJšœ˜Jšœ˜—J˜Jšœ˜—Jšœœ˜ Jšœž ˜J˜—šŸ œœ œ˜$Jšœ"™"J™Jšœœ˜/J˜2J˜J˜-J˜ J˜J˜MJ˜Jšœ#ž˜;Jšœœ˜Jšœ&œ˜+J˜JšœW˜WJ˜%J˜1J˜>Jšœ˜J˜JšœT˜TJ˜#J˜3J˜/J˜EJ˜J˜J˜Cš œœœœž˜:J˜mJšœ œ%˜2šœ œœœ˜Jšœ˜J˜Jšœ˜—J˜ Jšœ(œ˜/Jšœ˜—Jšœž˜J˜——šœD™DJ˜š Ÿ œœœ œFœ(˜¢JšœM™MJšœ™J˜-Jšœœ˜J˜Jšœ&œ˜+Jšœœ˜Jšœ˜Jšœ œ œ˜šœ˜šœœž0˜LJ˜OJ˜Jšœ˜—šœ˜ Jšœ!ž)˜JJ˜OJ˜Jšœ˜—šœ œž6˜FJšœ&œ˜+Jšœœ˜J˜OJ˜Jšœ˜—šœ ˜J˜ Jšœ˜—Jšœ˜—Jšœ˜Jšœž˜J˜—š Ÿœœ œœœ˜KJšœO™OJ˜Jšœœ ˜J˜J˜J˜#J˜0J˜J˜Jšœ œœœ˜-J˜Jšœ&ž˜?J˜3J˜Jšœ ˜Jšœž˜J˜—šŸ œœ œ5˜[Jšœ@™@J™Gšœ$œœ˜7šœ˜J˜^J˜LJšœ˜—Jšœ˜—Jšœž˜J˜—šŸ œœ œ*˜NJšœP™PJ™RJ™Jšœ œ%˜2J˜Jš œ œœœž!˜@šœœ6˜@Jš œœ œœž1˜QJš œ œœ œœ˜-šœ˜ J˜,J˜&Jšœ˜—Jšœž˜ —Jšœž˜J˜—šŸ œœ œ*˜NJšœO™OJšœK™KJšœ œ%˜2J˜Jš œ œœœž!˜@šœœ6˜@Jš œœ œœž1˜QJšœ œœ˜šœ˜ Jšœœ˜J˜ šœœœž2˜Eš œœœœ,˜EJ˜Jšœ˜—Jš œœœœž˜)š œœœœž˜,Jšœ!œž ˜FJ˜Jš˜—šœœž˜*Jšœœ˜"Jšœ œœ˜&Jšœœ˜Jš˜—Jšœ˜—Jšœ˜—Jšœž˜ —Jšœž˜J˜—š Ÿœœ œœ˜dJšœQ™QJšœJ™JJšœE™EJšœœ˜J˜Jšœœ˜ šœœ˜šœ œ˜(šœ œ ˜Jšœ!˜%Jšœœ œ˜Jš œœ œœ˜šœ˜ Jšœœ˜J˜ šœœ˜šœ'œœž˜Hšœœœ˜J˜Jšœž˜4Jšœž ˜Jš˜—šœœž˜*Jšœ,ž˜GJšœ œœ˜&Jšœœ˜Jš˜—Jš˜—šœ˜ J˜Jšœ˜—Jšœ˜—Jšœž˜—Jšœž˜—Jšœž˜—Jšœž ˜Jšœž˜—Jšœ˜ Jšœž˜J˜—J˜Jšœ˜——…—9T