From 5b12974a7f01a94c40552402b66b01bf8ec0e214 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 21 Sep 2019 11:58:51 +0200 Subject: [PATCH] fix 'hf iclass sim': * chg to reader command decoder in iso15693.c (require no modulation before SOF) * add 'has_been_low_for' logic to hi_simulate.v (same as in other FPGA modes, default to "no modulation") * add simulation of chip status (IDLE, ACTIVE, SELECTED, HALTED) * check ACSN on SELECT * add simulation of RESELECT * always check length of reader commands * fix printing of NR, MAC in sim 2 mode * fix response length to CHECK command --- armsrc/iclass.c | 286 ++++++++++++++++++++++++------------------- armsrc/iso15693.c | 25 ++-- client/cmdhficlass.c | 56 ++++++--- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_simulate.v | 24 +++- 5 files changed, 236 insertions(+), 155 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 66238a10..23701540 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -777,8 +777,6 @@ static void AppendCrc(uint8_t *data, int len) { /** * @brief Does the actual simulation - * @param csn - csn to use - * @param breakAfterMacReceived if true, returns after reader MAC has been received. */ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { @@ -919,6 +917,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { LED_A_ON(); bool buttonPressed = false; + enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; + while (!exitLoop) { WDT_HIT(); LED_B_OFF(); @@ -943,162 +943,193 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = NULL; trace_data_size = 0; - if (receivedCmd[0] == ICLASS_CMD_ACTALL) { - // Reader in anticollission phase - modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; - trace_data = sof_data; - trace_data_size = sizeof(sof_data); + if (receivedCmd[0] == ICLASS_CMD_ACTALL && len == 1) { + // Reader in anticollision phase + if (chip_state != HALTED) { + modulated_response = resp_sof; + modulated_response_size = resp_sof_Len; + trace_data = sof_data; + trace_data_size = sizeof(sof_data); + chip_state = ACTIVATED; + } } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // identify - // Reader asks for anticollission CSN - modulated_response = resp_anticoll; - modulated_response_size = resp_anticoll_len; - trace_data = anticoll_data; - trace_data_size = sizeof(anticoll_data); + // Reader asks for anticollision CSN + if (chip_state == SELECTED || chip_state == ACTIVATED) { + modulated_response = resp_anticoll; + modulated_response_size = resp_anticoll_len; + trace_data = anticoll_data; + trace_data_size = sizeof(anticoll_data); + } + + } else if (receivedCmd[0] == ICLASS_CMD_SELECT && len == 9) { + // Reader selects anticollision CSN. + // Tag sends the corresponding real CSN + if (chip_state == ACTIVATED || chip_state == SELECTED) { + if (!memcmp(receivedCmd+1, anticoll_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } else { + chip_state = IDLE; + } + } else if (chip_state == HALTED) { + // RESELECT with CSN + if (!memcmp(receivedCmd+1, csn_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } + } } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block uint16_t blockNo = receivedCmd[1]; - if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - // provide defaults for blocks 0 ... 5 - switch (blockNo) { - case 0: // csn (block 00) - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - break; - case 1: // configuration (block 01) - modulated_response = resp_conf; - modulated_response_size = resp_conf_len; - trace_data = conf_data; - trace_data_size = sizeof(conf_data); - break; - case 2: // e-purse (block 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - break; - case 3: - case 4: // Kd, Kd, always respond with 0xff bytes + if (chip_state == SELECTED) { + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + // provide defaults for blocks 0 ... 5 + switch (blockNo) { + case 0: // csn (block 00) + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + break; + case 1: // configuration (block 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_data; + trace_data_size = sizeof(conf_data); + break; + case 2: // e-purse (block 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } + break; + case 3: + case 4: // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + break; + case 5: // Application Issuer Area (block 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + break; + // default: don't respond + } + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { + if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes modulated_response = resp_ff; modulated_response_size = resp_ff_len; trace_data = ff_data; trace_data_size = sizeof(ff_data); - break; - case 5: // Application Issuer Area (block 05) - modulated_response = resp_aia; - modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - break; - // default: don't respond + } else { // use data from emulator memory + memcpy(data_generic_trace, emulator + 8*blockNo, 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } } - } else if (simulationMode == ICLASS_SIM_MODE_FULL) { - if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes - modulated_response = resp_ff; - modulated_response_size = resp_ff_len; - trace_data = ff_data; - trace_data_size = sizeof(ff_data); - } else { // use data from emulator memory - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); - AppendCrc(data_generic_trace, 8); + } + + } else if ((receivedCmd[0] == ICLASS_CMD_READCHECK_KD + || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && len == 2) { + // Read e-purse (88 02 || 18 02) + if (chip_state == SELECTED) { + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + LED_B_ON(); + } + + } else if (receivedCmd[0] == ICLASS_CMD_CHECK && len == 9) { + // Reader random and reader MAC!!! + if (chip_state == SELECTED) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { + //NR, from reader, is in receivedCmd+1 + opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); trace_data = data_generic_trace; - trace_data_size = 10; + trace_data_size = 4; CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; + //exitLoop = true; + } else { // Not fullsim, we don't respond + // We do not know what to answer, so lets keep quiet + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + if (reader_mac_buf != NULL) { + // save NR and MAC for sim 2,4 + memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); + } + exitLoop = true; + } } } - } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { - // Reader selects anticollission CSN. - // Tag sends the corresponding real CSN - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - - } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD - || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) { - // Read e-purse (88 02 || 18 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - LED_B_ON(); + } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { + if (chip_state == SELECTED) { + // Reader ends the session + chip_state = HALTED; + } - } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { - // Reader random and reader MAC!!! - if (simulationMode == ICLASS_SIM_MODE_FULL) { - //NR, from reader, is in receivedCmd+1 - opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); + } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 + //Read 4 blocks + if (chip_state == SELECTED) { + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); + AppendCrc(data_generic_trace, 8 * 4); trace_data = data_generic_trace; - trace_data_size = 4; + trace_data_size = 8 * 4 + 2; CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; - //exitLoop = true; - } else { // Not fullsim, we don't respond - // We do not know what to answer, so lets keep quiet - if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - if (reader_mac_buf != NULL) { - // save NR and MAC for sim 2,4 - memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); - } - exitLoop = true; - } } - } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { - // Reader ends the session - modulated_response = resp_sof; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; - - } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 - //Read block - //Take the data... - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); - AppendCrc(data_generic_trace, 8 * 4); - trace_data = data_generic_trace; - trace_data_size = 8 * 4 + 2; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - - } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == ICLASS_SIM_MODE_FULL) { + } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { // Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state // We're expected to respond with the data+crc, exactly what's already in the receivedCmd // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b - memcpy(data_generic_trace, receivedCmd + 2, 8); - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - - } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL) { + if (chip_state == SELECTED) { + memcpy(data_generic_trace, receivedCmd + 2, 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } + + } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // Pagesel - // Pagesel enables to select a page in the selected chip memory and return its configuration block - // Chips with a single page will not answer to this command - // It appears we're fine ignoring this. - // Otherwise, we should answer 8bytes (block) + 2bytes CRC + if (chip_state == SELECTED) { + // Pagesel enables to select a page in the selected chip memory and return its configuration block + // Chips with a single page will not answer to this command + // It appears we're fine ignoring this. + // Otherwise, we should answer 8bytes (block) + 2bytes CRC + } } else { - // Never seen this command before + // don't know how to handle this command char debug_message[250]; // should be enough sprintf(debug_message, "Unhandled command (len = %d) received from reader:", len); for (int i = 0; i < len && strlen(debug_message) < sizeof(debug_message) - 3 - 1; i++) { @@ -1187,8 +1218,9 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3], datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]); Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x", - datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], - datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); + mac_responses[i*16+ 8], mac_responses[i*16+ 9], mac_responses[i*16+10], mac_responses[i*16+11], + mac_responses[i*16+12], mac_responses[i*16+13], mac_responses[i*16+14], mac_responses[i*16+15]); + SpinDelay(100); // give the reader some time to prepare for next CSN } cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); } else if (simType == ICLASS_SIM_MODE_FULL) { diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 4b4577e7..f33e0156 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -671,6 +671,7 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim typedef struct DecodeReader { enum { STATE_READER_UNSYNCD, + STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, @@ -714,6 +715,13 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin { switch (DecodeReader->state) { case STATE_READER_UNSYNCD: + // wait for unmodulated carrier + if (bit) { + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } + break; + + case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: if (!bit) { // we went low, so this could be the beginning of a SOF DecodeReader->posCount = 1; @@ -725,7 +733,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin DecodeReader->posCount++; if (bit) { // detected rising edge if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // SOF DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; } @@ -748,13 +756,13 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) DecodeReaderReset(DecodeReader); - } else { // SOF for 1 out of 4 coding + } else { // SOF for 1 out of 256 coding DecodeReader->Coding = CODING_1_OUT_OF_256; DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } } else { if (DecodeReader->posCount > 29) { // stayed high for too long - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // do nothing, keep waiting } @@ -766,7 +774,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin if (bit) { // detected rising edge if (DecodeReader->Coding == CODING_1_OUT_OF_256) { if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { DecodeReader->posCount = 1; DecodeReader->bitCount = 0; @@ -777,21 +785,22 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin } } else { // CODING_1_OUT_OF_4 if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { + DecodeReader->posCount = 1; DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; } } } else { if (DecodeReader->Coding == CODING_1_OUT_OF_256) { if (DecodeReader->posCount > 34) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } } else { // CODING_1_OUT_OF_4 if (DecodeReader->posCount > 26) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } @@ -802,7 +811,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: DecodeReader->posCount++; if (bit) { - if (DecodeReader->posCount == 33) { + if (DecodeReader->posCount == 9) { DecodeReader->posCount = 1; DecodeReader->bitCount = 0; DecodeReader->byteCount = 0; diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index ee0dd16e..48b62b17 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -100,7 +100,46 @@ int usage_hf_iclass_sim(void) { return 0; } +// the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult, +// and Milosch Meriac. Dismantling iClass and iClass Elite. #define NUM_CSNS 15 +static uint8_t csns[8 * NUM_CSNS] = { + 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; + + +// pre-defined 9 CSNs by iceman. +// only one csn depend on several others. +// six depends only on the first csn, (0,1, 0x45) + +// #define NUM_CSNS 9 +// static uint8_t csns[8 * NUM_CSNS] = { + // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, + // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0, + // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0, + // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0, + // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0, + // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0, + // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0, + // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 + // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 +// }; + + int CmdHFiClassSim(const char *Cmd) { uint8_t simType = 0; uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -123,23 +162,6 @@ int CmdHFiClassSim(const char *Cmd) { UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, NUM_CSNS}}; UsbCommand resp = {0}; - uint8_t csns[8 * NUM_CSNS] = { - 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; - memcpy(c.d.asBytes, csns, 8 * NUM_CSNS); SendCommand(&c); diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 70c7909aeb328809bb41a63c389b1db42501aceb..1bd3c416fe728c26ee204ede9bc882c8f87486c8 100644 GIT binary patch literal 42175 zcma&Pe|!_ynJ)g$nXwsbWNWZZ>JpNUWkZA`+d`&5h>;Jr+f@=8oP2Zl!|vw0UqNZs z+oi4B?cFc!cJDow1;`kJAhdN-Zg+5K>ZG(4hVUzCGB|D`ek8alZArpr1$Bs%($q;v zY6F4$9Lbj4KlXmE_Vd}D$g`uFIp=+!_j%su9H_`Mmi-?hWi^#O)bS6i|G)N!YCG1g z{^FO`)_wJhYiSL+g8$qQ_?NFQ2n6VhWCQ~X?x+vkQ6F4DYpG~K!_q)->1P+xmx%Us z+`#9lNB`SH0TK!k%?KzF`G56*Vksn=Y6IlR|E9^m7X=94=l@#?5T`b({vwsiZ~v>0 zCNh8dKcAD3=O`?5=706SMCK3wH|PAHe=B>P|C@8l{;OM&-)osaUNX& zRZt-*f~x2iXGWlDDDzxS!F9SO_FL|h8W1nD2Fo+p6`~va7Np%@Ry(LeUPzel(P5w0 z(&OxL-tE*xj4gM2=}>u1TEAFoYXNyqyxg#Y4tFk86R%$r3oI=+=-U+>^Kh! zT*so5Y^hUhtEOhjb5aF9{JP)K53=_xwauG0K2=&tKPSu4Z8kt$o|7(EK}p+BK3}Pm z=Kv-yKL_gOfh^cg#EgAF_7~Fn=mN>oC2NZrbm8>z+H=i_|dS9_>0oC#XSSMtwW`TVYDmxD}!q zooYHVzAB`9VqN%#o+FP?UquMxqnjf%L7}xP9#sqZ@mR3Uy|e6+c!z?`eqpfeZwYNJ z9pV1<`mJmp>rPv3@$az_dXl`{XSysh<#j3ws_7Z4j)#-Y)zv+wx6PNpIo)J&J;4gI zW1(vr?Mu|jZ#4YL%XJgy?6&OXzEZ|AX@m|JM`%3{kzcfU?Nt8&xi@!>Qi=vi-jGT`%&->H7xfGw_K)|X+L)ls|)Ek z1)MoM)WYm|EiuzFcF3?_DRWSc zd(QsWtUa{P@~-;3?edW=JXbHPHXkK#n|$`{SlH!zXd*oDbx&{E+mYkpV7uOHRJR|e z0lW>DFB@MzLhMi|;^|c{n(wnv+tKH+br>Y0!P@b3H zkegau+4%BlK8$hI4r7#6(8H0Zh4EhLSvpEyp{JQEI~KkI&iALS;hTfAJ&7)|2aScy zK~#DjJ>YUp#g|D>^GY%vY%Zs5G*9}4bxL2t^z69z z&)RLBw1ZopxkLFdG zC6X=aY{tQ)>F7Jw635$a zJj*WjzQHWVmt+<<;t#|Ty5o0fV7s&zRg>xq3i*!mNi~0f>$|Tv# zF=;O;k5Hc+)5-WEy`9D|Tf#yek<*5IYz)e2`e(;KW>7Z1>|4g^8a0u}QOD?;@*u5V z)?{MzjLjG=%*=U58AFC_s&+f-2Xu<=L^?-&y-A;1yCQXaAUj@y-UaT|g?&4Br0w`I zuXVS$dme2T-cdY-rDdKyULa>(U05$;X+_MmXo=;DA-BwPDy%~96n^zv&nREz6^YVI z6d&?3m%Vw9)g!z^ahnCQFl@fu3JEs1W{YflL`)h$anR`wv$+oLn z)7ZAx)Q{*gEfyYbtOI^ErSX8{+4$n-5xN==a;>+j#vBia67DC|t;ib~(^wwAEdD(A zp4E4;I`c>*)a!eK)mdG@Q^QujksS+(U;A6D<3$uDjD>sEUFA6H#A`B$t)GgoTj`LP zYZt9zH`BqWZ*9@vuu|G2YSTuzG@QLo7;*g}Euz{Ts@6HC_*-w;r;6yYaO05YyXyT+ zP7UI>Jj-wBcZ!l>4BK_`wAQ_kLBZ%a7{MHVy(RHWxWzqwz(nYnJE8iJghS2@p}w0P zukg$m-(=M~dIy_B8zn%S0J2RI(KvfG`<@;89?+_GbJP};$?k$@qfXnUv$0U%M znAkhi9DeE}21vgSN~ z0j-wLPOw@!LUr6q0^_=IVDx&Y@N3oxqM+vUb>%Hj@H<$DyL*kbbld@2CDisw{8IKv zv|3ZV>k$+cdZ^h`s-B`FR%k8G$>UdIoB&%f!?IG#LyB9JSuB+u(<%Ha_%uDot1#;9 z4)fveS_xY<+U9tjFe2*RCYN)=S8x~Yi+hIwTgB{g$A88Z@@mu-&CIb${IZof^mI|B zb59$)iGEDAqUM`yPBrH9km2;TXRp(*-%8iTf;4a^L~jefRWfdr&`V<3sHa`c;n!Ze zBJVJPdH4o^tTw6sQDpMGJ%wLX@FtxSO_uv?%Ob#E!-)TESra?mSv9gEr8s6L|Mbt? zMQ6-f(*IkuoFAY{cX1n=WB!hAcXX~km7ViMy)xpM-sXCM4pF77k>=o=xsDz|R=4D{ zTji%{JNX$(k!DJAn~F@AC-TUSdmX)x#j|;}f7Zhm;=R&+;GTBv844osSv{Q;i&IF9 z?`D5X&^vU6hiKal)gHP!5=yLG2rRftOC1j?#wq-|Oeim_@$3zBO$0^Vm>Lpqh$aV! zmcy@q5KnFP28}t)OUVlBaPi?%H|r5~4hGJi!mm1H{ys8#OR8}{UR&>-?WZ4DIHwaa z$mMhCnwxgx5e>5>hMZ~Be3Q9Z7p--4Vo^n&LR7pKxg{VoKsAjkLE%fNe)b0P7&1Sp znN#dr#t=<_tzosp%mCS#dQN^L^Wo@>%vd-Dz-7P|zUjc97E~ACrGA@GZ={PI0A%JI zVP2ra2&sFb&0abZLs__kRa-xwJ^z$Tuypo4OZ)=nl0i|9`10{0YW9i8Eo-od*o7(l zvaQ3qml>T=%Q~Xhc;m=F^b@LaT%CiH{EN?epI_(u%Z*d&x3rJijz+d_QA_wADCm5l zR~??huRgl2-(-2>W#cp?Bsg5M$M7Tb2OakT z!_+MKf>H%u+N^nXU9kDQJHkXb$>yTKt2$OZz=GMaNEh78Iyq{IgKQ&3wLY%fg+;=U zwS>iT{OeY}K~$#o^@BHA8#}9Z>!YP1>cThOJ^%-ozXkrqk(N{LKv|4MDKO*@s5*Or z0**V7<6pq9k7j~xy|13(*Aw+(#+Y)BZkSCk;+q_PUCKU1QuUKdAiaySOZp$|V9G71 zW(vQypdtc`3^2DDrAlFN?{{dE&pM%VRyu`WKLo;7rsM0`t;+X0E7Qh$_9p!}xqB3~ zUjPFs?-}tWuM-Zi5{fF`v&KH}3VK{#`8ixCAkUHbHE1WrUI|;T)BavrLhyHKK=>~i zOQ-NlvaJkSrRkasG@(jippiTq^8D*Xaa;r=?p{?BC^I;4xf+=k2amBFemz9p!n<0Z z$>!?a-vr45fwE+N)^{RyOnE;NzqYnjwd!ZsXKAbaQ?j&LbhFGk8>ix{oHl5c%k>8s z4#?l?o7r65+-dp4xbkFt9WGwOQewbb5jVW-R98q&q)Kw|6#j>MewM8ddv5`L@lad+ zF7+)s(%RJSxuSj?n^+RMciZdgLxq{xsVMkZd?Fg!-DlNB;^qDZUYt@4aXXf}9@M{9U?n@ZexQzh!C(2@Y&jZ~5m@&n_GWgZV!Bd84LV1pRwyPru>PEh8 zI)3pKEh2YRwJOK;AR!T@tHDpnExJx*_MXVrhqiJnZECIjmEIO@!%L_XH+K|X1CY&46?L%D z>~;EeiB_m`m$>fN4v2k8&v(k+WT(>&X?IwCm&vI?`Yn4U?Q)RAZAmbNCs~C&&qKqw z`APmI@#{~>e%r>Y7SX+8f$d%oKs@at$C=lO6H8^| zs~?)xd1MJs(&eL+Xh`}y%Dx1ivfuG1^Z0d%;c?`19jDhKndcf2nI}Dv$FEP2-WyWx zG35xIN;E}1V`?KZ$$*1-=(J{Hxl>z5hg06P{zG;<0u5zGveeCgLf&J=iD-HXzx;GW zfNdRSd#%kR&nc|7dT`H@kxj*yn--Am_)NA1gX{0SN7hj?ZvYDh6*&~ZuXS=BItcT< zv^mR#Eq0n39Jj4H+4!<=xeR*p8NO2f_ci*Az&)Rts^_Qp7x3#$XA|k8?6P^v+8==I z6QpxundMofPVq1EEwjj1C-i~7w|Tc?g?$1=B60%Z&0E>`94~mmPAGl>wlz{JxTVZC z3yBisCqu9){xvg7aZwl5lirI6PlTS-50QUNBbw)5qx5=bs0~r@d+O#vaj#_%ofV<& zo{BvGdRD(io{nu-zBoefS2P_%&b&sSm`%cS*2v-4&yX`AL+w@HQc`?CxRa{XWP(ZH zdk(++7zS^L{w$>`U*}#2^=h3!ybE_{UOx<*Nm{e!E{ngYi&l#iceI&y;O6Hq%;VRm z^k0Zbr06T`x3nQq+0mV1|3d>hbm;2~pG2Tf#%|X`b$kb5YURvE>5qb?3$(@ z-tsJ6GoNoQNe8br<8gRNo3Trd7YCQg;TLKxEf{t`rS6ewM|f=2(ynNY5(jhmwbMF4 z7SxOj<>m%$zGFmC`yB%R@^!d!`1Kea5OXg;;oPL)R&8S(objNjPh%!b!>@t1>R0v8 zmby1|g?(vb36q+zKMm~8;}>0TJDBkAQ6HmMQo*Rl?()ehH;Q?f!><=G7E4W!sFM6x z0+|7=Nh&!`9>3lb$m(hLfv$`CaV^;Hc@+5dP6og7{Och?k=Lg0j9z5txwiwlL=5xC zFO#`FiC@ZGd~;zHrq)OdL)nHTvygtu>LdDaUOz0*x`72is}b#S+TD83ee3{$taz<{ z-*o(PC}{aL^@5#xGH81Cs6KO)hfM!aUO#-BJ`vA#%y_KqGQCBicF$7ec@UO%&(R$J zQZCVJtbrp=7izx*UU=G!YDDhhHg}tv<6ol)2Z>fvqsIY4#sZ?@zr=L@wH>pr!erH~ zi&@KW29SYd&6Cfb<6rV^c*F5oUg)bFv=l%_M-;CNv}ye7wFqEqr!lws7$4wBdevZC z3%T3O^RJ)r2?wy1tit11nZ$Sr_Z;H&)A374w&jkNooA^CWW$Y!FGQTaB4*_HmrrbF zU)!ng0hN827VTUyqW+Uq6m9)2=E}x}uV5whFn{3F0d`73u{1niu;tDG*<<XF-mY!$`YnKLUv+U<{cHZQ-H`UL z%JZ)u38;mlBnDgt?ZSjqFNqJ75TA};sDwp><(^RFbpU^7p@CeFH?4J#syY3zS5m5S z{Q3j5iB}HmYuRw*Al0wXFQ{M6)@(#OBhR;G(CV`F@4S)&+J*^2A`f#0>Ls7cg1+$# zS=C@At-eRdYD2<5Mgsr^y^w{od9{DmlenLtSl8M0lKyKaIfOiR0Tq78@%O7W+20Zb z6gC?Z9>Ler9~|J9t-hmQkps88EXTjDS~nO}{j~a#`3g1AmiN`g5P5(X=^TDhL_9-l zY+WF?{AAE;>T}eu;C|3|=w~_n^3gNQ3);m-isHg6^klQ&f+o!Mcr=G!y0RaS=+jwD zv5`)ZE>_?=Hpi3Z@T(n}txq6Jj3AE%XhjnI;tHXz6M6g^qyL{RlUd>b@T-aHhmq&6 zQMXhfcvY{vTqoRh&`>09y+zjC+uVL<6~xsgwOL2jmSZUj+B;)lmQ=$k;sU z-++jVP2pFn;FR`^R!v1V6Z9Bvz9+%BtPh<}m$5ZU_P1v4r5+8}v7y)Xpx~qgTSHF@ z<`gBGJF;WJ(f|5TTWA$Gs*lsz2ZF;MztK!7XW&ysd(>S2>sh*CH__KVP%{K`*mJ(? zS@~R6UApWrMdaL&{jaMw*yxYd%GB#^q2CrCQ1>|RL;@R&lT-M0wxE%o;dSRQIwkb$ zn14(^+FS=%>61ikAR8B>1?y0G`h~vGwUtDq+NuGg#;yAT$SsrnD~bB>Y4NqRKEZC~ zJHJ=k?+Qcc*p!%Gt%q3-zuf$NY9x21+DQ)5MTw=x%?swzRzKzW*DnH}n9F$mYS83s ztSN=5H4Of>xV41m@C)x}f*J+rn_mZ=Bp1>Sr3jVG!LCXDFopW?X~-;kN9i24iFOOb zjy$MxpeRo2hk|}6o)-1zD^`GMZWF5kwcfw4j)~P{`g%5{A8My)f7Cx5p99$H;uZ+q zU@;0sRA@_Zoq&ALqXqqRCEjGO7`=T7z4FR}1OE4v_4KgVpY;DIuODXkSD`1?1=xy& zXeD|j`nVaYfW9%+|Dq8-Awpr~`MH2C(1CsI=WSe7nX zrM_A58?hi#8&+?nKS!6P|587EM{5+tw(78VSx}S&)Cd8{oK3sc!P1DlA1e5mUKV#m zfL5jSQglJuzuuV5UQRr|7Bys!f9<5-n4cBC2V8T?V^ryatWi!l7&g{S=U*H2`5Y0~ z$RDOEf%2&VHPTn8CsLT_U&?l2MRhGo!A`fukv2;dfqKlq#MLtMS@N$JM2*;zRBNq4 z)T{2Ks%e9Eoj}q4uEuf4BuSp_fTRHwEdbpSF5zT1< zQ-tmk%_G+4`4N)mOvP75KTH<|09((1h#7%3?QAm=v(K8+=OzC_y-K)enH+*jrn!*e z?>6+qOnlk5T%(WZdG6@|Y-QRgV^!Dm%T!N2={$aoRewLQz=Cf4fp%InMOK_`IS76# zbx|Y7zy3hm%Dj$|qzfpP>HuWO^V|4sX??gf$G;r*h-Kmb$8@O6Uq?t6d#KAq^JQB9 z%NAgo!Z=Wx#^cmk`r#;Y3(a#V;hOA!!M~xsK?CPKTdID);$&On8VE|U=9APE@elXV zlzs^OqNX9wsg^PAe|CbN46E1a4O-Uf8SBdNucx#>SVy^kBgXVfIP?Jg8-C2yATQaO z*AKPUZE5dCJr*6Lqr7CfQ4Y7j^Tbx`$(EdcxEu;6tP4xnD}4X3d(>FOw1P*79&#OV z<@#Tmt3=%o*mP$UO>M$4?C!GkI@I@cRT@AqYuph zF9{g;GdX?G|LUb170?eaw~Wzs1w}>&i~%>wm#r>-y(P!LE{QiHLGkbb^+z(na*t2- zn^!ACgIjh~<@nbwzDa-FLCBc=Ak}h%d%?f%@;kn-PuCB>Z&!{1YIj%%MeShRUGFka={Cb%d^WtH6a=r!F@+45)PGCN7IcMbb!!*hqpjAKAu%j9R z1V37Scz2zNLNTWw4pArAR#9nm2u%~T>Js3d`*eSsUS2azKLr1hXb!p0@R$^Jl^Mi zOLfVsNQ?`k+vQ8>jZrt>pF-P9W3R~SeMwQZ>+UT7vXnW<(es5q&gSTgWgB;x?eZP6 zD`|GyRDAjLo9IPxr|n;_&Za|&+O%ht@h06!2drYBdUrOy^jl)=3Z5PLaFjCiq`YUX z0De(z!Wb-!$ot{5uFz?**hW75Ee;ye+Nip??S?={Y`n^x)DJ(sOV_MQ&FElf^dEDO ztZ%3f@I$gAc39_sTXUl`8DX{x{v>S6sBwuCymhft;xOPivyuER*O4~Wa_q`|+s zIG(~PEun^j>g8xEZJ{nvC*Sh;RD9ivZ@!q0x0jZ(SZr>;9xi;fJSJ)*H-}j&dmZ$@ z*b7>~aR&@H8>0gp1S(E1@J7CpT3*c#D!*kH{ZCX5p0TnqdVA&_-5#gvj3myn)4$5` zuYybBWCU%mc$rly`PY{Cr>bcQg+}xID?D?{(68G+>)gY?Jcs01xH<|e=#YYLa%75s zIrPI*Gwe!0Z7HjaiTT#%u&a~~bk|z?dYa;2<)?MHp`3e`G`qFO6>HelDDf-2E`^sc z#lL3l5O5nlyK)r6bb^j1{Cgj%(XKRyI-w}${2OTtP-}WRtHu)0v8mWm$2bTky8m4{ z{7QqKpt?w?LpVq_yAxd_GQma=xl{a0Tg$qW);DE-*19zqId;lKP2L9pWYhQ;a(FY7 zIsAVqRn0UUy-dHLpU8xt<6jEARu)GzohkjUQptU7?2Pscn!nbVIgNiY^uGvY;RXBb zlffE)wotso^!zNxzi#=EKH>FTZEG1ZrPS#$aWFxP+P6KH$FGm|UqS&cPN)~7nFgPH zz~colawOFkv-uGIL*N(qmuNn(Z@$l4j)OF28Hzx`UdhInUJ#oJ*ANH)I>R?mC9i2? zm(j(`Xs3fpCN3(<_gI;3U~k`Lw$)q3!^5Q?6`%2&!Z{Jcy)QbzVQk zg1SGJ!>;(Ep-Ggq1=xDMGAG6JpR|+hb2S z=!oU?LwDycv6^~P@G-_{wHa<@!#a$nm9KfJZ?jMxXq6f0#;XENemrM?PAw%B(2 z^8UlUd{hHZAy+C}`$;3m`}98q#NkQ&BIP>x*PWIp-109v2#XE+wuo-T{&{G{xt1LN zf`5bHhvbkoHY})&-L<;x0qqbblHNR>f5mA2AkHaoewtQ0#$`5(P}6ShZYy-MHGoxq z+Dafi4Q-8^?faE=rf3P%%>7Qfx=73Szn)c&(NfE^@a8IUg~L7+Wi_#J5ge{PFs=W^ zGx3$|>KCrcMoDT$X}m2IzBh?NF(C7pVxA+=HF$mU3U|>RXWGN&>AbGo0F&yVOX6+{jlg7@C#XDOt}U_ zwM>j4Vjn9_bg$Er!>^BNDAshMB&&E;pEAU}0bP2lC?lPa(%9tJ;5C=|{&#U?R7fP;UrHafROaPw3AOFLb@pL=B~g5t!nEZ+fF33VN_ zom2pQv`k!#7HsC%X_4@+RY%z?%}Z_f9`#@EeuXdY^N)7r`d?r!;pY%mT{!4K+be?w zR><X{a4fQBBaS2Hi&=sitoD58a8Jf1cJNcIy67PpE6@h*{TGvx_~! zb~|2PvkNc5l<%jaV6M_#4Gm3NgYMA%&3a<9TRh2uR!gFVQ}G4ako>ULH-C=yaeu38 zCg$Ojrqz04CVENoG8z9o?41_agco@3H{BZi8>7+@q~-fxpj|BVbFc2-*|JuuYq<)xSLxeb84Fdj6eFIhT`E46> z`r%vF@f2J!-&05E*x7+_@ebo5ny>@m;+;x+7EgT&7+DSAco*>NY7F{eLVcoR!W&v! zvP+dR5I&NBouwodBU4Z+0-;r?l?)X%xnt_x+5GG)_%wf5RCVfoULS2vp{?U%^9jCX zne?XPmsV{TRWNtqBji7e(r6uZt+p;e@z|V=FX=zr5T84!uPU5F->0uR`Zw8wv`w#M zIPhi1RQeBp*SYw7@hUZB{jPJFy~R=gS{oAk9Oy_-F?q}IZ)~9nT6%1odHWxoKQuRr zdQr6(gNq57RHNDWlKu_IP_}-y^7`;;r#|hTXqnAUiy0%Hb84>twJW^AyrVUIfAh6w zH0I8_{+T@*-@uRD3nk^LY@I;#EJ?>NBJNyg3}U{)3m4KxKG(UM<8CZ@Khl5L83ya0 z1ABSYnHM#R*n1Q=YnqWE-7?cBQZTm^FC|z^*i)3YYNwnA-%s$Fj$^2CiTNk?XOU) zd)v1jVc((ur25F+X||94gEj3gc5?nhrH&p2|0)9iGP}(>Dyne#TH%5-k<6{^Sb%?N zyS09+$9qdNNj54w&d|^uN?RLxAh@TQE(iq zHWi3k+qeq_442Oy*8TJXEkudl<9qFP-{k;hxkrjwM|B`GAY9V}a zNbk3Dh;kZ#XL%^>N#yiHZLL%SJM>4`Z7@OAg^iu+KS)Fi_mm@cCh@D9excPahxM-7 z#>uV5j%c;@qyi6lB9C9Q=xJVm4E#%zat$|3)~YE$G()bX%8Z3v|20OnNXso2p|~Z_ z<}R=OWqA`Tp0t0{&jfwk(2eLor0NMUsCRTc+uU);=K7=HccC=%?UcMjLuAKf=x5T!u9@ znfR)hwFhwA7Xd9@D1ITT!p3kE-W84)mDdkv!86$wYW2~ef`DHv#g~=49b^fl6y_dO1LBkgK_Hs1EyOw5Jf^^ZXx0lT zZ;-)x{TPJb2d!;RRa)2IS221~d_7$|KAnGE1^=oKAgg1t zq4-y2H~Co{+%v_$3a-;>r^zlEZ;^eXCd-oo|N00*B8(h){Ava^X|Qel2S3PbhkL%s zDk29_9~R%oCOsAKAF@ptK^JGkbijn>+2NW)&-2|9(Wc=S($4+*BGiXy`BfP1LM5IQ z)=&|M&m?}$0x3ti<_~ltWEVtZIaSU&EfA zdH;rNAvI9#uVig(ekSZsc3tDhnM0n5Jbrx#>reX}sMau?JCHHu!O?Wx2gZZ0eE$nA zE$?7al3n7@&{u`t$%_Q}HG7>jv-( zYzyWSjD=f{g*-rUo5QbjI46TvfGsK4I8_qAmi>i(cowq`ZjC|pemaF=@{i&HPqSr_ zpPtXH|HAs^?hW2Z@vhQ7ii9SBZHc;OePqhN5idACGiq8fy&7v+M24N=p1YK~ zyYwe={A=c3(T(*xc=kReZhANB$u*ZsQ89M-Y&O~dlKL|SQ}dsyY6gc6j=B5QYegri zG2*uK{Oc&glSVv$gT-r-h^eos=S)1Q0-lo754X^(Jdh~vR3nnmwR!s0b>>wUjL3eV~p*Z7S#FwK!Xe#y{-&h~5-Q&QBpyCl|y zagPj;=P5OZU(z213Ae*#Dlr8{4$jWe{%R;5kv#wUAws4y?OK9wVw>tMG{W9Q;{b}{ zKj!fZBk_pk^f$V60GZ#!guH~AX>}P^9>0D;!mjNxzEb0yT(j>Ae4N zkdHxo^oX7`M+~}Qn@{V9mjergI>o=Rep%9!S}9dsrCSlF>WF#FF698|yncvoa-Uq1 z{5Bo20ZGsgS$7JNl4zc$A8w_p=J~_ykK%~+RlpV-L4k)Vcba~v0nIbA;SlXp{GS7U z4YhV^{jK5Y`XQw{gH~}0Su!Ke*y`_LL|kh6OY-{RNBTrF+T}Y@M@_I$`$~v}0^UMN z#B%s`k>0U`5ws*0qTB^+4XYP%(6}6Uk?Vh**W-m=RO`q9AYy%n@Sf+Ak@ZaTAHFs7 zN6RbQiXK1-A%#SF&p22o4|4eRqr11FCh0z_SBoC4?sItdAw0Xp?p*(C){FFx7>InK zw`fN6xP`b#fMlVrYX^``!!LM^c)cm{%LZ)W9O$B%S|W#Ew#anb9pj5M9)T@W02Cz9 z!{{>A|0)3Oq72(wLeItPgnj`HzUK%BwwmK#Uy!9y+P7%U5bfuFM=wF%*l%I6VUkVu zza;6+f>Mg7&fDW?V>}a&^J0t-<{%L-SkMfvedPX?aW$DI-(EK(^Q3Xkku_2?^gMV zdlOO1LLK!veLq9*Pv-dnxx+&suOI%D-f#xS>ULJm#XLkR5Fk*9uOau?H2si9S);Sf zGEh({fB;+Ft6$*~?55+_pV3C~?@$+3exfgSW(;>-qibk{xjS2r zB-<$pya02TmdOd1*)^@H({o&1PZ9ZB z(tn7qnZRrD#b3w3xd)7DancGlyW@HMDuf>r>nq1xmf}!A*MHbNmz_;}+n|f)@atYG zBPPlMrLf*bs?)lkg{7F5tf-Do;#XR^De`@>+BW`m@Fv=t_@}k{aW@u!{3AvHt6BcO`qZP~I}|>wx(u*`55LYnZNSpVd6a0LN#j zDFUWBJR>5{=`Xm1>x6c=4|GZY;X(<2q`W}o0tc?iv6#7&ZPNUY>OrhMk%=1kWy**X zy2LL_UPqclf9!mv|IYPnDQy(>Hf-}j+SGYlB;Jl_&zyt(H^{d9q9*Wp(uCr}|5vG( z3ox><^v`F`!TK+HS5`#!&AJA`O0QuN>PJ}h|Bpm;QJCy9V^da2^ALn@|A!sfdtaNa#+1kn3=1+1(y|M z$TjY8*Fyb2=(Bw5ummy{j{3jwA08F{fWD;}aiL)o8*#U7;y@rSCiTON|IqKgyMk&q z(sofDL5W_Cw_$PIb7_u$X-8Nc!x)ty8crTkb+5dw6d?W$=5H=G1 zH3$M*L3kNl+j#T9ugsWc{D*iPk7!w|;pTx~NN5xEKUx7~uV?3m+-IV$G3O*-L8aa0b>0TH)tZ`U_ zR#rYP>-hk?I~zN4{nw8H6Gb1CE-|q@vl$QoVFBOVJj}wHDK8}T!j5lx&MY5QvRG+yw*Lg4o~6NE(`j`F?|fO{3iJ4jgcJ{=+q$49+=+$`muhygPgfU zPAy?92VXu^G&hQyce3v=Qhr+8uJj}Gm+BhAO59_YR+CNDt1)nAwSc_m{#iEt+`Q9q zCsjXk$p9I>1{~~Sk?lW>-|CR(2%y*BY4aomV9}5h3V?Q@rd_i%4iO`r&4y&+GKX8y*t;}__cJ1dH5H{(0faR4F6JPD=fpvCVREme}kXuY;e2N z>R92a>V`=1S#<#z5EvO&J!i*DnCErf>eKap@9)i?W8TQ-1he&cXN?u^1#il{XYjAi ze%;p#R^sqZ)60tzUP{=AuNsqmBO71NtZwQzeS=WHFA@aF^R9%;rhcm7&<}I`>pY@h zX~&km>bv@jfq{lwD)*fSSiV|XE+5S4vcUG<&p zb;7#F)0K_V(W>)fcrEUki1$HC0)S@Z^uq&mjyGvgcdxPM=Ph%L`&1YaS(9`69W_xH zk@wSI@D8@H2#%KYF`KTk0N)aT*8Ktv2)8{W$G>**%=)h{G86UTZW%;aaY^%q%PI_J z;}rf4Wv2lDx}7}+BDTB3xWo?9_l1=%YA>~>@aq)nC~FLmU4(P2IM#nX%pQsKJ175Q z{nzUvxVL0?*Q4UPzQFdZQ-2~}N99m#&Cd0|99m*NM?kCdVjM|N7hR5(My+1rs5$<1 zDRNSlj;3;vjzymWU6T7kB!cbQwEZ_85*ap;WVdPEYrGF-#!D_p#3o3&{ui>k0^8wX zwpMhP);O*NTdQp4Reb4i9={5xlS3`6K#A3f={I{jD^Q@Xa+mBS$=8hj*BZiVW!a%y z!&0IKk*co2{u=`|_nyf658r0c**Z|Y|M$XwsT}-6Miv>SYal&RG{9F-;^Z4 z(LU+lFM*?4L*Id8M~->f_*!D7Q1|*pSb(0O0H)&2SYZ<da7N4@ zi10DoJltz0yFZ6ta2v|~ZP`GC<^v94PVdNHRNjTi@JtaeLWs&6mU-X*V{Kq8CIm;$D*1 z53&A>AAP;#fGXF29dNb-^&`z)B9VNT)K zc6#1|nz1@+IvLx>2kL|LHi{EhM}Ga6q>7b04XhEMq`y36V_e7wJuA|);Q&-5fO3UO`>7Tzr1KhLM_!50+FO0f7sv6-f3LFM9y1z&XjoZ4js>Kd zb2@Q3?6YLwvnP5{Z03Dw&lqdeUlV<(k;*3HOBDF!IbkeCzd-TQH5{}HDwg9-#IY-2 zHrMHz4wc4VX;{q;3G(uuBy%gHPQGeAfMmU+B6H0(|)IsLGRo(b1|ujeCHC$PZH!Q;5e z1>Htpmgiqk3kSg^mawhX{uP#^6C>n}67aR=N&Xd4VA+KQ-I##)DYm`R(#H!!v=NA= zuaBm(V=DRAhgb>%+k9Lb!;)xs;Qw(0cd#R3Ag>?Fz8>i0W%Y954fA=&v%CyGJ=7cZ zV|o2BqY?|xk(;a88(Q!fhWpZ|-=#(58EDDjm(&l@GX4fb<5a06@ULO>H<{f4qPg|U zKcqv0U$OCAr51n;`eEU#%AU^o7P@#H+4u^Vr<9~X`4lKE(O@ohTuTf8==9kAXN|+y z9{jaDZ zA1mYEfLw!am-_CWRR5A1%pXp}N&|Vw_*pi-dT$w#+=_e7s3Vf6L_CMpiwY1eg1Yyi z!pvL+|DxA$&dS8?^PiXTHRbU&A+jSw(@#@50-3OTXkAB8Bl;7ajZHWmP}YU>j(pv%Fg-2SigMK4l%?9=>PKD#{5Ur z_Xd%TN9XiU(+}nJORcn3BnN9r3XgM%{?*I~iIeyx;NQsP7P&<6LuJ2HB3muj^#bho8G<4vD6iTlQf=ySV#(brHQp4L16fV^jR=6DuzKaorvy zt6#Xd{#(cq+eBZ)mtc|Xdj@_vQRF%u$wpv&9Q`J6nJ#)lV(x`W{F=Gf+-yNlu%p$~ z@50&v>~{eLZ(alk9ohKeGcPgeKSW*UV<&i^%|BLl8=U70I}q=~Q~0%u&|1ag08y_f zO;}%Xvs@SO4EMa=lH*@{>4cQmHmYA0C)$GN{D~f{FHnNRTatPGuo1uRJ?7fm^%Z(` z$U6p7tkE_LYh4r5@vD>8ilUt?LY;k9peVq?42nGlC7A1f-KuO6&=1$M`wPBnS6Yv* z+VS`F{lxqcc=>Yp<)>rXLQ$MBS}{on;wWXmK);?DIOCs&U%x-PlhiJ6`b5)20Aq`2edhA6G1j zw?*erm)s4Y%{#e%8T^YjC2P~hDt0T|B<9*h6(H!F_Ee^^3)UD}2(Rq^QHeUtF>G=6 z_|AEvCU`t3NBKAM5rel@Buj&2`dd9@IQ9HfW(eCAFo9@DRz2;z} z2{W%BR?`t38sk~^&C;zE^^%N0^d@fvh?dh2<@#l;oXWr!)k-0;I=iT9=9E64S-;Fe zR=D42)>F|Y+uaZ2@rnM7V?3uHzD*N!Ylmmo&2O6%tsr9O%An!X^O%Qu{)O_gAhg^) zT$b&BxzBZ#lU%=y=X!C9e@XmWO7YDuZ}hBE=W{*GEIO=ZHsZ+n=Z8==q3dc!H46v8 zCae;cL=4$)FdJVLGh-+V(RWAy)*mgbyUQi@gd^k)_n`MTiCm#ljk~>NvG3M}Vh0?WZor5*bZq_x7t-J#m(;dP}BX8vUUwjjN zW$13%Li!%7-BQ$1x`=k_yVF>4*`Cdr{d$PKm}nXW+$^ORMbl{QS@kCRl~|B=U&;5s zerjK_5IaH{k##RGL9v8|52z}q`48dW5KY(}*9g%ov8MBG*$8_{>`!Aw7)|l7T^zPU zL=(d5w^ZAzN6H@HKax92jZJwf;NL)*;dfkLXIm&HPv+PM2F22gKw-+pSH^#+;~W#` zB$T?Z>k9U?+)dV5MD8^I28PKgIjrtQE(x9TC)K$TESyPut{9VE5rM=#!5f`|11&JX zb17nE`;`u!E62Ys;Vi7`{g!$M8$w^kJ*;9wGul7uk^12zeyyW8uXB9k>{*IOZ|C$5 zLZ(yHI7VQ)e`B**=U`72H^sLihs$J+rji3hv-0>A)$m*awgp%XX^~vjtTWax&tZy8 zE!aQmJD5MXpQP%?LD2CN_TNAUT;4Nf>qEJIS;AIvr0N=6iYV-J`yWo@U)Shm(S*@y zxUR#X;;g{9^UI>al7^xw{5n-3I_oU>%r9U8S5+GOruwCeQpC5ort>ew?;x7cekGp+ z2yhF;j)-s1`8Q_$G>UqR;P*?*MwsL3-R$Sjh`zW_>W~rnSbWx>WL%trCi5;`b&fjN zh~7`{#{;%|4t#@|nl`OGiww|Yd7PGy#SOmL@nHS3{+}8cSz;RhLS9|!AmTTcz;~J|ce$_+@Prpo&<(Oq=4B zm#~!PO>JxEYCD|w&zGO3uCVR22V7fOmjlSIgTJ?{8~JBpe*gId-ZOsPR{J@c&%%vu z0oW_y{q~CASLO7>w48pX$6+0rZKL2@KF>!fqyf=#`eE9_@+g@_(UQ;`rM>)Z!Z)oY z)AYl&)M@suI+tm=pLB2vh*Kx6o7Y}1IoR5HCILPxaEsmv?kR!$bWF-_A z62C}(!yeAohjRbtoOoRHwixS|BnYe)eFtAmTEk874y4@1!f!#-( zNCYoo<0O88f4w7DCCDYNvf+q@%zJ3U8Q`Crt@dZ*%csOzVQ=8u;GYNW0&HdY7loE% zQ?F_GCHdD%xk_}L2go0TRiK?vP({@f+4%Am_z0_hY~v~Te=^(7TkML6(&Ct&#-!nL z9?JD!=zpb+#^_eWm*rFh*vsN^s&-tna84$^;NK7%u@~+=DVER<*=W#oz-zRPZfm={ z4J;sYoqpZJekqpOp7rd95CHe3VdS`ujeI|A-@87)|KU&VOt*_vY`bA0&u5B%Y818b z2o*+1exM(|Bo;*AW1I~jgY9q}*TIfbBXcIIrs3B{rBZ~y4lazaayEaRo#ThRl@DTc zCNU+8UvT(ySdry9xaTwUyiz$>F;<$xuhW+3#lPn8S-?bB8n)g5gsJ_n+ZKwG9DeOW zHHh^x2T*UEP7gTlee9xsl>&}?Y2H77iC@LG04qh;D9>zri04Am!@wn`;TIbs$+px* zHsH^}!DXo*`XD4u!>{fzs6BQ8bN6V7_ayt1=%PLo8{S$|{L4?!ggIs=_E=)xG;$`I zK>|5pz&j1UAg>7>TT5YZ`y5{Ypn#JRr+Od;3;EB zACu&9jKSzj^}J!UFf-?!0_<=eXjofvR$UstMhzXFk7d2Fy=m==2{ngb7wGwpzLee@ zv|^(>yr(oTJbq#Sc?O9|Ru22f<|rZDv93y(F&sc&#Y_M)np5~yP0wSP3{%}rhZS$9F=j}&ycau! zM05DnqF|3Q$5_hZGY3#h^kjW0_-4uGT>q=of^%;K{A-7DFfl)3e9Qay&D*4xZ#~Q5 zmk!n18uA3X;`D*Jq;2H_!_VR0a3Esj`d`n|4ZZ1?o-sVv_437BuK#Mozn?NB{Ttc% zf`7xlYGL|4hxdbteYRxsxt!_v1$`q>IRsh5B(w=|03h3z2_nkrhmUcrro?Vh(b?1` z=0;rWnRFmmf`3tfEE&q!zZWT`&(W8-N=iFjdxrFYt5|f2zHv<2sr6sbH?V7&0Nc95 zdWA2vOKcQ)Cv0pqn!Y`UU*{>a$|j~_Av0eJP%tuHHElZoy2vLmUhX5vneX@E0nIW= z5Rhr7@vpB0up82H{Cfc-=8+-nEx(f$Kn;`rjc86k%rFkXR&+!h(KCOVt9SAmoRjBY zU@p@BVKQurOA*Px=F)cVyH78l`u80&{`qKtd_r}AU(kE?%>GeJ$WM9vLV9= zH{%?By%fRrToG*Bdr_Yd0{~WI?jZV%64889__fE%$f1d<_uL=OhV9VA&Ep&SZvjlh zFN779h%O8z!?HM;h)`J(l$;#@s<9+&p|y&AMeIcaHe;X6ega+cJpUpITeAcIyS?j= zjjPJe=lvM_*)xvcB%Uy|0iGQv4937XF(C?Ray_w)8`3gtOh~s;^|D=6QMG?KELG`t zw|nhO5^FatW}#}9M%4t+u2%)gNkoCR!p|m7O`Cw#vQpGVWg4Xj2`KJ@MA#+ke&^oz z-i+hI?jQXRKalhJ`n>zz{c-Mh&$;K`*LGf>mcAI++_nN8682Y(|8NbxV7JaDA4XKe zX}VcB51TjGM|;%4gSm*mZls0EsVjVb6n!kayiRQ2Fkh2r%CMwj|6#d|^AG1R6jbD& z+FJ>#hqZR9^&b+ChmzwrtOfT%@Ed;WVsaB*kZ1hnS*yxl@E?Lkee)t67PpB;-phb` z7D-X%ugB;NAGKe{BppJ?m}xFJ**bPgp4v`(Z219mzk`a}pIlZ)`i;d=ky{bGlvJ2mbQk<+#eS zRfaa>;{9JA!#u&*vXud)%ByhTn`X3_zkHkls4S^caUUVSftFW90EU2mfIk zb#ni~iKA4@U-KMQj(0Y2j2>vKIY?pwg8hfZ*ngP#nZU7!`KEz;H<)kAySV!y5K6~y zg#N?8eGl7>+g^1}^Y$n`Ere5w!I(L(>v=XYJN!KlOZ;%$)8n~z!a9*8X?rx_7JjPr zD@Z@v3QvwMGH%D%K0>@3+QeuxuiJt$I6~Rxc{t8#zev}$q-LyB;x)0c#s0AsX#HaQ z>lZXBA7vNr0&U_&_DdK=w|UJq@f$y)cVT~p!#h5N!SQ42MEWO;n7=wP)%6_sJUw~Q zLve;pkFXcdcD@e>g=!1_ehOkvsFBbXqp&MGx*JoN0DE&C?TuTg$n8}zI_PMClLNnL z-sJvOa7$(9BZ!|rER9Ozfsw5`AJ|{=5^a{SV&V5QUJO>`Eo@}=@&OJ)jQMMv{u84_ zlIQAJN;une3N|Cgjk8TZs^Kp+s;_{bjhmZk3%rblFjzpL{WY6DZXThN5^Kj<^C*=A zCGLDbgyVfZNa^tM(V{0>TOl z{94AV#Oq(l^&@;DN6L-k5A9y4IrvKzZC0=je7mdDBdy{%@1E}5>$cFutH+gI!0SMZpZ#F z6~D2o8o$wi)2k%-D{HBZU_Qc!G*|&pH^lFA-1rFP+Ejdw{dH4f%YoEiTkGYk6B`bs zj@Pf({*BG9u|t{54qS zHM@plHGZQVr&6r->7u!s4o{(?<}h!mH`pSp#?PO1UzOcH*lIoOK~>LRRXysqvBq%y z3-O00wgW&1lb6j;oR?J~y@`ENNU`Ghjk3E7tATc4P0)FP5GUE=ar_2MLu)709+$Ge z44ftk+Ooexo3L;Y@z;2jzj*ztojRl`cVMl*;_x2Brf;Nk<3mz72Kzg=1`lB z^OjA*kd(Fa{64(?)gW<7#Bs3P4-f_Ac+Om|Zr1 z0f+fZ>z7RA*lRuNwDphEciZ8*A2V|a_`0E$Bc2}XIDTUUCQQyXOBgp`%Mgb82?GUm z8w&;(3-O04em=l?M9;#k@CXaC9%i`{Q2c8AM*RJ+A$<^sS~s^rWOG&ix=OF-!Eqm1 zr@;jqz2*-ObxQrdD`oo zL(nSG8KX?Ui*q=SpK&`2zg}Jc${eG=rQ3t=PBh{pgC^{_Jp7RCbz3lhSs1zp@|2`Av)=J1^Jc=s z9$ptOAIERp$Rj^iyBhiIH8#8IR*TT68P)kH{~^KZpFmTdad1#4_^SZ>%SA-TzoO1? z!GGw%TZnQU`V_ug_TD897Fq7Q(PN4#RL9DKUS+grTi;hlDm= zq19#+0ld@uG85UCw0?2?hO$arjPsv}4ZWDatmn}tfL2cHK8EjCHu6dqXseS>l`jPr z^Vds)BRW8cF4ti;(XKge458yML9HOuKB}WW%yYUe`25~sf!QF=0ai;$7Qg`dYA@!! zBU-;y{Gr6^`sgZ9t!zUeM{+IA2V4Ih@BH6Zk)L(^2CRPt2+upwfbcwl0slnuWBF1A zd#POO2X#YACc))`*~R>I)ld#nZC64E7p;Fih2aY<%x*&ja;W*C1X#5Gg?DyWs(0?e ztJ)~3Cjh1m^{i~Bg#B@Cy#CcLVW<{a#$BWiFfAs!gtwFnEg~DSjUYHS1rf zdG?E1mmMs7?Zltn^Wm792B@*W0y<5ojaC~U0z*@(?|&&ntj2!`Ypa|rH{L2={tnKA zEt@!hgNdwyE+V*owEqz2+vKr5@J!jOV7S0W6<%ZYAfxJ;_kZDgCDVvU$`ZB-%j6Kx z$INvTuz=pt`HVZ;M_wXdBkiHu@_*wYHg95gTegfDd7)dRE_0fqx#uMGIkD ziU7DC42$R*KjJU;A2R3SRkw-~tqVZDHp>uXV*Wahl45wrkV2B4nFb(?{GBV4n9}P$ zKd$yK!%H*Yunvm0X$~8UayC|2=J3un>tCVUu;M@m5ujqdPgjH@=$OCW15IoUn&#`f z%fB!Yb~pq&zEHwwQ?Y{HJeQrnpMv8Gd79b=mG(9RtfNtHi$uf4@f(P>f&JBxH*?;L z!)*ka9Auz_kkM_y_E$J=!2Xh7pXaPP94rmP|HrUHqf9tDCfE*8;DZ{nb_ zPdw;m&NArH0I}WxL6_=d1k=}(I3>`rF#<@TL6{;vl?{qu;JZ)8YD!23v{M7Ou^0%r@S4Gi;+JD(r!gc++GCYNP(Lvhyl*C(m&)JNT$%2uAGg zsRplqARWv2iM_@idO&6((Bd0=jRL2LsJ-fp9$EBTvWXgSzZ~Qgs+NnpsO#8f*jHOj z!2 zeL279Smx;vq@PX<1e}tV@uSdd;h-dpumIBZXpGu12C0-#$m#t`IxG8I)1wURegnWy zXG=(_=F?Y95B5G_WCQ~{V;Dj(;FRcDPHO>yD=i+3N(LG4@BqLd8vk%4LXCzgMcK{S z8WiEbGR%@niDgpOZh9lQGvBmJ0Wa?WB%a`u>a*w}TEqqE+4_(af+(Z4*@1IzSLxXP z5Ty36bw#i;Upm$riO}|i`xgFf;iHACOF=C2tANg*BsabC{=}KDF_^wk3*y^1Zr%0z zst?be{~rZ5)`D2(?mzqOw;q4t^824K_}*QY|NN7?9~n5e>eS`;{v?($6ff7?4O2Cs z=Y)H6OG6L|*@~C1Q@otmCqkfkIg&B29XITeC`CpxL`!H?r(}&-#sM#{k@tA%*&0A= z~3z2oUxAXQ5EC?`nKZfXelk0FjdrNo# zsRbkIQ6&1n%W?@XYl05PUIEc1yj)FD840{8=VLkWcwP$vC8C}c)9AGz91jJUlX-dZ z#3W3SI-jCZsM7J0e4=LwyJ)mfAElRo7E_PC15`&n()I1Eu@vZRXaF1+@p3u>QA#Ky zz^BaSHM|@Xbdw0jd4qZRgnv&qeNGW{EeOJQHu}wj@`QhLw&C0o5Xuz)FJ6wAdRjjV zZ4qfxtX46QhI*Jl+4sw=UzatGECEu#5B2%>BgTz%k4#sVfT(Yvy%zCuNYI*>bv|g* z#k?F7H1l#OgMNrTu3j(CwQ7Li6pG4aQ4#ExNEthp01@T`4XNd2HNTEhvCVI39;nlIqfw`pn#2*P|Q zL0uwsztuuB42o8ZJ7a4AjZ>HC+hO}t*?fO0eJBJ5LhW^m4C~Mk#G{BA^71u6=VJ^o z9Wx6nUIs8mMVKO^XNlfoy2b7@(h*R+tW%=)s+o(`w)qIpk)o@Xmo**7DWQny`z>p? zcw_F)?xv+cMCF2wX0DO-i@89vLl8ZS>3C(t%ZoryB=Y~t%ZuqaBIs|$&ss{yQOea= zW)UyP1g$_UV;MmBi6)MBV? zQ(iA{DRw|}N_goWD6Z*>o+M6*WpcxH`Y!A+jPhCS;d_p)+;91E$T3)%aUV9lS39*M zYh^l0>rc*(7dqU=((02mE;`&ThwC1*8N~TyVR$*R$HNS9eK^3^)up+BQQ7fgrCd}$ z$et@o;-k$r*H4s>>(*~IX6fs+WKJCN6NGvzOx4p6Hks&&xG53!yPNxh^g6O zxCJGGA13MyVXRzH4hYd@kR7&}VPzzv>&wKmLA_XEFlbD+qv1FuyrKb?P(ys-C;ksB z*=C5#jk2tQsL)z~wr+KWlq^YA;D;&A&7l-gaJ`16MAxG0aYvvNYJN&D`o)wHih)k> zqSwt)yM7aoJS5g!+ZPrV0{;D`$q;N`cuS|mQnAeTwMh;paj4SN#uE_@t97G`45}6&^XV87Z~8>?*fT z534X4y(G{qk#<+}Dy7g93R;CnxwFZ`bPGQDUZcxo+Xg|GTX-mtgsz^e+jOliv+2f~ zJ1SWjJ)Reb${0Rt5u2dD!Td*G)qN8{UC>jNkJ(1!a=p$cE7$vU3^`Y2Fe`!Aj>mu% z0IduVnK?{eRc1@c)GFLjGEdRC-?8S&(#n&w&pvdGF008}*5;w9=w*-F9R_xzd9j`< zUFO=r5a+QnTDA)vlw3d2`?v^-fC7G5tDASt}qb3iGSGcP^%7+CNnwCj|r2$0Rc6)DFm%ozVD z4Z+>&iWS#&MVJyN>EBtG1NqB!S(3aS|B)pO!J5ohpnk?b;;|a7tuKsK@n0k0c?y}4 zF5@?yqLT4rsb1VPdEaO2>Ev4h-+9N!p%U>g>Z-{n916BievZt-w*$TncWI#V2vhXa z<39mx58}TsmWhTG$mqKk$$kDWSe7%myXC3yo1ZVa{MY3gSgwKP8d$D@{4APg#2n844yC`_?qQyblKqaBY4Z%=D@E-ay(O}0- z{5}1>zkVo4LLs6#K_x2xTMsIhLZZ1oNRIs9H2u#@f`rct|62(XrwG-4iOS`t|F=I) zWdF&3;vR+l-@YUJdG34uGxz)_e(OK=%oYEC&!c7k;SE!X(mH%wu~2M^QWX`GB5-ks zRlKQr%#k-aMH%N6>u#&`muiMiiDt{4QiI|Ru_W!zs6pzG_XzVm^(RTe`X-&=jS2TXs!FekWuGrisu3;w zJ!xg6>Mzus?jP^kVBUDFx%;0oYMQRm^E*6AV+!NLA2<8xBnvT5w>p9EX-c{es%h&t zyvcMYYZ96z?@1K}M1Roh7>Sm*tzI*b)Q7!kig);VeWoHrT;7u|T0@VMb;&3#KQB7D ze_e@o|BJj=_#e}QYzj*Zf0i44O4zkRZ)?^JzRf`)kb@|1CFty<)YFP z_i{bKigR0`_ z=``KP`^RgR(sgR)n8D)Qd@VQAdYl5(DqI%Dm4IT{Y)Btr0rCk}mK(cXG)7O5f8}je ztaz?`_|;~MM*9?u)MP9dUsdzA&{GsxXY9DYmi15|Vk8h>hY0sz?76wHD+k#-)Wkgr zw!l0dZi;xmr_QI#$C^6)3B#9*FCXnSU!$g|$5hAc%R8Gshv7`nYd+kZP*3FI%V+Mk zrl_gX6H}w+locxX#MNq+q7Yjv3|B6`e43A%Xi?I*xb0qXl-KMq(&hJQ+j+H(0lIQ? z;VW88i^Kkyu^c1a-)&`#5msh(IaaNa#68*fY$>-8RtbKpbJn<%PK$lk+D)x>Oil&qckC5YT9d#i2I*TQr>Wv1 zT~V4=-gQ77&BYflx=A02{pqr^>PK|5vpMaaQm-VgKel4Re_f^Ad<`MK4)W?^J;Kh= zJyg%*5q6Fa2J40EPpob_j}h*n8sXw>+&W;^3mq}o{Ve?x*E?E}GUW3_D;;x~tYLi% zb0|6P59vkhB^r+VA8-Yko}2ffd3zCGp+woP7vG}Gyvf>FrT)>nY9qcf#`JFqnxqd2 z<3cJ3PVuG(vPtg{$0tD~hoJl|#k@v0tR+IOL*;r&GcLLsYq1Vv?u<%p*?T&*jdWP^ z3M09`r7z^vR{=(ulK zv&qn1OiOBhZU~o##|Vg$Al9n<8caqzVO;W=EgGSwPLF8y(`BqojEi#dW#5sZYsw1Y zaez(NXa(Wo5-t#E8FjL_Lw=1@bd9cw=4#KF8q!b4mS}6j>QeR!eJbtF)O48HdxUw; z8HoifqZ{MuA+HvXvq9EL-eaYIVR`&IW$h!sWfZ%7)a9$CuwCY+F1EnYgQI!;+N&HA zfoemv_#Wu7>Z1ByHq_E9yeW)p8o&5FtSGz5^4O}ydTE)@J*0Z+)5n)N{#p2Sgs!n> zQq!$h=zofP_@az@f&NS{ocCl}r*iL*n|o<8(!k3sgx*zzk!PsOVkar|OLtPu<5wfa zh1b-F*>O4~$~G8FF$F!y*rgdZ3%`=xKEH0pUUr@*chJy^zsh%$g>kWwnfSW1eP^u3 z*2Cp*@MlleTSkigEj^jooi5qLX5m*xSx$jZRHP#Nt;YL3WPFCbX@;CNNn;0-Q$hTW zBQ%klrfYl!H6QCgua59H%)7=smkRjx9-UB2nrZ`leVjZH?7OjWGMj+UiuNefJjd>r`=! ze5T&SJk%xpudcpl$D87b7UcO^_%%e^$L|yF!PU316FtodPrG{A^|A;Fzpdu+D@{|{ zGJO$M;G(U`T-z-#WcH&1e!V5$5utYX5p{ueoMBu$Dr)I?$*_YwAIrru@QXTyFQN~4 z@1~yGK-k#nnom!0@49dT6PJyzsv?b^vb-%r373C;j|fCpC)j-IE*HM_yT^>q!LnqUzV0?YihuPtl8sC22JGJXL9j1aL3zN zb-<>>>KX02eOLS1adtxhzuG-Jx(fKkenCqd|G2SK-s~WO)VeP#p_L!QFN%{FYZ0SB z`W6N*SR8nz3)glnJ1)KG6zwLUu*m>hz%O7^C3}+Q%TMz7HAqjHUI!zswV$U2@*a(C zrn}p8leSFb*SraO#|}N@-l^WL0h^+pZ+G2I?;Kke^(WLB{8IW*F&>R(VGAiG>`CG%*)*ku=-*>%4WFW6a(5#UrRaI`3w7HxeiivBr0pIsCS%L#=va-=H?+31 z*To*8+v=*^T=@gHSM-seA&wF`U_Mo4B%JM3)`wY z^fddX{$0KLF}=e(nfsn0{Z{_x&gyi@S>qG*XHk>(w^!WCUKaPI{r9O)Gr8n}Uqb?^ zz)=$_U`atvuvCXNAQC*oD$C&)72Tj$#9e9N;1&Lg-F(siEwu@NxY+8OdYp3kaA@vM z+N#uVMOpY7Z7x~#Mg1G)mGpB&oF~Jcp24qOw7IID8xeL^`*v;VnpF{2MF*&6gWiFs zvE=hum17tw){|&Su>ny_E^`|efU~E~2(tJLehtz|ac4(=LVbT6MMdQ0TGdZiQz3gc zeqE%i3aX18$aU|um9-abRwv|0fnNx;p!_Yxd>2*IH&8yQ%fxl%Yy4tbT~06SOB{(8 zGx*hR?x#IbU{ehq!yDAMwMOY_!iq|^MkCpED2gopJb9xf11`TdBD_|3g!z>o#Y?mB zOJnrBW^secHKZz=^n|MotJfl5uzb2cq|$bvm6w+$Fq|nYeuRS$>t~otJk7EeIPl9!JnH~=#&h*gTG>U{ zV?g0+z~$>84W7*78G0F6!jn|<{A;f`%|m0J&FYsE$9X8cCSla3-U)_qk74H4PpW7| zyhnI1>C2g4!q%I511qCmM|F&k;a8V!+jYxW2~VVLbD^IZWILK;gxK;tezC4?)q~(N zcd~ECt2dOqQ+_9H7W31_$MEY#3OZ$^D)cL?snW$N*c}~kP$OZe@(=jsy*YPy_R z7k?XxvFyRtYy3Lh=d8^X@av*=LIer;HEE`>MBPFS(*2t2l18XUqke|vp-S#<*u{l%d}!dPpg~QFKd?yB>Vz?u}QN@4+s@R4E*br zZWTm~noNLio`3za<)mney1#EM(2r3l>>g-cz>kYi)NL9w{0q`dPsAVf{ZIvdIiawA zJDWp299ey!fM4?!@UJ$ksQIGD^74}JwA50s&)cT&n8m-8P9ES@$n&g=_HbW<`CXk@ zy?Vt=eJJrOCBVOginKfwqR$8eKt{v1zgx}oub1euldT4KVjbSg`y&Uetn-Es2(n&*EPsB73Is3$d&VHK?6cmQh%^X7R61!kk80zGFTs z9^~Oj@i(cn(~6W7@T+K0K~=dxF_x3 zq`mpL<>F zo%9m)D9>5dnc-gp9QZY6e2!IV&r*G=^g%Vk|08nG*y;#-cLu-WMmK1e;UM%5RxdhL z6^$*SN2%HYqB&&Ac(*DYMaWX*UN%SUbNnkxs({@)qP31;vQ#dw4$T{)<6%Gd98q<^ zR-@zgxx8YV9deAMI{jOce_gc#F;C2x;NV}TC(-pDU2bU__tav5)A%(7HVW2%LA}IJ zRW)mC&ZtZ1A~lb@&ld2jMf-^v5UvD!mwvJ>aKZHq`>7Za{_`#rR5Sdmj(YTfrSD{E zEUf_6Dw5}65g65X$1LJi2U|A_jC^2fxm0QE6v^uxoT zR7aiC#BEnNhQlDQUDJL*V49f%e)S-$2Sw?Enm^D~Rf7q7;s;M@5bhCmT(jhRPN6>R zMRl?MM{E(H-iY8myQveb-6iIRJS9w~?LLiKU|o9xwGe1U&iTSavSnEM4fBC2hDYRjGUtXL#bID-M>FI@Su z))lwYL(AD3%xSIT3$7}oeVu-RIej%3Uz78mVkge;N&25Q{(-L065);-_lhfev(PQ| zO76G9n8+z=R6U|5E#s?v5f-h5wJH-x9=|5oF&gG&rWzQ$x7~jYV|`@D__D4|C;+t0?&<>{!qW0b?yv3fVytJc^NCpov0bg#g|W!8siZT{SawT zZH$6;P0$CJi$$ifilTCD_)J?kR)_*)s?|NEgMR_&H94oan9&arU)#uQ>vlyuQ1A&X z38P&cRstfNF5uT^sLQd^uEnfRkwh#WL=5g1ey5}{Hmx6me<@q_>d`nPIORFA#`O&Q zB0b0Jos!z}Jbsn27lpmMY`O6r>(63w+W#>0!@r2;$@)!3T`s<$A4(}ktQD>YB`!NC zcQ2Y(wWim%CuiXoof1o;?z628=1mBReN#qLq(4#dmit?3UOyb5F;d#}_3RdcKJR!s z*e?1pee#t4je>r7h$kY|rtgcch$ZjAGvBUn)vBGU4lkffzC#NcTnO8WTdakW32U^s z0WaYR@*&Xb^jv%m&HE|+CKdY7Kd63%{v<-9?nl%BokXn;T|KWKo@%*Djn1N->h2uv z!noQb)ASrD;MXGFe7 z2ORx?E0143NZimaMEQ^@i5QlaUp%h_j=6@hdbu2zuIWX{nJepp#SUN#@g?)>e)2oW z8#DSL_*YzMz-p-&GOrTySQ2^cDw1AVvVdP_wQFiK)n~B2|C&~irz0C*63ANf{Oc0^ zj`pS9o76k?S7Q6q{;8V3r5jyK6t~kljbDyANxcqemz3lMUaxMmy2`@>D|2WDzf#cW zA2%(>Wde?$kT1b3Z_}U0!&lKN@7xYKE@$45d_NBGy%WJ?yU(zK2msH|H}E7!Cp`fPVs0l(-NHMF~Bo|gcq0Kjd&XFnSvPl$LKe5q41R?XU!8bn!$d1#v%YZUiHLV8J*m}4F+i5buPu^otp=|| zZTyqSs?W1VlxB;|958kU+qdaUDli0 z&>EYN7u+*Y@mBOTYUFFbU(gSCLtkxj&k=@&*Rn)&I~744F{r!S)DyY*@&UiL&>~@^ z!9fo5WdgF{YC24TAtaE3euxs?p8?zQM4#v058Hz+r83v0k?T%SM9wMji$g|mZp*OB zq5}X5^pZY@_3T%0(VmO1A-zewE$Suzx>LJ}{ugwlJL!^GVfn)~?=tx{vi~LV%bAm4 z6R1hh(@Yv^{VHp6`VSWH>jqG7G4w^X0gbRF7A`{c%4Y`f<;i z)nhtWZ|B`}!L9zPfM2_0|I5LfucD)RHL@m)P+xg<>Nb9V9=}duq#Jk%x!mR;;O@$?n?Ul(aA()5~Vr+S{QSlK{(Ph5>O z`aH{D%=52nQj6p6wAx75?faa7qb{ab!b@n)VVc$t1^QoygnvECo*MU2WN~0_JqgF_ zxVsDd3y9_fy7fKGYmF#%5=KYQ=+aeEd&A<-;*y^YmS7hg?%u(BmbC^=} z5uHkW%DO#M6QUaeG&yA~qtl&B-f@3WljmP=(d*S-D+RVi-xn;62A>q%YA)#yyYl_7 z2`HrtET2_Q+VhMY1KPU@QO?nqvOT%@a_0SrzVGu|x=lVhr0q!=1FissARuENzi8eV zUEoVC{XW%#))aabEs_Q7m>32LHAJpHOe+Vp8v=4@rs5LFT5}rsbxprcO)mnV^ZMZ+ zUFNcn_Cz)PAiT^$l9@oj2FH-+^Y}HNAEpIlz(%5XrUJh-Y<7`)G;i9MaZTe_y6Aoy zCO`F7vQBG<@H>WCJRuz&89nGN=!g1&&iO&3ik0&%0==Y7?25KiR8NGzRlqMT`k~cG zp2e+p^wp(}j;B&R&VD1GXK?|)j==fwUubQ*b!y$U2omGCdY0ZJiC;1u>*b^_d?K3bO-U1^rMz2>dcSV&im%m68!v*UOS^R6r zy0K@;Q2$=&nJ41t3#Zk8u|Cp6q}#^7 zUr$k8)JVkqyyr`Sl}4g?LODcrEk1Y{X5wqm>}>NzQGpbZLJ)9FHpUNeD_kR?zfQ;3(;oq9UuSXYh0Gon3gaw0s^_qt|#=;q*=84%R!` zUM4$jRdk)a<+)j|3WnRI$Xq7(|+5J{xXs|;_DW~*R+0UVQQbFr&_-d zW?!_PqlL_HVvS0_Wt0B(;&5(GeR?^+8Nb&qYgfOZ{SQ%E>si-zC;f-L*m5_i+gSFu z^gDLb)yOhlYN=TuqdDJEFVdfoMHdzP8}qKv&E(>!KUHxBjj(1LICzv^iX$;zQ_X4p z@D})^%<49v=Oq-1^}Lh=$hOLe`=Eed1N591d^yU-t*rp@l8M-nmj0?I5tVovOFmFk zOVR!W6kw}G7AJnLSP0fGy;c}OZ`BO{+Cwim!@M-9rdg|Kj6QlmJ)*xP4v=S-f8$NM ziT+oaEoDRJktBHK`{F7!Sh&dJ*Cl#IU-Ff`@2FGO4Rc9!&A9roRBCYruV@D(_Xslf+k|@KY}LNlMh&cl-x>ruMCAAA znpNC|PjrjPwF<%lj01BS6fW?uB6$l@$wqoffsSOOmbgsA4wl45?IaD0?RXwQJ^pOq zm&9D86xkqqE&Hg%&b^q#oFo6bVwKE}?PsALia{cwTa>-cSB zDu#uGk`MUxHt*%$lsm!l`XRT_`bn=|O25#P3gSz;K)T|VSZJ}S+Ic&GUSnhN>(m{CDA&$Xx%djhlmoZn8FahG0EmsIC#0roPr`OoI!iyqxTv`eY-@^c zc$=wT%AsF1C0{P|zb@eSAwMow-E>R|QfUJD2Skjt;0*tg{zDl}=zp26&B)NMi26nJ z@h#+u0)8FT=Ex`f7uG~ScEG=;*bmvii|RD=!#w|bITkammA;@1E4%hXSFpT~et<;_ z{MwP5_sMx9;$>~|&NXlwTF>z3hD+DGMyxj~_dmYod~1P!p%nR!gaEX?AR3g$6}TfH z)UTbTA4&->)czS$9YlH`4*TV}-k}EWPUQKQ_GLQ6z0vlaY>w6`taV|S457w*Bf6lwb~qAe@T=%j zmVcFwtKZarEA>Md!05V?y(st(NuYw&v;2$7vlmrxdC80Ix%Vvnhh18oQ({8ul$wlg zy1KPP%8=~hzNIE8qY65xXo7Zs<2vh@awc$D#rC%SbYxhLCQ$iD}#^`Z7Hc)f{wGPl^30|M=?V zaO%n)>ut077a#!arUQP7=k)qfBNH=VNU3&uzs@Fe-vjN4sT20?(z9Caf0UTR6yGYh}gSVK;X z`;K_u(O_&7tK+CC^=@y}NEY-%Fc-m6(BdYdxF-y=M_TLBz1zS7tlV7anxA$9@DN{P z6emkSz;U4W*pex*TzpCXC1n=4!6!__JA$Yp&CvLkb3tlEKC@kVR;p^;rvWtNFP5tojIhMeG*X&)si<><3*Mi?Kzq zc%}OF++3uKK1-dOZDN)e7$<6vVN%?4yP|$Oe5-fU41P6f{R1_%`orune@;A^_Wd{4 zoua$5-qtsjPuGXiKmX!fcu1=&QtVH`TF1S^@WZIkDEdtG^Gr^K?0>cV#r(Oz>};Z! zBA;|TuNv3HH4~&}s(@ebGwcgc+zvu-b+qY%+f>)kA2{ayI|cmOHH}~FEN$hOuc-P( z2xX`bgWJky_}5Y8XQIZ^!|V+SzG?j&dxQo>wQa0pNkAR`!j-38d&oKyUdm2dFiJVT z+VWLUt+61Nw&d~aP~@%5zC_=}uFKX54X-z?{P(BvIRGCMz6Ye7H`mwm4@-~ZYm4kf(YwG-kt1< zx%3}eQFN270)8DL#`Q#OjNzUZaI36GQT|(b{#7K)!idXczmRor8~pRNe0Qa_68IG> z;1}9n)E8GB_%|9GJl#e$OY`BnvhBTj{`G5E3V$B;oWVK-VQF9cx^Y8Xwh?i!s}JSk ztEy;%evfgL4zy07#L5nE0|FKb-Wx_9zfxvg^A1h(FH4a?#QyoWq&G4^zzo+xgFkdvF zylrJ)_<-?cWReEFa3kOU+Dn(sCSJNv{XKnvM%bdAH52SImm)^%EdOC@aRd1~Ytpcd z0q8}ArJtgZ?%tC3&lfG^+Z_wK5>N(>FoA;H$F?!{Jv|+E<>Jd%^ciF}v?PFEOu|-4 z&{bx}VwM>m)bsr>$h=hJxH{Myd@HYZfCYEx-)a4lrFSr2?t6yxJFPKs@4M)O++Z&P zwmuU!8j#2KdHq#|{@0TXEOH!Oq4#XSRwuNbN&4^97)K@jK)&l)8+a>Tcc*M9bsXPTFkYF|a=c`XP)QUyD_CoT2(o2+`A+f(i)FTs`Ij#-aaJ zFOVvOv^lXzgWj9RF9$v=?->`yjyd%ULxWKN7%udxf`2|vCr9DuA5q_sQ0sU`DoW`D zhyFa&o5!zrtgB{IO4+MkwB$W&lU*0%aB-t=r{?+BhxCfyC_T+OjL@3DO`}$Ia_( zh46G3dHni_PKzZ`cgpy>q+J#aMddWsxx`xAQot`fD&d(?*MSBGQUD--5Quin*j(UW zr>IBq9>YEDlpw!~#i`yP11%-)rOGbqFAsh4@VA!2#{b&((E!7=@y z%K2|tQ?zX8aW6YQ8uEGUntcE32)k}$X<<8nel5`qurqFiZwxel2&S3mUx-0WWofm# zkxoYb`AmOOeGhrQ!SO7eg%+TPwFF>Z7-Th|#xuvRE(+zdqnij+>13*o&rr%wtug z=mT@P;!$SnhnS{gWoZ=~1S(NxjMrS^?@RvW6!7b!oMp^=#gFtIU?in$p<+ zmG^H*{6c+5t}1u7aE-Dm9YI8TN9@%+epycnz}7|fLy|_0TQ|Y;|D5>8^lbme`xFlc zoc1Vov59rI?>1s&CizBPKT_~-4AJ|n$#(CB5oep@O_u#k{Riht{E=bzGX?)fT0@Dh zVfkeQ3M#^8jSuLW)ocRMX7#_0+cLd(ZlKHX&(Hb3IuX8Ho~@P(_{DmTc_U$Ii9gf^ z|NIV_s6_x9oj%t8;$UP6_IvudzK9#+>=L|cxR}Miv`8o1^1ffOogDe6&4`qr<9I(3 z$foPVk{7~O)+`ZyS z&sXN;`PUF;5LIphu!TI&QR-im7XzN%1^oJmUO_%Ir2nw*JI%@72WPfE+ybwl%>q2BS~wC5n~XD6Jdv~fgz zpRPDf8RWX@--7>;WuYz6ihpEbzk?K=E+gAObjstG>?PeN`ZMZs>!xg2BY9R{3pdB` zJx*Kpw>q^=bcAYzG42|{h6V3j^ob@c#8;=0M(Jisco#*r1lz_+r0!ZRNtn}4HX+c{ zey}VXzwY+h3$@Bc{ICZ%#XSG>;ItWuJ=}Tj6^tfI(T4Kh$ zx%$wV_frLoY_udphZs>e--#%cdVqZz`xGZiwf98$hfGd!c7SP^g~!<4X9wN z^Z0du-(=0>Wf@Q^jH?rbK6fQnFPt{<$<&>1Ay*_JHAvD@GI)-GW{Q}uF_61X}X5^IcfcXhJfbYkz9O1Kcw$U z{cs(7gMeSP;fKAC;G)_pIa{2{&1sf@S&fdTTs@W5y4}H=Q`phmkZ_Z_0~Hzmz`yiA z>ZsnOO%wtt_gv~aLO11(=3{E4I4bWMD*A(U(t!#ZRR7UVO@;;lThNVbmv!Jp<@;X) ztSgANao2d?>hk^#+5g%q9?ZDT#{QQ7P*k7SzYhG`nw(EnQz#TI z`CH-2Q`y||l}6^)y14hkr-QDIEl|J77I&v- z`8POhhfEP&X*RX4iJ;rqltHcKnT1~$Wz9e4mUaTvV~&5oSYRKo9G)yo7_nR|%l%)6 zoInTiSS{;~VlH;I+^s()yd9ohs6evuCH2EYdLV+8sWI>`Y-Enr)}s1~U~lr4nfL<# z;?Du!W{XBWhu6--yHN?=S08SPJ{U0^K#wqibAkRB+u>l_GBGzj-sN|;jR44=FfHr>VAK6C_&4ZT zUOfs5bG!I1AOK~U>^Cih5ivHI`<@{@!2cHe_IN(6mWf}BMd`AXu>-p)7h7fP^8Wcd ze#%cs{9@`)*}Lr+mq2<)&LmHwt0fm-g#F9FFW3OoX6tl!a~ia(iGGJqx+m2c{-qqz z9;JK649*()lXxCiT75YB62XYbT~E*8*Dm_DxsdS85F4q!yCec5#}BDG0T!9(U#Bdv zEoLlYeVX9d=0U98+D6bf60vx0%@55xf-ZT3?Cgzm=r(3;Wk-@c+dTofDir; z{O&Y{vr!s3O#GvFkTaXcQHRgMubU1k;goTNei#2#%pFyi>ZlYrh#0ly@QXIm51hNv zepNS`BUR1js!61R-?lVAuxhL;I)h(+<*>dWT@qt{*z^3OkSuDW@hXeyHdZf}u_OH( z*a4A78+Q#Q$;VxUA%oNqE?TDXtLR~rsmrKDutq$pUm!qgv7&;C+sf;Qw_Kxh^eIB! zn=^9sI~5r^qevht;MX;F+G*DPXVq&G$Q<-5Lv&3nwmgmz?Bb^}51$_oU| z)6z#iAJCrf^rlzKXSU=$siHLRvizDZxiAVU!i999)biEj@^)tLapu{WBJ3U5SDp=6 zCtGJ8Ru;r>8v=f1e~ae*8FF7^5ZU;e6l@(NYG3?Au`GRCpGvuV(#nW+(}v_erH+al za``zha$Gm>qrbBY_%(#@8Lq@szSr^r1<5VcT6_``_1y*h(yd+#Vt7KF0 ztprDXRR1*7b9q(vzq%;dT^3Xw7%=cWK~+aF5_I~Al^4sO0)8c=9J*QJ7t0domFgM# zGy7juHr_fuCo1n5DoSG%LE%oKmYFIF9&?Y(@zZP6^!dAN)ipgAa|aOJvi}9x+Df}A z%$ccdp??&p{mL~kj}>oTQN1yhNa z;OM~}pCy(2DI@5b{+`Kshv`IYal$`T;nT15g@k+WC)?=@qS5ZZP}u(^nak0t{?68M zy2MwQo?|shSy^eG?gIb9X&WZ8`uEk^tdYZ=P$rm6`0iQ#ufMY7{wANvYAbr8*yxmC zVOwN>*t;?s27T} z>v;hFsMF>WUIwg&0+f%7*Q-p^cwRa$od zWd68{T@u=Ua>rFy?t6Siw~lV3>Q4PDQa==4TetAnk8X5tI_A)OY_%57h-(lN0- z>JH=LQfzV5J=N-B+3$h>&~=qBchD!gi0y1>A&J&3eyzl~ru9Q!bc6mlzW5?|T*!IZ zUShjn0}*=}_=Qg*xq4$r`g?=$Zy>%-ZLyx}_I<9nlD5pnTzsyeAMT1i*;##}s)L!o z{4Nf|(Z?4orR^M^w@WUbdxuf%U+z_Eh` z#Vm?wvQd*@(MnS~J`q@TdH)8X)~Dd8{ep%$^1L*P zha6nMe~A2yh@;$m*>{{_(yd{PS3E2eql1>;Ir|fTWQpjT&g!u_N zOmh$*_$H}~s?H34?WLRA3*3|WW5nscSjd)@;318qB^?ziwp-z;Y2Cd+49ER_elPA%v{RvNUEhgrUwNK z@RJNX)Fgv0@GrVqd6gTmZA5OEFE}0mnSztD#ysscxpe&coK@Dx^g{~8K)dc`zl41V7n5{Fs}orK zS8~54`(FbxnlP2QayNUSEKpEK&C(BLJH~HPEnq9ep;>{5ae4Sd!M_3iCAGnw6=Z8ECV=nQ^I{^k7~`d_$*ysL~~v8Ay`fnUbi0)9#UWkvK#wwZc3gdpU3 zMdFvSZsvRd$-gp4%WfU*9r|XII5X`gNy~dlC#f8#T&& znD=i0FIdw`_kc1V!-0`ruGQ1Dn7hXz%5}&&U2cv-KMeSM{p$KypY25f%+gGHl3jv* zHWy#gzwuNoX9gljgwz`t~y3^T5Ov-}R&Kcul1O{M2bpod2a{Oe8zyM^ta z%(lH2M`7fU`@iUG(4d7vF$$mFX0zTg{@qQ&dM>8)UJ> zaZi-B<>Jed`@bychs2JFrw9ojwXuL8kTR;+y4<|Ozk#gYkcQOx9^M%aKrq!(1PBD} z16^Oq%_;boj`KGhDTiWTc2feP(?#vF(iFsr9D_(P_{*Ljg%*-KT`>jy14fQtsgKZa z6N}QGN$eob-qWc)Oh>6+_|oN5DEYk0aZZJwkmu(@Bs`ysFHr>RI0aT_OGj8B#&i+e zAihU|vqrKwotsl#)4^OIePD@_jj^I`sRg3>37YVzA|D6(VS6?e$odEMD)L4`eL&XX zj?5BjZr<;hqD!<$MqGw|ODiN1gX1?VBo_D=jy(hl_c>n*l5CBw$rz37ceLL@hRo}S z)3i(44(}Cr+bBHT)UUx930%&NJznIHKqd#xAUr%;kU=j50WI5^&FhD@6?b_FL$<6# z`U2pxw?13gyAm_{ALl-a7>?a<@LioY^u8{3UBiT z^Rhr+FJs(@0nx@6Jyzgfo#gOf*sZD6$Q!{S_r4lGKZ*02Kzz(;{3`NV$P&@;7FNxB zqN=S=p_b?u%)#vB`PUi-ww3TL-`2-sVOx}pxB{#TB@bq2ntw$ViC@_NHH`&BCI6G% zMToem@a*$9#ET|)Q%LQj(b}M>52|iDY2kTh?f=TEh23)iTO3C0?*}qn*Q8RK@?4)& zz%Q)lP#U|ip@&mwzz<=3^rZRqQFK`H`e7g5DoVZ_=34Qp#q4&z)vP`XpK{*6@k81w z^M-up?}+Ll7!f~fcZr4RaFzGt`eF8aboktbE6CR3n|%(=+W$3#uo_OFG3WyT?iX&m zq642izf7Nf{)RTCfG=ZZ(na1xr9$n*K~f7o=0B7b{=c-#bgG=EAn!}4wsjmqvnEl& za%(KBA2M&p>Ye2iNXw`Xcd9rW%H@r?Ki2FD0euAZ(k>Ksy3jHsfs zUsiu_UgkJ<{oBNFaIrup2v?v#>Rmqg|%@7KcZX z2NLSGJbu9~k2ytd(WHCV(^<2d(t3lwrf~ita@{rxB%snvYN*v?#`$tM678A+Aew6i zzt+%qS*?R@DM%pET7m5IC_N!uX%y|QJbp3R&&}e+Rxw`y0&cao{7#5k?#nUw26+#r_w{VK2urJ(=fUMYV~;C4u8`YotL&0#sG) zEmfYj;EupOxw(+~A(%^A4;GJMWk?FsqT`!w0V4;?;g{k;1YYh6~HRlyVBkV$f zf1P)FV<_iF*dHLhF8VES`JB@$0&)GV*fe&>i&8*X%Q1p1r9((e=~R3whS?##x^R9} zT(Zau_?}7n0VYo0?3H{cU}8Pz`Bz$`(xEis{Uj1~z(JzEsJ}u@mfu##XZY6$yUDWj zYxm=i~q*p0twpZw%7qDEdSP)P+(CcHFzwy$l_(2&%8~8T|6&^?EPJ`mp=? z-JbEV&92e!Ec7DN?8Dq#q>I{Uf2Zxxa;D=j+l`K|m`QX9aMTi0x%je_PtXekH4+PM zrRTim_BK9g)H2(M)_;chxt3SX> zTV%u;3!ooHxdH|R3tI>c7K zV!1ipp9Zm^(Dni&WAYOv z??1dKkTZcqsvoe`#Mc7INM5X&#lQYuI}}D;CvEdjVG6+CCuDudk;C))A@~<&5EY1D zfSR=#S+k-q`$-Ag$89-MrgX^pg8vYdvyS@`EfYMu0cU6N1gd2)&Ds79 z@9{9w1@?X9hdju{6kCbI|l8- zu^aKm^`KoZkG>>Uq&-&({==sP&bf7v)qigxcB(vsD)#wO(>XX2r}0ake|RIYI1RP1 ziLMDW!p^BTtY3;H8SMX>g_*E6kvFz*JmD<=VS?0y*&!<=_bgkgx4aCi1sMPuIFmDp?QOJ#R)oVmfwcsGH6(W)HSTJ zCF7pVoIHNLL|25YH(D>oF&7S|>7rgjFy16*@JsS9oUk_rv}zI(3p{D{9G$L4gQlY< zk6-^J_N41%<$z;*#aAQnZ(JndV2@!^&G)}7SRlL(>}P2(*~-81BL9{TO}`Jxz6v zPagGCfOFN#EC6 zCwFnolTn9?vuo8Unxa#+OHB8ux>USkE>5{$t9fMQONsl=`)Bd5Kk&HYJyW%%xYp_K zsCl)HF&ocZNA664f2BNLEuU@oundFQ|f_fz;+u3*;iS(dEvyLzJKqBL1JKkA5nNdbNhv^p-#h2u%D z9&Q0r^FB2M>TJj&R-oh zU#Cj0U*DGJU#ln?+lUgPOjEj?=viHNsn)i%kNX;D_?M;Jsvi)5t@isrLEqh6o&K-? zb^YJ+Zx7eYv)uJueBt~k+HVE$Jy@$~U^#ApV8`gf zOUw33{yCP%uOHHLqT13od2c1uv=b%mETr|tYb-=l5V3?m;FkctV+LDvuPhWlxg7hy zx94`8gg?Q#`DP(S0-Le(iF$}8xD%V ztPzpayngr=m$KpQiJDq$D+qGGiF!@J=rvjCfGA1{dGv^Pwot)Q9r?`M4Oi zP^yI}6&tnyWY7jAijx&pYg||h#_v+ixMu?~De7Dw10v zKCh3*DhD>#J;UKLox!iUgTOD)Qi;ot(n1J{Y^nZJ%3*hIF6^Q){rFgjHzte)gzYvQ z)K#NS#XlRrR>He$9py+V6R~L`HlaxV1rVRXFS7MGPZD6uLcpSpg7Y_!eM1UDdj`K& z`VukSD@xPFK6rcf;Ox_y_QZ*=e?sV|3i$O|t&2sG>%6)mC`wiG&~hP2lHyeb{F(#& zilZJw*#+Rpu!q6g<~uMQwG)?X75)v-E^AVMB<7-DY+fRd-GGl80JP?+@fE}Y{`AtH z+CZyQ#;_r2SHOY2VK2H%hhIgWj}=F=HvzwHisp=GO1VOEKP>)_6&jRR65qJsnd+K_ zU(d~jzqf;(lsS3ts@h@5GFAutO)LMS3B1{0h=+466 zOnoT#e_bW{JYH$hZ$N$qke!tH70mOmTjXhMcS-z`8^Lg}gEI$+h77rV7XSK?u3Jl@ z?u*%aqj`?!LtMatEIjiu!w#i$c}(huN$zdc z0cyUafP}laybor3A2%%Tgp|ZU?&KZcIe)hY1v76hl^ZaY>n{?d? zh5dG`U!K)qVrlKAli`LzoKTeKUrG8vK?#vjWMA(tLO}(>(stJ|6cu^?W%J8?I0E|S zm%IS)2L@D}Phx_x=J5-sSCJKrkEk2X!_@&1&q!dk84o{M&<}YvN~5U~n@KN?pP-B4 z9>oF@6;JDj@E< zOZqqN8TF-Qy;@!WS4ai7(-yMEN~7poW#iPL?*obMelWc5ewhCg0ADF2J}Mqey4qPL zk6!@U1;>C^{-P}Z3Vy;Z&$l^?Lh;qyykq||yqxKnh5iiA?YFZ#ef==dLN1#C$%Kas^R7!haVR|LlbtkbK?Va17p zf9=FZ43I2z#Pa+L`STEeC`ypdsK>%Rm32kf*&*+lgc zRuy4;%QH*H$}$)ZXfp6Zt(E(~tXOzvp*IR*YT0hF=B zE;9zWAt@Uc?}VaQz0wsaoPYQu7hpY%|38H`)7%Vd?xX1+U&d$vsD*W6!<!i+m3leXhdNqSaZKo|uS>dDZCGHc;U zoGCQIgvJmm+~ffL(OcEDfp z7>;0)$fs5I7n?Aro1URNr!c_=_SdD_hlMLkmrO_gRQ@*>lQ@Xub^1{Lu+(}s;4hpX z_1iqWg}jyKZ}K?awuBA8NaT>1WX1yi5*M8IGTcz@#w*T-nWbl2J`l*?$fLw@=R@Rg zh-YZ6G;s_F;&Cm<@kx~TsTgk&DG}t)i%0vgHKSOULH^;B*5wXjWK%KtJjvXlJFb4& zarMoPsq2sFgY>vqHHF1(nFbu&GOg^St6zwJS?7vv#+qZ1WBPv%;aGJ9x%8I?kBqXu zyM2oImvzp$G#xH!yXo)6a_5G02-&=5+ZcRJp8t^dFMm(~TbB3Tt)E=cJ{INt4V=Fr z!HiBvn){+){5d`6wAiU>YK;%bWez*0cts@ZM)b0}QkB>&(O19@;PPovaZg zO6{j%0js3!_Nj`08N(W{)h*o4Bd^57;tQsLN<-T4251e zp&Z|LP)cilTxiGQ89Kaf}3=$-d;{{9zKPpv@8O9T7MvEBhM zH@}JOkzd0BxQ5SXXeSn@WV%d|<@UqSvM@;8{j zu!X^xO=1hfPaEGC=VQ!h75;jHPAun<`RcTZC2_fa;OVzHXe*;5p}1l5^Gt@@%zbiG zU!-3@PR|LX(ZJUvj*ely`mw&=5-d~J5dSKz$Rfsyb2B6ny$wIto++>kF8jLp!TqqmHtSp5K2`biwDG!!^sgK@;XfRxU#}e(Gt?$VMT5^RR2`<{x7heqjIPq%rbi1G14HieV+X_8T&`D)j^5~eF|wC zt0nZE^Nq1^{R!|+Ok01r{)y1r63;VK-&CKU&&x%&%KRg4gc389yZ9T(5uASS5{>*J~w6o_wyhA%wQ#vI>PHX)<}1&G~4vRe;DmY$WLzTYxn^6*XkFyfxpR+u$Dkbe_LZRyX6@Ul!~yWcX)T#%4nd z0MDFU-4CnH^B?AUe~PfDBAfe1aJEhG;Vo~J-2Mz#H=V`iI#7ZmZYG{6z?7fJ@!2L8h#%;D#8{szpG_pPthVEFZg+U!@T zof95xcMg}v-Sl+6c??Whre`(um&9R!_hT|Quj%*n3;cy1#2K64&z3dlAY`C=SVKz8 z;kK_|QRs<^CGlB97@};W^}8~je#xbGBg<=(KwsdQVP9;AeWAakwe!qx`}~FI3Bk`c z(}H=!;4!ADd82@Yhv^!ZQ^M!v?0T5VGoi=mCjv2-NeoC>&~@9-wxl&RR;BeD@uPIJ zT>UT2NN>ok{nyAqwwz}}to~@lf2cgSWUhF4P~X=C`^&+7daUAp4vo+17 z%Li_2ZQ!)S(1GT%fHj)M3y!$+D)A7dbs|II zZ8#CJ68}0z7pCxDZz6vKuk&M$e;!O)#UkJeE#9j1i}raNDsYaZ+UI$KZI6E zG}JU^$iV*M^Ltmr6~(l*e)Wm&ztp2PN5H?BtJq%;5{}&{A=?niC*Uvhb^Xh9-}hG^ zOzzMF`wQ{qp*8zlO~RqU_Ba2vLdM9+j$%TDN69{h9UPC6mB z95zZ-_7@IZ*iZZ-~%WxJ`2H_!V`8eVZsoeE^mOD2yf4|avtsm>d0chobv~8>p-zuHeV2H`k zuU-9m~1qV~*X-+R6+tRldc@EY`+Ew{wQ=xCW`UU=?cbyHn=;=^gy%)O4=L^iV zN(Zt3OCNBCZF8`W-SWe@UzP(5ipXAZ-`xz4)4{ymom$@9VHSwvUpgPefyu$bnpV|= z{6o6Gc{p?Un{)_kNXT&P4+kOghb$*t{X+gBqU0O0(F2VgI_Dp@s^{qj`3_a`4+jlw zA>UO$)N;mVUdHk3ikF@GA>H>Mg1=s~kApJHU!wnj zd0!J2z&R|sFrF=t!n9it@;Ag!<%XltvysR2UzDGkMgZ##ec~I}3_rBDl7ILlmOYBL zFlXL@&7t3Z@m+Dwh9MT%U*IndUkxjPtzICwp=JQojxhV7v!ROpMW>pY8oFonxbYp# z8*oIQ$MamC!}EAH5&I8|`X5S|T})(HI_AJ%54llk&;DZmde|uGW@^}=e?lV+)aozW z`^=QUyI1TlOoN+;qA$P=#rvCDOQ8$;HnF}J&s?#;yqT@>jLwOO+ly}CG6xyY{*u-k z$XDM`iso-@Grxs;%$d-6I!W!NYWr(9JwcC`Qt#+XbbcQ55DX2(mz}y1y<&ff{bsX? z9FMh7J*4oJ^pmu|VT}p?3hb{al`xE9e;M>R=1k6oAe?#bfS1Qy{gUt>^0o_vbym=< zzQI{G)OcRUJSGQ6D)!eYxYw>AOz#ZZoz)!wLOwPa&9}d3JQL~@r>!fErK1WgF~Xx- zUq+QU>y$3jct?1TcB{C>N*o91&HRA^becGn#Tpwusz_* zTp!LBa;4r>tPa2eNa&i7xsl%182RrN)o!GloJ2a@O#V4zd+(LkO}1tvdX)hwpkaTEG&A14#zi=<{W0B)_EF%kL_#jvrFEkuA^m3- zp*$vxO|(?{V891~Ox8#jqV`tP!pt84ygo|&Hk3qZ!rp1ZFbV+1lPa+-;tPG6mOXaJ zG{zKYH0j0gdZ)*3G!4gAA~c>2=L*yJ@QcnG`HjuC+5m@E~qClVXTu;)EskSu6|K=zFKwkYkfuR zPC;L|)ezNaJLQi2@?`kl0EBnSZj>aXC(|jyecG*b3nd%{ZlpK>^{5i>UY%LW%cNan zYW)hR0h=$tV~!Y=|IAs#MoAVQc2$5oF3x?5l8Q`N6moX2na~-eZ;B?eni%c1JIpZo z?-kN=PH#F94R5Uive!N#Gx-m8jOQDO!O!L6vwy;n=#4o?K(x7}wSb1~eXy36o2LdRoGFjD9(N z^I+of3g~uJiS(+$KQ@^{hsH9Hx=lm00&S#9JR!5=wph~XYKjdoFuF8=d@NZ+Nu{37 zT&&l)NlOR?5}GD5eu;lCvq^2@u<8nK`!N$P|65oqM;k< zlygOTX^#SSItrj2aMq=l3SY?7?xJ~Iu*72r$CqhIc28LAii0~n5Z&2g38x`l9BlGM zsC{<(?5nfy&t6yv0-4VOT7Mqd^y0fCPw!?h_Hs1{{(M7Q&rceEd;H{oDX^g$1Tt5D z?S^0c-4D*Z`w@eOuRQbhkFMU^J<<5onRos=kkRx$@u+o~Q9D`%GAN1HI=+xm&C3Bn zgO{P*zKlM9-Z1+866wnjeLA1|GNy5tcCozHj!jkpLP;v-_%ffZp832Cg2tfD=HYAh zu2shMg@#hc;aD}0s>G8pohYfPD-8$Ed>~x<0<%#yFGFQ9S*Q}BK|A>}oj`3|ZGrw& zKp~5_rJ0 zj52#-1D*oH2mH=_@x1~Xoe!it_X;gb6*~48CSHkD)lg3RUG=y!qEi?-El!;jn**>t zm*Tp6uWqWLjI{DbQdH0 z2@hQ41AnXvtxIP*zARZgu>d&gR+RfBUiKM(%xgnD^QW(S-FgJxeWy(3Ym(Z%3xITG zs55Wu)h?xLWvsja_+tb8HHViyf_8b?yBGRv4lf4;&AjZ%U~Gs24j?mQdNmMSLjHS& zDCfk};i$HC0T5n2P?c(44hWioE5hS&4lf4;UB$~n6ARTUDDm#KP`?62tCgM%+HkYB zjJD#y_65Le!yLv@8eWo+f$X38!13=Drgb8kgU4Zf0T}b|wbjUvCevLwOm+c~UK?tH z=1eELN6_vBqbd?wH`6h*u;S%8K>GI*9l2QC=+t7L0Q~-{T8mZpd4HuZXg)6o1P$Qc z3jOuP(2e5M)D;_-E(F4VukI=em`4hZR}nECH~73f2V{Ja|5IL`OUFJze>J$*LOS+K zE(9`jcsU?w1p=AoB0}dWQETbN=r_z%zApJzF@6wEhgy$ySkhPl1;~&k3@c_}8cdS0 z5u<^*C%AAtn`vfsOBQW_JhoRB)3Jf5&?_>QVPO>q9b+4oO_t5EP?1r~y#cKm zUN0n33~XR7U1^(~e&Ag$p$WD-t45$Dqr4mqWKsnz8#xSgRMn$%J!`P-3MKd}zDzPP zc}uCWTph;p1{*J?Lk`0{kf|#+96Whgtg`kO^@CK(Flat#a7iGOG*-eA$6Is*P!UG@ zj+zG7Hs>4R!m%mE%}oXtwN|M}O=dKsSwr`%a7+ApEDLIWlDayIxE>(ttRsDC6X=}5DluE$L`@k=$uXn4# z|DB6ms7nkjx=5nLEvWjxwA~-@;L{-!oYF=Rrvz7nD?kb58Jk271w8&8>^~ z7gGl*l|^>Wy=ee}5BK?(g{6mq5tW24qn)ADgu!OeTwRVTU5-PSW0IA6=pNf0V}3Q5 z69~gWP@I93tkgB@HRXp0WL#Z_#<4D&1GcNn25Y5vxhkwiW5 zAd`geMETjeja7J^jH}d!gi;4GR*}{jW(LhtwAN9S+o!m3CzM(bWGsT_PO=J@l?nsQ z_+XAM8))8Sxo9=9#cPq$<()x2IN^d2FN7|mW<*>dWumFENX8km!3E7t6Z`{lXkOZg z^0sv}Ks4IqJuw88P8w(m)A2Obu+VCxp%W?4W!tMVP~iZ0zo^z_UxfqhuF_?RhG!KH z39jG0gb)0GZRsNE>9Q&P5?=zt)>b%9$zTY(CB8_Y4xgW$b=4s#@kKsSzdm$lfKQP5 z&3vW)1ew|YcbVX(p9+xHuW<*bDSO?g3N8L(u>}@eV6g=jTVSyT7F%Gk1%8iPK&_Xs zV8VJy{2n*M;;S#Vz+ww5w!mTwEVjU63;dq8KpLJuqFujAlVk^7C{3dFvowV#A5K$A OIriLoM!!1$Z~qrf_Yi^r diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index 92ebcb51..097b8a08 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -33,15 +33,33 @@ module hi_simulate( output dbg; input [2:0] mod_type; +assign adc_clk = ck_1356meg; // The comparator with hysteresis on the output from the peak detector. reg after_hysteresis; -assign adc_clk = ck_1356meg; +reg [11:0] has_been_low_for; always @(negedge adc_clk) begin - if(& adc_d[7:5]) after_hysteresis = 1'b1; // if (adc_d >= 224) - else if(~(| adc_d[7:5])) after_hysteresis = 1'b0; // if (adc_d <= 31) + if (& adc_d[7:5]) after_hysteresis <= 1'b1; // if (adc_d >= 224) + else if (~(| adc_d[7:5])) after_hysteresis <= 1'b0; // if (adc_d <= 31) + + if (adc_d >= 224) + begin + has_been_low_for <= 12'd0; + end + else + begin + if (has_been_low_for == 12'd4095) + begin + has_been_low_for <= 12'd0; + after_hysteresis <= 1'b1; + end + else + begin + has_been_low_for <= has_been_low_for + 1; + end + end end -- 2.39.2