DIRECTORY Beam USING [Draw, Drawn, SetSyncs], Chord USING [Adjust, Draw], Graphics USING [DrawRectangle, MoveTo, SetTexture], MusicDefs, Note USING [FindChord, Delta, Draw], Score USING [DrawKey, DrawTimeSignature, DrawMetrenome, GetAccidental], Sheet USING [DrawClef, DrawOctava, FindSection, Map, MapNote], Sync USING [GetScoreIndex, GetStaff, RemoveNote], Utility USING [DrawChar, DrawLine]; SyncImpl: CEDAR PROGRAM IMPORTS Beam, Chord, Graphics, MusicDefs, Note, Score, Sheet, Sync, Utility EXPORTS MusicDefs, Sync = BEGIN OPEN Graphics, MusicDefs, Utility; Error: SIGNAL; Overflow: PUBLIC SIGNAL[type: Sequence] = CODE; GetScoreIndex: PUBLIC PROC[s: SyncPTR] RETURNS[CARDINAL] = {i, j, index: CARDINAL _ 0; binary: CARDINAL _ 8192; IF s=NIL THEN RETURN[scoreLength]; FOR i IN [0..13) DO binary _ binary/2; IF index+binary>=scoreLength THEN LOOP; IF score[index+binary].time<=s.time THEN index _ index+binary; IF score[index].time#s.time THEN LOOP; IF score[index]=s THEN RETURN[index]; FOR j IN (index..scoreLength) WHILE score[j].time=s.time DO IF score[j]=s THEN RETURN[j]; ENDLOOP; FOR j DECREASING IN [0..index) WHILE score[j].time=s.time DO IF score[j]=s THEN RETURN[j]; ENDLOOP; EXIT; ENDLOOP; FOR i IN [0..scoreLength) DO IF score[i]=s THEN RETURN[i]; ENDLOOP; RETURN[scoreLength]}; --not in score GetStaff: PUBLIC PROC[s: SyncPTR, staff: CARDINAL] RETURNS[LONG POINTER TO Staff] = {staves: StavesPTR = LOOPHOLE[@s.event]; RETURN[@staves.staff[staff]]}; Grace: PUBLIC PROC[s: SyncPTR] RETURNS[BOOL] = {IF s.type#notes THEN RETURN[FALSE]; FOR j: CARDINAL IN [0..syncLength) DO IF s.event[j]=NIL THEN EXIT; IF ~s.event[j].grace THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]}; InVoice: PUBLIC PROC[s: SyncPTR, voice: CARDINAL] RETURNS[BOOL] = {FOR j: CARDINAL IN [0..syncLength) DO IF s.event[j]=NIL THEN EXIT; IF s.event[j].voice=voice THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]}; Length: PUBLIC PROC[s: SyncPTR] RETURNS[CARDINAL] = {FOR i: CARDINAL IN [0..syncLength] DO IF i=syncLength THEN RETURN[i]; IF s.event[i]=NIL THEN RETURN[i]; ENDLOOP; ERROR}; AddNote: PUBLIC PROC[s: SyncPTR, n: NotePTR] = { i, j: CARDINAL; c: ChordPTR = Note.FindChord[n]; IF n.sync=s THEN RETURN; IF s.type#notes THEN ERROR; FOR j IN [0..chordLength) DO IF c=NIL AND j#0 THEN EXIT; IF c#NIL THEN n_ c.note[j]; IF n=NIL THEN EXIT; IF s.event[syncLength-1]#NIL THEN ERROR; --sync full! FOR i IN [0..syncLength) DO IF s.event[i]=n THEN EXIT; IF s.event[i]#NIL THEN LOOP; Sync.RemoveNote[n.sync, n]; n.sync _ s; s.event[i] _ n; IF n.beam#NIL THEN Beam.SetSyncs[n.beam]; EXIT; ENDLOOP; ENDLOOP; }; RemoveNote: PUBLIC PROC[s: SyncPTR, n: NotePTR] = { i, last: CARDINAL; first: BOOL _ TRUE; IF n=NIL OR s=NIL THEN RETURN; FOR i DECREASING IN [0..syncLength) DO IF first AND s.event[i]#NIL THEN { first _ FALSE; last _ i; }; IF s.event[i]#n THEN LOOP; s.event[i] _ s.event[last]; s.event[last] _ NIL; ENDLOOP; }; AddTimes: PUBLIC PROC[s: SyncPTR, time: Time, toc: Time] = { i: CARDINAL; IF s=NIL THEN RETURN; s.time _ s.time + time; FOR i IN [0..syncLength) DO IF s.event[i]=NIL THEN EXIT; s.event[i].toc _ s.event[i].toc + toc; ENDLOOP; }; Draw: PUBLIC PROC[s: SyncPTR] = { staves: StavesPTR; IF s=NIL THEN RETURN; Graphics.SetTexture[context, black]; SELECT s.type FROM notes => DrawNotes[s]; clef => Sheet.DrawClef[Sync.GetStaff[s, s.value].pitch, s.value, s.time]; octava1 => { pitch, height: INTEGER; octava2: SyncPTR = Octava[s]; IF octava2=NIL THEN {Error; RETURN}; staves _ LOOPHOLE[@s.event]; pitch _ Sync.GetStaff[s, s.value].pitch; height _ staves.height; Sheet.DrawOctava[pitch, s.value, height, s.time, octava2.time]}; octava2 => IF Octava[Octava[s]]#s THEN DrawMeasure[doubleMeasure, s.time, 20]; staves => DrawMeasure[measure, s.time, 10]; keySignature => Score.DrawKey[s.value, s.time]; timeSignature => Score.DrawTimeSignature[s.ts, s.time]; metrenome => Score.DrawMetrenome[s.value, s.time]; IN [measure..m5] => DrawMeasure[s.type, s.time, 0]; ENDCASE; }; SetStave: PUBLIC PROC[oldS: StavesPTR, new: SyncPTR] = { n, o: BOOL; newS: StavesPTR; pitch, height: INTEGER; IF new#NIL THEN newS _ LOOPHOLE[@new.event] ELSE RETURN; height _ newS.height; IF new.type#staves THEN { pitch _ newS.staff[new.value].pitch; newS^ _ oldS^; newS.height _ height; FOR j: CARDINAL IN [0..newS.sl] DO IF newS.staff[j].y#newS.staff[new.value].y THEN LOOP; newS.staff[j].pitch _ pitch; ENDLOOP; RETURN}; newS^ _ style[new.value]; newS.height _ height; IF oldS=NIL THEN RETURN; IF oldS.sl#newS.sl THEN RETURN; FOR i: CARDINAL IN [1..newS.sl] DO n _ newS.staff[i].y=newS.staff[i-1].y; o _ oldS.staff[i].y=oldS.staff[i-1].y; IF n#o THEN RETURN; ENDLOOP; FOR i: CARDINAL IN [0..newS.sl] DO newS.staff[i].pitch _ oldS.staff[i].pitch; ENDLOOP; }; Octava: PUBLIC PROC[s: SyncPTR] RETURNS[SyncPTR] = { OPEN Sync; -- USING [GetScoreIndex, GetStaff]; IF s=NIL THEN RETURN[NIL]; IF s.type=octava1 THEN { FOR i: CARDINAL IN (GetScoreIndex[s]..scoreLength) DO IF score[i].type#octava2 THEN LOOP; IF s.value=score[i].value THEN RETURN[score[i]]; IF GetStaff[s, s.value].y=GetStaff[score[i], score[i].value].y THEN RETURN[score[i]]; ENDLOOP}; IF s.type=octava2 THEN { FOR i: CARDINAL DECREASING IN [0..GetScoreIndex[s]) DO IF score[i].type#octava1 THEN LOOP; IF s.value=score[i].value THEN RETURN[score[i]]; IF GetStaff[s, s.value].y=GetStaff[score[i], score[i].value].y THEN RETURN[score[i]]; ENDLOOP}; RETURN[NIL]; }; DrawNotes: PROC[s: SyncPTR] = { b: BeamPTR; c: ChordPTR; x, y: INTEGER; sync: SyncRec; i, j, k: CARDINAL; min, vMin: INTEGER _ 1000; max, vMax: INTEGER _-1000; sync _ s^; FOR i IN [0..syncLength) DO IF s.event[i]=NIL THEN EXIT; IF sync.event[i]=NIL THEN LOOP; c _ Note.FindChord[s.event[i]]; b _ s.event[i].beam; IF b#NIL AND b.beam#NIL THEN b _ b.beam; IF c#NIL THEN FOR j IN [0..chordLength) DO IF c.note[j]=NIL THEN EXIT; FOR k IN (i..syncLength) DO IF sync.event[k]=c.note[j] THEN sync.event[k] _ NIL; ENDLOOP; ENDLOOP; IF b#NIL AND NOT Beam.Drawn[b] THEN { [] _ Beam.Draw[b]; LOOP; }; IF c#NIL AND b=NIL THEN { Chord.Draw[c]; LOOP; }; IF b=NIL THEN Note.Draw[s.event[i]]; ENDLOOP; IF NOT show.sync THEN RETURN; FOR i IN [0..syncLength) DO IF s.event[i]=NIL THEN EXIT; [x, y] _ Sheet.MapNote[s.event[i]]; min _ MIN[min, y]; max _ MAX[max, y]; IF voice AND s.event[i].voice#selectedVoice THEN LOOP; vMin _ MIN[vMin, y]; vMax _ MAX[vMax, y]; ENDLOOP; Graphics.SetTexture[context, light]; IF min#vMin OR max#vMax THEN DrawLine[x+4, min-6, x+4, max+6]; Graphics.SetTexture[context, black]; IF vMin#vMax AND vMin#1000 THEN DrawLine[x+4, vMin-6, x+4, vMax+6]; }; DrawMeasure: PROC[type: EventType[measure..m5], time: Time, dy: INTEGER] = { i: CARDINAL; staves: StavesPTR; x1, y1, top, delta: INTEGER; IF time=0 THEN RETURN; IF print THEN dy _ 0; Graphics.SetTexture[context, black]; staves _ sheet[Sheet.FindSection[time]].staves; [x1, y1] _ Sheet.Map[time,, staves.sl]; y1 _ y1 - dy; top _ -staves.staff[staves.sl].y+2*dy; SELECT type FROM measure => DrawLine[x1, y1, x1, y1+top]; doubleMeasure => {DrawLine[x1, y1, x1, y1+top]; IF print OR scale=1 THEN delta _ 2 ELSE delta _ 3; DrawLine[x1-delta, y1, x1-delta, y1+top]}; repeat1 => { DrawRectangle[context,[x1, y1],[x1+3, y1+top]]; DrawLine[x1+5, y1, x1+5, y1+top]; }; repeat2, endMeasure => { DrawRectangle[context,[x1+1, y1],[x1-2, y1+top]]; DrawLine[x1-5, y1, x1-5, y1+top]; }; ENDCASE; IF type#repeat1 AND type#repeat2 THEN RETURN; IF type=repeat1 THEN delta _ 6 ELSE delta _ -13; FOR i IN [0..staves.sl] DO [x1, y1] _ Sheet.Map[time,, i]; MoveTo[context,[x1+delta, y1+16+4]]; DrawChar[context,'.]; MoveTo[context,[x1+delta, y1+16-4]]; DrawChar[context,'.]; ENDLOOP; }; Adjust: PUBLIC PROC[s: SyncPTR] = { n: NotePTR; c: ChordPTR; sync: SyncRec; delta: INTEGER; pad: ScratchPad; top: CARDINAL _ syncLength-1; i, j, k, bottom: CARDINAL _ 0; length: CARDINAL _ 0; IF s=NIL THEN RETURN ELSE sync _ s^; IF s.type#notes THEN RETURN; FOR i IN [0..syncLength) DO IF (n _ s.event[i])=NIL THEN EXIT; n.delta _ n.accDelta _ 0; IF n.rest THEN LOOP; c _ Note.FindChord[n]; pad[length].n _ n; pad[length].c _ c; pad[length].y _ Sheet.MapNote[n].y; pad[length].acc _ Score.GetAccidental[n]; pad[length].stemUp _ IF c=NIL THEN n.stemUp ELSE c.stemUp; pad[length].stem _ IF pad[length].stemUp THEN pad[length].y+32 ELSE pad[length].y-32; length _ length+1; ENDLOOP; SortPad[FALSE,@pad]; FOR i IN [0..length) DO IF i#0 AND pad[i].y=pad[i-1].y AND pad[i].acc=pad[i-1].acc THEN pad[i].acc _ inKey; IF pad[i].acc#inKey THEN top _ MIN[top, i]; IF pad[i].acc#inKey THEN bottom _ MAX[bottom, i]; ENDLOOP; FOR i IN [0..length) DO IF sync.event[i]=NIL THEN LOOP; c _ Note.FindChord[sync.event[i]]; IF c#NIL THEN Chord.Adjust[c] ELSE LOOP; FOR j IN [0..chordLength) DO IF c.note[j]=NIL THEN EXIT; FOR k IN [0..syncLength) DO IF sync.event[k]=c.note[j] THEN {sync.event[k] _ NIL; EXIT}; ENDLOOP; ENDLOOP; ENDLOOP; FOR i IN [1..length) DO FOR j DECREASING IN [0..i) DO IF pad[j].c=pad[i].c AND pad[i].c#NIL THEN LOOP; IF Overlap[i, j,@pad, length] THEN LOOP; delta _ Note.Delta[pad[j].n]; IF pad[j].stemUp AND NOT pad[i].stemUp THEN { IF pad[j].y-pad[i].y>= 8 THEN LOOP; MoveRightTo[pad[i], delta]; MoveLeft[pad[i], 8]; EXIT; }; IF pad[j].y-pad[i].y< 8 THEN MoveRightTo[pad[i], delta+(IF pad[j].n.value=whole THEN 10 ELSE 8)]; IF pad[i].n.value=whole OR pad[i].n.value=unknown THEN LOOP; IF pad[j].stem< pad[i].y THEN MoveRightTo[pad[i], delta+2]; IF pad[i].stem> pad[j].y THEN MoveRightTo[pad[i], delta+2]; ENDLOOP; ENDLOOP; IF top>bottom THEN RETURN; FOR i IN [0..length) DO pad[i].x _ -10; ENDLOOP; FOR i IN [1..length) DO IF pad[i-1].y-pad[i].y>=8 THEN LOOP; IF pad[i-1].acc=inKey OR pad[i].acc=inKey THEN LOOP; IF Note.Delta[pad[i-1].n]>Note.Delta[pad[i].n] THEN pad[i-1].push _ i ELSE pad[i].push _ i-1; ENDLOOP; PlaceAccidental[@pad, top, length]; FOR i IN [0..length) DO IF i=top THEN LOOP; IF pad[i].push#bottom THEN LOOP; PlaceAccidental[@pad, i, length]; ENDLOOP; PlaceAccidental[@pad, bottom, length]; FOR i IN [0..length) DO IF i=top OR i=bottom THEN LOOP; IF pad[i].push=bottom THEN LOOP; IF pad[i].push=syncLength THEN LOOP; PlaceAccidental[@pad, i, length]; ENDLOOP; FOR i IN [0..length) DO IF i=top OR i=bottom THEN LOOP; IF pad[i].push#syncLength THEN LOOP; PlaceAccidental[@pad, i, length]; ENDLOOP; FOR i IN [0..length) DO IF pad[i].acc=inKey THEN LOOP; pad[i].n.accDelta _ -pad[i].n.delta - 8*pad[i].x; ENDLOOP; }; Overlap: PROC[a, b: CARDINAL, pad: POINTER TO ScratchPad, length: CARDINAL] RETURNS[BOOL]= { found: BOOL; top, bottom: CARDINAL _ length; PartOf: PROC[i, a: CARDINAL] RETURNS[BOOL]= INLINE { RETURN[a=i OR (pad[i].c=pad[a].c AND pad[a].c#NIL)]}; IF pad[a].c=NIL AND pad[b].c=NIL THEN { -- just single notes IF pad[a].y#pad[b].y THEN RETURN[FALSE]; IF pad[a].n.pitch#pad[b].n.pitch THEN RETURN[FALSE]; IF pad[a].stemUp=pad[b].stemUp THEN RETURN[FALSE]; IF pad[a].n.value=whole OR pad[b].n.value=whole THEN RETURN[FALSE]; RETURN[TRUE]}; FOR i: CARDINAL IN [0..length) DO IF ~PartOf[i, a] THEN LOOP; IF top=length THEN top _ i; bottom _ i; ENDLOOP; IF pad[a].stemUp THEN top _ 0 ELSE bottom _ length-1; FOR i: CARDINAL IN [top..bottom] DO IF ~PartOf[i, b] THEN LOOP; found _ FALSE; FOR j: CARDINAL IN [top..bottom] DO IF ~PartOf[j, a] THEN LOOP; IF pad[i].n.pitch#pad[j].n.pitch OR pad[i].y#pad[j].y THEN LOOP; IF Note.Delta[pad[i].n]#Note.Delta[pad[j].n] THEN LOOP; found _ TRUE; EXIT; ENDLOOP; IF ~found THEN RETURN[FALSE]; ENDLOOP; top _ length; FOR i: CARDINAL IN [0..length) DO IF ~PartOf[i, b] THEN LOOP; IF top=length THEN top _ i; bottom _ i; ENDLOOP; IF pad[b].stemUp THEN top _ 0 ELSE bottom _ length-1; FOR i: CARDINAL IN [top..bottom] DO IF ~PartOf[i, a] THEN LOOP; found _ FALSE; FOR j: CARDINAL IN [top..bottom] DO IF ~PartOf[j, b] THEN LOOP; IF pad[i].n.pitch#pad[j].n.pitch OR pad[i].y#pad[j].y THEN LOOP; IF Note.Delta[pad[i].n]#Note.Delta[pad[j].n] THEN LOOP; found _ TRUE; EXIT; ENDLOOP; IF ~found THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; PlaceAccidental: PROC[pad: POINTER TO ScratchPad, i, length: CARDINAL] = { j: CARDINAL; blocked: BOOL; d, h: INTEGER; IF i=syncLength THEN RETURN; IF pad[i].acc = inKey THEN RETURN; FOR j IN [0..length) DO IF pad[j].push=i THEN pad[i].x _ MAX[pad[j].x, pad[i].x]; ENDLOOP; FOR d IN [MAX[pad[i].x, 0]..6) DO blocked _ FALSE; FOR j IN [0..length) DO SELECT (IF pad[j].y>pad[i].y THEN pad[j].acc ELSE pad[i].acc) FROM flat, doubleFlat, doubleSharp => h _ 8; ENDCASE => h _ 16; SELECT (IF pad[j].y>pad[i].y THEN pad[i].acc ELSE pad[j].acc) FROM doubleSharp => NULL; ENDCASE => h _ h+8; IF pad[j].y-pad[i].y>=h THEN LOOP; IF pad[i].y-pad[j].y>=24 THEN EXIT; IF pad[i].y-pad[j].y>=h THEN LOOP; IF d=0 AND Note.Delta[pad[j].n]<0 THEN {blocked _ TRUE; EXIT}; IF j=i THEN LOOP; IF j=pad[i].push THEN LOOP; IF pad[j].acc#inKey AND pad[j].x=d THEN {blocked _ TRUE; EXIT}; ENDLOOP; IF blocked THEN LOOP; MoveAccTo[pad, i, d]; RETURN; ENDLOOP; ERROR; }; MoveRightTo: PROC[p: Scratch, x: INTEGER] = INLINE { IF p.c=NIL THEN p.n.delta _ MAX[p.n.delta, x] ELSE p.c.delta _ MAX[p.c.delta, x - p.n.delta]; }; MoveLeft: PROC[p: Scratch, delta: INTEGER] = INLINE { IF p.c=NIL THEN p.n.delta _ MIN[p.n.delta,-delta] ELSE p.c.delta _ MIN[p.c.delta,-delta - p.n.delta]; }; MoveAccTo: PROC[p: POINTER TO ScratchPad, i: CARDINAL, delta: INTEGER] = { p[i].x _ MAX[p[i].x, delta]; IF p[i].push#syncLength AND p[p[i].push].x>-1 THEN MoveAccTo[p, p[i].push, p[i].x+1]; }; SortPad: PROC[ascending: BOOL, pad: POINTER TO ScratchPad] = INLINE { i, j: CARDINAL; temp: Scratch; FOR i IN [0..syncLength) DO IF pad[i].n=NIL THEN EXIT; FOR j IN (i..syncLength) DO IF pad[j].n=NIL THEN EXIT; IF NOT ascending AND pad[i].ypad[j].y THEN { temp_ pad[i]; pad[i]_ pad[j]; pad[j]_ temp; }; ENDLOOP; ENDLOOP; }; ScratchPad: TYPE= ARRAY [0..syncLength) OF Scratch; Scratch: TYPE = RECORD[x, y, stem: INTEGER _ 0, push: CARDINAL _ syncLength, acc: Accidental, stemUp: BOOL, c: ChordPTR, n: NotePTR _ NIL]; Hidden: PUBLIC PROC[f, s: CARDINAL, leftEdge: Time] RETURNS[BOOL] = { IF score[s].type#clef AND score[s].type#keySignature THEN RETURN[FALSE]; IF score[s].time-leftEdge>15 THEN RETURN[FALSE]; RETURN[TRUE]; }; END. Hidden: PUBLIC PROC[f, s: CARDINAL, leftEdge: Time] RETURNS[BOOL] = { IF score[s].type#clef AND score[s].type#keySignature THEN RETURN[FALSE]; IF score[s].time-leftEdge>100 THEN RETURN[FALSE]; FOR i: CARDINAL DECREASING IN (f..s) DO IF score[i].timei **************************************************************************** does not automatically remove empty syncs! (see Voice.Correct) ****************************************************************** procedures for drawing syncs ****************************************************************** new.type=staves clef switches carry over if the staff form is the same draw the sync line **************************************************************************** look graphical (making sure that noteheads and accidentals don't interfere) **************************************************************************** build the pad handle note adjacencies within a chord no need to process a chord more than once determine the deltas special case: allow some notes to overlap special case: higher note with stem down and lower with stem up FOR k IN [0..i] DO IF pad[j].c=pad[k].c AND pad[k].c#NIL THEN LOOP; MoveLeft[pad[k], IF pad[k].n.value=whole THEN 10 ELSE 8]; ENDLOOP; general case: shift lower note to the right determine the deltas for the accidentals RULES: (in order of precedence) 1) all of the accidentals appear to the left of all of the notes 2) accidentals for notes offset in a chord have the same offset 3) there must be at least three lines vertically between accidentals 4) the highest and lowest accidentals should have the same horizontal position 5) lower accidentals should go to the left of higher accidentals do top, then whatever pushes bottom, then bottom, then whatever pushes, then whatever. put the results in accDelta we have at least one chord; can a and b overlap? find the tops and bottoms for a do all of the notes in b which are within top and bottom have a corresponding note in a? find the tops and bottoms for b do all of the notes in a which are within top and bottom have a corresponding note in b? Ê„˜šœ ™ Jšœ@™@Jšœ™Jšœ+™+J™2J˜—šÏk ˜ Jšœœ˜#Jšœœ˜Jšœ œ%˜3J˜ Jšœœ˜$Jšœœ<˜GJšœœ3˜>Jšœœ'˜1Jšœœ˜#J˜—Jšœ œ˜JšœD˜KJšœ˜Jšœœœ˜*J˜Jšœœ˜Jšœ œœœ˜/J˜š Ïn œœœ œœ˜;šœœ˜Jšœœ˜Jšœœœœ˜"šœœ ˜J˜Jšœœœ˜'Jšœ"œ˜>Jšœœœ˜&Jšœœœ˜%Jšœ™šœœœ˜;Jšœ œœœ˜&—š œ œœ œ˜Jšœœœ˜J˜Jšœœ˜Jšœ˜—Jšœ˜—J˜šžœœœ'˜J˜$Jšœ œ œ$˜CJšœ˜—J˜šž œœ/œ˜LJšœœ˜ J˜Jšœœ˜Jšœœœ˜Jšœœ˜J˜$J˜/J˜'J˜ J˜&šœ˜J˜(˜0Jšœœ œ œ ˜2J˜*—šœ>˜>Jšœ$˜$—šœL˜LJšœ%˜%—Jšœ˜—Jšœœœœ˜-Jšœœ œ ˜0šœœ˜J˜J˜:J˜:Jšœ˜—Jšœ˜—J˜JšœL™LJšœK™KJšœL™LJ˜šžœœœ˜#J˜ J˜ J˜Jšœœ˜J˜Jšœœ˜Jšœœ˜Jšœœ˜Jš œœœœœ ˜$Jšœœœ˜Jšœ ™ šœœ˜Jšœœœœ˜"J˜Jšœœœ˜J˜J˜J˜J˜#J˜)Jš œœœœ œ ˜:Jšœœœœ˜UJ˜Jšœ˜—Jšœœ˜šœœ ˜Jšœœœœ˜SJšœœœ ˜,Jšœœ œ ˜2Jšœ˜—Jšœ&™&šœœ ˜Jšœœœœ˜J˜"Jš œœœœœ˜(Jšœ)™)šœœ˜Jšœ œœœ˜šœœœ˜Jšœœœœ˜Jšœœœ˜Jšœœœ˜Jš œœ œ œœ˜?Jšœ˜—Jšœ œœ˜J˜Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—J˜šž œœœœ˜4šœœœ œ˜-Jšœ œ˜/—Jšœ˜—J˜šžœœœœ˜5šœœœ œ˜1Jšœ œ˜3—Jšœ˜—J˜š ž œœœœœ œ˜KJšœ œ˜Jšœœœ#˜UJšœ˜—J˜š žœœ œœœœ˜EJšœœ˜J˜šœœ˜Jšœ œœœ˜šœœ˜Jšœ œœœ˜šœœ œ˜'Jšœ œ˜#Jšœ1˜5—Jšœ˜—Jšœ˜—Jšœ˜—J˜Jšœ œœœ ˜4š œ œœ œ œ˜LJšœœ˜Jšœœ˜J˜—š žœœœœœœ˜EJš œœœœœ˜HJšœœœœ˜0Jšœœ˜ Jšœ˜—J˜Jšœ˜J˜š žœœœœœœ˜EJš œœœœœ˜HJšœœœœ˜1š œœ œœ˜'Jšœœœ˜$Jš œœœœœ˜PJšœœœœ˜*Jš œœ œœœ˜/Jšœœœœ˜+Jšœ˜—Jšœœ˜ Jšœ˜—J˜—…—9h[Ô