DIRECTORY Basics USING [Comparison], Buttons USING [Button, ButtonProc, Create], Containers USING [ChildXBound, ChildYBound, Container, Create], Labels USING [Create, Label, Set], Menus USING [CreateEntry, CreateMenu, InsertMenuEntry, Menu, MenuProc], Rules USING [Create, Rule], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, PaintViewer, SetMenu, SetOpenHeight], ViewerClasses USING [Viewer], ViewerTools USING [MakeNewTextViewer, GetContents, SetContents, SetSelection], FS USING [StreamOpen], GVBasics USING [oldestTime], GVNames USING [CheckStamp, GetList, GetMembers, GetRemark, ListType, MemberInfo, RemarkInfo, RListHandle], Histogram, IO USING [card, Flush, noWhereStream, PutF, PutFR, PutRope, STREAM, time], RedBlackTree USING [Create, EnumerateIncreasing, Insert, Key, Lookup, Table, UserData], Rope USING [Cat, Compare, Find, Length, ROPE, SkipOver, SkipTo, Substr]; CedarDLMapper: CEDAR MONITOR IMPORTS Buttons, Containers, Labels, Menus, Rules, ViewerIO, ViewerOps, ViewerTools, FS, GVNames, Histogram, IO, RedBlackTree, Rope = { ROPE: TYPE = Rope.ROPE; entryHeight: CARDINAL = 15; entryVSpace: CARDINAL = 10; entryHSpace: CARDINAL = 10; heightSoFar: CARDINAL _ 0; container: Containers.Container; currentGroups, totalGroups: Labels.Label; currentName: Labels.Label; exceptions: ViewerClasses.Viewer; inStr, outStr: IO.STREAM; fullFileName, conFileName, ARPAFileName, registries: ViewerClasses.Viewer; BuildOuter: PROC = { myMenu: Menus.Menu _ Menus.CreateMenu[]; container _ Containers.Create[ info: [name: "DLMap", scrollable: FALSE] ]; Menus.InsertMenuEntry[menu: myMenu, entry: Menus.CreateEntry[name: "DoIt", proc: DoIt] ]; Menus.InsertMenuEntry[menu: myMenu, entry: Menus.CreateEntry[name: "Stop", proc: StopIt] ]; ViewerOps.SetMenu[viewer: container, menu: myMenu]; BuildUserInput[]; BuildUserFeedback[]; BuildExceptions[]; ViewerOps.SetOpenHeight[viewer: container, clientHeight: heightSoFar]; ViewerOps.PaintViewer[viewer: container, hint: all]; }; BuildUserInput: PROC = { Bl1, Bl2, Bl3, Bl4: Buttons.Button; heightSoFar _ heightSoFar+entryVSpace/2; Bl1 _ Buttons.Create[info: [name: "Full map file name:", parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToFullFileName]; fullFileName _ ViewerTools.MakeNewTextViewer[info: [parent: container, wx: Bl1.wx+Bl1.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: entryHeight, data: defaultFullFileName, scrollable: FALSE, border: FALSE], paint: FALSE]; Containers.ChildXBound[container, fullFileName]; heightSoFar _ heightSoFar+entryVSpace+Bl1.wh; Bl2 _ Buttons.Create[info: [name: "Condensed map file name:", parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToConFileName]; conFileName _ ViewerTools.MakeNewTextViewer[info: [parent: container, wx: Bl2.wx+Bl2.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: entryHeight, data: defaultConFileName, scrollable: FALSE, border: FALSE], paint: FALSE]; Containers.ChildXBound[container, conFileName]; heightSoFar _ heightSoFar+entryVSpace+Bl2.wh; Bl3 _ Buttons.Create[info: [name: "Arpa DL map file name:", parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToARPAFileName]; ARPAFileName _ ViewerTools.MakeNewTextViewer[info: [parent: container, wx: Bl3.wx+Bl3.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: entryHeight, data: defaultARPAFileName, scrollable: FALSE, border: FALSE], paint: FALSE]; Containers.ChildXBound[container, ARPAFileName]; heightSoFar _ heightSoFar+entryVSpace+Bl3.wh; Bl4 _ Buttons.Create[info: [name: "Registries:", parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToRegistries]; registries _ ViewerTools.MakeNewTextViewer[info: [parent: container, wx: Bl4.wx+Bl4.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: 4*entryHeight, data: defaultRegistries, scrollable: TRUE, border: FALSE], paint: FALSE]; Containers.ChildXBound[container, registries]; heightSoFar _ heightSoFar+entryVSpace+registries.wh; }; ForceSelToFullFileName: Buttons.ButtonProc = { IF mouseButton#red THEN ViewerTools.SetContents[fullFileName, defaultFullFileName] ELSE ViewerTools.SetSelection[fullFileName]; }; ForceSelToConFileName: Buttons.ButtonProc = { IF mouseButton#red THEN ViewerTools.SetContents[conFileName, defaultConFileName] ELSE ViewerTools.SetSelection[conFileName]; }; ForceSelToARPAFileName: Buttons.ButtonProc = { IF mouseButton#red THEN ViewerTools.SetContents[ARPAFileName, defaultARPAFileName] ELSE ViewerTools.SetSelection[ARPAFileName]; }; ForceSelToRegistries: Buttons.ButtonProc = { IF mouseButton#red THEN ViewerTools.SetContents[registries, defaultRegistries] ELSE ViewerTools.SetSelection[registries]; }; BuildUserFeedback: PROC = { lg, ln, of: Labels.Label; r1: Rules.Rule; r1 _ Rules.Create[info: [parent: container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[container, r1]; heightSoFar _ heightSoFar+entryVSpace; lg _ Labels.Create[info: [name: "DL's:", parent: container, wx: 0, wy: heightSoFar, border: FALSE]]; currentGroups _ Labels.Create[info: [name: "0000", parent: container, wx: lg.wx+lg.ww+entryHSpace, wy: heightSoFar, border: TRUE]]; Labels.Set[currentGroups, "0"]; of _ Labels.Create[info: [name: "of", parent: container, wx: currentGroups.wx+currentGroups.ww+entryHSpace, wy: heightSoFar, border: FALSE]]; totalGroups _ Labels.Create[info: [name: "0000", parent: container, wx: of.wx+of.ww+entryHSpace, wy: heightSoFar, border: TRUE]]; Labels.Set[totalGroups, "0"]; heightSoFar _ heightSoFar+entryVSpace+of.wh; ln _ Labels.Create[info: [name: "Current Name:", parent: container, wx: 0, wy: heightSoFar, border: FALSE]]; currentName _ Labels.Create[info: [name: "", parent: container, wx: ln.wx+ln.ww+entryHSpace, wy: heightSoFar, border: FALSE]]; Labels.Set[currentName, "none"]; Containers.ChildXBound[container, currentName]; heightSoFar _ heightSoFar+entryVSpace+of.wh; }; BuildExceptions: PROC = { r2: Rules.Rule; r2 _ Rules.Create[info: [parent: container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[container, r2]; heightSoFar _ heightSoFar+entryVSpace; exceptions _ ViewerOps.CreateViewer[flavor: $Typescript, info: [name: "", parent: container, wx: 0, wy: heightSoFar, wh: 5*entryHeight, border: FALSE]]; heightSoFar _ heightSoFar+entryVSpace+exceptions.wh; Containers.ChildXBound[container, exceptions]; Containers.ChildYBound[container, exceptions]; [in: inStr, out: outStr] _ ViewerIO.CreateViewerStreams[name: "", viewer: exceptions, backingFile: "DLMap.log"]; }; mapperStopped: ERROR = CODE; mappingInProgress: BOOLEAN _ FALSE; allRegistries: ROPE _ NIL; defaultRegistries: ROPE = "DLOS EOSA ES FX Henr OSDA PA PASA RX Siemens WBST X XRCC"; defaultFullFileName: ROPE = "///GV/FullDLMap.txt"; defaultConFileName: ROPE = "///GV/DLMap.txt"; defaultARPAFileName: ROPE = "///GV/ARPA-DLMap.txt"; stop: BOOLEAN _ FALSE; DoIt: Menus.MenuProc = { IF ReserveMapper[] THEN { Map[ ! mapperStopped => {outStr.PutF["\nStopped at %t.\n\n", IO.time[]]; CONTINUE} ]; ReleaseMapper[]; }; }; -- DoIt-- StopIt: Menus.MenuProc = {SetStop[]}; ReserveMapper: ENTRY PROC RETURNS [BOOLEAN] = { IF mappingInProgress THEN RETURN [FALSE] ELSE {mappingInProgress _ TRUE; RETURN[TRUE]}; }; ReleaseMapper: ENTRY PROC = {mappingInProgress _ FALSE; stop _ FALSE}; SetStop: ENTRY PROC = {stop _ TRUE}; StopSet: ENTRY PROC RETURNS [BOOLEAN] = {RETURN [stop]}; Stopped: PROC RETURNS [BOOLEAN] = { IF StopSet[] THEN ERROR mapperStopped ELSE RETURN[FALSE]}; ReportAllDown: PROC [dot: BOOLEAN, name: ROPE] = { IF dot THEN outStr.PutRope["."] ELSE outStr.PutF["\nAll down: %g. ", [rope[name]]]; }; ForWordsInRopeDo: PROC [r: ROPE, work: PROC[ROPE] RETURNS[done: BOOLEAN]] RETURNS [stopped: BOOLEAN] = { parsePosition: CARDINAL _ Rope.SkipOver[r, 0, " "]; -- skip initial blanks UNTIL parsePosition = Rope.Length[r] DO --parse registry input-- start: CARDINAL = parsePosition; parsePosition _ Rope.SkipTo[r, parsePosition, " "]; IF work[Rope.Substr[r, start, parsePosition-start]] THEN RETURN [stopped: TRUE]; parsePosition _ Rope.SkipOver[r, parsePosition, " "]; ENDLOOP; RETURN [stopped: FALSE] }; -- ForWordsInRopeDo -- CheckRegistryValidity: PROC [reg: ROPE] RETURNS [done: BOOLEAN] = { printDot: BOOLEAN _ FALSE; UNTIL Stopped[] DO SELECT GVNames.CheckStamp[Rope.Cat[reg, ".gv"]] FROM group => NULL; individual, notFound => { outStr.PutF["%g%g\n\n", [rope[reg]], [rope[" is not a valid registry."]]]; ERROR mapperStopped }; allDown => {ReportAllDown[printDot, reg]; printDot_TRUE; LOOP}; ENDCASE => ERROR; EXIT; ENDLOOP; RETURN [done: FALSE] }; --CheckRegistryValidity-- CreateOutputFile: PROC[n: ROPE] RETURNS [IO.STREAM] = { RETURN [IF Rope.Length[n] = 0 THEN IO.noWhereStream ELSE FS.StreamOpen[n, create]] }; GroupNotFound: ERROR = CODE; GetRList: PROC [n: ROPE, t: GVNames.ListType] RETURNS [l: ROPE] = { printDot: BOOLEAN _ FALSE; UNTIL Stopped[] DO WITH GVNames.GetList[n, GVBasics.oldestTime, t] SELECT FROM g: GVNames.MemberInfo[group] => { AddNameToRope: PROC [m: ROPE] RETURNS [done: BOOL] = { IF l # NIL THEN l _ Rope.Cat[l, ", "]; l _ Rope.Cat[l, m]; done _ FALSE }; l _ NIL; EnumerateRList[g.members, AddNameToRope]; }; a: GVNames.MemberInfo[allDown] => {ReportAllDown[printDot, n]; printDot_TRUE; LOOP}; ENDCASE => ERROR GroupNotFound; EXIT; ENDLOOP; }; --GetRList-- GetMembers: PROC [g: ROPE] RETURNS [rLH: GVNames.RListHandle, c: CARDINAL] = { printDot: BOOLEAN _ FALSE; UNTIL Stopped[] DO WITH GVNames.GetMembers[g] SELECT FROM g: GVNames.MemberInfo[group] => {rLH _ g.members; c _ g.count}; a: GVNames.MemberInfo[allDown] => {ReportAllDown[printDot, g]; printDot_TRUE; LOOP}; ENDCASE => ERROR GroupNotFound; EXIT; ENDLOOP; }; --GetMembers-- GetRemark: PROCEDURE [g: ROPE] RETURNS [r: ROPE] = { printDot: BOOLEAN _ FALSE; UNTIL Stopped[] DO info: GVNames.RemarkInfo; [info, r] _ GVNames.GetRemark[g]; SELECT info FROM group => IF Rope.Length[r] = 0 THEN r _ NIL; allDown => {ReportAllDown[printDot, g]; printDot_TRUE; LOOP}; ENDCASE => ERROR GroupNotFound; EXIT; ENDLOOP; }; --GetRemark-- CardToRope: PROC [c: CARDINAL] RETURNS [ROPE] = INLINE {RETURN [IO.PutFR[v1: IO.card[c]]]}; DLInfo: TYPE = RECORD [ name: ROPE, printable, notFound: BOOLEAN, in, ind: CARDINAL, remark, owners, friends: ROPE, sub: LIST OF REF DLInfo ]; GetKey: PROC [data: RedBlackTree.UserData] RETURNS [key: RedBlackTree.Key] = { WITH data SELECT FROM r: ROPE => key _ r; m: REF DLInfo => key _ m.name; ENDCASE => ERROR; }; MyCompare: PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] = { a: ROPE _ NARROW[k]; b: ROPE _ NARROW[GetKey[data]]; RETURN [Rope.Compare[a, b, FALSE]] }; --MyCompare-- EnumerateRList: PROC [r: GVNames.RListHandle, p: PROCEDURE [ROPE] RETURNS [BOOLEAN] ] = { FOR r _ r, r.rest UNTIL r=NIL OR p[r.first] DO ENDLOOP}; Map: PROC = { GetEntry: PROC [n: ROPE] RETURNS [d: REF DLInfo] = { d _ NARROW[RedBlackTree.Lookup[tree, n]]; IF d = NIL THEN { d _ NEW [DLInfo _ [name:n, printable:FALSE, notFound:FALSE, in:0, ind:0, remark:NIL, owners:NIL, friends:NIL, sub:NIL]]; RedBlackTree.Insert[tree, d, n]; }; }; --GetEntry-- EnumerateRegistry: PROC [reg: ROPE] RETURNS [BOOLEAN] = { rG: ROPE = Rope.Cat["groups.", reg]; regRLH: GVNames.RListHandle; Labels.Set[currentName, rG]; [regRLH, ] _ GetMembers[rG ! GroupNotFound => {outStr.PutF["\n%g not found?", [rope[rG]]]; ERROR mapperStopped}]; EnumerateRList[regRLH, GroupWork]; RETURN[FALSE] }; --EnumerateRegsitry-- GroupWork: PROC [group: ROPE] RETURNS [done: BOOLEAN] = { ContentWork: PROC [m: ROPE] RETURNS [done: BOOLEAN] = { done _ FALSE; IF Rope.SkipTo[m, 0, "^"] = Rope.Length[m] THEN gDI.ind _ gDI.ind + 1 ELSE { end: LIST OF REF DLInfo; mDI: REF DLInfo = GetEntry[m]; mDI.in _ mDI.in + 1; IF gDI.sub = NIL THEN gDI.sub _ CONS[mDI, NIL] ELSE FOR end _ gDI.sub, end.rest UNTIL end.rest = NIL DO REPEAT FINISHED => end.rest _ CONS[mDI, NIL]; ENDLOOP; }; }; --ContentWork-- gDI: REF DLInfo _ NIL; rLH: GVNames.RListHandle; count: CARDINAL; notFound: BOOLEAN _ FALSE; Labels.Set[currentName, group]; Labels.Set[totalGroups, CardToRope[totalGrp _ totalGrp + 1]]; [rLH, count] _ GetMembers[group ! GroupNotFound => {notFound _ TRUE; CONTINUE}]; IF NOT notFound THEN gram.DataPoint[count]; IF Rope.SkipTo[group, 0, "^"] = Rope.Length[group] THEN RETURN [done: FALSE]; gDI _ GetEntry[group]; gDI.printable _ TRUE; IF notFound THEN gDI.notFound _ TRUE ELSE { IF fFH#IO.noWhereStream THEN { -- need extra info for the full listing -- EnumerateRList[rLH, ContentWork]; gDI.owners _ GetRList[group, owners]; }; gDI.remark _ GetRemark[group]; gDI.friends _ GetRList[group, friends]; }; RETURN [done: FALSE] }; -- GroupWork-- AlreadyDoneThis: SIGNAL [new: REF DLInfo] RETURNS [BOOLEAN] = CODE; WC: PROC [r1, r2, r3, r4: ROPE _ NIL] = { IF r1#NIL THEN cFH.PutRope[r1]; IF r2#NIL THEN cFH.PutRope[r2]; IF r3#NIL THEN cFH.PutRope[r3]; IF r4#NIL THEN cFH.PutRope[r4] }; WF: PROC [r1, r2, r3, r4: ROPE _ NIL] = { IF r1#NIL THEN fFH.PutRope[r1]; IF r2#NIL THEN fFH.PutRope[r2]; IF r3#NIL THEN fFH.PutRope[r3]; IF r4#NIL THEN fFH.PutRope[r4] }; WA: PROC [r1, r2, r3, r4: ROPE _ NIL] = { IF r1#NIL THEN aFH.PutRope[r1]; IF r2#NIL THEN aFH.PutRope[r2]; IF r3#NIL THEN aFH.PutRope[r3]; IF r4#NIL THEN aFH.PutRope[r4] }; W: PROC [r1, r2, r3, r4: ROPE _ NIL] = {WF[r1, r2, r3, r4]; WC[r1, r2, r3, r4]}; PrintDLEntry: PROC [dl: RedBlackTree.UserData] RETURNS [BOOLEAN] = { dlInfo: REF DLInfo = NARROW [dl]; IF NOT dlInfo.printable OR dlInfo.notFound THEN RETURN[FALSE]; Labels.Set[currentName, dlInfo.name]; Labels.Set[currentGroups, CardToRope[currentGrp _ currentGrp+1]]; W["\n"]; IF Rope.Find[dlInfo.remark, "@"] > -1 THEN { WA[dlInfo.name]; WA[" - ", dlInfo.remark, "\n"] }; W[dlInfo.name]; IF dlInfo.remark#NIL THEN {W[" - ", dlInfo.remark]; dlInfo.remark _ NIL}; WF["\n\t", CardToRope[dlInfo.ind], " individual", IF dlInfo.ind=1 THEN NIL ELSE "s"]; IF dlInfo.in#0 THEN WF["; in ", CardToRope[dlInfo.in], " other DL", IF dlInfo.in=1 THEN NIL ELSE "s"]; WF["\n"]; WF["\tOwners: "]; IF dlInfo.owners=NIL THEN WF[" Default", "\n"] ELSE {WF[dlInfo.owners, "\n"]; dlInfo.owners _ NIL}; WF["\tFriends: "]; IF dlInfo.friends=NIL THEN WF[" None", "\n"] ELSE {WF[dlInfo.friends, "\n"]; dlInfo.friends _ NIL}; PrintSubstructure[dlInfo ! AlreadyDoneThis => RESUME [new=dlInfo]]; RETURN[FALSE] }; PrintSubstructure: PROC [top: REF DLInfo] = { dots: ROPE = ". . . . . . . . . . "; -- 10 dot/space for indenting -- indention _ indention+1; FOR dlList: LIST OF REF DLInfo _ top.sub, dlList.rest UNTIL dlList = NIL DO dl: REF DLInfo = dlList.first; WF[Rope.Substr[dots, 0, MIN[indention*2, Rope.Length[dots]]], dl.name, " - "]; SELECT TRUE FROM (NOT dl.printable) => WF["not expanded.\n"]; (dl.notFound) => WF["not found.\n"]; (indention=1 AND top.ind=0 AND dlList=top.sub AND dlList.rest=NIL) => WF["is the only contained group; see that entry.\n"]; (SIGNAL AlreadyDoneThis[dl]) => WF["**loop**\n"]; ENDCASE => { WF[CardToRope[dl.ind], "\n"]; PrintSubstructure[dl ! AlreadyDoneThis => IF new=dl THEN RESUME[TRUE] ]; }; ENDLOOP; indention _ indention-1; }; --PrintSubstructure-- tree: RedBlackTree.Table = RedBlackTree.Create[GetKey, MyCompare]; inputRegs: ROPE = ViewerTools.GetContents[registries]; aFH: IO.STREAM = CreateOutputFile[ViewerTools.GetContents[ARPAFileName]]; cFH: IO.STREAM = CreateOutputFile[ViewerTools.GetContents[conFileName]]; fFH: IO.STREAM = CreateOutputFile[ViewerTools.GetContents[fullFileName]]; currentGrp, totalGrp: CARDINAL _ 0; indention: CARDINAL _ 0; gram: Histogram.Gram = Histogram.NewGram[0, 2000]; IF cFH=IO.noWhereStream AND fFH=IO.noWhereStream AND aFH=IO.noWhereStream THEN {outStr.PutRope["\nNo output files."]; RETURN}; outStr.PutF["Running at %t.", IO.time[]]; Labels.Set[currentName, "none"]; Labels.Set[totalGroups, "0"]; Labels.Set[currentGroups, "0"]; [] _ ForWordsInRopeDo[inputRegs, CheckRegistryValidity]; [] _ ForWordsInRopeDo[inputRegs, EnumerateRegistry]; W["Distribution list map of ", inputRegs]; WA["Arpanet redistribution list map of ", inputRegs]; W[".\n\nProduced at ", IO.PutFR[v1: IO.time[]]]; WA[".\n\nProduced at ", IO.PutFR[v1: IO.time[]]]; WC["\n\nTry using the ""Maintain"" program to add/remove yourself to/from a DL. "]; WC["If ""Maintain"" responds with ""you're not allowed to do that"", try adding/deleting yourself to firstPart-GV^.reg."]; WC["If that also fails, then send a message to ""Owners-firstPart^.reg"" requesting to be added/removed."]; W["\n\n"]; WA["\n\n"]; [] _ RedBlackTree.EnumerateIncreasing[tree, PrintDLEntry]; W["\n\nEnd of listing.\n"]; WA["\n\nEnd of listing.\n"]; fFH.Flush[]; cFH.Flush[]; aFH.Flush[]; gram.Print[outStr, "\n\nNumber of members in a group."]; outStr.PutF["\nDone at %t.\n\n", IO.time[]]; }; --Map-- BuildOuter[]; }. 2CedarDLMapper.mesa; Edited by Schroeder on March 21, 1983 8:32 am Last Edited by: RWeaver, February 10, 1984 10:50 am Hal Murray, April 7, 1986 1:00:19 am PST Hal Murray May 6, 1985 9:25:03 pm PDT John Larson, July 6, 1986 0:41:24 am PDT **************** start of operational code **************** Ê1˜šœA™AJšœ3™3Jšœ(™(Jšœ%™%Jšœ(™(J™—šÏk ˜ Jšœœ˜Jšœœ˜+Jšœ œ/˜?Jšœœ˜#Jšœœ=˜HJšœœ˜Jšœ œ˜%Jšœ œ6˜EJšœœ ˜Jšœ œ=˜NJšœœ˜Jšœ œ˜šœœ"˜/J˜:—J˜ Jšœœ4œ˜JJšœ œE˜WJšœœœ˜HJ˜—šÏn œœ˜JšœNœœ˜‡Jšœœœ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜J˜Jšœ œ˜J˜J˜!J˜)J˜J˜!Jšœœœ˜J˜JJ˜šž œœ˜J˜(JšœAœ˜J˜#J˜2J˜—˜#J˜4J˜—J˜3J˜J˜J˜J˜GJ˜4J˜J˜—šžœœ˜Jšœ#˜#J˜(šœTœ˜ZJ˜0—˜FJ˜GJšœ'œ œ œ˜L—J˜0J˜J˜-˜PJšœœ1˜>—˜EJ˜GJšœ&œ œ œ˜L—J˜/J˜-˜NJšœœ2˜?—˜FJ˜GJšœ'œ œ œ˜M—J˜0J˜J˜-šœLœ˜RJ˜.—˜DJ˜IJšœ%œ œ œ˜I—J˜.J˜4J˜J˜—šžœ˜.Jšœœ;˜RJšœ(˜,J˜J˜—šžœ˜-Jšœœ9˜PJšœ'˜+J˜—J˜šžœ˜.Jšœœ;˜RJšœ(˜,J˜J˜—šžœ˜,Jšœœ7˜NJšœ&˜*J˜J˜—šžœœ˜J˜J˜J˜SJ˜&J˜&˜;Jšœ œ˜(—˜EJšœ6œ˜=—J˜˜8JšœLœ˜T—˜CJšœ6œ˜=—J˜J˜,˜CJšœ œ˜(—˜?Jšœ6œ˜>—J˜ J˜/J˜,J˜J˜—šžœœ˜J˜˜+J˜'—J˜&J˜&˜8˜NJšœœ˜——J˜4J˜.J˜.˜UJ˜—J˜J˜—Jšœ;™;J™Jšœœœ˜Jšœœœ˜#Jšœœœ˜Jšœœ>˜UJšœœ˜2Jšœœ˜-Jšœœ˜3Jšœœœ˜J˜šžœ˜Jšœ˜˜Jšœ=œ œ˜UJ˜J˜—JšœÏc ˜ J˜—Jšžœ˜%J˜š ž œœœœœ˜/Jšœ˜Jšœœœ˜Jšœœœœ˜.J˜J˜—Jš ž œœœœ œ˜FJ˜Jšžœœœ œ˜$Jš žœœœœœœ ˜9šžœœœœ˜#Jš œ œœœœœ˜:J˜—šž œœœœ˜2Jšœ˜Jšœ˜Jšœ/˜3J˜J˜—Jšžœœœœœœœ˜Išœ œ˜JšœœŸ˜Jšœ œŸ˜@Jšœœ˜ J˜3Jšœ2œœ œ˜PJ˜5Jšœ˜—Jšœ œ˜JšœŸ˜J˜—š žœœœœœ˜CJšœ œœ˜šœ ˜šœ*˜4J˜Jšœ˜˜J˜JJšœ˜J˜—J˜ Jšœ(œœ˜4Jšœ˜ —Jšœ˜Jšœ˜Jšœ˜—Jšœœ˜JšœŸ˜J˜—Jš žœœœœœœ˜5š œœœœœ˜5Jšœœ˜J˜—J˜Jšž œœœ˜š žœœœœœ˜CJšœ œœ˜šœ ˜šœ,œ˜;˜!š ž œœœœœ˜6Jšœœœ˜&J˜šœ˜ J˜——Jšœœ˜J˜)J˜—J˜!Jšœ&œœ˜2Jšœ˜ —Jšœ˜Jšœ˜Jšœ˜—JšœŸ ˜J˜—š ž œœœœœ˜NJšœ œœ˜šœ ˜šœœ˜&J˜?J˜!Jšœ&œœ˜2Jšœœ˜—Jšœ˜Jšœ˜—JšœŸ˜J˜—š ž œ œœœœ˜4Jšœ œœ˜šœ ˜J˜J˜!šœ˜Jšœ œœœ˜,J˜ Jšœ&œœ˜2Jšœœ˜—Jšœ˜Jšœ˜—JšœŸ ˜—J˜Jš ž œœœœœ˜6Jšœœœ œ ˜$J˜šœœœ˜Jšœœ˜ Jšœœ˜Jšœ œ˜Jšœœ˜Jšœœœœ ˜J˜—šžœœœ˜Nšœœ˜Jšœœ ˜Jšœœ˜Jšœœ˜—J˜J˜—šž œœ4œ˜bJšœœœ˜Jšœœœ˜Jšœœ˜"JšœŸ ˜—J˜šžœœ˜-š œ œœœœ˜+Jš œœœœ œœ˜8——J˜šžœœ˜ š žœœœœœ ˜4Jšœœ˜)šœœœ˜šœœœ œ˜HJš œœ œ œœ˜/—J˜ J˜—JšœŸ œ˜—š žœœœœœ˜9Jšœœ˜$J˜J˜˜-Jšœ-œ˜C—J˜"Jšœœ˜ JšœŸ˜—š ž œœ œœœ˜9š ž œœœœœ˜7Jšœœ˜ Jšœ(˜*šœ˜šœ˜Jšœœœœ˜—Jšœœ˜J˜Jšœ ˜šœ œœ˜Jš œœœ œ˜8Jšœœœœ˜-Jšœ˜—J˜—JšœŸ˜—Jšœœ œ˜J˜Jšœœ˜Jšœ œœ˜J˜J˜=Jšœ?œœ˜PJšœœ œ˜+Jšœ1œœœ˜MJ˜Jšœœ˜Jšœ ˜ šœ˜šœ˜šœœœŸ*˜IJ˜!—J˜%J˜—J˜J˜'J˜—Jšœœ˜JšœŸ˜—Jš žœœœ œœœ˜Cšœœœœ˜)Jšœœœ˜Jšœœœ˜Jšœœœ˜Jšœœœ˜J˜—šœœœœ˜)Jšœœœ˜Jšœœœ˜Jšœœœ˜Jšœœœ˜J˜—šœœœœ˜)Jšœœœ˜Jšœœœ˜Jšœœœ˜Jšœœœ˜J˜—Jš žœœœœœœ˜PJ˜šž œœœœ˜DJšœœ œ˜!Jš œœœœœœ˜>J˜%J˜AJ˜J˜šœ$œ˜,Jšœœ˜/J˜—J˜Jšœœœ+œ˜IJ˜Jš œ0œœœœ˜UJšœ ˜Jš œ.œ œœœ˜RJšœ˜ J˜Jšœ˜Jšœ˜Jšœœ˜Jšœœ'œ˜4Jšœ˜Jšœ˜Jšœœ˜Jšœœ)œ˜6Jšœ.œ˜CJšœœ˜ J˜—šžœœœ ˜-JšœœŸ ˜EJ˜š œ œœœœ œ˜KJšœœ˜Jšœœ3˜Nšœœ˜Jšœœ˜Jšœ˜J˜Jšœ˜Jš œ œ œœ œ˜EJšœ3˜5Jšœœ˜Jšœ˜Jšœ˜ Jšœ˜Jš œ*œœœœ˜HJ˜—Jšœ˜—J˜JšœŸ˜—J˜CJšœ œ'˜6Jšœœœ;˜IJšœœœ:˜HJšœœœ;˜IJšœœ˜#Jšœ œ˜J˜2J˜Jš œœœœœœ˜NJšœ'œ˜/J˜Jšœœ ˜)J˜ J˜J˜J˜J˜8J˜4J˜J˜*Jšœ5˜7Jšœœ œ ˜0Jšœœ œ ˜1JšœR˜TJšœy˜{Jšœj˜lJ˜ Jšœ ˜ J˜:J˜Jšœ˜J˜ J˜ J˜ J˜8Jšœ!œ ˜,JšœŸ˜ J˜—J˜ J˜—J˜—…—A>T¡