DIRECTORY Beam USING [AddItem, Free, New, RemoveItem, SetStems], Chord USING [AddNote, New, RemoveNote, SetDefaultStem, Sort], Event USING [AddNote, Sync], Heuristic USING [MakeNTuplets], MusicDefs, Note USING [Free, GetBackTie, InVoice], Piece USING [AddEvent, CleanUpEvents, Replace], Real USING [FixI], Selection USING [Clear, Draw, MakeBeam, MakeBeamOfBeams, RemoveNote], Sheet USING [Height, HiLite, Map, MapNote, NextStaff], Utility; SelectionImpl: CEDAR PROGRAM IMPORTS Beam, Chord, Event, Heuristic, MusicDefs, Note, Piece, Real, Selection, Sheet, Utility EXPORTS Selection = BEGIN OPEN MusicDefs; selection: PUBLIC SelectionPTR _ NEW[SelectionRec[100]]; Includes: PUBLIC PROC[n: NotePTR] RETURNS[BOOL] = { IF selection.lineSelect THEN RETURN[n.sync.time IN [selection.select1..selection.select2)] ELSE FOR i: CARDINAL IN [0..selection.length) DO IF selection.note[i] = n THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; Clear: PUBLIC PROC = { Selection.Draw[]; selection.greySelect1 _ selection.select1 _ 1; selection.greySelect2 _ selection.select2 _ 0; selection.length _ 0; }; AddNote: PUBLIC PROC[score: ScorePTR, n: NotePTR] = { x, y: INTEGER; context: Utility.Context ~ score.sheet.context; IF selection.lineSelect THEN Clear[]; IF n = NIL OR score = NIL THEN RETURN; IF selection.score # score THEN {selection.score _ score; selection.length _ 0}; IF ~Note.InVoice[n, score.sheet.voice] THEN RETURN; IF selection.length = selection.max THEN RETURN; FOR i: NAT IN [0..selection.length) DO IF selection[i] = n THEN RETURN; ENDLOOP; selection[selection.length] _ n; selection.length _ selection.length+1; selection.lineSelect _ FALSE; [x, y] _ Sheet.MapNote[score.sheet, n]; Utility.SetCP[context, x, y]; Utility.SetBrush[context, black, invert]; Utility.DrawChar[context, 170C]; }; RemoveNote: PUBLIC PROC[n: NotePTR] = { x, y: INTEGER; context: Utility.Context ~ selection.score.sheet.context; IF n = NIL THEN RETURN; FOR i: NAT IN [0..selection.length) DO IF selection[i] # n THEN LOOP; selection.length _ selection.length - 1; selection[i] _ selection[selection.length]; selection[selection.length] _ NIL; Utility.SetBrush[context, black, invert]; [x, y] _ Sheet.MapNote[selection.score.sheet, n]; Utility.SetCP[context, x, y]; Utility.DrawChar[context, 170C]; EXIT; ENDLOOP; }; AddLine: PUBLIC PROC[score: ScorePTR, time1, time2: Time] = { IF selection.lineSelect AND selection.score # NIL THEN Sheet.HiLite[selection.score.sheet, black, selection.select1, selection.select2] ELSE Selection.Clear[]; selection.score _ score; selection.select1 _ time1; selection.select2 _ time2; selection.lineSelect _ TRUE; IF score # NIL THEN Sheet.HiLite[score.sheet, black, time1, time2]; }; AddGreyLine: PUBLIC PROC[score: ScorePTR, time1, time2: Time] = { IF selection.lineSelect AND selection.score2 # NIL THEN Sheet.HiLite[selection.score2.sheet, grey, selection.greySelect1, selection.greySelect2] ELSE Selection.Clear[]; selection.greySelect1 _ time1; selection.greySelect2 _ time2; selection.lineSelect _ TRUE; IF score # NIL THEN Sheet.HiLite[score.sheet, grey, time1, time2]; }; Draw: PUBLIC PROC = { x, y: INTEGER; IF selection.lineSelect THEN { IF selection.score # NIL THEN Sheet.HiLite[selection.score.sheet, black, selection.select1, selection.select2]; IF selection.score2 # NIL THEN Sheet.HiLite[selection.score2.sheet, grey, selection.greySelect1, selection.greySelect2]; RETURN}; IF selection.length = 0 OR selection.score = NIL THEN RETURN; Utility.SetBrush[selection.score.sheet.context, black, invert]; FOR i: CARDINAL IN [0..selection.length) DO IF selection[i] = NIL THEN LOOP; IF ~Note.InVoice[selection[i], selection.score.sheet.voice] THEN LOOP; [x, y] _ Sheet.MapNote[selection.score.sheet, selection[i]]; Utility.SetCP[selection.score.sheet.context, x, y]; Utility.DrawChar[selection.score.sheet.context, 170C]; ENDLOOP; }; Enumerate: PUBLIC PROC[proc: PROC[ScorePTR, NotePTR]] = { OPEN selection; -- ! ! ! IF score = NIL THEN RETURN; IF lineSelect THEN FOR i: CARDINAL DECREASING IN [0..score.length) DO IF score[i].time < select1 OR score[i].time > select2 THEN LOOP; IF score[i].type # sync THEN LOOP; FOR j: CARDINAL DECREASING IN [0..Event.Sync[score[i]].length) DO proc[score, Event.Sync[score[i]].note[j]]; ENDLOOP; ENDLOOP ELSE FOR i: CARDINAL IN [0..selection.length) DO IF ~Note.InVoice[selection[i], score.sheet.voice] THEN LOOP; proc[score, selection[i]]; SetDirty[score, selection[i].sync.time, selection[i].sync.time]; ENDLOOP; IF lineSelect THEN SetDirty[score, select1, select2]; }; SetNoteValue: PUBLIC PROC[v: NoteValue, dots: INTEGER] = { NoteValue: PROC[score: ScorePTR, n: NotePTR] = { n.value _ v; IF dots > 1 THEN n.doubleDotted _ TRUE ELSE n.doubleDotted _ FALSE; IF dots MOD 2 = 1 THEN n.dotted _ TRUE ELSE n.dotted _ FALSE; IF v > quarter OR n.beam = NIL OR NOT n.beam.beamed THEN RETURN; Beam.RemoveItem[score, n.beam, IF n.chord = NIL THEN n ELSE n.chord]; }; Enumerate[NoteValue]; }; SetRest: PUBLIC PROC[rest: BOOLEAN] = { Rest: PROC[score: ScorePTR, n: NotePTR] = { n.rest _ rest; }; Enumerate[Rest]; }; SetGrace: PUBLIC PROC[grace: BOOLEAN] = { Grace: PROC[score: ScorePTR, n: NotePTR] = { n.grace _ grace; }; Enumerate[Grace]; }; SetStaff: PUBLIC PROC[staff: CARDINAL] = { Staff: PROC[score: ScorePTR, n: NotePTR] = { Count: PROC[s: CARDINAL, t: Time] RETURNS[j: CARDINAL] = INLINE { j _ 0; FOR i: CARDINAL IN [0..s) DO j _ Sheet.NextStaff[score.sheet, j, t]; ENDLOOP}; n.staff _ Count[staff, n.sync.time]; IF n.beam # NIL THEN Beam.SetStems[score.sheet, n.beam]; }; IF selection.score = NIL THEN RETURN; IF staff = 0 THEN {selection.score.flash _ TRUE; RETURN} ELSE staff _ staff-1; Enumerate[Staff]; }; SetStem: PUBLIC PROC[stemUp: BOOLEAN] = { Stem: PROC[score: ScorePTR, n: NotePTR] = { b: BeamPTR; c: ChordPTR; x, y, xb, yb, d: INTEGER; n.stemUp _ stemUp; c _ n.chord; IF c # NIL THEN c.stemUp _ stemUp; IF (b _ n.beam) = NIL OR NOT n.beam.beamed THEN RETURN; [x, y] _ Sheet.Map[score.sheet, n.sync.time, n.pitch, n.staff]; [xb, yb] _ Sheet.Map[score.sheet, b.sync1.time, , b.staff]; yb _ yb+b.height; d _ Real.FixI[yb+b.tilt*(x-xb)-y]; b.height _ b.height-(IF stemUp THEN MIN[0, d-28] ELSE MAX[0, d+28]); }; Enumerate[Stem]; }; Transpose: PUBLIC PROC[halfsteps: INTEGER] = { Pitch: PROC[score: ScorePTR, n: NotePTR] = { n.pitch _ n.pitch+halfsteps; IF (halfsteps MOD 12) # 0 THEN {n.spelled _ inKey; n.show _ FALSE}; }; Enumerate[Pitch]; }; Delete: PUBLIC PROC = { n: NotePTR; IF selection.score = NIL THEN RETURN; IF selection.lineSelect THEN Piece.Replace[selection.score, NIL, selection.select1, selection.select2] ELSE FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[n, selection.score.sheet.voice] THEN LOOP; SetDirty[selection.score, n.sync.time, n.sync.time]; Selection.RemoveNote[n]; Note.Free[selection.score, n]; ENDLOOP; }; MakeSync: PUBLIC PROC = { n: NotePTR; c: ChordPTR; end: Time _ -1; sync: SyncPTR _ NIL; begin: Time _ LAST[Time]; IF selection.score = NIL THEN RETURN; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; begin _ MIN[begin, n.sync.time]; end _ MAX[end, n.sync.time]; ENDLOOP; IF ABS[end-begin] > 20 THEN {selection.score.flash _ TRUE; RETURN}; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[n, selection.score.sheet.voice] THEN LOOP; SetDirty[selection.score, n.sync.time, n.sync.time]; IF sync = NIL THEN { sync _ n.sync; LOOP; }; c _ n.chord; FOR j: CARDINAL IN [0..(IF c = NIL THEN 1 ELSE c.length)) DO IF c = NIL AND j # 0 THEN EXIT; IF c # NIL THEN n _ c.note[j]; IF n = NIL THEN EXIT; Event.AddNote[selection.score, sync, n]; ENDLOOP; ENDLOOP; Piece.CleanUpEvents[selection.score]; }; ClearSync: PUBLIC PROC = { Sync: PROC[score: ScorePTR, n: NotePTR] = { sync: SyncPTR ~ NEW[EventRec[sync][10] _ [variant: sync[note: ]]]; sync.time _ n.sync.time; Event.AddNote[score, sync, n]; Piece.AddEvent[score, sync]; }; IF selection.score = NIL THEN RETURN; Enumerate[Sync]; Piece.CleanUpEvents[selection.score]; }; MakeTie: PUBLIC PROC = { n: NotePTR; ties: ARRAY [0..10) OF RECORD[n1, n2: NotePTR]; ties _ ALL[[NIL, NIL]]; FOR i: CARDINAL IN [0..selection.length) DO IF selection[i] = NIL THEN LOOP; FOR j: CARDINAL IN [0..10) DO IF ties[j].n1 = NIL THEN {ties[j].n1 _ selection[i]; EXIT}; IF ties[j].n1.pitch # selection[i].pitch THEN LOOP; IF ties[j].n1.sync = selection[i].sync THEN {selection.score.flash _ TRUE; RETURN}; IF ties[j].n2 # NIL THEN {selection.score.flash _ TRUE; RETURN}; ties[j].n2 _ selection[i]; EXIT; ENDLOOP; ENDLOOP; IF ties[0].n1 = NIL THEN {selection.score.flash _ TRUE; RETURN}; IF ties[0].n2 = NIL AND ties[1].n2 = NIL AND ties[2].n1 = NIL THEN { ties[0].n2 _ ties[1].n1; ties[1].n1 _ NIL}; FOR i: CARDINAL IN [0..10) DO IF ties[i].n1 = NIL THEN EXIT; IF ties[i].n2 = NIL THEN {selection.score.flash _ TRUE; RETURN}; ENDLOOP; FOR i: CARDINAL IN [0..10) DO IF ties[i].n1 = NIL THEN EXIT; IF ties[i].n1.sync.time > ties[i].n2.sync.time THEN {n _ ties[i].n1; ties[i].n1 _ ties[i].n2; ties[i].n2 _ n}; IF ties[i].n1.tied THEN { (n _ Note.GetBackTie[selection.score, ties[i].n1]).tie _ NIL; SetDirty[selection.score, n.sync.time, n.sync.time]}; IF (n _ ties[i].n2.tie) # NIL THEN { n.tied _ FALSE; SetDirty[selection.score, n.sync.time, n.sync.time]}; ties[i].n2.tie _ ties[i].n1; ties[i].n1.tied _ TRUE; ties[i].n2.tieHeight _ -10; SetDirty[selection.score, ties[i].n1.sync.time, ties[i].n2.sync.time]; ENDLOOP; }; ClearTie: PUBLIC PROC = { UnTie: PROC[score: ScorePTR, n: NotePTR] = { IF n.tie # NIL THEN n.tie.tied _ FALSE; n.tie _ NIL; }; Enumerate[UnTie]; }; MakeChord: PUBLIC PROC = { n: NotePTR; end: Time _ -1; chord: ChordPTR; beam: BeamPTR _ NIL; sync: EventPTR _ NIL; count: CARDINAL _ 0; begin: Time _ LAST[Time]; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[n, selection.score.sheet.voice] THEN LOOP; begin _ MIN[begin, n.sync.time]; end _ MAX[end, n.sync.time]; count _ count+1; ENDLOOP; IF ABS[end-begin] > 20 OR count < 2 THEN {selection.score.flash _ TRUE; RETURN}; chord _ Chord.New[selection.score, selection.length+2]; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[n, selection.score.sheet.voice] THEN LOOP; SetDirty[selection.score, n.sync.time, n.sync.time]; Chord.AddNote[selection.score, chord, n]; ENDLOOP; Chord.SetDefaultStem[selection.score.sheet, chord]; Piece.CleanUpEvents[selection.score]; }; ClearChord: PUBLIC PROC = { UnChord: PROC[score: ScorePTR, n: NotePTR] = { c: ChordPTR _ n.chord; IF c # NIL THEN Chord.RemoveNote[score, c, n]; }; Enumerate[UnChord]; }; MakeBeam: PUBLIC PROC[beamed: BOOLEAN] = { b: BeamPTR; c: ChordPTR; n, tmp: NotePTR; score: ScorePTR _ selection.score; sheet: SheetPTR _ score.sheet; height, stem: INTEGER; stemUp, first: BOOLEAN _ TRUE; b _ Beam.New[selection.score, selection.length + 2]; b.beamed _ beamed; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[n, score.sheet.voice] THEN LOOP; IF beamed AND n.value < eighth THEN LOOP; IF n.beam = b THEN LOOP; -- beaming a note in a chord already beamed c _ n.chord; IF n.beam # NIL THEN Beam.RemoveItem[score, n.beam, IF c = NIL THEN n ELSE c]; IF c # NIL THEN { tmp _ c.note[0]; Beam.AddItem[score, b, c]; IF first THEN { stemUp _ c.stemUp; first _ FALSE; [] _ Chord.Sort[c, NOT stemUp]; height _ (IF stemUp THEN -1000 ELSE 1000); b.staff _ c.note[0].staff; }; IF beamed THEN c.stemUp _ stemUp; [] _ Chord.Sort[c, NOT stemUp]; tmp _ c.note[0]; IF c.stemUp AND height < Sheet.Height[sheet, tmp.sync.time, tmp.pitch, tmp.staff] OR NOT c.stemUp AND height > Sheet.Height[sheet, tmp.sync.time, tmp.pitch, tmp.staff] THEN height _ Sheet.Height[sheet, tmp.sync.time, tmp.pitch, tmp.staff]; }; IF c = NIL THEN { Beam.AddItem[score, b, n]; IF first THEN { stemUp _ n.stemUp; first _ FALSE; height _ (IF stemUp THEN -1000 ELSE 1000); b.staff _ n.staff; }; IF beamed THEN n.stemUp _ stemUp; IF n.stemUp AND height < Sheet.Height[sheet, n.sync.time, n.pitch, n.staff] OR NOT n.stemUp AND height > Sheet.Height[sheet, n.sync.time, n.pitch, n.staff] THEN height _ Sheet.Height[sheet, n.sync.time, n.pitch, n.staff]; }; ENDLOOP; IF beamed THEN stem _ 34 ELSE stem _ 28; b.height _ height-Sheet.Height[sheet, 0, , b.staff]+(IF stemUp THEN stem ELSE -stem); IF b.chord[1] = endOfBeam THEN {Beam.Free[score, b]; RETURN}; SetDirty[score, b.sync1.time, b.sync2.time]; }; MakeBeamOfBeams: PUBLIC PROC[beamed: BOOLEAN] = { n: NotePTR; oldBeam: BeamPTR; score: ScorePTR _ selection.score; b: BeamPTR _ Beam.New[score, 8]; b.beamed _ beamed; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF n.beam = NIL THEN LOOP; IF NOT n.beam.beamed THEN {score.flash _ TRUE; RETURN}; IF n.beam.beam # NIL THEN {score.flash _ TRUE; RETURN}; ENDLOOP; FOR i: CARDINAL IN [0..selection.length) DO IF (n _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[n, score.sheet.voice] THEN LOOP; oldBeam _ n.beam; IF oldBeam = b THEN LOOP; IF oldBeam # NIL THEN { Beam.AddItem[score, b, oldBeam]; b.staff _ oldBeam.staff; b.height _ oldBeam.height; LOOP; }; IF beamed AND n.value < eighth THEN LOOP; Beam.AddItem[score, b, IF n.chord=NIL THEN n ELSE n.chord]; ENDLOOP; IF beamed THEN FOR i: CARDINAL IN [0..b.length) DO WITH b.chord[i] SELECT FROM beam: BeamPTR => { beam.height _ b.height; beam.staff _ b.staff; beam.tilt _ 0; }; ENDCASE; ENDLOOP; b.tilt _ 0; SetDirty[score, b.sync1.time, b.sync2.time]; }; ClearBeam: PUBLIC PROC = { UnBeam: PROC[score: ScorePTR, n: NotePTR] = { IF n.beam#NIL THEN Beam.RemoveItem[score, n.beam, IF n.chord=NIL THEN n ELSE n.chord]; }; Enumerate[UnBeam]; }; MakeNTuplet: PUBLIC PROC[n, a: INTEGER] = { b: BeamPTR _ NIL; newBeam: BOOLEAN _ FALSE; IF selection.score = NIL THEN RETURN; IF selection.lineSelect THEN { Heuristic.MakeNTuplets[selection.score, a, n, selection.select1, selection.select2]; RETURN}; FOR i: CARDINAL IN [0..selection.length) DO IF ~Note.InVoice[selection[i], selection.score.sheet.voice] THEN LOOP; IF b = NIL THEN b _ selection[i].beam; IF b = NIL OR selection[i].beam # b THEN newBeam _ TRUE; ENDLOOP; IF newBeam THEN { Selection.MakeBeam[FALSE]; FOR i: CARDINAL IN [0..selection.length) DO IF ~Note.InVoice[selection[i], selection.score.sheet.voice] THEN LOOP; b _ selection[i].beam; EXIT; ENDLOOP; IF b # NIL THEN b.beamed _ FALSE}; IF b = NIL THEN RETURN; b.against _ n; b.ntuple _ a; b.invisible _ FALSE; SetDirty[selection.score, b.sync1.time, b.sync2.time]; }; HideNTuplets: PUBLIC PROC[invisible: BOOLEAN] = { Hide: PROC[score: ScorePTR, n: NotePTR] = { FOR b: BeamPTR _ n.beam, b.beam WHILE b # NIL DO IF b.ntuple = 0 THEN LOOP; b.invisible _ invisible; ENDLOOP; }; Enumerate[Hide]; }; MakeNTupletOfBeams: PUBLIC PROC[n, a: INTEGER] = { t: NotePTR; b: BeamPTR _ NIL; newBeam: BOOLEAN _ FALSE; TopBeam: PROC[b: BeamPTR] RETURNS[BeamPTR] = {IF b # NIL AND b.beam # NIL THEN RETURN[b.beam] ELSE RETURN[b]}; FOR i: CARDINAL IN [0..selection.length) DO IF (t _ selection[i]) = NIL THEN LOOP; IF ~Note.InVoice[t, selection.score.sheet.voice] THEN LOOP; IF b = NIL THEN b _ TopBeam[t.beam]; IF b = NIL OR TopBeam[t.beam] # b THEN newBeam _ TRUE; ENDLOOP; IF newBeam THEN { Selection.MakeBeamOfBeams[FALSE]; FOR i: CARDINAL IN [0..selection.length) DO IF selection[i] = NIL THEN LOOP; IF selection[i].beam = NIL THEN LOOP; IF ~Note.InVoice[selection[i], selection.score.sheet.voice] THEN LOOP; b _ TopBeam[selection[i].beam]; EXIT; ENDLOOP; IF b # NIL THEN b.beamed _ FALSE}; IF b = NIL THEN RETURN; b.against _ n; b.ntuple _ a; b.invisible _ FALSE; SetDirty[selection.score, b.sync1.time, b.sync2.time]; }; END. jSelectionImpl.mesa Copyright (C) 1981, 1983, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell Last Edited by: Maxwell, November 22, 1983 12:47 pm Last Edited by: Doug Wyatt, June 18, 1984 11:53:35 am PDT lineSelect: PUBLIC BOOLEAN; select1, greySelect1: PUBLIC Time _ 1; greySelect2, select2: PUBLIC Time _ 0; selection: PUBLIC ARRAY [0..maxSelectionLength) OF NotePTR; selection.length: PUBLIC CARDINAL _ 0; min, max: PUBLIC Time _ 1; command: PUBLIC BOOLEAN _ FALSE; flash: PUBLIC BOOLEAN _ FALSE; IF selection.voice # noVoice AND n.voice # selection.voice THEN RETURN[FALSE]; *************************************************************************** selection manipulation *************************************************************************** **************************************************************************** procedures that take the current selection as an implicit parameter **************************************************************************** ENABLE Piece.Overflow => ERROR; ************************************************************************** syncs ************************************************************************** ****************************************************************** ties ****************************************************************** build up matching pairs if there are only two notes, we ignore pitch constraints check that there are an even number of pitches tie the pairs together ****************************************************************** chords ****************************************************************** is this a legal chording? make the new chord **************************************************************************** beams and n-tuplets **************************************************************************** don't beam quarters or above CONTROL b beams beams together ÊZ˜šœ™JšœF™FJšœ™Jšœ3™3Jšœ9™9—J˜šÏk ˜ Jšœœ-˜7Jšœœ3˜>Jšœœ˜Jšœ œ˜ J˜ Jšœœ˜(Jšœœ%˜0Jšœœ ˜Jšœ œ7˜FJšœœ+˜6˜J˜——Jšœœ˜JšœY˜`Jšœ ˜Jšœœ ˜J˜Jšœ™Jšœ&™&Jšœ&™&J˜Jšœ;™;Jšœ&™&J˜Jšœ™Jšœ ™ Jšœ™J˜Jšœ œœ˜8J˜š Ïnœœœ œœ˜3Jš œœœœœ™NJšœœœ œ(˜Zš œœœœ˜0Jšœœœœ˜+Jšœ˜—Jšœœ˜Jšœ˜J˜—JšœK™KJšœ™JšœK™KJ˜šžœœœ˜J˜J˜/J˜.J˜Jšœ˜J˜—šžœœœ!˜5Jšœœ˜Jšœ/˜/Jšœœ ˜%Jš œœœ œœœ˜&Jšœœ1˜PJšœ%œœ˜3Jšœ"œœ˜0Jšœœœœœœœœ˜PJ˜ J˜&Jšœœ˜J˜'Jšœ˜Jšœ)˜)Jšœ ˜ Jšœ˜J˜—šž œœœ˜'Jšœœ˜Jšœ9˜9Jšœœœœ˜šœœœœ˜'Jšœœœ˜J˜(J˜+Jšœœ˜"Jšœ)˜)J˜1Jšœ˜Jšœ ˜ Jšœœ˜—Jšœ˜J˜—šžœœœ)˜=šœœœ˜2JšœR˜VJšœ˜—J˜J˜J˜Jšœœ˜Jšœ œœ0˜CJšœ˜J˜—šž œœœ)˜Ašœœœ˜3JšœZ˜^Jšœ˜—J˜J˜Jšœœ˜Jšœ œœ/˜BJšœ˜J˜—šžœœœ˜Jšœœ˜šœœ˜šœœœ˜J˜Q—šœœœ˜J˜Y—Jšœ˜—Jš œœœœœ˜=J˜?šœœœ˜+Jšœœœœ˜ Jšœ:œœ˜FJ˜