diff --git a/Makefile b/Makefile index 29eb5856..eaa08f74 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ MISSION_PATH = mission CONFIG_PATH = fsfwconfig TEST_PATH = test UNITTEST_PATH = unittest -GOMSPACE_PATH = gomspace +LIBCSP_PATH = libcsp # Board specific paths BSP_PATH = $(BOARD_FILE_ROOT) @@ -114,7 +114,7 @@ INCLUDES := # Directories where $(directoryname).mk files should be included from SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(BSP_PATH) $(UNITTEST_PATH)\ - $(CONFIG_PATH) $(MISSION_PATH) $(GOMSPACE_PATH) + $(CONFIG_PATH) $(MISSION_PATH) $(LIBCSP_PATH) # INCLUDES += framework/test/catch2 # ETL library include. diff --git a/README.md b/README.md index 71f7860e..f4d5c5f5 100644 --- a/README.md +++ b/README.md @@ -323,3 +323,28 @@ git merge upstream/master Alternatively, changes from other upstreams (forks) and branches can be merged like that in the same way. + +## PCDU +Connect to serial console of P60 Dock +```` +picocom -b 500000 /dev/ttyUSBx +```` +General information +```` +cmp ident +```` +List parameter table: +x values: 1,2 or 4 +```` +param table x +```` +Table 4 lists HK parameters +Changing parameters +First switch to table where parameter shall be changed (here table id is 1) +```` +p60-dock # param mem 1 +p60-dock # param set out_en[0] 1 +p60-dock # param get out_en[0] +GET out_en[0] = 1 +```` + diff --git a/bsp_linux/InitMission.cpp b/bsp_linux/InitMission.cpp index 92cd0853..0243c788 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_linux/InitMission.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -129,6 +130,23 @@ void InitMission::initTasks(){ sif::error << "Object add component failed" << std::endl; } +// PeriodicTaskIF* P60DockTask = TaskFactory::instance()-> +// createPeriodicTask("P60Dock Task", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE*4, +// 1.6, nullptr); +// result = P60DockTask->addComponent(objects::P60DOCK_HANDLER); +// if(result!=HasReturnvaluesIF::RETURN_OK){ +// sif::error << "Object add component failed" << std::endl; +// } + + FixedTimeslotTaskIF* GomSpacePstTask = TaskFactory::instance()-> + createFixedTimeslotTask("GS_PST_TASK", 50, + PeriodicTaskIF::MINIMUM_STACK_SIZE*4, 1.0, nullptr); + result = pst::gomspacePstInit(GomSpacePstTask); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "InitMission::initTasks: GomSpace PST initialization " + << "failed!" << std::endl; +} + #if ADD_TEST_CODE == 1 // FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> @@ -140,13 +158,6 @@ void InitMission::initTasks(){ // << "failed!" << std::endl; // } - PeriodicTaskIF* P60DockTestTask = - TaskFactory::instance()->createPeriodicTask("P60 Dock", 50, - PeriodicTaskIF::MINIMUM_STACK_SIZE, 1, nullptr); - result = PusLowPrio->addComponent(objects::P60DOCK_TEST_TASK); - if(result!=HasReturnvaluesIF::RETURN_OK){ - sif::error << "Object add component failed" << std::endl; - } #endif //Main thread sleep @@ -155,15 +166,18 @@ void InitMission::initTasks(){ UdpBridgeTask->startTask(); UdpPollingTask->startTask(); + GomSpacePstTask->startTask(); + PusVerification->startTask(); PusEvents->startTask(); PusHighPrio->startTask(); PusMedPrio->startTask(); PusLowPrio->startTask(); + +// P60DockTask->startTask(); + #if ADD_TEST_CODE == 1 // TestTimeslotTask->startTask(); - P60DockTestTask->startTask(); - #endif sif::info << "Tasks started.." << std::endl; } diff --git a/bsp_linux/bsp_linux.mk b/bsp_linux/bsp_linux.mk index f7f9a469..93bfdc78 100644 --- a/bsp_linux/bsp_linux.mk +++ b/bsp_linux/bsp_linux.mk @@ -1,4 +1,6 @@ CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/comIF/cookies/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/comIF/*.cpp) CSRC += $(wildcard $(CURRENTPATH)/*.c) CSRC += $(wildcard $(CURRENTPATH)/boardconfig/*.c) \ No newline at end of file diff --git a/bsp_linux/comIF/ArduinoComIF.cpp b/bsp_linux/comIF/ArduinoComIF.cpp deleted file mode 100644 index ffc59b47..00000000 --- a/bsp_linux/comIF/ArduinoComIF.cpp +++ /dev/null @@ -1,324 +0,0 @@ -#include "ArduinoCookie.h" -#include "ArduinoComIF.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -ArduinoCommInterface::ArduinoCommInterface(object_id_t setObjectId, - const char *serialDevice) : - spiMap(MAX_NUMBER_OF_SPI_DEVICES), rxBuffer( - MAX_PACKET_SIZE * MAX_NUMBER_OF_SPI_DEVICES*10, true), SystemObject(setObjectId) { - initialized = false; - serialPort = ::open("/dev/ttyUSB0", O_RDWR); - - if (serialPort < 0) { - //configuration error - printf("Error %i from open: %s\n", errno, strerror(errno)); - return; - } - - struct termios tty; - memset(&tty, 0, sizeof tty); - - // Read in existing settings, and handle any error - if (tcgetattr(serialPort, &tty) != 0) { - printf("Error %i from tcgetattr: %s\n", errno, strerror(errno)); - return; - } - - tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity - tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication - tty.c_cflag |= CS8; // 8 bits per byte - tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control - tty.c_lflag &= ~ICANON; //Disable Canonical Mode - tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) - tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed - tty.c_cc[VTIME] = 0; // Non Blocking - tty.c_cc[VMIN] = 0; - - cfsetispeed(&tty, B9600); //Baudrate - - if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { - //printf("Error %i from tcsetattr: %s\n", errno, strerror(errno)); - return; - } - - initialized = true; - -} - -ArduinoCommInterface::~ArduinoCommInterface() { - ::close(serialPort); -} - -ReturnValue_t ArduinoCommInterface::open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) { - //This is a hack, will be gone with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 - switch ((address >> 8) & 0xff) { - case 0: - *cookie = new ArduinoCookie(ArduinoCookie::SPI, address, maxReplyLen); - spiMap.insert(address, (ArduinoCookie*) *cookie); //Yes, I *do* know that it is an ArduinoSpiCookie, I just new'd it - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen) { - //too lazy right now will be irrelevant with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 - return HasReturnvaluesIF::RETURN_FAILED; -} - -void ArduinoCommInterface::close(Cookie *cookie) { - //too lazy as well, find the correct Map, delete it there, then the cookie... -} - -ReturnValue_t ArduinoCommInterface::sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len) { - ArduinoCookie *arduinoCookie = dynamic_cast(cookie); - if (arduinoCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - - return sendMessage(arduinoCookie->command, arduinoCookie->address, data, - len); -} - -ReturnValue_t ArduinoCommInterface::getSendSuccess(Cookie *cookie) { - return RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::requestReceiveMessage(Cookie *cookie) { - return RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::readReceivedMessage(Cookie *cookie, - uint8_t **buffer, uint32_t *size) { - - handleSerialPortRx(); - - ArduinoCookie *arduinoCookie = dynamic_cast(cookie); - if (arduinoCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - - *buffer = arduinoCookie->replyBuffer; - *size = arduinoCookie->receivedDataLen; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::setAddress(Cookie *cookie, - uint32_t address) { - //not implemented - return RETURN_FAILED; -} - -uint32_t ArduinoCommInterface::getAddress(Cookie *cookie) { - //not implemented - return 0; -} - -ReturnValue_t ArduinoCommInterface::setParameter(Cookie *cookie, - uint32_t parameter) { - //not implemented - return RETURN_FAILED; -} - -uint32_t ArduinoCommInterface::getParameter(Cookie *cookie) { - //not implemented - return 0; -} - -ReturnValue_t ArduinoCommInterface::sendMessage(uint8_t command, - uint8_t address, const uint8_t *data, size_t dataLen) { - if (dataLen > UINT16_MAX) { - return TOO_MUCH_DATA; - } - - //being conservative here - uint8_t sendBuffer[(dataLen + 6) * 2 + 2]; - - sendBuffer[0] = DleEncoder::STX; - - uint8_t *currentPosition = sendBuffer + 1; - size_t remainingLen = sizeof(sendBuffer) - 1; - uint32_t encodedLen; - - ReturnValue_t result = DleEncoder::encode(&command, 1, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - result = DleEncoder::encode(&address, 1, currentPosition, remainingLen, - &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - uint8_t temporaryBuffer[2]; - - //note to Lukas: yes we _could_ use Serialize here, but for 16 bit it is a bit too much... - temporaryBuffer[0] = dataLen >> 8; //we checked dataLen above - temporaryBuffer[1] = dataLen; - - result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - //encoding the actual data - result = DleEncoder::encode(data, dataLen, currentPosition, remainingLen, - &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - uint16_t crc = CRC::crc16ccitt(&command, 1); - crc = CRC::crc16ccitt(&address, 1, crc); - //fortunately the length is still there - crc = CRC::crc16ccitt(temporaryBuffer, 2, crc); - crc = CRC::crc16ccitt(data, dataLen, crc); - - temporaryBuffer[0] = crc >> 8; - temporaryBuffer[1] = crc; - - result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - if (remainingLen > 0) { - *currentPosition = DleEncoder::ETX; - } - remainingLen -= 1; - - encodedLen = sizeof(sendBuffer) - remainingLen; - - ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); - if (writtenlen < 0) { - //we could try to find out what happened... - return RETURN_FAILED; - } - if (writtenlen != encodedLen) { - //the OS failed us, we do not try to block until everything is written, as - //we can not block the whole system here - return RETURN_FAILED; - } - return RETURN_OK; -} - -void ArduinoCommInterface::handleSerialPortRx() { - uint32_t availableSpace = rxBuffer.availableWriteSpace(); - - uint8_t dataFromSerial[availableSpace]; - - ssize_t bytesRead = read(serialPort, dataFromSerial, - sizeof(dataFromSerial)); - - if (bytesRead < 0) { - return; - } - - rxBuffer.writeData(dataFromSerial, bytesRead); - - uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; - - uint32_t dataLenReceivedSoFar = 0; - - rxBuffer.readData(dataReceivedSoFar, sizeof(dataReceivedSoFar), true, - &dataLenReceivedSoFar); - - //look for STX - size_t firstSTXinRawData = 0; - while ((firstSTXinRawData < dataLenReceivedSoFar) - && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { - firstSTXinRawData++; - } - - if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { - //there is no STX in our data, throw it away... - rxBuffer.deleteData(dataLenReceivedSoFar); - return; - } - - uint8_t packet[MAX_PACKET_SIZE]; - uint32_t packetLen; - - uint32_t readSize; - - ReturnValue_t result = DleEncoder::decode( - dataReceivedSoFar + firstSTXinRawData, - dataLenReceivedSoFar - firstSTXinRawData, &readSize, packet, - sizeof(packet), &packetLen); - - size_t toDelete = firstSTXinRawData; - if (result == HasReturnvaluesIF::RETURN_OK) { - handlePacket(packet, packetLen); - - //after handling the packet, we can delete it from the raw stream, it has been copied to packet - toDelete += readSize; - } - - //remove Data which was processed - rxBuffer.deleteData(toDelete); -} - -void ArduinoCommInterface::handlePacket(uint8_t *packet, size_t packetLen) { - uint16_t crc = CRC::crc16ccitt(packet, packetLen); - if (crc != 0) { - //CRC error - return; - } - - uint8_t command = packet[0]; - uint8_t address = packet[1]; - - uint16_t size = (packet[2] << 8) + packet[3]; - - if (size != packetLen - 6) { - //Invalid Length - return; - } - - switch (command) { - case ArduinoCookie::SPI: { - ArduinoCookie **itsComplicated; - ReturnValue_t result = spiMap.find(address, &itsComplicated); - if (result != RETURN_OK) { - //we do no know this address - return; - } - ArduinoCookie *theActualCookie = *itsComplicated; - if (packetLen > theActualCookie->maxReplySize + 6) { - packetLen = theActualCookie->maxReplySize + 6; - } - memcpy(theActualCookie->replyBuffer, packet + 4, packetLen - 6); - theActualCookie->receivedDataLen = packetLen - 6; - } - break; - default: - return; - } -} diff --git a/bsp_linux/comIF/ArduinoComIF.h b/bsp_linux/comIF/ArduinoComIF.h deleted file mode 100644 index 9ab166de..00000000 --- a/bsp_linux/comIF/ArduinoComIF.h +++ /dev/null @@ -1,73 +0,0 @@ -//#ifndef MISSION_ARDUINOCOMMINTERFACE_H_ -//#define MISSION_ARDUINOCOMMINTERFACE_H_ -// -//#include -//#include -//#include -//#include -//#include -//#include -// -//#include "../../framework/objectmanager/SystemObject.h" -//#include "ArduinoCookie.h" -// -////Forward declaration, so users don't peek -//class ArduinoCookie; -// -//class ArduinoComIF: public SystemObject, -// public DeviceCommunicationIF { -//public: -// static const uint8_t MAX_NUMBER_OF_SPI_DEVICES = 8; -// static const uint8_t MAX_PACKET_SIZE = 64; -// -// static const uint8_t COMMAND_INVALID = -1; -// static const uint8_t COMMAND_SPI = 1; -// -// ArduinoComIF(object_id_t setObjectId, const char *serialDevice); -// virtual ~ArduinoComIF(); -// -// virtual ReturnValue_t open(Cookie **cookie, uint32_t address, -// uint32_t maxReplyLen); -// -// virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, -// uint32_t maxReplyLen); -// -// virtual void close(Cookie *cookie); -// -// //SHOULDDO can data be const? -// virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, -// uint32_t len); -// -// virtual ReturnValue_t getSendSuccess(Cookie *cookie); -// -// virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); -// -// virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, -// uint32_t *size); -// -// virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); -// -// virtual uint32_t getAddress(Cookie *cookie); -// -// virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); -// -// virtual uint32_t getParameter(Cookie *cookie); -//private: -// //remembering if the initialization in the ctor worked -// //if not, all calls are disabled -// bool initialized; -// int serialPort; -// //used to know where to put the data if a reply is received -// FixedMap spiMap; -// -// SimpleRingBuffer rxBuffer; -// -// ReturnValue_t sendMessage(uint8_t command, uint8_t address, -// const uint8_t *data, size_t dataLen); -// -// void handleSerialPortRx(); -// -// void handlePacket(uint8_t *packet, size_t packetLen); -//}; -// -//#endif /* MISSION_ARDUINOCOMMINTERFACE_H_ */ diff --git a/bsp_linux/comIF/ArduinoCookie.cpp b/bsp_linux/comIF/ArduinoCookie.cpp deleted file mode 100644 index d7e81192..00000000 --- a/bsp_linux/comIF/ArduinoCookie.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//#include -// -//ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address, -// size_t maxReplySize) : -// command(protocol), address(address), receivedDataLen(0), maxReplySize( -// maxReplySize) { -// replyBuffer = new uint8_t[maxReplySize]; -//} -// -//ArduinoCookie::~ArduinoCookie() { -// delete[] replyBuffer; -//} diff --git a/bsp_linux/comIF/ArduinoCookie.h b/bsp_linux/comIF/ArduinoCookie.h deleted file mode 100644 index 64eed4ad..00000000 --- a/bsp_linux/comIF/ArduinoCookie.h +++ /dev/null @@ -1,25 +0,0 @@ -//#ifndef MISSION_ARDUINO_ARDUINOCOOKIE_H_ -//#define MISSION_ARDUINO_ARDUINOCOOKIE_H_ -// -//#include -// -//#include -//#include -// -//class ArduinoCookie: public Cookie { -//public: -// enum Protocol_t { -// INVALID = 0, SPI = 1 -// }; -// ArduinoCookie(Protocol_t protocol, uint8_t address, size_t maxReplySize); -// virtual ~ArduinoCookie(); -// -// uint8_t command; -// uint8_t address; -// uint8_t *replyBuffer; -// size_t receivedDataLen; -// size_t maxReplySize; -// -//}; -// -//#endif /* MISSION_ARDUINO_ARDUINOCOOKIE_H_ */ diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp new file mode 100644 index 00000000..83be2864 --- /dev/null +++ b/bsp_linux/comIF/CspComIF.cpp @@ -0,0 +1,211 @@ +#include "CspComIF.h" +#include +#include +#include +#include + +CspComIF::CspComIF(object_id_t objectId) : + SystemObject(objectId) { + +} + +CspComIF::~CspComIF() { +} + +ReturnValue_t CspComIF::initializeInterface(CookieIF *cookie) { + if(cookie == nullptr) { + return NULLPOINTER; + } + + CspCookie* cspCookie = dynamic_cast(cookie); + if(cspCookie == nullptr) { + return NULLPOINTER; + } + + /* Perform CAN and CSP initialization only once */ + if(cspDeviceMap.empty()){ + /* Define the memory to allocate for the CSP stack */ + int buf_count = 10; + int buf_size = 300; + /* Init CSP and CSP buffer system */ + if (csp_init(cspClientAddress) != CSP_ERR_NONE + || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { + sif::error << "Failed to init CSP\r\n" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + int promisc = 0; // Set filter mode on + csp_iface_t *csp_if_ptr = &csp_if; + csp_if_ptr = csp_can_socketcan_init(canInterface, bitrate, promisc); + + /* Set default route and start router */ + uint8_t address = CSP_DEFAULT_ROUTE; + uint8_t netmask = 0; + uint8_t mac = CSP_NODE_MAC; + int result = csp_rtable_set(address, netmask, csp_if_ptr, mac); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to add can interface to router table" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Start the route task */ + unsigned int task_stack_size = 500; + unsigned int priority = 0; + result = csp_route_start_task(task_stack_size, priority); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to start csp route task" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + uint8_t cspAddress = cspCookie->getCspAddress(); + uint16_t maxReplyLength = cspCookie->getMaxReplyLength(); + if(cspDeviceMap.find(cspAddress) == cspDeviceMap.end()){ + /* Insert device information in CSP map */ + cspDeviceMap.emplace(cspAddress, vectorBuffer(maxReplyLength)); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + int result; + if(cookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + CspCookie* cspCookie = dynamic_cast (cookie); + if(cspCookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Extract csp port and bytes to query from command buffer */ + uint8_t cspPort; + uint16_t querySize; + result = getPortAndQuerySize(&sendData, &sendLen, &cspPort, &querySize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + uint8_t cspAddress = cspCookie->getCspAddress(); + switch(cspPort) { + case(Ports::CSP_PING): { + initiatePingRequest(cspAddress, querySize); + break; + } + case(Ports::CSP_REBOOT): { + csp_reboot(cspAddress); + break; + } + case(Ports::P60_PORT_GNDWDT_RESET): + case(Ports::P60_PORT_RPARAM): { + /* No CSP fixed port was selected. Send data to the specified port and + * wait for querySize number of bytes */ + result = cspTransfer(cspAddress, cspPort, sendData, sendLen, + querySize); + if(result != HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + replySize = querySize; + break; + } + default: + sif::error << "CspComIF: Invalid port specified" << std::endl; + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::getSendSuccess(CookieIF *cookie) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::requestReceiveMessage(CookieIF *cookie, + size_t requestLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::readReceivedMessage(CookieIF *cookie, + uint8_t** buffer, size_t* size) { + if(cookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + CspCookie* cspCookie = dynamic_cast (cookie); + if(cspCookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint8_t cspAddress = cspCookie->getCspAddress(); + + *buffer = cspDeviceMap[cspAddress].data(); + *size = replySize; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, + const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize) { + + uint32_t timeout_ms = 500; + vectorBufferIter iter = cspDeviceMap.find(cspAddress); + if(iter == cspDeviceMap.end()){ + sif::error << "CSP device with address " << cspAddress << " no found in" + << " device map" << std::endl; + } + uint8_t* replyBuffer = iter->second.data(); + uint8_t tmpCmdBuffer[cmdBufferLen]; + memcpy(tmpCmdBuffer, cmdBuffer, cmdBufferLen); + + csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, cspAddress, cspPort, 0, + CSP_O_NONE); + + int result = csp_transaction_persistent(conn, timeout_ms, + tmpCmdBuffer, cmdBufferLen, replyBuffer, querySize); + if(querySize != 0){ + if(result != querySize){ + sif::error << "CSP transfer failed to receive all requested bytes " + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + } else { + if(result != 1){ + sif::error << "CSP transfer failed" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + csp_close(conn); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::getPortAndQuerySize(const uint8_t** sendData, + size_t* sendLen, uint8_t* cspPort, uint16_t* querySize) { + ReturnValue_t result = SerializeAdapter::deSerialize(cspPort, sendData, + sendLen, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "CspComIF: Failed to deserialize CSP port from command " + << "buffer" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + SerializeAdapter::deSerialize(querySize, sendData, sendLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "CspComIF: Failed to deserialize querySize from command " + << "buffer" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void CspComIF::initiatePingRequest(uint8_t cspAddress, uint16_t querySize){ + uint32_t timeout_ms = 500; + uint32_t replyTime = csp_ping(cspAddress, timeout_ms, querySize, + CSP_O_NONE); + sif::info << "Ping address: " << cspAddress << ", reply after " + << replyTime << " ms" << std::endl; + /* Store reply time in reply buffer * */ + uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); + memcpy(replyBuffer, &replyTime, sizeof(replyTime)); + replySize = sizeof(replyTime); +} diff --git a/bsp_linux/comIF/CspComIF.h b/bsp_linux/comIF/CspComIF.h new file mode 100644 index 00000000..626b466c --- /dev/null +++ b/bsp_linux/comIF/CspComIF.h @@ -0,0 +1,89 @@ +#ifndef BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ +#define BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ + +#include +#include +#include +#include + +#include +#include + +/** + * @brief This class serves as the communication interface to devices + * supporting the CSP protocol. As physical layer can0 is used + * in this implementation. + * @author J. Meier + */ +class CspComIF: public DeviceCommunicationIF, public SystemObject { +public: + CspComIF(object_id_t objectId); + virtual ~CspComIF(); + + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, + uint8_t **readData, size_t *readLen) override; + +private: + + /** + * @brief This function initiates the CSP transfer. + * + * @param cspAddress The CSP address of the target device. + * @param cspPort The port of the target device. + * @param timeout The timeout to wait for csp_send and csp_read + * functions. Specifies how long the functions wait + * for a successful operation. + * @param cmdBuffer The data to send. + * @param cmpBuffer The number of bytes to send. + * @param querySize The size of the requested message. + */ + ReturnValue_t cspTransfer(uint8_t cspAddress, uint8_t cspPort, + const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize); + + enum Ports { + CSP_PING = 1, + CSP_REBOOT = 4, + P60_PORT_RPARAM = 7, + P60_PORT_GNDWDT_RESET = 9 + }; + + + typedef uint8_t node_t; + using vectorBuffer = std::vector; + using VectorBufferMap = std::unordered_map; + using vectorBufferIter = VectorBufferMap::iterator; + + /* In this map assigns reply buffers to a CSP device */ + VectorBufferMap cspDeviceMap; + + uint16_t replySize = 0; + + /* This is the CSP address of the OBC. */ + node_t cspClientAddress = 1; + + /* Interface struct for csp protocol stack */ + csp_iface_t csp_if; + + char canInterface[5] = "can0"; + int bitrate = 1000; + + /** + * @brief Function to extract the csp port and the query size from the + * command buffer. + */ + ReturnValue_t getPortAndQuerySize(const uint8_t** sendData, size_t* sendLen, + uint8_t* cspPort, uint16_t* querySize); + + /** + * @brief This function initiates the ping request. + */ + void initiatePingRequest(uint8_t cspAddress, uint16_t querySize); +}; + +#endif /* BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ */ diff --git a/bsp_linux/comIF/cookies/CspCookie.cpp b/bsp_linux/comIF/cookies/CspCookie.cpp new file mode 100644 index 00000000..18cfabd2 --- /dev/null +++ b/bsp_linux/comIF/cookies/CspCookie.cpp @@ -0,0 +1,16 @@ +#include "CspCookie.h" + +CspCookie::CspCookie(uint16_t maxReplyLength_, uint8_t cspAddress_) : + maxReplyLength(maxReplyLength_), cspAddress(cspAddress_) { +} + +CspCookie::~CspCookie() { +} + +uint16_t CspCookie::getMaxReplyLength(){ + return maxReplyLength; +} + +uint8_t CspCookie::getCspAddress(){ + return cspAddress; +} diff --git a/bsp_linux/comIF/cookies/CspCookie.h b/bsp_linux/comIF/cookies/CspCookie.h new file mode 100644 index 00000000..128926e5 --- /dev/null +++ b/bsp_linux/comIF/cookies/CspCookie.h @@ -0,0 +1,27 @@ +#ifndef BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ +#define BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ + +#include +#include + +/** + * @brief This is the cookie for devices supporting the CSP (CubeSat Space + * Protocol). + * @author J. Meier + */ +class CspCookie: public CookieIF { +public: + + CspCookie(uint16_t maxReplyLength_, uint8_t cspAddress_); + virtual ~CspCookie(); + + uint16_t getMaxReplyLength(); + uint8_t getCspAddress(); + +private: + + uint16_t maxReplyLength; + uint8_t cspAddress; +}; + +#endif /* BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ */ diff --git a/fsfw b/fsfw index 6bedc9b8..113397c6 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 6bedc9b805d9e51fbca0d4b881fab39f52b59a07 +Subproject commit 113397c6c6ae4c46341f4880710e4e4d9b6e7630 diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index 7e59992c..59a09ba4 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -6,7 +6,7 @@ #ifndef FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_ -#define ADD_TEST_CODE 1 +#define ADD_TEST_CODE 0 // Define not used yet, PUS stack and TMTC tasks are always started #define ADD_PUS_STACK 1 diff --git a/fsfwconfig/devices/logicalAddresses.cpp b/fsfwconfig/devices/addresses.cpp similarity index 52% rename from fsfwconfig/devices/logicalAddresses.cpp rename to fsfwconfig/devices/addresses.cpp index a6f0aa15..38877737 100644 --- a/fsfwconfig/devices/logicalAddresses.cpp +++ b/fsfwconfig/devices/addresses.cpp @@ -4,7 +4,7 @@ * \date 06.11.2019 */ -#include +#include "addresses.h" diff --git a/fsfwconfig/devices/addresses.h b/fsfwconfig/devices/addresses.h new file mode 100644 index 00000000..37d653fa --- /dev/null +++ b/fsfwconfig/devices/addresses.h @@ -0,0 +1,35 @@ +/** + * \file addresses.cpp + * + * \date 07.11.2019 + */ + +#ifndef FSFWCONFIG_DEVICES_ADDRESSES_H_ +#define FSFWCONFIG_DEVICES_ADDRESSES_H_ +#include +#include +#include + +namespace addresses { + /* Logical addresses have uint32_t datatype */ + enum logicalAddresses: address_t { + PCDU, + + /* Dummy and Test Addresses */ + DUMMY_ECHO = 129, + DUMMY_GPS0 = 130, + DUMMY_GPS1 = 131, + }; + + /* Addresses of devices supporting the CSP protocol */ + enum cspAddresses: uint8_t { + P60DOCK = 4, + ACU = 2, + PDU1 = 3, + /* PDU2 occupies X4 slot of P60Dock */ + PDU2 = 6 + }; +} + + +#endif /* FSFWCONFIG_DEVICES_ADDRESSES_H_ */ diff --git a/fsfwconfig/devices/logicalAddresses.h b/fsfwconfig/devices/logicalAddresses.h deleted file mode 100644 index 922c9ce1..00000000 --- a/fsfwconfig/devices/logicalAddresses.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * \file logicalAddresses.cpp - * - * \date 07.11.2019 - */ - -#ifndef FSFWCONFIG_DEVICES_LOGICALADDRESSES_H_ -#define FSFWCONFIG_DEVICES_LOGICALADDRESSES_H_ -#include -#include -#include - -namespace addresses { - /* Logical addresses have uint32_t datatype */ - enum logicalAddresses: address_t { - PCDU, - - /* Dummy and Test Addresses */ - DUMMY_ECHO = 129, - DUMMY_GPS0 = 130, - DUMMY_GPS1 = 131, - }; -} - - -#endif /* FSFWCONFIG_DEVICES_LOGICALADDRESSES_H_ */ diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index a77b8a7b..e1334af7 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -27,10 +27,17 @@ namespace objects { TEST_TASK = 0x42694269, DUMMY_INTERFACE = 0xCAFECAFE, DUMMY_HANDLER = 0x4400AFFE, + P60DOCK_TEST_TASK = 0x00005060, /* 0x49 ('I') for Communication Interfaces **/ ARDUINO_COM_IF = 0x49000001, - P60DOCK_TEST_TASK = 0x00005060 + CSP_COM_IF = 0x49000002, + + /* 0x44 ('D') for device handlers */ + P60DOCK_HANDLER = 0x44000001, + PDU1_HANDLER = 0x44000002, + PDU2_HANDLER = 0x44000003, + ACU_HANDLER = 0x44000004 }; } diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index 22c00034..c3f5872d 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -28,3 +28,52 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) } } +ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ + + uint32_t length = thisSequence->getPeriodMs(); + + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); + + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); + + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); + + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); + + if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + sif::error << "Initialization of GomSpace PST failed" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.h b/fsfwconfig/pollingsequence/PollingSequenceFactory.h index b6cc2f1e..0b12e6b8 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.h +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.h @@ -26,6 +26,13 @@ namespace pst { /* 0.4 second period init*/ ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence); +/** + * @brief This function creates the PST for all gomspace devices. They are + * scheduled in a separate PST because the gomspace library uses + * blocking calls when requesting data from devices. + */ +ReturnValue_t gomspacePstInit(FixedTimeslotTaskIF *thisSequence); } + #endif /* POLLINGSEQUENCEINIT_H_ */ diff --git a/gomspace/gomspace.mk b/gomspace/gomspace.mk deleted file mode 100644 index 675fa426..00000000 --- a/gomspace/gomspace.mk +++ /dev/null @@ -1,11 +0,0 @@ -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/drivers/can/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/interfaces/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/rtable/csp_rtable_cidr.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/crypto/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/arch/posix/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/transport/*.c) - -INCLUDES += $(CURRENTPATH)/libcsp/include -INCLUDES += $(CURRENTPATH)/libcsp/include/csp/crypto -INCLUDES += $(CURRENTPATH)/libcsp \ No newline at end of file diff --git a/gomspace/include/port.h b/gomspace/include/port.h deleted file mode 100644 index 29fa32e4..00000000 --- a/gomspace/include/port.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_PORT_H -#define LIBGSCSP_INCLUDE_GS_CSP_PORT_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Port definitions for standard CSP and GomSpace services. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Port definitions for standard CSP and GomSpace services. -*/ -typedef enum { - /** - CSP Management Protocol - standard CSP service. - */ - GS_CSP_CMP = CSP_CMP, // 0 - /** - Ping - standard CSP service. - */ - GS_CSP_PING = CSP_PING, // 1 - /** - Show process status - standard CSP service. - */ - GS_CSP_PS = CSP_PS, // 2 - /** - Show memory free - standard CSP service. - */ - GS_CSP_MEM_FREE = CSP_MEMFREE, // 3 - GS_CSP_MEMFREE = GS_CSP_MEM_FREE, - /** - Reboot/reset request - standard CSP service. - */ - GS_CSP_REBOOT = CSP_REBOOT, // 4 - /** - Show number of free CSP buffers - standard CSP service. - */ - GS_CSP_BUF_FREE = CSP_BUF_FREE, // 5 - /** - Show uptime (time since last reset) - standard CSP service. - */ - GS_CSP_UPTIME = CSP_UPTIME, // 6 - /** - Parameter service (libparam) - */ - GS_CSP_PORT_RPARAM = 7, - /** - File Transfer Service (libftp) - */ - GS_CSP_PORT_FTP = 9, - /** - Remote log service (liblog) - */ - GS_CSP_PORT_RLOG = 11, - /** - Remote GOSH service (librgosh) - */ - GS_CSP_PORT_RGOSH = 12, - /** - AIS command port (libais). - */ - GS_CSP_PORT_AIS = 13, - /** - ADS-B command port (libadsb). - */ - GS_CSP_PORT_ADSB = 14, - - /** - GomSpace Sensor Bus (libgssb). - */ - GS_CSP_PORT_GSSB = 16, - /** - Flight Planner (libfp). - */ - GS_CSP_PORT_FP = 18, - /** - ADCS (libadcs). - */ - GS_CSP_PORT_ADCS = 20, - /** - House Keeping (libhk). - */ - GS_CSP_PORT_HK = 21, - /** - G(omSpace) script service (libgosh) - */ - GS_CSP_PORT_GSCRIPT = 22, - /** - Remote shell (libgosh). - Executes shell commands (linux server only). - Requires CSP_O_RDP. - */ - GS_CSP_PORT_REMOTE_SHELL = 27, - /** - House keeping beacon port (libhk). - Default port for sending beacons from satellite to ground (configurable). - */ - GS_CSP_PORT_HK_BEACON = 30, - -} gs_csp_port_t; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/include/rparam.h b/gomspace/include/rparam.h deleted file mode 100644 index fb838c73..00000000 --- a/gomspace/include/rparam.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_RPARAM_H -#define GS_PARAM_INTERNAL_RPARAM_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Max query payload in a single message (bytes). -*/ -#define GS_RPARAM_QUERY_MAX_PAYLOAD 180 - -/** - Macro for calculating total query message size, header + payload. -*/ -#define RPARAM_QUERY_LENGTH(query, payload_size) (sizeof(*query) - sizeof(query->payload) + payload_size) - -/** - R(emote) parameter request codes. -*/ -typedef enum { - /** - Get one or more parameters. - */ - RPARAM_GET = 0x00, - /** - Reply to a request. - */ - RPARAM_REPLY = 0x55, - /** - Set one or more parameters. - */ - RPARAM_SET = 0xFF, - // RPARAM_SET_TO_FILE = 0xEE, - /** - Download table specification. - */ - RPARAM_TABLE = 0x44, - /** - Copy memory slot to memory slot. - @version 4.x: Not supported. - */ - RPARAM_COPY = 0x77, - /** - Load from file (slot) to memory (slot). - @version 4.x: Only load from primary store - file (slot) is ignored. - */ - RPARAM_LOAD = 0x88, - /** - Load from file (slot) to memory (slot). - @version 4.x: load by name(s). - */ - RPARAM_LOAD_FROM_STORE = 0x89, - /** - Save from memory (slot) to file (slot). - @version 4.x: Only save to primary store - file (slot) is ignored. - */ - RPARAM_SAVE = 0x99, - /** - Save from memory (slot) to file (slot). - @version 4.x: save by name(s). - */ - RPARAM_SAVE_TO_STORE = 0x9a, - // RPARAM_CLEAR = 0xAA, - completely removed -} gs_rparam_action_t; - -/** - R(emote) parameter reply/completion codes. -*/ -typedef enum { - RPARAM_SET_OK = 1, - RPARAM_LOAD_OK = 2, - RPARAM_SAVE_OK = 3, - RPARAM_COPY_OK = 4, - // RPARAM_CLEAR_OK = 5, - RPARAM_ERROR = 0xFF, -} gs_rparam_reply_t; - -/** - Payload - save/load to/from stores - @version 4 -*/ -typedef struct __attribute__ ((packed)) { - char table[25 + 1]; - char store[25 + 1]; - char slot[25 + 1]; -} gs_rparam_query_payload_store_t; - -/** - Payload. -*/ -typedef union __attribute__ ((packed)) { - uint16_t addr[0]; //! action = RPARAM_GET - uint8_t packed[0]; //! action = RPARAM_REPLY | RPARAM_SET - struct { //! action = RPARAM_COPY | RPARAM_LOAD | RPARM_SAVE - uint8_t from; - uint8_t to; - } copy; -} gs_rparam_query_payload_t; - -/** - Protocol between client and server. - @version 4.x: layout (size) has not changed - only naming of certain fields. -*/ -typedef struct __attribute__ ((packed)) { - /** - Request (gs_rparam_action_t) or Reply (gs_rparam_reply_t). - */ - uint8_t action; - /** - Table id. - Name changed in 4.0 from \a mem. - */ - uint8_t table_id; - /** - Length/size of \a payload in bytes. - */ - uint16_t length; - /** - Fletcher's checksum. - */ - uint16_t checksum; - /** - Sequence number when split over multiple frames (messages). - */ - uint16_t seq; - /** - Total number of frames. - */ - uint16_t total; - /** - Payload. - */ - gs_rparam_query_payload_t payload; -} gs_rparam_query_t; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libcsp/CHANGELOG b/gomspace/libcsp/CHANGELOG deleted file mode 100644 index a4945716..00000000 --- a/gomspace/libcsp/CHANGELOG +++ /dev/null @@ -1,113 +0,0 @@ -libcsp 1.4, 07-05-2015 ----------------------- -- new: General rtable interface with support for STATIC or CIDR format -- new: CIDR (classless interdomain routing) route table format with netmasks -- new: Bridge capability -- new: Added routing table (de)serialization functions for load/save -- new: Automatic packet deduplication using CRC32 (compile time option) -- new: Autogenerated python bindings using ctypesgen -- new: Task-less operation with router invocation from external scheduler function -- api: Refactor route_if_add to csp_iflist_add -- api: Refactor route_set and friends to rtable_set -- api: Refactor csp_fifo_qos to csp_qfifo -- api: Added defined to be backwards compatible with 1.x -- interfaces: Drop packets on LOOP interface not for own address (blackhole) -- interfaces: New ZMQHUB interface (using zeroMQ over TCP) -- other: Increase stack size from 250 to 1100 for csp_can_rx_task -- other: Cleanup in csp_route.c -- other: Show incoming interface name in debug message -- other: Remove newlines from debug calls -- improvement: Reduce debug hook function complexity with valist passing -- fix: csp_sleep_ms did not work - -libcsp 1.3, 07-05-2015 ----------------------- -- new: Split long process lists into multiple packets -- new: Added posix csp_clock.h -- new: cmp clock functions (requires that you provide csp_clock.h implementation) -- new: Added SFP (Small fragmentation protocol) for larger data chunks -- fix: csp_if_fifo example -- fix: NULL char at the end of rps -- doc: Updated mtu documentation -- other: Tested with FreeRTOS 8.0 -- other: Added disable-stlib option to build only object files - -libcsp 1.2, 25-10-2013 ----------------------- -- Feature release -- New: CMP service for peek and poke of memory -- New: CMP interface statistics struct is now packed -- New: Faster O(1) buffer system with reference counting and automatic alignment -- New: Thread safe KISS driver with support for multiple interfaces -- New: CSP interface struct now holds an opaque pointer to driver handle -- New: removed TXBUF from KISS driver entirely to minimize stack usage, added TX lock instead -- New: Pre-calculated CRC table .romem or PROGMEM on __avr__ -- New: Added buffer overflow protection to KISS interface -- New: Allow posting null pointers on conn RX queues -- New: Lower memory usage on AVR8 -- New: csp_route_save and csp_route_load functions -- New: option --disable-verbose to disable filenames and linenumber on debug -- Protocol: KISS uses csp_crc32 instead of it own embedded crc32 -- Improvement: Use buffer clone function to copy promisc packets -- Bugfix: Fix pointer size (32/16bit) in cmp_peek/poke -- Bugfix: Issue with double free in KISS fixed -- Bugfix: Change rdp_send timeout from packet to connection timeout to make sending task block longer -- Bugfix: Fix conn pool leak when using security check and discarding new packets -- Bugfix: Add packet too short check for CRC32 -- Bugfix: Accept CRC32 responses from nodes without CRC support -- Bugfix: Ensure csp_ping works for packets > 256 bytes -- Bugfix: Cleanup printf inside ISR functions -- Bugfix: Do not add forwarded packets to promisc queue twice -- Bugfix: Fix return value bug of csp_buffer_get when out of buffers -- Bugfix: Always post null pointer with lowest priority, not highest -- Bugfix: Add check on debug level before calling do_csp_debug, fixes #35 -- Other: Export csp/arch include files -- Other: Remove the use of bool type from csp_debug -- Other: Moved csp debug functions to csp_debug.h instead of csp.h -- Other: Ensure assignment of id happens using the uint32_t .ext value of the union, quenches warning - -libcsp 1.1, 24-08-2012 ----------------------- -- Feature release -- Defacto stable since Feb 2012 -- New: I2C interface -- New: KISS interface -- New: USART drivers for Linux, Mac and Windows -- New: Windows/MinGW support -- New: MacOSX support -- New: Interface register function -- New: Interface search function -- New: CMP service for remote route updating -- New: CMP service for interface statistics -- Improvement: Better QoS support -- Improvement: Send RDP control messages with high priority -- Improvement: WAF distcheck now works -- Improvement: Automatic endian discovery -- Improvement: Accept packets with CRC32 checksum if compiled without CRC32 support -- Improvement: Do not wake the router task if RDP is not enabled -- Improvement: Save 102 bytes of RAM by packing route entries -- Cleanup: Simplify CAN configuration -- Cleanup: Move architecture specific code to src/arch -- Bugfix: CSP_MEMFREE gives wrong answer on freertos AVR due to truncation -- Bugfix: Fixed wrong 64-bit size_t in csp_service_handler -- Bugfix: Fixed problem in csp_if_kiss when out of buffers -- Bigfix: Handle bus-off CAN IRQ for AT90CAN128 - -libcsp 1.0.1, 30-10-2011 ------------------------- -- Hotfix release -- Bugfix: missing extern in csp_if_lo.h - -libcsp 1.0, 24-10-2011 ----------------------- -- First official release -- New: CSP 32-bit header 1.0 -- Features: Network Router with promiscous mode, broadcast and QoS -- Features: Connection-oriented transport protocol w. flow-control -- Features: Connection-less "UDP" like transport -- Features: Encryption, Authentication and message check -- Features: Loopback interface -- Features: Python Bindings -- Features: CAN interface w. drivers for several chips -- Features: CSP-services (ping, reboot, uptime, memfree, buffree, ident) - diff --git a/gomspace/libcsp/CONTRIBUTORS b/gomspace/libcsp/CONTRIBUTORS deleted file mode 100644 index 97240f60..00000000 --- a/gomspace/libcsp/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -Jeppe Ledet-Pedersen -Johan De Claville Christiansen -Dan Erik Holmstrøm diff --git a/gomspace/libcsp/COPYING b/gomspace/libcsp/COPYING deleted file mode 100644 index 54c619ad..00000000 --- a/gomspace/libcsp/COPYING +++ /dev/null @@ -1,503 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - diff --git a/gomspace/libcsp/INSTALL.rst b/gomspace/libcsp/INSTALL.rst deleted file mode 100644 index e68a46ed..00000000 --- a/gomspace/libcsp/INSTALL.rst +++ /dev/null @@ -1,30 +0,0 @@ -How to install LibCSP -===================== - -CSP uses the `waf` build system (http://code.google.com/p/waf/). In order to -compile CSP, you first need to configure the toolchain, what operating system -to compile for, the location of required libraries and whether to enable -certain optional features. - -To configure CSP to build with the AVR32 toolchain for FreeRTOS and output -the compiled libcsp.a and header files to the install directory, issue: - -.. code-block:: bash - - ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install - -When compiling for FreeRTOS, the path to the FreeRTOS header files must be -specified with `--with-freertos=PATH.` - -A number of optional features can be enabled by from the configure script. -Support for XTEA encryption can e.g. be enabled with `--enable-xtea`. Run -`./waf configure --help` to list the available configure options. - -The CAN drivers can be enabled by appending the configure option `--with-driver-can=CHIP`, -where CHIP is one of 'socketcan', 'at91sam7a1', 'at91sam7a3' or 'at90can128'. - -To build and copy the library to the location specified with --prefix, use: - -.. code-block:: bash - - ./waf build install diff --git a/gomspace/libcsp/README.rst b/gomspace/libcsp/README.rst deleted file mode 100644 index c8aff3d8..00000000 --- a/gomspace/libcsp/README.rst +++ /dev/null @@ -1,41 +0,0 @@ -The Cubesat Space Protocol -========================== - -Cubesat Space Protocol (CSP) is a small protocol stack written in C. CSP is designed to ease communication between distributed embedded systems in smaller networks, such as Cubesats. The design follows the TCP/IP model and includes a transport protocol, a routing protocol and several MAC-layer interfaces. The core of libcsp includes a router, a socket buffer pool and a connection oriented socket API. - -The protocol is based on a 32-bit header containing both transport and network-layer information. Its implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in GNU C and is currently ported to run on FreeRTOS or POSIX operating systems such as Linux. - -The idea is to give sub-system developers of cubesats the same features of a TCP/IP stack, but without adding the huge overhead of the IP header. The small footprint and simple implementation allows a small 8-bit system with less than 4 kB of RAM to be fully connected on the network. This allows all subsystems to provide their services on the same network level, without any master node required. Using a service oriented architecture has several advantages compared to the traditional mater/slave topology used on many cubesats. - - * Standardised network protocol: All subsystems can communicate with eachother - * Service loose coupling: Services maintain a relationship that minimizes dependencies between subsystems - * Service abstraction: Beyond descriptions in the service contract, services hide logic from the outside world - * Service reusability: Logic is divided into services with the intention of promoting reuse. - * Service autonomy: Services have control over the logic they encapsulate. - * Service Redundancy: Easily add redundant services to the bus - * Reduces single point of failure: The complexity is moved from a single master node to several well defines services on the network - -The implementation of LibCSP is written with simplicity in mind, but it's compile time configuration allows it to have some rather advanced features as well: - -Features --------- - - * Thread safe Socket API - * Router task with Quality of Services - * Connection-oriented operation (RFC 908 and 1151). - * Connection-less operation (similar to UDP) - * ICMP-like requests such as ping and buffer status. - * Loopback interface - * Very Small Footprint 48 kB code and less that 1kB ram required on ARM - * Zero-copy buffer and queue system - * Modular network interface system - * Modular OS interface, ported to FreeRTOS, windows (cygwin) and Linux - * Broadcast traffic - * Promiscuous mode - * Encrypted packets with XTEA in CTR mode - * Truncated HMAC-SHA1 Authentication (RFC 2104) - -LGPL Software license ---------------------- -The source code is available under an LGPL 2.1 license. See COPYING for the license text. - diff --git a/gomspace/libcsp/waf b/gomspace/libcsp/waf deleted file mode 100644 index 4b322f1a..00000000 --- a/gomspace/libcsp/waf +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python -# encoding: ISO8859-1 -# Thomas Nagy, 2005-2016 - -""" -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -""" - -import os, sys, inspect - -VERSION="1.8.19" -REVISION="b1fc8f7baef51bd2db4c2971909a568d" -GIT="22213cd8abbd141bda40667f7ca2a48f2d6ad785" -INSTALL='' -C1='#5' -C2='#/' -C3='#,' -cwd = os.getcwd() -join = os.path.join - - -WAF='waf' -def b(x): - return x -if sys.hexversion>0x300000f: - WAF='waf3' - def b(x): - return x.encode() - -def err(m): - print(('\033[91mError: %s\033[0m' % m)) - sys.exit(1) - -def unpack_wafdir(dir, src): - f = open(src,'rb') - c = 'corrupt archive (%d)' - while 1: - line = f.readline() - if not line: err('run waf-light from a folder containing waflib') - if line == b('#==>\n'): - txt = f.readline() - if not txt: err(c % 1) - if f.readline() != b('#<==\n'): err(c % 2) - break - if not txt: err(c % 3) - txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) - - import shutil, tarfile - try: shutil.rmtree(dir) - except OSError: pass - try: - for x in ('Tools', 'extras'): - os.makedirs(join(dir, 'waflib', x)) - except OSError: - err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) - - os.chdir(dir) - tmp = 't.bz2' - t = open(tmp,'wb') - try: t.write(txt) - finally: t.close() - - try: - t = tarfile.open(tmp) - except: - try: - os.system('bunzip2 t.bz2') - t = tarfile.open('t') - tmp = 't' - except: - os.chdir(cwd) - try: shutil.rmtree(dir) - except OSError: pass - err("Waf cannot be unpacked, check that bzip2 support is present") - - try: - for x in t: t.extract(x) - finally: - t.close() - - for x in ('Tools', 'extras'): - os.chmod(join('waflib',x), 493) - - if sys.hexversion<0x300000f: - sys.path = [join(dir, 'waflib')] + sys.path - import fixpy2 - fixpy2.fixdir(dir) - - os.remove(tmp) - os.chdir(cwd) - - try: dir = unicode(dir, 'mbcs') - except: pass - try: - from ctypes import windll - windll.kernel32.SetFileAttributesW(dir, 2) - except: - pass - -def test(dir): - try: - os.stat(join(dir, 'waflib')) - return os.path.abspath(dir) - except OSError: - pass - -def find_lib(): - src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) - base, name = os.path.split(src) - - #devs use $WAFDIR - w=test(os.environ.get('WAFDIR', '')) - if w: return w - - #waf-light - if name.endswith('waf-light'): - w = test(base) - if w: return w - err('waf-light requires waflib -> export WAFDIR=/folder') - - dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) - for i in (INSTALL,'/usr','/usr/local','/opt'): - w = test(i + '/lib/' + dirname) - if w: return w - - #waf-local - dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) - w = test(dir) - if w: return w - - #unpack - unpack_wafdir(dir, src) - return dir - -wafdir = find_lib() -sys.path.insert(0, wafdir) - -if __name__ == '__main__': - - from waflib import Scripting - Scripting.waf_entry_point(cwd, VERSION, wafdir) - -#==> -#BZh91AY&SYmEõKQ#/ÿÿÿ°#,Óÿÿÿÿÿÿÿÿÿÿÿ„ Y Â#%H4#,`(bÜrû}Ñ#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,ÕÓ­ul]ZåÍë}i{l4­´ï±®í_pÝlkLϱ÷dzvúݺ{¾]òxì¾ó¥Ô´©…Rúøq楯½¯y\ÃÛe… h«Ì÷g¡éEm.Ç»u­w¦×ºÔë]2]ôõyk=·{»º¼å·[ž®×™½×ywÞ@=ggÅíkWe÷œ}}À}ìowÕãNzî#,#,#,è#, yì#,x->€è#,ûØÜ<¼À*©©{¸WLåÜû·a¦ƒOl¥Ø5nûÛ§FƒËÊ#,·m6Ð ØÑÛPP½ºu(QBª#5 JJöeGc@#,¤’ P6bªîàïA—nâûîׯZ>ÝÃãH½ž'»{´½íp#/ÍKØÔvPÊZ6îîûÞtÃjÒ>©·Þ·£¾{šûzèÓÝl›»_7Zíôìíëéß}ÙÛ¡¦MZûÚõlíζˮ83oM<€k=bWGÓªU¤Ž rz5O{½ÏyÞå뽇 ôz#/o3ÕPKh—F;ÛÝæ·Ûl5­#5ªvê½Ù¦‡¯f­î{©%žöëÕŽÚ»sg¼RÃË’î}¹Ÿ}ÞÐ#/#//·ZÅ"õîiµÍÀŸç@[ßsÇ­·®Øèì^s +ŽÞ€>û½îBqŸ*ÓKïxÓG5_/»=ÝÐ=ª£¾Ü'Ø}Â>9¶¦¶ë¯½÷e…åÏ6íëžÝÓmõvuÛnúåëÎãï{›E³{«·6·u.#/Ýö»ÎÛêï·îNî»^FM>ŽO}¤ÓˆßX¥­áÍL|R¡ZÛu.9ñ.÷;ìí«/nûÝÞÛ¯7rúçµj;<è¼ßF¾ù¹¾öogƒŸnžïj½zÛ|`uï¾uòú-íèúy=gÔ#, J=°#@˜S{0)ÚRO½Ôó5^‡¯^ñN²>·3îeÝÖk|½ÚðöP•Ü§;{¸Š‰ïUíØ)¨+×Kßw^|#,=Üu #,=ïŸ^—|ívõÞ§Ãv¾Ÿqw{ß]8¾ŽtÓz#¸§í×HÛ˜×@ÓÄåÎÙì^vÛlÒÈλ÷¼zÞ‹›g¾|å6ÝÛÀ%W ¢ëî»ïW×ݶûêx};ìßešô>æ&¾Ž{o=—Þ}î»{¶oŸkÛÝÞ:Þ{}»‡ÛkL}½>û>ya—Û½¾vòÛÀÖŠï°£®šqM_^/…ó:è5í„éx_-ê»IÚžÛíïynOµ@}o³+LUS¯4ºŸZ:û=àuîžæî­a+ïW{ëS¥¾ofw[{½ï\î7Ïvò_|î÷\VŠ€:Õ/±¡Û̳ÏnR„+Åw¨Ñ†#/×_wÑãÛ@mg #,#,ùíÜ:;¶5èkGv»sÉ®Wß"}½Àt@õïxõõèÞê“6ù·wuÏN×Vvû¤½­Îíº‹F’HÍÎ.î‰õ‡Sy½çUr^ßN/FϧÝîO®·Ð¦çq«^;N!ßyNû¬·£à´Ä“NŽí¸{›ovŒkwV¾]ÜÚÛv™òzÉ÷ßskí´ÙNÛ®Ûo6¾÷ÏSæo‡#|w M @#,É Ó#/ ™iODžˆ¥=CjA‰‘êx JhD@„Äi2hÔj6™Sð£D4òÓ'¨#,#,#,4#,#,A!! A¢bh' Sòh ž©6Dõ='©é6 Ð7©#,#,#,#,#,'ªQI4j<ši‰¤ôSf”ôÑ=OHz@#/#,Ш#,3I¡ #,#,#,#,$ˆ#, i0M#,§¡¦‰¦"{I“I‚O$z4Ð#,#,#,#,j"#, Ñ #5™é=SCÑ<©ížò‡Šzž§ê˜€ Ð#,È×ý+m«ÿîbcú†Ö¹µ¹uÉ~ÆÛS°“)#5=¶®º3&ª-5³åV­WêêmV¾Èþ#òþ'—òüµû #Îo{ÉÃMòÎg5ÌÇœ¦o9­Ì¦ç.înç9£šs-Ïð´èJ}B-~¨Z¯¦ÛRªßkæÈD&Tƒ%ŠªÆ(°xT)U\óâãóÏEÓ<š7^øIË̶ëXI³&>rµŒÕÞVª«L*ØiH ?#/ÕõŠ7ÀR ÀYeË©jÒµZ*Ú1µm#,-ÕB¨IX(¤È‚ ‚¡!„[*E±#,|à…R‚ Õ F±V«m¯¿kjµL‚@¡ ı™¦ &D4c6™QSR%Œ‰%(ÒŠm¤¨EL’X XMSQT”DJ “4M”-”ÆJÌ £I,hM0¥F’)6"ÑJmIJZS"Ô@ %–’#5’`˜2’)lQm“T#/A”²¢–&¥()%Ò‰Yš‹F¢´«iU©I6¢dÌ™4lUZ•¬f˜fÌÓ6¤±šm°KM±5-M2jadS$š djF•¤ÖB*M&ƒL’ZH-¦±’²h˜!`£3M1šlb`•4°HA˜†31#/†I‘(‰(l›R@‘KŠÉ¡’#2‘„–f–)2A´˜c%4–ÒTZ#/¦5*ECI†Š4Òl(’Q&È¥±1Pl™M¢’e¤2’&ƒF”ŒÉRŠ)™6ÈT2(–E’BH…6"ÒX5 ¨…"J*5D”…3b $Ô–)1H‰”Œd™3Fa-™S ØJ‚ˆ‰!*M‰ ’M%`Ä”–,³0lÚ#M#FÂJ!e$ ¤Í‘)š¥›,¥Ë0É¥’ji”h#/¥ŠK264ed&bIZ––HXCeA¦Ì Æ£f‘±†SKS[M†!3H¢ÌDjL”š@ÓIK-,©QQD‚Š#/‚&$Ȉ’”Æ4 #$4ÌP¢!•3-¤EaJ¤!”©&B”…6’ÒQl‘¬i&I% E’šÈ¶F̆LцÉ&Ê“L¦¢1Ë*™¥1 P©“DTѳSb“(²2bJE*I!e2,Ji‚´¤É²’f&É£&B¡¤`B5$Ë)YI†ÐY6J@“!%“(ÈE3A’2™HË0–’•Mš*6‹BeÈ”‘ÔbØÒLÖE#/&60’FTi#/*%k,˜Q¬eš™"f‹&–DJÅ,€5JJ2ŒÒ5µ6Ûh(¶0IS@´”ÊHÑb™)’cI£l–”³F˜¤Ìe3K*M”±jdcal’#5›(ÊFhÓe¯Úmv4…•¤¤%J2SX«EbÑQ²IšTDÓ%KAQ°Š’V¦"†Æ–!™e) RF³*Ô&Ú,Šk&Cc)–•E¡bd¦5-*c$&,32•Y£e”#k*ER©X¦Ê$²£)µdÔˆÖɦVD©5 [%YYJSL+f(i‘5£KMD–’%ƱXÕ3h¶ÛH3`±ªÂF¤Ñ¶Æѱ²Qª3LÄ5E!¨4jÅQ°ÍHmbY0¢5³Rhe1%‚h±„5(”Ú–Äm$šÆ5!b´’šµ³VÓA,#ei6F&³l‰3)©¥#5I–Õ6¢–’”Ô²¤¶š¦ÒZ¦˜“²¦Rɶ–m¦ÌZ4f¶k32I¬±¡›¤ÛKYRSJ(ˆ C5J4‰ŒQ°b„- 3–ѵ$JME2š£iI¥FLš#/%0ŠE,¨ŠAieH€i¢˜)’e6hbÄ„¤TZ,É b•š’ÀclË3K1š`©¨™Ñ2FLlBÌK!I´lI¤£&h4‹2‹S2TÅ4Rma3`Ñ#5TXÌ1S6 RÉBlE†54Ú3 3h¨±±±F„hÆÉ©¡"“aK-“$¤¦L¦Á’Ø…3R‰2I²ÒˆJ¨²Ô™¢6”ÒlÆÒei+Ä#”dfM”“BTš“)FÌÓj[,Ø´”³I²lbTQfŠJfdÑ©–´Œ”¥¢ÁH‘›$FY‘1¢Òš#@ÖY6Jhbb&“I F¢5BTmmˆ­1¤ÃI2ÄÊ &‘h¦•É K#5¥e$š *5“0²ie24´›mIkhЙfÚ‚H´–ÅA£ ,#/›R”JQliIš¨Ù&k2*H’£I"Ë*ÔƆMEc&&VJˆ¦”¡Q¥%4ET±*Je)FÛ`µ$Qd£dª0Ê6Kd¤Ô›j”ÑIEJjµ&ÅCI3d†RTXiH‹- ””ÆhÁ´˜#5‰3BÁª”FÈÊV&#JKEhƲEd„6%`Š1”¶#h¬¤”T€h1E& “V”ZST¦Òj-±¬VÍ1Y-f¢©š’‹Å(#(1³B$¡4l”Á£VÄm‹hØÒšÖHe¢#5Æ&¢Ñ­6Ë6£h´TZÆI5©fÍÒÊĪ1h³,UMIHÛ(Ë)DÒFÊÅ`’Æ’Ù-d¢Ô–±I´¦eM¢Â‘QIF‹kT­´ŒeCI¢$©”Z66† ÒZ[$ÛIŒÉl‚›%Eµ$¶ŠÑ­‹FÛhÚ¡K&ÖÄZ¦¥e´J2ŠbFÒL`©lMšlT‘²È¨ ™‰1$™I2$¡jM±fV¦?‹çý5üKý&¼ |ü©ŒRžÜÐZdI‹©±‡þå©-Iû²Ò/E¹±ò»´–^ï|¿¦¿¤ë×ô£Æ°Tԥƪ?ðÖã,Sý^‰b¨ O¦ò¢ób¬M4ºd7%‚•Ä3³m´5T;%ëvþ>zãyg÷îÐÿƒÌ³'ù£Ÿ,¯uc/eÕLŠYÝ]ÈZ1±, òt–u÷ë-²'«êÆÚe)‰QéjoÎQmå¦Ðn¥ØГfN½1j—qÈqÖ=c,„Â’¦6Ýr¸6=)`ó¨S‚¢5Š¨ªìÃKJÈÒ|9ëW®Y×[#¿Êní·ei”-M(¥@Ñ ¸_ñQ eRËFƶh&«ìºòO9Q ‰¸‘6Y6?óÀÝ€4Í5ȤU5vZ±ËQ­îX?ùhÿÀ¦ãaRµ^Ô›2Æ*Šžê2ØÁdX¿ë¹aßÝZ3#,©Ñ#57ªAOS(C (`)UAÒ¼®—é­u›ërÖæå‹òöêÞKŠež f>ÐD¹Ó§‘&²–9©%C™E¤¹æ%Š¿žªùOUòmº˜šƒ@ìQ†EÇÛ{zY]J4}]¢­0n(i¥JÂn@rpeË’nºìNºéŠƒ}K[ËÎÿlàUŠ ,D¬ÐÑ(Fí¶R·-"‚¿MTFzè­UiŽ´ÿÚz`™`ÿ¦ˆÎ™O-Li6ÂJ°¹@`@hÔ¨OÐVâ<çÕ€˜Ú˜Dã™{Œ’àq¶Ü`Cò“U}Ã]¿l]~>îÙ›ˆ­Vpò…§†o‘;J0Û)¨ãjåýeNôÕ8TãLhµÅ©j¶0æCfB(t\´Ã·µö% v3IêåS—ʉf´0 ÷09!àá­ñÁ±´µºÎš‰™Ú†{¦’z XZ%l²ÜÝ(ÂOa"ÚO– ½:Þ>×åŠ0ö@¨ÎÚÑfÉPe‰J#5WïÉ—RcäÝ¿£ZÁ6–‘»GÕ"_ºø7Ýv›$£#}þ»_zîF: ãe.¶W7"^*®P‹ÿ‰¥ð$cós´WŽLŽVÚiþÎУ²?.ãä]u6Š1£^9™dÞ5Ë–Æ«ù)¨Óï84mëwßêü¯ ™þº¾ïó{_Kâíå¹£UÝ\XŒQd$Äa–“Þ뻩 (hdS£C"¬éÊŒ&/º_†W x«¦¬oW“ñ{ÑJ_7*#5¾óáy›â¸ÌWíMu­»4 ‰"1SJBÌV·b·cX²júOöÅòW#kðº„"ȆùkÁ‡ÏPÐ?íV"0ãKŸEÓlØþz'<• "1Ò¶³d< ™!µõwë¼®mÔß9u#Es”H²sª›»Œ…¦õAu¢–•­Bz’ZÅŽ£”ÈP‚wQ&šÒ›³äšêP¨¬¢ÚTD×¾ï˜XùíÏIà•½raißÝv‘’dªFÓÊÊ90Õ L"ÈòªKv‰ÑÄ®áçˆ6ÊÃm-8ÂÉ2ÔQ¶Ùìᦻ`¶"§#5ôºœûªŒÀ(ò@Þø%€.ê}UÁ b‡dtAí²—ðŒ´Ö3Úá·0÷"+„úÇitˈ!cûœøÏE0Œ«“ꆀáÇ6¿v¹ÎÞ,MP—“$XŠ‚Œb‚ ÝT‚}åuÒV …H±CZ*SHuÅqf?áNåyaðÚ»™:¡¨ã…ufÿ/jiÉÐ80jN §Hï¯Öo/žø9`Î>®¿/,šÁ)Bµ)ÍA¿:—+«v#W*ƒÆ|™u ²&7½DjBQN84ÛüÕK°™&d¦«ý#5*mÏí¯gÓ|¸ÕÍŸQNoø (|‹¡Ù(ÅsÛ_á|¼»ðÄV'rï¾I3Æm¼c+¯-ÍIŸEMT}[×@0ØÏÂŽì$‰hJº¯ZÅX¿|ê*—º&dìFŽÚmÄŽÈŽ0¡üGʯg™kú‰;¼e ÷›¤x Á×ÇœønãoîqØàäñÕOì´÷¿.w’ô‡ž˜7p’3Œ¶=æF¶÷¿½P'ãûµ†HùOÀÌhËhÕq¦{æ2°oïüÒ¿„ѯ%BÒ„–¨¯:?_ÛëñͺC—öGÊŠo‡®.W’wD+:Äy/²"]žòæO{{õ•X*Rpª‘ëkq*(øV1)"­¯MëÝ´ò‹ýfŠì†˜­PcMïôå1­AÄ«pÒ¤V=§Aç=ÓFÐì¾ì¿n.ØÜ=oeŽH!aÝ$™hNü|dm«]-üÑ”ÈLÛ@áò:<¥—¤!iõ—o »h-ˆHAWã‰ûs2±ÃpTªj¹î]¬ð«³ƒ-öN˜H”Š#5Ft—æ¸>ªµ¨;ùÖ”ú?ÝŒv3ÜÜ¥D#PübžÐÓ®ÏZ:Ö4@Iî¥*h­=(<—Ü+Ã4—|õ#5ÇÅþŸšµB—_xá Ÿ>Ä4¯]ÀG§H­Ñ Œ|]#5b"«£.xù›ã•#/.SθÊîta¦aæ”ÚØ”†•7lDݶØ1Õmð¿þü,8HÑ“èºr.ÿ›>y#/‘A;÷Éí âo͘«HjEá¤Aƒhlù½W—â(¥ôvÝë\—évê0‚1:éeˆ9Jö0¯¢ÑG’·I”Ü•óåþÕéçþ§[Oïï¼û6±º{0)º¡J‰jUª×’ÒÙ.éaðg¸müÌAÖg­@I#5ÇBÞ‰¼`ÑG¡àaé-†{_#/™[á%Îs¶­OÏ>Ñ»5²F3Ù1õ «8 9ºùý71ÝF¿m€§zä¦(§-|4°²øbÌdj~.£áøQ’ʤX€Š=_©žoŽxpîð§çÌU5øøïWìýÊ,饌„{‰#ŒÖ³Õ'‘Tiç¯<P8°)‰:YßmMî£b‰w@ ‚Á@a”ãƒÓŒ=x³Õ¥dÀ}øëy”Ð+MuÞøb…#5nê3›°èM6~ŠR-äœÙ¡‡Žó\æòx@ëpÔ8\Ê6ir¢t{î¦P¤ª¡AFšòh„»ÜäSC°¡ã1ºb™RüŽÓ`^©š;4õªâÍl)W»µZ›ívE€Àe³CÌL¢ˆ²šèóª¤;&#/F‘Ò§»t^yyÊxq¦.K•ö3¸ë·á˜ËÌèQIŒ:d$Z¨g§7‹ ”†B©É=0JŠBJq¢}öÉé†>4ßi¶DÛ%RR„Ç’Â"[àCþõçoqE1×íàä‚ØáÚ{~Yƒ>«ÉökZ™;xZoÚ¤Lhø‰êÂ×VRŠÄ9³HÉ`œMuôÆÅxë²7cÌOrJD2ÇÓ: uÁv˜ôOîrÊêe“¦DeÿØ$Ï:3Îw׈X© *B²‹Ÿ,žöJø¾â¡œð½Úõˆ^ï0s‡wÒ‚åÓX‹F¶;¢ûn^Ÿß‡Ž›\ÍÈT#5p€Lt"Ý3ÃtíÝé8§Ç§„ÊóÑšMÀ¨§ƒHœ(£1ÅBP0ŒA¢Äßøºj¯f¯†§…Ó»}s[Õ{C©Ý}ÿ>Ï7M/e«å-o‘Œîe‡#5#5Ö¼ ¤dSRª{^{÷ê}i›ƒ¤#,$ ¡NjG÷G5íIÉOµÇÔ?Ë–ç§WègLäãóg]EÇòü*Ô;Þþù» ðzþ¨/o/b‘œwÒA«^?%g%ÛÓê÷ªzn©÷|ö.?#×}$éäüq=^E¤nñí¥¤Ö ìFcïv–f¦¶,ù#/³,ðgîg›œ!³¾#5~Š«ªPžâiå:: Ðš:䲦‰ïQi±WýÐÊ9ªÃÝkdUWk¢™B#/IMvýõgØøé(:0Ì"ðp8®H±/Fý“à@ô:Jæg‘ÿºÃª Uüבä¢e;tÊ™á‡óúÎ3†ÙöÛ¹ðÐC~ÛÍêÜôzM,„ÂçöÂÁT®œw6—j†)Ú!¥kûçövñ|­Cï£ÒPðˆ—.QËËÀGòB|‚rÆ=*D2•þ,Ñ®wÀ ÊÈßà›3•ÏÏÒìâý©ÕÈá´J?JwHMÂSÖ¥ÒXTñj,‡)< Ó'iÆ~ÈØG÷u>’wºÒ9×w5‘¬ú¹Lf8ë$„¿Z‹LÅfã4ž.çÒœLVsR÷¼`ÆY ALjg½)ÀÅ“BÏj~oJ“4„³}vZZÉU):èg {·£uü8P¹¨x󘳜ï³leüÊ:o]éùÙìÞÍÄîß<ï{ÔǽY/”?3Çðé5œÝà_µÊÐÓ1)4º:mË¿–šCuŒ›¥»¥ Ì „(b1#»/4ÜÂc-Å;Ä2Ž…Ç£«1T]†ÆcFzÏf¼ñ…YÕ#5FmUSZ6I»+dU½^¶S#/›4ãßO ËD=ô[¡©ÝqŒ1ùÚÕ¶UOÛÖ±Zä~ë3"Y·þ‚c|4oZ–0åÁËú]y‚üQ›‡ÛQâûÿFÃãó뼟#/6#/ùAA“Á©zø`e°¶÷¢—TT•˜,„UQ²–PûzÝkLCh¢%jV•MP-R‰¦˜.ð€èÔdNdƒMÙdJ¿•ù¢ç;­Ži]š\òQ?†8ÁUòØ–†Å#/ yJŸµRN5ûZ+H÷5úZ:||jînÖá¹½h§ÂqÖŽÌìëÙ˜ÕaÚtèI«Ý#¶Û‘‘§&ZƒÄ‹#Œå Ñß÷CÙmÃ)ã.#/„6G®it¬„/½iô®µP-§¥Ž¶›~òâZ0ú:¿~®J+JmÇM}î/sÚ»±¸´^i@ÁÑñ©Ç%”ÈCÊAòÍThÝ°Ñû|Æ‹Ç[4¨wpUüÜϧ‡ýú#稺…f¾\bÊÏLc‰Ñç¯B°Vü8éqæ÷ë²^©À€¡ Æ&[>¼Üµk6ª«Ž˜ñãl<ø9^K#/ÎÌSm/××;)ÂøtýVÖE×,×iýëþÖw-#5õÄ4&á7ÂߺutßÅdwçi#/>÷ÅZÙ~ŸÓ™¡©]w«DÚñ¥ï¨û|œ»}>˜ê®#uŸ¤†òñ´ÎÉáMgYYRóªó«TY¼q‰f¤Üбœ*qoj å›®¥ñ“f+­?Éæg—mº‡Ký¸Ç&Lã·C}W$3Ó«·4àe)„Þ«­býŒÕ“|×Æ©Ú²ÂÐ>u?……#/$î‡Ìã–æÂçŽi¤[Sß¹åÔ‰¦Ì“æƒïù¯|Ó #/‰é®Sw?„ëë›Ù{œùFÃÂ.Ó_Y$ŒøFïl;timâøv¬¨CÛÇO”+)ŽÐ~:*‰ºx­d!žÆ4W'߶Q1üÖðoØ„÷IëúÂfOÏËz6½Š²k.&Ü‚õwsŠð$D981…2â®Í»±í´øåsÊ#¬ŽOn6ÖØ›*3לÊ[LÖhùW’"¹#1˜|α#,TªME‹ºMqéªoävs6¸]–/œqŽ\ø<$öAó©C}¾%è•©LÑÉáSéM$ÔV9Ÿl{§šzk;öO~)tW¦\¹kר›¥§Uo‰˜–¬LÏ|^Ó‘s›¥žsÙe¶»¹ÖÎÝ›ìanÊ‘ üj‘@z•A6‹ßøý¼†ö´3Ž°¬·‚W{x‘a$ý++o}ÝZ¢@þ¨³e]Ò¡ºà•3¹äúT?Ù…S¨ÛU5ºÚaŽãnæ~ØbPI𥠮Ž¿/;#5ä‘ú ¦ÞªR“9ØK8ǣü¼9·Ùѽ(ÃKhœ-¡ºGsÂ(Ùk8Aqj wÇ”„Uü° s¢Ç“ÏŒÚãî‰Uy_¡'·~Â+Ž~ÕXgÔÒ]©I•â#/Lx¢ùBw3Â>gGè•B²BÇq×]!©¨w]ßçÏœ]vÆg›ëNßM4ô¾À§aBú9æsÒ5xöí¨£ÞsµG ’†Y¡Y†µ£$ÔÃîz´”¹@¾ì3š^Gt—+Î%y ݽ,Ù|ÛõR¡T¼$¥¼´IëCî—ÁYÛ;gX²$…MëÄäóÇC ÿ‰§Ù¢ªvgÑdKÍ9oI×V³…™ëÅ]ŸJÌvsȵ¤ŒPRÑ®¶Œa“¿÷3QÙ¬C Œ>©½–Bû÷ìÙ0´·¥òTUBšˆEeƒµ¶([¡(ùhí†G„\ìÙII“Þª‹K®D+²QÃášÀ«YÍÑæf®_m#/žìt};ôx#¡ZÍÎÖ·øÆ>cÿ8K|MPÓÃýPññå’ŒDÂd!,›I¶KƒÊæƒeN–ÇMÑbˆdÜ]‡ç;ê>¢ÉUò!¾yzwîgÓãòç¿ÐªPÛî[Õ@ðú?š@“L$NLjÿU­£¤PX´[7åä³ev4ú®P©iÏ›iyÐI'iq v†Êyº#/z¬¨¤8è‡Zõjòú¾›ž½¦Æ†þ Éîæwñz{&|I¾ÝZáÐX‰˜¼DÛFì Þy‰ÉT,cšÉ˜@#,˜`>únãùªfk­ÚøX~8Â~%·e“¨ócº¨šÝäÝÿ<ÿ¦æÒÛ Uí·i€Û À‰G’oŽ ÿ_;#/¿[´²Da©wà¨Õ  "Å‹>gΤÇÙµ]'•neÂfqU Å‘©z='U.aš6|½¥v•…O…¼¹süÓ¤QîüåÜÉšo$ !ãñU³,ÉU«}Z#W`åÕu”8Ò0HÈE[„^ÛÜ`//«]º#/tP^(ƒ–¸–wQná…·„VÍ%Ît’bƒ(ÚÌÌám˜Ìݽp“L'o˜“ 5û'ìs¥µË/”ô›Œ@ V„ÈM^%€æ-©ÞîbæaµÃÝ—«©bíð‡¢›ú~øûþâ€cþÕ À¬-Á§ø°t‰š„¯£PŽ#51U·Oìï,…P‡Â&£ïöw̯m¸âÇø?èòb®uYƒ©ëµ®Ê9•TñÏ?ŸM,ýxÁª·ögß ÌÚ¡¯F΃›ãӮݷXG÷ÂíÈÑU^ekuþß'TI²A¦Hk+Í~Fî!I—vsõ×^Å€ã€ÎQçs@õM=¸ä˜#/¤fÿ»¦ÙÕQL"žSL+Ü¡KSiÆÔ£ú sOǃ:…NVʹ”SsAßPT%B'ú? ˜u'.BÝÝ®³é©±ËPõŽÐh`¡¯1ŠÕ¾¤´¥æã@vü©õh7)ÝwÎyî*³Þ‘Á­I$5!ÝÂe‘óÌr&šmïC³C(¸³W&HLÁRÊý’iÚB­YàÓ{­ØNlÍ¡3¡†’)G¡5ç4nÛ@Û;Þ7覧þÊÍ‘‚)¾œuËÌÃVfeš5IDðç”jß„!@¿h¤ŠG4hf6D™X9FF)èÄ»ÝünZC†ÄDKßm£IúüyüÕ¶aÓÒå»4ÁAÀŲ¥Âñ?†¥´¦g² ýX<Ä ÂZ3°áÊÞ´IÊc#/ŸHªc?Œ‹œXXÌúéíåv‘ïìÏðŽ[Ù ¼»Œî*뉣êQÖ°ÆŸ{wN4‰Fè·ÀLdIAÛƒ´ˆŽší3¨×[”˜B¿wE fì°²‡Œ„©8÷p€»VCùô ¦§±#5÷L5i8.^£TéiݬòÇ40öþ\Î×s¶©ì\løîlÿ‹=ÄlêŸp·¯vöµ®M#/µ>ÇùòúàW§{ßl½3㢂̶WTô™ÈÀ×xTs+•¸S´ÀÚ{¥EP¹§~n^&¶þÅPï¦Ê.XZ9™IÑ®¿¥=SF™9ˆg!8ïyùþ—W¡4`˜üÔytÅ1î˜×ó©7,»/+i'}‰†nß”Ùðþî©“–Ðû†¤lï°#Ö:§¬>sñèÒòš§˜ÊÛl;BÞ`–§iùŸ•dŒVÁFú8Úq”ªtyG6¿Ÿ5#/+žÆúo¡E{fð÷w »¬ppÍ(”&d¥ïqÓ­|ŸÃf¸•‚áºÒIÀçË¿1œ åU‹c¿v¨Ø餑&`q|kŒLþ 5XQpùàâj‹‡Ü23(!°Èò¦íæËî–;¤„Aë|»¿Âö¢ãY#5mÜJä:Å!Ó·³¡ñ¦øïûkM³çV1»è¢ÊÇ“’&”˜«aÌ/†'Þóžk¦ùòԉ½ž*ŸNu½ÁD½L‚Á3´‰´µèJß?‡Ðg<á@dCDžÃ#5j3xÚX‹TiˆÒnÀ£:2.î\µÆ ¶Öƒi¤šQccyHà,ÇlÑa%Btš“0úæ?œq§¤ôÌü.£C¿ÿ`‘BÄ=uìç"1vŒ•€‹ ´‡Ðb*póÜÕe…6oçü¿ÈÌÌ¡™´!³¡!&[3F a6?>¹6LÕâå\¢•AuØÍ·¬.ÓªúR|ân [#5 hŒ;2ÌJAÈôSÄ£6.²ì³fÂJf”óêZ%•+æ|bôcÊN¶G.ä¢Óg]w$¯Çû93ÆÙéó?³ÄÉî®Ý5×J7*Wk˜²jrï•¡ ªÑÎ{ÈoóÆ;‹ÓXýZš„ww´Ù·¾ ØnÚ3‹óÄ@ûƒâ\ëÇHfÅ]†ZdjÊ!“â¼v¹5n>OsÔ5›_FjÂÿE[Å7sn×(Dð˜¤Úã¿ã©Û²f}‹ˆo(}Ë¥é/o¢ùÝ3MÔ#/*ô\˜ÒÛS‚c"ðµ]tÇe¢°üL(Dvó5èyÓCêÒeòó´Ky£lÎú!ÂÅ8–Ud˜ùî–Ià ‡0¹6ä`‹œ½B˜àB[‰CÕeØ©xìú\ªN¯ŸXÄ?Ÿ~öŒZWÞxßV8gŒâE/ptv6À¨¿1+Í- ÜKu—–™‡ÂÁ!+²5D7­KaA³Ù¦qšd·Žˆ=3`¢QSO›ú»ÓîŒýËñbYuvL 7´Æ` þ_Ïò3”‘ldÚZ¯®Ü+ÔCä–|’ó9©Ï»ÀªóÞùò{ê}2%\z¸m‘oM[ ‡þjÞ=Ì4å¾q0öÁH¦Y²aµ8B󺻼ó4æ¯;‘˜’,i•¦JH,Š£µ¾XÐLèÖ¿o?Gßœ=úr8üžLÔËe%0Š(5aH­RšÄPÁŒ+š>­{±­¢jED¥EAa zêVå —%YbTÂ}~Zâç 9‹×;® Š´< 9ÅFŸ*ŒP¢“’Oö~º+fcÈÇW%Ÿ®ƒ’莚ù¦‚0þ²HXºÐf¸0íf¼d­ø×Êú£Ç<wòÍT¿uH6\‰²E…0i©¥Ìà]äÉ*ê‚ÐÖD\LÄÀ‚l`Mü6W›ôñŶ•u=&0á‡t……"|"n¾½¨Æ¸‡L™×MoãùvÈ=Eóç'8H£¿ÈSÏ·©¢Œ–!#NÌí^ ýó†Z«¬i[<.ž6P*‰#5¥«7eP¹òƒS†¶ÙßÐ7bPžG®æˆŽRÖŸù2TÆ4`œ@×8jLL¦ŒF“K"áfƒµ™­ ‹å™›#5`g©¡œæÊ-TbB¢Â®¸ÜÑß]Mt:›´Ë®ñ^6ú-ËJöh?­‘¬ù¤1Š¢¶à¨%¢ó0ÝáÑ")œ…" G¿J.ëϯé‘úw½yŽüˆSªICQÄ(`a kï5¼UÉ4[5-Q¤aÉ‹#/XEÂV\ !<î­r×ÉnÍ⯄VêVÉ­š–½Q½é­°åBê£hD‡‹F{Ip×kN:µóŠW9HU’غ¯«U¥.àHªo>µ]Vâ"/z(•~©r#5°«+j¾O AÜÀÎÆîK]›ÈcÙ«×ûj¯v={[vëƒdIÑàj=qÞFRUxoÍ¥Ÿñp UswØU+nnÈ:.öÐÍôz¡êÓÓ–e~ƒ<P¶1öÊ1gMÛ7*â_'‚Ï0úº½ÀJÅ7(’Ù#5™H0Q’車£WË2¬úr«û³Õ“u˜­¨”»ŒªÜ¹hÂÊ) OƒnšÜt¾²I [º_Ž™Ù¿]A8âòVT‡ãP[úÜÔ“™NËù¿Å›¿»qž|tKƒê¹Î[ãðŸyVàWí­÷Íø6††Ná¡—´MŠ<·u,Ư âLÁ³:FßU¦hÞ‡1ü;HÆ‘Œ @ dJ•¦ÛÏ/5Ûòë±±^¸j-ñ/F‚d‹"ÂÈÐ ’ RE—‹¢¢²˜H4›I#/ I³.Îaϳš=u:Äj¢úc³ùô­5¾VR…k/’IÇú¬îvýÞ¼ñÇsÆc«üË©’è#ÒsD»OGÍøM‹F)ÅâH„cpÎ"MUöo¿WáÈu¡uG¾#–œ)˜{žSªd>?«ðr¨dÇr6&foÙ²j[!¬×J­!bSB»%ÖMk6{fþïp#/¶2ѲÞgZwéÊ/ê80n\„9PÁ$ï=®˜Xu,[À&ŽÅŠ­iêŸ ý§/ôËRdOʪ)È(dµûÓ.Z¤ØÆ(Q…E·T(0QµÔϵ’–L·:+wÚŒ‘gwÕ9¼†!ÇJ¯éiKËÈéÛ¥þ²ÙøÔÔs“Äf¨î¼ÜûN~¾\¤Èn€˜6ó$”Á<>)Î.±X‘! ö£&}÷·¿búŽŽ ð’þ2 ×z’lŽëì² ¬v×LT¢‰d$ŒyD}^ò—¶ßgöÎøNÑŒRèuÆ–8ÖT¤ˆ¡Ý®q/òÄ}–þ/)$·´Ø^sfõlÀ‡÷*ŒÛräÊ´‘¢Ì‹ÝU,^;æ\ÓæMt0se#5kã,6EUPq'=q#Ÿ^ºá§D>±à¡lÎF•¾)NB„xSqF†£ü* Y‚$/#/2·™&½¡¿ÙóŸòàû Àܲda=®ÄÝ­,ÕÂ\&ãf*ÑõÈZëÚjô¾½!ÊóŒ×;¤1î9TÆuCBs U.¢¢$ÚŒrÛ\ÚHµÍ¹­ÜÚÝ-¦iÌ÷n½öºDSU<*ì¨.;ð`X&Écñâ¤àèŽfÖ¡“ ¸n‰d©LNk”Ëë8ÇHQ¨rö>ÓÚzÂeâªhS30gÐcÕó`L#š~m!ô·#Íí#Ç/¿ÊFÝTŸoÇÝï]ýltËQ~×PÌbæiŽ«ê±­ #/„¬Q÷þõm¨ã¤ÿaëÑÕÚ-;ݾ´ÇêÞíÒŒ[ÓC%ߊãÊÉIŠ¼ÔÝåå«çÖjÖ<êyuåB?j§«`Áœ?Á½ÆhW,¿ëh¯ÖŽ2Îÿ>rã#íåoû«"å'RúÎôï ïPxÅ—²W–Ç+Û“Ë©­iÈ"#]“¼ 1û³BF]ÍãÈŒ²Ä½4†Ÿ=9üxOÏsÂzú_ìû;áDUãâÓ}><ûáË/1¤ÊÞ2n­ÿG&iŸ×LCk¸bÔƒ¨Òuüß«/5µÓÖ֓*“Ì:rëìÙ•·¯¡_ÑÄñ^+Ëùëûª•Òó]ÐZ!ê>Ì£Ù*6mçõ¿ðÍôcÙð>N¾+ú÷~Þ>ï·òųæ3öf_ž:Í´™Ø½gDøK;¹#5ì¡ ×‰E¦Qx Õ4{hyOçfßñì²Eʼnb|•ãŸ®_'¯AC9<Õ9³zt¢“FB”Ó–¨P!õ×­¿õL²k;±ù×Óöwé·•¶ ¾Ü#5ÇiéöY÷ÂŽÁ5‰V¡GW3à«Éa1¦”4Ü åÞQcziÉIP%4QhÕ¨%B¾ïßF¿Ä*†ÚhÿÒªB-ôÁä‡IWïü¿Nš¹™™‚–X0; ]ËÂâùsWŠùÿ{wëßÈsœ¡™ÄÜ"Ä[ø¶‰A™!!…Bb3âv´Lµ%“øÊæLHfÊ–%Iùf&’Ò£kúÿŽvÝlQY\Üvq0Ι ’ Þ&¹1 ¬=Å°ÝÖ^[-ŸÌÄ? MÃnzM¦v¶‰e4.Z)M!t¿}^Mzߣϻæù1ãDF"whª #52’ØO€b¢‘S†‚&H'{÷_ôLô®ÖxŽA‡N+Qó¡Ù ÈdD>žŸ{ý]L‡v0ŽQ£ˆ0›$3~ër½¿¿®¶¿B½EXŒ°ÚŒx¾gáb™d¿é«Hu¢„dY¼#5gEkò«Öõ·K^Í]J½ImóÑ\ˆ%%„Qñ.?äùÜúS¡Vª%´ÉlÞ"–eHhÀ¦#5[*‚‰àù]Ã11þCHOÑŸ0xjgüø/¦$(—ãoð³¿%Œ_ù#5»U0}q–_ùé§ï^™?3üììÙ:¦Ú [4À6?¸ ž³S»Lë[ž13£ŒN´?á½$y×%’1@z‰»qÁ„ ÓÎö ¥mú"Õz_ ΢׸n"=°áxM *¨èÎ3 뚣IU+«ÏN_F,Ýø#âI@ÿ·*"Ãû.N§#5è’‘P‰CdìQŒ.ð±q.CÛÒçúBkÝ…gâÖbkßùØdE=l|öDU)I÷0¤ý JÃõ´#·Mj°šëjú†Þâ–füÝuý‚å£W¨ê·/ÆÅ$㇮¥‰ƒCá?‹òÕÓåÛë>Tbß-ß»Ëñ§®¿¹Ú¸sÇž>8[Â%hæïÏïŸyù*ýÿMý"MÅy—JûŸNm…>‰Ö¿*™Ë匩E¬ÄÆi|ÿXçËgáÍa×vö1•t‡=¦ŽÏßH‡:ƒo­–ƒ˜–Rô<5áî{-ºÚG"j  Q‚¯•þ³&jçû(áÐ*ú°»#,ÀJo¹|ezmûf~áàµÅê¾?Ãþœ)í†ÌýúÓõé ¬»”M¹õÂ''ßÝV7q™°¹,RveS»wð28É/œVÄídîð$/@T\cLï¡îª´3cv¾»-E±Ø£L>ÝÀ4#,Ô%ñ3#5Oóô=Q[MW9ÙetŽ˜Æ=cñõ_[*[åØ´å§ÍEÍœÕÁ²Ï¥¯è—zµd ¦ã¯‘a¤ÃB#5LÜý445è>K·ñW*–¤ßYÜz¡=„¥ÆRLÜíã?Äܲ\*™wÂyÿ~ïÂ|ŒÎ¬ÜN& ^Û ?.¹©ÝT8#/ZÅ5ý­{ò€¤êÍÄ…¤c‘°o0€ÛNÂsüþ ›:Òß9t û „"uúO|ÈU¼&;éì·ïl}ðèÞIÈ~³ù¡Þš“°G-²DǯŠ‘,îìïå ßÜñ‹ýoÒÈo½Îc|ÈÑÙHxžG¤¯ÔDy¤!&B1d8ÐÁüóù Wð_¶?uŽÙ“fñ!’*„ùO@‰Ö˜|‡+N/•©ù?ºuôgYèÏn¥›y^9ÌœûS:gwi‡³ƒóDáIM~‰ˆÓ4ÑŠ »LFÚŸµè{!V4 A2IbçBÉpVl­à#ƒýYà.½Üât’‡cšH’LJ·×~µ ¦ÿüÁØòû»Õz0:* #5|ÀK‰¥TR#,Ý TDDEWåîñ† ÝÔîöLoÏ—M‰þeaüµúå”Ò%'ô©_ããÖ\Zñn2Sh2PÉ,ƒ ÎAÀ1¥ €ÒŒ]îoFƒåÖi31-´t¡1ûzŠÉøÓÔ¿ŸÍ³fîùfïû{{¸×êòâÇÛê>th|´tÜ»XöÝg»KzÿuÞÝGÈqü·Þsé#/xT{sÝ ìÀÛ3Gš¹ÆšðÆ/çPïêî?^½tiÇöíʼrÕÕùgÝQŸ£uÖBáUüèòá»~Tr«Žò¿úOœ¦~—½CÈ·x¹éþ8÷OMµ­³ –¼wkrùãWÔó‡DÍøÆ_)À§ÃuŸ^ýÞxú—ͧwÞDá¶ÍÝÍŸ<÷Ó»ö–†ˆözsËŸ²Û=méòñ5™°;²õz4ž\ú5žž^-mÓø7¯ùü~}7VGãi²f¶ÆœףɻÅ#/íæ×+%BÜ{bÚqóöž9N+ôÐŽ:àÞ‚¹í,9Ç?§fãÃg=÷í|ÝóÏú©–ª³Å»«–È×#/¯J¯ÌGFÎjàu~~=vû²l?¥0†zJäOtªå§Vy×l«4S\‘,‚ñZºö´Ipç=%Ò>^û.ðSž]Z·U³´UÒ:k²;9ÿ]1‚öâÜÕߤƎ|vø¡nj·gmJÊy çÝ—IÍ®Ìô°ù\ÀÆ2+ׯ‰#5U¨<8œ„äŠãô<¡÷üpm~òÝ:ê~Eüæë|°¸Ù·Ô´éJÝCø‘?wŲîû´úyüv–CŒ2ݳD'år.gmQ+õao.]¬ãÍeû=WUZeB+ÏÒ¦ÞZ¡#5•kôòvPÑþØÜ©ºþQÉ®S†Ùuü¾&¶7Ó3û¿ >¡´Iëæìüg™ïª’ѽSIŒ‹ÍR¯ß$£¹ÿMx~O6{‹!׿?ÎyÈß- ®+òÃdž_vÛ:¬È'ªÿò=Ê¢ï€AáPe Êß^»óÚlËuîŽßoš>ä¿n«—×áåáJbíÑüÌšÚÛ£þ÷×ðÚÕŸ»gËüý¸òÕ›B‘\çýœz*Ñ‘õzÆ¿W51ø/U[dXhÆݹ»gWó=™9µYgº€^ÞY÷}’¸³O]Ó/n¸{kÓÏÏüvëøº+¶ÉæMrôádÜ„ÿZK×\6¹þ8éjË“qpGtK³”×°Ž3öfÙ¶a²È—ú|ÿÎË~læmÙºOy·ý¿ËwÃäïúáXo?[ïæÛ|ñÏÓMB-Ñ^Ÿ]>&æª>ÚDò¼Ä(ŽøhðúwsþZ¿IºPØòÅè¢FFU!dÔú9Þå—ÒS“åáqC°H¤"œ‹L$⟎Ï_Å *l‰¦>@E ÃZ˜¶25˜fÚG˜—Ùòi÷ž ß»´«Ÿ´éê×óùù_ËÁ—¯òù~z÷öè#ð9‡œèòô°spšìúX¿oë­¼ñì;Ïô÷ño¯òþãfoš­Ñlí¯WEÞê›CTÚ|ú_Ó~˳s+\û~_x~;tÆ~£Iaæ&Ü^–¾7Í«/=f8|ÛEW.¾vÕ®ÉðÒ|ìº'ëÓi¿ðêÌS|²·•Rzì¹Û»låøرuû+êZtš§­­Pg•±JüíP9¡[ÈVË1qB T/;WRØž•¼/“Ý©tåÇTë²™^—Ç®œÞîeJKNWõf»–TäSsv'k»òÉ)Ês³—Ù Q¸ÂÜÍÍ)ÙýÜcÆy#E’I'!i!¹Ž¢Zƒ9/ÜÛ?#/^k#5óíõ ²¾>­_˜Ãâáâê¥;žÀÝ*kMê”;þ‘:ª'¶S©¨f‰Å<)ñí„>8Âœrìçß„1ds…óÂhœ!rÐ˦~߬rl}÷5ŠÕ½¹µwTb©<èäPÈØíÁõvDN¢Ô½ãvïŠ~¾UÞ±Þ·!žZ‡ŒüÒPéZ\ZgW ËDK¢’áBQx 3d¸YfHg¿ˆ—äöYp¸hâ×a-³Òf*•ùËrϯ˜ªÉ™l¶üÓ›™½[;âh÷üòÕauÀ‹bq&„ÑÆ%£–É„zV€Ë1 V­„±}2+†ó I–ºW k-ìÞ{ÿfë„'¦o›}†üµ=uÛ9c{bgîצ^cf·×mv·8›ôBP”+çšP[ÂiÃËMùõ>(c“9§HJíYŠ¿ÙàW§=‡ùK¼`¾—üÔ²y»5íÝÍò|•V¤r]:’®—vw×Ê—Ùëëü§GÃ/¨Ú#“tð5/ÓêÙ#/p<ël{ƒîŠ²Iÿ_/d¾Œºnå‹Ó¶žÉF Ùy!ÝÓ4"«ÎÞ6Ý}F8#/ÛôÇÕÓîóú¨cê4™G¼26©tÈÔsyJ\³Ó×Q`š„ùd`Žï>p#ûIȃU^^J¾Š¾©…×ê­õ.EwË»/¢ÜÕøý$¾ŸËWõ­a\q´ZŒÌ¹‘²¶ä%`Ïž*;GªAºÖÇuöÃta­¬¤°ŽƒšVŠ•$Ç´Cc†E„‚ª(8Ü#5*"ªjDÚF 6ΞšÛ[k[‰Ò `ÒŽ ÈLXµ‚V“a¦HhÄYSI¤ÝU X–š’¤0­Ò#@ÝÓ¶–k¨¨,›Ä06…ûóüY‹Ã8h Ô$m÷E¡=ø§M§X¾îóÈÞ³!¹À‚ŸìuòX~Õ1©&~˜­Zj]'åþáhkQ˜XÁàñغ9ˆˆ¢13S²%”R(Èùªæº t{¢t/9h#08Ž$ø™”ˆŽJ:QFk1}KIPc 0i`QV‹† M@„4í Dé Aà<Èwoì‡fIˆ”xS-ÇÔgoþl,î)~½ÿŸt»gÒ·Ÿ1‡ôëÂËóQ¨ñ/4W¥hÑÙÓ?¾«9¶Y¤æül¦Zµ%û½CÌ·þŸÉæÍ÷a_#/úz~Ó®ŒDÕ‹u~½-2üÔß]Ÿ%Ë<ãÙâ{n¹w;åmxû'š”ÓæýóÌ=ÇÏiäÐ1¯¥¬i5B·”}#5>fÅ®>ãÉÕêý_ƒÿ…^­ZýišöBB°ãÊ DÒ8%k½ÿw÷­?AfoºwqáÓ×¢}Y?¦ú‘³ñ…Ñþ’iIå)B1x×^@Àäêñã?åÛáO%>ÿ?㪥Íá4N=ßÜùÏ/ÉguÉ~>w祑ùkêøºÿºþ®þš»ïüìݸÝû«ü5zë(¨–‡î¤à}†spçGÁÊ|¢®õ?È~Aˆøo{Í8VšÏHm0ÿaÌcb!…hô22Ã!I¥n0KJÑÊØ¥ß%IH Ó@ÓHÁ˜2¬)#,i³ÜuF Ó¦$©Z¹LÚ›&ÈÉ®Ýôó^šö÷ÀÄŽ˜–™SÍ)jŠ€ÄÀr7h(UX¥¡`È£¡ÚHŒ*V&šefeX6<+-iNþüF„<Ç+Ú“{†º†Í„f#/² £IºàEƒ©‰‘AÆÚN…iÑÅv“yåN=Q˜R2ŠŠ9‰Á£DI°n€ÄB° ›pcK J ¸‘Š)"Éó†%ºæ¡¶„¦ˆ2)@lƃ2#/e&:EÕ‘'(<)‘LRÛŠX›-7օ̤«J#5%F#50¬ (älRÍ>7³Mi¡²ˆ‚Æ—s6„B§ˆ‘îÀÇ⢷f“ /öZU™¨¨V¦œ®Â jPï‚ÀÇX`- ed ?@¡ÐóÈQ§Â'Ѹ˜.j.DÝÊGºìqrº¡hs#/ü¸1”>=j0}'t’Pƒ»¼0ïsòM¬8…Ù#/¤$Ò¾«š0,ô.e‹/³ùÕå¹óš~hsÌÀ7ïQÉá8m5_:ˆñô{þdã·ltþTmg"éø•vS“Rìi— ²v÷I¢n7]#/CŒŠThb¬ƒÖ0£«ÊI¯DðZª^1¢ìfe!™i?Ï#8þ^[©50î!Ý5ô;ÖÿŒýÓôø›£<(.™£ÉÄ#äv;³)™ ·¢€¸ÄÐ|oà¨2{»ÙËþ\þûn¼XôÆ–TµMå Ú­EUµ6Ç?ðíS§Qá×±ÿfhèïÜTU¼Â[wBëµÛ¤/ÑÜž¼âBBåWÙ&Ž/^ša6¼yõ›¶MšºR—±FåºjnþHÉ$·o½•«hqØÏ#/<Ú”%­èµµ£&¯­¢r¶ý;_É56„UòȇÐVç1Ê'}˜}CŽnLé €ø •DÛÿ®±¦Ú¤ld„q‘!¨—ðb¶?Ó—MìÒ60¬Î8;"Ê·LÐ!ÅO7³éÕôztÝów—ÎõøOþ¿¦_DÉ‹cꀠˆTH(¤QŒèkš°ôÉ(VôMÁëLê ]Æ‚^©†1‘¡¥aÃ[ÌÃTu¢šùè] ÒÞà†r‚Ì2Æ¢Iæ¥f˜äq|(£x8V‘Šã3ƒˆ]»” Ò*0be¨°#5¾§¡è‘MÊx›X0¯g½«Èâ­–êŽÞÚÁgáó1@¼aå°Ù²=°¬h´;_ÞFC4FµÝ£*%ié†'äeCÑK9ntlV ‰ž™’Æ‘à:iëC9ª*‡·§iâ3‹b4‚ƒPK³5¾j&JQ@z+F ,#Q6ʵ´kï`bäJ.×^Î )iÄêvº‘rŒ‰6Q¨k0wçc+z;EA³¾hk ·ÄZ4”!÷îõ5M)Ž4ܦˆæšÑ ¦ŸüŸéž&ÿï?}éçʪ½Ñú;úéC£êÊÈô÷S^_kwž3^c¿ÏýÞrìº*>äV¿¿ˆü)úØmâËÎI ‘tÒHÜØêluÚ~&|f7¡TΘ77lÓ€ãDc#5çDŒx»S &´21· 1›l£'bF–åÖ“qÄB2š‹õ’,Ter¢Ö9q¼UºöT²ÀÐœj¸¹¦²dÄ…”9¨´SLŽÄËÌ…’™A ZaϬ|C;öÒ®½-j†‹´ªÁôÞŒ¥¤e]Jß1§×@l*œâCr¦[‚Çã9¼P@™è… àtДC0]#áŒfØûÓ³AqC­I*V÷Á“&sbÓ-Œ^,\ņÊy¹`tœZiAȤ ‚ŠGb“vHƈé”OR¿ºkYþkÓ¿©wóõä½üÅïŸïTGò†ÿgÇ«Ûë{ç1J6OøÅ)ÕãWj¶63sr²Ž„Z™ÓÀ˜0É©4NX°#I(9NÆÉ‹³»ÌlßGqªVdþ¸»­ÚcºLåpr¦v‰ˆa”G›Q#5šÐ&àð¼Ó‹0œ‹Ô„¿L¤—ô#fÌýí£#/êüj̳˜ ë;d3ÄÐãž,X« n¹bŒI”ÈòQ”pÔ.6ó²ÇâA±£a©¼l±·#f*U¼Ã2ÊeÃs]×›ËÍçW]9wP$$¡°`ÁÝšÙbЧ…ÂÍV¾þMw+^ïæÂ" 7¾+š±]š](Ò†‘ÔÀ¤Š¥R —mdÓ×GóÕ¤ÆúÿtD˜(4 x8)#5Ó°ã —È’4û5ÄlËŒH™˜¡#/§ao|›!ŽñBiNb™Ì!8˜‘±—#/’ÎoàDJÃö°Þ[áË€™%À‰Uº;åœ3˜aŒ/Í8kÒ fA#/¨í;æ~doa™]7›8:›ÙÉ°Ê`”ÂBLìívP¾|l¬kåóñx ¶Ð“ZôãÍ©u4„¯fù}’Ê]¤6ªºÉ²¡°,™&M+ˆwònÁµÛ#/à ƒˆ8,·äF Á‚÷r7Q¸J-âœÎ-“vmk­tQ6v5#5',ˆÇjŽÚÔÃv+zâ΃®©à+GÉcvs¦ÁÒ´ÝXÎÐqšW/€š!³X:XÆ1–¨qïìºÍfÙÂn¹ª\†¥HÕÐkƒ… µ‘Æ»\ëÙœL‹O¹®psnÝÔç\“..L“Òª™Zµ–ç%'frf“€ODHåaô;ôì÷Ž#/bûõL^…vîóØ\“#/ç<ÓLEç¥Æ#ÀŠ5x^éö'>7®±å->6ÚW¤òßoÌùëµôSƒ-¹ò~ÂÄoƒFqRæ2>De^ÌF/K©± ·}`²ÿÔsD!ô!à˜ÎÉŠÄç£ÿÉ&û|¾=mêw%²êOçÀõ¹£~k¿ †§µæesQ»?"ë0òJ»ˆØ+Uny\(·˜›qUF̳ÁSl¨·ï©ÆËês¶Œ]$„¥:dsu§‡å%ýš÷̧_#5sûL†3Ï‹{7Ó›fïÇ|2SDï錙49õÐèõi[ã>•&™0™2@×ÄrC’™wì®ï·ñÞfŸË™ŠÖYmsD¨ìz;A‡ËÃÍõ:vYÁ—Ášˆ˜1bð°]2ÔøÈCæDv!ÌRoñèqb|¥)iÅpg“¾«ŒÓ'šZlÿ¯GL·Û#/{Oíq„g=ùo¥‹X[èÃ¥¬@c«‡‹„CY·2Kdu£é}ÞˆêýÕk·;9Œ5[þ½§\A|+/éwÇè£b $Ú-2 exìÁ2f*Ÿ)ŽÑ—-üqÈØ2ô’½²\3°bB„b`•E£ú¦àoêf/\dÄ#/$]‘ ÉPq©A;HÁˆ¸;€Å3i»ø˜ô3žÏµ®³¾@˜)à‰DËùÛœsª¡àLï”þ¦íTãÑ¢¯´Ò©H©‘¤Jœ“ð&á=Så^;Üy¹…3«€’ƒÔž…K¿‘Ó#/ù²ôa¼#¶ßJ(¿¤ð©'ŽôZen· Zoí¢£Ü²[¹ƒ^o(5úÅd÷o]§h=Oh’G·&{¥ü#5dýZ…ðúgHÑzëºìCZ$V¢ð¼fS%¦Ã{i› n˧ª(“ ½‚0GË«ãšßÀ™)'¿|YÀôxÇhv¤™‚!Ƽ1ç׌ìÏsFÍ[HÜÑý½œuh劥ûÅÄxŽZ_)éúD©iœ¦jL<¹ ÖyÌc†Ì¯E¦²OóON4Z”ãæ&NFÛèÀ»C¹ÀeÑË5Üß$?ääS¯?ÜD3ÊŽ¦ÿN6ø¯³ v‡«.å:¼èÆ!€Hßã<ˆ]27|jƒ$Ó‘î¨0ÜÎTé$=Ì“,aÇgG>ãôDÞ‰á@'û.'Øøñ£_%æš·‡ ýUgn=-šåMŠroš^bZk£œÓI«&˜t:pé²2¬-{n»}nû10ÙÕcb(€–æº_FÕ±í£+ÅV›-÷´[}ʲ³PíŠÌ©¥ λ‰¡ÜëÂG‘Üv¨¨3^Í1'bøŸ˜ö/M˜ùöÑ„níevè›;ôJª®åÖ)l¹Ê—qµ‹w–‘¸Ìv]έ–j–f»ãÄ;ÿåQ_'.=”Ó‹÷¹”+Ãçå³ßá~ÃÝ‘œj°Òaß‹ˆg—Œ÷ÊXÆßXl´#5¬ya(\CÒv»±Å¿w¶í3Þqf2N"^JHç—æÊØ!þûÖ‡ø¬¦ìîË‚ÞSØà‰¹'*…Î {æç\•¥Ùq#/3”Ó†_gÀ’P—]ê<¸˜þ_Ê篵äúÞø¯Yï§:pùÁ"&¯-P&Ð5*¦÷¨Z¦–¼øL‰Ê™¶á™€ÚET4 Ë©:G¶ºXØ_sBÆ;2וZ~gÑqwF¸GFãÎ"[1”jjáuIý&™çà®V÷Ú›zC¿‡lg* ®¤]ƒ Û]jP‘Pí-Ç~Â#/Sa£â›[ëf<òÒ‹àrª9–b’ÐÐvÍzg¦­°¯\ë|õéQ’ h!ý^MÜmûcÎËÛ¸‹.Hn%ÓV3û—¬O¤ñNc3ßi{=Ûæ¿ÉÕ¬{ÙÛ|Á6ÓR„ÐâZôoÍcž.±ìÎäi.Ù(Ûa–U%ÎE;Å·¾aÐQŸ&Ò-FL4aØW*µ$MÚVÀƒ ¦!ÉæIˆ9Gתªúã§bDÝdÀ:Þ¤¥-WjjWÈè^6ôìUðäéÝ;§·KWñ×UvQ¬·.¡„*àóJ#,Ü‘$†s\’8¨±Ê'ø {ǧéÌ¿=sœ.ƒø/奊8<³W”¾=¦Z8l`ï;1)qŸZ·zΨœ{¹ÕQƒÂ‘ÌN'â{#,ï“ß®FâÄ›nØÑhùÇ;mñ1Mé²÷#œËŽ™q(¸VU qCáêÂ%I<ŽÎÍ™4s¶äH“°‡¿œË51€–$1¾È'lLq½-wqVaé¢4í&n½2/½¸œù§Go\ïµ\²t“÷—%øó¶ ìÖÉù*£ß2Š‡ðÜ÷ÎL$mð,¨‚<#5ëÆS2Ê[Áïs}ÌË¡¾Ïûï¬ Añ×R&9ðrD·,Ö(ƒKÉ賨Ê!L½FªFv³¦Â²P!f¾òynÌi&•îëaÁF,Î=x)“Re¦Þ¹=5"^#?#eóO•Ç-½eÀQ€~²,Äx-¸Lª ôÈlgW‡ÕHþÃ×—ÎÌ£}Š°˜ÜˆI n±hš{a¢ÐŒ¹ØšTéyV驵ú0ÞåèúÂÃýaãþvD^fÝßü~îMQN„ÉAÝWG~ïÕóÎÝŽÍQæ3]Ÿ)û#/»lÒîô\ñ|Þÿ•ùöH—ç.Øõ×f|`éøkÌhd7ˆ}g­gXVÖX%AE¯ÊŽÎV≟ £}ï õ/A ±ˆFõsÅÕY~’‰aG6âq¬¶©ªð;ŽÝJ*8…ê¦9íûüBºÊ—7o¿zí<œ}*ÏÉ´Q¦m¢ŽqI«ò8í8ZTD„¿ËúÁ¶[CNÒVF·¥üÅܳk%E^VÏ4Ä[w \3:“ñ¦jüRk)rP௼m9©¢Ûáe7ßÆ«ÌKpWW>ê]4÷‚ÂvÝ2YósÆuJ*rºO$¯œpí´Àž®zµÞÿ¯ñÝðßoÂý¸³°±ÛƼv'®’ŒfÊ”œ¾#ñ·H¾™ýUèi_Âëì}ØÅH¹÷D²ÌøÆšêãc1óI=ÝR¿™ùƒYSeY8=ùóXlY$®­]œ|•t”xJÍeÄ´N ÌŽ<Äckº\y!ý³ú<’2×–°ÓTNzw“^ÙPRiˆK»?…¡79ƒÞÏó{kõYX~›Æêãºmª³á'ámYªÂ™ðŒo€ˆ‘ "í¿ì®…e5,¶·½[—ÊP±µyo,­ž/ m±ë4ßH"$!LÚ&tŠWsW•èf5ð5fH‰l*;Ú®LOt3dcu r®‚#5a ô‰I<%Ç(G¦Uöø¶êªÚê.x—‰ô®Ô’—Òqðƒûf=b¹oG*0'ÍŒÄe{ÃË,bDŠDîÝÚ) ¼òB=‹¾Qe…£ÃG9l5až¼üÕ«¼s*+ó§¤ÊËçÎ̉{æàöþJâîÁìEiˆ‰díÊ£²Ço c[¥¾ —÷>ˆ6h_TvtÞ¿/>JÚ1†û"•Už5(÷ónšÜ2â*KCz×_[¡bú–QA]#èºfqiׇžUyNOS©çžq• ˆ7¹¡u×ø'Ò#5Ñy$ü rdòç53„å®äûÁÞúv{’ÜÉ-q¾1©4L“tpºo¢ß6YÍÏu¿"˜Ë2óWçØΪ9½VBâ§cÆ[Ù#5U;elóÌaWê[Sk\òVôËd.¯‡§§ÏaÌn5Ä“ß$‹Åó5j‡wǺ¬&6ßKxª®kk7q×î…ƒÓ¶d"õäö¬`|¯H²E°§ˆ©3êäÎ÷=k}ZǾéàŒ3÷NµŒóóßïX^XŽžÑ\Ü$Ξ‡Hi%ÙF裣ü|«<ãD U1Ÿœ{uÎ?o!¸Õü7t¯+Ô¿hÜôñkÓq3Wùbbüó-Æêxš…D:hvUƒÄ:s¿ãÄ÷?jZQ¸ŸG=y{ðîºâºã8­òúÏo~$èF øó'·7à 4³Ç ßWÇžkÏni’´9ùêÿ5Á£#5ªÆC¯5ò9çm±¡h3?¥lMAòÄصÜ`[U5¾<Ãœ¹[Unü±>Ü3bÑg\#uNI{®ýü秢Ïw>ÅñÛÓëY7ÎàNƒ‹•ënåçu6Lþ55Ê…vYª nª¨GF±®9Ú©¢Õ†’)¡¢.žÍ<9秊ãZ”YîôyBÇÙã™yj¬µÅrOíÎpe{#ç³êùé°ž•b\ãàA<`STO­ùžÙJ÷YŒL.g´šƒBV•Ae®ÜU‰®¸bU2²Õno’Š¯]`ªD{ÜTõ‹©wjuûD…4ð<梺âcŸ.ç”´}O>k¾úJb~÷n9ðFI럿›ŸOÎ#YÇB*4/9ž2ÿWö^“¬my$œýL{7½D°Œ.É¢98‘}ÑÇ—Æú#à¯:HóÑû®™Jk‡a›”#/û¥ÀòÍó‚¡/wéñã»]3¨mWQUpÕͦý÷™d”¢ÚE¨Ó^£sñ¤Ÿš¼ìÇÃzš0EüþŸ-ü+÷aöï­M‘kÕÝ¢›!Jë7YOß+O++^´A— ¬Úõ& SØžQ#/Ô2ÑG¯#5BAÓhêwlÍ*ìN§n-z×!å>+­5S¨§]S5Oš¶À°Õt#5ÚîTt>ڸϺSŽP×…ÇÚêz>7ñŸ4î·©ž"úxí0µÝ¯æ çzºÐXnß9~]ëVƒîÓro.˜iÇG¥\\\¨$y«…ȼÒAðwÉ2Š‡ TÜ‹´ N“çW4f²F¼Ù¿WÛéJÉå–Ëéﺙaf¯ñZF–Å zº±™$?CÀÍYײÖÌeÅùw$ ¾|µ<.‰_£æa«ŸÂ¹ãXGãF¾dªàx!ç+xóÔë#5B:&adΓ RÞª« hR#5DMüíÚhDc7,O=P®Ã1¿e0¥Ó|›e’ɇUlêÞžøü"¸í^UàPÔ›¿z¸nŒŸ¿=c&÷Ë—ÅM%çß”;º>^X­Ðß4}ÕÅsIñÚ¹¦¼§G{Õ"B×Åå¶o.ZµcJÅš&±š·Bd[× }άù!#5¬¯”%›šPËÍVŠo¡çòWA-«\c#,¶½1ˆD^æü¡§½‹ë¢Šny–„z_„NÛn/¹vÕÔtÞåÏw~ørÎkš$Îcy»ãªcüoÍ`]]¾~.÷ᄦ¯Å–2±†£äãÔøO­›ÄÕ×oÄ£52©Ãö¿âøò¦9ß#/ùÁ€KôŸ·ßÇÕ%½æyÜŸZ×Ãàð<â’¾ªeˆšƒB;s†ò‰n¼i[%§uÕ‘Ððœu¯DzÙÔÔ D]S1áËà ë +FËa  àìÖ#Ç1ú騃4uá2#/óÍôÍw¸@kS.‹s²Ïžwµ¥W‘Ct­p/Yk²Í—xGb;¬;«Ž.;EÇ´wΡ¦;a”'/[Ê© µÝÜ·Bvð«Ç‘(cÛ|7㟨]õæ¦bÖ‰C§d¦™YTc<7WÓ‹éÙUw=Zë0¼ÐǶþþknDqqZ7ÆPlÅR¨jsÕÃTõÕ¿Iï,ù³e šäÆÄ5ª1f÷nM<šÌ¢YdÍèIŒÂŠ³u˜žµ[\­gW…nïƒóV$QÍî>Õ¥÷ž¼TÕÉbåL/éˆb0›é׈֟ŽO³á÷]Mzà™î©²¼nKÒ¿Ôý»ôéÓªéËäܼ äy†—ÃÓW‡ˆAüFŸ.#5{ç®/~ä »ÈúÉmqoG:7—Rì<áá:ߣ2µcÚAuÒ^ºNš°!§CÚŠ\Œ³Ä€ C EÂ|HY9(îKÊ¿%ç#/'ýF/;Ìúj>`Ë_d¥º¨G’2/®^•Ûó‚úÄÈáÞ3—ò›=‘úðóÛÍŽÚ®üëÉtåìùl5J»ÎúúöÉãP?ßïHK×Øá×3¥œO2³ÝY<…òáT LâÊcÙø¡þï1. ËáѤü#/¿kUò„ž—š’ÞAøÄ ÑÈ’ÀÕG½ÉÖšèdÌ·éÅš–»âá3 ø£j±ˆ-1†7ÄŠÑh†K•BÚÕåqy§®ÆOG|`xO Qb(D£ª´\ÿd,¦ò XˆWõÔliï½2뉷íOØ•írqIÍzÎWÖ»,©õãD´Žö‡V·Å¶ûzþ³¦¦ÊÄoƒ]¹9ZbÔNŽoqÚäÂQç·l‘¨¹Ñ‘;¦Ó}óëUC‡Ôܧä -:úÕcó‰TsV씣§C¢Ñøm…dî«„œGlç*:¸IÊyH~Ž|,ðŠé†=Ð?‡n,OŠˆGv‚È–• vHø=Þ’1¾x3!>*Ý»L¡¾¡«µÞl™72éR šÁo¦(§LbåÖÿ5~CµâNá·w©{Eöº.“ƒH^:ì;Š™Žæ’tˆB—zéš³Þäç<&ÉTcKÚ#/vÙGÜPf¯e¿®f|ßÄzm$Ð爄rÿ{Žpr>ËISÀyYCdÅ5)œcÑ‹Æ<ÇxdÖ›Œæíû‘qˆ[¸)’RÔ'¢çË1È?¬·2¨é¬r”T·göl8ÈǤm›É0Ï–<ùËìf&&qÐà˜Ì¯…6e„œ34ëÑ7m+Ó‡ËrRÁ ï³}Pë.dž?g@ºÍ^,嫶cŒŠ:M:ÿ¦ëîÛÕ#,pöÿin-camvÙÒ™¦›ËŽ!hèÅJ¼3m׆Š„¿oŽñ~³›oA1 [Fy]}Œ¹gÒ1ÙS®Šïô;¤ÜI“vÑÂQßæƆ–ú#/»Ôü~¥î5Ù„°ƒÀ»TDJv®Þ_,pcÛê~Nö©ŸÚŽt×ô"ww__§n‚4N-uF:µWø½Úâñ½|~gû†÷bkKÀ#³¹ÐC»–¢— ât£ùÿJàú”äpðx})–) A.ç¢È„t3ïQ¨ÔðP„ó©uÔô,óÂ~;[Mc5)hº,ý§ñoš«nŸÌI|\!ë#h¹,ý§Ç¨V47£Á‹èõíôFãÎ<ý›Q¾9êNs_»)Áëìlîs+[-Ö¼¼3×li2ÂÚ6ý¦ÌJ:nW)C©øý>{­îñ´°ûå®R\¬Ù­3Dɾd7¥µ¿F?H¼\Zœ Hï\ uï?5–Ud!z!Ò˜µI§ëñhµN±#/$Û˜„†tÈöaùáqä³l1¶VÂèd¿¨í‘>¯ûÅCŠ0J¤‘Dm"¯§ò«‰˜+&Ö-X(¥Ìöf†#% !D è1È&çâæH+†›ÂP¦iÑQc7¡`«; sÅJm¥bÑ ØÒUòÖ­U"ª¥ƒÆù@1,>*«q“—pÝÛ¹‹'ª§jWµZ´R»4?ÆXlàFÒH‡Nì/ÈFT†¼ü‘…­é y›œlWƒ#/ïù2ÍÎ_Db´0©Ïí=ÚßKE*ªì<¾éýYT‘VqHTA|ÒÛÿeeÛF\P…äOô³7(Y~^êš½òøÃFº|Ý×[Mh­(÷¸Púö7fî„¿Çôzf{!P¦ÑLí1Ê”9C„5ð9ø›CS¾ÏUÞ|‚¿.fŽwûÎ1ü×Á¿'ÚÝÄgs¬ÏÁ+M-¹=Zqµ®îéjm}êŽ~ÊDŠkÐÃÌR$þI¼ ÓJ¯P|Ñ÷÷™úBm&2Q´û@°”ûÎ’ü¤;¬dØæR'ð~÷òUtˆb›ìDÂI«s’vCÙ¥JEP ÜhQû„c6AäQOê«žó‰6з='ïdXùÎYø}öíöýéo•n~ª3}é¡éS*ïBÒéìÒÖ˜r¿{o³Æì=ž›tÎúͶÅÁa#/J*#4«àWÁ¤¶0ˆS×F—q˜ß‡J6HGÚmÖ…ÏðÇ•Îè=#ÝÅ€V†Æ{‡y¢`‚wð©_“(Ìtñ³‚“b¸ò¬G¯•rÓX|Ulão,þï;²g„ðãxa»D,°ç#5¯¿JÏ>GòwG#îÜ$Ѓ-#,xÍ1w@P¾[wöp øIðúüÿé¬M=SÍRMÝ¡Aô¦à¼~q×Å1¦8D7‰àCœõÿVKÊmðí¡Õ¼N̓íªaì*R¡hÈlW¦f®ñ“QF¥á=Ú¦9Ë.wì:†3t)I†gRó ¢F¨ÝpÀцVÞL®Mvúa5#ª ?3ëιîTÖ‚q‘‚±BR‰½Ì7tñ©)–˜ÒâàmÀG(eA0€ï ¡Ãyßg üåµDŽß”_’ÕY*k~²+Q_Š©ê®*KNýæïN÷JË=L™õ û4¾q×RhíÝK«nf=`{ºàNV5ÊätÏr~]Oø•#@ªtFö«CãP È4 &“"Ó¢{t×H†wüìê¤ÚâòÏaÙPøÞ7vÊ[JŽª/y]‡T˜M¢8áÍL„ Ÿ-1¹×>ƒ“çêžêh°fÑk­bR‚MdR‹sðÓš§Ãmex:×#/µ¦^ž‘,…ðíòó„‘¢Aè{îÆ%ëdõ‚„ÍyóЪ] WžþÒYñ0kNRÉâ¯F9Wdo‡aKÑ|X"´ ‚2CÉ”¬PQìM ~‚«ã™´×a#5bÃï‰I#5Wc§ÁŽj9Åe¼¥÷[n cVÀù‚ßËñÔtÎSr‘72A¹‚Þ‰Ÿ²!t~¡®» ÄT%I³iL©±¾Y-Ù³t£tiq\;’Ño®âçN¹ÇNØ/+#/äÊzñ¥ÕTR8 )#/#/ˆ_#/—#/z—óÞÐ1/g§g–sºÐÔƒž(£ lâ%£·¾ÚsÄÚðuš…pIë—Y GA6Êx=ÌWà#«" Ô;MNü]ìàß‘¬;Ì|K4È!²/Ÿ@ä”CËC´µWW|3bÑ–Šóë­ˆ71žÍ|1€ýË6©–¡¦c.«æÌ<5oŽ OÀCI»fÎÙ÷Ï;¾#)Åa,~~X›Œ3q¨ÝvÀXÀgj3+ÅÕœŠñÑ;Îs’ˆ1âsÆO¥u¶ãÃÁ'Gø·NBæåˆË¬ŽG?£½ÂšßQ˜Á,]ôÀÄXL§I„þØ,¢uH§|i¸8††J(M¥ƒ˜–æ}«ž²ÄwÎÎûAº»˜/Wl#/s•3•GJ+Mã Ù %L¡œ\hå©LU2åkïÍlgß&ji±ÃXòLšPõÏiè÷ñVq!ÖÇüìo8s +#/ZלLVN‹<ðÇEÞH­¦Y(A¦\.{jÙŽWšNvµÝinæJÓŒÈ)«‰º6øÝtÔ5vjvãBg¢$ÐÔ #/#/—`’° 3ßvUo¯#5f›ÞväTšÙ9aï féÃ,}k¶¬ÚÖ©e&†r­ƒnx…¬R0!¡¹àÓØhŒ,í¬f]³>†|f´Ã±òÜ}ÜæÝ/7M¾ãAª•ò)(c5iE¤‹Ic#5m9øëòò9ʉ”xm4Ül4j†A8ÐÀ–MùûAÂ#5hÓ·«Ò·p³à&ºVî Õ&’¸E&‡©u¨<"Jl =>M|ØúÜ4"Rüås¾z§ï´þÈH?WúXRÏ.ï„O.Zè MP0ÿ¼…¿ÝJaÜ"ŠÍ6»._‘»o/<«1•*I ŸßüßÕãaʪTz¡ú”3þ¥6ï;M©ÅX}c! ¿ D&†aùº¸¿ók›V~tÓ¬ ¾0ø|eƒ„\gn$„¡›#5˜q’È:3þcÃ|½I&ŽD?fró¬Öºd9 BMtÃÜ¿u«-ÔÇ}8A^ZO÷¦£¿Ãã ð`x¡C†QõˆV-@‘Fè‹€);‘ Hb…˜{˜¢cÙˆ_c…9E’Ý#,ƒZÙI¥€Ø @ÓEL0î*"¯àï½Å.%%°R ÈçzG1”×éiEJ”Iá¨D*ΖÍ­‚í3<6f"È,²`‘¡Rè`Á…ÈSuï‚&g·X@’'ô q(&æ52ëI|]îëúóìóc‹/c—3³|šÿ!³Ù¹ì<²†"³ãöüfDÿ—Ë]q?ãÝlú6¿½%ýÏÊ[ûá…ÒÈ’Ä#/^!¸j 9q‰öŸ—ó®LŒý±=ŸMüÕðó¨(¸òéa‰épRjMŽTZ˜XxŒÌÁª™e1âcHIŠ~(´É{^£œÄz-#5ë?èÕGJ‹(9¸ÖÞˆ¶ˆ?£–r¨gCiŒõ¶>.sÎ`Œ¥é?äQ¦;#Ýçλ´ŒÌcr®·w’ŒyÖÝÉo Þiî«“VÈ,Ñ;mGJïlò) ]Ú,x3˜»AûÇ##/%iˆß!’aÇÀñ«Hl…uÎ#58 sV¢;Ê8–P±‘7(•¼hšèWÆPa)‹—/zU#/Ù;Æhê¨Õe#5OöÝïÊå3Å¡ ùü5!ä#¡ÄFŽíoÕ¿eCö[Ü:12µº ýp:Dì>F͇ðš(wQ–ëgaÌü(0Å¡{zƒ¼Õ+«ÂBCõð0óÎÇQ‰Eø®jøu×n#/,YÑ $dŒ‰^æõO39:Ñi¦¨©H¬PYET,í·¦³ q˜<ç3¹5wæm³GµÕºÖ&â’ð#/3p²»V`îƒ “IŒ¨$ˆ#5ñ*€¤Ý*”P!*¡Y_ŒA®D´Ýéó×õŽ}´#/B<»XÔ”î Â"B(T{#/Õ‘Œyõ†#/Pyög® 0ìÁ[’F pÎ8Ûmymp΢»H]!º ¶ƒÃ?9r':”"‚ÛMP:1H¸7 †Ó0´Nl`;(ÊΆ´qÌ£PKD}|ŽßUµÆ&>ul*ºŒ4¤TÛ¬à¡%Ýq­Äk^ø80 <'¬OH<,u³#ÛÊ)µ¹³·<ÎÄO}FÆpW|´yÓëÞdLÈó¼¬dd¨ªNÝÎéD8¦3¥ë#‘¶!ΉÎ4E„€gÒE8T„#5¢«­%WWMµí‘çö7UŒB¤ „D N<èdPF-©KfP‰"GÏ꯷/+Hå5I—té¡D–•¡/TÑÇ·€ˆmGšNG•t×¼ÈuJn1-Ȫ”%•É•37yzI ,jzüS&|YóÚNj…ÕOªê!äÑåR—(ÏŒ«òó¨s1ß>+#ÔÁ€‰Hˆ Õ\^âÞ¦„*pEëÎN>>ôŠ#L(ô1Œ#(.UÔ¸O{ɹÓ5D¢VÂ% ¡R] (׬Øó^Y¦O sУS7Å›`–C‘wÈ¢*ᩈØwÅ„NÖq°V4Ï=¬9ÚP’ ôa=J˜JúèC#,õÑAˆH=ùaఠȼHÐ}›=QÕ‚ )¨ÉÁ†tâæEÚékag=LÑ+¸ ÀMä¾ÂÞÃ)€Dˆ©Nï$[—”$!!&A… ¶àûº#xK"¸æÍú,M°¨Ïƒ3rçÑr4&z8éëJ VÉ›XXž­ºã#[•€`¢Z;Õ#5„dñÖótSO+k¸s!u~H£óíWZuË' e*:*ôÂ#5·ùÅóCr 2'o h(:¹ôÎϲ`L™²ÀwÝ@ ‚‡,7–÷ákW*ã/Ü-SÛÓKUB¼ÀZ#5±SB†Ò6é¾ÿ$çW(ŠÁ¹M‚Î%éCËÌùð8éÄÎ/ƒ:ì¢f‹ºêgÕæR‘þ<Ú#/1³Thõzõ½Ž…Ê®©ÑÉelUdà‹ÝÝßœB’“D¢H$ mTK=hŠA0i*zšëMË[ufr­7 63PA™ã“Ý9² N®ú-ŽX󹌊t;‡T±ñöÙPË1ømÝó³2RH(£XxM‚üŠ(”–!2ÉJöœ9ƒ7>®SXøžÎÛäc$õÆÅT#èær•8"p«ºÜyK}³ÊÛhŠG4!…Ä'–˜Ë)Õ)d °ÏÖùtó-vEØ…ª…[â÷ÙrCÙÛq[¤aÒ¸2.¦Ë8¨#/…(Ê6 mžJöU÷ùKf»QÂLï¸:kÁ’ȳö‹>‡~N•\&µÍ¿2BV~c‘˜ÛË7¯­¥ùãnü¦#/½­¸›üæÉŒy¢“ÄCØœ›4 øF¬ŠDA†'¥iT¦„Ù6¿èº8|#52Å"šê),(5#)Pö¢p ô9QòHmšt¯‡Çú,ë‘\tváv–‰ÛG.K} vCŽÞEâ«ÜÎŽ1£d4>?P=ˆ¾¶•M!5H«©Sà÷»Ñ|zë¹ÃÆÊ~x!Ë£»4­7ãíŸF'é’qŸ0ƒêìÎt,#Ñ÷¶ØðÖ[†A1,Xwl¥áý#5›ƒ{Ø‹KK9l£‡wÜ·#,ÝëÁ™¹!×I'D:u”ó!zÐÖs,ëÃ×ykåälö;ºÃ@#5L«qž½ÅZE µÅÙÍø̬#/¡uò‡;²)ÄCnûôõuÀófµ´5W´ˆó~£áÆç"&à±Î9Õ)Ò#ØA„-3aüFðÃ@J2ˆ÷}šyÃÁÎB;Zv`äYÔƒ¨­‘m„”ÒÅ£Öº©,É%)š1D5$:±0ðlT¥ªL—¨Øš57ˆq•‚¨=š%$7š#,zˆÞÛ˜“õÄ4—õzm‡SêS‹ß†t;ûùËJ,Á¯ìâuBuR!¿"¶Tï‘Iȃߣ5~#y5‡–$!¹t$à‡cò¯C™òlzEu]Åu&fr²Ëò^»j`…KJ ÐE#,Èôò–‘Ñ6z~ç ­œ›¾M‰:êƒÛ A2›ÉAÇÏNí»vlÃ1vkB>ÖÜ€–£–œ¾êسµÍp?tL“7‰1Æ÷2>9¢X’˜Öã+s¯:Å€°x~ÏϘdcDú>þXüœvÌ~ÿB¨e’¨o{l¾P3Š\yÑEºzC~à”äUdM"aùi¸K£š—ý¬ÌÁÓ(ò£ËËSû&R–iâf챇ùmåëÇÙÐÌâOt ½<#5VûZ:ï•»»\œXJ”ùžääÄÚ%o|©¾~À&b º“A+¸«: @Ï#50‹Y™ƒæ3­»ztÿa/da1A_âýã¤?Ô‘!!Êa/à ¨ù¾ÞtÙ]a¡¶&»e‘‚x@=æI®ûXt›õ ÂÌQBòüׂ“áeuÒ¯ÇÊ¥³éñÐ>Úôbý³Óm¹EoõÖOê•ÝÓwYmuwþ®'.pQ̆!3só÷œ»sñð»„#u1¥ygW[Ç#ùØsaI þ$¤¤(HŒ‘B¤?£%6¥ L¥þOyaýŸíÂ1÷úZ¨DoH˜j/½Øúañ|bB/ç‚P2w3ä£ur¡ ¡Ã¦;ÁqÓHq³äKD¥–•[Ž8V¾Þ±«˜öYŸ¤›~•ØÛGÔî#5šÖ2y_–Šçö~eÙÒõóÿÔÒïÞuø™†‹]fW—x€ Œ/®éîý÷ôá}•?ƒ30_¾}R«6-bj¬y‹;#/’`o§~VíÖ‡(uD×Y_s Îj&8Úc_¿yŽÌèfø¢e¡®G4·‡ÊŠ$Ôzj¯Îø1rVaD£ìkZWGó¾-·çg2mjˆ•Š¸gÕë}agæ+ª%ž®Þ³ê6açãwï1­rN–›Ns˜5311Pú`ŽKt¤yº¸æ!èóËÇwoëÅ‘`NÌ1/ú(KôÄkøÞ*²>²Š$>@ªˆ«ù~1[Þ+óÿ9RqXÌ°Ìr…§#,&éùúµs¹¥Cõ¢R"é&H<ìLjñã·¯œ‘º{ú(Ø».qÑAãºÉÂû¿Ñöc?‰.îöhD d(ù|mû7óê#/@OÖÈmLoO`•^.Þ²]ép0ÕÒûttð†WGš)xt áy(kÈóaöÙwu+°uÀ-‘³jß®Ï(ñ¿‡šÞÑ:l ^ÔuyãÉ¢Ë`Y-ŸAßêÜm z5ÄìØy½òT‹à禇˫çÑ¥"ß— ÌÁ'á9´äiÏ#5¡–´ÖÎÎÃ|©›fÇ"ÎÞ¸] ¶1z¬ë1[ĺ•|ý®®Z µ¤Ó’"kmõY‡lkø=xû|÷¾DYe-bBfGC\¦"ËÉ.}yfnûýÍÞ½ÿ5“Ïœûvúc1#,…† £E˜b"®P»–æ>!#ÚÞ³Ïí9NgÅ®¦ÓLOpÞ¶f`ý ¢'ÞÆã‹eå3šÒæÙh õæ„€’„)9⬣u4œ9À¯ãßsª"➺_ÂMÿÙåöÞ7Öÿ‡5ö¸ÒùLÃ.ì©"¸H¤{áÕup”æU“g†:¶z8]›½™˜}‡ßš2Ûª!Œ·@¼Ç3‰<“Nf?¿œi•A¨àÅ^½# ¼õ©ÉÛ<ï^Å¥ÎÞhmöÞ-4î¼3#,¬ßÕ½#/ÒüNªÞ,ÿW?]®É߈!Vâ šæ ‹¼Ãáà=PÌI êEš­/l×À’0iQýñ¿é–õû³”´wÕ""ª‡JæþöâB™PKE¿yŸžùçµæßþ¹®>Ó'#5|#/y²‹ð—;ÇÓb·sŸ*Ž/›öΠC÷xëƒñŒ’ýo‡×.^NÊ”:2t¸7·ä¸õ²OĆ!8KÁÛ’¥r„¥i‰(<öA³aNbìñ®SòþëÊw5Ú/ã¬Ow•Ë<‘0üÞ„z*Û/1IÊNyàÛõ¥w4Oª¡Ë^]¼/ ©/„»úÚðLz Ð M–óPÐòF×ù$sžHDŽO\°OQv¾/Úáªuñ\̉zà}Ûð‡˜ƒåÔ“¯Í¶N§Ž'¬âÇzžñ&]›ÇG:ñÄq£®ë~|Á83M0Ŷ-^\{uïŽñ×z+îs>ÛˆMgÙUùb6vLtOt*dƒdtºŠóõæèj·C‰~ÈyRãÈX¯~Lw$êéjãΫJÏœf.(ó|v5|cw1†”YùÝ%;ó‹;vÖ{ç]ëSª0¥“¨{ý#5™O~ªìù–aÁSúÞFÒº}“#5 SSa:›; bî4Í‘ÓM0–vñ®•8èL±ßðu_z<ÍQCØYª-™_¢eœö“"¡Ï¯# §ÒðÄ*‚Òð6¦yI¼GTWUñöò¬·/dzI#;~÷?N€ÀXó‰gíÖ©‹åðÃ2ô´ª3·kÓÀ…˜¹­1Ý›è›W®Ã¿.’ýQµlUŸõ}à«¢àu#ù6‘oÖé”ùÃZ¤î|üeyš¹áŒ|ÓÃ?u#/äˆyÌž0yÉ e²Á©}?6ÃöKžk›öò6^÷Ò$d›žÓ¬ú¡¬õ}lªŸAd0­•÷)¹eÓš*ŽñbfŽ\=~]H3ÑËÁGY'œ{l;üÅ8,J»Åž¤c.ê`ó—gÃG©½êÁ„çƒ÷¿ö«3õqà[Ci30öÔŠFª^;ÎlËškF½µíáøíwX56ZËY}.ˆsŸœušÿVÌŒsç9§wÃWi&yZ_ycé'-ê0ñÛÏ̽%êí¤uàÏAž«¬t?whlŸl?CUÀÓôÙl™ s¨#Ê·š¬§dÐRé.)NÈøõ}­¦r“öGüi©Ÿo‡6#¥Å)CýW_™ègß. ì,O/óD(-_ZÉA*9ìæZÜŠpÔìñ‚­þQàÌçÛeÁ×$n9µw;­-k1æ#/Ò·ÃùÐåÅÄ1èSñû2}j—Ç07ß?†ïŸmKó¢Iîìì‘lÝKpû‰Ä—æçÓÃÁÝú¹µømÛ¿Jç‚©£Fú%ü²ú3Ÿ)m5S0W–‚k(êN>vZ´9J =–âT*õ;ñRƒþkÀÍ á–¦·R^4ÞpÑðóï#5~§zHßÚžØ$ÇO¾p÷|œ-a{#õâaöýPt΢‘j+Vß3¯ZmY·EÛHÂDÚÛ´Bò…ñ¦dBi]×k%ôKÊ~âfQxô & Û´P“Å1¥8ƒÑGâ ´Å$¿äjêÅ‹ò‘à%ÄÎ{‡“éj£øYB®DÂ^Äi/¦ê8Ä0(O¬DãÔ,|–-‹$ʽ³—­.kstÓ‘Mâœ@Æ/(ì‹ðåñ 4(@vχ$ß㦔葠9#Æ_#5…“ôÌtMô4aþ¡G.ÚqÇò"Iêƒ";¼ÆøZó~”±Ë°#5±¹Ë£]õ5äÛ/èCKK–S¾üdûiÁxjÓ!ÒëqÄ ¦mäAìŽV-Ñ#b0ÿ9¢P“õUphÑñn‘kYB.Åã'Aˆly! ­ýw¬ÚmA/Ò³4ŒÞ¿Yþw6¿1…1>o„7?\/ŠM„‚ˆý±<#5³g‡‘ã"ÿ«îêÍÑ ìMSfé‡ZtžY´>õ”µ"ÙY:uè©×í7R§#Ö9D‰›/;¿+ü:ÈLœ20ÞÊ;ñ¿.ÎRýUß]§ì>öüM•cNnIï»ô#/OÐËâëøë峿ž,MÂ61ú¹§ù“Ë}^õ™¬'[XŒç*« J¼ßæ|wªŠsiùHÞ´½Å V’<°>ì³Oáð›Â+¸7þNE…»‹È„œ*jýI@ùJ„Hà8;׬×sº“uÁÂå¡É 0bî.ÊT÷À¼èôÀºSÖtǪ¦J+3½N°dl%ùðfg kD×Iú!{Hë_wçÛ†™Ï¶>ØéÎÇeâã(nvç"ìÊ<îB.&¥tÔwtô˜ëCYLæs¸™ª­$Ýh¨›±e—de^V©“ÊÿÇÝŸZ«Ûku$$Gpq3 Ý€Hb0PëÚ‹V#,°;«ÃO­=zò&°¨ã¾ZÊe2‰š7ˆ„Ý&q!þ±ãY}.+ÐWæ/b\îñ œn&݈vWdH% š=2ƒú®¹†!ð‚-Î5·6÷Ál÷ïÆCÜÅOèÉ@&àÕ=Js†¨Ï#,y]a>”VmÚ@ÂÊÕ{­y •OßAׄyáÄõ‚„× \ÖÞvæ,ÖTö²Ùá§N-e{ed:*gsàC;º¸Ü'ÆùJý~lŠHg Í®ð¸E¨‰W7‡ŽúŠžu+l¥­uSf½MÆYÔL`fe‡#/k8î± uŒq°å‡›9,èŸx$YG±©ä‚C¹ßMp­@üpÍkI·_luÌÇPaw=µ„H– w>õÉ©;qx,ÔñÈÂCÊX°L!T2šj‹vúˆeÛ.l:¼Á Úesj“5Æ2"X’~¦·O—¢ÉØ{{aϧy¼}á˜Û£ßÑ·›nÒVKJ3ÏlõʺÍ5N³¾Ò–¾Ú1,iª¬Ú{lÓ…åÚ³ u¯c³Ni0äÅtl_µ6ÔΚŽà#{³“AÁg©í¿<Šˆ{]ÉÓ^ÈsüS™)ZãÂÃij›ÞŒÄ“ú¸@è]ݤۻ¡}Ù¿<0UÆ&„Òþ¾¿7¼õßµ7È„u¯0$þÿÂ/ ˆÒ*‚g¿¶s§¦…áš¾}+˜óŒ 9ð7Ÿ‹®uüE4×J ï­±eóûú¬OÖ"&ܵ*£¤NžÓa•›ÄšcUÈ:bðÌÖxæÞxí*G¢¬¨sf¾&#/f2ÆJ&fŒ­·EVú‘ªfE*ä8R¦|¹çZV2©r¿«„Ý8Mý®Í«¢K¦p„þ•`©} 7É'˵U³QßùyØÞ9åͦQ#/(8z»X°Ìi¯KçÎÐÒe(U”W•0„~³ãøyÿ^¢ü(:zKk¬Ç’ ðŒdÀðV¨jÇŠ™û¾Õ~ënõÞNÍàã•ÊE^ÔúPù4ÆŽ„#5žBGeS‰Îá ¸éÆäiØ)ÏlO>hfëjÜj„ô¥f )•t~×3ߘŸ é BS/£j–n¬+²oº%ºCK›,¬†™k¿UE.ýЇ©šH”VéÃD/$ÏÛ»ÅD|¤îvá×Ý>}³ 1¯(Ç»àÆqš·¿EÙ°¹e% uÚ2öž§µ•ëÙi˜ÎÅÕ,Ѹ.'g±•b¹9€™YV#5ßk¯6ï#5êø*tòž0å#/2ÐRÀJ²Ÿ~Gó`jM½]å‹beýqKAJ`ñb¼­¼¿i8±!#/wî=„+-ÖØW8#,žp²CûÛˆÒÅ\wñ_Çc]îgÑ¿Ùõä_t…Ýy¼Õ×êßÝñÓC“9YH°fôQ¥þ5Œ´(ÛsŸ­š”›Í6ö8e6Äîè…;iøÑÁDvü7:L²í•ÓŠƒÍ:C¾ßÃŽï}y!!æT}£E#/înE ïQ†×ÔÒ&GÈaç´õ Ý#/=Ì4!´Kkúiÿ•†™7ô§s;cQ(Ò>=9\ÌeVŒé,¬,Y9µÜi@{}6ß_ßôÓ¶ëw0RDXìyð0Îh©ê~ú¯=O¶¥6Ê{k1¨÷|=9ñ©XÊƶØd{<³È½ˆRÔi##5;7¿ÑñP­‹R«”*&vl¸VO^5Ö5Žæq&ïèYè_f_ÑÆá‡óãÆ#5mÉÊÚ•äÒþÝ+ß FoÓœpÙŠvcgïøUôÈÈr°R~¹ÛyÜ"ij!”4f¬ä‹¢’d’K°™mí@(wÊaá›=§„õÇ“³®ã&öéQÑ\÷ú'âñÐ9Ý‚-ïß·®²GlM,]ÑÍä_Âyý?d¾÷CW“6#/úénP<¼å¹ú¯€Š¶W•ï6ì­²)†î9÷.¬9>sl:颅\†`ÒúgvÕ‡º9í>žª®ì¢YŒ0¡kË|`ÞÉ6´ÞéßìÕU¨%bÔ[ya·>ûé,ðÙq+Œ­Ci1b©œêíyØë3?TïñÆ..ˆ>Àè)®ýèÍxqûuÏz®Iûúo‡ßÄ`Ö5qŽYøç"­c0¬¦‡c5¶û´-à]¡àl„jÄ1Ï{bÜ…éÙšcçc‡GN=ýˆwä“Fz^`Å#5ç9HªÔmºj­Tœ ÕõDÈùNÛñÖóÆò#~¾Œù<Žù„&}<§åpÞ:òRÝQŽÏ4¬Œ3?–åœÙ½rÕFøðçómwÊ5èÚ@#<Ô–éPúS&79\Ó*E6HÜc>±n. E–gÛÀ: %“È{û°ä½(Ôa©#/Ó±8kŠ™‡nXÔÅ–ÌÀœS4AT(q»«Ýž2­Ÿ¯^M}PÀºm͵L‡túUø#3émk$íØä‚„¹üÆ¿Ç¡v˜Èº_=¶77˜ ‹¦Äån–âÛü æA ÈÒØFQ’›WÆbr%ºŒ)Øpr17ü çXÛŸÏ~è:«Sì~Ê:æíµük¶QË´88öÌ„¥q®0§kÕþ1Æ3ÄÉ%¿ué0#Pè!ÂÛ(¿##œÛn«jëŸf]š(ñÐh0r½tæ^ÃDYÑU{á‰ÛU »jz e~0Ž’^+c´x’ŽXuFOUY’Ëbpwù û*¬¯wIásÏ Z.7³A&ÐATiÆ$óÔtç‘ny[š«­ˆ_qsóK®·k*ºüœ9§ê†ÃÆ&Û`äe´>U\7ì¨Â&ØûËGI8å…û~_¹´€M’¬Y‡·Áù+•YcQTákC’+Ðg.ËÃUò­óÕ˜Ž.ñº4Ý5¨×œ¬gµÊê™S{w3ï¢ß¶ ­™©¦nªÔ·U@Ó\¸±l#5Zõ,Ô,nûdÆÆÔqr¯KŸŸ[߈jî[›%Ÿ&ºøLPIªä~býºaûŠú-ÍÈç#±¹€×¶,Pæ÷s®€Á0æÑeØ^8¹;=À'•¬=a Ó£MÛÔý9Y‘l˜V= Ê;ù˜®J͸j¸ººVÆ}ûg¶~·Ïfˆ;†ÄÚÆPË>¾wŠ¸Ò맶è™ðìÏù£ZëGÕVOA@%¿ùþ[?GÇñžÞóÛõxQÒÇD>ˆ¿ÒF¿”L+Й‡›ÿ›ÓDð˜ûâúìBµÝq< wõWÁ9äs¶¬ÖVj¢ªÄàÊ<ÎS¹9›-[61øØÓ_íëSïòóY{ŠûKãràr—é÷Û{yc‹v¾<ðSŸÉYâæsyV‡Õžâšr_e’ÌòÏûŸ§Ço›—Óù|–~—ól|Š²ð ÷5†ê¼c¦÷~‚ÖoÖg?ZÇVœ‰²°¶Ò#/ü ÏÇ–Z~¿ Xƒ¼áôËö&ÉÓeÑá@ªvH¡9” Ç ™–[_ì$÷~àt¿»6}ž/©\ ö°~ €ßb#,_`éÆ#/ο°`M™BI?ä/õÓÁ#,!ߢ¾™°€åa#±#/é‚6%Vá pU",#,þÇü¥ ËŽÝ³ü_Ôyk«·fDO+‘h›k öÁØ­™?Î=á6˜À Œyu£ íéÞn4LØv7*pÄÔ2“_vC„JÝn5 B"N¶¨Ö˜IµEœoRO—Å 3¹ Èz1~Ĉj á‚U1–º¢¼÷ò[§`áâÓѱîbv½çï°è|}þ Åú—Ú}®h£™¤=¨;!œ#,ÿdE, Þ.àø“­LÒËHæÆåî}ÖÉ52U¶u¨Yþ'צ* í ÞôÂêéú69¦‰èܼÇäÄAO´Oñ.‡‡øwwà¦ôé“âXñg\ÿMZ%Zß²mǸ°FG$-~AæþLéyOø/²í8Ô;:#/¼Úy >²1ò}~G×6ý¯SØ„ÑA`­'šü'ÕjY£›‚A"a‘KQ=eksý=ZŠ>'Ì2†ë¡ÌÈÙŸò“ Y*v}Ð7Wæ=¸¸;µçÃcUŒ%b.qJžº“XŽ\@"âØj.6IN‡Œ$6$ÇRg˜R±Du€Oä†AŸÑ<Š¼Þ¤?ËG¨bÿALxü*UVªa‰‘|O¢˜ÖR<¸€G°7®Ãknà#/€Çï$êÕ5îFÕïSqÜè‡#P-"†Ðñ²ÁŠ#/” )"b€N²cè{Ø\`pRƒK$aì-“"ÆÐ:\ÄNkÌ×"G:•°»°„,dLXÂT­J#/p/hÂQh:†÷çïH+P#/ Ðûâñ#5Ý™y‚ÝÕ¿õràÌ‘DÜã¡@Þ’¡€x͉¿.tJ‚†QÃBÆa2D‡ýd¹ÿ©ƒÝ ò€€xû‹—˜’#5ÒV}xT‚1òÿ+í‡ß\kƒgDÆ‹FhU<è…ÇCßá{‚JXÿÉq¯Õ¿Ï:‚ ˜(8£û<³êÎ&'[_ñÌõ³}fÖD»8RHç»?¨¸û]Á; ¨F#¸·yó4I“O}r$Õ’Ù9J>¥»äpææm9 Pþ{•T†ðüÏ)LHð§qDBD"S.‰Å¹Ÿ´ÚàáØëSHB3B= 8?ê—#/©Ä²í7ŽÿÝysµRTõ4ˆ„ €Sä4§äõþž‚ÕR„ÉƳ¼¥rl™ßm4ªUQÖ«lÕm ÏŸgzâŽý¸ag?q¸8àáæò8Ø?½÷ñqàGৈzNs‹,Xï×iå uÐÕ9”r4  îw`ä]Ñ,Û͈ÃôC­ú¾û-ë~“âF*^ƒä=ŠCÈ$%¯Rff{¿–š´6nÁkÝKIk}/òeŒʆº(ú&î?”û¤)#,ZÓ`ùT×ÐSÂû®3|s§V¸L[¡WwtÄ$N”Î êÒµ~à¤aA|‘¨Ÿñãäû!ƒ»KÓ4—iž#,,±*!¡5@´DÙ‡Ûgpøï]éá8„Ô‚Xd#åþè‰e¦JÓ¥aü”E"E‹|ƒ„¤4ìÕ:#/ú_¥Qqi,BT<Ú@Ò#,‹¼6?i`>|vîÞ#óaGÑ䘮dC1 Ž¬>¡J ¾ï»þ·46}¡öðð"*’™çÖ¦Ór‹Nñ‰Å³¸ÝP ëÒKÓb]ñÄ; #,GŽöŒD6™ø¥Ÿá±d6Q¿¡bÀûf(h©¾=ôÞé4¶xÄ—9°ˆŽF)R 0ñ‘Ã2‚Á!ÌIY"ÑÄÀ{ŽOwy_#,ÅÈšÄ>#×äଠ²‘Fm­Ïð~n5UB"{iÀâœ{Ty7, ?_ƒØ9¸Xf&f4e°³ØºS‘u0bØ.„ Xr!ù_¼ì7œûGû˜=/#,taû¿«÷÷l” `ÿ6…Ïß#$3<£¬m¡F’XÐß =.Y%„êüz¸Ž«ª¿#5Íùnî„»ìU[Ãu<ôhqkÈrªÍI ÕF³5„+Œ|‘ä|¥Ç·§HÞáI®T«|˜U3z5›–#ù¨‰z™Z›&`™±æ\ÈS©XD"“¦ìx N‡Ä£uEÈ÷iVeCMf°»D!cGùX@8l|߯èü‘¨,¨2"Hª~x¯Ù”ã,"s0þFŸó3Í®¤þ¿·ëõXö>ír6ýí÷W³—ÍU¾¦¿¾tvë€μ‚wCÅ¢$‰G$’I––ÆÉ#Ÿ`~ò xäa>Ÿ¯ô£ùDyý¨q§‡#,Þu(KCî!ÏÀ´%±°pxŠ‹_³G«K•ù—·7?h(ûãw|Ë4™fÈ‚Êñd“B¬Þ‹³XÄÄé•}Aá¸ÉɃ8)ÓID¾8ânòHàîât’HßUå]äúO<é'Wpë))¬éBŒCxÆ6ˆ,M^#yk#OFü#/Sfœ%Î;âSÜ÷‡-Q„Søï× ÷ÖgäÇ#,qô¾œ„ÉOHPÑFã›ä!dã²€½ø~•ö²Ð0¨‘#/ú/Ï\èn©¦æ5š6š6»¶×Ÿºû™ fï@xÖ$ü´ºü™Xƒ^æXö½€)g×H#,QT¹°CÔPô>ÞƒðC××÷?3ªOˆ›š±Z}ƒ@pH¾9¥¹‘#+ñ9„ ~Ç~¯pm>Þ ^óùè€F4äw_øŸ¬Óêlªr  $þËý({]›;Óñ7ˆpaÞ¬{E;#Dc‚;€àøx$Âd´lÊ6¤AÓç]qñwžAÅÜÑ€¶}¨Ïg"´DÊ<#,çá;ø”Ú4ÿŒê| ·pœ-ý9ðžÑPõ‚‚Š$!!|á4ȳ֧öKpx('™‰B&ÏEŽˆx'7ËðÌÜðäAjXúG®tŒ"± :dñ‡ÕÅCâp¯¬#5…ú»¿ã )úüt€_d„cÙù+ò }’e¯¾×Vñ=ÁàŸ(¶í~t3yxœÝähŸ *(kŒ-A[0ôº™6 b’z™$’y€\U=@f{8ÿ-´@µÊqͲ4dˆž¿GëñH¢^}ã3DI­VW½´£Ç»?¡>¾†  òå–Û¦rÜ«k|[çäÿ òÁnzŒã$ÙØF$ö·Añ‰`(2½0„*±u4Q“ŠÊÇf#5BËß…44ʽ‹…~ºTN;:šÔ)1J³ÛíøÈf &a™êQÈ$Šª&$0buq’ãÆñ#&Ën¾O5›˜NǨǠm}i§-î#,ˆ¼ÄöOg{®C1 ÷xX#/Ð_Ϭï<Á*B2† ôv;ŒDùÄj¶©vª­Kµg«³ˆ¦'¥'úÏX€ß0>¬žðö+Û¿„èêASÄ#,î6‡nÆŠrt`9+ÀR‹>SÅþAv%¿V^}MLÂÞ7 ‚iŒ3¯Ò·ôýÉ?¼Â)*Ÿç»¶'úmYCû^cCh:ÖiÆÍH#/3D"G[Ú¾#/B31tÔF®¤(wfC‡·OÍã«jç6¥­r„ˆîy­ƒf-`"÷•Ø®[ #,9RÕ|;ªªÙ,p…\À£þq6{˼Ññ ìó”*{€¡ÄcçxÛ°Ùô}FÓ`§0ô‹"¢)*F˜ >òÉÔý#,dû1EÉŠn‡e)Ô}a2}¹ÈÌ„9”hhX±ƒô\ì¹ÀðõWî»÷lËð1¯CÀWÄlŒhãYy°Ì홤w„NÒA$D"DŒQ ˆD˜Ð]È~™b!ï¢.Ì…ÌÎQgÕ}ÞáˆMwÒÕç uœ5@ŠbIrI2qÆöºDfä̦‚‚BLHzѽ`.~´P+g“P}BâQp=èþ„Á"#5° ÄP~ ôXŒ€ŒŒ2bÙ`’hXPÕèR@D0ƒ!#,báE&I¨‚dzý€¡Áƒšj4jZüÎì`Ro<ò÷¡âfFÆG‡Ž›Êø™&AB<A#ˆ°Ü«JQØÂÂõ_j4OP~1)Ù¼ÑLˆ}9šJ#5„IØ­ ÀˆGõ(þ¿ïøþèG>aöCÂï5AÈ#Uçì+)'µ¨£QÒ¡@ ±’m&S3oŸy«çï[;µskÎÜZÕÙB#bA#eSmw^xê³Ë®[Q‹{{>!œ9üíÓè«$Û:ü`x˜ÌÁ¡£Z]kuýà”ÝpËâÌA>²@%®Ð|Š( BùúÞ#,ÃUØÄ4´Ã°Úýú)’^ ”8‰l†•B‚ÁB) #56 ‚%›1Ä„:hf…È|è⥅¬”ñoòª²»ùÍ㜠=ïéveÌ^à„âE¥ÄyÑ¢A ›7'^äýSí¢–q®»´2œú¬‚m8…0-®Â‡lB¶É£Ÿ4{³ž^Æw[©š˜ÛÈFã#,Úf’³ƒ˜ÃÑm=ÿ zÈwwXÊ•®!^òÔÑ$¸Ù;Ág¶¯"ظn骔¬UQ|7¬+ýÀ?nÞÃéC .Ij^TÙHØÛên˜…}`À‡³cbåôoZýßœþé1†Ñ6}âØ«KL© ä â„‚#,ö$÷ &¸’O·êq0Y½¹‚ J<äÎ$ …Ô2¹”Àd£³#”T¢ƒ@’sì}Ýh¨€"r#ÕGSBPJfXâŽu2rŒrÙ±H&*7¦˜ "?P>'°¼ýžïп#¬¼˜“áÂÊô;OºZpìÙÕ!b÷Äã›$!·½Ï #äUóx÷37^Å7SÉ°®¡øï%by寧 bȱ;Ûõ¡PFKdZ˜*ví¥Š$™že¥ìÃxÉÉzOgÄGê#5MÉÁ ì.JGDÅþ|ÞôÌ¢¿RNÊ»Ë%ÙŠ+.ÀÄ©%#/ `ÄÀi1;½…&¥ø(­ÆrE„2–½Û# þq8D\èk\qÙõxø¦eŒ~¤`9•hT¥ŠÈ‰Ì\#…æy¼0nxho„H‡AL““#,T7»Ô#/‘ ¡l÷í-À#,@Óc¸?R(ØC·ÙöÙ.ŒL-ÈúzÎt fÌǨ u×¾øMœä" ‡ê²¦#5.€DìÕ û½X9ØrÄ:æP•×ˆ{ú“È;JéEX`“&@€YØoñ³›¹Ç¿4¬^m@ª1K ˜Ë I2mN/´ü›á2Eh®0­ÜŽ(¤Ùë^‰ûåI}²,€Ü#/ÑÞçP€‚ $4) zj™&“D);&$M¦ì/é×9À£¡ Ñ£D&èä$ZfÕÌ1úñ2:§6A¬å‰<—÷ˆþ¼£e“ë‡vÕrlwìC5s<%j¼™fgv÷§' ò´Öm¶3Dì=çëî”ðów]Ž£S£Ö{RD]‡#5â¿&Î.Aƒˆ+Ū9Wa¤Ö—^¢„Ì¥úÊ#Ú]§@ø$Ä å<“â—ëÇPIë§øeI$ÃŽÄ ;”­l h7àän\ÿV·· L‘ÓP‹É• è~‚(êgrò7·F0ŽrF* àF¯@l¤r7ÞŠà~xOZ/$ØhW§0øb˜¸Ñ ’¦%ª-‚¬LsÝ×ÀáÍíÌìsFEÞQB=õ´ÔÇ\ŸWÜè…³­<³·L¡¼îOÆRù!¨e/¥„ëõ™,<¢h<¾(ÖR,RåÜ#/™ò»w3vA&Ø?¬Þ¿O~÷¢Bâš¾"võÿRƒ3Ðn`ÌB®¥ÑQýñµ}/ =¶×ùc˜^65iÔKVäÜRMΟÎÞGgc›²h“š‚L!0‰IÈyÓvHðGiÕDçi2LÐ/ñµáTÍQþ^G4ìë ™¼Xtà†}p‰‡fì€ D Û|,8ݵ|²Û»ã†Ü3q׋±½?ˆ$ÏÖL@£ÄFL+¦Z÷‡Š4³FëŸ Ýt^ôpBÄ7£AµÁ#5CèÁ-4Hðp\ÆBÀ@è`©IõGãÞ`UîŽÓ LñûÚ(Çìˆ&\ ˆB$` Ÿ¿¨ï°.ªpmKÑèsîL»ÊÀ²à& Z*…ž‡¨àí{šfÐT7|ÿ­ÇÙ Ù=C¡ÍÆþœp„œbùôq¾XÆtL–?ëÐÄŸ€=ŽÒÞTVrG°.µ€\À'Ç8b\ÜÜàpqqÄp C¼È ¨ä•õû‰ªü{¾W€n88£·èJn»ÕG³Ã`Tv°)$+§ªüW¶ ©<ÂL«!{+ò>¿ô¸¤èU–#äˆÄíWt£ŠÅŠ2-µ#5˜ŒíøK•W iÛLY­À_Ù²’#l #¬­ÝŸÅµqíŠns¯ÞT‘¦–ôD·¿ðë?aÈžÔ­µ[i#/†Ú¡+ÒÐ¥f¶f,‹x ¸÷Õsà&öЂA–xno¾+½+'cùorXýºõ½9ŸoÚ—O²ó¨>óû_‰×õD~Gö!W*z&ýÌ*|õÒOö¸[|vKy¿y«¥ÖZæ¦o.qÓ2Ø6 jË A ,«L¢€~A¡€ÚF hàši²nÝ´ÒKÐbDÉŒJ1V4J¨„¨Ò´Ø#4°(‚±P¢¶„ˆ+Ùm·ÂÞÞu­â6ñIXÅ^à‰F ²*¤4ÿ€›Sþ g×#/ŒÜ„+ÿx¿Ôp‚Kf·Á=8 $Fhà BÈ(f¿€~}Bc‹Y$þõ–«Ô&1tõØ4AeòbÊïÝZ¹ôpÁqy :0¢G o~H wt«GRäÜÊô´*Äts† çk *ÅVLv Ä;/¦Ã7ÈLû›‡yêÐì{ȃHDS.W?=ÿ;~c³÷~/ûVñ@è„;ÁZÁ•ßƒlýFúQk¨˜¹Œgáþx»±Ú«úy/Ÿëý3b·Þl§~V’ÀÊe!’/‰ó¦f=¿ r’j‹Ð-"†œšÝý®ØN¯ äW¥¾ïÚ“×2 t“3¾î%š'3@ø@Dá' E·t@?Þcî.Î÷Ó¿´uñQì±—#/7dr‰Š*!9ÌNcÍØqúý‰F®;O7˜ŠBbqaHÌ€íøâ>>tɧ´ƒK×Ý7–1nóµÛì ¤W”P0€™À-PáBB™Ýõ¿Œ$ÍR$’R#5Á¿å‚"Fd(;ówI›Õä¤2dxDr¡øïdÞg¤qÈ!¼w ­¸3g׶£û[ØÔ)‚¶6åhJYšÃDlDÁt¡É#>jä)PÌ Åáù=nÌ7*ÛœˆA'P÷IÊï…ü†%l$Ž°¤„dàü©« 4¤áhîÕ‹@+!§§v‘‘²ç€k»ˆðsZš‹~‚üSºŒð!¿ŽñMO¦NZ3h>"Á#,R]"Aˆ HZig‰#/yš†!ç-üا“p¥Òûù¼Ÿý=ƒ´3‡×U<’mE™^ô:Œ‘EnBø¼É8<Ÿr‚°ÿOƪçÌüËšS¦¶ï©Âó¥Ñ=;iG\•;\×¾f óDœýLŸ¬õßhcÉË ·Ã_ÐãµwsI‘;-”™˜¶dˆ1êË+aïòYáT³GÒµ@ªY¬'îqÿgöŽ`”êhiôA˜"ÈžNÍñ»0¾D4ùµ4ªý|6¸ä¸Iµ&Єîu ‚¹ûàW-ÑÅDéW2Z9{š¼©%Ý$‘AQ)‘Æ|²±šôrE—yÌ!Vî=!#/iÊ:ƒŠaË¡².㼬†Z(}ø›U}¦¶BÎ~\šlG[I–÷+_OJܵÕÙv,´ÅË<ÈÃ4¥ß"¸ú A0Ž\&CïÉÛüôŽ>é’…—£EÛ#qVyO;õ#,‹Ž&¤U^#,ÛV¿#/ ÁA¿õØ/‹¯°øE·¼òi$©ñжœ•4Šõï•Hù,ù¡ü-„ó³+°Ì[„¾´Ñý VFl/žF%¦D©œ¼Œ @jñT#õ_UðÍS$hd8eb½í¯\%:LÔPþKÔÿw¾º~ß×µ’Ú=ÊoRJƒ¸›¢ñÝÏ]<áøEùÇ©}£Ãv‹#ÜøZé®#/­1RmªÄÆ}.ÚÛ•ˆµ¡¼F¸ñ×~Y#/çË›ï}&G;/kº«7å¼Àȸ칳\Œ‹•è¦*LFHzm€þ¹ðÔ¬¦×ë­*Y·^ŒíBå<žP¦Ë°@Mü²¿ ¡G5AsƒÚc Ñj«RsÍM¦óñ™ö¬&®Ü§„ÝqQ=%½‘=Pæ“ö„zt–J6œ^dxñvÓgŒïwHB^ÀíîQ#/´Ðº;œ;‹KÇEIõsyã!`Ôõõ¡ŠÒr6;öp{ëQ³ÕU9U1#01‰QS4h5)+5$ ÏQá­½ÑÆ9³•„¼>ÐfY0ã·nýˆE¥lßì{ä8¬¤ƒŒðÕlZ:¶•{V›*_ô8T50O‘ø~>_ô¯çù«ù.ÞÑœ¸äxô¼`KtymG"­Êk#/‰&³j-‘Ù³Ò¥÷YÐa]¹ïXR»‹ü*Š­Ô,Â$îÐéï«3Q¯GeR;tªá¸ò]>§óêåm§tNxPI_ñ:w‡ÞMgð9éy›ã9Ëƈ+²¬þ7=iÛü®ü˜øô<õÑŒž1é!»ŠÏ…#5ÇÛÁ1âEÙ㓶N¥Zw¾mA„¤ßar•š¡‹“;<邺ß2 !£ƒòŽ(ƒÜO~gÆ“µ¨ãX™ž;“0â !˜sG;Ì)¯`¿ëÎáõ·äûÛ§¶w÷\Ñò‡#/s%yOnËöpȇmdE‡,0;‘%°ü þc-{‰éÄñ¯U•3ì¥G¡ê«ƒ~£ßs‡†|m΋ŠæÜfûËOÁ5qow\;>Ã1Ê „këÃþª…ãéÒc}_Xó‚ÒLÃ:nWWwgºŽòÓËÙL:V€Ï›Èk©û¹ò ãÉ{Þ©­q:n³={r§¨³7 \;=¸ÝÐT ̈†P1‚ëÀó°¡¼ŠØˆƒ”Q#,("¹³0c¹Õ’Ü^7Rá@ãÌ„û¨J€ œPwAßåSŠkwÓûÕ^¦öElUNÙ ÂBïxF’sd4ó(ä†àV¶*r.¦ÙÕñ¼ægÝ]zB‚eÑ® ¡”ËØY˜.¢¬Oš©qªzyî­ó™à°dÈh›µý'¬Ì¬>´Siá(¦a¬b`îñ&@@ó rQäyW:ªÐ¤ðòÈ5Ü’¶e2W²&.ž¢ôÖÖŠcfJ3,xÎÏ~º?Å À<’4˜#ˆº€ÃYXa¡ET€0Á††±†ƒP‹J›®·£A¯ 1ÒQLç{8Š™#,p}郛!‰§¬¹à^^©~c^ÝÄé¸t'¯ÛE³{(,$’ö±!ÉaËmª©®¢a«Tbßj;[—!¼êçtvK£×.}Ú¿‡[µwôÂêì}½ý˜Æ­íøΓöj×CYËé§Ûÿ]¥Ú4Ýß¼]…€ã×M¡Cì7´‡mÊ;Š¨®ÈÕSxšŠl³ëd¼ FnË`((YM" â]•VÓŒýA&LJà/Þ•u¶î[‰5RÕýÏúŸÐø·ÄÍe,æo•Úo-ŠÙ]cU!%¤ª%„ƒòþÇT÷´¯±N!é!Q«»nÏ"¼î ‰¿½þÀz`ÉçÏm̦Ñ6“~¬IÁ| ú0‰„! +¬(ÏÚïyr.z“y ¶KK™cDw}’QµÄáÜ쨑¶Ò&¬;,„ŽCÂøb¶Ùº¼ò±EŽœ ¯\(°B,B&ðÍvȆšÔIg1G¼ÖŽ¦à&‚6Ô)ôàÀ„ÅQ˜Iã„Û'72…ÊYÄŽ{¯oãÚ믉|]T-4d¥_¤±ï.™ 01˳³¥¥­˜vyh¦ztÛ,¾@z¬”Àl qŽLBØ3vÛ ›zÍtj‚ZÙ»ø¡EYß•°ë¹«/¯5­NzʺáŽ.éÔ£)™ömk{U´i;ÊQiL<4êh±Ç6Ïqcã×WPr·Ç–ÎûÌœ"#ÓmÛû!wh”Ú^ÆŽ¼ì\¹Äa±ð[Y·¡èNZ)©lxÒ4S ^ÁÏôds>!ñà4‘“„ôî úÐÏÌb]n&ÆCÂF2îgÈ47„ë—(ÛÝçïØe×¼4,J'j=f)c òº¨MÇ8Mý|9eÝážÝwCF $‰dªIk6l~¹zôÉ«ŠRï¬{!ñ6òR`Šj‚Ó¼'ŒD˜!™½Ô22Þ$.¦3 HQ^‹5#y…ÀÆq3šÓ©²Ä)k°y ñÃzÅ,½|c¨FÄÀ‡»ùwu  ø;#/|4Ö >€·8HkÒÝ¡ì¯9Ç\x:GÕ”jì+¼Ü—7ÙG"&È÷(p³‰éz½cÔ&¦Ç¡  §q¨¡9#s oØë¹s2,©Úm#/Œha›X}ØÀÔƒà’9oVõqëÊwx„¹4ž„z/sÊâÆ9L6mt^”üJ†–$9^Æì’s¨ bˆ;xb\ðeÛþ»÷¨¡Rw»êXê-¾HÞˆ/‹™˜S¨dƒÄå @3‡Ã§ÉÀiº¶ø¯fï׃>çÞòÐOoªq›Âc-“ ,#/MÖ,û~ˆ÷Q¶Ã‰ 6‡ÔiØN<Ò¦2 ‘1ÃêŒÙ´×½d$è„ nyJ¦ÜD¦Î÷{Z$æ°`’ L¹}îšÑ\]Þ/bê`ôØȉÃÞ(‡¸Ü¤&‡QD^÷"àš@g0Gƒhj÷{0e! \(ÊBˆgüÿ@â= IMÊ’ˆÓÆmu±)¤H‘HvŠ›@×xdÙ>d¬j;ÕÉ£‡èÒ`DˆCáÁÉ¡ÃæK-„!™fBAG 1–i¡ÇØLái:àÙ6î/bŠ-jÍ~¢˜`3–3)ÝàJcXŠ¿Ÿ¡Ctˆ3(HÔbè0#,Œ] ¤;•x8Î!=–ÐÖü¦©áäf#5E!SNÙ9æ}ÿ^Ìô1¬¶˜³Ìð#5 !Ñøê`v#/s‘ 3ë©n%%=À{#:ŒŠãžÚ1@ˆ9s(ã ÍSCg³U¡@×,l¸Kd\²SU3Œ¬X7Š12âóæ›àðVp¦ne.S`a‹2=Í‚!ñ{dk2¢ÎÇFzæ9.þ—è„Ð¥aO%PÈ·LÃ#5˜Šd@g‰HzNcƒ”p›˜¬äd#Å:úŒ7¥p)¯¯Û%­ìŒæl9æÀŒ{^ðÂŽº2™–3^„¹´Ž2l#/¡F×q[–*.IÔe©RPY.ûsÙì¡Ý>¡­½‚Åžìcm¶ª]ꮪÚ³Ê]ªªª­yüîv$:†ìWÓáÖ—.DÑES1ÃÀ;Æ|¾8)›Ä5Žs¡åZNòcú¸¾„ʹ>Û žˆ˜CnÆŠdm#5ÆëU$5³Ñ3:g²¬’lf…-Ër%a=¥Š‚MXȵ‘À ÎF%F#, q.&gEÓ;-Ùê(ÊjÌ;2a!l†jŠof÷–rBgHÇ"-3$Ç(Øñ©ý° ®z}&Žž[†úíÛiu®&yüÍÅ‹±]ûDÿÖ„ íçÑ>¶ÍŒë‡ÿ:?ÛA£É!Ú=¯šæ»û0|x®Jü"©‹"¬VEø ÿÚ–,KËI‹NwïÝ]ì#/¤f‚…¤¡îòØ^zîú¸(Ö>%Â÷.X`Á**,F"”Y*–Áô( BQËú^‚‡±ª(h”ö\Š€!œ€˜:.m6#Ÿ9 ¢Ã£Ç¾0È?ÉÃýìÿŒüŪÇý?ôì I©¦5¸ô}Ð* °}ªùzvÛgêç³k³)4”ÕÚ·óճdz³ÑÞ=ÉÝJHlü=-ï)¹#,öiÏ &ýjR“Q²ÚdÛ) M¼ªŠ"HƒAHN QÏlÆ€9J·Ù\‘€Äš±iêüÓFFMlZ)rà3íþO:·Žû9qÛ¹xÀ ¬”“Ô.^Š<,û~ä„‘.ÄT¡¨ˆ4¢=Û('ïk©{¬r²5ì{ìUçýe\s´Œa©½‡‹âÒR|“ô÷ " ÌÊ%Œ A´& ¨üs=$ŠOÂ}òå4Ó#,ŒT²‚f®ªD@7)Ø @;ÐSÙ(hÀBDÈàªÀwûõŠ™—ÔsÒ¥ÂIäÅçy°Ìk1EAPp‰V ±±ŒEõÊ€Ù?AÆ&ŒF71ýí•FèkÙÜp‡”¬LhñÇãcí M`¡©³|„{L‰ÈªM°~eŠh•:üŠBÐH #,=fG@–ï§Ù 2cSàuQhbªÛÇXXÔP3–2Ï[ jFO#, kV–æ[†íû¬þtGÉ€+¦@`àÐ@ $EðÒû¦.ôÂ(A0 $ù'!:É÷ÅaDD$E"âD€W‡È.)åÅ$õ[u·[O.Þåáí×æîÓ'Ž;tUÏÕ©•¶¸ñIlNµƒXk#5iB Ð L”€¥BÉ‘6Sü¡þnW,jw^K{"õoK)%4[Þݼz­ÍìŠö\¹175ÒKË»–5Ç÷žkÇ.‘Ά74••Ýbå>¹ÛÊt»ëåk&±OªR*–‡x ‚hDÀÞ¿¤â32FÂRbkËÍ«ùðmø`\ ˆ§°˜¡q3þ‰K`Z6ôYûÈEEb±ê?)È'²×ð÷OçÈvû+“E’c©Bu‰Q¬C²æ¡È›0åˆÆÑJÒEj+”…‹œjNIA˜,¼íУž¬Ú3œú­´ÌÚZóà$`8Àãºr$ŠšR³¸®ºõU¿ÁÛ‚Ä"ª€qQàvÐ DŒd‰"áF,ŽFt#ÏÛ³–ëUH¯ñA1&öì¹äO ÇÓƒ‘Í_Jµ¼ '‚”àe#ÎTæ0¡É® \;Ò’hEd$rH”JÓntBt›)¥…%A€~,D ˆÇ®i¿‹u.œ0ðZ‡]Æ]Ámr85Ù2/â6ð݃ȓÞ8A4ÕÁRa#5î\K!¥Ž“ÏÁ1í#/#/¦¬8ˆÚ UƒµÞ^Ø!%ÔW¸/ØNÍôòý/Éus@øÄT{0îï徨å(´­õo÷ŸöÉ»nj좈AѳLË—eÌ!¡²ƒÉ™é}gÛ—¯è(Œ!EBŠ”RuvqÜœNå”rA5OM&t¾ˆ#,°‹(´3}ÒD~@ÆÌÉ ÓBéTáØ"jÓÌ¢ê–,è'žI×—Qm¡‘ 9§ö4º¬R¾þsîÒåÚfnKšÙc„@wxîÇumüþ>gaü,ÙeTJ$hªdTwÀ›ƒÀi¨Ý …Ñó #/£m±ªÅÕFEJ$¶*¦¥ZÌ…*’¥ª-’ՆʊÍšµ*Ø‚ˆúN ' òœmôÊ“”8lñ|‘a¨2 ȨœüÅ(VÑ#,@ ôý[Yœ½Lo’§…ˆp†ÚBØßì¸ðÊT`3#/ ±UÖ$ÌŒi(ô-ì;ѱ#,%• öÀÁX8±e:b=s˜z¬#/|÷U_… ÆØðGÕšFLöM6Ž˜Ë7L(âÃsCIFE h ˜6ZEWÉZ£9‰2銯·ëÚ¶D_nõ@V@Û´”ÑSc :³—hg=é9Ò­A‘m*]%]%¤#,”öÜ¿§³Á;ÈÀs ¤D*¨€;6„OÛ¼à<û6·Þ¯¼µd±ŠÍšÌªûÔáª*Jekr®Y+–»JfÅ“E¨¯ÆµÍÕãt-q+å*øÉ+8˜(n‹#, @AÈï]ç}z>Ž±µ¶úŽÿv[Êi£t´‡ü .7|^®­ ëz¤‡*ôù,‡²Ä‚$‡ïN"“Þ}¨ˆ•v>Å:ÿÙ»W¯Ëöýœßßþ6Ú˜9!Žuš.$@„ Îÿ2ü[p˜“,)µŠ’Й@îeî½*„?K ‘#5)Q`¢+åT:¶«n;N9XÉÖhæÐ)Qÿ\X/ç$&ÏÃIeTù¿öiª'T ?‚ï“Å:›x§¬1#/o / (gÂT¿«{ˆhbn#/´bDÖgdç®A²²c¨DH¥Ó¹2l`›zÝž‚ôaWõ\Ü0ÃÚ‚ÿ„Dvvu‘dC!«çq †ˆY‹ð:°°@¨i­ŒÅ¢6ÚÆA¸¿U#/¹‹o{dÖöˆä€¶úxÒ$ U 6$cL¹Ç¬zsE#5PþÇ›ç36pÅBAtʼn²¼–¶ÈÊâaDÜpÖò±ƒ@™ª‰®ËoÑO "¬ $(¾â’¢¡ëñ£¹T;5<€÷Òž1gN\Þ€ÝùÑùØÜ„Ê#ÅÐ~R›…BÖˆ)ª¢‚±eÄb]Vž¿·©æAHŒŠz‚¨¢$¨‚ #5DH ²xü‰2#,¦B†1X#,šd==ävߟsƒMjX3ù vNˆ#5Å÷QHFÅO~Úms`j#/6À#¡}@ô±d#, ² ”`†|ÁÃë²dèììõSö¿¿åŒdoß(ßž$ÛPîÂÕÛ8º“„‚"‚Ö[÷P–O|RMamC²¬. ý™³ãsg£B÷ÄL¤ø¼Ì’ù§ŸƒeZmr´¾#ÈbÒ¤GHJò8,öÒÿG‚tŒ>£Êâ÷òˆã4g¦#xVcmÖ¿[Dõ£DøL.z¦ ò­`tx~{SsÞ{.ž7Ö;g€Öœž×Ø<‘Ô²öýZFà[ÈQ0˜I»ñ~1Ï^zí…öÉT<Œ-ÀƒÌÁ`¡O¡dΙâXÈÇ×Û²X-SdéÒc(‚ˆ: ¿ÅçMÒûrw®ýGÞu£V‡ÏlþèZn uºc:·¼ü¸˜K‡­Ñ=ç–VuAÚ¨ÓFå§j–×J³5C¡!™œ°Ä+ÆB¯Ë¬1¦¶éO;îåò±#5<>?f×ëË»¿¬щ\^6&‰3Xi[²«Œ«}š^šèÅi°¥¾8Ž 66 `ÚŽÅÌ„G¬ê;8¡ÏÅ{Ôò-75¥­ hZšµ]ØzÑä¿®ÍZ[[»Š’'Šã,͵&æfñ¹«Ïf@ J0b¡cŠè©ª&hìÏ ‘‡äþ66mƒMž‹‹÷0äÞx®C¶×Ü"Ó±‚àÎo)žªÐb/ÇòrêïÞ™— /Æfï_#,À‡`À#¦3¾Fk‡¡£ ªk FÇÀf iœÂÉ“õµÂX“ ©,KíÀ/@÷lgèpÙ½œv7Â9ì¢isÙj.uäñC˜èÍqѤ÷†Fa"Ê íL(ËÂ8Aß(2p5S¯(SMUJ,b1d;vó%ÕD%&~×Ô„ÂÈ¢Ò)qæåÝ=DZ öí¾CDA‚F`˜õI=h§–}ïjá#/ÌPðŒwßàL!!“±s‘–DÊÆï˜øéÖÇ‹1;-°à9#,rF¾TÍœ îCGç³ðÿ‘ïxüÅM}`z| jFB‡*)ZP‡ÔÐ|*¦¤o/FGƒHqB:l×N0$—=HDégõ3¿vkï¼²wÁLÕ ÀØqdæõý[” 2!§}›Œc+äv@“¯ÝÚV»„Mþ§AçF6(ç,‘O#/óëÅ©š¦µ¼Úæ)dR›%E®–ìÕÔ³DÎíµuKk»ñ¬æëºë^/àxÞLj9bð¢Ô²! M¼;K˜ ‚SIyË»‹‡y¿ %„l+[óÞÚ¾Òû·ÊhjFRÔÈ«Q5ýS» ÚÃb4Z9˜œ^PmU¼{¯.³€\^øoúêýß›„žt2‰Dó.ËE#U ‰ßˆ±#€áE0žAªuªÂQÎ- YJÉCÞGB!ß#/ÿœÀï£éÀ>#/Ó'QtˆpòÉ#,#,rÛ#ÉåCª °¦C7;ë˜i’Í=h€÷%[»,9­ŒpQ9¡lGJ©„¢æe†¹újÄ3&šîÞµï@i¥ß±M †+e~Ì+‚âŽÿI%KLžÐ*¯©êdž|vž[ïH'$'ÓÐzSê¢bI"•jnÝ]hÖå»;­ÚêÝ­Ýo#CT’7©!Q4•ª#,#/$&H‚ØYöšJ…n¢B¡‚GA8žúXên%µ(.Ždb$ƒP(a áˆ}h¡–6Ï2`4LT5BÞ†ŠÏÙ£ž°šíÀÞI Žû×è<}O¿*¬-¶¶2<[ýY³ÏiÇ"Ëm±mž¢“Ä„‡V#,¥^¸aëš_» ó#/Í\vÈHPÌÃK#,ÓI:ˆ„RD#C·.#X¤7`q/ÇÈ¢éj¡Ö™Þ"ˆ wbwX‘D#v;¤á¶–·¾ÜÐCdXS à¡Øì449íÑD¼Gð¯»C4šËãz¦wÃëøóo5ìmìxÓ30ᤆ‚ÄZît¶6‰èù]ÇOÿdÅ34Q/¯Ï|r2oD”•²,HÈu¢#/±}gžÙ#òc¦³ÅZ’1ùCª¤Þü%à«Ò‘­5)$6‡߀£nÙü!û4ZÊ»I e@¯¹Ì\\6†ëNF¶Èn…$ £äµ)φ»pj²®¥J~Õ³rçÁÓÄÆ6~~–»3ÐС‚׎¨hãÒè„P®s¦úäÃ… jþÊŒ¨4ÌG9û(!¯EUCàì†3Ç7¨ÀÃ7n ­ÃA ´¼Ê/N6Aš ¨Q¸]\è|ò¡ B)L\Âaùƒa°{yÀ…Îl§²j Ð-" ê„„¹†¢Te…,‘9¿ÑÏ[²•üñ¡Ë3äCH&%•V «YAìU*#,…EV Òõ•ªœ$:Ä’ÙAÌ»±ˆF•$*$,„#2¥\c Ã3ØÒÖ“=Ì<šÍ¨Ül÷–ª3¢P A¾50tÖ,-(¸«jÙ‰€I0Ì‹#,Ûo)MD2› l²¶¾F#55`êR“®W¥GŸû'V/¾y”•Ýe•ë‰o¶”Ë‹$…;‹ÖT2‰±¤.; ººP– ã‘O”,HéÆÈ…EÙúDk-ö6™›PPrÌQ'äHéÅ´Íáµ^œSÜ‚Æ}“̶I†MK¹ue% ¼#/OwQÄö9oÌ’þ$áJ•‚ðÌ@ 9:Àq¶i#,,óF(ÐÎ$¡è/ãíÎd°À±~F6óññö÷#ìñâöšpoKž%EýKâF ©T+n‘„ã÷tæN»ô"s-qE’(¡—Yëï?µ ’B+!)ÐDè¥l>Ÿ¯W}ö†&ìÏ™kÖ2¥ž/Ë;Iëï3Ôz¨ñß…šjwHeSR‚Ž»Áp–0úžÛÉ{Óóõˆà¦&ƒìÔq¹áãøÇéˆ"ƒTIÙá„[\“Q êbçD BÍØNKœQPa0Nmj–pvT—sÖ#Þn#/ƒ~s_áò«{‡´`øæsp«í#,öþ³±…*/Z2)MÓzÕw0œâþÍÆñdoéO*TWäð4Ëõã8Ôîñ:Õ%ì(»ÕXÒrª°5ÁŸçgøY3ÒBnc1o|p#/7Ò[sQ¡¦!A9©«.Ë%Zo»-ïÜwJ,i¬#5#,U@W@t`¯?)@M†5B¨É2KäàÈ Ú'2/Z¤K@‘KÀ¹:EÊ ÈÈ –Æ#54ð ITpÇh8ÑÙœ¶ÏO&“‚ÅWMÊ8ZÂó\‰ô˜³a¦,ûŒ…aÆßé#/¶RÙÌOÊKl=ô—a<VN-ÛÅ¿IÍ+pÂ5A´ÐI§Ã$ñ ÖFh>àÕk;5åy¤2z/Ìm”„†Á5áÄÁ›‡±ÛQvb³ûÊ¢'G0Ð c#, Ŧϗ³¡;Ñõí4¶» A6e0!Šˆ¨4‹æ´¤ÏÇ¥ª.ƃ&ÆŽ%Ì”"Ùn±¤3M²IÄ#5i£I#/ #5 E4ðÒãc=íõ[&hˆ„¢ƒö³&úA…Y©b” ‘ ˆÇ@¸Ž#5 €ÞZÂãˆ}d “@¬ì‘¿ih`û^¿6ó€wn§§à™É§U>Õ0G©{`H‚@‹ ŽGYn#,5ïÑÓ«®Mc›=&Ø1¦Æ€wNÿGG"ÿa樌^oÊàq)8÷ä?L¹`—ÞOóAM ’g’©çÙdÿwæÈ!ÒB*B"‰sºvYƉè í­¿’Ðl‹6-oȹžunIKmÛ¯¹jª6Ô„‚ÿ`E´U´E$A¢ #5—iôê÷§¼£#,zˆÈ‘|ëî:¯iÏCÜ$©[¢X7ºz°îЀm…” T“íæu¦Vzž³äqHDî!2@‘†H%2RkHS$Ì–b“lZL´¥ÕÓ2¶˜dŠ6šT!’š#0)6IJÌ‘¯µÛ¦&Mi4h–R›Y¡S)™#0(Ð#/©‰I¡ÙÝD*hR$ŠIIbb Q’PZ4M’’Á(EŠiKQ²(š šFe‘¦£1!¥„”QŠ³Mgz»ö•;À8¦,ú0Ì9.ÛœX&Aò~u=JÎÙŸ·ôf̈ÿx¡=;p%­S*F9.¾ó•e† ì:¡§ºy®ƒ~)W¾/×ÝtÊe#/´îÕ¤•¬D!$Åt2ÒXï-œq1ñ ÐzŸM“Fýìß…Âöï7€y9,碓³¾åì¹·[BJ²G6”þ‰kÒË¥gßÏø¦dþ$¬|>˜/»}!‹…aº« ªhÀ\³#y,P!pÄ ^F¢ü#, @9/rÆcPÕ,ÒSiZMa4•¤¬ËL$$,qpxÖ}miåTx0ƒQÊ™Lø1Ç?büÄχŠ­ F=DØ„}ö“Dˆ•õêÚM³ ! ZÅ¥=ÙþÚäcõÖ;ÛÔµŽÅèõ}"DcqøC‘–Á[oZ}>·rþd‡/F› …Ùt”½*› Jè^á€faúþ‹²H1Õ‹õ‘½ZŽ 1d~æí“{©?å¼WÙÝ­Ûµ-ѵ´cH%µ“#V iô8$Ýiš m¿ ÒöÛMó“(á©ã#´Ê%j7®N.ø""àï3]{ãŽéDÆ°¢›Aa¿rP´OezA¹ÁÞi‚ìÆBÝ|J{Lš feðv^`ÙGäÌÜ$°Y¶ÜKß#5<öÒ@Ø#´ê@íÜeˆ¡ú½’ö?o-tž¼;î¿¢¼Í”‘@†kübØ<<õµc/Ñ´À5kìèrŸÏèÐ!V ÒiϸB½†vW5ƒI²¿5ç†ã-†?mg:eY| ±:YPìžì²ªôS||S%JÓÄ©=ý~õÊŽVpj@¨{% ܬ!¹Ï‘Ð3¯ ôœ²[ÓïäY ¸Y#,7\F0–rÑsÇ'B;Òmˤ7#5ˆÁñÞÉ ,>!C ÄÐ$ÃbaÌÃÔ#/Ôÿ¡¨Í}¤Cog‡ŸZ’ñI–ÓìvƤPû`M2!äûFˆèÖ Ó…-Ì­ÚÆÓÊ;Z#…ê¨Xe$|2’}ÙåÞùÍÖ?£V®lÛfI”Ô†ì)ÔÛÈïZºQW¬Æo a31þMf•.¥2^BåÒy51Á„-,.K¯W”£ÔZ1ìf¬Þž1`9Û©š‰”—ñ¢LKКB$ÎÔm¼JÝ µ6üt’AIÒÊΉÂæ>ùÛw•wws!šYÁŒL\.iäÁ Tø0R0JtÉžçOK7¢©á?óíÄÁz¶¹~#š¢ŒË­;"¥àFá`ÜådçάËì–Ã#5ƒC0jvœÖ ÚcTêX~Ôê¸Ü·1Roø‹g„r¤Øóˆ3%ÃÊ LBì 2´>t#/<;;, ú7žx¦dºCäÓ@Öp5‹¨íUƈڜ‘«y(aÌ\rm†–Âz¡W««2ùZBA¢ ¦³Wo0áë”àÛq’52v¾Ø³/Á§Áuy¾—h ûº;v[Û$ç3¨â3€ËÒÇu,­úfwÕØcbÔRd,vrhÀ L»_;l\;þNq#,X(‚‡cÆáŠ(ŠÕHeûÁ5-1”êqDW;4Xa&(Œ~]çªO÷Ž‡øÞu’ÛŽÇLêÀ¼øãs¸’xíÇ)Þns/x.ï>YÌ㦫 ¤’kL:‡C›Ø‘2Ž6I7= ¼c-l‚vÛ…É%ÅÞ“¥¢*êoNÐdÝΦ—ØÆëD@³ß™9;6.Än%à‘ÓÞÇG=²öâaÝðÜì¿Ün æˇbsÎéÎ'\µŽøRž¦Î]j)XÎÌqMíC“´#÷å¼—qê.gxÕßÃ7­0ln6Ôi•Â¸Ýq-n#ll#/j&¡Ü(]èºÇ&M–7K}KJÆèôRrA‘ƒaÎ`î¦é‹"Œm¾86v¤cpÎLc+ÑÆíÙ\»•ÓZÇsl£ÔÅ\#/e¬S!(òBƒfækKZï½´k**)šjÝ”ˆJfGºVXnÁC#ŸBÞ(BÛ‚ iÐ#5Ñ'Ks­ Á\½ Ï•1GQì±mP¹rIY¨M†1C8ÎÌöC´ù†ÇG2>TP™‘³.e†Ô[ê‡FPaNü+imðg`ÀŠrÐ5×U/V@ÅCd&Æ^‚,ÆÓI53S¥¤ ÓQ‰v9‡ Ta%3 8][ßPJc´$dÂ"méÙKJ¢P‘ê´TÕºùØÔ3‘É 3ø1z®C³mΕ­·Ìõ’`Lƒo´ÚwB\G,A(©Y+”;ßtÓcI¬7rX<ð5iaNF:tÞåt4 ÍËËÕ6ÂXK›e:G #5&$Y<Ú k‰ÈCEñçÃeá—Èã9€·zâòñ³Ñú‰ƒiÈDS‚QHn!¾¬s(a–M…d&°U2LŒTBš@»©O©6f¶RêT–Q§v(bÈ°2’P¹•40òd£zݘphU°-€`ªJº™8T-!–ój¬ YlY)7ªP1šË0`aV‚e©6IO$¤a–`J£€^¡ÓAX6öôÒŒM‡ Œ+ã¥dLÙR’Ù²[,¼Ô±›2evgrx³VE0`õQÇhc¶ögYföΔ:™]ë‰Ö©—ZRðz ‹LiM+ÙÂ3„‰‰w-Í ãÔ/®Ñ‰Ä!+)’e#,òôö ñ8à:H“a ë„<>VàÔ-gnK`lErùÔö×¥ó}™ÄŽí`G½+½è…PèP}R9‚AsI¦Ðî±¢`TiBƒfèÖ9³h'VÙåâ˜m‘#,@ ‡ ”ΆEÁ¶ÁÝÜÚ3#/¦Læ3ÈdçJ×¼ÑLMmH) #/¦á#H. ÑUV8(|WAÈ]G’DX°j(L Œ°:ˆÄõñÉ#,ß±ouš)‚&ßZ7-½m^¶¯%â-OnÛÒL6C„CŒŽÛ…o4ÌXn74§ž"£¯˜Ùä/ë¼ô|…‘æ#-¤J:?åike$‘#3 œ9ð3 £·}hELȆŒ÷ Ç ˜pqD` ¡‡­#/ŒAĶ‘@Š÷ǘ†ØhñÛ²M ÐQ£f&—¬GcrÕV ÒÅÚ•HˆurŽ˜U1Êò.IÀ8ɽÌ0(vî)7†Fk6Â&Â¥$,Ù3£™‰HB*Ùˆ@…À†Çc‘¾Œ8pv¨Ú‚‚x±£Iè,Òóa½Íf‘л/Y‘Øï%Óz`X†‰FÐÁÍuC­T¡k@º ,Ä׫zè6‚/#5úì”&i°ÜŒ`èpWî¬5M‡4f3•‰cžm,OqÞÁ™º5¡·#;pd0Ãr›\A¹Ë„á­Ê¡‰ªJ,&0  "BÁþÆ @‡ø¶”ôBE„M )˜»‰h °RÂìJU#5#/†ŸÞñWòx¿«Õ;€ÚüwV춌Œ‚²­M!¸>cûÌ‚N´TzÊqˆÒ—B«øÀï•#A¢¨³°µ¡²Ó!!ÜApVà^È;U îËKùEòù‡ÓÜÌj4ÈÉëÇÖ31®[>”çq9"ë_óADpX³[dú¡Ç.¦Ð‹¤ ih§¤#5tÄݺ…±RÍŽAiÅÎdÎ-+X¸#‘ƒ†Ûd¦¦k`(o Í[FFK¦ Œ#5ÚïMݧ`b̸«;¡b¨mMšv*†|.ã©´¶Œ÷À8›ˆKœd¹B‘$1ÜýÚСU{nÝ:Çk–emúi-m&ó@„U Œ‘›ïò‚PØ8„C‹ —§®‰€—#/yPåJ–,‚Ъ1Ã:z÷ E¸ª[géý?P±;÷ÇÊq:‡—à ²¯ÒE]¿vÓM+oßkè¼l¼%ɦcI]wfsu‰QmÒþÑy©ü÷#mg¢}Ƨ¦p¡Ô²¤g,rHȳÚÐ"Q#/Fžãò±2Ð>Uñø”Ýq Bá0®#/7>ÓGÞ‡ˆÈa$¶ÅRQ´¦Ú+FÕ%E-35PhÛEŒ#/ €I#, U¯ø&ïaážY‚_h –êSß·«½qLCà]NØ*~M¦½ÂžéØ˦Ÿ¹ç|ÞÉ}9š5v ²KÂÆÙ‰#Mè h$ÝFY•D…¤Ò ro!¬¨{§ŸM@H Šqö:-'„Íe¬ #ÎfÐu”/V*(~ÆRH)#,ÔÉRZ üä;¶#,÷v6hñçÑS¬Xd&A·ßUÆh*1’Ó"F¿#tJ²4&Ði©²#,\ŠÒ%¢ Ä«ÅmXÔ¸óD1–!p„HO“š3pÃLä\ÅÍeº&šEKÀ1€‰dÀfwùÏGÁðbvúÊ#/‚›”]! BÑjÅ l].t§Øè$ Ýq.´ýÄ[YD*"Ix¢ü,†ØŠä(£¹œFXÿB`>šùdé0òð°A |ûÅA¼$&œ ?mFƆ´Â~Ø#¥Ço´] 35o]ÈŠÈæºü!®Ï½ý ñk@nmpF_ol==1–„ɶW¤3ˆyQ„«Kc+ChãÚ la¦oZ4´cX±EzŸÝì°ó:ìҙǥ éVP½´[MÚé×3.º˜)d«Cƒaç¬074ê¥#53©#3“Îðãžfi™ª¿Â&©¨ý;dÎѱÎù!ÝÙÇ6Ü=ˆ.Ù¢“•@°.I›9Ä`5†#/#`†k”¢eL¬;C¬€Ú ÝÒ–S3:g"K`¹ AÍ=:j4Y%¸ºv~Øg3ˆj ‚qÚv†Ì6K:A‰F%‘–XÄ)¥rÔ)ÀÁ\Ød‰ #,ÅÌT°Ò¸0¦L1 ¦ ™C#/‹  †9‡Z$#5YEÇ„03#/Žnh/Ë[棈 ”¸?ã RD^„NFÝáeÓ×Ýë± ³Ùeýjæ°pH±]” £ý'ófn ?Q?T¡pü¡Î °Ÿ»â HÐ5à$éLò°]YG=#,‘Z@ùýPÍ)¥^î d#,ÓNqN˜U4QUUU#5¨4ïFßÛH²[h­’­bÕ¤«Uùµ”Û˜Æ~+ëÄÈ’8}üϸïd­¾h‹s#5}Ë#5ó”‹PꦊüOô`8ã¿›Ü:ubÅr¿½†âa©k²wŽËGº#/Š«d‹‘A“‡,ë§ q¤Ó2enjêˆMªt”’ÂÕÊu…®iubãê;ÞÚÊEF1¯p1¶×Ðèà\PàÄiÊtó©·¡ÁªR ‰1œ¤¥Ö;KÌ4›y¦óYÛ¢ÜÌZ’ž‡¾:Ý­t Ù&)§Už pQßPYbÞÈ…13±³Ë5B"òQ(ÜD е±fKñ-g)\áÎ:;X´3ßääáœBàQ‘2qño#"ì°˜±J|Å!¢ž†”ֵ̕+â;vÕ™§{o(Q4Þø½,m½MŒ/ˆêtQõ6ûe)Ég‰žL˜â}¶`òdCRŽ MNä2Jò¢ƒc`”VwvÍfÜË—\”ä† ¾,,Cˆî— "( ÌÅ9xokeAE¦ #,ƒPJ`Æ ˜¬FŒÍ2<Âå݈ Jte.%¡qžûæÅZóȹ4Rë&¶nÈĉ@K™…œBèÒ…8€Ð…úÙ¦#5:z¶ˆŒ©zÙŸÒ55 ø]ªîÝ’m[}Fù.Kµ³awsK·\f©Î·³s¦]ÎÉÆN»Œ¶ò‰ªéh6ëWi+r»®Ýݤů;¥5;Ow^o5¼jB×-¹­ÚTj“Ch*‘Êëi#/#/ii"Vª†…#,nÛ^62šÓI I‘6V6ÆÔÔ¢™®¥®•¥šX‰¬1b«"CÑå´ÙÀ0Æ fl#/’+[IQY’$AG‰?I«Ñ{%´"Й ö1‰±Œ˜‡}’Ã`¤¨œNM£.Ä¢-"°T†Hl²o‚ób ê;Ï;‰ØL'¬„Ï^‡êaKîZˆYLÃ?y·òb<´@÷Äà#/NíÍtFLJçmz¢×«å¾=›ÏT¯¤Kóéƒy#,ú¨UEÆz,qƒ‚æPî ‡ö¼Ïé’Hð|{†éLûK‚‡8Ú~šêÙL/B`ÁBÑjÔ‚ªÿ~ #5ÃlƒBfh •Z4XRÒ#/BD×d7Q¶Ûfv[MÅ)”a‚Ñû³3ߥ‹}Ù9-ù·XùÄ6kÚP%,jTŽ5\nƒ È3§vŠ'ݬJ¢s\mje2+çÅ@̪3p—¿ zϱ•¹êkÐ#ƒ§l‚Ó r*°+xºg"De“§çvJ9ó“Ýg ë‘t/Ð…ÂÌ(7$ÑtãxŸ§èk¨Ó¡®{ƤØkTcEÚnÍLRY&mÞfè·­Œ‡êøvüc-LªÔ„µrœä¦”Š(–·Ÿ|›[[å­ Þºf²Ò¢Y¦›i›El¤ÕJûKü?ÉÛ_¦Õ_&©¬Óm”µ¾­‘#|)‚D…š– gv¼™J×JƶrÅQm‚”o ÀÄ#/Ôˆ™ÐYÙ5ÜP£ÕH%A@$E 5Å-%&Õñiº0”jIk)¶­6ͦV̵šSE*KbÃ#ELª•±-¥0”PÚl¥2%I›)™´B˜Õ2‰)(¶5&²T•¨5)”Y šJjE(™±%©i²6jɵ4˜,‘T¦IY°•ZPl¥H”$’e’“)3’jdÑK6©¶1ª&Vƒ"FÔ”Ô¦Û*šÖ¥šL–4¦MJUK*Ù*Õ|ªµÝ­²²ÛM¤³i)*ùM­®•6mT¦Ûi*­«á«Í–¢«ÌÕcZÑl¦ØßZªåj‘5jUP‘CIF9Ÿ/HpnÏÀ–NÝoŽ†MYÛH÷e³{°Ù2í›0ñÑcBÝë'~«ÅÈ㸫 ©½»hYá$©=!â^#/)ÂÈÞD‡u/÷€1ؾèž_n'¢£²=PÂÇk´4#5.Ã,=ü½,k³g]¸bÙ 3meÌzË£»>™2Aó1ŽË`yd„E,Žàuõ¥¯¡}8þMCFßl¬ët+÷ŒYE„ Ã¥Q¦(fI QÖšÃM$DD‚jXªÅU#/ û#,;£Ü{dkù‹X'©Üè,š¡é5vî‡K°6Á0ùå&¹Ó’ v¢ª~#,© åžÅåûÐÀƒ1›°ý"|u‚E. y!ŒJ’Š­ÝÓ¯ÀºÆ2âCÛstæ¦!\ \£:q±1®"µàv_´• åïB*75¶0"t^+òA¦#/tøySyjzM‡I!Š“»4ê#ñôÇåo{ºòœÆa^E\^i­éY×O<íF‡ëu¼]ðи±FµÝ qWX¼4×Ñ沶ð·eÍ’¶½ºQW]ƒÙkÏc“B7kéR“ŽæÇ1…qPë6Mù«!ÎÿÌ]"LÅÃþŽHe™EÆZP+®ŒHŒ–Ú¹ÛéÆýƒ’cZPPRJA7+¯è—'±Š+ÚN…7HI!„ØòX;A¡–5g—ZÞÄXí=òª4ÍáGÄÔAFM#/½P*‘*0f=EîdÑhduç§ej®C2)Ò¬„BáPª °aAär+ò0€¢Ld^±zî.5£'[šÑ3D#5GÇx?!Ó¥ãQT­9ÖM°)¥hw)¹_cí#PEêzq–§MKCr¦ UK†QË4`ÅŽŽL·~%cÞPt#"#,ȆÈHÈýËiTÐëlñ¬ZŤŊ ”a&B[e¯Õ›2FŽìe$qJLØù ¯ÅÞöÌh”È#/"#,#¤Òløb#5&’G­*ä‹áÌTcÄÐhŸ,ô­†Þ-:Õ uåÕkQ5; 墬lí4QYTQ˜×¶˜Plv;¼ò´wÇy#/ÔcSfW<|ò:Òx½‚›PìàÓ·rì·NñA4ÒÀb²’tÁG­ R]Sc#Ng#>Ìðn,•D ´é‰B!²L8 ¡Írº$Š¢Jª¢„IÖ¥ ˆ[J¨ÝØY’k¦ëmGÉm½È¶+jòïY>!S®@‰Œ`F‚eAB¢*\¤–ÙB#µÄÄÌ0€}”Û×–Å׃Æd>É·#€ª1@ð3;õxÎ]Ü©q¦¸@åÝÑ"Zº#4Å–ŠW‹‰·ë_x ,À¥™ùúùùBkdÂ+õµ¢šâÿ!Õ€E‡:“A#/b`5|ܤ€(BÙ1UmµrÆͲÍ%6W]6‰×M5ŠÔj¿‘XŠ,I¶kÚQ­½÷«Ùl©hÄú?ª­#,a#,APÂ"PÆ7À°Î!Bå„îa”ü1NaÖ3÷¬ÝBÓçUk´0+Ø"A¡0¬ðf·×6˜Ä¿&®/†``i4‡ßø` `¢ì3›c°0-¡€*ŸŸÐmÃ#,ŒAV¢ª4JÑàÉg?+ŸUú›4ð;㺣,7–"’IÅ ˆψ¹ª‡×>;vI#,%ÖCh#/ý¹;Ç‘éO«Yöýyñ½Ïí½Ï镯 ­vǺ.øuQ³“‰Ûì!ø«6åF†n²àCw7i¨ÎD=wyG˜¢"»ØT"Ûöqô#¬pvv- @¡Y^F#Kô¼j(Ûh b¯XTe[1nŒX„ š¥ßìöoçÈ:Á2 B?PC¨Šq#/ªeÂÕ؃ÏÑ騱â¯Ó=ì_è0[ öúÄ=CmVKb¶¿Rjµ,®mu›U·Kj£i+¬µ¹ZÚ5²ú°ïFŘ¢‚TD$A¢% !&#,3«=wÞÂîËÑýpAW¹ÁVØÀ¹JPe$À" ê%#59#ª:BaXLÚhcAèÐÚÙw°»5 ÈÅ3a OÖsarz“Í(Ñê É8š£ÊÎ%cþQ:øÁGÁU,!ÜHwÑÞ< 1÷¤µH²ØR**+àvúÐÜQø÷hc10*Ä5Ã…hÂômXp[,‡šûä€&¡#/ÇŸq‘ãßM¼+1yåÖ~N,HVRª¡¤Àhxü½ü;;R#¨” 8J<ˆ¨R6USK‹Ç^4R †ÃÓ~¼Ÿ}ì_Œþ=!…„P6QúÉÊ&÷-š[­T&–"`åÕ¼Sh ‡ 1³ØW6¼s«¶î‰(Ù5&*RVѵ Ô×Ê[´i­¦•”öWRk%XªQÛ°-î¹@mßß¿p¥Á;#i“ïvÒEÇ€42£tñJ¶éÆ­…;ˆy³ÌoTŠU7ûmiàУ6ˆøêU&$¨gmÍ(¥8¸àðÝ`ÎqDUå‡Äa3œêèHzmW¹"Á(ª ¢ÅQ!Æêˆ#&Rä+YO’@Áa¸è ]æ’ Ø 1G¹wù '¥íí`u’$’LÀýq±ƒƒíõë¿×÷[ÝÅ é¤ÐqØ%³™¿wRh„"…›hÂ)V›¢`¿äøm#/¹›dŽzÈþzÌö‹ž–¶ün´h5õâR—¦È¬‰Cá :'ª¥t›ûŒÂQPnÊv@às’¾7i5$Ÿ{1#,Ø(2š0Ù†A“ ˆ†#/Ü …F%#,>Ìõý¸ñŸf“Õšà0†n(c‚<ù˜1ЫÌÒrÏõ¢#,¨å¤Ñ*M—ÙóTI%FÁÄ8¶Y0z¦$öi…“¾ñ“òÄt¿Š6ÒuuóObˆ{_zišó®˜‚|ºNµÄ&åßMå~hÖˆ´b-"„¡jM$%"’ªm´µ%¢Ú21™¯Ö› 2hJ‹K?q¶¹µ¦eR¥%XÔQM)i6ÓLKfµJÆ›YM-dÖ‰±ØÚPj•£"ËZQ¦U-*kU’)h5†‡æz”#/i„O÷?6“Žìd¶¤"f#€ƒˆ£ÕáücD‚5$AJ ÍZ£j5¨ÚêkZånÍà[2@$dH¸buC»«~H_r«o³¯£[š¹ÃW(ÆMÔ¿Áꄉù’ ² ùË”Íü¬¯¯uV,š”#/¤K>av\öýÙ#,2Ï~ñ¡: ·(Û°»`ˆÜ§.H€w`‰åßþw0âW„Ah€ÔöDáÏMÂzÓŠÙýÄ A2=‹öP•U*P” •¨ßäQ/j[¤(q XO½œ¯"ØÊ<Þ¿ §ðÌ•´Üm×Bƒ$€ÑÕÐ!=L=|î€âª¥Êh"jD£9–8˜'ëÝ•Å¿2Ð33²›–7ü}‚§¨‰Ú½&Œ$ziDk´ç*©°å4ø †õ@<{GÈ#/gA'1#,bjIÄ·Xj‡P3väž<䱬äN Hw0ãÈàlúḆ©ü\£Ï\»(ÍØH±’ƒŒÄ¡ýk<ÆÍœ„!pIª0Zà~¿ÙgÊ!G¹Ëú «÷Çòùi‹|@¡4´²/âçÝü¤û»My–Ôl&žä"Nçký’À½[FYD0uűŒ[ªd“Bd˜bû©e²¶ö¹Ò^^à07 š…ÅsC’»+Ž_°ÞäÂ} ‡±‡±»­S .Ü6‹i@11Å¥²„øf£&K>^&—×m5ŸFá~¬RE ‘AN䥂(Æ#b„ñKw>ïdŸ«6kG´:htt#,á=_ïÝŒ—¡p2€É¼n¬²ÈH‚‚£c¦TÛ=Ò1ˆÈ,¶’2&š,K¨QC£Ou†n–ê–‹4T$Y”²‚`UD)å-SÆ“¢~„˼S.›€(ÐÛ XcQ“¬qÀ-Ô' ùŠ÷ÁˆÌòAydfe@v`b qLqºß m]*H™ªJêä€Jd¹Ý¡-îÁçtõ¨vÁwÄ"Á\Ý++î6-¿KÍyñòåÕ7<“yrBóÎ¥~I#k,Œ'¢½>ÝÍ•E“\‘P3HoVžLÆ¢"3°ÇwkM´×m*o#/¡'EÚÖÆÆÒq8‹¹‹A-ÂH0„¤”z ]á£ïÒÖ ¤,€ÓŒQU¦¦¼ÌœÅ<eÍŸûB'0rwd§ëµ¸Žjá*Çy²K5^P¸Ç @œ3)ÙïcÞ·Ôº¨WŠ…RÅa0ý¸;§ÃaDȢ߅¶•Êoïó£}g%ø×Ã.³Ì¡T ÔåÊBIª¤‹n¼†È[FRPì#·[Ñ$Y íTiãŠ$økÒ¢µùfúÄ/êvAÎW<r²àˆ›®G$ÆbBÅÞì‰LCh~µ–Å…'6ÌA5F#,Öýäˆ7¤¥‰Oß¼(ÀF[$ï&»ÂZJËÜåóÞöcn½ŒBÛÁª?³ja䥅‹J“k.91-”âa¬†x}L®³Q·#/£ìfξž@¶k€jGR‚†‚РˆÙ±¼º]ª…`B@Fì(‰•iR´@HôE(¨„Ážf´#5¤•Àõw”:S §™±tEvoöο±P1uã±Ä5ç鬙kÈb¤ÄD(u’´ÇvËæð9´t` ¿«ØÜxÄD$6!É›UdE:ö`VAA%Z¬KÆö¶‹¸\ˆÙGèˆeêÉp×^Ó•³j‰©Èàýý°Öúü›Ý<‘}]ÜjÄ~ñhóuµ]v›xPšDÛ^ºò¥ƒQZ›JW 6ìB #,Æ„6’% 1‘¡(2¤*TUF¡ (PH}WC™È¢‚Ø÷P;{kTƒ¾ ˆ‹`©º›SU(ª¨€ªûù^§òW{Ä1\*ð&GaWŽ0­ n(šwŸ##57ôx—nïmëĬcºÂ[p™Œ(À#5Óa;@#:÷/2Þ(’µåÎæ“_R(ô€Ç¦9»ZÉ6ÐIN0ŒJlC*šDh) ›Ñ6¸L±"l˜sEg6f%Y¨–Sd WLë ÆžB]å0ìè›È‰Û­«DÈÂHÙ“Ä/òmZhl0Ò#/ós`Ö¤UD7wD 0ÚÄ1l®¤2Ž{TõEOé8 ÚpãÂB@„u"T#,/˜-ÙÖ—77¡çKïîcI©Ûê´Œ#d=^£š‘ix=KZ…ì#/À›'ùõ6á­•F¿sƒLu8š&ÇÀ:hì¡)#,êƒy, ‡¢*]ZRj™¶ÊZ6eLÖ¨ªRµùUù›[ò"W]¶Ú¹±…!(`°¤)’(£Î€‡Oݸcó!Ò<®Yh¹·£j˜_HqÚ#5€¬==Ö³VB¡ïš1NGŽÂ^uç–\T[”žö«öÑäÝYGÞAÏ ŒC#»:8ŒmNçÒãÓYÂÉŸ÷`â/ $–”kR/ë~ªÀÚE–y'áPÉ<Ö»ùf·˜ÀÚ4Ñ$ØÔÙ'½å2‰¡Ž’Êhå‡8á}“n±ªÓl@‹ŒQ:ÉP#5FõQA4ä'^ Ã#5 1ÉW)«¬ï½ºôë1LÅ‹=•_ ²¦))Š•*l#/r(\4JM¦f†AæwôÒþY’Kjé>Æ#/­µø˜þÜ‘cVÏN}M·ø¦<óMÛò#gz8ò!§Þì2vu¬#/eÁ;|jù`³ßÛDF`(ƒj¿ÕD«–™÷yyž#,zÐOIâ¢Û€Qž”`4jû{~Û‡œ^È”˜„ãÞ…ð dÅ(›N©È”ÕúñtHQ|ÑÑ÷&4Í@{R!ÄÇ*›ÑÀ܈7,cŒ —!Ïë`²|èVcSWn;>³<D’×—ê½õÓÖã„nŽ™àO‡d¿`”:üg„3!š¶#ªTÝ%T@÷DgD47:ÍŸvÁ£ Õ^}ó¯rû žŒGœ·1Ç+>ÇiïrC€Â'*¥YC(•9$—š 2idHAˆ½-"g7{´¿=Ù€¡¸/Bï6.®¯W°°³ý_EÞ+ Q!¶yVÑ`¨ÄÀdvÊ—RÚÕžvëÓ½©«lÍ[z­t֯ћSM_©uҕĈàVxâùÈ›ÍFFRàs±Ó$h1jšø$”¯ü_íbÇõ7ñ¶îÒÙè’¤=È?ìî› ƒÇ•™hæžrõ[F*&ƒkã±xŠ©ÄójV°¸²¡#Ê~HRe¬ç­ulLôеd#/0÷ƒ4â…ÅÁ±å­­Io#|Nz>P 4Ç–" ˆ§R7ø†%C2ämê﹄€G¢#`Â#5í‚H_8FHT¤Õ¨,±\ÝÂØJ€ ·vµ×,ÆÝn³Viµ›6ÔÍi’¥™«lËUu[7e4¼\“Jím}R¦bÚÙ`@E9Øèq`@ß: ë÷ÏDéÏÙñ»oUëÖæ÷<˜ÜÔ³ßÏØÒÙ5DzÌ"µäú*‘‹4„ª‡ÎÓ5!ñ>éMI¹ó†3lÂAëõlõš¾…ÒcZ<«ëÑÄ#/›rÄ£I-¥¦‹ý{¨l­>@ ÈÁkQ ²LU‡MFa°õ8½Ö¬ìbE,…” Æ4ú#/Sž¿Õ¹õ©ßW#/6ÞM»J16æ¸ß¸7plëÁð#/ÈâÊÅ_p6h^²oó®Ãnªø‚,ESøëÒ`ØßÕí[¸`”]Ô¶©#5hŽXæUÕ»°¨Dˆ€A¶ÄÂó RF~ÃVø‚Z*îÖÈ3%Ø÷Hk)JòFÛÐlÈ(3™TqMP90yÍEÁšAuög¡å#/­áTCð~”z,^G™"`÷¿=·<â‘I:~ÇÁï4òOZiƒ[9 ‰PÜäÈù}þg›òÙI0IÐFÿˆK÷#tH²À¬í dZvζâŒî0\7 ŠwnòÐ;#/ì8…‹È® Älô Ò¬ÜÖp#/ÇØ\×yܽ÷ù˜Œ"0ð3Ázõ¶ÛñâiK¸™íÚ(ˆ—IˆöÀ²RaDú•VIu }YK=™.!ö»Ò< áàE„Ö0‚È'!ÔeÁÝ)þ5‚›«1ŽÕÜkÂô Ž¡È3oÅ0ƒ? T7å àÜ„Aú tæ„&Øðº4qü`e3bXFËM£Lö›-¿#/ždl‰ß‚…@rMÓÔ±î£?Â27!áSÑ°»SXÇ•‚´ºÛ¬ÐÊR5vûÃÌø Š‡ÇßÊ|7ÓÜR~"Ä@ž €¨‰™ç;§2€^|7Á2ªº€¡êȵx«Qm¶Š¢¶Å¶£jŒQ!FÒ HP4&0»æû_ò__l'¬a€Ä;HÀ‰@?¿¡Á¹U{ ¸ØŽèØtÛO®¶qqFåœÃØ(nao3[²AD†¬Ì¹ë"1è2•Äšž—-¶ä+|±ÇšpAÌŸî#,í¦ž§˜`8óâŒ!o#˜$†Q[4ÆycP!øÖX¦20üÝ¡ðµ æú4ñý_­óU Q¨(¦‡­O^ýÔª›ÍÔ”IÐ(9†<„£ÄÏB€£`0Pž"ÂdvIOè!·ð©#/[IÀÔ£×ÇyÕ3†Ó}„ˆþ3ÍBçÕÜ|Fo«1=ð<6}Õ æeÖŽž˜Òbè T#/°*ãUÊJª’ƒÉïÁo6Í÷M¾¾å®Å]Ò«!²~Ô¡ˆÀˆ’{ÏaM² dp£AlMH?¿Ýî.xS>Cŧ£1îM|,‘¦Ýøòëd50®n>0†3¿hkľEƒÝFo5qIE.8<<4‰fjiªž ‹4ÍéßcÛC½U³5üïÂÙ”.!CF^ž¢2ónN£méEvÏ>†ùa0cc…¦ó±±—½æ¾¦ºèmi`Q00ƒ!’Ÿ€O¸eSiA›Léõ]-ÊÓ#âý%í»ìç/F 8éØ]T(£¾¬I¼¾ Úñƒ¼ç”ý8.0üa­áæy•žExѭퟧfpuꛧ<‘#5òáÃáŒÔ¤–%áq y³+Òž¤ÒœcÅQMBBÈniúÅI¼·Å‚ø¡d8ΓÙ#5ß<†×ÙÀ®Ù0áH:í@i}᤿5K`S™Ó#/$¦S«ø}aêêü“S.=êqP@o’ƒæ "¨ÌˆØZK‹d²¿8("|hUlºCHMœq­À°¦«2£J±¥ Á.å¾VñÒɼm»*®·6²m»ÇI±Z*òêK][r®íÈÌÝ×h®®ifÍÈÙ±²¥¹Â§vÖ’ÚM³l¬Œ#,´…ˆ BAB¨2ìÀl@¤œPK°ú†G ˆ­;ÑȨÛ£Ó)¡ñ¡Jk©ôaùuó÷¾vÖùµ`J•l¾5YpMZÒ”ºÕ»-¶ZóËlþ8¶P¸7Š‹Â6XjbH2@'%ÍÊÍ|my3D¶[kÊÕÑF.>/=òe5ŠÂ) €Ê„Ë!E´Vñ«©•I? íP%±X2”ض-¢1Y•Æ£TmTÍ££EE3F²Ve$ÈÍR Å´Í%±kf¯vè#5$9 ”A´÷ï°¡òÄÅ:þ,€ÉôÖ­{{#/&Õ„ “ky·í_‚ØúW§|vñm#/O:ˆ´OãÅÍ·’r½Š£]³„×VÃÑP"å#,‰H@Œ“¶rñMš*¯É+~&µ\JÚñ[¥ý[v"V)O7]&©ÝÕÓk·i)µ®&Åm£&²Vî®Ò›V•T¯W[KIQ‚”‹MÿÍ!Ä6^Ÿ™ A~’ŒüjIèJU G&0A´É F;JCay8ä X„EV)!­ÛP\7œøµJW#5#/ÅxaNŠ¦èŒ"ïW]0äÂñÕmúŸhP{ö5>Âo>«ãÆO~#5?^‹HÃ)AˆÃðEƒÞ~ÁÖ•84}& ð¸ëmf,FE[ÃôÙTlcUáŒcÓJ€ÐÒÌ­Y… ö2º$šhÁŒŸÇŠ÷ånµ´ÍáöLc,ÇzÈð³†d·øš˜ÛÇ¿aCsb­†á‹»±-PZ—öR#5¥(P ¼!Ûgꮤ¸MŒ;:>‡$Q8duÃ<^ÑwᲩœù½‹§[¢5]ÉÖó™¢mÜY`¾‚[hÆ‚QŸg{«42Š¸Ó-½?¾ãø“¾â ˆ#ö§Ö;ûñáÀ¬föÖãu»`vH©½O*£•ÄQÃ÷žt?º±ë0T‡!‰çÜLì3Kܺn¨E2ñ-Åõ!ó`y†f@<`«ôMmcTm¡-¾º_}µ¯Ï-äŒHÚGüäL¯J&12ˆÈg#,KEdχQlšÕZ5\Õµåuæê½À•ÜX1ü€nËÇ>pD  <ê0?a?C_¡ÏÙXZQ¶AÕ&´×_·y®ùq¢ÚÊV®––0£%îh€Ö ƒBƒKF¡¾@ÁÛXÍ…£ô½šØ‰Pl4$†ƒÚ¶ïvÕ¾Ø5ª™IŒQ­UãM±oŸ¸Ú¼î݉ð»Æ®¤J(D¦eR{Œ%—!a#‘¤šZawiZ{Ò¥cl¬Â‚àL#5X»‰›¹*Äid-Y* «°ˆ f c €ÂŠ‰(T(±`4½¨t6ÀLÁƒï¥¤µ\E”C2èËôé½q4bàÓ( ¢1‡¸–T„ ò_IP¼æð…#/JK¯¬úpcÒ4a`ªsõ€q•cõfLÜ&†CsÎÎWРèqŒc0Ô–£nÜþòÝš3³˜@9@’zDTQ1#,ò2“v¶ßIùüihqºX=nìšG·o¼7¢Éÿ¶¤²ÂçägƒgHÏíUyì78~X‡C8GG×!HC‘{zðç±úµ:Ô\9úpXÉŸWó𶖬¬äôþ1] ½þ¤q{8ë©qö8é ÖË(΀TáÇPUAà vü›&—ɷ䘎YJè’¤ÓHB eŠ#ÜÄI™˜ŸxÐ×mí Ç2¸¥©#5?U€yÈ,ª)ji-: [G„0÷KÁlÅ@(`-ËYEl8¶<¾€ÂàWH#“‘^yÎéáÏ>Â;u茒ÿi~6a“éã!ØgtÎÇ…ô+ÁæQÃË®6õ4õ5AÝþ÷@>þ¸’AðEUø&+»tî•\Õ¦·[MJ¾ü!VùîwÐP…D¨Þw&Vãû3‹u÷6Ûè×\J•Õ°fÓ±ˆF{‚Í…wŸ£Ù¸’I Ž-U#ÎòóÍ4櫆Iºï<Þe¢S–æ^s JjI’±”ªñmÕ+bÑ ÉcA²[Âk¦´š;¥uy¼GK¶è\·wn‘]/ñµx£ššW——mvœ¶e’uÏ5·U±«m±³MO5Ú“&Ôi6žuÜY.»­Ý”é·E+;®×*êNîÓbÑcš¨¦†(TE‡÷P(ÆÂ)qUö'²pØ`›‚‹Ù·×½UƘ[µ9QüžŠ$;ÔþÞñ-F :Eð„ €H–@S¹ˆ–U—Ú£ä$ëÄËóGÞŠÃx Ø×H7#,|`HŒLÃkÑÒûÙø¦‹õè•ÅÝ°ŒŠÐîõÞš7zòñŸu£á¹?GsÔ›NÀõ‘t•XÖfmQ)™¥ôÕíÌ$ è„#5uZ*Ðb Áp?„#,X(g:½ül*&ŒXEXD’0I†$OaáêPúÕBùòèØ5+¶u×wRÍEE»­w·m¼’ü>ï!ªgá#5ÂØÕ5jL¢·‹ÃÚR¨g ¢ÔA¢έðˆR&HÁz×M!;ŠH¢@0·1ÃB"ŠÌf£o¾uªˆÖ­×m»i³ìkÊŸë«nÕ»Ål¢&4:§žýé˜d'È@k:dÿGöáí)R0 L0)A´(‚#5l`|ÝüSCÙXÔ ú€î@#/ñ¦¶›YfËU4Ö¦ØÛi©ƒ†ð/#,1Û³é0VçQ#,uÌmõí³lšÊ¢¥Ô™›` *ÏÈñ`ÔÕT#¸ú0ÑFÑJRRj˜0²”€'ðP"$P ¹pÃrª¿êƒŽs[S>Šã5‹±\”å,AL•¦~>4Â7H΄ˆx²gW‹Llf-mEúºw÷c~«#,¥¼‘Šb„ BOÄ!{ßá?=¹^"Eå#,úe‡0ƒù³È8ƒÈg„+`_ÓÕ}CyfÊÈHC ÛIÚÔ4ˆ>7€ ÔÀÚz“8blfh J å…¡ü #>,-j#ø6 `j#/$Õ’1W&³hÂÁ8é$B(rA#/…Ú²¨0@ÞÝEd&1<¬¨#5´b#N°ÑM›¨X; •AµM¤‰„Xñ`]ÛL¨žúów•æ·ˆÖ-GŠ®X¼jå“W/‹*µâ¶«ÆW¬5úR¶Ûk;fN=Ñó{njöÖö‰0Ã#h~€bH$ÑG(‹"c\Æ<.ð ²Hk_Æ*-j‹Fž›i¡µ,Œ%£!Q*Ã6ÅîTb¨ÄIE#,ª5AE@‘‰w@ALZ`m6Ô]ƒÆC±Ï<±ÀHA}~…Ýɨ'§bWŒÅå½ù}$µ…ª ”Ž!A¤õ@Œ%(”Р7#/€º±—|ò³±†äOvj)À‘Œ$° ÄyDz·A¢ ²©€D‰(…B¨ ó÷E>A×óÕëX4¯ž6Y7OmwM¢ f#/”bubF(´„ÌèyCó?4YÐ5™á3˜Ag™OøÅ6¼zôþ¥üÔÎàÆ–ûlvAÈ[Ú>pZJ¥¤ÖðÀçÙ*üÍm5ÚFv“°ÃC$MËUÚèˆñt»¼îõÖë‰ùHÓF Á0cKOxÔÌnÉ©]!ýšp#/2ŒÃZ}G‡ý%R¨,¤³N ¢2M«O‘BPZÿ L–ڽϰÜtvc¦#5vbz"‰ù'‘êÔ/#/¦gyêA¼™Â ¯1>¸ìFâˆTWlüÕAœv÷ª ¹FEÆ"€HRD'º†˜ˆ¬¢#,‘#,“˜C¼"XSò#5â`yÓ`ì~ø#…¾Þ¨$ ¼Bﺌí§Pðþ>ödu½ê`B#’4”„§è¶¿nU°››¢ ’‚'ÐoÔ‡®Bx|úŸ¨WÓ—Jö•À."Š5'á±½}å™ÍP9JH”(˜ oÓì#MøÍõ-›¨6œh–Ã%wúÌ°:wýf79 ÕÓ¤’•*ø˜“c¥L°º†Ä@ûÐg¡Ð¢‡\ææiÆ`Ïz\·^è!ö!£[$f”§4XBKš LÈ­*­`&Y4n"Z}_$?/‚x*»ý»Û–&ào÷#/¼h‡¼Hba !ðd;¬_/Q­}h7Êúæ "/:ÜÏxð±Ö/Ë×ÆmàÛ™UT`ûäsž“»¼Ñ6]Y3PµŸÍ{4ÂÖšüÍ—èª;VÊBÝE‹–e0à:ûv„r¨Ã`Ð4#/'8eF©j¬qÛE¤¦‹„b±"À,q­Á#/#+Lé m-0f“Q2ÃìgrI §!Žú²Ù.¼æL;ëúµ HùƒNU”kbf CÕǯFsSÖçØ·÷R'¶ Kâv+Š`Ç”7±={9 lßGf-2>ú#¾Ýº‹xãˆZÞÂœ¡¨x‘ª†¯n¼ÇŸ‘ÞS¿eµI™Îé•|>Ÿõª·ò:lÊP#5Á.ƒÛ^)¥àIò z nÙp£¦ÓLMñéfÿÍß fæ‡ôl‚¥Þ5©^‡.ØÝJud„&ó#5!„3@8‡ )ùÔPhȘz#/QO@'»1ÔÃk:#/Âs>ø;ÁóÊõYZ”*€ðo†vfƒa‘UAÉðìêêÝž@JŸÏ8EuBåœs¦cÈÅš.oŽA°Mı Ô@i©Øp› n"õ¥R¡Û¯†VàeA‰Ð`T#š…pÿîöÔÀ¹@±~“K?¹’|v‘=•ýÞÐ0 Õ iL$DXªÝ–Y„´Œ` Ðò(ôêó®4 m¸¬žÝÍ#5hñ(>ú©¿Ñ1ðm§Ž#/?­üì9óœMI#5BHj¿ŸæÖÃ}_¹5}J#/~‡Ê­ÈÑ­¼šÒnD„ÄF‘ï’FrÙš»“…@ä7®ÇÍ<Ãó‡*„óÙµÉVÓee¿vÂvøxw$NIYúðñð›|h“"Øê½'¯dÐ<õCrÆXµÁ !߈h!2ocnÛìüÞZqpÂD¡ñ·=ØØ–ad1äm”" ¢#,™O2åkp´Î`ì ÒS¾ctà|]ËLõ¦ýW“„ 9Ñ1☖òFqexèô¤@îŽ?fëUÐÒáa¬';ôß¼tN*©&d8œ³ÇFÞ#/­bá=‚u³ž»YfŽ–¡˜ö:Ux1°ì¨HI$«6]ÇÖÂ0á|XBm™a¬Œ3¥|HM®JQ…8åÔæ,ãW7æï÷l—ÆŸÒÐ È9þ¹10H¤%¤"±Dô©ü‰¥a|> _éUƒw¸ˆŠ’H0ˆ²»KUÕ#/ŠŸ+›ägØ~Z}/¥0#/´Mê:·²1ƒÈ4=çÙ‡ä=éÙ.¢ý<ÍÌ4-à˜›Pr<ÎœD1Ûômz»¼Ì-¼¿jö¹ùäqò â admæC\ÕjÌ0¶ØÕ¬Õ­-K‡T\c#ç ŠÁ^%Š¤â#5šI#5–jwáx<ÖCí3ôƒhÇÕlº‰µ&W±Í-þž˜Å7AãÚo@Œ4œPCr‘†A)FP%DE!] þO¯*܆áĬé¼~žøÞÒ¿«·×½m™ Où¡TŠ´ÛÀ¤ê@>Í]`É÷*çÀt[6¸œpbZõõò`¡RÚ¡oB7‹#/]}Ùœf‰ <ŽF[CؘÀ€UUFëa…ß`}¦ì¥‘÷œ(–Æ®-Š ,HÀZÚÈ}x& ¢B·º²#/"PÔ³ÒäÃîË£©t3ìµ¢‘H";r÷ý{à~SH«ë¸î­ËmÜýû­RQ¬c[eRšVjlX–­*@B,êݲÀnxR…÷!ÄÄ ;òøô#5ŸKD‚R‘H(EÝ»ðå4Ó·ùo<ÀdRlÌÈËI&Â#/4”$¦Ä¡´ÊÃ%A²ÊšKHÓ"BÊ”©d)k÷s`Z#,Ç14t„ƒ¬GJf:Óc¡Îž©ËQ¦éá‡uáuž9Î.*v3#/&È„m1¨Œá˜A®¯ ´Ái¯%Q÷:¬Ë+Wwiå#Z¼tÃ+*qÝðif¤ž¸gè,LkzHÅâ ŠËÄ8öŽ \@ !ÞõóŸ)ãI³Ùœ¢»Bº@صYt+t'a¦˜¶@qÇ(£#”T‰¹ù&@b8˜ŽCq£â\Z.=ÛÏxÎ:oS,¢j¶†­õ¢²ö ߎ ÁÒägb5¥œÌ< 1wqáÇ&”¢òDd$‡(íõc_“#ã1ïQkR3„†ð×4V5ý ãÏóOíY;Ô1ZäI ¤þ4DF@ÂÕm¨¬‰–ÁºÆÄ#/24A#I`‚mŠ¶ CbH†Rg~¶®©\º«–›®Õ&·g%Í%æÊJ6Ć˜‰Å²´1¬™p.¶c6ÑŒ‹V#5ÀZ€;nR¡.Ñr!E’ŽË%#,æ8²¢ÚÔf?Ê#,*Â@c 3W¹“n].jw[¥¶Ûu{õ#/'·„ØÌÓšQŒAÌ<ë#,B™‘„#5ÅÓ#,{¨ãZm§ìU+qؼñA¬ ËÉXc)ÿ¼0Çðø›ÀÂB?'Yã ]5Ý]Ñ£È<ØüâWð/#5ŽÑ@Wjš2¥aeŽ(h¤b‚lt¬‡âÚlš(± ³\8l¨´›M ¢¼m¯smžæ-Ë·q‘Jr‰HÄÁ¸¢U =›y#iGM(ÚE¥ “š„qd ¾Dƒ,DCtF“X8¢‰Ë#QI_S³=Ok­{ïÃÂ%{Ž¸M- 6:7&Œ¡+…U§Kd2³ämbB¸ˆX°N5R+%"{2€±d+ 31ÆÒÆ6C ë ˜`ÃRtn(”¥#…IB=$yÔ*`ÝɳcšÖo(žjïzÝŠf;P˜›dÛ.ñæijæfyPŽ"eMž¡²X”™um[¸£ ‘Ƭ•¼#5Õds"X,#ËŒ£2†5€õˆß`ښÊÉïëñk†èh1ÐGC7DAŒj3l3 ™YÚ¨8‡¨Ñ#/j,Œ•Å‘ƒŒoÎàÃR féŒlñ­Y‚n(ë9·4TÖ€5#57× d.vt<Ô`¤yªŽŠ± á´¬f#/ôœ²j4œjŒ#/ ‚b¢Ý#5f“E³(È’Šɦ“bóLÛãÆMœcHB^»>hƒÛqËÙØÚ0‹£X>¥i °Nm(ÐvÖ­$äE‰l2ê’[BÜÁšf‰”,˜D„i4ÀND™…”’$119#,ƒ(`Pè…¤Œä¡¬GäV:Xi°Ç“Fµ}#,Œéáˆcm˜â¢6„˜&0‰ ‚hT‚"m#/,)^ª§FJ&ô{Xg&ÃAÏk´cG6»L~´c´¢¼A*u6(Ì&BÖ-#/4©ªcl[ÈËn“±1›g­M#m>Jash(Ë°Öšû¡ìbÂ…täDT×çѤpìEÐÄUHOID6<¥´ yÃpß4t=(·YeºU$â9¶H|“m'#,÷:hÜF [s(€Ùؘ;0fȈ„i-Æø*@Á’ä4!B†ÐQ bJŠ£"¤Á€4l`Ñö’È^)"¢à4fŸj´ÉÌéÜ‘iì%0±ý­*’ñ…*åM±“w½-åÝ›¤öñºë•ê¼^Mß]öWà´bƒkFª Qd`‘‹!GQ#5Õ?÷w#,YCüBd¼1#,.&ˆOϺýP6” $-Ù#,.vâ¢ê~Oæ2Æ÷¹E@_3#5#/(žª(ÔúˆBŠ2 ¨nÊH B"ˆÈ¢DŒ‹Fhƒ¸Š,™—±î B'¸¢´A9^çHä;æy{ìmò¡# BäR”Ÿ–Ÿ“Å!KFúÃyhÁ…ˆ7wRƒNçÖ‡uדù«xõÅœëcn®®š—¤ *©’Ásj‹G½%Ú¹™‚⋱‚†ótRSRHCö)gœ€víRK†æ¦ì·È˜Ê‰#/0ã§-™÷2cºþo£PDS{n)¥®åÙÞZƸK‘Þ¸k©ô¸–—à!ôÒ`6ùáw/hæÌŒGê]!¯Ú瘙Ií.À±œöÆ6AÈ¿x_Né‚!›Þq; þ°þH®­HD™¹§F*·;2“è×À “¿òyg©‰±!ê"^¸«gŸUݾÌõt48Y©/#/Ðý‡´HÆ"“L(òpDèE‘‚2%tù§`˜†Y‡¼ß{OGºÔwËRÃ*ãmTXÏêúçÖët©²å\T*#,›˜;Š5ÚkíÈ7–9”O.¢|ÂÀø`J¡Ù•[Y Ã¬Ã"ÜÎóh˜…²FbÁ"©TûY‚@ÀhZ¨ÑžæƒSé~'éãÅc«5nZUI'(i¶(°¦0%$Ù«âoƒ}Ì6À—r¾âçöåQB TÜ@´C!Uþ5A”ª¦t ÊKQ¶˜—VÅ×[ ÖOW4mðæ·_n›kžWbW¯®[kÇ5sh£xÜÖï;ZÅɵ!Ín•k`[%²BØ  KVØ#/ép¦Ýýæ·^ud®îå5\¯WÂ’,b#Hƒ¼aN@ð{4TÂØ8¦"|@º\GØ™ûƒÐb·²4c@IŠ¢å#,GÄŠÚ Ò#,z@÷?Ë€âEK´±ƒ»»omWÇ$ñ4§ƒ¾P¯Î!ÌSÎ)JÐ#—å?q @>úà…%Xù)Ô‰‚n"ÈUElïµ”×%­Ù¥®ãm×w#5ì¶tXîï.áB¶—T€§‚%€ÄÑ„pZÅj-¶´–¶íj&Úº„Y$#5j¤K6V#5˜vÉÄÂØ‘DNDQƒ$VHATˆ} #,Í#,t”¯ý¥Põ*†¿š£¥'U÷ÕOF¾áãA°GÞB&Çq–º¾ —ˆ#5©˜½¸³Àô¨!ÜzM‰X=ˆ`¿YÌÅéô”H'J^‡·`dÅï‚„:>B¹bEc„dR@²l¥14Øщ¡³-3DÊJI‰±´2¶ÑV¶Å¶ÅV›J¦U*Å©­cXÚf¢Í^hû‡Ÿik’2µ™¶@ Ð91‚•È‘>ü)pM#/1¨<¡–‘²1HEéd%T°5˜«ÊAh GGŒXÝ"˜W#5)`#/ƒeldE‘¡È1’T:„¨UFÁ‚44D"22*T ­Œ#,„•æfi–L"Ä'Ïõåkª&ô%¡ŠY¥¥Ý;7 ëO®׽^ùPD AF• B c#5FÖ‡h.*W N0é°^ËÅ6¦´“ÝshhyöKkÎ#/«EU)¥^ }#,1 ’´6ÃÃÛ±”!77´qÊà)…2u—ðm:;9øtM­`,Å#5ÎY!‹VF@A1ÄÞ©µ-Ö$<8k”bHµ›†µ’Âe.#,óm“Æááçç$¿Fb‰{¤£Žõç—]5ÕæÒåLÌßrý•ßÛ•F­¨ÛU\Õ\Ö»½¦©+ãkÝìÕÕààØç÷AÊ.qþY ”D³Úû°¹bVUÒã6±dš¤X|?f¸èmŽ8ÖAŒâ凔´}cï€r×BüÎÜâ'óÄË͸=÷PnÝO12R_áë'¸¯òvÛ¸‘´ÖâËϯ¿¶o.‘”‘ ï×eu¨={¬çpïÍl’×iõÜ“ÅÆ;ç:Ý7OKt Œk/ÑÂ)áÎ…-™Š—ÛÉ[ž/}‘äEð„/,L'ü©r‡B¤òŒ‹ôèþ©ºó’9·å]¸tMÐߊkåGW¨tYAÑ3Ï[”5ÑlJèÚ‡ÜEúy»F]Î×!Ý»®éŸÂ%#,âÅÃWN-¿b2 ÖtóßtU°uĶCŒ¯LÕK7ZXn®?“êv¹#,:°éÙN-Q“6ç¶<”h•Ò䮚ž¥°Ïå0¼‡99{ÃV48ŽŽÙ=4å²γÑ|=ÍÍvLç”ù·:8D§Èãwwj%™ ]N•æøkµŒa‚Ñnt{òƒu^9{’×F娄ǟ¥IÔ?9 ~\³½¶Í•Dã숭lÃ>7éŽÌʲéßá*ÔpDÝ5¿]NuD¤¨€ßTSLœEHˆE’æêßmyžú,[¯·ýxvvb–)ªÞWƒÕÛbOãdéb€ºL(«D”Ž—2ùÿS°wÈ´;¿®K×Oy7ËcÒ›c¢P4áÑ*“m…™¨W•Ï’’”ÇÊq[Û¾kÚwy@ûcoÍÑñð{ÃTã¢Ó<#1܇Ä÷Q'wbâü@ë¾½ìâ±ÊŽ¦u~HŠŠÉR×Þù*W˜çO•vé5Ó>ü¤#”F#5wÁTÀá öª'¤ÇRNÐú³†ºÐìÌ rldã5·îù<…ŽeÍëS’]žú=ÃñôÂ3«¦gÂH:&f#|8ßJÙjZœÊJÉÏËÇv0„! ³uŽ‹Šxéǘ!ÝÑÌ®ZœÕQ…sãšQ!Ô8s’„;È+Äu5LÆldR-ߧXRpËf‘(%¸t&!Hìj@"¢ˆÌkè/Nâ~’Ó#núž‰±gëFpðægž&˜Ý»áAÄÈéÐrúçü¾Õ´Ïq©6ºð?qä—™%bLn8ƒY|)®Ø¨ñ¬D¡ÙºøvKxdÍB—3¦zÛàMæ,4C^æ£ÜR£oä~‘¬—2_&O”O¼û˜¬àsÎÁÐç©7ï}ðkÄcŠvòÓ—#³ùônš8ü­øщH…Ë»<|:Ѫí`ƒ¬ºê‡ïD[¿e1›Ú\š»÷Æʤӱﳷ Üì.u«#ÑŸ^$àU†|£3ŸH%LôG›È´­$‰PúžÔªï¢sÇ,¤Ñlu;tm_8Ûð'äésâ]«1Çú`Ü©G„Aï‡#5ë?­å#­ðv(+t>Tú=õ®¾½<ö Aïäx @€2#5Õ‡¦æ¦&Gcª'!c–#/·Xäe“j•¦#/»•*Ô•©ò<óXœªG­_qû”4b8ì;z‹=AÀ~xHôj „qDÃ1#/*Î’v6˜±)‘){¬o¡xÑÇlè4gwò `¨äsÑ—ÅÏ•8Õ…•LbYˆØ-Á\/ILIUãœ)–Íd›mÀ9ÃmRº½Ã”(•‚YãJ^X*'¯$ÂõtÖþx“%S4!2Bð2Їs½le!ÒŠš #+‡—`“3‰—…ÚÊÂ\ºê!l2  ñ9’F£w»PW ¨ÞdÐÏa!HØ6Žã}i*ÔìÍ®“,Ìj]Š¹vmH+‘´¨óËnûd¥lrË-–¼œEŠ¡¹g2PÅj] Aò™–t#, )zè)É(— #5ˆF#,B(D[ðÄÑdÛ«…vmìdz²ÓÄ€îÐèRÏF‘,¨NHéÄÃ-òIÓ ®·@#/Ð3@Ë(ÈOœÔuç öÐÎ>± 9A%A‡š\=ZïëÅ?š•|4G°ª(="…LˆŽÈ»CÏ=Gš/¿ôK¾Ãßž<‡>7p%RÞh¥CÙL²s;Iî‡û‡H)Y.$gá„FÛ\ám°ØÌ>òùÓœ>O룦z“Ò»¢ãÕP{ƒ÷ó´‡M9ëµÉjj?Þ/£#/Û¿·k­¬„7U¨òƒ¹òwF‘®û³e1¶ˆÃw¿1¥6 X'#,Ä öJÇÄ·–Ûu¥¤kL9w*ûGnô |Pz iló0;®8~k¸óé¿F‹„ds$.j¦¸–S½£$2*!‘„’×S’Ú–3o`b‰#4@öæR÷àƒ ý8Dæ‚šyvvã˜b;8=qÀIzÓ¾.TéhünøÉÖáÆA¨Ò¦¼µØÖØq<3Gá¥:¸†ÀùŒ‘éÓM^áO•õÙK»p| 9#/š5ÞUš˜¡ª æË#5ïh*ÆN5²Qu}X5EG’ma¼°áÂÙeœ"5#/ƒ‹â¾—PAÍþüÆ8ýNœµ)é FT³†o—AÓ§\pµ Sh%¨ÔVÕ*ÉRXs›)ºÖfÌVjró¼ÊŒÌ•ÙË|¼ðL’vïlÇÉÀ´*C‚üô_ÊÇm PýX ¨ñÈ=À;ֈ缹e!M,à-²7‡R3±Áíu²œó3Îe²¸‡žy@ó((̈Æg„Py {»–ʤj®¡PÐׂ%öà˜Ì:f,øÒ­&CcÑ®d¥”Ò†#/¶…&„BÂ\ØH©½Ö–²›N,a$ß¾Mnô!Ìà:§ ØŒ ;$7„Ãj¬‘0çËì~€è®ÚòÔjxïédj†l#/~¿¯T~?"úµ¬%š—ò>œä=ÆòLo2±5!£À*€”‚}î·‰“¥D*Òs¬ðf…Ò³½1±fs“W‡D<=Áî^ÒØÈ÷¥£HQU:@ÐZX°æCV‹FѱD»¬ëw*I0 65'mû_±okV-ç–ºÕC0x5EÐØÑ¡Æ”£tZJ²F08ä àD¦@«fÞ­QA¬kšâsmͨõvíœiêGy£YUSq"T'†+·AêB¸`daL‹šbBÌQVd²ÕŒ{†±&0dUC¥›ÌwÓ6Î=>rFža†ßFv¶´O9×"}ª(ÙZ]›`Ú@ÚUÆ#¡DÐj¥†#2Yj2ZÝL3^‡võEÞ““')Œc !b3ä+•„nãËÃxºÍKÌÊ#c7ƒ´lÜA£A¶lȱÖ6¹¬5©Ñ™¼I¹s{)FÛmbm¥jZ#/µH›j¼0‹$ÍË_¦÷u®Œ½ÉÄ*qÔŠwœ#5Fu(3»ãƈŒ)a)ÓpM,(PÊ ©ÓcåƒfHÃSKÅ2¤Ô1wÌ¢ˆxpk3Žâ †iYŽ.Ílo! —R¤Æ±¶–ˆ@Óê+\ФIÛR¶Â7vÕÛmá¦oĨ#/)Âl¤‡æÂ41‰ïlñBMÐÑ¡ƒ[:JÓ6Ôj©je*Š¢…Xa†ñ“LV1·š‹.„ËÛ—KG]ÈŒ3…Ek©Š´š˜:¶†›¤†@aú°wmݳ hq²iƒ2òÈ ¶ûiæqõ<âñ˵aQÓèÃÙ”~n¡£UJ5™b´à£„Bc9GpáF2›¦ Q½åƒUƒ#cDÇF2#/BØR…hl;™1F%Ž´c4-]Fi¶pÂyë+`æ­z¥W¦dpìT¤ŠçaÌá“#jP˲ÆÔ£„rªÛ°ê ƒÐÖ?„… ­GÒ¦fn*£âjˆ‘ˆR-yZ«Œzp§m¥W—”\8@s¹eÇ-:1ês[u¡ñ­½,-™J`qšu6¾i¶Œ.òaZ³ JF™áÜ$go$®Öi‘Ôàè-2“FHÄFK3º*ÁÁ…ÓŒ»!^ž5¤E¤ŸIPÁQ®úµo´#/:Žp0ãG 0%2ÈÛ¾ÂlDqJs;¤*õÇŽ§åó„}+?_èX~×;ˆÒh©4n>õæóξw·¶zê_Ð×ÒŒ3+Ѧ#,B6i±J>°X"B“´*Q)#5UHkø¥2Iâû=µ(Òe!ߧeS¾¬gy­[€i T¦2Û³÷œŠ $UUFJ2ßê*{ÑŸñ/PèEÏó+ÚIŸCªšc‰jó=¾¸CÉûÀþ^°æ‹ëA"qm!–·JÍÈÍPƒ€ñÂ@A²ûµï¿JÙ&a28÷bÍ„Ú[Ýøš§Õ„zÞlº… uq–ÐúðöîF›ºNîäÈ!ݽx÷õ5¼i]tjaQp%-T¨Á³È3=‹g›ÝÆuë2‡^Ð÷¢? ;Q<ÍùT¡“ŒHQˆ á6o-ÕA#ôÏË9ž½Â(Vk{–±´à‘À]‰LÎÈ€ôRƒQ‘a#,X°Aˆ¯)¶¹µ«¦ñ­kË«¶¹¥R«ÍpÝüSòEæE?Aß×ß(Ò}ü$$ŒcPÙQ²’¶Ñ­(ÔF$ØQRRa¶¦VË2j’Ù¦ÅZÆÍ)*‰-&6fdÉ¥–Å)HÊZiR”fJˆ¡Šm¢l”li²Rš,Ô©¥h5"É› 0Œš2[V1­­üëßÒ¿%Þ‰‚ ñÀö¼«hâ/¶%¸PyòŒå¸ûæåteÌÄóÜýOÐ×ó°›ü\÷Õêî¶Ï\ÚD‡ÆsVÑ|’aAdƒpp½ïj–«U¬ZÊ#/5ÂþGŸ§Ç4AóÙÔo³Dó.F#5ä´v‚~Y»zOg†ƒƒM#55n’öÄ 5/öî„ð )"‚‹¬kI­}æÕ®[1¬)4H)-A›_r]¡j•BÅ#5PÅFR>´²eÏ€`'qxå!BŒ*O·Û˜\3W@Ëd}ö^¿°¸j@j" þ˜QjxoCŸŽ]+L"k¦VºŠŒ èËRûŽQÌE4\#/4‹¡w›¢eÙ“$ÂXÃ#,4Ž±w$Âl&‡…1H ªÏmM–ê”$ÅP* ÖXj%í%†¥ñÝ›&õÙcßÍÕõÍz“zÑmF:š¢¬´ò½¥*KHÆ‘#55Q’¥Ñ#5E#,ï8ã'áí5§æá ÙòÅ6FK^΃ҺâP{7¿g_©y»Þ-FÞ­»"’bTi²ƒYDqbÊÿÙÒÈlÐ.g›.j˜R´4•/ ¦d£$1A€`½Qˆ<,1‚:5$m|Ú¬ 8tˆDn`*LCq-ä "I$‘ÁPÙ·‡dœÐʨg˜b¥(¡˜HѨ€7$Ç¡æi;¼ÄMó­#/é\W‡_78ÏÚ•×(,ú/dî"B_òá6ø0 hú½*s¬añ²‰ª£-n]MµA}êÂRЗ0 úT%Ý|È#,ñ‚¿ ¡p˜{ ÄW(4ôçèþ·Œªôn%Ô¢•[«xc%Ö~~>O–ºèjIÛ:ãØ?‘ëSQž‹ñ*ûó)¤ÒÂ:#Êse·ö˜#Ø8…ïúèbáöôaç¦~ÉäX2ŸaÌÈWJñÆÓ­Œz™TZ™ÎÚäÉ64.Œ#51B}©%÷s]kÉ^vœƒ-¾ßaî°i«Ð=v²¾´äœ­r4ié>4"’§< f׸‘©"ø5,:ã»;í˶LÏgÕ&åØ›>f;}J`8§²$DW‘ë5êOñšØ§¦#/‡÷œËEŽç`VŽ@)2g³š Ú611ÿ}XwÄh7!€ì#QýÿTÄ7vuI¨™3>Þ_b7Olbwr>^þ‘BIDI(€Š%çìBöÕ(´jtû´íƒ }'‘n,,)Ÿ¿.¾¯ÏD~ìèGëì~Ç­n~MLáØÎôFB«¦‹ PÆ,+rc¹`Ã6'^ž]hlÅ0ÔU÷¡ƒÑËqQ$îö¡š©*}_m[îÃx`¾fo\e#/1IqˆoÁÚkö‰¼¤þB%„Ž¹°ÙW*Y5ÔX6Gîg|¢ƒ]82¿’Ü1´„–‘™Ÿèw»Þ:*DôyG7p‘l¹ 9R%T:­+ŠŽ\~q5Œæg”à§FÔ²4Ã0ÖÚbj„‚"Bl3Æ 2&#,¤LífÚŸÔZV’ÐÈúˆ¨ª) Ìú—l!Ã4ÈvWº«²™º"¨ih±bE `BFÈ„TIx6;8ØÓâ„Gx£½¡Èk™¡¤’9É¢K7PeÌÓ=™Ø#,˳RƘÈ­h¦RĹ”6ºsÐÙLv‘ƒª³”¬A‡8¦Më¥×'“&èy¶ ÃD…ˆ³Z(`€nQ©ê?i˜` `‚PÈÄ̃Þ"¸7§VŽ¨hͤ•B[ÊBÒ£SÈ4,U±M‚FÌÝîãø¥‘Y-…mÃs=rkš†™Ü±Qš ²dãg[YšÔE`؈‚Ù™ƒNcQ¨œWõúù¾¹Þ ûëgC‹èý #àSAcÕ›f&3ÖF|N.š°cðœ(F®u0ù„õ\ô€Ç;9ç5`Ž¯…í.†êiа;eÛCÀûï&:V3+»ä:ô)˜–t[½C‚;Î’Š[„.êö†5¦9Î'½‡<³‚XÐŽ8-TÑGˆ’Iº›AÊ… °4IAŠ’³#5Ð(„4Ãà˜o³Â^+Þž£ÈFÝøf´kq’Ç—á“SîÃJj—9½Ú›Ê㶠cïLé”hG“×2©á¤AkHÌŽqlcŒ°—Ó`CF”„8íîŠã ÎöêØDI"ÒÆL¨¬2‹™C4 xv´ÚMBÔrç4è…"•j‰D°Î²Òb|ErEbÝc,n#/3AÃkPÁ- A èw ƒ¦¶FH¨åJKy|2”˜LÕÙSÙÚâs\Iu`B2 ëÆÛ#/H³%@òÚ™Þju ©æ>Ír+R–fCÂÐe¶2g=×Ü×mtyBçC‘±Öi ¡f°E2Ç#,Ò7 ƒ@毧̇jXH8ºÎ.Q0tWF;bÑtç±Ócir8ŽMÒ(e#?ê‡h0._Òƒ Ì–‰Ó57“HaÊ< $t3 Sl†tÓi#,s´“Uˆ²P¢& mð±N5:þ[VÆ-ÎPd+‚¶’к0psW)„‡.˜(êã–Kiä¶ 5˜šf…PŒ`dYˆc0’“™Øïú×;ËÓð1 ¸ë\‡Zg;‰Ø0SC#,šÊ©&;XÒ){(zžpÛhK“bK¶èä&º†2Žƒö_ø6˜¶ÎS9’Ô`ôÊŒ¯ƒòö“wLôöx€51X0“Í“¹š£~G36‹ xÑ4õë~F´(ã›ky%\»}ˆGGѼ³Ñ_ k§Žp9kI©X«Ob\8W˜¬L°ˆ3‡f²á G”› ¥£íéxıu»Ú“¶¸ò• #5ÒtÚš–b¿o[£¦ À"l]D¥!Á˜¡*£ó~í¥¥÷ ƹȴš·¿¼7½NP¡Ù¨‚Ê]<ä¹nî7ƒ»åZ íû‚ï¨ò žzbŠd׎(ÍÙ1Ä0ã2ölUñ7’¼–¹¤å£^·*éÁX)ðžäŽtÂfªH›¦ -¬¸1laù¦‡@Íå1¯GYÛv"öÉ,˜;ç„ÎCÉœÉÕZÒ¾Rê41ë~¦XŸŸ•ôÎ0ÑÈ*ÐÆ»ùœ‚#FÎf;&Úlðæd#/ø´3J±v2›§œ¶/5Ê·æF*VøDtCH>4š[ï ’u,w1Œ`¢ÑÌËá¥GBmðX¿cõy­ÓŒÞ0fßE4Q«HˆPÈz!‹ªhEçAFH"¸ªPÝÖMO6÷ÜÉÂÄ;½S¤]Áõë- 2m)\g†`uns…˜®EÌv#DÌ" 3µœúQ4ºÙ"6#/KÀ2ÁÐÃDb¬HªŒbj0¦Iz©#/ÎUñO/wÉHRöYu,««DëJb(‘ÙÅ®ÿ#,Ì1aª"/eHÚ‚žhïCÀø3bi˜RœÊ»ƒÀ CiÁ¨Q Á’pìŒÆá Äaƒ¨bb_BÖŠ*EsI`dl!‚LZÐ6؈‰ ìªXò¨¦&Ý„—²z½}'Ñu”¹F TTEA³GnP]f^®¹=£`Ë*„;E„HH)¨ 5#,æE~íÿÜ[ײöUAÖs—¯}Ø* &ɸ‰U$_°. Äh”"%Q Èvøž@PÈO.Mæ31<Â+"Æ’©bP2Á8âd‚TLc`Ç4kÄÕçxKÍÝbT®[ÞëA±ä! d… È𢢌A¨5%TABJ‹J :éˆã#, >l|si(A¤:ënKßwL¹C®’dˆdÐØ&`¬R, „Nˆ{úÓ³´|û¼B|&>~šíFù ½pà‡ˆ)òáõ´Æ~嚈•Î†Ÿ×3¹FŒPp ‰R‘Ks1ŒµVDD Ð9†Y~И]ÄcaS&¾¨™Jëä%„õuØ'CŸAMìM€ð iÉîŽã¡L’xØÃ)âA!ÜH‹Žû"ÌCÉ©ä±Í#,…0¿‡B°ˆX¥ àïÙϲ؂l‚H„€†a>’6LNpNþ=AÓU7ö#5‡h‚˜|>#, t"qvõl"HÐjá†Tvè®#5dÜ:cD“A‘„\r,É#/ör}°áM‹BÏÌ~eŠ0„a#¥¹#ÏK5 Nè"‚i¢1XY«:ÔEŠñd<¹饤CM"ò£¿!Ý,FÙ‡†a­4¦…ªÂšØ}C¹Ï;PÚC-¶`¯³k9NPïÃ+Zë-sŸ‘‘ƒNÉ ; Ô÷gÛl¨í­õÛ”I°6“jÀ*á,YpèhYhý[¾¸©¼ïðQãU#,E€§¹% 6Ø¢j2‹•1pA-šý–a]Z³š‹06ˆpM Nÿ¬NJJ†RS,Ûs#,Þ&àŠN|P¤¡#,ë:Ûv¬®¾`R)eZ·Ò —Aý‚«! Ó.¾™Âþd|yõl C7Y0Ó®e‰ÖpLCÍ8äP$ E`AAÀU€®ç²=|°Mß#ÆƉòõª×aÈáÐ-@ª!RÈ.B¨6#,R¼„j#5~'»èý½ø$Àce„Yˆž>ߣáQ¼æÅœ+4¢SøÑÈtx×_¢ŠRÉk ‚ß…Ãð?ɨ|>>ïo*ÌŒ>k,"˜ö{M þ3Ah„'ÿÕ·Ä–ŽoN憨m·4kÊ«@(í#,¥$HßÝE‡*oßû©hÚä¾’¿ª ÝZDúbl *|ûÇd,)À_ï€vX.Øbvòر-¸$HÈLÈÅç\¬VaI)"îåŠûžtÞh5xñ^5û’çž^o+Ï|ñM¦«´E°ÙT"6¯uÛ¨à &³KQD™ Q底6Ó6†˜@J” *pþ$Šl¢›OùÊ_w›¼½y$†@!» ¼9›Æ@eÖD«M"¦!ë5ùßHö#,õö‡ok"È,€ÁH1FItIÜ‚Œ‚HKJ“$–*eh²YfKf’m_õãc}ÍWòõô)TC™Qª4še,Òîü°IüOÈEP¨‰Ÿ²–»|Æf7Ò@,)ºî¦I#,àOØc_T½´Ý×6bldÔM¬ÚŠ*Åe¦FÒ{çžjˆ@B {(#,´D"ïŸóD-ÍA5ÿ‡‰˜uw“âú¾¸Á×Iâ¯A5ÕÁ¾Cxtœþ{ŠÊÄ "ñ½WDLp1 ÷¢ž$‹Á¥ÇŠ3˜)–S T‘²Â½´`ÏžfÆð)B°ÆÄ%—óéA¸{ù›iq¢à2 Fû˜ã†1Øž¥MÂÀËCÚXS¢yL@A|Á€A¤Ím6´”„$µÍÉ­R­)6¦Útï–¦‚ Š)sVÛ7“Tì"®J€Ø=Z”`J¦H(HöÚÃe·XOn’ãK¸Ý¨ÕZ¦µÂ} @xÉàRŽ˜ô<ýT-ÙÉiHØœý4#âì:ÆØ£"H›hx’öBVÜÛl Lµ‰Ž„À?,·ïgÍóºÒå†.[6oYhD x˜`næçü¥¿©¶ÕÕúº¾¹}¾:(52&‰RE‘¬SEŠ)(*"Ú2UB•È­úm¯5#5- ÚJ€¦§á•³ñQ –|dK,'Ü2n„ŒD*–QE1cG¢Šh™ññ5± *…¡·`'¥ïŸ\p]»% n»š ´È‚…dCDZ‚´¡¬P›i²ƒ!ƒ$`'‰µòíÌÛæÎíí¥VXjc·Õ¾>øÁW6¾¿9Ž>¢ZØ–0l³(CÝÚmwû š_©ý~C´+CaXe²œÚã-‚#"T²44x d`;ý´:`&ÍlkrÜ’•}}«•¼»¨’Ú*+|®ëÎ˱\ÚZõ©ç[[Æ£E¥™ªÏrGë6³#¸Qý¥d8$-#,Ì,&íOQÏ¢I¨u#œˆr"ĺ3Çü3AZM±¦¬M ( pÈõhX}tfò]JCñ`aÀP®%Li¾pCq5‚u‚]¶ÅaÕ%A‘B0Xs¢k”´nåÕã^o*ëIbÝš™™UÜí´Ò¦Ô¡¯{µÎV+*TÔQ±­çvךû+½¡A#,¦Ac)H&5„h`ÆÈÚ[R•¥4ËfZé·nè”Ò ‚ˆNE¡RDBNεm!‰°éžXK„=¢ºÿÛ—òà«‚Yƒg±¯¤Uòf┘4Ñ8/Ž1†aU3ç qyjI²ë²©Ùíîù"Ö/PXL*&†©J8»÷zÞìñ0lèÑcMû=#/fü…º³ìÛÕB(£Š‡"­yšëÚ%ôÉ!ô^ˆKž‰ BA¢"˜5‰#/ðè:8$ÉQ;’ý 6’_éc MæÿÀZ׎§_¬•¥Çk“Û|å†ýi‹in‘Û¦Jµ ª-ä~?Prg´š¼<ûh_cBQ‘ƒQºô0m­Têð#/(PD>›r8”š_™­ê`×L‹ãõ9ô`¢ÀŸ~úÙ¤q<–ó€’Ešôbä¡HXÜáÛ(Mˉ‚„KÆV#5vÂ9¡4k%Pm¬ýLzŒlŒ¶Œ"À×F\¢é¿HbqK÷M|§hͤ†ÉpdLT“‘=Ic0äd¸(ŒR„¥ €CJâ'#Ãg¥1üÙå—÷#ö^3À!Ç<ª„¤2îz?2P?ø>³Ê¿DÉB6 ʇr³¯y±cÞÀÉï;ݦ"ó¥jIb8h™#ߎ'\¥„Ç:-¥i#,¾e#CûaU°þ¦ŠùŠ¶Ý¿hzž­:µ9´ â(dÿj‡©†È˜2*&½5趙®õmÑ߶…ÆÆF Ú[âôv3óŒõÞäB4Db†'RÖèmI€*™‚ØB#˜BC¡â”_óÄÈé†`– ¯N—À±¤ˆçç"RÚº#,“m2hæaŒ‡/b"fg;Q‰¬ãÛ¬˜‚ö ¬;h-Oî5z¼ìw™hiìºâˆ¤ýØA´ ¨cñ¯Ž+qÎz)\ X¡7 uâÆtù–‚ åþ%)`aá<‘êz¢¾*~LÌÁù]ü7¼žÜ4Ò÷̺‹DSo·\-baúâ.èg_îþ_áò~øÿ»ýÿîÿ»þͶ¿þ^Ïû7¿ÿ‡þ¼?ãþ_÷}ÿþ¹~ÿü<¿ŸüÿúßÿWûçÿ<ßønëÿ—§ðéŸþ?ùYýÿ÷ÿûÿ‡§þ{>ð³þ_ñïÿ‡øËÿχåÍÿøÿËþîÿ¯Ü~O÷þÿ¿7ßùéñ87ÝõõvŸù]†‡ô‡õ«b"jy6Å5M…\?Ð9ßJ<˜«î°B U!œpEÝ!#ZûW‘nóøwïi|§ñyÎî™$Š¢1Œy„ô2IRC²Šl`†éÝG¹¯(Ay4Ú!®z©¨§#,˜6Ç3ø]þꥂƒÜ?îßžÔÓi˜\Ùp–êx†ëqFï„_÷TK´,ã5(„æ)A@µ|nÌ&8ãt§00ÀQa×úèS<šßSÌÿxÿ/ûÞÒÊ?÷yšz6¦ÌÖÐèQþmIŒ‰ôŠ‚Å ºI'ˆÈeŒÌ ¯I?ôÍ@œIÀÜq¿ ÿ•ieqÖ&!3"…2*×r­göòì {­0ªB Ü”Ï&QFišÈ4).¨±ƒ—Y/$³ýùã’ìç1UjUø¦‘2ðÍD)(»p®ýq¡X0š+šANL1#/(=í8C(hškT˜mѤÝEpq1›ˆŒZæá–°ÛÖÓF˜›H†CÄ#/ÿeÉV×#/(k†â¯ÙæIJƒˆ”iåÅÓ%KK¦#/¡²°(R°™ÍŽÆo®'?ì&#/ôçÌö~¨]1ì¾3.ÊbVæ.Èœ¼Óò™àƲÌÌ5¡‘Þø(ÛÚ¿¤—^Íár#%µíÒsVoîÀUÓØÃy…I9óovÿy–#Ûî h1‡¢ #eëÛ³¶5c+KMoÎÃX`­±Œ9¤ž$½CÛ#/V¡¶çB¡<)aó¯´×»á¸ F¼6 ».ˆ¥ÔÏ×·*•ØŘ/S8òÒ`y±3DEa éŠHÎûs#1ïÎËXÍ¡&Hc|·E!Š†Q‹{ňPÑ~––2© E$€¨šy‘¨§J'\3Z€#,À’1-î ü ‰bfi¾ØX(/Õa狸1ågi±ZÒ#‘»#Rý^¼<À¦S ‚ˆ‹ ËJ%B…ATZ²”ʶJÒkL”²C`ÆÊú]ªå#,2Ê€qS#,™?Þ@2ˆÈÁ?ß&<*›(«yÁ-‹'3Ù( %ÂT@¥b(yóúCèïGU¤?ê‘Œ‰ yNð`ò54±Í%2gúF„c!t§“ì#5„Âdx‡‰útttþó‰,¤TG3‡ êú¥#5%±œsøâÓoæ0Ï{BŸûdk»:uNô§VÇë*K~¯xÆ=%ȼ©¾=Í©ò°ööpcõ•]*Se`nL2\aÓs.® #^áÆÙ²Ñ>Ê,7Ÿt›Qyä>–*m4ØšÙîá=(Ýá{.eoÆD'4Š°‡TCVzI”D%%Ý€-W­nm¥•´¥ëk^·ÂÕ}Ëã­IQTZ“D³hŒÆ#/1(мf±Ó¬"5Ýa+O(~^“ÒõÃñ¢ K‡?ìÄø KÔiµ @r19Nac#56œìÁäK–*%*¸”øóèI}0í$&PšÕk##=”´î#5'¯òŸe»".hp ÒH²!!7’æE Ðö‡qFO$v£“íà'‡ŒÿØ ¸zäj*„bECkµÇf•„”ÕË›­«%jF¸jûr¼Ûo%Wؽh›53_•ZüÈ£h€#,ˆäw·Ïá™åóÿ×Ö‚w!=~¨©ãå(ø{f8ò0m¶ÖŸŒx;.‰x§ª#/gȤòû?ñÿ¡EB§ýZþvÌÌ#/l‚Å'ù< Ué6áæçûÔU'ý]¿Å¨£Sõ#/ J®ýá—Ò>ý{pæWi.ò#/¹ÿÜZXßæ§wú¿ì†¯SüþÓúùµµ™ù#¥l³·¢1¡¨zeë¢×Ç¥vñ‰’©œ~®yËAƒSù>¶ÉÓ¶ˆÄÆVJsøzK„pYkϼ#Dâ¢ZÍÆ! ^G¿§,ÀŠÃ$ Œ}ûYOÎÏužº6³8•È'ÇõçÙL*Ï«Ï£o3¸žÍ~ŸWüÕ‘àRsŒâ;Ó¹j¬b/È5Y_ç²V7Ä|¤É{~¯ÿþ.äŠp¡ Ú‹ê– -#<== -#-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIcBAABCgAGBQJWpU3oAAoJEGelZe39+Q5kv04P/iyvALGAg2Z8oICEDjFkEXWW\nh2CMGLItAhqb3xNeV8WUMMpY4MbRRpN6cU/SPmt+as4oVn2pozca93eWD7yOxukK\n10seOyLTBamS0Wf+BNr6jYXZRQ2N7inc2p6AD75pMOFSg2HeIeQJ0aUIAxNeeojZ\nmUiLYMdtcrF1Kh7KWZAkYSbIAEjJeobLqk2oY7UyqKcODc4RtZJV1InnO4DItEWD\nnd3F5kkVMw4pwYAXaikmCXYBKHXdF5w82KxqEjrAWSoULipX0BVCsSbQ2L0UOs5h\nKXUS4M7AaYKyCcO17E7CnVXaW+vOVyGEECxtSaExWgK5MvYHIGE1OFvb12PkUvUY\nc7CiBxk6X5eZkPyxgxDj20r8zNQVGZ8jDI8Wg08yTAl8+09qCtkE8gGMdNeHYwX8\n2xDH+A3+19022ZZdyO2t5+2AzU6Kkl1qTPKaXJWFRtr8ApD45Y4D3/GAsTNqdOMi\nWeh1XvqQdHjm9rEoJX8aBXShzCMCNhmZalbUhrdzQY6/hnl0PqnlPtyvtkjCvWoF\nXLF6q8YV/ZtqCc36vePZ6lpUQB6FG3g6fhMGraT2VOmT3TROcG17pqIz5y9+85xy\nVSaDc82uHlyzIsZ7vuhV6d9x4yXnFkjMAogCJv6mitFbQsd+LtXYkU+2Zq6wOoEp\ndLLfK0Km4Vs9FYAUbuUi\n=7D7V\n-----END PGP SIGNATURE-----\n diff --git a/gomspace/libcsp/wscript b/gomspace/libcsp/wscript deleted file mode 100644 index 7b9cbdba..00000000 --- a/gomspace/libcsp/wscript +++ /dev/null @@ -1,346 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os - -APPNAME = 'libcsp' -VERSION = '1.5' - -top = '.' -out = 'build' - -def options(ctx): - # Load GCC options - ctx.load('gcc') - - ctx.add_option('--toolchain', default=None, help='Set toolchain prefix') - - # Set libcsp options - gr = ctx.add_option_group('libcsp options') - gr.add_option('--includes', default='', help='Add additional include paths. Separate with comma') - gr.add_option('--install-csp', action='store_true', help='Installs CSP headers and lib') - - gr.add_option('--disable-output', action='store_true', help='Disable CSP output') - gr.add_option('--disable-stlib', action='store_true', help='Build objects only') - gr.add_option('--enable-rdp', action='store_true', help='Enable RDP support') - gr.add_option('--enable-qos', action='store_true', help='Enable Quality of Service support') - gr.add_option('--enable-promisc', action='store_true', help='Enable promiscuous mode support') - gr.add_option('--enable-crc32', action='store_true', help='Enable CRC32 support') - gr.add_option('--enable-hmac', action='store_true', help='Enable HMAC-SHA1 support') - gr.add_option('--enable-xtea', action='store_true', help='Enable XTEA support') - gr.add_option('--enable-bindings', action='store_true', help='Enable Python bindings') - gr.add_option('--enable-python3-bindings', action='store_true', help='Enable Python3 bindings') - gr.add_option('--enable-examples', action='store_true', help='Enable examples') - gr.add_option('--enable-dedup', action='store_true', help='Enable packet deduplicator') - - # Interfaces - gr.add_option('--enable-if-i2c', action='store_true', help='Enable I2C interface') - gr.add_option('--enable-if-kiss', action='store_true', help='Enable KISS/RS.232 interface') - gr.add_option('--enable-if-can', action='store_true', help='Enable CAN interface') - gr.add_option('--enable-if-zmqhub', action='store_true', help='Enable ZMQHUB interface') - - # Drivers - gr.add_option('--enable-can-socketcan', action='store_true', help='Enable Linux socketcan driver') - gr.add_option('--with-driver-usart', default=None, metavar='DRIVER', help='Build USART driver. [windows, linux, None]') - - # OS - gr.add_option('--with-os', metavar='OS', default='posix', help='Set operating system. Must be either \'posix\', \'macosx\', \'windows\' or \'freertos\'') - gr.add_option('--enable-init-shutdown', action='store_true', help='Use init system commands for shutdown/reboot') - - # Options - gr.add_option('--with-rdp-max-window', metavar='SIZE', type=int, default=20, help='Set maximum window size for RDP') - gr.add_option('--with-max-bind-port', metavar='PORT', type=int, default=31, help='Set maximum bindable port') - gr.add_option('--with-max-connections', metavar='COUNT', type=int, default=10, help='Set maximum number of concurrent connections') - gr.add_option('--with-conn-queue-length', metavar='SIZE', type=int, default=100, help='Set maximum number of packets in queue for a connection') - gr.add_option('--with-router-queue-length', metavar='SIZE', type=int, default=10, help='Set maximum number of packets to be queued at the input of the router') - gr.add_option('--with-padding', metavar='BYTES', type=int, default=8, help='Set padding bytes before packet length field') - gr.add_option('--with-loglevel', metavar='LEVEL', default='debug', help='Set minimum compile time log level. Must be one of \'error\', \'warn\', \'info\' or \'debug\'') - gr.add_option('--with-rtable', metavar='TABLE', default='static', help='Set routing table type') - gr.add_option('--with-connection-so', metavar='CSP_SO', type=int, default='0x0000', help='Set outgoing connection socket options, see csp.h for valid values') - gr.add_option('--with-bufalign', metavar='BYTES', type=int, help='Set buffer alignment') - -def configure(ctx): - # Validate OS - if not ctx.options.with_os in ('posix', 'windows', 'freertos', 'macosx'): - ctx.fatal('--with-os must be either \'posix\', \'windows\', \'macosx\' or \'freertos\'') - - # Validate USART drivers - if not ctx.options.with_driver_usart in (None, 'windows', 'linux'): - ctx.fatal('--with-driver-usart must be either \'windows\' or \'linux\'') - - if not ctx.options.with_loglevel in ('error', 'warn', 'info', 'debug'): - ctx.fatal('--with-loglevel must be either \'error\', \'warn\', \'info\' or \'debug\'') - - # Setup and validate toolchain - if (len(ctx.stack_path) <= 1) and ctx.options.toolchain: - ctx.env.CC = ctx.options.toolchain + 'gcc' - ctx.env.AR = ctx.options.toolchain + 'ar' - - ctx.load('gcc') - - # Set git revision define - git_rev = os.popen('git describe --always 2> /dev/null || echo unknown').read().strip() - - # Setup DEFINES - ctx.define('GIT_REV', git_rev) - - # Set build output format - ctx.env.FEATURES = ['c'] - if not ctx.options.disable_stlib: - ctx.env.FEATURES += ['cstlib'] - - # Setup CFLAGS - if (len(ctx.stack_path) <= 1) and (len(ctx.env.CFLAGS) == 0): - ctx.env.prepend_value('CFLAGS', ["-std=gnu99", "-g", "-Os", "-Wall", "-Wextra", "-Wshadow", "-Wcast-align", "-Wwrite-strings", "-Wno-unused-parameter"]) - - # Setup extra includes - ctx.env.append_unique('INCLUDES_CSP', ['include'] + ctx.options.includes.split(',')) - - # Add default files - ctx.env.append_unique('FILES_CSP', ['src/*.c','src/interfaces/csp_if_lo.c','src/transport/csp_udp.c','src/arch/{0}/**/*.c'.format(ctx.options.with_os)]) - - # Store OS as env variable - ctx.env.append_unique('OS', ctx.options.with_os) - - # Libs - if 'posix' in ctx.env.OS: - ctx.env.append_unique('LIBS', ['rt', 'pthread', 'util']) - elif 'macosx' in ctx.env.OS: - ctx.env.append_unique('LIBS', ['pthread']) - - # Check for recursion - if ctx.path == ctx.srcnode: - ctx.options.install_csp = True - - # Windows build flags - if ctx.options.with_os == 'windows': - ctx.env.append_unique('CFLAGS', ['-D_WIN32_WINNT=0x0600']) - - ctx.define_cond('CSP_FREERTOS', ctx.options.with_os == 'freertos') - ctx.define_cond('CSP_POSIX', ctx.options.with_os == 'posix') - ctx.define_cond('CSP_WINDOWS', ctx.options.with_os == 'windows') - ctx.define_cond('CSP_MACOSX', ctx.options.with_os == 'macosx') - - # Add CAN driver - if ctx.options.enable_can_socketcan: - ctx.env.append_unique('FILES_CSP', 'src/drivers/can/can_socketcan.c') - - # Add USART driver - if ctx.options.with_driver_usart != None: - ctx.env.append_unique('FILES_CSP', 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart)) - - # Interfaces - if ctx.options.enable_if_can: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can.c') - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can_pbuf.c') - if ctx.options.enable_if_i2c: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_i2c.c') - if ctx.options.enable_if_kiss: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_kiss.c') - if ctx.options.enable_if_zmqhub: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_zmqhub.c') - ctx.check_cfg(package='libzmq', args='--cflags --libs') - ctx.env.append_unique('LIBS', ctx.env.LIB_LIBZMQ) - - # Store configuration options - ctx.env.ENABLE_BINDINGS = ctx.options.enable_bindings - ctx.env.ENABLE_EXAMPLES = ctx.options.enable_examples - - # Check for python development - if ctx.options.enable_bindings: - ctx.env.LIBCSP_PYTHON2 = ctx.check_cfg(package='python2', args='--cflags --libs', atleast_version='2.7', mandatory=False) - if ctx.options.enable_python3_bindings: - ctx.env.LIBCSP_PYTHON3 = ctx.check_cfg(package='python3', args='--cflags --libs', atleast_version='3.5', mandatory=False) - - # Create config file - if not ctx.options.disable_output: - ctx.env.append_unique('FILES_CSP', 'src/csp_debug.c') - else: - ctx.env.append_unique('EXCL_CSP', 'src/csp_debug.c') - - if ctx.options.enable_rdp: - ctx.env.append_unique('FILES_CSP', 'src/transport/csp_rdp.c') - - if ctx.options.enable_crc32: - ctx.env.append_unique('FILES_CSP', 'src/csp_crc32.c') - else: - ctx.env.append_unique('EXCL_CSP', 'src/csp_crc32.c') - - if not ctx.options.enable_dedup: - ctx.env.append_unique('EXCL_CSP', 'src/csp_dedup.c') - - if ctx.options.enable_hmac: - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_hmac.c') - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') - - if ctx.options.enable_xtea: - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_xtea.c') - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') - - ctx.env.append_unique('FILES_CSP', 'src/rtable/csp_rtable_' + ctx.options.with_rtable + '.c') - - ctx.define_cond('CSP_DEBUG', not ctx.options.disable_output) - ctx.define_cond('CSP_USE_RDP', ctx.options.enable_rdp) - ctx.define_cond('CSP_USE_CRC32', ctx.options.enable_crc32) - ctx.define_cond('CSP_USE_HMAC', ctx.options.enable_hmac) - ctx.define_cond('CSP_USE_XTEA', ctx.options.enable_xtea) - ctx.define_cond('CSP_USE_PROMISC', ctx.options.enable_promisc) - ctx.define_cond('CSP_USE_QOS', ctx.options.enable_qos) - ctx.define_cond('CSP_USE_DEDUP', ctx.options.enable_dedup) - ctx.define_cond('CSP_USE_INIT_SHUTDOWN', ctx.options.enable_init_shutdown) - ctx.define_cond('CSP_USE_CAN', ctx.options.enable_if_can) - ctx.define_cond('CSP_USE_I2C', ctx.options.enable_if_i2c) - ctx.define_cond('CSP_USE_KISS', ctx.options.enable_if_kiss) - ctx.define_cond('CSP_USE_ZMQHUB', ctx.options.enable_if_zmqhub) - ctx.define('CSP_CONN_MAX', ctx.options.with_max_connections) - ctx.define('CSP_CONN_QUEUE_LENGTH', ctx.options.with_conn_queue_length) - ctx.define('CSP_FIFO_INPUT', ctx.options.with_router_queue_length) - ctx.define('CSP_MAX_BIND_PORT', ctx.options.with_max_bind_port) - ctx.define('CSP_RDP_MAX_WINDOW', ctx.options.with_rdp_max_window) - ctx.define('CSP_PADDING_BYTES', ctx.options.with_padding) - ctx.define('CSP_CONNECTION_SO', ctx.options.with_connection_so) - - if ctx.options.with_bufalign != None: - ctx.define('CSP_BUFFER_ALIGN', ctx.options.with_bufalign) - - # Set logging level - ctx.define_cond('CSP_LOG_LEVEL_DEBUG', ctx.options.with_loglevel in ('debug')) - ctx.define_cond('CSP_LOG_LEVEL_INFO', ctx.options.with_loglevel in ('debug', 'info')) - ctx.define_cond('CSP_LOG_LEVEL_WARN', ctx.options.with_loglevel in ('debug', 'info', 'warn')) - ctx.define_cond('CSP_LOG_LEVEL_ERROR', ctx.options.with_loglevel in ('debug', 'info', 'warn', 'error')) - - # Check compiler endianness - endianness = ctx.check_endianness() - ctx.define_cond('CSP_LITTLE_ENDIAN', endianness == 'little') - ctx.define_cond('CSP_BIG_ENDIAN', endianness == 'big') - - # Check for stdbool.h - ctx.check_cc(header_name='stdbool.h', mandatory=False, define_name='CSP_HAVE_STDBOOL_H', type='cstlib') - - # Check for libsocketcan.h - if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: - have_socketcan = ctx.check_cc(lib='socketcan', mandatory=False, define_name='CSP_HAVE_LIBSOCKETCAN') - if have_socketcan: - ctx.env.append_unique('LIBS', ['socketcan']) - - ctx.define('LIBCSP_VERSION', VERSION) - - ctx.write_config_header('include/csp/csp_autoconfig.h') - -def build(ctx): - - # Set install path for header files - install_path = False - if ctx.options.install_csp: - install_path = '${PREFIX}/lib' - ctx.install_files('${PREFIX}/include/csp', ctx.path.ant_glob('include/csp/*.h')) - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_lo.h') - - if 'src/interfaces/csp_if_can.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_can.h') - if 'src/interfaces/csp_if_i2c.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_i2c.h') - if 'src/interfaces/csp_if_kiss.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_kiss.h') - if 'src/interfaces/csp_if_zmqhub.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_zmqhub.h') - if 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart) in ctx.env.FILES_CSP: - ctx.install_as('${PREFIX}/include/csp/drivers/usart.h', 'include/csp/drivers/usart.h') - if 'src/drivers/can/can_socketcan.c' in ctx.env.FILES_CSP: - ctx.install_as('${PREFIX}/include/csp/drivers/can_socketcan.h', 'include/csp/drivers/can_socketcan.h') - - ctx.install_files('${PREFIX}/include/csp', 'include/csp/csp_autoconfig.h', cwd=ctx.bldnode) - - ctx(export_includes='include', name='csp_h') - - ctx(features=ctx.env.FEATURES, - source=ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), - target = 'csp', - includes= ctx.env.INCLUDES_CSP, - export_includes = ctx.env.INCLUDES_CSP, - use = 'include freertos_h', - install_path = install_path, - ) - - # Build shared library for Python bindings - if ctx.env.ENABLE_BINDINGS: - ctx.shlib(source = ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), - name = 'csp_shlib', - target = 'csp', - includes = ctx.env.INCLUDES_CSP, - export_includes = 'include', - use = ['include'], - lib = ctx.env.LIBS) - - # python3 bindings - if ctx.env.LIBCSP_PYTHON3: - ctx.shlib(source = ['src/bindings/python/pycsp.c'], - target = 'csp_py3', - includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON3, - export_includes = 'include', - use = ['csp_shlib', 'include'], - lib = ctx.env.LIBS) - - # python2 bindings - if ctx.env.LIBCSP_PYTHON2: - ctx.shlib(source = ['src/bindings/python/pycsp.c'], - target = 'csp_py2', - includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON2, - export_includes = 'include', - use = ['csp_shlib', 'include'], - lib = ctx.env.LIBS) - - if ctx.env.ENABLE_EXAMPLES: - ctx.program(source = ctx.path.ant_glob('examples/simple.c'), - target = 'simple', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if ctx.options.enable_if_kiss: - ctx.program(source = 'examples/kiss.c', - target = 'kiss', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if ctx.options.enable_if_zmqhub: - ctx.program(source = 'examples/zmqproxy.c', - target = 'zmqproxy', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if 'posix' in ctx.env.OS: - ctx.program(source = 'examples/csp_if_fifo.c', - target = 'fifo', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if 'windows' in ctx.env.OS: - ctx.program(source = ctx.path.ant_glob('examples/csp_if_fifo_windows.c'), - target = 'csp_if_fifo', - includes = ctx.env.INCLUDES_CSP, - use = 'csp') - -def dist(ctx): - ctx.excl = 'build/* **/.* **/*.pyc **/*.o **/*~ *.tar.gz' diff --git a/gomspace/libcsp/bindings/python/libcsp/__init__.py b/libcsp/bindings/python/libcsp/__init__.py similarity index 100% rename from gomspace/libcsp/bindings/python/libcsp/__init__.py rename to libcsp/bindings/python/libcsp/__init__.py diff --git a/gomspace/libcsp/doc/example.rst b/libcsp/doc/example.rst similarity index 100% rename from gomspace/libcsp/doc/example.rst rename to libcsp/doc/example.rst diff --git a/gomspace/libcsp/doc/history.rst b/libcsp/doc/history.rst similarity index 100% rename from gomspace/libcsp/doc/history.rst rename to libcsp/doc/history.rst diff --git a/gomspace/libcsp/doc/interfaces.rst b/libcsp/doc/interfaces.rst similarity index 100% rename from gomspace/libcsp/doc/interfaces.rst rename to libcsp/doc/interfaces.rst diff --git a/gomspace/libcsp/doc/libcsp.rst b/libcsp/doc/libcsp.rst similarity index 100% rename from gomspace/libcsp/doc/libcsp.rst rename to libcsp/doc/libcsp.rst diff --git a/gomspace/libcsp/doc/memory.rst b/libcsp/doc/memory.rst similarity index 100% rename from gomspace/libcsp/doc/memory.rst rename to libcsp/doc/memory.rst diff --git a/gomspace/libcsp/doc/mtu.rst b/libcsp/doc/mtu.rst similarity index 100% rename from gomspace/libcsp/doc/mtu.rst rename to libcsp/doc/mtu.rst diff --git a/gomspace/libcsp/doc/protocolstack.rst b/libcsp/doc/protocolstack.rst similarity index 100% rename from gomspace/libcsp/doc/protocolstack.rst rename to libcsp/doc/protocolstack.rst diff --git a/gomspace/libcsp/doc/structure.rst b/libcsp/doc/structure.rst similarity index 100% rename from gomspace/libcsp/doc/structure.rst rename to libcsp/doc/structure.rst diff --git a/gomspace/libcsp/doc/topology.rst b/libcsp/doc/topology.rst similarity index 100% rename from gomspace/libcsp/doc/topology.rst rename to libcsp/doc/topology.rst diff --git a/gomspace/libcsp/examples/csp_if_fifo.c b/libcsp/examples/csp_if_fifo.c similarity index 100% rename from gomspace/libcsp/examples/csp_if_fifo.c rename to libcsp/examples/csp_if_fifo.c diff --git a/gomspace/libcsp/examples/csp_if_fifo_windows.c b/libcsp/examples/csp_if_fifo_windows.c similarity index 100% rename from gomspace/libcsp/examples/csp_if_fifo_windows.c rename to libcsp/examples/csp_if_fifo_windows.c diff --git a/gomspace/libcsp/examples/kiss.c b/libcsp/examples/kiss.c similarity index 100% rename from gomspace/libcsp/examples/kiss.c rename to libcsp/examples/kiss.c diff --git a/gomspace/libcsp/examples/python_bindings_example_client.py b/libcsp/examples/python_bindings_example_client.py similarity index 100% rename from gomspace/libcsp/examples/python_bindings_example_client.py rename to libcsp/examples/python_bindings_example_client.py diff --git a/gomspace/libcsp/examples/python_bindings_example_client_can.py b/libcsp/examples/python_bindings_example_client_can.py similarity index 100% rename from gomspace/libcsp/examples/python_bindings_example_client_can.py rename to libcsp/examples/python_bindings_example_client_can.py diff --git a/gomspace/libcsp/examples/python_bindings_example_server.py b/libcsp/examples/python_bindings_example_server.py similarity index 100% rename from gomspace/libcsp/examples/python_bindings_example_server.py rename to libcsp/examples/python_bindings_example_server.py diff --git a/gomspace/libcsp/examples/simple.c b/libcsp/examples/simple.c similarity index 100% rename from gomspace/libcsp/examples/simple.c rename to libcsp/examples/simple.c diff --git a/gomspace/libcsp/examples/zmqproxy.c b/libcsp/examples/zmqproxy.c similarity index 100% rename from gomspace/libcsp/examples/zmqproxy.c rename to libcsp/examples/zmqproxy.c diff --git a/gomspace/libcsp/include/csp/arch/csp_clock.h b/libcsp/include/csp/arch/csp_clock.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_clock.h rename to libcsp/include/csp/arch/csp_clock.h diff --git a/gomspace/libcsp/include/csp/arch/csp_malloc.h b/libcsp/include/csp/arch/csp_malloc.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_malloc.h rename to libcsp/include/csp/arch/csp_malloc.h diff --git a/gomspace/libcsp/include/csp/arch/csp_queue.h b/libcsp/include/csp/arch/csp_queue.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_queue.h rename to libcsp/include/csp/arch/csp_queue.h diff --git a/gomspace/libcsp/include/csp/arch/csp_semaphore.h b/libcsp/include/csp/arch/csp_semaphore.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_semaphore.h rename to libcsp/include/csp/arch/csp_semaphore.h diff --git a/gomspace/libcsp/include/csp/arch/csp_system.h b/libcsp/include/csp/arch/csp_system.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_system.h rename to libcsp/include/csp/arch/csp_system.h diff --git a/gomspace/libcsp/include/csp/arch/csp_thread.h b/libcsp/include/csp/arch/csp_thread.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_thread.h rename to libcsp/include/csp/arch/csp_thread.h diff --git a/gomspace/libcsp/include/csp/arch/csp_time.h b/libcsp/include/csp/arch/csp_time.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_time.h rename to libcsp/include/csp/arch/csp_time.h diff --git a/gomspace/libcsp/include/csp/arch/posix/pthread_queue.h b/libcsp/include/csp/arch/posix/pthread_queue.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/posix/pthread_queue.h rename to libcsp/include/csp/arch/posix/pthread_queue.h diff --git a/gomspace/libcsp/include/csp/crypto/csp_hmac.h b/libcsp/include/csp/crypto/csp_hmac.h similarity index 100% rename from gomspace/libcsp/include/csp/crypto/csp_hmac.h rename to libcsp/include/csp/crypto/csp_hmac.h diff --git a/gomspace/libcsp/include/csp/crypto/csp_sha1.h b/libcsp/include/csp/crypto/csp_sha1.h similarity index 100% rename from gomspace/libcsp/include/csp/crypto/csp_sha1.h rename to libcsp/include/csp/crypto/csp_sha1.h diff --git a/gomspace/libcsp/include/csp/crypto/csp_xtea.h b/libcsp/include/csp/crypto/csp_xtea.h similarity index 100% rename from gomspace/libcsp/include/csp/crypto/csp_xtea.h rename to libcsp/include/csp/crypto/csp_xtea.h diff --git a/gomspace/libcsp/include/csp/csp.h b/libcsp/include/csp/csp.h similarity index 100% rename from gomspace/libcsp/include/csp/csp.h rename to libcsp/include/csp/csp.h diff --git a/gomspace/libcsp/include/csp/csp_autoconfig.h b/libcsp/include/csp/csp_autoconfig.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_autoconfig.h rename to libcsp/include/csp/csp_autoconfig.h diff --git a/gomspace/libcsp/include/csp/csp_buffer.h b/libcsp/include/csp/csp_buffer.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_buffer.h rename to libcsp/include/csp/csp_buffer.h diff --git a/gomspace/libcsp/include/csp/csp_cmp.h b/libcsp/include/csp/csp_cmp.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_cmp.h rename to libcsp/include/csp/csp_cmp.h diff --git a/gomspace/libcsp/include/csp/csp_crc32.h b/libcsp/include/csp/csp_crc32.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_crc32.h rename to libcsp/include/csp/csp_crc32.h diff --git a/gomspace/libcsp/include/csp/csp_debug.h b/libcsp/include/csp/csp_debug.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_debug.h rename to libcsp/include/csp/csp_debug.h diff --git a/gomspace/libcsp/include/csp/csp_endian.h b/libcsp/include/csp/csp_endian.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_endian.h rename to libcsp/include/csp/csp_endian.h diff --git a/gomspace/libcsp/include/csp/csp_error.h b/libcsp/include/csp/csp_error.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_error.h rename to libcsp/include/csp/csp_error.h diff --git a/gomspace/libcsp/include/csp/csp_iflist.h b/libcsp/include/csp/csp_iflist.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_iflist.h rename to libcsp/include/csp/csp_iflist.h diff --git a/gomspace/libcsp/include/csp/csp_interface.h b/libcsp/include/csp/csp_interface.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_interface.h rename to libcsp/include/csp/csp_interface.h diff --git a/gomspace/libcsp/include/csp/csp_platform.h b/libcsp/include/csp/csp_platform.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_platform.h rename to libcsp/include/csp/csp_platform.h diff --git a/gomspace/libcsp/include/csp/csp_rtable.h b/libcsp/include/csp/csp_rtable.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_rtable.h rename to libcsp/include/csp/csp_rtable.h diff --git a/gomspace/libcsp/include/csp/csp_types.h b/libcsp/include/csp/csp_types.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_types.h rename to libcsp/include/csp/csp_types.h diff --git a/gomspace/libcsp/include/csp/drivers/can_socketcan.h b/libcsp/include/csp/drivers/can_socketcan.h similarity index 100% rename from gomspace/libcsp/include/csp/drivers/can_socketcan.h rename to libcsp/include/csp/drivers/can_socketcan.h diff --git a/gomspace/libcsp/include/csp/drivers/i2c.h b/libcsp/include/csp/drivers/i2c.h similarity index 100% rename from gomspace/libcsp/include/csp/drivers/i2c.h rename to libcsp/include/csp/drivers/i2c.h diff --git a/gomspace/libcsp/include/csp/drivers/usart.h b/libcsp/include/csp/drivers/usart.h similarity index 100% rename from gomspace/libcsp/include/csp/drivers/usart.h rename to libcsp/include/csp/drivers/usart.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_can.h b/libcsp/include/csp/interfaces/csp_if_can.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_can.h rename to libcsp/include/csp/interfaces/csp_if_can.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_i2c.h b/libcsp/include/csp/interfaces/csp_if_i2c.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_i2c.h rename to libcsp/include/csp/interfaces/csp_if_i2c.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_kiss.h b/libcsp/include/csp/interfaces/csp_if_kiss.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_kiss.h rename to libcsp/include/csp/interfaces/csp_if_kiss.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_lo.h b/libcsp/include/csp/interfaces/csp_if_lo.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_lo.h rename to libcsp/include/csp/interfaces/csp_if_lo.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_zmqhub.h b/libcsp/include/csp/interfaces/csp_if_zmqhub.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_zmqhub.h rename to libcsp/include/csp/interfaces/csp_if_zmqhub.h diff --git a/libcsp/libcsp.mk b/libcsp/libcsp.mk new file mode 100644 index 00000000..febffad7 --- /dev/null +++ b/libcsp/libcsp.mk @@ -0,0 +1,12 @@ +CSRC += $(wildcard $(CURRENTPATH)/src/drivers/can/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/interfaces/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/rtable/csp_rtable_cidr.c) +CSRC += $(wildcard $(CURRENTPATH)/src/crypto/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/arch/posix/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/transport/*.c) + +INCLUDES += $(CURRENTPATH)/include +INCLUDES += $(CURRENTPATH)/include/csp +INCLUDES += $(CURRENTPATH)/include/csp/crypto +INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/gomspace/libcsp/src/arch/freertos/csp_malloc.c b/libcsp/src/arch/freertos/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_malloc.c rename to libcsp/src/arch/freertos/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_queue.c b/libcsp/src/arch/freertos/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_queue.c rename to libcsp/src/arch/freertos/csp_queue.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_semaphore.c b/libcsp/src/arch/freertos/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_semaphore.c rename to libcsp/src/arch/freertos/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_system.c b/libcsp/src/arch/freertos/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_system.c rename to libcsp/src/arch/freertos/csp_system.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_thread.c b/libcsp/src/arch/freertos/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_thread.c rename to libcsp/src/arch/freertos/csp_thread.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_time.c b/libcsp/src/arch/freertos/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_time.c rename to libcsp/src/arch/freertos/csp_time.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_malloc.c b/libcsp/src/arch/macosx/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_malloc.c rename to libcsp/src/arch/macosx/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_queue.c b/libcsp/src/arch/macosx/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_queue.c rename to libcsp/src/arch/macosx/csp_queue.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_semaphore.c b/libcsp/src/arch/macosx/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_semaphore.c rename to libcsp/src/arch/macosx/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_system.c b/libcsp/src/arch/macosx/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_system.c rename to libcsp/src/arch/macosx/csp_system.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_thread.c b/libcsp/src/arch/macosx/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_thread.c rename to libcsp/src/arch/macosx/csp_thread.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_time.c b/libcsp/src/arch/macosx/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_time.c rename to libcsp/src/arch/macosx/csp_time.c diff --git a/gomspace/libcsp/src/arch/macosx/pthread_queue.c b/libcsp/src/arch/macosx/pthread_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/pthread_queue.c rename to libcsp/src/arch/macosx/pthread_queue.c diff --git a/gomspace/libcsp/src/arch/posix/csp_malloc.c b/libcsp/src/arch/posix/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_malloc.c rename to libcsp/src/arch/posix/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/posix/csp_queue.c b/libcsp/src/arch/posix/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_queue.c rename to libcsp/src/arch/posix/csp_queue.c diff --git a/gomspace/libcsp/src/arch/posix/csp_semaphore.c b/libcsp/src/arch/posix/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_semaphore.c rename to libcsp/src/arch/posix/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/posix/csp_system.c b/libcsp/src/arch/posix/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_system.c rename to libcsp/src/arch/posix/csp_system.c diff --git a/gomspace/libcsp/src/arch/posix/csp_thread.c b/libcsp/src/arch/posix/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_thread.c rename to libcsp/src/arch/posix/csp_thread.c diff --git a/gomspace/libcsp/src/arch/posix/csp_time.c b/libcsp/src/arch/posix/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_time.c rename to libcsp/src/arch/posix/csp_time.c diff --git a/gomspace/libcsp/src/arch/posix/pthread_queue.c b/libcsp/src/arch/posix/pthread_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/pthread_queue.c rename to libcsp/src/arch/posix/pthread_queue.c diff --git a/gomspace/libcsp/src/arch/windows/README b/libcsp/src/arch/windows/README similarity index 100% rename from gomspace/libcsp/src/arch/windows/README rename to libcsp/src/arch/windows/README diff --git a/gomspace/libcsp/src/arch/windows/csp_malloc.c b/libcsp/src/arch/windows/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_malloc.c rename to libcsp/src/arch/windows/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/windows/csp_queue.c b/libcsp/src/arch/windows/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_queue.c rename to libcsp/src/arch/windows/csp_queue.c diff --git a/gomspace/libcsp/src/arch/windows/csp_semaphore.c b/libcsp/src/arch/windows/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_semaphore.c rename to libcsp/src/arch/windows/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/windows/csp_system.c b/libcsp/src/arch/windows/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_system.c rename to libcsp/src/arch/windows/csp_system.c diff --git a/gomspace/libcsp/src/arch/windows/csp_thread.c b/libcsp/src/arch/windows/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_thread.c rename to libcsp/src/arch/windows/csp_thread.c diff --git a/gomspace/libcsp/src/arch/windows/csp_time.c b/libcsp/src/arch/windows/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_time.c rename to libcsp/src/arch/windows/csp_time.c diff --git a/gomspace/libcsp/src/arch/windows/windows_glue.h b/libcsp/src/arch/windows/windows_glue.h similarity index 100% rename from gomspace/libcsp/src/arch/windows/windows_glue.h rename to libcsp/src/arch/windows/windows_glue.h diff --git a/gomspace/libcsp/src/arch/windows/windows_queue.c b/libcsp/src/arch/windows/windows_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/windows_queue.c rename to libcsp/src/arch/windows/windows_queue.c diff --git a/gomspace/libcsp/src/arch/windows/windows_queue.h b/libcsp/src/arch/windows/windows_queue.h similarity index 100% rename from gomspace/libcsp/src/arch/windows/windows_queue.h rename to libcsp/src/arch/windows/windows_queue.h diff --git a/gomspace/libcsp/src/bindings/python/pycsp.c b/libcsp/src/bindings/python/pycsp.c similarity index 100% rename from gomspace/libcsp/src/bindings/python/pycsp.c rename to libcsp/src/bindings/python/pycsp.c diff --git a/gomspace/libcsp/src/crypto/csp_hmac.c b/libcsp/src/crypto/csp_hmac.c similarity index 100% rename from gomspace/libcsp/src/crypto/csp_hmac.c rename to libcsp/src/crypto/csp_hmac.c diff --git a/gomspace/libcsp/src/crypto/csp_sha1.c b/libcsp/src/crypto/csp_sha1.c similarity index 100% rename from gomspace/libcsp/src/crypto/csp_sha1.c rename to libcsp/src/crypto/csp_sha1.c diff --git a/gomspace/libcsp/src/crypto/csp_xtea.c b/libcsp/src/crypto/csp_xtea.c similarity index 100% rename from gomspace/libcsp/src/crypto/csp_xtea.c rename to libcsp/src/crypto/csp_xtea.c diff --git a/gomspace/libcsp/src/csp_bridge.c b/libcsp/src/csp_bridge.c similarity index 100% rename from gomspace/libcsp/src/csp_bridge.c rename to libcsp/src/csp_bridge.c diff --git a/gomspace/libcsp/src/csp_buffer.c b/libcsp/src/csp_buffer.c similarity index 100% rename from gomspace/libcsp/src/csp_buffer.c rename to libcsp/src/csp_buffer.c diff --git a/gomspace/libcsp/src/csp_conn.c b/libcsp/src/csp_conn.c similarity index 100% rename from gomspace/libcsp/src/csp_conn.c rename to libcsp/src/csp_conn.c diff --git a/gomspace/libcsp/src/csp_conn.h b/libcsp/src/csp_conn.h similarity index 100% rename from gomspace/libcsp/src/csp_conn.h rename to libcsp/src/csp_conn.h diff --git a/gomspace/libcsp/src/csp_crc32.c b/libcsp/src/csp_crc32.c similarity index 100% rename from gomspace/libcsp/src/csp_crc32.c rename to libcsp/src/csp_crc32.c diff --git a/gomspace/libcsp/src/csp_debug.c b/libcsp/src/csp_debug.c similarity index 100% rename from gomspace/libcsp/src/csp_debug.c rename to libcsp/src/csp_debug.c diff --git a/gomspace/libcsp/src/csp_dedup.c b/libcsp/src/csp_dedup.c similarity index 100% rename from gomspace/libcsp/src/csp_dedup.c rename to libcsp/src/csp_dedup.c diff --git a/gomspace/libcsp/src/csp_dedup.h b/libcsp/src/csp_dedup.h similarity index 100% rename from gomspace/libcsp/src/csp_dedup.h rename to libcsp/src/csp_dedup.h diff --git a/gomspace/libcsp/src/csp_endian.c b/libcsp/src/csp_endian.c similarity index 100% rename from gomspace/libcsp/src/csp_endian.c rename to libcsp/src/csp_endian.c diff --git a/gomspace/libcsp/src/csp_hex_dump.c b/libcsp/src/csp_hex_dump.c similarity index 100% rename from gomspace/libcsp/src/csp_hex_dump.c rename to libcsp/src/csp_hex_dump.c diff --git a/gomspace/libcsp/src/csp_iflist.c b/libcsp/src/csp_iflist.c similarity index 100% rename from gomspace/libcsp/src/csp_iflist.c rename to libcsp/src/csp_iflist.c diff --git a/gomspace/libcsp/src/csp_io.c b/libcsp/src/csp_io.c similarity index 100% rename from gomspace/libcsp/src/csp_io.c rename to libcsp/src/csp_io.c diff --git a/gomspace/libcsp/src/csp_io.h b/libcsp/src/csp_io.h similarity index 100% rename from gomspace/libcsp/src/csp_io.h rename to libcsp/src/csp_io.h diff --git a/gomspace/libcsp/src/csp_port.c b/libcsp/src/csp_port.c similarity index 100% rename from gomspace/libcsp/src/csp_port.c rename to libcsp/src/csp_port.c diff --git a/gomspace/libcsp/src/csp_port.h b/libcsp/src/csp_port.h similarity index 100% rename from gomspace/libcsp/src/csp_port.h rename to libcsp/src/csp_port.h diff --git a/gomspace/libcsp/src/csp_promisc.c b/libcsp/src/csp_promisc.c similarity index 100% rename from gomspace/libcsp/src/csp_promisc.c rename to libcsp/src/csp_promisc.c diff --git a/gomspace/libcsp/src/csp_promisc.h b/libcsp/src/csp_promisc.h similarity index 100% rename from gomspace/libcsp/src/csp_promisc.h rename to libcsp/src/csp_promisc.h diff --git a/gomspace/libcsp/src/csp_qfifo.c b/libcsp/src/csp_qfifo.c similarity index 100% rename from gomspace/libcsp/src/csp_qfifo.c rename to libcsp/src/csp_qfifo.c diff --git a/gomspace/libcsp/src/csp_qfifo.h b/libcsp/src/csp_qfifo.h similarity index 100% rename from gomspace/libcsp/src/csp_qfifo.h rename to libcsp/src/csp_qfifo.h diff --git a/gomspace/libcsp/src/csp_route.c b/libcsp/src/csp_route.c similarity index 100% rename from gomspace/libcsp/src/csp_route.c rename to libcsp/src/csp_route.c diff --git a/gomspace/libcsp/src/csp_route.h b/libcsp/src/csp_route.h similarity index 100% rename from gomspace/libcsp/src/csp_route.h rename to libcsp/src/csp_route.h diff --git a/gomspace/libcsp/src/csp_service_handler.c b/libcsp/src/csp_service_handler.c similarity index 100% rename from gomspace/libcsp/src/csp_service_handler.c rename to libcsp/src/csp_service_handler.c diff --git a/gomspace/libcsp/src/csp_services.c b/libcsp/src/csp_services.c similarity index 100% rename from gomspace/libcsp/src/csp_services.c rename to libcsp/src/csp_services.c diff --git a/gomspace/libcsp/src/csp_sfp.c b/libcsp/src/csp_sfp.c similarity index 100% rename from gomspace/libcsp/src/csp_sfp.c rename to libcsp/src/csp_sfp.c diff --git a/gomspace/libcsp/src/drivers/can/can_socketcan.c b/libcsp/src/drivers/can/can_socketcan.c similarity index 100% rename from gomspace/libcsp/src/drivers/can/can_socketcan.c rename to libcsp/src/drivers/can/can_socketcan.c diff --git a/gomspace/libcsp/src/drivers/usart/usart_linux.c b/libcsp/src/drivers/usart/usart_linux.c similarity index 100% rename from gomspace/libcsp/src/drivers/usart/usart_linux.c rename to libcsp/src/drivers/usart/usart_linux.c diff --git a/gomspace/libcsp/src/drivers/usart/usart_windows.c b/libcsp/src/drivers/usart/usart_windows.c similarity index 100% rename from gomspace/libcsp/src/drivers/usart/usart_windows.c rename to libcsp/src/drivers/usart/usart_windows.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_can.c b/libcsp/src/interfaces/csp_if_can.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_can.c rename to libcsp/src/interfaces/csp_if_can.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_can_pbuf.c b/libcsp/src/interfaces/csp_if_can_pbuf.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_can_pbuf.c rename to libcsp/src/interfaces/csp_if_can_pbuf.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_can_pbuf.h b/libcsp/src/interfaces/csp_if_can_pbuf.h similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_can_pbuf.h rename to libcsp/src/interfaces/csp_if_can_pbuf.h diff --git a/gomspace/libcsp/src/interfaces/csp_if_i2c.c b/libcsp/src/interfaces/csp_if_i2c.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_i2c.c rename to libcsp/src/interfaces/csp_if_i2c.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_kiss.c b/libcsp/src/interfaces/csp_if_kiss.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_kiss.c rename to libcsp/src/interfaces/csp_if_kiss.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_lo.c b/libcsp/src/interfaces/csp_if_lo.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_lo.c rename to libcsp/src/interfaces/csp_if_lo.c diff --git a/gomspace/libcsp/src/rtable/csp_rtable_cidr.c b/libcsp/src/rtable/csp_rtable_cidr.c similarity index 100% rename from gomspace/libcsp/src/rtable/csp_rtable_cidr.c rename to libcsp/src/rtable/csp_rtable_cidr.c diff --git a/gomspace/libcsp/src/rtable/csp_rtable_static.c b/libcsp/src/rtable/csp_rtable_static.c similarity index 100% rename from gomspace/libcsp/src/rtable/csp_rtable_static.c rename to libcsp/src/rtable/csp_rtable_static.c diff --git a/gomspace/libcsp/src/transport/csp_rdp.c b/libcsp/src/transport/csp_rdp.c similarity index 100% rename from gomspace/libcsp/src/transport/csp_rdp.c rename to libcsp/src/transport/csp_rdp.c diff --git a/gomspace/libcsp/src/transport/csp_transport.h b/libcsp/src/transport/csp_transport.h similarity index 100% rename from gomspace/libcsp/src/transport/csp_transport.h rename to libcsp/src/transport/csp_transport.h diff --git a/gomspace/libcsp/src/transport/csp_udp.c b/libcsp/src/transport/csp_udp.c similarity index 100% rename from gomspace/libcsp/src/transport/csp_udp.c rename to libcsp/src/transport/csp_udp.c diff --git a/gomspace/libcsp/utils/cfpsplit.py b/libcsp/utils/cfpsplit.py similarity index 100% rename from gomspace/libcsp/utils/cfpsplit.py rename to libcsp/utils/cfpsplit.py diff --git a/gomspace/libcsp/utils/cspsplit.py b/libcsp/utils/cspsplit.py similarity index 100% rename from gomspace/libcsp/utils/cspsplit.py rename to libcsp/utils/cspsplit.py diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index cfdf297f..1fb7ca38 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -19,10 +20,13 @@ #include #include #include +#include +#include +#include "mission/devices/GomspaceDeviceHandler.h" +#include "mission/devices/devicedefinitions/GomspaceDefinitions.h" #if ADD_TEST_CODE == 1 //#include -#include #endif void ObjectFactory::produceGenericObjects() { @@ -81,9 +85,35 @@ void ObjectFactory::produceGenericObjects() { new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT, apid::EIVE_OBSW, pus::PUS_SERVICE_200); + /* Cookies */ + CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, + addresses::P60DOCK); + CspCookie* pdu1CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, + addresses::PDU1); + CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, + addresses::PDU2); + CspCookie* acuCspCookie = new CspCookie(ACU::MAX_REPLY_LENGTH, + addresses::ACU); + + /* Communication interfaces */ + new CspComIF(objects::CSP_COM_IF); + + /* Device Handler */ + new GomspaceDeviceHandler(objects::P60DOCK_HANDLER, objects::CSP_COM_IF, + p60DockCspCookie, P60Dock::MAX_CONFIGTABLE_ADDRESS, + P60Dock::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::PDU1_HANDLER, objects::CSP_COM_IF, + pdu1CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, + PDU::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::PDU2_HANDLER, objects::CSP_COM_IF, + pdu2CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, + PDU::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::ACU_HANDLER, objects::CSP_COM_IF, + acuCspCookie, ACU::MAX_CONFIGTABLE_ADDRESS, + ACU::MAX_HKTABLE_ADDRESS); + /* Test Device Handler */ #if ADD_TEST_CODE == 1 // new TestTask(objects::TEST_TASK); - new P60DockTestTask(objects::P60DOCK_TEST_TASK); #endif } diff --git a/mission/devices/GomspaceDeviceHandler.cpp b/mission/devices/GomspaceDeviceHandler.cpp new file mode 100644 index 00000000..fcb97953 --- /dev/null +++ b/mission/devices/GomspaceDeviceHandler.cpp @@ -0,0 +1,334 @@ +#include +#include + +GomspaceDeviceHandler::GomspaceDeviceHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie, uint16_t maxConfigTableAddress, + uint16_t maxHkTableAddress) : + DeviceHandlerBase(objectId, comIF, comCookie), maxConfigTableAddress( + maxConfigTableAddress), maxHkTableAddress(maxHkTableAddress) { + mode = MODE_NORMAL; + if (comCookie == NULL) { + sif::error << "GomspaceDeviceHandler invalid com cookie" << std::endl; + } +} + +GomspaceDeviceHandler::~GomspaceDeviceHandler() { +} + + +void GomspaceDeviceHandler::doStartUp(){ +} + +void GomspaceDeviceHandler::doShutDown(){ + +} + +ReturnValue_t GomspaceDeviceHandler::buildNormalDeviceCommand( + DeviceCommandId_t * id) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::buildTransitionDeviceCommand( + DeviceCommandId_t * id){ + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t * commandData, + size_t commandDataLen) { + ReturnValue_t result; + switch(deviceCommand) { + case(PING): { + result = generatePingCommand(commandData, commandDataLen); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + break; + } + case(REBOOT): { + generateRebootCommand(); + break; + } + case(PARAM_SET):{ + result = generateSetParamCommand(commandData, commandDataLen); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + break; + } + case(PARAM_GET):{ + result = generateGetParamCommand(commandData, commandDataLen); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + break; + } + case(GNDWDT_RESET): { + result = generateResetWatchdogCmd(); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void GomspaceDeviceHandler::fillCommandAndReplyMap(){ + this->insertInCommandAndReplyMap(PING, 3); + this->insertInCommandMap(REBOOT); + this->insertInCommandAndReplyMap(PARAM_SET, 3); + this->insertInCommandAndReplyMap(PARAM_GET, 3); + this->insertInCommandMap(GNDWDT_RESET); +} + +ReturnValue_t GomspaceDeviceHandler::scanForReply(const uint8_t *start, + size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { + switch(rememberCommandId) { + case(PING): + *foundId = PING; + *foundLen = PING_REPLY_SIZE; + rememberCommandId = NONE; + break; + case(PARAM_GET): { + *foundId = PARAM_GET; + *foundLen = rememberRequestedSize + CspGetParamReply::GS_HDR_LENGTH; + rememberCommandId = NONE; + break; + } + case(PARAM_SET): { + *foundId = PARAM_SET; + *foundLen = rememberRequestedSize; + rememberCommandId = NONE; + break; + } + default: + return IGNORE_REPLY_DATA; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + switch(id) { + case(PING): { + SerializeElement replyTime = *packet; + handleDeviceTM(&replyTime, id, true); + break; + } + case(PARAM_GET): { + // -2 to subtract address size from gomspace parameter reply packet + uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; + if(payloadLength > sizeof(uint32_t)){ + sif::error << "GomspaceDeviceHandler: PARAM_GET: Invalid payload " + << "size in reply" << std::endl; + return INVALID_PAYLOAD_SIZE; + } + uint8_t tempPayloadBuffer[payloadLength]; + /* Extract information from received data */ + CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); + size_t size = CspGetParamReply::GS_HDR_LENGTH + payloadLength; + ReturnValue_t result = cspGetParamReply.deSerialize(&packet, &size, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to deserialize get parameter" + << "reply" << std::endl; + return result; + } + uint8_t action = cspGetParamReply.getAction(); + uint8_t tableId = cspGetParamReply.getTableId(); + uint16_t address = cspGetParamReply.getAddress(); + /* Pack relevant information into a tm packet */ + ParamReply paramReply(action, tableId, address, payloadLength, + tempPayloadBuffer); + handleDeviceTM(¶mReply, id, true); + break; + } + case(PARAM_SET): { + /* When setting a parameter, the p60dock sends back the state of the + * operation */ + if(*packet != PARAM_SET_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + break; + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void GomspaceDeviceHandler::setNormalDatapoolEntriesInvalid(){ + +} + +ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand( + const uint8_t * commandData, size_t commandDataLen) { + SetParamMessageUnpacker setParamMessageUnpacker; + ReturnValue_t result = setParamMessageUnpacker.deSerialize(&commandData, + &commandDataLen, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to deserialize set parameter " + "message" << std::endl; + return result; + } + /* Get and check address */ + uint16_t address = setParamMessageUnpacker.getAddress(); + if(address > maxConfigTableAddress){ + sif::error << "GomspaceDeviceHandler: Invalid address for set parameter " + << "action" << std::endl; + return INVALID_ADDRESS; + } + uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; + uint16_t seq = 0; + uint16_t total = 0; + /* CSP reply only contains the transaction state */ + uint16_t querySize = 1; + const uint8_t* parameterPtr = setParamMessageUnpacker.getParameter(); + uint8_t parameterSize = setParamMessageUnpacker.getParameterSize(); + uint16_t payloadlength = sizeof(address) + parameterSize; + + /* Generate command for CspComIF */ + CspSetParamCommand setParamCmd(querySize, payloadlength, checksum, seq, + total, address, parameterPtr, parameterSize); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + result = setParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize command for " + << "CspComIF" << std::endl; + return result; + } + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "GomspaceDeviceHandler: Invalid length of set parameter " + "command" << std::endl; + return PACKET_TOO_LONG; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = querySize; + rememberCommandId = PARAM_SET; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::generateGetParamCommand( + const uint8_t * commandData, size_t commandDataLen){ + ReturnValue_t result; + /* Unpack the received action message */ + GetParamMessageUnpacker getParamMessage; + result = getParamMessage.deSerialize(&commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Failed to deserialize message to extract information " + "from get parameter message" << std::endl; + return result; + } + /* Get an check table id to read from */ + uint8_t tableId = getParamMessage.getTableId(); + if(tableId != CONFIG_TABLE_ID && tableId != HK_TABLE_ID){ + sif::error << "GomspaceDeviceHandler: Invalid table id in get parameter" + " message" << std::endl; + return INVALID_TABLE_ID; + } + /* Get and check address */ + uint16_t address = getParamMessage.getAddress(); + if(address > maxHkTableAddress && tableId == HK_TABLE_ID){ + sif::error << "GomspaceDeviceHandler: Invalid address to get parameter from " + << "housekeeping table" << std::endl; + return INVALID_ADDRESS; + } + if(address > maxConfigTableAddress && tableId == CONFIG_TABLE_ID){ + sif::error << "GomspaceDeviceHandler: Invalid address to get parameter from " + << "configuration table" << std::endl; + return INVALID_ADDRESS; + } + uint16_t length = sizeof(address); + uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; + uint16_t seq = 0; + uint16_t total = 0; + uint8_t parameterSize = getParamMessage.getParameterSize(); + if(parameterSize > sizeof(uint32_t)) { + sif::error << "GomspaceDeviceHandler: GET_PARAM: Invalid parameter " + << "size" << std::endl; + return INVALID_PARAM_SIZE; + } + uint16_t querySize = parameterSize + CspGetParamCommand::GS_HDR_LENGTH; + + /* Generate the CSP command to send to the P60 Dock */ + CspGetParamCommand getParamCmd(querySize, tableId, length, + checksum, seq, total, address); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + result = getParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize command to " + << "get parameter" << std::endl; + } + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "GomspaceDeviceHandler: Received invalid get parameter " + "command" << std::endl; + return PACKET_TOO_LONG; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = querySize; + rememberCommandId = PARAM_GET; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::generatePingCommand( + const uint8_t * commandData, size_t commandDataLen) { + CspPingCommand cspPingCommand(commandData, commandDataLen); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + ReturnValue_t result = cspPingCommand.serialize(&buffer, &cspPacketLen, + sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize ping command" + << std::endl; + return result; + } + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "GomspaceDeviceHandler: Received invalid ping message" + << std::endl; + return PACKET_TOO_LONG; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberCommandId = PING; + return HasReturnvaluesIF::RETURN_OK; +} + +void GomspaceDeviceHandler::generateRebootCommand(){ + uint8_t cspPort = GOMSPACE::REBOOT_PORT; + uint16_t querySize = 0; + *cspPacket = GOMSPACE::REBOOT_PORT; + *(cspPacket + 1) = querySize; + size_t cspPacketLen = sizeof(cspPort) + sizeof(cspPacketLen); + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; +} + +ReturnValue_t GomspaceDeviceHandler::generateResetWatchdogCmd(){ + WatchdogResetCommand watchdogResetCommand; + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + ReturnValue_t result = watchdogResetCommand.serialize(&buffer, + &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize watchdog reset " + << "command" << std::endl; + return result; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = 0; // No bytes will be queried with the ground + // watchdog command. + rememberCommandId = GNDWDT_RESET; + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/mission/devices/GomspaceDeviceHandler.h b/mission/devices/GomspaceDeviceHandler.h new file mode 100644 index 00000000..35c89206 --- /dev/null +++ b/mission/devices/GomspaceDeviceHandler.h @@ -0,0 +1,108 @@ +#ifndef MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ +#define MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ + +#include + +/** + * @brief This is the device handler class for all gomspace devices. + * + * @details All gomspace devices are similar with respect to commanding. Thus + * most of the functionality to command a gomspace device can be + * accommodated in one class. For device specific functions, a new + * class could be created by inheriting from the GomspaceDeviceHandler. + */ +class GomspaceDeviceHandler: public DeviceHandlerBase { +public: + + static const ReturnValue_t PACKET_TOO_LONG = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t INVALID_TABLE_ID = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t INVALID_PARAM_SIZE = MAKE_RETURN_CODE(0xE3); + static const ReturnValue_t INVALID_PAYLOAD_SIZE = MAKE_RETURN_CODE(0xE4); + + /** + * @brief Constructor + * + * @param maxConfigTableAddress The maximum memory address of the configu- + * ration table of a gomspace device. + * @param maxHkTableAddress The maximum memory address of a value in the + * houskeeping (telemetry) table of a gomspace + * device. + */ + GomspaceDeviceHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie, uint16_t maxConfigTableAddress, + uint16_t maxHkTableAddress); + virtual ~GomspaceDeviceHandler(); + +protected: + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override; + ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override; + void fillCommandAndReplyMap() override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t * commandData,size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + void setNormalDatapoolEntriesInvalid() override; + +private: + + static const uint8_t MAX_PACKET_LEN = 36; + static const uint8_t PARAM_SET_OK = 1; + static const uint8_t PING_REPLY_SIZE = 2; + static const uint8_t CONFIG_TABLE_ID = 1; + static const uint8_t HK_TABLE_ID = 4; + /* Device commands are derived from the rparam.h of the gomspace lib */ + static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t NONE = 0x2; // Set when no command is pending + static const DeviceCommandId_t REBOOT = 0x4; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t GNDWDT_RESET = 0x9; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t PARAM_GET = 0x00; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t PARAM_SET = 0xFF; //!< [EXPORT] : [COMMAND] + + uint8_t rememberRequestedSize = 0; + uint8_t rememberCommandId = NONE; + uint8_t cspPacket[MAX_PACKET_LEN]; + + uint16_t maxConfigTableAddress; + uint16_t maxHkTableAddress; + + /** + * @brief Function to generate the command to set a parameter. Command + * will be sent to the ComIF over the rawPacket buffer. + */ + ReturnValue_t generateSetParamCommand(const uint8_t * commandData, + size_t commandDataLen); + + /** + * @brief Function to generate the command to get a parameter from a + * gomspace device. Command will be sent to the ComIF over the + * rawPacket buffer. + */ + ReturnValue_t generateGetParamCommand(const uint8_t * commandData, + size_t commandDataLen); + + /** + * @brief Function to generate the ping command for the ComIF. + */ + ReturnValue_t generatePingCommand(const uint8_t * commandData, + size_t commandDataLen); + + /** + * @brief Function to generate the command to reboot a gomspace device + * via the ComIF. + */ + void generateRebootCommand(); + + /** + * @brief Function to generate the command to force a ground watchdog + * reset in a gomspace device. + */ + ReturnValue_t generateResetWatchdogCmd(); + +}; + +#endif /* MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ */ diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp deleted file mode 100644 index f3ccc925..00000000 --- a/mission/devices/P60DockHandler.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * P60DockHandler.cpp - * - * Created on: 18.11.2020 - * Author: jakob - */ - -#include -#include -#include "P60DockHandler.h" - -//P60DockHandler::P60DockHandler() { -// -//} -// -// -//P60DockHandler::~P60DockHandler() { -//} -// -// -//P60DockHandler::performOperation(uint8_t operationCode) { -// -//} diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h deleted file mode 100644 index 20078cd8..00000000 --- a/mission/devices/P60DockHandler.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * P60DockHandler.h - * - * Created on: 18.11.2020 - * Author: jakob - */ - -#ifndef MISSION_DEVICES_P60DOCKHANDLER_H_ -#define MISSION_DEVICES_P60DOCKHANDLER_H_ - -//class P60DockHandler: public DeviceHandlerBase { -//public: -// P60DockHandler(); -// virtual ~P60DockHandler(); -// virtual ReturnValue_t performOperation(uint8_t operationCode = 0); -//}; - -#endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h new file mode 100644 index 00000000..6c3509f8 --- /dev/null +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -0,0 +1,362 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ + +#include "fsfw/serialize/SerialBufferAdapter.h" +#include "fsfw/serialize/SerializeElement.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/serialize/SerialFixedArrayListAdapter.h" + +namespace GOMSPACE{ + static const uint16_t IGNORE_CHECKSUM = 0xbb0; + /* CSP port to ping gomspace devices. */ + static const uint8_t PING_PORT = 1; + static const uint8_t REBOOT_PORT = 4; + /* CSP port of gomspace devices to request or set parameters */ + static const uint8_t PARAM_PORT = 7; + static const uint8_t P60_PORT_GNDWDT_RESET = 9; +} + + +/** + * @brief This class can be used to generated the command for the CspComIF + * to reset the watchdog in a gomspace device. + */ +class WatchdogResetCommand : public SerialLinkedListAdapter { +public: + + WatchdogResetCommand() { + setLinks(); + } + +private: + WatchdogResetCommand(const WatchdogResetCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&magic); + } + SerializeElement cspPort = GOMSPACE::P60_PORT_GNDWDT_RESET; + SerializeElement querySize = 1; + /* Sending 0x78 to port 9 of a gomspace device resets the ground watchdog */ + SerializeElement magic = 0x78; +}; + + +/** + * @brief A serial linked list adapter implementation to generate ping + * commands for devices supporting the CSP protocol. This command can + * be sent to the CspComIF which will send out the ping request. + * + * @details A ping request simply sends back the received data provided by the + * data buffer. cspPort and querySize are only informations required + * by the CspComI and other than the data array not physically + * transmitted to the target device. + */ +class CspPingCommand : public SerialLinkedListAdapter { +public: + /** + * @brief Constructor + * + * @param querySize_ The size of bytes replied by the ping request. + * Amounts to the number of bytes send. + * @param data_ Pointer to data which should be sent to the device. + * All data will be sent back by the ping target. + */ + CspPingCommand(const uint8_t* data_, uint16_t querySize_) : + querySize(querySize_), data(data_, querySize_) { + setLinks(); + } + +private: + CspPingCommand(const CspPingCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&data); + } + SerializeElement cspPort = GOMSPACE::PING_PORT; + SerializeElement querySize; + SerializeElement> data; +}; + + +/** + * @brief A serial linked list adapter implementation of the gs_rparam_query_t + * struct defined in rparam.h. Can be used to build the message to set + * a parameter in gomspace devices. + * + * @note cspPort and querySize will not be sent with the CSP packet to the + * gomspace device but are required for the CspComIF to get the port + * and the size to query. + */ +class CspSetParamCommand : public SerialLinkedListAdapter { +public: + + static const uint8_t GS_HDR_LENGTH = 12; + + CspSetParamCommand(uint16_t querySize_, uint16_t payloadlength_, + uint16_t checksum_, uint16_t seq_, uint16_t total_, uint16_t addr_, + const uint8_t* parameter_, uint8_t parameterCount_) : + querySize(querySize_), payloadlength( + payloadlength_), checksum(checksum_), seq(seq_), total( + total_), addr(addr_), parameter(parameter_, parameterCount_) { + setLinks(); + } + +private: + CspSetParamCommand(const CspSetParamCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&action); + action.setNext(&tableId); + tableId.setNext(&payloadlength); + payloadlength.setNext(&checksum); + checksum.setNext(&seq); + seq.setNext(&total); + total.setNext(&addr); + addr.setNext(¶meter); + } + SerializeElement cspPort = GOMSPACE::PARAM_PORT; + /* Only a parameter will be set. No data will be queried with this command */ + SerializeElement querySize; + SerializeElement action = 0xFF; // param set + /* We will never set a parameter in a table other than the configuration + * table */ + SerializeElement tableId = 1; + SerializeElement payloadlength; + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; + SerializeElement> parameter; +}; + + +/** + * @brief This class can be used to generate a get param command for the + * gomspace devices which will be sent to the device communication + * interface object. + * + * @note cspPort and querySize only serve as information for the CspComIF + * and will not be transmitted physically to the target device. + */ +class CspGetParamCommand : public SerialLinkedListAdapter { +public: + /* The size of the header of a gomspace CSP packet. */ + static const uint8_t GS_HDR_LENGTH = 12; + + CspGetParamCommand(uint16_t querySize_, uint8_t tableId_, + uint16_t addresslength_, uint16_t checksum_, uint16_t seq_, + uint16_t total_, uint16_t addr_) : + querySize(querySize_), tableId(tableId_), addresslength( + addresslength_), checksum(checksum_), seq(seq_), total( + total_), addr(addr_) { + fixedValuesInit(); + setLinks(); + } + +private: + CspGetParamCommand(const CspGetParamCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&action); + action.setNext(&tableId); + tableId.setNext(&addresslength); + addresslength.setNext(&checksum); + checksum.setNext(&seq); + seq.setNext(&total); + total.setNext(&addr); + } + void fixedValuesInit(){ + cspPort.entry = GOMSPACE::PARAM_PORT; + } + SerializeElement cspPort; + SerializeElement querySize; // size of bytes to query + /* Following information will also be physically transmitted to the target + * device*/ + SerializeElement action = 0x00; // get param + SerializeElement tableId; + SerializeElement addresslength; // size of address + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; +}; + + +/** + * @brief This class can be used to deserialize replies from gomspace devices + * and extract the relevant data. + */ +class CspGetParamReply : public SerialLinkedListAdapter { +public: + /* The size of the header of a gomspace CSP packet. */ + static const uint8_t GS_HDR_LENGTH = 12; + /** + * @brief Constructor + * + * @param payloadBuffer Pointer to a buffer to store the payload data of + * the CSP packet. + * @param payloadBufferSz The size of the payload buffer where the payload + * data will be stored. + */ + CspGetParamReply(uint8_t* payloadBuffer_, uint8_t payloadBufferSz_) : + payload(payloadBuffer_, payloadBufferSz_) { + setLinks(); + } + + uint8_t getAction(){ + return action; + } + + uint8_t getTableId(){ + return tableId; + } + + uint16_t getLength(){ + return length; + } + + uint16_t getAddress(){ + return addr; + } + +private: + CspGetParamReply(const CspGetParamReply &reply); + void setLinks() { + setStart(&action); + action.setNext(&tableId); + tableId.setNext(&length); + length.setNext(&checksum); + checksum.setNext(&seq); + seq.setNext(&total); + total.setNext(&addr); + addr.setNext(&payload); + } + + SerializeElement action; + SerializeElement tableId; + SerializeElement length; //length of address field + payload data + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; + SerializeElement> payload; +}; + + +/** + * @brief This class generates telemetry packets containing data from + * CSP get-parameter-replies. + */ +class ParamReply : public SerialLinkedListAdapter { +public: + /** + * @brief Constructor + * + * @param payloadBuffer Pointer to a buffer to store the payload data of + * the CSP packet. + * @param payloadBufferSz The size of the payload buffer where the payload + * data will be stored. + */ + ParamReply(uint8_t action_, uint8_t tableId_, uint16_t addr_, + uint16_t payloadLength_, uint8_t* payloadBuffer_) : + action(action_), tableId(tableId_), addr(addr_), payloadLength( + payloadLength_), payload(payloadBuffer_, payloadLength) { + setLinks(); + } + +private: + ParamReply(const CspGetParamReply &reply); + void setLinks() { + setStart(&action); + action.setNext(&tableId); + tableId.setNext(&addr); + addr.setNext(&payloadLength); + payloadLength.setNext(&payload); + } + SerializeElement action; + SerializeElement tableId; + SerializeElement addr; + SerializeElement payloadLength; + SerializeElement> payload; +}; + +/** + * @brief This class helps to unpack information from an action message + * to set a parameter in gomspace devices. The action message can be + * for example received from the PUS Service 8. + */ +class SetParamMessageUnpacker: public SerialLinkedListAdapter { +public: + /* Largest parameter is a uint32_t */ + static const uint32_t MAX_SIZE = 4; + + SetParamMessageUnpacker() { + setLinks(); + } + + uint16_t getAddress() { + return address; + } + + uint8_t* getParameter() { + return parameter->front(); + } + + uint8_t getParameterSize(){ + return parameter->size; + } + +private: + void setLinks() { + setStart(&address); + address.setNext(¶meter); + } + SetParamMessageUnpacker(const SetParamMessageUnpacker &message); + SerializeElement address; + SerializeElement> parameter; +}; + + +/** + * @brief This class helps to unpack information from an action message + * to get a parameter from gomspace devices. The action message can be + * for example received from the PUS Service 8. + */ +class GetParamMessageUnpacker: public SerialLinkedListAdapter { +public: + + GetParamMessageUnpacker() { + setLinks(); + } + + uint8_t getTableId() { + return tableId; + } + + uint16_t getAddress() { + return address; + } + + uint8_t getParameterSize(){ + return parameterSize; + } + + +private: + GetParamMessageUnpacker(const GetParamMessageUnpacker &message); + void setLinks() { + setStart(&tableId); + tableId.setNext(&address); + address.setNext(¶meterSize); + } + SerializeElement tableId; + SerializeElement address; //The memory address offset within the table + /* The size of the requested value (e.g. temperature is a uint16_t value) */ + SerializeElement parameterSize; +}; + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ */ diff --git a/mission/devices/devicedefinitions/GomspaceDefinitions.h b/mission/devices/devicedefinitions/GomspaceDefinitions.h new file mode 100644 index 00000000..a0c0cacd --- /dev/null +++ b/mission/devices/devicedefinitions/GomspaceDefinitions.h @@ -0,0 +1,39 @@ +/* + * GomspaceDefinitions.h + * + * @brief This file holds all definitions specific for devices from gomspace. + * @date 20.12.2020 + * @author J. Meier + */ + +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ + + +namespace P60Dock{ + /* The maximum size of a reply from the P60 dock. Maximum size is reached + * when retrieving the full parameter configuration table. 412 bytes of + * payload data and 12 bytes of CSP header data. */ + static const uint16_t MAX_REPLY_LENGTH = 424; + + static const uint16_t MAX_CONFIGTABLE_ADDRESS = 408; + static const uint16_t MAX_HKTABLE_ADDRESS = 187; +} + + +namespace PDU{ + /* When retrieving full configuration parameter table */ + static const uint16_t MAX_REPLY_LENGTH = 318; + static const uint16_t MAX_CONFIGTABLE_ADDRESS = 316; + static const uint16_t MAX_HKTABLE_ADDRESS = 140; +} + + +namespace ACU{ + /* When receiving full houskeeping (telemetry) table */ + static const uint16_t MAX_REPLY_LENGTH = 124; + static const uint16_t MAX_CONFIGTABLE_ADDRESS = 26; + static const uint16_t MAX_HKTABLE_ADDRESS = 120; +} + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ */ diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp deleted file mode 100644 index 41696870..00000000 --- a/test/testtasks/P60DockTestTask.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * P60DockTestTask.cpp - * - * Created on: 18.11.2020 - * Author: Jakob Meier - */ - -#include - -#include -#include "P60DockTestTask.h" -#include "gomspace/include/rparam.h" - -P60DockTestTask::P60DockTestTask(object_id_t objectId_): -SystemObject(objectId_){ - if(initializeCSPStack() != HasReturnvaluesIF::RETURN_OK){ - sif::error << "P60DockTestTask creation failed" << std::endl; - } -} - - -ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { - - if(sendPacket() != HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t P60DockTestTask::sendPacket(void){ - -// char *msg = "HELLO"; -// /* Get packet buffer for data */ -// csp_packet_t *packet = csp_buffer_get(strlen(msg)); -// if (packet == NULL) { -// /* Could not get buffer element */ -// sif::error("Failed to get buffer element\\n"); -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// -// /* Connect P60 Dock */ -// csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, c, CSP_PING, -// 1000, CSP_O_NONE); -// -// if (conn == NULL) { -// /* Connect failed */ -// sif::error("Connection failed\\n"); -// /* Remember to free packet buffer */ -// csp_buffer_free(packet); -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// -// /* Copy message to packet */ -// strcpy(packet->data, msg); -// /* Set packet length */ -// packet->length = strlen(msg); -// -// /* Send packet */ -// if (!csp_send(conn, packet, 1000)) { -// /* Send failed */ -// sif::error("Send failed\\n"); -// csp_buffer_free(packet); -// } -// /* Close connection */ -// csp_close(conn); - - uint32_t timeout = 1000; - unsigned int pingSize = 100; // 100 bytes - uint32_t replyTime = csp_ping(p60dockAddress, timeout, pingSize, CSP_O_NONE); - sif::info << "Ping address: " << p60dockAddress << ", reply after " - << replyTime << "ms" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t P60DockTestTask::getParameterTable(unit8_t tableId){ - - gs_rparam_query_t * query; - csp_packet_t * request = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0)); - if (request == NULL) { - sif::error << "Failed to get buffer for csp packet" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32); - if (!conn) { - csp_buffer_free(request); - sif::error << "CSP connection failure" << sif::error << std::endl; - return HasReturnvaluesIF::RETURN_OK; - } - - query = (gs_rparam_query_t *) request->data; - query->action = RPARAM_GET; - query->table_id = table_id; - query->length = 0; // == get full table - query->checksum = csp_hton16(checksum); - query->seq = 0; - query->total = 0; - - request->length = RPARAM_QUERY_LENGTH(query, 0); - if (!csp_send(conn, request, timeout_ms)) { - csp_buffer_free(request); - csp_close(conn); - sif::error << "CSP failed to send packet" << sif::error; - return HasReturnvaluesIF::RETURN_FAILED; - } - - csp_packet_t * reply; - unsigned int total_bytes = 0; - while ((reply = csp_read(conn, timeout_ms)) != NULL) { - - /* We have a reply */ - query = (void *) reply->data; - const uint16_t qlength = csp_ntoh16(query->length); - total_bytes += qlength; - const uint16_t seq = csp_ntoh16(query->seq); - const uint16_t total = csp_ntoh16(query->total); - - if (query->action == RPARAM_REPLY) { - error = gs_param_deserialize(tinst, query->payload.packed, qlength, F_FROM_BIG_ENDIAN); - } - csp_buffer_free(reply); - - if (error || (seq >= total)) { - break; - } - } - - if (reply == NULL) { - error = GS_ERROR_TIMEOUT; - } - - if ((error == GS_OK) && (expected_bytes != total_bytes)) { - log_warning("%s: expected %u != received %u bytes", __FUNCTION__, expected_bytes, total_bytes); - error = GS_ERROR_DATA; - } - - csp_close(conn); - - return error; -} - - -ReturnValue_t P60DockTestTask::initializeCSPStack(void){ - /* Init CSP and CSP buffer system */ - if (csp_init(cspAddress) != CSP_ERR_NONE - || csp_buffer_init(10, 300) != CSP_ERR_NONE) { - sif::error << "Failed to init CSP\r\n" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - csp_iface_t *csp_if_ptr = &csp_if; - csp_if_ptr = csp_can_socketcan_init("can0", bitrate, promisc); - - /* Set default route and start router */ - int result = csp_rtable_set(CSP_DEFAULT_ROUTE, 0, csp_if_ptr, CSP_NODE_MAC); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to add can interface to router table" - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - result = csp_route_start_task(500, 0); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to start route task" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -P60DockTestTask::~P60DockTestTask() { - // TODO Auto-generated destructor stub -} - diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h deleted file mode 100644 index 4222c017..00000000 --- a/test/testtasks/P60DockTestTask.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * P60DockTestTask.h - * - * Created on: 18.11.2020 - * Author: jakob - */ - -#ifndef TEST_TESTTASKS_P60DOCKTESTTASK_H_ -#define TEST_TESTTASKS_P60DOCKTESTTASK_H_ - -#include -#include -#include - -extern "C" { -#include -#include -} - - -class P60DockTestTask: public SystemObject, - public ExecutableObjectIF, - public HasReturnvaluesIF { -public: - P60DockTestTask(object_id_t objectId_); - virtual ~P60DockTestTask(); - - virtual ReturnValue_t performOperation(uint8_t operationCode = 0); - -private: - /* Interface struct for csp protocol stack */ - csp_iface_t csp_if; - uint8_t p60dockAddress = 4; - uint8_t CSP_PING = 1; - uint8_t cspAddress = 1; - const char* canIf = "can0"; - int bitrate = 1000; // bitrate of can - int promisc = 0; // set to 0 to enable filter mode - - ReturnValue_t sendPacket(void); - ReturnValue_t initializeCSPStack(void); - ReturnValue_t getParameterTable(unit8_t tableId); - -}; - -#endif /* TEST_TESTTASKS_P60DOCKTESTTASK_H_ */ diff --git a/tmtc b/tmtc index 3fc71f90..9342f773 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 3fc71f9094e8fb670942f0c29a9dea0b6e03d17f +Subproject commit 9342f773115856843b167225236b04a061602174