DIRECTORY
BluejaySmarts,
IO,
Jukebox		USING [ bytesPerChirp, CloseTune, CreateTune, Handle, OpenTune, Tune, TuneSize ],
Lark			USING [ noMachine, VoiceSocket ],

Nice,

Process		USING [ Detach, MsecToTicks, Pause, SecondsToTicks, SetTimeout ],
PupDefs		USING [ MsToTocks, PupSocket, PupSocketDestroy, PupSocketMake ],
Rope,
Log			USING [ Problem, Report ],
ThParty		USING [ Advance, DescribeParty, SetInterval ],
Thrush		USING [ ConvEvent, ConversationHandle, Disposition, IntervalSpec, NB, newTune, nullConvHandle, nullHandle, nullTune, PartyHandle, SHHH, Reason, SmartsHandle, StateInConv, Tune ],
ThSmarts,
ThSmartsPrivate USING [ ConvDesc, ConvDescBody, OpenConversations ],
VoiceStream	USING [ AddPiece, Close, FlushPieces, Handle, IsEmpty, NotifyProc, Open, SetSocket, wholeTune ]
;

BluejaySmartsImpl: CEDAR MONITOR
IMPORTS IO, Jukebox,     Nice,    Process, PupDefs, Log, Rope, ThParty, VoiceStream
EXPORTS BluejaySmarts, ThSmarts  = {
OPEN BluejaySmarts, IO;


ConvDesc: TYPE = ThSmartsPrivate.ConvDesc;
ConversationHandle: TYPE = Thrush.ConversationHandle;
nullConvHandle: ConversationHandle = Thrush.nullConvHandle;
Disposition: TYPE = Thrush.Disposition;
PartyHandle: TYPE = Thrush.PartyHandle;
SHHH: TYPE = Thrush.SHHH;
SmartsHandle: TYPE = Thrush.SmartsHandle;
StateInConv: TYPE = Thrush.StateInConv;

jayShh: PUBLIC SHHH;
interfaceIsImported: PUBLIC BOOLEAN_FALSE;
encryptionRequested: PUBLIC BOOLEAN _ TRUE;
handle: PUBLIC Jukebox.Handle;
debug: PUBLIC BOOLEAN _ TRUE;
pERROR: ERROR=CODE;
NB: TYPE = Thrush.NB;

noActiveSocket: Lark.VoiceSocket = [
net: [Lark.noMachine.net], host: [Lark.noMachine.host], socket: [0,0]];

infos: PUBLIC ARRAY[0..100) OF JayInfo_ALL[NIL];
smartses: PUBLIC ARRAY[0..100) OF Thrush.SmartsHandle _ ALL[Thrush.nullHandle];
numParties: PUBLIC NAT_0;
haveJuke: PUBLIC BOOL_TRUE;

timeoutNoAction: INTEGER _ 30;
Ctr: TYPE = RECORD[
count: INT,
stop: INT
];

PD: TYPE = RECORD [
cPr: REF Ctr_NEW[Ctr_[0,1000000]],
cSp: REF Ctr_NEW[Ctr_[0,1000000]],
cRs: REF Ctr_NEW[Ctr_[0,1000000]],
cZp: REF Ctr_NEW[Ctr_[0,1000000]],
cNw: REF Ctr_NEW[Ctr_[0,1000000]],
numReportDones: INT_0,
numReportDoneEs: INT_0,
doReports: BOOL_FALSE,
doNice: BOOL_FALSE
];
pd: REF PD _ NEW[PD_[]];

Report: PROC[what: ROPE, ctr: REF Ctr] = {
IF NOT pd.doReports THEN RETURN;
Log.Report[what, $Bluejay];
ctr.count_ctr.count+1;
IF ctr.count>ctr.stop THEN { Log.Problem["Report overflow", $Bluejay]; };
};

BeNice: PROC[r: REF, d: INT] = {
IF NOT pd.doNice THEN RETURN;
Nice.BeNice[r, d, $Bluejay, NIL];
};


Progress: PUBLIC ENTRY PROC[
shh: SHHH,
smartsID: Thrush.SmartsHandle,
event: Thrush.ConvEvent,
yourParty: BOOL,
latestEvent: BOOL,
informationOnly: BOOL
] RETURNS [ d: Thrush.Disposition ] = {
info: JayInfo _ InfoForSmarts[smartsID: smartsID];
cDesc: ThSmartsPrivate.ConvDesc;
IF info=NIL THEN RETURN[pass];
d_actedAndStop;

cDesc _ GetConv[info, event.credentials.convID, FALSE];

IF pd.doReports THEN Report[
Rope.Concat[
IO.PutFR["---- JyProg: %t(%d) %g %g yr=%g ",
time[event.credentials.convID], int[event.credentials.stateID],
refAny[NEW[StateInConv_event.state]], DParty[info, cDesc], bool[yourParty]],
IO.PutFR["lt=%g in=%g, ky=%g\n",
bool[latestEvent], bool[event.intervalSpec#NIL], bool[event.keyTable#NIL]]],
pd.cPr];

IF event.credentials.stateID <= cDesc.cState.credentials.stateID THEN RETURN[pass]; -- Old news!
cDesc.cState.credentials.smartsID _ smartsID;
cDesc.cState.credentials.stateID _ event.credentials.stateID;

IF event.keyTable#NIL THEN {
cDesc.cState.keyTable _ event.keyTable; cDesc.newKeys_TRUE; };
IF event.intervalSpec#NIL AND event.intervalSpec.type=request THEN
EnqueueInterval[cDesc, event.intervalSpec];
IF event.address#NIL THEN { cDesc.cState.address_event.address; cDesc.newAddress_TRUE; };
IF yourParty THEN {
cDesc.descValid _ TRUE;
cDesc.cState.credentials.partyID _ event.credentials.partyID;
cDesc.cState.state _ event.state;
cDesc.cState.comment _ event.comment;
cDesc.cState.reason _ event.reason;
IF event.spec#NIL THEN { cDesc.cState.spec _ event.spec; cDesc.newSpec_TRUE; };
IF event.comment#NIL THEN cDesc.cState.comment _ event.comment;
IF event.urgency#normal THEN cDesc.cState.urgency _ event.urgency;
IF event.alertKind#standard THEN cDesc.cState.alertKind _ event.alertKind;
};

BeNice[event, 4];
BeNice[cDesc, 6];
IF latestEvent THEN Apprise[info]; -- Wait for the last report to wake process.
};

Supervise: PUBLIC ENTRY PROC[info: JayInfo ] = {
TRUSTED {Process.SetTimeout[@info.thAction, Process.SecondsToTicks[timeoutNoAction]]; };
IF info.apprise THEN DO
ENABLE {
UNWIND => NULL;
ANY => { Log.Problem[NIL, $Bluejay]; GOTO Failing; };
};
prevL: ThSmartsPrivate.OpenConversations _ NIL;
nb: NB_success;
convL: ThSmartsPrivate.OpenConversations;
trans: Transition;
info.apprise _ FALSE;
FOR convL _ info.conversations,
convL.rest WHILE convL#NIL DO
cDesc: ConvDesc = convL.first;
stateNow: StateInConv = cDesc.cState.state;
ours: BOOL _ ( cDesc.cState.credentials.convID = info.currentConvID );

IF pd.doReports THEN Report[
Rope.Concat[
IO.PutFR["**** JySup: %t(%d) %g %g->%g",
time[cDesc.cState.credentials.convID], int[cDesc.cState.credentials.stateID],
DParty[info, cDesc], refAny[NEW[StateInConv_stateNow]], refAny[NEW[StateInConv_cDesc.desiredState]]],
IO.PutFR[" %g%g\n",
refAny[NEW[Transition_transForStates[stateNow][cDesc.desiredState]]],
rope[IF ours THEN " (ours)" ELSE ""]]],
pd.cSp];
BeNice[cDesc, 6];
IF NOT cDesc.descValid THEN LOOP;
IF info.currentConvID = nullConvHandle AND stateNow#idle THEN {
ours_TRUE; info.currentConvID _ cDesc.cState.credentials.convID;
};
IF stateNow#idle AND (NOT ours) THEN
nb _ ThParty.Advance[
shhh: info.shh,
credentials: cDesc.cState.credentials,
state: idle,
reason: busy,
comment: "One conversation at a time, please."
]
ELSE {
SELECT (trans_transForStates[stateNow][cDesc.desiredState]) FROM
noop => NULL;
elim => {

Report[IO.PutFR["  ** Zap: %t\n", time[cDesc.cState.credentials.convID]], pd.cZp];
IF prevL#NIL THEN { prevL.rest _ convL.rest; convL _ prevL; }
ELSE info.conversations_convL.rest;
IF ours THEN {
info.currentConvID _ nullConvHandle;
CloseConnection[info];
};
};
idle => nb _ AdvanceToDesired[info, cDesc];
actv => {
IF cDesc.signallingStarted THEN LOOP;
cDesc.signallingStarted _ TRUE;
cDesc.desiredState _ active;
nb _ AdvanceToDesired[info, cDesc];
};
nrvl => { -- report new interval accepted
IF cDesc.newSpec THEN OpenConnection[info, cDesc];
IF cDesc.newIntervals#NIL THEN {
IF DoSetInterval[info, cDesc] THEN
nb _ ThParty.SetInterval[
shhh: info.shh,
credentials: cDesc.cState.credentials,
intervalSpec: cDesc.newIntervals.first
];
IF nb=success THEN []_DequeueInterval[cDesc];
info.apprise _ TRUE; -- one more time, in case more intervals exist.
};
};
invl, ntiy => {
Log.Problem["LarkSmarts: Invalid or not yet implemented state transition request.", $Bluejay];
info.apprise_TRUE;
cDesc.desiredState _ idle;
cDesc.desiredReason _ error;
cDesc.desiredComment _ "Invalid state transition";
};
ENDCASE => pERROR;
};

IF nb#success THEN
Report[IO.PutFR["  ** Results: nb=%g\n", refAny[NEW[Thrush.NB_nb]]], pd.cRs];
SELECT nb FROM
success, stateMismatch => NULL;
partyNotEnabled => ours_FALSE;
invalidTransition, convNotActive, convStillActive => {
comment: ROPE="Party-level detected invalid state transition request";
Log.Problem[comment, $Bluejay];
cDesc.desiredState _ idle;
cDesc.cState.comment _ comment;
cDesc.cState.reason _ error;
info.apprise_TRUE;
};
notInConv, noSuchConv => { -- Complain, zap, go idle and repeat.
comment: ROPE="NotInConv or NoSuchConv";
Log.Problem[comment, $Bluejay];
IF ours THEN info.currentConvID _ nullConvHandle;
cDesc.cState.credentials.convID _ nullConvHandle;
cDesc.cState.credentials.stateID _ 0;
cDesc.desiredState _ idle;
cDesc.cState.comment _ comment;
cDesc.cState.reason _ error;
info.apprise_TRUE;
};
noSuchParty, noSuchSmarts => { -- Complain, deregister, we gone! Needs tuning.
Log.Problem[
"NoSuchParty or NoSuchSmarts reported, must try to go away", $Bluejay];
GOTO Failing;
};
noSuchParty2, narcissism => pERROR; -- shouldn't be provoking these
ENDCASE => pERROR;
prevL _ convL;
ENDLOOP;
IF NOT info.apprise THEN WAIT info.thAction;
IF info.conversations = NIL THEN EXIT;
REPEAT Failing => NULL; -- ThSmartsPrivate.Deregister[info]; now Failed
ENDLOOP;
info.thProcess _ NIL;
};

GetConv: PUBLIC INTERNAL PROC[info: JayInfo, convID: ConversationHandle, validIfNew: BOOL
] RETURNS [ cDesc: ConvDesc_NIL ] = --INLINE-- {
FOR convs: ThSmartsPrivate.OpenConversations _ info.conversations, convs.rest WHILE convs#NIL DO
IF convs.first.cState.credentials.convID = convID THEN RETURN[convs.first];
ENDLOOP;
cDesc _ NEW[ThSmartsPrivate.ConvDescBody_[]];
cDesc.descValid _ validIfNew;
cDesc.cState.credentials.convID _ convID;
cDesc.cState.credentials.smartsID _ info.smartsID;
cDesc.cState.credentials.partyID _ info.partyID;
info.conversations _ CONS[cDesc, info.conversations];

IF pd.doReports THEN
Report[IO.PutFR["  ** NewConv, %t %g, vl=%g\n", time[convID], DParty[info, cDesc], bool[validIfNew]], pd.cNw];
};

GetCDesc: PROC[info: JayInfo] RETURNS [ cDesc: ConvDesc_NIL ] = {
convID: ConversationHandle=info.currentConvID;
IF convID=nullConvHandle THEN RETURN;
FOR convs: ThSmartsPrivate.OpenConversations _ info.conversations, convs.rest WHILE convs#NIL DO
IF convs.first.cState.credentials.convID = convID THEN {
cDesc _ convs.first; EXIT; };
ENDLOOP;
RETURN[IF cDesc#NIL AND cDesc.descValid THEN cDesc ELSE NIL];
};

EnqueueInterval: INTERNAL PROC[cDesc: ConvDesc, int: Thrush.IntervalSpec] =  INLINE {
iL: LIST OF Thrush.IntervalSpec = LIST[int];
IF cDesc.newIntervals#NIL THEN cDesc.iTail.rest _ iL ELSE cDesc.newIntervals _ iL;
cDesc.iTail _ iL;
};

DequeueInterval: INTERNAL PROC[cDesc: ConvDesc] RETURNS [ int: Thrush.IntervalSpec_NIL ] =  INLINE {
IF cDesc.newIntervals=NIL THEN RETURN;
int_cDesc.newIntervals.first;
cDesc.newIntervals _ cDesc.newIntervals.rest;
};

GetSIC: PUBLIC INTERNAL PROC[info: JayInfo] RETURNS [ state: StateInConv ] = {
cDesc: ConvDesc = GetCDesc[info];
RETURN[IF cDesc=NIL THEN idle ELSE cDesc.cState.state];
};

Apprise: PUBLIC INTERNAL PROC[info: JayInfo] = TRUSTED --INLINE-- {
IF info.thProcess=NIL THEN
Process.Detach[info.thProcess _ FORK Supervise[info]];
info.apprise _ TRUE;
NOTIFY info.thAction;
};

AdvanceToDesired: INTERNAL PROC[info: JayInfo, cDesc: ConvDesc] RETURNS [nb: NB] = {
RETURN[nb _ ThParty.Advance[
shhh: info.shh,
credentials: cDesc.cState.credentials,
state: cDesc.desiredState,
reason: cDesc.desiredReason,
comment: cDesc.desiredComment
]];
};

InfoForSmarts: INTERNAL PROC [ smartsID: SmartsHandle ] RETURNS [ info: JayInfo ] = {
FOR i: NAT IN [0..numParties) DO IF smartsID=smartses[i] THEN RETURN [ infos[i] ]; ENDLOOP;
RETURN[ NIL ]; };

OpenConnection: INTERNAL PROC[info: JayInfo, cDesc: ConvDesc] = TRUSTED {
IF NOT cDesc.newSpec THEN RETURN;
IF info.stream=NIL THEN info.stream _ VoiceStream.Open[jukebox: handle, proc: ReportDone, clientData: info];
Log.Report[IO.PutFR["C %d ", card[info.smartsID]], $Bluejay];
info.socket _ PupDefs.PupSocketMake[
local: cDesc.cState.spec.localSocket.socket,
remote: cDesc.cState.spec.remoteSocket,
ticks: PupDefs.MsToTocks[100]];
VoiceStream.SetSocket[socket: info.socket, handle: info.stream];
info.lastIntervalSpec _ NIL;
cDesc.newSpec _ FALSE;
};

CloseConnection: INTERNAL PROC[info: JayInfo] = TRUSTED {
IF info.stream#NIL THEN VoiceStream.Close[info.stream];
info.stream _ NIL;
IF info.socket#NIL THEN PupDefs.PupSocketDestroy[info.socket];
info.lastIntervalSpec _ NIL;
Log.Report[IO.PutFR["D %d ", card[info.smartsID]], $Bluejay];
};


DoSetInterval: INTERNAL PROC[info: JayInfo, cDesc: ConvDesc] 
RETURNS[didSomething: BOOL] = TRUSTED {
jTune: Jukebox.Tune;
intervalSpec: Thrush.IntervalSpec = cDesc.newIntervals.first;
tune: Thrush.Tune;
flush: BOOL;
IF intervalSpec=NIL THEN pERROR;
flush _ intervalSpec.interval.length=0 AND (NOT intervalSpec.queueIt);
tune _ intervalSpec.tune;
SELECT intervalSpec.type FROM
request => NULL; -- Let's go start it.
started => RETURN[TRUE]; -- was started before, but not successfully reported (mismatch?)
finished => RETURN[NOT flush]; -- report unless due to flushing (does this happen?)
ENDCASE => pERROR;
IF info.stream=NIL THEN info.stream _ VoiceStream.Open[jukebox: handle, proc: ReportDone, clientData: info];
IF flush THEN {
VoiceStream.FlushPieces[handle: info.stream];
RETURN[FALSE]; -- no report
};
IF tune = Thrush.newTune THEN
IF intervalSpec.direction = record THEN {
jTune _ Jukebox.CreateTune[handle, -1];
tune _ jTune.tuneId;
intervalSpec.tune_tune;
Jukebox.CloseTune[ handle, jTune ]; }
ELSE RETURN[TRUE]--<<??>>--;
IF intervalSpec.direction = play THEN Process.Pause[Process.MsecToTicks[100]];
VoiceStream.AddPiece[
handle: info.stream,
tuneId: tune,
firstByte: intervalSpec.interval.start,
nBytes: IF intervalSpec.interval.length=-1 THEN VoiceStream.wholeTune
ELSE intervalSpec.interval.length,
create: intervalSpec.direction = record,
playback: intervalSpec.direction # record,
keyIndex: intervalSpec.keyIndex,
flush: NOT intervalSpec.queueIt ];
intervalSpec.type _ started;
info.lastIntervalSpec _ intervalSpec;
RETURN[TRUE];
};

ReportDone: VoiceStream.NotifyProc = TRUSTED {
info: JayInfo _ NARROW[clientData];
pd.numReportDones _ pd.numReportDones+1;
IF ~VoiceStream.IsEmpty[self] OR info=NIL THEN RETURN;
Process.Detach[FORK ReportDoneEntry[info]];
};

 ReportDoneEntry: ENTRY PROC[info: JayInfo] = TRUSTED {
cDesc: ConvDesc;
intervalSpec: Thrush.IntervalSpec;
tune: Thrush.Tune_Thrush.nullTune;
totLen, start: INT_0;
jTune: Jukebox.Tune_NIL;
pd.numReportDoneEs _ pd.numReportDoneEs+1;
cDesc _ GetCDesc[info];
IF cDesc=NIL OR cDesc.cState.state#active THEN RETURN;
intervalSpec _ info.lastIntervalSpec;
IF intervalSpec = NIL THEN { Log.Problem["No interval spec.", $Bluejay]; RETURN; };
tune _ intervalSpec.tune;
IF tune>=0 THEN jTune _ Jukebox.OpenTune[handle, tune, FALSE];
IF jTune#NIL THEN {
totLen _ Jukebox.TuneSize[jTune]*Jukebox.bytesPerChirp;
Jukebox.CloseTune[handle, jTune];
start _ MIN[intervalSpec.interval.start, totLen];
intervalSpec.interval _ [start: start, length: MAX[totLen-start, 0]];
};
intervalSpec.type _ finished;
info.lastIntervalSpec _ NIL;
EnqueueInterval[cDesc, intervalSpec]; -- Notify client
Apprise[info];
};

DParty: PROC[info: JayInfo, cDesc: ConvDesc] RETURNS [IO.Value] = {
RETURN[rope[ThParty.DescribeParty[shh: info.shh, partyID: cDesc.cState.credentials.partyID]]];
};

Transition: TYPE = {
noop, elim, idle, actv, nrvl, invl, ntiy
};

transForStates: ARRAY StateInConv OF ARRAY StateInConv OF Transition _ [
[ elim, invl, invl,    invl, invl, invl, invl, invl,   elim, ntiy,   elim ], -- idle	 (current)
[ idle, invl, invl,    invl, invl, invl, invl, invl,   invl, ntiy,    invl ], -- reserved
[ idle, invl, invl,    invl, invl, invl, invl, invl,   invl, ntiy,    invl ], -- parsing
[ idle, invl, invl,    invl, invl, invl, invl, invl,   invl, ntiy,   invl ], -- initiating

[ idle, invl, invl,    invl, invl, invl, invl, invl,   actv, ntiy,    actv ], -- pending
[ idle, invl, invl,    invl, invl, invl, invl, invl,   invl, ntiy,   invl ], -- maybe
[ idle, invl, invl,    invl, invl, invl, invl, invl,   invl, ntiy,    invl ], -- ringing
[ idle, invl, invl,    invl, invl, invl, invl, invl,   ntiy, ntiy,    ntiy ], -- canActivate

[ idle, invl, invl,    invl, invl, invl, invl, invl,   nrvl, ntiy,   nrvl ], -- active
[ idle, invl, invl,    invl, invl, invl, invl, invl,   ntiy, ntiy,    noop ], -- inactive
[ invl, invl, invl,   invl, invl, invl, invl, invl,   invl, invl,    invl ] -- any (nonex)
];

Nice.View[pd, "Bluejay PD"];
}.
���¶��BluejaySmartsImpl.mesa
Last modified by D. Swinehart, December 28, 1983 10:14 pm

Types, Definitions
Call Supervision
Update local state information

Fields always extracted
<<Need to check for increasing stateID here, and reject old ones?  If so, enable
test in alrt case below.>>
Extracted if present

Extracted if the event changes our state. 
Extracted if non-standard?


<<This stuff feels like it's in the wrong place.  Will feel more so when multi-calls
are dealt with. >>
Conv isn't the one we're interested in, and doesn't look like it's going idle: idle it.
Should probably consult transForStates for validity.
State and substate (below) and desired state indicate there's something to do. Do it:
Conv. is now idle: forget about it or re-use it, as a reserved conversation. 
Remove dead conversation from list.

Analyze any results of trying to reach a different state.

Complain and transition to idle
Utilities


Not at present protected by monitor -- LarkStateImpl back-pointer problem.
Tunes: control of recording and playback
<< Perhaps should be able to specify, in request, whether started/finished notes are needed.>>
<<Need list of specs, else multiple requests can confuse this!!!!!>>

State Transition Tables
Just codes to dispatch on in Supervisor; explained there
  idle  resrv  pars    init pend mayb ring canAc   activ inact   any -- desired

NB: examine relationship to validity table in PartyOpsImpl someday.
Debugging nonsense
�Ê��˜�Jšœ™Jšœ9™9J™�šÏk	˜	J˜Jšœ˜Jšœ	œL˜ZJšœœ˜(J˜�J˜J˜�Jšœ	œ<˜JJšœ	œ;˜IJ˜Jšœœ˜ Jšœ	œ)˜7Jšœœ=œ>œ,˜ºJ˜	Jšœœ/˜DJšœœZ˜kJ˜J˜�—šœ
˜ JšœœI˜SJšœ˜$Jšœœ˜J˜�—™J˜�Jšœ
œ˜*šœœ˜5Jšœ;˜;—Jšœ
œ˜'Jšœ
œ˜'Jšœœ
œ˜Jšœœ˜)J˜'J˜�Jšœœ˜Jšœœœ˜*Jšœœœ˜+Jšœœ˜Jšœœœ˜Jšœœœ˜Jšœœ
œ˜J˜�˜$J˜G—J˜�Jš	œœ	œ	œœ˜0Jšœ
œ	œœ˜OJšœ
œ˜Jšœ
œœœ˜J˜�Jšœœ˜šœœœ˜Jšœœ˜Jšœ˜	J˜—J˜�šœœœ˜Jšœœœ˜"Jšœœœ˜"Jšœœœ˜"Jšœœœ˜"Jšœœœ˜"Jšœœ˜Jšœœ˜Jšœœœ˜Jšœœ˜J˜—Jš	œœœœœ˜J˜�šÏnœœœœ	˜*Jšœœœœ˜ J˜J˜Jšœœ/˜IJ˜—J˜�šžœœœœ˜ Jšœœœœ˜Jšœœ˜!J˜—J˜�—™J˜�šžœœœœ˜Jšœœ˜
J˜Jšœ˜Jšœœ˜Jšœ
œ˜Jšœ˜Jšœœ˜'Jšœ2˜2Jšœ ˜ Jšœœœœ˜Jšœ˜J™J˜�Jšœ0œ˜7J˜�šœœ˜šœ˜šœ*˜,J˜?JšœœB˜L—šœ˜ Jšœ+œœ˜L——Jšœ˜—J˜�Jš	œ?œœœÏc˜`J™�J™J˜-˜=J™PJ™—J˜�J™šœœœ˜Jšœ6œ˜>—šœœœ!˜BJšœ+˜+—Jšœœœ8œ˜YJ™�J™*šœœ˜Jšœœ˜Jšœ=˜=Jšœ!˜!Jšœ%˜%Jšœ#˜#Jšœœœ1œ˜OJ™Jšœœœ&˜?Jšœœ&˜BJšœœ*˜JJ˜—J˜�J˜J˜J™�Jšœ
œŸ,˜OJ˜J˜�—šž	œœœ˜0JšœQ˜Xšœœ˜šœ˜Jšœœ˜Jšœœ
œ˜5J˜—Jšœ+œ˜/Jšœœ	˜Jšœ)˜)J˜Jšœœ˜šœ˜Jšœœœ˜J˜Jšœ+˜+Jšœœ<˜FJ˜�šœœ˜šœ˜šœ&˜(J˜MJšœœ œ#˜e—šœ˜Jšœœ;˜EJšœœœœ˜'——Jšœ˜—J˜J™�Jšœœœœ˜!šœ%œœ˜?J™gJšœœ7˜@Jšœ˜—šœœœ˜$J™WJ™4˜J˜J˜&J˜J˜
Jšœ.˜.J˜——šœ˜J™Ušœ6˜@Jšœœ˜
šœ	˜	J™MJ™#J˜�JšœR˜RJ™�Jšœœœ,˜=Jšœ˜#šœœ˜Jšœ$˜$J˜J˜—Jšœ˜—Jšœ+˜+šœ	˜	Jšœœœ˜%Jšœœ˜J˜Jšœ#˜#J˜—šœ
Ÿ˜)Jšœœ˜2šœœœ˜ šœ˜"šœ˜Jšœ˜Jšœ&˜&Jšœ&˜&Jšœ˜——Jšœœ˜-JšœœŸ/˜DJ˜—J˜—˜J˜^Jšœ
œ˜J˜J˜J˜2J˜—Jšœ˜—J˜—J™9J˜�šœ˜Jšœœ'œœ˜M—J™�šœ˜Jšœœ˜Jšœœ˜šœ6˜6Jšœ™Jšœ	œ9˜FJ˜Jšœ˜J˜J˜Jšœ
œ˜Jšœ˜—šœŸ%˜@Jšœ	œ˜(Jšœ˜Jšœœ%˜1Jšœ1˜1J˜%Jšœ˜J˜J˜Jšœ
œ˜Jšœ˜—šœŸ/˜Nšœ˜JšœG˜G—Jšœ	˜
J˜—Jšœ$Ÿ˜CJšœ˜—J˜Jšœ˜—Jšœœœœ˜,Jšœœœœ˜&JšœœŸ%œ
˜GJšœ˜—Jšœœ˜J˜J˜�——™	J™�šžœœœ8˜YJšœœœŸ
œ˜0šœKœœ˜`Jšœ0œœ˜KJšœ˜—Jšœœ"˜-J˜J˜)Jšœ2˜2Jšœ0˜0Jšœœ˜5J˜�šœ˜Jšœœe˜n—J™�J˜—J˜�šžœœœœ˜AJ™JJšœ.˜.Jšœœœ˜%šœKœœ˜`šœ0œ˜8Jšœœ˜—Jšœ˜—Jšœœœœœœœ˜=J˜J˜�—šžœœœ/œ˜UJšœœœœ˜,Jšœœœœ˜RJ˜J˜—J˜�šžœœœœœœ˜dJšœœœœ˜&J˜J˜-J˜—J˜�šžœœœ˜NJ˜!Jš
œœœœœ˜7Jšœ˜J˜�—šžœœœœœŸ
œ˜Cšœœ˜Jšœ œ˜6—Jšœœ˜Jšœ˜J˜J˜�—š
žœœœ!œœ˜Tšœ˜J˜J˜&J˜J˜J˜J˜—˜J˜�——šž
œœœœ˜UJšœœœœœœœœ˜[Jšœœ˜—J˜�šžœœœ#œ˜IJšœœœœ˜!Jšœ
œœU˜lJšœ=˜=˜$Jšœ,˜,Jšœ'˜'J˜—Jšœ@˜@Jšœœ˜Jšœœ˜Jšœ˜—J˜�šžœœœœ˜9Jšœ
œœ ˜7Jšœœ˜Jšœ
œœ'˜>Jšœœ˜Jšœ=˜=Jšœ˜—J˜�—šœ(™(J˜�šž
œœœ!˜=Jšœœœ˜'J˜J˜=J˜Jšœœ˜Jšœœœ˜ Jšœ'œœ˜FJ˜šœ˜Jšœœ˜&JšœœœC˜YJšœœœ=˜SJšœ˜—Jšœ
œœU˜lšœœ˜Jšœ-˜-JšœœŸ˜Jšœ˜—šœ˜šœ!œ˜)J˜'J˜J˜J˜%—Jšœœœ˜—Jšœœ)˜Nšœ˜J˜J˜
J˜'šœœ!œ˜EJšœ˜"—J˜(J˜*J˜ Jšœœ˜"—J˜J˜%Jšœœ˜
Jšœ^™^Jšœ˜—J˜�šž
œœ˜.Jšœœ
˜#J˜(Jš
œœœœœ˜6Jšœœ˜+J˜—J˜�šžœœœœ˜7J˜J˜"J˜"Jšœœ˜Jšœœ˜J˜*J˜Jš
œœœœœ˜6Jšœ%˜%šœœœ/œ˜SJ™D—Jšœ˜Jšœ	œ(œ˜>šœœœ˜Jšœ7˜7J˜!Jšœœ&˜1Jšœ/œ˜EJ˜—J˜Jšœœ˜Jšœ&Ÿ˜6J˜J˜—J˜�šžœœ!œœ˜CJšœX˜^J˜——J™�™J˜�˜J™8J˜(J˜—J˜�š	œœ
œœ
œ˜HJšœO™OJ™�JšœMŸ˜_JšœNŸ˜YJšœNŸ
˜XJšœMŸ
˜ZJ˜�JšœNŸ
˜XJšœMŸ˜UJšœNŸ
˜XJšœNŸ˜\J˜�JšœMŸ	˜VJšœNŸ˜YJšœLŸ˜Z—˜JšÏsC™C——J˜�™Jšœ˜—J˜—�…—����<Æ��S€��