DIRECTORY Arpa USING [Address], ArpaIP USING [AllocBuffers, Buffers, ChecksumProc, Error, FreeBuffers, GetUserBytes, SetUserBytes, Send], List USING [Nconc1], ArpaTCP USING [Error, Port], ArpaTCPLogging USING [PrintTCPPacket], ArpaTCPOps USING [Buffer, Flip, Flop, InitialTimeoutFromHandle, maxRTT, minRTT, pktsRexmitted, pktsSent, repacketizing, RexmitIntervalFromHandle, RexmitTimeoutFromHandle, sendBufferLength, SetTimeout, TCPChecksum, TCPControlSet, TCPHandle, tcpHdrByteLength, tcpHdrWordLength, TCPHeaderP, tcpIPHandle, TCPSendBuffer], ArpaTCPTransmit, BasicTime USING [GetClockPulses, PulsesToMicroseconds]; ArpaTCPTransmitImpl: CEDAR PROGRAM IMPORTS ArpaIP, List, ArpaTCP, ArpaTCPLogging, ArpaTCPOps, BasicTime EXPORTS ArpaTCPTransmit = BEGIN OPEN ArpaTCPOps, ArpaTCPTransmit; TCPSend: PROC [data: ArpaIP.Buffers, sourcePort, dstnPort: ArpaTCP.Port, dstn: Arpa.Address] ~ { TRUSTED { tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@data.body]; tcpHdrPtr.sourcePort _ sourcePort; tcpHdrPtr.dstnPort _ dstnPort; tcpHdrPtr.unused _ 0; tcpHdrPtr.dataWordOffset _ tcpHdrWordLength; }; pktsSent _ pktsSent + 1; [] _ ArpaIP.Send[ArpaTCPOps.tcpIPHandle, data, dstn, TCPChecksumCallback ! ArpaIP.Error => CONTINUE]; }; TCPChecksumCallback: ArpaIP.ChecksumProc ~ TRUSTED { tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@b.body]; tcpHdrPtr.checksum _ TCPChecksum[b]; }; SendSegmentToNet: PROC [handle: TCPHandle, sendDatagram: ArpaIP.Buffers, dataSegment: BOOL] ~ TRUSTED { bodyBytes: CARDINAL _ ArpaIP.GetUserBytes[sendDatagram].bodyBytes - tcpHdrByteLength; tcpHdrPtr: TCPHeaderP; -- TCP header to send tcpSendBufferPtr: REF TCPSendBuffer; -- information about sent segment tcpHdrPtr _ LOOPHOLE[@sendDatagram.body]; tcpHdrPtr.seqNumber _ Flop[handle.sndNxt]; -- set sequence number tcpHdrPtr.window _ handle.rcvWnd; -- send latest window handle.zeroRcvWnd _ handle.rcvWnd = 0; IF ~(handle.state = listen OR handle.state = synSent) THEN { -- if in synced state tcpHdrPtr.ack _ TRUE; -- send ack tcpHdrPtr.ackNumber _ Flop[handle.rcvNxt]; } ELSE { tcpHdrPtr.ack _ FALSE; tcpHdrPtr.ackNumber _ Flop[0]; }; handle.sndNxt _ handle.sndNxt + bodyBytes; IF tcpHdrPtr.syn THEN -- adjust seq number for SYN and FIN handle.sndNxt _ handle.sndNxt + 1; IF tcpHdrPtr.fin THEN { handle.sndNxt _ handle.sndNxt + 1; handle.finSequence _ Flip[tcpHdrPtr.seqNumber]; }; IF handle.sndUrgent THEN { tcpHdrPtr.urg _ TRUE; tcpHdrPtr.urgentPtr _ handle.sndUp - handle.sndNxt; } ELSE { tcpHdrPtr.urg _ FALSE; tcpHdrPtr.urgentPtr _ 0; }; TCPSend[sendDatagram, handle.localPort, handle.foreignPort, handle.foreignAddr]; ArpaTCPLogging.PrintTCPPacket[handle, sendDatagram, toNet]; IF dataSegment THEN { -- if didn't send ack alone IF bodyBytes#0 OR tcpHdrPtr.fin OR tcpHdrPtr.syn THEN { tcpSendBufferPtr _ NEW[TCPSendBuffer]; tcpSendBufferPtr.dataByteCount _ bodyBytes; tcpSendBufferPtr.datagram _ sendDatagram; IF (tcpSendBufferPtr.xmitTime _ BasicTime.GetClockPulses[]) = 0 THEN tcpSendBufferPtr.xmitTime _ 1; tcpSendBufferPtr.rexmitTime _ SetTimeout[RexmitIntervalFromHandle[handle]]; tcpSendBufferPtr.timeoutTime _ IF tcpHdrPtr.syn THEN SetTimeout[InitialTimeoutFromHandle[handle]] ELSE SetTimeout[RexmitTimeoutFromHandle[handle]]; handle.rexmitQueue _ List.Nconc1[handle.rexmitQueue, tcpSendBufferPtr]; }; }; }; -- SendSegmentToNet TryToSend: PUBLIC PROC [handle: TCPHandle] = { sendDatagram: ArpaIP.Buffers; -- datagram to send sendData: BOOL; -- set if sending data, not ack only IF handle.state = listen OR handle.state = synSent THEN -- if in unsynced state RETURN WITH ERROR ArpaTCP.Error[handle.reason]; -- Trying to send data in unsynced state IF handle.sndWnd = 0 THEN-- in synced state, if send window is zero IF handle.rexmitQueue = NIL THEN sendData _ TRUE -- if no pkts sent, send pkt to probe window ELSE sendData _ FALSE -- if pkts sent and unacked, send ack ELSE IF handle.sndNxt >= handle.sndUna + handle.sndWnd THEN sendData _ FALSE -- if non-zero window is full, send ack ELSE sendData _ TRUE; -- else send data IF -- if can send data, but no data to send sendData AND handle.toNetQueue = NIL THEN sendData _ FALSE; -- just send an ack IF NOT sendData THEN TRUSTED { -- if sending only an ack tcpHdrPtr: TCPHeaderP; -- TCP header to send sendDatagram _ ArpaIP.AllocBuffers[1]; tcpHdrPtr _ LOOPHOLE[@sendDatagram.body]; tcpHdrPtr.psh _ FALSE; tcpHdrPtr.syn _ FALSE; tcpHdrPtr.fin _ FALSE; tcpHdrPtr.rst _ FALSE; IF handle.sndUrgent THEN { tcpHdrPtr.urg _ TRUE; tcpHdrPtr.urgentPtr _ handle.sndUp - handle.sndNxt; } ELSE { tcpHdrPtr.urg _ FALSE; tcpHdrPtr.urgentPtr _ 0; }; ArpaIP.SetUserBytes[sendDatagram, tcpHdrByteLength+0]; SendSegmentToNet[handle, sendDatagram, FALSE]; -- send to net ArpaIP.FreeBuffers[sendDatagram]; RETURN; -- finished trying to send }; DO -- send data until send window is full or no more data to send IF handle.toNetQueue = NIL THEN RETURN; -- out of data TRUSTED{sendDatagram _ LOOPHOLE[handle.toNetQueue.first]}; handle.toNetQueue _ handle.toNetQueue.rest; SendSegmentToNet[handle, sendDatagram, TRUE]; -- send segment to net IF handle.sndNxt >= handle.sndUna + handle.sndWnd THEN EXIT ENDLOOP }; -- TryToSend TryToSendData: PUBLIC PROC [handle: TCPHandle] = { sendData: BOOL; IF handle.state = listen OR handle.state = synSent THEN -- if in unsynced state RETURN WITH ERROR ArpaTCP.Error[handle.reason]; -- Trying to send data in unsynced state IF handle.sndWnd = 0 THEN -- if send window is zero IF handle.rexmitQueue = NIL THEN sendData _ TRUE -- if no pkts sent, send pkt to probe window ELSE sendData _ FALSE -- if pkts sent and unacked, send ack ELSE IF handle.sndNxt >= handle.sndUna + handle.sndWnd THEN sendData _ FALSE -- if non-zero window is full, send ack ELSE sendData _ TRUE; -- else send data IF sendData AND handle.toNetQueue # NIL THEN -- if allowed to send data and data to send TryToSend[handle] -- then send it }; -- TryToSendData SendSegment: PUBLIC PROC [handle: TCPHandle, sendDatagram: Buffer, dataByteCount: INT, ctl: TCPControlSet] ~ TRUSTED { tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@sendDatagram.body]; IF repacketizing THEN { -- if repacketizing data then copy data to TCP buffer FOR i: INT IN [tcpHdrPtr.dataWordOffset*4..tcpHdrPtr.dataWordOffset*4+dataByteCount) DO handle.sendBuffer[handle.fillSlot] _ sendDatagram.body.bytes[i]; handle.fillSlot _ (handle.fillSlot + 1) MOD sendBufferLength; ENDLOOP; }; IF ctl.urg THEN { -- fill in urgent control and pointer tcpHdrPtr.urg _ TRUE; tcpHdrPtr.urgentPtr _ dataByteCount } ELSE { tcpHdrPtr.urg _ FALSE; tcpHdrPtr.urgentPtr _ 0; }; tcpHdrPtr.psh _ ctl.psh; tcpHdrPtr.ack _ FALSE; tcpHdrPtr.rst _ FALSE; tcpHdrPtr.syn _ FALSE; tcpHdrPtr.fin _ FALSE; tcpHdrPtr.checksum _ 0; ArpaIP.SetUserBytes[sendDatagram, tcpHdrByteLength+dataByteCount]; -- set data length handle.nBytesToSend _ handle.nBytesToSend + dataByteCount; handle.toNetQueue _ List.Nconc1[handle.toNetQueue, sendDatagram]; -- put buffer on queue to send IF handle.state = established OR handle.state = closeWait THEN TryToSendData[handle]; -- send it if window permits }; -- SendSegment SendSYN: PUBLIC PROC [handle: TCPHandle] = TRUSTED { sendDatagram: ArpaIP.Buffers _ ArpaIP.AllocBuffers[1]; tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@sendDatagram.body]; tcpHdrPtr.urg _ FALSE; tcpHdrPtr.urgentPtr _ 0; tcpHdrPtr.psh _ FALSE; tcpHdrPtr.rst _ FALSE; tcpHdrPtr.syn _ FALSE; tcpHdrPtr.fin _ FALSE; tcpHdrPtr.ack _ FALSE; ArpaIP.SetUserBytes[sendDatagram, tcpHdrByteLength+0]; -- set data length tcpHdrPtr.syn _ TRUE; tcpHdrPtr.seqNumber _ Flop[handle.iss]; handle.sndNxt _ handle.iss; SendSegmentToNet[handle, sendDatagram, TRUE]; }; SendFIN: PUBLIC PROC [handle: TCPHandle] = TRUSTED { sendDatagram: ArpaIP.Buffers _ ArpaIP.AllocBuffers[1]; tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@sendDatagram.body]; tcpHdrPtr.urg _ FALSE; tcpHdrPtr.urgentPtr _ 0; tcpHdrPtr.psh _ FALSE; tcpHdrPtr.rst _ FALSE; tcpHdrPtr.syn _ FALSE; tcpHdrPtr.fin _ TRUE; tcpHdrPtr.ack _ FALSE; ArpaIP.SetUserBytes[sendDatagram, tcpHdrByteLength+0]; handle.toNetQueue _ List.Nconc1[handle.toNetQueue, sendDatagram]; TryToSend[handle] -- try to send data and fin on to net queue }; -- SendFIN SendReset: PUBLIC PROC [handle: TCPHandle, sourcePort, dstnPort: ArpaTCP.Port, Dstn: Arpa.Address, seq, ack: INT] = TRUSTED { sendDatagram: ArpaIP.Buffers; -- segment to send tcpHdrPtr: TCPHeaderP; -- header to send sendDatagram _ ArpaIP.AllocBuffers[1]; ArpaIP.SetUserBytes[sendDatagram, tcpHdrByteLength+0]; tcpHdrPtr _ LOOPHOLE[@sendDatagram.body]; tcpHdrPtr.sourcePort _ sourcePort; tcpHdrPtr.dstnPort _ dstnPort; tcpHdrPtr.seqNumber _ Flop[seq]; tcpHdrPtr.ackNumber _ Flop[ack]; tcpHdrPtr.urg _ FALSE; tcpHdrPtr.psh _ FALSE; tcpHdrPtr.syn _ FALSE; tcpHdrPtr.fin _ FALSE; tcpHdrPtr.rst _ TRUE; IF ack # 0 THEN tcpHdrPtr.ack _ TRUE ELSE tcpHdrPtr.ack _ FALSE; tcpHdrPtr.window _ 0; tcpHdrPtr.checksum _ 0; tcpHdrPtr.urgentPtr _ 0; TCPSend[sendDatagram, sourcePort, dstnPort, Dstn]; ArpaTCPLogging.PrintTCPPacket[handle, sendDatagram, toNet]; ArpaIP.FreeBuffers[sendDatagram]; }; -- SendReset RemoveAckedSegments: PUBLIC PROC [handle: TCPHandle] ~ TRUSTED { IF handle.sndUna >= handle.sndUp THEN { handle.sndUrgent _ FALSE; handle.sndUp _ 0; }; WHILE handle.rexmitQueue # NIL DO tcpSendBufferPtr: REF TCPSendBuffer _ NARROW[handle.rexmitQueue.first]; tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@tcpSendBufferPtr.datagram.body]; lastSeqNumber: INT _ Flip[tcpHdrPtr.seqNumber] + tcpSendBufferPtr.dataByteCount - 1; IF tcpHdrPtr.syn THEN lastSeqNumber _ lastSeqNumber + 1; IF tcpHdrPtr.fin THEN lastSeqNumber _ lastSeqNumber + 1; IF handle.sndUna > lastSeqNumber THEN { beNiceToGC: LIST OF REF ANY _ handle.rexmitQueue; IF tcpSendBufferPtr.xmitTime # 0 THEN { delta: CARD; sampleRTT: INT; delta _ BasicTime.GetClockPulses[] - tcpSendBufferPtr.xmitTime; sampleRTT _ BasicTime.PulsesToMicroseconds[delta] / 1000; sampleRTT _ MIN[MAX[minRTT, sampleRTT], maxRTT]; handle.rtt _ (7*handle.rtt + sampleRTT)/8; }; ArpaIP.FreeBuffers[tcpSendBufferPtr.datagram]; handle.rexmitQueue _ handle.rexmitQueue.rest; beNiceToGC.first _ NIL; beNiceToGC.rest _ NIL; } ELSE RETURN; -- segment at head of queue not acked ENDLOOP; }; -- RemoveAckedSegments RepacketizeandRexmit: PUBLIC PROC [handle: TCPHandle, tcpSendBufferPtr: REF TCPSendBuffer] ~ TRUSTED { sendDatagram: ArpaIP.Buffers; tcpHdrPtr: TCPHeaderP; i, j: INT; bytesToSend: INT; bytesRexmitted: INT; tcpSendBufferPtr.xmitTime _ 0; tcpSendBufferPtr.rexmitTime _ SetTimeout[RexmitIntervalFromHandle[handle]]; IF handle.state = synSent OR handle.state = synRcvd THEN { sendDatagram _ tcpSendBufferPtr.datagram; pktsRexmitted _ pktsRexmitted + 1; handle.rexmits _ handle.rexmits + 1; tcpHdrPtr _ LOOPHOLE[@sendDatagram.body]; IF NOT (handle.state = listen OR handle.state = synSent) THEN IF NOT tcpHdrPtr.ack OR Flip[tcpHdrPtr.ackNumber] # handle.rcvNxt THEN { tcpHdrPtr.ack _ TRUE; tcpHdrPtr.ackNumber _ Flop[handle.rcvNxt]; }; TCPSend[sendDatagram, handle.localPort, handle.foreignPort, handle.foreignAddr]; ArpaTCPLogging.PrintTCPPacket[handle, sendDatagram, rexmitToNet]; RETURN }; IF handle.nBytesToSend = 0 AND NOT (SELECT handle.state FROM finWait1, closing, lastAck => TRUE ENDCASE => FALSE) THEN RETURN; -- if no data or fin to send, then exit bytesToSend _ handle.nBytesToSend; j _ handle.sendSlot; bytesRexmitted _ 0; sendDatagram _ ArpaIP.AllocBuffers[1]; DO -- allocate buffers to send and fill them i _ 0; WHILE i # bytesToSend AND i # handle.maxSegmentSize DO sendDatagram.body.bytes[i+tcpHdrByteLength] _ handle.sendBuffer[j]; j _ (j + 1) MOD sendBufferLength; i _ i + 1 ENDLOOP; bytesToSend _ bytesToSend - i; tcpHdrPtr _ LOOPHOLE[@sendDatagram.body]; tcpHdrPtr.urg _ FALSE; tcpHdrPtr.urgentPtr _ 0; tcpHdrPtr.psh _ FALSE; tcpHdrPtr.rst _ FALSE; tcpHdrPtr.syn _ FALSE; IF handle.sndUna + i = handle.finSequence THEN tcpHdrPtr.fin _ TRUE ELSE tcpHdrPtr.fin _ FALSE; tcpHdrPtr.checksum _ 0; ArpaIP.SetUserBytes[sendDatagram, tcpHdrByteLength+i]; -- set data length tcpHdrPtr.seqNumber _ Flop[handle.sndUna + bytesRexmitted]; bytesRexmitted _ bytesRexmitted + i; -- to calculate sequence numbers tcpHdrPtr.window _ handle.rcvWnd; -- send latest window handle.zeroRcvWnd _ handle.rcvWnd = 0; tcpHdrPtr.ack _ TRUE; tcpHdrPtr.ackNumber _ Flop[handle.rcvNxt]; pktsRexmitted _ pktsRexmitted + 1; handle.rexmits _ handle.rexmits + 1; TCPSend[sendDatagram, handle.localPort, handle.foreignPort, handle.foreignAddr]; ArpaTCPLogging.PrintTCPPacket[handle, sendDatagram, rexmitToNet]; IF bytesToSend = 0 THEN EXIT ENDLOOP; -- end filling send buffers ArpaIP.FreeBuffers[sendDatagram]; }; -- RepacketizeandRexmit Rexmit: PUBLIC PROC [handle: TCPHandle, tcpSendBufferPtr: REF TCPSendBuffer] ~ TRUSTED { sendDatagram: ArpaIP.Buffers; tcpHdrPtr: TCPHeaderP; tcpSendBufferPtr.xmitTime _ 0; tcpSendBufferPtr.rexmitTime _ SetTimeout[RexmitIntervalFromHandle[handle]]; sendDatagram _ tcpSendBufferPtr.datagram; pktsRexmitted _ pktsRexmitted + 1; handle.rexmits _ handle.rexmits + 1; tcpHdrPtr _ LOOPHOLE[@sendDatagram.body]; IF NOT (handle.state = listen OR handle.state = synSent) THEN -- update ack field IF NOT tcpHdrPtr.ack OR Flip[tcpHdrPtr.ackNumber] # handle.rcvNxt THEN { tcpHdrPtr.ack _ TRUE; tcpHdrPtr.ackNumber _ Flop[handle.rcvNxt]; }; TCPSend[sendDatagram, handle.localPort, handle.foreignPort, handle.foreignAddr]; ArpaTCPLogging.PrintTCPPacket[handle, sendDatagram, rexmitToNet]; }; END. ΤArpaTCPTransmitImpl.mesa Copyright (C) 1983, 1985 by Xerox Corporation. All rights reserved. The following program was created in 1983 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license. Last Edited by: Nichols, August 25, 1983 4:37 pm Last Edited by: Taft, January 4, 1984 12:01 pm Last Edited by: HGM, April 18, 1985 11:07:00 pm PST Demers, September 7, 1988 1:51:50 pm PDT Carl Hauser, April 22, 1988 4:51:51 pm PDT Doug Terry, April 27, 1988 5:09:46 pm PDT Hal Murray June 3, 1985 10:05:37 pm PDT John Larson, April 14, 1986 11:30:03 pm PST Fill in the header and miscellaneous stuff in the datagram and send it. ArpaIP fills in the IP header and uses a callback to compute the TCP checksum afterwards. tcpHdrPtr.checksum _ TCPChecksum[data]; -- computed later via TCPChecksumCallback Procedure to send data, control or ack only segments to network. The dataSegment argument should be set if there is control or data in the segment which should be acked, i.e. if it is not an ack only segment. If the dataSegment argument is set, the packet is put on the rexmit queue for the connection. common code for sending data or ack only segments update next seq number to send then put entry on rexmit queue dataSegment may lie. Check it out. -- CHH Called to send as much data as possible from the ToNet queue. Checks window to determine if data can be sent; if data can not be sent, sends an ack only segment. Calls SendSegmentToNet to actually send the data. allocate new buffer for ack and fill in header sendDatagram _ NARROW[handle.toNetQueue.first]; Called to determine if data can be sent; if so, it calls TryToSend. This routine is called when you want to send a segment if and only if data exists; thus it is called when an empty ack packet has been received and more data may be sent or when the user supplies more data to send via the TCPSend routine. TryToSend can't be called directly because it always generates an ack and we don't need acks for the acks. This function is called when there is data from the user to send. It fills in the TCP header, queues the packet on the TCB ToNet queue and if the connection is in a state in which data can be sent, it calls TryToSendData to try to send the data. The caller must ensure that the packet fits in the current TCP send window. byte following end of packet This procedure allocates a segment to send a SYN. It calls SendSegmentToNet to send the SYN segment. This procedure allocates a segment to send a FIN, queues it on the end of the ToNet queue and then calls TryToSend to send any data on the ToNet queue and the FIN. This procedure is called to send a reset; it sends directly to the network by calling the TCPSend routine; it does not use the TryToSend or SendSegmentToNet routines because resets can be sent when no TCB exists. sendDatagram.inHdr.destination _ Dstn; If not resent (so this is a valid sample) then update round-trip-time estimate in handle.rtt ... This procedure is called to repacketize and retransmit data on the retransmit queue. It is called from CheckRexmitQueues when repacketizing is enabled. if syn unacked, just rexmit users's packet fill send buffer until all bytes are sent or send buffer is full send the segment to the internet This procedure is called to retransmit a segment on the retransmit queue when Repacketizing is not enabled. It is called from CheckRexmitQueues. Κ@– "cedar" style˜head™Icode2šœ―™―J™0J™.J™3Icode™(M™*M™)J™'M™+J™šΟk ˜ Lšœœ ˜Lšœœ]˜iLšœœ ˜Lšœœ˜Lšœœ˜&Lšœ œ¬˜ΌL˜Lšœ œ(˜7——šœœ˜"Lšœ=˜DLšœ˜Lš˜Lšœ˜!šΟnœœS˜`Lšœ’™’L˜šœ˜ Lšœœ ˜-Lšœ"˜"Lšœ˜L˜Lšœ,˜,LšœR™RL˜—Lšœ˜Lšœ[œ˜fLšœ˜L˜—šžœœ˜4Lšœœ ˜*L˜%M˜—šžœœ@œœ˜gLšœ―™―Lšœ  œ?˜ULšœΟc˜-LšœœŸ"˜GL˜Lšœ2™2Lšœ œ˜)Lšœ+Ÿ˜BLšœ"Ÿ˜8Lšœœ œ˜'šœœœŸ˜RLšœœŸ ˜!Lšœ-˜-—šœ˜Lšœœ˜Lšœ"˜"—Lšœ™Lšœ+˜+šœœŸ%˜;Lšœ#˜#—šœœ˜Lšœ#˜#Lšœ2˜2—šœœ˜Lšœœ˜L˜5—šœ˜Lšœœ˜L˜—LšœP˜PL˜;šœ œŸ˜2Lšœ™Lšœ*™*šœ œœœ˜7Lšœœ˜'Lšœ,˜,Lšœ)˜)Lšœ>œ˜cLšœK˜Kšœ˜šœ˜Lšœ-˜1Lšœ-˜1——LšœJ˜J—L˜—LšœŸ˜—šž œœœ˜.LšœΤ™ΤLšœŸ˜2Lšœ œŸ%˜5L˜šœœŸ˜PLšœœœŸ(˜XL˜—šœŸ+˜DLš œœœ œŸ-˜^Lšœ œŸ&˜<—šœ˜Lšœ0œ œŸ(˜pLšœ œŸ˜(—šœŸ)˜,Lšœ œœœ˜*Lšœ œŸ˜&—š œœ œœŸ˜9Lšœ/™/LšœŸ˜-Lšœ'˜'Lšœ œ˜*Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜šœœ˜Lšœœ˜L˜5—šœ˜Lšœœ˜L˜—Lšœ6˜6Lšœ'œŸ˜>Lšœ!˜!LšœŸ˜"L˜—šœŸ?˜BLšœœ œŸ˜6Lšœœ™/Lšœœ˜:L˜+Lšœ'œŸ˜ELšœ0œ˜;Lš˜—LšœŸ ˜—šž œœœ˜2Lšœž™žLšœ œ˜L˜šœœŸ˜PLšœœœŸ(˜XL˜—šœŸ˜4Lš œœœ œŸ-˜^Lšœ œŸ&˜<—šœ˜Lšœ0œ œŸ(˜pLšœ œŸ˜(—š œ œœœŸ+˜XLšœŸ˜"—LšœŸ˜—š ž œœœ:œœ˜vLšœSœ"œΘ™ΓLšœœ˜5šœœŸ5˜MšœœœH˜WLšœA˜ALšœ(œ˜>Lšœ˜—Lšœ˜—šœ ˜ šœŸ%˜,Lšœœ˜Lšœ#˜#Lšœ˜Lšœ™—šœ˜Lšœœ˜Lšœ˜L˜——Lšœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœ˜LšœCŸ˜VLšœ;˜;LšœBŸ˜ašœœ˜>LšœŸ˜4—LšœŸ˜—šžœœœœ˜4Lšœe™eLšœ6Ÿ˜7Lšœœ˜5Lšœœ˜Lšœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœ7Ÿ˜JLšœœ˜Lšœ(˜(Lšœ˜Lšœ'œŸ˜1—šžœœœœ˜4Lšœ€™€Lšœ6Ÿ˜7Lšœœ˜5Lšœœ˜Lšœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœ6˜6L˜ALšœŸ+˜=LšœŸ ˜—š ž œœœWœœ˜}LšœΥ™ΥLšœŸ˜1LšœŸ˜)L˜Lšœ'˜'Lšœ6˜6L™&Lšœ œ˜)Lšœ"˜"Lšœ˜Lšœ!˜!Lšœ!˜!Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœ œœ˜%Lšœœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ2˜2L˜;Lšœ!˜!LšœŸ ˜—šžœœœœ˜@šœœ˜'Lšœœ˜L˜—šœœ˜!Lšœœœ˜GLšœœ#˜CLšœœC˜ULšœœ$˜9Lšœœ$˜9šœ˜'Lš œ œœœœ˜1™`šœœ˜'Lšœœ˜ Lšœ œ˜Lšœ?˜?Lšœ9˜9Lšœ œœ˜0Lšœ*˜*Lšœ˜——Lšœ.˜.Lšœ-˜-Lšœœ˜Lšœœ˜—LšœœŸ%˜2LšŸ˜ —LšœŸ˜—š žœœœ'œœ˜fLšœ˜™˜Lšœ˜Lšœ˜Lšœœ˜ Lšœ œ˜Lšœœ˜L˜Lšœ˜šœK˜KL˜—šœœœ˜:L™*Lšœ*˜*Lšœ#˜#Lšœ%˜%Lšœ œ˜*šœœœ˜=šœœœ+œ˜HLšœœ˜Lšœ-˜-——LšœP˜PLšœB˜BLšœŸ˜ —šœœ˜šœœœ˜Lšœ˜"Lšœœœ˜—LšœŸ(˜0—Lšœ#˜#Lšœ˜Lšœ˜Lšœ'˜'šœŸ*˜-Lšœ˜LšœA™Ašœœœ˜7LšœD˜DLšœ œ˜"Lšœ ˜ Lšœ˜ —Lšœ˜Lšœ œ˜*Lšœœ˜Lšœ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœ(œœ˜DLšœœ˜Lšœ˜Lšœ7Ÿ˜JLšœ<˜