DIRECTORY
Atom,
BasicTime,
CedarProcess,
CD,
CDEnvironment USING [ExecFileEntry],
CDEvents USING [EventProc, RegisterEventProc, ProcessEvent, EventRegistration, RegisterEventType],
CDIO,
CDOps USING [DoTheDelayedRedraws],
CDPrivate,
CDProperties,
CDSequencer,
IO,
MBQueue USING [Queue, Create, QueueClientAction, Flush],
MessageWindow,
PopUpSelection,
Process,
RefTab,
Rope,
RuntimeError USING [UNCAUGHT],
TerminalIO,
TokenIO,
UserProfile;

CDSequencerImpl: CEDAR MONITOR 
IMPORTS Atom, BasicTime, CedarProcess, CD, CDEvents, CDEnvironment, CDIO, CDOps, CDPrivate, CDProperties, IO, MBQueue, MessageWindow, PopUpSelection, Process, RefTab, Rope, RuntimeError, TerminalIO, TokenIO, UserProfile 
EXPORTS CDSequencer, CD = 
BEGIN

Message: PROC [r: Rope.ROPE] = {
MessageWindow.Append[r, TRUE];
MessageWindow.Blink[];
};

ErrorChangeReadOnlyDesign: PROC [d: CD.Design_NIL] = TRUSTED {
Process.Detach[FORK 
Message[Rope.Cat["design """, IF d=NIL THEN "" ELSE d.name, """ readonly"]]
];
ERROR CD.Error[designMutability];
};

Command: TYPE = CDSequencer.Command;
CommandProc: TYPE = CDSequencer.CommandProc;
QueueMethod: TYPE = CDSequencer.QueueMethod;

PrivateSequencerDRep: PUBLIC TYPE = RECORD [
queue: MBQueue.Queue,
whileCommand: INT_0, --modifyed by monitored procedures inside single call proc
whileOutput: BOOL_FALSE, --Set monitored, cleared by one single output process
stopWrite: REF BOOL,
abort: BOOL_FALSE,
abortFlags: LIST OF REF BOOL_NIL,
notInit: BOOL_TRUE,
lastCommand: BasicTime.GMT, 
lastOutput: BasicTime.GMT,
num: INT_0
];

PrivateSequencerTRep: PUBLIC TYPE = RECORD [
commandTab: RefTab.Ref
];

Registration: TYPE = REF RegistrationRec;
RegistrationRec: TYPE = RECORD [p: CommandProc, qm: QueueMethod, registrationData: REF_NIL];
InternalRec: TYPE = RECORD [comm: Command, qm: QueueMethod, proc: CommandProc];

globalTab: RefTab.Ref = RefTab.Create[mod: 193]; -- holds commands used in all technologies
quit: ERROR [msg: Rope.ROPE] = CODE; --actually is signal, but we never return...
designNumber: INT_0;
now: BasicTime.GMT _ BasicTime.Now[]; --lags behind 
savePeriod: INT _ 0;

reCheck: CONDITION _ [timeout: Process.MsecToTicks[1000]];

EnterCommand: ENTRY PROC [x: REF PrivateSequencerDRep] = INLINE {
ENABLE UNWIND => NULL;
x.whileCommand _ x.whileCommand+1;
};

LeaveCommand: ENTRY PROC [x: REF PrivateSequencerDRep] = INLINE {
ENABLE UNWIND => NULL;
x.whileCommand _ x.whileCommand-1;
};

EnterOutput: ENTRY PROC [x: REF PrivateSequencerDRep] RETURNS [enter: BOOL_FALSE] = {
ENABLE UNWIND => NULL;
IF enter_(x.whileCommand=0) THEN {
IF x.stopWrite=NIL THEN x.stopWrite_NEW[BOOL];
x.stopWrite^ _ FALSE;
x.whileOutput _ TRUE
}
};

DesignRegistrationEvent: CDEvents.EventProc = {
data: REF PrivateSequencerDRep _ NEW[PrivateSequencerDRep_[
queue: MBQueue.Create[],
stopWrite: NEW[BOOL_FALSE],
lastCommand: now, 
lastOutput: now, 
num: designNumber
]];
designNumber _ designNumber+1;
design.cdSequencerPriv _ data;
design.cdSequencerPriv.notInit _ FALSE;
};

TechRegistrationEvent: CDEvents.EventProc = {
tech: CD.Technology = NARROW[x];
tech.cdSequencerPriv _ NEW[PrivateSequencerTRep _ [commandTab: RefTab.Create[mod: 41]]]
};

UnKnownCommand: PROC [comm: CDSequencer.Command] = {
key: ATOM _ IF comm.key#NIL THEN comm.key ELSE $NIL;
r: Rope.ROPE _ IO.PutFR["command %g not known", [atom[key]]];
Message[r];
TerminalIO.PutRopes[r, "\n"];
};

TriedChangingReadonlyDesignCommand: PROC [comm: CDSequencer.Command] = {
key: ATOM _ IF comm.key#NIL THEN comm.key ELSE $NIL;
TerminalIO.PutF["command %g tries to change design ""%g"", but design is readonly\n", 
[atom[key]], [rope[CD.DesignName[comm.design]]]
];
};

WriteMsg: PROC [r: Rope.ROPE] = {
IF Rope.Length[r]>0 THEN {
IF Rope.Fetch[r, Rope.Length[r]-1]#'\n THEN r _ Rope.Concat[r, "\n"];
TerminalIO.PutRope[r];
};
};

InternalExec: PROC [ref: REF ANY] = { --type good for MBQueue.QueueClientAction
ENABLE {
ABORTED => {WriteMsg["** ABORTED"]; GOTO Oops};
quit => {WriteMsg[msg]; GOTO Oops};
CD.Error => IF ec=designMutability THEN {
WriteMsg["** aborted try to change readonly design"]; GOTO Oops
};
TerminalIO.UserAbort => {WriteMsg["** aborted interactive input"]; GOTO Oops};
};
ic: REF InternalRec = NARROW[ref];
IF ic.qm=dontQueue THEN 
ic.proc[ic.comm ! RuntimeError.UNCAUGHT => IF ShouldDebug[LOOPHOLE[signal]] 
THEN REJECT 
ELSE CONTINUE
]
ELSE {
de: REF PrivateSequencerDRep = ic.comm.design.cdSequencerPriv;
Protected: PROC [de: REF PrivateSequencerDRep] ~ {
ENABLE UNWIND => LeaveCommand[de];
WHILE de.whileOutput DO
stop: REF BOOL _ de.stopWrite;
IF stop#NIL THEN stop^ _ TRUE;
IF de.whileOutput THEN Process.Pause[1]
ENDLOOP;
de.lastCommand _ now;
IF ic.qm=doQueueAndMark THEN {
IF ~ic.comm.design.changedSinceSaving OR ~ic.comm.design.actual.first.specific.changed THEN 
MarkChanged[ic.comm.design
! CD.Error => 
IF ec=designMutability THEN {
ic.proc _ TriedChangingReadonlyDesignCommand; CONTINUE;
};
];
};
IF Process.GetPriority[]>Process.priorityNormal THEN CedarProcess.SetPriority[CedarProcess.Priority[normal]];
de.abort _ FALSE;
ic.proc[ic.comm ! RuntimeError.UNCAUGHT => IF ShouldDebug[LOOPHOLE[signal]] 
THEN REJECT 
ELSE CONTINUE
];
de.abortFlags _ NIL;
LeaveCommand[de]
};--END Protected
IF de=NIL THEN ERROR CD.Error[programming];
EnterCommand[de];
Protected[de];
};
CDOps.DoTheDelayedRedraws[ic.comm.design];
EXITS Oops => NULL
};

ShouldDebug: PROC [signal: SIGNAL ANY RETURNS ANY] RETURNS [debug: BOOL_TRUE] = {
WITH CDProperties.GetAtomProp[$CDDebugPrivate, $CDDebugPrivate] SELECT FROM
rs: REF SIGNAL ANY RETURNS ANY => IF signal=rs^ THEN RETURN [TRUE];
ENDCASE => NULL;
IF UserProfile.Boolean["ChipNDale.OpenEventViewers", FALSE] THEN RETURN [TRUE];
DO
SELECT PopUpSelection.Request[
header: "ERROR", 
choice: LIST["continue with ChipNDale", "debug"], 
headerDoc: "error while executing ChipNDale command", 
choiceDoc: LIST["usually ok", "land in debugger (abort will continue ChipNDale)"]
] FROM
1 => RETURN [FALSE];
2 => RETURN [TRUE];
ENDCASE => NULL;
TerminalIO.PutRope["don't skip this!\n"];
ENDLOOP
};

Quit: PUBLIC PROC [message: Rope.ROPE] = {
ERROR quit[message]
};

ImplementCommand: PUBLIC ENTRY PROC [key: ATOM, proc: CommandProc, technology: CD.Technology, queue: QueueMethod, registrationData: REF_NIL] = {
ENABLE UNWIND => NULL; 
table: RefTab.Ref _ globalTab;
IF technology#NIL THEN table _ technology.cdSequencerPriv.commandTab;
[] _ RefTab.Store[table, key, NEW[RegistrationRec _ [p: proc, qm: queue, registrationData: registrationData]]];
};

FetchCommand: PUBLIC PROC[key: ATOM, technology: CD.Technology, load: BOOL_TRUE] RETURNS [proc: CommandProc_NIL, qm: QueueMethod_dontQueue, registrationData: REF_NIL] = {

FetchRegistration: PROC[key: ATOM, technology: CD.Technology] RETURNS [cd: Registration] = INLINE {
IF technology#NIL THEN { -- search first for particular technology
cTab: REF PrivateSequencerTRep = technology.cdSequencerPriv;
val: RefTab.Val _ RefTab.Fetch[cTab.commandTab, key].val;
IF val#NIL THEN RETURN [NARROW[val]];
};
RETURN [NARROW[RefTab.Fetch[globalTab, key].val]];
};

cd: Registration _ FetchRegistration[key, technology];
IF cd=NIL AND load THEN {
CDEnvironment.ExecFileEntry[Atom.GetPName[key], technology, "cmds", FALSE, FALSE !
ABORTED => CONTINUE;
RuntimeError.UNCAUGHT => 
SELECT PopUpSelection.Request[
header: "ERROR", 
choice: LIST["continue with ChipNDale", "debug"], 
headerDoc: "error while executing command file", 
choiceDoc: LIST["usually ok", "land in debugger (abort will continue ChipNDale)"]
] FROM
1 => CONTINUE;
2 => REJECT;
ENDCASE => CONTINUE;
];
cd _ FetchRegistration[key, technology];
};
IF cd#NIL THEN {proc_cd.p; qm_cd.qm; registrationData_cd.registrationData};
};

Call: PROC [ic: REF InternalRec] = INLINE {
IF ic.qm=dontQueue THEN InternalExec[ic]   
ELSE { 
WHILE ic.comm.design.cdSequencerPriv.notInit DO
WaitInitialization[ic.comm.design.cdSequencerPriv]
ENDLOOP;
MBQueue.QueueClientAction[ic.comm.design.cdSequencerPriv.queue, InternalExec, ic]
}
};

ExecuteProc: PUBLIC PROC [proc: CommandProc, design: CD.Design, queue: QueueMethod, comm: CDSequencer.Command] = {
ic: REF InternalRec _ NEW[InternalRec_[
comm: NEW[CDSequencer.CommandRec],
proc: IF proc=NIL THEN UnKnownCommand ELSE proc,
qm: queue
]];
IF comm#NIL THEN ic.comm^ _ comm^;
IF design#NIL THEN ic.comm.design _ design;
Call[ic]
};

ExecuteCommand: PUBLIC PROC [key: ATOM, design: CD.Design, queue: QueueMethod, comm: CDSequencer.Command] = {
ic: REF InternalRec _ NEW[InternalRec_[
comm: NEW[CDSequencer.CommandRec],
proc: NIL,
qm: useDefault
]];
IF comm#NIL THEN ic.comm^ _ comm^;
IF key#NIL THEN ic.comm.key _ key;
IF design#NIL THEN ic.comm.design _ design;
[proc: ic.proc, qm: ic.qm] _ FetchCommand[ic.comm.key, ic.comm.design.technology, TRUE];
IF ic.proc=NIL THEN { 
ic.proc _ UnKnownCommand; ic.qm _ dontQueue;
};
IF queue#useDefault THEN ic.qm _ queue;
Call[ic]
};

RecheckEdited: PROC [design: CD.Design] = {
[] _ CDEvents.ProcessEvent[recheckEditedRequest, design];
};

SetEdited: PUBLIC PROC [design: CD.Design, edited: BOOL] = {
was: BOOL _ design.edited;
IF edited THEN IF design.mutability#editable THEN ErrorChangeReadOnlyDesign[design];
design.edited _ edited;
IF was#edited THEN RecheckEdited[design];
};

MarkChangedIOOnly: PUBLIC PROC [design: CD.Design] = {
IF ~design.actual.first.specific.changed OR ~design.changedSinceSaving THEN {
IF design.mutability#editable THEN ErrorChangeReadOnlyDesign[design];
design.changedSinceSaving _ TRUE;
design.edited _ TRUE;
TRUSTED {Process.Detach[FORK RecheckEdited[design]]};
}
};

MarkChanged: PUBLIC PROC [design: CD.Design] = {
IF ~design.actual.first.specific.changed OR ~design.changedSinceSaving THEN {
IF design.mutability#editable THEN ErrorChangeReadOnlyDesign[design];
design.actual.first.specific.changed _ TRUE;
design.changedSinceSaving _ TRUE;
design.edited _ TRUE;
TRUSTED {Process.Detach[FORK RecheckEdited[design]]};
}
};

WaitInitialization: ENTRY PROC [sPriv: REF PrivateSequencerDRep] = {
IF sPriv=NIL OR sPriv.notInit THEN WAIT reCheck
};


AbortDesignsCommand: PUBLIC PROC [design: CD.Design, flush: BOOL] = {
IF design=NIL THEN [] _ CDEvents.ProcessEvent[abortRequest, NIL]
ELSE {
de: REF PrivateSequencerDRep = design.cdSequencerPriv;
de.abort _ TRUE;
FOR bl: LIST OF REF BOOL _ de.abortFlags, bl.rest WHILE bl#NIL DO
IF bl.first#NIL THEN bl.first^_TRUE
ENDLOOP;
[] _ CDEvents.ProcessEvent[abortRequest, design];
IF flush THEN MBQueue.Flush[de.queue];
};
};

Aborted: PUBLIC PROC [design: CD.Design] RETURNS [BOOL] = {
RETURN [design.cdSequencerPriv.abort]
};

CheckAborted: PUBLIC PROC [design: CD.Design] = {
IF design.cdSequencerPriv.abort THEN Quit["command aborted"];
CedarProcess.CheckAbort[NIL];
};
UseAbortFlag: PUBLIC PROC [design: CD.Design, flag: REF BOOL] = {
IF design=NIL OR flag=NIL THEN ERROR CD.Error[calling];
design.cdSequencerPriv.abortFlags _ CONS[flag, design.cdSequencerPriv.abortFlags];
};

BackgroundSaveProcess: PROC = {

ProtectedSaveOneDesign: PROC [design: CD.Design] = {
de: REF PrivateSequencerDRep = design.cdSequencerPriv;
done: BOOL _ FALSE;
done _ CDIO.WriteDesign[design: design, to: NIL, quiet: TRUE, emergency: FALSE, stop: de.stopWrite ! TokenIO.Stopped, RuntimeError.UNCAUGHT => GOTO oops];
IF done THEN {
de.lastOutput _ BasicTime.Now[]; 
design.changedSinceSaving _ FALSE;
}
EXITS oops => NULL;
};

CheckDesignForSave: CDPrivate.DesignEnumerator = {
ENABLE RuntimeError.UNCAUGHT => GOTO oops; --give the next design a chance
Process.Pause[1]; -- little bit slower for the benefit of the viewer redraw
IF design#NIL THEN {
de: REF PrivateSequencerDRep = design.cdSequencerPriv; 
IF design.changedSinceSaving AND de#NIL AND de.whileCommand=0 AND BasicTime.Period[from: de.lastCommand, to: now]>2 AND BasicTime.Period[from: de.lastOutput, to: de.lastCommand]>savePeriod AND CDProperties.GetDesignProp[design, $CDxDontBackgroundSave]#$TRUE THEN {
IF EnterOutput[de] THEN  
ProtectedSaveOneDesign[design ! RuntimeError.UNCAUGHT => CONTINUE];
de.whileOutput _ FALSE;
CedarProcess.SetPriority[CedarProcess.Priority[background]]; --speed no more necessary
};
};
EXITS oops => NULL;
};

DO -- forever
now _ BasicTime.Now[]; Process.Pause[Process.SecondsToTicks[8]];
IF savePeriod>=0 THEN [] _ CDPrivate.EnumDesigns[CheckDesignForSave]
ENDLOOP;
};

NoteProfileChange: UserProfile.ProfileChangedProc = {
savePeriod _ UserProfile.Number[key: "ChipNDale.SavePeriod", default: 0];
}; 

abortRequest: CDEvents.EventRegistration = CDEvents.RegisterEventType[$Abort];
recheckEditedRequest: CDEvents.EventRegistration = CDEvents.RegisterEventType[$CheckEdited];
CDEvents.RegisterEventProc[$RegisterTechnology, TechRegistrationEvent];
CDEvents.RegisterEventProc[$CreateNewDesign, DesignRegistrationEvent];
UserProfile.CallWhenProfileChanges[NoteProfileChange];
TRUSTED {Process.Detach[FORK BackgroundSaveProcess[]]};
END. 


����CDSequencerImpl.mesa   (part of ChipNDale)
Copyright c 1983, 1986, 1987 by Xerox Corporation.  All rights reserved.
Created by Christian Jacobi, June 22, 1983 6:02 pm 
Last edited by: Christian Jacobi, April 2, 1987 2:31:43 pm PST
--Message r on Message window 
--using a RefTab is ok: we approximately know the number of entries

--not monitored: is called from inside a command
--CedarProcess.SetPriority[CedarProcess.Priority[normal]]; --so stops quickly if necessary
�Êv��˜�codešœ*™*Kšœ
Ïmœ=™HKšœ3™3K™>K˜�—šÏk	˜	K˜Kšœ
˜
Kšœ
˜
Kšžœ˜Kšœžœ˜$Kšœ	žœT˜bKšœ˜Kšœžœ˜"Kšœ
˜
Kšœ
˜
Kšœ˜Kšœ˜Kšœžœ+˜8Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ
žœžœ˜Kšœ˜Kšœ˜Kšœ˜—K˜�šÏbœžœžœ˜Kšžœ;žœ žœp˜ÜKšžœžœ˜—Kšž˜K˜�šÏnœžœ
žœ˜ K™Kšœžœ˜Kšœ˜K˜—K˜�š
 œžœžœžœžœ˜>šœžœ˜Kš	œžœžœžœžœ˜KKšœ˜—Kšžœžœ˜!Kšœ˜K˜�—Kšœ	žœ˜$Kšœ
žœ˜,Kšœ
žœ˜,K˜�šœžœžœ˜,Kšœ˜KšœžœÏc:˜OKšœ
žœžœ¡5˜NKšœžœžœ˜Kšœžœžœ˜Kšœžœžœžœžœžœ˜!Kšœ	žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜
Kšœ˜—K˜�šœžœžœžœ˜,K˜K˜—K˜�Kšœžœžœ˜)Kšœžœžœ5žœ˜\Kšœ
žœžœ5˜OK˜�šœ1¡*˜[KšœC™C—Kšœžœžœžœ¡,˜QKšœžœ˜Kšœžœ¡˜4Kšœžœ˜K˜�Kšœ	ž	œ(˜:K˜�š
 œžœžœžœžœ˜AKšžœžœžœ˜Kšœ"˜"K˜—K˜�š
 œžœžœžœžœ˜AKšžœžœžœ˜Kšœ"˜"K˜—K˜�š œžœžœžœžœ	žœžœ˜UKšžœžœžœ˜šžœžœ˜"Kš
žœ
žœžœ
žœžœ˜.Kšœžœ˜Kšœž˜K˜—K˜—K˜�šÐbnœ˜/šœžœžœ˜;Kšœ˜Kšœžœžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ!žœ˜'Kšœ˜—K˜�šŸœ˜-Kšœžœžœ˜ Kšœžœ=˜WKšœ˜—K˜�š œžœ ˜4Kšœžœžœ
žœžœ
žœ˜4Kšœžœžœ,˜=Kšœ˜Kšœ˜Kšœ˜—K˜�š "œžœ ˜HKšœžœžœ
žœžœ
žœ˜4šœV˜VKšœ/˜/Kšœ˜—Kšœ˜—K˜�š œžœ
žœ˜!šžœžœ˜Kšžœ%žœ˜EKšœ˜Kšœ˜—K˜—K˜�š	 œžœžœžœ¡)˜Ošžœ˜Kšžœžœ˜/Kšœžœ˜#šžœ
žœžœ˜)Kšœ6žœ˜?Kšœ˜—KšœCžœ˜NKšœ˜—Kšœžœžœ˜"šžœžœ˜šœžœžœ˜LKšžœžœ˜Kšžœž˜
Kšœ˜——šžœ˜Kšœžœ7˜>š 	œžœžœ˜2Kšžœžœ˜"šžœž˜Kšœžœžœ˜Kšžœžœžœ	žœ˜Kšžœžœ˜'Kšžœ˜—Kšœ˜šžœžœ˜šžœ$žœ/žœ˜\šœ˜šœžœ
˜šžœžœ˜Kšœ.žœ˜7K˜——Kšœ˜——Kšœ˜—Kšžœ.žœ9˜mKšœžœ˜šœžœžœ
žœ
˜LKšžœžœ˜Kšžœž˜
Kšœ˜—Kšœžœ˜Kšœ˜Kšœ¡˜—Kš
žœžœžœžœžœ˜+Kšœ˜Kšœ˜Kšœ˜—Kšœ*˜*Kšžœ	ž˜Kšœ˜—K˜�š œžœ
žœžœžœžœžœ	žœžœ˜Qšžœ<žœž˜KKšœžœžœžœžœžœžœžœžœžœ˜CKšžœžœ˜—Kš
žœ3žœžœžœžœ˜Ošž˜šžœ˜Kšœ˜Kšœžœ&˜2Kšœ6˜6KšœžœB˜QKšœž˜Kšœžœžœ˜Kšœžœžœ˜Kšžœžœ˜—K˜)Kšž˜—Kšœ˜—K˜�š œžœžœžœ˜*Kšžœ˜Kšœ˜—K˜�š œžœžœžœžœ!žœ3žœžœ˜Kšžœžœžœ˜Kšœ˜Kšžœžœžœ/˜EKšœžœN˜oKšœ˜—K˜�š œžœžœžœžœžœžœžœžœ/žœžœ˜ªK˜�š œžœžœžœ
žœžœ˜cšžœžœžœ¡)˜BKšœžœ3˜<Kšœ9˜9Kš
žœžœžœžœžœ˜%Kšœ˜—Kšžœžœ$˜2Kšœ˜—K˜�Kšœ6˜6šžœžœžœžœ˜šœDžœžœ˜RKšžœžœ˜šœ
žœ˜šžœ˜Kšœ˜Kšœžœ&˜2Kšœ1˜1KšœžœB˜QKšœž˜Kšœžœ˜Kšœžœ˜Kšžœžœ˜——Kšœ˜—Kšœ(˜(K˜—Kšžœžœžœ=˜KKšœ˜—K˜�š œžœžœžœ˜+Kšžœžœ˜+šžœ˜šžœ(ž˜/Kšœ2˜2Kšžœ˜—KšœQ˜QK˜—K˜—K˜�š œžœžœžœ;˜ršœžœžœ˜'Kšœžœ˜"Kš	œžœžœžœžœ˜0Kšœ	˜	Kšœ˜—Kšžœžœžœ˜"Kšžœžœžœ˜+Kšœ˜Kšœ˜—K˜�š
 œžœžœžœ
žœ;˜mšœžœžœ˜'Kšœžœ˜"Kšœžœ˜
Kšœ˜Kšœ˜—Kšžœžœžœ˜"Kšžœžœžœ˜"Kšžœžœžœ˜+KšœRžœ˜Xšžœ	žœžœ˜Kšœ,˜,K˜—Kšžœžœ˜'Kšœ˜Kšœ˜—K˜�š 
œžœ
žœ˜+Kšœ9˜9K˜—K˜�š
 	œžœžœ
žœžœ˜<Kšœžœ˜Kšžœžœžœžœ#˜TKšœ˜Kšžœžœ˜)K˜—K˜�š œžœžœ
žœ˜6šžœ'žœžœ˜MKšžœžœ#˜EKšœž˜!Kšœž˜Kšžœžœ˜5K˜—Kšœ˜—K˜�š œžœžœ
žœ˜0šžœ'žœžœ˜MKšžœžœ#˜EKšœ'ž˜,Kšœž˜!Kšœž˜Kšžœžœ˜5K˜—Kšœ˜—K˜�š œžœžœ	žœ˜DKš
žœžœžœžœžœ˜/Kšœ˜—K˜�K˜�š
¢œžœžœ
žœžœ˜EKšžœžœžœ*žœ˜@šžœ˜Kšœžœ/˜6Kšœžœ˜šžœžœžœžœžœžœžœž˜AKšžœ
žœžœž˜#Kšžœ˜—Kšœ1˜1Kšžœžœ˜&K˜—Kšœ˜—K˜�š œžœžœ
žœ	žœžœ˜;Kšžœ˜%Kšœ˜—K˜�š œžœžœ
žœ˜1Kšžœžœ˜=Kšœžœ˜Kšœ˜K™�—š
 œžœ
žœžœžœ˜AKšœ0™0Kšžœžœžœžœžœžœžœ˜7Kšœ$žœ*˜RK˜—K˜�š œžœ˜K˜�š œžœ
žœ˜4Kšœžœ/˜6Kšœžœžœ˜Kš
œžœ!žœ	žœ
žœ5žœžœ˜ššžœžœ˜Kšœ!˜!Kšœžœ˜"Kšœ˜—Kšžœ	žœ˜Kšœ˜K˜�—š œ ˜2Kšžœžœžœ¡˜JKšœ¡9˜Kšžœžœžœ˜Kšœžœ0˜7šžœžœžœžœžœ3žœFžœBžœ˜ˆKšœ;¡™Zšžœžœ˜Kšœ-žœžœ˜C—Kšœžœ˜Kšœ=¡˜VK˜—Kšœ˜—Kšžœ	žœ˜Kšœ˜—K˜�šžœ¡
˜
Kšœ@˜@Kšžœžœ/˜DKšžœ˜—Kšœ˜—K˜�šŸœ$˜5KšœI˜IKšœ˜—K˜�KšœN˜NKšœ\˜\KšœG˜GKšœF˜FKšœ6˜6Kšžœžœ˜7Kšžœ˜K˜�K˜�—�…—����1ô��EH��