diff --git a/lambda/.cproject b/lambda/.cproject new file mode 100644 index 0000000..53d0420 --- /dev/null +++ b/lambda/.cproject @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lambda/.gitignore b/lambda/.gitignore new file mode 100644 index 0000000..ac01e66 --- /dev/null +++ b/lambda/.gitignore @@ -0,0 +1,2 @@ +/Debug/ +/Release/ diff --git a/lambda/.project b/lambda/.project new file mode 100644 index 0000000..81cb2b3 --- /dev/null +++ b/lambda/.project @@ -0,0 +1,27 @@ + + + lambda + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + de.innot.avreclipse.core.avrnature + + diff --git a/lambda/.settings/de.innot.avreclipse.core.prefs b/lambda/.settings/de.innot.avreclipse.core.prefs new file mode 100644 index 0000000..7fa4086 --- /dev/null +++ b/lambda/.settings/de.innot.avreclipse.core.prefs @@ -0,0 +1,23 @@ +avrtarget/ClockFrequency=1000000 +avrtarget/ExtRAMSize=0 +avrtarget/ExtendedRAM=false +avrtarget/MCUType=atmega328p +avrtarget/UseEEPROM=false +avrtarget/UseExtendedRAMforHeap=true +avrtarget/avrdude/BitBangDelay= +avrtarget/avrdude/Bitclock= +avrtarget/avrdude/EEPROMFile= +avrtarget/avrdude/EEPROMFromConfig=true +avrtarget/avrdude/FlashFile= +avrtarget/avrdude/FlashFromConfig=true +avrtarget/avrdude/NoChipErase=false +avrtarget/avrdude/NoSigCheck=false +avrtarget/avrdude/NoVerify=false +avrtarget/avrdude/NoWrite=false +avrtarget/avrdude/OtherOptions= +avrtarget/avrdude/ProgrammerID=programmerconfig.1 +avrtarget/avrdude/UseCounter=false +avrtarget/avrdude/WriteEEPROM=false +avrtarget/avrdude/WriteFlash=true +avrtarget/perConfig=false +eclipse.preferences.version=1 diff --git a/lambda/Makefile b/lambda/Makefile new file mode 100644 index 0000000..cb77e29 --- /dev/null +++ b/lambda/Makefile @@ -0,0 +1,188 @@ + +##########------------------------------------------------------########## +########## Project-specific Details ########## +########## Check these every time you start a new project ########## +##########------------------------------------------------------########## + +MCU = atmega328p +F_CPU = 1000000 +BAUD = 9600 +## Also try BAUD = 19200 or 38400 if you're feeling lucky. + +## This is where your main() routine lives +MAIN = lambda.c + +## If you've split your program into multiple .c / .h files, +## include the additional source (in same directory) here +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +EXTRA_SOURCE_DIR = /data/Work/AVR/AVR-Programming-master/AVR-Programming-Library/ +EXTRA_SOURCE_FILES = USART.c + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## + +PROGRAMMER_TYPE = avrisp +# extra arguments to avrdude: baud rate, chip type, -F flag, etc. +PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM3 + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## Compilation options, type man avr-gcc if you're curious. +CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -DBAUD=$(BAUD) -Os -I. -I$(EXTRA_SOURCE_DIR) +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -Wall -Wstrict-prototypes +CFLAGS += -g -ggdb +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += -std=gnu99 +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC = $(TARGET).c +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +all: $(TARGET).hex + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS) $(SRC) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +disasm: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +## An alias +program: flash + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +avrdude_terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +## If you've got multiple programmers that you use, +## you can define them here so that it's easy to switch. +## To invoke, use something like `make flash_arduinoISP` +flash_usbtiny: PROGRAMMER_TYPE = usbtiny +flash_usbtiny: PROGRAMMER_ARGS = # USBTiny works with no further arguments +flash_usbtiny: flash + +flash_usbasp: PROGRAMMER_TYPE = usbasp +flash_usbasp: PROGRAMMER_ARGS = # USBasp works with no further arguments +flash_usbasp: flash + +flash_arduinoISP: PROGRAMMER_TYPE = avrisp +flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM0 +## (for windows) flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P com5 +flash_arduinoISP: flash + +flash_109: PROGRAMMER_TYPE = avr109 +flash_109: PROGRAMMER_ARGS = -b 9600 -P /dev/ttyUSB0 +flash_109: flash + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Mega 48, 88, 168, 328 default values +LFUSE = 0x62 +HFUSE = 0xdf +EFUSE = 0x00 + +## Generic +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses + +## Set the fuse byte for full-speed mode +## Note: can also be set in firmware for modern chips +set_fast_fuse: LFUSE = 0xE2 +set_fast_fuse: FUSE_STRING = -U lfuse:w:$(LFUSE):m +set_fast_fuse: fuses + +## Set the EESAVE fuse byte to preserve EEPROM across flashes +set_eeprom_save_fuse: HFUSE = 0xD7 +set_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m +set_eeprom_save_fuse: fuses + +## Clear the EESAVE fuse byte +clear_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m +clear_eeprom_save_fuse: fuses diff --git a/lambda/lambda.c b/lambda/lambda.c new file mode 100644 index 0000000..1882557 --- /dev/null +++ b/lambda/lambda.c @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include +#include +#include +#include "USART.h" +#include "lambda.h" + +#define AREF_MV 4850 +#define ADC_OFFSET_MV 7 + +static const char* lean = "Mager"; +static const char* ideal = "Ideal"; +static const char* rich = "Fett!"; + +typedef struct { + const int mV; + const float lambda; +} lambdaEntry; + +/** + * Table used to look up the lambda value at 12 V heater voltage + * and 220°C exhaust gas temperature. Most values are approximated + * from the characteristic curve in the datasheet. + * TODO equation? real table? + */ +static const lambdaEntry lambdaTable[] = { + { 4, 2.0 }, + { 5, 1.9 }, + { 6, 1.8 }, + { 8, 1.7 }, + { 10, 1.6 }, + { 12, 1.5 }, + { 15, 1.4 }, + { 20, 1.3 }, + { 28, 1.2 }, + { 40, 1.1 }, + { 68, 1.025 }, + { 400, 1.0 }, + { 800, 0.98 }, + { 860, 0.9 }, + { 880, 0.8 } +}; + +unsigned long previousMillis = 0; +float lambdaVoltageAvg = 0.0; +float tempVoltageAvg = 0.0; + +EMPTY_INTERRUPT(ADC_vect); + +void setupADC(void) { + ADMUX |= (1 << REFS0); // Use AVCC as reference voltage + // ADCSRA |= (1 << ADPS1) | (1 << ADPS2); // ADC clock prescaler /64 + ADCSRA |= (1 << ADPS2); // ADC clock prescaler /16 + ADCSRA |= (1 << ADEN); // Enable ADC +} + +void setupSleepMode(void) { + set_sleep_mode(SLEEP_MODE_ADC); + ADCSRA |= (1 << ADIE); // Enable ADC interrupt + sei(); // Enable global interrupts +} + +int main(void) { + + initUSART(); + setupADC(); + setupSleepMode(); + + // Disable digital input on ADC0 + // http://www.openmusiclabs.com/learning/digital/atmega-adc/ + // DIDR0 = 0b00000011; + + // Initial update + update(0.0, 0.0); + + // Main loop + while (1) { + run(); + } + + return 0; +} + +void run(void) { + float lambdaVoltage = getVoltage(PC2) / 11.0; + lambdaVoltageAvg = (lambdaVoltage + lambdaVoltageAvg * 2) / 3; + + int tempVoltage = getVoltage(PC5); + tempVoltageAvg = (tempVoltage + tempVoltageAvg * 2) / 3; + + update(tempVoltageAvg, lambdaVoltageAvg); + +// String tempText = "T val " + String(tempVoltage) + ", T avg: " + tempVoltageAvg; +// Serial.println(tempText); +// String lambdaText = "L val " + String(lambdaVoltage) + ", L avg: " + lambdaVoltageAvg; +// Serial.println(lambdaText); + + _delay_ms(1000); +} + +void update(float tempVoltage, float lambdaVoltage) { + int temp = toTemp(tempVoltage); + // String tempText = "Temp voltage: " + String(tempVoltage) + ", temp: " + temp + " C"; + // Serial.println(tempText); + + float lambda = lookupLambdaInter(lambdaVoltage); + // String lambdaText = "Lambda voltage: " + String(lambdaVoltage) + ", lambda: " + lambda + " (" + toInfo(lambda) + ")"; + // Serial.println(lambdaText); + + display(tempVoltage, temp, lambdaVoltage, lambda); +} + +void display(int tempVoltage, int temp, float lambdaVoltage, float lambda) { + char lambdaStr[13]; + dtostrf(lambda, 5, 3, lambdaStr); + char lambdaVoltageStr[13]; + dtostrf(lambdaVoltage, 5, 3, lambdaVoltageStr); + + char line0[20]; + char line1[20]; + snprintf(line0, sizeof(line0), "T %3d C %d\r\n", temp, tempVoltage); + snprintf(line1, sizeof(line1), "L %s (%s)\r\n", lambdaStr, lambdaVoltageStr); + printString(line0); + printString(line1); +} + +int getVoltage(int port) { + + ADMUX = (0b11110000 & ADMUX) | port; + + unsigned long overValue = 0; + for (int i = 0; i < 16; i++) { + sleep_mode(); + overValue += ADC; + } + float mV = ((overValue >> 2) * AREF_MV / 4096) + ADC_OFFSET_MV; + + return mV; +} + +/** + * Returns the temperature for the given voltage of a type K thermocouple + * amplified with an AD8495 (5 mV/°C). Type K thermocouple voltages are + * about linear between 0 and 800°C. Returns 0 for negative voltages. + */ +int toTemp(float mV) { + if (mV < 0) { + return 0; + } + + int temp = round(mV / 5); + + return temp; +} + +/** + * Returns the lambda value corresponding to the given voltage + * from the lookup table using linear interpolation. + * Thanks to http://stackoverflow.com/a/7091629/709426 and + * http://en.wikipedia.org/wiki/Linear_interpolation + */ +float lookupLambdaInter(float mV) { + int length = sizeof(lambdaTable) / sizeof(lambdaTable[0]); + + if (mV < lambdaTable[0].mV) { + return lambdaTable[0].lambda; + } else if (mV > lambdaTable[length - 1].mV) { + return lambdaTable[length - 1].lambda; + } + + int i = 0; + for (; i < length - 1; i++) { + if (lambdaTable[i + 1].mV > mV) { + break; + } + } + + float diffVoltage = lambdaTable[i + 1].mV - lambdaTable[i].mV; + float diffLambda = lambdaTable[i + 1].lambda - lambdaTable[i].lambda; + float lambda = lambdaTable[i].lambda + + (mV - lambdaTable[i].mV) * diffLambda / diffVoltage; + + // return round(lambda * 10) / 10.0; + return lambda; +} + +const char* toInfo(float lambda) { + if (lambda > 1.5) { + return lean; + } else if (lambda > 1.3 && lambda <= 1.5) { + return ideal; + } else { + return rich; + } +} + diff --git a/lambda/lambda.elf b/lambda/lambda.elf new file mode 100755 index 0000000..493abe0 --- /dev/null +++ b/lambda/lambda.elf Binary files differ diff --git a/lambda/lambda.h b/lambda/lambda.h new file mode 100644 index 0000000..49f8147 --- /dev/null +++ b/lambda/lambda.h @@ -0,0 +1,19 @@ +/* + * lambda.h + * + * Created on: 22.02.2015 + * Author: dode + */ +void run(void); + +void update(float tempVoltage, float lambdaVoltage); + +void display(int tempVoltage, int temp, float lambdaVoltage, float lambda); + +int getVoltage(int port); + +int toTemp(float mV); + +float lookupLambdaInter(float mV); + +const char* toInfo(float lambda); diff --git a/lambda/lambda.hex b/lambda/lambda.hex new file mode 100644 index 0000000..c58ad78 --- /dev/null +++ b/lambda/lambda.hex @@ -0,0 +1,364 @@ +:10000000B0C00000CAC00000C8C00000C6C00000E8 +:10001000C4C00000C2C00000C0C00000BEC00000DC +:10002000BCC00000BAC00000B8C00000B6C00000EC +:10003000B4C00000B2C00000B0C00000AEC00000FC +:10004000ACC00000AAC00000A8C00000A6C000000C +:10005000A4C00000A3C00000A0C000009EC000001B +:100060009CC000009AC0000000407A10F35A00A023 +:10007000724E18090010A5D4E80000E87648170071 +:1000800000E40B54020000CA9A3B000000E1F505B1 +:10009000000080969800000040420F000000A086FB +:1000A00001000000102700000000E803000000002D +:1000B0006400000000000A000000000001000000D1 +:1000C00000002C76D888DC674F0823DFC1DFAE59EB +:1000D000E1B1B796E5E3E453C63AE651997696E87E +:1000E000E6C28426EB898C9B62ED407C6FFCEFBC02 +:1000F0009C9F40F2BAA56FA5F490055A2AF75C932D +:100100006B6CF9676DC11BFCE0E40D47FEF520E662 +:10011000B500D0ED902E0300943577050080841E45 +:10012000080000204E0A000000C80C333333330FA0 +:10013000986E12831141EF8D2114893BE65516CF3D +:10014000FEE6DB18D1844B381BF77C1D901DA4BB49 +:10015000E424203284725E228100C9F124ECA1E5FE +:100160003D2711241FBECFEFD8E0DEBFCDBF11E089 +:10017000A0E0B1E0E4E1F6E102C005900D92A638FE +:10018000B107D9F721E0A6E8B1E001C01D92AE3871 +:10019000B207E1F749D20C94080B32CF1895ECE77F +:1001A000F0E0808180648083EAE7F0E08081846011 +:1001B0008083808180688083089583B7817F826097 +:1001C00083BFEAE7F0E080818860808378940895B7 +:1001D0004F925F926F927F928F929F92AF92BF9257 +:1001E000CF92DF92EF92FF920F931F93CF93DF9303 +:1001F000CDB7DEB7C254D1090FB6F894DEBF0FBE3B +:10020000CDBF582E492E762E672E49015A01C801BE +:10021000B7016E0126E3C20ED11C860123E045E042 +:10022000B5D47E0189E2E80EF11C870123E045E0A8 +:10023000C501B401ABD44F925F926F927F9280E080 +:1002400091E09F938F931F9214E11F935E0195E1BC +:10025000A90EB11CBF92AF92B9D4FF92EF92DF9278 +:10026000CF928DE091E09F938F931F921F938E0109 +:100270000F5F1F4F1F930F93A9D4C501F8D1C80179 +:10028000F6D10FB6F894DEBF0FBECDBFCE5BDF4F09 +:100290000FB6F894DEBF0FBECDBFDF91CF911F9197 +:1002A0000F91FF90EF90DF90CF90BF90AF909F9015 +:1002B0008F907F906F905F904F90089590917C0009 +:1002C000907F982B90937C0020E130E080E090E0DC +:1002D000DC0143B7416043BF889543B74E7F43BFBE +:1002E0004091780050917900840F951FA11DB11D98 +:1002F000215031092115310561F79C01AD0182E0E2 +:1003000056954795379527958A95D1F7A2EFB2E193 +:10031000C0D12CE096958795779567952A95D1F76A +:10032000695F7F4F8F4F9F4FCFD29DD2CB010895F2 +:10033000CF92DF92EF92FF926B017C0120E030E0E0 +:10034000A90125D287FD0BC020E030E040EA50E44F +:10035000C701B60120D2D1D386D2CB0102C080E042 +:1003600090E0FF90EF90DF90CF9008952F923F9212 +:100370004F925F926F927F928F929F92AF92BF92B5 +:10038000CF92DF92EF92FF920F931F93CF93DF9361 +:100390006B017C0120E030E040E850E4F8D187FDBB +:1003A00074C020E030E04CE554E4C701B6013ED310 +:1003B00018160CF46FC042E3A42E41E0B42E00E006 +:1003C00010E0E8012196F50160817181882777FDB1 +:1003D0008095982F7BD2A701960128D3181644F058 +:1003E000F6E0AF0EB11CCE30D10519F08E01E9CF89 +:1003F000E8018E010F5F1F4F36E0732E7C9EF001E7 +:100400007D9EF00D1124E45DFE4FC081D18182807C +:100410009380A480B580BE01882777FD8095982FB2 +:1004200055D29B01AC01C701B6014CD11B012C0177 +:10043000709E7001719EF00C1124C701845D9E4F67 +:100440007C01A5019401FC01628173818481958105 +:1004500039D19B01AC01C201B101ECD22B013C01AD +:10046000F701608171816C1B7D0B882777FD80957A +:10047000982F2CD29B01AC01C301B2018CD19B01FE +:10048000AC01C501B4011FD109C060E070E080E09B +:1004900090E404C06DEC7CEC8CE49FE3DF91CF91A1 +:1004A0001F910F91FF90EF90DF90CF90BF90AF9092 +:1004B0009F908F907F906F905F904F903F902F9084 +:1004C00008956F927F928F929F92AF92BF92CF9238 +:1004D000DF92EF92FF920F931F93CF93DF9300D0A1 +:1004E00000D0CDB7DEB76B017C0129833A834B8303 +:1004F0005C831EDF3C0129813A814B815C81CA010A +:10050000B90134DF4B015C01C701B601ACD1DC019C +:10051000CB018501740129813A814B815C81B30152 +:1005200057DE0F900F900F900F90DF91CF911F919A +:100530000F91FF90EF90DF90CF90BF90AF909F9082 +:100540008F907F906F900895CF92DF92EF92FF92FD +:1005500082E090E0B3DEBC01882777FD8095982F7C +:10056000B5D120E030E040E351E415D16B017C01CE +:1005700060918A0170918B0180918C0190918D0125 +:100580009B01AC01A0D09B01AC01C701B6019BD07F +:1005900020E030E040E450E4FED060938A017093A4 +:1005A0008B0180938C0190938D0185E090E086DE35 +:1005B000BC01882777FD8095982F88D16B017C013D +:1005C00060918601709187018091880190918901E5 +:1005D0009B01AC0178D09B01AC01C701B60173D07F +:1005E00020E030E040E450E4D6D060938601709380 +:1005F0008701809388019093890120918A0130912D +:100600008B0140918C0150918D015BDF2FE38DE0D8 +:1006100093E0215080409040E1F700C00000FF903F +:10062000EF90DF90CF9008950AD0B9DDC6DD20E0CD +:1006300030E0A901CA01B90144DF86DFFECF109284 +:10064000C5008CE08093C400E0ECF0E08081826023 +:10065000808388E18093C10086E08093C200089582 +:100660009091C00095FFFCCF8093C60008951F9322 +:10067000CF93DF93EC0110E0FE01E10FF11D8081CB +:10068000882319F0EDDF1F5FF7CFDF91CF911F9126 +:10069000089509D0A59F900DB49F900DA49F800D43 +:1006A000911D11240895A29FB001B39FC001A39F83 +:1006B000700D811D1124911DB29F700D811D11249B +:1006C000911D08955058BB27AA270ED075C166D139 +:1006D00030F06BD120F031F49F3F11F41EF45BC178 +:1006E0000EF4E095E7FB51C1E92F77D180F3BA17FB +:1006F000620773078407950718F071F49EF58FC1A0 +:100700000EF4E0950B2EBA2FA02D0B01B90190012C +:100710000C01CA01A0011124FF27591B99F0593F70 +:1007200050F4503E68F11A16F040A22F232F342FB8 +:100730004427585FF3CF469537952795A795F04006 +:100740005395C9F77EF41F16BA0B620B730B840B1B +:10075000BAF09150A1F0FF0FBB1F661F771F881FD3 +:10076000C2F70EC0BA0F621F731F841F48F487952B +:1007700077956795B795F7959E3F08F0B3CF93951A +:10078000880F08F09927EE0F979587950895D9D08F +:1007900008F481E008950CD00FC107D140F0FED0DD +:1007A00030F021F45F3F19F0F0C0511139C1F3C0AE +:1007B00014D198F39923C9F35523B1F3951B550B25 +:1007C000BB27AA2762177307840738F09F5F5F4F24 +:1007D000220F331F441FAA1FA9F333D00E2E3AF065 +:1007E000E0E830D091505040E695001CCAF729D07F +:1007F000FE2F27D0660F771F881FBB1F26173707CE +:100800004807AB07B0E809F0BB0B802DBF01FF27FD +:1008100093585F4F2AF09E3F510568F0B6C000C163 +:100820005F3FECF3983EDCF3869577956795B79537 +:10083000F7959F5FC9F7880F911D9695879597F952 +:100840000895E1E0660F771F881FBB1F62177307CB +:100850008407BA0720F0621B730B840BBA0BEE1FE0 +:1008600088F7E095089504D06894B111D9C008952F +:10087000BCD088F09F5790F0B92F9927B751A0F0BE +:10088000D1F0660F771F881F991F1AF0BA95C9F724 +:1008900012C0B13081F0C3D0B1E00895C0C0672F5D +:1008A000782F8827B85F39F0B93FCCF386957795D4 +:1008B0006795B395D9F73EF49095809570956195BD +:1008C0007F4F8F4F9F4F0895E89409C097FB3EF4E8 +:1008D00090958095709561957F4F8F4F9F4F99238D +:1008E000A9F0F92F96E9BB279395F695879577950B +:1008F0006795B795F111F8CFFAF4BB0F11F460FFCB +:100900001BC06F5F7F4F8F4F9F4F16C0882311F022 +:1009100096E911C0772321F09EE8872F762F05C036 +:10092000662371F096E8862F70E060E02AF09A95D1 +:10093000660F771F881FDAF7880F9695879597F9C6 +:100940000895990F0008550FAA0BE0E8FEEF161660 +:100950001706E807F907C0F012161306E407F507B3 +:1009600098F0621B730B840B950B39F40A2661F027 +:10097000232B242B252B21F408950A2609F4A140CA +:10098000A6958FEF811D811D089597F99F6780E8D7 +:1009900070E060E008959FEF80EC089500240A94D1 +:1009A0001616170618060906089500240A9412164A +:1009B0001306140605060895092E0394000C11F47D +:1009C000882352F0BB0F40F4BF2B11F460FF04C02A +:1009D0006F5F7F4F8F4F9F4F089557FD9058440F83 +:1009E000551F59F05F3F71F04795880F97FB991F8E +:1009F00061F09F3F79F0879508951216130614064B +:100A0000551FF2CF4695F1DF08C0161617061806D7 +:100A1000991FF1CF86957105610508940895E894B2 +:100A2000BB2766277727CB0197F908958ADF08F45B +:100A30008FEF08950BD0C0CFB1DF28F0B6DF18F0EC +:100A4000952309F0A2CFA7CF1124EACFC6DFA0F3E8 +:100A5000959FD1F3950F50E0551F629FF001729F53 +:100A6000BB27F00DB11D639FAA27F00DB11DAA1F72 +:100A7000649F6627B00DA11D661F829F2227B00DBF +:100A8000A11D621F739FB00DA11D621F839FA00D4A +:100A9000611D221F749F3327A00D611D231F849F9A +:100AA000600D211D822F762F6A2F11249F575040F1 +:100AB0008AF0E1F088234AF0EE0FFF1FBB1F661F8C +:100AC000771F881F91505040A9F79E3F510570F045 +:100AD0005CCFA6CF5F3FECF3983EDCF3869577952D +:100AE0006795B795F795E7959F5FC1F7FE2B880F40 +:100AF000911D9695879597F9089577DFE0F09E37D9 +:100B0000D8F09639B8F49E3848F4672F782F8827A4 +:100B1000985FF9CF86957795679593959539D0F33A +:100B2000B62FB1706B0F711D811D20F487957795DD +:100B30006795939502C01CC073CF882371F4772307 +:100B400021F09850872B762F07C0662311F4992740 +:100B50000DC09051862B70E060E02AF09A95660FE8 +:100B6000771F881FDAF7880F9695879597F908956C +:100B70009F3F31F0915020F4879577956795B79511 +:100B8000880F911D9695879597F90895EF920F9389 +:100B90001F93CF93DF93E80147FF02C034E101C008 +:100BA00034E0E42FFF27E7FDF095F7FF03C0F19550 +:100BB000E195F109E32E022F2E2FAE01F7D1CE01E0 +:100BC000DF91CF911F910F91EF900895AEE0B0E0CB +:100BD000EBEEF5E0F4C40D891E898F89988D26E02F +:100BE0002C831A83098397FF02C080E090E8019765 +:100BF0009E838D83AE01455E5F4F698D7A8DCE01F8 +:100C0000019611D04D815E8157FD0AC02F81388534 +:100C1000421753070CF49A01F801E20FF31F1082F8 +:100C20002E96E4E0E8C4ACE0B0E0E8E1F6E0B9C458 +:100C30007C016B018A01FC0117821682838181FF8E +:100C4000B0C1CE0101964C01F7019381F60193FDED +:100C5000859193FF81916F01882309F49EC18532AC +:100C600039F493FD859193FF81916F01853221F4D1 +:100C7000B70190E006D4E8CF512C312C20E020328F +:100C8000A0F48B3269F030F4803259F0833269F489 +:100C900020612CC08D3239F0803339F4216026C0B8 +:100CA0002260246023C0286021C027FD27C030EDCA +:100CB000380F3A3078F426FF06C0FAE05F9E300D18 +:100CC0001124532E13C08AE0389E300D1124332E88 +:100CD00020620CC08E3221F426FD5FC1206406C064 +:100CE0008C3611F4206802C0883641F4F60193FD79 +:100CF000859193FF81916F018111C1CF982F9F7DC5 +:100D00009554933028F40C5F1F4FFFE3F9830DC017 +:100D1000833631F0833771F0833509F057C021C035 +:100D2000F801808189830E5F1F4F44244394512C26 +:100D3000540114C03801F2E06F0E711CF801A0805C +:100D4000B18026FF03C0652D70E002C06FEF7FEF1A +:100D5000C5012C878BD32C0183012C852F77222E64 +:100D600016C03801F2E06F0E711CF801A080B1804E +:100D700026FF03C0652D70E002C06FEF7FEFC50155 +:100D80002C8769D32C012C852068222E830123FC1B +:100D900019C0832D90E048165906A0F4B70180E2EF +:100DA00090E06FD33A94F5CFF50127FC859127FEAB +:100DB00081915F01B70190E064D331103A94F1E082 +:100DC0004F1A51084114510479F7DEC0843611F0EE +:100DD000893631F5F80127FF07C060817181828172 +:100DE00093810C5F1F4F08C060817181882777FD58 +:100DF0008095982F0E5F1F4F2F76B22E97FF09C058 +:100E000090958095709561957F4F8F4F9F4F20688B +:100E1000B22E2AE030E0A40166D3A82EA81843C061 +:100E2000853729F42F7EB22E2AE030E025C0F22F3C +:100E3000F97FBF2E8F36C1F018F4883579F0ADC038 +:100E4000803719F0883721F0A8C02F2F2061B22EEB +:100E5000B4FE0DC08B2D8460B82E09C024FF0AC0DB +:100E60009F2F9660B92E06C028E030E005C020E133 +:100E700030E002C020E132E0F801B7FE07C0608137 +:100E80007181828193810C5F1F4F06C060817181E7 +:100E900080E090E00E5F1F4FA40125D3A82EA81874 +:100EA000FB2DFF77BF2EB6FE0BC02B2D2E7FA5147A +:100EB00050F4B4FE0AC0B2FC08C02B2D2E7E05C033 +:100EC0007A2C2B2D03C07A2C01C0752C24FF0DC069 +:100ED000FE01EA0DF11D8081803311F4297E09C0E5 +:100EE00022FF06C07394739404C0822F867809F0A1 +:100EF000739423FD12C020FF06C05A2C731418F4FB +:100F0000530C5718732C731460F4B70180E290E00F +:100F10002C87B7D273942C85F6CF731410F437183E +:100F200001C0312C24FF11C0B70180E390E02C8771 +:100F3000A8D22C8522FF16C021FF03C088E590E0CF +:100F400002C088E790E0B7010CC0822F867851F08C +:100F500021FD02C080E201C08BE227FD8DE2B701D6 +:100F600090E08FD2A51430F4B70180E390E089D2ED +:100F70005A94F8CFAA94F401EA0DF11D8081B701CB +:100F800090E07FD2A110F6CF332009F45DCEB701F7 +:100F900080E290E076D23A94F7CFF701868197818C +:100FA00002C08FEF9FEF2C96E2E117C36F927F9202 +:100FB0009F92AF92BF92CF92DF92EF92FF920F93E8 +:100FC0001F93CF93DF93CDB7DEB729970FB6F89471 +:100FD000DEBF0FBECDBF6A01B22E102F0C3320F43E +:100FE000FF24F394F00E02C04CE3F42E0F2D27E003 +:100FF000AE014F5F5F4F57D17981272F2970213084 +:1010000031F0E1FC06C0E0FC06C060E005C06DE226 +:1010100003C06BE201C060E2AE2DA07173FF36C069 +:10102000662311F084E001C083E08B1510F4B81A38 +:1010300001C0B12CA1110BC0F6018B2D90E28823C9 +:1010400019F091938150FBCFCB0CD11CB12C6623AE +:1010500031F0F601608396012F5F3F4F6901C601B1 +:101060000396E2FE05C02EE4F601208331E404C0BD +:101070002EE6F601208331E631832283FC012B2DFD +:1010800030E22223F1F131932150FBCF72FF40C0B7 +:10109000662311F084E001C083E08B1510F4B81AC8 +:1010A00001C0B12CA1110BC0F6018B2D90E2882359 +:1010B00019F091938150FBCFCB0CD11CB12C66233E +:1010C00031F0F601608396012F5F3F4F6901C60141 +:1010D0000396E2FE07C029E4F60120832EE4218373 +:1010E00026E406C029E6F60120832EE6218326E6C3 +:1010F0002283FC012B2D30E2222319F03193215061 +:10110000FBCFFC01EB0DF11D10828EEF9FEFB7C0FE +:10111000B1E0611101C0B0E04B2F50E01816190684 +:1011200024F49C012F5F3F4F02C021E030E0240FE8 +:10113000351F112329F0412F50E04F5F5F4F02C050 +:1011400040E050E0420F531F2B2D30E04217530771 +:1011500014F4B41A01C0B12C2E2D287159F4F601E3 +:101160002B2D30E2222319F031932150FBCFCB0CF1 +:10117000D11CB12CBB2331F0F601608396012F5FA7 +:101180003F4F6901A1110BC0F6012B2D30E3222343 +:1011900019F031932150FBCFCB0CD11CB12CF80EA0 +:1011A0000A81372F3071A32E74FF03C0013309F475 +:1011B000FA941F142CF42F2D293018F028E001C0C8 +:1011C00021E0682F392F97FF02C060E030E0462F02 +:1011D000532F612C712C3EE2932EBC01621B7109CE +:1011E0009B01DC01A41BB50BE1E0F0E0EC0FFD1F5F +:1011F000AE0FBF1FE12EF12CF194E194F1084F3FA7 +:10120000FFEF5F0731F4F6019082B6016F5F7F4F09 +:101210006B01841795074CF02417350734F4BD0192 +:10122000660D771DFB01118101C010E3415051098A +:10123000FFEF6F1A7F0AB6016F5F7F4F4E155F0594 +:1012400024F0F60110836B01DACF4817590739F4FF +:10125000063320F4053319F4A11001C011E3F6019F +:101260001083FB018B2D90E2882319F0919381501C +:10127000FBCFFB01EB0DF11D108280E090E0299681 +:101280000FB6F894DEBF0FBECDBFDF91CF911F9197 +:101290000F91FF90EF90DF90CF90BF90AF909F9015 +:1012A0007F906F900895283008F027E03327DA0107 +:1012B000990F311D87FD916000966105710539F424 +:1012C00032602E5F3D9330E32A95E1F708959F3F0A +:1012D00030F080387105610509F03C5F3C5F3D935B +:1012E000913008F08068911DDF93CF931F930F9387 +:1012F000FF92EF92192F987F9695E92F96959695E4 +:10130000E90FFF27EE53FF4F99273327EE24FF24E1 +:10131000A701E70105900894079428F4360FE71E0B +:10132000F81E491F511D660F771F881F991F0694CD +:10133000A1F70590079428F4E70EF81E491F561FE1 +:10134000C11D770F881F991F661F0694A1F705908E +:10135000079428F4F80E491F561FC71FD11D880F88 +:10136000991F661F771F0694A1F70590079420F434 +:10137000490F561FC71FD81F990F661F771F881F59 +:101380000694A9F784911095177041F0D695C795EA +:1013900057954795F794E7941A95C1F7E8E6F0E07A +:1013A00068941590159135916591959105907FE21E +:1013B0007395E118F10A430B560BC90BD009C0F71E +:1013C000E10CF11E431F561FC91FD01D7EF4703360 +:1013D00011F48A95E6CFE894015030F0080F0AF432 +:1013E0000027021708F4202F2395022F7A3328F0C4 +:1013F00079E37D932A95E9F710C07D932A9589F6C4 +:10140000069497956795379517951794E118F10A03 +:10141000430B560BC90BD00998F023957E91739519 +:101420007A3308F070E37C932013B8F77E917061F3 +:101430007D9330F0839571E37D9370E32A95E1F716 +:101440001124EF90FF900F911F91CF91DF91992779 +:1014500087FD90950895FC01059061507040011042 +:10146000D8F7809590958E0F9F1F0895FC016150CD +:10147000704001900110D8F7809590958E0F9F1FB6 +:1014800008950F931F93CF93DF93182F092FEB012C +:101490008B8181FD03C08FEF9FEF20C082FF10C0C2 +:1014A0004E815F812C813D81421753077CF4E88196 +:1014B000F9819F012F5F3F4F39832883108306C036 +:1014C000E885F985812F0995892B29F72E813F81A0 +:1014D0002F5F3F4F3F832E83812F902FDF91CF913E +:1014E0001F910F910895FA01AA27283051F1203158 +:1014F00081F1E8946F936E7F6E5F7F4F8F4F9F4FA8 +:10150000AF4FB1E03ED0B4E03CD0670F781F891FE9 +:101510009A1FA11D680F791F8A1F911DA11D6A0FB7 +:10152000711D811D911DA11D20D009F468943F916A +:101530002AE0269F11243019305D3193DEF6CF0169 +:101540000895462F4770405D4193B3E00FD0C9F72F +:10155000F6CF462F4F70405D4A3318F0495D31FD9C +:101560004052419302D0A9F7EACFB4E0A6959795EF +:10157000879577956795BA95C9F7009761057105C5 +:1015800008959B01AC010A2E06945795479537950F +:101590002795BA95C9F7620F731F841F951FA01D69 +:1015A00008952F923F924F925F926F927F928F9207 +:1015B0009F92AF92BF92CF92DF92EF92FF920F93E2 +:1015C0001F93CF93DF93CDB7DEB7CA1BDB0B0FB6EC +:1015D000F894DEBF0FBECDBF09942A8839884888A9 +:1015E0005F846E847D848C849B84AA84B984C8843F +:1015F000DF80EE80FD800C811B81AA81B981CE0F36 +:10160000D11D0FB6F894DEBF0FBECDBFED0108951A +:04161000F894FFCF7C +:10161400542025336420432025640D0A004C2025E2 +:10162400732020282573290D0A004D616765720017 +:10163400496465616C00466574742100040000000F +:10164400004005003333F33F06006666E63F0800BA +:101654009A99D93F0A00CDCCCC3F0C000000C03F82 +:101664000F003333B33F14006666A63F1C009A99FB +:10167400993F2800CDCC8C3F44003333833F900105 +:101684000000803F200348E17A3F5C036666663FC2 +:061694007003CDCC4C3FB9 +:00000001FF