DIRECTORY BansheeControl USING [--BandBLTTransferCreatePage, BandBLTTransferReady, --Display, EngineEvent, EngineStatus, EventContext, GetEnginePaper, GetEngineStatus, Initialize, PageTransferSet, SendEngineCommand, SetToCurrentEventContext, TransferRelease, unlimitedAvailable, WaitEngineStatus, WaitEngineEvent], BansheeEngine USING [DisplayDigit, JobHandle], BansheeSequence USING [--GetBandlist, --pageCount, Set], BansheeStatus USING [Type], PrincOps USING [PageCount], LSEPFace USING [AdvanceBand], PaperTypes USING [Paper], PrintingState USING [Type], Process USING [Detach, Pause, priorityForeground, priorityRealTime, SecondsToTicks, SetPriority], Loader USING [MakeGlobalFrameResident, MakeProcedureResident]; BansheeEngineImpl: CEDAR MONITOR IMPORTS BansheeControl, BansheeSequence, Loader, LSEPFace, Process EXPORTS BansheeEngine = BEGIN PrintingStateKind: TYPE = {current, next}; newPrintingState: ARRAY PrintingStateKind OF CONDITION; debugForceTransferWait: BOOLEAN _ FALSE; -- are we always going to wait for transfer to be ready before feeding jobInternal: BansheeEngine.JobHandle; printingState: ARRAY PrintingStateKind OF PrintingState.Type; pageDelivered, pageFeed, pageTransfer, pageTrash: CARDINAL; stickyEngineStatus: BansheeControl.EngineStatus _ okay; Beep: PUBLIC PROCEDURE = BEGIN BansheeControl.SendEngineCommand[chime]; END; Display: PUBLIC PROCEDURE [digitLS, digitMS: BansheeEngine.DisplayDigit] = BEGIN BansheeControl.Display[LOOPHOLE[digitLS], LOOPHOLE[digitMS]]; END; GetPageBalance: PUBLIC PROCEDURE RETURNS [balance: CARDINAL] = BEGIN RETURN[balance: SELECT GetPrintingStateEntry[kind: current] FROM completed => 0, ENDCASE => BansheeSequence.pageCount + pageTrash - pageDelivered]; END; -- GetPageBalance GetPaperSize: PUBLIC PROCEDURE RETURNS [paperSize: PaperTypes.Paper] = BEGIN RETURN[SELECT BansheeControl.GetEnginePaper[] FROM paperLetter => [knownSize: letter], paperLegal => [knownSize: legal], paperA4 => [knownSize: a4], paper215X330 => [knownSize: legal], paperEnvelope10 => [knownSize: other, otherSize: [114, 254]], -- 4.5x10" paperEnvelopeRX => [knownSize: other, otherSize: [114, 254]], ENDCASE => ERROR]; END; -- GetPaperSize GetPrintingState: PUBLIC PROCEDURE RETURNS [state: PrintingState.Type] = BEGIN RETURN[state: GetPrintingStateEntry[kind: current]]; END; -- GetPrintingState GetStatus: PUBLIC PROCEDURE RETURNS [status: BansheeStatus.Type] = BEGIN IF stickyEngineStatus NOT IN [imageFault1..sequenceFault] THEN stickyEngineStatus _ BansheeControl.GetEngineStatus[]; -- "sticky" stauses status _ SELECT stickyEngineStatus FROM okay => okay, okayFlushRequired => okay, diagnosticOkay => repairMode, noPaper => noPaper, preregistrationJam => preRegistrationJam, fuserJam => fuserJam, noExit => exitJam, outputTrayFull => outputTrayFull, feedTrayNotEngaged => paperCassetteRemoved, clamShellOpen => clamshellOpen, copyModeOn => copyMode, noToner => noToner, callForService => callForService, diagnosticNotReady => repairMode, offline => offLine, communicationFault => communicationFault, imageFault1 => imageFault1, imageFault2 => imageFault2, imageFault3 => imageFault2, sequenceFault => sequenceFault, ENDCASE => ERROR; END; -- GetStatus Initialize: PUBLIC PROCEDURE [bufferSize: PrincOps.PageCount, enableUnlimited: BOOLEAN] = TRUSTED BEGIN Loader.MakeProcedureResident[LSEPFace.AdvanceBand]; Loader.MakeGlobalFrameResident[LSEPFace.AdvanceBand]; Loader.MakeGlobalFrameResident[BansheeControl.SendEngineCommand]; Loader.MakeProcedureResident[BansheeControl.SendEngineCommand]; BansheeControl.Initialize[bufferSize: bufferSize, enableUnlimited: TRUE]; Process.Detach[FORK Print]; -- priority = 2 (sometimes 5) END; -- Initialize SetJob: PUBLIC PROCEDURE [job: BansheeEngine.JobHandle] = BEGIN jobInternal _ job; END; -- SetJob SetPrintingState: PUBLIC PROCEDURE [state: PrintingState.Type] = BEGIN SetPrintingStateEntry[kind: next, state: state]; END; -- SetPrintingState WaitPrintingState: PUBLIC PROCEDURE [targetState: PrintingState.Type, targetEqual: BOOLEAN] RETURNS [state: PrintingState.Type] = BEGIN RETURN[state: WaitPrintingStateEntry[kind: current, targetState: targetState, targetEqual: targetEqual]]; END; -- WaitPrintingState WaitStatus: PUBLIC PROCEDURE RETURNS [status: BansheeStatus.Type] = BEGIN [] _ BansheeControl.WaitEngineStatus[]; RETURN[GetStatus[]]; END; -- WaitStatus GetPrintingStateEntry: ENTRY PROCEDURE [kind: PrintingStateKind] RETURNS [state: PrintingState.Type] = BEGIN RETURN[state: printingState[kind]]; END; SetPrintingStateEntry: ENTRY PROCEDURE [kind: PrintingStateKind, state: PrintingState.Type] = BEGIN printingState[kind] _ state; BROADCAST newPrintingState[kind]; END; WaitPrintingStateEntry: ENTRY PROCEDURE [kind: PrintingStateKind, targetState: PrintingState.Type, targetEqual: BOOLEAN] RETURNS [state: PrintingState.Type] = BEGIN UNTIL targetEqual = (printingState[kind] = targetState) DO WAIT newPrintingState[kind]; ENDLOOP; RETURN[state: printingState[kind]]; END; -- WaitPrintingStateEntry Print: PROCEDURE = BEGIN diagnosticPrint: BOOLEAN _ FALSE; -- wait for pageDelivery before feeding forceTransferWait: BOOLEAN; -- Always wait for transfer if page sync miss. transferWait: BOOLEAN; -- Should we wait for transfer to be ready before feed feedOkay: BOOLEAN; -- Will engine accept feed command unlimitedPage: BOOLEAN _ FALSE; -- print this page in unlimited mode printEvent --, transferEvent-- : BansheeControl.EngineEvent; engineError, transferIsReady: BOOLEAN; beeperActive: BOOLEAN _ FALSE; eventContextHandleTransfer: REF BansheeControl.EventContext _ NEW[BansheeControl.EventContext]; eventContextPrint: REF BansheeControl.EventContext _ NEW[BansheeControl.EventContext]; DisplayFault: PROCEDURE = TRUSTED BEGIN Beeper: PROCEDURE = TRUSTED BEGIN THROUGH [1..5] DO BansheeControl.SendEngineCommand[chime]; Process.Pause[Process.SecondsToTicks[2]]; ENDLOOP; beeperActive _ FALSE; END; -- Beeper SELECT BansheeControl.GetEngineStatus[] FROM imageFault1, imageFault2, imageFault3, sequenceFault => BEGIN BansheeControl.SendEngineCommand[SELECT BansheeControl.GetEngineStatus[] FROM imageFault1 => displayP1, imageFault2 => displayP2, imageFault3 => displayP3, ENDCASE => displayP5]; IF NOT beeperActive THEN BEGIN beeperActive _ TRUE; Process.Detach[FORK Beeper]; -- beep, then go away END; END; ENDCASE => Display[blank, blank]; END; -- DisplayFault Process.SetPriority[Process.priorityForeground]; DO -- forever SetPrintingStateEntry[kind: next, state: completed]; SetPrintingStateEntry[kind: current, state: completed]; [] _ WaitPrintingStateEntry[kind: next, targetState: started, targetEqual: TRUE]; IF NOT BansheeSequence.Set[jobInternal] THEN BEGIN Process.Pause[Process.SecondsToTicks[1]]; LOOP; END; pageDelivered _ pageTrash _ 0; forceTransferWait _ TRUE; -- this document has not missed a page sync (yet) DO -- document loop SetPrintingStateEntry[kind: current, state: GetPrintingStateEntry[next]]; IF WaitPrintingStateEntry[kind: next, targetState: stopped, targetEqual: FALSE] = completed THEN EXIT; -- job aborted SetPrintingStateEntry[kind: current, state: started]; IF stickyEngineStatus IN [imageFault1..sequenceFault] THEN stickyEngineStatus _ okay; -- clear "sticky" status with new job start SELECT BansheeControl.GetEngineStatus[] FROM okay, diagnosticOkay => NULL; -- no problem okayFlushRequired, IN [imageFault1..imageFault3] => BEGIN BansheeControl.SetToCurrentEventContext[eventContextPrint]; BansheeControl.SendEngineCommand[feed]; DO -- flush printing loop SELECT printEvent _ BansheeControl.WaitEngineEvent[eventContextPrint] FROM pageDelivery, feedError, softError, hardError, timeout => EXIT; -- wait for these ENDCASE => LOOP; -- others are in-process ENDLOOP; -- flush printing loop IF BansheeControl.GetEngineStatus[] IN [imageFault1..sequenceFault] AND GetPrintingStateEntry[next] = started THEN SetPrintingStateEntry[kind: next, state: stopped]; -- restarted by BansheeMarkerControlImpl DisplayFault[]; LOOP; -- flushed one sheet, try again END; ENDCASE => BEGIN Process.Pause[Process.SecondsToTicks[1]]; LOOP; END; diagnosticPrint _ BansheeControl.GetEngineStatus[] = diagnosticOkay; pageTransfer _ pageFeed _ pageDelivered _ pageDelivered - pageTrash; pageTrash _ 0; engineError _ FALSE; transferWait _ forceTransferWait -- OR PredictTransferWait[pageTransfer]--; BansheeControl.PageTransferSet[pageDelivered+1]; -- Build Bitmap. transferIsReady _ TRUE; Process.SetPriority[Process.priorityRealTime]; -- don't miss events feedOkay _ FALSE; BansheeControl.SetToCurrentEventContext[eventContext: eventContextPrint]; BansheeControl.SendEngineCommand[feed]; DO -- page printing loop SELECT printEvent _ BansheeControl.WaitEngineEvent[eventContextPrint] FROM readyToFeed => BEGIN feedOkay _ TRUE; IF (transferWait AND NOT transferIsReady) OR diagnosticPrint THEN LOOP; END; feeding => BEGIN pageFeed _ pageFeed + 1; transferIsReady _ FALSE; Display[LOOPHOLE[(pageFeed - pageTrash) MOD 10], LOOPHOLE[((pageFeed - pageTrash) / 10) MOD 10]]; LOOP; END; transferReady => BEGIN transferIsReady _ TRUE; IF (NOT transferWait) OR (NOT feedOkay) OR diagnosticPrint THEN LOOP; END; imaged => LOOP; imagedOverrun => BEGIN IF BansheeControl.unlimitedAvailable THEN BEGIN pageTrash _ pageTrash + 1; transferWait _ TRUE; END; LOOP; END; pageSyncMiss => BEGIN pageTrash _ pageTrash + 1; IF NOT unlimitedPage THEN -- don't set forceTransferWait if unlimitedPage forceTransferWait _ transferWait _ TRUE; LOOP; END; pageDelivery => BEGIN pageDelivered _ pageDelivered + 1; IF pageDelivered >= BansheeSequence.pageCount + pageTrash THEN EXIT; IF pageDelivered >= pageFeed AND (GetPrintingStateEntry[next] # started OR engineError) THEN EXIT; IF NOT diagnosticPrint THEN LOOP; -- feed next page if diagnostic END; feedError => BEGIN IF NOT engineError THEN -- feedError should only occur once pageFeed _ pageFeed - 1; -- but occurs lots, so decrement pageFeed if not previous error engineError _ TRUE; IF pageDelivered >= pageFeed THEN EXIT ELSE LOOP; END; softError => BEGIN engineError _ TRUE; IF pageDelivered >= pageFeed THEN EXIT ELSE LOOP; END; hardError => BEGIN engineError _ TRUE; EXIT; END; timeout => IF engineError OR pageTransfer >= BansheeSequence.pageCount OR GetPrintingStateEntry[next] # started THEN EXIT -- these should only occur when waiting for transferReady ELSE IF NOT transferIsReady THEN LOOP; -- else we missed transferReady event ENDCASE => ERROR; IF pageFeed < BansheeSequence.pageCount + pageTrash AND GetPrintingStateEntry[next] = started THEN BEGIN transferWait _ forceTransferWait -- OR PredictTransferWait[pageFeed - pageTrash]--; feedOkay _ FALSE; BansheeControl.SendEngineCommand[feed]; END; ENDLOOP; -- page printing loop Process.SetPriority[Process.priorityForeground]; IF BansheeControl.GetEngineStatus[] IN [imageFault1..sequenceFault] AND GetPrintingStateEntry[next] = started THEN SetPrintingStateEntry[kind: next, state: stopped]; -- restarted by BansheeMarkerControlImpl DisplayFault[]; BansheeControl.TransferRelease[]; IF pageDelivered = BansheeSequence.pageCount + pageTrash THEN EXIT; ENDLOOP; -- document loop ENDLOOP; -- forever END; -- Print END. LOG When / Who / What. 12-Dec-84 23:29:22 / Strickberger / Created. 28-Jan-85 16:12:59 / Strickberger / Update to new BansheeFace. 14-Feb-85 17:24:42 / Strickberger / Add offline mode handling. 25-Feb-85 23:08:49 / Strickberger / Add prediction logic to wait for transfer ready if a new fontload will be required. 1-Apr-85 23:13:01 / Strickberger / Stop printing if image fault. Flush printer control moved to this module - part of ImageFault fix (AR13951). Display image fault/sequence fault code display. 13-May-85 0:12:46 / Strickberger / Fix pageDelivered pageMissed initialization before page printing loop. Check pageTransfer limit and printingState at Idle event in page printing loop. Check engineState at Idle event in HandleTransfer. 23-May-85 22:53:10 / Strickberger / Decrement pageFeed only once in page printing loop if feedError event by checking engineError. 28-May-85 17:56:42 / Strickberger / Check engineError, pageTransfer >= BansheeSequence.pageCount, GetPrintingStateEntry[next] # started before SELECTing on transferEvent in HandleTransfer (AR15492). 31-Jul-85 21:07:12 / Strickberger / Do not call debugger if timeout event in HandleTransfer, fall through if timeout event and transferIsReady in page printing loop of Print (AR15541). Run page printing loop of Print at priorityIOLow. 12-Aug-85 23:45:06 / Strickberger / Add unlimited printing. Update for Euclid. FixArrows. 25-Aug-85 20:55:57 / Strickberger / Feed next page at pageDelivery in diagnostic mode. 19-Sep-85 19:15:44 / Strickberger / Added enableUnlimited parameter to Initialize. 3-Oct-85 2:56:25 / Strickberger / Fix race condition with setting transferWait in HandleTransfer by adding feedOkay logic. 14-Oct-85 17:26:44 / Strickberger / Add envelope handling to GetPaperSize. 24-Feb-86 12:12:12 / Strickberger / Add Beeper to chime for software detected faults (AR3107). 1-Apr-86 22:57:21 / Strickberger / Set debugForceTransferWait _ TRUE if 192kW server (AR3752). Modified flush logic to not fall through after flush; stop printing if image fault after flush. 4-May-86 23:59:08 / Strickberger / Modify pageDelivery case in Print to not subtract pageTrash from pageDelivered, avoids hang after imagedOverrun print (AR4225). 14-May-86 20:04:14 / Prochaska / Update for new BansheeControl, add calls to BansheeControl.SetToCurrentEventContext. FBansheeEngineImpl.mesa Copyright (C) Xerox Corporation 1985, 1986. All rights reserved. Edited by prochaska 14-May-86 14:11:30 Ruseli Binsol: October 13, 1986 3:24:15 pm PDT Make LSEPHeadDLion resident Make BansheeControlImpl resident Initialize BansheeControlImpl start the printing processes sets next state of job returns when current job achieves desired relationship (equal or not equal) with the target state wait until desired relationship is achieved with targetState transferProcess: PROCESS; HandleTransfer: PROCEDURE = BEGIN unlimitedPage _ False; BansheeControl.SetToCurrentEventContext[eventContext: eventContextHandleTransfer]; DO IF engineError THEN EXIT; transferEvent _ RavenControl.WaitEngineEvent[eventContextHandleTransfer]; IF engineError OR GetPrintingStateEntry[next] # started THEN EXIT; SELECT transferEvent FROM imaged => pageTransfer _ pageTransfer + 1; -- and fall through imagedOverrun => IF BansheeControl.unlimitedAvailable THEN unlimitedPage _ TRUE ELSE pageTransfer _ pageTransfer + 1; feederror, softerror, harderror => EXIT; ENDCASE => LOOP; -- update BandBLTTable for next page and make bandlists and fontloads resident IF pageTransfer >= BansheeSequence.pageCount THEN EXIT; IF unlimitedPage THEN BEGIN BandBLTTransfer.Update[ bandlist: BansheeSequence.GetBandlist[page: pageTransfer], nextBandlist: BansheeSequence.GetBandlist[page: pageTransfer]]; BansheeControl.BandBLTTransferCreatePage[firstPlate: TRUE]; -- create page bitmap BandBLTTransfer.Reset[]; -- make bandlists and fontloads swappable BansheeControl.PageTransferSet[]; -- signal that page is ready unlimitedPage _ FALSE; END ELSE BEGIN BandBLTTransfer.Update[ bandlist: BansheeSequence.GetBandlist[page: pageTransfer], nextBandlist: BansheeSequence.GetBandlist[ MIN[BansheeSequence.pageCount - 1, pageTransfer + 1]]]; BansheeControl.BandBLTTransferReady[]; -- signal that bands are ready END; transferIsReady _ TRUE; -- insurance if transferReady event missed in page printing loop ENDLOOP; END; -- HandleTransfer Print mainline code wait till a "request" is made to start a job "Flush" the printer with a blank sheet to complete previous unfinished imaging reset counters to new starting page set up bandBLTTable and make bandlists and fontloads for first page resident BandBLTTransfer.Set[ transfer: jobInternal.document, bandlist: RavenSequence.GetBandlist[page: pageTransfer], nextBandlist: RavenSequence.GetBandlist[ page: MIN[RavenSequence.pageCount - 1, pageTransfer + 1]]]; BansheeControl.BandBLTTransferReady[]; transferProcess _ FORK HandleTransfer[]; JOIN transferProcess; BandBLTTransfer.Resset[]; Κ z˜codešΟi™KšA™AKš&™&K™.K˜—šΟk ˜ šœžœΟc5œ­˜ψK˜=—Kšœžœ˜.KšœžœŸœ˜8Kšœžœ˜Kšœ žœ ˜Kšœ žœ˜Kšœ žœ ˜Kšœžœ˜KšœžœU˜bKšœžœ2˜>K˜KšΟnœžœž˜ Kšžœ;˜BKšžœž˜K˜K˜Kšœžœ˜*K˜K˜Kšœžœžœž œ˜7K˜K˜KšœžœžœŸF˜pK˜K˜%Kšœžœžœ˜=Kšœ2žœ˜;K˜7K˜K˜Kš  œžœž œžœ*žœ˜LK˜K˜Kš œžœž œ2žœžœ žœ žœ˜“K˜K˜Kš  œžœž œžœ žœž˜DKšžœ žœ&žœ˜PKšžœ;˜BKšžœŸ˜K˜K˜š   œžœž œžœ!ž˜Lšžœžœ!ž˜2K˜#K˜!K˜K˜#Kšœ?Ÿ ˜IK˜=Kšžœžœ˜KšžœŸ˜K˜——K˜š  œžœž œžœž˜NKšžœ.˜4KšžœŸ˜K˜—K˜š   œžœž œžœ ž˜Hšžœžœžœž˜>Kšœ8Ÿ˜K—šœ žœž˜'K˜ K˜K˜K˜K˜)K˜K˜K˜!K˜+K˜K˜K˜K˜!K˜!K˜K˜)K˜K˜K˜K˜Kšžœžœ˜KšžœŸ ˜——K˜K˜Kš   œžœž œ3žœžœž˜g˜Kšœ™K˜3K˜5K˜Kšœ ™ K˜AK˜?K˜Kšœ™KšœCžœ˜IK˜Kšœ™Kšœžœ Ÿ˜:K˜KšžœŸ ˜—K˜K˜š œžœž œ"ž˜?K˜KšžœŸ ˜—K˜K˜š œžœž œž˜FKšœ™K˜0KšžœŸ˜—K˜K˜š œžœž œ0žœ˜[Kšžœž˜+Kšœa™aKšžœd˜jKšžœŸ˜K˜—K˜š   œžœž œžœ ž˜IKšœ(žœžœŸ ˜P—K˜K˜š œžœž œ˜@Kšžœ˜&—Kšžœžœžœ˜.K˜K˜š œžœž œ!˜Gšœžœ˜Kšœž œžœ˜C——K˜K˜š œžœž œ˜Bšœ.žœ˜6Kšžœž˜+—Kšœ<™Kšžœ!™%—Kšœ#žœ™(Kšžœžœ™KšŸN™NKšžœ+žœžœ™7šžœž™Kšž™šœ™K™:K™?—Kšœ5žœŸ™RKšœŸ*™DKšœ#Ÿ™?Kšœžœ™Kšž™—šž ™ ™K™:K™*Kšžœ4™7—Kšœ(Ÿ™FKšžœ™——KšœžœŸ@™YKšžœ™—KšžœŸ™—˜K™K˜0šžœŸ ˜K˜4K˜7Kšœ,™,KšœKžœ˜QKš žœžœ"žœžœ+žœžœ˜g—K˜KšœžœŸ1˜LšžœŸ˜K˜IKš žœGžœžœžœŸ˜vK˜5KšžœžœžœŸ+˜‚——˜šžœ"ž˜,KšœžœŸ ˜,šœžœž˜9˜;KšœN™N—Kšœ'˜'šžœŸ˜šžœ@ž˜JKšœ:žœŸ˜SKšžœžœŸ˜*—KšžœŸ˜ —šžœ"žœž˜Gšœ&ž˜*Kšœ4Ÿ(˜\——K˜KšžœŸ˜&Kšžœ˜—Kšžœžœ+žœžœ˜E—K˜K˜DK™K™#K˜DK˜Kšœžœ˜KšœL™L™K™K™8K™(Kšœžœ2™;—Kšœ!Ÿ)œ˜KKšœ&™&K˜Kšœ2Ÿ˜BK™Kšœžœ™(K™Kšœžœ˜K˜Kšœ0Ÿ˜DKšœ žœ˜K˜IK˜'šžœŸ˜šžœ@ž˜JKšœž˜Kšœ žœ˜Kšžœžœžœžœžœžœžœ˜Lšœ ž˜K˜Kšœžœ˜Kš œžœžœžœžœžœžœ˜l—Kšœž˜Kšœžœ˜Kšžœžœžœžœ žœžœžœžœ˜JKšœ žœ˜Kšœž˜Kš žœ#žœžœ+žœžœžœ˜kKšžœ˜šœž˜K˜šžœžœžœŸ/˜JKšœ#žœ˜(—Kšžœ˜Kšžœ˜—šœž˜K˜"Kšžœ8žœžœ˜DKš žœžœ(žœžœžœ˜bKš žœžœžœžœŸ˜BKšžœ˜—šœ ž˜Kšžœžœ žœŸ$˜=KšœŸ?˜Y—šœžœ˜Kš žœžœžœžœžœ˜2Kšžœ˜—šœ ž˜Kšœžœ˜Kš žœžœžœžœžœ˜1Kšžœ˜—š œ žœžœžœžœ˜1Kš œ žœ žœ+žœ'žœžœŸ9˜΄š žœžœžœžœžœŸ%˜MKšžœžœ˜—Kšžœ2žœ'žœž˜h—Kšœ!Ÿ1œ˜SKšœ žœ˜K˜'Kšžœ˜—KšžœŸ˜—˜K˜0Kšžœ"žœžœ'ž˜rKšœ4Ÿ(˜\K˜Kšžœ™Kšœ!˜!K™Kšžœ7žœžœ˜CKšžœŸ˜—KšžœŸ ˜—šžœŸ˜K˜—Kšžœ˜K˜Kšž˜K˜K˜,K˜>K˜>K˜wK˜ΒK˜οK˜‚K˜ΖK˜λK˜[K˜VK˜RK˜{K˜JK˜^Kšœ@žœ{˜ΏK˜’K˜uJ˜—J˜J˜—…—5Lά