Skip to content

Instantly share code, notes, and snippets.

@atomofiron
Last active March 6, 2026 07:17
Show Gist options
  • Select an option

  • Save atomofiron/11c301dee7a6793e2a6436a2705f53ee to your computer and use it in GitHub Desktop.

Select an option

Save atomofiron/11c301dee7a6793e2a6436a2705f53ee to your computer and use it in GitHub Desktop.
USBASP firmware update via Pro Micro
brew install arduino-cli
arduino-cli core update-index
arduino-cli core install arduino:avr
mkdir ProMicroISP
cp ArduinoISP.ino ProMicroISP/ProMicroISP.ino
  • connect USB to Pro Micro
arduino-cli board list
arduino-cli compile -b arduino:avr:micro ProMicroISP
arduino-cli upload -p /dev/cu.usbmodemX -b arduino:avr:micro ProMicroISP

New upload port: /dev/cu.usbmodemX (serial)

  • close JP2 on USBASP
  • connect
USBASP Pro Micro
10 GND GND
2 VCC VCC
7 SCK 15
9 MISO 14
1 MOSI 16
5 RST 10
avrdude -C avrdude.conf -c avrisp -P /dev/cu.usbmodemX -b 19200 -p m8 -v
output
Using port            : /dev/cu.usbmodem101
Using programmer      : avrisp
Setting baud rate     : 19200
AVR part              : ATmega8
Programming modes     : SPM, ISP, HVPP
Programmer type       : STK500
Description           : Atmel AVR ISP
HW Version            : 2
FW Version            : 1.18
Topcard               : Unknown
SCK period            : 0.0 us
XTAL frequency        : 7.372800 MHz

AVR device initialized and ready to accept instructions
Device signature = 1E 93 07 (ATmega8, ATmega8A)
avrdude -C avrdude.conf -c avrisp -P /dev/cu.usbmodemX -b 19200 -p m8 -U flash:w:usbasp.atmega8.2011-05-28.hex:i
output
Reading 4700 bytes for flash from input file usbasp.atmega8.2011-05-28.hex
Writing 4700 bytes to flash
Writing | ################################################## | 100% 9.55 s 
Reading | ################################################## | 100% 7.24 s 
4700 bytes of flash verified

IMG_20260306_022006756

// ArduinoISP version 04m3
// Copyright (c) 2008-2011 Randall Bohn
// If you require a license, see
// http://www.opensource.org/licenses/bsd-license.php
//
// This sketch turns the Arduino into a AVRISP
// using the following arduino pins:
//
// pin name: not-mega: mega(1280 and 2560)
// slave reset: 10: 53
// MOSI: 11: 51
// MISO: 12: 50
// SCK: 13: 52
//
// Put an LED (with resistor) on the following pins:
// 9: Heartbeat - shows the programmer is running
// 8: Error - Lights up if something goes wrong (use red if that makes sense)
// 7: Programming - In communication with the slave
//
// 23 July 2011 Randall Bohn
// -Address Arduino issue 509 :: Portability of ArduinoISP
// http://code.google.com/p/arduino/issues/detail?id=509
//
// October 2010 by Randall Bohn
// - Write to EEPROM > 256 bytes
// - Better use of LEDs:
// -- Flash LED_PMODE on each flash commit
// -- Flash LED_PMODE while writing EEPROM (both give visual feedback of writing progress)
// - Light LED_ERR whenever we hit a STK_NOSYNC. Turn it off when back in sync.
// - Use pins_arduino.h (should also work on Arduino Mega)
//
// October 2009 by David A. Mellis
// - Added support for the read signature command
//
// February 2009 by Randall Bohn
// - Added support for writing to EEPROM (what took so long?)
// Windows users should consider WinAVR's avrdude instead of the
// avrdude included with Arduino software.
//
// January 2008 by Randall Bohn
// - Thanks to Amplificar for helping me with the STK500 protocol
// - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader
// - The SPI functions herein were developed for the AVR910_ARD programmer
// - More information at http://code.google.com/p/mega-isp
#include "SPI.h"
#include "pins_arduino.h"
#define RESET 10
#define LED_HB 9
#define LED_ERR 8
#define LED_PMODE 7
#define PROG_FLICKER true
#define HWVER 2
#define SWMAJ 1
#define SWMIN 18
// STK Definitions
#define STK_OK 0x10
#define STK_FAILED 0x11
#define STK_UNKNOWN 0x12
#define STK_INSYNC 0x14
#define STK_NOSYNC 0x15
#define CRC_EOP 0x20 //ok it is a space...
void pulse(int pin, int times);
void setup() {
Serial.begin(9600);
SPI.setDataMode(0);
SPI.setBitOrder(MSBFIRST);
// Clock Div can be 2,4,8,16,32,64, or 128
SPI.setClockDivider(SPI_CLOCK_DIV128);
pinMode(LED_PMODE, OUTPUT);
pulse(LED_PMODE, 2);
pinMode(LED_ERR, OUTPUT);
pulse(LED_ERR, 2);
pinMode(LED_HB, OUTPUT);
pulse(LED_HB, 2);
}
int error=0;
int pmode=0;
// address for reading and writing, set by 'U' command
int here;
uint8_t buff[256]; // global block storage
#define beget16(addr) (*addr * 256 + *(addr+1) )
typedef struct param {
uint8_t devicecode;
uint8_t revision;
uint8_t progtype;
uint8_t parmode;
uint8_t polling;
uint8_t selftimed;
uint8_t lockbytes;
uint8_t fusebytes;
uint8_t flashpoll;
uint16_t eeprompoll;
uint16_t pagesize;
uint16_t eepromsize;
uint32_t flashsize;
}
parameter;
parameter param;
// this provides a heartbeat on pin 9, so you can tell the software is running.
uint8_t hbval=128;
int8_t hbdelta=8;
void heartbeat() {
if (hbval > 192) hbdelta = -hbdelta;
if (hbval < 32) hbdelta = -hbdelta;
hbval += hbdelta;
analogWrite(LED_HB, hbval);
delay(40);
}
void loop(void) {
// is pmode active?
if (pmode) digitalWrite(LED_PMODE, HIGH);
else digitalWrite(LED_PMODE, LOW);
// is there an error?
if (error) digitalWrite(LED_ERR, HIGH);
else digitalWrite(LED_ERR, LOW);
// light the heartbeat LED
heartbeat();
if (Serial.available()) {
avrisp();
}
}
uint8_t getch() {
while(!Serial.available());
return Serial.read();
}
void fill(int n) {
for (int x = 0; x < n; x++) {
buff[x] = getch();
}
}
#define PTIME 30
void pulse(int pin, int times) {
do {
digitalWrite(pin, HIGH);
delay(PTIME);
digitalWrite(pin, LOW);
delay(PTIME);
}
while (times--);
}
void prog_lamp(int state) {
if (PROG_FLICKER)
digitalWrite(LED_PMODE, state);
}
uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
uint8_t n;
SPI.transfer(a);
n=SPI.transfer(b);
//if (n != a) error = -1;
n=SPI.transfer(c);
return SPI.transfer(d);
}
void empty_reply() {
if (CRC_EOP == getch()) {
Serial.print((char)STK_INSYNC);
Serial.print((char)STK_OK);
}
else {
error++;
Serial.print((char)STK_NOSYNC);
}
}
void breply(uint8_t b) {
if (CRC_EOP == getch()) {
Serial.print((char)STK_INSYNC);
Serial.print((char)b);
Serial.print((char)STK_OK);
}
else {
error++;
Serial.print((char)STK_NOSYNC);
}
}
void get_version(uint8_t c) {
switch(c) {
case 0x80:
breply(HWVER);
break;
case 0x81:
breply(SWMAJ);
break;
case 0x82:
breply(SWMIN);
break;
case 0x93:
breply('S'); // serial programmer
break;
default:
breply(0);
}
}
void set_parameters() {
// call this after reading paramter packet into buff[]
param.devicecode = buff[0];
param.revision = buff[1];
param.progtype = buff[2];
param.parmode = buff[3];
param.polling = buff[4];
param.selftimed = buff[5];
param.lockbytes = buff[6];
param.fusebytes = buff[7];
param.flashpoll = buff[8];
// ignore buff[9] (= buff[8])
// following are 16 bits (big endian)
param.eeprompoll = beget16(&buff[10]);
param.pagesize = beget16(&buff[12]);
param.eepromsize = beget16(&buff[14]);
// 32 bits flashsize (big endian)
param.flashsize = buff[16] * 0x01000000
+ buff[17] * 0x00010000
+ buff[18] * 0x00000100
+ buff[19];
}
void start_pmode() {
SPI.begin();
digitalWrite(RESET, HIGH);
pinMode(RESET, OUTPUT);
digitalWrite(SCK, LOW);
delay(20);
digitalWrite(RESET, LOW);
spi_transaction(0xAC, 0x53, 0x00, 0x00);
pmode = 1;
}
void end_pmode() {
SPI.end();
digitalWrite(RESET, HIGH);
pinMode(RESET, INPUT);
pmode = 0;
}
void universal() {
int w;
uint8_t ch;
fill(4);
ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
breply(ch);
}
void flash(uint8_t hilo, int addr, uint8_t data) {
spi_transaction(0x40+8*hilo,
addr>>8 & 0xFF,
addr & 0xFF,
data);
}
void commit(int addr) {
if (PROG_FLICKER) prog_lamp(LOW);
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
if (PROG_FLICKER) {
delay(PTIME);
prog_lamp(HIGH);
}
}
//#define _current_page(x) (here & 0xFFFFE0)
int current_page(int addr) {
if (param.pagesize == 32) return here & 0xFFFFFFF0;
if (param.pagesize == 64) return here & 0xFFFFFFE0;
if (param.pagesize == 128) return here & 0xFFFFFFC0;
if (param.pagesize == 256) return here & 0xFFFFFF80;
return here;
}
void write_flash(int length) {
fill(length);
if (CRC_EOP == getch()) {
Serial.print((char) STK_INSYNC);
Serial.print((char) write_flash_pages(length));
}
else {
error++;
Serial.print((char) STK_NOSYNC);
}
}
uint8_t write_flash_pages(int length) {
int x = 0;
int page = current_page(here);
while (x < length) {
if (page != current_page(here)) {
commit(page);
page = current_page(here);
}
flash(LOW, here, buff[x++]);
flash(HIGH, here, buff[x++]);
here++;
}
commit(page);
return STK_OK;
}
#define EECHUNK (32)
uint8_t write_eeprom(int length) {
// here is a word address, get the byte address
int start = here * 2;
int remaining = length;
if (length > param.eepromsize) {
error++;
return STK_FAILED;
}
while (remaining > EECHUNK) {
write_eeprom_chunk(start, EECHUNK);
start += EECHUNK;
remaining -= EECHUNK;
}
write_eeprom_chunk(start, remaining);
return STK_OK;
}
// write (length) bytes, (start) is a byte address
uint8_t write_eeprom_chunk(int start, int length) {
// this writes byte-by-byte,
// page writing may be faster (4 bytes at a time)
fill(length);
prog_lamp(LOW);
for (int x = 0; x < length; x++) {
int addr = start+x;
spi_transaction(0xC0, (addr>>8) & 0xFF, addr & 0xFF, buff[x]);
delay(45);
}
prog_lamp(HIGH);
return STK_OK;
}
void program_page() {
char result = (char) STK_FAILED;
int length = 256 * getch();
length += getch();
char memtype = getch();
// flash memory @here, (length) bytes
if (memtype == 'F') {
write_flash(length);
return;
}
if (memtype == 'E') {
result = (char)write_eeprom(length);
if (CRC_EOP == getch()) {
Serial.print((char) STK_INSYNC);
Serial.print(result);
}
else {
error++;
Serial.print((char) STK_NOSYNC);
}
return;
}
Serial.print((char)STK_FAILED);
return;
}
uint8_t flash_read(uint8_t hilo, int addr) {
return spi_transaction(0x20 + hilo * 8,
(addr >> 8) & 0xFF,
addr & 0xFF,
0);
}
char flash_read_page(int length) {
for (int x = 0; x < length; x+=2) {
uint8_t low = flash_read(LOW, here);
Serial.print((char) low);
uint8_t high = flash_read(HIGH, here);
Serial.print((char) high);
here++;
}
return STK_OK;
}
char eeprom_read_page(int length) {
// here again we have a word address
int start = here * 2;
for (int x = 0; x < length; x++) {
int addr = start + x;
uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
Serial.print((char) ee);
}
return STK_OK;
}
void read_page() {
char result = (char)STK_FAILED;
int length = 256 * getch();
length += getch();
char memtype = getch();
if (CRC_EOP != getch()) {
error++;
Serial.print((char) STK_NOSYNC);
return;
}
Serial.print((char) STK_INSYNC);
if (memtype == 'F') result = flash_read_page(length);
if (memtype == 'E') result = eeprom_read_page(length);
Serial.print(result);
return;
}
void read_signature() {
if (CRC_EOP != getch()) {
error++;
Serial.print((char) STK_NOSYNC);
return;
}
Serial.print((char) STK_INSYNC);
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
Serial.print((char) high);
uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
Serial.print((char) middle);
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
Serial.print((char) low);
Serial.print((char) STK_OK);
}
//////////////////////////////////////////
//////////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
int avrisp() {
uint8_t data, low, high;
uint8_t ch = getch();
switch (ch) {
case '0': // signon
error = 0;
empty_reply();
break;
case '1':
if (getch() == CRC_EOP) {
Serial.print((char) STK_INSYNC);
Serial.print("AVR ISP");
Serial.print((char) STK_OK);
} else {
error++;
Serial.print((char) STK_NOSYNC);
}
break;
case 'A':
get_version(getch());
break;
case 'B':
fill(20);
set_parameters();
empty_reply();
break;
case 'E': // extended parameters - ignore for now
fill(5);
empty_reply();
break;
case 'P':
if (pmode) {
pulse(LED_ERR, 3);
} else {
start_pmode();
}
empty_reply();
break;
case 'U': // set address (word)
here = getch();
here += 256 * getch();
empty_reply();
break;
case 0x60: //STK_PROG_FLASH
low = getch();
high = getch();
empty_reply();
break;
case 0x61: //STK_PROG_DATA
data = getch();
empty_reply();
break;
case 0x64: //STK_PROG_PAGE
program_page();
break;
case 0x74: //STK_READ_PAGE 't'
read_page();
break;
case 'V': //0x56
universal();
break;
case 'Q': //0x51
error=0;
end_pmode();
empty_reply();
break;
case 0x75: //STK_READ_SIGN 'u'
read_signature();
break;
// expecting a command, not CRC_EOP
// this is how we can get back in sync
case CRC_EOP:
error++;
Serial.print((char) STK_NOSYNC);
break;
// anything else we will return STK_UNKNOWN
default:
error++;
if (CRC_EOP == getch())
Serial.print((char)STK_UNKNOWN);
else
Serial.print((char)STK_NOSYNC);
}
}
:100000003BC0A6C154C053C052C051C050C04FC025
:100010004EC04DC04CC04BC04AC049C048C047C08C
:1000200046C045C044C0040309041C0377007700A0
:1000300077002E00660069007300630068006C00A2
:100040002E00640065000E0355005300420061005D
:100050007300700012011001FF000008C016DC05DB
:1000600004010102000109021200010100801909C6
:10007000040000000000000011241FBECFE5D4E002
:10008000DEBFCDBF10E0A0E6B0E0EAE5F2E102C0DD
:1000900005900D92A236B107D9F710E0A2E6B0E0C4
:1000A00001C01D92AA3AB107E1F766D5D4C8A8CF1E
:1000B00085B7836085BF8BB780648BBF08951F931E
:1000C000CF93DF9360918800635067FD13C08091E8
:1000D0008500CCE0D0E0C81BD109C457DF4F809128
:1000E00084008D3209F462C08091620087FD84C073
:1000F000109288008091600084FF4AC06091610086
:100100006F3F09F445C0693070F168506093610039
:100110008091780098E889278093780068E0809142
:10012000620087FD8BC0209186003091870086FF9A
:100130006DC0A9E7B0E080E090E0F901E80FF91F99
:10014000E491ED9301966817C1F76150862F90E016
:100150006F5F0196820F931F9093870080938600B4
:10016000162F1C5F0BC0109261008091780098E8F8
:10017000892780937800662391F614E089E790E060
:10018000E3D01C3019F08FEF809361001093600072
:1001900094E186B3837031F49150D9F710928900BD
:1001A00010928300DF91CF911F910895683009F07C
:1001B0009FCF83EC809378008AE580936000109253
:1001C00062008881807659F59A8110928100898138
:1001D000882309F043C01092820022E081E890E079
:1001E00090938700809386008F81882319F49E81E5
:1001F000921708F1922F1FC0CE01CFD48F3F51F13B
:10020000882309F475CF1092610072CF962FD9011F
:10021000E9E7F0E08D9181939150E1F796CFCE011F
:1002200004D6282F8F3F01F7888187FD25C09FEFD7
:1002300080E880936200909361005ACF89E790E054
:1002400082D5682F893008F453C08FEF8093610006
:100250001EE19CCF8EE1809360004ACF853071F023
:10026000863091F0883031F1893061F18A3031F196
:1002700020E081E890E0B4CF9E81DACF90938900AE
:1002800020E081E890E0ACCF8B81813049F1823071
:10029000F9F0833029F020E080E480936200A4CF5D
:1002A000992349F586E290E0909387008093860039
:1002B00024E0F2CF21E08BE890E092CF21E081E8CA
:1002C00090E08ECF90938B0020E081E890E088CF83
:1002D00086E690E0909387008093860022E1DCCF51
:1002E00084E590E0909387008093860022E1D4CF4C
:1002F000182F1C5F43CF913051F0923061F686E4A5
:1003000090E090938700809386002EE0C5CF8AE22C
:1003100090E090938700809386002CE1BDCFA82FBA
:10032000B92F80E090E041E050EA609530E009C0EC
:100330002D9182279795879510F084279527305E19
:10034000C8F36F5FA8F30895EADF8D939D93089536
:10035000CF93CFB7CF93C395B09BE9F7B09B09C0BC
:10036000B09B07C0B09B05C0B09B03C0B09B01C051
:10037000A1C0DF93C0918500DD27C457DF4FB09B3C
:1003800002C0DF91EBCF2F930F931F9306B32FEF94
:1003900000FB20F94F933F9316B34FEF012700FB6B
:1003A00021F93BE031C04E7F012F16B3216028C0F8
:1003B000102F4D7F2260000006B329C04B7F2460C0
:1003C000012F000016B32BC016B3477F28602AC048
:1003D0004F7E06B320612CC04F7D16B320622FC024
:1003E0004F7B06B3206432C0422706B349934FEFD8
:1003F0000000102710FB20F916B31370C9F1297FF4
:1004000091F2012700FB21F906B3237F89F23150D5
:1004100058F1102710FB22F916B3277E79F2012735
:1004200000FB23F92F7C81F206B3102710FB24F97F
:100430002F7971F200C016B3012700FB25F92F7345
:1004400059F200C006B3102710FB26F9223040F203
:1004500000C016B3012700FB27F9243028F64F7798
:10046000206816B30000F9CF10E41ABF002717C0A8
:100470003B503195C31BD04010E41ABF0881033CA8
:10048000E9F00B34D9F0209183001981110F121378
:10049000EDCF093641F10D3211F0013E39F70093ED
:1004A0008A003F914F911F910F912F91DF91CAB711
:1004B000C6FD51CFCF91CFBFCF91189520918A0023
:1004C000222379F310918800112311F5343012F1B1
:1004D0003093880020938400109185003BE0311B0D
:1004E0003093850017C00091880001308CF40AE534
:1004F0003091600034FD10C000936000C8E7D0E088
:100500000FC02795A8F45150A9F4220F0000F9CF8D
:100510004AE503C042ED01C0432FC4E1D0E032E020
:1005200017B31360C09A17BB08B320E413E05F93BE
:10053000012756E008BB279520F4515021F4220FE3
:10054000F9CF012756E000003B5A08BBD0F22795AF
:1005500028F4515029F4220F0000F9CF012756E06A
:10056000279508BB20F4515021F4220FF9CF012721
:1005700056E02991332308BB21F60C7F10918900A6
:10058000110FC651D04008BB11F01093830010E446
:100590001ABF016017B31C7F402F4C7F5F9100C0D2
:1005A00000C008BB17BB48BB7CCF8091A5008DB9AC
:1005B0008091A2008EB90895282F8823A1F0883059
:1005C00008F042C08EE793E09093A4008093A300CC
:1005D000243019F12530B8F0263099F1263068F131
:1005E0002730F9F008958FE993E09093A400809369
:1005F000A30081E08093A70082E58093A50081E0BD
:100600008093A20008952230A1F0233070F42130AD
:1006100049F780EC8093A700089588E18093A700B4
:10062000089583E08093A700089580E38093A70056
:10063000089580E68093A70008958CE08093A7003A
:1006400008952093A70008958FE993E09093A40064
:100650008093A3001092A20081E08093A70029302C
:1006600041F02A3050F4283039F683E58093A50014
:10067000089582E58093A50008952B3029F02C3051
:1006800009F0BACF8093A20081E58093A500089578
:1006900022B79091A70082B7821B8917E0F30895D3
:1006A00087B38C6287BBC298C59892B72091A70088
:1006B00082B7891B8217E0F3C29A92B782B7891B6F
:1006C0008217E0F3C2988091A3009091A4008F5903
:1006D000934019F01092A60008958091A5008DB95D
:1006E0008091A2008EB91092A600089587B3837DF1
:1006F00087BB88B3837D88BB1DB80895582F209190
:10070000A70040E030E057FD16C0C398440FB499ED
:100710004F5FC59A92B782B7891B8217E0F3C598DD
:1007200092B782B7891B8217E0F33F5F383029F018
:10073000550F57FFEACFC39AE9CF842F08958FB999
:10074000779BFECF8FB108950F931F930FE1E09138
:10075000A300F091A4008CEA0995E091A300F09128
:10076000A40083E50995E091A300F091A40080E046
:100770000995182FE091A300F091A40080E009955D
:10078000133561F11DB822B79091A70082B7821B83
:100790008917E0F3C29A22B782B7821B8917E0F368
:1007A000C29822B782B7821B8917E0F3E091A300B9
:1007B000F091A40083E0EF39F80721F0002351F015
:1007C0000150C9CF8091A5008DB98091A2008EB94A
:1007D0000023B1F781E01F910F91089580E01F91F0
:1007E0000F9108959B01AC0181E15695479537958E
:1007F00027958A95D1F78091A6008217D9F020938A
:10080000A600E091A300F091A4008DE40995E09189
:10081000A300F091A40080E00995E091A300F0917D
:10082000A4008091A6000995E091A300F091A40096
:1008300080E009950895EF92FF920F931F937B013B
:100840008C01D0DF8E2D8170880F880F880FE0918A
:10085000A300F091A40080620995D801C70129E0A6
:10086000B695A795979587952A95D1F7E091A3001E
:10087000F091A400099516950795F794E794E091F7
:10088000A300F091A4008E2D0995E091A300F091B2
:10089000A40080E009951F910F91FF90EF900895BB
:1008A0000F931F938C01E091A300F091A40080EAC4
:1008B0000995E091A300F091A400812F0995E091A2
:1008C000A300F091A400802F0995E091A300F0917E
:1008D000A40080E009951F910F910895FF920F9356
:1008E0001F938C01F62EE091A300F091A40080EC00
:1008F0000995E091A300F091A400812F0995E09162
:10090000A300F091A400802F0995E091A300F0913D
:10091000A4008F2D09958EE1B9D080E01F910F9131
:10092000FF900895CF92DF92EF92FF920F931F9363
:100930006B017C01142F56DFE091A300F091A4001D
:100940008CE40995D701C60149E0B695A79597951E
:1009500087954A95D1F7E091A300F091A4000995FD
:10096000D701C601B695A79597958795E091A30005
:10097000F091A4000995E091A300F091A40080E01B
:1009800009951F3FF1F012B70EE1C701B60153DF21
:100990008F3F79F482B7811B8D33B8F312B70150C2
:1009A000A1F781E01F910F91FF90EF90DF90CF9022
:1009B000089580E01F910F91FF90EF90DF90CF900E
:1009C00008958FE063D080E01F910F91FF90EF902A
:1009D000DF90CF900895CF92DF92EF92FF920F9326
:1009E0001F936B017C01042F122FFCDE8C2D817074
:1009F000880F880F880FE091A300F091A400806415
:100A00000995D701C60169E0B695A7959795879591
:100A10006A95D1F7E091A300F091A4000995D70160
:100A2000C601B695A79597958795E091A300F0919B
:100A3000A4000995E091A300F091A400802F0995EE
:100A40001123C1F00F37F1F012B70EE1C701B60163
:100A5000F2DE8F3779F482B7811B8D33B8F312B78A
:100A60000150A1F781E01F910F91FF90EF90DF906F
:100A7000CF90089580E01F910F91FF90EF90DF904D
:100A8000CF9008958FE002D080E0F5CF382F8823F3
:100A900049F020E092B782B7891B8C33E0F32F5FD7
:100AA0002317C0F30895BD9ABB98C39A50E217D09C
:100AB0005A95E9F70895AC0188E605D0842F03D054
:100AC00089E601D0852F0FD028E030E0382780FB61
:100AD000869506D02A95D1F730FB02D000D06894D5
:100AE000BB98C39A16F0C398BB9AE091A800F09106
:100AF000A9003197F0F7C59AE6B3E3FBE091A800AF
:100B0000F091A9003197F0F7C598089520ECE7DF40
:100B100046F42A95E1F780E02AE1E5DF2A95E9F736
:100B2000DECF28E030E0DBDF869587F938272A958D
:100B3000D1F7D5DF27F9322772F3D1DFD0CFDB0130
:100B4000742FB9DF84E2BFDFE1DF8D937A95D1F7AF
:100B50000895DB01742FAFDF83EFB5DF8DE1B3DFE5
:100B600084E6B1DF8D91AFDF82E7ADDFCFDF807844
:100B7000D9F77A9589F7089512BA18BA8BEF81BB25
:100B80008FEF87BB17BA93E094BB8EEF85BB93BF03
:100B90008FDA789494DA93DAFDCFFF920F931F9354
:100BA000CF93DF93082F792FF62E409163004130C9
:100BB00069F0443059F0463009F492C01FEF812F9C
:100BC000DF91CF911F910F91FF900895FF2009F4BD
:100BD000B2C0802F972F9C01E90110E053C0809193
:100BE000740090917500892B09F058C060917000D5
:100BF000709171008091720090917300488121E0A2
:100C0000EADE809164009091650001979093650001
:100C100080936400892BD9F4109263008091760050
:100C200081FF3AC08091770090E02091740030916C
:100C300075008217930781F16091700070917100C7
:100C4000809172009091730048816CDE11E0809178
:100C5000700090917100A0917200B09173000196A4
:100C6000A11DB11D8093700090937100A09372003C
:100C7000B093730021969E01201B2F1508F09FCF83
:100C800040916300413009F4AACF809170009091A7
:100C90007100688123DEB5CF11E0D9CF609170007B
:100CA000709171008091720090917300488120E0F2
:100CB00092DE80917700815080937700882309F03D
:100CC000A0CF60917000709171008091720090913E
:100CD0007300488127DE809174008093770091CF64
:100CE0008091700090917100602F4F2D32DF8091C4
:100CF000700090917100A0917200B09173008F0DFF
:100D0000911DA11DB11D8093700090937100A0935F
:100D10007200B093730080916400909165008F1908
:100D200091099093650080936400892B21F41092BF
:100D3000630011E044CF10E0812FDF91CF911F912C
:100D40000F91FF9008950F931F93CF93DF93082F78
:100D5000792F162F40916300842F8250823050F0FB
:100D6000453009F446C01FEF812FDF91CF911F91CD
:100D70000F9108954530E9F1662399F1802F9C0188
:100D8000E90120C0809170009091710089DD888315
:100D90008091700090917100A0917200B0917300E9
:100DA0000196A11DB11D8093700090937100A093D6
:100DB0007200B093730021969E01201B211778F4D6
:100DC000409163004230F1F66091700070917100C3
:100DD00080917200909173002EDD8883D9CF1830F6
:100DE00018F610926300812FDF91CF911F910F9120
:100DF00008958091700090917100602F412F9FDEC7
:100E00008091700090917100A0917200B091730078
:100E1000810F911DA11DB11D8093700090937100F1
:100E2000A0937200B09373009FCF0F931F93CF9343
:100E3000DF938C01DC0111968C91813009F44EC056
:100E4000823009F4E7C0833009F455C0843009F4D6
:100E5000B5C0873009F486C0853009F45AC18630A0
:100E600009F410C1883009F4DBC0893009F458C195
:100E70008A3009F469C18B3009F49CC18C3009F4C3
:100E8000B7C18D3009F4CBC18E3009F4CFC18F309A
:100E900009F065C1F801938180E0228130E0822B66
:100EA000932BAA2797FDA095BA2F8093700090935B
:100EB0007100A0937200B0937300978180E0268147
:100EC00030E0822B932B909365008093640085E043
:100ED000809363008FEFC8E6D0E038C09A9B3FC094
:100EE0008091660069DB10926700A998D9DB80E0E9
:100EF000C8E6D0E02BC0E091A300F091A400D80197
:100F000012968C910995C8E6D0E080936800E09134
:100F1000A300F091A400D80113968C9109958093B9
:100F20006900E091A300F091A400D80114968C917F
:100F3000099580936A00E091A300F091A400D80184
:100F400015968C91099580936B0084E0D09387006F
:100F5000C0938600DF91CF911F910F91089585E096
:100F60002BDBC1CF80916700882399F4F80193812E
:100F700080E0228130E0822B932BAA2797FDA09559
:100F8000BA2F8093700090937100A0937200B09379
:100F90007300D80117969C91179780E016962C91B4
:100FA00030E0822B932B909365008093640083E064
:100FB000809363008FEFC8E6D0E0C8CF80916700D0
:100FC000882399F4F801938180E0228130E0822B1C
:100FD000932BAA2797FDA095BA2F8093700090932A
:100FE0007100A0937200B0937300D80117969C9182
:100FF000179780E016962C9130E0822B932B9093DC
:1010000065008093640082E0809363008FEFC8E600
:10101000D0E09CCF6BDBA99A80E0C8E6D0E096CF09
:10102000809167008823B1F4D80113969C9113979F
:1010300080E012962C9130E0822B932BAA2797FD0B
:10104000A095BA2F8093700090937100A0937200C6
:10105000B093730010927500109274001092760095
:10106000F801978180E0268130E0822B932B9093CA
:1010700065008093640084E0809363008FEFC8E68E
:10108000D0E064CF80916700882399F4F8019381C0
:1010900080E0228130E0822B932BAA2797FDA09538
:1010A000BA2F8093700090937100A0937200B09358
:1010B0007300D80114968C91149715969C91292F42
:1010C0002F7020937600492F50E0407F507042955A
:1010D0005295507F5427407F5427480F511D5093FD
:1010E00075004093740020FF02C040937700F80120
:1010F000978180E0268130E0822B932B90936500CE
:101100008093640081E0809363008FEFC8E6D0E0B5
:101110001DCF1ADBC8E6D0E08093680081E016CFCF
:1011200081E080936700F80182819381A481B58179
:101130008093700090937100A0937200B09373003D
:1011400080E0C8E6D0E002CFD80112968C9180935F
:101150006600C8E6D0E01092680081E0F7CE8031EA
:1011600009F040C0D80113969C91139780E0129625
:101170002C9130E0822B932BAA2797FDA095BA2FB4
:101180008093700090937100A0937200B0937300ED
:10119000F801978180E0268130E0822B932B909399
:1011A00065008093640086E0809363008FEFC8E65B
:1011B000D0E0CCCEF801938180E0228130E0822B18
:1011C000932B9093A9008093A800C29ABA9A83E0C7
:1011D0005DDCC298A99880E159DC65DC80E0C8E656
:1011E000D0E0B4CE8F3751F180E0C8E6D0E0AECE8B
:1011F00080EC69DC80E067DC8AE048DCC29A85E04C
:1012000045DCC29885E042DC87B3837D87BB88B329
:10121000837D88BBA99A80E0C8E6D0E097CE76DCD3
:10122000C8E6D0E08093680081E090CED8011296A5
:101230008C9149DC80E0C8E6D0E088CEC8E6D0E0FA
:1012400081E0809368001092690010926A00109209
:0A1250006B0084E07BCEF894FFCF22
:02125A005AFF39
:00000001FF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment