Browse Source

Merge pull request #288 from PavelSindler/MK3_for_merging

Merging MK3 from dev repository
PavelSindler 7 năm trước cách đây
mục cha
commit
9c7a4e4882
77 tập tin đã thay đổi với 41963 bổ sung13785 xóa
  1. 137 16
      Firmware/Configuration.h
  2. 87 46
      Firmware/ConfigurationStore.cpp
  3. 8 3
      Firmware/ConfigurationStore.h
  4. 50 19
      Firmware/Configuration_adv.h
  5. 530 0
      Firmware/Configuration_prusa.h
  6. 462 0
      Firmware/Dcodes.cpp
  7. 22 0
      Firmware/Dcodes.h
  8. 14889 0
      Firmware/Firmware.ino.rambo.hex
  9. 1 1
      Firmware/Firmware.sublime-project
  10. 142 1
      Firmware/LiquidCrystal.cpp
  11. 10 1
      Firmware/LiquidCrystal.h
  12. 427 312
      Firmware/Marlin.h
  13. 51 4
      Firmware/MarlinSerial.cpp
  14. 42 17
      Firmware/MarlinSerial.h
  15. 3862 1250
      Firmware/Marlin_main.cpp
  16. 813 811
      Firmware/Sd2Card.cpp
  17. 261 257
      Firmware/Sd2Card.h
  18. 367 367
      Firmware/Sd2PinMap.h
  19. 3 3
      Firmware/SdBaseFile.cpp
  20. 5 5
      Firmware/SdBaseFile.h
  21. 28 0
      Firmware/SdFatUtil.cpp
  22. 50 47
      Firmware/SdFatUtil.h
  23. 95 95
      Firmware/SdFile.cpp
  24. 285 285
      Firmware/SdInfo.h
  25. 404 404
      Firmware/SdVolume.cpp
  26. 6 5
      Firmware/boards.h
  27. 25 3
      Firmware/cardreader.cpp
  28. 6 0
      Firmware/cardreader.h
  29. 680 0
      Firmware/cmdqueue.cpp
  30. 89 0
      Firmware/cmdqueue.h
  31. 199 0
      Firmware/fsensor.cpp
  32. 32 0
      Firmware/fsensor.h
  33. 224 27
      Firmware/langtool.pl
  34. 0 33
      Firmware/language.h
  35. 1260 2694
      Firmware/language_all.cpp
  36. 513 347
      Firmware/language_all.h
  37. 110 0
      Firmware/language_common.h
  38. 155 116
      Firmware/language_cz.h
  39. 350 0
      Firmware/language_de.h
  40. 219 158
      Firmware/language_en.h
  41. 189 143
      Firmware/language_es.h
  42. 322 275
      Firmware/language_it.h
  43. 148 105
      Firmware/language_pl.h
  44. 29 0
      Firmware/le.sh
  45. 2613 2066
      Firmware/mesh_bed_calibration.cpp
  46. 191 170
      Firmware/mesh_bed_calibration.h
  47. 139 0
      Firmware/pat9125.cpp
  48. 46 0
      Firmware/pat9125.h
  49. 18 266
      Firmware/pins.h
  50. 129 0
      Firmware/pins_Einy_0_3.h
  51. 124 0
      Firmware/pins_Einy_0_4.h
  52. 162 0
      Firmware/pins_Rambo.h
  53. 94 0
      Firmware/pins_Rambo_1_0.h
  54. 102 0
      Firmware/pins_Rambo_1_3.h
  55. 447 221
      Firmware/planner.cpp
  56. 58 16
      Firmware/planner.h
  57. 403 186
      Firmware/stepper.cpp
  58. 16 0
      Firmware/stepper.h
  59. 209 0
      Firmware/swi2c.cpp
  60. 22 0
      Firmware/swi2c.h
  61. 93 0
      Firmware/swspi.cpp
  62. 14 0
      Firmware/swspi.h
  63. 2244 1861
      Firmware/temperature.cpp
  64. 228 209
      Firmware/temperature.h
  65. 166 0
      Firmware/thermistortables.h
  66. 780 0
      Firmware/tmc2130.cpp
  67. 97 0
      Firmware/tmc2130.h
  68. 3846 559
      Firmware/ultralcd.cpp
  69. 102 18
      Firmware/ultralcd.h
  70. 184 46
      Firmware/ultralcd_implementation_hitachi_HD44780.h
  71. 31 0
      Firmware/uni_avr_rpi.h
  72. 288 288
      Firmware/util.cpp
  73. 35 24
      Firmware/util.h
  74. 485 0
      Firmware/variants/1_75mm_MK3-EINY03-E3Dv6full.h
  75. 493 0
      Firmware/variants/1_75mm_MK3-EINY04-E3Dv6full.h
  76. 512 0
      Firmware/variants/1_75mm_MK3-EINY10a-E3Dv6full.h
  77. 5 5
      README.md

+ 137 - 16
Firmware/Configuration.h

@@ -4,20 +4,27 @@
 #include "boards.h"
 #include "Configuration_prusa.h"
 
+#define STR_HELPER(x) #x
+#define STR(x) STR_HELPER(x)
+
 // Firmware version
-#define FW_version "3.0.5"
+#define FW_version "3.1.1-RC1"
+#define FW_build   121
+//#define FW_build   --BUILD-NUMBER--
+#define FW_version_build FW_version " b" STR(FW_build)
+
 
 #define FW_PRUSA3D_MAGIC "PRUSA3DFW"
 #define FW_PRUSA3D_MAGIC_LEN 10
-
 // The total size of the EEPROM is
 // 4096 for the Atmega2560
+#define EEPROM_TOP 4096
 #define EEPROM_SILENT 4095
 #define EEPROM_LANG 4094
 #define EEPROM_BABYSTEP_X 4092
 #define EEPROM_BABYSTEP_Y 4090
 #define EEPROM_BABYSTEP_Z 4088
-#define EEPROM_BABYSTEP_Z_SET 4087
+#define EEPROM_CALIBRATION_STATUS 4087
 #define EEPROM_BABYSTEP_Z0 4085
 #define EEPROM_FILAMENTUSED 4081
 // uint32_t
@@ -30,17 +37,92 @@
 // Offsets of the Z heiths of the calibration points from the first point.
 // The offsets are saved as 16bit signed int, scaled to tenths of microns.
 #define EEPROM_BED_CALIBRATION_Z_JITTER   (EEPROM_BED_CALIBRATION_VEC_Y-2*8)
-
-#define EEPROM_FARM_MODE (EEPROM_BED_CALIBRATION_Z_JITTER-4)
+#define EEPROM_FARM_MODE (EEPROM_BED_CALIBRATION_Z_JITTER-1)
+#define EEPROM_FARM_NUMBER (EEPROM_FARM_MODE-3)
+
+// Correction of the bed leveling, in micrometers.
+// Maximum 50 micrometers allowed.
+// Bed correction is valid if set to 1. If set to zero or 255, the successive 4 bytes are invalid.
+#define EEPROM_BED_CORRECTION_VALID (EEPROM_FARM_NUMBER-1)
+#define EEPROM_BED_CORRECTION_LEFT  (EEPROM_BED_CORRECTION_VALID-1)
+#define EEPROM_BED_CORRECTION_RIGHT (EEPROM_BED_CORRECTION_LEFT-1)
+#define EEPROM_BED_CORRECTION_FRONT (EEPROM_BED_CORRECTION_RIGHT-1)
+#define EEPROM_BED_CORRECTION_REAR  (EEPROM_BED_CORRECTION_FRONT-1)
+#define EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY (EEPROM_BED_CORRECTION_REAR-1)
+#define EEPROM_PRINT_FLAG (EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY-1)
+#define EEPROM_PROBE_TEMP_SHIFT (EEPROM_PRINT_FLAG - 2*5) //5 x int for storing pinda probe temp shift relative to 50 C; unit: motor steps 
+#define EEPROM_TEMP_CAL_ACTIVE (EEPROM_PROBE_TEMP_SHIFT - 1)
+#define EEPROM_BOWDEN_LENGTH (EEPROM_TEMP_CAL_ACTIVE - 2*4) //4 x int for bowden lengths for multimaterial
+#define EEPROM_CALIBRATION_STATUS_PINDA (EEPROM_BOWDEN_LENGTH - 1) //0 - not calibrated; 1 - calibrated
+#define EEPROM_UVLO						(EEPROM_CALIBRATION_STATUS_PINDA - 1) //1 - uvlo during print
+#define EEPROM_UVLO_CURRENT_POSITION	(EEPROM_UVLO-2*4) // 2 x float for current_position in X and Y axes
+#define EEPROM_FILENAME (EEPROM_UVLO_CURRENT_POSITION - 8) //8chars to store filename without extension
+#define EEPROM_FILE_POSITION (EEPROM_FILENAME - 4) //32 bit for uint32_t file position 
+#define EEPROM_UVLO_CURRENT_POSITION_Z	(EEPROM_FILE_POSITION - 4) //float for current position in Z
+#define EEPROM_UVLO_TARGET_HOTEND		(EEPROM_UVLO_CURRENT_POSITION_Z - 1)
+#define EEPROM_UVLO_TARGET_BED			(EEPROM_UVLO_TARGET_HOTEND - 1)
+#define EEPROM_UVLO_FEEDRATE			(EEPROM_UVLO_TARGET_BED - 2)
+#define EEPROM_UVLO_FAN_SPEED			(EEPROM_UVLO_FEEDRATE - 1) 
+#define EEPROM_FAN_CHECK_ENABLED		(EEPROM_UVLO_FAN_SPEED - 1)
+#define EEPROM_UVLO_MESH_BED_LEVELING     (EEPROM_FAN_CHECK_ENABLED - 9*2)
+#define EEPROM_UVLO_Z_MICROSTEPS     (EEPROM_UVLO_MESH_BED_LEVELING - 2)
+#define EEPROM_UVLO_E_ABS            (EEPROM_UVLO_Z_MICROSTEPS - 1)
+#define EEPROM_UVLO_CURRENT_POSITION_E	(EEPROM_UVLO_E_ABS - 4) //float for current position in E
+
+// Crash detection mode EEPROM setting 
+#define EEPROM_CRASH_DET       (EEPROM_UVLO_MESH_BED_LEVELING-12) 
+// Filament sensor on/off EEPROM setting 
+#define EEPROM_FSENSOR       (EEPROM_UVLO_MESH_BED_LEVELING-14) 
+// Crash detection counter
+#define EEPROM_CRASH_COUNT       (EEPROM_UVLO_MESH_BED_LEVELING-15)
+// Filament runout/error coutner
+#define EEPROM_FERROR_COUNT      (EEPROM_UVLO_MESH_BED_LEVELING-16)
+// Power loss errors
+#define EEPROM_POWER_COUNT       (EEPROM_UVLO_MESH_BED_LEVELING-17)
+#define EEPROM_DIR_DEPTH        (EEPROM_POWER_COUNT-1)
+#define EEPROM_DIRS  (EEPROM_DIR_DEPTH-80) //8 chars for each dir name, max 10 levels
+
+//TMC2130 configuration
+#define EEPROM_TMC_AXIS_SIZE  //axis configuration block size
+#define EEPROM_TMC_X (EEPROM_TMC + 0 * EEPROM_TMC_AXIS_SIZE) //X axis configuration blok
+#define EEPROM_TMC_Y (EEPROM_TMC + 1 * EEPROM_TMC_AXIS_SIZE) //Y axis
+#define EEPROM_TMC_Z (EEPROM_TMC + 2 * EEPROM_TMC_AXIS_SIZE) //Z axis
+#define EEPROM_TMC_E (EEPROM_TMC + 3 * EEPROM_TMC_AXIS_SIZE) //E axis
+//TMC2130 - X axis
+#define EEPROM_TMC_X_USTEPS_INTPOL   (EEPROM_TMC_X +  0) // 1byte, bit 0..4 USTEPS, bit 7 INTPOL
+#define EEPROM_TMC_X_PWM_AMPL        (EEPROM_TMC_X +  1) // 1byte (0..255)
+#define EEPROM_TMC_X_PWM_GRAD_FREQ   (EEPROM_TMC_X +  2) // 1byte, bit 0..3 GRAD, bit 4..5 FREQ
+#define EEPROM_TMC_X_TCOOLTHRS       (EEPROM_TMC_X +  3) // 2bytes (0..)
+#define EEPROM_TMC_X_SG_THRS         (EEPROM_TMC_X +  5) // 1byte, (-64..+63)
+#define EEPROM_TMC_X_CURRENT_H       (EEPROM_TMC_X +  6) // 1byte, (0..63)
+#define EEPROM_TMC_X_CURRENT_R       (EEPROM_TMC_X +  7) // 1byte, (0..63)
+#define EEPROM_TMC_X_HOME_SG_THRS    (EEPROM_TMC_X +  8) // 1byte, (-64..+63)
+#define EEPROM_TMC_X_HOME_CURRENT_R  (EEPROM_TMC_X +  9) // 1byte, (-64..+63)
+#define EEPROM_TMC_X_HOME_DTCOOLTHRS (EEPROM_TMC_X + 10) // 1byte (-128..+127)
+#define EEPROM_TMC_X_DTCOOLTHRS_LOW  (EEPROM_TMC_X + 11) // 1byte (-128..+127)
+#define EEPROM_TMC_X_DTCOOLTHRS_HIGH (EEPROM_TMC_X + 12) // 1byte (-128..+127)
+#define EEPROM_TMC_X_SG_THRS_LOW     (EEPROM_TMC_X + 13) // 1byte, (-64..+63)
+#define EEPROM_TMC_X_SG_THRS_HIGH    (EEPROM_TMC_X + 14) // 1byte, (-64..+63)
+
+#define EEPROM_XYZ_CAL_SKEW (EEPROM_POWER_COUNT - 4) //float for skew backup
+
+#define EEPROM_WIZARD_ACTIVE (EEPROM_XYZ_CAL_SKEW - 1)
+
+#define EEPROM_BELTSTATUS_X (EEPROM_WIZARD_ACTIVE - 2) //uint16
+#define EEPROM_BELTSTATUS_Y (EEPROM_BELTSTATUS_X - 2) //uint16
 
 // Currently running firmware, each digit stored as uint16_t.
 // The flavor differentiates a dev, alpha, beta, release candidate or a release version.
+#define EEPROM_FIRMWARE_VERSION_END       (FW_PRUSA3D_MAGIC_LEN+8)
 #define EEPROM_FIRMWARE_VERSION_FLAVOR    (FW_PRUSA3D_MAGIC_LEN+6)
 #define EEPROM_FIRMWARE_VERSION_REVISION  (FW_PRUSA3D_MAGIC_LEN+4)
 #define EEPROM_FIRMWARE_VERSION_MINOR     (FW_PRUSA3D_MAGIC_LEN+2)
 #define EEPROM_FIRMWARE_VERSION_MAJOR     FW_PRUSA3D_MAGIC_LEN
 // Magic string, indicating that the current or the previous firmware running was the Prusa3D firmware.
-#define EEPROM_FIRMWARE_PRUSA_MAGIC
+#define EEPROM_FIRMWARE_PRUSA_MAGIC 0
+
+#define EEPROM_OFFSET 20 //offset for storing settings using M500
+//#define EEPROM_OFFSET 
 
 // This configuration file contains the basic settings.
 // Advanced settings can be found in Configuration_adv.h
@@ -154,6 +236,10 @@
 //if PREVENT_DANGEROUS_EXTRUDE is on, you can still disable (uncomment) very long bits of extrusion separately.
 #define PREVENT_LENGTHY_EXTRUDE
 
+#ifdef DEBUG_DISABLE_PREVENT_EXTRUDER
+#undef PREVENT_DANGEROUS_EXTRUDE
+#undef PREVENT_LENGTHY_EXTRUDE
+#endif //DEBUG_DISABLE_PREVENT_EXTRUDER
 
 #define EXTRUDE_MAXLENGTH (X_MAX_LENGTH+Y_MAX_LENGTH) //prevent extrusion of very large distances.
 
@@ -226,8 +312,8 @@ your extruder heater takes 2 minutes to hit the target on heating.
 
 // The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins.
 
-const bool X_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop.
-const bool Y_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop.
+const bool X_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Y_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
 const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop.
 //#define DISABLE_MAX_ENDSTOPS
 //#define DISABLE_MIN_ENDSTOPS
@@ -250,10 +336,10 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
 #define DISABLE_E false // For all extruders
 #define DISABLE_INACTIVE_EXTRUDER true //disable only inactive extruders and keep active extruder enabled
 
-#define INVERT_X_DIR false    // for Mendel set to false, for Orca set to true
+#define INVERT_X_DIR true    // for Mendel set to false, for Orca set to true
 #define INVERT_Y_DIR false    // for Mendel set to true, for Orca set to false
-#define INVERT_Z_DIR false     // for Mendel set to false, for Orca set to true
-#define INVERT_E0_DIR true   // for direct drive extruder v9 set to true, for geared extruder set to false
+#define INVERT_Z_DIR true     // for Mendel set to false, for Orca set to true
+#define INVERT_E0_DIR false   // for direct drive extruder v9 set to true, for geared extruder set to false
 #define INVERT_E1_DIR false    // for direct drive extruder v9 set to true, for geared extruder set to false
 #define INVERT_E2_DIR false   // for direct drive extruder v9 set to true, for geared extruder set to false
 
@@ -263,15 +349,21 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
 #define Y_HOME_DIR -1
 #define Z_HOME_DIR -1
 
+#ifdef DEBUG_DISABLE_SWLIMITS
+#define min_software_endstops false
+#define max_software_endstops false
+#else
 #define min_software_endstops true // If true, axis won't move to coordinates less than HOME_POS.
 #define max_software_endstops true  // If true, axis won't move to coordinates greater than the defined lengths below.
-
+#endif //DEBUG_DISABLE_SWLIMITS
 
 
 #define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS)
 #define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) 
 #define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS)
 
+#define Z_HEIGHT_HIDE_LIVE_ADJUST_MENU 2.0f
+
 //============================= Bed Auto Leveling ===========================
 
 //#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line)
@@ -405,9 +497,10 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
 // #define EXTRUDER_OFFSET_Y {0.0, 5.00}  // (in mm) for each extruder, offset of the hotend on the Y axis
 
 // The speed change that does not require acceleration (i.e. the software might assume it can be done instantaneously)
-#define DEFAULT_XYJERK                20.0    // (mm/sec)
+#define DEFAULT_XJERK                15       // (mm/sec)
+#define DEFAULT_YJERK                15       // (mm/sec)
 #define DEFAULT_ZJERK                 0.4     // (mm/sec)
-#define DEFAULT_EJERK                 5.0    // (mm/sec)
+#define DEFAULT_EJERK                 2.5     // (mm/sec)
 
 //===========================================================================
 //=============================Additional Features===========================
@@ -433,7 +526,13 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
 // please keep turned on if you can.
 //#define EEPROM_CHITCHAT
 
-
+// Host Keepalive
+//
+// When enabled Marlin will send a busy status message to the host
+// every couple of seconds when it can't accept commands.
+//
+#define HOST_KEEPALIVE_FEATURE    // Disable this if your host doesn't like keepalive messages
+#define HOST_KEEPALIVE_INTERVAL 2 // Number of seconds between "busy" messages. Set with M113.
 
 //LCD and SD support
 #define ULTRA_LCD  //general LCD support, also 16x2
@@ -678,14 +777,36 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
 //#define FILAMENT_LCD_DISPLAY
 
 
+// Calibration status of the machine, to be stored into the EEPROM,
+// (unsigned char*)EEPROM_CALIBRATION_STATUS
+enum CalibrationStatus
+{
+	// Freshly assembled, needs to peform a self-test and the XYZ calibration.
+	CALIBRATION_STATUS_ASSEMBLED = 255,
 
+	// For the wizard: self test has been performed, now the XYZ calibration is needed.
+	CALIBRATION_STATUS_XYZ_CALIBRATION = 250,
 
+	// For the wizard: factory assembled, needs to run Z calibration.
+	CALIBRATION_STATUS_Z_CALIBRATION = 240,
 
+	// The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode.
+	CALIBRATION_STATUS_LIVE_ADJUST = 230,
+
+    // Calibrated, ready to print.
+    CALIBRATION_STATUS_CALIBRATED = 1,
+
+    // Legacy: resetted by issuing a G86 G-code.
+    // This value can only be expected after an upgrade from the initial MK2 firmware releases.
+    // Currently the G86 sets the calibration status to 
+    CALIBRATION_STATUS_UNKNOWN = 0,
+};
 
 #include "Configuration_adv.h"
 #include "thermistortables.h"
 
+#define PINDA_THERMISTOR
 
-
+#define AMBIENT_THERMISTOR
 
 #endif //__CONFIGURATION_H

+ 87 - 46
Firmware/ConfigurationStore.cpp

@@ -11,12 +11,22 @@
 
 void _EEPROM_writeData(int &pos, uint8_t* value, uint8_t size)
 {
-    do
-    {
-        eeprom_write_byte((unsigned char*)pos, *value);
-        pos++;
-        value++;
-    }while(--size);
+	while (size--) {
+		uint8_t * const p = (uint8_t * const)pos;
+		uint8_t v = *value;
+		// EEPROM has only ~100,000 write cycles,
+		// so only write bytes that have changed!
+		if (v != eeprom_read_byte(p)) {
+			eeprom_write_byte(p, v);
+			if (eeprom_read_byte(p) != v) {
+				SERIAL_ECHOLNPGM("EEPROM Error");
+				return;
+			}
+		}
+		pos++;
+		value++;
+	};
+
 }
 #define EEPROM_WRITE_VAR(pos, value) _EEPROM_writeData(pos, (uint8_t*)&value, sizeof(value))
 void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size)
@@ -30,26 +40,20 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size)
 }
 #define EEPROM_READ_VAR(pos, value) _EEPROM_readData(pos, (uint8_t*)&value, sizeof(value))
 //======================================================================================
-
-
-
-
-#define EEPROM_OFFSET 100
-
-
+#define EEPROM_OFFSET 20
 // IMPORTANT:  Whenever there are changes made to the variables stored in EEPROM
 // in the functions below, also increment the version number. This makes sure that
 // the default values are used whenever there is a change to the data, to prevent
 // wrong data being written to the variables.
 // ALSO:  always make sure the variables in the Store and retrieve sections are in the same order.
 
-#define EEPROM_VERSION "V13"
+#define EEPROM_VERSION "V1"
 
 #ifdef EEPROM_SETTINGS
-void Config_StoreSettings() 
+void Config_StoreSettings(uint16_t offset, uint8_t level) 
 {
   char ver[4]= "000";
-  int i=EEPROM_OFFSET;
+  int i = offset;
   EEPROM_WRITE_VAR(i,ver); // invalidate data first 
   EEPROM_WRITE_VAR(i,axis_steps_per_unit);
   EEPROM_WRITE_VAR(i,max_feedrate);  
@@ -59,9 +63,10 @@ void Config_StoreSettings()
   EEPROM_WRITE_VAR(i,minimumfeedrate);
   EEPROM_WRITE_VAR(i,mintravelfeedrate);
   EEPROM_WRITE_VAR(i,minsegmenttime);
-  EEPROM_WRITE_VAR(i,max_xy_jerk);
-  EEPROM_WRITE_VAR(i,max_z_jerk);
-  EEPROM_WRITE_VAR(i,max_e_jerk);
+  EEPROM_WRITE_VAR(i,max_jerk[X_AXIS]);
+  EEPROM_WRITE_VAR(i,max_jerk[Y_AXIS]);
+  EEPROM_WRITE_VAR(i,max_jerk[Z_AXIS]);
+  EEPROM_WRITE_VAR(i,max_jerk[E_AXIS]);
   EEPROM_WRITE_VAR(i,add_homing);
   #ifndef ULTIPANEL
   int plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP, plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP, plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED;
@@ -70,12 +75,13 @@ void Config_StoreSettings()
 
   
   #endif
-  EEPROM_WRITE_VAR(i,plaPreheatHotendTemp);
+/*  EEPROM_WRITE_VAR(i,plaPreheatHotendTemp);
   EEPROM_WRITE_VAR(i,plaPreheatHPBTemp);
   EEPROM_WRITE_VAR(i,plaPreheatFanSpeed);
   EEPROM_WRITE_VAR(i,absPreheatHotendTemp);
   EEPROM_WRITE_VAR(i,absPreheatHPBTemp);
   EEPROM_WRITE_VAR(i,absPreheatFanSpeed);
+*/
   
   EEPROM_WRITE_VAR(i,zprobe_zoffset);
   #ifdef PIDTEMP
@@ -89,6 +95,11 @@ void Config_StoreSettings()
     EEPROM_WRITE_VAR(i,dummy);
     EEPROM_WRITE_VAR(i,dummy);
   #endif
+  #ifdef PIDTEMPBED
+	EEPROM_WRITE_VAR(i, bedKp);
+	EEPROM_WRITE_VAR(i, bedKi);
+	EEPROM_WRITE_VAR(i, bedKd);
+  #endif
   #ifndef DOGLCD
     int lcd_contrast = 32;
   #endif
@@ -117,9 +128,17 @@ void Config_StoreSettings()
   EEPROM_WRITE_VAR(i, filament_size[2]);
   #endif
   #endif
-  
+
+  if (level >= 10) {
+	  EEPROM_WRITE_VAR(i, extruder_advance_k);
+	  EEPROM_WRITE_VAR(i, advance_ed_ratio);
+  }
+  /*MYSERIAL.print("Top address used:\n");
+  MYSERIAL.print(i); 
+  MYSERIAL.print("\n");
+  */
   char ver2[4]=EEPROM_VERSION;
-  i=EEPROM_OFFSET;
+  i=offset;
   EEPROM_WRITE_VAR(i,ver2); // validate data
   SERIAL_ECHO_START;
   SERIAL_ECHOLNPGM("Settings Stored");
@@ -128,9 +147,10 @@ void Config_StoreSettings()
 
 
 #ifndef DISABLE_M503
-void Config_PrintSettings()
+void Config_PrintSettings(uint8_t level)
 {  // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown
-    SERIAL_ECHO_START;
+	
+	SERIAL_ECHO_START;
     SERIAL_ECHOLNPGM("Steps per unit:");
     SERIAL_ECHO_START;
     SERIAL_ECHOPAIR("  M92 X",axis_steps_per_unit[X_AXIS]);
@@ -169,9 +189,10 @@ void Config_PrintSettings()
     SERIAL_ECHOPAIR("  M205 S",minimumfeedrate ); 
     SERIAL_ECHOPAIR(" T" ,mintravelfeedrate ); 
     SERIAL_ECHOPAIR(" B" ,minsegmenttime ); 
-    SERIAL_ECHOPAIR(" X" ,max_xy_jerk ); 
-    SERIAL_ECHOPAIR(" Z" ,max_z_jerk);
-    SERIAL_ECHOPAIR(" E" ,max_e_jerk);
+    SERIAL_ECHOPAIR(" X" ,max_jerk[X_AXIS] ); 
+    SERIAL_ECHOPAIR(" Y" ,max_jerk[Y_AXIS] ); 
+    SERIAL_ECHOPAIR(" Z" ,max_jerk[Z_AXIS] ); 
+    SERIAL_ECHOPAIR(" E" ,max_jerk[E_AXIS] ); 
     SERIAL_ECHOLN(""); 
 
     SERIAL_ECHO_START;
@@ -190,6 +211,15 @@ void Config_PrintSettings()
     SERIAL_ECHOPAIR(" D" ,unscalePID_d(Kd));
     SERIAL_ECHOLN(""); 
 #endif
+#ifdef PIDTEMPBED
+	SERIAL_ECHO_START;
+	SERIAL_ECHOLNPGM("PID heatbed settings:");
+	SERIAL_ECHO_START;
+	SERIAL_ECHOPAIR("   M304 P", bedKp);
+	SERIAL_ECHOPAIR(" I", unscalePID_i(bedKi));
+	SERIAL_ECHOPAIR(" D", unscalePID_d(bedKd));
+	SERIAL_ECHOLN("");
+#endif
 #ifdef FWRETRACT
     SERIAL_ECHO_START;
     SERIAL_ECHOLNPGM("Retract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)");
@@ -239,14 +269,22 @@ void Config_PrintSettings()
         SERIAL_ECHOLNPGM("Filament settings: Disabled");
     }
 #endif
+	if (level >= 10) {
+#ifdef LIN_ADVANCE
+		SERIAL_ECHO_START;
+		SERIAL_ECHOLNPGM("Linear advance settings:");
+		SERIAL_ECHOPAIR("   M900 K", extruder_advance_k);
+		SERIAL_ECHOPAIR("   E/D = ", advance_ed_ratio);
+#endif //LIN_ADVANCE
+	}
 }
 #endif
 
 
 #ifdef EEPROM_SETTINGS
-void Config_RetrieveSettings()
+void Config_RetrieveSettings(uint16_t offset, uint8_t level)
 {
-    int i=EEPROM_OFFSET;
+    int i=offset;
     char stored_ver[4];
     char ver[4]=EEPROM_VERSION;
     EEPROM_READ_VAR(i,stored_ver); //read stored version
@@ -266,22 +304,24 @@ void Config_RetrieveSettings()
         EEPROM_READ_VAR(i,minimumfeedrate);
         EEPROM_READ_VAR(i,mintravelfeedrate);
         EEPROM_READ_VAR(i,minsegmenttime);
-        EEPROM_READ_VAR(i,max_xy_jerk);
-        EEPROM_READ_VAR(i,max_z_jerk);
-        EEPROM_READ_VAR(i,max_e_jerk);
+        EEPROM_READ_VAR(i,max_jerk[X_AXIS]);
+        EEPROM_READ_VAR(i,max_jerk[Y_AXIS]);
+		EEPROM_READ_VAR(i,max_jerk[Z_AXIS]);
+		EEPROM_READ_VAR(i,max_jerk[E_AXIS]);
         EEPROM_READ_VAR(i,add_homing);
         #ifndef ULTIPANEL
         int plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed;
         int absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed;
 
         #endif
+	/*
         EEPROM_READ_VAR(i,plaPreheatHotendTemp);
         EEPROM_READ_VAR(i,plaPreheatHPBTemp);
         EEPROM_READ_VAR(i,plaPreheatFanSpeed);
         EEPROM_READ_VAR(i,absPreheatHotendTemp);
         EEPROM_READ_VAR(i,absPreheatHPBTemp);
         EEPROM_READ_VAR(i,absPreheatFanSpeed);
-        
+        */
 
         
         EEPROM_READ_VAR(i,zprobe_zoffset);
@@ -292,7 +332,12 @@ void Config_RetrieveSettings()
         EEPROM_READ_VAR(i,Kp);
         EEPROM_READ_VAR(i,Ki);
         EEPROM_READ_VAR(i,Kd);
-        #ifndef DOGLCD
+		#ifdef PIDTEMPBED
+		EEPROM_READ_VAR(i, bedKp);
+		EEPROM_READ_VAR(i, bedKi);
+		EEPROM_READ_VAR(i, bedKd);
+		#endif
+		#ifndef DOGLCD
         int lcd_contrast;
         #endif
         EEPROM_READ_VAR(i,lcd_contrast);
@@ -320,6 +365,10 @@ void Config_RetrieveSettings()
 		EEPROM_READ_VAR(i, filament_size[2]);
 #endif
 #endif
+		if (level >= 10) {
+			EEPROM_READ_VAR(i, extruder_advance_k);
+			EEPROM_READ_VAR(i, advance_ed_ratio);
+		}
 		calculate_volumetric_multipliers();
 		// Call updatePID (similar to when we have processed M301)
 		updatePID();
@@ -356,20 +405,12 @@ void Config_ResetDefault()
     minimumfeedrate=DEFAULT_MINIMUMFEEDRATE;
     minsegmenttime=DEFAULT_MINSEGMENTTIME;       
     mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE;
-    max_xy_jerk=DEFAULT_XYJERK;
-    max_z_jerk=DEFAULT_ZJERK;
-    max_e_jerk=DEFAULT_EJERK;
+    max_jerk[X_AXIS] = DEFAULT_XJERK;
+    max_jerk[Y_AXIS] = DEFAULT_YJERK;
+    max_jerk[Z_AXIS] = DEFAULT_ZJERK;
+    max_jerk[E_AXIS] = DEFAULT_EJERK;
     add_homing[X_AXIS] = add_homing[Y_AXIS] = add_homing[Z_AXIS] = 0;
-#ifdef ULTIPANEL
-    plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP;
-    plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP;
-    plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED;
-    absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP;
-    absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP;
-    absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED;
-    
 
-#endif
 #ifdef ENABLE_AUTO_BED_LEVELING
     zprobe_zoffset = -Z_PROBE_OFFSET_FROM_EXTRUDER;
 #endif

+ 8 - 3
Firmware/ConfigurationStore.h

@@ -1,22 +1,27 @@
 #ifndef CONFIG_STORE_H
 #define CONFIG_STORE_H
+#define EEPROM_SETTINGS
 
 #include "Configuration.h"
 
 void Config_ResetDefault();
 
 #ifndef DISABLE_M503
-void Config_PrintSettings();
+void Config_PrintSettings(uint8_t level = 0);
 #else
 FORCE_INLINE void Config_PrintSettings() {}
 #endif
 
 #ifdef EEPROM_SETTINGS
-void Config_StoreSettings();
-void Config_RetrieveSettings();
+void Config_StoreSettings(uint16_t offset, uint8_t level = 0);
+void Config_RetrieveSettings(uint16_t offset, uint8_t level = 0);
 #else
 FORCE_INLINE void Config_StoreSettings() {}
 FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_PrintSettings(); }
 #endif
 
+inline uint8_t calibration_status() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); }
+inline uint8_t calibration_status_store(uint8_t status) { eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); }
+inline bool calibration_status_pinda() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA); }
+
 #endif//CONFIG_STORE_H

+ 50 - 19
Firmware/Configuration_adv.h

@@ -68,7 +68,7 @@
 // When first starting the main fan, run it at full speed for the
 // given number of milliseconds.  This gets the fan spinning reliably
 // before setting a PWM value. (Does not work with software PWM for fan on Sanguinololu)
-//#define FAN_KICKSTART_TIME 100
+#define FAN_KICKSTART_TIME 800
 
 
 
@@ -265,24 +265,45 @@
   #endif
 #endif
 
-// extruder advance constant (s2/mm3)
-//
-// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K * cubic mm per second ^ 2
-//
-// Hooke's law says:		force = k * distance
-// Bernoulli's principle says:	v ^ 2 / 2 + g . h + pressure / density = constant
-// so: v ^ 2 is proportional to number of steps we advance the extruder
-//#define ADVANCE
-
-#ifdef ADVANCE
-  #define EXTRUDER_ADVANCE_K .006
-
-  #define D_FILAMENT 1.75
-  #define STEPS_MM_E 174.6
-  #define EXTRUSION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159)
-  #define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUSION_AREA)
-
-#endif // ADVANCE
+/**
+    * Implementation of linear pressure control
+    *
+    * Assumption: advance = k * (delta velocity)
+    * K=0 means advance disabled.
+    * See Marlin documentation for calibration instructions.
+    */
+#define LIN_ADVANCE
+
+#ifdef LIN_ADVANCE
+  #define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS.
+
+ /**
+        * Some Slicers produce Gcode with randomly jumping extrusion widths occasionally.
+        * For example within a 0.4mm perimeter it may produce a single segment of 0.05mm width.
+        * While this is harmless for normal printing (the fluid nature of the filament will
+        * close this very, very tiny gap), it throws off the LIN_ADVANCE pressure adaption.
+        *
+        * For this case LIN_ADVANCE_E_D_RATIO can be used to set the extrusion:distance ratio
+        * to a fixed value. Note that using a fixed ratio will lead to wrong nozzle pressures
+        * if the slicer is using variable widths or layer heights within one print!
+        *
+        * This option sets the default E:D ratio at startup. Use `M900` to override this value.
+        *
+        * Example: `M900 W0.4 H0.2 D1.75`, where:
+        *   - W is the extrusion width in mm
+        *   - H is the layer height in mm
+        *   - D is the filament diameter in mm
+        *
+        * Example: `M900 R0.0458` to set the ratio directly.
+        *
+        * Set to 0 to auto-detect the ratio based on given Gcode G1 print moves.
+        *
+        * Slic3r (including Prusa Slic3r) produces Gcode compatible with the automatic mode.
+        * Cura (as of this writing) may produce Gcode incompatible with the automatic mode.
+        */
+#define LIN_ADVANCE_E_D_RATIO 0 // The calculated ratio (or 0) according to the formula W * H / ((D / 2) ^ 2 * PI)
+                                // Example: 0.4 * 0.2 / ((1.75 / 2) ^ 2 * PI) = 0.033260135
+#endif
 
 // Arc interpretation settings:
 #define MM_PER_ARC_SEGMENT 1
@@ -335,6 +356,10 @@ const unsigned int dropsegments=5; //everything with less than this number of st
 //The ASCII buffer for receiving from the serial:
 #define MAX_CMD_SIZE 96
 #define BUFSIZE 4
+// The command header contains the following values:
+// 1st byte: the command source (CMDBUFFER_CURRENT_TYPE_USB, CMDBUFFER_CURRENT_TYPE_SDCARD, CMDBUFFER_CURRENT_TYPE_UI or CMDBUFFER_CURRENT_TYPE_CHAINED)
+// 2nd and 3rd byte (LSB first) contains a 16bit length of a command including its preceding comments.
+#define CMDHDRSIZE 3
 
 
 // Firmware based and LCD controlled retract
@@ -392,6 +417,12 @@ const unsigned int dropsegments=5; //everything with less than this number of st
   #define THERMISTORBED TEMP_SENSOR_BED
   #define BED_USES_THERMISTOR
 #endif
+#if TEMP_SENSOR_PINDA > 0
+  #define THERMISTORPINDA TEMP_SENSOR_PINDA
+#endif
+#if TEMP_SENSOR_AMBIENT > 0
+  #define THERMISTORAMBIENT TEMP_SENSOR_AMBIENT
+#endif
 #if TEMP_SENSOR_0 == -1
   #define HEATER_0_USES_AD595
 #endif

+ 530 - 0
Firmware/Configuration_prusa.h

@@ -0,0 +1,530 @@
+#ifndef CONFIGURATION_PRUSA_H
+#define CONFIGURATION_PRUSA_H
+
+/*------------------------------------
+ GENERAL SETTINGS
+ *------------------------------------*/
+
+// Printer revision
+#define FILAMENT_SIZE "1_75mm_MK3"
+#define NOZZLE_TYPE "E3Dv6full"
+
+// Developer flag
+#define DEVELOPER
+
+// Printer name
+#define CUSTOM_MENDEL_NAME "Prusa i3 MK3"
+
+// Electronics
+#define MOTHERBOARD BOARD_EINSY_0_4a
+
+
+// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier)
+//#define E3D_PT100_EXTRUDER_WITH_AMP
+//#define E3D_PT100_EXTRUDER_NO_AMP
+//#define E3D_PT100_BED_WITH_AMP
+//#define E3D_PT100_BED_NO_AMP
+
+
+/*------------------------------------
+ AXIS SETTINGS
+ *------------------------------------*/
+
+// Steps per unit {X,Y,Z,E}
+//#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,140}
+//#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,280}
+#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,560}
+
+// Endstop inverting
+const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+
+// Home position
+#define MANUAL_X_HOME_POS 0
+#define MANUAL_Y_HOME_POS -2.2
+#define MANUAL_Z_HOME_POS 0.2
+
+// Travel limits after homing
+#define X_MAX_POS 255
+#define X_MIN_POS 0
+#define Y_MAX_POS 210
+#define Y_MIN_POS -4 //orig -4
+#define Z_MAX_POS 210
+#define Z_MIN_POS 0.15
+
+// Canceled home position
+#define X_CANCEL_POS 50
+#define Y_CANCEL_POS 190
+
+//Pause print position
+#define X_PAUSE_POS 50
+#define Y_PAUSE_POS 190
+#define Z_PAUSE_LIFT 20
+
+#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E
+#define HOMING_FEEDRATE {2500, 3000, 800, 0}  // set the homing speeds (mm/min) // 3000 is also valid for stallGuard homing. Valid range: 2200 - 3000
+
+//#define DEFAULT_MAX_FEEDRATE          {400, 400, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_FEEDRATE          {500, 500, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_ACCELERATION      {1000, 1000, 200, 5000}    // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot.
+
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts
+
+#define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
+//#define MAX_SILENT_FEEDRATE           2700   // 
+
+#define Z_AXIS_ALWAYS_ON 1
+
+// Automatic recovery after crash is detected
+#define AUTOMATIC_RECOVERY_AFTER_CRASH
+
+//DEBUG
+//#define _NO_ASM
+#define DEBUG_DCODES //D codes
+#if 1
+//#define DEBUG_FSENSOR_LOG          //Reports fsensor status to serial
+//#define DEBUG_CRASHDET_COUNTERS  //Display crash-detection counters on LCD
+//#define DEBUG_RESUME_PRINT       //Resume/save print debug enable 
+//#define DEBUG_UVLO_AUTOMATIC_RECOVER // Power panic automatic recovery debug output 
+//#define DEBUG_DISABLE_XMINLIMIT  //x min limit ignored
+//#define DEBUG_DISABLE_XMAXLIMIT  //x max limit ignored
+//#define DEBUG_DISABLE_YMINLIMIT  //y min limit ignored
+//#define DEBUG_DISABLE_YMAXLIMIT  //y max limit ignored
+//#define DEBUG_DISABLE_ZMINLIMIT  //z min limit ignored
+//#define DEBUG_DISABLE_ZMAXLIMIT  //z max limit ignored
+//#define DEBUG_DISABLE_STARTMSGS //no startup messages 
+//#define DEBUG_DISABLE_MINTEMP   //mintemp error ignored
+//#define DEBUG_DISABLE_SWLIMITS  //sw limits ignored
+//#define DEBUG_DISABLE_LCD_STATUS_LINE  //empty four lcd line
+//#define DEBUG_DISABLE_PREVENT_EXTRUDER //cold extrusion and long extrusion allowed
+//#define DEBUG_DISABLE_PRUSA_STATISTICS //disable prusa_statistics() mesages
+//#define DEBUG_XSTEP_DUP_PIN 21   //duplicate x-step output to pin 21 (SCL on P3)
+//#define DEBUG_YSTEP_DUP_PIN 21   //duplicate y-step output to pin 21 (SCL on P3)
+//#define DEBUG_BLINK_ACTIVE
+#endif
+
+
+/*------------------------------------
+ TMC2130 default settings
+ *------------------------------------*/
+
+#define TMC2130_FCLK 12000000       // fclk = 12MHz
+
+#define TMC2130_USTEPS_XY   16        // microstep resolution for XY axes
+#define TMC2130_USTEPS_Z    16        // microstep resolution for Z axis
+#define TMC2130_USTEPS_E    64        // microstep resolution for E axis
+#define TMC2130_INTPOL_XY   1         // extrapolate 256 for XY axes
+#define TMC2130_INTPOL_Z    1         // extrapolate 256 for Z axis
+#define TMC2130_INTPOL_E    1         // extrapolate 256 for E axis
+
+#define TMC2130_PWM_GRAD_X  2         // PWMCONF
+#define TMC2130_PWM_AMPL_X  230       // PWMCONF
+#define TMC2130_PWM_AUTO_X  1         // PWMCONF
+#define TMC2130_PWM_FREQ_X  2         // PWMCONF
+
+#define TMC2130_PWM_GRAD_Y  2         // PWMCONF
+#define TMC2130_PWM_AMPL_Y  235       // PWMCONF
+#define TMC2130_PWM_AUTO_Y  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Y  2         // PWMCONF
+
+/* //not used
+#define TMC2130_PWM_GRAD_Z  4         // PWMCONF
+#define TMC2130_PWM_AMPL_Z  200       // PWMCONF
+#define TMC2130_PWM_AUTO_Z  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Z  2         // PWMCONF
+#define TMC2130_PWM_GRAD_E  4         // PWMCONF
+#define TMC2130_PWM_AMPL_E  200       // PWMCONF
+#define TMC2130_PWM_AUTO_E  1         // PWMCONF
+#define TMC2130_PWM_FREQ_E  2         // PWMCONF
+*/
+
+//#define TMC2130_PWM_DIV   683         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_DIV   512         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_CLK   (2 * TMC2130_FCLK / TMC2130_PWM_DIV) // PWM frequency (23.4kHz, 35.1kHz, 46.9kHz, 58.5kHz for 12MHz fclk)
+
+#define TMC2130_TPWMTHRS  0         // TPWMTHRS - Sets the switching speed threshold based on TSTEP from stealthChop to spreadCycle mode
+#define TMC2130_THIGH     0         // THIGH - unused
+
+//#define TMC2130_TCOOLTHRS_X 450       // TCOOLTHRS - coolstep treshold
+//#define TMC2130_TCOOLTHRS_Y 450       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_X 430       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_Y 430       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_Z 500       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_E 500       // TCOOLTHRS - coolstep treshold
+
+#define TMC2130_SG_HOMING       1     // stallguard homing
+//#define TMC2130_SG_HOMING_SW_XY  1    // stallguard "software" homing for XY axes
+#define TMC2130_SG_HOMING_SW_Z  1     // stallguard "software" homing for Z axis
+#define TMC2130_SG_THRS_X       3     // stallguard sensitivity for X axis
+#define TMC2130_SG_THRS_Y       4     // stallguard sensitivity for Y axis
+#define TMC2130_SG_THRS_Z       3     // stallguard sensitivity for Z axis
+#define TMC2130_SG_THRS_E       3     // stallguard sensitivity for E axis
+#define TMC2130_SG_DELTA      128    // stallguard delta [usteps] (minimum usteps before stallguard readed - SW homing)
+
+//new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only)
+#define TMC2130_CURRENTS_H {13, 20, 20, 35}  // default holding currents for all axes
+#define TMC2130_CURRENTS_R {13, 20, 20, 35}  // default running currents for all axes
+
+//#define TMC2130_DEBUG
+//#define TMC2130_DEBUG_WR
+//#define TMC2130_DEBUG_RD
+
+
+/*------------------------------------
+ EXTRUDER SETTINGS
+ *------------------------------------*/
+
+// Mintemps
+#define HEATER_0_MINTEMP 15
+#define HEATER_1_MINTEMP 5
+#define HEATER_2_MINTEMP 5
+#define BED_MINTEMP 15
+
+// Maxtemps
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define HEATER_0_MAXTEMP 410
+#else
+#define HEATER_0_MAXTEMP 305
+#endif
+#define HEATER_1_MAXTEMP 305
+#define HEATER_2_MAXTEMP 305
+#define BED_MAXTEMP 150
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_Kp 21.70
+#define  DEFAULT_Ki 1.60
+#define  DEFAULT_Kd 73.76
+#else
+// Define PID constants for extruder
+//#define  DEFAULT_Kp 40.925
+//#define  DEFAULT_Ki 4.875
+//#define  DEFAULT_Kd 86.085
+#define  DEFAULT_Kp 16.13
+#define  DEFAULT_Ki 1.1625
+#define  DEFAULT_Kd 56.23
+#endif
+
+// Extrude mintemp
+#define EXTRUDE_MINTEMP 130
+
+// Extruder cooling fans
+#define EXTRUDER_0_AUTO_FAN_PIN   8
+#define EXTRUDER_1_AUTO_FAN_PIN   -1
+#define EXTRUDER_2_AUTO_FAN_PIN   -1
+#define EXTRUDER_AUTO_FAN_TEMPERATURE 50
+#define EXTRUDER_AUTO_FAN_SPEED   255  // == full speed
+
+
+
+/*------------------------------------
+ LOAD/UNLOAD FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Load filament commands
+#define LOAD_FILAMENT_0 "M83"
+#define LOAD_FILAMENT_1 "G1 E70 F400"
+#define LOAD_FILAMENT_2 "G1 E40 F100"
+
+// Unload filament commands
+#define UNLOAD_FILAMENT_0 "M83"
+#define UNLOAD_FILAMENT_1 "G1 E-80 F7000"
+
+/*------------------------------------
+ CHANGE FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Filament change configuration
+#define FILAMENTCHANGEENABLE
+#ifdef FILAMENTCHANGEENABLE
+#define FILAMENTCHANGE_XPOS 211
+#define FILAMENTCHANGE_YPOS 0
+#define FILAMENTCHANGE_ZADD 2
+#define FILAMENTCHANGE_FIRSTRETRACT -2
+#define FILAMENTCHANGE_FINALRETRACT -80
+
+#define FILAMENTCHANGE_FIRSTFEED 70
+#define FILAMENTCHANGE_FINALFEED 50
+#define FILAMENTCHANGE_RECFEED 5
+
+#define FILAMENTCHANGE_XYFEED 50
+#define FILAMENTCHANGE_EFEED 20
+//#define FILAMENTCHANGE_RFEED 400
+#define FILAMENTCHANGE_RFEED 7000 / 60
+#define FILAMENTCHANGE_EXFEED 2
+#define FILAMENTCHANGE_ZFEED 15
+
+#endif
+
+/*------------------------------------
+ ADDITIONAL FEATURES SETTINGS
+ *------------------------------------*/
+
+// Define Prusa filament runout sensor
+//#define FILAMENT_RUNOUT_SUPPORT
+
+#ifdef FILAMENT_RUNOUT_SUPPORT
+#define FILAMENT_RUNOUT_SENSOR 1
+#endif
+
+// temperature runaway
+//#define TEMP_RUNAWAY_BED_HYSTERESIS 5
+//#define TEMP_RUNAWAY_BED_TIMEOUT 360
+
+#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15
+#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45
+
+/*------------------------------------
+ MOTOR CURRENT SETTINGS
+ *------------------------------------*/
+
+// Motor Current setting for BIG RAMBo
+#define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A)
+#define DIGIPOT_MOTOR_CURRENT_LOUD {135,135,135,135,135}
+
+// Motor Current settings for RAMBo mini PWM value = MotorCurrentSetting * 255 / range
+#if MOTHERBOARD == 200 || MOTHERBOARD == 203 || MOTHERBOARD == 303 || MOTHERBOARD == 304 || MOTHERBOARD == 305
+#define MOTOR_CURRENT_PWM_RANGE 2000
+#define DEFAULT_PWM_MOTOR_CURRENT  {400, 750, 750} // {XY,Z,E}
+#define DEFAULT_PWM_MOTOR_CURRENT_LOUD  {400, 750, 750} // {XY,Z,E}
+#endif
+
+/*------------------------------------
+ PAT9125 SETTINGS
+ *------------------------------------*/
+
+#define PAT9125_XRES			200
+#define PAT9125_YRES			200
+
+/*------------------------------------
+ BED SETTINGS
+ *------------------------------------*/
+
+// Define Mesh Bed Leveling system to enable it
+#define MESH_BED_LEVELING
+#ifdef MESH_BED_LEVELING
+
+#define MBL_Z_STEP 0.01
+
+// Mesh definitions
+#define MESH_MIN_X 35
+#define MESH_MAX_X 238
+#define MESH_MIN_Y 6
+#define MESH_MAX_Y 202
+
+// Mesh upsample definition
+#define MESH_NUM_X_POINTS 7
+#define MESH_NUM_Y_POINTS 7
+// Mesh measure definition
+#define MESH_MEAS_NUM_X_POINTS 3
+#define MESH_MEAS_NUM_Y_POINTS 3
+
+#define MESH_HOME_Z_CALIB 0.2
+#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc.
+
+#define X_PROBE_OFFSET_FROM_EXTRUDER 23     // Z probe to nozzle X offset: -left  +right
+#define Y_PROBE_OFFSET_FROM_EXTRUDER 5     // Z probe to nozzle Y offset: -front +behind
+#define Z_PROBE_OFFSET_FROM_EXTRUDER -0.4  // Z probe to nozzle Z offset: -below (always!)
+#endif
+
+// Bed Temperature Control
+// Select PID or bang-bang with PIDTEMPBED. If bang-bang, BED_LIMIT_SWITCHING will enable hysteresis
+//
+// Uncomment this to enable PID on the bed. It uses the same frequency PWM as the extruder.
+// If your PID_dT above is the default, and correct for your hardware/configuration, that means 7.689Hz,
+// which is fine for driving a square wave into a resistive load and does not significantly impact you FET heating.
+// This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W heater.
+// If your configuration is significantly different than this and you don't understand the issues involved, you probably
+// shouldn't use bed PID until someone else verifies your hardware works.
+// If this is enabled, find your own PID constants below.
+#define PIDTEMPBED
+//
+//#define BED_LIMIT_SWITCHING
+
+// This sets the max power delivered to the bed, and replaces the HEATER_BED_DUTY_CYCLE_DIVIDER option.
+// all forms of bed control obey this (PID, bang-bang, bang-bang with hysteresis)
+// setting this to anything other than 255 enables a form of PWM to the bed just like HEATER_BED_DUTY_CYCLE_DIVIDER did,
+// so you shouldn't use it unless you are OK with PWM on your bed.  (see the comment on enabling PIDTEMPBED)
+#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current
+
+// Bed temperature compensation settings
+#define BED_OFFSET 10
+#define BED_OFFSET_START 40
+#define BED_OFFSET_CENTER 50
+
+
+#ifdef PIDTEMPBED
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10)
+#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_bedKp 21.70
+#define  DEFAULT_bedKi 1.60
+#define  DEFAULT_bedKd 73.76
+#else
+#define  DEFAULT_bedKp 126.13
+#define  DEFAULT_bedKi 4.30
+#define  DEFAULT_bedKd 924.76
+#endif
+
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from pidautotune
+//    #define  DEFAULT_bedKp 97.1
+//    #define  DEFAULT_bedKi 1.41
+//    #define  DEFAULT_bedKd 1675.16
+
+// FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles.
+#endif // PIDTEMPBED
+
+
+/*-----------------------------------
+ PREHEAT SETTINGS
+ *------------------------------------*/
+
+#define FARM_PREHEAT_HOTEND_TEMP 250
+#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_FAN_SPEED 0
+
+#define PLA_PREHEAT_HOTEND_TEMP 215
+#define PLA_PREHEAT_HPB_TEMP 60
+#define PLA_PREHEAT_FAN_SPEED 0
+
+#define ABS_PREHEAT_HOTEND_TEMP 255
+#define ABS_PREHEAT_HPB_TEMP 100
+#define ABS_PREHEAT_FAN_SPEED 0
+
+#define HIPS_PREHEAT_HOTEND_TEMP 220
+#define HIPS_PREHEAT_HPB_TEMP 100
+#define HIPS_PREHEAT_FAN_SPEED 0
+
+#define PP_PREHEAT_HOTEND_TEMP 254
+#define PP_PREHEAT_HPB_TEMP 100
+#define PP_PREHEAT_FAN_SPEED 0
+
+#define PET_PREHEAT_HOTEND_TEMP 240
+#define PET_PREHEAT_HPB_TEMP 90
+#define PET_PREHEAT_FAN_SPEED 0
+
+#define FLEX_PREHEAT_HOTEND_TEMP 230
+#define FLEX_PREHEAT_HPB_TEMP 50
+#define FLEX_PREHEAT_FAN_SPEED 0
+
+/*------------------------------------
+ THERMISTORS SETTINGS
+ *------------------------------------*/
+
+//
+//--NORMAL IS 4.7kohm PULLUP!-- 1kohm pullup can be used on hotend sensor, using correct resistor and table
+//
+//// Temperature sensor settings:
+// -2 is thermocouple with MAX6675 (only for sensor 0)
+// -1 is thermocouple with AD595
+// 0 is not used
+// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
+// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
+// 3 is Mendel-parts thermistor (4.7k pullup)
+// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
+// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup)
+// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
+// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
+// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup)
+// 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup)
+// 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
+// 10 is 100k RS thermistor 198-961 (4.7k pullup)
+// 11 is 100k beta 3950 1% thermistor (4.7k pullup)
+// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed)
+// 13 is 100k Hisens 3950  1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE"
+// 20 is the PT100 circuit found in the Ultimainboard V2.x
+// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950
+//
+//    1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
+//                          (but gives greater accuracy and more stable PID)
+// 51 is 100k thermistor - EPCOS (1k pullup)
+// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
+// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup)
+//
+// 1047 is Pt1000 with 4k7 pullup
+// 1010 is Pt1000 with 1k pullup (non standard)
+// 147 is Pt100 with 4k7 pullup
+// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a
+// 247 is Pt100 with 4k7 pullup and PT100 Amplifier
+// 110 is Pt100 with 1k pullup (non standard)
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP)
+#define TEMP_SENSOR_0 247
+#elif defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define TEMP_SENSOR_0 148
+#else
+#define TEMP_SENSOR_0 5
+#endif
+#define TEMP_SENSOR_1 0
+#define TEMP_SENSOR_2 0
+#if defined(E3D_PT100_BED_WITH_AMP)
+#define TEMP_SENSOR_BED 247
+#elif defined(E3D_PT100_BED_NO_AMP)
+#define TEMP_SENSOR_BED 148
+#else
+#define TEMP_SENSOR_BED 1
+#endif
+#define TEMP_SENSOR_PINDA 1
+#define TEMP_SENSOR_AMBIENT 2000
+
+#define STACK_GUARD_TEST_VALUE 0xA2A2
+
+#define MAX_BED_TEMP_CALIBRATION 50
+#define MAX_HOTEND_TEMP_CALIBRATION 50
+
+#define MAX_E_STEPS_PER_UNIT 250
+#define MIN_E_STEPS_PER_UNIT 100
+
+#define Z_BABYSTEP_MIN -3999
+#define Z_BABYSTEP_MAX 0
+
+#define PINDA_PREHEAT_X 20
+#define PINDA_PREHEAT_Y 60
+#define PINDA_PREHEAT_Z 0.15
+/*
+#define PINDA_PREHEAT_X 70
+#define PINDA_PREHEAT_Y -3
+#define PINDA_PREHEAT_Z 1*/
+#define PINDA_HEAT_T 120 //time in s
+
+#define PINDA_MIN_T 50
+#define PINDA_STEP_T 10
+#define PINDA_MAX_T 100
+
+#define PING_TIME 60 //time in s
+#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes
+#define PING_ALLERT_PERIOD 60 //time in s
+
+#define LONG_PRESS_TIME 1000 //time in ms for button long press
+#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release
+
+#define DEFAULT_PID_TEMP 210
+
+#define MIN_PRINT_FAN_SPEED 75
+
+#ifdef SNMM
+#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print
+#else
+#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print
+#endif
+
+// How much shall the print head be lifted on power panic?
+// Ideally the Z axis will reach a zero phase of the stepper driver on power outage. To simplify this,
+// UVLO_Z_AXIS_SHIFT shall be an integer multiply of the stepper driver cycle, that is 4x full step.
+// For example, the Prusa i3 MK2 with 16 microsteps per full step has Z stepping of 400 microsteps per mm.
+// At 400 microsteps per mm, a full step lifts the Z axis by 0.04mm, and a stepper driver cycle is 0.16mm.
+// The following example, 12 * (4 * 16 / 400) = 12 * 0.16mm = 1.92mm.
+//#define UVLO_Z_AXIS_SHIFT 1.92
+#define UVLO_Z_AXIS_SHIFT 0.64
+// If power panic occured, and the current temperature is higher then target temperature before interrupt minus this offset, print will be recovered automatically. 
+#define AUTOMATIC_UVLO_BED_TEMP_OFFSET 5 
+
+#define HEATBED_V2
+
+//#define SUPPORT_VERBOSITY
+
+#endif //__CONFIGURATION_PRUSA_H

+ 462 - 0
Firmware/Dcodes.cpp

@@ -0,0 +1,462 @@
+#include "Dcodes.h"
+#include "Marlin.h"
+
+#ifdef DEBUG_DCODES
+
+#include "ConfigurationStore.h"
+#include "cmdqueue.h"
+#include "pat9125.h"
+#include <avr/wdt.h>
+
+
+#define FLASHSIZE     0x40000
+
+#define RAMSIZE        0x2000
+#define boot_src_addr  (*((uint32_t*)(RAMSIZE - 16)))
+#define boot_dst_addr  (*((uint32_t*)(RAMSIZE - 12)))
+#define boot_copy_size (*((uint16_t*)(RAMSIZE - 8)))
+#define boot_reserved  (*((uint8_t*)(RAMSIZE - 6)))
+#define boot_app_flags (*((uint8_t*)(RAMSIZE - 5)))
+#define boot_app_magic (*((uint32_t*)(RAMSIZE - 4)))
+#define BOOT_APP_FLG_ERASE 0x01
+#define BOOT_APP_FLG_COPY  0x02
+#define BOOT_APP_FLG_FLASH 0x04
+
+extern uint8_t fsensor_log;
+extern float current_temperature_pinda;
+extern float axis_steps_per_unit[NUM_AXIS];
+
+
+inline void print_hex_nibble(uint8_t val)
+{
+	putchar((val > 9)?(val - 10 + 'a'):(val + '0'));
+}
+
+void print_hex_byte(uint8_t val)
+{
+	print_hex_nibble(val >> 4);
+	print_hex_nibble(val & 15);
+}
+
+void print_hex_word(uint16_t val)
+{
+	print_hex_byte(val >> 8);
+	print_hex_byte(val & 255);
+}
+
+void print_mem(uint32_t address, uint16_t count, uint8_t type, uint8_t countperline = 16)
+{
+	while (count)
+	{
+		if (type == 2)
+			print_hex_nibble(address >> 16);
+		print_hex_word(address);
+		putchar(' ');
+		uint8_t count_line = countperline;
+		while (count && count_line)
+		{
+			uint8_t data = 0;
+			switch (type)
+			{
+			case 0: data = *((uint8_t*)address++); break;
+			case 1: data = eeprom_read_byte((uint8_t*)address++); break;
+			case 2: data = pgm_read_byte_far((uint8_t*)address++); break;
+			}
+			putchar(' ');
+			print_hex_byte(data);
+			count_line--;
+			count--;
+		}
+		putchar('\n');
+	}
+}
+
+//#define LOG(args...) printf(args)
+#define LOG(args...)
+
+int parse_hex(char* hex, uint8_t* data, int count)
+{
+	int parsed = 0;
+	while (*hex)
+	{
+		if (count && (parsed >= count)) break;
+		char c = *(hex++);
+		if (c == ' ') continue;
+		if (c == '\n') break;
+		uint8_t val = 0x00;
+		if ((c >= '0') && (c <= '9')) val |= ((c - '0') << 4);
+		else if ((c >= 'a') && (c <= 'f')) val |= ((c - 'a' + 10) << 4);
+		else return -parsed;
+		c = *(hex++);
+		if ((c >= '0') && (c <= '9')) val |= (c - '0');
+		else if ((c >= 'a') && (c <= 'f')) val |= (c - 'a' + 10);
+		else return -parsed;
+		data[parsed] = val;
+		parsed++;
+	}
+	return parsed;
+}
+
+void dcode__1()
+{
+	printf("D-1 - Endless loop\n");
+	cli();
+	while (1);
+}
+
+void dcode_0()
+{
+	if (*(strchr_pointer + 1) == 0) return;
+	LOG("D0 - Reset\n");
+	if (code_seen('B')) //bootloader
+	{
+		cli();
+		wdt_enable(WDTO_15MS);
+		while(1);
+	}
+	else //reset
+	{
+#ifndef _NO_ASM
+		asm volatile("jmp 0x00000");
+#endif //_NO_ASM
+	}
+}
+
+void dcode_1()
+{
+	LOG("D1 - Clear EEPROM and RESET\n");
+	cli();
+	for (int i = 0; i < 8192; i++)
+		eeprom_write_byte((unsigned char*)i, (unsigned char)0xff);
+	wdt_enable(WDTO_15MS);
+	while(1);
+}
+
+void dcode_2()
+{
+	LOG("D2 - Read/Write RAM\n");
+	uint16_t address = 0x0000; //default 0x0000
+	uint16_t count = 0x2000; //default 0x2000 (entire ram)
+	if (code_seen('A')) // Address (0x0000-0x1fff)
+		address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value();
+	if (code_seen('C')) // Count (0x0001-0x2000)
+		count = (int)code_value();
+	address &= 0x1fff;
+	if (count > 0x2000) count = 0x2000;
+	if ((address + count) > 0x2000) count = 0x2000 - address;
+	if (code_seen('X')) // Data
+	{
+		uint8_t data[16];
+		count = parse_hex(strchr_pointer + 1, data, 16);
+		if (count > 0)
+		{
+			for (int i = 0; i < count; i++)
+				*((uint8_t*)(address + i)) =  data[i];
+			LOG("%d bytes written to RAM at address %04x", count, address);
+		}
+		else
+			count = 0;
+	}
+	print_mem(address, count, 0);
+/*	while (count)
+	{
+		print_hex_word(address);
+		putchar(' ');
+		uint8_t countperline = 16;
+		while (count && countperline)
+		{
+			uint8_t data = *((uint8_t*)address++);
+			putchar(' ');
+			print_hex_byte(data);
+			countperline--;
+			count--;
+		}
+		putchar('\n');
+	}*/
+}
+
+void dcode_3()
+{
+	LOG("D3 - Read/Write EEPROM\n");
+	uint16_t address = 0x0000; //default 0x0000
+	uint16_t count = 0x2000; //default 0x2000 (entire eeprom)
+	if (code_seen('A')) // Address (0x0000-0x1fff)
+		address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value();
+	if (code_seen('C')) // Count (0x0001-0x2000)
+		count = (int)code_value();
+	address &= 0x1fff;
+	if (count > 0x2000) count = 0x2000;
+	if ((address + count) > 0x2000) count = 0x2000 - address;
+	if (code_seen('X')) // Data
+	{
+		uint8_t data[16];
+		count = parse_hex(strchr_pointer + 1, data, 16);
+		if (count > 0)
+		{
+			for (int i = 0; i < count; i++)
+				eeprom_write_byte((uint8_t*)(address + i), data[i]);
+			LOG(count, DEC);
+			LOG(" bytes written to EEPROM at address ");
+			print_hex_word(address);
+			putchar('\n');
+		}
+		else
+			count = 0;
+	}
+	print_mem(address, count, 1);
+/*	while (count)
+	{
+		print_hex_word(address);
+		putchar(' ');
+		uint8_t countperline = 16;
+		while (count && countperline)
+		{
+			uint8_t data = eeprom_read_byte((uint8_t*)address++);
+			putchar(' ');
+			print_hex_byte(data);
+			countperline--;
+			count--;
+		}
+		putchar('\n');
+	}*/
+}
+
+void dcode_4()
+{
+	LOG("D4 - Read/Write PIN\n");
+	if (code_seen('P')) // Pin (0-255)
+	{
+		int pin = (int)code_value();
+		if ((pin >= 0) && (pin <= 255))
+		{
+			if (code_seen('F')) // Function in/out (0/1)
+			{
+				int fnc = (int)code_value();
+				if (fnc == 0) pinMode(pin, INPUT);
+				else if (fnc == 1) pinMode(pin, OUTPUT);
+			}
+			if (code_seen('V')) // Value (0/1)
+			{
+				int val = (int)code_value();
+				if (val == 0) digitalWrite(pin, LOW);
+				else if (val == 1) digitalWrite(pin, HIGH);
+			}
+			else
+			{
+				int val = (digitalRead(pin) != LOW)?1:0;
+				printf("PIN%d=%d", pin, val);
+			}
+		}
+	}
+}
+/*
+void dcode_5()
+{
+	LOG("D5 - Read/Write FLASH\n");
+	uint32_t address = 0x0000; //default 0x0000
+	uint16_t count = 0x0400; //default 0x0400 (1kb block)
+	if (code_seen('A')) // Address (0x00000-0x3ffff)
+		address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value();
+	if (code_seen('C')) // Count (0x0001-0x2000)
+		count = (int)code_value();
+	address &= 0x3ffff;
+	if (count > 0x2000) count = 0x2000;
+	if ((address + count) > 0x40000) count = 0x40000 - address;
+	bool bErase = false;
+	bool bCopy = false;
+	if (code_seen('E')) //Erase
+		bErase = true;
+	uint8_t data[16];
+	if (code_seen('X')) // Data
+	{
+		count = parse_hex(strchr_pointer + 1, data, 16);
+		if (count > 0) bCopy = true;
+	}
+	if (bErase || bCopy)
+	{
+		if (bErase)
+		{
+			LOG(count, DEC);
+			LOG(" bytes of FLASH at address ");
+			print_hex_word(address);
+			putchar(" will be erased\n");
+		}
+		if (bCopy)
+		{
+			LOG(count, DEC);
+			LOG(" bytes will be written to FLASH at address ");
+			print_hex_word(address);
+			putchar('\n');
+		}
+		cli();
+		boot_app_magic = 0x55aa55aa;
+		boot_app_flags = (bErase?(BOOT_APP_FLG_ERASE):0) | (bCopy?(BOOT_APP_FLG_COPY):0);
+		boot_copy_size = (uint16_t)count;
+		boot_dst_addr = (uint32_t)address;
+		boot_src_addr = (uint32_t)(&data);
+		wdt_enable(WDTO_15MS);
+		while(1);
+	}
+	while (count)
+	{
+		print_hex_nibble(address >> 16);
+		print_hex_word(address);
+		putchar(' ');
+		uint8_t countperline = 16;
+		while (count && countperline)
+		{
+			uint8_t data = pgm_read_byte_far((uint8_t*)address++);
+			putchar(' ');
+			print_hex_byte(data);
+			countperline--;
+			count--;
+		}
+		putchar('\n');
+	}
+}
+*/
+
+void dcode_6()
+{
+	LOG("D6 - Read/Write external FLASH\n");
+}
+
+void dcode_7()
+{
+	LOG("D7 - Read/Write Bootloader\n");
+/*
+	cli();
+	boot_app_magic = 0x55aa55aa;
+	boot_app_flags = BOOT_APP_FLG_ERASE | BOOT_APP_FLG_COPY | BOOT_APP_FLG_FLASH;
+	boot_copy_size = (uint16_t)0xc00;
+	boot_src_addr = (uint32_t)0x0003e400;
+	boot_dst_addr = (uint32_t)0x0003f400;
+	wdt_enable(WDTO_15MS);
+	while(1);
+*/
+}
+
+void dcode_8()
+{
+	printf_P(PSTR("D8 - Read/Write PINDA\n"));
+	uint8_t cal_status = calibration_status_pinda();
+	float temp_pinda = current_temperature_pinda;
+	float offset_z = temp_compensation_pinda_thermistor_offset(temp_pinda);
+	if ((strchr_pointer[1+1] == '?') || (strchr_pointer[1+1] == 0))
+	{
+		printf_P(PSTR("cal_status=%d\n"), cal_status?1:0);
+		for (uint8_t i = 0; i < 6; i++)
+		{
+			uint16_t offs = 0;
+			if (i > 0) offs = eeprom_read_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + (i - 1));
+			float foffs = ((float)offs) / axis_steps_per_unit[Z_AXIS];
+			offs = 1000 * foffs;
+			printf_P(PSTR("temp_pinda=%dC temp_shift=%dum\n"), 35 + i * 5, offs);
+		}
+	}
+	else if (strchr_pointer[1+1] == '!')
+	{
+		cal_status = 1;
+		eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, cal_status);
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 0,   8); //40C -  20um -   8usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 1,  24); //45C -  60um -  24usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 2,  48); //50C - 120um -  48usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 3,  80); //55C - 200um -  80usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 4, 120); //60C - 300um - 120usteps
+	}
+	else
+	{
+		if (code_seen('P')) // Pinda temperature [C]
+			temp_pinda = code_value();
+		offset_z = temp_compensation_pinda_thermistor_offset(temp_pinda);
+		if (code_seen('Z')) // Z Offset [mm]
+		{
+			offset_z = code_value();
+		}
+	}
+	printf_P(PSTR("temp_pinda=%d offset_z=%d.%03d\n"), (int)temp_pinda, (int)offset_z, ((int)(1000 * offset_z) % 1000));
+}
+
+void dcode_10()
+{//Tell the printer that XYZ calibration went OK
+	LOG("D10 - XYZ calibration = OK\n");
+	calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); 
+}
+
+void dcode_12()
+{//Reset Filament error, Power loss and crash counter ( Do it before every print and you can get stats for the print )
+	LOG("D12 - Reset failstat counters\n");
+    eeprom_update_byte((uint8_t*)EEPROM_CRASH_COUNT, 0x00);
+    eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, 0x00);
+    eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, 0x00);
+}
+
+#include "tmc2130.h"
+#include "Marlin.h"
+#include "planner.h"
+extern void st_synchronize();
+
+void dcode_2130()
+{
+//	printf("test");
+	printf_P(PSTR("D2130 - TMC2130\n"));
+	uint8_t axis = 0xff;
+	if (code_seen('X'))
+		axis = X_AXIS;
+	else if (code_seen('Y'))
+		axis = Y_AXIS;
+	if (axis != 0xff)
+	{
+		homeaxis(axis);
+		tmc2130_sg_meassure_start(axis);
+		memcpy(destination, current_position, sizeof(destination));
+        destination[axis] = 200;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], homing_feedrate[X_AXIS]/60, active_extruder);
+        st_synchronize();
+		memcpy(destination, current_position, sizeof(destination));
+        destination[axis] = 0;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], homing_feedrate[X_AXIS]/60, active_extruder);
+        st_synchronize();
+		uint16_t sg = tmc2130_sg_meassure_stop();
+		tmc2130_sg_meassure = 0xff;
+		printf_P(PSTR("Meassure avg = %d\n"), sg);
+	}
+}
+
+void dcode_9125()
+{
+	LOG("D9125 - PAT9125\n");
+	if ((strchr_pointer[1+4] == '?') || (strchr_pointer[1+4] == 0))
+	{
+		printf("res_x=%d res_y=%d x=%d y=%d b=%d s=%d\n", pat9125_xres, pat9125_yres, pat9125_x, pat9125_y, pat9125_b, pat9125_s);
+		return;
+	}
+	if (strchr_pointer[1+4] == '!')
+	{
+		pat9125_update();
+		printf("x=%d y=%d b=%d s=%d\n", pat9125_x, pat9125_y, pat9125_b, pat9125_s);
+		return;
+	}
+	if (code_seen('R'))
+	{
+		unsigned char res = (int)code_value();
+		LOG("pat9125_init(xres=yres=%d)=%d\n", res, pat9125_init(res, res));
+	}
+	if (code_seen('X'))
+	{
+		pat9125_x = (int)code_value();
+		LOG("pat9125_x=%d\n", pat9125_x);
+	}
+	if (code_seen('Y'))
+	{
+		pat9125_y = (int)code_value();
+		LOG("pat9125_y=%d\n", pat9125_y);
+	}
+	if (code_seen('L'))
+	{
+		fsensor_log = (int)code_value();
+		LOG("fsensor_log=%d\n", fsensor_log);
+	}
+}
+
+#endif //DEBUG_DCODES

+ 22 - 0
Firmware/Dcodes.h

@@ -0,0 +1,22 @@
+#ifndef DCODES_H
+#define DCODES_H
+
+extern void dcode__1(); //D-1 - Endless loop (to simulate deadlock)
+
+extern void dcode_0(); //D0 - Reset
+extern void dcode_1(); //D1 - Clear EEPROM
+extern void dcode_2(); //D2 - Read/Write RAM
+extern void dcode_3(); //D3 - Read/Write EEPROM
+extern void dcode_4(); //D4 - Read/Write PIN
+extern void dcode_5(); //D5 - Read/Write FLASH
+extern void dcode_6(); //D6 - Read/Write external FLASH
+extern void dcode_7(); //D7 - Read/Write Bootloader
+extern void dcode_8(); //D8 - Read/Write PINDA
+
+extern void dcode_10(); //D10 - XYZ calibration = OK
+extern void dcode_12(); //D12 - Reset failstat counters
+
+extern void dcode_2130(); //D2130 - TMC2130
+extern void dcode_9125(); //D9125 - PAT9125
+
+#endif //DCODES_H

+ 14889 - 0
Firmware/Firmware.ino.rambo.hex

@@ -0,0 +1,14889 @@
+:100000000C94762E0C94A72E0C94A72E0C94A72E4D
+:100010000C94A72E0C940A690C94A72E0C94A72E6E
+:100020000C948B680C94A72E0C94A72E0C94F5CAF4
+:100030000C94A72E0D947EBC0C94A72E0C94A72E86
+:100040000C94A72E0D94E01E0C94A72E0C94A72EB2
+:100050000C94A72E0C94A72E0D9448350D94A5B49E
+:100060000C94A72E0C9450400C94A72E0C94A72E01
+:100070000C94A72E0C94A72E0C94A72E0C94A72EAC
+:100080000C94A72E0C94A72E0C94A72E0C94A72E9C
+:100090000C94A72E0C94A72E0C94A72E0C94A72E8C
+:1000A0000C94A72E0C94A72E0C94A72E0C94A72E7C
+:1000B0000C94A72E0C94A72E0C94A72E0C94A72E6C
+:1000C0000C94A72E0C94A72E0C94A72E0C94904061
+:1000D0000C94A72E0C94A72E0C94A72E0C94A72E4C
+:1000E0000C94A72E533F573F5C3F643F793F923FAC
+:1000F000B73FE13F99019D016701BB01BF010B02C1
+:10010000C7017301B1018F01B501C901E10191017D
+:1001100089013701D701BD01E7013D014B016501AF
+:10012000CF014701590195016301450193014D013B
+:1001300043019B01FF0107029701A301DF016D014C
+:100140007D017D017D015B015B015B01E9018B01AB
+:100150005B01CD015501D101CB0105024F016101C8
+:10016000A701A50153010902FB01C5016901ED01C8
+:100170006101F1017901EB013B011102B7010F02AD
+:100180008501C3015101A901F9018301B901570199
+:100190006F017701C3011302F701D501084AD73B6C
+:1001A0003BCE016E84BCBFFDC12F3D6C74319ABD46
+:1001B00056833DDA3D00C77F11BED9E4BB4C3E916A
+:1001C0006BAAAABE000000803F05A84CCDB2D44E59
+:1001D000B93836A9020C50B9918688083CA6AAAA5B
+:1001E0002ABE000000803F07634236B79BD8A71A9B
+:1001F00039685618AEBAAB558C1D3CB7CC5763BDA9
+:100200006DEDFD753EF6177231BF000000803F08AE
+:10021000000000BE922449123EABAAAA2ABECDCC51
+:10022000CC4C3E00000080BEABAAAAAA3E00000053
+:1002300000BF000000803F0000000000084178D3AC
+:10024000BB4387D1133D190E3CC3BD4282AD2B3E4B
+:1002500068EC8276BED98FE1A93E4C80EFFFBE01EB
+:10026000C4FF7F3F0000000000000D94A36A0D94BE
+:100270003F6C0D9448530D949FB60D94AB6C0D9448
+:100280005A5D0D94D79C0D9450830D940B830D945F
+:10029000E96C0D9427990D94B06C0D9433830D94F3
+:1002A00004B60D94A6B60D941EB60D94E6B50D9445
+:1002B000BEB60D94C7820D94F0840D9471730D94A5
+:1002C00070B70D947DB60D94F6820D94BA6C0D94B2
+:1002D000F7350D944BB60D94C4680D94C2840D94FB
+:1002E000C2B60D94B2420D944B360D9439700D94F4
+:1002F000C6B60D9469B60D9430440D94CA840D941D
+:100300006EA50D940A580D94B4B60D949BB60D9439
+:10031000B54C0D94A9360D9400850D9480470D942D
+:1003200051360D9489360D941F830D94DF820D9400
+:1003300068840D94CD350D9418840D94DB350D949F
+:10034000CD680D944F490D9491840D9416B60D947B
+:100350000EB60D94AAB60D949E5B0D94BB680D94D9
+:1003600099AA0D944D360D940D530D9453360D945A
+:1003700091B60D94B8B60D9405360D946C6C0D9431
+:100380001F360D94CC6B0D94D9B60D943CB60D94DC
+:1003900047360D9461360D94F0B50D94DC840D94C0
+:1003A000D46C0D94EBB50D94DC450D94D4B60D943E
+:1003B000546C0D94C2210D94CF450D9438910D9439
+:1003C000BA840D947B360D94B2680D9446670D94F3
+:1003D000866C0D94D2840D9473B60D9455B60D941D
+:1003E0000C790D945FB60D9493580D9477690D9424
+:1003F000D0B60D94B0B60D9432B60D946B470D94F3
+:100400003A840D9443A20D94AB650D94FAB50D9406
+:100410004B840D9428B60D942D360D940F980D94A1
+:1004200095B60D94A2B60D94CCB60D947A4748615A
+:100430007264636F6465642044656661756C7420E2
+:1004400053657474696E6773204C6F6164656400F2
+:1004500053746F7265642073657474696E6773207A
+:1004600072657472696576656400202020452F44AA
+:10047000203D20002020204D393030204B004C6999
+:100480006E65617220616476616E63652073657468
+:1004900074696E67733A0046696C616D656E7420AD
+:1004A00073657474696E67733A2044697361626C32
+:1004B0006564002020204D32303020440046696CB5
+:1004C000616D656E742073657474696E67733A004C
+:1004D0002020204D3230392053004175746F2D5249
+:1004E0006574726163743A20533D3020746F2064E8
+:1004F000697361626C652C203120746F20696E74A1
+:1005000065727072657420657874727564652D6F9C
+:100510006E6C79206D6F76657320617320726574DF
+:100520007261637473206F72207265636F76657297
+:10053000696573002046002020204D32303820535A
+:10054000005265636F7665723A20533D4578747248
+:1005500061206C656E67746820286D6D2920463AAD
+:10056000537065656420286D6D2F6D2900205A0039
+:100570002046002020204D32303720530052657431
+:10058000726163743A20533D4C656E67746820282D
+:100590006D6D2920463A537065656420286D6D2F76
+:1005A0006D29205A3A205A4C69667420286D6D29AD
+:1005B000002044002049002020204D3330342050BA
+:1005C00000504944206865617462656420736574F5
+:1005D00074696E67733A002044002049002020208F
+:1005E0004D33303120500050494420736574746994
+:1005F0006E67733A00205A0020590020204D323097
+:1006000036205800486F6D65206F666673657420EC
+:10061000286D6D293A00204500205A0020590020FD
+:10062000580020420020540020204D323035205305
+:1006300000416476616E636564207661726961620F
+:100640006C65733A20533D4D696E20666565647232
+:1006500061746520286D6D2F73292C20543D4D69E0
+:100660006E2074726176656C206665656472617473
+:100670006520286D6D2F73292C20423D6D696E69B0
+:100680006D756D207365676D656E742074696D6539
+:1006900020286D73292C20583D6D6178696D756D2A
+:1006A000205859206A65726B20286D6D2F73292C94
+:1006B00020205A3D6D6178696D756D205A206A65FC
+:1006C000726B20286D6D2F73292C2020453D6D61A4
+:1006D00078696D756D2045206A65726B20286D6D97
+:1006E0002F73290020540020204D32303420530035
+:1006F000416363656C65726174696F6E3A20533D46
+:10070000616363656C65726174696F6E2C20543D22
+:100710007265747261637420616363656C65726194
+:1007200074696F6E00204500205A00205900202077
+:100730004D3230312058004D6178696D756D204122
+:100740006363656C65726174696F6E20286D6D2FCF
+:100750007332293A00204500205A002059002020F9
+:100760004D3230332058004D6178696D756D2066CB
+:10077000656564726174657320286D6D2F73293A05
+:1007800000204500205A0020590020204D393220F9
+:10079000580053746570732070657220756E6974AB
+:1007A0003A0053657474696E67732053746F726591
+:1007B0006400454550524F4D204572726F72004D96
+:1007C0006561737375726520617667203D202564CD
+:1007D0000A004432313330202D20544D433231331E
+:1007E000300A0074656D705F70696E64613D2564E8
+:1007F000206F66667365745F7A3D25642E253033FD
+:10080000640A0074656D705F70696E64613D256493
+:10081000432074656D705F73686966743D25647507
+:100820006D0A0063616C5F7374617475733D256458
+:100830000A004438202D20526561642F5772697474
+:10084000652050494E44410A000020006D657368E0
+:1008500020626564206C6576656C696E673A20007D
+:1008600029002C20002C2000706879736963616C6A
+:1008700020636F6F7264696E617465733A2028003B
+:1008800029002C20002C2000776F726C6420636F8D
+:100890006F7264696E617465733A202800204600A7
+:1008A0002045004731205A004D3234004D32362069
+:1008B00053256C75004D31303620530047312046AA
+:1008C0002564004731204531204634383000473117
+:1008D000205A002046323030300020590047312065
+:1008E00058004D383300506F736974696F6E207211
+:1008F0006561642066726F6D20656570726F6D3A18
+:10090000004D3233202573002E67636F0046656506
+:1009100064726174653A007265636F7665725F6DCB
+:10092000616368696E655F73746174655F61667445
+:1009300065725F706F7765725F70616E69632C209E
+:10094000696E697469616C20007265636F766572A7
+:100950005F6D616368696E655F73746174655F6123
+:10096000667465725F706F7765725F70616E6963E0
+:100970002C20696E697469616C20007265636F7602
+:1009800065725F6D616368696E655F7374617465DC
+:100990005F61667465725F706F7765725F70616EBC
+:1009A00069632C20696E697469616C2000637572DB
+:1009B00072656E745F706F736974696F6E5B455FAB
+:1009C000415849535D3A0063757272656E745F7089
+:1009D0006F736974696F6E5B5A5F415849535D3A32
+:1009E0000043757272656E7420706F736974696FFD
+:1009F0006E20595F415849533A0043757272656ED3
+:100A00007420706F736974696F6E20585F41584924
+:100A1000533A0041667465722077616974696E6744
+:100A200020666F722074656D703A00473932204538
+:100A3000004D383200473120452D312046343830C2
+:100A40000047312045352046313230004D383300E3
+:100A50004D31393020532564004D31303920532534
+:100A6000640047323820582059004731205A323527
+:100A70002046383030004D31343020532564004D4D
+:100A80003130342053256400494E54340055564CBF
+:100A90004F202D20656E6400737470730055564CA2
+:100AA0004F0020423A0020453A00543A005A206C48
+:100AB0006976652061646A757374206F7574206F40
+:100AC000662072616E67652E2053657474696E6767
+:100AD00020746F20302E20436C69636B20746F206C
+:100AE000636F6E74696E75652E005A206C69766549
+:100AF0002061646A757374206F7574206F6620724C
+:100B0000616E67652E2053657474696E6720746F1B
+:100B100020300020573A0020453A00543A004B4913
+:100B20004C4C3A20004175746F0020452F443D0025
+:100B3000416476616E6365204B3D002228322900B6
+:100B40005400496E76616C6964205420636F64655B
+:100B50002E00496E76616C6964204D20636F646578
+:100B60002E004D3232302053256900203A200000FB
+:100B70004C414E472053454C20464F52434544007C
+:100B8000222831290020453A00205A3A0020593ABB
+:100B90000020453A00205A3A0020593A00583A00BD
+:100BA0004D31313320530020002E0020423A0020E6
+:100BB000453A00543A0020413A0020503A00204281
+:100BC000403A0020403A00202F003A0020540020F4
+:100BD0002F0020423A00202F006F6B20543A00254E
+:100BE00069206D696E2C2025692073656300496E4C
+:100BF00076616C6964204D20636F6465004D657398
+:100C00006820626564206C6576656C696E67206E2D
+:100C10006F74206163746976652E000A00202000DD
+:100C20000A4D6561737572656420706F696E7473C7
+:100C30003A000A5A207365617263682068656967C3
+:100C400068743A20002C004E756D20582C593A20BB
+:100C500000476F20686F6D652066696E697368650F
+:100C600064004D65736820626564206C6576656C10
+:100C7000696E67206163746976617465640055709C
+:100C800073616D706C652066696E69736865640078
+:100C9000426564206C6576656C696E6720636F726F
+:100CA00072656374696F6E2066696E6973686564E6
+:100CB00000206D6963726F6E7300457863657373AE
+:100CC00069766520626564206C6576656C696E671F
+:100CD00020636F7272656374696F6E3A200062619F
+:100CE000627973746570206170706C69656400630B
+:100CF0006C65616E2075702066696E6973686564E5
+:100D0000200000206F66667365743A20006D65737D
+:100D10006820626564206C6576656C696E673A2050
+:100D200000473238205730003A200054656D706516
+:100D30007261747572652063616C69627261746955
+:100D40006F6E20646F6E652E20436F6E74696E75D2
+:100D5000652077697468207072657373696E6720A7
+:100D6000746865206B6E6F622E0000205A207368D5
+:100D700069667420286D6D293A0050494E4441201F
+:100D800074656D70657261747572653A2000002F2C
+:100D90003600537465703A200000205A2073686949
+:100DA000667420286D6D293A0050494E44412074E4
+:100DB000656D70657261747572653A20002F36201A
+:100DC00028736B69707065642900537465703A20EC
+:100DD00000005A45524F3A2000007374617274202B
+:100DE00074656D70657261747572653A2000504962
+:100DF0004E44412070726F62652063616C6962725B
+:100E00006174696F6E2073746172740047323820A8
+:100E10005730000A00205A3A200020593A2000207A
+:100E2000583A20004732382C2066696E616C2000E9
+:100E30004732382C2066696E616C20004732382CAE
+:100E40002066696E616C20004732382C20696E691B
+:100E50007469616C20004732382C20696E697469AE
+:100E6000616C200043524153485F4445544543540C
+:100E70004544004D323900627573793A20706175CE
+:100E800073656420666F7220696E70757400627598
+:100E900073793A2070617573656420666F7220758E
+:100EA00073657200627573793A2070726F6365734F
+:100EB00073696E67002055706C6F616420696E20E5
+:100EC00070726F677265737300696E697469616CC3
+:100ED000207A737465707320616674657220726520
+:100EE0007365743A2000696E697469616C207A7365
+:100EF00074657073206F6E20706F776572207570E7
+:100F00003A2000466163746F72792052455345540C
+:100F10000044495341424C45440A00454E41424C2D
+:100F200045440A004653656E736F72200050415469
+:100F3000393132355F696E69743A25640A004E6F43
+:100F400076203239203230313700436F6D70696C52
+:100F500065643A2000286E6F6E652C2064656661BA
+:100F6000756C7420636F6E66696729004E6F76201A
+:100F7000323920323031372030323A30313A303065
+:100F8000007374617274001B5B324A1B5B313B312E
+:100F9000484F726967696E616C2050727573612089
+:100FA00069331B5B323B3348507275736120526565
+:100FB00073656172636800250020202020202000D6
+:100FC0002020202020200045524153494E472061D7
+:100FD0006C6C206461746100466163746F72792087
+:100FE00052455345540043524153485F5245434F85
+:100FF00056455200473238205900473238205800B1
+:10100000FFFFFF0000A0400000A0400000004000E3
+:10101000007F43000056439AD9514300000000006E
+:101020000080C09A99193E00007F4300005243009F
+:1010300000524300000000000080C09A99193E65EC
+:1010400063686F3A004572726F723A0000002110B7
+:10105000422063308440A550C660E7700881299122
+:101060004AA16BB18CC1ADD1CEE1EFF131121002CA
+:1010700073325222B5529442F772D6623993188372
+:101080007BB35AA3BDD39CC3FFF3DEE36224433496
+:1010900020040114E664C774A44485546AA54BB5C2
+:1010A00028850995EEE5CFF5ACC58DD5533672266A
+:1010B00011163006D776F6669556B4465BB77AA712
+:1010C00019973887DFF7FEE79DD7BCC7C448E558B6
+:1010D0008668A7784008611802282338CCC9EDD962
+:1010E0008EE9AFF9488969990AA92BB9F55AD44A0A
+:1010F000B77A966A711A500A333A122AFDDBDCCBB2
+:10110000BFFB9EEB799B588B3BBB1AABA66C877CD5
+:10111000E44CC55C222C033C600C411CAEED8FFD01
+:10112000ECCDCDDD2AAD0BBD688D499D977EB66EA9
+:10113000D55EF44E133E322E511E700E9FFFBEEF51
+:10114000DDDFFCCF1BBF3AAF599F788F8891A98113
+:10115000CAB1EBA10CD12DC14EF16FE18010A100FD
+:10116000C230E3200450254046706760B9839893ED
+:10117000FBA3DAB33DC31CD37FE35EF3B10290124D
+:10118000F322D2323542145277625672EAB5CBA5B9
+:10119000A89589856EF54FE52CD50DC5E234C3249D
+:1011A000A01481046674476424540544DBA7FAB78D
+:1011B0009987B8975FE77EF71DC73CD7D326F236ED
+:1011C0009106B01657667676154634564CD96DC9D9
+:1011D0000EF92FE9C899E9898AB9ABA9445865483D
+:1011E00006782768C018E1088238A3287DCB5CDB2D
+:1011F0003FEB1EFBF98BD89BBBAB9ABB754A545A8D
+:10120000376A167AF10AD01AB32A923A2EFD0FEDF8
+:101210006CDD4DCDAABD8BADE89DC98D267C076CDC
+:10122000645C454CA23C832CE01CC10C1FEF3EFFCC
+:101230005DCF7CDF9BAFBABFD98FF89F176E367E2C
+:10124000554E745E932EB23ED10EF01E7C3C3E5E37
+:101250002B3D3F2F5B5D3B2C2A225C004D38342018
+:10126000582059205A2045004D3234004D32332049
+:101270002573006175746F25692E67000A002F00C1
+:101280000A002E0044656C6574696F6E20666169A2
+:101290006C65642C2046696C653A200046696C6573
+:1012A0002064656C657465643A002E002E002E0083
+:1012B0002E004E6F772066726573682066696C65D4
+:1012C0003A20004E6F7720646F696E672066696C04
+:1012D000653A20002220706F7300222070617265D1
+:1012E0006E743A2200535542524F5554494E452090
+:1012F00043414C4C207461726765743A22007472E9
+:1013000079696E6720746F2063616C6C20737562FD
+:101310002D67636F64652066696C657320776974F7
+:101320006820746F6F206D616E79206C6576656CD6
+:10133000732E204D4158206C6576656C2069733A98
+:1013400000256920686F757273202569206D696EAC
+:10135000757465730054494D454F55543A004D31ED
+:1013600031300046756C6C205258204275666665B7
+:10137000720022206661696C65643A204275666677
+:1013800065722066756C6C2100456E717565696EBD
+:101390006720746F207468652066726F6E743A20DF
+:1013A00022002200456E717565696E6720746F209A
+:1013B0007468652066726F6E743A2022002220667F
+:1013C00061696C65643A204275666665722066756F
+:1013D0006C6C210022004D363030006673656E73F0
+:1013E0006F725F64697361626C650A0050415439C1
+:1013F0003132355F696E69743A25640A0066736537
+:101400006E736F725F656E61626C650A0050727513
+:101410007361206933204D4B33206F6B0050727520
+:101420007361206933204D4B332072656164792EDE
+:10143000007A5F6D696E3A20007A5F6D61783A20BC
+:10144000005A204F666673657400795F6D696E3A65
+:101450002000795F6D61783A20005920767A6461C6
+:101460006C656E6F7374206F64206D696E3A0059FD
+:101470002064697374616E63652066726F6D206DA0
+:10148000696E3A00416E6F0059657300785F6D694F
+:101490006E3A2000785F6D61783A2000446574618F
+:1014A000696C792058595A206B616C2E0058595A32
+:1014B0002063616C2E2064657461696C73004E79E1
+:1014C0006E692070726F76656475207A206B616C2E
+:1014D0006962726163692E00492077696C6C2072C1
+:1014E000756E207A2063616C6962726174696F6ED7
+:1014F000206E6F772E004E796E692070726F766560
+:1015000064752078797A206B616C696272616369B5
+:101510002E205A616265726520746F207072696254
+:101520006C697A6E65203132206D696E2E0049201B
+:1015300077696C6C2072756E2078797A2063616CA3
+:101540006962726174696F6E206E6F772E204974C4
+:101550002077696C6C2074616B6520617070726FAC
+:10156000782E203132206D696E732E004E796E69AF
+:101570002070726564656872656A69207472797337
+:101580006B752070726F20504C412E004E6F77208B
+:10159000492077696C6C2070726568656174206E93
+:1015A0006F7A7A6C6520666F7220504C412E004431
+:1015B0006F6272792064656E2C206A73656D207687
+:1015C000617365207469736B61726E61204F72691B
+:1015D00067696E616C2050727573612069332E20CB
+:1015E000436863657465206162796368205661733E
+:1015F0002070726F7665646C61206B616C696272D9
+:1016000061636E696D2070726F636573656D3F0015
+:1016100048692C204920616D20796F7572204F72C6
+:101620006967696E616C205072757361206933203F
+:101630007072696E7465722E20576F756C642079B4
+:101640006F75206C696B65206D6520746F20677500
+:1016500069646520796F75207468726F756768209A
+:101660007468652073657475702070726F6365733C
+:10167000733F005A61636E75207469736B6E6F758A
+:1016800074206C696E6B75206120567920627564D8
+:1016900065746520706F737475706E6520736E6904
+:1016A0007A6F76617420747279736B75206F7461D0
+:1016B00063656E696D20746C616369746B6120642D
+:1016C0006F6B7564206E65646F7361686E657465B9
+:1016D000206F7074696D616C6E69207679736B79B7
+:1016E0002E2050726F686C65646E65746520736936
+:1016F000206F6272617A6B792076206E6173692047
+:1017000070726972756363652076206B61706974AD
+:101710006F6C65204B616C69627261636500492082
+:1017200077696C6C20737461727420746F207072AE
+:10173000696E74206C696E6520616E6420796F75C6
+:101740002077696C6C206772616475616C6C7920BC
+:101750006C6F77657220746865206E6F7A7A6C653D
+:1017600020627920726F746174696E672074686595
+:10177000206B6E6F622C20756E74696C20796F75AA
+:10178000207265616368206F7074696D616C206898
+:1017900065696768742E20436865636B20746865AB
+:1017A00020706963747572657320696E206F75723D
+:1017B0002068616E64626F6F6B20696E2063686180
+:1017C000707465722043616C6962726174696F6ED6
+:1017D0002E004E796E69207A6B616C696272756A4F
+:1017E0006920767A64616C656E6F7374206D657ABA
+:1017F00069206B6F6E63656D20747279736B7920ED
+:101800006120706F76726368656D206865617462CF
+:101810006564752E004E6F7720492077696C6C20C7
+:1018200063616C6962726174652064697374616E6E
+:101830006365206265747765656E20746970206FDA
+:101840006620746865206E6F7A7A6C6520616E64BC
+:101850002068656174626564207375726661636592
+:101860002E004E656A6472697620706F6D6F6369D1
+:101870002073656C667465737475207A6B6F6E7413
+:101880006F6C756A69206E656A63617374656A73EB
+:101890006920636879627920767A6E696B616A691A
+:1018A00063692070726920736573746176656E690F
+:1018B000207469736B61726E792E0046697273745D
+:1018C0002C20492077696C6C2072756E20746865D5
+:1018D0002073656C667465737420746F206368652B
+:1018E000636B206D6F737420636F6D6D6F6E20611D
+:1018F0007373656D626C792070726F626C656D7365
+:101900002E005370757374656E692057697A617221
+:1019100064612076796D617A6520756C6F7A656E89
+:1019200065207679736C65646B792076736563687E
+:10193000206B616C696272616369206120737075EC
+:10194000737469206B616C69627261636E69207087
+:10195000726F636573206F64207A616361746B7565
+:101960002E20506F6B7261636F7661743F00527509
+:101970006E6E696E672057697A6172642077696C50
+:101980006C2064656C6574652063757272656E7435
+:101990002063616C6962726174696F6E2072657335
+:1019A000756C747320616E64207374617274206648
+:1019B000726F6D2074686520626567696E6E696E0E
+:1019C000672E20436F6E74696E75653F00436863D0
+:1019D000657465206F70616B6F76617420706F73D2
+:1019E0006C65646E69206B726F6B206120706F7A1A
+:1019F0006D656E697420767A64616C656E6F737460
+:101A0000206D657A6920747279736B6F752061201F
+:101A1000686561746265643F00446F20796F75206A
+:101A200077616E7420746F20726570656174206CCC
+:101A3000617374207374657020746F2072656164C3
+:101A40006A7573742064697374616E63652062657E
+:101A5000747765656E206E6F7A7A6C6520616E644E
+:101A600020686561746265643F0057697A617264D9
+:101A700061206D757A657465206B64796B6F6C6934
+:101A800076207A6E6F767520737075737469742022
+:101A90007A206D656E752043616C6962726174694C
+:101AA0006F6E202D3E2057697A61726400596F7500
+:101AB0002063616E20616C77617973207265737544
+:101AC0006D65207468652057697A6172642066725A
+:101AD0006F6D2043616C6962726174696F6E202D55
+:101AE0003E2057697A6172642E004A6520746F2027
+:101AF000504C412066696C616D656E743F0049739E
+:101B000020697420504C412066696C616D656E746B
+:101B10003F0050726F73696D20766C6F7A74652028
+:101B2000504C412066696C616D656E7420646F2055
+:101B30006578747275646572752C20706F20746599
+:101B400020737469736B6E65746520746C6163696E
+:101B5000746B6F2070726F207A61766564656E6950
+:101B60002066696C616D656E74752E00506C6561E0
+:101B7000736520696E7365727420504C41206669EC
+:101B80006C616D656E7420746F2074686520657873
+:101B90007472756465722C207468656E207072654D
+:101BA0007373206B6E6F6220746F206C6F616420A2
+:101BB00069742E0050726F73696D207A6176656466
+:101BC000746520504C412066696C616D656E7420AF
+:101BD0006120706F207465206F626E6F767465206F
+:101BE00057697A6172646120737469736B6E75747E
+:101BF000696D20726573657420746C616369746BC0
+:101C0000612E00506C65617365206C6F61642050BB
+:101C10004C412066696C616D656E7420616E642054
+:101C20007468656E20726573756D652057697A6199
+:101C30007264206279207265626F6F74696E6720CA
+:101C4000746865207072696E7465722E00507265DA
+:101C5000646568726976616D20747279736B752E34
+:101C60002050726F73696D2063656B656A74652EB1
+:101C70000050726568656174696E67206E6F7A7A6C
+:101C80006C652E20506C6561736520776169742ED8
+:101C9000004A652066696C616D656E74207A6176B4
+:101CA0006564656E3F0049732066696C616D656EA1
+:101CB00074206C6F616465643F00567365206A65CB
+:101CC00020686F746F766F2E00416C6C20697320F2
+:101CD000646F6E652E204861707079207072696E35
+:101CE00074696E67210050726F73696D206F63694C
+:101CF0007374657465206865617462656420612031
+:101D0000737469736B6E65746520746C6163697458
+:101D10006B6F2E00506C6561736520636C65616E3E
+:101D2000206865617462656420616E642074686512
+:101D30006E20707265737320746865206B6E6F62BD
+:101D40002E0050726F73696D206E61686C65646EF1
+:101D500065746520646F206D616E75616C752061BE
+:101D6000206F7072617674652070726F626C656D41
+:101D70002E20506F207465206F626E6F7674652020
+:101D800057697A61726461207265626F6F746F76F1
+:101D9000616E696D207469736B61726E792E00508B
+:101DA0006C6561736520636865636B206F75722075
+:101DB00068616E64626F6F6B20616E642066697823
+:101DC000207468652070726F626C656D2E20546897
+:101DD000656E20726573756D65207468652057693E
+:101DE0007A617264206279207265626F6F74696EC5
+:101DF0006720746865207072696E7465722E005772
+:101E0000697A61726400205761746368646F672047
+:101E1000526573657400496E666F726D616365002B
+:101E2000496E666F2073637265656E004B616C2E40
+:101E3000207072766E6920767273747679004669C6
+:101E4000727374206C617965722063616C2E005727
+:101E500061697420666F7220757365722E2E2E0074
+:101E6000506F757A69746520626568656D20746964
+:101E7000736B75005573656420647572696E6720B5
+:101E80007072696E74004F70616B6F76617420764A
+:101E90007973756E7574692066696C616D656E74B1
+:101EA000753F0052657065617420756E6C6F61647A
+:101EB000696E672066696C616D656E743F00567966
+:101EC0006A6D6F75742066696C616D656E7400551E
+:101ED0006E6C6F61642066696C616D656E7400562E
+:101EE00079736F7576616D2066696C616D656E746E
+:101EF00000556E6C6F6164696E672066696C616D18
+:101F0000656E7400556E6B6E6F776E20636F6D6DCE
+:101F1000616E643A2022004C616469740054756EED
+:101F2000650053442063617264205B466C736841B2
+:101F300069725D0053442063617264205B6E6F724E
+:101F40006D616C5D005465706C2E206B616C2E2091
+:101F5000205B7A61705D0054656D702E2063616C4A
+:101F60002E2020205B6F6E5D005465706C2E206B00
+:101F7000616C2E20205B7679705D0054656D702E4B
+:101F80002063616C2E20205B6F66665D0054657077
+:101F90006C6F746E69206B616C696272616365203D
+:101FA000646F6B6F6E63656E612E20506F6B726134
+:101FB00063756A746520737469736B656D20746CE6
+:101FC000616369746B612E0054656D706572617434
+:101FD0007572652063616C6962726174696F6E20ED
+:101FE00069732066696E69736865642E20436C6945
+:101FF000636B20746F20636F6E74696E75652E005D
+:102000005465706C2E206B616C2E202020202020C7
+:10201000202020200054656D702E2063616C2E20DE
+:10202000202020202020202020005465706C6F7418
+:10203000610054656D706572617475726500506FF2
+:1020400064706F726100537570706F7274005A61C2
+:10205000737461766974207469736B0053746F7064
+:10206000207072696E740053544F505045442E20B6
+:1020700000537465707261746520746F6F206869B5
+:1020800067683A20004A65207469736B6F7679201F
+:10209000706C6174206E6120686561746265643F74
+:1020A00000497320737465656C20736865657420DE
+:1020B0006F6E20686561746265643F0043656C6B98
+:1020C0006F767920636173203A00546F74616C20DD
+:1020D0007072696E742074696D65203A0046696C8F
+:1020E000616D656E742063656C6B656D203A00549C
+:1020F0006F74616C2066696C616D656E74203A0066
+:10210000436173207469736B75203A20200050720C
+:10211000696E742074696D653A20200046696C61AF
+:102120006D656E74203A20200046696C616D656EA5
+:102130007420757365643A20200053746174697368
+:1021400074696B61202000537461746973746963EE
+:10215000732020004572726F72202D207374617499
+:102160006963206D656D6F727920686173206265A7
+:10217000656E206F7665727772697474656E005251
+:102180007963686C6F7374005370656564002053E5
+:102190006F667477617265205265736574004C6573
+:1021A000686B65207A6B6F73656E693A00536C6972
+:1021B00067687420736B65773A004D6F6420202048
+:1021C00020205B537465616C74685D004D6F6465BD
+:1021D000202020205B537465616C74685D004D6F36
+:1021E000642020202020205B4E6F726D616C5D00AA
+:1021F0004D6F646520202020205B4E6F726D616CF6
+:102200005D0053746176206B6F6E632E207370696E
+:102210006E2E0053686F7720656E642073746F7044
+:10222000730054657A6B65207A6B6F73656E693ADB
+:102230000053657665726520736B65773A004E6171
+:10224000737461767465207465706C6F74753A0090
+:102250005365742074656D70657261747572653A4A
+:10226000004E6173746176656E69005365747469BC
+:102270006E6773004368796261207A61706F6A6586
+:102280006E6900576972696E67206572726F7200BD
+:1022900053656C6620746573742073746172742066
+:1022A00020005A6B6F6E74726F6C756A7465203A99
+:1022B00000506C6561736520636865636B203A004C
+:1022C00053656C662074657374204F4B004E657ABD
+:1022D00061706F6A656E6F20202020004E6F742041
+:1022E000636F6E6E6563746564004D6F746F72002A
+:1022F0004865617465722F546865726D6973746F97
+:102300007200546573742076656E74696C61746FC5
+:1023100072750046616E20746573740053656C6657
+:10232000746573742073656C68616C20200053655C
+:102330006C6674657374206661696C656420200046
+:102340004C6576792076656E74206E6120747279A2
+:102350007363653F004C65667420686F74656E64D6
+:102360002066616E3F0053656C667465737420650A
+:1023700072726F72202100456E6473746F70206EEC
+:102380006F742068697400456E6473746F707300B5
+:10239000456E6473746F7000507265646E6920746A
+:1023A00069736B6F76792076656E743F0046726F45
+:1023B0006E74207072696E742066616E3F004B6FA0
+:1023C0006E74726F6C61205A2061786973202000EE
+:1023D000436865636B696E67205A20617869732072
+:1023E00020004B6F6E74726F6C61205920617869A8
+:1023F00073202000436865636B696E672059206114
+:102400007869732020004B6F6E74726F6C61205876
+:102410002061786973202000436865636B696E678B
+:10242000205820617869732020004B6F6E74726FA2
+:102430006C6120686F74656E64202000436865637A
+:102440006B696E6720686F74656E642020004B6F47
+:102450006E74726F6C6120656E6473746F7073005C
+:10246000436865636B696E6720656E6473746F7033
+:1024700073004B6F6E74726F6C6120626564202014
+:1024800020202000436865636B696E672062656485
+:10249000202020202000567365204F4B2020202034
+:1024A0002020202020202000416C6C20636F72725D
+:1024B00065637420202020202000426564202F20A6
+:1024C0004865617465720044656C6B61206F737957
+:1024D0000041786973206C656E677468004F7361A2
+:1024E00000417869730053656C66746573742020CD
+:1024F000202020202020200057726974696E6720F8
+:10250000746F2066696C653A2000766F6C756D6536
+:102510002E696E6974206661696C65640020536978
+:102520007A653A20004B617274612076796A6D7524
+:10253000746100436172642072656D6F766564003A
+:102540005344207072696E74696E67206279746595
+:1025500020006F70656E206661696C65642C204692
+:10256000696C653A20006F70656E526F6F742066FB
+:1025700061696C6564004B6172746120766C6F7A7E
+:10258000656E61004361726420696E736572746583
+:102590006400534420696E6974206661696C00466A
+:1025A000696C652073656C65637465640046696C6D
+:1025B00065206F70656E65643A20006572726F7297
+:1025C0002077726974696E6720746F2066696C6524
+:1025D0000053442063617264206F6B0043616E6E30
+:1025E0006F7420656E746572207375626469723AE7
+:1025F000200050726176793A0052696768743A0037
+:102600004F626E6F766F76616E69207469736B7559
+:1026100000526573756D696E67207072696E740023
+:102620004F626E6F76656E69207469736B750052C8
+:102630006573756D696E67207072696E7400506F96
+:102640006B7261636F76617400526573756D65209E
+:102650007072696E7400526573656E643A20004F43
+:1026600064737472616E7465207469736B6F7679CC
+:1026700020706C6174207A206865617462656420E2
+:1026800070726F73696D2E00506C65617365207296
+:10269000656D6F766520737465656C20736865651C
+:1026A000742066726F6D20686561746265642E00C7
+:1026B000446574656B6F76616E20767970616465D0
+:1026C0006B2070726F7564752E4F626E6F766974D1
+:1026D000207469736B3F00426C61636B6F7574208B
+:1026E0006F636375727265642E205265636F7665E1
+:1026F00072207072696E743F004F626E6F766F76F3
+:10270000616E69207469736B75202020200052650A
+:10271000636F766572696E67207072696E742020CF
+:10272000202000686F77746F2E7072757361336448
+:102730002E637A00686F77746F2E707275736133D1
+:10274000642E636F6D00666F72756D2E7072757397
+:102750006133642E637A00666F72756D2E707275C8
+:10276000736133642E636F6D0070727573613364CF
+:102770002E637A00707275736133642E636F6D001F
+:102780005469736B20706F7A6173746176656E0043
+:102790005072696E7420706175736564005469735A
+:1027A0006B20707265727573656E005072696E741D
+:1027B0002061626F72746564005072696E74657234
+:1027C00020646973636F6E6E656374656400507234
+:1027D0006F20767973756E7574692066696C616DAA
+:1027E000656E747520737469736B6E6574652070A3
+:1027F000726F73696D20746C616369746B6F0050E4
+:102800006C656173652070726573732074686520F0
+:102810006B6E6F6220746F20756E6C6F61642066E2
+:10282000696C616D656E74006120737469736B6EA1
+:1028300065746520746C616369746B6F00616E64AC
+:1028400020707265737320746865206B6E6F620010
+:1028500050726564656872656A7465207472797314
+:102860006B7521005072656865617420746865201D
+:102870006E6F7A7A6C652100507265646568726566
+:1028800076005072656865617400506F77657255A7
+:10289000700050726F73696D2063656B656A746553
+:1028A00000506C656173652077616974004E656ADC
+:1028B0006472697665207A61766564746520504C2F
+:1028C000412066696C616D656E742070726F73690A
+:1028D0006D2E00506C65617365206C6F61642050D3
+:1028E0004C412066696C616D656E74206669727317
+:1028F000742E004A6520504C412066696C616D65FC
+:102900006E74207A61766564656E3F00497320506D
+:102910004C412066696C616D656E74206C6F6164FA
+:1029200065643F002020506C616E6E657242756672
+:1029300066657242797465733A2000556D697374E7
+:102940006574652070726F73696D207469736B6F45
+:10295000767920706C6174206E61206865617462A4
+:10296000656400506C6561736520706C61636520FF
+:10297000737465656C207368656574206F6E20687C
+:102980006561746265642E004E6168726976616E7D
+:10299000692050494E44410050494E444120486509
+:1029A0006174696E6700504944206B616C2E202071
+:1029B0002020202020202020200050494420636136
+:1029C0006C2E202020202020202020202000504974
+:1029D00044206B616C2E20756B6F6E63656E6100B9
+:1029E0005049442063616C2E2066696E6973686586
+:1029F0006400504944206B616C69627261636500D8
+:102A00005049442063616C6962726174696F6E0041
+:102A1000506F7A61737461766974207469736B00A6
+:102A20005061757365207072696E7400556D6973BD
+:102A300074657465206C6973742070617069727557
+:102A4000206E6120706F646C6F7A6B7520612075E9
+:102A500064727A756A7465206A656A20706F642092
+:102A6000747279736B6F7520626568656D206D6532
+:102A700072656E69207072766E69636820342062B8
+:102A80006F64752E20506F6B756420747279736B50
+:102A900061207A6163687974692070617069722C51
+:102AA000207679706E657465207469736B61726EDF
+:102AB000752E00506C6163652061207368656574D4
+:102AC000206F6620706170657220756E646572207B
+:102AD000746865206E6F7A7A6C6520647572696EB1
+:102AE00067207468652063616C6962726174696FE4
+:102AF0006E206F66206669727374203420706F696F
+:102B00006E74732E20496620746865206E6F7A7A21
+:102B10006C652063617463686573207468652070F8
+:102B2000617065722C20706F776572206F66662009
+:102B3000746865207072696E74657220696D6D6568
+:102B400064696174656C792E006F6B004F66660076
+:102B50004E6F206D6F76652E005A61646E61205352
+:102B600044206B61727461004E6F20534420636196
+:102B7000726400547279736B61004E6F7A7A6C657F
+:102B80000046696C616D656E74206E657A6176656C
+:102B900064656E0046696C616D656E74206E6F745D
+:102BA000206C6F61646564004261727661206E65BD
+:102BB0006E6920636973746100436F6C6F72206E7D
+:102BC0006F7420636C656172004E65004E6F00503B
+:102BD000726F73696D20616B7475616C697A756A67
+:102BE00074652E00506C6561736520757067726145
+:102BF00064652E005679736C61206E6F7661207665
+:102C000065727A65206669726D776172653A004E09
+:102C10006577206669726D7761726520766572737B
+:102C2000696F6E20617661696C61626C653A005013
+:102C30006F73756E6F7574205A004D6F7665205AEC
+:102C400000506F73756E6F75742059004D6F766507
+:102C5000205900506F73756E6F75742058004D6F5A
+:102C60007665205800457874727564657200506FFF
+:102C700073756E6F7574206F7375004D6F76652078
+:102C800061786973004D65736820426564204C6506
+:102C900076656C696E67004B616C69627261636531
+:102CA0000043616C6962726174696F6E00207A2002
+:102CB0003900206F662039004D6572696D2072659C
+:102CC000666572656E636E69207679736B75206BCD
+:102CD000616C69627261636E69686F20626F6475AE
+:102CE000004D6561737572696E6720726566657205
+:102CF000656E636520686569676874206F66206328
+:102D0000616C6962726174696F6E20706F696E7454
+:102D1000004D6572656E65207A6B6F73656E693AFA
+:102D2000004D6561737572656420736B65773A0059
+:102D3000486C61766E69206E616269646B61004DFA
+:102D400061696E004D32323120496E76616C696482
+:102D500020657874727564657220004D32313820B8
+:102D6000496E76616C696420657874727564657209
+:102D700020004D32303020496E76616C69642065E8
+:102D80007874727564657220005265706F72746930
+:102D90006E6720656E6473746F70207374617475F0
+:102DA00073004D313137204B616C2E207072766E7E
+:102DB0006920767273747679004D31313720466917
+:102DC000727374206C617965722063616C2E0046A9
+:102DD00049524D574152455F4E414D453A4D617202
+:102DE0006C696E2056312E302E323B205370726942
+:102DF0006E7465722F6772626C206D617368757096
+:102E000020666F722067656E36204649524D5741E5
+:102E100052455F55524C3A68747470733A2F2F675D
+:102E200069746875622E636F6D2F7072757361338C
+:102E3000642F50727573612D69332D506C75732F2B
+:102E40002050524F544F434F4C5F56455253494FB9
+:102E50004E3A312E30204D414348494E455F54593A
+:102E600050453A5072757361206933204D4B3320C1
+:102E700045585452554445525F434F554E543A318C
+:102E800020555549443A30303030303030302D30D4
+:102E90003030302D303030302D303030302D30303B
+:102EA000303030303030303030300A004D31303951
+:102EB00020496E76616C696420657874727564650A
+:102EC0007220004D31303520496E76616C69642086
+:102ED000657874727564657220004D313034204914
+:102EE0006E76616C696420657874727564657220B1
+:102EF0000055766F6C6E656E612072656D656E69EA
+:102F0000636B61004C6F6F73652070756C6C6579D5
+:102F1000005A61766573742066696C616D656E74C4
+:102F2000004C6F61642066696C616D656E74005A57
+:102F300061766164656E692066696C616D656E7449
+:102F400075004C6F6164696E672066696C616D65C0
+:102F50006E740043697374656E692062617276797C
+:102F6000004C6F6164696E6720636F6C6F72004C18
+:102F70006576793A004C6566743A005679626572F6
+:102F8000206A617A796B610053656C656374206CAB
+:102F9000616E67756167650043657374696E610092
+:102FA000456E676C697368004B494C4C45442E2054
+:102FB00000496E76616C6964206578747275646529
+:102FC0007200566C6F7A74652066696C616D656E0F
+:102FD0007400496E736572742066696C616D656E0C
+:102FE00074005072696E742046414E3A20004E6F54
+:102FF0007A7A6C652046414E3A0045787472756461
+:10300000657220696E666F00207A203400206F663A
+:103010002034005A6C657073756A6920707265732C
+:103020006E6F7374206B616C69627261636E696844
+:103030006F20626F647500496D70726F76696E679C
+:10304000206265642063616C6962726174696F6E8D
+:1030500020706F696E74004B616C696272756A6989
+:10306000205A0043616C6962726174696E67205A0C
+:10307000004B616C696272616365204F4B00436174
+:103080006C6962726174696F6E20646F6E65004B6B
+:10309000616C6962726F766174205A0043616C6979
+:1030A0006272617465205A005A6168726976616E55
+:1030B00069204F4B2E0048656174696E6720646F0C
+:1030C0006E652E005A6168726976616E69004865A6
+:1030D0006174696E670046696C2E2073656E7A6F45
+:1030E00072205B7A61705D0046696C2E2073656E9C
+:1030F000736F7220205B6F6E5D0046696C2E2073CB
+:10310000656E7A6F72205B7679705D0046696C2E11
+:103110002073656E736F72205B6F66665D0020467C
+:10312000726565204D656D6F72793A200054697340
+:103130006B61726E61206E6562796C61206A657385
+:103140007465207A6B616C6962726F76616E612E54
+:1031500020506F73747570756A74652070726F7328
+:10316000696D20706F646C65206D616E75616C7542
+:103170002C206B617069746F6C61205A6163696E99
+:10318000616D652C206F6473746176656320506F88
+:1031900073747570206B616C6962726163652E0077
+:1031A0005072696E74657220686173206E6F74204E
+:1031B0006265656E2063616C69627261746564202A
+:1031C0007965742E20506C6561736520666F6C6C38
+:1031D0006F7720746865206D616E75616C2C20635B
+:1031E00068617074657220466972737420737465C7
+:1031F00070732C2073656374696F6E2043616C6912
+:1032000062726174696F6E20666C6F772E00507207
+:1032100075746F6B00466C6F7700446F6B6F6E63F5
+:103220006F76616E6920706F687962750046696EAD
+:10323000697368696E67206D6F76656D656E74730E
+:1032400000207A203400206F66203400486C6564CA
+:10325000616D206B616C69627261636E6920626F7F
+:103260006420706F646C6F7A6B7900536561726370
+:1032700068696E67206265642063616C696272616F
+:1032800074696F6E20706F696E7400497465726145
+:1032900063652000497465726174696F6E20004433
+:1032A0006F6E6520736176696E672066696C652E46
+:1032B00000446F6E65207072696E74696E67206677
+:1032C000696C65004A65206261727661206369738A
+:1032D00074613F00497320636F6C6F7220636C658B
+:1032E00061723F0056796D656E69742066696C6124
+:1032F0006D656E74004368616E67652066696C6118
+:103300006D656E7400527963686C6F7374207665B6
+:103310006E742E0046616E207370656564004B6F9D
+:103320006E74722E2076656E742E5B7A61705D000D
+:1033300046616E7320636865636B2020205B6F6E4F
+:103340005D004B6F6E74722E2076656E742E5B7608
+:1033500079705D0046616E7320636865636B202041
+:103360005B6F66665D00656E717565696E672022CC
+:1033700000457874727564657200204578746572D2
+:103380006E616C205265736574005072696E74656D
+:10339000722073746F707065642064756520746F3B
+:1033A000206572726F72732E20466978207468658A
+:1033B000206572726F7220616E6420757365204D96
+:1033C00039393920746F20726573746172742E20DC
+:1033D0002854656D7065726174757265206973201B
+:1033E00072657365742E205365742069742061665C
+:1033F0007465722072657374617274696E672900F6
+:103400004E6F204C696E65204E756D626572207737
+:1034100069746820636865636B73756D2C204C61FB
+:103420007374204C696E653A20004E6F20436865C6
+:10343000636B73756D2077697468206C696E6520A5
+:103440006E756D6265722C204C617374204C696ED0
+:10345000653A200020746F6F206C6F6E672065786E
+:1034600074727573696F6E2070726576656E7465BF
+:1034700064004C696E65204E756D626572206973DB
+:10348000206E6F74204C617374204C696E65204E01
+:10349000756D6265722B312C204C617374204C6900
+:1034A0006E653A20005072696E7465722068616CB6
+:1034B0007465642E206B696C6C28292063616C6CC8
+:1034C0006564210020636F6C642065787472757385
+:1034D000696F6E2070726576656E746564006368EE
+:1034E00065636B73756D206D69736D617463682CB2
+:1034F000204C617374204C696E653A200043485932
+:1035000042413A004552524F523A00456E6420669D
+:10351000696C65206C697374006F70656E0054523D
+:103520004947474552454400656E6473746F707334
+:10353000206869743A2000536C6565702E2E2E0049
+:103540005679706E6F7574206D6F746F7279004468
+:10355000697361626C652073746570706572730065
+:10356000446174756D3A00446174653A00506F753A
+:103570007A6520616B7475616C6E69004375727257
+:10358000656E74004372617368206465742E202038
+:103590005B7A61705D004372617368206465742EAC
+:1035A0002020205B6F6E5D0043726173682064654C
+:1035B000742E20205B7679705D0043726173682001
+:1035C0006465742E20205B6F66665D0020436F7516
+:1035D0006E7420583A200056796D656E61206F6BCD
+:1035E0003F004368616E67656420636F7272656354
+:1035F000746C793F005A63686C6164697400436F4E
+:103600006F6C646F776E0050726F207573706573A6
+:103610006E6F75206B616C696272616369206F63A4
+:103620006973746574652070726F73696D20746955
+:10363000736B6F766F7520747279736B752E205073
+:103640006F74767264746520746C616369746B6501
+:103650006D2E00506C6561736520636C65616E2032
+:10366000746865206E6F7A7A6C6520666F7220636D
+:10367000616C6962726174696F6E2E20436C69635C
+:103680006B207768656E20646F6E652E00204C613C
+:10369000737420557064617465643A2000567962D1
+:1036A000657274652065787472756465723A00435A
+:1036B000686F6F73652065787472756465723A001F
+:1036C0005A6D656E612075737065736E612100437C
+:1036D00068616E6765207375636365737321005459
+:1036E00069736B207A205344005072696E742066AF
+:1036F000726F6D205344005465706C6F742E206B94
+:10370000616C6962726163650054656D702E20633F
+:10371000616C6962726174696F6E004B616C6962A1
+:1037200072756A69205A0043616C696272617469DA
+:103730006E67205A005A6B616C6962726F766174B1
+:103740000043616C696272617465005265736574EF
+:103750002058595A206B616C6962722E0052657351
+:1037600065742058595A2063616C6962722E004B4F
+:10377000616C6962726163652058595A0043616CDB
+:103780006962726174652058595A002042726F77DD
+:103790006E206F75742052657365740042656769A9
+:1037A0006E2066696C65206C697374004B616C698E
+:1037B00062726163652058595A206E657072657334
+:1037C0006E612E204C65767920707265646E69207A
+:1037D000626F64206D6F63207670726564752E0071
+:1037E00058595A2063616C6962726174696F6E2006
+:1037F000636F6D70726F6D697365642E204C6566C2
+:10380000742066726F6E742063616C696272617499
+:10381000696F6E20706F696E74206E6F74207265B0
+:1038200061636861626C652E004B616C69627261F4
+:1038300063652058595A206E65707265736E612EEB
+:1038400020507265646E69206B616C69627261639D
+:103850006E6920626F6479206D6F63207670726587
+:1038600064752E0058595A2063616C6962726174E4
+:10387000696F6E20636F6D70726F6D697365642E12
+:103880002046726F6E742063616C69627261746944
+:103890006F6E20706F696E7473206E6F7420726526
+:1038A00061636861626C652E004B616C6962726174
+:1038B00063652058595A207620706F7261646B7569
+:1038C0002E20582F59206F7379206D69726E6520F4
+:1038D0007A6B6F73656E652E20446F627261207023
+:1038E00072616365210058595A2063616C69627284
+:1038F0006174696F6E20616C6C2072696768742EE8
+:1039000020582F5920617865732061726520736C8F
+:10391000696768746C7920736B657765642E2047DE
+:103920006F6F64206A6F6221004B616C6962726123
+:1039300063652058595A207620706F7261646B75E8
+:103940002E205A6B6F73656E692062756465206105
+:1039500075746F6D617469636B79207679726F76B7
+:103960006E616E6F20707269207469736B752E00C2
+:1039700058595A2063616C6962726174696F6E2074
+:10398000616C6C2072696768742E20536B657720B8
+:1039900077696C6C20626520636F72726563746511
+:1039A00064206175746F6D61746963616C6C792EEC
+:1039B000004B616C6962726163652058595A2073CB
+:1039C000656C68616C612E204B616C696272616329
+:1039D0006E6920626F6420706F646C6F7A6B7920FF
+:1039E0006E656E616C657A656E2E0058595A20635B
+:1039F000616C6962726174696F6E206661696C6581
+:103A0000642E204265642063616C6962726174692E
+:103A10006F6E20706F696E7420776173206E6F74A3
+:103A200020666F756E642E004B616C696272616313
+:103A3000652058595A207620706F7261646B752E1C
+:103A400020582F59206F7379206A736F75206B6F20
+:103A50006C6D652E2047726174756C756A69210002
+:103A600058595A2063616C6962726174696F6E2083
+:103A70006F6B2E20582F5920617865732061726515
+:103A80002070657270656E646963756C61722E205A
+:103A9000436F6E67726174756C6174696F6E7321C8
+:103AA000004B616C6962726163652058595A2073DA
+:103AB000656C68616C612E204E61686C65646E6532
+:103AC000746520646F206D616E75616C752E005891
+:103AD000595A2063616C6962726174696F6E206605
+:103AE00061696C65642E20506C6561736520636F3D
+:103AF0006E73756C7420746865206D616E75616C91
+:103B00002E004B616C6962726163652058595A20BE
+:103B100073656C68616C612E204C657679207072DB
+:103B200065646E6920626F64206D6F6320767072C9
+:103B30006564752E2053726F766E656A74652074A5
+:103B400069736B61726E752E0058595A2063616CEF
+:103B50006962726174696F6E206661696C65642E5A
+:103B6000204C6566742066726F6E742063616C69A8
+:103B700062726174696F6E20706F696E74206E6F0F
+:103B80007420726561636861626C652E004B616CC4
+:103B90006962726163652058595A2073656C686167
+:103BA0006C612E20507265646E69206B616C696275
+:103BB0007261636E6920626F6479206D6F63207635
+:103BC00070726564752E2053726F766E656A7465C7
+:103BD000207469736B61726E752E0058595A206398
+:103BE000616C6962726174696F6E206661696C658F
+:103BF000642E2046726F6E742063616C696272611C
+:103C000074696F6E20706F696E7473206E6F7420AC
+:103C1000726561636861626C652E004B616C6962FC
+:103C200072616365205A2073656C68616C612E2037
+:103C300053656E736F72206A65206F64706F6A657A
+:103C40006E79206E65626F20707265727573656E35
+:103C500079206B6162656C2E2043656B616D206E0F
+:103C6000612072657365742E00426564206C657610
+:103C7000656C696E67206661696C65642E205365AA
+:103C80006E736F7220646973636F6E6E65637465C3
+:103C900064206F72206361626C652062726F6B6575
+:103CA0006E2E2057616974696E6720666F7220728C
+:103CB000657365742E004B616C6962726163652087
+:103CC0005A2073656C68616C612E2053656E736F4A
+:103CD00072206E657365706E756C2E205A6E65630A
+:103CE000697374656E6120747279736B613F2043F0
+:103CF000656B616D206E612072657365742E004284
+:103D00006564206C6576656C696E67206661696CB8
+:103D100065642E2053656E736F72206469646E74DF
+:103D200020747269676765722E20446562726973D8
+:103D3000206F6E206E6F7A7A6C653F2057616974D0
+:103D4000696E6720666F722072657365742E004B12
+:103D5000616C696272616365205A2073656C686189
+:103D60006C612E2053656E736F72207365706E7573
+:103D70006C207072696C6973207679736F6B6F2E2B
+:103D80002043656B616D206E612072657365742ED2
+:103D900000426564206C6576656C696E67206661BB
+:103DA000696C65642E2053656E736F72207472693E
+:103DB00067676572656420746F6F20686967682E35
+:103DC0002057616974696E6720666F72207265732F
+:103DD00065742E005A6168726976616E6920626549
+:103DE00064004265642048656174696E67004265DD
+:103DF00064204F4B2E0042656420646F6E65005650
+:103E0000707261766F205B756D5D005269676874D2
+:103E100020736964655B756D5D0052657365740040
+:103E2000567A61647520205B756D5D005265617224
+:103E30002073696465205B756D5D004B6F72656B07
+:103E4000636520706F646C6F7A6B790042656420E3
+:103E50006C6576656C20636F727265637400566C76
+:103E600065766F20205B756D5D004C656674207310
+:103E7000696465205B756D5D0056707265647520C0
+:103E80005B756D5D0046726F6E7420736964655B6F
+:103E9000756D5D00426564004E656E69207A6B61E8
+:103EA0006C6962726F76616E6120767A64616C65AE
+:103EB0006E6F737420747279736B79206F642074E1
+:103EC00069736B6F766520706F646C6F7A6B792E97
+:103ED00020506F73747570756A74652070726F739B
+:103EE000696D20706F646C65206D616E75616C75B5
+:103EF0002C206B617069746F6C61205A6163696E0C
+:103F0000616D652C206F64737461766563204E610A
+:103F100073746176656E69207072766E6920767250
+:103F2000737476792E0044697374616E63652062E0
+:103F300065747765656E20746970206F662074689B
+:103F400065206E6F7A7A6C6520616E642074686596
+:103F500020626564207375726661636520686173B1
+:103F6000206E6F74206265656E20736574207965BC
+:103F7000742E20506C6561736520666F6C6C6F7772
+:103F800020746865206D616E75616C2C20636861BA
+:103F900070746572204669727374207374657073EF
+:103FA0002C2073656374696F6E2046697273742088
+:103FB0006C617965722063616C6962726174696FAA
+:103FC0006E2E00446F6C6164656E69206F7379209A
+:103FD0005A004C6976652061646A757374205A00D2
+:103FE00041646A757374696E67205A004175746F15
+:103FF00020686F6D6500207C20417574686F723A8F
+:10400000200056736500416C6C00416374697665ED
+:104010002045787472756465723A20001D140D1481
+:104020003114391441144A1452146F145A14881458
+:1040300084148C149414AD149C14D814BE142E152E
+:10404000F6148C156C151016AF151E17731615186F
+:10405000D217BB1862186E190219191ACD19AD1AA8
+:104060006A1AFE1AEA1A6C1B121B031CB41B711C81
+:104070004D1CA61C911CC91CBA1C141DE61C9F1DBE
+:10408000421DFF1D061E201E161E3E1E2C1E4F1E0C
+:10409000741E601EA31E861ECF1EBE1EF11EDF1ED6
+:1040A000041F1D1F171F221F341F571F451F7B1F73
+:1040B000691FC81F8D1F1520002032202A2046208E
+:1040C0003E205C204E2067207120A1208520CA2040
+:1040D000BC20EF20DD200E21002129211C214721B9
+:1040E0003A21542188217F218E21AD219E21CC218E
+:1040F000BA21F021DE211322022231222222502273
+:104100003E226B226122832274229022B122A222BB
+:10411000C022DC22CD22EA22F022132302232E2306
+:104120001C23552340236623772387239023AD2325
+:104130009823D023BE23F423E223182406243C240E
+:104140002A2460244E2484247224A8249624BA2489
+:10415000D124C724E124DD24E624F8240A251D25E2
+:10416000332525254025522566258425762592254B
+:104170009F25AD25BB25D125DC25F925F225112666
+:1041800000262F26202649263E26562688265F26EC
+:10419000D726B0260E27F926342723275727462768
+:1041A0007427692790278027AB279D27B927FF27EA
+:1041B000CE273D28282864285028822878288A2855
+:1041C000A1289228D328AD280C29F3282429632973
+:1041D0003B2998298829BA29A629E029CE29002A2D
+:1041E000F229202A102AB32A2C2A492B4C2B502B97
+:1041F000682B592B7A2B732B942B812BB92BA82B43
+:10420000CC2BC92BE42BCF2B0F2CF42B3A2C2F2C9F
+:104210004C2C412C5E2C532C652C7B2C6E2C852C2D
+:10422000A12C972CB22CAD2CE12CB82C212D112DCA
+:104230003F2D302D442D5B2D722D892DB92DA22DB2
+:10424000CF2DAC2EC32EDA2E042FF12E212F112FBD
+:10425000422F2F2F612F532F752F6F2F882F7B2FDA
+:10426000A02F982FA82FB12FD22FC22FE22FEE2FE1
+:10427000FA2F0D30083037301330633057307E302E
+:1042800071309C308F30B630A830CE30C430E8303A
+:10429000D6300C31FA301E31A0312D3115320E32AC
+:1042A0002D321A32463241326B324C3294328B32DA
+:1042B0009F32B132D432C432F532E4321433053392
+:1042C00030331E3354334233663371337A338A3397
+:1042D00000342A3454347234A534C434DE34043502
+:1042E000FD340B3519351E35283537354F354035FA
+:1042F000673560357C356D3596358435BA35A835EA
+:10430000CC35E235D735FE35F535533607368D36A3
+:10431000AF369D36CF36C036E936DF360937F73649
+:1043200027371B37413735375D374B377D376F3789
+:104330008B379C37E037AC3764382938E638A938F2
+:1043400070392939EB39B139603A283ACF3AA13A74
+:10435000493B023BDB3B8D3B693C1B3CFF3CB63C95
+:10436000913D4F3DE23DD43DF63DEE3D0B3EFF3DE0
+:104370001A3E2C3E203E4C3E3B3E6A3E5E3E853E13
+:10438000793E943E263F983ED23FC33FE03FEC3F0C
+:10439000F63F064002400A40457872656D6520731D
+:1043A00070616E206F6620746865205A2076616C9B
+:1043B000756573210043616C63756C6174696F6E20
+:1043C000206F6620746865206D616368696E652082
+:1043D000736B657720616E64206F66667365742009
+:1043E0006661696C65642E00203C20005741524E86
+:1043F000494E473A2046726F6E7420706F696E7432
+:10440000206E6F7420726561636861626C652E2036
+:104410005920636F6F7264696E6174653A00004978
+:104420007465726174696F6E3A2000496E76616CD2
+:1044300069642062656420636F7272656374696F7A
+:104440006E206D61747269782E2052657365747484
+:10445000696E6720746F206964656E746974792E63
+:1044600000496E76616C69642062656420636F72D6
+:1044700072656374696F6E206D61747269782E2045
+:10448000582F5920617865732061726520666172CA
+:104490002066726F6D206265696E6720706572704C
+:1044A000656E646963756C61722E00496E76616C2D
+:1044B00069642062656420636F7272656374696FFA
+:1044C0006E206D61747269782E205368696674205D
+:1044D0006F7574206F662072616E67652E005A6575
+:1044E000726F20706F696E7420636F72726563748F
+:1044F000696F6E3A00496E76616C6964206265642A
+:1045000020636F7272656374696F6E206D6174727F
+:1045100069782E204C656E677468206F6620746819
+:1045200065205920766563746F72206F7574206FF3
+:10453000662072616E67652E005920766563746F20
+:1045400072206C656E6774683A00496E76616C69BA
+:10455000642062656420636F7272656374696F6E54
+:10456000206D61747269782E204C656E67746820C6
+:104570006F6620746865205820766563746F7220BA
+:104580006F7574206F662072616E67652E0058200B
+:10459000766563746F72206C656E6774683A005557
+:1045A0006E646566696E65642062656420636F721F
+:1045B00072656374696F6E206D61747269782E0024
+:1045C00000004041FFFFBF4000005C43FFFFBF40D1
+:1045D00000005C43000046430000404100004643A9
+:1045E00000004041FFFFBF400000E442FFFFBF402A
+:1045F00000005743FFFFBF40000057430000CC427C
+:104600000000E4420000CC42000040410000CC42E7
+:1046100000004041000046430000E44200004643E1
+:1046200000005743000046435A00205A3A00590000
+:1046300020593A00580020583A0024F4D43050C38E
+:104640008E20C2A24017828B7011127A910D816C5C
+:10465000D90AA861E108C7586607615143061E4B95
+:104660005D05C145A7041A411104093D980371393C
+:1046700031034036DB0265339102D4305402802E80
+:104680001D02632CEE01752AC501B028A001102778
+:1046900081018F2564012B244B01E0223401AC21E0
+:1046A0001F018D200D01801FFC00841EED00971D51
+:1046B000DF00B81CD200E61BC600201BBC00641A39
+:1046C000B200B219A8000A19A0006A189900D117FF
+:1046D000910040178B00B516840031167E00B3158B
+:1046E00079003A157300C7146F0058146A00EE136E
+:1046F00066008813630025135E00C7125B006C120E
+:10470000570015125400C111510070114F002111B2
+:104710004B00D61049008D1047004610440002108F
+:104720004200C00F4000800F3E00420F3C00060FC9
+:104730003B00CB0E3800930E37005C0E3500270E81
+:104740003400F30D3200C10D3100900D3000600DCA
+:104750002E00320D2D00050D2C00D90C2B00AE0CB7
+:104760002900850C29005C0C2700350C27000E0C55
+:104770002600E80B2400C40B2400A00B23007D0BB3
+:1047800023005A0B2100390B2100180B2000F80AD6
+:104790001F00D90A1E00BB0A1E009D0A1D00800AC8
+:1047A0001D00630A1C00470A1B002C0A1B00110A8B
+:1047B0001A00F7091A00DD091900C4091900AB092C
+:1047C0001900920917007B091800630917004C09AA
+:1047D000160036091600200916000A091500F5080A
+:1047E0001500E0081400CC081400B8081400A40850
+:1047F0001400900813007D0812006B08130058087D
+:104800001200460812003408110023081100120893
+:10481000110001081100F0071000E0071000D00798
+:104820001000C0071000B0070F00A107100091078B
+:104830000E0083070F0074070F0065070E0057076F
+:104840000E0049070E003B070D002E070E00200743
+:104850000D0013070D0006070D00F9060C00ED060C
+:104860000D00E0060C00D4060C00C8060C00BC06C7
+:104870000C00B0060C00A4060B0099060C008D0677
+:104880000B0082060B0077060B006C060B0061061E
+:104890000A0057060B004C060A0042060A003806BA
+:1048A0000A002E060A0024060A001A060A0010064C
+:1048B000090007060A00FD050900F4050900EB05DB
+:1048C0000900E2050900D9050900D0050900C7055E
+:1048D0000900BE050900B5050800AD050800A505DD
+:1048E00009009C050800940508008C050800840553
+:1048F00008007C050800740508006C0507006505C4
+:1049000008005D050700560508004E05070047052D
+:1049100007004005080038050700310507002A0593
+:104920000700230507001C050600160507000F05F4
+:1049300007000805060002050700FB040600F50451
+:104940000700EE040600E8040600E2040700DB04AA
+:104950000600D5040600CF040600C9040600C304FF
+:104960000600BD040600B7040600B1040500AC044F
+:104970000600A6040600A00405009B04060095049A
+:104980000500900406008A040500850405008004E3
+:1049900006007A04050075040500700405006B0428
+:1049A000050066040500610405005C040500570469
+:1049B0000500520405004D040500480405004304A9
+:1049C00005003E0404003A040500350405003004E7
+:1049D00004002C04050027040400230405001E0421
+:1049E00004001A04040016040500110404000D0458
+:1049F0000400090405000404040000040400FC038E
+:104A00000400F8030400F4030400F0030400EC03C2
+:104A10000400E8030400E4030400E0030400DC03F2
+:104A20000400D8030400D4030400D0030400CC0322
+:104A30000400C8030300C503030024F404D9201BA9
+:104A4000C40C5C0E9804C4095F0265077101F4058B
+:104A5000F900FB04B30048048700C1036900580350
+:104A6000550003034500BE023A00840231005302A0
+:104A70002A002902250004022000E4011C00C801CC
+:104A80001900AF011700980114008401130071018F
+:104A900010006101100051010E0043010D003601AC
+:104AA0000B002B010B0020010B00150109000C016C
+:104AB000090003010800FB000800F3000800EB00F8
+:104AC0000700E4000600DE000600D8000600D20061
+:104AD0000600CC000500C7000500C2000500BD00AF
+:104AE0000400B9000400B5000400B1000400AD00EA
+:104AF0000400A9000400A5000300A20003009F0019
+:104B000004009B000300980003009500020093003E
+:104B10000300900003008D0002008B00030088005A
+:104B200002008600020084000300810002007F0072
+:104B300002007D0002007B00020079000200770085
+:104B40000100760002007400020072000100710092
+:104B500002006F0002006D0001006C0002006A009C
+:104B600001006900020067000100660001006500A5
+:104B700001006400020062000100610001006000A9
+:104B800001005F0002005D0001005C0001005B00AD
+:104B900001005A00010059000100580001005700AF
+:104BA00001005600010055000100540001005300AF
+:104BB00000005300010052000100510001005000AC
+:104BC00001004F0001004E0000004E0001004D00AA
+:104BD00001004C0001004B0000004B0001004A00A6
+:104BE00001004900010048000000480001004700A2
+:104BF000010046000000460001004500000045009D
+:104C00000100440001004300000043000100420095
+:104C1000000042000100410000004100010040008E
+:104C200001003F0000003F0001003E0000003E0088
+:104C300001003D0000003D0001003C0000003C0080
+:104C400000003C0001003B0000003B0001003A0076
+:104C500000003A000100390000003900010038006E
+:104C60000000380000003800010037000000370065
+:104C7000010036000000360000003600010035005B
+:104C80000000350000003500010034000000340051
+:104C90000000340001003300000033000000330046
+:104CA000010032000000320000003200010031003B
+:104CB0000000310000003100010030000000300031
+:104CC0000000300001002F0000002F0000002F0026
+:104CD00000002F0001002E0000002E0000002E001A
+:104CE00001002D0000002D0000002D0000002D000F
+:104CF00001002C0000002C0000002C0000002C0003
+:104D000001002B0000002B0000002B0000002B00F6
+:104D100001002A0000002A0000002A0000002A00EA
+:104D200001002900000029000000290000002900DE
+:104D300000002900010028000000280000002800D1
+:104D400000002800000028000100270000002700C4
+:104D500000002700000027000000270001002600B7
+:104D600000002600000026000000260000002600AB
+:104D7000010025000000250000002500000025009E
+:104D80000000250000002500010024000000240090
+:104D90000000240000002400000024000100230083
+:104DA0000000230000002300000023000000230077
+:104DB0000000230000002300010022000000220068
+:104DC000000022000000220000002200000022005B
+:104DD000010021000000210000002100000021004E
+:104DE000000021000000210000002100010020003F
+:104DF0000000200000002000000020000000200033
+:104E000000002000000020000000200001001F0022
+:104E100000001F0000001F0000001F0000001F0016
+:104E200000001F0000001F0001001E0000001E0007
+:104E300000001E0000001E0000004572723A204D66
+:104E4000494E54454D50204245440054656D7065AF
+:104E5000726174757265206865617465642062654D
+:104E600064207377697463686564206F66662E20BA
+:104E70004D494E54454D502074726967676572659F
+:104E8000642021004572723A204D415854454D50DE
+:104E9000204245440054656D706572617475726599
+:104EA0002068656174656420626564207377697445
+:104EB00063686564206F66662E204D415854454DE9
+:104EC00050207472696767657265642021004572BD
+:104ED000723A204D494E54454D50003A2045787461
+:104EE0007275646572207377697463686564206F96
+:104EF00066662E204D494E54454D502074726967A8
+:104F000067657265642021004572723A204D4158F0
+:104F100054454D50003A204578747275646572208E
+:104F20007377697463686564206F66662E204D41EF
+:104F30005854454D502074726967676572656420E6
+:104F4000210020484F54454E4420544845524D417D
+:104F50004C2052554E41574159002048454154423A
+:104F6000454420544845524D414C2052554E4157DE
+:104F7000415900544845524D414C2052554E4157DD
+:104F800041590042454420544845524D414C20521D
+:104F9000554E415741590020544845524D414C20EF
+:104FA00052554E41574159202820505245484541BD
+:104FB0005420484F54454E44290020544845524DF2
+:104FC000414C2052554E41574159202820505245BE
+:104FD00048454154204845415442454429005052D7
+:104FE0004548454154204552524F520042454420C5
+:104FF00050524548454154204552524F5200457247
+:10500000723A205052494E542046414E2045525249
+:105010004F52004552524F523A205072696E7420DE
+:1050200066616E207370656564206973206C6F77AC
+:105030006572207468656E20657870656374656458
+:10504000004572723A20455854522E2046414E2057
+:105050004552524F52004552524F523A20457874B1
+:1050600072756465722066616E2073706565642078
+:105070006973206C6F776572207468656E2065783F
+:1050800070656374656400202D20496E76616C69DB
+:1050900064206578747275646572206E756D6265E2
+:1050A00072202100504944204175746F74756E65FB
+:1050B0002066696E69736865642120507574207478
+:1050C0006865206C617374204B702C204B692061E3
+:1050D0006E64204B6420636F6E7374616E74732012
+:1050E00066726F6D2061626F766520696E746F20E5
+:1050F000436F6E66696775726174696F6E2E6800C2
+:10510000504944204175746F74756E6520666169FD
+:105110006C6564212074696D656F75740020403A78
+:10512000006F6B20543A006F6B20423A00504944A4
+:10513000204175746F74756E65206661696C656475
+:10514000212054656D706572617475726520746F8D
+:105150006F206869676800204B643A2000204B6923
+:105160003A2000204B703A200020436C6173736931
+:10517000632050494420002054753A2000204B758C
+:105180003A2000206D61783A2000206D696E3A2047
+:105190000020643A200020626961733A20001013F5
+:1051A0007D002015780060177300C0196E00401C48
+:1051B0006900E01E640080215F0040245A00F02650
+:1051C000550090295000202C4B00802E4600C03006
+:1051D0004100D0323C00B034370050363200C03786
+:1051E0002D0000392800103A2300F03A1E00B03B91
+:1051F0001900503C1400D03C0F00303D0A00803DA7
+:105200000500C03D0000F03DFBFF103EF6FF303EC4
+:10521000F1FF403EECFF503EE7FF603EE2FF703E94
+:10522000DDFF703ED8FF1000C90210012C014001C3
+:10523000220170011801B0010E01F00104015002B9
+:10524000FA00B002F0003003E600D003DC00900466
+:10525000D2007005C800A006BE000008B400B00966
+:10526000AA00D00BA000600E960060118C00001503
+:10527000820020197800C01D6E00A0226400B027B3
+:105280005A00902C500000314600E0343C001038A9
+:105290003200903A2800603C1E00A03D1400803E81
+:1052A0000A00203F000070012C0190012701B0018D
+:1052B0002201C0011D01F00118011002130130028A
+:1052C0000E016002090190020401C002FF00000308
+:1052D000FA004003F5008003F000D003EB00200447
+:1052E000E6007004E100E004DC004005D700C005E2
+:1052F000D2004006CD00D006C8008007C3003008A9
+:10530000BE00F008B900C009B400B00AAF00B00B8D
+:10531000AA00D00CA500000EA000500F9B00C010EA
+:1053200096005012910000148C00C0158700B01731
+:105330008200B0197D00D01B7800001E7300402051
+:105340006E0090226900F024640040275F009029DD
+:105350005A00E02B5500102E500020304B00103228
+:105360004600E033410090353C001037370070387C
+:105370003200A0392D00B03A2800A03B2300603C49
+:105380001E00103D1900903D1400103E0F00703EAD
+:105390000A00C03E0500003F0000544D4320445227
+:1053A00049564552204F56455254454D50200043D2
+:1053B0006F6E74696E7565207769746820616E6FB1
+:1053C0007468657220626F7764656E3F0053746124
+:1053D00074653A2000473736004D3435205A004D69
+:1053E0003435004738300020003E003E0020003EAB
+:1053F000003E003E003E0020003E003E0020000037
+:10540000002D2D2D2D2D2D2D2D2D2D2D2D2D2D2DF9
+:105410002D2D2D2D2D004E2F41004E2F41006D6D55
+:1054200000004D373031004D37303200496E766123
+:105430006C6964205049442063616C2E207265734E
+:10544000756C74732E204E6F742073746F72656464
+:1054500020746F20454550524F4D2E004D35303051
+:10546000004731205A313520463135303000473938
+:1054700031004731205835302059313930204530FE
+:1054800020463730303000473930004D3730320059
+:105490004D3730322043004D3730322055004D37E4
+:1054A0003032004731205A31352046313530300016
+:1054B00047393100473120583530205931393020B3
+:1054C0004530204637303030004D383300473930D2
+:1054D000004D3834004D313034205330004D3834D5
+:1054E000004731205831302059313830204634308F
+:1054F0003030004731205A31302046313330302EA1
+:10550000303030004D313430205330004D313034A4
+:10551000205330004D31303700473120452D302E9B
+:1055200030373530302046323130302E3030303068
+:105530003000473120583530205935352045332E3D
+:105540003632373733004731205832303020593522
+:10555000352045302E343933383600473120583223
+:105560003030205937352045332E36323737330027
+:10557000473120583530205937352045302E3439C1
+:1055800033383600473120583530205939352045D9
+:10559000332E3632373733004731205832303020FF
+:1055A0005939352045302E343933383600473120CB
+:1055B0005832303020593131352045332E3632378C
+:1055C00037330047312058353020593131352045A7
+:1055D000302E343933383600473120583530205991
+:1055E0003133352045332E363237373300473120BB
+:1055F0005832303020593133352045302E3636314F
+:105600003734004731205832303020593135352079
+:1056100045322E363237373300473120583130305B
+:105620002059313535204532004731205837352053
+:10563000593135352045322E35004731204631303D
+:105640003830004731205835302059313535004742
+:1056500031204634303030004D3230342053313038
+:105660003030004731205A302E3135302046373225
+:1056700030302E30303000473120452D312E35303E
+:105680003030302046323130302E30303030300043
+:105690004D38330047393000473231004739322026
+:1056A00045302E3000473120583130302E302045E3
+:1056B00031322E352046313030302E300047312007
+:1056C0005836302E302045392E302046313030309B
+:1056D0002E30004739322045302E30004732380016
+:1056E000473837004D3130392053323130004D3199
+:1056F000393020533535004D3134302053353500A5
+:105700004D3130342053323130004D313037004785
+:105710003930004731204531004D383200473120C3
+:105720004531004D3833004D31303620532564006B
+:105730004D32323020532564003A200020202020B2
+:105740002020202020202020202020202020200079
+:10575000203A20002020202020202020202020204F
+:105760002020202020202020002020202020202059
+:10577000202020202020002573002020002D2D3AFD
+:105780002D2D002000200020004C0020200020466D
+:10579000002D2D2D003E555342005344002D2D0069
+:1057A0002520202020200020200020200001200093
+:1057B0002020202D2D2D200020205A002020000107
+:1057C00020004D36303000464C4558202D202032E8
+:1057D00033302F35300050502020202D20203235FE
+:1057E000342F3130300048495053202D20203232A0
+:1057F000302F3130300041425320202D20203235CF
+:10580000352F3130300050455420202D20203234A7
+:10581000302F393000504C4120202D20203231359E
+:105820002F3630006661726D20202D2020323530F9
+:105830002F3430004D3234004D32332025730005B3
+:105840002E2E00580059005A004578747275646510
+:1058500072004739390044697361626C6520666182
+:10586000726D206D6F64653F0044697361626C65A1
+:10587000206661726D206D6F6465004661726D20F7
+:105880006E756D626572004D3834005072696E74C9
+:105890002066616E3A0045787472756465722066A0
+:1058A000616E3A0041786973206C656E6774682098
+:1058B000646966666572656E63653A004D6561731D
+:1058C000757265642061786973206C656E677468B1
+:1058D0003A0025632041584953205347313D256400
+:1058E0000A004D3834004731205A313500473238EC
+:1058F0002057005A30005A310059300059310058B1
+:105900003000583100456E642073746F70732064EA
+:10591000696167004D3434004732382057001B5B03
+:10592000303B314842656C74207374617475731B2D
+:105930005B313B3248582025641B5B323B3248596F
+:10594000202564001B5B313B3148416D6269656E07
+:10595000743A2020256425631B5B323B3148504953
+:105960004E44413A20202020256425630054656D73
+:105970007065726174757265730042656C74207332
+:105980007461747573002D2D2D2D2D2D2D2D2D2D24
+:105990002D2D00466C617368416972204950204189
+:1059A0006464723A002D2D2D2D2D2D2D2D2D2D2D94
+:1059B0002D004E6F762032392032303137002D2DB8
+:1059C0002D2D2D2D2D2D2D2D2D2D004533447636AD
+:1059D00066756C6C0045494E595F30346100315F2B
+:1059E00037356D6D5F4D4B33002D2D2D2D2D2D2D0C
+:1059F0002D2D2D2D2D0020332E312E312D524331C2
+:105A00002062313231004669726D776172653A0009
+:105A100025642E25642E25642E2564004661696C5C
+:105A2000207374617473004661726D206E756D62CF
+:105A3000657200007263006265746100616C706879
+:105A40006100646576005052555341334446570017
+:105A5000332E312E312D5243310000000A0B020942
+:105A60000C0D0E08070304010000000000000000F8
+:105A70000000000000000000000000000000000026
+:105A800000000000000012111000000000000000E3
+:105A90000000000000000000000000000000000006
+:105AA00000000000000000000000000000000000F6
+:105AB0000102102020080810204010204080020120
+:105AC0000201080402010102040810204080804005
+:105AD0002010080402018004020180402010080404
+:105AE00002010804020101020408102040800102A2
+:105AF0000408102040801008040880102040044052
+:105B000080102040048005050505070508080808E1
+:105B1000020202020A0A0808040404040101010145
+:105B20000101010103030303030303030407070740
+:105B30000C0C0C0C0C0C0C0C0202020206060606E5
+:105B4000060606060B0B0B0B0B0B0B0B07070A0AC3
+:105B50000A0A0A0A050505040404080800002000D2
+:105B60002300260029002C002F0032000001000035
+:105B700003010601090100002200250028002B0076
+:105B80002E003100340002010000050108010B0164
+:105B900000002100240027002A002D0030003300DF
+:105BA00001010000040107010A01024E414E494E65
+:105BB000495459494E46CDCCCC3D0AD7233C17B762
+:105BC000D13877CC2B329595E6241FB14F0A0000CF
+:105BD00020410000C84200401C4620BCBE4CCA1BED
+:105BE0000E5AAEC59D7400407A10F35A00A0724E52
+:105BF00018090010A5D4E80000E87648170000E472
+:105C00000B54020000CA9A3B000000E1F5050000B9
+:105C100080969800000040420F000000A08601001E
+:105C20000000102700000000E803000000006400EE
+:105C3000000000000A000000000001000000000059
+:105C40002C76D888DC674F0823DFC1DFAE59E1B17D
+:105C5000B796E5E3E453C63AE651997696E8E6C28C
+:105C60008426EB898C9B62ED407C6FFCEFBC9C9F93
+:105C700040F2BAA56FA5F490055A2AF75C936B6CB5
+:105C8000F9676DC11BFCE0E40D47FEF520E6B500A9
+:105C9000D0ED902E0300943577050080841E080017
+:105CA00000204E0A000000C80C333333330F986EC7
+:105CB00012831141EF8D2114893BE65516CFFEE684
+:105CC000DB18D1844B381BF77C1D901DA4BBE4244A
+:105CD000203284725E228100C9F124ECA1E53D27C7
+:105CE00091A336CAD5FBD901E501C2A311241FBE79
+:105CF000CFEFD1E2DEBFCDBF00E00CBF19E0A0E0E6
+:105D0000B2E0E6ECFAE903E00BBF02C007900D92A7
+:105D1000AE37B107D9F72BE1AEE7B9E001C01D926C
+:105D2000AC3FB207E1F71CE5CAEEDCE500E006C0D7
+:105D300022970109FE010BBF0F9406C3C03ED10795
+:105D400080E00807A9F70F94DEBC0D9451CD0C94A8
+:105D50000000CF92DF92EF92FF920F931F93CF93A9
+:105D6000DF938C01D42EC62FD72FD60EDC1671F1FF
+:105D7000F801E080F180C990C7010F9444CAC816A9
+:105D8000F1F06C2DC7010F9474CAC7010F9444CA77
+:105D90008C15A9F0E2EBF7E08491882341F0909113
+:105DA000C00095FFFCCF8093C6003196F5CF80915F
+:105DB000C00085FFFCCF8AE08093C60007C0F801D1
+:105DC00080819181019691838083D0CFDF91CF91A3
+:105DD0001F910F91FF90EF90DF90CF900895EF9279
+:105DE000FF920F931F93CF93DF931F92CDB7DEB730
+:105DF0008C017B01460FF8018081918149830F94CA
+:105E000044CAF70181937F01F80180819181019655
+:105E10009183808349814E11EECF0F90DF91CF9116
+:105E20001F910F91FF90EF900895FF920F931F9392
+:105E3000CF93DF93CDB7DEB72C970FB6F894DEBFC4
+:105E40000FBECDBF8C01F62E80E390E3A0E3B0E05F
+:105E50008D839E83AF83B8871C870B8744E0BE0188
+:105E60006B5F7F4FCE010B9674DF40E160E479E118
+:105E7000CE010B966EDF40E160E579E1CE010B9635
+:105E800068DF40E160E379E1CE010B9662DF44E038
+:105E900068E279E1CE010B965CDF44E064E279E1EF
+:105EA000CE010B9656DF44E06CE279E1CE010B9611
+:105EB00050DF44E060E179E1CE010B964ADF44E037
+:105EC00060E679E1CE010B9644DF44E064E179E1DC
+:105ED000CE010B963EDF44E068E179E1CE010B96FE
+:105EE00038DF44E06CE179E1CE010B9632DF44E02B
+:105EF00060E279E1CE010B962CDF4CE064ED7AE0B4
+:105F0000CE010B9626DF44E06DEC7AE0CE010B96D5
+:105F100020DF44E06DEA72E0CE010B961ADF44E028
+:105F200069EA72E0CE010B9614DF44E065EA72E0A4
+:105F3000CE010B960EDF44E06DE972E0CE010B96C8
+:105F400008DF44E069E972E0CE010B9602DF44E02D
+:105F500065E972E0CE010B96FCDE80E290E09A8764
+:105F6000898742E0BE01675F7F4FCE010B96F1DE6D
+:105F700041E069EC7AE0CE010B96EBDE44E064E2AE
+:105F800072E0CE010B96E5DE44E06CE172E0CE01FA
+:105F90000B96DFDE44E064EC7AE0CE010B96D9DEAE
+:105FA00044E060EC7AE0CE010B96D3DE44E068E199
+:105FB00072E0CE010B96CDDE41E060EF7AE0CE01DB
+:105FC0000B96C7DE44E064E472E0CE010B96C1DEBE
+:105FD00089E08F1560F444E06FE573E1CE010B9624
+:105FE000B8DE44E06BE573E1CE010B96B2DE46E528
+:105FF00051E360E070E049835A836B837C831C87A4
+:106000000B8744E0BE016F5F7F4FCE010B96A1DE90
+:10601000EFE3F0E18491882341F09091C00095FF77
+:10602000FCCF8093C6003196F5CFE2EAF7E0849189
+:10603000882341F09091C00095FFFCCF8093C6006B
+:106040003196F5CF8091C00085FFFCCF8AE0809328
+:10605000C6002C960FB6F894DEBF0FBECDBFDF9101
+:10606000CF911F910F91FF9008951F93CF93DF93CE
+:10607000182FCFE3D0E1FE018491882341F0909165
+:10608000C00095FFFCCF8093C6003196F5CFE2E9C2
+:10609000F7E08491882341F09091C00095FFFCCFF8
+:1060A0008093C6003196F5CF8091C00085FFFCCF6C
+:1060B0008AE08093C600FE018491EFE3F0E188233B
+:1060C00049F09091C00095FFFCCF8093C6003196B7
+:1060D0008491F5CF40914019509141196091421936
+:1060E000709143198AE897E00E944848409144190A
+:1060F00050914519609146197091471987E897E0CA
+:106100000E944848409148195091491960914A1994
+:1061100070914B1984E897E00E94484840914C19CF
+:1061200050914D1960914E1970914F1981E897E087
+:106130000E9448488091C00085FFFCCF8AE0809390
+:10614000C600FE018491EFE3F0E1882349F09091CD
+:10615000C00095FFFCCF8093C60031968491F5CFA7
+:10616000E7E6F7E08491882341F09091C00095FF25
+:10617000FCCF8093C6003196F5CF8091C00085FF9B
+:10618000FCCF8AE08093C600FE018491EFE3F0E14A
+:10619000882349F09091C00095FFFCCF8093C60002
+:1061A00031968491F5CF40915019509151196091D9
+:1061B0005219709153198EE597E00E94484840911A
+:1061C00054195091551960915619709157198BE5D2
+:1061D00097E00E9448484091581950915919609190
+:1061E0005A1970915B1988E597E00E9448484091E0
+:1061F0005C1950915D1960915E1970915F1985E588
+:1062000097E00E9448488091C00085FFFCCF8AE05B
+:106210008093C600FE018491EFE3F0E1882349F00A
+:106220009091C00095FFFCCF8093C6003196849179
+:10623000F5CFE7E3F7E08491882341F09091C00027
+:1062400095FFFCCF8093C6003196F5CF8091C000BA
+:1062500085FFFCCF8AE08093C600FE018491EFE3C6
+:10626000F0E1882349F09091C00095FFFCCF809326
+:10627000C60031968491F5CF409130195091311973
+:1062800060913219709133198EE297E00E9459485B
+:106290004091341950913519609136197091371920
+:1062A0008BE297E00E945948409138195091391972
+:1062B00060913A1970913B1988E297E00E94594821
+:1062C00040913C1950913D1960913E1970913F19D0
+:1062D00085E297E00E9459488091C00085FFFCCF7D
+:1062E0008AE08093C600FE018491EFE3F0E1882309
+:1062F00049F09091C00095FFFCCF8093C600319685
+:106300008491F5CFE0EFF6E08491882341F09091FD
+:10631000C00095FFFCCF8093C6003196F5CF8091E9
+:10632000C00085FFFCCF8AE08093C600FE01849107
+:10633000EFE3F0E1882349F09091C00095FFFCCF96
+:106340008093C60031968491F5CF409128195091E1
+:10635000291960912A1970912B1987EE96E00E94F5
+:10636000484840912419509125196091261970913F
+:10637000271984EE96E00E9448488091C00085FF6E
+:10638000FCCF8AE08093C600FE018491EFE3F0E148
+:10639000882349F09091C00095FFFCCF8093C60000
+:1063A00031968491F5CFE1E3F6E08491882341F0C2
+:1063B0009091C00095FFFCCF8093C6003196F5CF39
+:1063C0008091C00085FFFCCF8AE08093C600FE016B
+:1063D0008491EFE3F0E1882349F09091C00095FFAC
+:1063E000FCCF8093C60031968491F5CF40912C1953
+:1063F00050912D1960912E1970912F1988E296E015
+:106400000E94484840911019509111196091121939
+:106410007091131985E296E00E94484840916019F6
+:1064200050916119609162197091631982E296E04E
+:106430000E945948409114195091151960911619EC
+:10644000709117198FE196E00E9448484091181901
+:106450005091191960911A1970911B198CE196E0ED
+:106460000E94484840911C1950911D1960911E19B5
+:1064700070911F1989E196E00E94484840912019C7
+:1064800050912119609122197091231986E196E0AB
+:106490000E9448488091C00085FFFCCF8AE080932D
+:1064A000C600FE018491EFE3F0E1882349F090916A
+:1064B000C00095FFFCCF8093C60031968491F5CF44
+:1064C000E4E0F6E08491882341F09091C00095FFCC
+:1064D000FCCF8093C6003196F5CF8091C00085FF38
+:1064E000FCCF8AE08093C600FE018491EFE3F0E1E7
+:1064F000882349F09091C00095FFFCCF8093C6009F
+:1065000031968491F5CF4091D40A5091D50A60918B
+:10651000D60A7091D70A8BEF95E00E9448484091C7
+:10652000D80A5091D90A6091DA0A7091DB0A88EF93
+:1065300095E00E9448484091DC0A5091DD0A609144
+:10654000DE0A7091DF0A85EF95E00E94484880914D
+:10655000C00085FFFCCF8AE08093C600FE018491D5
+:10656000EFE3F0E1882349F09091C00095FFFCCF64
+:106570008093C60031968491F5CFE7EEF5E08491E3
+:10658000882341F09091C00095FFFCCF8093C60016
+:106590003196F5CF8091C00085FFFCCF8AE08093D3
+:1065A000C600FE018491EFE3F0E1882349F0909169
+:1065B000C00095FFFCCF8093C60031968491F5CF43
+:1065C0004091AD025091AE026091AF027091B00265
+:1065D0008DED95E00E9448486091A9027091AA0251
+:1065E0008091AB029091AC020F948137AB01BC015A
+:1065F0008AED95E00E9448486091A5027091A6023C
+:106600008091A7029091A8020F948D37AB01BC0135
+:1066100087ED95E00E9448488091C00085FFFCCF3F
+:106620008AE08093C600FE018491EFE3F0E18823C5
+:1066300049F09091C00095FFFCCF8093C600319641
+:106640008491F5CFE1ECF5E08491882341F09091BD
+:10665000C00095FFFCCF8093C6003196F5CF8091A6
+:10666000C00085FFFCCF8AE08093C600FE018491C4
+:10667000EFE3F0E1882349F09091C00095FFFCCF53
+:106680008093C60031968491F5CF40919D02509140
+:106690009E0260919F027091A00287EB95E00E949C
+:1066A00048486091990270919A0280919B02909162
+:1066B0009C020F948137AB01BC0184EB95E00E94F2
+:1066C000484860919502709196028091970290914E
+:1066D00098020F948D37AB01BC0181EB95E00E94CD
+:1066E00048488091C00085FFFCCF8AE08093C600B7
+:1066F000FE018491EFE3F0E1882349F09091C0001E
+:1067000095FFFCCF8093C60031968491F5CFEDE7DD
+:10671000F5E08491882341F09091C00095FFFCCF73
+:106720008093C6003196F5CF8091C00085FFFCCFE5
+:106730008AE08093C600FE018491EFE3F0E18823B4
+:1067400049F09091C00095FFFCCF8093C600319630
+:106750008491F5CF40912402509125026091260248
+:106760007091270283E795E00E94484820E030E0DE
+:1067700040E752E460911C0270911D0280911E025C
+:1067800090911F020F949BC0AB01BC0180E795E084
+:106790000E9448484091C40A5091C50A6091C60AB7
+:1067A0007091C70A8DE695E00E9448488091C0002C
+:1067B00085FFFCCF8AE08093C600FE018491EFE361
+:1067C000F0E1882349F09091C00095FFFCCF8093C1
+:1067D000C60031968491F5CFE1E4F5E084918823F9
+:1067E00041F09091C00095FFFCCF8093C600319698
+:1067F000F5CF8091C00085FFFCCF8AE08093C60072
+:10680000FE018491EFE3F0E1882349F09091C0000C
+:1068100095FFFCCF8093C60031968491F5CF4091CF
+:10682000C00A5091C10A6091C20A7091C30A87E3FD
+:1068300095E00E94484820E030E040E752E4609153
+:1068400018027091190280911A0290911B020F9404
+:106850009BC0AB01BC0184E395E00E944848809155
+:10686000C00085FFFCCF8AE08093C600FE018491C2
+:10687000EFE3F0E1882349F09091C00095FFFCCF51
+:106880008093C60031968491F5CFEAEDF4E08491CF
+:10689000882341F09091C00095FFFCCF8093C60003
+:1068A0003196F5CF8091C00085FFFCCF8AE08093C0
+:1068B000C600FE018491EFE3F0E1882349F0909156
+:1068C000C00095FFFCCF8093C60031968491F5CF30
+:1068D0004091C90A50E060E070E080ED94E00E94D1
+:1068E00059488091C00085FFFCCF8AE08093C600A4
+:1068F000FE018491EFE3F0E1882349F09091C0001C
+:1069000095FFFCCF8093C60031968491F5CF80919E
+:10691000F00A8823A1F1EDEBF4E08491882341F0A3
+:106920009091C00095FFFCCF8093C6003196F5CFC3
+:106930008091C00085FFFCCF8AE08093C600FE01F5
+:106940008491EFE3F0E1882349F09091C00095FF36
+:10695000FCCF8093C60031968491F5CF40914402DC
+:1069600050914502609146027091470283EB94E09A
+:106970000E9448488091C00085FFFCCF11C0E7E924
+:10698000F4E08491882341F09091C00095FFFCCF02
+:106990008093C6003196F5CF8091C00085FFFCCF73
+:1069A0008AE08093C6001A3008F43EC0FE01C4910C
+:1069B000EFE3F0E1CC2349F08091C00085FFFCCFEC
+:1069C000C093C6003196C491F5CFEEE7F4E0849110
+:1069D000882341F09091C00095FFFCCF8093C600C2
+:1069E0003196F5CF8091C00085FFFCCF8AE080937F
+:1069F000C60040915F1350916013609161137091D4
+:106A0000621384E794E00E94484840915B135091E0
+:106A10005C1360915D1370915E138AE694E0DF91E0
+:106A2000CF911F910C944848DF91CF911F91089509
+:106A3000AF92BF92CF92DF92EF92FF920F931F938C
+:106A4000CF93DF93CDB7DEB7E0970FB6F894DEBFF4
+:106A50000FBECDBF80E1E3EEF2E0DE019196019042
+:106A60000D928A95E1F780E1E3EFF2E0DE015196C5
+:106A700001900D928A95E1F780E1E3E0F3E0DE0119
+:106A8000119601900D928A95E1F76E0181E2C80E90
+:106A9000D11C80E4E82E89E1F82E8E010F5E1F4F95
+:106AA00060E579E1AE014F5F5F4F90E3A92E99E178
+:106AB000B92E20E030E0F60181919191A191B19140
+:106AC0006F01F70181939193A193B1937F01F80135
+:106AD00081919191A191B1918F01FB01819391934A
+:106AE000A193B193BF01FA0181919191A191B191CB
+:106AF000AF01F50181939193A193B1935F012F5F52
+:106B00003F4F24303105B9F60F94E31380E090E451
+:106B1000ACE9B4E48093281990932919A0932A1919
+:106B2000B0932B198093241990932519A0932619BB
+:106B3000B093271910922C1910922D1910922E191A
+:106B400010922F1980E29EE4A0E0B0E080936019DB
+:106B500090936119A0936219B09363191092101960
+:106B600010921119109212191092131980E090E0EE
+:106B7000A0E7B1E48093141990931519A093161906
+:106B8000B09317198093181990931919A0931A1993
+:106B9000B0931B198DEC9CECACECBEE380931C19FC
+:106BA00090931D19A0931E19B0931F1980E090E0D7
+:106BB000A0E2B0E48093201990932119A0932219A8
+:106BC000B09323191092DC0A1092DD0A1092DE0AAB
+:106BD0001092DF0A1092D80A1092D90A1092DA0A9B
+:106BE0001092DB0A1092D40A1092D50A1092D60A9B
+:106BF0001092D70A8DE39AE0A1E8B1E48093AD0248
+:106C00009093AE02A093AF02B093B0026DEC7CEC17
+:106C100084E99FE30F947B376093A9027093AA02E3
+:106C20008093AB029093AC0265E87BEE80E692E441
+:106C30000F9487376093A5027093A6028093A702F2
+:106C40009093A8020F94522680E090E0A0E8BFE362
+:106C50008093A1029093A202A093A302B093A402F6
+:106C60001092C90A80E090E0A0E4B0E4809324028E
+:106C700090932502A0932602B093270240E050E0B3
+:106C800064E372E440931C0250931D0260931E0261
+:106C900070931F021092C40A1092C50A1092C60A7D
+:106CA0001092C70A1092C00A1092C10A1092C20A2A
+:106CB0001092C30A40E050E060E071E44093180293
+:106CC0005093190260931A0270931B021092F00AFB
+:106CD0008093440290934502A0934602B0934702EA
+:106CE0000E94CC5EEFE3F0E18491882341F0909123
+:106CF000C00095FFFCCF8093C6003196F5CFEEE241
+:106D0000F4E08491882341F09091C00095FFFCCF7E
+:106D10008093C6003196F5CF8091C00085FFFCCFEF
+:106D20008AE08093C600E0960FB6F894DEBF0FBEEF
+:106D3000CDBFDF91CF911F910F91FF90EF90DF902A
+:106D4000CF90BF90AF9008951F93CF93DF93CDB7AF
+:106D5000DEB72C970FB6F894DEBF0FBECDBF162F4F
+:106D60009C878B8786E591E3A0E0B0E089839A83D6
+:106D7000AB83BC8344E0BE016B5F7F4FCE010B96BB
+:106D80002ED843E050E0BE016B5F7F4FCE010196ED
+:106D90000F94A8C6892B09F0FFC040E160E479E1B7
+:106DA000CE010B961CD840E160E579E1CE010B964F
+:106DB00016D840E160E379E1CE010B9610D80F942C
+:106DC000E31344E068E279E1CE010B9608D844E091
+:106DD00064E279E1CE010B9602D844E06CE279E1FD
+:106DE000CE010B960E94EF2E44E060E179E1CE01E6
+:106DF0000B960E94EF2E44E060E679E1CE010B96FF
+:106E00000E94EF2E44E064E179E1CE010B960E94EE
+:106E1000EF2E44E068E179E1CE010B960E94EF2E5F
+:106E200044E06CE179E1CE010B960E94EF2E44E044
+:106E300060E279E1CE010B960E94EF2E4CE064ED0A
+:106E40007AE0CE010B960E94EF2E44E06DEC7AE0E2
+:106E5000CE010B960E94EF2E44E06DEA72E0CE0167
+:106E60000B960E94EF2E44E069EA72E0CE010B9689
+:106E70000E94EF2E44E065EA72E0CE010B960E947C
+:106E8000EF2E44E06DE972E0CE010B960E94EF2EEA
+:106E900044E069E972E0CE010B960E94EF2E44E0D7
+:106EA00065E972E0CE010B960E94EF2E42E0BE0132
+:106EB000675F7F4FCE010B960E94EF2E41E069EC99
+:106EC0007AE0CE010B960E94EF2E44E064E272E07D
+:106ED000CE010B960E94EF2E44E06CE172E0CE01F1
+:106EE0000B960E94EF2E44E064EC7AE0CE010B9604
+:106EF0000E94EF2E44E060EC7AE0CE010B960E94F7
+:106F0000EF2E44E068E172E0CE010B960E94EF2E76
+:106F100041E060EF7AE0CE010B960E94EF2E44E054
+:106F200064E472E0CE010B960E94EF2E1A3070F0EE
+:106F300044E06FE573E1CE010B960E94EF2E44E032
+:106F40006BE573E1CE010B960E94EF2E0E94CC5EA2
+:106F50000F945226EFE3F0E18491882341F0909161
+:106F6000C00095FFFCCF8093C6003196F5CFE0E5D9
+:106F7000F4E08491882341F09091C00095FFFCCF0C
+:106F80008093C6003196F5CF8091C00085FFFCCF7D
+:106F90008AE08093C60001C04BDD2C960FB6F894B2
+:106FA000DEBF0FBECDBFDF91CF911F910895682F37
+:106FB000772767FD70958091431090914410885B0E
+:106FC0009F4E0F948DC690933A108093391021E014
+:106FD000892B09F420E0822F089580913910909137
+:106FE0003A1060E070E001960D9436C3282F60914E
+:106FF000F61B7091F71B90E02A3018F0895A9F4FCA
+:1070000001C0C0960D94FBC6CF93C82F82958F7098
+:10701000EDDF8C2F8F70CF91E9CFCF93C82F892FC1
+:10702000F3DF8C2FCF91F0CF6F927F928F929F9250
+:10703000AF92BF92CF92DF92EF92FF920F931F9386
+:10704000CF93DF936B017C01EA01122F209709F4A3
+:1070500055C0123011F48E2DC9DFC601DEDF6091FC
+:10706000F61B7091F71B80E290E00F94FBC6702E28
+:107070007C1A8C2F870D09F438C01130D1F088F0BC
+:10708000123029F5460157018FEF881A980AA80A8D
+:10709000B80AEE24D7FCE094FE2CEBBEF601679014
+:1070A00013C0F60160808FEFC81AD80AE80AF80A00
+:1070B0000FC0460157018FEF881A980AA80AB80A2C
+:1070C000C6010F9444CA682E7501640101C0612C89
+:1070D0006091F61B7091F71B80E290E00F94FBC665
+:1070E000862D92DF219709F0C4CF6091F61B709135
+:1070F000F71B8AE090E00F94FBC6A8CFDF91CF91F9
+:107100001F910F91FF90EF90DF90CF90BF90AF90C5
+:107110009F908F907F906F900895CF93DF93FB01A6
+:1071200020E030E0DC01ED018D918823A1F14115D3
+:10713000510519F02417350774F58032A1F38A3010
+:1071400051F190ED980F9A3020F4682F6295607F8E
+:1071500008C09FE9980F9630A8F4682F6295607F69
+:107160006057CE0102967981A0EDA70FAA3018F4DE
+:10717000762F7A2B0CC0AFE9A70FA63018F47755FD
+:10718000762B05C088279927821B930B05C0719326
+:107190002F5F3F4FC7CFC901DF91CF9108958BE695
+:1071A00093E00F948EC7F894FFCFE0913910F091DF
+:1071B0003A108181882399F082E4F9DE882369F00E
+:1071C000F89428E088E190E00FB6F894A8958093B1
+:1071D00060000FBE20936000FFCF0C940000089564
+:1071E000F894C0E0D0E06FEFCE010F9474CA2196FE
+:1071F000C11580E2D807B9F728E088E190E00FB622
+:10720000F894A895809360000FBE20936000FFCF94
+:107210000F931F93CF93DF93CDB7DEB762970FB66F
+:10722000F894DEBF0FBECDBF81E4C1DE8823A9F094
+:107230008091391090913A10FC012181283741F456
+:1072400040E150E060E070E002960F949EC403C0FD
+:10725000C4DE0F9435BE8B0102C000E010E083E471
+:10726000A6DE882331F0B9DE0F9435BE262F872F96
+:1072700002C020E080E21F71422F582F4130F0E21F
+:107280005F0710F040E050E2CA01800F911F81308B
+:10729000904220F040E050E2401B510B88E5498BC2
+:1072A0005A8B85DE49895A898823D1F0809139101B
+:1072B00090913A1040E150E0BE016F5F7F4F019620
+:1072C0002CDFAC01009761F0FE013196CF01840FF5
+:1072D000951FD801E817F90719F021912D93FACFDE
+:1072E000B80180E090E000E120E09EDE62960FB6FB
+:1072F000F894DEBF0FBECDBFDF91CF911F910F91EC
+:107300000895AF92BF92CF92DF92EF92FF920F93C8
+:107310001F93CF93DF93CDB7DEB760970FB6F89486
+:10732000DEBF0FBECDBF81E442DE8823A9F080918D
+:10733000391090913A10FC012181283741F440E145
+:1073400050E060E070E002960F949EC403C045DEFA
+:107350000F9435BE8B0102C000E010E083E427DE0D
+:10736000882331F03ADE0F9435BE262F872F02C0D6
+:1073700020E080E21F71E22EF82EF1E0EF16F0E23D
+:10738000FF0618F0E12C90E2F92EC701800F911F43
+:107390008130904228F0E12C80E2F82EE01AF10AC8
+:1073A00088E505DE882361F18091391090913A10CB
+:1073B00040E150E0BE016F5F7F4F0196AEDE7C0181
+:1073C0000097F1F0CE0101965C01C12CD12CCE14B6
+:1073D000DF0461F0F50161915F01C601800F911F2B
+:1073E0000F9474CAFFEFCF1ADF0AF1CFC80115DE80
+:1073F0006091F61B7091F71B8AE090E00F94FBC63A
+:10740000B80180E090E000E121E0A7010DDE609688
+:107410000FB6F894DEBF0FBECDBFDF91CF911F91A5
+:107420000F91FF90EF90DF90CF90BF90AF900895B5
+:10743000CF92DF92EF92FF9280E5B9DD882309F4C5
+:107440004CC0CBDD0F9435BE6B017C018FEFC816AD
+:10745000D10411F008F041C086E4A9DD882379F059
+:10746000BCDD0F9435BE6115710511F460E004C0F8
+:107470006130710521F461E08C2D0F94DAB686E558
+:1074800096DD882399F0A9DD0F9435BE611571054D
+:1074900011F460E004C061307105F9F461E08C2DF5
+:1074A000FF90EF90DF90CF900D9413B78C2D0F9439
+:1074B00048B721E0892B09F420E01F922F93DF9237
+:1074C000CF928EE793E09F938F930F945AC70F90BC
+:1074D0000F900F900F900F900F90FF90EF90DF9014
+:1074E000CF900895089508954F925F926F927F9282
+:1074F0009F92AF92BF92CF92DF92EF92FF920F9343
+:107500001F93CF93DF9382E398E09F938F930F9421
+:107510006BC786EA9FE00F9444CAC82FC090691ACF
+:10752000D0906A1AE0906B1AF0906C1AC701B601FD
+:107530000E9482642B013C01E0913910F0913A10D5
+:1075400092810F900F909F3311F091114CC091E0F8
+:10755000C11101C090E01F929F9383E298E09F9336
+:107560008F930F946BC70F900F900F900F9000EBBD
+:107570001FE0C3E2D0E0912C80E090E023E0A22E57
+:1075800028E0B22EBC0180E090E00F9466BE20910E
+:1075900048193091491940914A1950914B190F944B
+:1075A000CDBD20E030E04AE754E40F949BC00F9437
+:1075B0003ABE7F936F93DF93CF93BF92AF920F94B6
+:1075C0006BC793940F900F900F900F900F900F90A8
+:1075D00086E0981609F441C0C8010F9451CA259657
+:1075E0000E5F1F4FCFCF913221F561E086EA9FE019
+:1075F0000F9474CA68E070E080EB9FE00F9482CA39
+:1076000068E170E082EB9FE00F9482CA60E370E073
+:1076100084EB9FE00F9482CA60E570E086EB9FE008
+:107620000F9482CA68E770E088EB9FE00F9482CAEB
+:1076300014C080E5BCDC882319F0CFDC6B017C0131
+:10764000C701B6010E9482642B013C018AE5AFDCD0
+:10765000882319F0C2DC2B013C0120E030E04AE72E
+:1076600054E4C301B2010F949BC00F9435BECB010B
+:1076700068EE73E00F948AC29F938F93C301B201A7
+:107680000F9435BE7F936F93C701B6010F9435BE3B
+:107690007F936F9383EE97E09F938F930F946BC7C5
+:1076A0008DB79EB708960FB6F8949EBF0FBE8DBFDC
+:1076B000DF91CF911F910F91FF90EF90DF90CF90CE
+:1076C000BF90AF909F907F906F905F904F90089584
+:1076D00066EE87EF9FE00D9456CA60E086E69FE075
+:1076E0000F9456CA60E085E69FE00F9456CA60E0AA
+:1076F00084E69FE00D9456CA6F927F928F929F927C
+:10770000AF92BF92CF92DF92EF92FF920F931F93AF
+:10771000CF93DF9382ED97E09F938F930F946BC786
+:1077200088E545DC0F900F90811107C089E53FDCAB
+:10773000882309F4AAC0C1E001C0C0E06C2E712CFE
+:10774000C3010E94574D8C2F0F944C3880E1E0EE1E
+:10775000FAE0ABEABAE001900D928A95E1F7660C87
+:10776000771C660C771CC3018555954F3C0180E062
+:1077700090E0A8E4B3E4F30180839183A283B38310
+:1077800020E030E040E752E46091580270915902E5
+:1077900080915A0290915B020F94CDBD4B015C0128
+:1077A000E090B30AF090B40A0091B50A1091B60ABD
+:1077B0002091AF0A3091B00A4091B10A5091B20ABB
+:1077C0006091AB0A7091AC0A8091AD0A9091AE0ABB
+:1077D000CCECDAE0DF93CF93E7EBCE2EEAE0DE2EBF
+:1077E0000F9458050F94071F80E1E0EEFAE0ABEA32
+:1077F000BAE001900D928A95E1F7F30110821182AF
+:107800001282138220E030E040E752E46091580297
+:107810007091590280915A0290915B020F94CDBDF4
+:107820004B015C01E090B30AF090B40A0091B50AF4
+:107830001091B60A2091AF0A3091B00A4091B10A76
+:107840005091B20A6091AB0A7091AC0A8091AD0A76
+:107850009091AE0ADF93CF930F9458050F94071FB2
+:107860000F945B382FEF2093B2029F938F938FEB8F
+:1078700097E09F938F930F946BC78DB79EB7089631
+:107880000FB6F8949EBF0FBE8DBFDF91CF911F91B1
+:107890000F91FF90EF90DF90CF90BF90AF909F90AF
+:1078A0008F907F906F900895E0913910F0913A1089
+:1078B00085818F3311F081112BC080913C131F9271
+:1078C0008F9380913D131F928F9380913F138F93DD
+:1078D00080913E138F93809141138F938091401339
+:1078E0008F93809142131F928F93809143131F9225
+:1078F0008F9387E893E09F938F930F945AC78DB728
+:107900009EB70E960FB6F8949EBF0FBE8DBF08951A
+:10791000813229F50E946BFF80913C131F928F9357
+:1079200080913D131F928F9380913F138F9380918D
+:107930003E138F93809141138F93809140138F93C7
+:1079400089E993E09F938F930F945AC78DB79EB7A1
+:107950000A960FB6F8949EBF0FBE8DBF089582E5BC
+:1079600026DB81113ADB88E522DB882339F035DB21
+:107970000F9435BE709341136093401389E517DB74
+:10798000882339F02ADB0F9435BE70933F13609340
+:107990003E138CE40CDB882329F01FDB0F9435BEEB
+:1079A000609368020895CF93DF93EC0160E08E81CD
+:1079B0000F9413B781E090E00F9455B561E08E818C
+:1079C0000F9413B781E090E00F9455B560E08E817D
+:1079D0000F9413B784E690E0DF91CF910D9455B5E5
+:1079E000CF92DF92EF92FF920F931F93CF93DF938B
+:1079F0007C01C0E0D0E0C62ED12C87010C0F1D1FEA
+:107A000061E0F80187810F94DAB6B6010C2E02C04E
+:107A1000759567950A94E2F76170F80187810F9474
+:107A200013B72196C430D10541F7C701DF91CF913B
+:107A30001F910F91FF90EF90DF90CF90B4CFCF9236
+:107A4000DF92EF92FF920F931F93CF93DF937C010E
+:107A5000C0E0D0E0C62ED12C87010C0F1D1F61E0C5
+:107A6000F80187810F94DAB6B6010C2E02C0759525
+:107A700067950A94E2F76170F80187810F9413B754
+:107A80002196C830D10541F7C701DF91CF911F91F1
+:107A90000F91FF90EF90DF90CF9085CF1F93CF9302
+:107AA000DF93EC01162F642F8C810F9413B78D8117
+:107AB0008F3F19F060E00F9413B78F85612F84FF1B
+:107AC00005C0CE01DF91CF911F91B9CF70E084E066
+:107AD000759567958A95E1F7CE0182DF612FCE011A
+:107AE000DF91CF911F917CCF40E0D8CF61E0FCDFE8
+:107AF00080E496E00D9455B562E0F6DF80E496E010
+:107B00000D9455B5CF93DF93CDB7DEB728970FB659
+:107B1000F894DEBF0FBECDBF28E0E3E1F3E0DE0165
+:107B2000119601900D922A95E1F7FC0123894217E5
+:107B300010F04FEF420FFE013196E40FF11DE40FFC
+:107B4000F11D2081260F2068622F28960FB6F89429
+:107B5000DEBF0FBECDBFDF91CF91C6CFFC016089E4
+:107B6000262F2460208B6C60BFCFCF93DF93EC0176
+:107B7000423018F08F8588608F874B8B1C8A2223B8
+:107B800029F0413019F48F8584608F8780E593EC6C
+:107B90000F9455B560E08C810F9413B760E08E812F
+:107BA0000F9413B78D818F3F19F060E00F9413B7D6
+:107BB0006F8564FD19C063E0CE0112DF84E991E1B5
+:107BC0000F9455B563E0CE010BDF84E991E10F948A
+:107BD00055B563E0CE0104DF86E990E00F9455B51A
+:107BE00062E0CE01FDDE13C06062CE017DDF84E97C
+:107BF00091E10F9455B56F856062CE0175DF86E91E
+:107C000090E00F9455B56F856062CE016DDF6F8592
+:107C10006062CE0169DF8CE390E00F9455B584E09B
+:107C2000888BCE019BDF8CE390E00F9455B5CE019D
+:107C30005DDF88EB9BE00F9455B582E0898B66E0B1
+:107C4000CE0152DF8CE390E00F9455B51D8ADF9191
+:107C5000CF9108956F927F928F92AF92CF92EF92D1
+:107C60000F931F93CF93DF93CDB7DEB73C01162F51
+:107C7000842F5E854F8538899989F3018483258314
+:107C80000683E782C086A18682865387448735872C
+:107C9000968761E00F94DAB6F30185818F3F19F082
+:107CA00061E00F94DAB661E0F30186810F94DAB6F1
+:107CB000112319F0F301178603C080E1F3018787D0
+:107CC00020E041E060E1C301DF91CF911F910F916E
+:107CD000EF90CF90AF908F907F906F9046CF8F9224
+:107CE000AF92CF92EF920F93DC0113961C921E92EB
+:107CF0001297E2EBF3E0ED93FC931F921F921F9219
+:107D00001F928C2CAE2CC02EE22E042F2FEF462F6C
+:107D100061E0A0DF0F900F900F900F900F91EF9008
+:107D2000CF90AF908F900895CF93DF93EC014230C6
+:107D300018F08F8588608F874B8B1C8A222329F04F
+:107D4000413019F48F8584608F8780E593EC0F9420
+:107D500055B560E08C810F9413B760E08E810F946D
+:107D600013B78D818F3F19F060E00F9413B76F85C3
+:107D700064FD19C063E0CE0133DE84E991E10F9424
+:107D800055B563E0CE012CDE84E991E10F9455B541
+:107D900063E0CE0125DE86E990E00F9455B562E000
+:107DA000CE011EDE13C06062CE019EDE84E991E149
+:107DB0000F9455B56F856062CE0196DE86E990E03E
+:107DC0000F9455B56F856062CE018EDE6F8560625F
+:107DD000CE018ADE8CE390E00F9455B584E0888B69
+:107DE000CE01BCDE8CE390E00F9455B5CE0184DE6D
+:107DF00080E496E00F9455B582E0898B66E0CE0171
+:107E000073DE8CE390E00F9455B540E068E0CE015E
+:107E100079DE6BEC78E0CE010F94AEB741E068E01C
+:107E2000CE0170DE6BEC78E0CE010F94AEB742E08D
+:107E300066E0CE0167DE69EC78E0CE01DF91CF919C
+:107E40000D94AEB7FC0160896D7F608B68604CCE8D
+:107E5000CF93DF93EC01262F8D898230B0F0FE01A5
+:107E6000E80FF11D658B3E8980ED860F8A3058F44E
+:107E7000316081E090E00D8802C0880F991F0A945C
+:107E8000E2F7382B01C03E7F3E8B4D8981E0840FA5
+:107E90008D8B50E04830510508F0B6C0FA01EE581D
+:107EA000FF4F0D94DBC22B3109F0AEC0AEC01E8A6D
+:107EB0002B3509F0A9C0A9C0223309F4A6C02F337D
+:107EC00009F4A3C08E897AC08F89823331F08F3351
+:107ED00049F4223309F098C098C02A3419F4CE012D
+:107EE00005DE92C08E8982FF8FC02B3309F066C0F9
+:107EF0008CC08F898F3341F4888D823309F084C020
+:107F0000253309F081C081C08E8982FF7DC0988DA4
+:107F10009B3311F480FD79C083FF76C02B3309F0C9
+:107F200073C073C04F894F3371F4888D823309F069
+:107F30006BC0898D853309F067C02C3609F064C0A9
+:107F4000CE0180DF61C08E8982FF5EC0988D9B3339
+:107F500039F484FF05C0283489F54053698D2CC05D
+:107F600083FF52C0998D9B3309F04EC027C08E8984
+:107F700082FF4AC0488D4B3361F4982F9073903341
+:107F800041F4283431F44F8940536A8D6053898D10
+:107F900032C083FF39C0998D9B33B1F585FF34C062
+:107FA000283461F440538F89880F8056982F990F99
+:107FB000990F980F490F6A8D605324C080FF24C029
+:107FC00024C08E89982F9C709C30F1F4998D9B333E
+:107FD000D9F480768036C1F42834B1F4488D40530A
+:107FE0008F89880F8056982F990F990F980F490FF6
+:107FF0006B8D60538A8D880F8056982F990F990F3B
+:10800000980F690FCE017EDD1D8A81E090E0DF913F
+:10801000CF910895CF92DF92EF92FF920F931F932B
+:10802000CF93DF931F921F92CDB7DEB78C0167709D
+:1080300088E0689FB00111246064C80149835A83B5
+:1080400053DD4981C42E5A81D52EE12CF12CD60165
+:108050006D916D01D801ED91FC910190F081E02DC1
+:10806000C8011995BFEFEB1AFB0AE8E0EE16F10420
+:1080700071F70F900F90DF91CF911F910F91FF90AB
+:10808000EF90DF90CF900895FC012589211102C067
+:108090006B3109F4DDCE41E001DD81E090E008952F
+:1080A0001F920F920FB60F9211240BB60F922F93BF
+:1080B0003F934F935F936F938F939F93EF93FF93B0
+:1080C0008091C00084FF03C08091C60019C06091F8
+:1080D000C6002091FF093091000AC90101968F77EF
+:1080E00099274091010A5091020A8417950741F09F
+:1080F000F901E158F64F60839093000A8093FF09DD
+:10810000FF91EF919F918F916F915F914F913F916F
+:108110002F910F900BBE0F900FBE0F901F901895D0
+:108120001F920F920FB60F9211240BB60F922F933E
+:108130003F934F935F936F938F939F93EF93FF932F
+:108140008091030A813001F58091D00084FF03C043
+:108150008091D60019C06091D6002091FF0930911E
+:10816000000AC90101968F7799274091010A509121
+:10817000020A8417950741F0F901E158F64F608330
+:108180009093000A8093FF09FF91EF919F918F9147
+:108190006F915F914F913F912F910F900BBE0F9078
+:1081A0000FBE0F901F901895CF92DF92EF92FF9223
+:1081B0006A017B01411581EE58076105710509F4DB
+:1081C00063C082E08093C00060E079E08DE390E0DE
+:1081D000A70196010F94BFC22150310941095109ED
+:1081E000CA01B90122E030E040E050E00F94BFC284
+:1081F00091E03093C5002093C4008091C10080615C
+:108200008093C1008091C10088608093C1008091FB
+:10821000C10080688093C1008091030A8130D1F54C
+:10822000992341F082E08093D00060E079E08DE313
+:1082300090E006C01092D00060E874E88EE190E013
+:10824000A70196010F94BFC221503109410951097C
+:10825000CA01B90122E030E040E050E00F94BFC213
+:108260003093D5002093D4008091D1008061809319
+:10827000D1008091D10088608093D1008091D1009D
+:1082800080688093D10006C01092C00090E020E189
+:1082900030E0AFCFFF90EF90DF90CF900895209126
+:1082A000010A3091020A8091FF099091000A821719
+:1082B000930771F0F901E158F64F80812F5F3F4F2E
+:1082C0002F7733273093020A2093010A90E0089514
+:1082D0008FEF9FEF08958091010A9091020A909389
+:1082E000000A8093FF0908954F925F926F927F92E8
+:1082F0008F929F92AF92BF92CF92DF92EF92FF92B6
+:108300000F931F93CF93DF93CDB7DEB7A0970FB630
+:10831000F894DEBF0FBECDBF5C014115510561056C
+:108320007105E9F420E030E040E350E060E070E007
+:10833000A0960FB6F894DEBF0FBECDBFDF91CF91F0
+:108340001F910F91FF90EF90DF90CF90BF90AF9073
+:108350009F908F907F906F905F904F905BC08E0149
+:108360000F5F1F4FC12CD12C76014801422E512C9A
+:10837000612C712C8FEFC81AD80AE80AF80ACB01D1
+:10838000BA01A30192010F949DC2CA01F801619341
+:108390008F01A901BC01411551056105710551F716
+:1083A000F1E0CF1AD108E108F108F401EC0DFD1D50
+:1083B00080818A3010F440E301C047E3480F55271D
+:1083C00047FD5095652F752F20E030E0C50122D084
+:1083D00081E0C81AD108E108F108EFEFCE16DE06F9
+:1083E000EE06FE0611F7A0960FB6F894DEBF0FBE9C
+:1083F000CDBFDF91CF911F910F91FF90EF90DF9054
+:10840000CF90BF90AF909F908F907F906F905F9034
+:108410004F9008952115310539F48091C00085FFF2
+:10842000FCCF4093C60008952A30310509F43FC0BF
+:108430005BCF9A01462F552747FD5095652F752F25
+:10844000E9CFCF93DF93EC0120E030E04DE050E046
+:1084500060E070E0DFDF20E030E04AE050E060E024
+:1084600070E0CE01DF91CF91D5CFFB012191BF010B
+:10847000222339F03091C00035FFFCCF2093C60095
+:10848000F4CFDFCF9A01AB01662757FD6095762FB9
+:10849000C1CFCF93DF93EC019A01AB01662757FD63
+:1084A0006095762FB7DFCE01DF91CF91CACFCF9203
+:1084B000DF92EF92FF92CF93DF93EC016A017B0191
+:1084C00077FF0FC020E030E04DE250E060E070E068
+:1084D000A1DFF094E094D094C094C11CD11CE11CA5
+:1084E000F11C2AE0B701A601CE01DF91CF91FF90E8
+:1084F000EF90DF90CF90F8CE2115310539F48091BF
+:10850000C00085FFFCCF4093C6000895EDCECF9309
+:10851000DF93EC019A01462F50E060E070E0ECDF61
+:10852000CE01DF91CF918DCFCF93DF93EC019A01F4
+:10853000AB0160E070E0E0DFCE01DF91CF9181CF51
+:10854000CF93DF93EC01D8DFCE01DF91CF9179CFCC
+:108550008F929F92AF92BF92CF92DF92EF92FF9253
+:108560001F93CF93DF93EC016A017B01122F20E070
+:1085700030E0A901C701B6010F94C6BD87FF0CC04A
+:1085800020E030E04DE250E060E070E0CE0142DFFC
+:10859000F7FAF094F7F8F094B12C60E070E080E026
+:1085A0009FE3B11641F020E030E040E251E40F9447
+:1085B000CDBDB394F6CF9B01AC01C701B6010F94BA
+:1085C000EDBC6B017C010F943ABE4B015C010F9432
+:1085D00066BE9B01AC01C701B6010F94ECBC6B01F8
+:1085E0007C012AE0B501A401CE017EDE112361F0F9
+:1085F000EDECF5E08191882339F09091C00095FF72
+:10860000FCCF8093C600F6CF112319F120E030E0B3
+:1086100040E251E4C701B6010F949BC06B017C019D
+:108620000F9435BE4B01AA2497FCA094BA2CB50137
+:10863000A401CE013CDFC501B4010F9468BE9B01CB
+:10864000AC01C701B6010F94ECBC6B017C01115069
+:10865000DBCFDF91CF911F91FF90EF90DF90CF9014
+:10866000BF90AF909F908F90089572CFCF93DF937C
+:10867000EC016EDFCE01DF91CF91E3CE9091C0008F
+:1086800095FFFCCF8093C60080E090E00895FC0148
+:1086900065917591859194910895EF92FF920F9352
+:1086A0001F93CF93DF93EC01CC0FDD1FCC0FDD1FA9
+:1086B000CE01855E9F4EEBDF9E012052354F790142
+:1086C0008E010C52154FF801208131814281538176
+:1086D0000F94EDBCF7016083718382839383CE0195
+:1086E0008D5C9F4ED4DF9E012C5C3D4F7901F801DB
+:1086F00020813181428153810F94EDBCF701608369
+:10870000718382839383CE01895D9F4EC0DFC85DF4
+:10871000DD4FF80120813181428153810F94EDBCFE
+:10872000688379838A839B83DF91CF911F910F9117
+:10873000FF90EF900895CF93C82F40910C02509175
+:108740000D0260910E0270910F024093970A5093B0
+:10875000980A6093990A70939A0A20915602309170
+:1087600057023093610B2093600B24E630E0309386
+:108770005702209356020F94EFB46093920A7093BD
+:10878000930A8093940A9093950A8C2FCF910D941D
+:108790008C1580E00F948C158091970A9091980A1F
+:1087A000A091990AB0919A0A80930C0290930D02BD
+:1087B000A0930E02B0930F028091600B9091610B19
+:1087C00090935702809356020F94EFB46093920AED
+:1087D0007093930A8093940A9093950A0895682F52
+:1087E000772767FD70958091431090914410885BC6
+:1087F0009F4E0F948DC690933A108093391021E0CC
+:10880000892B09F420E0822F0895809139109091EE
+:108810003A104AE050E060E070E001960F949EC488
+:10882000CB0108958091391090913A104AE050E0C0
+:1088300060E070E001960D949EC420914310309149
+:108840004410BC01C901885B9F4E0F94C5C690932C
+:108850003A108093391021E0892B09F420E0822F0F
+:1088600008950F931F93CF93DF93009139101091C8
+:108870003A1065E470E0C8010F948DC6EC010097D2
+:1088800051F460E070E0C8010196DF91CF911F9133
+:108890000F910D9436C318828091391090913A103F
+:1088A00060E070E001960F9436C325E42883DF91E1
+:1088B000CF911F910F9108958091391090913A10A6
+:1088C00060E070E001960D9436C32F923F924F9274
+:1088D0005F926F927F928F929F92AF92BF92CF9250
+:1088E000DF92EF92FF920F931F93CF93DF93CDB759
+:1088F000DEB760970FB6F894DEBF0FBECDBF1C0188
+:108900002A013B014801590120E030E04CE052E4EB
+:10891000C301B2010F94ECBC25E535E547E052E414
+:108920000F94CDBD6B017C010F94A3BE0F9435BE97
+:108930008B0177FF12C020E030E040E85FE3C70121
+:10894000B6010F94C9BF18160CF05DC0C12CD12C14
+:10895000E0E8EE2EEFE3FE2E56C066307105DCF047
+:108960002AEA3AE24CE453E4C301B2010F94ECBCAE
+:1089700025E535E547E052E40F94CDBD6B017C0160
+:1089800020E030E0A9010F94C6BD87FF3FC0C12C95
+:10899000D12C76013BC0882777FD8095982F0F94C6
+:1089A00068BE25E535E547E052E40F949BC020E022
+:1089B00030E04CE052E40F94EDBC9B01AC01C301EC
+:1089C000B2010F94ECBC25E535E547E052E40F9485
+:1089D000CDBD6B017C0120E030E0A9010F94C6BD44
+:1089E00087FD17C020E030E040E85FE3C701B60133
+:1089F0000F94C9BF181684F4C12CD12C70E8E72E4F
+:108A00007FE3F72E09C000E010E006C005E010E0AB
+:108A100003C0C12CD12C760120E030E040EC50E4C2
+:108A2000C501B4010F94ECBC2BEA3AEA42E052E4EF
+:108A30000F94CDBD2B013C010F94A3BE0F9435BE06
+:108A4000788B6F8777FF12C020E030E040E85FE36B
+:108A5000C301B2010F94C9BF18160CF05FC0412CBE
+:108A6000512C60E8662E6FE3762E58C0AF85B8892A
+:108A70001697E4F026E535E549E253E4C501B40173
+:108A80000F94ECBC2BEA3AEA42E052E40F94CDBDDD
+:108A90002B013C0120E030E0A9010F94C6BD87FD09
+:108AA00040C0E5E0F0E0F88BEF8746C0882777FD0F
+:108AB0008095982F0F9468BE2BEA3AEA42E052E480
+:108AC0000F949BC020E030E040EC50E40F94EDBCEC
+:108AD0009B01AC01C501B4010F94ECBC2BEA3AEA4E
+:108AE00042E052E40F94CDBD2B013C0120E030E088
+:108AF000A9010F94C6BD87FD1CC020E030E040E80E
+:108B00005FE3C301B2010F94C9BF1816ACF4412C46
+:108B1000512C50E8652E5FE3752E0EC0188A1F8613
+:108B20000BC0412C512C320125E030E0388B2F87CF
+:108B300003C0412C512C3201A701960160E070E086
+:108B400080E89FE30F94ECBC69837A838B839C83DA
+:108B5000C80101969E838D83AF85B8891196BA8727
+:108B6000A987A301920160E070E080E89FE30F9481
+:108B7000ECBC6B877C878D879E8747E02F85388983
+:108B8000429FF001439FF00D1124F887EF83E00F1F
+:108B9000F11FEE0FFF1FEE0FFF1FE20DF31D2181EE
+:108BA00032814381548169817A818B819C810F94C8
+:108BB0009BC04B015C01EF81F8858D819E81E80FA0
+:108BC000F91FEE0FFF1FEE0FFF1FE20DF31D2181B6
+:108BD000328143815481C701B6010F949BC09B0130
+:108BE000AC01C501B4010F94EDBC9B01AC016B85D8
+:108BF0007C858D859E850F949BC04B015C0127E091
+:108C0000E985FA852E9FD0012F9FB00D1124B887DA
+:108C1000AF83FD01E00FF11FEE0FFF1FEE0FFF1FEF
+:108C2000E20DF31D218132814381548169817A8172
+:108C30008B819C810F949BC069837A838B839C83F7
+:108C4000AF81B8858D819E81A80FB91FAA0FBB1F68
+:108C5000AA0FBB1FA20DB31D11962D913D914D91F1
+:108C60005C911497C701B6010F949BC09B01AC01A6
+:108C700069817A818B819C810F94EDBC9B01AC0151
+:108C8000C301B2010F949BC09B01AC01C501B401AB
+:108C90000F94EDBC60960FB6F894DEBF0FBECDBF4B
+:108CA000DF91CF911F910F91FF90EF90DF90CF90C8
+:108CB000BF90AF909F908F907F906F905F904F90FC
+:108CC0003F902F9008954F925F926F927F929F9264
+:108CD000AF92BF92CF92DF92EF92FF920F931F93CA
+:108CE000CF93DF937C015B018A01E90190907612BA
+:108CF000911014C0FC0180819181A281B381FA019D
+:108D000080839183A283B383FB0180819181A281BF
+:108D1000B38188839983AA83BB837FC091FE55C0AA
+:108D2000FC012081318142815381609166127091F2
+:108D3000671280916812909169120F949BC02B0169
+:108D40003C01F501208131814281538160916A1299
+:108D500070916B1280916C1290916D120F949BC068
+:108D60009B01AC01C301B2010F94EDBCF80160831B
+:108D7000718382839383F701208131814281538102
+:108D800060916E1270916F128091701290917112B9
+:108D90000F949BC06B017C01F501208131814281E0
+:108DA000538160917212709173128091741290913C
+:108DB00075120F949BC09B01AC01C701B6010F94C3
+:108DC000EDBC688379838A839B8390FE26C02091C3
+:108DD0004E1230914F124091501250915112F801A1
+:108DE00060817181828193810F94EDBCF801608371
+:108DF0007183828393832091521230915312409158
+:108E0000541250915512688179818A819B810F9407
+:108E1000EDBC688379838A839B83DF91CF911F9117
+:108E20000F91FF90EF90DF90CF90BF90AF909F9009
+:108E30007F906F905F904F9008952F923F924F9246
+:108E40005F926F927F928F929F92AF92BF92CF92DA
+:108E5000DF92EF92FF920F931F93CF93DF93CDB7E3
+:108E6000DEB728970FB6F894DEBF0FBECDBF8C01DA
+:108E70001B019E012F5F3F4FAE014B5F5F4F23DF12
+:108E800020E030E0A9016D817E818F8198850F946B
+:108E9000C6BD87FF07C01D821E821F821886FF2461
+:108EA000F39401C0F12C20E030E040E850EC6981FF
+:108EB0007A818B819C810F94C6BD87FF0AC080E0B8
+:108EC00090E0A0E8B0EC89839A83AB83BC83FF2455
+:108ED000F39420E030E04FE753E46D817E818F8191
+:108EE00098850F94C9BF181654F480E090E0AFE75E
+:108EF000B3E48D839E83AF83B887FF24F39420E08F
+:108F000030E042E553E469817A818B819C810F9442
+:108F1000C9BF18164CF480E090E0A2E5B3E4898361
+:108F20009A83AB83BC8303C0FF2009F483C0C9804C
+:108F3000DA80EB80FC808D809E80AF80B88470905A
+:108F4000761271100BC0F80180829182A282B382E6
+:108F5000F101C082D182E282F3826AC070FE1CC03D
+:108F600020914E1230914F12409150125091511257
+:108F7000C501B4010F94ECBC4B015C01209152126D
+:108F8000309153124091541250915512C701B601BD
+:108F90000F94ECBC6B017C0171FE4AC0209156120B
+:108FA000309157124091581250915912C501B40195
+:108FB0000F949BC02B013C0120915A1230915B12FF
+:108FC00040915C1250915D12C701B6010F949BC095
+:108FD0009B01AC01C301B2010F94EDBCF8016083A9
+:108FE00071838283938320915E1230915F1240914E
+:108FF000601250916112C501B4010F949BC04B01E6
+:109000005C01209162123091631240916412509180
+:109010006512C701B6010F949BC09B01AC01C5014D
+:10902000B4010F94EDBCF10160837183828393835B
+:10903000FF24F3948F2D28960FB6F894DEBF0FBE51
+:10904000CDBFDF91CF911F910F91FF90EF90DF90F7
+:10905000CF90BF90AF909F908F907F906F905F90D8
+:109060004F903F902F900895CF93DF931F92CDB7ED
+:10907000DEB7BE016F5F7F4F0F94109A0F90DF91A4
+:10908000CF910895682F87EF9FE00D9456CA0895F9
+:10909000FC012491222341F03091C00035FFFCCF28
+:1090A0002093C6000196F4CF22E030E08EE799E0ED
+:1090B000DCCAFC012491222341F03091C00035FF2D
+:1090C000FCCF2093C6000196F4CF2AE030E08EE773
+:1090D00099E012CACF9366EB73E08EE799E0C5D9A9
+:1090E000C1E0C093B1026FEF89E69FE00F9456CACA
+:1090F000C093DF02CF91089566EC73E08EE799E0AC
+:10910000B4D91092B10260E089E69FE00F9456CA8C
+:109110001092DF02089587ED93E09F938F930F9451
+:109120005AC70F94071F81E00F94D1990F9466508E
+:1091300082E00F940A9786E69FE00F9444CA61E0AC
+:10914000680F86E69FE00F9456CA81E00F94D1998C
+:1091500082E00F940A97E091300BF0E0EE0FFF1FD2
+:10916000E45EFF4B859194910F947E5161E08AEF0C
+:109170009FE00E9411C361E084EF9FE00E9411C351
+:109180000F900F9061E086EE9FE00C9411C3109257
+:109190006C0B60E08AE69BE00E9463BC81E08093F8
+:1091A000B1020895EF92FF920F931F93CF93DF9335
+:1091B0001F92CDB7DEB789830F94665089818230C4
+:1091C00009F468C0B4F5882309F442C0813009F07D
+:1091D000F4C09FB7F89480910201846080930201EB
+:1091E0009FBFEFEFF1EE24E0E150F0402040E1F7C7
+:1091F00000C000009FB7F894809102018B7F80939C
+:1092000002019FBF40E050E0BA018DEE9FE00F9455
+:1092100068CA40E050E0BA0181EF9FE00F9468CA4D
+:109220000F90DF91CF911F910F91FF90EF900D94D0
+:109230000C79833009F45CC0843009F0BEC00F9013
+:10924000DF91CF911F910F91FF90EF900D9487A226
+:109250009FB7F894809102018460809302019FBFC0
+:109260002FEF81EE94E0215080409040E1F700C064
+:1092700000009FB7F894809102018B7F80930201D8
+:109280009FBF0F90DF91CF911F910F91FF90EF90B3
+:109290000D940F510F940F5180EFF4DE1092911B3B
+:1092A0001092901B6091921B84EC9FE00F9456CA21
+:1092B00060E97BE181EC9FE00F9494509FB7F894B4
+:1092C000809102018460809302019FBF8FEF91EE35
+:1092D000E4E081509040E040E1F700C000009FB71B
+:1092E000F894809102018B7F809302019FBF65C03B
+:1092F00088ED9FE00F94776747EC5FE062E081E0E4
+:109300000F94507D9FB7F894809102018460809300
+:1093100002019FBFFFEF21EE84E0F150204080402A
+:10932000E1F700C000009FB7F894809102018B7FA5
+:10933000809302019FBF10927E0A10927D0A40EC3A
+:109340005FE063E083E00F94507D40917D0A50918F
+:109350007E0A63E083E00F947150E12CF12C09E266
+:1093600010E06FEFC7010F9474CAC701B8010F94E2
+:109370008AC2892BD9F480917D0A90917E0A019648
+:1093800090937E0A80937D0A49EB5FE063E083E07F
+:109390000F94507D40917D0A50917E0A63E083E0F6
+:1093A0000F94715087EB9FE00F9477679FEFE91A56
+:1093B000F90AE114E0E1FE06A1F60F90DF91CF91EA
+:1093C0001F910F91FF90EF9008956FE67AE087E884
+:1093D0009FE00D942DC78F929F92AF92BF92CF9234
+:1093E000DF92EF92FF928091921B81119DC00F94AA
+:1093F000EFB46B017C0120911002222309F48CC090
+:1094000040911502509116024130510509F484C073
+:109410008091110290911202A0911302B091140256
+:1094200046015701881A990AAA0ABB0A30E0A8EE39
+:10943000B3E00F94E1C286169706A806B9060CF4AD
+:1094400073C04430510559F13CF4423051050CF4DD
+:1094500063C0EFE3F0E10EC04530510509F05CC098
+:10946000EFE3F0E142C09091C00095FFFCCF809304
+:10947000C600319684918111F6CFE4EAFEE0849132
+:10948000882341F09091C00095FFFCCF8093C600E7
+:109490003196F5CF8091C00085FFFCCF3AC0EFE355
+:1094A000F0E18491882341F09091C00095FFFCCFBA
+:1094B0008093C6003196F5CFEEE8FEE084918823D4
+:1094C00041F09091C00095FFFCCF8093C60031968B
+:1094D000F5CF8091C00085FFFCCF1BC09091C000EC
+:1094E00095FFFCCF8093C600319684918111F6CF11
+:1094F000E7E7FEE08491882341F09091C00095FF5A
+:10950000FCCF8093C6003196F5CF8091C00085FFD7
+:10951000FCCF8AE08093C600C0921102D092120262
+:10952000E0921302F0921402FF90EF90DF90CF9040
+:10953000BF90AF909F908F90089580E1E0EEFAE0A9
+:10954000ABEABAE001900D928A95E1F708954F9247
+:109550005F926F927F928F929F92AF92BF92CF92C3
+:10956000DF92EF92FF92CF93DF9300D01F92CDB79F
+:10957000DEB70F94071F8BE432D9882391F071D99D
+:109580006B017C0120E030E0A9010F94C9BF87FD89
+:1095900008C0C0925F13D0926013E0926113F09202
+:1095A000621382E51CD9882359F05BD96B017C01D9
+:1095B00020E030E0A9010F94C6BD87FF83C006C03C
+:1095C000C12CD12CE0E8EE2EEFEBFE2E84E407D97F
+:1095D000882321F046D94B015C0106C0812C912CD7
+:1095E00070E8A72E7FEBB72E87E5F9D8882321F006
+:1095F00038D92B013C0106C0412C512C60E8662E65
+:109600006FEB762E88E4EBD8882331F02AD9698372
+:109610007A838B839C8308C080E090E0A0E8BFEB56
+:1096200089839A83AB83BC8320E030E0A901C50124
+:10963000B4010F94C9BF87FD45C020E030E0A90107
+:10964000C301B2010F94C9BF87FD3CC020E030E0E8
+:10965000A90169817A818B819C810F94C9BF87FDA3
+:1096600031C020E030E0A901C501B4010F94C6BDAE
+:10967000882391F120E030E040E05FE3C501B401D0
+:109680000F949BC06B017C0129813A814B815C81E5
+:10969000C301B2010F949BC04B015C01A70196016D
+:1096A000C701B6010F949BC02BED3FE049E450E4A5
+:1096B0000F949BC09B01AC01C501B4010F94CDBDBB
+:1096C0006B017C0120E030E0A901C701B6010F94D5
+:1096D000C9BF87FF04C00BC0C12CD12C7601C0923A
+:1096E0005B13D0925C13E0925D13F0925E13EFE394
+:1096F000F0E18491882341F09091C00095FFFCCF68
+:109700008093C6003196F5CFE0E3FBE08491882397
+:1097100041F09091C00095FFFCCF8093C600319638
+:10972000F5CF40915F135091601360916113709178
+:10973000621322E030E08EE799E00E943543809189
+:10974000C00085FFFCCF8AE08093C600EAE2FBE020
+:109750008491882341F09091C00095FFFCCF8093C5
+:10976000C6003196F5CFC0905B13D0905C13E090AB
+:109770005D13F0905E1320E030E0A901C701B6014F
+:109780000F94C6BD882369F022E030E0B701A6013E
+:109790008EE799E00E9435438091C00085FFFCCFA1
+:1097A00011C0E5E2FBE08491882341F09091C00074
+:1097B00095FFFCCF8093C6003196F5CF8091C00015
+:1097C00085FFFCCF8AE08093C6000F900F900F902A
+:1097D0000F90DF91CF91FF90EF90DF90CF90BF90EF
+:1097E000AF909F908F907F906F905F904F90089573
+:1097F0002F923F924F925F926F927F928F929F92A1
+:10980000AF92BF92CF92DF92EF92FF920F931F938E
+:10981000CF93DF931F92CDB7DEB70F946650E091E0
+:10982000300BF0E0EE0FFF1FE05EFC4B45915491D2
+:1098300061E080E00F94507D81E00F948C15898366
+:10984000E2E0F0E1E4918E2F992781950CF4909558
+:109850001C0184E00F94E43AA8EEBAE01D921D9238
+:109860001D921C921397E4EEFAE02081318142812F
+:109870005381A0EEBAE06D917D918D919C91BCEEEB
+:10988000CB2EBAE0DB2EE12CF12C87010F940612CF
+:1098900054DE87E190E10E9447432DEC3CEC4CE81C
+:1098A0005FE30F949BC04B015C01B101882777FDFA
+:1098B0008095982F0F9468BE9B01AC01C501B4013F
+:1098C0000F949BC0E3EBFAE0208131814281538108
+:1098D0000F94EDBC2B013C01A3EBBAE06D937D939B
+:1098E0008D939C931397E0E6F2E060817181828111
+:1098F000938160930C0270930D0280930E029093FB
+:109900000F0220E030E040E752E40F94CDBD4B0160
+:109910005C01AFEABAE02D913D914D915C91EBEA8B
+:10992000FAE06081718182819381ACECBAE0BF93EF
+:10993000AF9317EBC12E1AE0D12E830172010F9461
+:10994000580582E00F9435380F94071F0F94643B3D
+:1099500080E00F948C15A8EEBAE01D921D921D9226
+:109960001C921397E4EEFAE0208131814281538109
+:10997000A0EEBAE06D917D918D919C910CEEC02E80
+:109980000AE0D02EE12CF12C87010F940612D5DDD0
+:109990008AE0829DB001839D700D1124882777FD98
+:1099A0008095982F0F9468BEE3EBFAE02081318117
+:1099B000428153810F94EDBC2B013C01A3EBBAE033
+:1099C0006D937D938D939C93139720E030E040E05E
+:1099D0005FE3E0E6F2E060817181828193810F9420
+:1099E0009BC060930C0270930D0280930E029093C3
+:1099F0000F0220E030E040E752E40F94CDBD4B0170
+:109A00005C01AFEABAE02D913D914D915C91EBEA9A
+:109A1000FAE06081718182819381ACECBAE0BF93FE
+:109A2000AF93E7EBCE2EEAE0DE2E830172010F94B6
+:109A300058050F94071F89810F948C1580E090E0E2
+:109A4000A4E5B3E4E8EEFAE080839183A283B383D4
+:109A5000A4EEBAE02D913D914D915C91E0EEFAE0DB
+:109A60006081718182819381FCEECF2EFAE0DF2E3E
+:109A7000E12CF12C04E513E40F94061281E00F9021
+:109A80000F900F900F900F90DF91CF911F910F913A
+:109A9000FF90EF90DF90CF90BF90AF909F908F900E
+:109AA0007F906F905F904F903F902F9008952F92EE
+:109AB0003F924F925F926F927F928F929F92AF925E
+:109AC000BF92CF92DF92EF92FF920F931F93CF93AB
+:109AD000DF93CDB7DEB729970FB6F894DEBF0FBE80
+:109AE000CDBF3C0181E00F948C158F8382E0681616
+:109AF000710408F081C2F301E050F04FE491D3010A
+:109B0000AA0FBB1FAA0FBB1FBA83A983A85ABD4FB8
+:109B1000BE83AD838D919D910D90BC91A02D8093BE
+:109B20000C0290930D02A0930E02B0930F0281E0FD
+:109B3000062C01C0880F0A94EAF70F94E43AE981F1
+:109B4000FA81E052F54FF987E8871082118212827C
+:109B50001382E090E80AF090E90A0091EA0A109175
+:109B6000EB0A2091E40A3091E50A4091E60A50910F
+:109B7000E70A6091E00A7091E10A8091E20A90910F
+:109B8000E30AECEECE2EEAE0DE2E0F940612E98117
+:109B9000FA81E555F54F2F0180E090E0A0E4B0E4B4
+:109BA00080839183A283B38320E030E040E752E4D6
+:109BB00060910C0270910D0280910E0290910F0243
+:109BC0000F94CDBD4B015C01E090B30AF090B40A54
+:109BD0000091B50A1091B60A2091AF0A3091B00AEF
+:109BE0004091B10A5091B20A6091AB0A7091AC0AEF
+:109BF0008091AD0A9091AE0AFCEC2F2EFAE03F2E38
+:109C00003F922F92A7EBCA2EAAE0DA2E0F945805A6
+:109C10000F94071F0F94741580E00F948C15A8857E
+:109C2000B9851D921D921D921C921397E090E80A2F
+:109C3000F090E90A0091EA0A1091EB0A2091E40AF7
+:109C40003091E50A4091E60A5091E70A6091E00AF6
+:109C50007091E10A8091E20A9091E30ABCEECB2E6A
+:109C6000BAE0DB2E0F94061280E090E0A0E8BFEB94
+:109C7000F20180839183A283B38320E030E040E748
+:109C800052E460910C0270910D0280910E0290914D
+:109C90000F020F94CDBD4B015C01E090B30AF09030
+:109CA000B40A0091B50A1091B60A2091AF0A30911A
+:109CB000B00A4091B10A5091B20A6091AB0A70911A
+:109CC000AC0A8091AD0A9091AE0A3F922F92E7EBD9
+:109CD000CE2EEAE0DE2E0F9458050F94071F81E088
+:109CE0000F948C1589819A81815F9F4E0E94474312
+:109CF0002DEC3CEC4CE85FEB0F949BC0D2016D93D4
+:109D00007D938D939C93139720E030E040E752E4DD
+:109D100060910C0270910D0280910E0290910F02E1
+:109D20000F94CDBD4B015C01E090B30AF090B40AF2
+:109D30000091B50A1091B60A2091AF0A3091B00A8D
+:109D40004091B10A5091B20A6091AB0A7091AC0A8D
+:109D50008091AD0A9091AE0A3F922F920F945805D0
+:109D60000F94071F0F94741580E00F948C15E885ED
+:109D7000F9851082118212821382E090E80AF09035
+:109D8000E90A0091EA0A1091EB0A2091E40A309165
+:109D9000E50A4091E60A5091E70A6091E00A709165
+:109DA000E10A8091E20A9091E30AFCEECF2EFAE0FC
+:109DB000DF2E0F94061280E090E0A0E2B1E4F20101
+:109DC00080839183A283B38320E030E040E752E4B4
+:109DD00060910C0270910D0280910E0290910F0221
+:109DE0000F94CDBD4B015C01E090B30AF090B40A32
+:109DF0000091B50A1091B60A2091AF0A3091B00ACD
+:109E00004091B10A5091B20A6091AB0A7091AC0ACC
+:109E10008091AD0A9091AE0A3F922F92A7EBCA2E85
+:109E2000AAE0DA2E0F9458050F94071F0F947415AB
+:109E300081E00F948C1580E090E0A0E7B1ECF20196
+:109E400080839183A283B38320E030E040E05FE32E
+:109E5000AD81BE816D917D918D919C910F949BC040
+:109E600060930C0270930D0280930E0290930F0288
+:109E700020E030E040E752E40F94CDBD4B015C019F
+:109E8000E090B30AF090B40A0091B50A1091B60AB6
+:109E90002091AF0A3091B00A4091B10A5091B20AB4
+:109EA0006091AB0A7091AC0A8091AD0A9091AE0AB4
+:109EB0003F922F920F9458050F94071FC3010E94E1
+:109EC0004D43F301EF52F54F81E080830F94643BE3
+:109ED0000F94741580E00F948C152AE037ED43E25F
+:109EE0005FE3E885F98560817181828193810F94B8
+:109EF000ECBCA885B9856D937D938D939C93139746
+:109F0000E090E80AF090E90A0091EA0A1091EB0A61
+:109F10002091E40A3091E50A4091E60A5091E70A5F
+:109F20006091E00A7091E10A8091E20A9091E30A5F
+:109F3000BCEECB2EBAE0DB2E0F9406122AE037EDF2
+:109F400043E25FE3E885F9856081718182819381D5
+:109F50000F94EDBCA885B9856D937D938D939C93EB
+:109F60001397F20160837183828393832AE939E92D
+:109F700049E95EE360910C0270910D0280910E023E
+:109F800090910F020F949BC020E030E040E752E434
+:109F90000F94CDBD4B015C01E090B30AF090B40A80
+:109FA0000091B50A1091B60A2091AF0A3091B00A1B
+:109FB0004091B10A5091B20A6091AB0A7091AC0A1B
+:109FC0008091AD0A9091AE0A3F922F92E7EBCE2E90
+:109FD000EAE0DE2E0F9458050F94071F10920C0232
+:109FE00010920D0210920E0210920F020FB6F8940A
+:109FF000DEBF0FBECDBF62C192E06916710409F0E9
+:10A000005DC1E2E0F0E174901092E80A1092E90A72
+:10A010001092EA0A1092EB0A2091E40A3091E50AC4
+:10A020004091E60A5091E70A6091E00A7091E10AD6
+:10A030008091E20A9091E30ABCEECB2EBAE0DB2ECF
+:10A04000E12CF12C87010F94061287E190E10E9428
+:10A0500047434B015C01672D772767FD7095872F7C
+:10A06000972F0F9468BE2B013C0120E030E040ECBC
+:10A070005FE3C501B4010F949BC0A30192010F944B
+:10A080009BC069837A838B839C836093B30A7093AC
+:10A09000B40A8093B50A9093B60A609160027091F9
+:10A0A0006102809162029091630260930C0270934E
+:10A0B0000D0280930E0290930F0220E030E040E703
+:10A0C00052E40F94CDBD4B015C012091AF0A309159
+:10A0D000B00A4091B10A5091B20A6091AB0A7091F6
+:10A0E000AC0A8091AD0A9091AE0A1CEC212E1AE0C8
+:10A0F000312E3F922F9207EBC02E0AE0D02EE9803E
+:10A10000FA800B811C810F9458050F94071F109241
+:10A11000E80A1092E90A1092EA0A1092EB0A2091DA
+:10A12000E40A3091E50A4091E60A5091E70A60910D
+:10A13000E00A7091E10A8091E20A9091E30AECEE64
+:10A14000CE2EEAE0DE2EE12CF12C87010F940612D0
+:10A150008BE090E10E9447439058A30192010F9435
+:10A160009BC069837A838B839C836093B30A7093CB
+:10A17000B40A8093B50A9093B60A20E030E040E735
+:10A1800052E460910C0270910D0280910E02909148
+:10A190000F020F94CDBD4B015C012091AF0A3091AD
+:10A1A000B00A4091B10A5091B20A6091AB0A709125
+:10A1B000AC0A8091AD0A9091AE0A3F922F92F7EBD4
+:10A1C000CF2EFAE0DF2EE980FA800B811C810F94FC
+:10A1D00058050F94071F8BE090E10E9447439B01B5
+:10A1E000AC010F94EDBCA30192010F949BC02B0115
+:10A1F0003C016093B30A7093B40A8093B50A9093BC
+:10A20000B60A20E030E040E05FE3609160027091C8
+:10A21000610280916202909163020F949BC06093EF
+:10A220000C0270930D0280930E0290930F0220E0B7
+:10A2300030E040E752E40F94CDBD4B015C0120912A
+:10A24000AF0A3091B00A4091B10A5091B20A6091C0
+:10A25000AB0A7091AC0A8091AD0A9091AE0A3F9220
+:10A260002F92830172010F9458050F94071F82E00B
+:10A2700090E00E944D438091E80A9091E90AA091F4
+:10A28000EA0AB091EB0A8093B30A9093B40AA093C0
+:10A29000B50AB093B60A10920C0210920D021092F9
+:10A2A0000E0210920F020F94741581E08093D30A6E
+:10A2B0000F900F900F900F900F900F908F81299615
+:10A2C0000FB6F894DEBF0FBECDBFDF91CF911F91C7
+:10A2D0000F91FF90EF90DF90CF90BF90AF909F9045
+:10A2E0008F907F906F905F904F903F902F900D9444
+:10A2F0008C15CF92DF92EF92FF920F931F931DD98F
+:10A3000080E090E0D4DB81E090E0D1DBE090E80AEF
+:10A31000F090E90A0091EA0A1091EB0A2091E40A10
+:10A320003091E50A4091E60A5091E70A6091E00A0F
+:10A330007091E10A8091E20A9091E30AFCEECF2E3F
+:10A34000FAE0DF2E0F9406121F910F91FF90EF900D
+:10A35000DF90CF900D9474150F94EFB46093920A30
+:10A360007093930A8093940A9093950A089520E03D
+:10A3700030E0A90168EB71E084E50F9447B969E129
+:10A3800070E080E090E00F941EB584E50F946BBC04
+:10A3900064E170E080E090E00D941EB57F928F92B2
+:10A3A0009F92AF92BF92CF92DF92EF92FF920F9364
+:10A3B0001F93CF93DF9300D01F92CDB7DEB71092DB
+:10A3C000781A1092771A1092761A1092751A0F94C2
+:10A3D000665085EB9EE00F9477678E010F5F1F4FED
+:10A3E0007E0125E0E20EF11C8EE799E00E944F41CC
+:10A3F0008F3FEFEF9E07C1F3F80181938F01EE15B8
+:10A40000FF0591F789809A80AB80BC808091C00065
+:10A4100085FFFCCF8BE28093C600C12CD12C760146
+:10A42000ABE27A2E80912F0B882309F450C000E212
+:10A430001AE0C814D904EA04FB04A1F08EE799E0FD
+:10A440000E944F418F3FFFEF9F07C1F32FEFC21ACA
+:10A45000D20AE20AF20AF80181938F01FAE000368B
+:10A460001F0739F760E27AE08AE69BE00E9430BB82
+:10A470008091C00085FFFCCF7092C6000F94F32B33
+:10A48000C814D904EA04FB0469F671DF60E08AE6C7
+:10A490009BE00E9463BC10922F0BE0EBF2E48591ED
+:10A4A0009491FC012491222341F03091C00035FFAA
+:10A4B000FCCF2093C6000196F4CF8091C00085FFA9
+:10A4C000FCCF8AE08093C60080E090E000C00F904F
+:10A4D0000F900F900F90DF91CF911F910F91FF90F0
+:10A4E000EF90DF90CF90BF90AF909F908F907F9034
+:10A4F00008952F923F924F925F926F927F928F9228
+:10A500009F92AF92BF92CF92DF92EF92FF920F9302
+:10A510001F93CF93DF931F921F92CDB7DEB7382ED4
+:10A52000811112C01092761A1092751A1092781A30
+:10A530001092771A10927A1A1092791A10927C1A45
+:10A5400010927B1A0F94BB5080E00F94D19987E74B
+:10A5500092E10E94F3F90E9455DB0E9444F91092A7
+:10A56000D10A1092D20A1092D30A81E00E949B4332
+:10A57000EEE8F3E4859194910E943448BADE38D92C
+:10A58000882309F483C1E8DE311058C084E090E0EC
+:10A590009093160280931502E091300BF0E0EE0FDD
+:10A5A000FF1FE653FF4B8591949140E060E00F94CC
+:10A5B000BE9B882359F0E091300BF0E0EE0FFF1FB7
+:10A5C000E457FE4B859194910F947EA4E091300B5B
+:10A5D000F0E0EE0FFF1FE65FFC4B859194910F9426
+:10A5E0007EA4E091300BF0E0EE0FFF1FEA51FE4B2E
+:10A5F000859194910F947EA482E090E0909316024E
+:10A6000080931502E091300BF0E0EE0FFF1FE8554C
+:10A61000FD4B859194910E94344841E050E062E006
+:10A6200080E00F947150E091300BF0E0EE0FFF1FCF
+:10A63000EC55FD4B859194910F94776780E090E005
+:10A64000A0EAB0E48093E80A9093E90AA093EA0AAA
+:10A65000B093EB0A20E030E040E252E46091600207
+:10A660007091610280916202909163020F94CDBD5E
+:10A670004B015C012091E40A3091E50A4091E60A21
+:10A680005091E70A6091E00A7091E10A8091E20A34
+:10A690009091E30AECECFAE0FF93EF93ECEECE2E10
+:10A6A000EAE0DE2EE12CF12C00EA10E40F945805CC
+:10A6B0000F94071F86E50E94EF430F900F908823A9
+:10A6C00061F0E0913910F0913A108181893039F0D0
+:10A6D0008F7D41F00E94054403C01A8205C081E0CD
+:10A6E0008A8302C0A1E0AA833320B1F00E94C9434B
+:10A6F0000E94AADB0E94C6DD0E949AF2882309F418
+:10A70000C1C087EF9FE00F9444CA803F09F0BAC0F0
+:10A7100081E00E944248B6C08FEF0E94424860E04C
+:10A7200070E088EF9FE00F9470CA1982BE016F5FDE
+:10A730007F4F8A810E946BEF3C010E94C943212C0C
+:10A74000312C10EA412E10E4512E2092E80A30926A
+:10A75000E90A4092EA0A5092EB0A20E030E040E237
+:10A7600052E4609160027091610280916202909166
+:10A7700063020F94CDBD4B015C012091E40A30913E
+:10A78000E50A4091E60A5091E70A6091E00A70916B
+:10A79000E10A8091E20A9091E30AACECBAE0BF933F
+:10A7A000AF930CEEC02E0AE0D02E820171010F94FF
+:10A7B00058050F94071F0F900F9077FC47C0198220
+:10A7C00087E792E10E94F3F90E941CDB81E00E947E
+:10A7D0009B438FDDAE014F5F5F4F6A8181E00E9436
+:10A7E000C0F43C010E94C9432092E80A3092E90A71
+:10A7F0004092EA0A5092EB0A20E030E040E252E454
+:10A800006091600270916102809162029091630296
+:10A810000F94CDBD4B015C012091E40A3091E50A13
+:10A820004091E60A5091E70A6091E00A7091E10ACE
+:10A830008091E20A9091E30AACECBAE0BF93AF9347
+:10A840000F9458050F94071F0F900F906981C30153
+:10A850000F94E8A477FC16C086EE0E9442488FE56C
+:10A860009FE00F9444CA813059F0E091300BF0E042
+:10A87000EE0FFF1FEC57FC4B859194910F947EA433
+:10A8800011E001C010E00F94643B01C010E081E0D2
+:10A890000F94D199812F0F900F90DF91CF911F913D
+:10A8A0000F91FF90EF90DF90CF90BF90AF909F906F
+:10A8B0008F907F906F905F904F903F902F90089572
+:10A8C0008F929F92AF92BF92CF92DF92EF92FF92C0
+:10A8D0000F931F93CF93DF93159881E08093240B00
+:10A8E00082E090E09093220B8093210BE091300B5B
+:10A8F000F0E0EE0FFF1FE05BFD4B859194910F940C
+:10A900007E5120E030E04CE852E46091EC0A709116
+:10A91000ED0A8091EE0A9091EF0A0F94EDBC6093DE
+:10A92000EC0A7093ED0A8093EE0A9093EF0AE090A0
+:10A93000E80AF090E90A0091EA0A1091EB0A2091E6
+:10A94000E40A3091E50A4091E60A5091E70A6091E5
+:10A95000E00A7091E10A8091E20A9091E30ACCEC5E
+:10A96000DAE0DF93CF93812C912CE0ECAE2EE0E483
+:10A97000BE2EFCEECF2EFAE0DF2E0F94580520E01D
+:10A9800030E048EC51E46091EC0A7091ED0A80915E
+:10A99000EE0A9091EF0A0F94EDBC6093EC0A70936D
+:10A9A000ED0A8093EE0A9093EF0AE090E80AF090A7
+:10A9B000E90A0091EA0A1091EB0A2091E40A309129
+:10A9C000E50A4091E60A5091E70A6091E00A709129
+:10A9D000E10A8091E20A9091E30ADF93CF93812C00
+:10A9E000912CA0E8AA2EAFE3BA2E0F9458050F942D
+:10A9F000071F0F900F900F900F908091921B88234C
+:10AA000031F181E00F94D19982E00F940A97E0919F
+:10AA1000300BF0E0EE0FFF1FE45EFF4B8591949149
+:10AA20000F947E511092230B1092240B1092220B44
+:10AA30001092210BDF91CF911F910F91FF90EF901A
+:10AA4000DF90CF90BF90AF909F908F9008958091AE
+:10AA5000230B8823B1F2E091300BF0E0EE0FFF1FE3
+:10AA6000EC54FD4B8591949141E060E00F94BE9BC6
+:10AA700091E0811101C090E0CCECDAE09111C1CFFE
+:10AA800081E00F94D19982E00F940A9720E030E0A2
+:10AA900048EC51E46091EC0A7091ED0A8091EE0A65
+:10AAA0009091EF0A0F94EDBC6093EC0A7093ED0A5D
+:10AAB0008093EE0A9093EF0AE090E80AF090E90A9A
+:10AAC0000091EA0A1091EB0A2091E40A3091E50A1C
+:10AAD0004091E60A5091E70A6091E00A7091E10A1C
+:10AAE0008091E20A9091E30ADF93CF93812C912C1D
+:10AAF000E0E8AE2EEFE3BE2EFCEECF2EFAE0DF2E26
+:10AB00000F9458050F94071FE091300BF0E0EE0F03
+:10AB1000FF1FEC54FD4B8591949141E060E00F9450
+:10AB2000BE9B0F900F9081116CCFAACF0F94EFB402
+:10AB30006093920A7093930A8093940A9093950A73
+:10AB4000E0914310F0914410EB5BFF4E8081813027
+:10AB5000B9F4EAEEF1E485919491FC012491222369
+:10AB600041F03091C00035FFFCCF2093C600019624
+:10AB7000F4CF8091C00085FFFCCF8AE08093C600AF
+:10AB800008958EE799E00E946B41EAE8F1E485912F
+:10AB90009491FC012491222341F03091C00035FFB3
+:10ABA000FCCF2093C6000196F4CF4091291050911C
+:10ABB0002A1060912B1070912C104F5F5F4F6F4FD8
+:10ABC0007F4F2AE030E08EE799E00E940A428091B0
+:10ABD000C00085FFFCCF8AE08093C600A7CF8F928C
+:10ABE0009F92AF92BF92CF92DF92EF92FF920F931C
+:10ABF0001F93CF93DF93B9E7EB2EB5E0FB2E00EE6A
+:10AC00001AE0CBEADAE082E6C82E8BE0D82EF70114
+:10AC100081917F010E94EF43882319F10E945C44D7
+:10AC20004B015C01F6018081811103C06091960A9D
+:10AC300001C061E070E080E090E00F9468BEF80130
+:10AC400020813181428153810F949BC09B01AC01D3
+:10AC5000C501B4010F94EDBC688379838A839B831B
+:10AC600009C0F80180819181A281B3818883998391
+:10AC7000AA83BB830C5F1F4F2496FFEFCF1ADF0A16
+:10AC80008DE7E81685E0F80611F686E40E94EF43AA
+:10AC90008823D9F00E945C446B017C0160939B0A7D
+:10ACA00070939C0A80939D0A90939E0A20E030E066
+:10ACB000A9010F94C9BF181644F4C0920C02D09297
+:10ACC0000D02E0920E02F0920F02DF91CF911F91E0
+:10ACD0000F91FF90EF90DF90CF90BF90AF909F903B
+:10ACE0008F9008957CDF89E40E94EF43882359F018
+:10ACF0000E945C4460939F0A7093A00A8093A10A0B
+:10AD00009093A20A08C010929F0A1092A00A109273
+:10AD1000A10A1092A20A8AE40E94EF43882359F004
+:10AD20000E945C446093A30A7093A40A8093A50ACE
+:10AD30009093A60A08951092A30A1092A40A109262
+:10AD4000A50A1092A60A0895CF92DF92EF92FF9281
+:10AD5000CF93DF93EC01BC016C5F7F4F0E941D47D6
+:10AD600020E030E0A90160913C0270913D028091A9
+:10AD70003E0290913F020F94EDBC6B017C019B0160
+:10AD8000AC01688579858A859B850F94C6BD87FF50
+:10AD900004C0C886D986EA86FB86C0903002D0906F
+:10ADA0003102E0903202F0903302A70196016885EB
+:10ADB00079858A859B850F94C9BF181624F4C886A7
+:10ADC000D986EA86FB86DF91CF91FF90EF90DF90E6
+:10ADD000CF9008952F923F924F925F926F927F9201
+:10ADE0008F929F92AF92BF92CF92DF92EF92FF929B
+:10ADF0000F931F93CF93DF93CDB7DEB7AB970FB60B
+:10AE0000F894DEBF0FBECDBF9F878E87798B688B8E
+:10AE10005B8B4A8B3D8B2C8B1F8B0E8BED82DC0169
+:10AE20008D909D90AD90BC904090E00A5090E10ACA
+:10AE30006090E20A7090E30ADB018D919D910D9084
+:10AE4000BC91A02D88879987AA87BB87C090E40A08
+:10AE5000D090E50AE090E60AF090E70A2091E80A2F
+:10AE60003091E90A4091EA0A5091EB0AEA89FB899C
+:10AE700060817181828193810F94ECBC688F798F9E
+:10AE80008A8F9B8F80917712811173C0AE89BF89A1
+:10AE90008D909D90AD90BC90EA89FB89E080F18017
+:10AEA00002811381A889B9892D913D914D915C91C1
+:10AEB000EE85FF856081718182819381FE013596E7
+:10AEC000FF93EF93CC88DD880F945805EE85FF85BE
+:10AED00080819181A281B3818093E00A9093E10AFD
+:10AEE000A093E20AB093E30AE889F989808191810D
+:10AEF000A281B3818093E40A9093E50AA093E60AC5
+:10AF0000B093E70AEA89FB8980819181A281B381AC
+:10AF10008093E80A9093E90AA093EA0AB093EB0AB7
+:10AF2000EC89FD8980819181A281B3818093EC0AB3
+:10AF30009093ED0AA093EE0AB093EF0A0F900F9052
+:10AF4000AB960FB6F894DEBF0FBECDBFDF91CF91A9
+:10AF50001F910F91FF90EF90DF90CF90BF90AF9037
+:10AF60009F908F907F906F905F904F903F902F9029
+:10AF70000895A3019201C501B4010F94ECBC2B010B
+:10AF80003C0120E030E0A9010F94C9BF5301420108
+:10AF9000181624F0B7FAB094B7F8B094A701960148
+:10AFA000688579858A859B850F94ECBC688779874D
+:10AFB0008A879B8720E030E0A9010F94C9BF2885CC
+:10AFC00039854A855B8518160CF05058C501B401C7
+:10AFD0000F94EDBC6B017C0120E030E0A9010F94DF
+:10AFE000C9BF18160CF052CF20E030E040EF51E41A
+:10AFF000C701B6010F94CDBD0F94B3BD0F9435BEFC
+:10B000007D876C87623071050CF440CF2091EC0A8B
+:10B010003091ED0A4091EE0A5091EF0AAC89BD895A
+:10B020006D917D918D919C910F94ECBC6C8F7D8F77
+:10B030008E8F9F8F22242394312C8C859D85AA2767
+:10B0400097FDA095BA2F88A799A7AAA7BBA7DE014D
+:10B050001596BF83AE83B101882777FD8095982F21
+:10B060000F9468BE6B017C0168A579A58AA59BA594
+:10B070000F9468BE9B01AC01C701B6010F94CDBD12
+:10B080006B017C01EE89FF8980809180A280B38072
+:10B090002C8D3D8D4E8D5F8D0F949BC09B01AC011F
+:10B0A0006091EC0A7091ED0A8091EE0A9091EF0A9E
+:10B0B0000F94EDBC69837A838B839C83288D398DB3
+:10B0C0004A8D5B8DC701B6010F949BC02091E80AA1
+:10B0D0003091E90A4091EA0A5091EB0A0F94EDBCD5
+:10B0E00068A379A38AA39BA3288539854A855B85B4
+:10B0F000C701B6010F949BC02091E40A3091E50A84
+:10B100004091E60A5091E70A0F94EDBC6CA37DA331
+:10B110008EA39FA3A3019201C701B6010F949BC008
+:10B120002091E00A3091E10A4091E20A5091E30A4D
+:10B130000F94EDBCFF81FF932E812F93DE011196BA
+:10B140006D01E8A0F9A00AA11BA12CA13DA14EA16F
+:10B150005FA10F945805BFEF2B1A3B0A0F900F9079
+:10B16000EC85FD852E163F0609F075CF8FCE4F92E8
+:10B170005F926F927F928F929F92AF92BF92CF9287
+:10B18000DF92EF92FF920F931F93CF93DF93CDB790
+:10B19000DEB728970FB6F894DEBF0FBECDBF8BEA9F
+:10B1A0009AE0D2DD0F94EFB46093920A7093930A01
+:10B1B0008093940A9093950A8091AB0A9091AC0A7F
+:10B1C000A091AD0AB091AE0A8D839E83AF83B887FC
+:10B1D0009C01AD016091E00A7091E10A8091E20A60
+:10B1E0009091E30A0F94C6BD811197C04090AF0AB9
+:10B1F0005090B00A6090B10A7090B20AA301920117
+:10B200006091E40A7091E50A8091E60A9091E70A5C
+:10B210000F94C6BD811181C020E030E040E752E4C8
+:10B2200060910C0270910D0280910E0290910F02BC
+:10B230000F94CDBD4B015C01E090B30AF090B40ACD
+:10B240000091B50A1091B60A8CEC9AE09F938F9307
+:10B2500027EBC22E2AE0D22EA30192016D817E81BE
+:10B260008F8198850F9458050F900F908091AB0AAD
+:10B270009091AC0AA091AD0AB091AE0A8093E00A19
+:10B280009093E10AA093E20AB093E30A8091AF0A97
+:10B290009091B00AA091B10AB091B20A8093E40AE9
+:10B2A0009093E50AA093E60AB093E70A8091B30A67
+:10B2B0009091B40AA091B50AB091B60A8093E80AB9
+:10B2C0009093E90AA093EA0AB093EB0A8091B70A37
+:10B2D0009091B80AA091B90AB091BA0A8093EC0A89
+:10B2E0009093ED0AA093EE0AB093EF0A28960FB65A
+:10B2F000F894DEBF0FBECDBFDF91CF911F910F91AC
+:10B30000FF90EF90DF90CF90BF90AF909F908F9085
+:10B310007F906F905F904F900895E090CC0A60917D
+:10B32000560270915702882777FD8095982F0F94C9
+:10B3300068BE20910C0230910D0240910E02509196
+:10B340000F020F949BC02EE333EC4EE259E30F94AF
+:10B350009BC069837A838B839C838E010F5F1F4F11
+:10B3600027EB3AE043EB5AE06FEA7AE08BEA9AE0A7
+:10B3700031DD7CCF4F925F926F927F928F929F923E
+:10B38000AF92BF92CF92DF92EF92FF920F931F93F3
+:10B39000CF93C62FE091CC0AF0E0882309F4D9C0FE
+:10B3A000DF01A853B54F8C918111AFC18091E00AA4
+:10B3B0009091E10AA091E20AB091E30A8093AB0A6E
+:10B3C0009093AC0AA093AD0AB093AE0A8091E40AC0
+:10B3D0009091E50AA091E60AB091E70A8093AF0A3E
+:10B3E0009093B00AA093B10AB093B20A8091E80A90
+:10B3F0009091E90AA091EA0AB091EB0A8093B30A0E
+:10B400009093B40AA093B50AB093B60AC090EC0A20
+:10B41000D090ED0AE090EE0AF090EF0AC092B70AE1
+:10B42000D092B80AE092B90AF092BA0AEE0FFF1F62
+:10B43000EE0FFF1FE05CFD4F20813181428153817F
+:10B44000662349F0609120027091210280912202CE
+:10B450009091230208C0609124027091250280918E
+:10B460002602909127020F94CDBD9B01AC01C7012C
+:10B47000B6010F94EDBC6093EC0A7093ED0A8093D3
+:10B48000EE0A9093EF0A8CEE9AE00F94B11380903D
+:10B490000C0290900D02A0900E02B0900F0220E0DE
+:10B4A00030E040E752E460911C0270911D028091EF
+:10B4B0001E0290911F020F949BC060930C02709328
+:10B4C0000D0280930E0290930F02E091CC0AF0E0FF
+:10B4D000E853F54F81E080834ADE2091C40A309121
+:10B4E000C50A4091C60A5091C70A6091E80A709156
+:10B4F000E90A8091EA0A9091EB0A0F94ECBC7B0177
+:10B500008C016093E80A7093E90A8093EA0A9093A9
+:10B51000EB0A2091E40A3091E50A4091E60A509145
+:10B52000E70A6091E00A7091E10A8091E20A909145
+:10B53000E30AECEECE2EEAE0DE2E0F94061217DEC2
+:10B5400080920C0290920D02A0920E02B0920F0215
+:10B55000DCC0E853F54F8081882309F4D6C0809081
+:10B56000E00A9090E10AA090E20AB090E30A80928B
+:10B57000AB0A9092AC0AA092AD0AB092AE0A40908B
+:10B58000E40A5090E50A6090E60A7090E70A40925B
+:10B59000AF0A5092B00A6092B10A7092B20A6091FA
+:10B5A000E80A7091E90A8091EA0A9091EB0A6093A7
+:10B5B000B30A7093B40A8093B50A9093B60A0091C7
+:10B5C000EC0A1091ED0A2091EE0A3091EF0A0093F7
+:10B5D000B70A1093B80A2093B90A3093BA0A209197
+:10B5E000C40A3091C50A4091C60A5091C70A0F9407
+:10B5F000EDBC7B018C016093E80A7093E90A8093AB
+:10B60000EA0A9093EB0A3CEEC32E3AE0D32EA30154
+:10B610009201C501B4010F9406121091CC0ACC23FB
+:10B6200089F02091BC0A3091BD0A4091BE0A509128
+:10B63000BF0A6091200270912102809122029091B4
+:10B64000230210C02091C00A3091C10A4091C20A61
+:10B650005091C30A609124027091250280912602C4
+:10B66000909127020F94EDBC24E0129FF001112469
+:10B67000E05CFD4F20813181428153810F94CDBD2B
+:10B680009B01AC016091EC0A7091ED0A8091EE0A89
+:10B690009091EF0A0F94ECBC6093EC0A7093ED0A62
+:10B6A0008093EE0A9093EF0A8CEE9AE00F94B11318
+:10B6B000C0900C02D0900D02E0900E02F0900F02AC
+:10B6C00020E030E040E752E46091180270911902E6
+:10B6D00080911A0290911B020F949BC060930C0200
+:10B6E00070930D0280930E0290930F02E091CC0AAA
+:10B6F000F0E0E853F54F10823ADDC0920C02D09290
+:10B700000D02E0920E02F0920F02CF911F910F9165
+:10B71000FF90EF90DF90CF90BF90AF909F908F9071
+:10B720007F906F905F904F900895AF92BF92CF92AD
+:10B73000DF92EF92FF920F931F93CF93DF93D82F57
+:10B740002091A30A3091A40A4091A50A5091A60A1B
+:10B7500060919F0A7091A00A8091A10A9091A20A1B
+:10B760000F94D6BFC62F172F082FF92E60915602BF
+:10B7700070915702882777FD8095982F0F9468BEA7
+:10B7800020910C0230910D0240910E0250910F0257
+:10B790000F949BC020E030E040E752E40F94CDBD11
+:10B7A00020E030E048EC52E40F94CDBD2091CC0A6B
+:10B7B0002F93DF93FF920F931F93CF935B016C0145
+:10B7C000B2E0EB2E01E020E04FE95AE06BEA7AE0CC
+:10B7D00080EE9AE00E94D8FB8091AB0A9091AC0A6F
+:10B7E000A091AD0AB091AE0A8093E00A9093E10A6D
+:10B7F000A093E20AB093E30A8091AF0A9091B00A55
+:10B80000A091B10AB091B20A8093E40A9093E50A3C
+:10B81000A093E60AB093E70A8091B30A9091B40A24
+:10B82000A091B50AB091B60A8093E80A9093E90A0C
+:10B83000A093EA0AB093EB0A8091B70A9091B80AF4
+:10B84000A091B90AB091BA0A8093EC0A9093ED0ADC
+:10B85000A093EE0AB093EF0A0F94EFB46093920AAC
+:10B860007093930A8093940A9093950A0F900F9087
+:10B870000F900F900F900F90DF91CF911F910F912C
+:10B88000FF90EF90DF90CF90BF90AF900895EC01C4
+:10B89000EEE1FBE08491882341F09091C00095FF98
+:10B8A000FCCF8093C6003196F5CF70E04AE050E0BF
+:10B8B0008EE799E00E944942F8940F94FF28179A66
+:10B8C0001092D10A169A1092D20A149AE5E4F0E185
+:10B8D0008491882341F09091C00095FFFCCF809324
+:10B8E000C6003196F5CFE8EDF2E485919491FC0124
+:10B8F0002491222341F03091C00035FFFCCF2093EA
+:10B90000C6000196F4CF8091C00085FFFCCF8AE08D
+:10B910008093C6002097C9F0FE018491FE01882320
+:10B9200049F09091C00095FFFCCF8093C6003196FE
+:10B930008491F5CF8091C00085FFFCCF8AE0809391
+:10B94000C600CE010E94344806C0E4E6F2E48591C8
+:10B9500094910F94A9517894C6E0D0E0219751F0CA
+:10B9600068EC70E080E090E00F941EB580E00F94EA
+:10B970000A97F4CFF894A895FECFCF92DF92EF927A
+:10B98000FF920F931F93CF93C82F80913F109091F8
+:10B990004010039714F40E94BDC40F94EFB40091BB
+:10B9A0008E0A10918F0A2091900A3091910AC090CE
+:10B9B000920AD090930AE090940AF090950A6C193C
+:10B9C0007D098E099F09061717072807390740F4D4
+:10B9D000012B022B032B21F064E08EEF98E057DF60
+:10B9E000409108025091090260910A0270910B0285
+:10B9F000452B462B472B19F10F94EFB40091920A77
+:10BA00001091930A2091940A3091950A601B710B52
+:10BA1000820B930B009108021091090220910A02F7
+:10BA200030910B02061717072807390740F4909149
+:10BA3000641380916313981302C0CC2349F0CF9113
+:10BA40001F910F91FF90EF90DF90CF900D948603A0
+:10BA5000179A1092D10A169A1092D20A149AEFCF1E
+:10BA60000F94FF288091800A81113DC081E080936E
+:10BA7000800A8091291090912A10A0912B10B091EA
+:10BA80002C108093251090932610A0932710B0932C
+:10BA90002810E5E4F0E18491882341F09091C00002
+:10BAA00095FFFCCF8093C6003196F5CFEEECF2E423
+:10BAB00085919491FC012491222341F03091C000A2
+:10BAC00035FFFCCF2093C6000196F4CF8091C000D3
+:10BAD00085FFFCCF8AE08093C600E6ECF0E4859118
+:10BAE00094910D947E5108958091800A0895CF938A
+:10BAF000DF93EC018091CC0A8093810A84E50E9457
+:10BB0000EF43811102C080E084C00E945C440F9426
+:10BB10003ABE6093810A6623B1F3EFE3F0E18491CA
+:10BB2000882341F09091C00095FFFCCF8093C60020
+:10BB30003196F5CFCD36D10509F435C064F4C83659
+:10BB4000D105B1F0C936D10509F052C0E4E4F2E400
+:10BB5000A591B49124C0CA3DD10509F432C0CD3DB0
+:10BB6000D10509F045C0E4E3F2E4A591B4913DC0EC
+:10BB7000E6E4F2E485919491FC012491222309F4F6
+:10BB800037C03091C00035FFFCCF2093C60001962E
+:10BB9000F3CF9091C00095FFFCCF8093C6008D91AC
+:10BBA0008111F7CF25C0E2E4F2E4A591B4918D9123
+:10BBB0008823F1F09091C00095FFFCCF8093C600E0
+:10BBC000F6CFE6E3F2E4A591B4918D91882381F05C
+:10BBD0009091C00095FFFCCF8093C600F6CF909166
+:10BBE000C00095FFFCCF8093C6008D918111F7CFE7
+:10BBF0006091810A70E04AE050E08EE799E00E948F
+:10BC000042428091C00085FFFCCF8AE08093C6004D
+:10BC100081E0DF91CF9108954F925F926F927F9272
+:10BC20008F929F92AF92BF92CF92DF92EF92FF924C
+:10BC3000CF93DF9300D01F92CDB7DEB72B013C012D
+:10BC400029833A834B835C838DEE9FE00F9444CA33
+:10BC50008F3F01F58EEE9FE00F9444CA8F3FD1F4E1
+:10BC60008FEE9FE00F9444CA8F3FA1F480EF9FE0D6
+:10BC70000F9444CA8F3F71F440E050E0BA018DEE5A
+:10BC80009FE00F9468CA40E050E0BA0181EF9FE066
+:10BC90000F9468CA81EF9FE00F944CCA4B015C017E
+:10BCA0008DEE9FE00F944CCA6B017C0169817A8113
+:10BCB0008B819C812CE330E040E050E00F949DC2EA
+:10BCC000C20ED31EE41EF51EB701A6018DEE9FE045
+:10BCD0000F9468CAC301B20128EE33E040E050E09F
+:10BCE0000F949DC2BA01A901480D591D6A1D7B1D03
+:10BCF00081EF9FE00F9468CA1092290B10922A0BD3
+:10BD000010922B0B10922C0B0F900F900F900F9006
+:10BD1000DF91CF91FF90EF90DF90CF90BF90AF90E9
+:10BD20009F908F907F906F905F904F900895CF92EB
+:10BD3000DF92EF92FF922091F00A2223F1F020E0AF
+:10BD400030E040E05FE30F949BC06B017C0120E09A
+:10BD500030E0A9010F94C6BD882379F0A7019601B0
+:10BD6000C701B6010F949BC02BED3FE049E450E4BE
+:10BD70000F949BC09B01AC0104C020E030E040E880
+:10BD80005FE360E070E080E89FE30F94CDBDFF903B
+:10BD9000EF90DF90CF90089560914402709145023A
+:10BDA0008091460290914702C2DF609340027093F7
+:10BDB000410280934202909343020895CF93DF9310
+:10BDC000EC010F94F32B81E0D8DD80E00F940A970B
+:10BDD000209799F0C233D10540F062E370E080E033
+:10BDE00090E00F941EB5E297ECCFBE0180E090E0AA
+:10BDF0000F941EB5C0E0D0E0E4CFDF91CF9108955D
+:10BE00002F923F924F925F926F927F928F929F926A
+:10BE1000AF92BF92CF92DF92EF92FF921F93CF9398
+:10BE2000DF934B015C01CC24CA94DC2C760153E1F6
+:10BE3000252E5BE0352E68EE462E63E0562E612CF3
+:10BE4000712C1AE08091BB0A811126C12FEFC21616
+:10BE5000D206E206F20651F0F7FC1EC10F94EFB4D1
+:10BE60006C197D09683B7B4008F016C10F94EFB454
+:10BE7000681979098A099B09693E73408105910512
+:10BE800008F47FC08091921B811177C0EBE1FBE049
+:10BE90008491882341F09091C00095FFFCCF80935E
+:10BEA000C6003196F5CFE091810A24E0E29FF001CF
+:10BEB0001124E159F54E408151816281738121E065
+:10BEC00030E08EE799E00E943543E7E1FBE08491A2
+:10BED000882341F09091C00095FFFCCF8093C6006D
+:10BEE0003196F5CF6091810A70E04AE050E08EE72C
+:10BEF00099E00E944242F1018491E3E1FBE0882352
+:10BF000049F09091C00095FFFCCF8093C600319618
+:10BF10008491F5CFF7FE03C0E9EDF8E025C00F945A
+:10BF2000EFB44B015C01C701B6016854744F8F4FE9
+:10BF30009F4F681979098A099B09A30192010F94FF
+:10BF40009DC2BA01A9012AE030E08EE799E00E9483
+:10BF50000A428091C00085FFFCCF0DC09091C000C7
+:10BF600095FFFCCF8093C60081918111F7CF80911E
+:10BF7000C00085FFFCCF1093C6000F94EFB44B01B7
+:10BF80005C010F94F32B80E0F8DC80E00F940A97BB
+:10BF9000FFEFCF16DF06EF06FF0609F046C08091DF
+:10BFA0007F0AE091810AF0E0EF01CC0FDD1FCC0F9A
+:10BFB000DD1FC159D54EEE0FFF1FE958F54E8823FE
+:10BFC000D1F080819181BC01882777FD8095982FE1
+:10BFD0000F9468BE20E030E040E85FE30F94ECBCD3
+:10BFE0009B01AC01688179818A819B810F94C9BFD3
+:10BFF00087FF4DC027CF80819181BC01882777FDC5
+:10C000008095982F0F9468BE20E030E040E85FE311
+:10C010000F94EDBC9B01AC01688179818A819B8181
+:10C020000F94C6BD18169CF50DCFF7FC0BCFE09111
+:10C03000810AF0E0EF01CC0FDD1FCC0FDD1FC159ED
+:10C04000D54EEE0FFF1FE958F54E80819181BC015E
+:10C05000882777FD8095982F0F9468BE9B01AC01CF
+:10C06000688179818A819B810F94ECBC0F9435BEE5
+:10C0700097FF07C090958095709561957F4F8F4F82
+:10C080009F4F66307105810591050CF4DBCE0F944E
+:10C09000EFB46B017C01D6CEDF91CF911F91FF9061
+:10C0A000EF90DF90CF90BF90AF909F908F907F9058
+:10C0B0006F905F904F903F902F900895CF93DF93B4
+:10C0C0001F921F92CDB7DEB7BE016F5F7F4F88EF23
+:10C0D0009FE00F94A55089819A818156904F803AB4
+:10C0E0009F4020F11A821982EAEEFAE084918823B7
+:10C0F00041F09091C00095FFFCCF8093C60031962F
+:10C10000F5CF8091C00085FFFCCF8AE08093C60008
+:10C11000BE016F5F7F4F88EF9FE00F9494508DEAD0
+:10C120009AE00F947EA481E00F94D1990F900F9024
+:10C13000DF91CF9108952F923F924F925F926F922D
+:10C140007F928F929F92AF92BF92CF92DF92EF92A7
+:10C15000FF920F931F93CF93DF93CDB7DEB7CA58EB
+:10C16000D2400FB6F894DEBF0FBECDBFC958DD4F29
+:10C17000688379838A839B83C757D240FE01E75F38
+:10C18000FD4F88E2DF011D928A95E9F7E850F24001
+:10C1900080E991E0DF019C011D9221503040E1F7E0
+:10C1A000C75ADD4F19821882C955D240CE01875A2D
+:10C1B0009D4F5C014E019FE6891A9EEF990ADE01B0
+:10C1C000AF51BE4F3D0190EBC92E9FE0D92E23E227
+:10C1D000E22EF12C00E010E0C359DD4F8882CD56ED
+:10C1E000D240CD58DD4F9882C357D240B70188273F
+:10C1F00077FD8095982F0F9468BED3016D937D9342
+:10C200008D939D933D01F501619171915F018827A7
+:10C2100077FD8095982F0F9468BED4016D937D9320
+:10C220008D939D934D010F5F1F4F0630110559F0FF
+:10C23000B501C6010F94A550B5E0EB0EF11CE2E08C
+:10C24000CE0ED11CD3CFCF51DE4F288139814A8108
+:10C250005B81C15ED140C958DD4F688179818A8197
+:10C260009B81C757D2400F94C6BD87FD2BC3FE01EB
+:10C27000EF51FE4F7F016E01FFE2CF1AFEEFDF0AA2
+:10C280003E012BEB621A2DEF720AC359DD4F088174
+:10C29000CD56D240CD58DD4F1881C357D24085E0EE
+:10C2A00090E0CF58DD4F99838883C157D240CF5853
+:10C2B000DD4FA881B981C157D2401197CF58DD4FCA
+:10C2C000B983A883C157D240F701208931894289B7
+:10C2D000538964897589868997890F94ECBC4B01D1
+:10C2E0005C01D80150962D913D914D915C915397F1
+:10C2F00054966D917D918D919C9157970F94ECBCC4
+:10C30000A50194010F94CDBDF6019293829372938F
+:10C3100062936F01D301BE92AE929E928E923D01C6
+:10C3200004501109B4E0EB1AF108CF58DD4FE88151
+:10C33000F981C157D240EF2B09F0B9CF6E01FFEC64
+:10C34000CF1AFDEFDF0A3E0127E4621A2EEF720AD0
+:10C350002E013DE3430E511CCE0101967C0101E00C
+:10C3600010E0D6018D909D90AD90BC9013971496DF
+:10C370002D913D914D915C911797C501B4010F949A
+:10C38000EDBC9B01AC010F94EDBCF70164A775A750
+:10C3900086A797A70130110541F080A691A6A2A615
+:10C3A000B3A684829582A682B7820F5F1F4FD30106
+:10C3B00014962D913D914D915C91179718966D9122
+:10C3C0007D918D919C911B970F94ECBC20E030E007
+:10C3D00040EC50E40F949BC0F20160837183828330
+:10C3E0009383F4E0CF0ED11C2CE2E20EF11C34E07A
+:10C3F000630E711C88E2480E511C0530110509F0CE
+:10C40000B0CF8E010B5A1F4F6E0191E5C90ED11CA2
+:10C4100022242394312C2C0E3D1EA8ED2A0E311C13
+:10C42000F801B8972081318142815381F801608100
+:10C430007181828193810F94CDBD4B015C01E12C10
+:10C44000F12C3601F8E26F1A710826014E0C5F1CC0
+:10C45000F301EE0DFF1D2481358146815781C50111
+:10C46000B4010F949BC09B01AC01D20114966D9155
+:10C470007D918D919C9117970F94ECBCF201648390
+:10C48000758386839783F4E0EF0EF11C24E1E216B6
+:10C49000F104D9F6045D1F4F38E2C30ED11C02151A
+:10C4A000130509F0BDCF1E0185EB280E311C6E016E
+:10C4B00091EBC90ED11C3E01A7EE6A1AADEF7A0AC4
+:10C4C00014E0E12EF12C270100E010E0812C912CEA
+:10C4D000A12CB12CF601E00FF11FD301A00FB11F69
+:10C4E0002D913D914D915C9160817181828193810B
+:10C4F0000F949BC09B01AC01B401C5010F94EDBC2E
+:10C500004B015C01BFEF4B1A5B0A0C5F1F4FE5E06C
+:10C510004E165104F9F69B01AC01D1016D917D914C
+:10C520008D919C910F94ECBCF60120813181428168
+:10C5300053810F94CDBDD3016D937D938D939C93C7
+:10C540001397B1E0EB1AF108E8E22E1A3108FCE289
+:10C55000CF1AD10824E0621A7108E114F10409F03D
+:10C56000B2CFCB50DE4F88819981AA81BB81C55F54
+:10C57000D140C957DD4F88839983AA83BB83C758AD
+:10C58000D2408E01075F1D4FDE01AF5CBD4FC55825
+:10C59000DD4FB983A883CB57D240C359DD4F2880E4
+:10C5A000CD56D240CD58DD4F3880C357D240FE0122
+:10C5B000EF51FE4FC358DD4FF983E883CD57D2408A
+:10C5C000C358DD4FA881B981CD57D240CD90DD90C1
+:10C5D000ED90FD90C358DD4FB983A883CD57D2406D
+:10C5E000C958DD4F288139814A815B81C757D240C4
+:10C5F000C701B6010F94C6BD1816B4F0C358DD4F7D
+:10C60000E881F981CD57D240208131814281538127
+:10C61000C958DD4F688179818A819B81C757D24093
+:10C620000F94C6BD1816FCF4CF58DD4F2881398110
+:10C63000C157D2402430310509F01FC1C957DD4F21
+:10C64000288139814A815B81C758D240C958DD4F62
+:10C65000688179818A819B81C757D2400F94C9BF75
+:10C6600018160CF00AC1D80114968D919D910D9069
+:10C67000BC91A02DC158DD4F88839983AA83BB83C9
+:10C68000CF57D240F8014080518062807380C558F6
+:10C69000DD4FA881B981CB57D2408D919D910D90EE
+:10C6A000BC91A02DC359DD4F88839983AA83BB8396
+:10C6B000CD56D240D1018D919D910D90BC91A02D70
+:10C6C000CD57DD4F88839983AA83BB83C358D2405B
+:10C6D000A7019601C958DD4F688179818A819B81C4
+:10C6E000C757D2400F94ECBCCD58DD4F6883798397
+:10C6F0008A839B83C357D24020E030E040E450E47B
+:10C700000F94FEC06B017C01A3019201C158DD4F63
+:10C71000688179818A819B81CF57D2400F94ECBC8C
+:10C720004B015C0120E030E040EC50E4C359DD4FA8
+:10C73000688179818A819B81CD56D2400F949BC0BC
+:10C740009B01AC01C501B4010F94CDBDA7019601B9
+:10C750000F949BC06B017C0120E030E040E05FE380
+:10C76000C301B2010F949BC04B015C01CD58DD4F5A
+:10C77000288139814A815B81C357D240CA01B901FE
+:10C780000F949BC09B01AC01C501B4010F949BC0E9
+:10C790009B01AC01C701B6010F94EDBC6B017C019C
+:10C7A000CD57DD4F288139814A815B81C358D24002
+:10C7B000F10164817581868197810F94ECBCC35926
+:10C7C000DD4F288139814A815B81CD56D2400F945B
+:10C7D000CDBD4B015C01C359DD4F288139814A81B0
+:10C7E0005B81CD56D240CA01B9010F94EDBCA301C3
+:10C7F00092010F949BC02B013C01C359DD4F28814E
+:10C8000039814A815B81CD56D240C158DD4F688164
+:10C8100079818A819B81CF57D2400F949BC09B0125
+:10C82000AC01C301B2010F94EDBC20E030E040EC5C
+:10C8300050E40F94CDBD9B01AC01C501B4010F9430
+:10C84000ECBCCD58DD4F288139814A815B81C357CB
+:10C85000D2400F949BC09B01AC01C701B6010F945D
+:10C86000EDBCCD57DD4F288139814A815B81C358AA
+:10C87000D2400F94EDBC4B015C01CF58DD4F2881B5
+:10C880003981C157D2402F5F3F4FCF58DD4F398399
+:10C890002883C157D2400C5F1F4FC558DD4F888198
+:10C8A0009981CB57D2400496C558DD4F9983888330
+:10C8B000CB57D24094E0290E311C2530310509F0C8
+:10C8C0007FCE04C0812C912CA12CB12CB401C501C8
+:10C8D000C657DD4F0FB6F894DEBF0FBECDBFDF9158
+:10C8E000CF911F910F91FF90EF90DF90CF90BF906D
+:10C8F000AF909F908F907F906F905F904F903F9000
+:10C900002F900895CF92DF92EF92FF926B017C01FE
+:10C9100080915D0B8823A1F086EA9FE00F9444CAC2
+:10C92000882371F0C701B60106DC209148193091C7
+:10C93000491940914A1950914B190F94CDBD03C02C
+:10C9400060E070E0CB01FF90EF90DF90CF90089512
+:10C950004F925F926F927F928F929F92AF92BF920F
+:10C96000CF92DF92EF92FF920F931F93CF93DF93BB
+:10C97000CDB7DEB728970FB6F894DEBF0FBECDBF98
+:10C980000F94071F80915602909157029093610B6C
+:10C990008093600BE091CC0AF0E0EE0FFF1FE958A6
+:10C9A000F54E60817181882777FD8095982F0F94CF
+:10C9B00068BE6093510B7093520B8093530B90930E
+:10C9C000540B8091CA0A9091CB0A9093500B80939C
+:10C9D0004F0B0F94EFB46093370B7093380B809329
+:10C9E000390B90933A0B8091E00A9091E10AA09163
+:10C9F000E20AB091E30A89839A83AB83BC83809374
+:10CA00003F0B9093400BA093410BB093420B40908F
+:10CA1000E40A5090E50A6090E60A7090E70A4092B6
+:10CA2000430B5092440B6092450B7092460B8091E1
+:10CA3000E80A9091E90AA091EA0AB091EB0A8D8385
+:10CA40009E83AF83B8878093470B9093480BA09346
+:10CA5000490BB0934A0B6091EC0A7091ED0A8091FA
+:10CA6000EE0A9091EF0A60934B0B70934C0B8093FE
+:10CA70004D0B90934E0B20E030E040E85FE30F94C5
+:10CA8000ECBC6093EC0A7093ED0A8093EE0A9093ED
+:10CA9000EF0A8CEC9AE09F938F93812C912CB8EC49
+:10CAA000AB2EB3E4BB2E1CEEC12E1AE0D12EED80CE
+:10CAB000FE800F811885A301920169817A818B81A3
+:10CAC0009C810F94580520E030E040EA51E46091E9
+:10CAD000E80A7091E90A8091EA0A9091EB0A0F94B2
+:10CAE000EDBC2B013C010F900F9020E030E042E5BF
+:10CAF00053E40F94C9BF18164CF04092E80A5092C4
+:10CB0000E90A6092EA0A7092EB0A0CC080E090E0B9
+:10CB1000A2E5B3E48093E80A9093E90AA093EA0AB5
+:10CB2000B093EB0AE090E80AF090E90A0091EA0A73
+:10CB30001091EB0A2091E40A3091E50A4091E60A4F
+:10CB40005091E70A6091E00A7091E10A8091E20A4F
+:10CB50009091E30AACEC6A2EAAE07A2E7F926F9253
+:10CB6000812C912CB0E7AB2EB1E4BB2EECEECE2E97
+:10CB7000EAE0DE2E0F9458051092781A1092771A78
+:10CB800010927A1A1092791A10927C1A10927B1ACB
+:10CB900080E090E0A8E4B2E48093E00A9093E10A98
+:10CBA000A093E20AB093E30A80E090E0AEE3B3E43E
+:10CBB0008093E40A9093E50AA093E60AB093E70A0B
+:10CBC000E090E80AF090E90A0091EA0A1091EB0A75
+:10CBD0007F926F92812C912CF8E4AF2EF2E4BF2E5D
+:10CBE0009C01AD01C501B4010F9458051092CB0A08
+:10CBF0001092CA0A0F900F900F900F9028960FB6C0
+:10CC0000F894DEBF0FBECDBFDF91CF911F910F9182
+:10CC1000FF90EF90DF90CF90BF90AF909F908F905C
+:10CC20007F906F905F904F900D94071FE091CC0A1A
+:10CC300084E0E89FF0011124E159F54E40815181D3
+:10CC400062817381EAEAFAE08491882341F090914D
+:10CC5000C00095FFFCCF8093C6003196F5CF22E04F
+:10CC600030E08EE799E00E943543E6EAFAE08491ED
+:10CC7000882341F09091C00095FFFCCF8093C600BF
+:10CC80003196F5CF6091CC0A70E04AE050E08EE733
+:10CC900099E00E944242E2EAFAE08491882341F05E
+:10CCA0009091C00095FFFCCF8093C6003196F5CFE0
+:10CCB00040915D1A50915E1A60915F1A7091601AEE
+:10CCC00021E030E08EE799E00E9435438091C0007A
+:10CCD00085FFFCCF8AE08093C6000895CF93DF9351
+:10CCE000CDB7DEB72B970FB6F894DEBF0FBECDBF22
+:10CCF0000F94EFB46F83788789879A8720916C0BA4
+:10CD00002B87179A1092D10A169A1092D20A6CE0C9
+:10CD100082E00F94E33B6CE082E00F94243C64E1FA
+:10CD200083E00F94E33B64E183E00F94243CEDE95E
+:10CD3000FAE08491882341F09091C00095FFFCCFE8
+:10CD40008093C6003196F5CF8091C00085FFFCCF5F
+:10CD50008AE08093C60083E40F94003F1C0140905A
+:10CD600021105090221060902310709024100F9486
+:10CD70004B14481A590A610871080E94F5C9481AEB
+:10CD8000590A6108710877FE03C0412C512C320109
+:10CD90009091641380916313981799F0E091631355
+:10CDA00087E5E89FF0011124EB59FC4E20E030E0CC
+:10CDB00040E752E462A173A184A195A10F949BC0A6
+:10CDC00008C060910C0270910D0280910E0290914A
+:10CDD0000F020F9435BE7E836D830F94DD0383E0D5
+:10CDE0000F94761FAB01BC018EE69FE00F9468CADA
+:10CDF0006091650B81E0682782E79FE00F9456CA37
+:10CE00000E949BC210926C0B789420E030E040E8C6
+:10CE10005FE36091EC0A7091ED0A8091EE0A9091C7
+:10CE2000EF0A0F94ECBC69837A838B839C83E09038
+:10CE3000E80AF090E90A0091EA0A1091EB0A2091C1
+:10CE4000E40A3091E50A4091E60A5091E70A6091C0
+:10CE5000E00A7091E10A8091E20A9091E30AACEC59
+:10CE6000BAE0BF93AF93812C912CE8ECAE2EE3E4B3
+:10CE7000BE2EDE0111966D010F94580520E030E0C2
+:10CE800040E85FE36091EC0A7091ED0A8091EE0A50
+:10CE90009091EF0A0F94ECBC69837A838B839C8317
+:10CEA0002AE037ED43E25FE36091E80A7091E90A16
+:10CEB0008091EA0A9091EB0A0F94EDBC6B017C0122
+:10CEC00067E074E062197309F4E076956795FA9566
+:10CED000E1F780E090E00F9466BE20914819309110
+:10CEE000491940914A1950914B190F94CDBD9B019E
+:10CEF000AC01C701B6010F94EDBC7B018C01209100
+:10CF0000E40A3091E50A4091E60A5091E70A6091FF
+:10CF1000E00A7091E10A8091E20A9091E30AACEC98
+:10CF2000BAE0BF93AF93812C912CA0E2AA2EA2E489
+:10CF3000BA2EDE0111966D010F945805B301A201BE
+:10CF400081E99FE00F9468CA0F900F900F900F90A7
+:10CF500005E71FE0F12CB3E0EB2E809177128823D8
+:10CF600041F18F2D6E2D0F9469C2B5E18B02F00156
+:10CF7000112423E09202E00DF11D1124EE0FFF1F9A
+:10CF8000EE0FFF1FE958FD4E20E030E04AE754E481
+:10CF900061817281838194810F949BC020E030E095
+:10CFA00040E05FE30F94EDBC0F94A3BE0F9435BE39
+:10CFB00002C060E070E0C8010F9470CAF3940E5F85
+:10CFC0001F4F89E0F812C9CFB10183E79FE00F94AA
+:10CFD00070CA4091E00A5091E10A6091E20A7091B2
+:10CFE000E30A8DE99FE00F9468CA4091E40A5091EA
+:10CFF000E50A6091E60A7091E70A81EA9FE00F94E2
+:10D0000068CA4091E80A5091E90A6091EA0A709171
+:10D01000EB0A8DE89FE00F9468CABE016B5F7F4FFB
+:10D0200089E89FE00F949450E091CC0AF0E0EE0F75
+:10D03000FF1FE958F54E60818CE89FE00F9456CAB7
+:10D040006091751A8BE89FE00F9456CA6091CA0AE6
+:10D0500088E89FE00F9456CA9B85992329F061E0E8
+:10D0600085EA9FE00F9456CA0F94071FE8E9FAE09B
+:10D070008491882341F09091C00095FFFCCF80936C
+:10D08000C6003196F5CF83E40F94003F4AE050E0AC
+:10D09000BC018EE799E00E94944284E69FE00F94E1
+:10D0A00044CA61E0680F84E69FE00F9456CAEDE839
+:10D0B000FAE08491882341F09091C00095FFFCCF65
+:10D0C0008093C6003196F5CF8091C00085FFFCCFDC
+:10D0D0008AE08093C6000F94EFB4AB01BC018F814E
+:10D0E0009885A985BA85481B590B6A0B7B0B2AE0EA
+:10D0F00030E08EE799E00E94A042F894FFCF6F984D
+:10D100007798EAE6F0E080818F7B80838081806879
+:10D110008083EF9A08951F920F920FB60F921124F9
+:10D120000BB60F920F931F932F933F934F935F93E1
+:10D130006F937F938F939F93AF93BF93EF93FF93DF
+:10D140008091CA0A9091CB0A8B3491050CF441C0AE
+:10D1500080916A0086FF0BC00F94EFB46093330B8D
+:10D160007093340B8093350B9093360B2CC00F9437
+:10D17000EFB40091330B1091340B2091350B3091AB
+:10D18000360B601B710B820B930B2091CA0A3091F6
+:10D19000CB0A253631052CF003E010E020E030E02A
+:10D1A00004C004E010E020E030E06017710782075F
+:10D1B000930748F08091120B9091130B0296909375
+:10D1C000130B8093120B80916A0090E4892780935F
+:10D1D0006A00FF91EF91BF91AF919F918F917F91E5
+:10D1E0006F915F914F913F912F911F910F910F90F0
+:10D1F0000BBE0F900FBE0F901F9018956C987498EF
+:10D20000EAE6F0E080818160808380818D7F808389
+:10D21000EC9A08951F920F920FB60F9211240BB63D
+:10D220000F922F933F934F935F936F937F938F93BF
+:10D230009F93AF93BF93EF93FF93EC98E8E8FAE0E6
+:10D240008491882341F09091C00095FFFCCF80939A
+:10D25000C6003196F5CF8091C00085FFFCCF8AE0F3
+:10D260008093C60080916C0B811138DDFF91EF91A6
+:10D27000BF91AF919F918F917F916F915F914F91EE
+:10D280003F912F910F900BBE0F900FBE0F901F90EC
+:10D2900018954F925F926F927F928F929F92BF925A
+:10D2A000CF92DF92EF92FF920F931F93CF93DF9372
+:10D2B000CDB7DEB7EA970FB6F894DEBF0FBECDBF8D
+:10D2C00088E89FE00F9444CAB82EBE01675C7F4F88
+:10D2D00089E89FE00F94A550EDE0F9E08491882360
+:10D2E00041F09091C00095FFFCCF8093C60031962D
+:10D2F000F5CF69AD7AAD4AE050E08EE799E00E9443
+:10D30000494283E69FE00F9444CA882E912C4AE05C
+:10D3100050E0B4018EE799E00E94494203E11FE02A
+:10D32000E12CF12C3E0184E3680E711CE814F90431
+:10D330002CF5FE01BC962F016801C6010F9444CA6A
+:10D34000F20181932F01FFEFCF1ADF0A4614570431
+:10D35000A1F71CAABE01645D7F4F8EE799E00E9491
+:10D360003542BE01645D7F4F8AE69BE00E9479C032
+:10D370008FEFE81AF80A085F1F4FD8CF8E01015EC1
+:10D380001F4F85E9E82E8FE0F82ED02EC12EC70161
+:10D390000F9444CAF80181938F01FFEFEF1AFF0A3F
+:10D3A0008DE9E8168FE0F80691F71FA2ED2DFC2D10
+:10D3B0008191882339F09091C00095FFFCCF809334
+:10D3C000C600F6CF68E079E08D2D9C2D0F94E8C55E
+:10D3D000CF92DF9281E099E09F938F938E010F5F50
+:10D3E0001F4F1F930F930F9418C80F900F900F901B
+:10D3F0000F900F900F907E0195E0E90EF11CF70160
+:10D400008081882349F0992787FD90950F94D7C58F
+:10D41000F70181937F01F3CF60E0C8010E9411C33F
+:10D4200081E99FE00F944CCAF62EE72ED82EC92E24
+:10D43000E6EEF8E08491882341F09091C00095FFDA
+:10D44000FCCF8093C6003196F5CF2AE030E04F2D17
+:10D450005E2D6D2D7C2D8EE799E00E94A04261E04B
+:10D4600082EE98E00E9411C36DED78E0C8010F9440
+:10D47000F3C58DE99FE00F944CCA6DAB7EAB8FABCB
+:10D4800098AFCE01C5960F94F654BC01C8010F9415
+:10D4900082C66AED78E0C8010F94E8C581EA9FE092
+:10D4A0000F944CCA6DAB7EAB8FAB98AFCE01C596D7
+:10D4B0000F94F654BC01C8010F9482C663ED78E066
+:10D4C000C8010F94E8C560E0C8010E9411C36EEC6A
+:10D4D00078E0C8010F94F3C58DE89FE00F944CCA23
+:10D4E0006DAB7EAB8FAB98AFCE01C5960F94F65463
+:10D4F000BC01C8010F9482C660E0C8010E9411C33C
+:10D5000061E083EC98E00E9411C38AAD8F9389ADEE
+:10D510008F938CEB98E09F938F931F930F930F94AF
+:10D5200018C860E0C8010E9411C365EB78E0C8012B
+:10D530000F94F3C58B2D90E09EAB8DABCE01C596BD
+:10D540000F94CB57BC01C8010F9482C660E0C8019C
+:10D550000E9411C3CF92DF92EF92FF928CEA98E083
+:10D560009F938F931F930F930F9418C860E0C80187
+:10D570000E9411C361E088EA98E00E9411C30FB6CF
+:10D58000F894DEBF0FBECDBFEA960FB6F894DEBFAB
+:10D590000FBECDBFDF91CF911F910F91FF90EF9004
+:10D5A000DF90CF90BF909F908F907F906F905F9013
+:10D5B0004F9008954F925F926F927F92AF92BF9279
+:10D5C000CF92DF92EF92FF920F931F93CF93DF934F
+:10D5D000CDB7DEB7E0970FB6F894DEBF0FBECDBF74
+:10D5E0002B013C0169017A0180911F0A8111E5C07C
+:10D5F000F8940F942B148091211090912210A091F7
+:10D600002310B091241080931B0A90931C0AA093BE
+:10D610001D0AB0931E0A0F944B1440911B0A50919F
+:10D620001C0A60911D0A70911E0A481B590B610962
+:10D63000710940931B0A50931C0A60931D0A709352
+:10D640001E0A0E94F5C940911B0A50911C0A609164
+:10D650001D0A70911E0A481B590B610971094093FC
+:10D660001B0A50931C0A60931D0A70931E0A909126
+:10D67000641380916313981799F0E091631387E521
+:10D68000E89FF0011124EB59FC4E20E030E040E728
+:10D6900052E462A173A184A195A10F949BC008C01C
+:10D6A00060910C0270910D0280910E0290910F0218
+:10D6B0006093070A7093080A8093090A90930A0AF4
+:10D6C0000F94DD0380E1E0EEFAE0ABE0BAE0019018
+:10D6D0000D928A95E1F78091CC0A8093060A809199
+:10D6E00007028093050A0E949BC210926C0B81E096
+:10D6F00080931F0A789420E030E0A901C301B201B1
+:10D700000F94C6BD81110AC020E030E0A901C70115
+:10D71000B6010F94C6BD882309F44FC063EA78E0D0
+:10D72000FE0131965F01CF010F94F3C5F501019021
+:10D730000020E9F78F01015011092091130A30915F
+:10D74000140A4091150A5091160AC301B2010F94B0
+:10D75000EDBC23E048E00F9416C360EA78E0C50111
+:10D760000F94E8C5F50101900020E9F78F01015001
+:10D77000110923E046E0C701B6010F9416C36DE915
+:10D7800078E0C5010F94E8C5F50101900020E9F7A4
+:10D790008F010150110960916002709161028091C6
+:10D7A00062029091630223E048E00F9416C360E0A8
+:10D7B000C5010E9411C30E94B0C4E0960FB6F89450
+:10D7C000DEBF0FBECDBFDF91CF911F910F91FF90B4
+:10D7D000EF90DF90CF90BF90AF907F906F905F9071
+:10D7E0004F90089520E030E0A90160E070E080E211
+:10D7F00091E4E0CE8F929F92AF92BF92CF92DF9250
+:10D80000EF92FF920F931F93CF93DF9300D01F925D
+:10D81000CDB7DEB79B01AC0180911F0A882309F4C4
+:10D8200097C08091060A8093CC0A8091070A909154
+:10D83000080AA091090AB0910A0A80930C029093F9
+:10D840000D02A0930E02B0930F026091170A70911F
+:10D85000180A8091190A90911A0A0F94ECBC6983F6
+:10D860007A838B839C83CE0101960F94B11320E0C1
+:10D8700030E040E551E46091600270916102809176
+:10D880006202909163020F94CDBD4B015C01E09068
+:10D89000130AF090140A0091150A1091160A2091AB
+:10D8A0000F0A3091100A4091110A5091120A6091AA
+:10D8B0000B0A70910C0A80910D0A90910E0AECEC03
+:10D8C000FAE0FF93EF93E7E1CE2EEAE0DE2E0F942D
+:10D8D00058050F94071F80E1EBE0FAE0A0EEBAE0F4
+:10D8E00001900D928A95E1F780E1E0EEFAE0ABEA73
+:10D8F000BAE001900D928A95E1F740911B0A509190
+:10D900001C0A60911D0A70911E0A4093080E5093E4
+:10D91000090E60930A0E70930B0E83E59DE00E9442
+:10D920007FAA80911B0A90911C0AA0911D0AB091B8
+:10D930001E0A8093211090932210A0932310B0937D
+:10D94000241081E080936C0B10921F0A0F900F90AF
+:10D950000F900F900F900F90DF91CF911F910F912B
+:10D96000FF90EF90DF90CF90BF90AF909F908F90FF
+:10D97000089560E070E0CB013DCFFBDF81E0809354
+:10D98000B1020895E8E8F8E08491882341F090918D
+:10D99000C00095FFFCCF8093C6003196F5CF409133
+:10D9A000E00A5091E10A6091E20A7091E30A23E0F3
+:10D9B00030E08EE799E00E943543E5E8F8E0849195
+:10D9C000882341F09091C00095FFFCCF8093C60062
+:10D9D0003196F5CF4091E40A5091E50A6091E60A4C
+:10D9E0007091E70A23E030E08EE799E00E9435432A
+:10D9F000E2E8F8E08491882341F09091C00095FF1F
+:10DA0000FCCF8093C6003196F5CF4091E80A509143
+:10DA1000E90A6091EA0A7091EB0A23E030E08EE7B0
+:10DA200099E00E943543E0E8F8E08491882341F0D2
+:10DA30009091C00095FFFCCF8093C6003196F5CF42
+:10DA40008091C00085FFFCCF8AE08093C6000895D6
+:10DA5000E8E6F8E08491882341F09091C00095FFBA
+:10DA6000FCCF8093C6003196F5CF0F94761FAB01A3
+:10DA7000BC0123E030E08EE799E00E943543E5E603
+:10DA8000F8E08491882341F09091C00095FFFCCF8D
+:10DA90008093C6003196F5CF81E00F94761FAB01DD
+:10DAA000BC0123E030E08EE799E00E943543E2E6D6
+:10DAB000F8E08491882341F09091C00095FFFCCF5D
+:10DAC0008093C6003196F5CF82E00F94761FAB01AC
+:10DAD000BC0123E030E08EE799E00E943543E0E6A8
+:10DAE000F8E08491882341F09091C00095FFFCCF2D
+:10DAF0008093C6003196F5CF8091C00085FFFCCFA2
+:10DB00008AE08093C6000895EF92FF920F931F93CF
+:10DB1000CF93DF93ECE4F8E08491882341F0909177
+:10DB2000C00095FFFCCF8093C6003196F5CF07E784
+:10DB300012E1FAE4EF2EF8E0FF2EC0E0D0E0F801A9
+:10DB4000EC0FFD1F418152816381748123E030E03D
+:10DB50008EE799E00E943543F7018491EAE4F8E00A
+:10DB6000882349F09091C00095FFFCCF8093C600B8
+:10DB700031968491F5CF2496CC31D10501F7045E1E
+:10DB80001F4FF3E10B331F07C1F6E9E4F8E084917E
+:10DB9000882341F09091C00095FFFCCF8093C60090
+:10DBA0003196F5CF8091C00085FFFCCF8AE080934D
+:10DBB000C600DF91CF911F910F91FF90EF900895D4
+:10DBC0002F923F924F925F926F927F928F929F928D
+:10DBD000AF92BF92CF92DF92EF92FF920F931F937B
+:10DBE000CF93DF93CDB7DEB7C355D1090FB6F89405
+:10DBF000DEBF0FBECDBF82E090E09093160280930F
+:10DC0000150286EE93E00E941D448823B1F08091B6
+:10DC1000391090913A106AE270E005960F948DC623
+:10DC2000009711F0DC011C928091391090913A100C
+:10DC300005960F9471510C94159A87ED93E00E940C
+:10DC40001D44882321F00E948B480C94159A8BEE7A
+:10DC500093E00E941D44882319F08FDE0C94159ADE
+:10DC600089EF93E00E941D44882321F00E94C74859
+:10DC70000C94159A86E094E00E941D44882309F4D0
+:10DC8000C4C18CE094E00E941D44882391F08091EF
+:10DC9000921B882311F40C94159A0F94EFB460939F
+:10DCA000660B7093670B8093680B9093690B0C94D1
+:10DCB000159A81E194E00E941D44882361F06091EF
+:10DCC0002D0B70912E0B4AE050E08EE799E00E94F8
+:10DCD00094420C94159A85E194E00E941D44882397
+:10DCE00009F446C0E9E1F4E08191882339F090918C
+:10DCF000C00095FFFCCF8093C600F6CF80910C0B3F
+:10DD000090910D0B2CE3289FB001299F700D1124D9
+:10DD10004AE050E08EE799E00E9442426DE174E0F3
+:10DD20008EE799E00E943542E2E2F4E08191882397
+:10DD300039F09091C00095FFFCCF8093C600F6CFDC
+:10DD400080910E0B90910F0B2CE3289FB001299F1F
+:10DD5000700D11244AE050E08EE799E00E944242A3
+:10DD60006DE174E08EE799E00E9435420C94159ABB
+:10DD700088E294E00E941D448823C1F08091921BA8
+:10DD8000882361F06091901B7091911B4AE050E0F4
+:10DD90008EE799E00E9449420C94159A6BE274E078
+:10DDA0008EE799E00E9435420C94159A8DE394E039
+:10DDB0000E941D44882379F16091391070913A10C6
+:10DDC0006D5F7F4F21E041E08AE69BE00E94D3BC7B
+:10DDD00080915B0D90915C0DA0915D0DB0915E0DF9
+:10DDE0008093080E9093090EA0930A0EB0930B0E29
+:10DDF00083E59DE00E94B6A92091C00025FFFCCFDD
+:10DE00008093C6000A9721F760E08AE69BE00E94B3
+:10DE100063BC0C94159A80E494E00E941D4488230E
+:10DE200099F00E94B75181E080932F0B60913910D7
+:10DE300070913A106C5F7F4F21E040E08AE69BE0F2
+:10DE40000E94D3BC0C94159A84E494E00E941D4473
+:10DE5000882309F445C08091921B882309F49ECF42
+:10DE60001092030AE7E4F4E08191882339F090915D
+:10DE7000C00095FFFCCF8093C600F6CF00E010E015
+:10DE8000FF24F3948091FF099091000A2091010AE8
+:10DE90003091020A821B930B8F779927892B89F087
+:10DEA0008EE799E00E944F41F092030A9091C000E2
+:10DEB00095FFFCCF8093C6000F5F1F4F1092030A9F
+:10DEC000E1CF03311105F4F281E08093030A8091E0
+:10DED000C00085FFFCCF8AE08093C6000C94159AA1
+:10DEE0008AE494E00E941D448823A9F0EEE4F4E063
+:10DEF0008191882339F09091C00095FFFCCF8093E9
+:10DF0000C600F6CF8091C00085FFFCCF8AE08093E9
+:10DF1000C6000C94159A88E594E00E941D4488235D
+:10DF2000A9F0ECE5F4E08191882339F09091C000EC
+:10DF300095FFFCCF8093C600F6CF8091C00085FF8F
+:10DF4000FCCF8AE08093C6000C94159A8AE794E08F
+:10DF50000E941D44882321F00F940F510C94159AB0
+:10DF60008FE794E00E941D44882341F060E070E058
+:10DF700088EF9FE00F9494500C94159A82E894E0F7
+:10DF80000E941D44882359F062E874E08EE799E00E
+:10DF90000E94354240E052EC61E070E010C08DE834
+:10DFA00094E00E941D44882381F06DE874E08EE7C0
+:10DFB00099E00E94354240E054E961E170E08EE76B
+:10DFC00099E00E94D4400C947F9B89E994E00E94E0
+:10DFD0001D44882361F00F94EFB46093590B709344
+:10DFE0005A0B80935B0B90935C0B0C94159A8EE903
+:10DFF00094E00E941D44882311F40C94159A61E06A
+:10E0000080E00E94D2480C94159A8EE50E94EF435E
+:10E0100081110C94159A87E40E94EF43882311F430
+:10E020000C94C17F0E945C440F9435BE6C34710522
+:10E0300009F430C47CF56430710509F409C154F465
+:10E040006230710509F4ECC00CF0F6C077FF78C0BF
+:10E050000C94159A6C31710509F451C17CF46A3045
+:10E06000710509F446C16B30710511F00C94159AD5
+:10E0700060E080E00E94BA590C94159A6E317105E7
+:10E0800009F44DC36B34710511F00C94159A08E234
+:10E0900010E0F6C36735710511F40C94417F14F557
+:10E0A0006035710511F40C941A796CF46F347105B4
+:10E0B00011F00C94159A0FEF10E0A8E2CA2EADE013
+:10E0C000DA2E0C9405796135710511F40C94887E73
+:10E0D0006635710511F00C94159A86EE0E9442483F
+:10E0E0000C94159A6C35710511F40C944A7F7CF4EC
+:10E0F0006A35710511F40C94467F6B35710511F08A
+:10E100000C94159A81E08093960A0C94159A6236C5
+:10E11000710511F40C94AC7F6336710511F00C9409
+:10E12000159A1092921B0F9414516091921B84ECDB
+:10E130009FE00F9456CA82E00F940A970C94159AA8
+:10E140008091800A81110C94159A0E94EF5560917C
+:10E15000290B70912A0B80912B0B90912C0B0F9413
+:10E1600066BE6B017C014090EC0A5090ED0A609015
+:10E17000EE0A7090EF0A8090B70A9090B80AA090CB
+:10E18000B90AB090BA0AA5019401C301B2010F9473
+:10E19000ECBC20E030E048EC52E40F949BC09B01C3
+:10E1A000AC01C701B6010F94C9BF1816E4F4A3016E
+:10E1B0009201C501B4010F94ECBC20E030E048ECC2
+:10E1C00052E40F949BC09B01AC01C701B6010F94B0
+:10E1D000EDBC0F943ABE6093290B70932A0B809389
+:10E1E0002B0B90932C0B8091C90A8823A9F088E50A
+:10E1F0000E94EF43811110C089E50E94EF43811115
+:10E200000BC08AE50E94EF43811106C085E40E949D
+:10E21000EF4381110C941E9A0E94B7580C94159AE2
+:10E220008091800A81110C94159A0E94725681E0A7
+:10E230000E94955B0C94159A8091800A81110C9430
+:10E24000159A0E94725680E00E94955B0C94159A74
+:10E2500080E50E94EF43882339F00E945C440F94CC
+:10E260003ABE6B017C0103C0C12CD12C760183E541
+:10E270000E94EF43882361F00E945C4420E030E07C
+:10E280004AE754E40F949BC00F943ABE6B017C01A3
+:10E29000C114D104E104F10431F0EAEEF2E4859115
+:10E2A00094910F947E510F94071F0F94EFB44B017C
+:10E2B0005C018C0C9D1CAE1CBF1C0F94EFB46093D2
+:10E2C000920A7093930A8093940A9093950A0F94FC
+:10E2D000EFB4681579058A059B0510F00C94159A22
+:10E2E0000F94F32B80E00E94BD5C80E00F940A97AE
+:10E2F000EECF60E081E00E94BA590C94159A0F9419
+:10E30000071FE6E5FEE08491882341F09091C0006C
+:10E3100095FFFCCF8093C6003196F5CF33DBE8E460
+:10E32000FEE08491882341F09091C00095FFFCCFDE
+:10E330008093C6003196F5CF8BDB81E080935E0B36
+:10E3400088E50E94EF43182F89E50E94EF43082FCC
+:10E350008AE50E94EF43782E101308C0181711F0B9
+:10E36000012F04C07724739401E011E00E9455DB73
+:10E37000609077121092771282E00F94761F60936C
+:10E38000E80A7093E90A8093EA0A9093EB0A711005
+:10E390000E9429F940910C0250910D0260910E02E9
+:10E3A00070910F024093970A5093980A6093990ACC
+:10E3B00070939A0A80915602909157029093610B44
+:10E3C0008093600B84E690E090935702809356020E
+:10E3D0000F94EFB46093920A7093930A8093940A17
+:10E3E0009093950A81E00F948C1580E1E0EEFAE0BD
+:10E3F000ABEABAE001900D928A95E1F710920C0217
+:10E4000010920D0210920E0210920F02112321F0B1
+:10E4100080E090E00E94574D002321F081E090E0E1
+:10E420000E94574D88E50E94EF43882341F00E94E7
+:10E430001244672B682B692B11F00C944D9A89E5D7
+:10E440000E94EF43882341F00E941244672B682BFF
+:10E45000692B11F00C94639A772009F4F1C0809134
+:10E46000D10A882321F08091D20A811108C080E06E
+:10E4700090E00E94574D81E090E00E94574D0E942D
+:10E48000AADBE4EEF5E485919591A591B491898399
+:10E490009A83AB83BC83E0EEF5E485919591A591D9
+:10E4A000B4918F8F98A3A9A3BAA32FEA3AE04BEABD
+:10E4B0005AE0BE016F5F7F4FCE014F960E946346C8
+:10E4C0000E941CDB20E030E040E850EC6091AF0A95
+:10E4D0007091B00A8091B10A9091B20A0F94C6BDB2
+:10E4E00087FF0CC080E090E0A0E8B0EC8093AF0A1A
+:10E4F0009093B00AA093B10AB093B20A80E090E082
+:10E50000A0EAB0E48093B30A9093B40AA093B50A4A
+:10E51000B093B60A20E030E040E251E4609160023E
+:10E520007091610280916202909163020F94CDBD5F
+:10E5300060930C0270930D0280930E0290930F0271
+:10E540001092E80A1092E90A1092EA0A1092EB0A75
+:10E5500080E00F948C15E090E80AF090E90A0091B1
+:10E56000EA0A1091EB0A2091E40A3091E50A409101
+:10E57000E60A5091E70A6091E00A7091E10A809101
+:10E58000E20A9091E30AFCEECF2EFAE0DF2E0F9420
+:10E59000061280900C0290900D02A0900E02B09096
+:10E5A0000F02E090B30AF090B40A0091B50A1091FE
+:10E5B000B60A2091AF0A3091B00A4091B10A509149
+:10E5C000B20A6091AB0A7091AC0A8091AD0A909149
+:10E5D000AE0AECECFAE0FF93EF93A7EBCA2EAAE0A9
+:10E5E000DA2E0F9458050F94071F8091AB0A909173
+:10E5F000AC0AA091AD0AB091AE0A8093E00A909364
+:10E60000E10AA093E20AB093E30A8091AF0A9091E5
+:10E61000B00AA091B10AB091B20A8093E40A909333
+:10E62000E50AA093E60AB093E70A81E00F948C15FF
+:10E630000F94741582E090E00E94574D0F900F9058
+:10E640008AE50E94EF43882341F00E941244672B21
+:10E65000682B692B11F00C94799AE090E80AF090FD
+:10E66000E90A0091EA0A1091EB0A2091E40A30913C
+:10E67000E50A4091E60A5091E70A6091E00A70913C
+:10E68000E10A8091E20A9091E30AECEECE2EEAE0F4
+:10E69000DE2E0F94061280E00F948C158091970A5D
+:10E6A0009091980AA091990AB0919A0A80930C02CD
+:10E6B00090930D02A0930E02B0930F028091600B15
+:10E6C0009091610B90935702809356020F94EFB490
+:10E6D0006093920A7093930A8093940A9093950A98
+:10E6E0000F9474150E94AADB0E94C6DD88E50E9483
+:10E6F000EF4381110C948F9A89E50E94EF438111B9
+:10E700000C948F9A87E50E94EF4381110C948F9AA5
+:10E710008AE50E94EF4381110C948F9A87C50F946C
+:10E72000071F81E00E949B438091600290916102EB
+:10E73000A0916202B091630280930C0290930D024B
+:10E74000A0930E02B0930F0220E030E043E060E0BF
+:10E7500070E080E291EC0E9455DEE2E8F3E48591FE
+:10E760009491FC012491222341F03091C00035FFA7
+:10E77000FCCF2093C6000196F4CFEFE1FEE0849138
+:10E78000882341F09091C00095FFFCCF8093C60094
+:10E790003196F5CF4091E00A5091E10A6091E20A8A
+:10E7A0007091E30A25E030E08EE799E00E9435435E
+:10E7B000EAE1FEE08491882341F09091C00095FF4A
+:10E7C000FCCF8093C6003196F5CF4091E40A50917A
+:10E7D000E50A6091E60A7091E70A25E030E08EE7ED
+:10E7E00099E00E943543E5E1FEE08491882341F001
+:10E7F0009091C00095FFFCCF8093C6003196F5CF75
+:10E800004091E80A5091E90A6091EA0A7091EB0A96
+:10E8100025E030E08EE799E00E943543E3E1FEE039
+:10E820008491882341F09091C00095FFFCCF8093A4
+:10E83000C6003196F5CF0E94C9430C94159A909169
+:10E84000C00095FFFCCF8093C60081918111F7CF66
+:10E85000B801882777FD8095982F0F9468BE0E9495
+:10E860009B60AB01BC0122E030E08EE799E00E94A2
+:10E8700036430F5F1F4F0F36110511F40C94159A94
+:10E880004AE050E0B8018EE799E00E944242EDEC88
+:10E89000F8E0DBCF8091D10A882341F08091D20A41
+:10E8A000882321F08091D30A811109C00E94B0C44D
+:10E8B00061E08CE09EE00E94F8C30C94159A81E020
+:10E8C00090E09093160280931502EEEEFDE08491A5
+:10E8D000882341F09091C00095FFFCCF8093C60043
+:10E8E0003196F5CF8091C00085FFFCCF8AE0809300
+:10E8F000C6001A821982C090691AD0906A1AE090F4
+:10E900006B1AF0906C1A20E030E040EA50E4C70146
+:10E91000B6010F94CDBD0F9435BE45E0469F9001E2
+:10E92000479F300D1124B901882777FD8095982FD6
+:10E930000F9468BE2B013C0120E030E04CE052E433
+:10E940000F94C6BD87FF06C0412C512C2CE0622ECF
+:10E9500022E4722EA7019601C301B2010F94C6BD35
+:10E9600087FF0AC020E030E040EA50E4C301B20172
+:10E970000F94EDBC2B013C01EAEDFDE0849188236E
+:10E9800041F09091C00095FFFCCF8093C600319676
+:10E99000F5CF22E030E0B301A2018EE799E00E94BA
+:10E9A000364320E030E040EF51E4C301B2010F9460
+:10E9B000ECBC20E030E04CE852E40F94EDBC0F9446
+:10E9C00035BE7093761A6093751A84E090E0909348
+:10E9D000220B8093210B81E090E09093200B809399
+:10E9E0001F0BE091300BF0E0EE0FFF1FEA54FF4BDE
+:10E9F0008591949121E0892B09F420E02093240B48
+:10EA000080E090E0A0EAB1E48093E00A9093E10A0C
+:10EA1000A093E20AB093E30A80E090E0A0E7B2E4BA
+:10EA20008093E40A9093E50AA093E60AB093E70A7C
+:10EA30008AE999E9A9E1BEE38093E80A9093E90A9B
+:10EA4000A093EA0AB093EB0A8CEC9AE09F938F9321
+:10EA5000812C912C18E4A12E12E4B12E0CEEC02EC4
+:10EA60000AE0D02E1AE9E12E19E9F12E09E11EE3A0
+:10EA700020E030E040E752E460E070E080EA91E4BA
+:10EA80000F9458050F94071F0F900F90A301920148
+:10EA90006091691A70916A1A80916B1A90916C1A40
+:10EAA0000F94C6BD87FF07C088EE93E00E94DE5E2C
+:10EAB0000E941666EBCF60E086EA9FE00F9456CA8C
+:10EAC00080E090E0A0EAB0E48093E80A9093E90A3D
+:10EAD000A093EA0AB093EB0A2091E40A3091E50A88
+:10EAE0004091E60A5091E70A6091E00A7091E10ACC
+:10EAF0008091E20A9091E30AECECFAE0FF93EF9345
+:10EB0000812C912CE8E4AE2EE2E4BE2EFCEECF2E5A
+:10EB1000FAE0DF2EE12CF12C00EA10E40F94580506
+:10EB2000E0EEF5E485919591A591B4918093E00A8A
+:10EB30009093E10AA093E20AB093E30AE4EEF5E4CD
+:10EB400025913591459154912093E40A3093E50A3B
+:10EB50004093E60A5093E70AE090E80AF090E90A49
+:10EB60000091EA0A1091EB0A6091E00A7091E10AC3
+:10EB70008091E20A9091E30AECECFAE0FF93EF93C4
+:10EB8000812C912CB8E4AB2EB2E4BB2E0F94580527
+:10EB90000F94071F20E030E043E060E070E080E881
+:10EBA0009FEB0E9455DE8091E80A9091E90AA091BE
+:10EBB000EA0AB091EB0A8AAF9BAFACAFBDAFE9ED0B
+:10EBC000FDE084910F900F900F900F904091E80A14
+:10EBD0005091E90A6091EA0A7091EB0A882349F0A2
+:10EBE0009091C00095FFFCCF8093C6003196849130
+:10EBF000F5CF8091C00085FFFCCF8AE08093C600EE
+:10EC0000E2EDFDE08491882341F09091C00095FFF2
+:10EC1000FCCF8093C6003196F5CF22E030E08EE73E
+:10EC200099E00E943543E1EDFDE08491882341F0B5
+:10EC30009091C00095FFFCCF8093C6003196F5CF30
+:10EC40008091C00085FFFCCF8AE08093C6002EEA49
+:10EC5000C22E2FE0D22E33E2E32EF12C0FEF1FEF66
+:10EC60004AE0342EB701882777FD8095982F0F94BE
+:10EC700068BE4B015C01EAECFDE08491882341F021
+:10EC80009091C00095FFFCCF8093C6003196F5CFE0
+:10EC90004AE050E0B8016E5F7F4F8EE799E00E9436
+:10ECA0004242EDEBFDE08491882341F09091C00059
+:10ECB00095FFFCCF8093C6003196F5CF8091C000C0
+:10ECC00085FFFCCF3092C600E9EAFDE084918823FD
+:10ECD00041F09091C00095FFFCCF8093C600319623
+:10ECE000F5CF4AE050E0B7018EE799E00E9442423A
+:10ECF000EAE9FDE08491882341F09091C00095FFFE
+:10ED0000FCCF8093C6003196F5CF4AE050E060E03A
+:10ED100070E08EE799E00E944242E9E9FDE08491CB
+:10ED2000882341F09091C00095FFFCCF8093C600EE
+:10ED30003196F5CF8091C00085FFFCCF3092C600A0
+:10ED40000F3FFFEF1F0731F0BE016F5F7F4FC6011E
+:10ED50000F949450A5019401C301B2010F94C6BD54
+:10ED6000181664F40F5F1F4F25E0E20EF11C32E02D
+:10ED7000C30ED11C0530110509F074CF280187E2BC
+:10ED8000481A88EF580A440C551C380193E0690E64
+:10ED9000711C85E0809F1001819F300C112419AEF9
+:10EDA00018AEADE22A0E311CC301029705970CF094
+:10EDB000CBC168AD79AD620D731D882777FD809555
+:10EDC000982F0F9468BE22966CAF7DAF8EAF9FAF29
+:10EDD0002297E2E9FDE08491882341F09091C00000
+:10EDE00095FFFCCF8093C6003196F5CF4AE050E006
+:10EDF000B3018EE799E00E944242EFE8FDE0849182
+:10EE0000882341F09091C00095FFFCCF8093C6000D
+:10EE10003196F5CF8091C00085FFFCCFFAE0F093EA
+:10EE2000C6007092200B60921F0B20E030E040EF94
+:10EE300051E422966CAD7DAD8EAD9FAD22970F94BF
+:10EE4000ECBC20E030E040E251E40F949BC020E0B5
+:10EE500030E040EA50E40F94CDBD20E030E048E4DB
+:10EE600052E40F94EDBC0F9435BE7093761A609304
+:10EE7000751A80E090E0A0EAB1E48093E00A9093F4
+:10EE8000E10AA093E20AB093E30A80E090E0A0E7F1
+:10EE9000B2E48093E40A9093E50AA093E60AB09363
+:10EEA000E70A8AE999E9A9E1BEE38093E80A909329
+:10EEB000E90AA093EA0AB093EB0AACECBAE0BF937C
+:10EEC000AF93812C912CA8E4AA2EA2E4BA2EBCEE1A
+:10EED000CB2EBAE0DB2E1AE9E12E19E9F12E09E179
+:10EEE0001EE320E030E040E752E460E070E080EABA
+:10EEF00091E40F9458050F94071F0F900F902296DE
+:10EF00002CAD3DAD4EAD5FAD22976091691A709109
+:10EF10006A1A80916B1A90916C1A0F94C6BD87FF84
+:10EF200007C088EE93E00E94DE5E0E941666E7CF7F
+:10EF300080E090E0A0EAB0E48093E80A9093E90AC8
+:10EF4000A093EA0AB093EB0A2091E40A3091E50A13
+:10EF50004091E60A5091E70A6091E00A7091E10A57
+:10EF60008091E20A9091E30AACECBAE0BF93AF93D0
+:10EF7000812C912C18E4A12E12E4B12E0CEEC02E9F
+:10EF80000AE0D02EE12CF12C00EA10E40F94580591
+:10EF9000E0EEF5E485919591A591B4918093E00A16
+:10EFA0009093E10AA093E20AB093E30AE4EEF5E459
+:10EFB00025913591459154912093E40A3093E50AC7
+:10EFC0004093E60A5093E70AE090E80AF090E90AD5
+:10EFD0000091EA0A1091EB0A6091E00A7091E10A4F
+:10EFE0008091E20A9091E30AACECBAE0BF93AF9350
+:10EFF000812C912CF8E4AF2EF2E4BF2E0F9458052B
+:10F000000F94071F20E030E043E060E070E080E80C
+:10F010009FEB0E9455DE2AAD3BAD4CAD5DAD6091DE
+:10F02000E80A7091E90A8091EA0A9091EB0A0F943C
+:10F03000ECBC209148193091491940914A195091DE
+:10F040004B190F949BC00F9435BE7A836983EEE809
+:10F05000FDE084910F900F900F900F90882349F05E
+:10F060009091C00095FFFCCF8093C60031968491AB
+:10F07000F5CF8091C00085FFFCCFFAE0F093C60089
+:10F08000EAE7FDE08491882341F09091C00095FF6C
+:10F09000FCCF8093C6003196F5CF4091691A50910C
+:10F0A0006A1A60916B1A70916C1A22E030E08EE758
+:10F0B00099E00E943543EBE6FDE08491882341F01E
+:10F0C0009091C00095FFFCCF8093C6003196F5CF9C
+:10F0D0002AAD3BAD4CAD5DAD6091E80A7091E90A97
+:10F0E0008091EA0A9091EB0A0F94ECBCAB01BC0151
+:10F0F00022E030E08EE799E00E943543EAE6FDE049
+:10F100008491882341F09091C00095FFFCCF8093BB
+:10F11000C6003196F5CF8091C00085FFFCCFFAE0A4
+:10F12000F093C600BE016F5F7F4FC2010F949450F1
+:10F1300022E0420E511C3FEF631A730A88AD99AD6D
+:10F14000059699AF88AF30CE1092220B1092210B0A
+:10F150001092240B61E086EA9FE00F9456CAEBE21E
+:10F16000FDE08491882341F09091C00095FFFCCF91
+:10F170008093C6003196F5CF8091C00085FFFCCF0B
+:10F180008AE08093C600179A1092D10A169A1092BC
+:10F19000D20A149AE091300BF0E0EE0FFF1FEE540C
+:10F1A000FF4B859194910F947EA481E00F94D199A7
+:10F1B00082E00F940A971092761A1092751A0C94A6
+:10F1C000159A84E690E00E94DE5E91E0E91AF1086B
+:10F1D000C1F74AE050E0B8018EE799E00E94424250
+:10F1E000F6012491E8E2FDE0211117C060910E0BB9
+:10F1F00070910F0B4AE050E08EE799E00E9449427F
+:10F200000550110911F40C94159A1093CB0A009330
+:10F21000CA0AF4E6EF2EF12CD4CF3091C00035FFAE
+:10F22000FCCF2093C60031962491DECF0F94071FA8
+:10F2300010925E0B81E08093320B86E50E94EF43D3
+:10F24000882359F0E0913910F0913A10818189308A
+:10F2500021F08F7D11F00E9405442091D10A809108
+:10F26000961B9091971B222341F02091D20A2223D2
+:10F2700021F02091D30A21110FC0029749F00E947A
+:10F28000B0C461E081E29DE00E94F8C30C94159A3D
+:10F290001092320B0C94159A1092040A029721F4E2
+:10F2A0001092320B0C94159AF091240B2896FFAF14
+:10F2B00028972091210B3091220B2A963FAF2EAF39
+:10F2C0002A9780911F0B9091200B2C969FAF8EAFA9
+:10F2D0002C9781E08093240B81E090E09093220BA7
+:10F2E0008093210B83E190E09093200B80931F0B80
+:10F2F00081E00F940A9787E792E10E94F3F90E9458
+:10F3000029F980E090E0A0EAB0E48093E80A9093C5
+:10F31000E90AA093EA0AB093EB0A20E030E040E764
+:10F3200052E460916002709161028091620290915A
+:10F3300063020F94CDBD4B015C012091E40A309132
+:10F34000E50A4091E60A5091E70A6091E00A70915F
+:10F35000E10A8091E20A9091E30AECECFAE0FF9373
+:10F36000EF931CEEC12E1AE0D12EE12CF12C00EA15
+:10F3700010E40F945805E0EEF5E485919591A59180
+:10F38000B4918093E00A9093E10AA093E20AB093CB
+:10F39000E30AE4EEF5E485919591A591B49180930B
+:10F3A000E40A9093E50AA093E60AB093E70A64EEB4
+:10F3B0007AE080EE9AE00E941D4720E030E040EFC6
+:10F3C00051E4609158027091590280915A029091D3
+:10F3D0005B020F94CDBD4B015C01E090E80AF09018
+:10F3E000E90A0091EA0A1091EB0A2091E40A3091AF
+:10F3F000E50A4091E60A5091E70A6091E00A7091AF
+:10F40000E10A8091E20A9091E30AECECFAE0FF93C2
+:10F41000EF930F9458050F94071F20E030E040EA67
+:10F4200051E4609158027091590280915A02909172
+:10F430005B020F94CDBD0F9435BE8B0120E030E010
+:10F4400040E252E460916002709161028091620238
+:10F45000909163020F94CDBD0F9435BE7B010E9445
+:10F4600008DB23968FAF239780E00E949B430F9089
+:10F470000F900F900F90A0EEB5E4BBAFAAAF212C78
+:10F48000312CC701AA2797FDA095BA2F60968CAFA3
+:10F490009DAFAEAFBFAF6097C801AA2797FDA095FB
+:10F4A000BA2F64968CAF9DAFAEAFBFAF6497C1016A
+:10F4B00063E070E00F948AC27FAF6EAF99AF88AF00
+:10F4C0009EAD90FF08C0A2E0B0E0E8ADF9ADAE1B84
+:10F4D000BF0BB9AFA8AF2396FFAD2397FF2379F1F8
+:10F4E0002114310461F18EAD9FAD880F991F2EADAF
+:10F4F0003FAD820F931FA8ADB9AD8A0F9B1F880F38
+:10F50000991F8D53904F0F9451CABC01882777FDE6
+:10F510008095982F0F9468BE2AE037ED43E25CE3B4
+:10F520000F949BC0209178123091791240917A12F9
+:10F5300050917B120F94EDBC2B013C0103C0412C78
+:10F54000512C320180E090E0A0EAB0E48093E80A18
+:10F550009093E90AA093EA0AB093EB0A60966CAD27
+:10F560007DAD8EAD9FAD60970F9468BE27966CAF52
+:10F570007DAF8EAF9FAF27972091E40A3091E50AC7
+:10F580004091E60A5091E70A6091E00A7091E10A21
+:10F590008091E20A9091E30AACECBAE0BF93AF939A
+:10F5A00027968CAC9DACAEACBFAC2797ECEECE2EC4
+:10F5B000EAE0DE2EE12CF12C00EA10E40F9458056D
+:10F5C0000F94071FEAADFBAD85919591A591B4917C
+:10F5D0008093E00A9093E10AA093E20AB093E30AD1
+:10F5E000EAADFBAD349685919591A591B491809348
+:10F5F000E40A9093E50AA093E60AB093E70A64EE62
+:10F600007AE080EE9AE00E941D4764966CAD7DAD75
+:10F610008EAD9FAD64970F9468BE4B015C01E09086
+:10F62000E80AF090E90A0091EA0A1091EB0A2091A9
+:10F63000E40A3091E50A4091E60A5091E70A6091A8
+:10F64000E00A7091E10A8091E20A9091E30AACEC41
+:10F65000BAE0BF93AF930F9458050F94071F0F9014
+:10F660000F900F900F902396FFAD2397FF2361F02B
+:10F670002114310449F020E030E040E85FE3C301A9
+:10F68000B2010F94ECBC04C060E070E080E291EC49
+:10F6900020E030E043E00E9455DE811108C0E09197
+:10F6A000300BF0E0EE0FFF1FE45AFC4B1FC0C09080
+:10F6B000E80AD090E90AE090EA0AF090EB0AA70184
+:10F6C000960160E070E080EA90E40F94ECBC2DECD1
+:10F6D0003CEC4CEC5DE30F94C6BD87FF0AC0E091A3
+:10F6E000300BF0E0EE0FFF1FE85AFC4B6590749072
+:10F6F000ABC023962FAD23972223B9F0A701960123
+:10F70000C301B2010F94ECBC9F7720E030E040E8E9
+:10F710005FE30F94C9BF181644F4E091300BF0E09A
+:10F72000EE0FFF1FE05AFC4BE1CF6091691A709118
+:10F730006A1A80916B1A90916C1A0E9482646B0114
+:10F740007C01EDE0FDE08491882341F09091C000C0
+:10F7500095FFFCCF8093C6003196F5CF4091E80A23
+:10F760005091E90A6091EA0A7091EB0A25E030E0D5
+:10F770008EE799E00E943543E3E0FDE08491882321
+:10F7800041F09091C00095FFFCCF8093C600319668
+:10F79000F5CF25E030E0B701A6018EE799E00E94A1
+:10F7A0003543E2E0FDE08491882341F09091C00070
+:10F7B00095FFFCCF8093C6003196F5CF8091C000B5
+:10F7C00085FFFCCFFAE0F093C60087E02EAD3FAD99
+:10F7D000829F8001839F100D1124A8ADB9AD0A0F3F
+:10F7E0001B1F000F111F000F111F09581D4EA701ED
+:10F7F00096016091E80A7091E90A8091EA0A909175
+:10F80000EB0A0F94ECBCF8016183728383839483C9
+:10F8100080911F0B9091200B01979093200B809368
+:10F820001F0BFFEF2F1A3F0A81E00F940A972AADB2
+:10F830003BAD285F3F4F3BAF2AAF39E02316310481
+:10F8400009F035CE612C712C80E090E0A0EAB0E4A4
+:10F850008093E80A9093E90AA093EA0AB093EB0A2E
+:10F860002091E40A3091E50A4091E60A5091E70AB6
+:10F870006091E00A7091E10A8091E20A9091E30AB6
+:10F88000ECECFAE0FF93EF9327968CAC9DACAEAC1A
+:10F89000BFAC2797ECEECE2EEAE0DE2EE12CF12C69
+:10F8A00000EA10E40F9458050F94071F0F900F9073
+:10F8B00089E02816310421F060E0C3010C943785FB
+:10F8C0000E94C943EFEEFCE08491882341F09091BF
+:10F8D000C00095FFFCCF8093C6003196F5CF809194
+:10F8E000C00085FFFCCF8AE08093C6000E9411F91A
+:10F8F000EEEDFCE08491882341F09091C00095FFEB
+:10F90000FCCF8093C6003196F5CF8091C00085FF73
+:10F91000FCCF8AE08093C60080EC9FE00F9444CA3D
+:10F92000A82EDE0111963D01B12C32E5932E46E45E
+:10F93000842EBCE4B9839A828B8282E48C83F301A7
+:10F9400081913F010E94EF43882319F00E941244E5
+:10F950001DC0F1E0AF1235C1FB1528F0B11009C090
+:10F960008FEB9FE00BC022E0B21206C08DEB9FE050
+:10F9700005C08EEB9FE002C08CEB9FE00F9444CA61
+:10F98000682F772767FD7095872F972F6115710571
+:10F990008105910509F415C10F9468BE2FE632E187
+:10F9A00043E85AE30F949BC06B017C019F7727E1EA
+:10F9B00039ED4EEC5DE30F94C9BF18160CF037C05B
+:10F9C000E5E4F0E18491882341F09091C00095FF37
+:10F9D000FCCF8093C6003196F5CFEAEBFCE0849132
+:10F9E000882341F09091C00095FFFCCF8093C60022
+:10F9F0003196F5CF22E030E0B701A6018EE799E01D
+:10FA00000E943543E1EBFCE08491882341F0909122
+:10FA1000C00095FFFCCF8093C6003196F5CF809152
+:10FA2000C00085FFFCCF8AE08093C600CAC0F2E028
+:10FA3000BF1609F469C023E0B21609F494C031E09E
+:10FA4000B31689F120E030E040E05FE3C701B60182
+:10FA50000F949BC01B012C0108E712E1A201910148
+:10FA6000D80114966D917D918D919C9117970F946B
+:10FA7000EDBCF8016483758386839783A7019601A3
+:10FA800060817181828193810F94EDBCD8016D9367
+:10FA90007D938D939C931397045E1F4FB2E10C3CB2
+:10FAA0001B07E1F68EC020E030E040E05FE3C701D5
+:10FAB000B6010F949BC01B012C010CE712E1A201BF
+:10FAC0009101F80160817181828193810F94EDBC75
+:10FAD000D8016D937D938D939C931397A701960105
+:10FAE00014966D917D918D919C9117970F94EDBC1B
+:10FAF000F8016483758386839783045E1F4FF2E168
+:10FB0000003D1F07E1F65DC020E030E040E05FE32C
+:10FB1000C701B6010F949BC01B012C0108E712E13D
+:10FB2000A2019101D8015C966D917D918D919C917E
+:10FB30005F970F94EDBCF801648F758F868F978F58
+:10FB4000A701960160817181828193810F94EDBC40
+:10FB5000D8016D937D938D939D938D01B2E104380F
+:10FB60001B07F1F62EC020E030E040E05FE3C70164
+:10FB7000B6010F949BC01B012C0104E912E1A20104
+:10FB80009101F80160817181828193810F94EDBCB4
+:10FB9000D8016D937D938D939D938D01A70196015F
+:10FBA00058966D917D918D919C915B970F94EDBCD2
+:10FBB000F801608F718F828F938FF2E1003A1F07F7
+:10FBC000F1F6B39424E0B212B4CEE0E9FCE0849103
+:10FBD000882341F09091C00095FFFCCF8093C60030
+:10FBE0003196F5CF8091C00085FFFCCF8AE08093ED
+:10FBF000C60087E792E10E940EFAEEE7FCE08491EE
+:10FC0000882341F09091C00095FFFCCF8093C600FF
+:10FC10003196F5CF8091C00085FFFCCF8AE08093BC
+:10FC2000C60081E080937712E2E6FCE084918823AD
+:10FC300041F09091C00095FFFCCF8093C6003196B3
+:10FC4000F5CF8091C00085FFFCCF8AE08093C6008D
+:10FC50000E9434F2E1E5FCE08491882341F0909128
+:10FC6000C00095FFFCCF8093C6003196F5CF809100
+:10FC7000C00085FFFCCF8AE08093C600E091CC0AEB
+:10FC800034E0E39FF0011124E159F54E20E030E02B
+:10FC900042E053E460817181828193810F94C9BFF6
+:10FCA000181694F480915D0B882371F086EA9FE02A
+:10FCB0000F9444CA882341F08091751A9091761A66
+:10FCC000C29714F00C94F19A81E090E090931602A0
+:10FCD0008093150228968FAD28978093240B2A963F
+:10FCE000AEADBFAD2A97B093220BA093210B2C96FB
+:10FCF000EEADFFAD2C97F093200BE0931F0B10920D
+:10FD0000320B1092310B82E00F940A970C94159AE3
+:10FD100080917712882309F49EC0E7E4FCE0849187
+:10FD2000882341F09091C00095FFFCCF8093C600DE
+:10FD30003196F5CF4AE050E067E070E08EE799E059
+:10FD40000E944242E5E4FCE08491882341F09091D6
+:10FD5000C00095FFFCCF8093C6003196F5CF4AE0F6
+:10FD600050E067E070E08EE799E00E944242E2E3F3
+:10FD7000FCE08491882341F09091C00095FFFCCF76
+:10FD80008093C6003196F5CF4AE050E065E070E020
+:10FD90008EE799E00E944242E0E2FCE084918823F1
+:10FDA00041F09091C00095FFFCCF8093C600319642
+:10FDB000F5CF8091C00085FFFCCF8AE08093C6001C
+:10FDC00000E010E09DE1A92E9CE0B92E2BE1822EEF
+:10FDD0002CE0922EE12CF12C9801215E3C4E690121
+:10FDE000F5018491EDE1FCE0882349F09091C00099
+:10FDF00095FFFCCF8093C60031968491F5CFF60134
+:10FE0000EE0DFF1D418152816381748125E030E058
+:10FE10008EE799E00E943543F4E0EF0EF11C2CE1EF
+:10FE2000E216F104E9F6F4018491EBE1FCE08823A9
+:10FE300049F09091C00095FFFCCF8093C6003196A9
+:10FE40008491F5CF0C5111090C33FFEF1F0709F016
+:10FE5000C1CF0C94159AEDEFFBE08491882341F01B
+:10FE60009091C00095FFFCCF8093C6003196F5CFEE
+:10FE70008091C00085FFFCCF8AE08093C6000C947F
+:10FE8000159A81E00E9442480C94159A1092960AA5
+:10FE90000C94159A85E40E94EF43811102C00F94DF
+:10FEA000071F19E7612E15E0712E04ED802E0AE080
+:10FEB000902E80EEA82E8AE0B82E512CD3018D9181
+:10FEC0003D010E94EF438823D9F1B3E05B120CC0DF
+:10FED0000E945C44F50160837183828393838CEE7E
+:10FEE0009AE00F94B1132CC00E945C44D4012D9170
+:10FEF0003D914D915C910F94EDBCF5016083718350
+:10FF000082839383E090E80AF090E90A0091EA0A7C
+:10FF10001091EB0A2091E40A3091E50A4091E60A3B
+:10FF20005091E70A6091E00A7091E10A8091E20A3B
+:10FF30009091E30ABCEECB2EBAE0DB2E0F940612B2
+:10FF40005394F4E08F0E911C24E0A20EB11C34E017
+:10FF50005312B4CF0C94159A81E08093921B0F94A6
+:10FF6000EFB46093660B7093670B8093680B90936C
+:10FF7000690B6091921B84EC9FE00F9456CA0C941D
+:10FF8000159A8DE40E94EF43882311F40C949B98FA
+:10FF9000E0913910F0913A10319681918032E9F375
+:10FFA0008930D9F380538A30B0F0EEEEFBE08491D3
+:10FFB000882341F09091C00095FFFCCF8093C6004C
+:10FFC0003196F5CF8091C00085FFFCCF8AE0809309
+:10FFD000C6000C94159A0E945C440F9435BE6B3C8D
+:10FFE000710511F40C94338D0CF0F7C06135710577
+:10FFF00011F40C94B1880CF077C06A31710509F4E2
+:020000021000EC
+:1000000047C3D4F56431710509F4DDC294F461315C
+:10001000710509F4CCC234F46230710508F409C2E8
+:100020000C9486986231710511F40C94E0880C945C
+:1000300086986731710509F400C37CF46531710558
+:1000400009F4F5C26631710511F00C9486988AE6C0
+:100050009BE00E9421B80C94159A6831710509F44F
+:1000600007C36931710511F00C9486988AE69BE00C
+:100070000E942CB80C94159A6F31710509F419C4BB
+:100080008CF46C31710509F417C30CF40FC36D3196
+:10009000710511F40C94159A6E31710509F43BC386
+:1000A0000C9486986C32710509F4AAC454F4603239
+:1000B000710509F468C36A32710509F45AC40C94D5
+:1000C00086986D32710509F4AAC46F32710511F07A
+:1000D0000C94869884E090E0909316028093150229
+:1000E0000F94DD6B0C94159A6037710509F4BCC44C
+:1000F000A4F56C35710511F40C943489A4F46335BE
+:10010000710511F40C94DB8814F40C94D7886435D1
+:10011000710511F40C94E0886535710511F40C94A7
+:1001200019890C9486986A36710509F4E4C754F469
+:100130006836710509F47AC46936710509F4AAC4F0
+:100140000C9486986B36710511F40C94AB886D365F
+:10015000710509F4E8C50C9486986837710511F4A7
+:100160000C94298BC4F46237710511F40C94218A24
+:1001700014F40C94B7896337710511F40C94E18978
+:100180006737710511F00C948698EAE3F2E48591E3
+:1001900094910C943A8B6E3B710509F46EC65CF435
+:1001A0006937710511F40C942E8B6C38710509F4C4
+:1001B00060C40C948698683C710511F40C94A18C71
+:1001C000693C710511F00C94869809E715E020E36D
+:1001D000E22E29E1F22E0C94188D673F81E078071A
+:1001E00011F40C945E910CF07EC06C32A1E07A07A1
+:1001F00011F40C94638FC4F5603D710511F40C94F7
+:100200003D8EA4F46D3C710511F40C94728D14F4C0
+:100210000C94508D6E3C710511F40C94E98D6F3C7B
+:10022000710511F40C94068E0C9486986D3D710541
+:1002300011F40C94D78E64F4613D710511F40C94A3
+:10024000658E6C3D710511F40C94C68E0C948698E5
+:10025000623E710511F40C94018F603F710511F439
+:100260000C94159A0C9486986036E1E07E07E4F4CD
+:100270006E35F1E07F0714F00C94159A6E3221E090
+:10028000720711F40C94089114F40C949B8F6F3244
+:1002900081E0780711F40C9417916033714011F4E8
+:1002A0000C9466900C948698643FA1E07A0711F450
+:1002B0000C9450914CF46039714011F00C94869874
+:1002C0000F94071F0C94159A653FF1E07F0711F416
+:1002D0000C945791663F714011F00C9486980E94DF
+:1002E00018350C94159A6E3833E0730711F40C949A
+:1002F000C4960CF047C06D3B92E0790711F40C9462
+:100300001598FCF46835B2E07B0711F40C947092F8
+:100310005CF46D3F714011F00C9486980F940F516E
+:10032000EFE3F0E10C946A91693522E0720711F471
+:100330000C947F966A35724011F40C948D960C944F
+:100340008698643883E0780711F40C949B966CF4DB
+:100350006E3BA2E07A0711F40C9418986335734051
+:1003600011F40C947C910C9486986B38E3E07E0732
+:1003700011F40C949E966C38734011F40C94159AF9
+:100380000C948698633923E0720711F40C942E972D
+:10039000D4F4603983E0780711F40C94F99614F4DE
+:1003A0000C94C7966139A3E07A0711F40C942B974B
+:1003B0006239734011F00C9486981092E81A0F94E9
+:1003C000653C0C94159A6639E3E07E0711F40C94B1
+:1003D000E3976CF4643923E0720711F40C943497BA
+:1003E0006539734011F40C94B1970C948698603A77
+:1003F00083E0780709F430C2673E734011F00C9433
+:1004000086981092800A0F94AF5180912510909198
+:100410002610A0912710B091281080932910909356
+:100420002A10A0932B10B0932C100E94C1550C944D
+:10043000159A0091391010913A100E5F1F4F80E508
+:100440000E94EF43882379F00E945C440F943ABEE7
+:100450006B017C01BB24B394611571058105910585
+:1004600031F4B12C04C0B12CC12CD12C760183E520
+:100470000E94EF43882399F00E945C4420E030E022
+:100480004AE754E40F949BC00F943ABE6B017C0181
+:10049000AA24A394611571058105910509F4A12C85
+:1004A0006AE270E0C8010F948DC6009711F0DC017C
+:1004B0001C92F801CF0121912032E1F3B11007C065
+:1004C000A11005C0222319F00F94715106C0EEE867
+:1004D000F0E4859194910F947E5181E00F945151F5
+:1004E0000F94071F0F94EFB46093920A7093930ACE
+:1004F0008093940A9093950AC114D104E104F10405
+:10050000F1F00F94EFB44B015C018C0C9D1CAE1C00
+:10051000BF1C84E090E090931602809315020F9424
+:10052000EFB4681579058A059B0510F00C94339B90
+:100530000F94045381110C94339B0C943E9B0F94A5
+:100540000253882311F40C94159A84E090E0909360
+:100550001602809315020F940453811109C00F9461
+:10056000F32B81E00E94BD5C80E00F940A97F3CFEB
+:1005700082E090E0909316028093150280916C0BBC
+:10058000E091300BF0E0EE0FFF1F882341F0EE57B3
+:10059000FE4B859194910F947E510C94159AE45ED4
+:1005A000FF4B859194910F947E510C94159AEEEE29
+:1005B000F1E4859194910F947E51179816981598AF
+:1005C00014980C94159AE2E3F3E485919491FC015C
+:1005D0002491222341F03091C00035FFFCCF2093BD
+:1005E000C6000196F4CF8091C00085FFFCCF8AE061
+:1005F0008093C6008AE69BE00E94F6B6E2EEF2E443
+:1006000085919491FC012491222341F03091C00006
+:1006100035FFFCCF2093C6000196F4CF8091C00037
+:1006200085FFFCCF8AE08093C6000C94159A8AE679
+:100630009BE00E944CB70C94159A809139109091D0
+:100640003A106AE270E004960F948DC6009711F09C
+:10065000DC011C926091391070913A106C5F7F4FF1
+:1006600021E041E08AE69BE00E94D3BC0C94159AFD
+:100670008AE69BE00E9425B80F94EFB460938A0A43
+:1006800070938B0A80938C0A90938D0A0C94159A20
+:1006900080916D0B882311F40C94159A83E50E94C8
+:1006A000EF4381110C94489B0C94159A8AE69BE0C9
+:1006B0000E94D7B90C94159A8091391090913A10F4
+:1006C0006AE270E004960F948DC68C010097A9F041
+:1006D00080914310909144106EE470E0885B9F4ECF
+:1006E0000F948DC660E270E00F948DC601969093D2
+:1006F0003A1080933910F80110826091391070918E
+:100700003A106C5F7F4F21E040E08AE69BE00E9458
+:10071000D3BC0C94159A80916D0B882311F40C9422
+:10072000159A60E08AE69BE00E9463BC80913910D4
+:1007300090913A106AE270E004960F948DC68C0195
+:100740000097A9F080914310909144106EE470E0FE
+:10075000885B9F4E0F948DC660E270E00F948DC64B
+:10076000019690933A1080933910D8011C926091B1
+:10077000391070913A106C5F7F4F8AE69BE00E94BF
+:1007800096B80C94159A80916C0B81110F94071FE9
+:100790000091391010913A100C5F1F4F6AE270E01F
+:1007A000C8010F948DC67C0161E270E0C8010F940E
+:1007B0008DC6009719F08C010F5F1F4FE114F104F3
+:1007C00011F0F701108280E50E94EF43F82E20918E
+:1007D000391030913A100217130708F4F12C809168
+:1007E0006D0B882311F40C94159A21E02F2541E01C
+:1007F000B8018AE69BE00E94D3BC83E50E94EF43E8
+:100800008823B9F02091391030913A102017310720
+:1008100080F40E941244AB01BC014093080E509337
+:10082000090E60930A0E70930B0E83E59DE00E9403
+:100830007FAA8AE69BE00E9425B8F1100C94159AD5
+:100840000F94EFB460938A0A70938B0A80938C0A9A
+:1008500090938D0A0C94159A8091391090913A10CA
+:100860006AE270E005960F948DC68C010097A9F09E
+:1008700080914310909144106EE470E0885B9F4E2D
+:100880000F948DC660E270E00F948DC60196909330
+:100890003A1080933910D8011C92609139107091F0
+:1008A0003A106B5F7F4F8AE69BE00E9411C00C9468
+:1008B000159A0F94EFB46093860A7093870A809319
+:1008C000880A9093890A00918A0A10918B0A2091D4
+:1008D0008C0A30918D0A601B710B820B930B28EEF2
+:1008E00033E040E050E00F949DC2CA01B9012CE30F
+:1008F00030E040E050E00F949DC27F936F933F93B0
+:100900002F938FED9BE09F938F93CE0101969F9342
+:100910008F930F9418C8EFE3F0E184910FB6F89429
+:10092000DEBF0FBECDBFEFE3F0E1882349F0909129
+:10093000C00095FFFCCF8093C60031968491F5CF1F
+:10094000FE0131968191882339F09091C00095FF86
+:10095000FCCF8093C600F6CF8091C00085FFFCCF0E
+:100960008AE08093C600CE0101960F9471510C94D9
+:10097000159A83E50E94EF43882311F40C94159A8D
+:100980000E945C440F9435BEF62EE72E862F9E2DD6
+:100990008C0180E50E94EF43882331F00F3F110561
+:1009A00009F010F40C94599B0DE010E0E1E4F5E03F
+:1009B000819191918017910711F40C94159A25E07B
+:1009C000E937F207A9F70630110539F48F2D9E2D6E
+:1009D0009093CB0A8093CA0A04C017FF02C00C94FC
+:1009E000159A61E0802F0F94DAB66F2D802F0F9447
+:1009F00013B76F2D7E2D802F0F94C2B50C94159ACE
+:100A00008FEF0E94424860E070E088EF9FE00F9413
+:100A100070CA0E94C2DA0E9455DB0C94159A8AE5CE
+:100A20000E94EF430E9479520C94159A88E690E058
+:100A30000E94775D81110C94159A83E50E94EF4323
+:100A4000882371F00091810A0E945C4410E0000F3D
+:100A5000111F0958154E0F9435BED8016D937C9324
+:100A60000F94FE280C94159A63E08EEF98E00E9494
+:100A7000475C83E50E94EF43882311F40C94159A98
+:100A80000E945C440F9435BE7093761A6093751A79
+:100A90000C94159A89E690E00E94775D81110C9480
+:100AA000159AE9EDFBE08491882341F09091C00014
+:100AB00095FFFCCF8093C6003196F5CFE091810A77
+:100AC000B4E0EB9FF0011124E159F54E40815181D2
+:100AD0006281738121E030E08EE799E00E94354326
+:100AE000E6EDFBE08491882341F09091C00095FFF2
+:100AF000FCCF8093C6003196F5CFE091810AF0E0FB
+:100B0000EE0FFF1FE958F54E60817181882777FD50
+:100B10008095982F0F9468BEAB01BC0121E030E0B6
+:100B20008EE799E00E943543E2EDFBE08491882353
+:100B300041F09091C00095FFFCCF8093C6003196A4
+:100B4000F5CF40915D1A50915E1A60915F1A7091D5
+:100B5000601A21E030E08EE799E00E943543EFEC27
+:100B6000FBE08491882341F09091C00095FFFCCF79
+:100B70008093C6003196F5CF6091751A7091761A00
+:100B8000882777FD8095982F0F9468BEAB01BC0134
+:100B900021E030E08EE799E00E943543ECECFBE089
+:100BA0008491882341F09091C00095FFFCCF809301
+:100BB000C6003196F5CF4AE050E060E070E08EE785
+:100BC00099E00E944242EAECFBE08491882341F0E4
+:100BD0009091C00095FFFCCF8093C6003196F5CF71
+:100BE00040916F1A5091701A6091711A7091721A37
+:100BF00021E030E08EE799E00E943543E7ECFBE02E
+:100C00008491882341F09091C00095FFFCCF8093A0
+:100C1000C6003196F5CF6091771A7091781A8827BF
+:100C200077FD8095982F0F9468BEAB01BC0121E041
+:100C300030E08EE799E00E943543E3ECFBE08491DD
+:100C4000882341F09091C00095FFFCCF8093C600AF
+:100C50003196F5CF8091810A90E00F947F264AE08B
+:100C600050E0BC018EE799E00E944242EEEBFBE0CF
+:100C70008491882341F09091C00095FFFCCF809330
+:100C8000C6003196F5CF8FEF9FEF0F947F264AE095
+:100C900050E0BC018EE799E00E944242EAEBFBE0A3
+:100CA0008491882341F09091C00095FFFCCF809300
+:100CB000C6003196F5CF4091691A50916A1A609139
+:100CC0006B1A70916C1A21E030E08EE799E00E9477
+:100CD0003543E6EBFBE08491882341F09091C0001E
+:100CE00095FFFCCF8093C6003196F5CF4091631AF3
+:100CF0005091641A6091651A7091661A21E030E093
+:100D00008EE799E00E9435438091C00085FFFCCFBB
+:100D10008AE08093C60081E090E090931602809371
+:100D200015020C947F9B8DE690E00E94775D811107
+:100D30000C94159AE091300BF0E0EE0FFF1FE65790
+:100D4000FD4B859194910F947E5181E090E09093BA
+:100D5000280B8093270B8091921B882321F081E040
+:100D600090E00F94FF6083E50E94EF43882391F0A9
+:100D70000091810A0E945C4410E0000F111F095885
+:100D8000154E0F9435BEF8017183608381E0809326
+:100D9000060215C082E50E94EF43882381F000918E
+:100DA000810A0E945C4410E0000F111F0958154E83
+:100DB0000F9435BED8016D937C93109206020F9468
+:100DC000FE280F94EFB46B017C010091810A10E0C2
+:100DD000F801EE0FFF1FE958F54E608171818827F9
+:100DE00077FD8095982F0F9468BEF801EE0FFF1FD6
+:100DF000EE0FFF1FE159F54E11E020813181428154
+:100E000053810F94C9BF18160CF010E010937F0A9D
+:100E100081E090E090931602809315021092BB0A35
+:100E2000C701B6010E94005FE091300BF0E0EE0FC9
+:100E3000FF1FEA57FD4B859194910F947E5182E0FC
+:100E400090E090931602809315029093280B809364
+:100E5000270B8091921B882321F082E090E00F9471
+:100E6000FF600F94EFB46093920A7093930A80939B
+:100E7000940A9093950A0C94159AE091300BF0E047
+:100E8000EE0FFF1FEC59FC4B859194910F947E510E
+:100E900083E090E09093280B8093270B8091921B26
+:100EA000882321F081E090E00F94FF6083E50E94A9
+:100EB000EF43882361F00E945C440F9435BE709329
+:100EC000761A6093751A81E0809306020FC082E55E
+:100ED0000E94EF43882351F00E945C440F9435BE7A
+:100EE0007093761A6093751A109206020F94EFB4FD
+:100EF0004B015C011092BB0A6091751A7091761AD1
+:100F0000882777FD8095982F0F9468BE11E0209177
+:100F10005D1A30915E1A40915F1A5091601A0F94D9
+:100F2000C9BF18160CF010E010937F0A81E090E022
+:100F3000909316028093150203EB1BE07FEAE72EE5
+:100F40007BE0F72EEBEACE2EEBE0DE2EFAE07F2EF2
+:100F500080917F0A6091751A7091761A882309F43E
+:100F600090C08091BB0A81118CC0882777FD809545
+:100F7000982F0F9468BE20915D1A30915E1A4091AF
+:100F80005F1A5091601A0F94C9BF18160CF090C0E8
+:100F90000F94EFB4681979098A099B09693E734077
+:100FA0008105910508F464C08091921B81115CC099
+:100FB000E091CC0A24E0E29FF0011124E159F54EC2
+:100FC0004081518162817381F8018491E3EBFBE000
+:100FD000882349F09091C00095FFFCCF8093C60014
+:100FE00031968491F5CF22E030E08EE799E00E94BF
+:100FF0003543F7018491EFEAFBE0882349F09091B3
+:10100000C00095FFFCCF8093C60031968491F5CF48
+:101010006091CC0A70E04AE050E08EE799E00E94CF
+:101020004242F6018491EBEAFBE0882349F090917B
+:10103000C00095FFFCCF8093C60031968491F5CF18
+:1010400040915D1A50915E1A60915F1A7091601A1A
+:1010500021E030E08EE799E00E9435438091C000A6
+:1010600085FFFCCF7092C6000F94EFB44B015C017A
+:101070000F94F32B80E00E94BD5C80E00F940A97F0
+:1010800067CF882777FD8095982F0F9468BE2091B1
+:101090005D1A30915E1A40915F1A5091601A0F9458
+:1010A000C6BD87FF05C080910602882309F470CF72
+:1010B000E091300BF0E0EE0FFF1FE859FC4B8591FB
+:1010C00094910F947E5182E090E090931602809369
+:1010D000150284E090E09093280B8093270B0F94E7
+:1010E000EFB46093920A7093930A8093940A90935A
+:1010F000950A0C94159A83E50E94EF43882319F111
+:101100000E945C4420E030E0A9010F94C6BD87FD39
+:101110000FC00E945C4420E030E04FE753E40F949E
+:10112000C9BF181644F00E945C440F9435BE05C038
+:1011300060E070E002C06FEF70E07093CB0A6093E4
+:10114000CA0A0C94159A8FEF90E09093CB0A809383
+:10115000CA0A0C94159A1092CB0A1092CA0A0C94DF
+:10116000159A0F94FF280F94071F149A0F94891F44
+:101170001092CB0A1092CA0A68EE73E080E090E009
+:101180000F941EB510921702ECEEF1E445915491C4
+:1011900029EA3BE067EA7BE081EA94E00E94EFCB3A
+:1011A0000F947E5180E00F940A970C94159A109238
+:1011B000650B0C94159A81E08093650B0C94159A3D
+:1011C00083E50E94EF43882399F00E945C4420E06D
+:1011D00030E04AE754E40F949BC00F943ABE60930A
+:1011E00008027093090280930A0290930B021DC0BB
+:1011F00088E50E94EF4381110C94609B89E50E9471
+:10120000EF4381110C94609B8AE50E94EF438111AA
+:101210000C94609B85E40E94EF4381110C94609BC9
+:101220000F94071F149A0F94891F10921E0B0C9491
+:10123000159A83E50E94EF43882311F40C94159AC4
+:101240000E945C4420E030E04AE754E40F949BC0E5
+:101250000F943ABE60938E0A70938F0A8093900A1F
+:101260009093910A0C94159A29E735E039AF28AF8D
+:1012700000E419E140E5C42E49E1D42E50E0E52E0A
+:1012800059E1F52E312CA8ADB9AD8D91B9AFA8AF0C
+:101290000E94EF43882309F45CC0B3E03B1252C0C4
+:1012A0000E945C442B013C0120E030E040EA51E424
+:1012B0000F94C6BD87FF3FC0A3019201F801608172
+:1012C0007181828193810F94CDBD4B015C019B01A3
+:1012D000AC0160912019709121198091221990918F
+:1012E00023190F949BC06093201970932119809348
+:1012F000221990932319A5019401D6016D917D9136
+:101300008D919C910F949BC0F601608371838283C1
+:101310009383D7016D917D918D919C910F9466BEC1
+:10132000A50194010F949BC00F943ABEF70160830E
+:10133000718382839383D8014D925D926D927C92EA
+:10134000139707C00E945C44F80160837183828315
+:10135000938333940C5F1F4FF4E0CF0ED11C24E035
+:10136000E20EF11C34E033128ECF0C94159A83E513
+:101370000E94EF43882331F00E94054480931002BD
+:101380000C94159AEFE3F0E18491882341F0909159
+:10139000C00095FFFCCF8093C6003196F5CF4091F9
+:1013A000100250E060E070E080EA9BE00E94594843
+:1013B0008091C00085FFFCCF8AE08093C6000C942A
+:1013C000159A86E50E94EF438823B9F00F9432B155
+:1013D000FC012491222341F03091C00035FFFCCF65
+:1013E0002093C6000196F4CF8091C00085FFFCCF0A
+:1013F0008AE08093C6000C94159A85E50E94EF431D
+:10140000882369F08091391090913A100196909359
+:101410003A10809339100F94A3B30C94159AE0E41A
+:10142000F2E485919491FC012491222311F40C940F
+:10143000159A3091C00035FFFCCF2093C60001966D
+:10144000F2CFEDE9FBE08491882341F09091C00058
+:1014500095FFFCCF8093C6003196F5CF4091E00A0E
+:101460005091E10A6091E20A7091E30A22E030E0D3
+:101470008EE799E00E943543E9E9FBE084918823F7
+:1014800041F09091C00095FFFCCF8093C60031964B
+:10149000F5CF4091E40A5091E50A6091E60A709117
+:1014A000E70A22E030E08EE799E00E943543E5E963
+:1014B000FBE08491882341F09091C00095FFFCCF20
+:1014C0008093C6003196F5CF4091E80A5091E90A21
+:1014D0006091EA0A7091EB0A22E030E08EE799E031
+:1014E0000E943543E1E9FBE08491882341F090912B
+:1014F000C00095FFFCCF8093C6003196F5CF409198
+:10150000EC0A5091ED0A6091EE0A7091EF0A22E028
+:1015100030E08EE799E00E943543E0E0F3E4859106
+:101520009491FC012491222341F03091C00035FFB9
+:10153000FCCF2093C6000196F4CF80E00F94681F83
+:101540000F9468BE20914019309141194091421981
+:10155000509143190F94CDBDAB01BC0122E030E0A6
+:101560008EE799E00E943543EDE8FBE08491882303
+:1015700041F09091C00095FFFCCF8093C60031965A
+:10158000F5CF81E00F94681F0F9468BE2091441935
+:101590003091451940914619509147190F94CDBD8E
+:1015A000AB01BC0122E030E08EE799E00E943543B8
+:1015B000E9E8FBE08491882341F09091C00095FF19
+:1015C000FCCF8093C6003196F5CF82E00F94681F60
+:1015D0000F9468BE209148193091491940914A19D9
+:1015E00050914B190F94CDBDAB01BC0122E030E00E
+:1015F0008EE799E00E943543E5E8FBE0849188237B
+:1016000041F09091C00095FFFCCF8093C6003196C9
+:10161000F5CF83E00F94681F0F9468BE20914C199A
+:1016200030914D1940914E1950914F190F94CDBDE5
+:10163000AB01BC0122E030E08EE799E00E94354327
+:101640008091C00085FFFCCF8AE08093C6000C9497
+:10165000159A80E00F948C150C94159A81E00F94E4
+:101660008C150C94159A3091C00035FFFCCF209357
+:10167000C6000196FC0124912111F5CF8091C00094
+:1016800085FFFCCF8AE08093C600E2E3F0E4859119
+:101690009491FC012491222341F03091C00035FF48
+:1016A000FCCF2093C6000196F4CF1E9B10C0E6EE3F
+:1016B000F2E485919491FC0124912223C1F03091B0
+:1016C000C00035FFFCCF2093C6000196F4CFE4EEB6
+:1016D000F2E485919491FC012491222341F0309110
+:1016E000C00035FFFCCF2093C6000196F4CF809157
+:1016F000C00085FFFCCF8AE08093C600E4E3F0E4FD
+:1017000085919491FC012491222341F03091C000F5
+:1017100035FFFCCF2093C6000196F4CF80910601DF
+:1017200082FF10C0E6EEF2E485919491FC012491D1
+:101730002223C1F03091C00035FFFCCF2093C600BA
+:101740000196F4CFE4EEF2E485919491FC012491AA
+:10175000222341F03091C00035FFFCCF2093C6001A
+:101760000196F4CF8091C00085FFFCCF8AE0809382
+:10177000C600E6E2F0E485919491FC0124912223D5
+:1017800041F03091C00035FFFCCF2093C600019698
+:10179000F4CF1D9B10C0E6EEF2E485919491FC011C
+:1017A00024912223C1F03091C00035FFFCCF20935B
+:1017B000C6000196F4CFE4EEF2E485919491FC0129
+:1017C0002491222341F03091C00035FFFCCF2093BB
+:1017D000C6000196F4CF8091C00085FFFCCF8AE05F
+:1017E0008093C600E8E2F0E485919491FC01249195
+:1017F000222341F03091C00035FFFCCF2093C6007A
+:101800000196F4CF8091060187FF10C0E6EEF2E466
+:1018100085919491FC0124912223C1F03091C00064
+:1018200035FFFCCF2093C6000196F4CFE4EEF2E43E
+:1018300085919491FC012491222341F03091C000C4
+:1018400035FFFCCF2093C6000196F4CF8091C000F5
+:1018500085FFFCCF8AE08093C600E0E2F0E485914A
+:101860009491FC012491222341F03091C00035FF76
+:10187000FCCF2093C6000196F4CF1C9B10C0E6EE6F
+:10188000F2E485919491FC0124912223C1F03091DE
+:10189000C00035FFFCCF2093C6000196F4CFE4EEE4
+:1018A000F2E485919491FC012491222341F030913E
+:1018B000C00035FFFCCF2093C6000196F4CF809185
+:1018C000C00085FFFCCF8AE08093C600E2E2F0E42E
+:1018D00085919491FC012491222341F03091C00024
+:1018E00035FFFCCF2093C6000196F4CF019910C0BC
+:1018F000E6EEF2E485919491FC0124912223C1F05B
+:101900003091C00035FFFCCF2093C6000196F4CF84
+:10191000E4EEF2E485919491FC012491222341F0BC
+:101920003091C00035FFFCCF2093C6000196F4CF64
+:101930008091C00085FFFCCF8AE08093C6000C94A4
+:10194000159A8091CC0A8093810A84E50E94EF4326
+:10195000882329F10E945C440F943ABE6093810A67
+:101960006623E9F0EFE3F0E18491882341F0909160
+:10197000C00095FFFCCF8093C6003196F5CFE8E319
+:10198000F2E4A591B4918D91882311F40C94159AE9
+:101990009091C00095FFFCCF8093C600F4CF84E403
+:1019A0000E94EF43882311F40C94159A0E945C4422
+:1019B00020E030E0A9010F94C6BD811103C0109250
+:1019C000F00A32C00091810A10E00E945C44F801E4
+:1019D000EE0FFF1FEE0FFF1FEC5BFD4F6083718367
+:1019E00082839383E0904402F09045020091460286
+:1019F0001091470220E030E0A901B701C8010F941F
+:101A0000C6BD811104C0E12CF12C00E410E4C70133
+:101A1000D8018093440290934502A0934602B0936C
+:101A2000470281E08093F00A0E94CC5E0C94159AE4
+:101A3000D8018D918D010E94EF43882349F00E94C7
+:101A40005C440F943ABEF701608371838283938371
+:101A5000F4E0EF0EF11C25E00D37120749F70F9463
+:101A6000E3130C94159A09E715E090E5E92E99E146
+:101A7000F92ED8018D918D010E94EF43882339F012
+:101A80000E945C44F7016083718382839383F4E056
+:101A9000EF0EF11C25E00D37120759F70C94159A3B
+:101AA00083E50E94EF43882351F00E945C446093D9
+:101AB00028197093291980932A1990932B1984E57A
+:101AC0000E94EF43882311F40C94159A0E945C4401
+:101AD00060932419709325198093261990932719E0
+:101AE0000C94159A83E50E94EF43882351F00E94DD
+:101AF0005C4460932C1970932D1980932E19909348
+:101B00002F1984E50E94EF43882351F00E945C4422
+:101B100060931019709311198093121990931319EF
+:101B200082E40E94EF43882361F00E945C440F949A
+:101B30003ABE609360197093611980936219909313
+:101B4000631988E50E94EF43882391F00E945C446A
+:101B5000609318197093191980931A1990931B198F
+:101B6000609314197093151980931619909317198F
+:101B700089E50E94EF43882351F00E945C44609302
+:101B800018197093191980931A1990931B198AE5E3
+:101B90000E94EF43882351F00E945C4460931C191B
+:101BA00070931D1980931E1990931F1985E40E944C
+:101BB000EF43882311F40C94159A0E945C446093BF
+:101BC00020197093211980932219909323190C9452
+:101BD000159A09E715E084EDE82E8AE0F82ED80181
+:101BE0008D918D010E94EF43882339F00E945C445F
+:101BF000F7016083718382839383F4E0EF0EF11C1D
+:101C000025E00C37120759F70C94159A83E50E94CA
+:101C1000EF43882351F00E945C4460932402709348
+:101C20002502809326029093270286E40E94EF43C8
+:101C3000882381F00E945C4420E030E040E752E4D9
+:101C40000F94CDBD60931C0270931D0280931E0201
+:101C500090931F028AE50E94EF43882311F40C94AD
+:101C6000159A0E945C446093C40A7093C50A8093DD
+:101C7000C60A9093C70A0C94159A83E50E94EF4315
+:101C8000882351F00E945C446093C00A7093C10A9B
+:101C90008093C20A9093C30A86E40E94EF4388238C
+:101CA00011F40C94159A0E945C4420E030E040E767
+:101CB00052E40F94CDBD6093180270931902809383
+:101CC0001A0290931B020C94159A83E50E94EF432D
+:101CD000882311F40C94159A0E945C440F9435BE2D
+:101CE0006115710551F06130710569F481E08093EF
+:101CF000C90A1092C80A0C94159A1092C90A109237
+:101D0000C80A0C94159AEFE3F0E18491882341F01E
+:101D10009091C00095FFFCCF8093C6003196F5CF1F
+:101D2000E0EAF0E485919491FC012491222341F0B2
+:101D30003091C00035FFFCCF2093C6000196F4CF50
+:101D4000E0914310F0914410E85BFF4E81918823AD
+:101D500039F09091C00095FFFCCF8093C600F6CF7C
+:101D6000E0E8FBE08491882341F09091C00095FF6A
+:101D7000FCCF8093C6003196F5CF8091C00085FFDF
+:101D8000FCCF8AE08093C6000C94159A83E50E94EC
+:101D9000EF43882311F40C94159A0E945C440F942D
+:101DA00035BE70935702609356020C94159A83E5E2
+:101DB0000E94EF43882311F40C94159A0E945C440E
+:101DC0000F9435BE6B017C0184E50E94EF438823AC
+:101DD00091F08DED90E00E94775D81110C94159A41
+:101DE000E091810AF0E0EE0FFF1FEE5AFD4FD18225
+:101DF000C0820C94159AD0925502C09254020C9451
+:101E0000159A80E50E94EF43882311F40C94159AEB
+:101E10000E945C440F9435BED62E062F172F83E503
+:101E20000E94EF43882331F00E945C440F9435BE3A
+:101E30007B0103C0EE24EA94FE2CC70101960397B0
+:101E400010F00C94159AE1E4F5E0819191918017DE
+:101E5000910711F40C94159A25E0E937F207A9F7D8
+:101E600017FF02C00C94159A0F94071FCD2C60E049
+:101E70008D2D0F94DAB63FEFE316F30631F0EA94B6
+:101E8000EF2871F000E010E00DC08D2D0F9448B7E1
+:101E900031E020E0892B09F030E0032F122F02C03F
+:101EA00001E010E08C2D0F9448B78017910711F4D2
+:101EB0000C94159A0F94F32B80E00E94BD5C80E097
+:101EC0000F940A97EFCF83E50E94EF43882331F008
+:101ED0000E945C440F9435BE8B0102C00EE610E0F8
+:101EE00080E50E94EF43882331F00E945C440F9408
+:101EF00035BECB0102C088EE93E06C01EE24D7FC26
+:101F0000E094FE2C1016110684F420E030E0A901C4
+:101F1000B80184E50F9447B9C701B6010F941EB507
+:101F200084E50F946BBC0C94159AC701B6010F940D
+:101F30001EB50C94159A80E50E94EF43882351F05A
+:101F40000E945C446093AD027093AE028093AF0236
+:101F50009093B00289E40E94EF43882361F00E94CD
+:101F60005C440F947B376093A9027093AA0280931C
+:101F7000AB029093AC0284E40E94EF43882361F0AB
+:101F80000E945C440F9487376093A5027093A60269
+:101F90008093A7029093A80283E40E94EF438823D2
+:101FA00051F00E945C446093A1027093A20280935E
+:101FB000A3029093A4020F945226EAEEF1E48591D5
+:101FC0009491FC012491222341F03091C00035FF0F
+:101FD000FCCF2093C6000196F4CFEEEAF4E08191A5
+:101FE000882339F09091C00095FFFCCF8093C60004
+:101FF000F6CF4091AD025091AE026091AF02709168
+:10200000B00222E030E08EE799E00E943543E2EB37
+:10201000F4E08191882339F09091C00095FFFCCFC6
+:102020008093C600F6CF6091A9027091AA028091B8
+:10203000AB029091AC020F948137AB01BC0122E05E
+:1020400030E08EE799E00E943543E6EBF4E08191C1
+:10205000882339F09091C00095FFFCCF8093C60093
+:10206000F6CF6091A5027091A6028091A70290918F
+:10207000A8020F948D37AB01BC0122E030E08EE75F
+:1020800099E00E943543EAEBF4E08191882339F02E
+:102090009091C00095FFFCCF8093C600F6CF409191
+:1020A000A1025091A2026091A3027091A40222E0C9
+:1020B00030E08EE799E00E9435438091C00085FFB3
+:1020C000FCCF8AE08093C6000C94159A80E50E94AC
+:1020D000EF43882351F00E945C4460939D0270930B
+:1020E0009E0280939F029093A00289E40E94EF4396
+:1020F000882361F00E945C440F947B3760939902BF
+:1021000070939A0280939B0290939C0284E40E94B5
+:10211000EF43882361F00E945C440F9487376093FB
+:1021200095027093960280939702909398020F9471
+:102130005226EAEEF1E485919491FC012491222348
+:1021400041F03091C00035FFFCCF2093C6000196CE
+:10215000F4CFEEEAF4E08191882339F09091C00049
+:1021600095FFFCCF8093C600F6CF40919D02509121
+:102170009E0260919F027091A00222E030E08EE703
+:1021800099E00E943543E2EBF4E08191882339F035
+:102190009091C00095FFFCCF8093C600F6CF609170
+:1021A000990270919A0280919B0290919C020F94E7
+:1021B0008137AB01BC0122E030E08EE799E00E945C
+:1021C0003543E6EBF4E08191882339F09091C0002B
+:1021D00095FFFCCF8093C600F6CF60919502709179
+:1021E000960280919702909198020F948D37AB01DF
+:1021F000BC0122E030E08EE799E00E9435438091F7
+:10220000C00085FFFCCF8AE08093C6000C94159A2D
+:1022100083E50E94EF43882319F00E945C4403C0C9
+:1022200060E070E0CB010F94DA130C94159A85E40A
+:102230000E94EF43882341F00E945C440F9435BE16
+:102240008B0177FF03C009C000E010E0C12CD12C46
+:10225000A6E1EA2EA3E4FA2E06C0C12CD12CFCE89C
+:10226000EF2EF2E4FF2E83E50E94EF43882321F056
+:102270000E945C446B017C0183E40E94EF4388234D
+:1022800031F00E945C440F9435BE9B0102C025E0F2
+:1022900030E0A801C701B6010F94512F0C94159A94
+:1022A00060E084E190E00E94152F0C94159A60E0A4
+:1022B00084E190E00E94A4360C94159A80E00E947C
+:1022C00035300C94159A9091C00095FFFCCF809307
+:1022D000C600319684918111F6CFE0E7FBE084914E
+:1022E000882311F40C94159A9091C00095FFFCCFAF
+:1022F0008093C6003196F3CF8AE50E94EF4388238E
+:1023000009F4AFC00E945C446B017C0120E030E026
+:1023100040E751EC0F94C9BF87FD4EC020E030E08C
+:1023200040EA50ECC701B6010F94C6BD18160CF474
+:1023300043C0F7FAF094F7F8F094C092CD0AD09227
+:10234000CE0AE092CF0AF092D00AEFE3F0E1849156
+:10235000882341F09091C00095FFFCCF8093C60088
+:102360003196F5CFEAEEF1E445915491E4E2F0E4E0
+:10237000859194912FE63BE06EEC78E00E94EFCBE4
+:10238000FC012491222341F03091C00035FFFCCFA5
+:102390002093C6000196F4CF8091C00085FFFCCF4A
+:1023A0008AE08093C6008091C00085FFFCCF8AE060
+:1023B0008093C6000C94159AEFE3F0E18491882392
+:1023C00041F09091C00095FFFCCF8093C6003196FC
+:1023D000F5CFE4E2F0E485919491FC01249122236D
+:1023E00041F03091C00035FFFCCF2093C60001962C
+:1023F000F4CFE0E2F0E485919491FC012491222352
+:1024000041F03091C00035FFFCCF2093C60001960B
+:10241000F4CF4AE050E061EF7FEF8EE799E00E9451
+:102420004242E2E2F0E485919491FC01249122235E
+:1024300041F03091C00035FFFCCF2093C6000196DB
+:10244000F4CF4AE050E06BEF7FEF8EE799E00E9417
+:1024500042428091C00085FFFCCF8AE08093C60095
+:10246000E4C7EFE3F0E18491882341F09091C0004C
+:1024700095FFFCCF8093C6003196F5CFE4E2F0E4FF
+:10248000859194916BE67BE00E94CECBFC01249178
+:10249000222341F03091C00035FFFCCF2093C600CD
+:1024A0000196F4CF8091C00085FFFCCF8AE0809335
+:1024B000C6004091CD0A5091CE0A6091CF0A70912A
+:1024C000D00A705822E030E08EE799E00E94354350
+:1024D0008091C00085FFFCCF8AE08093C600A5C72D
+:1024E0006EEB74E08EE799E00E943542F09169024C
+:1024F000F8AF109269020F94071F8091921B8823F6
+:1025000021F086E190E00F94FF6080915602909157
+:1025100057029093490280934802C090E00AD090FD
+:10252000E10AE090E20AF090E30ACF8ED8A2E9A295
+:10253000FAA20091E40A1091E50A2091E60A30918E
+:10254000E70A0BA31CA32DA33EA34091E80A5091D8
+:10255000E90A6091EA0A7091EB0A4FA358A769A7AC
+:102560007AA78091EC0A9091ED0AA091EE0AB091C1
+:10257000EF0A8BA79CA7ADA7BEA7C982DA82EB8220
+:10258000FC820D831E832F83388749875A876B8788
+:102590007C878D879E87AF87B88B85E40E94EF4349
+:1025A000882359F00E945C449B01AC016BA57CA57B
+:1025B0008DA59EA50F94EDBC0AC020E030E040E060
+:1025C00050E46BA57CA58DA59EA50F94ECBC6BA7D4
+:1025D0007CA78DA79EA7EFA0F8A409A51AA52BA1FB
+:1025E0003CA14DA15EA16F8D78A189A19AA1ECECCF
+:1025F000FAE0FF93EF93812C912CE8EEAE2EE2E40B
+:10260000BE2EDE019B966D010F9458058AE50E944F
+:10261000EF430F900F90882349F00E945C449B0188
+:10262000AC016FA178A589A59AA51EC020E030E075
+:1026300040E050E46FA178A589A59AA50F94EDBC60
+:102640006B017C016FA378A789A79AA720E030E0EF
+:1026500040E251E40F94C6BD87FF0CC020E030E09B
+:1026600040E251E4C701B6010F94EDBC6FA378A717
+:1026700089A79AA7EFA0F8A409A51AA52BA13CA1A8
+:102680004DA15EA16F8D78A189A19AA1ECECFAE031
+:10269000FF93EF93812C912CB0E7AB2EB1E4BB2ECE
+:1026A000FE01BB966F010F94580588E50E94EF4329
+:1026B0000F900F90882379F00E945C449B01AC013D
+:1026C0006F8D78A189A19AA10F94EDBC6F8F78A32B
+:1026D00089A39AA308C080E090E0A3E5B3E48F8FBC
+:1026E00098A3A9A3BAA389E50E94EF43882339F0F0
+:1026F0000E945C446BA37CA38DA39EA304C01BA279
+:102700001CA21DA21EA2EFA0F8A409A51AA52BA128
+:102710003CA14DA15EA16F8D78A189A19AA1ECEC9D
+:10272000FAE0FF93EF93812C912CE8E4AE2EE2E4E3
+:10273000BE2EDE019B966D010F9458050F94071F66
+:1027400084E090E09093160280931502E091300BA4
+:10275000F0E0EE0FFF1FE255FE4B859194910E9431
+:1027600034480F900F9000E010E0F12C0F940453C8
+:1027700081112AC0F3940F94F32B81E00E94BD5C79
+:10278000F110F4CF043FB1E01B0711F400E010E0BA
+:10279000809101018460809301010115110531F4DC
+:1027A0009FB7F89480910201846008C0043111053C
+:1027B00041F49FB7F894809102018B7F80930201CE
+:1027C0009FBF0F5F1F4FD2CF9FB7F8948091020138
+:1027D0008B7F809302019FBF1092560B1092550B76
+:1027E00092E0292E312C2CEC622E2AE0722E34E05D
+:1027F000432E512C8091550B9091560B892B09F04B
+:102800007EC0E091300BF0E0EE0FFF1FE456FF4B6F
+:10281000859194910E9434483092160220921502BC
+:10282000E1E0E093240BE091300BF0E0EE0FFF1FAE
+:10283000E456FF4B859194910F947E518CE40E9455
+:10284000EF43882359F00E945C449B01AC016BA5C7
+:102850007CA58DA59EA50F94EDBC0AC020E030E0BC
+:1028600040EA52E46BA57CA58DA59EA50F94ECBC17
+:102870006BA77CA78DA79EA7EFA0F8A409A51AA512
+:102880002BA13CA14DA15EA16F8D78A189A19AA138
+:102890007F926F92812C912CB8E6AB2EB2E4BB2EC6
+:1028A000DE019B966D010F9458050F94071F149A33
+:1028B00064E670E080E090E00F941EB5509216023E
+:1028C00040921502E091300BF0E0EE0FFF1FEC5646
+:1028D000FF4B8591949140E060E00F94BE9B21E016
+:1028E00030E00F900F90882311F020E030E030931B
+:1028F000560B2093550B81E00F94D1997BCF0F9409
+:102900006C7184E090E090931602809315020F940E
+:102910000453811106C00F94F32B81E00E94BD5C2B
+:10292000F6CF82E090E0909316028093150220E0AB
+:1029300030E04CE852E46BA57CA58DA59EA50F94D4
+:10294000EDBC6BA77CA78DA79EA7EFA0F8A409A557
+:102950001AA52BA13CA14DA15EA16F8D78A189A1E3
+:102960009AA1ACEC6A2EAAE07A2E7F926F92812C0B
+:10297000912CB0EAAB2EB1E4BB2EFE01BB966F01E9
+:102980000F94580520E030E048E452E46BA57CA5A4
+:102990008DA59EA50F94EDBC6BA77CA78DA79EA7C8
+:1029A000EFA0F8A409A51AA52BA13CA14DA15EA1F9
+:1029B0006F8D78A189A19AA17F926F92812C912C21
+:1029C000A12CE0E4BE2E0F9458051092560B1092E5
+:1029D000550B0F94ED710F900F900F900F90F4E046
+:1029E0002F2E312CA2E04A2E512C8091550B909124
+:1029F000560B019709F49AC01092560B1092550B82
+:102A000030921602209215020F94377250921602DD
+:102A1000409215028091550B9091560B8230910592
+:102A200071F1039709F07CC020E030E048E452E403
+:102A30006BA57CA58DA59EA50F94EDBC6BA77CA76F
+:102A40008DA79EA7EFA0F8A409A51AA52BA13CA1CC
+:102A50004DA15EA16F8D78A189A19AA17F926F92FD
+:102A6000812C912CA12CB0E4BB2EFE01BB966F01F2
+:102A70000F9458050F94A3710F900F90B6CF20E0DC
+:102A800030E04CE852E46BA57CA58DA59EA50F9483
+:102A9000EDBC6BA77CA78DA79EA7EFA0F8A409A506
+:102AA0001AA52BA13CA14DA15EA16F8D78A189A192
+:102AB0009AA17F926F92812C912CE0EAAE2EE1E4F4
+:102AC000BE2EFE01BB966F010F94580520E030E04A
+:102AD00048E452E46BA57CA58DA59EA50F94EDBCA2
+:102AE0006BA77CA78DA79EA7EFA0F8A409A51AA5A0
+:102AF0002BA13CA14DA15EA16F8D78A189A19AA1C6
+:102B00007F926F92812C912CA12CF0E4BF2E0F9418
+:102B100058050F94ED710F900F900F900F9065CFA7
+:102B20000F94907181E00F94D1995FCF20E030E055
+:102B300040EA50E46BA57CA58DA59EA50F94EDBC45
+:102B40006BA77CA78DA79EA7EFA0F8A409A51AA53F
+:102B50002BA13CA14DA15EA16F8D78A189A19AA165
+:102B6000BCEC6B2EBAE07B2E7F926F92812C912C65
+:102B7000A12CE0E4BE2EDE019B966D010F9458055A
+:102B8000A50194016BA57CA58DA59EA50F94ECBC19
+:102B90006BA77CA78DA79EA7EFA0F8A409A51AA5EF
+:102BA0002BA13CA14DA15EA16F8D78A189A19AA115
+:102BB0007F926F92812C912CF8EEAF2EF2E4BF2E13
+:102BC0000F945805EFA0F8A409A51AA52D813E8100
+:102BD0004F81588569817A818B819C817F926F9228
+:102BE000812C912CA8E4AA2EA2E4BA2E0F945805A9
+:102BF000E984FA840B851C852D813E814F8158859F
+:102C000069817A818B819C817F926F92812C912C3A
+:102C1000B0E7AB2EB1E4BB2E0F94580520E030E0B6
+:102C200040E050E46BA57CA58DA59EA50F94EDBC5E
+:102C30006BA77CA78DA79EA7E984FA840B851C85CA
+:102C40002D813E814F81588569817A818B819C815C
+:102C50007F926F92812C912CE8EEAE2EE2E4BE2E94
+:102C60000F945805CE010D960F94B1138091480230
+:102C70009091490280935602909357029F938F93AD
+:102C800082E69BE09F938F938E01015D1F4F1F9300
+:102C90000F930F9418C860E0C8010E9411C3E0911F
+:102CA000300BF0E0EE0FFF1FE45EFF4B8591949137
+:102CB0000F947E511092240B1092220B1092210B34
+:102CC000B8ADB09369020FB6F894DEBF0FBECDBFAA
+:102CD00080913512882309F4A8C30E943BC20F9447
+:102CE000071F0E94B4C4811105C00E94E06D0E94BC
+:102CF0003BC2F7CF0E9457CA0E9452CA96C3809126
+:102D0000961B9091971B892B09F08FC385E090E06B
+:102D10009093971B8093961B88C38091961B9091EC
+:102D2000971B892B09F081C386E090E09093971B55
+:102D30008093961B7AC30E94A74A77C388E50E94B6
+:102D4000EF43882339F00E945C440F9435BE80E045
+:102D50000F947F208AE50E94EF43882339F00E9478
+:102D60005C440F9435BE81E00F947F2085E40E947F
+:102D7000EF43882309F459C30E945C440F9435BE85
+:102D800082E00F947F2051C30F94653C4EC388E5C9
+:102D90000E94EF43882339F00E945C440F943ABEAE
+:102DA00080E00F94E33B89E50E94EF43882339F0EC
+:102DB0000E945C440F943ABE81E00F94E33B8AE5A5
+:102DC0000E94EF43882339F00E945C440F943ABE7E
+:102DD00082E00F94E33B85E40E94EF43882309F4EB
+:102DE00024C30E945C440F943ABE83E00F94E33BFB
+:102DF0001CC388E50E94EF43882339F00E945C449D
+:102E00000F943ABE80E00F94243C89E50E94EF4382
+:102E1000882339F00E945C440F943ABE81E00F94FD
+:102E2000243C8AE50E94EF43882339F00E945C44E9
+:102E30000F943ABE82E00F94243C85E40E94EF4355
+:102E4000882309F4F2C20E945C440F943ABE83E0E6
+:102E50000F94243CEAC20F947038E7C281E080935B
+:102E6000E81A0F94653CE1C288E50E94EF4388238D
+:102E700031F00E945C440F943ABE6093B70289E53A
+:102E80000E94EF43882331F00E945C440F943ABEC5
+:102E90006093B8028AE50E94EF43882331F00E94D4
+:102EA0005C440F943ABE6093B90285E40E94EF43FC
+:102EB000882331F00E945C440F943ABE6093BA02BA
+:102EC000EBECF4E08191882339F09091C00095FFFC
+:102ED000FCCF8093C600F6CF4AE050E06091B70285
+:102EE0008EE799E00E948742EEEDF4E0819188231D
+:102EF00039F09091C00095FFFCCF8093C600F6CFCB
+:102F00004AE050E06091B8028EE799E00E94874263
+:102F1000E1EFF4E08191882339F09091C00095FFB2
+:102F2000FCCF8093C600F6CF4AE050E06091B90232
+:102F30008EE799E00E948742E4E0F5E081918823E2
+:102F400039F09091C00095FFFCCF8093C600F6CF7A
+:102F50004AE050E06091BA028EE799E00E94874211
+:102F600064C288E50E94EF43882339F00E945C44E4
+:102F70000F943ABE80E00F94E43989E50E94EF4354
+:102F8000882339F00E945C440F943ABE81E00F948C
+:102F9000E4398AE50E94EF43882339F00E945C44BB
+:102FA0000F943ABE82E00F94E43985E40E94EF4327
+:102FB000882309F43AC20E945C440F943ABE83E02D
+:102FC0000F94E43932C288E50E94EF43882339F038
+:102FD0000E945C440F943ABE80E00F943B3A89E52E
+:102FE0000E94EF43882339F00E945C440F943ABE5C
+:102FF00081E00F943B3A8AE50E94EF43882339F041
+:103000000E945C440F943ABE82E00F943B3A85E400
+:103010000E94EF43882309F408C20E945C440F9485
+:103020003ABE83E00F943B3A00C20E946054FDC157
+:10303000709069021092690281E08093240B82E013
+:1030400090E09093220B8093210BE091300BF0E005
+:10305000EE0FFF1FE456FF4B859194910F947E5124
+:1030600020E030E040EA52E46091EC0A7091ED0A11
+:103070008091EE0A9091EF0A0F94ECBC6093EC0AF9
+:103080007093ED0A8093EE0A9093EF0AE090E80ABD
+:10309000F090E90A0091EA0A1091EB0A2091E40A03
+:1030A0003091E50A4091E60A5091E70A6091E00A02
+:1030B0007091E10A8091E20A9091E30AECECFAE067
+:1030C000FF93EF93812C912CE8EEAE2EE2E4BE2E1E
+:1030D000FCEECF2EFAE0DF2E0F9458050F94071F59
+:1030E000E091300BF0E0EE0FFF1FE45EFF4B8591A7
+:1030F00094910F947E511092240B1092220B1092F7
+:10310000210B709269020F900F908FC1E2E5FBE0F6
+:103110008491882341F09091C00095FFFCCF80936B
+:10312000C6003196F5CF8091C00085FFFCCF8AE0C4
+:103130008093C6007AC184E50E94EF43882309F496
+:10314000D3C00F94071FE0913910F0913A103196D7
+:1031500081918032E9F38930D9F390ED980F9A305C
+:10316000E0F08F33A9F0E2E4FBE08491882341F0A2
+:103170009091C00095FFFCCF8093C6003196F5CFAB
+:103180008091C00085FFFCCF8AE08093C6004DC1CE
+:103190000F9412B08093810A06C00E945C440F9481
+:1031A0003ABE6093810A2091810A81E090E0022E6C
+:1031B00001C0880F0A94EAF790911E0B982B909308
+:1031C0001E0B222309F442C0EFE3F0E1849188232F
+:1031D00041F09091C00095FFFCCF8093C6003196DE
+:1031E000F5CFE0E4FBE08491882341F09091C000AA
+:1031F00095FFFCCF8093C6003196F5CF6091810A90
+:1032000070E04AE050E08EE799E00E9442428091EF
+:10321000C00085FFFCCF8AE08093C600E6E6F2E4BA
+:1032200085919491FC012491222341F03091C000BA
+:1032300035FFFCCF2093C6000196F4CF8091C000EB
+:1032400085FFFCCF8AE08093C600EFC086E40E9431
+:10325000EF438823D9F00E945C446B017C016093AA
+:103260009B0A70939C0A80939D0A90939E0A20E08B
+:1032700030E0A9010F94C9BF181644F4C0920C02A3
+:10328000D0920D02E0920E02F0920F02EFE3F0E115
+:103290008491882341F09091C00095FFFCCF8093EA
+:1032A000C6003196F5CFE6E9F3E485919491FC01EF
+:1032B0002491222341F03091C00035FFFCCF2093B0
+:1032C000C6000196F4CF6091CC0A70E04AE050E06D
+:1032D0008EE799E00E9442428091C00085FFFCCFBA
+:1032E0008AE08093C600A1C084E40E94EF43882353
+:1032F00009F45AC00E945C440F9435BE66307105D3
+:1033000009F443C0CCF461307105B1F154F46F3F5E
+:10331000FFEF7F0771F1672B09F087C00E94D53856
+:1033200084C06330710571F154F16430710509F0A6
+:103330007CC00E94183A79C06A30710561F154F47A
+:103340006730710529F16830710509F06EC00E947F
+:10335000743A6BC0623528E0720701F1653A33E2D6
+:103360007307F9F06C30710509F05FC00E946D3B86
+:103370005CC00E94CF3859C00E94F03856C00E94ED
+:10338000083953C00E94813950C00E94723A4DC022
+:103390000E94733A4AC00E94683B47C00E947C3B2F
+:1033A00044C00E94543C41C0EFE3F0E18491882383
+:1033B00041F09091C00095FFFCCF8093C6003196FC
+:1033C000F5CFE0EAF0E485919491FC012491222369
+:1033D00041F03091C00035FFFCCF2093C60001962C
+:1033E000F4CFE0914310F0914410E85BFF4E8191DF
+:1033F000882339F09091C00095FFFCCF8093C600E0
+:10340000F6CFEBE3FBE08491882341F09091C0007C
+:1034100095FFFCCF8093C6003196F5CF8091C00018
+:1034200085FFFCCF8AE08093C60081E090E0909316
+:103430001602809315020E94965561C1C090B70A8A
+:10344000D090B80AE090B90AF090BA0A2091EC0A3C
+:103450003091ED0A4091EE0A5091EF0AC701B60192
+:103460000F94ECBC2DEC3CEC4CEC5DE30F94C9BF2D
+:10347000181614F00C940C71C092EC0AD092ED0A5C
+:10348000E092EE0AF092EF0A8CEE9AE00F94B113FC
+:1034900060E080E00E94BA5932C10E945C442091F1
+:1034A000D40A3091D50A4091D60A5091D70A0F9488
+:1034B000EDBC6093E00A7093E10A8093E20A909376
+:1034C000E30A0C941F720E945C442091D80A309148
+:1034D000D90A4091DA0A5091DB0A0F94EDBC60934F
+:1034E000E40A7093E50A8093E60A9093E70A0C9445
+:1034F0002C720E945C442091DC0A3091DD0A4091DC
+:10350000DE0A5091DF0A0F94EDBC6093E80A7093D5
+:10351000E90A8093EA0A9093EB0A0C942D737110D8
+:1035200028C0662031F181E0809377120F94761FD6
+:103530006B017C0180E00F94761FAB01BC01970109
+:10354000860187E792E10E9465449B01AC0160918E
+:10355000E80A7091E90A8091EA0A9091EB0A0F94C7
+:10356000ECBC6093E80A7093E90A8093EA0A9093AE
+:10357000EB0A8091921B882321F084E190E00F9464
+:10358000FF6010925E0BECE3FEE08491882341F033
+:103590009091C00095FFFCCF8093C6003196F5CF87
+:1035A0000E94C26CE0E3FEE08491882341F0909198
+:1035B000C00095FFFCCF8093C6003196F5CF0E94E6
+:1035C000286DE4E2FEE08491882341F09091C000F0
+:1035D00095FFFCCF8093C6003196F5CF0E94846D95
+:1035E00024CF20E030E040E85FE36091EC0A709186
+:1035F000ED0A8091EE0A9091EF0A0F94EDBC609372
+:10360000EC0A7093ED0A8093EE0A9093EF0AE09033
+:10361000E80AF090E90A0091EA0A1091EB0A209179
+:10362000E40A3091E50A4091E60A5091E70A609178
+:10363000E00A7091E10A8091E20A9091E30AECECD1
+:10364000FAE0FF93EF93812C912CA8ECAA2EA3E42F
+:10365000BA2EBCEECB2EBAE0DB2E0F9458050F909D
+:103660000F900C94647E82E090E090931602809319
+:10367000150280E00F9451510C94BE820F94F32BED
+:1036800081E00E94BD5C80E00F940A970C948F82C9
+:103690000E941244AB01BC014093080E5093090EE6
+:1036A00060930A0E70930B0E83E59DE00E947FAA43
+:1036B000BCCE0E945C440F9435BE8B010C94D68422
+:1036C0000F94071F88E50E94EF43882319F0179A8B
+:1036D0001092D10A89E50E94EF43882319F0169AC7
+:1036E0001092D20A8AE50E94EF4385E40E94EF43DC
+:1036F000882311F40C941589149A0C941589CD5AC9
+:10370000DF4F0FB6F894DEBF0FBECDBFDF91CF9174
+:103710001F910F91FF90EF90DF90CF90BF90AF90EF
+:103720009F908F907F906F905F904F903F902F90E1
+:1037300008950F931F93CF93DF931F92CDB7DEB7FA
+:1037400081E090E090931602809315028091570BD0
+:103750009091580B892BA1F00F94EFB40091820A3D
+:103760001091830A2091840A3091850A601B710BA5
+:10377000820B930B693E73408105910508F0B3C03D
+:103780008091570B9091580B892B11F410925F0B7D
+:1037900080912F0B882319F00E94CE5180C00E9487
+:1037A000BDC460E08AE69BE00E946DBB80913F1043
+:1037B00090914010892B09F472C010923E108091B4
+:1037C0006A0B8823B1F00091431010914410085BFC
+:1037D0001F4E63E77EE0C8010F9438C6892B09F5B8
+:1037E000B8018AE69BE00E94BCBA80916B0B8823EB
+:1037F00019F00E94E06D31C0EAEEF1E485919491F8
+:10380000FC012491222341F03091C00035FFFCCF10
+:103810002093C6000196F4CF8091C00085FFFCCFB5
+:1038200019C060E08AE69BE00E9463BCE0EBF2E432
+:1038300085919491FC012491222341F03091C000A4
+:1038400035FFFCCF2093C6000196F4CF8091C000D5
+:1038500085FFFCCF8AE08093C60080913E108111E5
+:103860001CC080913F1090914010892BB1F0F894CA
+:1038700010E090E0E0914310F0914410EB5BFF4EBC
+:103880008081823011F41181928199830E943BC220
+:10389000812F99810F94321478940E94EB490F94F0
+:1038A000F32B8091931B882311F081E001C080E00D
+:1038B0000E94BD5C0F94C21480E00F940A970E948E
+:1038C000AFCB0F94F03D8091C81A882319F1109264
+:1038D000C81A61E084E69EE00F90DF91CF911F91BE
+:1038E0000F910C9411C381E080935F0B8091570B73
+:1038F0009091580B01979093580B8093570B0F940E
+:10390000EFB46093820A7093830A8093840A909341
+:10391000850A36CF0F90DF91CF911F910F910895B7
+:103920009F92AF92BF92CF92DF92EF92FF920F934E
+:103930001F93CF93DF931F921F92CDB7DEB78DE910
+:103940009FE00F944CCA6093E00A7093E10A809361
+:10395000E20A9093E30A81EA9FE00F944CCA6093D5
+:10396000E40A7093E50A8093E60A9093E70A8DE8EB
+:103970009FE00F944CCA6B017C0183E79FE00F949A
+:1039800051CA8C012AE037ED43E25FE3C701B6017B
+:103990000F94EDBC6B017C0167E074E0601B710B60
+:1039A00004E0769567950A95E1F780E090E00F9442
+:1039B00066BE209148193091491940914A19509199
+:1039C0004B190F94CDBD9B01AC01C701B6010F94FB
+:1039D000EDBC6093E80A7093E90A8093EA0A909339
+:1039E000EB0A80E1E0EEFAE0ABEABAE001900D927A
+:1039F0008A95E1F7EBE7F9E08491882341F0909113
+:103A0000C00095FFFCCF8093C6003196F5CF0E9491
+:103A1000C26C0E94AADB10927712A5E7EA2EAFE0F3
+:103A2000FA2ED12CB3E0BB2EAA24A39417E0C12E0A
+:103A30008D2D6B2D0F9469C2082F992E42E050E016
+:103A4000B701CE0101960F9434CA69817A8161155C
+:103A5000710511F0A09277122C2D02038001112420
+:103A6000090D111D97FC1A95000F111F000F111F52
+:103A700009581D4E882777FD8095982F0F9468BEB2
+:103A80002FE632E143E85AE30F949BC0F8016183CB
+:103A9000728383839483D394F2E0EF0EF11C29E0C8
+:103AA000D212C6CF80917712882321F087E792E166
+:103AB0000E940EFAE9E4F9E08491882341F09091A4
+:103AC000C00095FFFCCF8093C6003196F5CF0E94D1
+:103AD000846D0E9402F9E090E80AF090E90A0091F2
+:103AE000EA0A1091EB0A2091E40A3091E50A40912C
+:103AF000E60A5091E70A6091E00A7091E10A80912C
+:103B0000E20A9091E30AECEECE2EEAE0DE2E0F946C
+:103B1000061281E08093D10A17988093D20A1698F2
+:103B20008093D30A1598E7E1F9E08491882341F066
+:103B30009091C00095FFFCCF8093C6003196F5CFE1
+:103B40000E94286D8CE89FE00F9444CAE091CC0A53
+:103B5000F0E0EE0FFF1FE958F54E90E0918380836F
+:103B60008BE89FE00F9444CA90E09093761A80937C
+:103B7000751A0F900F90DF91CF911F910F91FF90C9
+:103B8000EF90DF90CF90BF90AF909F900895AF924D
+:103B9000BF92CF92DF92EF92FF920F931F93CF933A
+:103BA000DF93CDB7DEB76E970FB6F894DEBF0FBECA
+:103BB000CDBF182F81E00F94D19982E00F940A971E
+:103BC000E091300BF0E0EE0FFF1FEC56FE4B8591BD
+:103BD00094910F947E51A4DEE091CC0AF0E0EE0FB8
+:103BE000FF1FE958F54E81818F9380818F938FE776
+:103BF0009AE09F938F93CE0101965C01BF928F93C1
+:103C00000F9418C860E0C5010E9411C38091761A14
+:103C10008F938091751A8F9386E79AE09F938F9385
+:103C2000BF92AF920F9418C860E0C5010E9411C303
+:103C30000FB6F894DEBF0FBECDBF20E030E048ECF9
+:103C400051E46091E80A7091E90A8091EA0A909142
+:103C5000EB0A0F94C6BD87FF05C061E08AE69AE0D3
+:103C60000E9411C361E082E69AE00E9411C3E091D4
+:103C7000CC0AF0E0EE0FFF1FE958F54E81818F93DB
+:103C800080818F9329E53AE03F932F93BF92AF92C3
+:103C90000F9418C860E0C5010E9411C38091761A84
+:103CA0008F938091751A8F9320E53AE03F932F937D
+:103CB000BF92AF920F9418C860E0C5010E9411C373
+:103CC00061E08CE49AE00E9411C30FB6F894DEBF65
+:103CD0000FBECDBF111105C061E081E49AE00E94E2
+:103CE00011C361E085E39AE00E9411C382E79FE07F
+:103CF0000F9444CA882341F18EE69FE00F944CCA8A
+:103D00006B017C0161E081E39AE00E9411C38BE2C8
+:103D10009AE09F938F93BF92AF920F9418C8F501CA
+:103D200001900020E9F78F010150110923E046E0DE
+:103D3000C701B6010F9416C360E0C5010E9411C30C
+:103D40000F900F900F900F9060E085EA9FE00F9426
+:103D500056CAE3E1FAE08491882341F09091C000D3
+:103D600095FFFCCF8093C6003196F5CFEAEFF9E0DE
+:103D70008491882341F09091C00095FFFCCF8093FF
+:103D8000C6003196F5CF4091E00A5091E10A60916A
+:103D9000E20A7091E30A22E030E08EE799E00E94A7
+:103DA0003643E1EEF9E08491882341F09091C00020
+:103DB00095FFFCCF8093C6003196F5CF4091E40A81
+:103DC0005091E50A6091E60A7091E70A22E030E03E
+:103DD0008EE799E00E9436430E944969E7ECF9E0DA
+:103DE0008491882341F09091C00095FFFCCF80938F
+:103DF000C6003196F5CF4091E80A5091E90A6091EA
+:103E0000EA0A7091EB0A22E030E08EE799E00E9426
+:103E10003543EDEAF9E08491882341F09091C000A8
+:103E200095FFFCCF8093C6003196F5CF4091EC0A08
+:103E30005091ED0A6091EE0A7091EF0A22E030E0B5
+:103E40008EE799E00E9435436E960FB6F894DEBF78
+:103E50000FBECDBFDF91CF911F910F91FF90EF90DB
+:103E6000DF90CF90BF90AF900895CF92DF92EF9206
+:103E7000FF92CF93DF930F94C75285EC93EA909310
+:103E8000780A8093770A10927A0A1092790A82E06F
+:103E90008093720A10927C0A10927B0A0E94E54974
+:103EA00084EC9FE00F9444CA8093921B60E97BE10D
+:103EB00081EC9FE00F94A5502091921B8091901B64
+:103EC0009091911B2F3F11F4009721F08F3F2FEF1E
+:103ED000920711F41092921B019621F41092911BFB
+:103EE0001092901B8091921B882341F088E090E013
+:103EF0000F94FF6081E08093030A02C01092030ACE
+:103F000040E052EC61E070E08EE799E00E94D4401E
+:103F10008EE393E490936A0A8093690A10926C0A84
+:103F200010926B0A82E08093640A10926E0A1092DB
+:103F30006D0A81E69AE09093F71B8093F61BE1E807
+:103F4000FFE08491882341F09091C00095FFFCCF61
+:103F50008093C6003196F5CF8091C00085FFFCCFDD
+:103F60008AE08093C600CFE3D0E1FE0184918823EC
+:103F700041F09091C00095FFFCCF8093C600319630
+:103F8000F5CFF4B6F0FE06C0EEEBF1E48591949126
+:103F90000F94BBC7F1FE06C0ECECF2E4859194915E
+:103FA0000F94BBC7F2FE06C0E0E3F3E48591949161
+:103FB0000F94BBC7F3FE06C0E4E8F0E4859194914A
+:103FC0000F94BBC7F5FE06C0E8EEF0E4859194912E
+:103FD0000F94BBC714BEFE018491EFE3F0E1882388
+:103FE00049F09091C00095FFFCCF8093C6003196B8
+:103FF0008491F5CFEEE0F3E485919491FC01249156
+:10400000222341F03091C00035FFFCCF2093C60041
+:104010000196F4CFECE6FFE08491882341F0909183
+:10402000C00095FFFCCF8093C6003196F5CFE0E944
+:10403000F3E485919491FC012491222341F0309185
+:10404000C00035FFFCCF2093C6000196F4CFE5E514
+:10405000FFE08491882341F09091C00095FFFCCF50
+:104060008093C6003196F5CF8091C00085FFFCCFCC
+:104070008AE08093C600EAE4FFE08491882341F05F
+:104080009091C00095FFFCCF8093C6003196F5CF8C
+:10409000EEE3FFE08491882341F09091C00095FF0A
+:1040A000FCCF8093C6003196F5CF8091C00085FF8C
+:1040B000FCCF8AE08093C600FE01C491EFE3F0E1FB
+:1040C000CC2349F08091C00085FFFCCFC093C6008F
+:1040D0003196C491F5CFE6E9F2E485919491FC0123
+:1040E0002491222341F03091C00035FFFCCF209372
+:1040F000C6000196F4CF0E94E4AF4AE050E0BC0154
+:104100008EE799E00E944242ECECF1E485919491B3
+:10411000FC012491222341F03091C00035FFFCCFF7
+:104120002093C6000196F4CF4AE050E060E775E0C6
+:104130008EE799E00E9442428091C00085FFFCCF4B
+:104140008AE08093C60060E084E190E00E94A4369B
+:104150000E94FBAF0F9420280E94E5490F944B0367
+:104160008FEF9FE00F9444CA91E0811101C090E06D
+:104170009093E81A89E69FE00F9444CA882329F0B7
+:104180000E946A4867E175E004C00E947C486CE2C6
+:1041900075E08EE799E00E94354268EC88EC0E9459
+:1041A000F7FFEC01DF938F938DE29FE09F938F9356
+:1041B0000F946BC787E69FE00F9444CAF82E0F90C8
+:1041C0000F900F900F90CD2B09F4F12C84E29FE01B
+:1041D0000F94BBC7FF2039F08BE19FE00F94BBC762
+:1041E0000E9457CA06C081E19FE00F94BBC70E949E
+:1041F00083CA0F941B210E941CDB84E090E0909303
+:104200001602809315028091000186FD3AC08FEF5F
+:1042100093EDE0E381509040E040E1F700C0000002
+:104220008091000186FD2DC00F94665083E09FE0D1
+:104230000F947767809101018460809301019FB79B
+:10424000F894809102018460809302019FBF809165
+:10425000000186FFFCCF9FB7F894809102018B7F0D
+:10426000809302019FBFFFEF27EA81E6F1502040D3
+:104270008040E1F700C000000F94975360E00E9477
+:10428000D2483D9AE6EEFEE08491882341F0909179
+:10429000C00095FFFCCF8093C6003196F5CF83E434
+:1042A0000F94003F4AE050E0BC018EE799E00E9485
+:1042B00094429FB7F89480910B01846080930B0126
+:1042C0009FBF83E40F94003F08967C0174E0F6944E
+:1042D000E7947A95E1F7E114F10491F0429A62E0F3
+:1042E00070E080E090E00F941EB5429862E070E0CC
+:1042F00080E090E00F941EB591E0E91AF108EBCF51
+:10430000E9ECFEE08491882341F09091C00095FF94
+:10431000FCCF8093C6003196F5CF83E40F94003F25
+:104320004AE050E0BC018EE799E00E949442159863
+:1043300084EC9FE00F9444CA8093921B60E97BE178
+:1043400081EC9FE00F94A5502091921B8091901BCF
+:104350009091911B2F3F11F4009721F08F3FEFEFC9
+:104360009E0711F41092921B019621F41092911B5A
+:104370001092901B8091921B882321F088E090E09E
+:104380000F94FF608BEB9FE00F9444CA91E0813063
+:1043900009F090E09093300D8AE69BE00E944CB7C4
+:1043A0008CEF9FE00F944CCA6F3F7F4F8F4F9F4F12
+:1043B000E1F488EF9FE00F944CCA6F3F7F4F8F4F1F
+:1043C0009F4F99F484EF9FE00F944CCA6F3F7F4F4B
+:1043D0008F4F9F4F51F460E08FEF9FE00F9474CAAE
+:1043E00061E08FE59FE00F9474CA8EEF9FE00F9419
+:1043F00044CA8093300B823010F00F94157C8FEA02
+:104400009FE00F9444CA8F3F41F460E08FEA9FE041
+:104410000F9474CA10925D0B06C091E0811101C027
+:1044200090E090935D0B86EA9FE00F9444CA8F3F23
+:1044300059F561E086EA9FE00F9474CA68E070E085
+:1044400080EB9FE00F9482CA68E170E082EB9FE00E
+:104450000F9482CA60E370E084EB9FE00F9482CAFD
+:1044600060E570E086EB9FE00F9482CA68E770E039
+:1044700088EB9FE00F9482CA61E08FEA9FE00F947F
+:1044800074CA81E080935D0B85EA9FE00F9444CA73
+:104490008F3F29F460E085EA9FE00F9474CA0E9480
+:1044A0005E600E94FE680E947F680E94E9CA6AE41A
+:1044B00072E087EA9FE00F94A5506CE472E089EA0D
+:1044C0009FE00F94A5506EE472E08BEA9FE00F949A
+:1044D000A55060E572E08DEA9FE00F94A5508FE54E
+:1044E0009FE00F9444CA813021F480E090E00F9463
+:1044F0009F828FE59FE00F9444CA81111AC087EF15
+:104500009FE00F9444CA9FEF980F9E3F08F48CC021
+:1045100060E070E088EF9FE00F9470CAE091300B8C
+:10452000F0E0EE0FFF1FE856FD4B859194910F943C
+:104530007EA483E090E0909316028093150281E0C0
+:104540000F94D1990F94665082E00F940A970F94BC
+:104550003FB485EA9FE00F9444CA813009F04CC013
+:104560000F94F32BC0905D1AD0905E1AE0905F1A02
+:10457000F090601A8BE89FE00F9444CA682F70E0B7
+:1045800080E090E00F9466BE20E030E040EA50E426
+:104590000F94ECBC9B01AC01C701B6010F94C9BFDD
+:1045A000181614F481E010C0E091300BF0E0EE0F2B
+:1045B000FF1FE057FE4B8591949140E060E00F941F
+:1045C000BE9B882319F080E0E2DA16C060E085EA3D
+:1045D0009FE00F9456CA81E00F94D19982E00F9426
+:1045E0000A97E091300BF0E0EE0FFF1FE45EFF4B07
+:1045F000859194910F947E5181E090E09093160202
+:104600008093150228E288E190E00FB6F894A8950F
+:10461000809360000FBE20936000DF91CF91FF90E8
+:10462000EF90DF90CF900895863E61F4E091300BDB
+:10463000F0E0EE0FFF1FEC57FC4B859194910F9427
+:104640007EA40DC0813079F480915D0B882309F43C
+:1046500070CF86EA9FE00F9444CA81116ACF81E04F
+:104660000F94D19966CF803F09F063CF57CF21E8EF
+:1046700035E0FC01318320832781222319F0049641
+:104680000C9462AB08958F929F92AF92BF92CF929B
+:10469000DF92EF92FF920F931F93CF93DF938C01E2
+:1046A0008B519E4FE4DF680189E8C80ED11CC1140C
+:1046B000D10419F1780181E4E81A8EEFF80AE701D4
+:1046C00057018FE1A81AB10881E8882E85E0982E5D
+:1046D000CC15DD0591F0FE01EE19FF09EA0DFB1D79
+:1046E00091828082FE0178978081811102C06F974C
+:1046F000EFCFCE014B97E6D7FACFC80186599F4F2F
+:10470000B6DFC801875B9F4FDF91CF911F910F915B
+:10471000FF90EF90DF90CF90BF90AF909F908F90E1
+:10472000A6CF8AE69BE00E94C6B40F94EFB46093D4
+:10473000660B7093670B8093680B9093690B0F94D3
+:10474000EFB4605679478E4F9F4F6093590B70932B
+:104750005A0B80935B0B90935C0B0F94EFB46093B8
+:10476000370B7093380B8093390B90933A0B0F945F
+:10477000EFB46093330B7093340B8093350B9093AD
+:10478000360B08958AE69BE07ECF682F81E19BE19E
+:104790000E94444080E090E008958FEF8EBD0DB4FC
+:1047A00007FEFDCF8EB508958EBD0DB407FEFDCF7B
+:1047B000089561E0FC0180810D9413B7FC01228112
+:1047C000322F306A36953CBD20FD06C031E02630E0
+:1047D00009F430E0232F01C020E02DBD60E0FC0192
+:1047E00080810D9413B7CF92DF92EF92FF920F93D7
+:1047F0001F93CF93DF93EC018B017A010F94EFB4F9
+:104800006B01CBDF8B838F3F49F40F94EFB46C19AE
+:104810007D096D327140A8F381E144C08E3F11F0F3
+:104820008FE040C0E114F104D9F0C70101972FEFE8
+:104830002EBDF8014FEF9F01201B310B28173907C0
+:1048400038F40DB407FEFDCF2EB521934EBDF3CF46
+:104850000DB407FEFDCF2EB5F801E80FF91F208338
+:10486000D801E00EF11EC12CD12CAE15BF0579F098
+:104870008D91ED2DFF27E827EE0FFF1FE45BFF4E24
+:1048800085919491DC2CCC24C826D926EECF85DFE7
+:10489000082F10E0102F002780DF082BC016D1064C
+:1048A00059F080E28983CE0184DFCD81CC2369F089
+:1048B0008FEF7ADFC0E009C0CE017BDFCD81CC2352
+:1048C00019F08FEF71DF01C0C1E08C2FDF91CF9124
+:1048D0001F910F91FF90EF90DF90CF9008950F936D
+:1048E0001F93CF93DF93EB010F94EFB48B0155DF50
+:1048F0008F3F49F00F94EFB4601B710B6C177D076D
+:10490000B0F380E001C081E0DF91CF911F910F9162
+:104910000895CF92DF92FF920F931F93CF93DF936F
+:1049200000D01F92CDB7DEB76C01F62E29833A83F3
+:104930004B835C8343DF6CE271E0C601D0DF8F2DD7
+:10494000806432DF08E110E05C814B813A8129818B
+:10495000DA01C901002E04C0B695A79597958795F1
+:104960000A94D2F729833A834B835C831DDF085076
+:10497000110929813A814B815C81083F8FEF18072B
+:1049800039F7FF2029F0E8E0FE1621F08FEF03C091
+:1049900085E901C087E808DFFCE0FF1201C0FDDE09
+:1049A00010E0FBDEF601838387FF04C01F3F11F098
+:1049B0001F5FF7CF0F900F900F900F90DF91CF9167
+:1049C0001F910F91FF90DF90CF900895BF92CF92EB
+:1049D000DF92EF92FF920F931F93CF93DF93EC013F
+:1049E000B62E1C82198248830F94EFB48B0161E0CC
+:1049F00088810F94DAB6CE01DCDE60E082E30F94AA
+:104A0000DAB661E083E30F94DAB661E084E30F94F1
+:104A1000DAB661E085E30F94DAB661E085E30F94DE
+:104A200013B785E08A8382E58CBD1DBC6AE0F62E53
+:104A30008FEFBADEFA94E1F720E030E0A90160E000
+:104A4000CE0167DFF82E8B8381E0F81649F00F94D2
+:104A5000EFB4601B710B613D774070F381E046C09D
+:104A60002AEA31E040E050E068E0CE0152DF82FF08
+:104A700002C0FC820CC054E0F52E8FDE8B83FA94CA
+:104A8000E1F78A3A11F082E031C082E08C838C81B8
+:104A9000823031F4C12CD12CE12C40E4F42E03C03F
+:104AA000C12CD12C760120E030E0A90167E3CE01D2
+:104AB00030DFA701960169E2CE012BDF8B838823CB
+:104AC00049F00F94EFB4601B710B613D774058F3D0
+:104AD0008AE00CC08C818230B1F420E030E0A90182
+:104AE0006AE3CE0116DF882329F088E08983CE01AE
+:104AF00060DE14C052DE807C803C11F483E08C8345
+:104B00004CDE4BDE4ADECE0154DE86E08B1518F417
+:104B100088E1898303C0BA8281E001C080E0DF912F
+:104B2000CF911F910F91FF90EF90DF90CF90BF90AA
+:104B30000895AF92BF92CF92DF92EF92FF920F93C0
+:104B40001F93CF93DF93EC016A017B0189018C8174
+:104B5000833039F0F9E0CC0CDD1CEE1CFF1CFA951B
+:104B6000D1F773E0B72EE4E0AE2EBA94A701960118
+:104B700061E1CE01CEDE882311F0A98207C040E0BA
+:104B800052E0B801CE012FDE81110EC0CE01BB2054
+:104B900049F00FDE20E030E0A9016CE0CE01B9DE83
+:104BA0001982E3CF06DE80E0DF91CF911F910F9154
+:104BB000FF90EF90DF90CF90BF90AF900895CF938C
+:104BC000DF93EC016EBD20E030E00DB407FEFDCFB9
+:104BD000FA01E20FF31F80818EBD0DB407FEFDCFF9
+:104BE00081818EBD2E5F3F4F211582E0380769F726
+:104BF0000DB407FEFDCF8FEFD7DD8FEFD5DDCDDD17
+:104C00008B838F71853031F083E18983CE01D1DDD3
+:104C100080E001C081E0DF91CF9108950F931F9351
+:104C2000CF93DF93EC0189018C81833039F0B9E0B7
+:104C3000440F551F661F771FBA95D1F79A01AB0134
+:104C400068E1CE0166DE882311F086E01EC0A8016F
+:104C50006EEFCE01B4DF8823C9F068E572E0CE01C3
+:104C60003EDE182F811102C087E10FC020E030E046
+:104C7000A9016DE0CE014DDE811106C08EDD8111EE
+:104C800003C0CE0196DD05C086E18983CE0191DDAA
+:104C900010E0812FDF91CF911F910F9108950F9315
+:104CA0001F93CF93DF93EC010F94EFB48B0175DD6D
+:104CB0008B838F3F49F40F94EFB4601B710B6D32FF
+:104CC0007140A8F381E103C08E3F31F08FE089830A
+:104CD000CE016FDD80E001C081E0DF91CF911F91B7
+:104CE0000F910895CF92DF92EF92FF920F931F934F
+:104CF000CF93DF937C0169019A01AB0160E309DE88
+:104D0000882321F080E8F70181831BC0C701C7DF3A
+:104D10008823B9F0E601C00ED11ECC15DD0519F0CF
+:104D20003CDD8993FACF0230F2E01F0720F435DD35
+:104D30000F5F1F4FF8CFC7013CDD8FEF35DD81E0FE
+:104D400003C0C70136DD80E0DF91CF911F910F9145
+:104D5000FF90EF90DF90CF9008954F925F926F9207
+:104D60007F928F929F92AF92BF92CF92DF92EF92FB
+:104D7000FF920F931F934801590151E09522AA24F5
+:104D8000BB24240135014E0C5F1C611C711C51E0D9
+:104D9000451652E055066104710430F0E12CE2E062
+:104DA000FE2EE818F90804C0E114F10409F448C023
+:104DB000462E512C612C712C7724469477946624CE
+:104DC00055244424662369F04770842E912CA12C2D
+:104DD000B12C5CE1880C991CAA1CBB1C5A95D1F71C
+:104DE0000CC04F70842E912CA12CB12C4BE1880C5F
+:104DF000991CAA1CBB1C4A95D1F7B901A801617086
+:104E0000772709E0440F551F661F771F0A95D1F7D2
+:104E10004429552966297729270121E0421A51089A
+:104E200021E05222612C712C4429552966297729C9
+:104E3000482959296A297B298701960153DF01C036
+:104E400081E01F910F91FF90EF90DF90CF90BF9086
+:104E5000AF909F908F907F906F905F904F9008954C
+:104E6000CF93DF93EC019C012C5F3F4F41E050E07A
+:104E700060E070E0898D9A8D0E9422B2882399F0BB
+:104E80004D895E896F89788D452B462B472B59F4C8
+:104E90004C815D816E817F814D8B5E8B6F8B788FB6
+:104EA000998190689983DF91CF910895CF92DF9295
+:104EB000EF92FF920F931F93CF93DF93EC018989B9
+:104EC0009A89AB89BC89803E9F4FAF41B10510F0F4
+:104ED00080E06AC0CE01C4DF8823D1F30E9436B0DF
+:104EE000182F8823A9F3E98DFA8DCC80DD80EE8020
+:104EF000FF8032E0C31AD108E108F108058404C03C
+:104F0000CC0CDD1CEE1CFF1C0A94D2F7868597851D
+:104F1000A089B189C80ED91EEA1EFB1E81E08093CC
+:104F2000190EC0921C10D0921D10E0921E10F0922B
+:104F30001F1080E092E0ECE1FEE0DF019C011D9299
+:104F400021503040E1F701E0E98DFA8D84810817A6
+:104F500088F42CE13EE0B701A601400F511D611D10
+:104F6000711D80911A0E90911B0E58DE8823E1F07E
+:104F70000F5FEACFC12C82E0D82EE12CF12C058402
+:104F800004C0CC0CDD1CEE1CFF1C0A94D2F749892E
+:104F90005A896B897C894C0D5D1D6E1D7F1D498B67
+:104FA0005A8B6B8B7C8B812FDF91CF911F910F914F
+:104FB000FF90EF90DF90CF900895CF93DF93EC01B7
+:104FC00041E0611101C040E06C857D858E859F8543
+:104FD0000E9476B0882341F0888920E2829FC00138
+:104FE0001124845E914F02C080E090E0DF91CF9168
+:104FF000089530E020E04EE2DC015C91503271F027
+:10500000383029F4FB01E20FF11D40832F5FFB01D3
+:10501000E20FF11DDC015C9150832F5F3F5F019631
+:105020003B3051F7FB01E20FF11D10820895CF9341
+:10503000DF93EB01FC012381211102C080E00EC04F
+:105040002250223020F48FE28883198206C060E06B
+:10505000B4DF009799F3BE01CCDF81E0DF91CF91FF
+:105060000895FB012BE030E231932150E9F7DC0198
+:1050700090E027E03A2FEB2F8D9181110AC0DA01E1
+:105080003C931196EC9381E0FB019081903239F5CD
+:1050900025C08F32A1F38E3219F0ECE4F2E108C0A2
+:1050A0002A30E1F098E02AE0E5CF31963817B1F0E8
+:1050B00034913111FACF291788F03FED380F3E3582
+:1050C00068F431E0390FFB01E90FF11D9FE9980FFA
+:1050D0009A3108F480528083932FCCCF80E00895DA
+:1050E0000F931F93CF93DF93EC018B018B81882368
+:1050F00011F080E042C0FB018789803139F18032B4
+:10510000C1F783E08B83F801428D538D648D758DDB
+:105110004D8B5E8B6F8B788F9E012F5E3F4FC8014A
+:105120000E942DB1882329F31A8F098F81E089838A
+:105130001C821D821E821F82188619861A861B8673
+:105140001C861D861E861F86188A17C082E08B83E8
+:105150001D8A1E8A1F8A188EFB01408D518D60E0CA
+:1051600070E095E0440F551F661F771F9A95D1F7A1
+:10517000498B5A8B6B8B7C8BD7CFDF91CF911F9153
+:105180000F9108952F923F924F925F926F927F926C
+:105190008F929F92AF92BF92CF92DF92EF92FF9247
+:1051A0000F931F93CF93DF93EC015B016A018B8117
+:1051B000811103C08FEF9FEFC6C0898180FFFACFB6
+:1051C00049895A896B897C8988859985AA85BB8597
+:1051D0002601612C712C8A019B01081B190B2A0BDB
+:1051E0003B0B401651066206730618F06A01C81A96
+:1051F000D90A76013E0124E0620E711CE114F1042B
+:1052000009F476C0488559856A857B854A0181E025
+:1052100098222B811A012B01E9E056944794379488
+:105220002794EA95D1F7898D9A8DFC01223049F4B3
+:10523000628D738D848D958D620D731D841D951DFA
+:105240003CC014811150122181149104C1F4111138
+:1052500016C0452B462B472B49F48D899E89AF8973
+:10526000B88D8C839D83AE83BF8309C04C815D81E3
+:105270006E817F81930172D7882309F49BCFE98DDA
+:10528000FA8D6C817D818E819F81625071098109C7
+:105290009109058404C0660F771F881F991F0A941F
+:1052A000D2F72685378540895189620F731F841F85
+:1052B000951F610F711D811D911D20E032E028199D
+:1052C000390987012E153F0508F489010115F2E01F
+:1052D0001F0761F520911C1030911D1040911E1088
+:1052E00050911F10621773078407950719F41EC0A9
+:1052F000C60129C09501AB01BC0180911A0E9091A5
+:105300001B0E17DC882309F455CFA00EB11E88852B
+:105310009985AA85BB85800F911FA11DB11D888726
+:105320009987AA87BB87E01AF10A68CF40E0DED6EA
+:10533000882309F43FCFB401645E714FA801C50111
+:105340000F945FC6E2CFDF91CF911F910F91FF9035
+:10535000EF90DF90CF90BF90AF909F908F907F9015
+:105360006F905F904F903F902F900895CF93DF9371
+:105370001F92CDB7DEB741E050E0BE016F5F7F4FB7
+:1053800001DF019719F4898190E002C08FEF9FEF50
+:105390000F90DF91CF910895CF92DF92EF92FF921D
+:1053A0000F931F93CF93DF936C01EB017A01FC0104
+:1053B0008381823060F000851185228533850F71ED
+:1053C000112722273327012B022B032B11F08FEFFC
+:1053D0005CC04115510511F0F70110821DE040E25B
+:1053E00050E0BE01C601CEDE8032910539F021E0E9
+:1053F000892B09F420E0822F819547C02881222340
+:10540000C1F0253E61F32E3251F33B853F733F30AF
+:1054100061F4E114F10449F04A8D5B8D452B29F4C8
+:105420002F713FEF320F343030F02B8523FDD7CF73
+:105430002CC080E02AC030E021503109129FC00109
+:10544000139F900D1124F701E80FF91F2981208384
+:105450002B8121832D8122832F81238329852483FE
+:105460002E852583288926832A8927832C892087CE
+:105470002E892187288D22872C8D23872E8D2487A6
+:10548000288126FFD2CF1586D0CFDF91CF911F91F3
+:105490000F91FF90EF90DF90CF9008951F93CF93DF
+:1054A000DF93EC018B81823018F480E090E023C020
+:1054B000488559856A857B85A5E0769567955795DA
+:1054C0004795AA95D1F7142F1F70CE014FDF97FD96
+:1054D000ECCF488559856A857B85415E5F4F6F4F6C
+:1054E0007F4F488759876A877B8720E2129FC001D8
+:1054F0001124845E914FDF91CF911F9108954F92B7
+:105500005F926F927F92AF92BF92CF92DF92EF92B3
+:10551000FF920F931F93CF93DF93EC016A017B01FE
+:105520002B81222349F089899A89AB89BC89841708
+:105530009507A607B70710F480E06BC0223009F486
+:1055400063C0C114D104E104F10449F41C821D823A
+:105550001E821F82188619861A861B8659C0888566
+:105560009985AA85BB85E98DFA8DE585F0E03996A8
+:10557000AC01BD0141505109610971090E2E04C0F1
+:1055800076956795579547950A94D2F797018601C6
+:10559000015011092109310904C036952795179545
+:1055A0000795EA95D2F7041715072607370720F065
+:1055B000892B8A2B8B2B49F48D899E89AF89B88DD5
+:1055C0008C839D83AE83BF8304C0041B150B260B05
+:1055D000370B280139015E0184E0A80EB11C41148B
+:1055E00051046104710481F04C815D816E817F8181
+:1055F0009501898D9A8DB2D591E0491A51086108BB
+:1056000071088111ECCF05C0C886D986EA86FB8671
+:1056100081E0DF91CF911F910F91FF90EF90DF908C
+:10562000CF90BF90AF907F906F905F904F90089514
+:105630000F931F93CF93DF93EC018B818823D1F1DC
+:10564000898187FF32C061E0CE01B7DC8C01009711
+:1056500089F1FC018081853E69F18B81823040F4C3
+:1056600049895A896B897C89448F558F668F778FDA
+:105670004D895E896F89788DF801538F428F758BC4
+:10568000648BE091130EF091140E309759F0B8012D
+:105690006A5E7F4FC80148961995F801808D918DFB
+:1056A000938B828B89818F778983DF91CF911F9133
+:1056B0000F91DCC481E0888380E0DF91CF911F915E
+:1056C0000F910895CF93DF93EC01B2DF1B82DF913E
+:1056D000CF910895FC0123812111F4CF08954F92B9
+:1056E0005F926F927F92AF92BF92CF92DF92EF92D2
+:1056F000FF920F931F93CF93DF9300D01F92CDB7EC
+:10570000DEB75C016A017B01FC0183818130E9F431
+:10571000818181FF1AC0F50181899289A389B489A9
+:1057200084179507A607B70780F0892B8A2B8B2B48
+:1057300009F472C0F5014084518462847384B70116
+:10574000A601C501DCDE811102C080E066C0F50162
+:10575000818D928DC114D104E104F10469F445896D
+:1057600056896789708D77D7882379F3F501158A73
+:10577000168A178A108E37C0F501448155816681DB
+:1057800077819E012F5F3F4FE9D48823F1F2498151
+:105790005A816B817C81F501818D928DFC01278975
+:1057A000203139F4483FFFEF5F0761057105D8F4F8
+:1057B00007C0483F2FEF520762072FE0720798F4A7
+:1057C0004AD7882309F4C1CFF50144815581668108
+:1057D00077810FEF1FEF2FEF3FE0818D928DA3D5E3
+:1057E000882309F4B2CFF501C18AD28AE38AF48A08
+:1057F000818180688183C5011BDF882309F4A5CFDF
+:10580000B701A6014C145D046E047F0410F4B301CB
+:10581000A201C50174DE01C081E00F900F900F90CE
+:105820000F90DF91CF911F910F91FF90EF90DF903C
+:10583000CF90BF90AF907F906F905F904F90089502
+:10584000FF920F931F93CF93DF93EC01F42E80E22E
+:10585000689FF0011124E45EF14F8385817121F08E
+:10586000842F827109F04EC080911C1090911D1000
+:10587000A0911E10B0911F108C879D87AE87BF87A7
+:10588000688B4489558960E070E0BA015527442748
+:10589000028D138D20E030E0402B512B622B732BB7
+:1058A0004D8B5E8B6F8B788F8385887151F4048D5F
+:1058B000158D268D378D098B1A8B2B8B3C8B81E0B8
+:1058C0000BC08031F9F49E012F5E3F4F898D9A8D78
+:1058D000C4D48823B9F084E08B838F2D8F708983A3
+:1058E0001C821D821E821F82188619861A861B86BC
+:1058F000F4FE0BC040E050E0BA01CE01F0DE8111B1
+:1059000004C011C01B8280E00EC0F5FE0BC04989A7
+:105910005A896B897C89CE01DF91CF911F910F91BC
+:10592000FF90EDCD81E0DF91CF911F910F91FF901E
+:105930000895AF92BF92CF92DF92EF92FF920F93B2
+:105940001F93CF93DF937C01EB016A01B22E898D07
+:105950009A8DF701928F818F40E050E0BA01CE011D
+:10596000CEDDA12C088519852A853B8589899A89F0
+:10597000AB89BC89081719072A073B07A0F585E002
+:1059800036952795179507958A95D1F70F70CE0113
+:1059900085DD009709F481C0FC012081222311F0EC
+:1059A000253EB9F4A1100EC040911C1050911D105D
+:1059B00060911E1070911F10F7014487558766870C
+:1059C0007787008BFC018081AA24A3948111CACF20
+:1059D0000AC04BE050E0BC01C6010F9452C6892BAF
+:1059E00009F0C0CF58C08B2D8274823409F055C0A5
+:1059F000AA2049F0F701008961E0C701DEDAEC0175
+:105A0000009769F44AC08B81823009F446C0CE0108
+:105A10004DDA882309F441C0CCE1DEE000E080E209
+:105A2000FE0111928A95E9F78BE0F601DE01019003
+:105A30000D928A95E1F7E091130EF091140E3097D4
+:105A400039F0BE01625F7F4FCE014096199508C0C4
+:105A500081E298E2998B888B80E098E09F878E871F
+:105A6000888999899B8B8A8B998F888F8E859F8552
+:105A70009F8B8E8BFBD2882381F04B2D602FC7012B
+:105A8000DF91CF911F910F91FF90EF90DF90CF901A
+:105A9000BF90AF90D5CEB7FEF0CF80E0DF91CF9131
+:105AA0001F910F91FF90EF90DF90CF90BF90AF903C
+:105AB00008953F924F925F926F927F928F929F9242
+:105AC000AF92BF92CF92DF92EF92FF920F931F930C
+:105AD000CF93DF93CDB7DEB7C354D1090FB6F89497
+:105AE000DEBF0FBECDBF5C016B0124965FAF4EAF32
+:105AF0002497522E1C8E1F8E19821C8261157105EF
+:105B000011F410E073C0FC0183818111FACF249657
+:105B1000EEADFFAD249780818F3211F076011DC06C
+:105B20002496EEADFFAD249780818F3231F431960B
+:105B30002496FFAFEEAF2497F3CFF6018381825016
+:105B4000823060F3F601618D728DCE010196C8DA64
+:105B50008823B9F2CE0101967C018E01045E1F4FAD
+:105B60003801FE0131964F01402E312E19C0882395
+:105B7000A9F121E0AE01495C5F4FB701C801D9DE50
+:105B8000882309F4BECFEC14FD0411F0C7019ADD9F
+:105B90000615170501F1942D832D7801092F182F73
+:105BA000AE014E5B5F4FBE01695C7F4F24968EADA8
+:105BB0009FAD249756DA882309F4A3CF2496EEAD3F
+:105BC000FFAD249780818F3291F631962496FFAFF6
+:105BD000EEAF2497F3CF982D892DDFCF252DAE0181
+:105BE000495C5F4FB701C501A4DE182FCE010196B5
+:105BF00071DDCE014C966EDD812FCD5BDF4F0FB690
+:105C0000F894DEBF0FBECDBFDF91CF911F910F91F2
+:105C1000FF90EF90DF90CF90BF90AF909F908F90CC
+:105C20007F906F905F904F903F900895CF93DF9358
+:105C3000EC0140E050E0BA0152DD882361F061E000
+:105C4000CE01BBD9009739F025EEFC0120831B82E1
+:105C5000DF91CF910BC280E0DF91CF9108951F9328
+:105C6000CF93DF93CDB7DEB76B970FB6F894DEBF57
+:105C70000FBECDBFAB0119821C8222E0BC01CE0158
+:105C8000019617DF182F882321F0CE010196CEDF71
+:105C9000182FCE0101961EDD812F6B960FB6F8945A
+:105CA000DEBF0FBECDBFDF91CF911F9108952F9220
+:105CB0003F924F925F926F927F928F929F92AF929C
+:105CC000BF92CF92DF92EF92FF920F931F93CF93E9
+:105CD000DF9300D01F921F92CDB7DEB78C015B011E
+:105CE0003A01DC0113968C9113978130C1F411961F
+:105CF0008C9181FF14C082FF18C0F801418952893C
+:105D00006389748980859185A285B38584179507F9
+:105D1000A607B70751F0C801F2DB811106C081E088
+:105D2000F80180838FEF9FEF37C1630183C0D801F3
+:105D300059968D919C915A97FC01F481F1501A016A
+:105D40002B0169E056944794379427946A95D1F7CC
+:105D5000F221FD834A0121E09222FF2309F476C05B
+:105D600080E092E08819990976018C159D0508F468
+:105D70007C01D8015996ED91FC915A9714962D907B
+:105D80003D904D905C901797B2E02B1A3108410876
+:105D90005108058404C0220C331C441C551C0A9471
+:105DA000D2F786859785A089B189280E391E4A1EAB
+:105DB0005B1EED812E0E311C411C511CE114F2E0E2
+:105DC000FF0609F089C080911C1090911D10A091D0
+:105DD0001E10B0911F1082159305A405B50569F436
+:105DE0001092190E8FEF9FEFDC0180931C1090939F
+:105DF0001D10A0931E10B0931F109501B201A101B8
+:105E000080911A0E90911B0E0E940EA6882309F411
+:105E100086CFF80180859185A285B3858E0D9F1D63
+:105E2000A11DB11D80879187A287B387AE0CBF1CCF
+:105E3000CE18DF08D80118964D915D916D917C9137
+:105E40001B97C114D10409F072CF7AC08114910458
+:105E500009F086CF14964D915D916D917C911797C5
+:105E6000411551056105710559F455968D919D9126
+:105E70000D90BC91A02D0097A105B10539F520C06A
+:105E80009E012F5F3F4F6AD1882309F448CF898153
+:105E90009A81AB81BC81F801218D328DF90127896E
+:105EA000203139F4883FFFEF9F07A105B10540F489
+:105EB0000DC0883F2FEF9207A2072FE0B20730F006
+:105EC000C8010E9430A781114BCF29CFF8018483EC
+:105ED0009583A683B78344CF8114910411F5D8012B
+:105EE00018964D915D916D917C911B9751968D9176
+:105EF0009D910D90BC91A02D481759076A077B070B
+:105F000080F0B4D0882309F40ACF81E08093190E81
+:105F100020921C1030921D1040921E1050921F10A3
+:105F200007C041E0C201B101E1D0882309F4F7CEF6
+:105F3000A701B501C401845E914F0F945FC669CF7C
+:105F400051968D919D910D90BC91A02DF8012181CC
+:105F500084179507A607B70738F4418B528B638BDC
+:105F6000748B206821830CC08091130E9091140EC5
+:105F7000892B31F06114710419F02068F801218334
+:105F8000D80111968C9183FD02C0C30105C0C801E0
+:105F90004FDB8111FACFC3CE0F900F900F900F906F
+:105FA0000F90DF91CF911F910F91FF90EF90DF90B5
+:105FB000CF90BF90AF909F908F907F906F905F90A9
+:105FC0004F903F902F900895CF93DF931F92CDB7BE
+:105FD000DEB72091F01B3091F11BCE010196211507
+:105FE000310519F0821B930B02C08C5F9B410F900F
+:105FF000DF91CF91089582EA92EAA0E0B0E0809329
+:10600000FC1B9093FD1BA093FE1BB093FF1B0895F8
+:1060100081E04091FC1B5091FD1B6091FE1B709133
+:10602000FF1B423A524A6105710509F080E008956C
+:10603000CF93DF931F92CDB7DEB7698341E050E085
+:10604000BE016F5F7F4F049632DE0F90DF91CF91DC
+:10605000089504962CCEFB0101900020E9F7AF01D2
+:1060600041505109461B570B049621CECF93809186
+:10607000190E8823B9F140911C1050911D106091A8
+:106080001E1070911F102CE13EE080911A0E90912D
+:106090001B0E0E940EA6C82F811102C0C0E023C0B3
+:1060A0004091150E5091160E6091170E7091180EBA
+:1060B000411551056105710591F02CE13EE080919B
+:1060C0001A0E90911B0E0E940EA6882339F310928F
+:1060D000150E1092160E1092170E1092180E1092A6
+:1060E000190E01C0C1E08C2FCF910895CF92DF929D
+:1060F000EF92FF92CF936B017C01C42F80911C1013
+:1061000090911D10A0911E10B0911F108C159D052F
+:10611000AE05BF05C9F0AADF811102C080E018C03A
+:106120002CE13EE0B701A60180911A0E90911B0E62
+:106130000E9499A5882391F3C0921C10D0921D1043
+:10614000E0921E10F0921F1081E0C1118093190E91
+:10615000CF91FF90EF90DF90CF9008958F929F9214
+:10616000AF92BF92CF92DF92EF92FF920F931F9365
+:10617000CF93DF93EC016A017B01890189859A85C0
+:10618000AB85BC850196A11DB11D84179507A60797
+:10619000B70710F480E054C08F89803129F4992723
+:1061A000872F762F652F0BC08032A1F7CB01BA0164
+:1061B00027E096958795779567952A95D1F78B88EF
+:1061C0009C88AD88BE88680D791D8A1D9B1D8090B6
+:1061D0001C1090901D10A0901E10B0901F106815FC
+:1061E00079058A059B0581F48F89803191F4DD243E
+:1061F000EE24FF24F601EE0FFF1FE45EF14F8081D5
+:106200009181A0E0B0E016C040E070DF8111ECCFDA
+:10621000C1CFE894C7F8DD24EE24FF24F601EE0F89
+:10622000FF1FEE0FFF1FE45EF14F80819181A2817D
+:10623000B381BF70F80180839183A283B38381E02F
+:10624000DF91CF911F910F91FF90EF90DF90CF9052
+:10625000BF90AF909F908F9008954F925F926F92F2
+:106260007F92AF92BF92CF92DF92EF92FF920F9305
+:106270001F93CF93DF9300D01F92CDB7DEB78C0171
+:1062800049835A836B837C835901C12CD12C7601BD
+:10629000412C42E0542E612C712C49815A816B8132
+:1062A0007C819E012F5F3F4FC80158DF882341F159
+:1062B000D301C201F801058404C0880F991FAA1FE9
+:1062C000BB1F0A94D2F7C80ED91EEA1EFB1E4981D5
+:1062D0005A816B817C818789803139F481E0483F24
+:1062E0005F4F6105710538F4D8CF81E0483F5F4FBB
+:1062F0006F4F7F4090F2F501C082D182E282F3823B
+:106300000F900F900F900F90DF91CF911F910F91F1
+:10631000FF90EF90DF90CF90BF90AF907F906F9005
+:106320005F904F9008954F925F926F927F928F92FD
+:106330009F92AF92BF92CF92DF92EF92FF920F9314
+:106340001F93CF93DF93EC014A015B0128013901D0
+:10635000423051056105710508F462C049855A85CE
+:106360006B857C854F5F5F4F6F4F7F4F4815590599
+:106370006A057B0508F454C08F89803129F4FF2415
+:10638000EB2CDA2CC92C0CC0803209F049C0750105
+:10639000640177E0F694E794D794C7947A95D1F79F
+:1063A0004B895C896D897E89C40ED51EE61EF71E59
+:1063B00041E0C701B6019ADE882391F19F899031AF
+:1063C00059F49924AA24BB24F401EE0FFF1FE45EC4
+:1063D000F14F5182408210C0E89487F89924AA2492
+:1063E000BB24F401EE0FFF1FEE0FFF1FE45EF14F21
+:1063F00040825182628273829A89923090F04D81FC
+:106400005E816F8178854C0D5D1D6E1D7F1D4093F3
+:10641000150E5093160E6093170E7093180E01C050
+:1064200080E0DF91CF911F910F91FF90EF90DF906F
+:10643000CF90BF90AF909F908F907F906F905F9024
+:106440004F9008952F923F924F925F926F927F925A
+:106450008F929F92AF92BF92CF92DF92EF92FF9274
+:106460000F931F93CF93DF93CDB7DEB72F970FB660
+:10647000F894DEBF0FBECDBF1C014C875D876E87D1
+:106480007F873B872A87DC0119960D911D912D91FD
+:106490003C911C970F5F1F4F2F4F3F4F0D831E8363
+:1064A0002F833887EA85FB8580809180A280B38026
+:1064B00081149104A104B10431F0FFEF8F1A9F0AF7
+:1064C000AF0ABF0A10C0DC018D909D90AD90BC90CA
+:1064D000B1E0B9870C851D852E853F8501301105FA
+:1064E0002105310509F0198675016401412C512CF3
+:1064F0003201F10181859285A385B485481659063C
+:106500006A067B0608F04EC00D811E812F813885FA
+:106510000C151D052E053F0550F4F2E0CF2ED12CB1
+:10652000E12CF12CA2E08A2E912CA12CB12C9E0101
+:106530002F5F3F4FB701A601C10110DE882391F103
+:1065400049815A816B817C81D701C6010196A11DC9
+:10655000B11D452B462B472B19F04C015D010FC097
+:10656000AC01BD01481959096A097B090C851D85D3
+:106570002E853F85401751076207730741F01FEFD3
+:10658000411A510A610A710A6C017D01B2CF0FEF05
+:106590001FEF2FEF3FE0B701A601C101C4DE8D83DD
+:1065A000811113C01D823DC02601370121E0421A2E
+:1065B00051086108710897018601B301A201C10168
+:1065C000B2DE882379F3730162018C149D04AE045A
+:1065D000BF0450F3AA85BB854D915D916D917C916F
+:1065E0004115510561057105A9F4EA85FB85808295
+:1065F0009182A282B382F985FF2399F00FEF801A6E
+:10660000900AA00AB00AD1018D929D92AD92BC92DF
+:10661000139707C095018401C10185DE8111E5CF83
+:10662000C1CF8D812F960FB6F894DEBF0FBECDBFC0
+:10663000DF91CF911F910F91FF90EF90DF90CF905E
+:10664000BF90AF909F908F907F906F905F904F9092
+:106650003F902F900895AF92BF92CF92DF92EF922A
+:10666000FF920F931F93CF93DF9300D01F92CDB76C
+:10667000DEB75C016A017B0182E090E0A0E0B0E05F
+:10668000F50180839183A283B3839E012F5F3F4FE7
+:10669000B701A601C50162DD811102C080E023C0FF
+:1066A00000E010E09801B701A601C5013CDE882397
+:1066B000A9F3C980DA80EB80FC80F50187898031FD
+:1066C00049F481E0F8EFCF16FFEFDF06E104F104B3
+:1066D00050F4DBCF81E098EFC9169FEFD906E906A9
+:1066E0009FE0F90690F20F900F900F900F90DF91BE
+:1066F000CF911F910F91FF90EF90DF90CF90BF90BF
+:10670000AF9008957F928F929F92AF92BF92CF9257
+:10671000DF92EF92FF920F931F93CF93DF93EC01E1
+:10672000142F70931B0E60931A0E1F8A82E090E064
+:10673000A0E0B0E088839983AA83BB831092190EEE
+:106740001092150E1092160E1092170E1092180E2F
+:106750008FEF9FEFDC0180931C1090931D10A0938E
+:106760001E10B0931F10442349F1453008F0DEC0DD
+:1067700040E060E070E0CB01B9DC882309F4D6C0CA
+:1067800020E1129FF0011124E653F04F80818F77B2
+:1067900009F0CCC084859585A685B785843691059A
+:1067A000A105B10508F4C2C0C084D184E284F38499
+:1067B000C114D104E104F10421F4B8C0C12CD12CDE
+:1067C000760140E0C701B60191DC782E882309F4F8
+:1067D000ADC08091270E9091280E8115924009F04E
+:1067E000A5C030912C0E332309F4A0C080912A0E4D
+:1067F00090912B0E892B09F499C02091290E222308
+:1068000009F494C03A8B2C831D8630E041E050E0BF
+:106810006D85062FCA01062E02C0880F991F0A94A3
+:10682000E2F72817390731F081E0860F8D8768304D
+:1068300078F37CC02091320E3091330E2115310552
+:1068400019F040E050E008C02091400E3091410E18
+:106850004091420E5091430E2D833E834F835887C3
+:1068600080912A0E90912B0E46015701880E991E99
+:10687000A11CB11C8B8A9C8AAD8ABE8AE0912D0E28
+:10688000F0912E0EF98FE88FA0912C0EB0E00F94AE
+:10689000F6C2680D791D8A1D9B1D6A8F7B8F8C8FB8
+:1068A0009D8FB5E0EE0FFF1FBA95E1F7E150FE4F67
+:1068B000EF2FFF27E695DC01CB018E0F9F1FA11D57
+:1068C000B11D8E879F87A88BB98B80902F0E9090DB
+:1068D000300E8114910419F0A12CB12C08C08090C5
+:1068E0003C0E90903D0EA0903E0EB0903F0EA70142
+:1068F0009601281B390B4A0B5B0BDA01C901880D85
+:10690000991DAA1DBB1D04C0B695A795979587959F
+:106910000A95D2F789879A87AB87BC87853F3FE086
+:106920009307A105B10520F48CE08F8B712C15C065
+:10693000853F9F4FA105B10510F480E10DC0809106
+:10694000480E9091490EA0914A0EB0914B0E8A8F3D
+:106950009B8FAC8FBD8F80E28F8B872DDF91CF9186
+:106960001F910F91FF90EF90DF90CF90BF90AF906D
+:106970009F908F907F900895FC011482178213825C
+:10698000128281E895E0918380830895CF92DF920F
+:10699000EF92FF920F931F93CF93DF93EC01875BEE
+:1069A0009F4FEADFCE0186599F4FE6DF7E0129E83F
+:1069B000E20EF11C87016E0131E4C31A3EEFD30AE7
+:1069C000C801DADF015E1F4F0C151D05C9F7FE0176
+:1069D000EF53FE4F89E18183148215823696178A20
+:1069E000CE018B519E4FC8DFFE01EA56FD4F10824B
+:1069F00011821282138238961082118212821382BF
+:106A00001A821B82188219826E0186E6C81A8DEFDF
+:106A1000D80AF6011082118212821382F8011182C3
+:106A20001082FE01EC5FFD4F108286E391E0F701DA
+:106A30009C01119221503040E1F7FE01EE55FD4FCF
+:106A400081E08083C95BDF4F198218820F94EFB415
+:106A500068577C4E8F4F9F4FF6016083718382830E
+:106A60009383DF91CF911F910F91FF90EF90DF9073
+:106A7000CF900895FC0120E03EE2DB014C914032D2
+:106A800041F0283011F430833196DB014C91408382
+:106A900031962F5F6F5F7F4F2B3079F7108208950B
+:106AA0002F923F924F925F926F927F928F929F921E
+:106AB000AF92BF92CF92DF92EF92FF920F931F930C
+:106AC000CF93DF93CDB7DEB7CA58D1090FB6F8948C
+:106AD000DEBF0FBECDBF8C016B017A014901CA57E1
+:106AE000DF4F1882C658D04084E0E80EF11C180130
+:106AF00091E1290E311CF801EA5BFF4FC957DF4FC6
+:106B0000F983E883C758D0403801FDE56F1AFDEFDF
+:106B10007F0A58018BE5A81A8DEFB80A80E4482E49
+:106B2000512C4C0E5D1E94E0490E511CA101BE017A
+:106B30006F5F7F4FC7010E94CCA918160CF03CC1B3
+:106B40002C85322F3871303109F09DC0F3018081DE
+:106B500091810197029708F496C0BE016F5F7F4F45
+:106B6000CE0187589F4F86DFA0961FAEA097F601F3
+:106B70008081811107C065E875E0CE01815A9F4F81
+:106B80000F9482C6B601CE01815A9F4F0F9482C6E0
+:106B9000BE0167587F4FCE01815A9F4F0F9482C626
+:106BA00065E875E0CE01815A9F4F0F9482C6CE01F1
+:106BB000805C9F4FE1DE21E0AE0147585F4FB70197
+:106BC000C2010E9459AD811136C0F30180819181CB
+:106BD000892B89F5EFE3F0E18491882341F09091CE
+:106BE000C00095FFFCCF8093C6003196F5CFE8E753
+:106BF000F1E485919491FC012491222341F030919C
+:106C0000C00035FFFCCF2093C6000196F4CFFE01F3
+:106C1000E758FF4F8191882339F09091C00095FF8C
+:106C2000FCCF8093C600F6CF8091C00085FFFCCFDB
+:106C30008AE08093C6008BE1FE01EC5BFF4FDE0132
+:106C4000959601900D928A95E1F724968EAD9FADB1
+:106C500024979CA38BA381E895E09AA389A320E0C5
+:106C600030E0AE014F5D5F4FBE01615A7F4FC801FA
+:106C700017DFCE0181960E9437A3CE01805C9F4F23
+:106C80000E9437A353CF8981882309F495C08E329F
+:106C900009F44CCF8F3509F449CFF80181898E3240
+:106CA00009F444CF8F3509F441CF2E7009F03ECF5F
+:106CB00081E0303109F080E0C957DF4FE881F98188
+:106CC000C758D0408083811108C08985873409F076
+:106CD0002DCF8A858E3709F429CF98012C5F3F4F3D
+:106CE000BE016F5F7F4FC901C757DF4F2883C95867
+:106CF000D040C657DF4F3883CA58D040BBDEF301BF
+:106D000080819181C757DF4F2881C958D040C6572D
+:106D1000DF4F3881CA58D0400097F1F4F6018191D5
+:106D2000882339F09091C00095FFFCCF8093C60076
+:106D3000F6CFF9018191882339F09091C00095FF39
+:106D4000FCCF8093C600F6CF8091C00085FFFCCFBA
+:106D50008AE08093C600EACE8130910539F4F501CE
+:106D600080819181019691838083E0CE029709F022
+:106D7000DDCE8114910439F0B901C4010F946FC6BE
+:106D8000892B71F419C0CA57DF4FF881C658D0401B
+:106D90002F2F30E0F501808191812817390761F0AC
+:106DA000CA57DF4FF881C658D040FF5FCA57DF4F40
+:106DB000F883C658D040BACEC657DF4F0FB6F89406
+:106DC000DEBF0FBECDBFDF91CF911F910F91FF901E
+:106DD000EF90DF90CF90BF90AF909F908F907F907B
+:106DE0006F905F904F903F902F9008950F931F9357
+:106DF000CF93DF93CDB7DEB76F970FB6F894DEBFB2
+:106E00000FBECDBF8C01FC01ED55FD4F11821082EC
+:106E100040E050E0BA01835B9F4F0E947FAAC80107
+:106E2000875B9F4F2BE1FC013496DE0115960190A4
+:106E30000D922A95E1F7FC01828193819C838B83DB
+:106E400081E895E09A83898320E030E0AE014F5FCE
+:106E50005F4F6EEF78E0C80123DECE0101960E94FD
+:106E600037A36F960FB6F894DEBF0FBECDBFDF918C
+:106E7000CF911F910F9108952BE1FB013496DC0116
+:106E8000149601900D922A95E1F7FB01228133813E
+:106E9000FC01338322830895EF92FF920F931F9397
+:106EA000CF93DF93EC011B82FC01E05BFF4F8081FD
+:106EB000882329F0CE01835B9F4F0E9462AB7E0145
+:106EC0008FE3E81A8EEFF80A4DE460E0C7010E94F4
+:106ED000E6A4811122C0EFE3F0E18491882341F020
+:106EE0009091C00095FFFCCF8093C6003196F5CFFE
+:106EF000EEE6F1E485919491FC012491222341F086
+:106F00003091C00035FFFCCF2093C6000196F4CF2E
+:106F10008091C00085FFFCCF7EC08E0109531E4FBB
+:106F200041E0B701C801EEDB811128C040E0B701A4
+:106F3000C801E8DB811122C0E5E4F0E184918823F7
+:106F400041F09091C00095FFFCCF8093C600319630
+:106F5000F5CFECE5F1E485919491FC012491222395
+:106F600041F03091C00035FFFCCF2093C600019660
+:106F7000F4CF8091C00085FFFCCF4DC0B801CE0199
+:106F8000835B9F4F0E9470A8811122C0E5E4F0E16D
+:106F90008491882341F09091C00095FFFCCF8093AD
+:106FA000C6003196F5CFE8E6F1E485919491FC01B5
+:106FB0002491222341F03091C00035FFFCCF209373
+:106FC000C6000196F4CF8091C00085FFFCCF23C09E
+:106FD00081E08B83EFE3F0E18491882341F090918D
+:106FE000C00095FFFCCF8093C6003196F5CFE6E751
+:106FF000F1E485919491FC012491222341F0309198
+:10700000C00035FFFCCF2093C6000196F4CF8091DD
+:10701000C00085FFFCCF8AE08093C6008E01075B2D
+:107020001F4FB801CE0186599F4F26DFC859DF4F49
+:1070300019830883DF91CF911F910F91FF90EF90FB
+:107040000895FC01128213820895FC0123812223FA
+:1070500011F021E022830895FC0122812111128286
+:10706000089581549E4FFC01808191810895AF92D3
+:10707000BF92CF92DF92EF92FF920F931F93CF9325
+:10708000DF931F92CDB7DEB78C018FE2FB018193B6
+:107090005F01D12C41E07801F1E4EF1AFEEFFF0A25
+:1070A0009FE1C92E2D2D30E0F701808191812817B5
+:1070B0003907D8F4C29EC001C39E900D1124835796
+:1070C0009F4FB501800F911F49830E9417A8C501EA
+:1070D00049815C010196F5012081222321F04D3880
+:1070E00010F44F5FF6CFD394DDCF47FD11C0B5014B
+:1070F000C80187519E4F0F90DF91CF911F910F9143
+:10710000FF90EF90DF90CF90BF90AF900C9417A8B6
+:10711000F50110820F90DF91CF911F910F91FF9099
+:10712000EF90DF90CF90BF90AF9008953F924F9235
+:107130005F926F927F928F929F92AF92BF92CF9207
+:10714000DF92EF92FF920F931F93CF93DF93CDB710
+:10715000DEB7AC970FB6F894DEBF0FBECDBF7C0193
+:107160005B01FC018381882309F409C1C7018751B0
+:107170009E4F0E9462ABF7011282CE0101966C0114
+:10718000FBDB270198E6490E511CC701875B9F4F27
+:10719000F20191838083F50180818F3209F084C0F0
+:1071A0006FE270E0C5010F948DC68C010F5F1F4F19
+:1071B0002AE0322E0115110509F47CC06FE270E05F
+:1071C000C8010F948DC64C01009709F474C00817CC
+:1071D000190708F070C03C01601A710AA301B801D8
+:1071E000CE0180960F94B6C6E0E2F0E0EC0FFD1FF2
+:1071F000E60DF71D1082FE01B0968191882339F0CB
+:107200009091C00095FFFCCF8093C600F6CF80918F
+:10721000C00085FFFCCF3092C600F2016081718111
+:107220006115710519F06C5F7F4F02C060E070E07E
+:1072300021E0AE01405E5F4FCE0105960E9459AD40
+:1072400081112BC0E7E8F5E08491882341F090910B
+:10725000C00095FFFCCF8093C6003196F5CFFE01AC
+:10726000B0968191882339F09091C00095FFFCCFB2
+:107270008093C600F6CFEAEAF2E18491882341F0D8
+:107280009091C00095FFFCCF8093C6003196F5CF5A
+:107290008091C00085FFFCCF6CC0F201D182C0821A
+:1072A00084010F5F1F4F86CFC70186599F4FF201A0
+:1072B000918380838501F20180819181009711F093
+:1072C000049602C080E090E0B8010E942FAE8823AF
+:1072D00039F1ECE9F2E18491882341F09091C0000A
+:1072E00095FFFCCF8093C6003196F5CFF8018191D0
+:1072F000882339F09091C00095FFFCCF8093C600A1
+:10730000F6CF8091C00085FFFCCF8AE08093C60055
+:10731000F701E256FD4F10821182128213822CC0B7
+:10732000E4E8F2E18491882341F09091C00095FF58
+:10733000FCCF8093C6003196F5CFF8018191882368
+:1073400039F09091C00095FFFCCF8093C600F6CF36
+:10735000E2E8F2E18491882341F09091C00095FF2A
+:10736000FCCF8093C6003196F5CF8091C00085FF99
+:10737000FCCF8AE08093C600C6010E9437A3AC967A
+:107380000FB6F894DEBF0FBECDBFDF91CF911F9136
+:107390000F91FF90EF90DF90CF90BF90AF909F90B4
+:1073A0008F907F906F905F904F903F9008958F9255
+:1073B0009F92AF92BF92CF92DF92EF92FF92CF93C4
+:1073C000DF931F92CDB7DEB77C01FC018281882359
+:1073D00009F4B2C071968191882339F09091C00070
+:1073E00095FFFCCF8093C600F6CFE0E8F2E18491F0
+:1073F000882341F09091C00095FFFCCF8093C60098
+:107400003196F5CFE4E6F1E485919491FC01249165
+:10741000222341F03091C00035FFFCCF2093C600FD
+:107420000196F4CFF701E256FD4F40815181628110
+:1074300073812AE030E08EE799E00E947C42EEE71B
+:10744000F2E18491882341F09091C00095FFFCCF38
+:107450008093C6003196F5CFF701EA56FD4F408183
+:107460005181628173812AE030E08EE799E00E94C9
+:107470007C428091C00085FFFCCF8AE08093C600EB
+:107480000F94EFB430E6C32E3AEED32EE12CF12C5C
+:10749000A70196010F949DC249015A0160918A0A81
+:1074A00070918B0A80918C0A90918D0AA7019601A8
+:1074B0000F949DC2821A930AC4016CE370E00F948A
+:1074C00076C26983CE0101960F949254FC012191FA
+:1074D000CF01222339F03091C00035FFFCCF20933B
+:1074E000C600F4CF40E050E06AE38EE799E00E94E6
+:1074F0001942C4016CE370E00F9476C28983CE0117
+:1075000001960F949254FC012191CF01222339F06E
+:107510003091C00035FFFCCF2093C600F4CFECE7DC
+:10752000F2E184918823E1F09091C00095FFFCCFB7
+:107530008093C6003196F5CFEBE9F5E0849188237E
+:1075400041F09091C00095FFFCCF8093C60031962A
+:10755000F5CF8091C00085FFFCCF8AE08093C60004
+:107560000F90DF91CF91FF90EF90DF90CF90BF9081
+:10757000AF909F908F900895AF92BF92CF92DF927D
+:10758000EF92FF920F931F93CF93DF935C01EB0178
+:10759000FB0101900020E9F78F0101501109061B42
+:1075A000170B6C01F7E1CF1AFEEFDF0AF60110822C
+:1075B0006EE470E0CE010F948DC67C01009729F433
+:1075C000F8013197EC0FFD1F0DC060E270E00F94E1
+:1075D0008DC6EC0121966AE270E0C7010F948DC65A
+:1075E000FC0131978DE081838AE082831382BE01A2
+:1075F000C5018B519E4F0E942BB0F60180818823DC
+:1076000021F1E5E4F0E18491882341F09091C000FC
+:1076100095FFFCCF8093C6003196F5CFE4E7F1E407
+:1076200085919491FC012491222341F03091C00076
+:1076300035FFFCCF2093C6000196F4CF8091C000A7
+:1076400085FFFCCF8AE08093C600DF91CF911F9128
+:107650000F91FF90EF90DF90CF90BF90AF90089583
+:10766000CF93DF93EC0140E450E08B519E4F0E949A
+:1076700029B0C751DE4F8881882361F1E5E4F0E14C
+:107680008491882341F09091C00095FFFCCF8093B6
+:10769000C6003196F5CFE4E7F1E485919491FC01C1
+:1076A0002491222341F03091C00035FFFCCF20937C
+:1076B000C6000196F4CF8091C00085FFFCCF8AE020
+:1076C0008093C60068EA75E08EE799E0DF91CF917C
+:1076D0000C943542DF91CF9108952F923F924F92B3
+:1076E0005F926F927F928F929F92AF92BF92CF9252
+:1076F000DF92EF92FF920F931F93CF93DF93CDB75B
+:10770000DEB7CC55D1090FB6F894DEBF0FBECDBFA2
+:107710004C018C010E551D4F662339F0F801108283
+:10772000F401838181111DC015C0F8018081882377
+:1077300009F4AFC0F401E656FD4FC080D180E2806D
+:10774000F3800F94EFB4C616D706E806F90608F4DE
+:10775000A0C0E4CFC401A0DBF4018381882309F435
+:1077600098C07401F7E4EF0EF11CF70181818F934B
+:1077700080818F9383E792E19F938F938E01015CC9
+:107780001F4F1F930F930F9418C80F900F900F90D7
+:107790000F900F900F90B12CF80101900020E9F7A5
+:1077A0003197E01BF10BBE1684F46801CB0CD11CA1
+:1077B000B7FCDA94F6018081992787FD90950F94A4
+:1077C000D7C5F6018083B394E7CFFDE48F0E911CFB
+:1077D00040E050E0BA01C4010E947FAA512CCE01C2
+:1077E00001966C014CE6642E42E1742E5E0191E23A
+:1077F000A90EB11C40E050E0B601C4010E94CCA922
+:107800001816DCF5412CF60101900020E9F73197BC
+:10781000EC19FD094E1674F41601240C311C47FCBA
+:107820003A94F101808190E00F94D7C5F1018083F3
+:107830004394E9CF8A858E37E9F245E050E0B801FC
+:10784000C6010F94A8C6892BA9F61F930F937F92A8
+:107850006F92BF92AF920F9418C860E0C501E1D655
+:1078600061E088E692E1DDD60F900F900F900F90C7
+:107870000F900F9055245394BDCF511004C08FEF3B
+:107880009FEFF70104C0F7018081918101969183F8
+:107890008083C45ADF4F0FB6F894DEBF0FBECDBF52
+:1078A000DF91CF911F910F91FF90EF90DF90CF90DC
+:1078B000BF90AF909F908F907F906F905F904F9010
+:1078C0003F902F9008950F931F93CF93DF93EC0178
+:1078D0008C0107511E4FC8010E9418ABC8010E94BD
+:1078E00062AB18821982DF91CF911F910F91089599
+:1078F000CF92DF92EF92FF920F931F93CF93DF937C
+:10790000CDB7DEB76F970FB6F894DEBF0FBECDBF11
+:107910008C016A017C0188E6E80EF11CC8018659D9
+:107920009F4FF70191838083E55CFD4F22E030E0BB
+:107930003183208332967183608340E050E0BA0146
+:1079400004960E947FAAF701808191812BE1FC01BE
+:107950003496DE01159601900D922A95E1F7FC010F
+:10796000828193819C838B8381E895E09A838983CC
+:107970009601AE014F5F5F4F6EEF78E0C80190D87F
+:10798000CE0101960E9437A36F960FB6F894DEBF22
+:107990000FBECDBFDF91CF911F910F91FF90EF9060
+:1079A000DF90CF9008952F923F924F925F926F9207
+:1079B0007F928F929F92AF92BF92CF92DF92EF927F
+:1079C000FF920F931F93CF93DF93CDB7DEB7AC97A2
+:1079D0000FB6F894DEBF0FBECDBF8C016B01342E05
+:1079E000FC018381882309F403C3E451FE4F8081A5
+:1079F000882309F4FBC02111C7C07801FCEFEF1AFE
+:107A0000FDEFFF0AF7018081882379F1E5E4F0E1D9
+:107A10008491882341F09091C00095FFFCCF809322
+:107A2000C6003196F5CFEEEFF2E18491882341F064
+:107A30009091C00095FFFCCF8093C6003196F5CFA2
+:107A40004AE050E061E070E08EE799E00E94424237
+:107A50008091C00085FFFCCF8AE08093C60061E082
+:107A60008EEF98E00E94475CC3C2EFE3F0E184919F
+:107A7000882341F09091C00095FFFCCF8093C60011
+:107A80003196F5CFE5EEF2E18491882341F09091B3
+:107A9000C00095FFFCCF8093C6003196F5CFF6016C
+:107AA0008191882339F09091C00095FFFCCF80939D
+:107AB000C600F6CFEAEDF2E18491882341F090917F
+:107AC000C00095FFFCCF8093C6003196F5CFF7013B
+:107AD00080816DE8B62EB801B89E600D711D11242D
+:107AE000675F7D4FC801C3DAF7018081F801B89E56
+:107AF000E00DF11D1124E75FFD4F8191882339F0DE
+:107B00009091C00095FFFCCF8093C600F6CFE4EDC6
+:107B1000F2E18491882341F09091C00095FFFCCF61
+:107B20008093C6003196F5CF5801F2E6AF1AFDEF0B
+:107B3000BF0AF50140815181628173812AE030E002
+:107B40008EE799E00E947C428091C00085FFFCCFC7
+:107B50008AE08093C600F7012081F80184E0289F25
+:107B6000E00DF11D1124AF014B5F5D4FF5018081E8
+:107B70009181A281B381FA0180839183A283B3832F
+:107B80002F5FF70120832CC0EFE3F0E1849188237D
+:107B900041F09091C00095FFFCCF8093C6003196D4
+:107BA000F5CFE3ECF2E18491882341F09091C0009D
+:107BB00095FFFCCF8093C6003196F5CFF6018191F9
+:107BC000882339F09091C00095FFFCCF8093C600C8
+:107BD000F6CF8091C00085FFFCCF8AE08093C6007D
+:107BE000C80187519E4F0E9462AB30C0F801EC5F24
+:107BF000FD4F1082EFE3F0E18491882341F09091F2
+:107C0000C00095FFFCCF8093C6003196F5CFE2EB24
+:107C1000F2E18491882341F09091C00095FFFCCF60
+:107C20008093C6003196F5CFF6018191882339F013
+:107C30009091C00095FFFCCF8093C600F6CF809155
+:107C4000C00085FFFCCF8AE08093C600F801128255
+:107C5000CE0101965C010E94BCB4280198E6490E51
+:107C6000511CC801875B9F4FF20191838083F6010D
+:107C700080818F3209F087C06FE270E0C6010F94F7
+:107C80008DC601967C015AE0252EE114F10409F419
+:107C900080C06FE270E0C7010F948DC64C01009761
+:107CA00009F478C0E816F90608F074C03C016E18B3
+:107CB0007F08A301B701CE0180960F94B6C6E0E21B
+:107CC000F0E0EC0FFD1FE60DF71D1082FE01B096EF
+:107CD0008191882339F09091C00095FFFCCF80936B
+:107CE000C600F6CF8091C00085FFFCCF2092C60071
+:107CF000F201608171816115710519F06C5F7F4F30
+:107D000002C060E070E021E0AE01405E5F4FCE0156
+:107D100005960E9459AD81112EC0E6E6F1E48591E9
+:107D20009491FC012491222341F03091C00035FF51
+:107D3000FCCF2093C6000196F4CFFE01B09681914E
+:107D4000882339F09091C00095FFFCCF8093C60046
+:107D5000F6CFE0EBF2E18491882341F09091C000EE
+:107D600095FFFCCF8093C6003196F5CF8091C0007F
+:107D700085FFFCCF0EC1F201B182A0827401FFEF3A
+:107D8000EF1AFF0A82CFC80186599F4FF2019183F3
+:107D900080837601C80187519E4F4C01F2016081BA
+:107DA0007181332009F4BAC06115710519F06C5F57
+:107DB0007F4F02C060E070E021E0A701C4010E9493
+:107DC00059AD882309F47DC0F40181899289A38982
+:107DD000B489F801EA56FD4F80839183A283B3836F
+:107DE000E2E7F1E485919491FC012491D801AA562F
+:107DF000BD4F222351F03091C00035FFFCCF2093BE
+:107E0000C6000196FC012491F4CFF70181918823EB
+:107E100039F09091C00095FFFCCF8093C600F6CF5B
+:107E2000EEE5F1E485919491FC012491222341F047
+:107E30003091C00035FFFCCF2093C6000196F4CFEF
+:107E40004D915D916D917C912AE030E08EE799E053
+:107E50000E947C428091C00085FFFCCF8AE0809325
+:107E6000C600F801E256FD4F108211821282138281
+:107E7000E0E7F1E485919491FC012491222341F003
+:107E80003091C00035FFFCCF2093C6000196F4CF9F
+:107E90008091C00085FFFCCF8AE08093C600A701D7
+:107EA00060E070E0C80124DDF8018189882319F0C1
+:107EB000C801419601C0C7010F9471518FEC95E044
+:107EC00092C0E6E6F1E485919491FC01249122238D
+:107ED00041F03091C00035FFFCCF2093C6000196E1
+:107EE000F4CFF7018191882339F09091C00095FF7C
+:107EF000FCCF8093C600F6CFEEEAF2E184918823AE
+:107F000041F09091C00095FFFCCF8093C600319660
+:107F1000F5CF8091C00085FFFCCF3BC06115710596
+:107F200019F06C5F7F4F02C060E070E026E5A701AA
+:107F3000C4010E9459AD811130C0E6E6F1E485919B
+:107F40009491FC012491222341F03091C00035FF2F
+:107F5000FCCF2093C6000196F4CFF70181918823CE
+:107F600039F09091C00095FFFCCF8093C600F6CF0A
+:107F7000ECEAF2E18491882341F09091C00095FFF2
+:107F8000FCCF8093C6003196F5CF8091C00085FF6D
+:107F9000FCCF8AE08093C60028C081E0F80180838E
+:107FA000EAE5F1E485919491FC012491222341F0CA
+:107FB0003091C00035FFFCCF2093C6000196F4CF6E
+:107FC000F6018191882339F09091C00095FFFCCF94
+:107FD0008093C600F6CF8091C00085FFFCCF8AE079
+:107FE0008093C600C7010F947151C5010E9437A349
+:107FF000AC960FB6F894DEBF0FBECDBFDF91CF9128
+:108000001F910F91FF90EF90DF90CF90BF90AF90B6
+:108010009F908F907F906F905F904F903F902F90A8
+:10802000089521E0FC01218340E0BDCCCF92DF9296
+:10803000EF92FF920F931F93CF93DF93CDB7DEB7ED
+:108040006F970FB6F894DEBF0FBECDBF8C016C01E9
+:1080500028E6C20ED11C86599F4FF601918380837A
+:10806000E55CFD4F21E030E0318320837801FBE5C2
+:10807000EF1AFDEFFF0AF7011182108240E050E095
+:10808000BA0104960E947FAAF601808191812BE1BA
+:10809000FC013496DE01159601900D922A95E1F7C8
+:1080A000FC01828193819C838B8381E895E09A8394
+:1080B000898320E030E0AE014F5F5F4F6EEF78E0E4
+:1080C000C8010E9450B5CE0101960E9437A3F70166
+:1080D000808191816F960FB6F894DEBF0FBECDBF41
+:1080E000DF91CF911F910F91FF90EF90DF90CF9094
+:1080F0000895AF92BF92CF92DF92EF92FF920F93CB
+:108100001F93CF93DF93CDB7DEB76F970FB6F89479
+:10811000DEBF0FBECDBF8C017B01CE0101960E9458
+:10812000BCB4F801EF58FF4F80816801811104C091
+:1081300029E4C20ED11C03C08AE6C80ED11C21E07E
+:10814000A701B6016C5F7F4FCE0105960E9459AD25
+:10815000811130C0EFE3F0E18491882341F09091E8
+:10816000C00095FFFCCF8093C6003196F5CFE8E7BD
+:10817000F1E485919491FC012491222341F0309106
+:10818000C00035FFFCCF2093C6000196F4CFF70165
+:108190008191882339F09091C00095FFFCCF8093A6
+:1081A000C600F6CF8091C00085FFFCCF8AE08093A7
+:1081B000C60036C0F801E154FE4F808191818A30BB
+:1081C000910530F59C012F5F3F4F318320832FE1D4
+:1081D000289F7001299FF00C1124F9E8EF0EF11C83
+:1081E000E00EF11E5C01B701C7014F960E943CB73B
+:1081F00021E0A21AB1088FE1E81AF108EFEFAE16FC
+:10820000BE0689F7B601C80187579F4F0E943CB749
+:10821000BE016F5F7F4FC80186599F4F0E943CB7D8
+:10822000CE0101960E9437A36F960FB6F894DEBF79
+:108230000FBECDBFDF91CF911F910F91FF90EF90B7
+:10824000DF90CF90BF90AF900895EF92FF920F9381
+:108250001F93CF93DF93EC01C154DE4F2881398106
+:1082600021153105F9F021503109398328838C011A
+:1082700007571F4FB80186599F4F0E943CB7C8014E
+:1082800000E010E07C012FE1E20EF11C2881398131
+:108290000217130738F40F5F1F4FB7010E943CB756
+:1082A000C701F0CFDF91CF911F910F91FF90EF9019
+:1082B0000895EF92FF920F931F93CF93DF93EC01FA
+:1082C0000F94071F8E010C5F1D4FF80180819E01E6
+:1082D00027513E4F79018823A1F1C9010E9462AB69
+:1082E000F801808181508083BE01FDE88F9F600D81
+:1082F000711D1124675F7D4F21E041E0CE0153DB0A
+:10830000F8018081FE0124E0829FE00DF11D11241F
+:10831000EB5FFD4F4081518162817381FE01E25626
+:10832000FD4F4083518362837383C7010E947FAAFC
+:10833000CE01DF91CF911F910F91FF90EF900C94A0
+:1083400025B80F94921FC7010E9462AB1A8261E0A8
+:108350008CE592E1DF91CF911F910F91FF90EF900B
+:1083600060C1CF92DF92EF92FF920F931F93FB01B8
+:1083700010821182128213826B0174E0E72EF12CBD
+:1083800000E515E020E030E041E061E08F539E4FD2
+:108390000E94ADA691E0811101C090E0892F1F914C
+:1083A0000F91FF90EF90DF90CF900895CF93C62F5D
+:1083B0002091431030914410E0914110F09142100F
+:1083C0002E173F0741F440913F1050914010141672
+:1083D00015060CF44DC060913C1070913D10AF013A
+:1083E000480F591F161617067CF4E217F3077CF0A6
+:1083F000BA0163597F4F6E3E7140C0F14C5F5F4FD1
+:108400004E3E5140C8F415C0E217F3073CF44459FE
+:108410005F4F81E04217530764F12AC0DA01A35984
+:10842000BF4FAE3EB14010F14C5F5F4F4E3E5140EA
+:1084300018F429363105D4F484599F4F82179307D5
+:10844000BCF44DEE51E04E1B5F0B60E070E0CF01DD
+:108450008B5B9F4E0F9468C6CC2309F0F894109262
+:10846000421010924110CC2309F0789481E001C0B1
+:1084700080E0CF91089580913F10909140101816A0
+:1084800019060CF056C001979093401080933F104E
+:10849000892B99F480913C1090913D10892B21F407
+:1084A0001092421010924110809141109091421010
+:1084B00090934410809343103AC020914310309120
+:1084C00044102D5F3F4F2F5F3F4FF901EC5BFF4E94
+:1084D00040814111F8CFC901382F292F8D3E41E04D
+:1084E000940740F090934410809343108D3E914048
+:1084F000F1F40EC00196FC01EC5BFF4E4081442379
+:1085000059F33093431020934410832F922FEECFD2
+:1085100080E090E0382F292F0196FC01EC5BFF4EA4
+:1085200040814423B9F3309343102093441081E0F9
+:10853000089580E008951092441010924310109214
+:108540004210109241101092401010923F10109261
+:108550003E1008950F931F93CF93DF93EC01803665
+:10856000910514F080E052C080913E10811104C04A
+:1085700082DF81E080933E1040914310509144107F
+:1085800080914110909142104817590739F4209179
+:108590003F10309140101216130624F320913C1026
+:1085A00030913D101216130624F49C012F593F4FB1
+:1085B00001C09C018417950744F44C1B5D0B44508B
+:1085C00051094217530774F209C0CE01039684176C
+:1085D00095074CF44C1B5D0B4450510950934410CB
+:1085E0004093431012C009EE11E00C1B1D0B021743
+:1085F00013070CF4B7CF60E070E085E490E10F94CE
+:1086000068C6109344100093431081E0DF91CF912E
+:108610001F910F910895803691050CF4C7CE80E02C
+:108620000895FF920F931F93CF93DF93EC01F62EE3
+:10863000662321F00F94FAC58C0109C0FC0101905A
+:108640000020E9F78F0101501109081B190B60E0A8
+:10865000C801E1DF882309F474C080914110909132
+:108660004210FC01EB5BFF4E23E020830396BE012A
+:108670008B5B9F4EFF2019F00F94F3C502C00F943F
+:10868000A1C6EFE3F0E18491882341F09091C0000E
+:1086900095FFFCCF8093C6003196F5CFE8ECF2E46D
+:1086A00085919491FC012491222341F03091C000E6
+:1086B00035FFFCCF2093C6000196F4CFE091411026
+:1086C000F0914210E85BFF4E8191882339F0909140
+:1086D000C00095FFFCCF8093C600F6CFE4EDF3E138
+:1086E0008491882341F09091C00095FFFCCF809346
+:1086F000C6003196F5CF8091C00085FFFCCF8AE09F
+:108700008093C6000C5F1F4F8091411090914210E2
+:10871000080F191F0D3EF1E01F0729F010934210BA
+:108720000093411004C010924210109241108091A9
+:108730003F109091401001969093401080933F100D
+:1087400048C0E5E4F0E18491882341F09091C000B5
+:1087500095FFFCCF8093C6003196F5CFE8ECF2E4AC
+:1087600085919491FC012491222341F03091C00025
+:1087700035FFFCCF2093C6000196F4CFFF2091F087
+:10878000FE018491882389F09091C00095FFFCCF71
+:108790008093C6002196F4CF9091C00095FFFCCF46
+:1087A0008093C60089918111F7CFEDEBF3E107C00B
+:1087B0009091C00095FFFCCF8093C60031968491C4
+:1087C0008111F6CF8091C00085FFFCCF8AE08093B5
+:1087D000C600DF91CF911F910F91FF90089581E026
+:1087E00020913F1030914010232B09F080E0089534
+:1087F0001F93CF93DF93EC01162F662319F00F948C
+:10880000FAC508C0FC0101900020E9F7CF010197EB
+:108810008C1B9D0B9FDE882309F459C08091431067
+:1088200090914410FC01EB5BFF4E23E02083039604
+:10883000BE018B5B9F4E112319F00F94F3C502C04C
+:108840000F94A1C680913F10909140100196909393
+:10885000401080933F10EFE3F0E18491882341F0D2
+:108860009091C00095FFFCCF8093C6003196F5CF64
+:10887000E4EAF3E18491882341F09091C00095FFF0
+:10888000FCCF8093C6003196F5CFE0914310F09174
+:108890004410E85BFF4E8191882339F09091C0002D
+:1088A00095FFFCCF8093C600F6CFE2EAF3E1849116
+:1088B000882341F09091C00095FFFCCF8093C600C3
+:1088C0003196F5CF8091C00085FFFCCF42C0E5E432
+:1088D000F0E18491882341F09091C00095FFFCCF96
+:1088E0008093C6003196F5CFE9E8F3E184918823BF
+:1088F00041F09091C00095FFFCCF8093C600319667
+:10890000F5CF112391F0FE018491882389F0909195
+:10891000C00095FFFCCF8093C6002196F4CF9091C4
+:10892000C00095FFFCCF8093C60089918111F7CFDD
+:10893000E2E7F3E107C09091C00095FFFCCF809380
+:10894000C600319684918111F6CF8091C00085FFD9
+:10895000FCCF8AE08093C600DF91CF911F910895EC
+:1089600081E080933E10089581E020913F10309186
+:108970004010232B09F080E008952F923F924F92F0
+:108980005F926F927F928F929F92AF92BF92CF929F
+:10899000DF92EF92FF920F931F93CF93DF93CDB7A8
+:1089A000DEB7A0970FB6F894DEBF0FBECDBF61E073
+:1089B0008FE590E0FBDC882309F4FEC4912C03E6EC
+:1089C00013E13AE0732E882483944EECE42E42E4C3
+:1089D000F42E56ECC52E50E4D52E8091FF099091CF
+:1089E000000A2091010A3091020A821B930B8F77B3
+:1089F0009927009709F418C18F379105B9F4F80148
+:108A00008491E3E6F3E1882349F09091C00095FF5B
+:108A1000FCCF8093C60031968491F5CF8091C00041
+:108A200085FFFCCF7092C600992493948EE799E05D
+:108A30000E944F41282F8091030A813051F41092F7
+:108A4000030A8091C00085FFFCCF2093C60080926E
+:108A5000030A28A30F94EFB4609335107093361077
+:108A600080933710909338100F94EFB460933110C7
+:108A700070933210809333109093341028A127FD07
+:108A8000ACCF40913C1050913D102A3061F02D3018
+:108A900051F02A3321F480913B10882321F04F3587
+:108AA00051050CF4A9C04115510519F410923B1061
+:108AB00083C48091411090914210FA01EB5BFF4E0C
+:108AC000E80FF91F138220913B1021117BC09C01FC
+:108AD000285B3F4E590166E074E0C9010F94C5C69A
+:108AE00090933A1080933910892B09F0D4C16EE429
+:108AF00070E0C5010F948DC690933A1080933910A1
+:108B0000892B09F050C1C7C1E0913910F0913A109A
+:108B1000108280912D1090912E10A0912F10B09165
+:108B200030108093291090932A10A0932B10B093AB
+:108B30002C10809141109091421067E470E0885BA6
+:108B40009F4E0F948DC690933A10809339100097E2
+:108B500009F065C1809141109091421064EE75E07A
+:108B6000885B9F4E0F9498C6892B29F462E08EEFA4
+:108B700098E00E94475C8091411090914210FC0166
+:108B8000EB5BFF4E8082DC01A85BBF4EFD010190D4
+:108B90000020E9F73197EA1BFB0B04968E0F9F1F0D
+:108BA0008D3EF1E09F0709F471C1909342108093CC
+:108BB000411080913F109091401001969093401089
+:108BC00080933F1010923D1010923C108091FF094D
+:108BD0009091000A2091010A3091020A821B930BA6
+:108BE0008F779927892B09F4E7C361E08FE590E03F
+:108BF000DDDB8111F2CEE0C32B3311F480923B1008
+:108C000080913B108111E9CEE0914110F09142102A
+:108C1000CA01019690933D1080933C10E40FF51F1C
+:108C2000E85BFF4E2083D9CE8091921B882309F404
+:108C300062C00F94EFB46093311070933210809340
+:108C4000331090933410009135101091361020910C
+:108C5000371030913810DC01CB01801B910BA20B37
+:108C6000B30B81329340A105B10508F444C0E091F3
+:108C70003C10F0913D101E161F060CF03CC0809178
+:108C8000411090914210EB5BFF4EE80FF91F1382E9
+:108C9000DC01A85BBF4EFD0101900020E9F7319790
+:108CA000EA1BFB0B04968E0F9F1F9093421080933C
+:108CB00041108D3E914021F41092421010924110CB
+:108CC00080913F10909140100196909340108093B6
+:108CD0003F1010923D1010923C10E5E5F3E18491B5
+:108CE000882309F469C39091C00095FFFCCF80935D
+:108CF000C6003196F4CF9920A9F020913C10309114
+:108D00003D101216130674F4809141109091421098
+:108D1000821B930B909342108093411010923D1050
+:108D200010923C1080916C0B882309F445C380910C
+:108D30003C1090913D10892B09F03EC380913F106B
+:108D400090914010892B11F41092201088EE482E3B
+:108D500083E0582E612C712C9CE3892E912CA12C40
+:108D6000B12C21E4222E23E1322E8E010F5F1F4F02
+:108D70004091080E5091090E60910A0E70910B0EF1
+:108D80008091000E9091010EA091020EB091030E01
+:108D9000481759076A077B0708F00EC38091201017
+:108DA00081110AC372C16EE470E0C5010F948DC6D3
+:108DB00090933A1080933910009709F4BACE4AE0A4
+:108DC00050E060E070E001960F949EC460932D1017
+:108DD00070932E1080932F109093301020912910B3
+:108DE00030912A1040912B1050912C102F5F3F4F43
+:108DF0004F4F5F4FA0904110B09042106217730721
+:108E00008407950709F486C06EE573E1C501885BA8
+:108E10009F4E0F9438C6892B09F07CC006C1209163
+:108E20006C0B211108C02AE030E03093580B2093DE
+:108E3000570B80925F0B2091800A222309F48ACE7F
+:108E40004AE050E060E070E001960F949EC4643008
+:108E5000710508F07FCEF70185919491FC01249172
+:108E6000222341F03091C00035FFFCCF2093C60093
+:108E70000196F4CF8091C00085FFFCCF7092C600B0
+:108E8000F601859194910F947E5164CE1092421018
+:108E9000109241108ECE6AE270E0C5010F948DC62B
+:108EA000892B09F446CEE5E4F0E18491882341F072
+:108EB0009091C00095FFFCCF8093C6003196F5CF0E
+:108EC000E0EDF2E485919491FC012491222341F09C
+:108ED0003091C00035FFFCCF2093C6000196F4CF3F
+:108EE0004091291050912A1060912B1070912C10F4
+:108EF0002AE030E08EE799E00E940A428091C000AB
+:108F000085FFFCCF8AE08093C60010923D1010923E
+:108F10003C1052C2F501E85BFF4E5F016AE270E06F
+:108F2000CF010F948DC690933A108093391000971B
+:108F300009F035C0E5E4F0E18491882341F0909197
+:108F4000C00095FFFCCF8093C6003196F5CFE2EDCF
+:108F5000F2E485919491FC012491222341F0309117
+:108F6000C00035FFFCCF2093C6000196F4CF40919E
+:108F7000291050912A1060912B1070912C102AE02A
+:108F800030E08EE799E00E940A428091C00085FFA0
+:108F9000FCCF8AE08093C6000E94C155B6CFF50190
+:108FA000B12CE817F90719F02191B226FACF4AE05F
+:108FB00050E060E070E0CF0101960F949EC42B2D2D
+:108FC00030E02617370709F49FCDE5E4F0E18491FE
+:108FD000882341F09091C00095FFFCCF8093C6009C
+:108FE0003196F5CFECEDF2E485919491FC0124915A
+:108FF000222341F03091C00035FFFCCF2093C60002
+:109000000196F4CF4091291050912A1060912B10B5
+:1090100070912C102AE030E08EE799E00E940A421D
+:109020008091C00085FFFCCFB4CFE5E4F0E18491EE
+:10903000882341F09091C00095FFFCCF8093C6003B
+:109040003196F5CFE6EDF2E485919491FC012491FF
+:10905000222341F03091C00035FFFCCF2093C600A1
+:109060000196F4CF4091291050912A1060912B1055
+:1090700070912C102AE030E08EE799E00E940A42BD
+:109080008091C00085FFFCCF84CF80915B0D9091D3
+:109090005C0DA0915D0DB0915E0D8093080E9093D4
+:1090A000090EA0930A0EB0930B0E83E59DE00E947B
+:1090B000B6A98F8F8A30B9F04F8D4D30A1F0433271
+:1090C00011F04A3321F420913B10222361F02091CA
+:1090D0003C1030913D102F3531052CF48F3FEFEFD0
+:1090E0009E0709F04DC14091080E5091090E609104
+:1090F0000A0E70910B0E8091000E9091010EA091BE
+:10910000020EB091030E481759076A077B0708F44F
+:10911000ADC0E2EBF2E485919491FC01249122230D
+:1091200041F03091C00035FFFCCF2093C60001967E
+:10913000F4CF8091C00085FFFCCFFAE0F093C60029
+:109140000F94EFB46093860A7093870A8093880A1D
+:109150009093890AC0908A0AD0908B0AE0908C0A7A
+:10916000F0908D0A6C197D098E099F09C0903B0B08
+:10917000D0903C0BE0903D0BF0903E0B6C197D09BC
+:109180008E099F09A30192010F949DC269017A0182
+:1091900010923B0B10923C0B10923D0B10923E0B29
+:1091A0006091290B70912A0B80912B0B90912C0BC5
+:1091B0000E940C5EC701B601A50194010F949DC2E7
+:1091C000CA01B901A50194010F949DC27F936F93C9
+:1091D000C701B60120E13EE040E050E00F949DC29F
+:1091E0003F932F933F922F921F930F930F9418C882
+:1091F000EFE3F0E184910FB6F894DEBF0FBECDBF70
+:10920000882349F09091C00095FFFCCF8093C60061
+:1092100031968491F5CFF8018191882339F09091AE
+:10922000C00095FFFCCF8093C600F6CF8091C000B0
+:1092300085FFFCCF3AE03093C600C8010F9471510E
+:109240008AE69BE036D861E08AE69BE00E946DBB2F
+:109250008091921B882351F086E090E00F94FF608C
+:1092600084E090E09093971B8093961B9F8D9332A0
+:1092700019F4E1E0E093201020913C1030913D1072
+:109280002115310519F410923B1072CD8091560DC5
+:10929000882349F0C090080ED090090EE0900A0E85
+:1092A000F0900B0E03C0C12CD12C760181E090E030
+:1092B0004091211050912210841B950B8C0D9D1D07
+:1092C0004091411050914210FA01EB5BFF4E62E079
+:1092D000608381839283F901EB5BFF4EE40FF51FFE
+:1092E0001382DA01A85BBF4EFD0101900020E9F76F
+:1092F0003197EA1BFB0BF89480913F10909140103E
+:1093000001969093401080933F10EC5F20914110A4
+:10931000309142102E0F311D309342102093411096
+:109320008091560D882349F08091080E9091090E86
+:10933000A0910A0EB0910B0E03C080E090E0DC011A
+:109340000196A11DB11D8093211090932210A0932E
+:109350002310B09324102D3E314021F4109242107E
+:1093600010924110789410923B1010923D10109280
+:109370003C1061E08FE590E019D88111F9CC1CC058
+:109380004F8D4B3321F481E080933B10F1CC409121
+:109390003B104111EDCCE0914110F0914210A90138
+:1093A0004F5F5F4F50933D1040933C10E20FF31F0F
+:1093B000E85BFF4E8083DCCCA0960FB6F894DEBF4E
+:1093C0000FBECDBFDF91CF911F910F91FF90EF9016
+:1093D000DF90CF90BF90AF909F908F907F906F90D5
+:1093E0005F904F903F902F90089540913F10509183
+:1093F000401041155105A9F18091431090914410FE
+:1094000020E030E0FC01EB5BFF4EA081A23021F4B4
+:1094100061817281260F371F4150510929F103964E
+:10942000FC01EB5BFF4EE0810196E111F9CF8D3E2F
+:10943000E1E09E0738F08D3EE1E09E0719F7E5E494
+:10944000F0E108C0FC01EB5BFF4EE081E111F3CFDE
+:109450000196EDCFCF0185549041A191AA23D1F37C
+:10946000D1CF80E090E00895C90108950F94EFB442
+:1094700060933510709336108093371090933810A6
+:109480000F94EFB4609331107093321080933310C7
+:1094900090933410089520E030E0A901CA01B90189
+:1094A0000C94DA6A60E070E0CB010C94FA6BCF9315
+:1094B000DF938DEF93E10F94BBC768EC88EC0E94BB
+:1094C000F7FFEC01DF93CF938CEE93E19F938F93A3
+:1094D0000F946BC761E00F900F900F900F90CD2B02
+:1094E00009F460E060936902109235121092341210
+:1094F00087E69FE00F9456CA809169028093E0024C
+:10950000DF91CF9108958BED93E10F94BBC710923B
+:10951000690260E087E69FE00F9456CA1092E0026D
+:10952000089526EF280F92EC980F243050F03EEC6F
+:10953000380F343030F0983008F041C0ADE6B0E07C
+:1095400040C0ABE6B0E0EBE6F0E03081243010F450
+:10955000865009C0823399F0833399F0843399F0AF
+:10956000983098F48E5341E050E060E070E004C021
+:10957000440F551F661F771F8A95D2F707C048E032
+:1095800005C044E003C042E001C041E0432B4C93DE
+:109590004BB331E0983018F030E081E001C084E056
+:1095A000842B8BBB90916800243020F0332311F082
+:1095B00084E001C081E0892B809368000895A0E0D9
+:1095C000B0E0983018F4EDE6F0E0BFCFE0E0F0E076
+:1095D000BCCF61E08FE30F94DAB660E08FE30F94C5
+:1095E00013B7109236128FE39CCF1F920F920FB6D3
+:1095F0000F9211240BB60F922F933F934F935F93CB
+:109600006F937F938F939F93AF93BF93CF93DF938A
+:10961000EF93FF938091060190913612892781FF85
+:109620002DC0C0913212D091331210923312109289
+:10963000321278940E94BAFF2097E1F080913E1395
+:1096400090913F13009741F01CF0D7FF0CC012C05F
+:109650001C161D0624F007C01C161D065CF4809124
+:1096600034128F5F05C080913412882319F0815025
+:109670008093341210923F1310923E13FF91EF919A
+:10968000DF91CF91BF91AF919F918F917F916F911A
+:109690005F914F913F912F910F900BBE0F900FBE96
+:1096A0000F901F90189520916902222319F12091A3
+:1096B000321230913312121613062CF4FC01808DF5
+:1096C00083FD07C00895232BA9F0FC01808D83FD45
+:1096D00011C0809106019FB781FF05C0F894809169
+:1096E00008018D7F04C0F894809108018260809306
+:1096F00008019FBF089520916902222379F12091EA
+:10970000321230913312FC01808D83FF03C07195BA
+:1097100061957109620F731F709333126093321257
+:1097200080916A0290916B026817790734F49195E1
+:1097300081959109861797078CF0809106019FB754
+:1097400081FF05C0F894809108018D7F04C0F894D2
+:10975000809108018260809308019FBF08958091E5
+:1097600069028823D1F0809134128630B0F069EE1E
+:1097700075E08EE799E00E9435426CE176E08EE775
+:1097800099E00E94354287DE61E086ED93E130D8B2
+:1097900081E0809335121092690208950F931F9310
+:1097A000CF93DF93EC018B0144E150E0BC0187E3F0
+:1097B00092E10F9429C6CE010F94FAC5992744E18E
+:1097C00050E0481B590BB801895C9D4E0F9429C687
+:1097D00087E392E1DF91CF911F910F910895AF92AE
+:1097E000BF92CF92DF92EF92FF920F931F93CF938E
+:1097F000DF93EC015B017A01690144E150E0BC01B7
+:1098000087E392E10F9429C6CE010F94FAC5EC01CB
+:10981000DD2704E110E0A8014C1B5D0BB501CE0172
+:10982000895C9D4E0F9429C6C5010F94FAC5C80FD7
+:10983000D91FDD27A8014C1B5D0BB701CE01895C48
+:109840009D4E0F9429C6C7010F94FAC58C0F9D1F1A
+:109850009927A801481B590BB601895C9D4E0F94AE
+:1098600029C687E392E1DF91CF911F910F91FF907D
+:10987000EF90DF90CF90BF90AF9008954F925F929E
+:109880006F927F928F929F92AF92BF92CF92DF9210
+:10989000EF92FF920F931F93CF93DF93CDB7DEB775
+:1098A00028970FB6F894DEBF0FBECDBFDC01CD9078
+:1098B000DD90ED90FC901397C0926612D0926712E3
+:1098C000E0926812F092691214960D911D912D91FB
+:1098D0003C91179709831A832B833C8300936E1264
+:1098E00010936F122093701230937112DB010D915F
+:1098F0001D912D913C9113970D831E832F833887E3
+:1099000000936A1210936B1220936C1230936D12B5
+:1099100014964D905D906D907C90179740927212C6
+:10992000509273126092741270927512FA016081F3
+:1099300071818281938160934E1270934F12809354
+:1099400050129093511284809580A680B7808092A7
+:10995000521290925312A0925412B092551220E0DB
+:1099600030E0A9010F94C6BD81110CC020E030E0A9
+:10997000A901C501B4010F94C6BD811103C01092A5
+:10998000761203C081E08093761220E030E040E858
+:109990005FE3C701B6010F94C6BD811121C020E06D
+:1099A00030E0A9016D817E818F8198850F94C6BDBD
+:1099B000811116C020E030E0A90169817A818B8194
+:1099C0009C810F94C6BD81110BC020E030E040E8BF
+:1099D0005FE3C301B2010F94C6BD882309F45EC0E2
+:1099E00080917612826080937612A3019201C70162
+:1099F000B6010F949BC04B015C012D813E814F81CC
+:109A0000588569817A818B819C810F949BC09B01D1
+:109A1000AC01C501B4010F94ECBC4B015C019B018E
+:109A2000AC01C301B2010F94CDBD60935612709387
+:109A3000571280935812909359126D817E818F81B5
+:109A400098859058A50194010F94CDBD60935A124A
+:109A500070935B1280935C1290935D1269817A819E
+:109A60008B819C819058A50194010F94CDBD60938A
+:109A70005E1270935F128093601290936112A50141
+:109A80009401C701B6010F94CDBD6093621270932B
+:109A90006312809364129093651224C080E090E07A
+:109AA000A0E8BFE38093561290935712A0935812E8
+:109AB000B093591210925A1210925B1210925C12CB
+:109AC00010925D1210925E1210925F12109260124C
+:109AD000109261128093621290936312A0936412A9
+:109AE000B093651228960FB6F894DEBF0FBECDBFB7
+:109AF000DF91CF911F910F91FF90EF90DF90CF906A
+:109B0000BF90AF909F908F907F906F905F904F909D
+:109B100008958F929F92AF92BF92CF92DF92EF9271
+:109B2000FF920F931F9345015601ECECFAE0FF936F
+:109B3000EF93ECEECE2EEAE0DE2E0F9458050F9058
+:109B40000F901F910F91FF90EF90DF90CF90BF90FB
+:109B5000AF909F908F900D94071F8F929F92AF921E
+:109B6000BF92CF92DF92EF92FF920F931F93470124
+:109B70005801E090E80AF090E90A0091EA0A109191
+:109B8000EB0AECECFAE0FF93EF93FCEECF2EFAE059
+:109B9000DF2E0F9458050F900F901F910F91FF909B
+:109BA000EF90DF90CF90BF90AF909F908F900D94EB
+:109BB000071F8F929F92AF92BF92CF92DF92EF9248
+:109BC000FF920F931F934B015C01E090E80AF09025
+:109BD000E90A0091EA0A1091EB0A2091E40A309117
+:109BE000E50A4091E60A5091E70A6091E00A709117
+:109BF000E10A8091E20A9091E30AECECFAE0FF932B
+:109C0000EF93ACEECA2EAAE0DA2E0F9458050F900F
+:109C10000F901F910F91FF90EF90DF90CF90BF902A
+:109C2000AF909F908F900D94071FCF92DF92EF928D
+:109C3000FF920F931F93CF93DF9380E00F94761FD3
+:109C4000C0EEDAE0688379838A839B8381E00F9496
+:109C5000761FB4EECB2EBAE0DB2EF6016083718363
+:109C60008283938382E00F94761F7B018C01609343
+:109C7000E80A7093E90A8093EA0A9093EB0AF601E6
+:109C80002081318142815381688179818A819B81E0
+:109C9000CCEECC2ECAE0DC2E0F940612DF91CF91D1
+:109CA0001F910F91FF90EF90DF90CF90089582E089
+:109CB0000F94761F6093E80A7093E90A8093EA0A8A
+:109CC0009093EB0A88EE9AE00D9482138F929F9204
+:109CD000AF92BF92CF92DF92EF92FF920F931F93BA
+:109CE0006B017C0120E030E040E252E460916002D0
+:109CF0007091610280916202909163020F94CDBDD8
+:109D00004B015C01A70196016091E80A7091E90A94
+:109D10008091EA0A9091EB0A0F94ECBC7B018C01D4
+:109D20002091E40A3091E50A4091E60A5091E70A51
+:109D30006091E00A7091E10A8091E20A9091E30A51
+:109D4000ECECFAE0FF93EF93ECEECE2EEAE0DE2EA1
+:109D50000F9458050F94071F0F900F9088EE9AE00C
+:109D60001F910F91FF90EF90DF90CF90BF90AF9039
+:109D70009F908F900D948213CF92DF92EF92FF927B
+:109D8000823008F041C0FB01C080D180E280F380C6
+:109D900020E030E040E85FEBC701B6010F94C9BF97
+:109DA00087FF32C020E030E040E950ECC701B60147
+:109DB0000F94C6BD87FD23C020E030E040E950E4A9
+:109DC000C701B6010F94EDBC20E030E040E650E45E
+:109DD0000F94CDBD6B017C019B01AC0160E070E094
+:109DE00080E89FE30F94ECBC23E333E343EB5EE3B3
+:109DF0000F949BC0A70196010F94EDBC09C063E3CB
+:109E000073E383EB9EE304C060E070E080E89FE3CF
+:109E1000FF90EF90DF90CF9008958F929F92AF9236
+:109E2000BF92CF92DF92EF92FF92FC01C080D1806F
+:109E3000E280F38020E030E040E85FEBC701B6014C
+:109E40000F94C9BF87FF38C020E030E040E950ECF4
+:109E5000C701B6010F94C6BD87FD33C020E030E0D6
+:109E600040E950E4C701B6010F94EDBC20E030E0BA
+:109E700040E650E40F94CDBD6B017C019B01AC0129
+:109E800060E070E080E89FE30F94ECBC20E030E0FD
+:109E9000A9010F949BC04B015C012AE939E949E90A
+:109EA0005EE3C701B6010F949BC09B01AC01C501E5
+:109EB000B4010F94EDBC08C06AE979E989E99EE331
+:109EC00003C060E070E0CB01FF90EF90DF90CF9097
+:109ED000BF90AF909F908F9008952F923F924F9296
+:109EE0005F926F927F928F929F92AF92BF92CF922A
+:109EF000DF92EF92FF920F931F93CF93DF93CDB733
+:109F0000DEB7C05CD1090FB6F894DEBF0FBECDBF7F
+:109F1000E5969FAF8EAFE597C056DF4F6883C05A76
+:109F2000D040C757DF4F59834883C958D040AD96BA
+:109F30003FAF2EAFAD97AF961FAF0EAFAF976B96FB
+:109F4000FFAEEEAE6B97D7011D921D921D921C9233
+:109F50001397F7011482158216821782F4E6C15610
+:109F6000DF4FF883CF59D040A7961CAE1DAE1EAE72
+:109F70001FAEA7976F961CAE1DAE1EAE1FAE6F979D
+:109F8000CE01019663969FAF8EAF6397DE01AF5B04
+:109F9000BF4F6596BFAFAEAF65976F966CAD7DADA9
+:109FA0008EAD9FAD6F970F94CABDE3966CAF7DAF3A
+:109FB0008EAF9FAFE3976F966CAD7DAD8EAD9FADCD
+:109FC0006F970F944AC1C557DF4F688379838A839F
+:109FD0009B83CB58D040A7966CAD7DAD8EAD9FAD29
+:109FE000A7970F94CABDC157DF4F688379838A83CF
+:109FF0009B83CF58D040A7966CAD7DAD8EAD9FAD05
+:10A00000A7970F944AC1CD56DF4F688379838A831F
+:10A010009B83C359D0406396EEADFFAD639720E4B8
+:10A0200011922A95E9F76596AEADBFAD6597E0E16F
+:10A030001D92EA95E9F7CE018F5B9F4FC556DF4F22
+:10A0400099838883CB59D040DE011196E796BFAF44
+:10A05000AEAFE79700E0CD56DF4F88819981AA81A6
+:10A06000BB81C359D040B058C358DF4F8883998310
+:10A07000AA83BB83CD57D040C157DF4F88819981D8
+:10A08000AA81BB81CF58D040B058CF57DF4F8883CB
+:10A090009983AA83BB83C158D040C557DF4F8881BD
+:10A0A0009981AA81BB81CB58D040B058CB57DF4FA4
+:10A0B00088839983AA83BB83C558D040A1961FAEDD
+:10A0C0001EAEA19710E0E5962EAC3FACE5976696E4
+:10A0D0001FAE6697C12CD12C760166969FAD669710
+:10A0E000C056DF4FA881C05AD0409A1709F41AC150
+:10A0F000013011F40C9458D9113011F40C948FD90B
+:10A10000002311F1023071F4D1012D913D914D9157
+:10A110005C91CB57DF4F688179818A819B81C558DB
+:10A12000D0400DC0F1012481358146815781CF5740
+:10A13000DF4F688179818A819B81C158D0400F941B
+:10A140009BC04B015C0106C0812C912CB0E8AB2E6A
+:10A15000BFE3BB2E112311F1123071F4D1012D9107
+:10A160003D914D915C91CB57DF4F688179818A8118
+:10A170009B81C558D0400DC0F101248135814681B5
+:10A180005781CF57DF4F688179818A819B81C15880
+:10A19000D0400F949BC09B01AC0104C020E030E094
+:10A1A00040E85FE3B1016C5F7F4F66968FAD6697C5
+:10A1B000C354DF4F2883CD5BD040C254DF4F388378
+:10A1C000CE5BD040C154DF4F4883CF5BD040C054FA
+:10A1D000DF4F5883C05CD040CFDD2B013C01C3541E
+:10A1E000DF4F2881CD5BD040C254DF4F3881CE5B3A
+:10A1F000D040C154DF4F4881CF5BD040C054DF4FC7
+:10A200005881C05CD040C501B4010F949BC0A3012C
+:10A2100092010F949BC09B01AC01C701B6010F9442
+:10A22000EDBC6B017C01002309F471C0112309F41A
+:10A230006EC0023011F00C9480D9D1012D913D9166
+:10A240004D915C91E3966CAD7DAD8EAD9FADE39786
+:10A250000F949BC04B015C01113011F40C9472D926
+:10A26000123011F00C9463D9D1012D913D914D9193
+:10A270005C91E3966CAD7DAD8EAD9FADE3970F9491
+:10A280009BC09B01AC016696FFAD6697F23010F063
+:10A290000C9478D9C1010496C354DF4F2883CD5B59
+:10A2A000D040C254DF4F3883CE5BD040C154DF4F23
+:10A2B0004883CF5BD040C054DF4F5883C05CD04050
+:10A2C000ACDD2B013C01C354DF4F2881CD5BD04076
+:10A2D000C254DF4F3881CE5BD040C154DF4F48813C
+:10A2E000CF5BD040C054DF4F5881C05CD040C50127
+:10A2F000B4010F949BC0A30192010F949BC09B01DA
+:10A30000AC01C701B6010F94EDBC6B017C016696F0
+:10A310002FAD66972F5F66962FAF669788E0280E61
+:10A32000311CDBCEE796EEADFFADE797A1968EAD83
+:10A330009FADA197E80FF91FC082D182E282F3821C
+:10A340001F5F0496A1969FAF8EAFA197409709F02B
+:10A35000BACEE5962EAC3FACE597C757DF4FA88144
+:10A36000B981C958D0406796BFAFAEAF679710E0CC
+:10A37000AB961CAE1DAE1EAE1FAEAB97C056DF4FE8
+:10A380002881C05AD040121709F498C1002331F136
+:10A39000013059F1023071F4F101208131814281A3
+:10A3A0005381CB57DF4F688179818A819B81C55862
+:10A3B000D0400FC0D10114962D913D914D915C91EB
+:10A3C0001797CF57DF4F688179818A819B81C15868
+:10A3D000D0400F949BC04B015C010AC0812C912C92
+:10A3E000E0E8AE2EEFE3BE2E03C0812C912C540189
+:10A3F000F10181919191A191B191A196FFAFEEAF41
+:10A40000A197C956DF4F88839983AA83BB83C75915
+:10A41000D0409C01AD01E3966CAD7DAD8EAD9FAD9E
+:10A42000E3970F949BC06B017C01D10114968D9131
+:10A430009D910D90BC91A02DED968CAF9DAFAEAFD0
+:10A44000BFAFED976796EEADFFAD6797459055901E
+:10A4500065907490ED962CAD3DAD4EAD5FADED9732
+:10A46000CD56DF4F688179818A819B81C359D04065
+:10A470000F949BC09B01AC01C701B6010F94ECBCCB
+:10A480006B96EEADFFAD6B97208131814281538198
+:10A490000F94EDBCA30192010F94ECBC9B01AC01A5
+:10A4A000A1966EAD7FADA197812FC354DF4F288356
+:10A4B000CD5BD040C254DF4F3883CE5BD040C15417
+:10A4C000DF4F4883CF5BD040C054DF4F5883C05C20
+:10A4D000D04052DC2B013C01C354DF4F2881CD5BBF
+:10A4E000D040C254DF4F3881CE5BD040C154DF4FE3
+:10A4F0004881CF5BD040C054DF4F5881C05CD04012
+:10A50000C501B4010F949BC0A30192010F949BC09D
+:10A510009B01AC01AB966CAD7DAD8EAD9FADAB97A5
+:10A520000F94EDBCAB966CAF7DAF8EAF9FAFAB978A
+:10A530000023B9F00130C9F00230E9F0ED962CADFE
+:10A540003DAD4EAD5FADED97C358DF4F688179816A
+:10A550008A819B81CD57D0400F949BC06B017C01B9
+:10A560000AC0C12CD12C760106C0C12CD12C70E8B8
+:10A57000E72E7FE3F72E6796EEADFFAD6797349633
+:10A5800085909590A590B490C956DF4F2881398168
+:10A590004A815B81C759D040C557DF4F68817981B7
+:10A5A0008A819B81CB58D0400F949BC02B013C01EA
+:10A5B000ED962CAD3DAD4EAD5FADED97C157DF4F84
+:10A5C000688179818A819B81CF58D0400F949BC04C
+:10A5D0009B01AC01C301B2010F94EDBC6B96AEAD13
+:10A5E000BFAD6B9714962D913D914D915C9117974E
+:10A5F0000F94EDBCA50194010F94ECBC9B01AC0140
+:10A60000123080F5A1968EAD9FADA197C354DF4F58
+:10A610002883CD5BD040C254DF4F3883CE5BD0401F
+:10A62000C154DF4F4883CF5BD040C054DF4F5883C5
+:10A63000C05CD040F2DB4B015C01C354DF4F28818A
+:10A64000CD5BD040C254DF4F3881CE5BD040C15487
+:10A65000DF4F4881CF5BD040C054DF4F5881C05C92
+:10A66000D04006C0812C912C60E8A62E6FE3B62E58
+:10A67000C701B6010F949BC0A50194010F949BC024
+:10A680009B01AC01AB966CAD7DAD8EAD9FADAB9734
+:10A690000F94EDBCAB966CAF7DAF8EAF9FAFAB9719
+:10A6A0001F5F6796EEADFFAD679738966796FFAF71
+:10A6B000EEAF6797F8E02F0E311C60CEAB968CADF5
+:10A6C0009DADAEADBFADAB97B058C556DF4FE8817D
+:10A6D000F981CB59D04081939193A193B193C55601
+:10A6E000DF4FF983E883CB59D0400F5FE7968EADFB
+:10A6F0009FADE7974096E7969FAF8EAFE797043000
+:10A7000009F0DCCC25968CAD9DADAEADBFAD2597E7
+:10A71000A3968CAF9DAFAEAFBFAFA3978D819E8147
+:10A72000AF81B885AB968CAF9DAFAEAFBFAFAB97E7
+:10A7300089859A85AB85BC85E3968CAF9DAFAEAF1E
+:10A74000BFAFE3978D859E85AF85B889E9968CAFBD
+:10A750009DAFAEAFBFAFE99789819A81AB81BC81D4
+:10A76000ED968CAF9DAFAEAFBFAFED9729968CAD98
+:10A770009DADAEADBFAD2997C358DF4F8883998398
+:10A78000AA83BB83CD57D04089899A89AB89BC897C
+:10A79000CF57DF4F88839983AA83BB83C158D040AA
+:10A7A000898D9A8DAB8DBC8DCB57DF4F8883998374
+:10A7B000AA83BB83C558D0408D8D9E8DAF8DB8A127
+:10A7C000C557DF4F88839983AA83BB83CB58D0407A
+:10A7D0008D899E89AF89B88DC157DF4F8883998352
+:10A7E000AA83BB83CF58D0402D968CAD9DADAEAD26
+:10A7F000BFAD2D97CD56DF4F88839983AA83BB8346
+:10A80000C359D04089A19AA1ABA1BCA1C956DF4FC1
+:10A8100088839983AA83BB83C759D0408DA19EA109
+:10A82000AFA1B8A5C556DF4F88839983AA83BB83A0
+:10A83000CB59D0408DA59EA5AFA5B8A9CF55DF4F68
+:10A8400088839983AA83BB83C15AD04089A59AA5DE
+:10A85000ABA5BCA5CB55DF4F88839983AA83BB8367
+:10A86000C55AD04061968CAD9DADAEADBFAD619780
+:10A87000C755DF4F88839983AA83BB83C95AD040C9
+:10A8800089A99AA9ABA9BCA9C355DF4F888399832D
+:10A89000AA83BB83CD5AD0408DA99EA9AFA9B8ADDC
+:10A8A000CF54DF4F88839983AA83BB83C15BD04099
+:10A8B00089AD9AADABADBCADCB54DF4F88839983E6
+:10A8C000AA83BB83C55BD04021968CAD9DADAEAD58
+:10A8D000BFAD2197C754DF4F88839983AA83BB8379
+:10A8E000C95BD04014E6412C512C32015301420186
+:10A8F00073016201A3019201AB966CAD7DAD8EAD8B
+:10A900009FADAB970F949BC09B01AC01A3966CAD20
+:10A910007DAD8EAD9FADA3970F94ECBC2B013C0198
+:10A92000A5019401E3966CAD7DAD8EAD9FADE3972F
+:10A930000F949BC09B01AC01C301B2010F94ECBC0E
+:10A940002B013C01A7019601E9966CAD7DAD8EAD62
+:10A950009FADE9970F949BC09B01AC01C301B2016D
+:10A960000F94ECBCED962CAD3DAD4EAD5FADED97CB
+:10A970000F94CDBD69966CAF7DAF8EAF9FAF6997D9
+:10A980009B01AC01CF57DF4F688179818A819B8120
+:10A99000C158D0400F949BC09B01AC01C358DF4FFE
+:10A9A000688179818A819B81CD57D0400F94ECBC1E
+:10A9B0002B013C01A5019401CB57DF4F68817981C0
+:10A9C0008A819B81C558D0400F949BC09B01AC01EC
+:10A9D000C301B2010F94ECBC4B015C01A7019601CD
+:10A9E000C557DF4F688179818A819B81CB58D040E0
+:10A9F0000F949BC09B01AC01C501B4010F94ECBC4A
+:10AA0000C157DF4F288139814A815B81CF58D040BF
+:10AA10000F94CDBD2B013C0169962CAD3DAD4EADE3
+:10AA20005FAD6997C956DF4F688179818A819B81C3
+:10AA3000C759D0400F949BC09B01AC01CD56DF4F4E
+:10AA4000688179818A819B81C359D0400F94ECBC85
+:10AA50004B015C01A3019201C556DF4F68817981EA
+:10AA60008A819B81CB59D0400F949BC09B01AC0144
+:10AA7000C501B4010F94ECBC4B015C01A701960128
+:10AA8000CF55DF4F688179818A819B81C15AD0403F
+:10AA90000F949BC09B01AC01C501B4010F94ECBCA9
+:10AAA000CB55DF4F288139814A815B81C55AD0401F
+:10AAB0000F94CDBD4B015C0169962CAD3DAD4EAD03
+:10AAC0005FAD6997C355DF4F688179818A819B812A
+:10AAD000CD5AD0400F949BC09B01AC01C755DF4FAE
+:10AAE000688179818A819B81C95AD0400F94ECBCDE
+:10AAF0006B017C01A3019201CF54DF4F6881798102
+:10AB00008A819B81C15BD0400F949BC09B01AC01AB
+:10AB1000C701B6010F94ECBC6B017C01A501940147
+:10AB2000CB54DF4F688179818A819B81C55BD0409E
+:10AB30000F949BC09B01AC01C701B6010F94ECBC04
+:10AB4000C754DF4F288139814A815B81C95BD0407E
+:10AB50000F94CDBD6B017C01115009F0CBCE6996ED
+:10AB60002CAD3DAD4EAD5FAD69976B96AEADBFAD53
+:10AB70006B976D917D918D919C910F94EDBC6B962F
+:10AB8000EEADFFAD6B976083718382839383A301E6
+:10AB9000920164817581868197810F94EDBC6B96DB
+:10ABA000AEADBFAD6B9714966D937D938D939C93D3
+:10ABB0001797A50194016F966CAD7DAD8EAD9FADDD
+:10ABC0006F970F94EDBC6F966CAF7DAF8EAF9FAF5C
+:10ABD0006F97A7019601A7966CAD7DAD8EAD9FAD29
+:10ABE000A7970F94EDBCA7966CAF7DAF8EAF9FAFCC
+:10ABF000A797C156DF4FB881CF59D040B150C15649
+:10AC0000DF4FB883CF59D040B111C7C96F966CAD33
+:10AC10007DAD8EAD9FAD6F970F94CABDAD96EEAD75
+:10AC2000FFADAD9760837183828393836F966CAD24
+:10AC30007DAD8EAD9FAD6F970F944AC1AD96AEAD11
+:10AC4000BFADAD9714966D937D938D939C9317979D
+:10AC5000A7966CAD7DAD8EAD9FADA7970F944AC101
+:10AC6000DC01CB01B058AF96EEADFFADAF9780835E
+:10AC70009183A283B383A7966CAD7DAD8EAD9FAD5E
+:10AC8000A7970F94CABDAF96AEADBFADAF97149660
+:10AC90006D937D938D939C9317976F962CAD3DADDF
+:10ACA0004EAD5FAD6F97A7966CAD7DAD8EAD9FAD90
+:10ACB000A7970F94ECBC6B017C01E894F7F8B701FF
+:10ACC000A60180E69FE00F9468CA2FE132E449E0D4
+:10ACD0005BE3C701B6010F94C9BF18166CF425E3F6
+:10ACE0003AEF4EE85BE3C701B6010F94C9BF1816EF
+:10ACF00034F402E010E005C000E010E002C001E022
+:10AD000010E025E33AEF4EE85BE36F966CAD7DAD66
+:10AD10008EAD9FAD6F979F770F94C9BF18167CF0CB
+:10AD200025E33AEF4EE85BE3A7966CAD7DAD8EADC3
+:10AD30009FADA7979F770F94C9BF181614F402E030
+:10AD400010E0C757DF4F28803980C958D040E596BA
+:10AD5000EEADFFADE597A196FFAFEEAFA19766967A
+:10AD60001FAE66976696AFAD6697C056DF4FB88147
+:10AD7000C05AD040AB1709F4EEC0A1968EAD9FAD7E
+:10AD8000A197DC018D909D90AD90BD90A996BFAF2D
+:10AD9000AEAFA997DC0114968D919D910D90BC9159
+:10ADA000A02DE3968CAF9DAFAEAFBFAFE397F1019F
+:10ADB000C590D590E590F490AD96EEADFFADAD9712
+:10ADC0002081318142815381C501B4010F949BC020
+:10ADD0002B013C01AF96AEADBFADAF972D913D912C
+:10ADE0004D915C91E3966CAD7DAD8EAD9FADE397DB
+:10ADF0000F949BC09B01AC01C301B2010F94EDBC49
+:10AE00006B96EEADFFAD6B9720813181428153810E
+:10AE10000F94EDBC9B01AC01C701B6010F94ECBCD3
+:10AE20009B01AC010F949BC06B017C01F101349636
+:10AE30004590559065907490AD96AEADBFADAD9711
+:10AE400014962D913D914D915C911797C501B401D8
+:10AE50000F949BC04B015C01AF96EEADFFADAF9779
+:10AE60002481358146815781E3966CAD7DAD8EADF1
+:10AE70009FADE3970F949BC09B01AC01C501B4014A
+:10AE80000F94EDBC6B96AEADBFAD6B9714962D9144
+:10AE90003D914D915C9117970F94EDBC9B01AC01D6
+:10AEA000C301B2010F94ECBC9B01AC010F949BC099
+:10AEB0004B015C019B01AC01C701B6010F94EDBCD5
+:10AEC0000F9454C16696BFAD6697B23030F5A9961F
+:10AED0008EAD9FADA9970E940DCF2B013C01C701FC
+:10AEE000B6010F9454C12DEC3CEC4CE45FE30F949D
+:10AEF000C9BF1816D4F020E030E0A901C301B201A7
+:10AF00000F94C6BD882399F0C501B4010F9454C1B4
+:10AF100020E030E040EC5FE304C02DEC3CEC4CE47E
+:10AF20005FE30F94C9BF181614F40EEF1FEF669677
+:10AF3000EFAD6697EF5F6696EFAF6697A1968EAD21
+:10AF40009FADA1970896A1969FAF8EAFA19798E06D
+:10AF5000290E311C07CF0115110509F0E5C1A7968F
+:10AF60002CAD3DAD4EAD5FADA7976F966CAD7DAD91
+:10AF70008EAD9FAD6F970F94EDBC20E030E040E0C8
+:10AF80005FE30F949BC04B015C010F94CABD6B0142
+:10AF90007C01AD96EEADFFADAD976083718382838A
+:10AFA0009383C501B4010F944AC1AD96AEADBFAD58
+:10AFB000AD9714966D937D938D939C931797DC01B9
+:10AFC000CB01B058AF96EEADFFADAF9780839183C4
+:10AFD000A283B383C482D582E682F7826B96EEADFC
+:10AFE000FFAD6B9710821182128213821482158238
+:10AFF000168217826C961FAE6C97A3961CAE1DAE80
+:10B000001EAE1FAEA397A7961CAE1DAE1EAE1FAE02
+:10B01000A7976696FFAD6697EF2FF0E0A996FFAF72
+:10B02000EEAFA9976C962FAD6C97222E332427FC98
+:10B030003094A9968EAD9FADA997281639060CF0CD
+:10B0400008C193E0220C331C9A95E1F7E596EEAD2A
+:10B05000FFADE597E20DF31D80809180A280B38063
+:10B06000C101049667969FAF8EAF6797E596EEADE8
+:10B07000FFADE597E80FF91FC080D180E280F38033
+:10B08000AD96AEADBFADAD972D913D914D915C911B
+:10B09000C501B4010F949BC02B013C01AF96EEADEE
+:10B0A000FFADAF972081318142815381C701B60145
+:10B0B0000F949BC09B01AC01C301B2010F94EDBC86
+:10B0C0002B013C01AD96AEADBFADAD9714962D9161
+:10B0D0003D914D915C911797C501B4010F949BC0B0
+:10B0E0004B015C01AF96EEADFFADAF97248135818A
+:10B0F00046815781C701B6010F949BC09B01AC01EB
+:10B10000C501B4010F94EDBC6B017C0169837A83A6
+:10B110008B839C83BE016F5F7F4F6C968FAD6C9766
+:10B120000E94BCCE4B015C01C757DF4F88819981DB
+:10B13000C958D040280E391EF1016591759185914D
+:10B140009491A30192010F94ECBC9B01AC01C50149
+:10B15000B4010F949BC09B01AC016B96AEADBFAD2B
+:10B160006B976D917D918D919C910F94EDBC6B9639
+:10B17000EEADFFAD6B976083718382839383A501EE
+:10B180009401A7966CAD7DAD8EAD9FADA7970F9442
+:10B19000EDBCA7966CAF7DAF8EAF9FAFA7976C96B7
+:10B1A0008FAD6C97823038F4CE0101960E940DCF9E
+:10B1B0004B015C0106C0812C912C80E8A82E8FE306
+:10B1C000B82EC757DF4FE881F981C958D04067963C
+:10B1D0008EAD9FAD6797E80FF91F659175918591C9
+:10B1E0009491A70196010F94ECBC9B01AC01C501A1
+:10B1F000B4010F949BC09B01AC016B96AEADBFAD8B
+:10B200006B9714966D917D918D919C9117970F94EA
+:10B21000EDBC6B96EEADFFAD6B9764837583868353
+:10B220009783A5019401A3966CAD7DAD8EAD9FADC6
+:10B23000A3970F94EDBCA3966CAF7DAF8EAF9FAF7D
+:10B24000A3976C96FFAD6C97FF5F6C96FFAF6C9702
+:10B25000E9CEA7962CAD3DAD4EAD5FADA7976B96F1
+:10B26000AEADBFAD6B976D917D918D919C910F941B
+:10B27000CDBD6B96EEADFFAD6B976083718382831E
+:10B280009383A3962CAD3DAD4EAD5FADA397648186
+:10B290007581868197810F94CDBD6B96AEADBFADA4
+:10B2A0006B9714966D937D938D939C9317973CC0E9
+:10B2B000112309F42CC8812C912CA0E8AA2EAFE30D
+:10B2C000BA2E0C942CD1F10124813581468157810D
+:10B2D000C358DF4F688179818A819B81CD57D040E7
+:10B2E0000C943FD120E030E040E85FE30C9443D180
+:10B2F000412C512CF0E86F2EFFE37F2E0C9477D178
+:10B30000F1012481358146815781C358DF4F68811F
+:10B3100079818A819B81CD57D0400C9428D101112D
+:10B320000C9419D10C9487D1AD96AEADBFADAD974D
+:10B330008D919D910D90BC91A02D6F968CAF9DAF7E
+:10B34000AEAFBFAF6F97AF96EEADFFADAF97848056
+:10B350009580A680B780AD96AEADBFADAD97149683
+:10B360008D919D910D90BC91A02DA7968CAF9DAF16
+:10B37000AEAFBFAFA79780819181A281B38169965B
+:10B380008CAF9DAFAEAFBFAF6997A50194016F962B
+:10B390006CAD7DAD8EAD9FAD6F970F949BC06B0173
+:10B3A0007C0169962CAD3DAD4EAD5FAD6997A7961A
+:10B3B0006CAD7DAD8EAD9FADA7970F949BC09B01EB
+:10B3C000AC01C701B6010F94ECBC6B017C019B0181
+:10B3D000AC01C501B4010F94CDBD2B013C016996B0
+:10B3E0006CAD7DAD8EAD9FAD69979058A70196016C
+:10B3F0000F94CDBD4B015C01A7966CAD7DAD8EADBC
+:10B400009FADA7979058A70196010F94CDBD69965F
+:10B410006CAF7DAF8EAF9FAF6997A70196016F9616
+:10B420006CAD7DAD8EAD9FAD6F970F94CDBD6B01B3
+:10B430007C016B96AEADBFAD6B978D919D910D90DC
+:10B44000BC91A02D6F968CAF9DAFAEAFBFAF6F9785
+:10B450006B96AEADBFAD6B9714968D919D910D908F
+:10B46000BC91A02DA7968CAF9DAFAEAFBFAFA797F5
+:10B47000AD96EEADFFADAD97408251826282738290
+:10B4800069968CAD9DADAEADBFAD69978483958354
+:10B49000A683B783AF96AEADBFADAF978D929D92A9
+:10B4A000AD92BC921397FD01C482D582E682F782E9
+:10B4B000C301B20190586F962CAD3DAD4EAD5FAD5E
+:10B4C0006F970F949BC02B013C01A7962CAD3DAD0F
+:10B4D0004EAD5FADA797C501B4010F949BC09B0112
+:10B4E000AC01C301B2010F94ECBC6B96AEADBFAD25
+:10B4F0006B976D937D938D939C93139769966CAD29
+:10B500007DAD8EAD9FAD699790586F962CAD3DADDA
+:10B510004EAD5FAD6F970F949BC04B015C01A7963A
+:10B520002CAD3DAD4EAD5FADA797C701B6010F94F1
+:10B530009BC09B01AC01C501B4010F94ECBC6B96A0
+:10B54000EEADFFAD6B976483758386839783C801E7
+:10B55000C054DF4F0FB6F894DEBF0FBECDBFDF91F2
+:10B56000CF911F910F91FF90EF90DF90CF90BF9000
+:10B57000AF909F908F907F906F905F904F903F9093
+:10B580002F9008954FEF5FEFBA0185EE9FE00F9483
+:10B5900068CA4FEF5FEFBA0189EE9FE00F9468CA67
+:10B5A0004FEF5FEFBA018DED9FE00F9468CA4FEF48
+:10B5B0005FEFBA0181EE9FE00F9468CA4FEF5FEF33
+:10B5C000BA0185ED9FE00F9468CA4FEF5FEFBA01B3
+:10B5D00089ED9FE00F9468CA4FEF5FEFBA0185ECE9
+:10B5E0009FE00F9468CA4FEF5FEFBA0189EC9FE0CC
+:10B5F0000F9468CA4FEF5FEFBA018DEC9FE00F9494
+:10B6000068CA4FEF5FEFBA0181ED9FE00D9468CA01
+:10B61000CF93DF93C5ECDFE0CE010F9451CA0196C2
+:10B6200039F02296C53D8FE0D807B1F781E001C01F
+:10B6300080E0DF91CF910895CF93DF93CDB7DEB750
+:10B6400068970FB6F894DEBF0FBECDBF80E090E0E4
+:10B65000A0E8BFE3898B9A8BAB8BBC8B1D8A1E8ABB
+:10B660001F8A188E19861A861B861C868D879E87D0
+:10B67000AF87B88B19821A821B821C821D821E82A0
+:10B680001F821886AE014F5F5F4FBE01675F7F4F1D
+:10B69000CE0141960E943ECC68960FB6F894DEBF6C
+:10B6A0000FBECDBFDF91CF910895CF93DF93CDB77C
+:10B6B000DEB768970FB6F894DEBF0FBECDBF80919E
+:10B6C00076128823F1F180E090E0A0E8BFE3898B57
+:10B6D0009A8BAB8BBC8B1D8A1E8A1F8A188E19868B
+:10B6E0001A861B861C868D879E87AF87B88B19822A
+:10B6F0001A821B821C821D821E821F821886AE0146
+:10B700004F5F5F4FBE01675F7F4FCE0141960E9442
+:10B710003ECC0F94071F80E00F94761F6093E00AE1
+:10B720007093E10A8093E20A9093E30A81E00F9418
+:10B73000761F6093E40A7093E50A8093E60A90937B
+:10B74000E70A68960FB6F894DEBF0FBECDBFDF9153
+:10B75000CF9108954F925F926F927F928F929F92B6
+:10B76000AF92BF92CF92DF92EF92FF921F93CF934F
+:10B77000DF93CDB7DEB7A0970FB6F894DEBF0FBE4C
+:10B78000CDBF85EE9FE00F944CCA9B01AC01698B45
+:10B790007A8B8B8B9C8B89EE9FE02D8F3E8F4F8F0A
+:10B7A00058A30F944CCA2B013C016D8B7E8B8F8B61
+:10B7B000988F8DED9FE00F944CCA6B017C016987D7
+:10B7C0007A878B879C8781EE9FE00F944CCA4B0150
+:10B7D0005C016D877E878F87988B85ED9FE00F9446
+:10B7E0004CCA698F7A8F8B8F9C8F69837A838B8306
+:10B7F0009C8389ED9FE00F944CCA6D837E838F8379
+:10B8000098872D8D3E8D4F8D58A12F3F3F4F4F4F25
+:10B810005F4FF9F04720462045204094D1F03FEF9C
+:10B82000C316D306E306F306A1F0EFEF8E169E06CD
+:10B83000AE06BE0671F0298D3A8D4B8D5C8D2F3F83
+:10B840003F4F4F4F5F4F29F06F3F7F4F8F4F9F4FBD
+:10B8500091F4EFE9F5E48491882341F09091C000E0
+:10B8600095FFFCCF8093C6003196F5CF8091C00044
+:10B8700085FFFCCFF3C0A7019601C701B6010F9465
+:10B880009BC06B017C01A5019401C501B4010F941B
+:10B890009BC09B01AC01C701B6010F94EDBC0F9496
+:10B8A00054C16B017C0126E636E646E65FE30F9461
+:10B8B000C6BD87FD0BC02DEC3CEC4CE85FE3C70137
+:10B8C000B6010F94C9BF18160CF0F2C0EEE8F5E40B
+:10B8D00084918111DDC08091C00085FFFCCF8AE09A
+:10B8E0008093C60022E030E0B701A6018EE799E020
+:10B8F0000E943643EAE4F5E484918111D1C080913D
+:10B90000C00085FFFCCF8AE08093C60011E069810A
+:10B910007A818B819C81CD80DE80EF80F8849B01D1
+:10B92000AC010F949BC04B015C01A7019601C701BC
+:10B93000B6010F949BC09B01AC01C501B4010F94EB
+:10B94000EDBC0F9454C16B017C0126E636E646E659
+:10B950005FE30F94C6BD87FDADC02DEC3CEC4CE819
+:10B960005FE3C701B6010F94C9BF18160CF4A2C05B
+:10B9700069897A898B899C89CD88DE88EF88F88CE3
+:10B980009B01AC010F949BC04B015C01A701960188
+:10B99000C701B6010F949BC09B01AC01C501B40166
+:10B9A0000F94EDBC0F9454C16B017C0120E030E09A
+:10B9B00040E751E40F94C9BF18160CF5EEEDF4E41E
+:10B9C00084918111A9C08091C00085FFFCCF8AE0DD
+:10B9D0008093C60022E030E0B701A6018EE799E02F
+:10B9E0000E943643EBEAF4E4849181119DC080917A
+:10B9F000C00085FFFCCF8AE08093C60011E029815A
+:10BA00003A814B815C8169857A858B859C850F9411
+:10BA10009BC06B017C012D813E814F8158856D85D6
+:10BA20007E858F8598890F949BC09B01AC01C701CF
+:10BA3000B6010F94EDBC9F772DEC3CEC4CEC5DE334
+:10BA40000F94C9BF18160CF07FC0E1E6F4E48491AE
+:10BA5000811172C08091C00085FFFCCF8AE0809385
+:10BA6000C600EBE2F4E48491882341F09091C00099
+:10BA700095FFFCCF8093C6003196F5CF8091C00032
+:10BA800085FFFCCF8AE08093C6007CDDD5DD68C0F1
+:10BA90009091C00095FFFCCF8093C600319618CFDF
+:10BAA0009091C00095FFFCCF8093C600319624CFC3
+:10BAB00010E02DCFE9E3F5E48491882341F09091E3
+:10BAC000C00095FFFCCF8093C6003196F5CF8091E2
+:10BAD000C00085FFFCCF8AE08093C60022E030E002
+:10BAE000B701A6018EE799E00E943643E5EFF4E442
+:10BAF0008491882341F09091C00095FFFCCF809302
+:10BB0000C6003196F5CF8091C00085FFFCCF8AE05A
+:10BB10008093C60011E02CCF9091C00095FFFCCF20
+:10BB20008093C60031964CCF9091C00095FFFCCF1A
+:10BB30008093C600319658CF9091C00095FFFCCFFE
+:10BB40008093C600319683CF11118BCFAE014F5E2B
+:10BB50005F4FBE016F5F7F4FCE0109960E943ECCC2
+:10BB6000A0960FB6F894DEBF0FBECDBFDF91CF9188
+:10BB70001F91FF90EF90DF90CF90BF90AF909F907C
+:10BB80008F907F906F905F904F9008954F925F924B
+:10BB90006F927F928F929F92AF92BF92CF92DF92DD
+:10BBA000EF92FF920F931F93CF93DF93C0EEDAE0F3
+:10BBB00020914E1230914F124091501250915112DB
+:10BBC000688179818A819B810F94ECBC4B015C0177
+:10BBD00004EE1AE020915212309153124091541207
+:10BBE00050915512F80160817181828193810F9487
+:10BBF000ECBC6B017C0120915612309157124091A0
+:10BC0000581250915912C501B4010F949BC02B01D9
+:10BC10003C0120915A1230915B1240915C1250917C
+:10BC20005D12C701B6010F949BC09B01AC01C3011B
+:10BC3000B2010F94EDBC688379838A839B83209142
+:10BC40005E1230915F124091601250916112C501F5
+:10BC5000B4010F949BC04B015C01209162123091A2
+:10BC600063124091641250916512C701B6010F949E
+:10BC70009BC09B01AC01C501B4010F94EDBCF80160
+:10BC80006083718382839383DF91CF911F910F91A2
+:10BC9000FF90EF90DF90CF90BF90AF909F908F90EC
+:10BCA0007F906F905F904F9008957F928F929F92B8
+:10BCB000AF92BF92CF92DF92EF92FF920F931F93BA
+:10BCC000CF93DF934B015C01742E81E00F948C15B0
+:10BCD000182F80E00F949215D82F0F94871580921B
+:10BCE000E80A9092E90AA092EA0AB092EB0A20E0F0
+:10BCF00030E040E752E4609160027091610280910F
+:10BD00006202909163020F94CDBD0E94D9CD0E9432
+:10BD100057CE0F948715C82F882309F481C000E0FF
+:10BD2000C12CD12C7601071509F454C020E030E075
+:10BD300040E05FE36091E80A7091E90A8091EA0AC5
+:10BD40009091EB0A0F94EDBC6093E80A7093E90AB6
+:10BD50008093EA0A9093EB0A20E030E040E752E457
+:10BD60006091600270916102809162029091630221
+:10BD70000F94CDBD0E94D9CD8092E80A9092E90A35
+:10BD8000A092EA0AB092EB0A20E030E040E753E4E8
+:10BD900060916002709161028091620290916302F1
+:10BDA0000F94CDBD0E94D9CD0E9457CE0F94871518
+:10BDB0008823B1F12091E80A3091E90A4091EA0A1A
+:10BDC0005091EB0AC701B6010F94EDBC6B017C01E9
+:10BDD0000F5FA9CF023048F4C092E80AD092E90A76
+:10BDE000E092EA0AF092EB0A14C0602F70E080E063
+:10BDF00090E00F9466BE9B01AC01C701B6010F94A1
+:10BE0000CDBD6093E80A7093E90A8093EA0A9093A3
+:10BE1000EB0A812F0F948C158D2F0F94921507C06C
+:10BE2000812F0F948C158D2F0F949215C0E08C2FBD
+:10BE3000DF91CF911F910F91FF90EF90DF90CF9006
+:10BE4000BF90AF909F908F907F9008952F923F92D8
+:10BE50004F925F926F927F928F929F92AF92BF921A
+:10BE6000CF92DF92EF92FF920F931F93CF93DF93C6
+:10BE7000CDB7DEB7A3970FB6F894DEBF0FBECDBF28
+:10BE800020E030E040E752E460915802709159029E
+:10BE900080915A0290915B020F94CDBD2B013C0121
+:10BEA000C090E00AD090E10AE090E20AF090E30A44
+:10BEB00020E030E040E051E4C701B6010F94ECBC53
+:10BEC00069837A831C0120E030E040E051E4C7013F
+:10BED000B6010F94EDBC6F83788789879A8780902D
+:10BEE000E40A9090E50AA090E60AB090E70A20E004
+:10BEF00030E040EC50E4C501B4010F94ECBC6B831E
+:10BF00007C838D839E8320E030E040EC50E4C501CB
+:10BF1000B4010F94EDBC6B877C878D879E8720E0F2
+:10BF200030E0A90169817A81C1010F94C6BD87FF04
+:10BF300004C019821A82212C312C20E030E04FE716
+:10BF400053E46F81788589859A850F94C9BF181647
+:10BF500034F41F8218862FE7298733E43A8720E0DC
+:10BF600030E040E850EC6B817C818D819E810F94A4
+:10BF7000C6BD87FF08C080E090E0A0E8B0EC8B83EE
+:10BF80009C83AD83BE8320E030E042E553E46B85C3
+:10BF90007C858D859E850F94C9BF181644F420E0DA
+:10BFA00030E042E553E42B873C874D875E872B8149
+:10BFB0003C814D815E816B857C858D859E850F944E
+:10BFC000ECBC6B8B7C8B8D8B9E8B0F94B3BD0F94D5
+:10BFD00035BE4B016F8B80E00F948C15E090E80A22
+:10BFE000F090E90A0091EA0A1091EB0A630152010C
+:10BFF0002B813C814D815E8169817A81C1010E94E2
+:10C0000089CD0F94741581E00F94921531E038A317
+:10C010009F89892F90E0A0E0B0E08F87988BA98B53
+:10C02000BA8BC401992701979C01442737FD40959D
+:10C03000542F288F398F4A8F5B8F20E030E040E209
+:10C0400051EC6091E80A7091E90A8091EA0A9091B6
+:10C05000EB0A0F94C9BF181674F48B819C81AD81D3
+:10C06000BE818093E40A9093E50AA093E60AB09318
+:10C07000E70A1BA27AC00E9415CE1F86C401992729
+:10C0800001979C01442737FD4095542F288F398F05
+:10C090004A8F5B8FA7C16F85788989899A890F94A8
+:10C0A00066BE9B01AC016DEC7CEC8CE49EE30F94CE
+:10C0B000CDBD9B01AC016091E80A7091E90A8091C5
+:10C0C000EA0A9091EB0A0F94ECBC6093E80A709333
+:10C0D000E90A8093EA0A9093EB0A2091E40A3091EE
+:10C0E000E50A4091E60A5091E70AA8A1AA2309F4BB
+:10C0F00042C0BF81A885E985E9A3FA8563015201A1
+:10C100007B018C016B2F7A2F89A19F2F0E9489CDF3
+:10C11000F8A121E0F227F8A30F9487158111ABCF86
+:10C12000688D798D8A8D9B8D0F9468BE9B01AC01C3
+:10C130006B897C898D899E890F94CDBD9B01AC0153
+:10C140006091E40A7091E50A8091E60A9091E70A0D
+:10C150000F94EDBC6093E40A7093E50A8093E60ABD
+:10C160009093E70A3BA13F5F3BA34BA15F89451733
+:10C1700008F491CF05C0B981AA8129A2F32DBECFC1
+:10C180001BA24BA15F89451708F057CF6F857889AF
+:10C1900089899A890F9466BE9B01AC016DEC7CEC99
+:10C1A0008CE49EE30F94CDBD9B01AC016091E80A45
+:10C1B0007091E90A8091EA0A9091EB0A0F94ECBC25
+:10C1C0006093E80A7093E90A8093EA0A9093EB0A75
+:10C1D0002091E40A3091E50A4091E60A5091E70A7D
+:10C1E000A8A1AA2331F0BF81A885E985E9A3FA8532
+:10C1F00004C0B981AA8129A2F32D630152017B01F8
+:10C200008C016B2F7A2F89A19F2F0E9489CDF8A1D5
+:10C2100021E0F227F8A30F94871581112CCF688DA8
+:10C22000798D8A8D9B8D0F9468BE9B01AC016B89C3
+:10C230007C898D899E890F94CDBD9B01AC01609155
+:10C24000E40A7091E50A8091E60A9091E70A0F945A
+:10C25000ECBC6093E40A7093E50A8093E60A90933D
+:10C26000E70A3BA13F5F3BA38CCF2091E40A3091CA
+:10C27000E50A4091E60A5091E70AAA2009F4D2C0E3
+:10C28000BF81A885C984BA84830172016B2F7A2F7C
+:10C290008C2D9B2D0E94ADCD0F9487158111C7C0A9
+:10C2A000688D798D8A8D9B8D0F9468BE9B01AC0142
+:10C2B0006B897C898D899E890F94CDBD9B01AC01D2
+:10C2C0006091E40A7091E50A8091E60A9091E70A8C
+:10C2D0000F94EDBC6093E40A7093E50A8093E60A3C
+:10C2E0009093E70AD39431E0A3264F89D41608F43B
+:10C2F000BCCFD12C0E9415CEDD2079F18090E40ACC
+:10C300009090E50AA090E60AB090E70A80E00F94CA
+:10C3100092158B859C85AD85BE858093E40A9093AC
+:10C32000E50AA093E60AB093E70A830172019C0133
+:10C33000AD0169817A81C1010E94ADCD81E00F9488
+:10C34000921591E09AA3C12CFF89CF1608F472C010
+:10C35000D12C0E9415CED110B3C02F852F5F2F870F
+:10C36000233009F4DCC18F858823E1F12AE037ED21
+:10C3700043EA5CE36091E80A7091E90A8091EA0A75
+:10C380009091EB0A0F94ECBC6093E80A7093E90A71
+:10C390008093EA0A9093EB0A20E030E040E752E411
+:10C3A00060916002709161028091620290916302DB
+:10C3B0000F94CDBD5B016C012091E40A3091E50A38
+:10C3C0004091E60A5091E70A6091E00A7091E10A13
+:10C3D0008091E20A9091E30AE12CF12C00EA10E44A
+:10C3E0000E9489CD80E00F948C1580E00F94921507
+:10C3F0002B813C814D815E812093E40A3093E50AD4
+:10C400004093E60A5093E70A8301720169817A81B9
+:10C41000C1010E94ADCD81E00F949215AA24A3948E
+:10C42000D12C63CFB981AA81C22CB32C2DCFDD24AE
+:10C43000D39460CF2091E40A3091E50A4091E60A56
+:10C440005091E70AAAA1AA2329F0BF81A885E9850E
+:10C45000FA8503C0B981AA81F101830172016B2FB2
+:10C460007A2FCF010E94ADCD0F948715811171CF26
+:10C47000688D798D8A8D9B8D0F9468BE9B01AC0170
+:10C480006B897C898D899E890F94CDBD9B01AC0100
+:10C490006091E40A7091E50A8091E60A9091E70ABA
+:10C4A0000F94ECBC6093E40A7093E50A8093E60A6B
+:10C4B0009093E70AC394BAA1E1E0BE27BAA344CFA0
+:10C4C0002091E40A3091E50A4091E60A5091E70A8A
+:10C4D000C501B4010F94EDBC20E030E040E05FE323
+:10C4E0000F949BC06093E40A7093E50A8093E60A78
+:10C4F0009093E70A80E00F9492152091E40A30911E
+:10C50000E50A4091E60A5091E70A830172016981C8
+:10C510007A81C1010E94ADCD81E00F9492152091E6
+:10C52000E40A3091E50A4091E60A5091E70A6F81EA
+:10C53000788589859A850E94ADCD0E9415CE0F948D
+:10C540008715882309F409CF8090E00A9090E10ACA
+:10C55000A090E20AB090E30A80E00F949215209137
+:10C56000E40A3091E50A4091E60A5091E70A6F81AA
+:10C57000788589859A850E94ADCD81E00F949215CA
+:10C580002091E40A3091E50A4091E60A5091E70AC9
+:10C5900069817A81C1010E94ADCD0E9415CE0F94B0
+:10C5A0008715882309F4D9CE2091E00A3091E10A59
+:10C5B0004091E20A5091E30A80E02C8F3D8F4E8F2C
+:10C5C0005F8F0F9492152C8D3D8D4E8D5F8DC50123
+:10C5D000B4010F94EDBC20E030E040E05FE30F9445
+:10C5E0009BC06093E00A7093E10A8093E20A909303
+:10C5F000E30A2091E40A3091E50A4091E60A50915D
+:10C60000E70A0E94ADCD80E00F9492156091E00A98
+:10C610007091E10A8091E20A9091E30A2B813C81BA
+:10C620004D815E810E94ADCD81E00F9492156091A5
+:10C63000E00A7091E10A8091E20A9091E30A2B8569
+:10C640003C854D855E850E94ADCD0E9415CE0F9430
+:10C650008715882309F481CE8090E40A9090E50A3A
+:10C66000A090E60AB090E70A80E00F9492156091DE
+:10C67000E00A7091E10A8091E20A9091E30A2B8529
+:10C680003C854D855E850E94ADCD81E00F9492156D
+:10C690006091E00A7091E10A8091E20A9091E30AC8
+:10C6A0002B813C814D815E810E94ADCD0E9415CED3
+:10C6B0000F948715882309F450CE2091E40A309115
+:10C6C000E50A4091E60A5091E70A80E02C8F3D8F01
+:10C6D0004E8F5F8F0F9492152C8D3D8D4E8D5F8DFB
+:10C6E000C501B4010F94EDBC20E030E040E05FE311
+:10C6F0000F949BC09B01AC016093E40A7093E50A20
+:10C700008093E60A9093E70A6091E00A7091E10A4B
+:10C710008091E20A9091E30A0E94ADCD01C0D12C34
+:10C7200080E00F9492158D2DA3960FB6F894DEBF7E
+:10C730000FBECDBFDF91CF911F910F91FF90EF9072
+:10C74000DF90CF90BF90AF909F908F907F906F9031
+:10C750005F904F903F902F9008952F923F924F926D
+:10C760005F926F927F928F929F92AF92BF92CF9281
+:10C77000DF92EF92FF920F931F93CF93DF93CDB78A
+:10C78000DEB769970FB6F894DEBF0FBECDBF80E06D
+:10C790000F948C15898F80E00F949215382E20E02D
+:10C7A00030E040E752E46091580270915902809164
+:10C7B0005A0290915B020F94CDBD698B7A8B8B8B63
+:10C7C0009C8B4090E00A5090E10A6090E20A7090E1
+:10C7D000E30A8090E40A9090E50AA090E60AB090FF
+:10C7E000E70A212C19861A861B861C861D821E824A
+:10C7F0001F82188681E02816B9F0281660F092E0B2
+:10C8000029122CC024EF3DEF44EB50E4C301B201E8
+:10C810000F94EDBC12C024EF3DEF44EB50E4C30194
+:10C82000B2010F94ECBC09C024EF3DEF44EB50E49F
+:10C83000C301B2010F94EDBC19C06093AB0A7093B1
+:10C84000AC0A8093AD0A9093AE0A24EF3DEF44EB1F
+:10C8500050E4C501B4010F94ECBC18C024EF3DEFC7
+:10C8600044EB50E4C301B2010F94ECBC6093AB0AFB
+:10C870007093AC0A8093AD0A9093AE0A24EF3DEF1B
+:10C8800044EB50E4C501B4010F94EDBC6093AF0AD2
+:10C890007093B00A8093B10A9093B20A8091AB0A68
+:10C8A0009091AC0AA091AD0AB091AE0A8D8B9E8B8F
+:10C8B000AF8BB88FA3019201BC01CD010F94ECBCEA
+:10C8C0006D877E878F87988BA50194016091AF0A51
+:10C8D0007091B00A8091B10A9091B20A0F94ECBCA9
+:10C8E00069837A838B839C832D853E854F85588908
+:10C8F000CA01B9010F949BC06B017C0129813A8167
+:10C900004B815C81CA01B9010F949BC09B01AC01B2
+:10C91000C701B6010F94EDBC0F9454C16B017C01AB
+:10C9200020E030E0A9016D897E898F89988D0F9470
+:10C93000C6BD87FF0FC01092AB0A1092AC0A1092CE
+:10C94000AD0A1092AE0AA70196016D817E818F819A
+:10C95000988522C020E030E04FE753E46D897E895E
+:10C960008F89988D0F94C9BF181664F580E090E008
+:10C97000AFE7B3E48093AB0A9093AC0AA093AD0AFF
+:10C98000B093AE0A2D813E814F815885BC01CD0107
+:10C990000F94ECBCA70196010F94CDBD29813A817B
+:10C9A0004B815C810F949BC09B01AC01C501B4011C
+:10C9B0000F94EDBC6093AF0A7093B00A8093B10AF4
+:10C9C0009093B20A8091AF0A9091B00AA091B10AF7
+:10C9D000B091B20A89839A83AB83BC8320E030E0B4
+:10C9E00040E850ECBC01CD010F94C6BD87FF27C0C5
+:10C9F00020E030E040E850E469857A858B859C85AD
+:10CA00000F94EDBCA70196010F94CDBD2D853E85F9
+:10CA10004F8558890F949BC09B01AC01C301B201A3
+:10CA20000F94EDBC6093AB0A7093AC0A8093AD0A8F
+:10CA30009093AE0A80E090E0A0E8B0EC32C020E035
+:10CA400030E042E553E469817A818B819C810F94C7
+:10CA5000C9BF181674F529853A854B855C8560E059
+:10CA600070E082E593E40F94ECBCA70196010F946B
+:10CA7000CDBD2D853E854F8558890F949BC09B0168
+:10CA8000AC01C301B2010F94EDBC6093AB0A70938B
+:10CA9000AC0A8093AD0A9093AE0A80E090E0A2E5E4
+:10CAA000B3E48093AF0A9093B00AA093B10AB09315
+:10CAB000B20A80E00F948C152091AF0A3091B00A31
+:10CAC0004091B10A5091B20A6091AB0A7091AC0AE0
+:10CAD0008091AD0A9091AE0AE988FA880B891C8989
+:10CAE0000E94ADCD81E00F948C15E988FA880B89FE
+:10CAF0001C89A5019401C301B2010E94ADCD0E9421
+:10CB000015CE2091E00A3091E10A4091E20A50915D
+:10CB1000E30A6D817E818F8198850F94EDBC6D83D2
+:10CB20007E838F8398872091E40A3091E50A4091B3
+:10CB3000E60A5091E70A69857A858B859C850F9472
+:10CB4000EDBC69877A878B879C87239494E02912B0
+:10CB500051CE20E030E040E85EE36D817E818F8140
+:10CB600098850F949BC06093E00A7093E10A8093CC
+:10CB7000E20A9093E30A20E030E040E85EE3698552
+:10CB80007A858B859C850F949BC06093E40A709393
+:10CB9000E50A8093E60A9093E70A80E00F948C15EB
+:10CBA0002091E40A3091E50A4091E60A5091E70AA3
+:10CBB0006091E00A7091E10A8091E20A9091E30AA3
+:10CBC000E988FA880B891C890E94ADCD898D0F9464
+:10CBD0008C15832D0F94921580E069960FB6F8940A
+:10CBE000DEBF0FBECDBFDF91CF911F910F91FF90A0
+:10CBF000EF90DF90CF90BF90AF909F908F907F90FD
+:10CC00006F905F904F903F902F9008953F924F927A
+:10CC10005F926F927F928F929F92AF92BF92CF92CC
+:10CC2000DF92EF92FF920F931F93CF93DF93CDB7D5
+:10CC3000DEB72C970FB6F894DEBF0FBECDBFD82E4F
+:10CC40008091E00A9091E10AA091E20AB091E30A92
+:10CC500089839A83AB83BC838091E40A9091E50A2F
+:10CC6000A091E60AB091E70A8D839E83AF83B887CF
+:10CC700080E00F948C1520E030E040E051E46981C1
+:10CC80007A818B819C810F94ECBC4B015C0120E08C
+:10CC900030E040E051E469817A818B819C810F947E
+:10CCA000EDBC2B013C0120E030E0A901C501B4013D
+:10CCB0000F94C6BD87FF03C0812C912C540120E046
+:10CCC00030E04FE753E4C301B2010F94C9BF181617
+:10CCD00034F4412C512CAFE76A2EA3E47A2E80E085
+:10CCE0000F94921520E030E040E752E46091580242
+:10CCF0007091590280915A0290915B020F94CDBDC0
+:10CD00002091E40A3091E50A4091E60A5091E70A41
+:10CD10007B018C01C501B4010E94ADCD81E00F946F
+:10CD2000921520E030E040E752E4609158027091A3
+:10CD3000590280915A0290915B020F94CDBD2091CF
+:10CD4000E40A3091E50A4091E60A5091E70A7B0136
+:10CD50008C01C301B2010E94ADCD0E9415CE0F948B
+:10CD60008715882309F474C08091E00A9091E10A44
+:10CD7000A091E20AB091E30A89879A87AB87BC87C2
+:10CD800080E00F94921520E030E040E752E460919B
+:10CD900058027091590280915A0290915B020F944F
+:10CDA000CDBD2091E40A3091E50A4091E60A509108
+:10CDB000E70A7B018C01C301B2010E94ADCD81E085
+:10CDC0000F94921520E030E040E752E46091580261
+:10CDD0007091590280915A0290915B020F94CDBDDF
+:10CDE0002091E40A3091E50A4091E60A5091E70A61
+:10CDF0007B018C01C501B4010E94ADCD0E9415CE0E
+:10CE00000F948715882321F18090E00A9090E10A21
+:10CE1000A090E20AB090E30A29853A854B855C85AB
+:10CE2000C501B4010F94ECBC2B013C0120E030E0C3
+:10CE300040E050E40F94C6BD87FF17C020E030E00B
+:10CE400040E85FE3C301B2010F94C6BD87FF0FC086
+:10CE500089819A81AB81BC818093E00A9093E10A39
+:10CE6000A093E20AB093E30ACEC1312C02C033246E
+:10CE7000339480E00F949215A501940169857A8519
+:10CE80008B859C850F94EDBC20E030E040E05FE3B3
+:10CE90000F949BC04B015C016093E00A7093E10A20
+:10CEA0008093E20A9093E30A20E030E040E752E406
+:10CEB000609158027091590280915A0290915B02E0
+:10CEC0000F94CDBD2091E40A3091E50A4091E60A25
+:10CED0005091E70A7B018C01C501B4010E94ADCDE0
+:10CEE00020E030E040E051E46D817E818F819885C3
+:10CEF0000F94ECBC2B013C0120E030E040E051E419
+:10CF00006D817E818F8198850F94EDBC69837A83D2
+:10CF10008B839C8320E030E040E850ECC301B201F9
+:10CF20000F94C6BD87FF06C0412C512CF0E86F2E30
+:10CF3000F0EC7F2E20E030E042E553E469817A8115
+:10CF40008B819C810F94C9BF181644F480E090E057
+:10CF5000A2E5B3E489839A83AB83BC8380E00F941A
+:10CF6000921520E030E040E752E460915802709161
+:10CF7000590280915A0290915B020F94CDBD80902E
+:10CF8000E00A9090E10AA090E20AB090E30A7B01E7
+:10CF90008C01A3019201C501B4010E94ADCDDD2039
+:10CFA00009F452C020E030E040E752E460916002B2
+:10CFB0007091610280916202909163020F94CDBDE5
+:10CFC0005B016C0120E030E040EC5FE36091E80A37
+:10CFD0007091E90A8091EA0A9091EB0A0F94EDBCF6
+:10CFE0007B018C016091E00A7091E10A8091E20A74
+:10CFF0009091E30AA30192010E9489CD20E030E0E4
+:10D0000040E752E460916002709161028091620297
+:10D01000909163020F94CDBD5B016C01E090E80A32
+:10D02000F090E90A0091EA0A1091EB0A6091E00A97
+:10D030007091E10A8091E20A9091E30AA3019201C2
+:10D040000E9489CD1C9928C081E00F94921520E0A0
+:10D0500030E040E752E460915802709159028091AB
+:10D060005A0290915B020F94CDBD7B018C016091BF
+:10D07000E00A7091E10A8091E20A9091E30A298125
+:10D080003A814B815C810E94ADCD0E9415CE0F94F8
+:10D090008715882309F470C08090E40A9090E50A0F
+:10D0A000A090E60AB090E70A80E00F94921520E085
+:10D0B00030E040E752E4609158027091590280914B
+:10D0C0005A0290915B020F94CDBD7B018C0160915F
+:10D0D000E00A7091E10A8091E20A9091E30A2981C5
+:10D0E0003A814B815C810E94ADCD81E00F94921515
+:10D0F00020E030E040E752E460915802709159021C
+:10D1000080915A0290915B020F94CDBD7B018C01FE
+:10D110006091E00A7091E10A8091E20A9091E30A3D
+:10D12000A30192010E94ADCD0E9415CE0F948715E8
+:10D13000882311F14090E40A5090E50A6090E60AD5
+:10D140007090E70AA5019401C301B2010F94ECBCF1
+:10D150006B017C0120E030E040E050E40F94C6BD5C
+:10D1600087FF19C020E030E040E85FE3C701B60167
+:10D170000F94C6BD87FF0DC08D819E81AF81B8859C
+:10D180008093E40A9093E50AA093E60AB093E70A35
+:10D190003AC03324339480E00F949215A301920196
+:10D1A000C501B4010F94EDBC20E030E040E05FE346
+:10D1B0000F949BC04B015C016093E40A7093E50AF5
+:10D1C0008093E60A9093E70A20E030E040E752E4DB
+:10D1D000609158027091590280915A0290915B02BD
+:10D1E0000F94CDBD7B018C016091E00A7091E10A42
+:10D1F0008091E20A9091E30AA50194010E94ADCDCD
+:10D2000081E0832526C080E00F94921520E030E075
+:10D2100040E752E4609158027091590280915A029D
+:10D2200090915B020F94CDBD7B018C012091E40AAB
+:10D230003091E50A4091E60A5091E70A6091E00AD0
+:10D240007091E10A8091E20A9091E30A0E94ADCDCB
+:10D2500080E02C960FB6F894DEBF0FBECDBFDF91F5
+:10D26000CF911F910F91FF90EF90DF90CF90BF90E3
+:10D27000AF909F908F907F906F905F904F903F9076
+:10D2800008952F923F924F925F926F927F928F926A
+:10D290009F92AF92BF92CF92DF92EF92FF920F9345
+:10D2A0001F93CF93DF93CDB7DEB7A5970FB6F89452
+:10D2B000DEBF0FBECDBF4090E00A5090E10A609003
+:10D2C000E20A7090E30A8091E40A9091E50AA09145
+:10D2D000E60AB091E70A8B8F9C8FAD8FBE8F20E05E
+:10D2E00030E040E850E4C301B2010F94ECBC6E871B
+:10D2F0007F87888B998B20E030E040E850E4C301C1
+:10D30000B2010F94EDBC6E8B7F8B888F998F20E0DC
+:10D3100030E040E850E46B8D7C8D8D8D9E8D0F94B8
+:10D32000ECBC6D837E838F83988720E030E040E8FB
+:10D3300050E46B8D7C8D8D8D9E8D0F94EDBC4B01DB
+:10D340005C0120E030E0A9016E857F85888999899C
+:10D350000F94C6BD87FF04C01E861F86188A198ACF
+:10D3600020E030E04FE753E46E897F89888D998D06
+:10D370000F94C9BF181644F480E090E0AFE7B3E41F
+:10D380008E8B9F8BA88FB98F20E030E040E850EC67
+:10D390006D817E818F8198850F94C6BD87FF06C001
+:10D3A0001D821E8290E89F83A0ECA88720E030E0D9
+:10D3B00042E553E4C501B4010F94C9BF181634F413
+:10D3C000812C912CB2E5AB2EB3E4BB2E3D802E8098
+:10D3D000BF81B8A3E885EF8F1A8A1B8A1C8A1D8A31
+:10D3E00019821A821B821C82A5019401632D722D61
+:10D3F00088A19F8D0F94C6BD87FFECC080E00F947D
+:10D40000921520E030E040E752E4609158027091BC
+:10D41000590280915A0290915B020F94CDBD7B011D
+:10D420008C01232D322D48A15F8D6E857F858889E3
+:10D4300099890E94ADCD81E00F94921520E030E0F3
+:10D4400040E752E4609158027091590280915A026B
+:10D4500090915B020F94CDBD7B018C01232D322D69
+:10D4600048A15F8D6E897F89888D998D0E94ADCD91
+:10D470000E9415CE0F948715882309F49CC08091D3
+:10D48000E00A9091E10AA091E20AB091E30A89874B
+:10D490009A87AB87BC8780E00F94921520E030E03C
+:10D4A00040E752E4609158027091590280915A020B
+:10D4B00090915B020F94CDBD7B018C01232D322D09
+:10D4C00048A15F8D6E897F89888D998D0E94ADCD31
+:10D4D00081E00F94921520E030E040E752E4609143
+:10D4E00058027091590280915A0290915B020F94F8
+:10D4F000CDBD7B018C01232D322D48A15F8D6E8522
+:10D500007F85888999890E94ADCD0E9415CE0F94A0
+:10D510008715882309F44FC0C090E00AD090E10A33
+:10D52000E090E20AF090E30A29853A854B855C8514
+:10D53000C701B6010F94ECBC162F7D878A8F092F87
+:10D5400029813A814B815C810F94C9BF1816CCF4B4
+:10D55000A701960169857A858B859C850F94EDBC22
+:10D5600020E030E040E05FE30F949BC06A8B7B8B50
+:10D570008C8B9D8B19839D859A83AA8DAB830C839D
+:10D580001AC020E030E0A90169817A818B819C81F9
+:10D590000F94C9BF18167CF42DEC3CEC4CEC5DE309
+:10D5A000632D722D88A19F8D0F94ECBC6D837E83BB
+:10D5B0008F8398870FC02DEC3CEC4CEC5DE3632D22
+:10D5C000722D88A19F8D0F94EDBC362E272E88A337
+:10D5D0009F8F0ACF20E030E0A90169817A818B8199
+:10D5E0009C810F94C6BD811109C04092E00A5092FF
+:10D5F000E10A6092E20A7092E30AE6C280E00F94C8
+:10D60000921520E030E040E752E4609158027091BA
+:10D61000590280915A0290915B020F94CDBD6B012B
+:10D620007C0120E030E040E051E46D817E818F811B
+:10D6300098850F94EDBC9B01AC01870176016A8946
+:10D640007B898C899D890E94ADCD81E00F949215D4
+:10D6500020E030E040E752E46091580270915902B6
+:10D6600080915A0290915B020F94CDBD6B017C01B9
+:10D6700020E030E040E051E46D817E818F8198852B
+:10D680000F94ECBC8B015C0120E030E040E850ECF2
+:10D690000F94C9BF18162CF080E090E070E860ECA1
+:10D6A00003C0C8017A2D6B2D870176019C01472F9D
+:10D6B000562F6A897B898C899D890E94ADCD0E94F5
+:10D6C00015CE0F948715882309F47EC29091E40A41
+:10D6D0009A8FA091E50AAF8FB091E60AB8A3E091C6
+:10D6E000E70AE9A32D813E814F815885692F7A2F62
+:10D6F0008B2F9E2F0F94C6BD18160CF065C27A8C26
+:10D700006F8C58A049A01AA21BA21CA21DA21B82AA
+:10D710001C8219861D862D813E814F815885672D7B
+:10D72000762D852D942D0F94C9BF87FDE2C080E032
+:10D730000F94921520E030E040E752E460915802E7
+:10D740007091590280915A0290915B020F94CDBD65
+:10D750007B018C01272D362D452D542D6E857F851F
+:10D76000888999890E94ADCD81E00F94921520E0BF
+:10D7700030E040E752E46091580270915902809184
+:10D780005A0290915B020F94CDBD7B018C01272D35
+:10D79000362D452D542D6E897F89888D998D0E9457
+:10D7A000ADCD0E9415CE0F948715882309F492C041
+:10D7B0008090E00A9090E10AA090E20AB090E30A1B
+:10D7C00080E00F94921520E030E040E752E4609151
+:10D7D00058027091590280915A0290915B020F9405
+:10D7E000CDBD7B018C01272D362D452D542D6E8905
+:10D7F0007F89888D998D0E94ADCD81E00F9492151F
+:10D8000020E030E040E752E4609158027091590204
+:10D8100080915A0290915B020F94CDBD7B018C01E7
+:10D82000272D362D452D542D6E857F858889998924
+:10D830000E94ADCD0E9415CE0F948715882309F460
+:10D8400049C0C090E00AD090E10AE090E20AF0906E
+:10D85000E30AA5019401C701B6010F94ECBC162F91
+:10D86000272E382E092F2B813C8149855D850F9409
+:10D87000C9BF1816ACF4A7019601C501B4010F94F5
+:10D88000EDBC20E030E040E05FE30F949BC06AA372
+:10D890007BA38CA39DA31B832C8239860D871AC082
+:10D8A00020E030E0A9016B817C8189859D850F9402
+:10D8B000C9BF18167CF42DEC3CEC4CEC5DE3672DF5
+:10D8C000762D852D942D0F94EDBC6A8F7F8F88A3C4
+:10D8D00099A30FC02DEC3CEC4CEC5DE3672D762D4D
+:10D8E000852D942D0F94ECBC762E672E582E492E44
+:10D8F00012CF20E030E0A9016B817C8189859D8574
+:10D900000F94C6BD882309F4F3C02A8D3F8D48A12A
+:10D9100059A16D817E818F8198850F94EDBC20E0A7
+:10D9200030E040E05FE30F949BC069837A831C0181
+:10D930009AA19A8BABA1AB8BBCA1BC8BEDA1ED8B5B
+:10D940002D813E814F815885672D762D852D942D13
+:10D950000F94C9BF87FDD2C080E00F94921520E0DC
+:10D9600030E040E752E46091580270915902809192
+:10D970005A0290915B020F94CDBD7B018C01272D43
+:10D98000362D452D542D6E857F85888999890E9475
+:10D99000ADCD81E00F94921520E030E040E752E4F5
+:10D9A000609158027091590280915A0290915B02E5
+:10D9B0000F94CDBD7B018C01272D362D452D542D87
+:10D9C0006E897F89888D998D0E94ADCD0E9415CE7C
+:10D9D0000F948715882309F47CC08090E00A90900A
+:10D9E000E10AA090E20AB090E30A80E00F94921559
+:10D9F00020E030E040E752E4609158027091590213
+:10DA000080915A0290915B020F94CDBD7B018C01F5
+:10DA1000272D362D452D542D6E897F89888D998D22
+:10DA20000E94ADCD81E00F94921520E030E040E7F8
+:10DA300052E4609158027091590280915A0290917B
+:10DA40005B020F94CDBD7B018C01272D362D452D1A
+:10DA5000542D6E857F85888999890E94ADCD0E945D
+:10DA600015CE0F9487158823A1F1C090E00AD090BD
+:10DA7000E10AE090E20AF090E30AA5019401C701EF
+:10DA8000B6010F94ECBC162F7BA38AA3092F2B8120
+:10DA90003C8149855D850F94C9BF1816D4F4A70150
+:10DAA0009601C501B4010F94EDBC20E030E040E0E8
+:10DAB0005FE30F949BC06A8B7B8B8C8B9D8B7982F1
+:10DAC0006A82252C342C1B83FBA1FC838AA18987C5
+:10DAD0000D872DEC3CEC4CEC5DE3672D762D852D10
+:10DAE000942D0F94ECBC762E672E582E492E28CFFD
+:10DAF0009D819983AE81AA832F80388480E00F9422
+:10DB0000921520E030E040E752E4609158027091B5
+:10DB1000590280915A0290915B020F94CDBD6B0126
+:10DB20007C0120E030E040E051E469817A81C1016C
+:10DB30000F94EDBC9B01AC01870176016A897B895A
+:10DB40008C899D890E94ADCD81E00F94921520E0D3
+:10DB500030E040E752E460915802709159028091A0
+:10DB60005A0290915B020F94CDBD6B017C0120E0C5
+:10DB700030E040E051E469817A81C1010F94ECBC4E
+:10DB80008B015C0120E030E040E850EC0F94C9BF0D
+:10DB900018162CF080E090E070E860EC03C0C8013B
+:10DBA0007A2D6B2D870176019C01472F562F6A89AC
+:10DBB0007B898C899D890E94ADCD0E9415CE0F94E2
+:10DBC00087158E8B81110DC08B8D9C8DAD8DBE8D7B
+:10DBD0008093E40A9093E50AA093E60AB093E70ADB
+:10DBE0001EC1C090E40AD090E50AE090E60AF090E9
+:10DBF000E70A20E030E040E05FE36B817C818985CB
+:10DC00009D850F949BC06E877F87888B998B20E0C2
+:10DC100030E040E850E4C701B6010F94EDBC2E851A
+:10DC20003F85488959890F94C6BD87FF6CC02981FB
+:10DC30003A81A101C701B6010F94C6BD87FDA2C0FC
+:10DC400020E030E040E85FE36B817C8189859D8541
+:10DC50000F94C6BD87FD96C029813A81A101C701F5
+:10DC6000B6010F94ECBC4B015C012B813C814985D2
+:10DC70005D856B817C8189859D850F949BC02B017F
+:10DC80003C0120E030E040E051E4C501B4010F94D4
+:10DC90009BC09B01AC01C301B2010F94CDBD2B0110
+:10DCA0003C0120E030E040E05FE3C501B4010F94A7
+:10DCB0009BC09B01AC01C301B2010F94EDBC4B01B1
+:10DCC0005C012DEC3CEC4CEC5FE30F94C6BD87FD92
+:10DCD00059C0A50194016E857F85888999890F9423
+:10DCE000EDBC20E030E040E05FE30F949BC09B017F
+:10DCF000AC01C701B6010F94ECBC69837A831C01A7
+:10DD0000BB24B39440C0BB24B39420E030E040E097
+:10DD100050E46A897B898C899D890F94C9BF87FDEE
+:10DD2000B12C23E333E343E750EC6D817E818F8197
+:10DD300098850F94C9BF181634F520E030E040E014
+:10DD40005FE369817A81C1010F949BC06B017C0103
+:10DD50002A8D3F8D48A159A16D817E818F81988543
+:10DD60000F94EDBC20E030E040E85EE30F949BC0F0
+:10DD70009B01AC01C701B6010F94EDBC69837A83A6
+:10DD80001C0101C0B12C80E00F9492158A899B89F7
+:10DD9000AC89BD898093E00A9093E10AA093E20ADE
+:10DDA000B093E30A89819A81D1018093E40A909328
+:10DDB000E50AA093E60AB093E70A20E030E040E7E6
+:10DDC00052E4609158027091590280915A029091E8
+:10DDD0005B020F94CDBD6B017C0120E030E040E898
+:10DDE00050EC69817A81C1010F94C6BD87FF05C0DF
+:10DDF00070E060E090E880EC04C079816A81922D47
+:10DE0000832D87017601272F362F492F582F6A89B6
+:10DE10007B898C899D890E94ADCDB11042C080E084
+:10DE20000F94921520E030E040E850EC6091E40A55
+:10DE30007091E50A8091E60A9091E70A0F94C6BDB9
+:10DE400087FF0CC080E090E0A0E8B0EC8093E40A8B
+:10DE50009093E50AA093E60AB093E70A20E030E049
+:10DE600040E752E4609158027091590280915A0241
+:10DE700090915B020F94CDBD7B018C012091E40A4F
+:10DE80003091E50A4091E60A5091E70A6091E00A74
+:10DE90007091E10A8091E20A9091E30A0E94ADCD6F
+:10DEA0001E8A8E89A5960FB6F894DEBF0FBECDBF31
+:10DEB000DF91CF911F910F91FF90EF90DF90CF9066
+:10DEC000BF90AF909F908F907F906F905F904F909A
+:10DED0003F902F9008952F923F924F925F926F92B2
+:10DEE0007F928F929F92AF92BF92CF92DF92EF92EA
+:10DEF000FF920F931F93CF93DF93CDB7DEB7679752
+:10DF00000FB6F894DEBF0FBECDBF8C877F836E83C4
+:10DF10000E94AC5184ECE8E7F2E1DF011D928A95A2
+:10DF2000E9F7E12CF12CEC85FF27E7FDF095FE8762
+:10DF3000ED87EFE1F4E48491882341F09091C000F3
+:10DF400095FFFCCF8093C6003196F5CF1701FFEF08
+:10DF50002F1A3F0A4AE050E0B1018EE799E00E9493
+:10DF60004942E091300BF0E0EE0FFF1FE855FD4B0A
+:10DF700085919491BE016F5F7F4F0F94109A8981B4
+:10DF8000843010F083E08983B701882777FD80957E
+:10DF9000982F0F9468BE6A837B838C839D832DECBE
+:10DFA0003CEC4CE45EE30F949BC02AE939E949E973
+:10DFB0005EE30F949BC0688779878A879B8720E000
+:10DFC00030E040EA50E40F94EDBC6093E80A7093AF
+:10DFD000E90A8093EA0A9093EB0A38E7432E32E18C
+:10DFE000532E40EC642E45E4742E00E010E0EB8AE2
+:10DFF000C101AA2797FDA095BA2F8C8B9D8BAE8B64
+:10E00000BF8B0E94AC510F5F1F4FA801698180E058
+:10E010000F947150E091300BF0E0EE0FFF1FEC55C4
+:10E02000FD4B859194910F9477679B89992389F093
+:10E03000E091300BF0E0EE0FFF1FE455FD4B4591F2
+:10E04000549169816F5F80E00F94507DC1010F94FE
+:10E050006A5020E030E040E752E460916002709145
+:10E06000610280916202909163020F94CDBD0E9483
+:10E07000D9CDF30185919591A591B4918093E00A52
+:10E080009093E10AA093E20AB093E30AF301349675
+:10E0900085919591A591B4918093E40A9093E50AB6
+:10E0A000A093E60AB093E70A20E030E040E752E4AC
+:10E0B000609158027091590280915A0290915B02CE
+:10E0C0000F94CDBD0E94D9CD8D859E850E9426DFFF
+:10E0D000882309F4AAC1C80101970297D0F520E06E
+:10E0E00030E043E060E070E080E291EC0E9455DEB9
+:10E0F00084E0F82E8D859E85C4D881112AC0FA94BB
+:10E1000009F493C12DEC3CEC4CEC5CE36091E80A23
+:10E110007091E90A8091EA0A9091EB0A0F94ECBCA5
+:10E120006093E80A7093E90A8093EA0A9093EB0AF5
+:10E1300080E00F948C1580E00F949215609160023E
+:10E140007091610280916202909163020E94D9CD28
+:10E15000D1CF6C897D898E899F890F9468BE6B01B0
+:10E160007C01D2012D913D914D915C916A817B8121
+:10E170008C819D810F949BC0A70196010F94CDBD0A
+:10E180004B015C01A70196016091E00A7091E10AE0
+:10E190008091E20A9091E30A0F94CDBD9B01AC01FE
+:10E1A000C501B4010F94EDBCF201608371838283D9
+:10E1B00093838090E40A9090E50AA090E60AB090DC
+:10E1C000E70A24813581468157816A817B818C8170
+:10E1D0009D810F949BC0A70196010F94CDBD6F87C1
+:10E1E000788B898B9A8BA7019601C501B4010F9496
+:10E1F000CDBD9B01AC016F85788989899A890F947F
+:10E20000EDBCD20114966D937D938D939C931797DB
+:10E2100020E030E040E850ECC501B4010F94C6BDE9
+:10E2200087FF0CC080E090E0A0E8B0EC8093E40AA7
+:10E230009093E50AA093E60AB093E70A20E030E065
+:10E2400040E450E4688579858A859B850F94EDBC10
+:10E250009B01AC016091E80A7091E90A8091EA0A99
+:10E260009091EB0A0F94EDBC6093E80A7093E90A71
+:10E270008093EA0A9093EB0AB8E04B0E511CE8E059
+:10E280006E0E711C0430110509F0BBCE20E030E0A9
+:10E2900040E950EC60917C1270917D1280917E1269
+:10E2A00090917F120F94C6BD87FF4BC0AE81BF8196
+:10E2B0008C9182608C93EEE1F4E48491882341F0A8
+:10E2C0009091C00095FFFCCF8093C6003196F5CFAA
+:10E2D0008091C00085FFFCCF8AE08093C600ECEE01
+:10E2E000F3E48491882341F09091C00095FFFCCF26
+:10E2F0008093C6003196F5CF40917C1250917D12EB
+:10E3000060917E1270917F1222E030E08EE799E0FA
+:10E310000E943543E8EEF3E48491882341F0909124
+:10E32000C00095FFFCCF8093C6003196F5CF22E068
+:10E3300030E040E050E060E970EC8EE799E00E9448
+:10E340003643CC8408EAE02E02E1F02E00EA12E126
+:10E3500028E932E140EC55E464E088E792E10E946C
+:10E360006DCF8C0197FD52C0A70160EA72E188E988
+:10E3700092E10E943ECC4091A8125091A912609166
+:10E38000AA127091AB1285EE9FE00F9468CA40917B
+:10E39000AC125091AD126091AE127091AF1289EE35
+:10E3A0009FE00F9468CA4091981250919912609121
+:10E3B0009A1270919B128DED9FE00F9468CA409164
+:10E3C0009C1250919D1260919E1270919F1281EE4D
+:10E3D0009FE00F9468CA4091A0125091A1126091E1
+:10E3E000A2127091A31285ED9FE00F9468CA40912C
+:10E3F000A4125091A5126091A6127091A71289EDF6
+:10E400009FE00F9468CA0E94C6DD14C08E3FFFEFE4
+:10E410009F0729F4AE81BF818C91823041F0B3E037
+:10E420002B16310439F0710184CD8FEF01C08EEFCE
+:10E430009FEF01C0C80167960FB6F894DEBF0FBE0C
+:10E44000CDBFDF91CF911F910F91FF90EF90DF90A3
+:10E45000CF90BF90AF909F908F907F906F905F9084
+:10E460004F903F902F9008950F931F93CF93DF937A
+:10E470000E94AC5108EE1AE080E090E0A0EAB0E41F
+:10E48000F80180839183A283B383C0E6D2E020E0C9
+:10E4900030E040E752E4688179818A819B810F9462
+:10E4A000CDBD0E94D9CD8DEC9CECACE4BEE3809355
+:10E4B000E00A9093E10AA093E20AB093E30A83E3AF
+:10E4C00093E3A3E7B0EC8093E40A9093E50AA0936A
+:10E4D000E60AB093E70A64EE7AE080EE9AE00E94E2
+:10E4E0001D4720E030E040E752E46091580270910F
+:10E4F000590280915A0290915B020F94CDBD0E9407
+:10E50000D9CD8AE999E9A9E1BEE3F8018083918335
+:10E51000A283B38320E030E040E752E46881798150
+:10E520008A819B810F94CDBDDF91CF911F910F9177
+:10E530000C94D9CD2F923F924F925F926F927F921F
+:10E540008F929F92AF92BF92CF92DF92EF92FF9203
+:10E550000F931F93CF93DF9300D0CDB7DEB780E04A
+:10E560000F948C158A8380E00F9492158B830E9400
+:10E57000AC51E091300BF0E0EE0FFF1FE85DFD4B7A
+:10E5800085919491BE016F5F7F4F0F94109A89819E
+:10E59000843010F083E0898341E050E0698180E0BD
+:10E5A0000F947150E091300BF0E0EE0FFF1FEC5D27
+:10E5B000FD4B859194910F94776780E090E0A0EAFD
+:10E5C000B0E48093E80A9093E90AA093EA0AB09332
+:10E5D000EB0A20E030E040E752E460916002709185
+:10E5E000610280916202909163020F94CDBD0E94FE
+:10E5F000D9CDE0EEF5E485919591A591B491809304
+:10E60000E00A9093E10AA093E20AB093E30AE4EEF1
+:10E61000F5E485919591A591B4918093E40A909346
+:10E62000E50AA093E60AB093E70A64EE7AE080EE8A
+:10E630009AE00E941D4720E030E040E752E46091FC
+:10E6400058027091590280915A0290915B020F9486
+:10E65000CDBD0E94D9CD80E1E0EEFAE0ABEABAE0B0
+:10E6600001900D928A95E1F781E00F948C1582E07C
+:10E6700090E00E94574D80E00F948C1520E030E030
+:10E6800043E060E070E080E291EC0E9455DE809112
+:10E69000E80A9091E90AA091EA0AB091EB0A809306
+:10E6A000781290937912A0937A12B0937B1208EEAD
+:10E6B000E02E05E4F02E02E010E0412C512C80EA1F
+:10E6C000682E80E4782E92E0892E27E0922E0E9418
+:10E6D000AC514092E80A5092E90A6092EA0A7092BC
+:10E6E000EB0A20E030E040E752E460916002709174
+:10E6F000610280916202909163020F94CDBD0E94ED
+:10E70000D9CDF70185919591A591B4918093E00AB7
+:10E710009093E10AA093E20AB093E30AF7013496DA
+:10E7200085919591A591B4918093E40A9093E50A1F
+:10E73000A093E60AB093E70A64EE7AE080EE9AE0EE
+:10E740000E941D4720E030E040E752E4609158020B
+:10E750007091590280915A0290915B020F94CDBD45
+:10E760000E94D9CDA801698180E00F947150E09199
+:10E77000300BF0E0EE0FFF1FEC5DFD4B85919491A7
+:10E780000F94776720E030E043E060E070E080E2E3
+:10E7900091EC0E9455DE8FEF800F63E00F9469C209
+:10E7A00080FF03C0282D291B922F392D282F2303EA
+:10E7B000F0011124E90FF11D97FDFA95EE0FFF1FEF
+:10E7C000EE0FFF1FE958FD4E4091E80A5091E90A0B
+:10E7D0006091EA0A7091EB0A4183528363837483E8
+:10E7E00038E0E30EF11C0F5F1F4F0A30110509F0EE
+:10E7F0006ECF809078129090791260907A1270901B
+:10E800007B12E7E7EE2EE2E1FE2E1501260100E085
+:10E8100010E0F701E00FF11FA180B280C380D48027
+:10E820009501A601B401C3010F94C6BD87FD02C0C6
+:10E83000450136019501A601B101C2010F94C6BD83
+:10E8400087FF02C0510162010C5F1F4F0C301105A0
+:10E8500019F015012601DDCF8CE1E80EF11C2BEC3F
+:10E86000E21622E1F20689F69401A301B501C60180
+:10E870000F94ECBC20E030E040E450E40F94C9BFBA
+:10E88000181654F067E7C62E62E1D62EA12C75EC5F
+:10E89000E72E7FE0F72E16C0E8E9F3E484918823A1
+:10E8A00041F09091C00095FFFCCF8093C600319657
+:10E8B000F5CF8091C00085FFFCCF8AE08093C60031
+:10E8C00080E048C000E010E0B12CB11002C0AA20E6
+:10E8D00039F1209178123091791240917A12509149
+:10E8E0007B12F601E00FF11F6181728183819481B7
+:10E8F0000F94ECBC20E030E048EC52E40F949BC055
+:10E9000020E030E040E05FE30F94EDBC0F94A3BE45
+:10E910000F9435BEC7010F9470CA32E0E30EF11CAC
+:10E92000B3940C5F1F4F83E0B812CFCFA3942CE1B8
+:10E93000C20ED11CA812C6CF87E792E16FD581E045
+:10E940008093771291DD8A810F948C158B810F94BF
+:10E95000921581E00F900F900F90DF91CF911F9152
+:10E960000F91FF90EF90DF90CF90BF90AF909F906E
+:10E970008F907F906F905F904F903F902F90089571
+:10E980002F923F924F925F926F927F928F929F92BF
+:10E99000AF92BF92CF92DF92EF92FF920F931F93AD
+:10E9A000CF93DF93CDB7DEB729970FB6F894DEBFCC
+:10E9B0000FBECDBFD82EC62E3A010E94AC51D30156
+:10E9C0001C9284ECE8E7F2E1DF011D928A95E9F7F9
+:10E9D0000E94AADB8091661290916712A091681242
+:10E9E000B09169128093C0129093C112A093C21289
+:10E9F000B093C31280916E1290916F12A091701219
+:10EA0000B09171128093C4129093C512A093C61254
+:10EA1000B093C71280916A1290916B12A0916C1200
+:10EA2000B0916D128093C8129093C912A093CA122C
+:10EA3000B093CB128091721290917312A0917412C4
+:10EA4000B09175128093CC129093CD12A093CE12F8
+:10EA5000B093CF1280914E1290914F12A09150120C
+:10EA6000B09151128093D0129093D112A093D212F0
+:10EA7000B093D3128091521290915312A0915412DC
+:10EA8000B09155128093D4129093D512A093D612C0
+:10EA9000B093D7120E941CDB80E00F948C158E83FC
+:10EAA00080E00F9492158F83E091300BF0E0EE0F31
+:10EAB000FF1FEA58FD4B85919491BE016F5F7F4F18
+:10EAC0000F94109A8981843010F083E08983E8E7FD
+:10EAD0004E2EE2E15E2EF0ECEF2EF5E4FF2E222426
+:10EAE0002394312CEC2DFF27E7FDF095F987E8877B
+:10EAF0000E94AC51A101698180E00F947150E091B6
+:10EB0000300BF0E0EE0FFF1FEE58FD4B8591949116
+:10EB10000F94776720E030E040EA50E42093E80A61
+:10EB20003093E90A4093EA0A5093EB0A80E00F948D
+:10EB30008C1580E00F94921520E030E040E752E41D
+:10EB40006091600270916102809162029091630213
+:10EB50000F94CDBD0E94D9CDF70165917591859136
+:10EB6000949187010C5F1F4FF801259135914591D4
+:10EB700054912A833B834C835D832091C012309152
+:10EB8000C1124091C2125091C3120F949BC04B010D
+:10EB90005C012091C8123091C9124091CA12509163
+:10EBA000CB126A817B818C819D810F949BC09B01DC
+:10EBB000AC01C501B4010F94EDBC2091D01230918D
+:10EBC000D1124091D2125091D3120F94EDBC6093A8
+:10EBD000E00A7093E10A8093E20A9093E30AF70156
+:10EBE0006591759185919491F801259135914591A3
+:10EBF00054912A833B834C835D832091C4123091CE
+:10EC0000C5124091C6125091C7120F949BC04B0180
+:10EC10005C012091CC123091CD124091CE125091D6
+:10EC2000CF126A817B818C819D810F949BC09B0157
+:10EC3000AC01C501B4010F94EDBC2091D412309108
+:10EC4000D5124091D6125091D7120F94EDBC4B01C2
+:10EC50005C0120E030E040E850EC0F94C6BD87FD39
+:10EC600009C08092E40A9092E50AA092E60AB09266
+:10EC7000E70A0CC080E090E0A0E8B0EC8093E40AE2
+:10EC80009093E50AA093E60AB093E70A20E030E00B
+:10EC900040E752E4609158027091590280915A0203
+:10ECA00090915B020F94CDBD0E94D9CD20E030E061
+:10ECB00043E060E070E080E291EC0E9455DE2DECD4
+:10ECC0003CEC4CEC5CE36091E80A7091E90A8091BD
+:10ECD000EA0A9091EB0A0F94ECBC6093E80A7093F7
+:10ECE000E90A8093EA0A9093EB0A00E063E0B62E0B
+:10ECF000AA24AA94A20C31E03A152CF088859985B3
+:10ED00000E9441E90CC0DD2041F041E0D41253C023
+:10ED10006C2D80E00E9406E602C00E94ADE38823CD
+:10ED200009F449C004304CF12091E00A3091E10A25
+:10ED30004091E20A5091E30AD2016D917D918D914B
+:10ED40009C910F94EDBCF201608371838283938365
+:10ED50002091E40A3091E50A4091E60A5091E70AD1
+:10ED600064817581868197810F94EDBCD2011496E0
+:10ED70006D937D938D939C93179720E030E040E84E
+:10ED800050EC6091E40A7091E50A8091E60A909156
+:10ED9000E70A0F94C6BD87FF0CC080E090E0A0E8B2
+:10EDA000B0EC8093E40A9093E50AA093E60AB0934E
+:10EDB000E70A0F5F2DC099249A949B0CBB2009F49D
+:10EDC000DFC12DEC3CEC4CE45DE36091E80A70910E
+:10EDD000E90A8091EA0A9091EB0A0F94ECBC6093E7
+:10EDE000E80A7093E90A8093EA0A9093EB0A80E0BC
+:10EDF0000F948C1580E00F949215609160027091D1
+:10EE0000610280916202909163020E94D9CDB92C77
+:10EE100008300CF470CFBFEF2B1A3B0AE8E0EE0E7F
+:10EE2000F11CF8E04F0E511C25E02216310409F0C8
+:10EE30005FCE0E94AC5108E712E120E030E040E8EC
+:10EE40005EE3D8016D917D918D919C910F949BC053
+:10EE5000F80161937193819391938F01F2E10839E5
+:10EE60001F0759F780E00F948C1580E00F949215DE
+:10EE700020E030E040E950EC60917C1270917D120E
+:10EE800080917E1290917F120F94C6BD87FF04C0BF
+:10EE9000D3018C9181608C9320E030E040E950EC0C
+:10EEA00060918412709185128091861290918712E0
+:10EEB0000F94C6BD87FF04C0F30180818260808308
+:10EEC00050EDE52E52E1F52E08EC12E120EC32E196
+:10EED00040EC55E464E088E792E10E946DCF8C013C
+:10EEE00097FD39C1E0ECF5E46591759185919491B8
+:10EEF000E4ECF5E4C590D590E590F4902091C4122F
+:10EF00003091C5124091C6125091C7120F949BC008
+:10EF10004B015C012091CC123091CD124091CE1268
+:10EF20005091CF12C701B6010F949BC09B01AC0159
+:10EF3000C501B4010F94EDBC2091D4123091D512CB
+:10EF40004091D6125091D7120F94EDBC4B015C0149
+:10EF500020E030E040E950E40F94EDBC6093160BE4
+:10EF60007093170B8093180B9093190B20E030E0EF
+:10EF700040E950ECC501B4010F94C6BD87FF04C041
+:10EF8000D3018C9181608C93E8ECF5E465917591E7
+:10EF900085919491ECECF5E4C590D590E590F490D2
+:10EFA0002091C4123091C5124091C6125091C712DF
+:10EFB0000F949BC04B015C012091CC123091CD127B
+:10EFC0004091CE125091CF12C701B6010F949BC051
+:10EFD0009B01AC01C501B4010F94EDBC2091D4128A
+:10EFE0003091D5124091D6125091D7120F94EDBCAA
+:10EFF0004B015C0120E030E040E950E40F94EDBCAF
+:10F0000060931A0B70931B0B80931C0B90931D0B3A
+:10F0100020E030E040E950ECC501B4010F94C6BDDA
+:10F0200087FF04C0F30180818260808340ED52E15C
+:10F0300068EC72E180EC92E10E943ECC4091D012EB
+:10F040005091D1126091D2127091D31285EE9FE04F
+:10F050000F9468CA4091D4125091D5126091D61283
+:10F060007091D71289EE9FE00F9468CA4091C01248
+:10F070005091C1126091C2127091C3128DED9FE048
+:10F080000F9468CA4091C4125091C5126091C61283
+:10F090007091C71281EE9FE00F9468CA4091C81228
+:10F0A0005091C9126091CA127091CB1285ED9FE008
+:10F0B0000F9468CA4091CC125091CD126091CE123B
+:10F0C0007091CF1289ED9FE00F9468CA0E94C6DD4F
+:10F0D00080E00F948C1580E00F94921520E030E0D2
+:10F0E00046E153E46091E80A7091E90A8091EA0AE6
+:10F0F0009091EB0A0F94EDBC6093E80A7093E90AD3
+:10F100008093EA0A9093EB0A20E030E040E752E473
+:10F11000609160027091610280916202909163023D
+:10F120000F94CDBD0E94D9CDE091300BF0E0EE0FF1
+:10F13000FF1FE253FE4B859194910F947EA4FAD960
+:10F14000882301F18E810F948C158F810F94921575
+:10F150000E94AC513DC0E5EBF3E48491882341F07B
+:10F160009091C00095FFFCCF8093C6003196F5CFFB
+:10F170008091C00085FFFCCF8AE08093C60002C06A
+:10F180000FEF1FEF0E94AC5180E090E0A0EAB0E4E6
+:10F190008093E80A9093E90AA093EA0AB093EB0AF5
+:10F1A00020E030E040E752E460916002709161023B
+:10F1B00080916202909163020F94CDBD0E94D9CDDF
+:10F1C0000E94C2DA8E810F948C158F810F94921554
+:10F1D000C80129960FB6F894DEBF0FBECDBFDF91F0
+:10F1E000CF911F910F91FF90EF90DF90CF90BF9044
+:10F1F000AF909F908F907F906F905F904F903F90D7
+:10F200002F90089587EF9FE00F9444CA863E40F404
+:10F210000E945E606CE472E188EF9FE00D94A5505F
+:10F220000895F0DF60914C1270914D12882777FDA0
+:10F230008095982F0F9468BE90582091481930916E
+:10F24000491940914A1950914B190F94CDBD0C9416
+:10F2500066CE60914C1270914D12882777FD809593
+:10F26000982F0F9468BE2091481930914919409108
+:10F270004A1950914B190F94CDBD0E9466CE109241
+:10F280004D1210924C12089510924D1210924C1281
+:10F2900008954F925F926F927F928F929F92AF925A
+:10F2A000BF92CF92DF92EF92FF92CF93DF93CDB7D1
+:10F2B000DEB728970FB6F894DEBF0FBECDBF89EE3C
+:10F2C0009FE00F944CCA69837A838B839C8381EE81
+:10F2D0009FE00F944CCA4B015C0189ED9FE00F94B5
+:10F2E0004CCA6B017C01E0ECF5E425913591459128
+:10F2F000549164EC75E4FB0185919591A591B491CD
+:10F300008D839E83AF83B887C501B4010F949BC0E2
+:10F310002B013C012D813E814F815885C701B601EB
+:10F320000F949BC09B01AC01C301B2010F94EDBCD3
+:10F3300029813A814B815C810F94EDBC20E030E063
+:10F3400040E950E40F94EDBC6093160B7093170BDB
+:10F350008093180B9093190BE8ECF5E42591359107
+:10F3600045915491ECECF5E445905590659074907E
+:10F37000C501B4010F949BC04B015C01A301920134
+:10F38000C701B6010F949BC09B01AC01C501B4013C
+:10F390000F94EDBC29813A814B815C810F94EDBCC7
+:10F3A00020E030E040E950E40F94EDBC60931A0B8C
+:10F3B00070931B0B80931C0B90931D0B28960FB61C
+:10F3C000F894DEBF0FBECDBFDF91CF91FF90EF90DD
+:10F3D000DF90CF90BF90AF909F908F907F906F9075
+:10F3E0005F904F900895FC01108220E030E040E0F3
+:10F3F00050E0BC01620F731FFB01E40FF51F118287
+:10F400001282138214824C5F5F4F4C315105A1F779
+:10F41000245E3F4F243C310551F708952F923F92CF
+:10F420004F925F926F927F928F929F92AF92BF9214
+:10F43000CF92DF92EF92FF920F931F93CF93DF93C0
+:10F44000CDB7DEB760970FB6F894DEBF0FBECDBF65
+:10F450008B839D838B879C8703E010E0EB85FC8585
+:10F4600081859285A385B485818F928FA38FB48F78
+:10F4700085819681A781B08585879687A787B08B80
+:10F4800022242394312CF3E02F16310409F491C087
+:10F49000B101882777FD8095982F0F9468BE25E5E8
+:10F4A00035E547E052E40F949BC020E030E04CE0AB
+:10F4B00052E40F94EDBC6B017C0120E030E848E0A1
+:10F4C00053E40F94ECBC2B013C0120E030E04EE60D
+:10F4D00053E4C701B6010F94ECBC4B015C0120E082
+:10F4E00030E04CE052E4C701B6010F94ECBC6B0174
+:10F4F0007C019101220F331F220F331F8B859C85C6
+:10F50000280F391F3A832983FC01218132814381ED
+:10F510005481C301B2010F949BC0A50194010F94C3
+:10F520009BC020E039EF40EA56E40F94CDBD6F83D5
+:10F53000788789879A87EB85FC8525853685478579
+:10F540005089C701B6010F949BC0A50194010F9487
+:10F550009BC020E039EF40E256EC0F94CDBD9B01FB
+:10F56000AC016F81788589859A850F94EDBC4B013C
+:10F570005C01EB85FC85218D328D438D548DC70157
+:10F58000B6010F949BC0A30192010F949BC020E091
+:10F5900039EF40EA56E40F94CDBD9B01AC01C501A3
+:10F5A000B4010F94EDBCE981FA8161837283838396
+:10F5B0009483FFEF2F1A3F0A26E02216310409F048
+:10F5C00062CF015011098B859C854C969C878B8757
+:10F5D0000115110509F042CF9B819F87ED81E88BD2
+:10F5E00027E030E03A832983EF85F88981AD92AD39
+:10F5F000A3ADB4ADE755FF4FFC83EB8380839183CC
+:10F60000A283B383EF85F889858D968DA78DB0A1F0
+:10F61000EB5AFF4FFE83ED8380839183A283B383F4
+:10F62000212C312C01E010E00330110509F48DC0CC
+:10F63000B801882777FD8095982F0F9468BE2BEA34
+:10F640003AEA42E052E40F949BC020E030E040EC04
+:10F6500050E40F94EDBC6B017C0120E030E040ED04
+:10F6600052E40F94ECBC2B013C0120E030E04AE472
+:10F6700053E4C701B6010F94ECBC4B015C0120E0E0
+:10F6800030E040EC50E4C701B6010F94ECBC6B01D4
+:10F690007C012F853889220D331D38872F83EF8514
+:10F6A000F8892181328143815481C301B2010F94D1
+:10F6B0009BC0A50194010F949BC020E030E146E976
+:10F6C00056E40F94CDBD6B877C878D879E87ED8137
+:10F6D000FE812081318142815381C701B6010F949F
+:10F6E0009BC0A50194010F949BC020E030E146E14E
+:10F6F00056EC0F94CDBD9B01AC016B857C858D854F
+:10F700009E850F94EDBC4B015C01EB81FC81208157
+:10F71000318142815381C701B6010F949BC0A3017F
+:10F7200092010F949BC020E030E146E956E40F942B
+:10F73000CDBD9B01AC01C501B4010F94EDBCEF81BF
+:10F74000F885658F768F878F90A30F5F1F4FFCE141
+:10F750002F0E311C0630110509F066CF29813A8140
+:10F76000215031093A8329838F8598890496988B93
+:10F770008F87232B09F038CF60960FB6F894DEBF41
+:10F780000FBECDBFDF91CF911F910F91FF90EF90F2
+:10F79000DF90CF90BF90AF909F908F907F906F90B1
+:10F7A0005F904F903F902F90089587E792E11BCE96
+:10F7B0002F923F924F925F926F927F928F929F9281
+:10F7C000AF92BF92CF92DF92EF92FF920F931F936F
+:10F7D000CF93DF93CDB7DEB7C155D1090FB6F894FB
+:10F7E000DEBF0FBECDBF1C0178A36F8F4A012DABCA
+:10F7F0000FAB2A96EFAE2A972E96ACAEBDAECEAE2C
+:10F80000DFAE2E9734E0239F50011124FC01EA0D56
+:10F81000FB1D80819181A281B3818F8B988FA98FED
+:10F82000BA8FDA01AA0DBB1DBEAFADAF4D905D9092
+:10F830006D907C90A30192016F89788D898D9A8D4E
+:10F840000F94EDBC23966CAF7DAF8EAF9FAF239727
+:10F85000B4E00B9F80011124F101E00FF11F208122
+:10F8600031814281538129A33AA34BA35CA3A40114
+:10F87000400F511F25965FAF4EAF2597DA01CD900F
+:10F88000DD90ED90FC90A701960169A17AA18BA172
+:10F890009CA10F94EDBC29966CAF7DAF8EAF9FAF4E
+:10F8A00029972A96EFAD2A97B4E0EB9FC001112467
+:10F8B000F101E80FF91F20813181428153812B8FA3
+:10F8C0003C8F4D8F5E8FEF8DF8A1E80FF91F60819F
+:10F8D0007181828193810F94ECBC6DA37EA38FA371
+:10F8E00098A7AF8DB8A11C968D919D910D90BC915C
+:10F8F000A02D62968CAF9DAFAEAFBFAF6297D10126
+:10F900001C962D913D914D915C911F9729A73AA787
+:10F910004BA75CA777FA709477F87094A7019601CB
+:10F9200050582B8B3C8B4D8B5E8BEF8DF8A1EA0DE5
+:10F93000FB1D80819181A281B3818DA79EA7AFA776
+:10F94000B8AB23962CAD3DAD4EAD5FAD2397BC015A
+:10F95000CD010F94ECBC6B017C01EF8DF8A1E00FA1
+:10F96000F11F208131814281538129AB3AAB4BABEE
+:10F970005CAB29962CAD3DAD4EAD5FAD299769A925
+:10F980007AA98BA99CA90F94ECBC4B015C01A7013F
+:10F990009601C301B2010F949BC069AF7AAF8BAFE0
+:10F9A0009CAFA50194016B897C898D899E890F94F8
+:10F9B0009BC09B01AC0169AD7AAD8BAD9CAD0F9442
+:10F9C000EDBC69AF7AAF8BAF9CAFA5019401C301C9
+:10F9D000B2010F949BC04B015C01A70196016B899A
+:10F9E0007C898D899E890F949BC09B01AC01C501C8
+:10F9F000B4010F94ECBC29AD3AAD4BAD5CAD0F94A6
+:10FA000060BD6B017C0120E030E0A9010F94C6BD10
+:10FA100087FF0AC02BED3FE049EC50E4C701B60177
+:10FA20000F94EDBC6B017C01AC968FADAC97882335
+:10FA300051F02BED3FE049EC50E4C701B6010F94C3
+:10FA4000ECBC6B017C012DA53EA54FA558A96F8983
+:10FA5000788D898D9A8D0F94C6BD81111FC029A9FB
+:10FA60003AA94BA95CA969A17AA18BA19CA10F9489
+:10FA7000C6BD811113C020E030E0A901C701B60165
+:10FA80000F94C6BD81110AC02BED3FE049EC50E454
+:10FA9000C701B6010F94EDBC6B017C01AB962CAD98
+:10FAA0003DAD4EAD5FADAB97C701B6010F949BC0A6
+:10FAB0002DA13EA14FA158A55F770F94D6BF4B0152
+:10FAC0005C012FE632E143E85AE30F94C6BD87FD9F
+:10FAD000D6C1C501B4010F94A3BE0F943ABE7AA358
+:10FAE00069A36115710521F481E090E09AA389A3CF
+:10FAF000A9A1BAA1BD0180E090E00F9466BE4B01C0
+:10FB00005C019B01AC01C701B6010F94CDBD6F8BA9
+:10FB1000788F898F9A8FA50194016DA17EA18FA105
+:10FB200098A50F94CDBD6DA77EA78FA798AB29A5EB
+:10FB30003AA54BA55CA562966CAD7DAD8EAD9FAD33
+:10FB400062970F94ECBCA50194010F94CDBD69ABF5
+:10FB50007AAB8BAB9CAB20E030E040E05FE36F8999
+:10FB6000788D898D9A8D0F949BC02F89388D498D02
+:10FB70005A8D0F949BC09B01AC0160E070E080E85F
+:10FB80009FE30F94ECBC6DA37EA38FA398A7CE0137
+:10FB90000196FC012A962FAD2A97B4E02B9FE00D29
+:10FBA000F11D11242B8D3C8D4D8D5E8D2083318375
+:10FBB0004283538329A53AA54BA55CA52D873E8793
+:10FBC0004F87588B1B8E22242394312CAC019DA986
+:10FBD00084E0989F400D511D11245EAB4DABA1E018
+:10FBE000B0E0AC0FBD1F3FA924E0329FA00DB11DB6
+:10FBF0001124B8AFAFABFAA7E9A7AE0144595F4FE4
+:10FC00005A8B498BE9A1FAA12E163F0608F012C1C2
+:10FC10005B8D59310CF040C02DA13EA14FA158A5DC
+:10FC20006B897C898D899E890F949BC06B017C01B7
+:10FC30002F89388D498D5A8DC301B2010F949BC015
+:10FC4000A70196010F94EDBC7B018C012DA13EA173
+:10FC50004FA158A5C301B2010F949BC04B015C0199
+:10FC60002F89388D498D5A8D6B897C898D899E8924
+:10FC70000F949BC09B01AC01C501B4010F94ECBC77
+:10FC80002B013C018B8D8F5F8B8FA701B8014B8BB4
+:10FC90005C8B6D8B7E8B66C0B10180E090E00F9431
+:10FCA00066BE2F89388D498D5A8D0F949BC06B018C
+:10FCB0007C010F94CABD6B8B7C8B8D8B9E8BC70197
+:10FCC000B6010F944AC14B015C01ADADBEADCD9004
+:10FCD000DD90ED90FC90F7FAF094F7F8F09425960B
+:10FCE000AEADBFAD25972D913D914D915C912B8F80
+:10FCF0003C8F4D8F5E8F2B893C894D895E89C70172
+:10FD0000B6010F949BC02B013C01A50194016B8DA2
+:10FD10007C8D8D8D9E8D0F949BC09B01AC01C3018A
+:10FD2000B2010F94EDBC2B013C01A5019401C70168
+:10FD3000B6010F949BC06B017C012B893C894D89D6
+:10FD40005E896B8D7C8D8D8D9E8D0F949BC09B01EC
+:10FD5000AC01C701B6010F94ECBC6B8B7C8B8D8B17
+:10FD60009E8B1B8EA301920123966CAD7DAD8EAD53
+:10FD70009FAD23970F94EDBCEDA9FEA9608371831D
+:10FD8000828393832B893C894D895E8929966CAD4A
+:10FD90007DAD8EAD9FAD29970F94EDBCAFA9B8ADE9
+:10FDA0006D937D938D939C9313972DA53EA54FA5A1
+:10FDB00058A9E9A5FAA560817181828193810F9488
+:10FDC000EDBCA9A5BAA56D937D938D939C931397D4
+:10FDD00029A93AA94BA95CA96D857E858F8598894B
+:10FDE0000F94EDBC6D877E878F87988BCE0101962F
+:10FDF0000E94A456E984FA840B851C852D813E81DE
+:10FE00004F81588569817A818B819C81BA89BF93A2
+:10FE1000E989EF932E968CAC9DACAEACBFAC2E971F
+:10FE2000DE011D966D0144D6BFEF2B1A3B0A0F90E1
+:10FE30000F90E8CECF8CD8A0FCE0CF0ED11CAF8DB8
+:10FE4000B8A11896ED90FD900D911C911B971496FA
+:10FE50002D913D914D915C9117976D917D918D9173
+:10FE60009C91FE01E459FF4FFF93EF932E968CACCB
+:10FE70009DACAEACBFAC2E971BD60F900F90CF5A57
+:10FE8000DF4F0FB6F894DEBF0FBECDBFDF91CF912D
+:10FE90001F910F91FF90EF90DF90CF90BF90AF90A8
+:10FEA0009F908F907F906F905F904F903F902F909A
+:10FEB0000895CF93DF931F92CDB7DEB71982AE01BD
+:10FEC0004F5F5F4F682F85E70F94DF2289810F9086
+:10FED000DF91CF910895CF93DF93809145138133C4
+:10FEE00019F080E090E043C0809144138139C9F754
+:10FEF00082E0DFDFC82F87E1DCDF80933D1384E100
+:10FF0000D8DF80933C13C7FFECCF83E0D2DFD82F3C
+:10FF100084E0CFDFC82F82E1CCDF282F30E0A901B9
+:10FF200084E0440F551F8A95E1F744275F704D2BFD
+:10FF3000322F222722273F702C2B53FD505133FDA7
+:10FF400030518091401390914113840F951F9093ED
+:10FF500041138093401380913E1390913F13821B75
+:10FF6000930B90933F1380933E1381E090E0DF91D9
+:10FF7000CF910895CF9380914513813319F080E09C
+:10FF800090E022C0809144138139C9F782E091DF6B
+:10FF900087FFF5CF84E08DDFC82F82E18ADF282F2D
+:10FFA00030E0322F222722273F702C2B33FD305197
+:10FFB00080913E1390913F13821B930B90933F13BC
+:10FFC00080933E1381E090E0CF910895CF93DF932B
+:10FFD0001F92CDB7DEB76983AE014F5F5F4F682FC9
+:10FFE00085E70F9444230F90DF91CF910895CF932D
+:10FFF000DF93D82FC62F41EB65E184E10F94CF2129
+:020000022000DC
+:10000000D0934313C093421380E053DF8093451392
+:1000100081E04FDF8093441390914513913369F44D
+:10002000813959F4609143138DE0D0DF6091421320
+:100030008EE0CCDF81E090E002C080E090E0DF91D4
+:10004000CF9108952F923F924F925F926F927F923D
+:100050008F929F92AF92BF92CF92DF92EF92FF92D8
+:100060000F931F93CF93DF93CDB7DEB768970FB68B
+:10007000F894DEBF0FBECDBF1C01CB01BA01280131
+:100080003901F101E45BFF4FC080D180E280F38051
+:10009000A70196010F949BC00F94B3BD0F943ABE75
+:1000A0004B015C01A7019601C301B2010F949BC0F3
+:1000B0000F94B3BD0F943ABE08E780169104A104D3
+:1000C000B10428F4B8E78B2E912CA12CB12CD101CE
+:1000D000D796CD90DD90ED90FC90DA972401350114
+:1000E000C814D904EA04FB0410F426013701683768
+:1000F00071058105910520F468E770E080E090E0EB
+:1001000069877A878B879C87C616D706E806F90623
+:1001100020F4C986DA86EB86FC8691012D5B3F4F81
+:10012000D9018D919D910D90BC91A02D89839A83C9
+:10013000AB83BC83892B8A2B8B2B41F401E010E02D
+:1001400020E030E009831A832B833C83A3019201D2
+:10015000C301B2010F945AC26D877E878F87988B37
+:10016000A7019601C701B6010F945AC24B015C0169
+:1001700029853A854B855C85CA01B9010F945AC21D
+:10018000698B7A8B8B8B9C8BE980FA800B811C812D
+:10019000EE0CFF1C001F111FED82FE820F831887DB
+:1001A000C501B40161507109810991090D851E8550
+:1001B0002F853889601B710B820B930BED80FE80BD
+:1001C0000F8118856E0D7F1D801F911FA80197015B
+:1001D0000F949DC269017A01C501B40109891A8988
+:1001E0002B893C89601B710B820B930B2D813E8107
+:1001F0004F8158850F949DC22C0D3D1D4E1D5F1DD6
+:10020000D10150968D909D90AD90BC90539728153C
+:1002100039054A055B0548F4D501C401821B930BDF
+:10022000A40BB50BAC01BD0194C029813A814B816F
+:100230005C81E2E0220F331F441F551FEA95D1F77E
+:10024000D501C40181709927AA27BB278D8B9E8B6E
+:10025000AF8BB88F8501740116950795F794E794D5
+:10026000E982FA820B831C83E988FA880B891C894E
+:100270008D859E85AF85B889E816F9060A071B07A4
+:1002800090F1BC01CD0160957095809590956E0DB3
+:100290007F1D801F911F620F731F841F951FED88A4
+:1002A000FE880F89188DEF28E02AE12A41F0ED80C1
+:1002B000FE800F8118856E0D7F1D801F911F0F948A
+:1002C0009DC269017A0109811A812B813C81C00E8E
+:1002D000D11EE21EF31E8C149D04AE04BF04B0F5C3
+:1002E0007501640133C06D857E858F859889E988A5
+:1002F000FA880B891C896E197F09800B910BED8898
+:10030000FE880F89188DEF28E02AE12A41F0ED8060
+:10031000FE800F8118856E0D7F1D801F911F0F9429
+:100320009DC2E980FA800B811C812E0D3F1D401F6C
+:10033000511F82169306A406B50610F4A501940178
+:1003400075016401C21AD30AE40AF50A40E050E0DC
+:10035000BA018FB7F894F101E55BFF4F90819111DD
+:1003600020C0D1015A96CD92DD92ED92FC925D971C
+:10037000C40ED51EE61EF71EF101C68ED78EE0A272
+:10038000F1A2DB964D925D926D927C92DE97DF96A4
+:10039000E984FA840B851C85ED92FD920D931C93E4
+:1003A00013978FBF68960FB6F894DEBF0FBECDBF10
+:1003B000DF91CF911F910F91FF90EF90DF90CF9041
+:1003C000BF90AF909F908F907F906F905F904F9075
+:1003D0003F902F9008952F923F924F925F926F928D
+:1003E0007F928F929F92AF92BF92CF92DF92EF92C5
+:1003F000FF920F931F93CF93DF935C017090631371
+:100400008091641387198F70833008F486C08091BF
+:100410006413811101C080E1815027E5829F800132
+:1004200011240B591C4E811101C080E1FF24FA9464
+:10043000F80E87E5F89EE0011124CB59DC4EF71445
+:1004400009F46DC09AA4CBA4DCA4EDA4292D3C2D05
+:100450004D2D5E2D6EA17FA188A599A50F94C6BDD7
+:10046000882309F44CC0F80126A037A040A451A469
+:10047000A2019101692D7C2D8D2D9E2D0F94C6BD5D
+:1004800018169CF5A2019101C201B1010F949BC005
+:100490001B012C018AA99BA9ACA9BDA9BC01CD0156
+:1004A00090589B01AC010F94EDBC2EA53FA548A927
+:1004B00059A90F949BC09B01AC01C201B1010F94DB
+:1004C000ECBC0F9454C1662E872E8C01262F372F3B
+:1004D000AC01692D7C2D8D2D9E2D0F94C6BD87FD01
+:1004E00004C0962CC82CD02EE12E892D9C2DAD2D2C
+:1004F000BE2D8EA39FA3A8A7B9A7F1E0FEAB8F2DB9
+:10050000F11001C080E1FF24FA94F80E27E5F29E75
+:10051000C00111248E01EC0190CF823061F487E597
+:10052000789EE0011124CB59DC4E81E0870D8031AB
+:1005300041F480E006C0C0916413C11186C0C0E1DF
+:1005400084C0782E97E5899F40011124F401EB596E
+:10055000FC4E4F0144244394CEA0DFA0E8A4F9A4AC
+:10056000F40156A067A000A511A5252D362DA801E0
+:10057000C701B6010F94C6BD87FF40C0A701960111
+:10058000C701B6010F949BC06B017C018AA99BA98E
+:10059000ACA9BDA9BC01CD0190589B01AC010F9441
+:1005A000EDBC2EA53FA548A959A90F949BC09B015E
+:1005B000AC01C701B6010F94ECBC0F9454C16B01A0
+:1005C0007C019B01AC01652D762DC8010F94C6BD41
+:1005D00087FF03C0C52CD62C78019601A701652D95
+:1005E000762DC8010F94C6BD882341F0C601D701FE
+:1005F000F40186A397A3A0A7B1A746AAF40186A9F0
+:10060000811103C08EA9882361F0F40106A117A10E
+:1006100020A531A54EA15FA168A579A5CE0112DD67
+:100620001EAA81E0870D803109F480E0782EF7E57D
+:100630008F9FC00111248B599C4E20916413721618
+:1006400009F479CFE4014C0187CFC15027E5C202FC
+:10065000E0011124CB59DC4EF5010081118122818A
+:1006600033814EA15FA168A579A5CE01EBDC1EAA5E
+:10067000DF91CF911F910F91FF90EF90DF90CF907E
+:10068000BF90AF909F908F907F906F905F904F90B2
+:100690003F902F900895109264131092631380E19D
+:1006A000E0EFF8E1DF01982F1D929A95E9F7EBE46E
+:1006B000F3E1DF011D928A95E9F71092E01810929C
+:1006C000E1181092E2181092E3181092E4181092B8
+:1006D000E5181092E6181092E7181092E818109298
+:1006E000E9181092EA181092EB181092EC18109278
+:1006F000ED181092EE181092EF181092DC1810926C
+:10070000DD181092DE181092DF180895CF92DF9254
+:10071000EF92FF92CF93C091CA0A90916313809198
+:100720006413981781F08091631397E5899FF00116
+:100730001124E455FC4EC08190916413891719F07F
+:100740008F5F8F70F9CFCC2321F1C0904613D090EA
+:100750004713E0904813F0904913C114D104E10409
+:10076000F10479F40F94EFB4605E7C4F8F4F9F4F8C
+:1007700060934613709347138093481390934913E3
+:1007800011C00F94EFB46C157D058E059F0550F0D8
+:100790000AC01092461310924713109248131092F9
+:1007A000491301C0CFEF6C2F70E086E0CF91FF902E
+:1007B000EF90DF90CF900D94C2B54F925F926F9201
+:1007C0007F928F929F92AF92BF92CF92DF92EF92E1
+:1007D000FF920F931F9380916F008D7F80936F0026
+:1007E00080E00F94681F6093F0187093F118809365
+:1007F000F2189093F31881E00F94681F6093F41837
+:100800007093F5188093F6189093F71882E00F9480
+:10081000681F6093F8187093F9188093FA189093F2
+:10082000FB1883E00F94681F6093FC187093FD1809
+:100830008093FE189093FF1880E00F94761F6093CA
+:10084000E00A7093E10A8093E20A9093E30A81E060
+:100850000F94761F6093E40A7093E50A8093E60A8A
+:100860009093E70A82E00F94761F6093E80A7093F2
+:10087000E90A8093EA0A9093EB0A83E00F94761FCB
+:100880006093EC0A7093ED0A8093EE0A9093EF0A5E
+:1008900080917712882341F10091E40A1091E50AD2
+:1008A0002091E60A3091E70A4091E00A5091E10A6E
+:1008B0006091E20A7091E30A87E792E10E94654441
+:1008C0009B01AC016091E80A7091E90A8091EA0A03
+:1008D0009091EB0A0F94ECBC6093E80A7093E90ADC
+:1008E0008093EA0A9093EB0A0F94921F109176126C
+:1008F000112309F49AC010FF34C020914E12309198
+:100900004F1240915012509151126091E00A709133
+:10091000E10A8091E20A9091E30A0F94ECBC6093A3
+:10092000E00A7093E10A8093E20A9093E30A20912F
+:1009300052123091531240915412509155126091BD
+:10094000E40A7091E50A8091E60A9091E70A0F9413
+:10095000ECBC6093E40A7093E50A8093E60A9093F6
+:10096000E70A11FF62C08090E00A9090E10AA0902F
+:10097000E20AB090E30AC090E40AD090E50AE09061
+:10098000E60AF090E70A20915E1230915F124091E2
+:10099000601250916112C501B4010F949BC02B01EC
+:1009A0003C01209162123091631240916412509187
+:1009B0006512C701B6010F949BC09B01AC01C30136
+:1009C000B2010F94EDBC2B013C01209156123091E5
+:1009D00057124091581250915912C501B4010F9409
+:1009E0009BC04B015C0120915A1230915B124091E7
+:1009F0005C1250915D12C701B6010F949BC09B0120
+:100A0000AC01C501B4010F94EDBC6093E00A709392
+:100A1000E10A8093E20A9093E30A4092E40A50923A
+:100A2000E50A6092E60A7092E70A80E1E0EEFAE0F9
+:100A3000ABEABAE001900D928A95E1F71092DC18CA
+:100A40001092DD181092DE181092DF181092E01844
+:100A50001092E1181092E2181092E3181092E41824
+:100A60001092E5181092E6181092E7181092E81804
+:100A70001092E9181092EA181092EB181092EC18E4
+:100A80001092ED181092EE181092EF1881E08093FA
+:100A90004A131F910F91FF90EF90DF90CF90BF907E
+:100AA000AF909F908F907F906F905F904F90089540
+:100AB0002F923F924F925F926F927F928F929F926E
+:100AC000AF92BF92CF92DF92EF92FF920F931F935C
+:100AD000CF93DF93CDB7DEB7C158D1090FB6F894E5
+:100AE000DEBF0FBECDBF2A966FAF2A972B967FAF82
+:100AF0002B972C968FAF2C972D969FAF2D972996DD
+:100B00002CAF3DAF4EAF5FAF2997E496ECAEFDAE94
+:100B10000EAF1FAFE497E696DFAECEAEE6978BAA98
+:100B200062969FAE6297AFAE2296BFAE229720919B
+:100B300064132F5F6E962FAF6E97203119F46E9667
+:100B40001FAE6E970091631310E06E963FAD6E97E7
+:100B5000832F992787FD90950817190729F0109181
+:100B60007612111117C0C2C010924A130F94F32BC2
+:100B700080E00E94BD5C80E00F940A97809163132F
+:100B800090E08017910791F380914A1381110D94A1
+:100B9000EC11E5CF11FF70C0209166123091671201
+:100BA00040916812509169122A966FAD2A972B9640
+:100BB0007FAD2B972C968FAD2C972D969FAD2D97B3
+:100BC0000F949BC06B017C0120916A1230916B12D3
+:100BD00040916C1250916D1229966CAD7DAD8EAD29
+:100BE0009FAD29970F949BC09B01AC01C701B60133
+:100BF0000F94EDBCD62EE72EF82E092F20917212FD
+:100C000030917312409174125091751229966CAD07
+:100C10007DAD8EAD9FAD29970F949BC04B015C01BC
+:100C200020916E1230916F1240917012509171129A
+:100C30002A966FAD2A972B967FAD2B972C968FAD6A
+:100C40002C972D969FAD2D970F949BC0A5019401D5
+:100C50000F94EDBC29966CAF7DAF8EAF9FAF2997F7
+:100C60002A96DFAE2A972B96EFAE2B972C96FFAEE7
+:100C70002C972D960FAF2D9710FF38C020914E1254
+:100C800030914F1240915012509151122A966FADEF
+:100C90002A972B967FAD2B972C968FAD2C972D9660
+:100CA0009FAD2D970F94EDBC2A966FAF2A972B9688
+:100CB0007FAF2B972C968FAF2C972D969FAF2D97AC
+:100CC000209152123091531240915412509155126A
+:100CD00029966CAD7DAD8EAD9FAD29970F94EDBC7F
+:100CE00029966CAF7DAF8EAF9FAF299720914019A9
+:100CF0003091411940914219509143192A966FAD94
+:100D00002A972B967FAD2B972C968FAD2C972D96EF
+:100D10009FAD2D970F949BC00F946BC0AC966CAF9A
+:100D20007DAF8EAF9FAFAC9720914419309145199C
+:100D3000409146195091471929966CAD7DAD8EAD05
+:100D40009FAD29970F949BC00F946BC0E0966CAF3A
+:100D50007DAF8EAF9FAFE09780917712882349F1E6
+:100D600029960CAD1DAD2EAD3FAD29972A964FADFE
+:100D70002A972B965FAD2B972C966FAD2C972D96BF
+:100D80007FAD2D9787E792E10E9465449B01AC01FE
+:100D9000E4966CAD7DAD8EAD9FADE4970F94EDBC48
+:100DA000209148193091491940914A1950914B1995
+:100DB0000EC0209148193091491940914A1950911B
+:100DC0004B19E4966CAD7DAD8EAD9FADE4970F945D
+:100DD0009BC00F946BC0A2966CAF7DAF8EAF9FAFE0
+:100DE000A297E696AEADBFADE6974D905D906D9043
+:100DF0007C9020914C1930914D1940914E19509191
+:100E00004F19C301B2010F949BC00F946BC0619640
+:100E10006CAF7DAF8EAF9FAF619720914B13309138
+:100E20004C1340914D1350914E132A966FAD2A9753
+:100E30002B967FAD2B972C968FAD2C972D969FAD33
+:100E40002D970F94ECBC4B015C0120914F13309116
+:100E50005013409151135091521329966CAD7DADB2
+:100E60008EAD9FAD29970F94ECBC6B017C01A50161
+:100E70009401C501B4010F949BC04B015C01A70113
+:100E80009601C701B6010F949BC09B01AC01C5013F
+:100E9000B4010F94EDBC0F9454C1C258DF4F688366
+:100EA00079838A839B83CE57D0402091571330910A
+:100EB00058134091591350915A13C301B2010F9422
+:100EC000ECBCA8966CAF7DAF8EAF9FAFA89780911A
+:100ED000FC189091FD18A091FE18B091FF18619632
+:100EE0002CAD3DAD4EAD5FAD6197281739074A0770
+:100EF0005B0709F4D8C0E091CC0A34E0E39FF0012D
+:100F00001124E159F54E20916C0230916D0240910F
+:100F10006E0250916F0260817181828193810F9482
+:100F2000C6BD87FF40C061968CAD9DADAEADBFAD77
+:100F300061978093FC189093FD18A093FE18B093CE
+:100F4000FF184092571350925813609259137092A1
+:100F50005A13EFE3F0E18491882341F09091C000AF
+:100F600095FFFCCF8093C6003196F5CFEAEDF2E411
+:100F700085919491FC012491222341F03091C0008D
+:100F800035FFFCCF2093C6000196F4CF8091C000BE
+:100F900085FFFCCF8AE08093C600A8961CAE1DAEEC
+:100FA0001EAE1FAEA8978091FC189091FD18A091DD
+:100FB000FE18B091FF1861962CAD3DAD4EAD5FAD02
+:100FC0006197281B390B4A0B5B0BCA01B90157FF0C
+:100FD00007C090958095709561957F4F8F4F9F4F7B
+:100FE0000F9468BE6B017C0120E030E84AEE53E4C8
+:100FF00060914C1970914D1980914E1990914F1933
+:101000000F949BC09B01AC01C701B6010F94C9BFEF
+:1010100018160CF048C061968CAD9DADAEADBFAD5D
+:1010200061978093FC189093FD18A093FE18B093DD
+:10103000FF18E696EEADFFADE69780819181A28123
+:10104000B3818093571390935813A0935913B0937F
+:101050005A13EFE3F0E18491882341F09091C000AE
+:1010600095FFFCCF8093C6003196F5CFE4EDF2E416
+:1010700085919491FC012491222341F03091C0008C
+:1010800035FFFCCF2093C6000196F4CF8091C000BD
+:1010900085FFFCCF8AE08093C600A8961CAE1DAEEB
+:1010A0001EAE1FAEA89780916413F7E58F9F1001C5
+:1010B000112491012B593C4E1901F901EB5AFF4FB4
+:1010C000118210823A9710828091F0189091F11855
+:1010D000A091F218B091F3188BA79CA7ADA7BEA75B
+:1010E000AC968CAC9DACAEACBFACAC97881A990AF0
+:1010F000AA0ABB0AB7FE08C0B094A094909480944A
+:10110000811C911CA11CB11CD1018D929D92AD92AC
+:10111000BC9213972091F4183091F5184091F6186D
+:101120005091F7182FA738AB49AB5AABE0968CAD6E
+:101130009DADAEADBFADE097821B930BA40BB50B7D
+:101140008FA398A7A9A7BAA7B7FF0BC0B095A09582
+:10115000909581959F4FAF4FBF4F8FA398A7A9A799
+:10116000BAA72FA138A549A55AA5D10114962D9348
+:101170003D934D935C9317972091F8183091F9188F
+:101180004091FA185091FB182FAB38AF49AF5AAFC6
+:10119000A2964CAC5DAC6EAC7FACA297421A530ADF
+:1011A000640A750A77FE08C0709460945094409465
+:1011B000411C511C611C711CD10118964D925D920D
+:1011C0006D927C921B972091FC183091FD184091F4
+:1011D000FE185091FF182BAF3CAF4DAF5EAF61963C
+:1011E000CCACDDACEEACFFAC6197C21AD30AE40A1A
+:1011F000F50AF7FE08C0F094E094D094C094C11CA6
+:10120000D11CE11CF11CD1011C96CD92DD92ED9216
+:10121000FC921F97E091CC0AB4E0EB9FF0011124FF
+:10122000E05CFD4F20813181428153816D962CAF6E
+:101230003DAF4EAF5FAF6D9720E030E040E85FE339
+:101240006D966CAD7DAD8EAD9FAD6D970F94C6BDA7
+:101250008823A9F0C701B6010F9468BE6D962CAD26
+:101260003DAD4EAD5FAD6D970F949BC00F9435BEF5
+:10127000D1011C966D937D938D939C931F97A091A4
+:101280005402B0915502A436B105A1F0F1012485B4
+:101290003585468557850F9400C324E630E040E04D
+:1012A00050E00F94BFC2D1011C962D933D934D93F6
+:1012B0005C931F97F10144855585668577858FA1DD
+:1012C00098A5A9A5BAA584179507A607B70714F48A
+:1012D000DB01CA0184159505A605B70514F4D301F1
+:1012E000C201B501A40188169906AA06BB0614F42A
+:1012F000AC01BD01D10150964D935D936D937C93EC
+:101300005397463051056105710510F40D94EC11A9
+:10131000F101E95BFF4F8091CA0A9091CB0AAA279D
+:1013200097FDA095BA2F80839183A283B383AC9657
+:101330002CAD3DAD4EAD5FADAC978BA59CA5ADA5DD
+:10134000BEA5281739074A075B0724F0D101589634
+:101350001C9203C081E0F101808FE0962CAD3DAD81
+:101360004EAD5FADE0978FA598A9A9A9BAA9281796
+:1013700039074A075B073CF4D10158968C9158977E
+:10138000826058968C93A2962CAD3DAD4EAD5FAD6C
+:10139000A2978FA998ADA9ADBAAD281739074A070A
+:1013A0005B073CF4D10158968C915897846058960D
+:1013B0008C9361962CAD3DAD4EAD5FAD61978BAD1D
+:1013C0009CADADADBEAD281739074A075B073CF4AD
+:1013D000D10158968C915897886058968C93C9562D
+:1013E000DF4FE881F981C759D0408081D1015996FA
+:1013F0008C9389288A288B2809F01798F101848119
+:101400009581A681B781892B8A2B8B2B09F01698A1
+:10141000F10180859185A285B385892B8A2B8B2B41
+:1014200009F01598F10184859585A685B785892BE6
+:101430008A2B8B2B91F18091D518882319F081503C
+:101440008093D5188091D618882319F08150809305
+:10145000D6188091D718882319F081508093D71817
+:10146000C956DF4FA881B981C759D0408C918130CE
+:1014700061F030F0823089F480E28093D71808C0A0
+:10148000149880E28093D51808C080E28093D61823
+:101490008091D518811101C0149AD1011C962D910B
+:1014A0003D914D915C911F976D962CAF3DAF4EAF26
+:1014B0005FAF6D97232B242B252B29F5B0911019A5
+:1014C000BFA3E0911119EBA7109112190091131904
+:1014D0002B2F3E2F412F502F6BA962967FAD629725
+:1014E0008FAD22969FAD22970F94C6BD87FD18C081
+:1014F000FBA9FFA362962FAD62972BA71FAD229683
+:101500000FAD22970DC030912C193FA340912D199A
+:101510004BA710912E1900912F19232F342FDACFBA
+:101520008091F0189091F118A091F218B091F318F1
+:10153000AC962CAD3DAD4EAD5FADAC97281B390BD5
+:101540004A0B5B0BCA01B9010F9468BE2091401988
+:101550003091411940914219509143190F94CDBDDA
+:101560006BAB7CAB8DAB9EAB698B7A8B8B8B9C8B87
+:10157000E0966CAD7DAD8EAD9FADE0972FA538A9FF
+:1015800049A95AA9621B730B840B950B0F9468BE73
+:1015900020914419309145194091461950914719AD
+:1015A0000F94CDBD4B015C016D8B7E8B8F8B988F23
+:1015B000A2966CAD7DAD8EAD9FADA2972FA938AD33
+:1015C00049AD5AAD621B730B840B950B0F9468BE2B
+:1015D000209148193091491940914A1950914B195D
+:1015E0000F94CDBD6B017C01698F7A8F8B8F9C8F9F
+:1015F00061966CAD7DAD8EAD9FAD61972BAD3CAD71
+:101600004DAD5EAD621B730B840B950B0F9468BEE2
+:1016100020914C1930914D1940914E1950914F190C
+:101620000F94CDBDE091CC0A34E0E39FF00111248A
+:10163000E05CFD4F20813181428153810F949BC03A
+:101640002B013C016091540270915502882777FD6F
+:101650008095982F0F9468BE9B01AC01C301B20125
+:101660000F949BC020E030E048EC52E40F94CDBDD5
+:101670006D8F7E8F8F8F98A3D1012D913D914D91CC
+:101680005C9113972FAB38AF49AF5AAF2630310575
+:101690004105510504F514964D905D906D907C9038
+:1016A0001797B6E04B16510461047104A4F4F101DC
+:1016B0004084518462847384F6E04F1651046104BF
+:1016C00071044CF4DC01CB01BF77F10186A797A729
+:1016D000A0ABB1AB27C06BA97CA98DA99EA90F9423
+:1016E00092C12B013C01C501B4010F9492C19B0131
+:1016F000AC01C301B2010F94EDBC4B015C01C70109
+:10170000B6010F9492C19B01AC01C501B4010F94C5
+:10171000EDBC0F9454C1D1019E966D937D938D9332
+:101720009C93D197D1019E962D913D914D915C91C5
+:10173000D19765962CAF3DAF4EAF5FAF659760E038
+:1017400070E080E89FE30F94CDBD9B01AC016FA1D9
+:101750007BA5812F902F0F949BC02B013C011091F2
+:10176000641380916313181B1F70E12FF0E0219622
+:10177000FFAFEEAF2197CF010297069708F03FC069
+:10178000A301920160E074E284E799E40F94CDBD77
+:101790000F946BC06B017C0180916019909161196D
+:1017A000A0916219B0916319C816D906EA06FB0622
+:1017B00030F5BC01CD016C197D098E099F09660FBA
+:1017C000771F881F991F212F30E040E050E00F94D1
+:1017D0009DC2CA01B9010F9466BE0F946BC06C0D17
+:1017E0007D1D8E1D9F1D0F9466BE9B01AC0160E0A8
+:1017F00074E284E799E40F94CDBD2B013C01A30171
+:10180000920165966CAD7DAD8EAD9FAD65970F94E1
+:101810009BC06BAB7CAB8DAB9EABD10192966D93B5
+:101820007D938D939C93959750966D917D918D911D
+:101830009C9153970F9466BE6FA378A789A79AA728
+:10184000A30192010F949BC00F94B3BD0F943ABEB5
+:101850006B017C01F10167AB70AF81AF92AF9E016C
+:101860002F5E3F4F3CAF2BAF40E559E1A4965FAFF1
+:101870004EAFA497CE0181969EA38DA3DE01119653
+:101880006796BFAFAEAF67971BA61FA600E81FE322
+:10189000EBADFCAD6191719181919191FCAFEBAF9A
+:1018A000A30192010F949BC06796AEADBFAD679741
+:1018B0006D937D938D939D936796BFAFAEAF679702
+:1018C0009B01AC015F7725962CAF3DAF4EAF5FAF6C
+:1018D0002597A496AEADBFADA4978D909D90AD9089
+:1018E000BD90A496BFAFAEAFA497A5019401259675
+:1018F0006CAD7DAD8EAD9FAD25970F94C9BF181609
+:10190000ECF425962CAD3DAD4EAD5FAD2597C501F0
+:10191000B4010F94CDBDB62EA72E982E892E262F5A
+:10192000372F482F592F6BA57FA5C8010F94C6BD2F
+:1019300087FD04C0BBA6AFA6092D182DEBADFCADED
+:101940002DA13EA1E217F30709F0A2CF20E030E07D
+:1019500040E85FE36BA57FA5C8010F94C6BD87FF74
+:101960003BC04E0131E1830E911CAE014F5F5F4FD2
+:101970005A012BA53FA5A801D5016D917D918D91AF
+:101980009C910F949BC0F501619371938193919306
+:101990005F01E815F90569F72BA53FA5A8016BA91B
+:1019A0007CA98DA99EA90F949BC0D10192966D939D
+:1019B0007D938D939C939597C701B6010F9466BE56
+:1019C0002BA53FA5A8010F949BC00F943ABEF1012F
+:1019D00067AB70AF81AF92AF65962CAD3DAD4EADAC
+:1019E0005FAD65976FA178A589A59AA50F94CDBD28
+:1019F0006B017C012FA938AD49AD5AAD232B242BA7
+:101A0000252B59F5F10184819581A681B781892B18
+:101A10008A2B8B2B11F580859185A285B385892B27
+:101A20008A2B8B2BD1F420912419309125194091C8
+:101A3000261950912719C701B6010F949BC00F9426
+:101A4000B3BD81010D5B1F4F0F943ABED8016D935A
+:101A50007D938D939C931397F6C020912819309114
+:101A6000291940912A1950912B19C701B6010F94D9
+:101A70009BC00F94B3BD0F943ABE81010D5B1F4F05
+:101A8000F8016083718382839383409000195090A2
+:101A9000011960900219709003190F9466BE4B01F2
+:101AA0005C016FA978AD89AD9AAD0F9468BE9B01BA
+:101AB000AC01C501B4010F949BC02FA138A549A565
+:101AC0005AA50F94CDBD4B015C01C301B2010F9427
+:101AD00066BE9B01AC01C501B4010F94C9BF1816C5
+:101AE00034F4D8014D925D926D927C9213974090A0
+:101AF0000419509005196090061970900719F801A3
+:101B000060817181828193810F9466BE4B015C017B
+:101B1000D10114966D917D918D919C9117970F94A1
+:101B200068BE9B01AC01C501B4010F949BC02FA1FD
+:101B300038A549A55AA50F94CDBD4B015C01C30141
+:101B4000B2010F9466BE9B01AC01C501B4010F94B4
+:101B5000C9BF18162CF4F801408251826282738248
+:101B600040900C1950900D1960900E1970900F193B
+:101B700081010D5B1F4FD8016D917D918D919C91DD
+:101B80000F9466BE4B015C016D966CAD7DAD8EAD64
+:101B90009FAD6D970F9468BE9B01AC01C501B40168
+:101BA0000F949BC02FA138A549A55AA50F94CDBD70
+:101BB0004B015C01C301B2010F9466BE9B01AC01F5
+:101BC000C501B4010F94C9BF18162CF4F801408266
+:101BD0005182628273824090081950900919609076
+:101BE0000A1970900B19D8016D917D918D919C917E
+:101BF0000F9466BE4B015C01F101608571858285A1
+:101C000093850F9468BE9B01AC01C501B4010F948C
+:101C10009BC02FA138A549A55AA50F94CDBD4B0156
+:101C20005C01C301B2010F9466BE9B01AC01C5010A
+:101C3000B4010F94C9BF181634F4D8014D925D92C7
+:101C40006D927C921397F101ED5BFF4F6081718182
+:101C5000828193810F9466BE4B015C01A7019601BE
+:101C60000F94CDBD69966CAF7DAF8EAF9FAF699776
+:101C7000F10162AB73AB84AB95AB2DEB37E346E080
+:101C800051E4C501B4010F949BC00F9435BED1013E
+:101C900054966D937D938D939C9357979296BC9198
+:101CA000BFA7F101F3A1FFABD1019496BC91BBAFEB
+:101CB000F101F5A1FBAB9E012F5E3F4F3EA32DA38B
+:101CC00044E159E15CA74BA78E010F5F1F4F4FA462
+:101CD0005FA86B2E7F2E1FA2D8018D909D90AD9096
+:101CE000BD908D01E894B7F8EBA5FCA5C190D1900B
+:101CF000E190F190FCA7EBA7A7019601C501B40103
+:101D00000F94C9BF181684F5FFA1FF2349F1920172
+:101D1000A301C501B4010F949BC04B015C012FA529
+:101D20003FA94BAD5BA9C701B6010F949BC06B01E6
+:101D30007C019B01AC01C501B4010F94C9BF181609
+:101D40009CF4A5019401C701B6010F94CDBD9B0180
+:101D5000AC01B201C3010F949BC02B013C0104C034
+:101D60002601370121E02FA34DA15EA1041715071D
+:101D700009F0B2CFC201D30189A39AA3ABA3BCA33C
+:101D800021968EAD9FAD219702970CF457C190918B
+:101D9000DC189FA3A091DD18ABA71091DE1800916D
+:101DA000DF1827E137EB41ED58E3692F7A2F812FB8
+:101DB000902F0F94C9BF18160CF040C1B1E0A39644
+:101DC000BFAFA3972FA53FA94BAD5BA96FA17BA583
+:101DD000812F902F0F94C9BF1816A4F0A3961FAEA1
+:101DE000A3972FA53FA94BAD5BA96FA17BA5812F21
+:101DF000902F0F94CDBDEA966CAF7DAF8EAF9FAFA5
+:101E0000EA9716C02FA13BA5412F502F6FA57FA9A0
+:101E10008BAD9BA90F94CDBDEA966CAF7DAF8EAF15
+:101E20009FAFEA97EFA5EFA3FFA9FBA71BAD0BA9F7
+:101E300020EE38E123963FAF2EAF239744E159E1DE
+:101E4000EC965FAF4EAFEC97CE010196EE969FAF4A
+:101E50008EAFEE97412C512C80E8682E8FE3782EC0
+:101E60001FAE2396AEADBFAD23978D909D90AD90E4
+:101E7000BD902396BFAFAEAF2397EE96EEADFFAD0C
+:101E8000EE97C190D190E190F190EE96FFAFEEAF5A
+:101E9000EE97A396FFADA397FF2361F0EA962CADD2
+:101EA0003DAD4EAD5FADEA97C501B4010F949BC047
+:101EB0004B015C012FAD222381F0A3019201C501EA
+:101EC000B4010F949BC04B015C01A3019201C701B7
+:101ED000B6010F949BC06B017C01A7019601C5015F
+:101EE000B4010F94C9BF20E030E0A9011816CCF46A
+:101EF000C701B6010F94C9BF18164CF020E030E0BE
+:101F0000A901C501B4010F94C6BD87FF05C0A70193
+:101F10009601C501B40118C0F7FAF094F7F8F094EF
+:101F20001CC0C701B6010F94C6BD87FD09C020E0E3
+:101F300030E0A901C501B4010F94C9BF18164CF4D3
+:101F4000A5019401C701B6010F94ECBC6B017C01A3
+:101F50000EC0B7FAB094B7F8B094A7019601C501C6
+:101F6000B4010F94C9BF181614F475016401EC96FE
+:101F7000AEADBFADEC978D909D90AD90BD90EC96C1
+:101F8000BFAFAEAFEC97A5019401C701B6010F94A6
+:101F9000C9BF181684F4A7019601C501B4010F94B6
+:101FA000CDBD9B01AC01C301B2010F949BC02B01BD
+:101FB0003C01B1E0BFAF2396EEADFFAD2397E05FEC
+:101FC000F84109F04ECF3FAD332361F0A3019201F8
+:101FD0006FA17BA5812F902F0F949BC06FA37BA730
+:101FE000182F092F24EA30E74DE75FE36FA17BA5A7
+:101FF000812F902F0F949BC06B017C019B01AC0142
+:102000006091D8187091D9188091DA189091DB18E6
+:102010000F94C9BF1816C4F4B9A0AAA09BA08CA0A5
+:10202000A70196016B2D7A2D892D982D0F94C9BF8C
+:10203000181654F4BFA2ABA6840106C049A14FA351
+:102040005AA15BA71BA10CA18FA19BA5A12FB02F0B
+:10205000F10182A793A7A4A7B5A7C9A0DAA0EBA016
+:10206000FCA0A7019601C701B6010F949BC04B01CC
+:102070005C0169966CAD7DAD8EAD9FAD6997905852
+:102080009B01AC010F94EDBC65962CAD3DAD4EAD02
+:102090005FAD65970F949BC09B01AC01C501B40176
+:1020A0000F94ECBC0F9454C1B62EA72E982E892EF7
+:1020B000262F372F482F592F6FA17BA5812F902FC7
+:1020C0000F94C6BD87FF05C04FA05BA4612E702E84
+:1020D00004C04B2C5A2C692C782CC201D301F1017D
+:1020E00086A397A3A0A7B1A781E086AB80E1FE01FC
+:1020F0003196A0EEB8E101900D928A95E1F78FA597
+:102100009FA9ABADBBA98093DC189093DD18A09379
+:10211000DE18B093DF18C092D818D092D918E09288
+:10212000DA18F092DB186D962CAD3DAD4EAD5FAD7B
+:102130006D97232B242B252B09F43EC0F1018081C0
+:102140009181A281B381892B8A2B8B2B41F48481CD
+:102150009581A681B781892B8A2B8B2B69F120E091
+:1021600030E0A90160915F13709160138091611359
+:10217000909162130F94C6BD8823F1F0F10180891C
+:102180009189A289B3896D962CAD3DAD4EAD5FAD01
+:102190006D97281739074A075B0771F011E020E0B7
+:1021A00030E0A901A8966CAD7DAD8EAD9FADA8972E
+:1021B0000F94C9BF18160CF010E0F101E05BFF4F5F
+:1021C0001083112309F469C080905F13909060130D
+:1021D000A0906113B090621330915B133FA34091C4
+:1021E0005C134BA700915D1310915E132DEB37E349
+:1021F00046E855E36FA17BA5C8010F94C6BD87FFD4
+:1022000011C0C258DF4F288139814A815B81CE5786
+:10221000D040A8966CAD7DAD8EAD9FADA8970F94C4
+:10222000CDBD03C06FA17BA5C8019B01AC01C50159
+:10223000B4010F949BC04B015C01D101D7966D9105
+:102240007D918D919C91DA970F9466BE9B01AC01B4
+:102250006FA57FA98BAD9BA90F94CDBD9B01AC0150
+:10226000C501B4010F949BC020914C1930914D19B8
+:1022700040914E1950914F190F949BC020E030E0CF
+:1022800040E853E40F949BC00F946BC0F101EF5AE8
+:10229000FF4F60837183828393838101045B1F4FAF
+:1022A000F10167A970AD81AD92AD0F9466BE2FA507
+:1022B0003FA94BAD5BA90F94CDBDD8016D937D9324
+:1022C0008D939C93139797018601A201B301C101DD
+:1022D0000F9422006E96BFAD6E97B0936413AC96C8
+:1022E0002CAD3DAD4EAD5FADAC972093F018309363
+:1022F000F1184093F2185093F318E0968CAD9DAD11
+:10230000AEADBFADE0978093F4189093F518A0930D
+:10231000F618B093F718A2962CAD3DAD4EAD5FAD5B
+:10232000A2972093F8183093F9184093FA18509315
+:10233000FB1861968CAD9DADAEADBFAD619780933E
+:10234000FC189093FD18A093FE18B093FF182A96DE
+:102350008FAD2A972B969FAD2B972C96AFAD2C97D0
+:102360002D96BFAD2D9780934B1390934C13A09354
+:102370004D13B0934E1329962CAD3DAD4EAD5FADD0
+:10238000299720934F133093501340935113509338
+:102390005213E4968CAD9DADAEADBFADE497809386
+:1023A000531390935413A0935513B0935613E6967A
+:1023B000EEADFFADE69780819181A281B3818093DC
+:1023C000571390935813A0935913B0935A13CE01F7
+:1023D00081960F94EB01AED3CF57DF4F0FB6F89431
+:1023E000DEBF0FBECDBFDF91CF911F910F91FF9048
+:1023F000EF90DF90CF90BF90AF909F908F907F90A5
+:102400006F905F904F903F902F9008952F923F9242
+:102410004F925F926F927F928F929F92AF92BF92F4
+:10242000CF92DF92EF92FF920F931F93CF93DF93A0
+:10243000CDB7DEB727970FB6F894DEBF0FBECDBF7E
+:10244000362E7F838B83292E49015A0127013801BB
+:10245000DA82C98280917612882309F463C02091C0
+:1024600066123091671240916812509169128B8107
+:102470000F949BC06B017C0120916A1230916B120A
+:1024800040916C1250916D12C501B4010F949BC024
+:102490009B01AC01C701B6010F94EDBC20914E1217
+:1024A00030914F1240915012509151120F94EDBC47
+:1024B000F62EE72ED82EC92E20916E1230916F1273
+:1024C0004091701250917112632D7F818B81922DFA
+:1024D0000F949BC06B837C838D839E8320917212AB
+:1024E000309173124091741250917512C501B4016C
+:1024F0000F949BC09B01AC016B817C818D819E817F
+:102500000F94EDBC2091521230915312409154120D
+:10251000509155120F94EDBC4B015C013F2CEF82A2
+:10252000DB822C2C209140193091411940914219A5
+:1025300050914319632D7F818B81922D0F949BC005
+:102540000F946BC06093F0187093F1188093F21899
+:102550009093F318209144193091451940914619F0
+:1025600050914719C501B4010F949BC00F946BC0E3
+:102570006093F4187093F5188093F6189093F718F9
+:10258000809177128823C9F095018401432D5F81E2
+:102590006B81722D87E792E10E9465449B01AC013B
+:1025A000C301B2010F94EDBC209148193091491933
+:1025B00040914A1950914B190AC020914819309105
+:1025C000491940914A1950914B19C301B2010F9416
+:1025D0009BC00F946BC06093F8187093F9188093A8
+:1025E000FA189093FB1820914C1930914D19409195
+:1025F0004E1950914F19E981FA8160817181828170
+:1026000093810F949BC00F946BC06093FC187093E0
+:10261000FD188093FE189093FF18832D9F81AB8146
+:10262000B22D80934B1390934C13A0934D13B09302
+:102630004E1380924F1390925013A0925113B09268
+:102640005213409253135092541360925513709248
+:102650005613E981FA8180819181A281B3818093AF
+:10266000571390935813A0935913B0935A132CEF08
+:1026700038E148EF58E164EF78E180EF98E10F949A
+:102680001B1F1092DC181092DD181092DE181092A9
+:10269000DF181092E0181092E1181092E2181092D0
+:1026A000E3181092E4181092E5181092E6181092B0
+:1026B000E7181092E8181092E9181092EA18109290
+:1026C000EB181092EC181092ED181092EE18109270
+:1026D000EF1827960FB6F894DEBF0FBECDBFDF917F
+:1026E000CF911F910F91FF90EF90DF90CF90BF900F
+:1026F000AF909F908F907F906F905F904F903F90A2
+:102700002F900895FC014081518162817381409333
+:102710005313509354136093551370935613209191
+:1027200048193091491940914A1950914B196081CB
+:102730007181828193810F949BC00F946BC06093D1
+:10274000F8187093F9188093FA189093FB182CEFEF
+:1027500038E148EF58E164EF78E180EF98E10D94BB
+:102760001B1FFC014081518162817381409357138B
+:10277000509358136093591370935A1320914C1926
+:1027800030914D1940914E1950914F1960817181CE
+:10279000828193810F949BC00F946BC06093FC184F
+:1027A0007093FD188093FE189093FF188CEF98E1BA
+:1027B0000D94571F60936C0270936D0280936E02AC
+:1027C00090936F020895CF92DF92EF92FF920F9352
+:1027D0001F93CF93DF9300D01F92CDB7DEB730E3C6
+:1027E000C32E39E1D32E40E4E42E49E1F42E00E07B
+:1027F00019E1F60161917191819191916F01F70158
+:1028000021913191419151917F0129833A834B83E9
+:102810005C830F9466BE29813A814B815C810F9461
+:102820009BC00F943ABEF801619371938193919389
+:102830008F01F0E4CF16F9E1DF06D9F60F900F9083
+:102840000F900F90DF91CF911F910F91FF90EF901C
+:10285000DF90CF9008958091641390916313891B4A
+:102860008F7008953091641320916313321791F0A3
+:10287000E0916413E11101C0E0E1E15027E5E202DB
+:10288000F0011124E654FC4E20813181280F391FBC
+:10289000318320830895509164134091631380E045
+:1028A00090E067E5541761F0649FF0011124E6544D
+:1028B000FC4E20813181820F931F4F5F4F70F2CF0A
+:1028C0000895CF93DF931F921F92CDB7DEB780910B
+:1028D000030A811128C08091C00087FF4EC08091FB
+:1028E000C00084FF04C08091C6008A8346C0609106
+:1028F000C6002091FF093091000AC90101968F7727
+:1029000099274091010A5091020A8417950741F0D6
+:10291000F901E158F64F60839093000A8093FF0914
+:102920001092030A2AC0813041F58091D00087FFC0
+:1029300024C08091D00084FF04C08091D600898398
+:102940001CC06091D6002091FF093091000AC90196
+:1029500001968F7799274091010A5091020A8417B6
+:10296000950741F0F901E158F64F60839093000A12
+:102970008093FF0981E08093030A0F900F90DF910D
+:10298000CF910895CF93DF9380918D19811109C064
+:1029900080918C19811105C080918B19882309F4CD
+:1029A000A0C0EFE3F0E18491882341F09091C00052
+:1029B00095FFFCCF8093C6003196F5CFC8EED2E4E8
+:1029C000FE0185919491FC012491222341F03091E4
+:1029D000C00035FFFCCF2093C6000196F4CF809154
+:1029E0008D19882319F160918E1970918F1980913A
+:1029F0009019909191190F9468BE209140193091CF
+:102A0000411940914219509143190F94CDBDAB012A
+:102A1000BC0186E396E40E944848FE0185919491AA
+:102A200064E376E40E94CECB0F947E5180918C19A2
+:102A3000882319F1609192197091931980919419DA
+:102A4000909195190F9468BE2091441930914519C1
+:102A500040914619509147190F94CDBDAB01BC016F
+:102A600080E396E40E944848FE01859194916EE2CD
+:102A700076E40E94CECB0F947E5180918B198823EF
+:102A800019F1609196197091971980919819909108
+:102A900099190F9468BE20914819309149194091B5
+:102AA0004A1950914B190F94CDBDAB01BC018AE27C
+:102AB00096E40E944848FE018591949168E276E48C
+:102AC0000E94CECB0F947E518091C00085FFFCCF39
+:102AD0008AE08093C60010928D1910928C19109282
+:102AE0008B19DF91CF91089580918D19811107C0C5
+:102AF00080918C19811103C080918B1901C081E0F4
+:102B000010928D1910928C1910928B190895809142
+:102B10008B1910928B19089590917602809376020A
+:102B2000892F0895909184198093841910928B199C
+:102B3000892F0895EFE6F0E0808182608083089518
+:102B4000CF92DF92EF92FF920F931F93CF93DF9379
+:102B50008091C3199091C419892B09F0BAC1909141
+:102B6000641380916313981771F08091631327E5C4
+:102B7000829FC00111248B599C4EFC01E55BFF4FE5
+:102B800021E0208302C080E090E09093C4198093FC
+:102B9000C319009709F497C11092C6191092C5196C
+:102BA0000E9453CB1092A0191092A1191092A21951
+:102BB0001092A319E091C319F091C41967A970ADDF
+:102BC00061344CE9740728F461325EE4750748F01B
+:102BD00002C060E47CE9769567957695679584E018
+:102BE00007C0613187E2780730F07695679582E01B
+:102BF00080939D1908C081E080939D196032710512
+:102C000010F460E270E0605271096115E8E07E073F
+:102C1000D0F0872F9927880F991F880F991F865CFE
+:102C2000954BFC01329645915491AA27659F9001DE
+:102C3000649F210D3A1F06942A1F3A1F1124FC019C
+:102C4000859194911DC0CB01969587958C7F865C6C
+:102C5000994BFC01459154910296FC018591949108
+:102C6000FB01E770FF278E9F90018F9F300D9E9F85
+:102C7000300D1124E3E036952795EA95E1F7CA0176
+:102C8000821B930B84369105B0F4E8ECF0E4A59137
+:102C9000B4918D91882339F09091C00095FFFCCFBD
+:102CA0008093C600F6CF4AE050E08EE799E00E949C
+:102CB000944284E690E090939C1980939B198091B4
+:102CC0009D1980939A19E091C319F091C41963ADCD
+:102CD00074AD70939F1960939E196134FCE97F076E
+:102CE00028F461322EE4720748F002C060E47CE907
+:102CF000769567957695679584E007C0613147E2E0
+:102D0000740730F07695679582E080939D1908C02E
+:102D100081E080939D196032710510F460E270E0EB
+:102D200060527109611558E07507E0F0872F992707
+:102D3000880F991F880F991F865C954BFC0132966E
+:102D400025913491AA27639FA001629F410D5A1FCC
+:102D500006944A1F5A1F1124FC0125913491241B0B
+:102D6000350B1EC0CB01969587958C7F865C994B61
+:102D7000FC01259134910296FC0145915491FB018F
+:102D8000E770FF274E9FC0014F9F900D5E9F900DF3
+:102D90001124D3E096958795DA95E1F7281B390B36
+:102DA00024363105B0F4E8ECF0E4A591B4918D91AE
+:102DB000882339F09091C00095FFFCCF8093C60026
+:102DC000F6CF4AE050E08EE799E00E94944224E674
+:102DD00030E0C901A0E0B0E08093A4199093A51958
+:102DE000A093A619B093A719309371192093701965
+:102DF000E091C319F091C419DF01A05BBF4F8C9122
+:102E0000882349F11196CD90DD90ED90FC90A09132
+:102E10009E19B0919F19A70196010F94F6C2A1E1E6
+:102E20009695879577956795AA95D1F770936719C9
+:102E30006093661967A970AD81AD92AD0F945AC2C7
+:102E4000B1E19695879577956795BA95D1F7709387
+:102E500069196093681980899189A289B389B695A7
+:102E6000A79597958795B095A095909581959F4F3B
+:102E7000AF4FBF4F8093B8199093B919A093BA1967
+:102E8000B093BB198093B4199093B519A093B61958
+:102E9000B093B7198093B0199093B119A093B21958
+:102EA000B093B3198093AC199093AD19A093AE1958
+:102EB000B093AF191092A8191092A9191092AA19DB
+:102EC0001092AB1906C080ED97E090937119809332
+:102ED000701910927219E091C319F091C4193097CA
+:102EE00009F4A2C6808D8093BC199FB780FF09C0EA
+:102EF000F89480910B01816080930B019FBF8FEF4D
+:102F000008C0F89480910B018E7F80930B019FBFC6
+:102F100081E0809372028091BC199FB781FF09C044
+:102F2000F89480910B018D7F80930B019FBF8FEFF1
+:102F300008C0F89480910B01826080930B019FBFC1
+:102F400081E0809373022091BC193091760220FFBA
+:102F50003FC0332309F479C04091060142FB442766
+:102F600040F94093C219442381F180918A19882342
+:102F700061F1E091C319F091C41980819181A2811E
+:102F8000B381181619061A061B06FCF480917319F2
+:102F900090917419A0917519B091761980938E193A
+:102FA00090938F19A0939019B093911981E0809319
+:102FB0008D1980899189A289B3898093A8199093EA
+:102FC000A919A093AA19B093AB1940938A193DC0CF
+:102FD0003323D9F14091060142FB442740F9409345
+:102FE000C119442381F180918919882361F1E0910D
+:102FF000C319F091C41980819181A281B3811816FF
+:1030000019061A061B06FCF4809173199091741925
+:10301000A0917519B091761980938E1990938F199C
+:10302000A0939019B093911981E080938D198089B4
+:103030009189A289B3898093A8199093A919A09323
+:10304000AA19B093AB194093891921FF3FC03323CC
+:1030500009F479C030910601331F3327331F3093B1
+:10306000C019332381F180918819882361F1E0919F
+:10307000C319F091C41984819581A681B78118166E
+:1030800019061A061B06FCF480917719909178199D
+:10309000A0917919B0917A1980939219909393190C
+:1030A000A0939419B093951981E080938C1980892D
+:1030B0009189A289B3898093A8199093A919A093A3
+:1030C000AA19B093AB19309388193DC03323D9F1B5
+:1030D00030910601331F3327331F3093BF19332339
+:1030E00081F180918719882361F1E091C319F091F2
+:1030F000C41984819581A681B781181619061A060C
+:103100001B06FCF48091771990917819A091791998
+:10311000B0917A198093921990939319A09394196E
+:10312000B093951981E080938C1980899189A28947
+:10313000B3898093A8199093A919A093AA19B09361
+:10314000AB19309387199FB722FF4DC0F894809137
+:103150000B01846080930B019FBF8FEF80937402FB
+:1031600080917602882309F488C0809184198111A6
+:1031700084C023B1229521702093BE19222381F1AE
+:1031800080918619882361F1E091C319F091C419E7
+:1031900080859185A285B385181619061A061B0627
+:1031A000FCF480917B1990917C19A0917D19B091CC
+:1031B0007E198093961990939719A0939819B093BC
+:1031C000991981E080938B1980899189A289B389AB
+:1031D0008093A8199093A919A093AA19B093AB1939
+:1031E000209386194AC0F89480910B018B7F8093BD
+:1031F0000B019FBF81E08093740280917602882347
+:10320000E1F121E08091E61A811101C020E02093D4
+:10321000BD19222381F180918519882361F1E09104
+:10322000C319F091C41980859185A285B3851816BC
+:1032300019061A061B06FCF480917B1990917C19E3
+:10324000A0917D19B0917E1980939619909397194A
+:10325000A0939819B093991981E080938B19808974
+:103260009189A289B3898093A8199093A919A093F1
+:10327000AA19B093AB1920938519809184198823DA
+:1032800081F123B1229521702093BE19222339F1B7
+:1032900080918619882319F180917B1990917C196E
+:1032A000A0917D19B0917E198093961990939719EA
+:1032B000A0939819B093991981E080938B19E091AC
+:1032C000C319F091C41980899189A289B389809327
+:1032D000A8199093A919A093AA19B093AB19209398
+:1032E00086198091BC199FB783FF09C0F89480911B
+:1032F0000B018F7B80930B019FBF8FEF08C0F89469
+:1033000080910B01806480930B019FBF81E08093CB
+:10331000750210E080919D19181708F0A3C18EE77F
+:1033200099E0CFDAE091C319F091C4198091AC19FA
+:103330009091AD19A091AE19B091AF194485558502
+:1033400066857785840F951FA61FB71F8093AC19DC
+:103350009093AD19A093AE19B093AF191816190632
+:103360001A061B06F4F54089518962897389841B0A
+:10337000950BA60BB70B8093AC199093AD19A09346
+:10338000AE19B093AF194091750280917F19909159
+:103390008019A0918119B0918219552747FD509548
+:1033A000652F752F840F951FA61FB71F80937F1958
+:1033B00090938019A0938119B09382198091BC19C0
+:1033C00083FF06C080916A1990916B19019705C01F
+:1033D00080916A1990916B19019690936B19809363
+:1033E0006A198091B8199091B919A091BA19B09140
+:1033F000BB194081518162817381840F951FA61F83
+:10340000B71F8093B8199093B919A093BA19B093C4
+:10341000BB19181619061A061B06F4F5409A809176
+:103420007219816080937219E091C319F091C419E7
+:103430008091B8199091B919A091BA19B091BB199E
+:103440004089518962897389841B950BA60BB70B40
+:103450008093B8199093B919A093BA19B093BB1976
+:10346000409172028091731990917419A09175190D
+:10347000B0917619552747FD5095652F752F840F0C
+:10348000951FA61FB71F8093731990937419A0936B
+:103490007519B09376194098E091C319F091C41949
+:1034A0008091B4199091B519A091B619B091B7193E
+:1034B0004481558166817781840F951FA61FB71FB0
+:1034C0008093B4199093B519A093B619B093B71916
+:1034D000181619061A061B06F4F5419A80917219FE
+:1034E000826080937219E091C319F091C4198091A0
+:1034F000B4199091B519A091B619B091B719408936
+:10350000518962897389841B950BA60BB70B809335
+:10351000B4199093B519A093B619B093B719409107
+:1035200073028091771990917819A0917919B091CF
+:103530007A19552747FD5095652F752F840F951FD4
+:10354000A61FB71F8093771990937819A0937919C4
+:10355000B0937A194198E091C319F091C419809100
+:10356000B0199091B119A091B219B091B3194085D9
+:10357000518562857385840F951FA61FB71F8093A1
+:10358000B0199093B119A093B219B093B31918164A
+:1035900019061A061B06F4F5429A80917219846086
+:1035A00080937219E091C319F091C4198091B019F8
+:1035B0009091B119A091B219B091B3194089518974
+:1035C00062897389841B950BA60BB70B8093B01986
+:1035D0009093B119A093B219B093B31940917402AA
+:1035E00080917B1990917C19A0917D19B0917E19E1
+:1035F000552747FD5095652F752F840F951FA61FE2
+:10360000B71F80937B1990937C19A0937D19B09379
+:103610007E1942988091A8199091A919A091AA1990
+:10362000B091AB190196A11DB11D8093A81990937B
+:10363000A919A093AA19B093AB194091A819509158
+:10364000A9196091AA197091AB19E091C319F09171
+:10365000C41980899189A289B389481759076A07D3
+:103660007B0720F1E091C319F091C419DF01A05B41
+:10367000BF4F1C911123E1F0809166199091671959
+:103680002091641930916519AC01421B530B909342
+:1036900065198093641980916A1990916B19840F50
+:1036A000951F90936B1980936A1902C01F5F32CEE9
+:1036B00080916A1990916B19892B21F010926F19E2
+:1036C00010926E194091A8195091A9196091AA19E8
+:1036D0007091AB19828D938DA48DB58D841795074C
+:1036E000A607B70708F4F2C04091A4195091A51994
+:1036F0006091A6197091A7190489158926893789BF
+:10370000AA27419FB12D529FC001629F900D619FDA
+:10371000800D911D429FB00D811D9A1F519FB00DCC
+:10372000811D9A1F609FB00D811D9A1F509FB10D82
+:103730008A1F9A1FB6958A1F9A1F112443AD54AD54
+:10374000480F591F50939F1940939E1987A990AD18
+:10375000A1ADB2AD60E070E084179507A607B7078A
+:1037600020F490939F1980939E1960919E197091F7
+:103770009F1961345CE9750728F461328EE478079B
+:1037800048F002C060E47CE9769567957695679588
+:1037900084E007C06131E7E27E0730F076956795F7
+:1037A00082E080939D1908C081E080939D1960326A
+:1037B000710510F460E270E0605271096115F8E083
+:1037C0007F07E8F0872F9927880F991F880F991F87
+:1037D000865C954BFC01329645915491AA27659FD2
+:1037E0009001649F210D3A1F06942A1F3A1F11244D
+:1037F000FC0145915491FA01E21BF30B1FC0CB0170
+:10380000969587958C7F865C994BFC012591349128
+:103810000296FC0145915491FB01E770FF274E9FF2
+:10382000C0014F9F900D5E9F900D1124C3E09695AF
+:103830008795CA95E1F7F901E81BF90BE436F10524
+:10384000B0F4E8ECF0E4A591B4918D91882339F0BF
+:103850009091C00095FFFCCF8093C600F6CF4AE060
+:1038600050E08EE799E00E949442E4E6F0E0F093A5
+:103870007119E09370198091A4199091A519A091E4
+:10388000A619B091A7198E0F9F1FA11DB11D80937E
+:10389000A4199093A519A093A619B093A719809184
+:1038A000C3199091C419DC01A05BBF4F2C91222356
+:1038B00009F419C1A0919E19B0919F19EC01CF5A3A
+:1038C000DF4F288139814A815B8100C14091A8196D
+:1038D0005091A9196091AA197091AB19868D978D95
+:1038E000A0A1B1A184179507A607B70708F022C1C8
+:1038F0004091A0195091A1196091A2197091A3193A
+:103900000489158926893789AA27419FB12D529F9D
+:10391000C001629F900D619F800D911D429FB00D6F
+:10392000811D9A1F519FB00D811D9A1F609FB00D80
+:10393000811D9A1F509FB10D8A1F9A1FB6958A1F2D
+:103940009A1F112400919E1910919F19FF96081734
+:10395000190718F40081118102C0081B190B80811E
+:103960009181A281B381A80160E070E048175907F6
+:103970006A077B0708F48C0101342CE9120730F444
+:1039800001324EE4140750F0B80102C060E47CE953
+:10399000769567957695679584E008C0013157E282
+:1039A000150738F0B8017695679582E080939D19E8
+:1039B0000AC081E080939D190032110510F0B80112
+:1039C00002C060E270E060527109611588E078071A
+:1039D000E8F0872F9927880F991F880F991F865C19
+:1039E000954BFC01329645915491AA27659F900111
+:1039F000649F210D3A1F06942A1F3A1F1124FC01CF
+:103A000045915491FA01E21BF30B1FC0CB0196952F
+:103A100087958C7F865C994BFC01259134910296A9
+:103A2000FC0145915491FB01E770FF274E9FC001B7
+:103A30004F9F900D5E9F900D112443E096958795C2
+:103A40004A95E1F7F901E81BF90BE436F105B0F40A
+:103A5000E8ECF0E4A591B4918D91882339F0909130
+:103A6000C00095FFFCCF8093C600F6CF4AE050E03F
+:103A70008EE799E00E949442E4E6F0E0F093711939
+:103A8000E09370198091A0199091A119A091A219A9
+:103A9000B091A3198E0F9F1FA11DB11D8093A01976
+:103AA0009093A119A093A219B093A3198091C3195F
+:103AB0009091C419DC01A05BBF4F2C91222399F097
+:103AC00011962D913D914D915C91D8010F94F6C2C4
+:103AD00021E196958795779567952A95D1F770930B
+:103AE00067196093661980916A1990916B19892BF7
+:103AF000C1F020919D192E9FC0012F9F900D112480
+:103B000020916A1930916B1960916A1970916B1943
+:103B1000121613061CF07195619571090F9476C207
+:103B200004C0609170027091710270936D1960937E
+:103B30006C193AC0112341F080916819909169196C
+:103B4000909367198093661980916A1990916B1907
+:103B5000E0919A1920919B1930919C19892BB1F011
+:103B6000E29FC001E39F900D112440916A1950918A
+:103B70006B1960916A1970916B19141615061CF077
+:103B80007195619571090F9476C204C060917002BD
+:103B90007091710270936D1960936C193093711963
+:103BA00020937019E0939D190091A8191091A919FB
+:103BB0002091AA193091AB198091C3199091C41921
+:103BC000FC014089518962897389E091C519F0919E
+:103BD000C6190417150726073707C0F0BF010E9452
+:103BE0007BCB1092C6191092C5191092C41910926D
+:103BF000C31990916413809163139817A9F0809171
+:103C000063138F5F8F70809363130EC020916A02DD
+:103C100030916B02E217F3073CF0BF010E947BCBAF
+:103C20001092C6191092C51980917219DF91CF9127
+:103C30001F910F91FF90EF90DF90CF900D94CF37B1
+:103C400080916A1990916B19892BF9F080916A190A
+:103C500090916B1997FD06C09FB7F89480910B0166
+:103C6000806405C09FB7F89480910B018F7B80938F
+:103C70000B019FBF20919D1980916A1990916B193A
+:103C8000892B59F0211112C008C0809170029091C7
+:103C9000710290936D1980936C1980916C199091B9
+:103CA0006D1990936F1980936E190895439A8091BE
+:103CB0006A1990916B1997FF06C080916A199091CB
+:103CC0006B19019605C080916A1990916B19019743
+:103CD00090936B1980936A1943988091C5199091BC
+:103CE000C61901969093C6198093C5192150C4CF67
+:103CF0008091701990917119892B11F40F94A0156E
+:103D000080916E1990916F19892B09F499DF209198
+:103D10006E1930916F1980917019909171198217F5
+:103D20009307C8F030938900209388008091701920
+:103D300090917119009751F020916E1930916F197F
+:103D4000821B930B909371198093701910926F19C5
+:103D500010926E191FC09093890080938800809103
+:103D60006E1990916F19009789F02091700230912F
+:103D700071028217930751F02091701930917119D7
+:103D8000821B930B90936F1980936E191092711987
+:103D900010927019209188003091890080918400E0
+:103DA0009091850040962817390748F48091840047
+:103DB00090918500409690938900809388000895A3
+:103DC0001F920F920FB60F9211240BB60F922F93E2
+:103DD0003F934F935F936F937F938F939F93AF9393
+:103DE000BF93EF93FF9384DFFF91EF91BF91AF916A
+:103DF0009F918F917F916F915F914F913F912F9103
+:103E00000F900BBE0F900FBE0F901F9018959091C2
+:103E1000641380916313981769F00F94F32B0F9438
+:103E2000813F8111F4CF81E00E94BD5C80E00F945E
+:103E30000A97EDCF0895CF93DF93EFB7F894EC0195
+:103E400088819981AA81BB81809373199093741999
+:103E5000A0937519B0937619EB0188819981AA8195
+:103E6000BB818093771990937819A0937919B093B7
+:103E70007A19EA0188819981AA81BB8180937B1993
+:103E800090937C19A0937D19B0937E19E9018881E4
+:103E90009981AA81BB8180937F1990938019A09307
+:103EA0008119B0938219EFBFDF91CF9108952FB799
+:103EB000F894FC0180819181A281B38180937F1964
+:103EC00090938019A0938119B09382192FBF089500
+:103ED0002FB7F89494E0899FF0011124ED58F64E25
+:103EE00060817181828193812FBF0895CF93C82F04
+:103EF000EFDF0F9468BE24E0C29FF0011124E05C64
+:103F0000F64E20813181428153810F94CDBDCF91F6
+:103F100008957DDF179A1092D10A169A1092D20A4C
+:103F2000149A089580916F008D7F80936F00909117
+:103F3000641380916313981769F0909164138091D2
+:103F400063139817A1F3809163138F5F8F70809331
+:103F50006313EDCF1092C4191092C31980916F00B2
+:103F6000826080936F000895CF93DF93CDB7DEB763
+:103F70002C970FB6F894DEBF0FBECDBF8130A1F1F4
+:103F800020F0823009F45FC08FC01798209109019A
+:103F900021709FB7611105C0F89480910B01816079
+:103FA00004C0F89480910B018E7F80930B019FBF1A
+:103FB000409A8091721981608093721980E090E03C
+:103FC000A0E0BFE389879A87AB87BC8740989FB7FB
+:103FD000222329F0F89480910B01816062C0F8944B
+:103FE00080910B018E7F5DC016982091090122708F
+:103FF0009FB7662329F0F89480910B01826004C07A
+:10400000F89480910B018D7F80930B019FBF419AA3
+:10401000809172198260809372198BEA9AEAAAE2FF
+:10402000BEE38D839E83AF83B88741989FB72223D9
+:1040300029F0F89480910B01826033C0F89480914C
+:104040000B018D7F2EC015982091090124709FB718
+:10405000611105C0F89480910B01846004C0F8944C
+:1040600080910B018B7F80930B019FBF429A8091BF
+:1040700072198460809372198BEA9AEAAAEABEE305
+:1040800089839A83AB83BC8342989FB7222329F00C
+:10409000F89480910B01846004C0F89480910B0126
+:1040A0008B7F80930B019FBF2C960FB6F894DEBFD9
+:1040B0000FBECDBFDF91CF910895EF92FF920F9386
+:1040C0001F93CF93DF931F92CDB7DEB77B018C0197
+:1040D000061B170B460FC701800F911F49830F94D2
+:1040E00044CAF70181937F0149814E13F4CF0F90A9
+:1040F000DF91CF911F910F91FF90EF900895DB0119
+:1041000081110DC02FEF30E00F94F0C220ED37E0A9
+:1041100040E050E00F94BFC2B9018EE21DC0813073
+:1041200069F42FEF30E00F94F0C220ED37E040E06B
+:1041300050E00F94BFC2B9018DE20EC0823071F41D
+:104140002FEF30E00F94F0C220ED37E040E050E078
+:104150000F94BFC2B9018CE20D94C2B5089541E03D
+:1041600063E879E18FEF9FE0A8DF61E08EE20F94D2
+:10417000DAB661E08DE20F94DAB661E08CE20F947A
+:10418000DAB680918319882321F08091921B8823CD
+:10419000A9F08091770290917802909384028093A5
+:1041A00083028091790290917A02909386028093A3
+:1041B000850280917B0290917C0214C080917D02E7
+:1041C00090917E02909384028093830280917F027B
+:1041D0009091800290938602809385028091810263
+:1041E000909182029093880280938702609183026B
+:1041F0007091840280E083DF609185027091860275
+:1042000081E07DDFA0918702B09188022FEF30E03E
+:104210000F94F0C220ED37E040E050E00F94BFC2B1
+:10422000B9018CE20F94C2B580912101887F816031
+:104230008093210108950F94653C91DFEAE0F1E05D
+:1042400080818160808380818260808380818460BE
+:1042500080838081806480830F9A179A0E9A169AC1
+:104260000D9A159A0C9A149AE7E0F1E080818B7F01
+:1042700080839FB7F894E8E0F1E0808184608083D8
+:104280009FBFE7E0F1E080818F7780839FB7F8944C
+:10429000E8E0F1E08081806880839FBFE7E0F1E0A3
+:1042A00080818F7B80839FB7F894E8E0F1E0808184
+:1042B000806480839FBF26982E9A25982D9A2498F3
+:1042C0002C9AE7E0F1E080818B7F80839FB7F894A0
+:1042D000E8E0F1E08081846080839FBFE7E0F1E067
+:1042E00080818F7780839FB7F894E8E0F1E0808148
+:1042F000806880839FBF0998119A389A4098179ACE
+:104300001092D10A399A4198169A1092D20A3A9A82
+:1043100042983B9A4398149AA1E8B0E08C918F7E22
+:104320008C938C9188608C93E0E8F0E080818D7FA5
+:10433000808380818E7F808380818F738083808162
+:104340008F7C80838C91887F82608C9380E090E466
+:1043500090938900809388001092850010928400C9
+:10436000EFE6F0E080818260808310926B191092FA
+:104370006A19109265191092641981E0809376028F
+:1043800078940895809170029091710290936F19C2
+:1043900080936E1990936D1980936C190895809392
+:1043A0008B0260938A024093890261E00F94DAB62F
+:1043B00061E080918A020F94DAB661E080918B020D
+:1043C0000F9413B761E080918A020F9413B788EEBF
+:1043D00093E00D9455B5CF93DF93EC0160E08091AD
+:1043E0008B020F9413B7CE010F9455B560E0809106
+:1043F0008A020F9413B7CE01DF91CF910D9455B57A
+:10440000CF93DF93EC0161E080918A020F9413B7A0
+:10441000CE010F9455B561E080918B020F9413B7D4
+:10442000CE01DF91CF910D9455B50F931F93CF938C
+:10443000DF93EC018B0160E080918B020F94DAB680
+:10444000CE010F9455B5CE010F9455B561E0809122
+:104450008A020F9413B780918B020F9448B7892B6F
+:1044600019F401E010E00CC00115110519F400E089
+:1044700010E006C001501109CE010F9455B5EBCFE5
+:1044800060E080918A020F9413B7CE010F9455B566
+:1044900061E080918B020F94DAB6CE010F9455B58E
+:1044A00060E080918B020F9413B7CE010F9455B545
+:1044B000C801DF91CF911F910F910895DF92EF9284
+:1044C000FF920F931F93CF93DF937C0161E0809164
+:1044D0008B020F9413B7C7010F9455B560E080911C
+:1044E0008B020F94DAB607E010E0D12C61E08091E6
+:1044F0008A020F9413B7C7010F9455B580918B02B0
+:104500000F9448B7C1E0D0E0892B11F4C0E0D0E0AF
+:10451000002E01C0CC0F0A94EAF7CD29DC2E60E012
+:1045200080918A020F9413B7C7010F9455B50150BB
+:104530001109E0F661E080918B020F94DAB68C2FBE
+:10454000DF91CF911F910F91FF90EF90DF90089531
+:10455000EF92FF920F931F93CF93DF938C01C7E0ED
+:10456000D0E0E62EF12CC7010C2E02C09595879560
+:104570000A94E2F780FF02C061E001C060E0809130
+:104580008B020F9413B7C8010F9455B561E0809169
+:104590008A020F9413B7C8010F9455B560E080915B
+:1045A0008A020F9413B7C8010F9455B52197D8F616
+:1045B000DF91CF911F910F91FF90EF9008959F92FF
+:1045C000AF92BF92CF92DF92EF92FF920F931F9321
+:1045D000CF93DF93E82E962E5A0190918902C92F2E
+:1045E000CF7021E030E0A90102C0440F551FCA95E9
+:1045F000E2F7EA0192959F70690102C0CC0CDD1CC4
+:104600009A95E2F7CA01E7DEF12CEE0CFF1C6E2D45
+:10461000CE019EDFB601CE0108DF8C01009719F4B0
+:10462000CE01EEDE24C0692DCE0192DFB601CE01AF
+:10463000FCDE892B19F400E010E019C0CE01E0DEA9
+:10464000CE01C9DE6E2D6160CE0182DFB601CE01E2
+:10465000ECDE892B81F3CE0131DF182FCE01D0DEC5
+:10466000A114B10411F0F501108301E010E0C801BC
+:10467000DF91CF911F910F91FF90EF90DF90CF903E
+:10468000BF90AF909F900895BF92CF92DF92EF922C
+:10469000FF920F931F93CF93DF93182FB62E6A01CB
+:1046A00090918902C92FCF7021E030E0A90102C0AA
+:1046B000440F551FCA95E2F7EA0192959F70790160
+:1046C00002C0EE0CFF1C9A95E2F7CA0184DE612F4E
+:1046D00070E0660F771FCE013BDFB701CE01A5DE8C
+:1046E0008C01009719F4CE018BDE18C06B2DCE0122
+:1046F0002FDFB701CE0199DE892B19F400E010E01D
+:104700000DC0F6016081CE0123DFB701CE018DDE41
+:10471000892BA1F3CE0174DE01E010E0C801DF9126
+:10472000CF911F910F91FF90EF90DF90CF90BF90AE
+:1047300008954F925F926F927F928F929F92AF9265
+:10474000BF92CF92DF92EF92FF920F931F93CF937E
+:10475000DF932C012AEA32E581E090E0F9014591EE
+:104760005491441655060CF062C0AC0141505109F9
+:10477000DA01AA0FBB1FAA0FBB1FA855BD4AFD0136
+:1047800065917491440F551F440F551F4A555D4A5A
+:10479000FA0165907490FC01EE0FFF1FEE0FFF1FF2
+:1047A000E855FD4AA590B490FD0105911491F901D9
+:1047B000C591D491FA0185909490882777FD8095D2
+:1047C000982F0F9468BE6B017C01B20166197709BE
+:1047D000882777FD8095982F0F9468BE2B013C01A8
+:1047E000B501601B710B882777FD8095982F0F947A
+:1047F00068BE9B01AC01C301B2010F949BC02B01A9
+:104800003C01BE0168197909882777FD8095982FAA
+:104810000F9468BE9B01AC01C301B2010F94CDBDE2
+:104820009B01AC01C701B6010F94EDBC11C001960C
+:104830002C5F3F4F8D33910509F090CFE8E9F3E508
+:1048400065917491882777FD8095982F0F9468BEA5
+:104850006B017C0120E030E040E252E4C701B60188
+:104860000F94C9BF87FD1BC020E030E048E452E44C
+:10487000C701B6010F94C6BD18168CF020E030E0D9
+:1048800040E252E4C701B6010F94ECBC20E030E0F6
+:1048900040E05FE30F949BC09B01AC013FC020E070
+:1048A00030E048E452E4C701B6010F94C9BF1816BE
+:1048B0003CF520E030E048EC52E4C701B6010F942B
+:1048C000C6BD1816ECF020E030E040EA50E4C70125
+:1048D000B6010F94EDBC4B015C0120E030E048E4F0
+:1048E00052E4C701B6010F94ECBC2DEC3CEC4CEC4F
+:1048F0005DE30F949BC09B01AC01C501B40110C0E6
+:1049000020E030E048EC52E4C701B6010F94C9BF83
+:10491000181654F420E030E040E251E4C701B6013B
+:104920000F94EDBC6B017C01C701B601DF91CF9103
+:104930001F910F91FF90EF90DF90CF90BF90AF90BD
+:104940009F908F907F906F905F904F9008954F92BF
+:104950005F926F927F928F929F92AF92BF92CF920F
+:10496000DF92EF92FF920F931F93CF93DF932C016F
+:10497000662389F1E5E4F0E18491882341F0909188
+:10498000C00095FFFCCF8093C6003196F5CF70E054
+:104990004AE050E08EE799E00E944242E7E8F0E505
+:1049A0008491882341F09091C00095FFFCCF8093C3
+:1049B000C6003196F5CF8091C00085FFFCCF8AE01C
+:1049C0008093C60066E08EEF98E00E94475C60E04E
+:1049D00070E0CB017EC02AE232E581E090E0F9018F
+:1049E00045915491441655060CF062C0AC014150FB
+:1049F0005109DA01AA0FBB1FAA0FBB1FA85DBD4A50
+:104A0000FD0165917491440F551F440F551F4A5D78
+:104A10005D4AFA0165907490FC01EE0FFF1FEE0FE6
+:104A2000FF1FE85DFD4AA590B490FD01059114912A
+:104A3000F901C591D491FA0185909490882777FD6A
+:104A40008095982F0F9468BE6B017C01B2016619A6
+:104A50007709882777FD8095982F0F9468BE2B01E2
+:104A60003C01B501601B710B882777FD8095982F5D
+:104A70000F9468BE9B01AC01C301B2010F949BC0AF
+:104A80002B013C01BE0168197909882777FD8095C3
+:104A9000982F0F9468BE9B01AC01C301B2010F9423
+:104AA000CDBD9B01AC01C701B6010F94EDBC11C097
+:104AB00001962C5F3F4F8032910509F090CFE4EAD8
+:104AC000F2E565917491882777FD8095982F0F9472
+:104AD00068BEDF91CF911F910F91FF90EF90DF9013
+:104AE000CF90BF90AF909F908F907F906F905F908E
+:104AF0004F9008954F925F926F927F928F929F9204
+:104B0000AF92BF92CF92DF92EF92FF920F931F93DB
+:104B1000CF93DF9360E08091731A9091741A17DF3E
+:104B200060936F1A7093701A8093711A9093721A2F
+:104B300080916D1A90916E1AFCDD6093691A7093E2
+:104B40006A1A80936B1A90936C1A4090671A50906F
+:104B5000681A22EA31E581E090E0F901459154912B
+:104B6000441655060CF062C0AC0141505109DA01FF
+:104B7000AA0FBB1FAA0FBB1FA056BE4AFD0165911D
+:104B80007491440F551F440F551F42565E4AFA0157
+:104B900065907490FC01EE0FFF1FEE0FFF1FE056B3
+:104BA000FE4AA590B490FD0105911491F901C591BB
+:104BB000D491FA0185909490882777FD8095982F5D
+:104BC0000F9468BE6B017C01B201661977098827D2
+:104BD00077FD8095982F0F9468BE2B013C01B5019D
+:104BE000601B710B882777FD8095982F0F9468BE06
+:104BF0009B01AC01C301B2010F949BC02B013C018E
+:104C0000BE0168197909882777FD8095982F0F9440
+:104C100068BE9B01AC01C301B2010F94CDBD9B01E5
+:104C2000AC01C701B6010F94EDBC11C001962C5F19
+:104C30003F4F8232910509F090CFE4E2F2E56591B1
+:104C40007491882777FD8095982F0F9468BE6093A4
+:104C5000631A7093641A8093651A9093661A809110
+:104C6000611A9091621A65DD60935D1A70935E1A05
+:104C700080935F1A9093601A8FB7F8941092431A3A
+:104C80008FBFDF91CF911F910F91FF90EF90DF9039
+:104C9000CF90BF90AF909F908F907F906F905F90DC
+:104CA0004F9008952091A9023091AA024091AB0241
+:104CB0005091AC0260E070E08FE793E40F94CDBDBB
+:104CC0006093231A7093241A8093251A9093261ABE
+:104CD0002091990230919A0240919B0250919C023E
+:104CE00060E070E08FE793E40F94CDBD6093021A0B
+:104CF0007093031A8093041A9093051A089597FFEE
+:104D000003C080914A1A04C0FC01EF5FF54E808118
+:104D100090E00895CF93DF93D82FC62FC19561E01F
+:104D20000F94DAB66C2F8D2F0F9413B76C2F70E0A1
+:104D30008D2FDF91CF910D94C2B58F929F92AF923C
+:104D4000BF92CF92DF92EF92FF920F931F93CF9378
+:104D5000DF93C0E1DBE068817981882777FD80956A
+:104D6000982F0F9468BE6B017C010F94EFB40091F3
+:104D7000FD191091FE192091FF193091001A601B46
+:104D8000710B820B930B0F9466BE9B01AC0160E02C
+:104D900070E08AE793E40F94CDBD9B01AC01C7019D
+:104DA000B6010F949BC00F9435BE70930D0B6093AA
+:104DB0000C0B02E11BE0F80160817181882777FD0F
+:104DC0008095982F0F9468BE6B017C010F94EFB40F
+:104DD0008090FD199090FE19A090FF19B090001AD4
+:104DE000681979098A099B090F9466BE9B01AC0179
+:104DF00060E070E08AE793E40F94CDBD9B01AC01C5
+:104E0000C701B6010F949BC00F9435BE70930F0B72
+:104E100060930E0B19821882F80111821082DF91C3
+:104E2000CF911F910F91FF90EF90DF90CF90BF90A7
+:104E3000AF909F908F900895CF93C82F0F94B25149
+:104E4000882321F08091931B811191C080916C0B7C
+:104E5000882379F02091270B3091280B232B19F010
+:104E60000F94A3980AC081E08093931B0F9463472B
+:104E700004C01092781A1092771AE5E4F0E1949148
+:104E8000992341F08091C00085FFFCCF9093C6002C
+:104E90003196F5CFCC2331F0C13009F068C0E3E1A1
+:104EA000F0E53AC0E6E5F0E58491882341F0909181
+:104EB000C00095FFFCCF8093C6003196F5CF80915E
+:104EC000C00085FFFCCF8AE08093C6000F94B251EA
+:104ED00081114DC09FB7F894809102018460809346
+:104EE00002019FBF88EC90E00F9455B59FB7F894EE
+:104EF000809102018B7F809302019FBF84E690E046
+:104F00000F9455B581E490E52FC09091C00095FFB6
+:104F1000FCCF8093C600319684918111F6CF8091A9
+:104F2000C00085FFFCCF8AE08093C6000F94B25189
+:104F300081111DC09FB7F894809102018460809315
+:104F400002019FBF88EC90E00F9455B59FB7F8948D
+:104F5000809102018B7F809302019FBF84E690E0E5
+:104F60000F9455B58EEF9FE4CF910D94A951CF9139
+:104F70000895CF9387E89FE00F9444CAC1E0811160
+:104F800001C0C0E080910C0B90910D0B892BB1F406
+:104F900020E030E048E452E460916F1A7091701A9A
+:104FA0008091711A9091721A0F94C9BF181634F437
+:104FB0008091F2198F5F8093F21902C01092F2195A
+:104FC00080910E0B90910F0B892B69F48091CA0A86
+:104FD0009091CB0A8C34910534F08091F3198F5F56
+:104FE0008093F31902C01092F3198091F219863060
+:104FF00020F0CC2311F080E01FDF8091F319803185
+:1050000028F0CC2319F081E0CF9116CFCF910895ED
+:10501000CF93C1E020E030E048E452E460916F1AA1
+:105020007091701A8091711A9091721A0F94C9BF81
+:1050300018160CF0C0E06C2F88E090E0CF916ACE9B
+:10504000CF93DF931092271A1092281A1092291AE0
+:1050500010922A1A2091A9023091AA024091AB0223
+:105060005091AC0260E070E08FE793E40F94CDBD07
+:105070006093231A7093241A8093251A9093261A0A
+:105080001092061A1092071A1092081A1092091A12
+:105090002091990230919A0240919B0250919C027A
+:1050A00060E070E08FE793E40F94CDBD6093021A47
+:1050B0007093031A8093041A9093051A6D9A9D9A1F
+:1050C000809101018860809301018091940286950E
+:1050D0008093FC1980914B1A8093FB1981E0809397
+:1050E000FA1987ED80937A0010927E0010927D006D
+:1050F00080917E00816080937E0080917E0082603E
+:1051000080937E0080917E00846080937E0080E8A2
+:1051100088BD80916E00846080936E006AEF70E0BD
+:1051200080E090E00F941EB58FE090E09093F71927
+:105130008093F61960E0809192029091930207DCCF
+:1051400020E030E040E751E40F94C6BD87FF0AC07D
+:105150008091920290919302409790939302809352
+:105160009202E8CF81E391E09093910280939002C4
+:1051700060E08091F8199091F919E9DB20E030E8BE
+:1051800048E953E40F94C9BF181654F48091F819F4
+:105190009091F91940969093F9198093F819E8CFF6
+:1051A000C0918E02D0918F02CE01C3DA20E030E0B0
+:1051B00040E751E40F94C6BD87FF06C06097D093C7
+:1051C0008F02C0938E02ECCF8091F4199091F51963
+:1051D000B0DA20E030E046E153E40F94C9BF18167E
+:1051E00054F48091F4199091F51940969093F51923
+:1051F0008093F419E9CFDF91CF910895089510922B
+:10520000781A1092771A1092761A1092751A1092D4
+:10521000011A75981092761A1092751A10924A1AFD
+:10522000A5980895CF93DF93D82FC62F81E0809360
+:10523000BB0A0F94921F80916C0B882339F0109257
+:105240006C0B60E08AE69BE00E9463BCD8DF179A93
+:105250001092D10A169A1092D20A149AC4D280E0FF
+:105260000F940A978FB7F8949091020194609093ED
+:1052700002018FBF84EF91E00F9455B58FB7F8947A
+:10528000909102019B7F909302018FBF84E690E092
+:105290000F9455B5DD2309F463C00E94305DCC2323
+:1052A00019F08CEE9FE402C08EED9FE40F94A9519B
+:1052B000E5E4F0E18491882341F09091C00095FFEE
+:1052C000FCCF8093C6003196F5CFCC2391F0EAEB6A
+:1052D000FFE48491882341F09091C00095FFFCCFBA
+:1052E0008093C6003196F5CF8091C00085FFFCCF3A
+:1052F00011C0E7E9FFE48491882341F09091C00058
+:1053000095FFFCCF8093C6003196F5CF8091C00009
+:1053100085FFFCCF8AE08093C60080910101806206
+:1053200080930101809101018860809301019FB702
+:10533000F894809102018062809302019FBF6FEF19
+:1053400070E086E00F94C2B58FEF90E09093CB0AA7
+:105350008093CA0A80ED97E0DF91CF910D9455B507
+:10536000CC2319F083E89FE402C083E79FE40F9405
+:10537000A951E5E4F0E18491882341F09091C000C7
+:1053800095FFFCCF8093C6003196F5CFCC2391F0EA
+:10539000EAE5FFE48491882341F09091C00095FFF5
+:1053A000FCCF8093C6003196F5CF8091C00085FF79
+:1053B000FCCF11C0E2E4FFE48491882341F0909196
+:1053C000C00095FFFCCF8093C6003196F5CF809149
+:1053D000C00085FFFCCF8AE08093C600DF91CF91AB
+:1053E00008952F923F924F925F926F927F928F9289
+:1053F0009F92AF92CF92DF92EF92FF920F931F9303
+:10540000CF93DF93CDB7DEB72C970FB6F894DEBFFE
+:105410000FBECDBF1C012A013B0109831A832B83D8
+:105420003C83AA2039F01A8619861D821E821F82AB
+:1054300018860CC02DE230E03A87298780E090E0A2
+:10544000A0E7B1E48D839E83AF83B8870F94EFB458
+:105450000F9466BE8101000F111F000F111FD801AC
+:10546000AF57B54E4D012D913D914D915C910F94EB
+:10547000ECBC20E030E04AEF54E40F94C9BF1816AA
+:105480000CF099C10F94EFB40F9466BEF4016083E1
+:1054900071838283938320E030E0A901C701B601C4
+:1054A0000F94C6BD811107C0F101EE0FFF1FE75831
+:1054B000F54E1182108298012F56354E4901A301F5
+:1054C0009201D4016D917D918D919C910F94C6BDF7
+:1054D0008823B1F120E030E0A901C301B2010F94AB
+:1054E000C9BFF801EF55F54E181604F580E090E0BD
+:1054F000A0E8BFE380839183A283B383F401408259
+:10550000518262827382F801E651F64E89819A8156
+:10551000AB81BC8180839183A283B383F101EE0FC1
+:10552000FF1FEA51F64E118210820AC010821182CA
+:1055300012821382D4014D925D926D927C921397E8
+:1055400020E030E040E85FE3F801EF55F54E608180
+:105550007181828193810F94C6BD81118BC0AA2075
+:1055600059F02DEC3CEC4CE45FE3C301B2010F9425
+:105570009BC09B01AC0104C020E030E046E153E455
+:1055800069817A818B819C810F94C6BD87FF72C02F
+:105590004101880C991CF401EA51F64E80819181F9
+:1055A000019691838083AA2019F020E130E002C0A7
+:1055B00028E030E0281739070CF05CC0F801E6510C
+:1055C000F64E208131814281538169817A818B81BC
+:1055D0009C810F94ECBC20E030E040E050E40F945C
+:1055E000C6BD9101220F331F3C872B8787FF09C05F
+:1055F000F401EE51F64E8081918101969183808372
+:1056000006C0EB85FC85EE51F64E11821082F40146
+:10561000EE51F64E20813181AA2019F082E090E00F
+:1056200002C085E090E0821793079CF48091921B62
+:10563000882321F080E090E00F94FF606A2D81E0E4
+:10564000F1DD8091921B882321F08BE590E00F948F
+:10565000FF60F801E651F64E89819A81AB81BC81E9
+:1056600080839183A283B383EB85FC85EA51F64E58
+:1056700011821082A301920169817A818B819C81C0
+:105680000F94C9BF87FD19C0D801AF55B54E4D0164
+:1056900020E030E040E85FE36D917D918D919C9139
+:1056A0000F94C6BD811109C080E090E0A0E0B0E495
+:1056B000F40180839183A283B38320E030E0A901C9
+:1056C000C701B6010F94C9BF18160CF074C02D8124
+:1056D0003E814F815885C301B2010F94ECBC2981F2
+:1056E0003A814B815C810F94C6BD87FF1AC02D8122
+:1056F0003E814F815885C301B2010F94EDBC9B01DF
+:10570000AC0169817A818B819C810F94C6BD87FF32
+:1057100008C0F101EE0FFF1FE758F54E118210820D
+:105720004AC0F801EF55F54E20E030E040E85FE375
+:1057300060817181828193810F94C9BF1816DCF555
+:10574000F101EE0FFF1FE758F54E80819181019620
+:1057500091838083880F991F29853A8528173907F7
+:1057600054F58091921B882321F080E090E00F9403
+:10577000FF606A2D80E056DD8091921B8823D9F06E
+:105780008AE590E02C960FB6F894DEBF0FBECDBF31
+:10579000DF91CF911F910F91FF90EF90DF90CF900D
+:1057A000AF909F908F907F906F905F904F903F90C1
+:1057B0002F900D94FF602C960FB6F894DEBF0FBEAD
+:1057C000CDBFDF91CF911F910F91FF90EF90DF90B0
+:1057D000CF90AF909F908F907F906F905F904F9001
+:1057E0003F902F9008952F923F924F925F926F9229
+:1057F0007F928F929F92AF92BF92CF92DF92EF9261
+:10580000FF920F931F93CF93DF93CDB7DEB7289707
+:105810000FB6F894DEBF0FBECDBFA8958091431A96
+:10582000882309F425C366D96091011A70E080E0ED
+:1058300090E00F9468BE6B017C0140906F1A50900D
+:10584000701A6090711A7090721A6091771A709144
+:10585000781A882777FD8095982F0F9468BEAB0142
+:10586000BC01A12C9301820181E090E0BADD80901F
+:105870006F1A9090701AA090711AB090721A0091DD
+:10588000771A1091781AB801882777FD8095982F9C
+:105890000F9468BEA50194010F94ECBC6B017C01D0
+:1058A00060932B1A70932C1A80932D1A90932E1AB2
+:1058B00020E030E040E251E40F94C9BF181624F410
+:1058C00081E08093221AF7C020E030E040E251EC02
+:1058D000C701B6010F94C6BD87FD02C0012B21F49C
+:1058E00081E08093221A0CC18091221A882351F002
+:1058F00010923F1A1092401A1092411A1092421AB6
+:105900001092221A2091AD023091AE024091AF0266
+:105910005091B002C701B6010F949BC069837A838E
+:105920008B839C836093371A7093381A8093391A4B
+:1059300090933A1A20913F1A3091401A4091411A9F
+:105940005091421AC701B6010F94EDBC2B013C01E6
+:105950002090271A3090281A1091291A00912A1A9B
+:105960009101412F502F0F94C6BD87FD14C0209088
+:10597000231A3090241A1091251A0091261A9101A9
+:10598000412F502FB201C3010F94C9BF18161CF04C
+:105990001201162D072DC101A12FB02F80933F1AA0
+:1059A0009093401AA093411AB093421A2091A902F1
+:1059B0003091AA024091AB025091AC02B101812F0B
+:1059C000902F0F949BC06D837E838F839887609305
+:1059D000331A7093341A8093351A9093361A2091A3
+:1059E0003B1A30913C1A40913D1A50913E1AC50124
+:1059F000B4010F94ECBC2091A5023091A602409115
+:105A0000A7025091A8020F949BC020ED3CEC4CE4FF
+:105A10005DE30F949BC02B013C0123E333E343E799
+:105A20005FE360912F1A7091301A8091311A909132
+:105A3000321A0F949BC09B01AC01C301B2010F94B9
+:105A4000EDBC2B013C0160932F1A7093301A8093A8
+:105A5000311A9093321A2D813E814F815885698188
+:105A60007A818B819C810F94EDBCA30192010F94EC
+:105A7000ECBC2B013C0120E030E04FE753E40F94F5
+:105A8000C9BF20E030E0A9011816E4F4C701B6014F
+:105A90000F94C9BF18167CF4A7019601B101812F9C
+:105AA000902F0F94ECBC60933F1A7093401A809330
+:105AB000411A9093421A412C512CBFE76B2EB3E44C
+:105AC0007B2E21C0C301B2010F94C6BD87FF1BC04E
+:105AD00020E030E0A901C701B6010F94C6BD87FFE1
+:105AE0000FC0A7019601B101812F902F0F94ECBC3C
+:105AF00060933F1A7093401A8093411A9093421A10
+:105B0000412C512C320180923B1A90923C1AA09267
+:105B10003D1AB0923E1A6091F6197091F7198827D4
+:105B200077FD8095982F0F9468BE9B01AC01C5014D
+:105B3000B4010F94C9BF1816DCF460919002709103
+:105B40009102882777FD8095982F0F9468BE9B015E
+:105B5000AC01C501B4010F94C6BD87FF09C0C301E4
+:105B6000B2010F9435BE759567956093011A02C016
+:105B70001092011A0F94EFB40091FD191091FE19C3
+:105B80002091FF193091001A601B710B820B930B4F
+:105B9000693E73408105910568F0CFD8EAD938DABB
+:105BA0000F94EFB46093FD197093FE198093FF1961
+:105BB0009093001A80905D1A90905E1AA0905F1AE0
+:105BC000B090601A6091751A7091761A882777FDE7
+:105BD0008095982F0F9468BEA50194010F94ECBC9A
+:105BE0006B017C0160930A1A70930B1A80930C1A54
+:105BF00090930D1A20919D0230919E0240919F0238
+:105C00005091A0020F949BC069837A838B839C83FD
+:105C10006093161A7093171A8093181A9093191A92
+:105C200020911E1A30911F1A4091201A5091211A6A
+:105C3000C701B6010F94EDBC8B011C016090061AE0
+:105C40007090071A5090081A4090091A9301452D38
+:105C5000542D0F94C6BD87FD11C06090021A70903C
+:105C6000031A5090041A4090051A9301452D542DA3
+:105C7000B801C1010F94C9BF18161CF48301252C6B
+:105C8000342CC801D10180931E1A90931F1AA0933F
+:105C9000201AB093211A2091990230919A024091D2
+:105CA0009B0250919C02B801C1010F949BC06D836F
+:105CB0007E838F8398876093121A7093131A809350
+:105CC000141A9093151A20911A1A30911B1A4091A8
+:105CD0001C1A50911D1AC501B4010F94ECBC2091FF
+:105CE00095023091960240919702509198020F943C
+:105CF0009BC020ED3CEC4CE45DE30F949BC02B017A
+:105D00003C0123E333E343E75FE360910E1A7091B4
+:105D10000F1A8091101A9091111A0F949BC09B0139
+:105D2000AC01C301B2010F94EDBC2B013C016093A7
+:105D30000E1A70930F1A8093101A9093111A809272
+:105D40001A1A90921B1AA0921C1AB0921D1A2D8139
+:105D50003E814F81588569817A818B819C810F9426
+:105D6000EDBCA30192010F94ECBC2B013C0120E09F
+:105D700030E04FE753E40F94C9BF20E030E0A901C1
+:105D80001816ACF4C701B6010F94C9BF18166CF50C
+:105D9000A7019601B801C1010F94ECBC60931E1AD3
+:105DA00070931F1A8093201A9093211A1EC0C3016A
+:105DB000B2010F94C6BD87FF22C020E030E0A901E8
+:105DC000C701B6010F94C6BD87FF16C0A701960193
+:105DD000B801C1010F94ECBC60931E1A70931F1A96
+:105DE0008093201A9093211A07C0412C512CFFE771
+:105DF0006F2EF3E47F2E03C0412C512C320120E0A2
+:105E000030E040E751E4C501B4010F94C9BF181652
+:105E10009CF420E030E046E153E4C501B4010F9466
+:105E2000C6BD87FF09C0C301B2010F9435BE759589
+:105E3000679560934A1A02C010924A1A28960FB6C4
+:105E4000F894DEBF0FBECDBFDF91CF911F910F91B0
+:105E5000FF90EF90DF90CF90BF90AF909F908F908A
+:105E60007F906F905F904F903F902F900C94EB49F4
+:105E700028960FB6F894DEBF0FBECDBFDF91CF914D
+:105E80001F910F91FF90EF90DF90CF90BF90AF9058
+:105E90009F908F907F906F905F904F903F902F904A
+:105EA00008952F923F924F925F926F927F928F92BE
+:105EB0009F92AF92BF92CF92DF92EF92FF920F9399
+:105EC0001F93CF93DF93CDB7DEB7E5970FB6F89466
+:105ED000DEBF0FBECDBF6D8F7E8F8F8F98A31A014F
+:105EE0003BA72AA730934E1A20934D1A10924C1AB2
+:105EF0001092501A10924F1A0F94EFB46B017C015C
+:105F000037FE03C02DE22DA302C03AE03DA30F945B
+:105F1000EFB46EA37FA388A799A7121413041CF0F3
+:105F2000EEE3F6E017C0E1E5F6E08191882339F071
+:105F30009091C00095FFFCCF8093C600F6CF809172
+:105F4000C00085FFFCCF5DC29091C00095FFFCCFE3
+:105F50008093C60081918111F7CF8091C00085FFA9
+:105F6000FCCF8AE08093C6004AD98FE72114310420
+:105F700071F180934A1ACA8ADB8AEC8AFD8ACE863E
+:105F8000DF86E88AF98A1986198240E44A8F5CE143
+:105F90005B8F86E48C8F1E8A1F8A188E198E4FE7BE
+:105FA000442E512C612C712C4D825E826F8278863A
+:105FB00048AA59AA6AAA7BAA19A21AA21BA21CA2C1
+:105FC00021E02A8700E010E01DAA1CAA06C08093E9
+:105FD000011AD1CF80E00F940A978091431A882349
+:105FE00009F4F9C00F947A252114310459F0009175
+:105FF0005D1A10915E1A40905F1A4DAA5090601A77
+:106000005CAA0AC000916F1A1091701A6090711A00
+:106010006DAA7090721A7CAA98014DA95CA96E892C
+:106020007F89888D998D0F94C9BF181634F00E8B17
+:106030001F8B4DA8488E5CA8598E98014DA95CA96C
+:1060400069817A8D8B8D9C8D0F94C6BD87FD06C0AE
+:1060500009831A8F6DA86B8E7CA87C8E0F94EFB489
+:106060004EA05FA068A479A46419750986099709F0
+:10607000653C79408105910540F00F9408280F9404
+:10608000EFB46EA37FA388A799A74A84442009F49C
+:1060900050C02D8D3E8D4F8D58A1B8018DA99CA962
+:1060A0000F94C9BF18160CF096C00F94EFB44A882D
+:1060B0005B886C887D886419750986099709693839
+:1060C00073418105910508F486C088A999A9AAA9F8
+:1060D000BBA94D805E806F80788484199509A609DC
+:1060E000B709B595A795979587952114310419F0AF
+:1060F00080934A1A02C08093011A0F94EFB46E87FE
+:106100007F87888B998B2B013C012A893B894C899D
+:106110005D89421A530A640A750A49A25AA26BA2FF
+:106120007CA24D8C4E8A5E8C5F8A6F8C688E78A0C4
+:10613000798E2D8D3E8D4F8D58A1B8018DA99CA9CA
+:106140000F94C6BD87FF5CC30F94EFB44E845F8489
+:1061500068887988641975098609970969387341CF
+:106160008105910508F44CC30F94EFB46A8B7B8BC7
+:106170008C8B9D8B80914F1A9091501A181619068E
+:106180000CF44AC18D819E81AF81B88548A859A879
+:106190006AA87BA8840D951DA61DB71DB595A7956A
+:1061A000979587952114310409F427C380934A1ADF
+:1061B00080914F1A9091501A01969093501A8093A3
+:1061C0004F1A5D8C59826E8C6A8E7F8C7B8E48A0B4
+:1061D0004C8E21E02A8720E030E040EA51E46D8DCA
+:1061E0007E8D8F8D98A10F94EDBC9B01AC01B80101
+:1061F0008DA99CA90F94C9BF181694F4EDE2F1E59E
+:106200008491882341F09091C00095FFFCCF80934A
+:10621000C6003196F5CF8091C00085FFFCCFF1C05C
+:106220000F94EFB46C197D098E099F09613D774089
+:106230008105910508F496C02114310481F0E090A5
+:106240004A1AF12CE7E2F1E584918823C1F090919C
+:10625000C00095FFFCCF8093C6003196F5CFE0904B
+:10626000011AF12CE1E2F1E58491882341F090914B
+:10627000C00095FFFCCF8093C6003196F5CF22E099
+:1062800030E0A8016DA97CA98EE799E00E94354312
+:10629000EDE1F1E58491882341F09091C00095FFF4
+:1062A000FCCF8093C6003196F5CF4AE050E0B701AD
+:1062B0008EE799E00E9442428091C00085FFFCCFAA
+:1062C0008AE08093C6004984442009F43FC05DA061
+:1062D000451418F4242D2F5F40C049845DA045105B
+:1062E0003DC0242D2F5F29872CA53DA54EA55FA578
+:1062F000B8018DA99CA90F94ECBC6B017C0120E036
+:1063000030E0A9010F94C9BF18165CF420E030E01A
+:1063100040EA50E4C701B6010F94C6BD87FF1EC016
+:106320000AC020E030E040EA50ECC701B6010F940B
+:10633000C9BF18169CF4632D661F6627661F80E090
+:106340000F94122981E080934C1A5CC20CA71DA700
+:106350004DA84EA65CA85FA621E029870F94EFB454
+:106360006B017C010F94EFB44B015C010F94EFB40F
+:106370002A893B894C895D894E845F846888798845
+:10638000240D351D461D571D821A930AA40AB50A0D
+:10639000860E971EA81EB91E21E882162FE49206CB
+:1063A00022E1A206B10490F0E0E0F1E584918823B7
+:1063B00041F09091C00095FFFCCF8093C6003196CC
+:1063C000F5CF8091C00085FFFCCF1BC080914F1A94
+:1063D0009091501A4AA45BA4481659060CF0FACDC5
+:1063E000E4EAF0E58491882341F09091C00095FFA4
+:1063F000FCCF8093C6003196F5CF8091C00085FF19
+:10640000FCCF8AE08093C60081E080934C1A109202
+:10641000501A10924F1AF6C18A899B89AC89BD899E
+:1064200084199509A609B70949A05AA06BA07CA0B8
+:10643000480E591E6A1E7B1E29A13AA14BA15CA1E0
+:10644000281B390B4A0B5B0BCA01B9012D813E8118
+:106450004F8158850F945AC2A30192010F94BFC275
+:1064600088A999A9AAA9BBA9280F391F4A1F5B1F90
+:1064700024313105410551051CF128AB39AB4AAB3C
+:106480005BAB2C3E31054105510544F02BEE30E06D
+:1064900040E050E028AB39AB4AAB5BAB88A999A987
+:1064A000AAA9BBA980389105A105B105D4F02EEFAA
+:1064B00030E040E050E0281B390B4A0B5B0B0CC06E
+:1064C00084E190E0A0E0B0E088AB99ABAAABBBABB5
+:1064D00024E130E040E050E02D833E834F83588735
+:1064E00008C088A999A9AAA9BBA98D839E83AF8357
+:1064F000B887E6E9F1E58491882341F09091C000E6
+:1065000095FFFCCF8093C6003196F5CF2AE030E0AE
+:1065100048A959A96AA97BA98EE799E00E940A4275
+:10652000E1E9F1E58491882341F09091C00095FF65
+:10653000FCCF8093C6003196F5CF2AE030E04D8144
+:106540005E816F8178858EE799E00E940A42EAE8D1
+:10655000F1E58491882341F09091C00095FFFCCF34
+:106560008093C6003196F5CF22E030E049815A8D04
+:106570006B8D7C8D8EE799E00E943543E3E8F1E571
+:106580008491882341F09091C00095FFFCCF8093C7
+:10659000C6003196F5CF22E030E04E895F89688DE4
+:1065A000798D8EE799E00E9435438091C00085FF88
+:1065B000FCCF8AE08093C60080914F1A9091501AC8
+:1065C00003970CF4DFCD6D817E818F8198850F94C8
+:1065D00068BE20E030E040E850E40F949BC04B01DF
+:1065E0005C0129813A8D4B8D5C8D6E897F89888D08
+:1065F000998D0F94ECBC20ED3FE049E450E40F94FA
+:106600009BC020E030E040E05FE30F949BC09B0123
+:10661000AC01C501B4010F94CDBD4B015C01C301B8
+:10662000B2010F9468BE20E030E04AE754E40F94D2
+:10663000CDBD2B013C01EDE7F1E58491882341F0CC
+:106640009091C00095FFFCCF8093C6003196F5CFA6
+:1066500022E030E0B501A4018EE799E00E943543C5
+:10666000E7E7F1E58491882341F09091C00095FF20
+:10667000FCCF8093C6003196F5CF22E030E0B30125
+:10668000A2018EE799E00E9435438091C00085FF0A
+:10669000FCCF8AE08093C6002AE939E949E15FE34B
+:1066A000C501B4010F949BC04B015C016093591A62
+:1066B00070935A1A80935B1A90935C1A9B01AC01F9
+:1066C0000F94EDBCA30192010F94CDBD6093551AB8
+:1066D0007093561A8093571A9093581AA3019201F7
+:1066E000C501B4010F949BC020E030E040E05EE3C0
+:1066F0000F949BC06093511A7093521A8093531A4F
+:106700009093541AE9E6F1E58491882341F0909141
+:10671000C00095FFFCCF8093C6003196F5CF8091E5
+:10672000C00085FFFCCF8AE08093C600E3E6F1E578
+:106730008491882341F09091C00095FFFCCF809315
+:10674000C6003196F5CF4091591A50915A1A60916E
+:106750005B1A70915C1A22E030E08EE799E00E94AB
+:1067600035438091C00085FFFCCF8AE08093C6004E
+:10677000EDE5F1E58491882341F09091C00095FF0B
+:10678000FCCF8093C6003196F5CF4091551A5091B9
+:10679000561A6091571A7091581A22E030E08EE72D
+:1067A00099E00E9435438091C00085FFFCCF8AE0CC
+:1067B0008093C600E7E5F1E58491882341F090914C
+:1067C000C00095FFFCCF8093C6003196F5CF409175
+:1067D000511A5091521A6091531A7091541A22E032
+:1067E00030E08EE799E00E9435438091C00085FF3C
+:1067F000FCCF8AE08093C600C5CC8093011AD8CC28
+:106800001A86E9CCE5960FB6F894DEBF0FBECDBF71
+:10681000DF91CF911F910F91FF90EF90DF90CF907C
+:10682000BF90AF909F908F907F906F905F904F90B0
+:106830003F902F900895CF93C82F0F94FF280E9468
+:10684000745D811134C0E5E4F0E19491992341F045
+:106850008091C00085FFFCCF9093C6003196F5CFA4
+:106860006C2F70E04AE050E08EE799E00E944242CF
+:106870008091C00085FFFCCF8AE08093C600E5E1EF
+:10688000FFE48491882341F09091C00095FFFCCFF4
+:106890008093C6003196F5CF8091C00085FFFCCF74
+:1068A0008AE08093C60088E09FE40F94A9510E947B
+:1068B000305D80910101806280930101809101012E
+:1068C00088608093010180910101846080930101BF
+:1068D0009FB7F894809102018860809302019FBF66
+:1068E0009FB7F894809102018062809302019FBF5C
+:1068F0009FB7F894809102018460809302019FBF4A
+:106900008FEF90E09093CB0A8093CA0A8091921BFC
+:10691000882329F08DE590E0CF910D94FF60CF9111
+:106920000895CF93C82F0F94FF280E94745D8111A2
+:1069300034C0E5E4F0E19491992341F08091C000E6
+:1069400085FFFCCF9093C6003196F5CF6C2F70E099
+:106950004AE050E08EE799E00E9442428091C000F8
+:1069600085FFFCCF8AE08093C600EBEDFEE48491C6
+:10697000882341F09091C00095FFFCCF8093C60022
+:106980003196F5CF8091C00085FFFCCF8AE08093DF
+:10699000C6008EEC9EE40F94A9510E94305D809158
+:1069A000921B882329F08CE590E0CF910D94FF6035
+:1069B000CF910895A5980E94745D811125C0E5E4EA
+:1069C000F0E18491882341F09091C00095FFFCCFC5
+:1069D0008093C6003196F5CFE5E9FEE484918823E3
+:1069E00041F09091C00095FFFCCF8093C600319696
+:1069F000F5CF8091C00085FFFCCF8AE08093C60070
+:106A000084E89EE40F94A9510C94305DA5980E94EF
+:106A1000745D811125C0E5E4F0E18491882341F0A3
+:106A20009091C00095FFFCCF8093C6003196F5CFC2
+:106A3000EBE4FEE48491882341F09091C00095FF3F
+:106A4000FCCF8093C6003196F5CF8091C00085FFC2
+:106A5000FCCF8AE08093C6008AE39EE40F94A9519C
+:106A60000C94305D8CB12091140B86FB882780F943
+:106A7000821769F08091100B9091110B0196909301
+:106A8000110B8093100B81E082278093140B0895E3
+:106A90001F920F920FB60F9211240BB60F920F9305
+:106AA0001F932F933F934F935F936F937F938F9396
+:106AB0009F93AF93BF93CF93DF93EF93FF93809117
+:106AC0008D02811112C08091011A8093E1198823EF
+:106AD00011F0759A01C0759880914A1A8093E01957
+:106AE000882311F0A59A01C0A5989091E119809191
+:106AF0008D02981708F4759880918D028F7049F572
+:106B00008091FB19882371F081508093FB198111CA
+:106B100010C080914B1A8093FB198091FA1991E073
+:106B2000892705C080914B1A8093FB1981E08093DF
+:106B3000FA198091FA19882321F0809194028695A0
+:106B400001C080E08093FC19882311F0459A01C0B0
+:106B500045989091E01980918D02981708F4A598B6
+:106B60002091FC1930E080918D028F7090E0281701
+:106B700039070CF4459880918D028F5F8F77809351
+:106B80008D0280918C0290E08F30910508F0E3C077
+:106B9000FC01E658FF4F0D94DBC210927B0080E4AD
+:106BA00080937C0080917A00806480937A000F94B7
+:106BB000B55181E019C02091780030917900809121
+:106BC000DC199091DD19A091DE19B091DF19820FC7
+:106BD000931FA11DB11D8093DC199093DD19A09323
+:106BE000DE19B093DF1982E080938C02B4C010925A
+:106BF0007B0082E480937C0080917A0080648093A3
+:106C00007A000F94B55183E0EFCF20917800309156
+:106C100079008091D8199091D919A091DA19B09181
+:106C2000DB19820F931FA11DB11D8093D81990937A
+:106C3000D919A093DA19B093DB1984E0D5CF10925B
+:106C40007B0081E480937C0080917A008064809353
+:106C50007A000F94B55185E0C7CF2091780030912C
+:106C600079008091D4199091D519A091D619B0913D
+:106C7000D719820F931FA11DB11D8093D419909332
+:106C8000D519A093D619B093D71986E0ADCF0F943C
+:106C9000B55187E0A9CF88E0A7CF0F94B55189E01F
+:106CA000A3CF8AE0A1CF10927B0086E480937C0082
+:106CB00080917A00806480937A000F94B5518BE0C4
+:106CC00093CF20917800309179008091D0199091E4
+:106CD000D119A091D219B091D319820F931FA11D80
+:106CE000B11D8093D0199093D119A093D219B0936C
+:106CF000D3198CE079CF10927B0083E480937C00E1
+:106D000080917A00806480937A000F94B5518DE071
+:106D10006BCF20917800309179008091CC199091BF
+:106D2000CD19A091CE19B091CF19820F931FA11D3B
+:106D3000B11D8093CC199093CD19A093CE19B09327
+:106D4000CF1910928C028091CB198F5F8093CB1951
+:106D500002C010928C028091CB19803108F483C05C
+:106D60008091431A811120C08091DC199091DD1926
+:106D70009093741A8093731A8091CC199091CD19C5
+:106D800090936E1A80936D1A8091D0199091D119B9
+:106D90009093681A8093671A8091D8199091D919A5
+:106DA0009093621A8093611A81E08093431A109243
+:106DB000CB191092DC191092DD191092DE19109285
+:106DC000DF191092D4191092D5191092D619109279
+:106DD000D7191092C7191092C8191092C919109298
+:106DE000CA191092D8191092D9191092DA19109262
+:106DF000DB191092CC191092CD191092CE19109265
+:106E0000CF191092D0191092D1191092D219109254
+:106E1000D3192091731A3091741A8091F8199091B6
+:106E2000F9198217930714F080E005DD2091731A99
+:106E30003091741A80919202909193022817390729
+:106E400014F080E06EDD2091611A3091621A809119
+:106E5000F4199091F519821793072CF01092761A75
+:106E60001092751AA7DD2091611A3091621A8091F3
+:106E70008E0290918F02281739070CF0C7DD00E0D1
+:106E800010E0E801CC0FDD1FCC5BD54E88819981E5
+:106E90001816190644F461E0802F0F94B41F8881FE
+:106EA0009981019709C0892B49F060E0802F0F94E8
+:106EB000B41F888199810196998388830F5F1F4F42
+:106EC00003301105F1F6CEDDFF91EF91DF91CF9107
+:106ED000BF91AF919F918F917F916F915F914F91F2
+:106EE0003F912F911F910F910F900BBE0F900FBEEE
+:106EF0000F901F9018952CEA35EC47E25EE30D9455
+:106F00009BC02CEA35EC47E25EE30D94CDBD2CEA44
+:106F100035EC47E25EE30D94CDBD2CEA35EC47E25B
+:106F20005EE30D949BC02091BB1B222399F03FB7D9
+:106F3000F8942091BB1B213059F42DB32093B91B39
+:106F40004DB32091BA1B209524232DBB3FBF02C017
+:106F50003093B91B8CBD9DBD08958EBD00000DB44E
+:106F600007FEFDCF8EB508958091BB1B882361F08D
+:106F70009FB7F8942091BB1B8091B91B213019F465
+:106F80008DBB9FBF08958FBF08958091060182FB3E
+:106F9000882780F99091060197FD826008951F93DC
+:106FA000CF93DF938091E81A813009F45AC0809121
+:106FB000B102882309F455C0E8DF9091B61AA7EB17
+:106FC000BAE1EFEBFAE120E030E010E061E070E0E0
+:106FD000AB01022E01C0440F0A94EAF7482329F0BE
+:106FE000408151814F5F5F4F07C040815181411502
+:106FF000510521F041505109518340834081518115
+:10700000CD91DC911197C417D50760F411965C936C
+:107010004E934034510528F01182108291E011E026
+:1070200001C091E02F5F3F4F12963296223031051A
+:1070300079F69093B61A8093C71A8091CF1A81116E
+:1070400010C08091B102882361F0112351F081E0DA
+:107050008093C81A1092B102DF91CF911F910C94C6
+:10706000F26BDF91CF911F910895CF93DF93C82FDB
+:10707000D0E00F94681FFE01EE0FFF1FEE0FFF1F01
+:10708000E053F54E6083718382839383CC51D54E58
+:107090001882DF91CF9108958093B2021092CE1A98
+:1070A0001092CD1A1092C91A1092CA1A1092CB1AC5
+:1070B0001092CC1A08958FEF8093B2022091CD1ACE
+:1070C0003091CE1A40E050E06091C91A7091CA1A0E
+:1070D0008091CB1A9091CC1A0F949DC2C90108954A
+:1070E0006BE776E08EE799E00E94354262E976E050
+:1070F0008EE799E00E943542E7E9F6E08191882326
+:1071000039F09091C00095FFFCCF8093C600F6CF78
+:107110006091CB0270E04AE050E08EE799E00E9477
+:107120004242E1EAF6E08191882339F09091C00073
+:1071300095FFFCCF8093C600F6CF6091C70270E048
+:107140004AE050E08EE799E00E944942EAE9F6E021
+:107150008191882339F09091C00095FFFCCF8093F6
+:10716000C600F6CF6091CC0270E04AE050E08EE7B6
+:1071700099E00E944242E1EAF6E08191882339F0E9
+:107180009091C00095FFFCCF8093C600F6CF609130
+:10719000C80270E04AE050E08EE799E00E94494260
+:1071A000EDE9F6E08191882339F09091C00095FFD8
+:1071B000FCCF8093C600F6CF6091CD0270E04AE02C
+:1071C00050E08EE799E00E944242E1EAF6E08191C8
+:1071D000882339F09091C00095FFFCCF8093C600C2
+:1071E000F6CF6091C90270E04AE050E08EE799E086
+:1071F0000E944942E0EAF6E08191882339F09091BB
+:10720000C00095FFFCCF8093C600F6CF6091CE0200
+:1072100070E04AE050E08EE799E00E944242E1EAE5
+:10722000F6E08191882339F09091C00095FFFCCF62
+:107230008093C600F6CF6091CA0270E04AE050E049
+:107240008EE799E00C944942AF92BF92CF92DF92C1
+:10725000EF92FF920F931F93CF93DF9300D01F9273
+:10726000CDB7DEB7B82EF62E8CE590E02C833B83AD
+:107270004A83598358DE60E08B2D0F9413B78F2D0E
+:107280006CDE5981852F69DE4A81842F66DE3B8161
+:10729000832F63DE2C81822F60DE61E08B2D0F94C3
+:1072A00013B762DE8CE590E03EDE60E08B2D0F943C
+:1072B00013B780E052DEA82E80E04FDEC82ED12C1E
+:1072C000E12CF12CFE2CED2CDC2CCC2480E045DED6
+:1072D000C82AFE2CED2CDC2CCC2480E03EDEC82A13
+:1072E000FE2CED2CDC2CCC2480E037DEC82A61E0BB
+:1072F0008B2D0F9413B738DE0115110529F0F80115
+:10730000C082D182E282F3828A2D0F900F900F907B
+:107310000F90DF91CF911F910F91FF90EF90DF9031
+:10732000CF90BF90AF9008950F931F93606800E0D7
+:1073300010E08ADF1F910F9108958F929F92AF9274
+:10734000BF92CF92DF92EF92FF920F93742F922F02
+:107350002E2DEC2D217030E040E050E0F3E1220FC3
+:10736000331F441F551FFA95D1F7E3708E2E912CD1
+:10737000A12CB12CA4E1880C991CAA1CBB1CAA95B9
+:10738000D1F7282939294A295B290170C02ED12C2F
+:10739000E12CF12CB2E1CC0CDD1CEE1CFF1CBA95EB
+:1073A000D1F72C293D294E295F29262B372B9370A5
+:1073B000492B60E70F91FF90EF90DF90CF90BF9047
+:1073C000AF909F908F90B0CFCF92EF920F931F937B
+:1073D000CF93DF93082F162FE3EAF6E081918823FD
+:1073E00039F09091C00095FFFCCF8093C600F6CF96
+:1073F000C02FD0E04AE050E0BE018EE799E00E9445
+:107400004242EEECF8E08191882339F09091C0007F
+:1074100095FFFCCF8093C600F6CF612F70E04AE065
+:1074200050E08EE799E00E944942FE01EF53FD4F84
+:1074300010830230C8F48091E81A8130A9F4CE019B
+:1074400083549D4FDE01A554BD4FAE0141545D4FA5
+:10745000C153DD4FC12CE12CFC0100812C91FA01BC
+:107460004081612F888169DFDF91CF911F910F915A
+:10747000EF90CF900895CF92EF920F931F93CF93F9
+:10748000DF93082F162FE9EBF6E08191882339F07E
+:107490009091C00095FFFCCF8093C600F6CFC02F1F
+:1074A000D0E04AE050E0BE018EE799E00E944242FF
+:1074B000EEECF8E08191882339F09091C00095FFBF
+:1074C000FCCF8093C600F6CF612F70E04AE050E019
+:1074D0008EE799E00E944942FE01E154FD4F10837E
+:1074E0000230C8F48091E81A8130A9F4CE018354A7
+:1074F0009D4FDE01A554BD4FBE016F537D4FC1535B
+:10750000DD4FC12CE12CFC0100812C91412FFB01AE
+:107510006081888112DFDF91CF911F910F91EF90F1
+:10752000CF9008959A01AB0163E1FECE0F931F93B4
+:10753000CF93DF93042FE82FF0E0E153FD4F10814C
+:107540006F70C22FD0E0862F90E0A0E0B0E0203234
+:1075500088F4582F442733272227236D4360506136
+:107560006CE6812FE1DE202F2F7130E040E050E00B
+:107570004F6019C0582F442733272227236D4160BD
+:1075800050616CE6812FD0DE202F30E035952795B5
+:107590002F713327442737FD4095542F4F60D595E1
+:1075A000C795CF71DD279C2F8827AA2797FDA09527
+:1075B000BA2F282B392B4A2B5B2B60E1812FDF91CF
+:1075C000CF911F910F91B0CE8F929F92AF92BF92A9
+:1075D000CF92DF92EF92FF920F931F93CF93DF939F
+:1075E000882EFFECCF2EF2E0DF2E00ED1AE1C0E096
+:1075F000D0E0AA24A394B12C75010C2E02C0EE0C8D
+:10760000FF1C0A94E2F7F60191906F01882D8E21FC
+:1076100009F446C08091CF1A8E298093CF1A8C2FFF
+:107620000F94681FF8016083718382839383FE0146
+:10763000EC51F54E108220E030E0A90160E0892D88
+:1076400073DEFE01ED54FD4F2081822F90E0A0E01B
+:10765000B0E0AC01332722276DE6892D65DE2EEAE6
+:1076600031E040E050E064E1892D5EDEFE01ED5343
+:10767000FD4F2081FE01E553FD4F4081FE01E052A8
+:10768000F54E60818C2F52DFF3E0EF22FF24EF28CC
+:1076900039F020E831E340E050E060E0892D44DE3D
+:1076A00021960C5F1F4FC330D10509F0A5CFDF91A4
+:1076B000CF911F910F91FF90EF90DF90CF90BF90EF
+:1076C000AF909F908F900895CF92DF92EF92FF92AC
+:1076D0000F931F93CF93DF938091CF1A882309F4E0
+:1076E00069C034EEE32E3AE1F32E0FEC12E0C0E075
+:1076F000D0E0CC24C394D12C2091CF1A2370C601A2
+:107700000C2E01C0880F0A94EAF7282309F446C01A
+:107710008091E81A813069F424E030E040E050E0E4
+:1077200060E0F801808100DE20E030E0A90164E142
+:1077300032C0FE01E953FD4F2081FE01E553FD4FAC
+:107740004081FE01E052F54E60818C2FEFDEFE019C
+:10775000E954FD4F2081822F90E0A0E0B0E0AC0121
+:10776000332722276DE6F8018081DEDD8091E81A5B
+:10777000813021F420E030E0A90104C02EEA31E09C
+:1077800040E050E064E1F8018081CEDD20E831E3A3
+:1077900040E050E060E0F8018081C6DDF701119221
+:1077A0007F0121960F5F1F4FC330D10509F0A4CF91
+:1077B0001092CF1ADF91CF911F910F91FF90EF9010
+:1077C000DF90CF9008950F931F93CF93DF93082FEF
+:1077D000162FEFECF6E08191882339F09091C000EC
+:1077E00095FFFCCF8093C600F6CFC02FD0E04AE0D3
+:1077F00050E0BE018EE799E00E944242EEECF8E0D4
+:107800008191882339F09091C00095FFFCCF80933F
+:10781000C600F6CF612F70E04AE050E08EE799E0B5
+:107820000E944942FE01E553FD4F1083FE01E953DA
+:10783000FD4FC052D54E2081412F6881802FDF91AE
+:10784000CF911F910F9172CE0F931F93CF93DF9320
+:10785000082F162FE6EEF6E08191882339F09091FB
+:10786000C00095FFFCCF8093C600F6CFC02FD0E0BC
+:107870004AE050E0BE018EE799E00E944242EEEC01
+:10788000F8E08191882339F09091C00095FFFCCFFA
+:107890008093C600F6CF612F70E04AE050E08EE79B
+:1078A00099E00E944942FE01E953FD4F1083FE0119
+:1078B000E553FD4FC052D54E212F40816881802F66
+:1078C000DF91CF911F910F9131CE2F923F924F9226
+:1078D0005F926F927F928F929F92AF92BF92CF9260
+:1078E000EF920F931F93CF93DF93CDB7DEB7289717
+:1078F0000FB6F894DEBF0FBECDBF84E08093E01AD0
+:107900008093E11A8093E21A82E08093E31AEDEF0C
+:10791000F6E08191882339F09091C00095FFFCCF6B
+:107920008093C600F6CF4AE050E06091E81A8EE7F7
+:1079300099E00E948742A09AA29A9FB7F8948091FA
+:1079400008018062809308019FBF9FB7F8948091DF
+:1079500008018061809308019FBF989A9A9A80914C
+:107960000701806280930701809107018061809305
+:107970000701809107018B7F8093070180910701A8
+:107980008F7780930701809107018F7B8093070198
+:1079900080910701877F809307010F9484B467EC7F
+:1079A000462E62E0562E7BEC672E72E0772EE0EEDC
+:1079B000AE2EEAE1BE2E8FEC92E098878F83F7EB34
+:1079C0008F2EF2E09F2EADEB2A2EA2E03A2EEBEBAB
+:1079D000F2E0FE83ED838FEB92E09C838B83E1ECFE
+:1079E000F2E0FA83E98310E0F20121912F01F30123
+:1079F00041913F01F50161915F01812F97DD20E009
+:107A000030E0A90161E1EF81F88580818DDCF4012E
+:107A100021914F01822F90E0A0E0B0E0AC0133272C
+:107A200022276DE6EF81F88580817EDC8091E81A5F
+:107A3000813021F420E030E0A90104C02EEA31E0D9
+:107A400040E050E064E1EF81F88580816DDC809159
+:107A5000E81A813029F424E030E040E050E004C02E
+:107A600020E831E340E050E060E0EF81F88580817C
+:107A70005BDCF10101911F01ED81FE812191FE830B
+:107A8000ED83EB81FC814191FC83EB83E981FA81F9
+:107A90006191FA83E983C12CE12CEF81F885808123
+:107AA0004CDC40E050E0BA01EF81F8858191F88725
+:107AB000EF8338DD1F5F123009F096CF2091C902A5
+:107AC0004091CD026091E21A82E030DD20E030E0AA
+:107AD000A90161E18091D10227DC20E831E340E097
+:107AE00050E060E08091D1021FDC2091CA024091F9
+:107AF000CE026091E31A83E019DD20E030E0A901B5
+:107B000061E18091D20210DC20E831E340E050E0F6
+:107B100060E08091D20208DC1092C01A1092BF1A65
+:107B20001092C21A1092C11A1092C41A1092C31A5B
+:107B30001092C61A1092C51A1092B81A1092B71A5B
+:107B40001092BA1A1092B91A1092BC1A1092BB1A5B
+:107B50001092BE1A1092BD1A28960FB6F894DEBF86
+:107B60000FBECDBFDF91CF911F910F91EF90CF90BE
+:107B7000BF90AF909F908F907F906F905F904F904D
+:107B80003F902F900895EF92FF920F931F93CF9302
+:107B9000DF9300D01F92CDB7DEB77A0119821A8227
+:107BA0001B821C828E010F5F1F4F20E030E0A90175
+:107BB0004BDBE114F10449F009811A812B813C81EE
+:107BC000F70100831183228333830F900F900F906E
+:107BD0000F90DF91CF911F910F91FF90EF9008953B
+:107BE0008F929F92AF92BF92CF92DF92EF92FF92CD
+:107BF0000F931F93CF93DF9300D01F92CDB7DEB7C3
+:107C00000F94EFB40091B11A1091B21A2091B31AE7
+:107C10003091B41A601B710B820B930B693E734059
+:107C20008105910508F468C01FECE12E12E0F12EE9
+:107C300000E010E0992493948AE9C82E83E5D82EB9
+:107C40009AE0892E19821A821B821C829092B51AA0
+:107C5000AE014F5F5F4F6FE6F70181917F0193DFC8
+:107C600089819A81AB81BC81B2FF33C0F6018491D6
+:107C7000EAE9F3E5882349F09091C00095FFFCCF35
+:107C80008093C60031968491F5CF4AE050E0B80168
+:107C90008EE799E00E9442428091C00085FFFCCFB0
+:107CA0008092C600BFECAB2EB2E0BB2E20E030E0ED
+:107CB00041E050E06CE6F50181915F0135DBF3EDC9
+:107CC000AF16F2E0BF0691F760E08AE993E50E9403
+:107CD000475C0F5F1F4F0430110509F0B3CF0F94BD
+:107CE000EFB46093B11A7093B21A8093B31A909361
+:107CF000B41A81E08093B61A0F900F900F900F90F6
+:107D0000DF91CF911F910F91FF90EF90DF90CF9077
+:107D1000BF90AF909F908F9008950F931F93CF9334
+:107D2000DF93CDB7DEB729970FB6F894DEBF0FBE4D
+:107D3000CDBF8C01101611068CF51D821E821F828C
+:107D4000188619821A821B821C82AE014B5F5F4F1C
+:107D50006FE68091CF0217DFAE014F5F5F4F6FE696
+:107D60008091D00210DF4D815E816F81788577FF31
+:107D70000CC049815A816B817C81442777FD4395F2
+:107D8000552766277727842F01C080E0898728DF61
+:107D9000015011098985882369F201C080E0299684
+:107DA0000FB6F894DEBF0FBECDBFDF91CF911F910C
+:107DB0000F910895CF93DF9300D01F92CDB7DEB718
+:107DC00019821A821B821C82AE014F5F5F4F62E1F3
+:107DD000DADE89819A81AB81BC81AC01BD01442787
+:107DE00055276F707727452B462B472B11F08FEFC8
+:107DF0009FEF0F900F900F900F90DF91CF9108950C
+:107E0000CF93DF9300D01F92CDB7DEB719821A82CD
+:107E10001B821C82AE014F5F5F4F6AE6B4DE898130
+:107E20009A8193700F900F900F900F90DF91CF91E8
+:107E30000895CF93DF9300D01F92CDB7DEB719829C
+:107E40001A821B821C82AE014F5F5F4F6FE69BDE82
+:107E500089819A810F900F900F900F90DF91CF91B1
+:107E600008958F929F92AF92BF92DF92EF92FF920E
+:107E70000F931F93CF93DF93182FE82EF12CE70178
+:107E8000CC51D54E8881811130C0F701E153FD4FAF
+:107E9000D0808D2D8FDF843F914038F5812F0F9456
+:107EA000681FF701EE0FFF1FEE0FFF1FE053F54EA7
+:107EB0000081118122813381601771078207930746
+:107EC000A1F04B015C01801A910AA20AB30A950144
+:107ED0008401013811052105310538F08D2DA9DF08
+:107EE0009370892B11F481E08883DF91CF911F91EA
+:107EF0000F91FF90EF90DF90BF90AF909F908F9089
+:107F00000895E091B202E43028F5F0E0E153FD4F2E
+:107F100080818FDF93704091C91A5091CA1A609185
+:107F2000CB1A7091CC1A480F591F611D711D4093D7
+:107F3000C91A5093CA1A6093CB1A7093CC1A8091C5
+:107F4000CD1A9091CE1A01969093CE1A8093CD1AA5
+:107F500081E008958091CF1A82FF02C082E081DF24
+:107F600080E00895FC019491903249F0892F8B7F35
+:107F7000893029F081E09A3019F080E0089581E09D
+:107F80000895CF93DF93CDB7DEB7C054D1090FB6B4
+:107F9000F894DEBF0FBECDBF88E0EBE1F3E0DE0179
+:107FA000D99601900D928A95E1F788E0E3E2F3E03B
+:107FB000DE01D19601900D928A95E1F788E0EBE21F
+:107FC000F3E0DE01999601900D928A95E1F788E041
+:107FD000E3E3F3E0DE01919601900D928A95E1F7DB
+:107FE00088E0EBE3F3E0DE01599601900D928A956B
+:107FF000E1F788E0E3E4F3E0DE01519601900D92B1
+:108000008A95E1F788E0EBE4F3E0DE011996019050
+:108010000D928A95E1F788E0E3E5F3E0DE01119641
+:1080200001900D928A95E1F7AE01475C5F4F60E0E9
+:1080300081E19BE10E940A40AE014F5C5F4F61E02D
+:1080400081E19BE10E940A40AE01475D5F4F62E023
+:1080500081E19BE10E940A40AE014F5D5F4F63E00A
+:1080600081E19BE10E940A40AE01475E5F4F64E000
+:1080700081E19BE10E940A40AE014F5E5F4F65E0E7
+:1080800081E19BE10E940A40AE01475F5F4F66E0DD
+:1080900081E19BE10E940A40AE014F5F5F4F67E0C4
+:1080A00081E19BE10E940A40C05CDF4F0FB6F8946B
+:1080B000DEBF0FBECDBFDF91CF9108950F931F9309
+:1080C000CF93DF93EB01142F022F482F60E081E163
+:1080D0009BE10E94823D612F81E19BE10F94AFB74C
+:1080E00011E1FE016491662311F0111117C01123F3
+:1080F00039F060E281E19BE10F94AFB71150F7CF07
+:10810000602F81E19BE10F94AFB760E281E19BE1D9
+:10811000DF91CF911F910F910D94AFB781E19BE15A
+:108120000F94AFB721961150DCCFEF92FF920F93CF
+:108130001F93CF93DF93EB01E42E8901F9010190A6
+:108140000020E9F7F22EFE1A92E1F90E482F60E0C6
+:1081500081E19BE10E94823D6E2D81E19BE10F94C4
+:10816000AFB7FE016491662311F0F11019C06AE304
+:1081700081E19BE10F94AFB7FF2039F060E281E12C
+:108180009BE10F94AFB7FA94F7CFB80181E19BE17F
+:10819000DF91CF911F910F91FF90EF900D94AEB7AB
+:1081A00081E19BE10F94AFB72196FA94DACFCF9299
+:1081B000DF92EF92FF920F931F93CF93DF93D82E0E
+:1081C000C62E7A01E901482F81E19BE10E94823DA0
+:1081D00081E0E816F10469F182E0E816F10409F0A3
+:1081E0004FC0BE0181E19BE10F94AEB7FE0101904B
+:1081F0000020E9F73197EC1BFD0B6C2D6E0F4D2D18
+:1082000081E19BE10E94823D6BE174E081E19BE1B1
+:108210000F94AEB7FE0101900020E9F76C2D6C1BA6
+:108220006E0F4D2D81E19BE10E94823D6AE277E075
+:1082300028C0BE0181E19BE10F94AEB7FE01019021
+:108240000020E9F73197EC1BFD0B6C2D6E0F4D2DC7
+:1082500081E19BE10E94823D6BE174E081E19BE161
+:108260000F94AEB7FE0101900020E9F76C2D6C1B56
+:108270006E0F4D2D81E19BE10E94823DB80101C04E
+:10828000BE0181E19BE1DF91CF911F910F91FF90A2
+:10829000EF90DF90CF900D94AEB78093300B91E0CC
+:1082A0009093D702682F8EEF9FE00F9456CA80916B
+:1082B000FB1A813019F482E08093FB1A0895E0E301
+:1082C000FDE0608181E0682760838BEB9FE00D9487
+:1082D00056CA8F929F92AF92BF92CF92DF92EF9247
+:1082E000FF920F931F93CF93DF9394E08902E001F5
+:1082F0001124C052D54F20E030E040E251E46881C3
+:1083000079818A819B810F94EDBC688379838A830C
+:108310009B83E090E80AF090E90A0091EA0A109144
+:10832000EB0A2091E40A3091E50A4091E60A509167
+:10833000E70A6091E00A7091E10A8091E20A909167
+:10834000E30AECECFAE0FF93EF93812C912CE4E349
+:10835000AE2EE2E4BE2EFCEECF2EFAE0DF2E0F941E
+:1083600058050F94071F89E69FE00F9444CA0F90A9
+:108370000F90882319F081E08093B102DF91CF91B3
+:108380001F910F91FF90EF90DF90CF90BF90AF9033
+:108390009F908F900895CF93809101018460809386
+:1083A0000101CAE09FB7F894809102018460809334
+:1083B00002019FBF84E690E00F9455B59FB7F894F3
+:1083C000809102018B7F809302019FBF84E690E041
+:1083D0000F9455B5C15031F7CF91089582E0809345
+:1083E000D40210927C1BD7CF1092991B8AE69BE097
+:1083F0000E9425C110920F1B08950F93E091D502A2
+:10840000F091D602E817F907C9F09093D60280934D
+:10841000D50240930A1B50930B1B60930C1B709367
+:108420000D1B002339F08DE1EBE9FBE1DF011D922B
+:108430008A95E9F7222311F00F91D0CF0F9108957B
+:108440000F9361E080EC9FE00F9456CA60E08FEBE1
+:108450009FE00F9456CA60E08EEB9FE00F9456CADF
+:1084600060E08DEB9FE00F9456CA60E08CEB9FE0DC
+:108470000F9456CA01E020E040E050E0BA0183EFDB
+:1084800091E0BBDF1092AB1B0F9108950F93FB019E
+:10849000BA01A9012091D5023091D60230939C1BDC
+:1084A00020939B1B20910A1B30910B1B30939E1B2A
+:1084B00020939D1B22E02093D4029093A01B8093D5
+:1084C0009F1BF093A21BE093A11BCB01AA2797FD52
+:1084D000A095BA2F8093A31B9093A41BA093A51BD8
+:1084E000B093A61B662757FD6095762F481B590B46
+:1084F0006A0B7B0B4093A71B5093A81B6093A91B8F
+:108500007093AA1B40815181662757FD6095762F95
+:10851000481B590B6A0B7B0B00E021E08FE991E0CF
+:108520006CDF0F9108950F936091E10281E068275D
+:108530006093E10287E89FE00F9456CA01E021E0D2
+:1085400048E050E060E070E081E491E056DF0F9198
+:1085500008950F9301E021E040E050E0BA014DDFC3
+:108560000F9108957F928F929F92AF92BF92CF9278
+:10857000DF92EF92FF920F931F93CF93DF9380913F
+:108580000A1B90910B1BA0910C1BB0910D1B81300D
+:108590009048A105B10540F010920A1B10920B1BE8
+:1085A00010920C1B10920D1B80910A1B90910B1BBB
+:1085B000A0910C1BB0910D1BB695A795979587952B
+:1085C00040910F1B50E060E070E084179507A6070C
+:1085D000B70710F480930F1BE0900F1BD090101B77
+:1085E000D2FADD24D0F8F12CCC24C3948091FB1A6C
+:1085F000811127C0EE2019F07724739425C0809153
+:10860000D4028823D9F0E091300BF0E0EE0FFF1F89
+:10861000EE5FFE4B6591749180910A1B90910B1B4C
+:10862000A0910C1BB0910D1B23E00297A105B10591
+:1086300010F443E001C040E28F2D40DDD1100DC0A9
+:10864000DBCF8230D9F0712C00E612E4C0E0D0E03C
+:108650008E2C912CA12CB12C61C080910A1B909181
+:108660000B1BA0910C1BB0910D1B0297A105B1052E
+:1086700008F0C2CFB3DE81E491E034C0E110BCCF9A
+:108680008091D4028823D9F0E091300BF0E0EE0F16
+:10869000FF1FEA57FF4B6591749180910A1B9091DF
+:1086A0000B1BA0910C1BB0910D1B23E00297A105A1
+:1086B000B10510F443E001C040E28F2DFFDCDD2066
+:1086C00009F49ACF80910A1B90910B1BA0910C1B6F
+:1086D000B0910D1B0297A105B10508F08DCF7EDE8C
+:1086E0008DED91E0DF91CF911F910F91FF90EF9071
+:1086F000DF90CF90BF90AF909F908F907F9029CFC9
+:108700008091D40281110DC0D11026C0739421969E
+:108710000E5F1F4FC230D10509F43FC07E10F6CF67
+:10872000EFCFF8016591749180910A1B90910B1B1A
+:10873000A0910C1BB0910D1BB695A79597958795A9
+:1087400020E288159905AA05BB0511F44EE301C086
+:1087500040E28F2DB3DCD8CF80910A1B90910B1B88
+:10876000A0910C1BB0910D1BB695A7959795879579
+:1087700088159905AA05BB0549F630DE8C2FDF91D7
+:10878000CF911F910F91FF90EF90DF90CF90BF900E
+:10879000AF909F908F907F9080CD40910A1B509119
+:1087A0000B1B60910C1B70910D1B7695679557956F
+:1087B0004795872D90E0A0E0B0E0481759076A0779
+:1087C0007B0788F0872D90E0880F991F0197AA27D3
+:1087D00097FDA095BA2F80930A1B90930B1BA09333
+:1087E0000C1BB0930D1B40910A1B50910B1B609109
+:1087F0000C1B70910D1B7695679557954795809149
+:108800000F1B90E00396242F30E0821793075CF44F
+:108810008DEF840F80930F1BC092D402ACEFEA2E31
+:10882000E40EFF24FA94F394E39483E08F1508F0A8
+:10883000DDCEDF91CF911F910F91FF90EF90DF90F0
+:10884000CF90BF90AF909F908F907F9008950F939F
+:1088500001E021E040E050E0BA01CFDD0F91089542
+:10886000AF92BF92CF92DF92EF92FF920F931F933E
+:10887000CF93DF9380910A1B90910B1BA0910C1B4F
+:10888000B0910D1B81309048A105B10540F01092C8
+:108890000A1B10920B1B10920C1B10920D1B809147
+:1088A0000A1B90910B1BA0910C1BB0910D1BB69550
+:1088B000A7959795879540910F1B50E060E070E079
+:1088C00084179507A607B70710F480930F1B009134
+:1088D0000F1BB090101BB2FABB24B0F810E0C8E137
+:1088E000D2E459E0C52ED12CE12CF12CAA24A3947A
+:1088F00080910A1B90910B1BA0910C1BB0910D1B3A
+:10890000011135C02091D402222399F0E091300B5F
+:10891000F0E0EE0FFF1FEE5FFE4B6591749123E0D8
+:108920000297A105B10510F443E001C040E2812F98
+:10893000C5DBBB2009F4F1C080910A1B90910B1B91
+:10894000A0910C1BB0910D1B0297A105B10508F079
+:10895000E4C044DD81E491E0DF91CF911F910F915C
+:10896000FF90EF90DF90CF90BF90AF90F2CD0130AD
+:1089700099F52091D4022223B9F0E091300BF0E078
+:10898000EE0FFF1FEC5EFD4B65917491B695A795B8
+:10899000979587952EE70197A105B10511F44EE350
+:1089A00001C040E2812F8ADBBB2009F4B6C0809170
+:1089B0000A1B90910B1BA0910C1BB0910D1BB6953F
+:1089C000A795979587950197A105B10509F0A5C0D1
+:1089D00005DD8BE691E096C0023099F52091D40236
+:1089E0002223B9F0E091300BF0E0EE0FFF1FE05FC3
+:1089F000FD4B65917491B695A795979587952EE750
+:108A00000297A105B10511F44EE301C040E2812FA8
+:108A100055DBBB2009F481C080910A1B90910B1B90
+:108A2000A0910C1BB0910D1BB695A79597958795B6
+:108A30000297A105B10509F070C0D0DC8DEA91E084
+:108A400061C0033099F52091D4022223B9F0E0915E
+:108A5000300BF0E0EE0FFF1FE45FFD4B659174916A
+:108A6000B695A795979587952EE70397A105B1052C
+:108A700011F44EE301C040E2812F20DBBB2009F45A
+:108A80004CC080910A1B90910B1BA0910C1BB091C4
+:108A90000D1BB695A795979587950397A105B105E9
+:108AA00009F03BC09BDC83EE91E02CC00430A9F5BB
+:108AB0002091D402222389F0FE0165917491B6952C
+:108AC000A795979587952EE70497A105B10511F411
+:108AD0004EE301C040E2812FF1DABB20F1F080913A
+:108AE0000A1B90910B1BA0910C1BB0910D1BB6950E
+:108AF000A795979587950497A105B10571F46EDC4C
+:108B000085E791E0DF91CF911F910F91FF90EF905A
+:108B1000DF90CF90BF90AF909ACE80910A1B90913A
+:108B20000B1BA0910C1BB0910D1B0A97A105B10561
+:108B300040F0C0920A1BD0920B1BE0920C1BF092EB
+:108B40000D1B40910A1B50910B1B60910C1B7091E7
+:108B50000D1B769567955795479580910F1B90E073
+:108B60000396242F30E0821793074CF48DEF840F87
+:108B700080930F1BA092D4020CEF040F1FEF1F5F16
+:108B80000F5F143008F4B4CEDF91CF911F910F9195
+:108B9000FF90EF90DF90CF90BF90AF90089580E06E
+:108BA00090E0A0E8BFE38093F71A9093F81AA0939F
+:108BB000F91AB093FA1A54CECF92DF92EF92FF9245
+:108BC0000F931F93CF93DF9380910A1B90910B1B00
+:108BD000A0910C1BB0910D1B81309048A105B105EF
+:108BE00040F010920A1B10920B1B10920C1B10925B
+:108BF0000D1B80910A1B90910B1BA0910C1BB09137
+:108C00000D1BB695A7959795879540910F1B50E042
+:108C100060E070E084179507A607B70710F480930B
+:108C20000F1BC0910F1BD091101BD2FBDD27D0F979
+:108C300000E093E0C92ED12CE12CF12C11E0409101
+:108C40000A1B50910B1B60910C1B70910D1BC111E5
+:108C500035C08091D4028823A9F0E091300BF0E078
+:108C6000EE0FFF1FE05EFD4B8591949123E04230B3
+:108C700051056105710510F443E001C040E2BC01FB
+:108C8000802F1CDADD2309F458C080910A1B9091D3
+:108C90000B1BA0910C1BB0910D1B0297A105B105F8
+:108CA00008F04BC09BDB8FE791E0DF91CF911F91E4
+:108CB0000F91FF90EF90DF90CF904BCCC13009F037
+:108CC0003CC08091D4028823C9F0E091300BF0E0E1
+:108CD000EE0FFF1FEC5DFC4B8591949176956795A7
+:108CE000579547952EE7413051056105710511F4FF
+:108CF0004EE301C040E2BC01802FE0D9DD23E9F062
+:108D000040910A1B50910B1B60910C1B70910D1B25
+:108D100076956795579547954130510561057105E1
+:108D200061F45CDB8DE891E0DF91CF911F910F91B1
+:108D3000FF90EF90DF90CF908ACD80910A1B9091A9
+:108D40000B1BA0910C1BB0910D1B0497A105B10545
+:108D500040F0C0920A1BD0920B1BE0920C1BF092C9
+:108D60000D1B40910A1B50910B1B60910C1B7091C5
+:108D70000D1B769567955795479580910F1B90E051
+:108D80000396242F30E0821793074CF48DEF840F65
+:108D900080930F1B1093D402CCEFC40F0FEF0F5F23
+:108DA000CF5F043008F44BCFDF91CF911F910F912B
+:108DB000FF90EF90DF90CF9008950F9360915D0B3F
+:108DC00081E0682760935D0B8FEA9FE00F9456CA9D
+:108DD0000F94AF2001E021E04AE050E060E070E055
+:108DE00081E491E00ADB0F9108950F9361E0809197
+:108DF000981B811160E06093981B8FEF9FE00F94A8
+:108E000056CA0F94071F88EE93E00F948D3E811190
+:108E100003C0E0E1F7E012C0EFE1F7E081918823C1
+:108E200081F09091C00095FFFCCF8093C600F6CFF3
+:108E30009091C00095FFFCCF8093C6008191811175
+:108E4000F7CFF89481E09091981B911101C080E0D8
+:108E50008093E81A0F94653C78940F94AF2080912A
+:108E60006C0B811104C080915F0B882349F001E0F5
+:108E700021E048E050E060E070E08FE391E008C05E
+:108E800001E021E047E050E060E070E081E491E043
+:108E9000B4DA0F91089520E044E064E181E19BE1C0
+:108EA0000E94B53D6ED881E19BE10C94763D0F9315
+:108EB000F2DF01E020E040E050E0BA018DED91E00A
+:108EC0009CDA0F910895F3DF85E090E09093971B73
+:108ED0008093961B089581E08093310B61E083EECF
+:108EE00093E50E9411C3E3CF61E08FED93E50E940B
+:108EF00011C3DDCF61E089ED93E50E9411C3D7CFA7
+:108F000061E085ED93E50E9411C3D1CF1092781AEC
+:108F10001092771A1092761A1092751A1092CB0A44
+:108F20001092CA0AC4CFC3DF10927A1B86E090E089
+:108F30009093971B8093961B08958AEF90E09093EF
+:108F4000781A8093771A88E290E09093761A80934B
+:108F5000751A1092CB0A1092CA0AA9DF0D94FE2846
+:108F600087ED90E09093781A8093771A8CE390E0E5
+:108F70009093761A8093751A1092CB0A1092CA0AAF
+:108F800096DF0D94FE288FEF90E09093781A8093EF
+:108F9000771A84E690E09093761A8093751A10926F
+:108FA000CB0A1092CA0A83DF0D94FE288EEF90E060
+:108FB0009093781A8093771A84E690E09093761ACB
+:108FC0008093751A1092CB0A1092CA0A70DF0D9422
+:108FD000FE2880EF90E09093781A8093771A8AE5C4
+:108FE00090E09093761A8093751A1092CB0A1092A3
+:108FF000CA0A5DDF0D94FE288CED90E09093781AFC
+:109000008093771A84E690E09093761A8093751A8D
+:109010001092CB0A1092CA0A4ADF0D94FE2886EEFF
+:1090200090E09093781A8093771A82E390E090937F
+:10903000761A8093751A1092CB0A1092CA0A37DFFB
+:109040000D94FE28EDE2F7E02191222339F03091D2
+:10905000C00035FFFCCF2093C600F6CF4AE050E0B9
+:10906000BC018EE799E00E944242E5E2F8E081917E
+:10907000882339F09091C00095FFFCCF8093C60003
+:10908000F6CF0895E6E0F8E08191882339F09091D9
+:10909000C00095FFFCCF8093C600F6CF6091901B77
+:1090A0007091911B4AE050E08EE799E00E944242A5
+:1090B000E5E2F8E08191882339F09091C00095FFB6
+:1090C000FCCF8093C600F6CF0895E3E3F7E08191EB
+:1090D000882339F09091C00095FFFCCF8093C600A3
+:1090E000F6CF6091771A7091781A4AE050E08EE7D7
+:1090F00099E00E944242E9E3F7E08191882339F048
+:109100009091C00095FFFCCF8093C600F6CF609190
+:10911000751A7091761A4AE050E08EE799E00E9445
+:109120004242E0E4F7E08191882339F09091C00059
+:1091300095FFFCCF8093C600F6CF40916F1A5091F7
+:10914000701A6091711A7091721A22E030E08EE705
+:1091500099E00E943543E7E4F7E08191882339F0F4
+:109160009091C00095FFFCCF8093C600F6CF409150
+:109170005D1A50915E1A60915F1A7091601A22E038
+:1091800030E08EE799E00E943543E5E2F8E0819116
+:10919000882339F09091C00095FFFCCF8093C600E2
+:1091A000F6CF08950F9381E09091DF02911180E056
+:1091B0008093DF02811103C00E947C4802C00E949C
+:1091C0006A4880916C0B01E021E049E050E060E0EA
+:1091D00070E0811104C080915F0B882319F08FE348
+:1091E00091E002C081E491E008D90F9108950F93B6
+:1091F00081E09091E002911180E08093E002811182
+:1092000003C00E9483CA02C00E9457CA80916C0B9F
+:1092100001E021E047E050E060E070E0811104C02F
+:1092200080915F0B882319F08FE391E002C081E405
+:1092300091E0E3D80F9108951F93CF93DF93C62F4A
+:10924000482F60E081E19BE10E94823D6C2F81E12B
+:109250009BE10F94AFB7C1EADBE111E169916623AD
+:1092600011F0111116C0112339F060E281E19BE188
+:109270000F94AFB71150F7CF63E081E19BE10F94FA
+:10928000AFB760E281E19BE1DF91CF911F910D9437
+:10929000AFB781E19BE10F94AFB71150DFCF2F92B1
+:1092A0003F924F925F926F927F928F929F92AF9276
+:1092B000BF92CF92DF92EF92FF920F931F93CF93C3
+:1092C000DF93CDB7DEB7A2970FB6F894DEBF0FBE1F
+:1092D000CDBF8091D402811104C08091101B82FF08
+:1092E0002BC38AE69BE00E9416C098A38F8F8091C3
+:1092F0000A1B90910B1BA0910C1BB0910D1B813090
+:109300009048A105B10540F010920A1B10920B1B6A
+:1093100010920C1B10920D1B80910A1B90910B1B3D
+:10932000A0910C1BB0910D1BB695A79597958795AD
+:1093300040910F1B50E060E070E084179507A6078E
+:10934000B70710F480930F1B40900F1B8091101BE8
+:1093500082FB332430F8512C411033C08091D40269
+:109360008823E1F0E091300BF0E0EE0FFF1FE05DAD
+:10937000FD4B6591749180910A1B90910B1BA091FC
+:109380000C1BB0910D1B23E00297A105B10510F451
+:1093900043E001C040E2852D0F945E40332089F008
+:1093A00080910A1B90910B1BA0910C1BB0910D1B7F
+:1093B0000297A105B10528F411D88DE591E0C9D82F
+:1093C000BBC26EE67BE088ED9BE00E9417A880910F
+:1093D0006E0B21E08F3219F0421671F022E0AF8C53
+:1093E000B8A081E0A81AB108C42CD12CE12CF12C32
+:1093F00022242394240C4CC08091D4028823C9F0E9
+:1094000080910A1B90910B1BA0910C1BB0910D1B1E
+:10941000B695A7959795879520E20197A105B10587
+:1094200011F44EE301C040E26FE378E5852D0F941F
+:109430005E40332099F280910A1B90910B1BA09102
+:109440000C1BB0910D1BB695A79597958795019725
+:10945000A105B10519F60F94EE410F94F4416CC2C9
+:109460002411EFC140E050E0B5018AE69BE00E9484
+:1094700078BC9091B00B8091D402992309F4B8C0C4
+:1094800081110BC031107DC0222D91E0A91AB108C5
+:10949000EFEFAE16BE0621F7D6C1E091300BF0E03B
+:1094A000EE0FFF1FE85EFC4B8591949180910A1BA3
+:1094B00090910B1BA0910C1BB0910D1BB695A7951D
+:1094C00097958795452D60E08C159D05AE05BF05E8
+:1094D00061F581E19BE10E94823D6EE381E19BE1C8
+:1094E0000F94AFB765E081E19BE10F94AFB7809136
+:1094F0007B0B882329F010928D0B0BE71BE002C039
+:109500000EE61BE042E1942EF80161918F01662383
+:1095100011F09110E7C1992009F4B4CF60E281E124
+:109520009BE10F94AFB79A94F6CF81E19BE10E9443
+:10953000823D60E281E19BE10F94AFB765E081E19C
+:109540009BE10F94AFB780917B0B882329F0109299
+:109550008D0B0BE71BE002C00EE61BE032E1932E01
+:10956000F80161918F01662311F09110C1C199201A
+:1095700009F488CF60E281E19BE10F94AFB79A9440
+:10958000F6CF80910A1B90910B1BA0910C1BB09100
+:109590000D1BB695A795979587958C159D05AE05DE
+:1095A000BF0509F071CF0F94EE418AE69BE00E945F
+:1095B00031B8F9E08F9F800111240F50154F6EE6EE
+:1095C0007BE0C8010F94A1C6B8018EE799E00E9424
+:1095D00035426EE67BE08AE69BE00E9479C01092FD
+:1095E0000A1B10920B1B10920C1B10920D1BA4C196
+:1095F000811103C03110A1C047CFE091300BF0E0E2
+:10960000EE0FFF1FE85EFC4B8591949180910A1B41
+:1096100090910B1BA0910C1BB0910D1BB695A795BB
+:10962000979587958C159D05AE05BF0509F05CC023
+:109630002091B81B29A310E0412F60E081E19BE15C
+:109640000E94823D60E281E19BE10F94AFB71F5F12
+:10965000143091F7452D60E081E19BE10E94823D4D
+:109660006EE381E19BE10F94AFB7BBE76B2EBBE0EC
+:109670007B2E812C912C01E010E0F30121913F0120
+:10968000222341F1452D602F81E19BE12AA30E9415
+:10969000823D2AA1622F81E19BE10F94AFB70F5F5A
+:1096A0001F4F0431110549F78FEF881A980AF4010A
+:1096B000E558F44F3F010CE211E00F94F32B809139
+:1096C000101B82FD1BC18091B81B29A1281709F42A
+:1096D00018C114C114E1101B60E281E19BE10F94F9
+:1096E000AFB71150C9F786CF452D60E081E19BE10E
+:1096F0000E94823D60E281E19BE10F94AFB78091CF
+:109700007B0B882329F010928E0B0BE71BE002C025
+:109710000EE61BE0A3E19A2EF80161918F0166230A
+:1097200011F0911003C1992009F464CF60E281E146
+:109730009BE10F94AFB79A94F6CF80910A1B90915A
+:109740000B1BA0910C1BB0910D1BB695A79597957F
+:1097500087958C159D05AE05BF0509F095CE0F9434
+:10976000EE411092230B8EE69BE09F938F9388E34C
+:1097700098E59F938F938E010F5F1F4F1F930F9359
+:109780000F9418C80F900F900F900F900F900F909C
+:109790007E01F5E0EF0EF11CF7018081882349F08E
+:1097A000992787FD90950F94D7C5F70181937F0185
+:1097B000F3CF60E0C8010E9411C3EEE6EE2EEBE0AD
+:1097C000FE2E05E91FE0F70161917F01C8010F94AA
+:1097D00074CA0F5F1F4F0D39FFE01F07A1F78AE61C
+:1097E0009BE00E9431B8982E71EFC72E7AE0D72EF9
+:1097F000760100E010E08E2D8C198915B0F4580127
+:1098000088E0A80EB11CF701E00FF11F6081C801CC
+:109810008D5E904F0F9474CA0F5F1F4F0A151B0582
+:1098200091F72FEFE21AF20AE6CF692D83E69FE067
+:109830000F9474CA61E084E398E50E9411C337DB9A
+:109840007BC02F5F22CE80910A1B90910B1BA091B1
+:109850000C1BB0910D1BB695A79597958795422F38
+:1098600050E060E070E084179507A607B70788F01E
+:10987000822F90E0880F991F0197AA2797FDA09546
+:10988000BA2F80930A1B90930B1BA0930C1BB093D1
+:109890000D1B80910A1B90910B1BA0910C1BB0918A
+:1098A0000D1BB695A7959795879520910F1B30E0D6
+:1098B0002D5F3F4F482F50E02417350764F42DEFFC
+:1098C000280F20930F1B21E02093D4023CEF432E5E
+:1098D000480E55245A9453944394F3E0F51508F038
+:1098E0003BCD2AC081E19BE10F94AFB79A940CCE97
+:1098F00081E19BE10F94AFB79A9432CE10928D0B19
+:10990000B4CE81E08816910431F463E070E080E029
+:1099100090E00F941EB561E070E080E090E00F945D
+:109920001EB50150110909F0C8CEA5CE81E19BE119
+:109930000F94AFB79A94F0CEA2960FB6F894DEBF0C
+:109940000FBECDBFDF91CF911F910F91FF90EF9090
+:10995000DF90CF90BF90AF909F908F907F906F904F
+:109960005F904F903F902F9008958F929F92AF926B
+:10997000BF92EF92FF920F931F93CF93DF9380914B
+:109980000A1B90910B1BA0910C1BB0910D1B8130F9
+:109990009048A105B10540F010920A1B10920B1BD4
+:1099A00010920C1B10920D1B80910A1B90910B1BA7
+:1099B000A0910C1BB0910D1BB695A7959795879517
+:1099C00040910F1B50E060E070E084179507A607F8
+:1099D000B70710F480930F1BD0910F1B1091101B31
+:1099E00012FB112710F9C0E0FF24F394D1113EC0FF
+:1099F0008091D4028823E1F0E091300BF0E0EE0F8B
+:109A0000FF1FE05DFD4B6591749180910A1B909161
+:109A10000B1BA0910C1BB0910D1B23E00297A1051D
+:109A2000B10510F443E001C040E28C2F0F945E407A
+:109A30001123E1F080910A1B90910B1BA0910C1B4C
+:109A4000B0910D1B0297A105B10580F40F94EE4172
+:109A50008DE591E0DF91CF911F910F91FF90EF90F5
+:109A6000BF90AF909F908F900D94A9422091921B30
+:109A700080910A1B90910B1BA0910C1BB0910D1BA8
+:109A80002223C1F1D130C1F52091D402222389F0E3
+:109A9000B695A7959795879520E20197A105B10501
+:109AA00011F44EE301C040E264E278E58C2F0F949C
+:109AB0005E40112309F461C080910A1B90910B1B39
+:109AC000A0910C1BB0910D1BB695A7959795879506
+:109AD0000197A105B10509F050C00F94EE41DF9147
+:109AE000CF911F910F91FF90EF90BF90AF909F90FB
+:109AF0008F9023CA01E001C002E00D133FC0209106
+:109B0000D4022223B1F0B695A79597958795402F5B
+:109B100050E060E070E020E284179507A607B707E1
+:109B200011F44EE301C040E265E178E58C2F0F941B
+:109B30005E40112319F180910A1B90910B1BA0919B
+:109B40000C1BB0910D1BB695A79597958795402F47
+:109B500050E060E070E084179507A607B70771F43E
+:109B60000F94EE41DF91CF911F910F91FF90EF90F5
+:109B7000BF90AF909F908F90F3C902E0EE24E394E2
+:109B8000E00EED1246C08091D4028823F1F080915E
+:109B90000A1B90910B1BA0910C1BB0910D1BB6954D
+:109BA000A795979587958D2E912CA12CB12C20E20D
+:109BB00088159905AA05BB0511F44EE301C040E2E2
+:109BC00066E078E58C2F0F945E40112311F18091AF
+:109BD0000A1B90910B1BA0910C1BB0910D1BB6950D
+:109BE000A795979587954E2D50E060E070E084171B
+:109BF0009507A607B70769F40F94EE41DF91CF915F
+:109C00001F910F91FF90EF90BF90AF909F908F901A
+:109C1000E0C972E0E72EE00EED1246C08091D4025A
+:109C20008823F1F080910A1B90910B1BA0910C1BD3
+:109C3000B0910D1BB695A795979587958D2E912C74
+:109C4000A12CB12C20E288159905AA05BB0511F4B9
+:109C50004EE301C040E266EF77E58C2F0F945E4043
+:109C6000112311F180910A1B90910B1BA0910C1BE9
+:109C7000B0910D1BB695A795979587954E2D50E001
+:109C800060E070E084179507A607B70769F40F94A2
+:109C9000EE41DF91CF911F910F91FF90EF90BF9018
+:109CA000AF909F908F906FC943E0E42EE00EED12CD
+:109CB00046C08091D4028823F1F080910A1B9091D4
+:109CC0000B1BA0910C1BB0910D1BB695A7959795FA
+:109CD00087958D2E912CA12CB12C20E28815990509
+:109CE000AA05BB0511F44EE301C040E266EE77E53C
+:109CF0008C2F0F945E40112311F180910A1B9091DB
+:109D00000B1BA0910C1BB0910D1BB695A7959795B9
+:109D100087954E2D50E060E070E084179507A60708
+:109D2000B70769F40F94EE41DF91CF911F910F9126
+:109D3000FF90EF90BF90AF909F908F905DC9F4E03F
+:109D4000EF2EE00EED1246C08091D4028823F1F090
+:109D500080910A1B90910B1BA0910C1BB0910D1BC5
+:109D6000B695A795979587958D2E912CA12CB12C02
+:109D700020E288159905AA05BB0511F44EE301C040
+:109D800040E266ED77E58C2F0F945E40112311F1D0
+:109D900080910A1B90910B1BA0910C1BB0910D1B85
+:109DA000B695A795979587954E2D50E060E070E0A9
+:109DB00084179507A607B70769F40F94EE41DF9162
+:109DC000CF911F910F91FF90EF90BF90AF909F9018
+:109DD0008F90ECC865E0E62EE00EED1246C0809153
+:109DE000D4028823F1F080910A1B90910B1BA09163
+:109DF0000C1BB0910D1BB695A795979587958D2E49
+:109E0000912CA12CB12C20E288159905AA05BB053F
+:109E100011F44EE301C040E267EC77E58C2F0F941C
+:109E20005E40112311F180910A1B90910B1BA091B0
+:109E30000C1BB0910D1BB695A795979587954E2D48
+:109E400050E060E070E084179507A607B70769F453
+:109E50000F94EE41DF91CF911F910F91FF90EF9002
+:109E6000BF90AF909F908F90DAC836E0E32EE00E5F
+:109E7000ED124EC08091D402882329F1E091300B7D
+:109E8000F0E0EE0FFF1FEA5FFC4B6591749180914B
+:109E90000A1B90910B1BA0910C1BB0910D1BB6954A
+:109EA000A795979587958E2C912CA12CB12C20E20B
+:109EB00088159905AA05BB0511F44EE301C040E2DF
+:109EC0008C2F0F945E40112319F140910A1B509181
+:109ED0000B1B60910C1B70910D1B76956795579528
+:109EE00047958E2D90E0A0E0B0E0481759076A072B
+:109EF0007B0771F40F94EE41DF91CF911F910F9189
+:109F0000FF90EF90BF90AF909F908F900D948647F9
+:109F100027E0200F40910A1B50910B1B60910C1BF6
+:109F200070910D1B7695679557954795822F90E018
+:109F3000A0E0B0E0481759076A077B0788F0822F36
+:109F400090E0880F991F0197AA2797FDA095BA2F37
+:109F500080930A1B90930B1BA0930C1BB0930D1BBB
+:109F600040910A1B50910B1B60910C1B70910D1BB3
+:109F7000769567955795479580910F1B90E00396CE
+:109F8000242F30E0821793074CF48DEF840F8093D9
+:109F90000F1BF092D402DCEFD40FCFEFCF5FDF5F67
+:109FA000C43008F423CDDF91CF911F910F91FF9022
+:109FB000EF90BF90AF909F908F900895CF93DF93D5
+:109FC000CDB7DEB728970FB6F894DEBF0FBECDBF72
+:109FD00088E0EBE5F3E0DE01119601900D928A95A1
+:109FE000E1F7AE014F5F5F4F61E081E19BE10E94CD
+:109FF0000A4028960FB6F894DEBF0FBECDBFDF91A2
+:10A00000CF9108950F931F93CF93DF93CDB7DEB712
+:10A0100060970FB6F894DEBF0FBECDBF88E0E3E6D1
+:10A02000F3E0DE01199601900D928A95E1F788E040
+:10A030008E010F5F1F4FF801982F11929A95E9F743
+:10A0400091E09A8393E09B8396E19C839CE19D83BE
+:10A050008E83AE01475F5F4F61E081E19BE10E942B
+:10A060000A40A80162E081E19BE10E940A406096FB
+:10A070000FB6F894DEBF0FBECDBFDF91CF911F9119
+:10A080000F910895CF93DF93CDB7DEB728970FB622
+:10A09000F894DEBF0FBECDBF88E0E3E2F3E0DE015F
+:10A0A000119601900D928A95E1F7AE014F5F5F4FD7
+:10A0B00061E081E19BE10E940A4028960FB6F89486
+:10A0C000DEBF0FBECDBFDF91CF91089581E19BE14F
+:10A0D0000C94763D4AE050E0BC0181E19BE10D9497
+:10A0E00055B8CF93DF93EA01462F682F81E19BE1BA
+:10A0F0000E94823D4AE050E0BE0181E19BE1DF9198
+:10A10000CF910D9455B88EEF9FE00F9444CA8230E2
+:10A1100028F48093300B1092FB1A089581E080930D
+:10A12000300B8093FB1A08951F93CF93DF93EC01BC
+:10A13000FB01608111810F9456CA612FCE010196F7
+:10A14000DF91CF911F910D9456CAFF920F931F93E9
+:10A15000CF93DF938C01EB010F9444CAF82EC80112
+:10A1600001960F9444CAF8828983DF91CF911F91A1
+:10A170000F91FF90089561E080EC9FE00F9456CA24
+:10A1800060E08FEB9FE00F9456CA60E08EEB9FE09B
+:10A190000F9456CA60E08DEB9FE00F9456CA60E0C2
+:10A1A0008CEB9FE00F9456CA1092B11B1092B01B1B
+:10A1B0001092AC1B1092B31B1092B21B1092AD1BED
+:10A1C0001092B51B1092B41B1092AE1B1092B71BCD
+:10A1D0001092B61B1092AF1B0895EF92FF920F934F
+:10A1E0001F93CF93DF931F92CDB7DEB77B018C0116
+:10A1F000061B170B460FC701800F911F49830F9451
+:10A2000044CAF70181937F0149814E13F4CF0F9027
+:10A21000DF91CF911F910F91FF90EF9008956EEF16
+:10A220008EEF9FE00D9456CA81E08093DC02089582
+:10A230000F931F93CF938091921B882371F10E94FB
+:10A24000B4C4C82F0F94EFB40091660B1091670B44
+:10A250002091680B3091690B601B710B820B930B83
+:10A260000F9466BE2FE632E143E85AE30F949BC099
+:10A27000CC2329F020E030E040E752E404C020E0A5
+:10A2800030E046E154E40F94C9BF18161CF4109254
+:10A29000DC0203C081E08093DC02CF911F910F911B
+:10A2A00008958093FD1A1092FC1A0895E5E6FBE1EB
+:10A2B00001900020E9F73197E556FB411E161F0675
+:10A2C00034F01092791B82E08093D402089580E2EA
+:10A2D000E431F105B4F7DF01AB59B44E8C933196FC
+:10A2E000F7CF20917A1B211108C044E150E0BC0156
+:10A2F00085E69BE10F94B6C6D9CF089520917A1BCD
+:10A30000211108C044E150E0BC0185E69BE10F94B7
+:10A3100029C6CCCF089561E082EC97E50E9411C375
+:10A3200081E08093240B82E090E09093220B809355
+:10A33000210BE091300BF0E0EE0FFF1FE056FD4BDC
+:10A3400085919491DBDF0F94574783E08093D4028B
+:10A350000895D4DF81E080937A1B0D9457471092C3
+:10A360007A1B089580917A1B08950F931F93CF93C2
+:10A37000C0910301C2FBCC27C0F981E0C8278091BE
+:10A38000030181FFC2608091D302882309F4C4C015
+:10A390008091000186FD89C00F94EFB4605D7A481A
+:10A3A0008F4F9F4F6093F31A7093F41A8093F51AAE
+:10A3B0009093F61A0F94EFB400917D1B10917E1BC1
+:10A3C00020917F1B3091801B06171707280739073C
+:10A3D00008F0A6C00F94EFB468537F4F8F4F9F4F84
+:10A3E00060937D1B70937E1B80937F1B9093801BDB
+:10A3F00080917C1B81112EC08091851B81112AC008
+:10A400008091D5029091D60221E0833E9207A1F07F
+:10A410009093041B8093031B80910A1B90910B1B4C
+:10A42000A0910C1BB0910D1B8093061B9093071BF2
+:10A43000A093081BB093091B0F94EFB46093811B8A
+:10A440007093821B8093831B9093841B81E0809385
+:10A450007C1B66C00F94EFB40091811B1091821B8E
+:10A460002091831B3091841B601B710B820B930B1B
+:10A47000693E73408105910508F452C081E08093E4
+:10A48000851B80E090E0A0E8BFE38093F71A9093EB
+:10A49000F81AA093F91AB093FA1A01E021E040E00B
+:10A4A00050E0BA0183EE91E02BC080917C1B8823A1
+:10A4B00081F10F94EFB468537F4F8F4F9F4F60939C
+:10A4C0007D1B70937E1B80937F1B9093801B20913C
+:10A4D000851B8091D5029091D602211114C0835E14
+:10A4E0009140E9F44091061B5091071B6091081BB5
+:10A4F0007091091B01E021E08091031B9091041BE6
+:10A500000F94FD410DC0835E914051F40F94EE41D4
+:10A5100007C01092851B04C08091000186FFC460B3
+:10A52000C093101B8091101B81709091101B91FDA6
+:10A53000826090910E1B891721F18130F1F028F093
+:10A54000823089F08330A1F01CC0913021F49091C9
+:10A55000B81B9F5F05C09230A1F49091B81B915039
+:10A560009093B81B0EC0992391F3933051F4F5CF1B
+:10A57000923069F3913029F4F0CF933041F399236D
+:10A5800061F380930E1BCF911F910F9108950F944B
+:10A590004B47E4E0F1E080818B7F808380818D7F79
+:10A5A00080839FB7F894E5E0F1E080818460808348
+:10A5B0009FBF9FB7F8948081826080839FBFE1E056
+:10A5C000F1E080818F7B80839FB7F894E2E0F1E037
+:10A5D0008081806480839FBF60E08FE00F94DAB653
+:10A5E0009FB7F894E5E0F1E08081816080839FBFB0
+:10A5F00080910301809581708093051BB6DE1092D7
+:10A60000B81B089581E008959091101B92FB882754
+:10A6100080F992FD10927C1B0895CF931F92C1E0A8
+:10A62000CF936091691A70916A1A80916B1A909118
+:10A630006C1A0F9435BE7F936F931F92CF936091E6
+:10A64000631A7091641A8091651A9091661A0F943A
+:10A6500035BE7F936F9384E499E59F938F938FE644
+:10A660009AE09F938F930F94DFC6CEDF2DB73EB74E
+:10A67000245F3F4F0FB6F8943EBF0FBE2DBF882317
+:10A6800029F00F94EE41CF910D945747CF91089543
+:10A69000CF93DF938BE59FE00F9451CAEC018DE5DA
+:10A6A0009FE00F9451CADF93CF939F938F938EE1D6
+:10A6B00099E59F938F938FE69AE09F938F930F94E2
+:10A6C000DFC6A2DF2DB73EB7285F3F4F0FB6F89425
+:10A6D0003EBF0FBE2DBF882331F00F94EE41DF91B6
+:10A6E000CF910D945747DF91CF91089584E090E08A
+:10A6F00090931602809315020F94F32B81E00E9431
+:10A70000BD5C82DF8823C1F37FDF8111FDCF6AE06A
+:10A7100070E080E090E00F941EB576DF8111FDCFF0
+:10A7200082E090E090931602809315020895DF92E4
+:10A73000EF92FF920F931F93CF93DF93CDB7DEB7C6
+:10A7400028970FB6F894DEBF0FBECDBF80E597E027
+:10A750009A83898389E597E09C838B8384E697E0DD
+:10A760009E838D8382E797E098878F83E090B81B64
+:10A77000FF24E7FCF094AADC40E060E081E19BE18B
+:10A780000E94823D6EE477E081E19BE10F94AEB7D9
+:10A79000D12C00E010E0402F61E081E19BE10E94BC
+:10A7A000823DE091E91AF091EA1AE00FF11FEE0FF5
+:10A7B000FF1F81E090E08C0F9D1FE80FF91F608163
+:10A7C000718181E19BE10F94AEB70F5F1F4F0430A1
+:10A7D000110509F70F94F32B81E00E94BD5C2091D5
+:10A7E000B81B332727FD3095C701821B930B97FFBA
+:10A7F00003C091958195910905970CF46FC02E15B2
+:10A800003F050CF4DA94E216F3060CF4D39493E0CB
+:10A810009D156CF48091E91A9091EA1A97FF7FC018
+:10A8200001969093EA1A8093E91A50DC78C0D7FE1B
+:10A830000EC08091E91A9091EA1A1816190634F49C
+:10A8400001979093EA1A8093E91A40DCD12C40E0FA
+:10A8500060E081E19BE10E94823D6EEC78E081E165
+:10A860009BE10F94AEB741E060E081E19BE10E9483
+:10A87000823D6EEC78E081E19BE10F94AEB742E05F
+:10A8800060E081E19BE10E94823D6EEC78E081E135
+:10A890009BE10F94AEB743E060E081E19BE10E9451
+:10A8A000823D6EEC78E081E19BE10F94AEB74D2DD7
+:10A8B00060E081E19BE10E94823D6EE477E081E10E
+:10A8C0009BE10F94AEB7E090B81BFF24E7FCF09437
+:10A8D00064E670E080E090E00F941EB595DE88237A
+:10A8E00009F457CF91DE8111FDCF6AE070E080E07E
+:10A8F00090E00F941EB588DE8111FDCF8091E91A9A
+:10A900008D0D28960FB6F894DEBF0FBECDBFDF9138
+:10A91000CF911F910F91FF90EF90DF90089513E07A
+:10A92000D12E95CFFC01808190E02AE030E0B90182
+:10A930000F948AC2482FCB01B9010F948AC2805D5F
+:10A940008093EB1A405D4093EC1A1092ED1A8BEE57
+:10A950009AE1089520E030E040E251E4FC0160819A
+:10A960007181828193810F949BC00F9435BE77FDD6
+:10A9700002C02BE201C02DE22093EB1A9B0177FF6E
+:10A9800004C022273327261B370BC90168EE73E06A
+:10A990000F948AC2CB01EAE0F0E0BF010F948AC2B3
+:10A9A000805D8093EC1AC90164E670E00F948AC25E
+:10A9B000CB01BF010F948AC2805D8093ED1AC9015B
+:10A9C000BF010F948AC2282FCB01BF010F948AC206
+:10A9D000805D8093EE1A8EE28093EF1A205D2093C3
+:10A9E000F01A1092F11A8BEE9AE108958F929F92CD
+:10A9F000AF92BF92CF92DF92EF92FF92CF9320E07F
+:10AA000030E048EC52E4FC016081718182819381E5
+:10AA10000F949BC00F9435BE6B017C0197FD12C053
+:10AA200020E137E240E050E00F94BFC2CA01B90113
+:10AA30002AE030E040E050E00F94BFC2605D6093D8
+:10AA4000EB1A03C08DE28093EB1AF7FE08C0F09476
+:10AA5000E094D094C094C11CD11CE11CF11CC7012E
+:10AA6000B60128EE33E040E050E00F94BFC29AE018
+:10AA7000892E912CA12CB12CCA01B901A5019401F8
+:10AA80000F94BFC2605D6093EC1AC701B60124E663
+:10AA900030E040E050E00F94BFC2CA01B901A50107
+:10AAA00094010F94BFC2605D6093ED1A8EE28093B3
+:10AAB000EE1AC701B601A50194010F94BFC2C62FBB
+:10AAC000CA01B901A50194010F94BFC2605D6093F2
+:10AAD000EF1AC05DC093F01A1092F11A8BEE9AE152
+:10AAE000CF91FF90EF90DF90CF90BF90AF909F906D
+:10AAF0008F9008958F929F92AF92BF92CF92DF92E4
+:10AB0000EF92FF92CF93FC01C080D180E280F3806E
+:10AB100020E030E0A901C701B6010F94C9BF1816A3
+:10AB20001CF4C701B60103C0C701B60190580F94C9
+:10AB300035BE6B017C016031F7E27F07810591052D
+:10AB400084F020E137E240E050E00F94BFC2CA0138
+:10AB5000B9012AE030E040E050E00F94BFC2605DF0
+:10AB600001C060E26093EB1A88EEC81683E0D80655
+:10AB7000E104F10494F0C701B60128EE33E040E0AF
+:10AB800050E00F94BFC2CA01B9012AE030E040E0B2
+:10AB900050E00F94BFC2605D01C060E26093EC1AA8
+:10ABA000E4E6CE16D104E104F10494F0C701B60145
+:10ABB00024E630E040E050E00F94BFC2CA01B90182
+:10ABC0002AE030E040E050E00F94BFC2605D01C079
+:10ABD00060E36093ED1A8EE28093EE1A2AE0822EF3
+:10ABE000912CA12CB12CC701B601A50194010F94A1
+:10ABF000BFC2C62FCA01B901A50194010F94BFC2FB
+:10AC0000605D6093EF1AC05DC093F01A8BEE9AE11D
+:10AC1000CF91FF90EF90DF90CF90BF90AF909F903B
+:10AC20008F9008958F929F92AF92BF92CF92DF92B2
+:10AC3000EF92FF92CF9320E030E04AE754E4FC012A
+:10AC400060817181828193810F949BC00F9435BE86
+:10AC50006B017C0197FD12C028EE33E040E050E02C
+:10AC60000F94BFC2CA01B9012AE030E040E050E0D1
+:10AC70000F94BFC2605D6093EB1A03C08DE28093B6
+:10AC8000EB1AF7FE08C0F094E094D094C094C11C75
+:10AC9000D11CE11CF11C8EE28093EC1AC701B601B5
+:10ACA00024E630E040E050E00F94BFC26AE0862E18
+:10ACB000912CA12CB12CCA01B901A50194010F94CA
+:10ACC000BFC2605D6093ED1AC701B601A501940192
+:10ACD0000F94BFC2C62FCA01B901A50194010F94F8
+:10ACE000BFC2605D6093EE1AC05DC093EF1A109210
+:10ACF000F01A8BEE9AE1CF91FF90EF90DF90CF901A
+:10AD0000BF90AF909F908F9008958F929F92AF9237
+:10AD1000BF92CF92DF92EF92FF92CF9320E030E08C
+:10AD20004AE754E4FC0160817181828193810F9430
+:10AD30009BC00F9435BE97FD02C020E201C02DE2FA
+:10AD40002093EB1A6B017C0197FF08C0F094E0940C
+:10AD5000D094C094C11CD11CE11CF11CC701B601E8
+:10AD600028EE33E040E050E00F94BFC2EAE08E2EC0
+:10AD7000912CA12CB12CCA01B901A50194010F9409
+:10AD8000BFC2605D6093EC1A8EE28093ED1AC7013A
+:10AD9000B60124E630E040E050E00F94BFC2CA01A3
+:10ADA000B901A50194010F94BFC2605D6093EE1AD2
+:10ADB000C701B601A50194010F94BFC2C62FCA01F5
+:10ADC000B901A50194010F94BFC2605D6093EF1AB1
+:10ADD000C05DC093F01A1092F11A8BEE9AE1CF91F8
+:10ADE000FF90EF90DF90CF90BF90AF909F908F90AB
+:10ADF00008958F929F92AF92BF92CF92DF92EF927F
+:10AE0000FF92FC0180809180A280B38020E030E03E
+:10AE100048EC52E4C501B4010F949BC06B017C0166
+:10AE200020E030E0A9010F94C9BF18161CF4C70137
+:10AE3000B60103C0C701B60190580F9435BE6B012F
+:10AE40007C0120E030E0A901C501B4010F94C6BD2A
+:10AE500087FF12C08DE28093EB1AC701B60128EE7E
+:10AE600033E040E050E00F94BFC2CA01B9012AE0CC
+:10AE700030E040E050E036C0C701B60120E137E2E3
+:10AE800040E050E00F94BFC2AAE08A2E912CA12C82
+:10AE9000B12CCA01B901A50194010F94BFC2662368
+:10AEA00091F0605D6093EB1AC701B60128EE33E0C4
+:10AEB00040E050E00F94BFC2CA01B901A50194015E
+:10AEC0000F94BFC213C080E28093EB1AC701B60192
+:10AED00028EE33E040E050E00F94BFC2CA01B90150
+:10AEE000A50194010F94BFC2662311F0605D01C0FB
+:10AEF00060E26093EC1AC701B60124E630E040E05E
+:10AF000050E00F94BFC2FAE08F2E912CA12CB12CEF
+:10AF1000CA01B901A50194010F94BFC2605D60939D
+:10AF2000ED1AC701B601A50194010F94BFC26623B3
+:10AF300081F0605D6093F01ACA01B901A501940126
+:10AF40000F94BFC2605D6093EF1A8EE28093EE1A99
+:10AF500015C0CA01B901A50194010F94BFC26623AF
+:10AF600029F0605D6093EF1A8EE203C080E2809367
+:10AF7000EF1A8093EE1A80E28093F01A1092F11A81
+:10AF80008BEE9AE1FF90EF90DF90CF90BF90AF9063
+:10AF90009F908F900895FC012081318137FF07C079
+:10AFA0008DE28093EB1A31952195310914C0243636
+:10AFB000310574F0C90164E670E00F948AC2CB01D8
+:10AFC0006AE070E00F948AC2805D8093EB1A06C03D
+:10AFD00080E28093EB1A2A30310564F0EAE0F0E079
+:10AFE000C901BF010F948AC2CB01BF010F948AC26D
+:10AFF000805D01C080E28093EC1AC9016AE070E0D4
+:10B000000F948AC2805D8093ED1A1092EE1A8BEE37
+:10B010009AE108951F93CF93DF931F921F92CDB7AC
+:10B02000DEB740E060E081E19BE10E94823D6BE79A
+:10B0300077E081E19BE10F94AEB784E69FE00F9447
+:10B0400044CA182F41E060E081E19BE10E94823D0B
+:10B0500060E977E081E19BE10F94AEB741E061E107
+:10B0600081E19BE10E94823D812F90E09A83898358
+:10B07000CE01019690DFBC0181E19BE10F94AEB758
+:10B0800086E69FE00F9444CA182F42E060E081E119
+:10B090009BE10E94823D65EA77E081E19BE10F94AC
+:10B0A000AEB742E061E181E19BE10E94823D812FE8
+:10B0B00090E09A838983CE0101966DDFBC0181E126
+:10B0C0009BE10F94AEB785E69FE00F9444CA182F1A
+:10B0D00043E060E081E19BE10E94823D6AEB77E022
+:10B0E00081E19BE10F94AEB743E061E181E19BE137
+:10B0F0000E94823D812F90E09A838983CE01019640
+:10B100004ADFBC0181E19BE10F94AEB77DDA882371
+:10B1100021F00F94EE410F9457470F900F90DF915D
+:10B12000CF911F9108956F927F929F92BF92CF927D
+:10B13000DF92EF92FF920F931F93CF93DF93809153
+:10B14000AB1B81115EC081E08093AB1B8FEB9FE056
+:10B150000F9444CA082F282F332727FD30953093AA
+:10B16000B11B2093B01B8093AC1B8EEB9FE00F9420
+:10B1700044CA182F282F332727FD30953093B31B4F
+:10B180002093B21B8093AD1B8DEB9FE00F9444CABC
+:10B19000D82F282F332727FD30953093B51B2093C8
+:10B1A000B41B8093AE1B8CEB9FE00F9444CAC82F56
+:10B1B000282F332727FD30953093B71B2093B61BDC
+:10B1C0008093AF1B80EC9FE00F9444CA813009F05C
+:10B1D000A4C20E5C053608F0A0C21E5C153608F04D
+:10B1E0009CC2DE5CD53608F098C2CE5CC53608F04D
+:10B1F00094C281E08093D40261E080EC9FE00F94E0
+:10B2000056CA6091B01B7091B11B8091AC1B9927FD
+:10B2100087FD90958617970731F06093AC1B8FEBF5
+:10B220009FE00F9456CA6091B21B7091B31B80913E
+:10B23000AD1B992787FD90958617970731F060938E
+:10B24000AD1B8EEB9FE00F9456CA6091B41B7091BA
+:10B25000B51B8091AE1B992787FD909586179707A0
+:10B2600031F06093AE1B8DEB9FE00F9456CA609156
+:10B27000B61B7091B71B8091AF1B992787FD9095E6
+:10B280008617970731F06093AF1B8CEB9FE00F940C
+:10B2900056CA80910A1B90910B1BA0910C1BB09178
+:10B2A0000D1B81309048A105B10540F010920A1B9A
+:10B2B00010920B1B10920C1B10920D1B80910A1BFD
+:10B2C00090910B1BA0910C1BB0910D1BB695A795EF
+:10B2D0009795879540910F1B50E060E070E08417D0
+:10B2E0009507A607B70710F480930F1B10910F1B4B
+:10B2F0009090101B92FA992490F8B12CE0E76E2EF2
+:10B30000E3E47E2EFBE0CF2ED12CE12CF12C01E0EA
+:10B3100080910A1B90910B1BA0910C1BB0910D1BEF
+:10B3200011113AC02091D4022223A1F0E091300BF8
+:10B33000F0E0EE0FFF1FEE5FFE4B6591749123E08E
+:10B340000297A105B10510F443E001C040E28B2D46
+:10B350000F945E40992009F49AC180910A1B909144
+:10B360000B1BA0910C1BB0910D1B0297A105B10501
+:10B3700008F08DC10F94EE418FE791E0DF91CF91FE
+:10B380001F910F91FF90EF90DF90CF90BF909F9013
+:10B390007F906F900D94A942113009F04AC020911E
+:10B3A000D402222301F1E091300BF0E0EE0FFF1FF9
+:10B3B000E658FC4BC591D491B695A795979587957E
+:10B3C0000197A105B10531F480EB9BE1E4DD9C011F
+:10B3D0004EE305C080EB9BE1DEDD9C0140E2BE0157
+:10B3E0008B2D0F949540992009F451C180910A1B2F
+:10B3F00090910B1BA0910C1BB0910D1BB695A795BE
+:10B40000979587950197A105B10509F040C10F9463
+:10B41000EE41E091300BF0E0EE0FFF1FE658FC4BE1
+:10B420008591949122E330E04EEC5FEF60EB7BE19D
+:10B430004CC0123009F057C02091D402222301F1F0
+:10B44000E091300BF0E0EE0FFF1FE459FC4BC5918B
+:10B45000D491B695A795979587950297A105B105C3
+:10B4600031F482EB9BE197DD9C014EE305C082EB5A
+:10B470009BE191DD9C0140E2BE018B2D0F94954034
+:10B48000992009F404C180910A1B90910B1BA09193
+:10B490000C1BB0910D1BB695A795979587950297B4
+:10B4A000A105B10509F0F3C00F94EE41E091300B16
+:10B4B000F0E0EE0FFF1FE459FC4B8591949122E3DD
+:10B4C00030E04EEC5FEF62EB7BE1DF91CF911F91BB
+:10B4D0000F91FF90EF90DF90CF90BF909F907F9063
+:10B4E0006F900D944642133009F04AC02091D40267
+:10B4F000222301F1E091300BF0E0EE0FFF1FE25844
+:10B50000FC4BC591D491B695A795979587950397D0
+:10B51000A105B10531F484EB9BE13DDD9C014EE3D7
+:10B5200005C084EB9BE137DD9C0140E2BE018B2D21
+:10B530000F949540992009F4AAC080910A1B90911C
+:10B540000B1BA0910C1BB0910D1BB695A795979561
+:10B5500087950397A105B10509F099C00F94EE41B5
+:10B56000E091300BF0E0EE0FFF1FE258FC4B8591AD
+:10B57000949122E330E04EEC5FEF64EB7BE1A5CFEA
+:10B58000143009F04AC02091D402222301F1E09145
+:10B59000300BF0E0EE0FFF1FEE58FC4BC591D4913D
+:10B5A000B695A795979587950497A105B10531F4B0
+:10B5B00086EB9BE1F0DC9C014EE305C086EB9BE152
+:10B5C000EADC9C0140E2BE018B2D0F94954099204E
+:10B5D00009F45DC080910A1B90910B1BA0910C1B7C
+:10B5E000B0910D1BB695A795979587950497A105E2
+:10B5F000B10509F04CC00F94EE41E091300BF0E042
+:10B60000EE0FFF1FEE58FC4B8591949122E330E042
+:10B610004EEC5FEF66EB7BE158CF1530C1F5209122
+:10B62000D402222391F0F30165917491B695A79508
+:10B630009795879520E20597A105B10511F44EE392
+:10B6400001C040E28B2D0F945E40992001F1809162
+:10B650000A1B90910B1BA0910C1BB0910D1BB69572
+:10B66000A795979587950597A105B10581F40F9446
+:10B67000EE41DF91CF911F910F91FF90EF90DF90FE
+:10B68000CF90BF909F907F906F900D9420428091BB
+:10B690000A1B90910B1BA0910C1BB0910D1B0C97DA
+:10B6A000A105B10540F0C0920A1BD0920B1BE0929D
+:10B6B0000C1BF0920D1B40910A1B50910B1B6091CB
+:10B6C0000C1B70910D1B769567955795479580914A
+:10B6D0000F1B90E00396242F30E08217930754F459
+:10B6E0008DEF840F80930F1B0093D4021CEF140F77
+:10B6F000BB24BA94B3941F5F83E08B1508F008CE87
+:10B70000DF91CF911F910F91FF90EF90DF90CF903D
+:10B71000BF909F907F906F9008951092B11B1092F0
+:10B72000B01B1092B31B1092B21B1092B51B10925B
+:10B73000B41B1092B71B1092B61B5BCD8F929F92D9
+:10B74000AF92BF92CF92DF92EF92FF920F931F932F
+:10B75000CF93DF9380910A1B90910B1BA0910C1B40
+:10B76000B0910D1B81309048A105B10540F01092B9
+:10B770000A1B10920B1B10920C1B10920D1B809138
+:10B780000A1B90910B1BA0910C1BB0910D1BB69541
+:10B79000A7959795879540910F1B50E060E070E06A
+:10B7A00084179507A607B70710F480930F1BA09086
+:10B7B0000F1B9090101B92FA992490F8B12C02E87C
+:10B7C00013E447E0C42ED12CE12CF12C882483947F
+:10B7D00080910A1B90910B1BA0910C1BB0910D1B2B
+:10B7E000A1103AC02091D4022223A1F0E091300BA5
+:10B7F000F0E0EE0FFF1FEE5FFE4B6591749123E0CA
+:10B800000297A105B10510F443E001C040E28B2D81
+:10B810000F945E40992009F406C180910A1B909113
+:10B820000B1BA0910C1BB0910D1B0297A105B1053C
+:10B8300008F0F9C00F94EE4181E491E0DF91CF91DF
+:10B840001F910F91FF90EF90DF90CF90BF90AF903E
+:10B850009F908F900D94A94221E0A2124AC020919E
+:10B86000D402222301F1E091300BF0E0EE0FFF1F34
+:10B87000EC50FE4BC591D491B695A79597958795B9
+:10B880000197A105B10531F487E79AE184DB9C01BA
+:10B890004EE305C087E79AE17EDB9C0140E2BE01F2
+:10B8A0008B2D0F949540992009F4BDC080910A1BFF
+:10B8B00090910B1BA0910C1BB0910D1BB695A795F9
+:10B8C000979587950197A105B10509F0ACC00F9434
+:10B8D000EE41E091300BF0E0EE0FFF1FEC50FE4B1D
+:10B8E0008591949127E231E040E050E067E77AE10A
+:10B8F0008CC022E0A2123FC02091D4022223D1F0BA
+:10B90000F801C591D491B695A7959795879502971B
+:10B91000A105B10531F485E79AE13DDB9C014EE3D9
+:10B9200005C085E79AE137DB9C0140E2BE018B2D23
+:10B930000F949540992009F476C080910A1B90914C
+:10B940000B1BA0910C1BB0910D1BB695A79597955D
+:10B9500087950297A105B10509F065C00F94EE41E6
+:10B96000E2E8F3E48591949123E930E040E050E08F
+:10B9700065E77AE14AC023E0A21255C02091D402C3
+:10B98000222301F1E091300BF0E0EE0FFF1FE454B1
+:10B99000FD4BC591D491B695A7959795879503973B
+:10B9A000A105B10531F48AEC9AE0F5DA9C014EE389
+:10B9B00005C08AEC9AE0EFDA9C0140E2BE018B2DD3
+:10B9C0000F949540992079F180910A1B90910B1B5F
+:10B9D000A0910C1BB0910D1BB695A79597958795D7
+:10B9E0000397A105B105F9F40F94EE41E091300BF6
+:10B9F000F0E0EE0FFF1FE454FD4B859194912FEF83
+:10BA000030E040E050E06AEC7AE0DF91CF911F91A6
+:10BA10000F91FF90EF90DF90CF90BF90AF909F90ED
+:10BA20008F900D94464280910A1B90910B1BA09120
+:10BA30000C1BB0910D1B0897A105B10540F0C092F9
+:10BA40000A1BD0920B1BE0920C1BF0920D1B409135
+:10BA50000A1B50910B1B60910C1B70910D1B76956E
+:10BA600067955795479580910F1B90E00396242F7B
+:10BA700030E0821793075CF48DEF840F80930F1BE7
+:10BA80008092D402DCEFAD2EA40EBB24BA94B39402
+:10BA9000A39483E08B1508F09BCEDF91CF911F918B
+:10BAA0000F91FF90EF90DF90CF90BF90AF909F905D
+:10BAB0008F900895AF92BF92DF92FF920F931F93E2
+:10BAC000CF93DF9341E068E97BE18FEF9FE00F9434
+:10BAD000ED5080910A1B90910B1BA0910C1BB09113
+:10BAE0000D1B81309048A105B10540F010920A1B52
+:10BAF00010920B1B10920C1B10920D1B80910A1BB5
+:10BB000090910B1BA0910C1BB0910D1BB695A795A6
+:10BB10009795879540910F1B50E060E070E0841787
+:10BB20009507A607B70710F480930F1B10910F1B02
+:10BB3000D090101BD2FADD24D0F8F12CE2E8AE2E22
+:10BB4000E3E4BE2E01E080910A1B90910B1BA091B3
+:10BB50000C1BB0910D1B111136C02091D402222371
+:10BB6000A1F0E091300BF0E0EE0FFF1FE05DFD4B28
+:10BB70006591749123E00297A105B10510F443E0AB
+:10BB800001C040E28F2D0F945E40DD2009F4D6C144
+:10BB900080910A1B90910B1BA0910C1BB0910D1B67
+:10BBA0000297A105B10508F0C9C10F94EE418DE5DA
+:10BBB00091E0DF91CF911F910F91FF90DF90BF90A7
+:10BBC000AF900D94A942113009F04AC02091D402DF
+:10BBD000222301F1E091300BF0E0EE0FFF1FEC515A
+:10BBE000FF4BC591D491B695A795979587950197E9
+:10BBF000A105B10531F486E592E0CDD99C014EE373
+:10BC000005C086E592E0C7D99C0140E2BE018F2DB8
+:10BC10000F949540DD2009F491C180910A1B909109
+:10BC20000B1BA0910C1BB0910D1BB695A79597957A
+:10BC300087950197A105B10509F080C10F94EE41E8
+:10BC4000E091300BF0E0EE0FFF1FEC51FF4B8591C0
+:10BC5000949127EE33E04AE050E066E572E04CC094
+:10BC6000123009F053C02091D402222301F1E09157
+:10BC7000300BF0E0EE0FFF1FEC50FE4BC591D4915E
+:10BC8000B695A795979587950297A105B10531F4CB
+:10BC900087E79AE180D99C014EE305C087E79AE1E6
+:10BCA0007AD99C0140E2BE018F2D0F949540DD2092
+:10BCB00009F444C180910A1B90910B1BA0910C1BAD
+:10BCC000B0910D1BB695A795979587950297A105FD
+:10BCD000B10509F033C10F94EE41E091300BF0E073
+:10BCE000EE0FFF1FEC50FE4B8591949127E231E05F
+:10BCF00040E050E067E77AE1DF91CF911F910F912B
+:10BD0000FF90DF90BF90AF900D944642133009F042
+:10BD10003FC02091D4022223D1F0F501C591D491E6
+:10BD2000B695A795979587950397A105B10531F429
+:10BD300085E79AE130D99C014EE305C085E79AE199
+:10BD40002AD99C0140E2BE018F2D0F949540DD2041
+:10BD500009F4F4C080910A1B90910B1BA0910C1B5D
+:10BD6000B0910D1BB695A795979587950397A1055B
+:10BD7000B10509F0E3C00F94EE41E2E8F3E48591E8
+:10BD800094912CE830E040E050E065E77AE1B4CFF0
+:10BD9000143009F04AC02091D402222301F1E0912D
+:10BDA000300BF0E0EE0FFF1FE454FD4BC591D49132
+:10BDB000B695A795979587950497A105B10531F498
+:10BDC0008AEC9AE0E8D89C014EE305C08AEC9AE040
+:10BDD000E2D89C0140E2BE018F2D0F949540DD20FA
+:10BDE00009F4ACC080910A1B90910B1BA0910C1B15
+:10BDF000B0910D1BB695A795979587950497A105CA
+:10BE0000B10509F09BC00F94EE41E091300BF0E0DA
+:10BE1000EE0FFF1FE454FD4B859194912FEF30E01E
+:10BE200040E050E06AEC7AE067CF153009F04AC094
+:10BE30002091D402222301F1E091300BF0E0EE0FCB
+:10BE4000FF1FE456FD4BC591D491B695A7959795E4
+:10BE500087950597A105B10531F484E592E09BD85B
+:10BE60009C014EE305C084E592E095D89C0140E238
+:10BE7000BE018F2D0F949540DD2009F45FC08091A5
+:10BE80000A1B90910B1BA0910C1BB0910D1BB6953A
+:10BE9000A795979587950597A105B10509F04EC01F
+:10BEA0000F94EE41E091300BF0E0EE0FFF1FE456EF
+:10BEB000FD4B8591949127EE33E04AE050E064E534
+:10BEC00072E01ACF1630D1F52091D4022223C1F0AE
+:10BED000E091300BF0E0EE0FFF1FE854FD4B659151
+:10BEE0007491B695A7959795879520E20697A10539
+:10BEF000B10511F44EE301C040E28F2D0F945E4076
+:10BF0000DD20E1F080910A1B90910B1BA0910C1B8E
+:10BF1000B0910D1BB695A795979587950697A105A6
+:10BF2000B10561F40F94EE41DF91CF911F910F9114
+:10BF3000FF90DF90BF90AF900D948B512091E00265
+:10BF400080910A1B90910B1BA0910C1BB0910D1BB3
+:10BF500021110FC0173009F048C02091D4022223CC
+:10BF600021F1E091300BF0E0EE0FFF1FEE56FD4B9C
+:10BF70000DC01730D1F52091D4022223B1F0E09109
+:10BF8000300BF0E0EE0FFF1FE257FD4B659174910F
+:10BF9000B695A7959795879520E20797A105B105D6
+:10BFA00011F140E28F2D0F945E40DD20F1F0809181
+:10BFB0000A1B90910B1BA0910C1BB0910D1BB69509
+:10BFC000A795979587950797A105B10571F40F94EB
+:10BFD000EE41DF91CF911F910F91FF90DF90BF90C5
+:10BFE000AF900D94F7484EE3DDCF2091981B8091E0
+:10BFF0000A1B90910B1BA0910C1BB0910D1B2111E2
+:10C000000FC0183009F048C02091D402222321F13A
+:10C01000E091300BF0E0EE0FFF1FEE50FF4B0DC034
+:10C020001830D1F52091D4022223B1F0E091300BE9
+:10C03000F0E0EE0FFF1FE251FF4B65917491B69552
+:10C04000A7959795879520E20897A105B10511F16D
+:10C0500040E28F2D0F945E40DD20F1F080910A1BAD
+:10C0600090910B1BA0910C1BB0910D1BB695A79541
+:10C07000979587950897A105B10571F40F94EE4146
+:10C08000DF91CF911F910F91FF90DF90BF90AF9004
+:10C090000D94F5464EE3DDCF8091981B811159C078
+:10C0A0002091DF0280910A1B90910B1BA0910C1B29
+:10C0B000B0910D1B211110C0193011F02AE04AC0B7
+:10C0C0002091D402222321F1E091300BF0E0EE0F19
+:10C0D000FF1FE450FD4B0DC0193081F72091D402B1
+:10C0E0002223B1F0E091300BF0E0EE0FFF1FE8509B
+:10C0F000FD4B65917491B695A7959795879520E22C
+:10C100000997A105B10519F140E28F2D0F945E400A
+:10C11000DD20A1F280910A1B90910B1BA0910C1BBA
+:10C12000B0910D1BB695A795979587950997A10591
+:10C13000B10509F0C3CF0F94EE41DF91CF911F916C
+:10C140000F91FF90DF90BF90AF900D94D2484EE3D7
+:10C15000DCCF29E080910A1B90910B1BA0910C1B56
+:10C16000B0910D1BB695A79597958795422F50E0F6
+:10C1700060E070E084179507A607B70788F0822F64
+:10C1800090E0880F991F0197AA2797FDA095BA2FD5
+:10C1900080930A1B90930B1BA0930C1BB0930D1B59
+:10C1A00080910A1B90910B1BA0910C1BB0910D1B51
+:10C1B000B695A7959795879520910F1B30E02D5F39
+:10C1C0003F4F482F50E02417350754F42DEF280F28
+:10C1D00020930F1B0093D4021CEF180FFF24FA9436
+:10C1E000F3941F5F83E08F1508F0ADCCDF91CF9102
+:10C1F0001F910F91FF90DF90BF90AF9008958F92A5
+:10C200009F92AF92BF92CF92DF92EF92FF92CF9325
+:10C21000DF931F921F92CDB7DEB78830910509F4E6
+:10C2200049C0C4F48430910509F44DC064F48130F0
+:10C23000910509F49DC18230910509F4C7C1892B8C
+:10C2400009F07CC443C086309105B9F1CCF1ECE033
+:10C25000F8E0D3C28A35910521F164F48531910566
+:10C2600031F18631910501F1449709F067C4ECEF93
+:10C27000F7E01CC38C35910571F084F08D35910584
+:10C2800039F08336910509F059C4E0E3F8E01CC4A5
+:10C29000EFECF7E0F6C3E8EDF7E0D0C3E1EEF7E04E
+:10C2A000AAC3EAEEF7E084C3E3EFF7E055C3ECEF8F
+:10C2B000F7E02EC3EEEFF7E0CCC2E5E1F8E075C29F
+:10C2C000EEE1F8E049C2E7E2F8E01DC280916C0BB4
+:10C2D000ECEFF7E0882309F42CC18191882339F031
+:10C2E0009091C00095FFFCCF8093C600F6CF84E00C
+:10C2F00090E00F9422480F944248EAE3F8E08191DD
+:10C30000882339F09091C00095FFFCCF8093C60040
+:10C31000F6CF4091290B50912A0B60912B0B709115
+:10C320002C0B2AE030E08EE799E00E947C42E0E4AA
+:10C33000F8E08191882339F09091C00095FFFCCFFF
+:10C340008093C600F6CF8091560D882319F1809115
+:10C35000000E9091010EA091020EB091030E009775
+:10C36000A105B105B9F0BC01CD016D597F4F8F4FCB
+:10C370009F4F24E630E040E050E00F949DC2609172
+:10C38000080E7091090E80910A0E90910B0E0F9479
+:10C390009DC201C020E030E03A832983CE0101969E
+:10C3A0000F94CB57FC012191CF01222339F030911A
+:10C3B000C00035FFFCCF2093C600F4CFE7E4F8E0DF
+:10C3C0008191882339F09091C00095FFFCCF809334
+:10C3D000C600F6CF86E592E00F94CB57FC01219181
+:10C3E000CF01222339F03091C00035FFFCCF2093DC
+:10C3F000C600F4CFEEE4F8E08191882339F0909103
+:10C40000C00095FFFCCF8093C600F6CFEEE2FBE1C3
+:10C410008191882339F09091C00095FFFCCF8093E3
+:10C42000C600F6CFE5E5F8E08191882339F09091D8
+:10C43000C00095FFFCCF8093C600F6CF80918A0A9A
+:10C4400090918B0AA0918C0AB0918D0A892B8A2B2E
+:10C450008B2B49F10F94EFB4A8EE8A2EA3E09A2E0D
+:10C46000A12CB12CA50194010F949DC269017A0100
+:10C4700060918A0A70918B0A80918C0A90918D0A42
+:10C48000A50194010F949DC2C21AD30AE40AF50AC9
+:10C490002AE030E0B701A6018EE799E00E947C42D5
+:10C4A000ECE5F8E00FC04AE050E060E070E08EE7B5
+:10C4B00099E00E944242F4CF9091C00095FFFCCFDA
+:10C4C0008093C60081918111F7CFEEE4F4E0819171
+:10C4D000882339F09091C00095FFFCCF8093C6006F
+:10C4E000F6CFE5E2F8E08191882339F09091C00021
+:10C4F00095FFFCCF8093C600F6CFE4E6F8E081918B
+:10C50000882339F09091C00095FFFCCF8093C6003E
+:10C51000F6CF8091C00085FFFCCF8AE08093C600F3
+:10C5200084E090E03AC29091C00095FFFCCF8093E8
+:10C53000C60081918111F7CF81E090E00F942248ED
+:10C540000F944248E4E6F8E08191882339F0909115
+:10C55000C00095FFFCCF8093C600F6CF8091C0004D
+:10C5600085FFFCCF8AE08093C60081E090E015C291
+:10C5700082E090E090938F1B80938E1BECEFF7E0AE
+:10C580008191882339F09091C00095FFFCCF809372
+:10C59000C600F6CF82E090E00F9422480F94424804
+:10C5A000E4E6F8E08191882339F09091C00095FF8E
+:10C5B000FCCF8093C600F6CF8091C00085FFFCCFF2
+:10C5C0008AE08093C60082E090E090C083E090E033
+:10C5D00090938F1B80938E1BECEFF7E08191882363
+:10C5E00039F09091C00095FFFCCF8093C600F6CF44
+:10C5F00083E090E00F9422480F944248E4E6F8E08C
+:10C600008191882339F09091C00095FFFCCF8093F1
+:10C61000C600F6CF8091C00085FFFCCF8AE08093F2
+:10C62000C60083E090E090932E0B80932D0B81E069
+:10C6300090E09093DE028093DD0280916C0B81117B
+:10C6400003C0ECEFF7E034C084E090E090938F1BE0
+:10C6500080938E1BECEFF7E08191882339F0909165
+:10C66000C00095FFFCCF8093C600F6CF84E090E039
+:10C670000F9422480F944248E4E6F8E08191882321
+:10C6800039F09091C00095FFFCCF8093C600F6CFA3
+:10C690008091C00085FFFCCF8AE08093C60084E0D3
+:10C6A00090E024C09091C00095FFFCCF8093C6001D
+:10C6B00081918111F7CF83E090E00F9422480F948D
+:10C6C0004248E4E6F8E08191882339F09091C00077
+:10C6D00095FFFCCF8093C600F6CF8091C00085FF08
+:10C6E000FCCF8AE08093C60083E090E090932E0B0D
+:10C6F00080932D0B81E090E000C19091C00095FFE8
+:10C70000FCCF8093C60081918111F7CF8091C0004A
+:10C7100085FFFCCF8AE08093C60080912D0B90911D
+:10C720002E0B0F9422480F944248E4E6F8E08191E2
+:10C73000882339F09091C00095FFFCCF8093C6000C
+:10C74000F6CF8091C00085FFFCCFA4C09091C000BF
+:10C7500095FFFCCF8093C60081918111F7CF809126
+:10C76000C00085FFFCCF8AE08093C60080912D0B2E
+:10C7700090912E0B0F9422480F944248E4E6F8E083
+:10C780008191882339F09091C00095FFFCCF809370
+:10C79000C600F6CF8091C00085FFFCCF7BC0909192
+:10C7A000C00095FFFCCF8093C60081918111F7CF27
+:10C7B0008091C00085FFFCCF8AE08093C6000F9473
+:10C7C0004248E4E6F8E08191882339F09091C00076
+:10C7D00095FFFCCF8093C600F6CF8091C00085FF07
+:10C7E000FCCF8AE08093C60088E090E027C090915B
+:10C7F000C00095FFFCCF8093C60081918111F7CFD7
+:10C800008091C00085FFFCCF8AE08093C6000F9422
+:10C810004248E4E6F8E08191882339F09091C00025
+:10C8200095FFFCCF8093C600F6CF8091C00085FFB6
+:10C83000FCCF8AE08093C60089E090E090932E0BB5
+:10C8400080932D0B2AC09091C00095FFFCCF809360
+:10C85000C60081918111F7CF10922E0B10922D0BF3
+:10C860006091901B7091911B4AE050E08EE799E037
+:10C870000E944242E3E6F8E08191882339F09091EA
+:10C88000C00095FFFCCF8093C600F6CF8091C0001A
+:10C8900085FFFCCF8AE08093C60082E090E02DC047
+:10C8A0009091C00095FFFCCF8093C60081918111CB
+:10C8B000F7CF8091C00085FFFCCF8AE08093C6004F
+:10C8C00080912D0B90912E0B0F9422480F9442488B
+:10C8D000E4E6F8E08191882339F09091C00095FF5B
+:10C8E000FCCF8093C600F6CF8091C00085FFFCCFBF
+:10C8F0008AE08093C60085E090E09093DE0280930A
+:10C90000DD021CC19091C00095FFFCCF8093C60052
+:10C9100081918111F7CF0F9465480F94424880911F
+:10C920002D0B90912E0B0F942248E4E6F8E08191B4
+:10C93000882339F09091C00095FFFCCF8093C6000A
+:10C94000F6CF8091C00085FFFCCFF5C09091C0006C
+:10C9500095FFFCCF8093C60081918111F7CF809124
+:10C96000C00085FFFCCF8AE08093C6000F94424848
+:10C97000E4E6F8E08191882339F09091C00095FFBA
+:10C98000FCCF8093C600F6CF8091C00085FFFCCF1E
+:10C990008AE08093C60085E090E090932E0B809310
+:10C9A0002D0BCCC09091C00095FFFCCF8093C600AA
+:10C9B00081918111F7CF8091C00085FFFCCF8AE083
+:10C9C0008093C6000F944248E4E6F8E08191882302
+:10C9D00039F09091C00095FFFCCF8093C600F6CF50
+:10C9E0008091C00085FFFCCFA6C09091C00095FF4C
+:10C9F000FCCF8093C60081918111F7CF8091C00058
+:10CA000085FFFCCF8AE08093C6000F944248E4E69D
+:10CA1000F8E08191882339F09091C00095FFFCCF18
+:10CA20008093C600F6CF8091C00085FFFCCF83C005
+:10CA30009091C00095FFFCCF8093C6008191811139
+:10CA4000F7CF8091C00085FFFCCF8AE08093C600BD
+:10CA50000F944248E4E6F8E08191882339F0909100
+:10CA6000C00095FFFCCF8093C600F6CF8091C00038
+:10CA700085FFFCCF60C09091C00095FFFCCF8093F4
+:10CA8000C60081918111F7CF8091C00085FFFCCF56
+:10CA90008AE08093C6000F944248E4E6F8E0819172
+:10CAA000882339F09091C00095FFFCCF8093C60099
+:10CAB000F6CF8091C00085FFFCCF3DC09091C000B3
+:10CAC00095FFFCCF8093C60081918111F7CF0F9421
+:10CAD0006548E6E0F8E08191882339F09091C00044
+:10CAE00095FFFCCF8093C600F6CF6091901B7091AC
+:10CAF000911B4AE050E08EE799E00E944242E5E255
+:10CB0000F8E08191882339F09091C00095FFFCCF27
+:10CB10008093C600F6CFE4E6F8E08191882339F0EF
+:10CB20009091C00095FFFCCF8093C600F6CF809116
+:10CB3000C00085FFFCCF8AE08093C6000F900F9065
+:10CB4000DF91CF91FF90EF90DF90CF90BF90AF90AB
+:10CB50009F908F900895BF92CF92DF92EF92FF92B5
+:10CB60000F931F93CF93DF93C091901BD091911B94
+:10CB70000F94665040E060E081E19BE10E94823DBD
+:10CB800066E678E081E19BE10F94AEB7B12CB4E6A4
+:10CB9000EB2EF12C1AE0C12ED12C2091B81B422F84
+:10CBA000552741950CF45095CA0157FF03C0919544
+:10CBB0008195910903970CF444C027FF1FC051E0F1
+:10CBC000B51659F082E0B81681F0B11038C0C436FD
+:10CBD000D105ACF1C456D10932C0CE01B7010F94D2
+:10CBE0008AC20A9764F12A972AC0CE01B6010F942F
+:10CBF0008AC2181619061CF5219721C02223F9F0C4
+:10CC000041E0B41661F052E0B51691F0B11017C0D2
+:10CC1000C43883E0D8079CF4CC59DF4F10C0CE0154
+:10CC2000B7010F948AC28A3591054CF42A9607C041
+:10CC3000CE01B6010F948AC2099709F0219610928D
+:10CC4000B81B42E060E081E19BE10E94823DC43676
+:10CC5000D1057CF46EE678E081E19BE10F94AEB7FC
+:10CC6000CA30D10534F46EE678E081E19BE10F949F
+:10CC7000AEB74AE050E0BE0181E19BE10F9455B8A8
+:10CC80006DEC78E081E19BE10F94AEB743E060E0AA
+:10CC900081E19BE10E94823D6CEC78E081E19BE1C7
+:10CCA0000F94AEB743E06B2D81E19BE10E94823D82
+:10CCB00060E778E081E19BE10F94AEB764E670E055
+:10CCC00080E090E00F941EB50F9404538823E1F0A8
+:10CCD00068EC70E080E090E00F941EB5B39443E000
+:10CCE000B41212C0D093911BC093901B60E97BE1FA
+:10CCF00081EC9FE00F94945084E190E080DA0F94EF
+:10CD0000574701E010E002C000E010E00F94F32B61
+:10CD1000012B09F442CFDF91CF911F910F91FF902A
+:10CD2000EF90DF90CF90BF900895CF93DF931F9245
+:10CD30001F92CDB7DEB7FC01608171818281938142
+:10CD40000F9435BE7A836983CE0101960F94CB5739
+:10CD50000F900F90DF91CF910895FC018081918118
+:10CD60008436910524F164E670E00F948AC2CB0109
+:10CD70002AE030E0B9010F948AC2805D8093EB1AFB
+:10CD800080819181B9010F948AC2CB01B9010F94BE
+:10CD90008AC2805D8093EC1A80819181B9010F94E1
+:10CDA0008AC2805D8093ED1A1092EE1A23C08A30F9
+:10CDB0009105BCF02AE030E0B9010F948AC2CB01A2
+:10CDC000B9010F948AC2805D8093EB1A80819181B2
+:10CDD000B9010F948AC2805D8093EC1A1092ED1A0B
+:10CDE00009C06AE070E00F948AC2805D8093EB1AFC
+:10CDF0001092EC1A8BEE9AE10895FC0180819181EA
+:10CE0000883E23E092075CF068EE73E00F948AC2DC
+:10CE1000CB016AE070E00F948AC2805D01C080E2BD
+:10CE20008093EB1A80819181843691055CF064E6F1
+:10CE300070E00F948AC2CB016AE070E00F948AC25E
+:10CE4000805D01C080E28093EC1A808191818A30FC
+:10CE500091055CF02AE030E0B9010F948AC2CB0161
+:10CE6000B9010F948AC2805D01C080E28093ED1AFF
+:10CE7000808191816AE070E00F948AC2805D809326
+:10CE8000EE1A1092EF1A8BEE9AE10895CF92EF927C
+:10CE90000F930F94EFB460938A1B70938B1B809356
+:10CEA0008C1B90938D1B0F94EFB46093811B709338
+:10CEB000821B8093831B9093841B0F94EFB4609329
+:10CEC0007D1B70937E1B80937F1B9093801B77E468
+:10CED000C72EE5E5EE2E06E42BE34DE362E581E1A6
+:10CEE0009BE10E946F3E0F91EF90CF900895CF93FA
+:10CEF000DF93FC016491EC012196662331F081E11E
+:10CF00009BE10E944440CE01F4CFDF91CF91089580
+:10CF10000F931F93CF93DF938C01EB0141E061E00E
+:10CF200081E19BE10E94823DC801E1DF6AE381E18A
+:10CF30009BE10F94AFB7FE0101900020E9F76C2F41
+:10CF40006E1B6C5E41E081E19BE10E94823DBE016F
+:10CF500081E19BE1DF91CF911F910F910D94AEB7CD
+:10CF60002F923F924F925F926F927F928F929F92F9
+:10CF7000AF92BF92CF92DF92EF92FF920F931F93E7
+:10CF8000CF93DF931C01EB017A01490180910A1BC9
+:10CF900090910B1BA0910C1BB0910D1B892B8A2B20
+:10CFA0008B2B09F4AFC00E94AC51809164138F5F4A
+:10CFB000803109F480E090916313981709F4A2C0BE
+:10CFC0008E01000F111F000F111FC8018052954FD5
+:10CFD0005C0160910A1B70910B1B882777FD80957F
+:10CFE000982F0F9468BE2091F71A3091F81A40914B
+:10CFF000F91A5091FA1A0F949BC0F50120813181E2
+:10D00000428153810F94EDBC2B013C01B70188276D
+:10D0100077FD8095982F0F9468BE6B017C019B0172
+:10D02000AC01C301B2010F94C6BDF50187FD05C077
+:10D03000408251826282738204C0C082D182E282C5
+:10D04000F382B401882777FD8095982F0F9468BEEE
+:10D050004B015C01C8018052954F7C01A5019401F0
+:10D06000FC0160817181828193810F94C9BF181680
+:10D070002CF4F70180829182A282B38210920A1B63
+:10D0800010920B1B10920C1B10920D1B64EE7AE099
+:10D0900080EE9AE00E941D47F801EF59F64F20E01C
+:10D0A00030E040E752E460817181828193810F9486
+:10D0B000CDBD4B015C01E090E80AF090E90A0091D7
+:10D0C000EA0A1091EB0A2091E40A3091E50A4091B6
+:10D0D000E60A5091E70A6091E00A7091E10A8091B6
+:10D0E000E20A9091E30AECECFAE0FF93EF93ACEEE6
+:10D0F000CA2EAAE0DA2E0F94580581E08093D4025C
+:10D100000F900F908091D402882361F0CE01880F98
+:10D11000991F880F991F8052954F0F94AA54BC01F4
+:10D12000C101F6DE8091101B82FF09C001E021E001
+:10D1300040E050E0BA018BE791E00F94FD41DF91B0
+:10D14000CF911F910F91FF90EF90DF90CF90BF9004
+:10D15000AF909F908F907F906F905F904F903F9097
+:10D160002F90089522ED30E040E050E062E070E062
+:10D1700087E498E5F5CE22ED30E04CEF5FEF61E01B
+:10D1800070E085E498E5ECCE2FEF30E040E050E031
+:10D1900060E070E083E498E5E3CE0F93CF93DF93F4
+:10D1A0001F921F92CDB7DEB780910A1B90910B1B87
+:10D1B000A0910C1BB0910D1BB7FF08C010920A1B69
+:10D1C00010920B1B10920C1B10920D1B8091A71B31
+:10D1D0009091A81BA091A91BB091AA1B40910A1B7A
+:10D1E00050910B1B60910C1B70910D1B84179507C0
+:10D1F000A607B70744F480930A1B90930B1BA093D8
+:10D200000C1BB0930D1B8091D4028823B1F0809148
+:10D21000A31B9091A41B20910A1B30910B1B820F22
+:10D22000931F9A838983CE0101960F94CB57BC013B
+:10D2300080919F1B9091A01B6BDE8091101B82FF41
+:10D240001EC0E091A11BF091A21B8091A31B9091A5
+:10D25000A41B20910A1B30910B1B820F931F9183FB
+:10D26000808340919D1B50919E1B60E070E000E028
+:10D2700021E080919B1B90919C1B0F94FD410F908E
+:10D280000F90DF91CF910F9108950F931F93CF933C
+:10D29000DF938C01EB0141E060E081E19BE10E94C2
+:10D2A000823DC80124DE6AE381E19BE10F94AFB7C0
+:10D2B000FE0101900020E9F7BE016E1B7F0B6B5E43
+:10D2C0007F4F7695679543E081E19BE10E94823D27
+:10D2D000BE0181E19BE10F94AEB762E778E081E1A6
+:10D2E0009BE1DF91CF911F910F910D94AEB70F93FA
+:10D2F0001F93CF93DF93ECE8F3E4C591D491809131
+:10D300009B1B81117BC011E010939B1B0E945E60F0
+:10D310006CE97BE18CEF9FE00F94A5506EE97BE117
+:10D320008AEF9FE00F94A55060EA7BE188EF9FE0D1
+:10D330000F94A55060919C1B70919D1B882777FDD1
+:10D340008095982F0F9468BE209140193091411913
+:10D3500040914219509143190F94CDBD6093A21B87
+:10D360007093A31B8093A41B9093A51B60919E1B9D
+:10D3700070919F1B882777FD8095982F0F9468BE2A
+:10D3800020914419309145194091461950914719FF
+:10D390000F94CDBD6093A61B7093A71B8093A81B11
+:10D3A0009093A91B6091A01B7091A11B882777FD0A
+:10D3B0008095982F0F9468BE209148193091491993
+:10D3C00040914A1950914B190F94CDBD6093AA1BFF
+:10D3D0007093AB1B8093AC1B9093AD1B1093D40246
+:10D3E0000F94EFB46057704A8E4F9F4F6093F31ABB
+:10D3F0007093F41A8093F51A9093F61A40910A1BD1
+:10D4000050910B1B60910C1B70910D1B452B462BF3
+:10D41000472B09F46BC080915E0B882341F010927A
+:10D420000A1B10920B1B10920C1B10920D1B80916B
+:10D43000A01B9091A11B20910A1B30910B1B820F06
+:10D44000931F9093A11B8093A01B813620EF92071E
+:10D450003CF481E690EF9093A11B8093A01B19C030
+:10D46000181619062CF41092A11B1092A01B11C0C3
+:10D470004FB7F8948091481A9091491A20910A1B4D
+:10D4800030910B1B820F931F9093491A8093481A77
+:10D490004FBF6091A01B7091A11B882777FD8095DD
+:10D4A000982F0F9468BE20914819309149194091E6
+:10D4B0004A1950914B190F94CDBD6093AA1B7093DC
+:10D4C000AB1B8093AC1B9093AD1B62E370E080E0DC
+:10D4D00090E00F941EB510920A1B10920B1B109235
+:10D4E0000C1B10920D1B81E08093D4028091D4021A
+:10D4F000882339F08AEA9BE10F948556BC01CE015E
+:10D50000C4DE8091101B82FD12C080917B1B8111B3
+:10D510000EC08091101B82FF11C001E021E040E0AD
+:10D5200050E0BA018DE591E00F94FD4107C060EA3B
+:10D530007BE188EF9FE00F949450EBCFDF91CF9188
+:10D540001F910F910895CF93DF9300D000D0CDB7F6
+:10D55000DEB70E946BFF20910C0B30910D0B4CE35A
+:10D56000429FC001439F900D11249A83898320918B
+:10D570000E0B30910F0B429FC001439F900D112461
+:10D580009C838B8340E060E081E19BE10E94823DCF
+:10D59000EEE6F2E485919491AADC40E06BE081E153
+:10D5A0009BE10E94823D66EC78E081E19BE10F9473
+:10D5B000AEB740E06CE081E19BE10E94823DCE018C
+:10D5C00001961BDCBC0181E19BE10F94AEB76DE1DC
+:10D5D00074E081E19BE10F94AEB741E060E081E14E
+:10D5E0009BE10E94823DECE6F2E4859194917FDC20
+:10D5F00041E06BE081E19BE10E94823D66EC78E0D6
+:10D6000081E19BE10F94AEB741E06CE081E19BE1E9
+:10D610000E94823DCE010396F0DBBC0181E19BE1DB
+:10D620000F94AEB76DE174E081E19BE10F94AEB76A
+:10D6300042E060E081E19BE10E94823D66E778E0A4
+:10D6400081E19BE10F94AEB780E493E10F94CB5757
+:10D65000BC0181E19BE10F94AEB76CEC78E081E115
+:10D660009BE10F94AEB742E06CE081E19BE10E9448
+:10D67000823D6FE778E081E19BE10F94AEB78EE3E6
+:10D6800093E10F94CB57BC0181E19BE10F94AEB7BE
+:10D6900043E060E081E19BE10E94823D63E878E045
+:10D6A00081E19BE10F94AEB743E065E081E19BE14E
+:10D6B0000E94823D80913D1390E09E838D83CE0138
+:10D6C00005960F94CB57BC0181E19BE10F94AEB757
+:10D6D00043E06AE081E19BE10E94823D65E978E0F8
+:10D6E00081E19BE10F94AEB743E06FE081E19BE104
+:10D6F0000E94823D80913C1390E09E838D83CE01F9
+:10D7000005960F94CB57BC0181E19BE10F94AEB716
+:10D710000F940453882321F00F94EE410F94574740
+:10D7200026960FB6F894DEBF0FBECDBFDF91CF9126
+:10D73000089540E060E081E19BE10E94823D85E048
+:10D7400099E5D5DB41E060E081E19BE10E94823D0B
+:10D750001E9B03C082E099E502C08FEF98E5C7DB0E
+:10D7600042E060E081E19BE10E94823D1D9B03C09D
+:10D770008CEF98E502C089EF98E5B9DB43E060E003
+:10D7800081E19BE10E94823D1C9B03C086EF98E5EE
+:10D7900002C083EF98E5ABCB0F93CBDF8091101BDA
+:10D7A00082FF09C001E021E040E050E0BA018FE7CC
+:10D7B00091E00F94FD410F9108950F9466500F94DE
+:10D7C000F32B81E00E94BD5CB4DF0F9404538823E7
+:10D7D000B1F30F9404538111FCCF6AE070E080E054
+:10D7E00090E00F941EB50F9404538111FCCF0F9459
+:10D7F00066500D945747EF92FF920F931F93CF936C
+:10D80000DF937C01EB018A010F94CB411092781ACF
+:10D810001092771A1092761A1092751A0F94F32BB1
+:10D8200080E00E94BD5C0F94665040E060E081E1C2
+:10D830009BE10E94823DE6E2F1E48591949157DB01
+:10D8400041E060E081E19BE10E94823D2091300B4C
+:10D8500030E0220F331F245F3E4BF90185919491F4
+:10D8600046DBF7013197E930F10508F0D9C0E757F9
+:10D87000FF4F42E060E081E19BE10D94DBC20E943A
+:10D88000823DE8E1F1E48591949131DB43E060E091
+:10D8900081E19BE10E94823DE091300BF0E0EE0FD0
+:10D8A000FF1FEE5EFE4B14C00E94823DEEE4F1E4E9
+:10D8B000859194911CDB43E060E081E19BE10E9453
+:10D8C000823DE091300BF0E0EE0FFF1FEA5FFE4B70
+:10D8D000859194910CDBA4C00E94823DEAE2F1E4C0
+:10D8E0008591949104DB43E060E081E19BE10E943B
+:10D8F000823DE091300BF0E0EE0FFF1FEA5FFE4B40
+:10D9000085919491F4DA43E061E181C00E94823D07
+:10D91000E6E1F1E485919491EADA42E062E181E1A5
+:10D920009BE10E94823DBE0181E19BE10F94AEB775
+:10D9300043E060E081E19BE10E94823DECE2F1E4A2
+:10D9400085919491D4DA43E062E181E19BE10E9408
+:10D95000823DB80161C00E94823DE8E2F1E42DC041
+:10D960000E94823DE091300BF0E0EE0FFF1FE25D80
+:10D97000FE4B09C00E94823DE091300BF0E0EE0FBB
+:10D98000FF1FEE5DFE4B85919491B1DA43E060E0BC
+:10D9900081E19BE10E94823DE091300BF0E0EE0FCF
+:10D9A000FF1FEA5FFE4B2EC00E94823DE091300BCC
+:10D9B000F0E0EE0FFF1FE85BFD4B8591949197DA45
+:10D9C00043E060E081E19BE10E94823DE6E1F1E419
+:10D9D00019C00E94823DE091300BF0E0EE0FFF1F76
+:10D9E000E05BFE4B8591949182DA43E060E081E157
+:10D9F0009BE10E94823DE091300BF0E0EE0FFF1FB3
+:10DA0000EC5AFE4B8591949172DA43E062E181E138
+:10DA10009BE10E94823DBE0181E19BE10F94AEB784
+:10DA200068EE73E080E090E00F941EB50F94CB4158
+:10DA300064E670E080E090E00F941EB50F94F32B45
+:10DA400080E00E94BD5C0F940453882389F3E09129
+:10DA5000300BF0E0EE0FFF1FE25EFE4B85919491DC
+:10DA60000F94A951DF91CF911F910F91FF90EF90EB
+:10DA70000D9457473F924F925F926F927F928F9291
+:10DA80009F92AF92BF92CF92DF92EF92FF920F934D
+:10DA90001F93CF93DF93CDB7DEB76C970FB6F89493
+:10DAA000DEBF0FBECDBF382E882341F081E038168F
+:10DAB00051F080E090E0A2E5B3E409C080E090E09E
+:10DAC000AFE7B3E404C080E090E0AAE5B3E48B875D
+:10DAD0009C87AD87BE871092B1020F94643B81E0B2
+:10DAE0000F948C15311041C020E030E048E851E43B
+:10DAF0006091E80A7091E90A8091EA0A9091EB0A34
+:10DB00000F94EDBC7B018C016093E80A7093E90AE5
+:10DB10008093EA0A9093EB0A2091E40A3091E50A97
+:10DB20004091E60A5091E70A6091E00A7091E10A9B
+:10DB30008091E20A9091E30AECECFAE0FF93EF9314
+:10DB4000812C912CA4E3AA2EA2E4BA2EBCEECB2EFB
+:10DB5000BAE0DB2E0F94580584E00F94E43A0F945A
+:10DB6000071F0F94643B0F900F90A1E0B0E0032CCF
+:10DB700002C0AA0FBB1F0A94E2F7B88BAF878F854C
+:10DB80000F94E43A20E030E040E752E46B857C8576
+:10DB90008D859E850F94EDBC6B8B7C8B8D8B9E8BC6
+:10DBA000E32DFF27E7FDF095FA8BE98BEE0FFF1FC2
+:10DBB000EE0FFF1FFA87E987E052F54F3F019B0107
+:10DBC000AC0160817181828193810F94ECBCD3019F
+:10DBD0006D937D938D939C931397E090E80AF0905A
+:10DBE000E90A0091EA0A1091EB0A2091E40A3091C7
+:10DBF000E50A4091E60A5091E70A6091E00A7091C7
+:10DC0000E10A8091E20A9091E30ABCEC4B2EBAE063
+:10DC10005B2E5F924F92812C912CE4E3AE2EE2E4D6
+:10DC2000BE2EFCEECF2EFAE0DF2E0F9458050F9497
+:10DC3000071F0F94643B832D0F944C38832D0F9452
+:10DC4000761F6F8B788F898F9A8F20E030E040EFBE
+:10DC500052E4F30160817181828193810F94EDBC64
+:10DC6000D3016D937D938D939C931397E090E80A75
+:10DC7000F090E90A0091EA0A1091EB0A2091E40A77
+:10DC80003091E50A4091E60A5091E70A6091E00A76
+:10DC90007091E10A8091E20A9091E30A5F924F92BB
+:10DCA0000F9458050F94071F2B853C854D855E8585
+:10DCB000F30160817181828193810F94EDBCD30166
+:10DCC0006D937D938D939C931397E090E80AF09069
+:10DCD000E90A0091EA0A1091EB0A2091E40A3091D6
+:10DCE000E50A4091E60A5091E70A6091E00A7091D6
+:10DCF000E10A8091E20A9091E30A5F924F920F94B9
+:10DD000058058F850F94E43A0F94071F0F94643BD6
+:10DD10000F945B38BC017F938F9329893A89285AE5
+:10DD20003F4F3F932F9322ED38E53F932F938B8FF7
+:10DD30007C8F0F946BC70FB6F894DEBF0FBECDBFBC
+:10DD40006B8D7C8D311003C08DE59FE002C08BE5AB
+:10DD50009FE00F9482CA832D0F94761F2B013C0104
+:10DD60002F89388D498D5A8D0F94ECBC6B017C0145
+:10DD700020E030E0A9010F94C9BF181624F0F7FA8B
+:10DD8000F094F7F8F094C982DA82EB82FC828985FC
+:10DD90009A858052954F9A87898720E030E040E746
+:10DDA00052E4DC016D917D918D919C910F94ECBCBE
+:10DDB000E985FA856083718382839383E090E80A22
+:10DDC000F090E90A0091EA0A1091EB0A2091E40A26
+:10DDD0003091E50A4091E60A5091E70A6091E00A25
+:10DDE0007091E10A8091E20A9091E30AACECBAE00A
+:10DDF000BF93AF93812C912CE4E3AE2EE2E4BE2ED0
+:10DE0000FCEECF2EFAE0DF2E0F9458050F94071F7B
+:10DE10008F850F94E43A2B893C894D895E89A985C9
+:10DE2000BA856D917D918D919C910F94ECBCE985A3
+:10DE3000FA856083718382839383E090E80AF0908F
+:10DE4000E90A0091EA0A1091EB0A2091E40A309164
+:10DE5000E50A4091E60A5091E70A6091E00A709164
+:10DE6000E10A8091E20A9091E30AACECBAE0BF9338
+:10DE7000AF930F9458050F94071F0F94643B832DA5
+:10DE80000F94761F9B01AC01C301B2010F94ECBC4F
+:10DE90006B017C010F900F900F900F9020E030E00D
+:10DEA000A9010F94C9BF181624F0F7FAF094F7F8F7
+:10DEB000F094CD82DE82EF82F8868E010F5F1F4FD5
+:10DEC0003E01F9E06F0E711C8CEB482E88E5582E50
+:10DED000F2018491ECEBF8E5882349F09091C000C1
+:10DEE00095FFFCCF8093C60031968491F5CFD80181
+:10DEF000CD90DD90ED90FD908D0122E030E0B701F6
+:10DF0000A6018EE799E00E9436432B853C854D851E
+:10DF10005E85C701B6010F94ECBC6B017C0120E06B
+:10DF200030E0A9010F94C9BF181624F0C701B6014B
+:10DF3000905802C0C701B60120E030E040EA50E44A
+:10DF40000F94C9BF1816B4F480E00F948C15B1E09B
+:10DF50003B1631F0E2E03E1631F069E379E005C0AE
+:10DF600064E179E002C066E279E040E050E089E0F7
+:10DF700090E05DC00615170509F0AACFE4EAF8E5C0
+:10DF80008491882341F09091C00095FFFCCF80934D
+:10DF9000C6003196F5CF2D813E814F81588569812C
+:10DFA0007A818B819C810F94ECBC2B013C0120E099
+:10DFB00030E0A9010F94C9BFB301A20118160CF0FB
+:10DFC000705822E030E08EE799E00E94364320E06E
+:10DFD00030E0A901C301B2010F94C9BF18165CF467
+:10DFE00020E030E040E85FE3C301B2010F94C9BF15
+:10DFF00018165CF022C020E030E040E85FEBC3017F
+:10E00000B2010F94C6BD87FF18C0F1E03F1631F092
+:10E0100082E0381631F069E379E005C064E179E027
+:10E0200002C066E279E040E050E088E090E0E3DBA7
+:10E03000832D0F94694180E004C0832D0F946941C2
+:10E0400081E06C960FB6F894DEBF0FBECDBFDF91B6
+:10E05000CF911F910F91FF90EF90DF90CF90BF90E5
+:10E06000AF909F908F907F906F905F904F903F9078
+:10E0700008958F929F92AF92BF92CF92DF92EF92CC
+:10E08000FF920F931F9320E030E042E053E4609151
+:10E090006F1A7091701A8091711A9091721A0F9480
+:10E0A000C9BF18160CF093C080910A1B90910B1BEE
+:10E0B000A0910C1BB0910D1B892B8A2B8B2B09F483
+:10E0C0006BC00E94AC51809164138F5F803109F462
+:10E0D00080E090916313981709F45EC060910A1B69
+:10E0E00070910B1B882777FD8095982F0F9468BE41
+:10E0F0002091F71A3091F81A4091F91A5091FA1AB2
+:10E100000F949BC09B01AC016091EC0A7091ED0AE9
+:10E110008091EE0A9091EF0A0F94EDBC6093EC0AA7
+:10E120007093ED0A8093EE0A9093EF0A10920A1B07
+:10E1300010920B1B10920C1B10920D1BE090E80A22
+:10E14000F090E90A0091EA0A1091EB0A2091E40AA2
+:10E150003091E50A4091E60A5091E70A6091E00AA1
+:10E160007091E10A8091E20A9091E30AECECFAE006
+:10E17000FF93EF93E5E58E2E982CE5EDAE2EEFE3C1
+:10E18000BE2EFCEECF2EFAE0DF2E0F94580581E074
+:10E190008093D4020F900F908091D402882349F08D
+:10E1A0008CEE9AE00F94AA54BC0189E498E50F9490
+:10E1B00088678091101B82FF40C001E021E040E0B1
+:10E1C00050E0BA018BE791E00F94FD4136C00F9407
+:10E1D000665040E060E081E19BE10E94823DE09179
+:10E1E000300BF0E0EE0FFF1FE252FD4B8591949152
+:10E1F0000F94776742E060E081E19BE10E94823DFD
+:10E20000E091300BF0E0EE0FFF1FEA54FE4B8591DA
+:10E2100094910F94776760ED77E080E090E00F9441
+:10E220001EB51F910F91FF90EF90DF90CF90BF90A0
+:10E23000AF909F908F900D9457471F910F91FF9033
+:10E24000EF90DF90CF90BF90AF909F908F90089508
+:10E2500020E030E042E053E460916F1A7091701A50
+:10E260008091711A9091721A0F94C9BF181634F4E4
+:10E2700061E087E294E50E9411C32CC00F946650C0
+:10E2800040E060E081E19BE10E94823DE091300B43
+:10E29000F0E0EE0FFF1FE252FD4B859194910F9439
+:10E2A000776742E060E081E19BE10E94823DE0917E
+:10E2B000300BF0E0EE0FFF1FEA54FE4B8591949176
+:10E2C0000F94776760ED77E080E090E00F941EB5E3
+:10E2D0000F9466500D9457470F94665041E060E0EC
+:10E2E00081E19BE10E94823DE091300BF0E0EE0F76
+:10E2F000FF1FE859FD4B859194910F94776742E099
+:10E3000060E081E19BE10E94823DE091300BF0E012
+:10E31000EE0FFF1FEE54FE4B859194910D9477679D
+:10E320000F94665042E060E081E19BE10E94823DF3
+:10E33000E091300BF0E0EE0FFF1FEC5EFC4B85919F
+:10E3400094910D9477671F93CF93DF930F9466504A
+:10E3500040E060E081E19BE10E94823DE091300B72
+:10E36000F0E0EE0FFF1FEC5AFD4B859194910F9456
+:10E37000776742E060E081E19BE10E94823DE091AD
+:10E38000300BF0E0EE0FFF1FE054FE4B85919491AF
+:10E390000F94776710E043E0612F81E19BE10E94D9
+:10E3A000823D6DEC75E081E19BE10F94AEB7CAE070
+:10E3B000D0E00F94F32B81E00E94BD5C65E570E036
+:10E3C00080E090E00F941EB5219799F71F5F1431FC
+:10E3D00011F7DF91CF911F9108951F93CF93DF9392
+:10E3E0000F94665040E060E081E19BE10E94823D35
+:10E3F000E091300BF0E0EE0FFF1FE05BFD4B8591ED
+:10E4000094910F94776742E060E081E19BE10E9484
+:10E41000823DE091300BF0E0EE0FFF1FE054FE4B29
+:10E42000859194910F94776710E043E0612F81E12B
+:10E430009BE10E94823D6DEC75E081E19BE10F94D0
+:10E44000AEB7CAE0D0E00F94F32B81E00E94BD5C30
+:10E4500069E870E080E090E00F941EB5219799F78D
+:10E460001F5F143111F7DF91CF911F9108950F9322
+:10E470001F93CF93DF930F94665040E060E081E1FB
+:10E480009BE10E94823DE091300BF0E0EE0FFF1F18
+:10E49000EE5FFC4B859194910F94776741E061E0CA
+:10E4A00081E19BE10E94823DE091300BF0E0EE0FB4
+:10E4B000FF1FE25DFF4B859194910F94776742E0D7
+:10E4C00061E081E19BE10E94823DE091300BF0E050
+:10E4D000EE0FFF1FE850FE4B859194910F947767E4
+:10E4E00043E061E081E19BE10E94823DE091300BDD
+:10E4F000F0E0EE0FFF1FE450FE4B859194910F94D6
+:10E50000776741E060E081E19BE10E94823D6EE43B
+:10E5100077E081E19BE10F94AEB70091B81B112722
+:10E5200007FD1095C1E0D0E08091550B9091560BFE
+:10E53000892B09F072C00F94F32B81E00E94BD5C1F
+:10E540002091B81B332727FD3095C801821B930B00
+:10E5500097FF03C091958195910905970CF44DC0E3
+:10E56000201731070CF42197021713070CF421969A
+:10E57000C430D1052CF4209729F4C1E0D0E002C0CA
+:10E58000C3E0D0E041E060E081E19BE10E94823D98
+:10E590006EEC78E081E19BE10F94AEB742E060E081
+:10E5A00081E19BE10E94823D6EEC78E081E19BE19C
+:10E5B0000F94AEB743E060E081E19BE10E94823DB1
+:10E5C0006EEC78E081E19BE10F94AEB74C2F60E0F8
+:10E5D00081E19BE10E94823D6EE477E081E19BE175
+:10E5E0000F94AEB70091B81B112707FD109564E694
+:10E5F00070E080E090E00F941EB50F9404538823E0
+:10E6000009F492CFD093560BC093550B64EF71E091
+:10E6100080E090E00F941EB587CF0F946650DF9195
+:10E62000CF911F910F910D94574720E030E042E0C9
+:10E6300053E460916F1A7091701A8091711A9091E1
+:10E64000721A0F94C9BF1816F4F481E08093240B5A
+:10E650008093230B61E082E294E50E9411C3EFE90D
+:10E66000F8E08191882339F09091C00095FFFCCFAC
+:10E670008093C600F6CF8091C00085FFFCCF8AE072
+:10E680008093C6002CC00F94665040E060E081E1AA
+:10E690009BE10E94823DE091300BF0E0EE0FFF1F06
+:10E6A000E252FD4B859194910F94776742E060E0D0
+:10E6B00081E19BE10E94823DE091300BF0E0EE0FA2
+:10E6C000FF1FEA54FE4B859194910F94776760ED9C
+:10E6D00077E080E090E00F941EB50F9466500D94A3
+:10E6E00057478F929F92AF92BF92DF92EF92FF9225
+:10E6F0000F931F93CF93DF931092991B80910A1B66
+:10E7000090910B1BA0910C1BB0910D1B8130904878
+:10E71000A105B10540F010920A1B10920B1B10923C
+:10E720000C1B10920D1B80910A1B90910B1BA0914A
+:10E730000C1BB0910D1BB695A795979587954091A9
+:10E740000F1B50E060E070E084179507A607B7073D
+:10E7500010F480930F1BD0910F1B1091101B12FB14
+:10E76000112710F9C0E0DD24D394D1113FC080916E
+:10E77000D4028823E1F0E091300BF0E0EE0FFF1FB0
+:10E78000EA57FF4B6591749180910A1B90910B1B86
+:10E79000A0910C1BB0910D1B23E00297A105B105C0
+:10E7A00010F443E001C040E28C2F0F945E4011232F
+:10E7B000E9F080910A1B90910B1BA0910C1BB0916A
+:10E7C0000D1B0297A105B10588F40F94EE418DED64
+:10E7D00091E0DF91CF911F910F91FF90EF90DF902B
+:10E7E000BF90AF909F908F900D94A94280916C0B39
+:10E7F00081110BC080915F0B811107C08091961B26
+:10E800009091971B089709F057C020E030E040E056
+:10E8100050E46091E80A7091E90A8091EA0A9091C7
+:10E82000EB0A0F94C6BD87FF47C080915E0B811134
+:10E8300043C08091320B81113FC0D13011F002E012
+:10E840003CC08091D402882301F1E091300BF0E0CC
+:10E85000EE0FFF1FE857FC4B6591749180910A1BE6
+:10E8600090910B1BA0910C1BB0910D1BB695A79519
+:10E87000979587952EE70197A105B10511F44EE311
+:10E8800001C040E28C2F0F945E401123C1F28091B1
+:10E890000A1B90910B1BA0910C1BB0910D1BB69500
+:10E8A000A795979587950197A105B10541F60F9416
+:10E8B000EE4185EF91E03CC001E02091641380912E
+:10E8C0006313281B2F7080910A1B90910B1BA09142
+:10E8D0000C1BB0910D1B211108C020916C0B211154
+:10E8E00004C020915F0B222381F10D136DC0209194
+:10E8F000D402211173C4112309F466C080910A1B4C
+:10E9000090910B1BA0910C1BB0910D1BB695A79578
+:10E9100097958795402F50E060E070E08417950749
+:10E92000A607B70709F050C00F94EE418FE391E0BE
+:10E93000DF91CF911F910F91FF90EF90DF90BF90EB
+:10E94000AF909F908F900D9427440D133DC0209160
+:10E95000D4022223E9F0E091300BF0E0EE0FFF1F2C
+:10E96000E654FE4B65917491B695A795979587955A
+:10E97000802E912CA12CB12C2EE788159905AA0583
+:10E98000BB0511F44EE301C040E28C2F0F945E40B2
+:10E990001123D1F080910A1B90910B1BA0910C1BAD
+:10E9A000B0910D1BB695A79597958795402F50E090
+:10E9B00060E070E084179507A607B70729F40F9465
+:10E9C000EE4187E891E0B4CF0F5F80916D0B4091ED
+:10E9D0000A1B50910B1B60910C1B70910D1B88231F
+:10E9E00009F407C18091560D882309F4F0C0809185
+:10E9F000320B81113FC180915E0B81113BC180912F
+:10EA00006C0B882309F44CC00D1394C08091D40280
+:10EA10008823F1F0E091300BF0E0EE0FFF1FEE5194
+:10EA2000FE4B859194917695679557954795802EE5
+:10EA3000912CA12CB12C20E2481559056A057B05C3
+:10EA400011F44EE301C040E2BC018C2F0F945E40F4
+:10EA5000112309F46FC080910A1B90910B1BA091A8
+:10EA60000C1BB0910D1BB695A79597958795402FD8
+:10EA700050E060E070E084179507A607B70709F03B
+:10EA800059C00F94EE41DF91CF911F910F91FF90EC
+:10EA9000EF90DF90BF90AF909F908F900D94634761
+:10EAA0000D1348C08091D4028823F1F0E091300B1F
+:10EAB000F0E0EE0FFF1FEA57FE4B8591949176959B
+:10EAC000679557954795802E912CA12CB12C20E26B
+:10EAD000481559056A057B0511F44EE301C040E273
+:10EAE000BC018C2F0F945E40112321F180910A1BF1
+:10EAF00090910B1BA0910C1BB0910D1BB695A79587
+:10EB000097958795402F50E060E070E08417950757
+:10EB1000A607B70779F40F94EE41DF91CF911F91CB
+:10EB20000F91FF90EF90DF90BF90AF909F908F90EC
+:10EB30000D949347FF24F394F00EFD1245C080918D
+:10EB4000D402882329F1E091300BF0E0EE0FFF1F93
+:10EB5000EE53FF4B6591749180910A1B90910B1BB2
+:10EB6000A0910C1BB0910D1BB695A7959795879515
+:10EB70008F2C912CA12CB12C2EE788159905AA0574
+:10EB8000BB0511F44EE301C040E28C2F0F945E40B0
+:10EB90001123D1F080910A1B90910B1BA0910C1BAB
+:10EBA000B0910D1BB695A795979587954F2D50E081
+:10EBB00060E070E084179507A607B70729F40F9463
+:10EBC000EE4189E491E0B4CE01E00F0D53C0809195
+:10EBD0005F0B81114FC00D134CC08091D40288236C
+:10EBE00051F1E091300BF0E0EE0FFF1FE85EFC4BBF
+:10EBF0000DC00D133EC08091D4028823E1F0E09156
+:10EC0000300BF0E0EE0FFF1FE051FE4B8591949129
+:10EC10007695679557954795802E912CA12CB12C10
+:10EC20002EE7481559056A057B0509F140E2BC014C
+:10EC30008C2F0F945E401123E1F080910A1B90917C
+:10EC40000B1BA0910C1BB0910D1BB695A79597952A
+:10EC50008795402F50E060E070E084179507A60785
+:10EC6000B70739F40F94EE4181EA91E061CE4EE3AB
+:10EC7000DECF0F5F20916C0B80910A1B90910B1BD4
+:10EC8000A0910C1BB0910D1B211105C020915F0BB1
+:10EC9000222309F43FC02091921B222309F470C162
+:10ECA0000D1336C02091D4022223B1F0B695A7955A
+:10ECB00097958795402F50E060E070E02EE784172D
+:10ECC0009507A607B70711F44EE301C040E267E2DB
+:10ECD0007AE58C2F0F945E401123D1F080910A1BAE
+:10ECE00090910B1BA0910C1BB0910D1BB695A79595
+:10ECF00097958795402F50E060E070E08417950766
+:10ED0000A607B70729F40F94EE4183E092E010CEF6
+:10ED10000F5F36C10D1346C02091D4022223E9F0C3
+:10ED2000E091300BF0E0EE0FFF1FE45BFD4B6591CF
+:10ED30007491B695A79597958795802E912CA12CC7
+:10ED4000B12C20E288159905AA05BB0511F44EE304
+:10ED500001C040E28C2F0F945E40112319F1809185
+:10ED60000A1B90910B1BA0910C1BB0910D1BB6952B
+:10ED7000A79597958795402F50E060E070E0841745
+:10ED80009507A607B70771F40F94EE41DF91CF9175
+:10ED90001F910F91FF90EF90DF90BF90AF909F90E9
+:10EDA0008F9043CCEE24E394E00EED124EC08091A0
+:10EDB000D402882329F1E091300BF0E0EE0FFF1F21
+:10EDC000E856FF4B6591749180910A1B90910B1B43
+:10EDD000A0910C1BB0910D1BB695A79597958795A3
+:10EDE0008E2C912CA12CB12C20E288159905AA0516
+:10EDF000BB0511F44EE301C040E28C2F0F945E403E
+:10EE0000112319F180910A1B90910B1BA0910C1BEF
+:10EE1000B0910D1BB695A795979587954E2D50E00F
+:10EE200060E070E084179507A607B70771F40F94A8
+:10EE3000EE41DF91CF911F910F91FF90EF90DF9006
+:10EE4000BF90AF909F908F9003CAF2E0EF2EE00E3C
+:10EE5000ED1245C08091D402882329F1E091300B56
+:10EE6000F0E0EE0FFF1FEE5FFE4B65917491809115
+:10EE70000A1B90910B1BA0910C1BB0910D1BB6951A
+:10EE8000A795979587958E2C912CA12CB12C2EE7C8
+:10EE900088159905AA05BB0511F44EE301C040E2AF
+:10EEA0008C2F0F945E401123D1F080910A1B90911A
+:10EEB0000B1BA0910C1BB0910D1BB695A7959795B8
+:10EEC00087954E2D50E060E070E084179507A60707
+:10EED000B70729F40F94EE4181E491E029CD33E0A6
+:10EEE000E32EE00E8091931B811149C0ED1245C0C5
+:10EEF0008091D402882329F1E091300BF0E0EE0FED
+:10EF0000FF1FE05EFD4B6591749180910A1B90910B
+:10EF10000B1BA0910C1BB0910D1BB695A795979557
+:10EF200087958E2C912CA12CB12C2EE78815990554
+:10EF3000AA05BB0511F44EE301C040E28C2F0F94EB
+:10EF40005E401123D1F080910A1B90910B1BA09180
+:10EF50000C1BB0910D1BB695A795979587954E2DD7
+:10EF600050E060E070E084179507A607B70729F422
+:10EF70000F94EE418FE791E0DBCC0C5F01C00E2DCA
+:10EF800080915F0B811148C00D1345C08091D40260
+:10EF9000882329F1E091300BF0E0EE0FFF1FE252E1
+:10EFA000FF4B6591749180910A1B90910B1BA0916E
+:10EFB0000C1BB0910D1BB695A79597958795802E44
+:10EFC000912CA12CB12C2EE788159905AA05BB051B
+:10EFD00011F44EE301C040E28C2F0F945E401123E8
+:10EFE000D1F080910A1B90910B1BA0910C1BB0914A
+:10EFF0000D1BB695A79597958795402F50E060E03B
+:10F0000070E084179507A607B70729F40F94EE411F
+:10F010008FEE91E08DCC0F5F0D1345C08091D4022F
+:10F02000882329F1E091300BF0E0EE0FFF1FE2544E
+:10F03000FF4B6591749180910A1B90910B1BA091DD
+:10F040000C1BB0910D1BB695A79597958795802EB3
+:10F05000912CA12CB12C2EE788159905AA05BB058A
+:10F0600011F44EE301C040E28C2F0F945E40112357
+:10F07000D1F080910A1B90910B1BA0910C1BB091B9
+:10F080000D1BB695A79597958795402F50E060E0AA
+:10F0900070E084179507A607B70729F40F94EE418F
+:10F0A0008FEA91E045CCEE24E394E00EED123EC0F1
+:10F0B0008091D4028823F1F080910A1B90910B1B60
+:10F0C000A0910C1BB0910D1BB695A79597958795B0
+:10F0D0008D2E912CA12CB12C2EE788159905AA050F
+:10F0E000BB0511F44EE301C040E26CE17AE58C2FE0
+:10F0F0000F945E401123D1F080910A1B90910B1B5D
+:10F10000A0910C1BB0910D1BB695A795979587956F
+:10F110004E2D50E060E070E084179507A607B70712
+:10F1200029F40F94EE4181E891E002CC42E0F42E04
+:10F13000F00E40910A1B50910B1B60910C1B7091BB
+:10F140000D1B76956795579547958F2D90E0A0E01C
+:10F15000B0E0481759076A077B0788F08F2D90E0C9
+:10F16000880F991F0197AA2797FDA095BA2F809322
+:10F170000A1B90930B1BA0930C1BB0930D1B40918B
+:10F180000A1B50910B1B60910C1B70910D1B769507
+:10F1900067955795479580910F1B90E00396242F14
+:10F1A00030E0821793074CF48DEF840F80930F1B90
+:10F1B000D092D402DCEFD40FCFEFCF5FDF5FC4304B
+:10F1C00008F4D3CADF91CF911F910F91FF90EF9078
+:10F1D000DF90BF90AF909F908F900895E091300B9B
+:10F1E000F0E0EE0FFF1FEE55FF4B65917491B69561
+:10F1F000A79597958795802E912CA12CB12C2EE761
+:10F2000088159905AA05BB0511F44EE301C040E23B
+:10F210008C2F0F945E406FCB4F925F926F927F92D4
+:10F220008F929F92AF92BF92CF92DF92EF92FF9216
+:10F230000F931F93CF93DF93CDB7DEB72C970FB605
+:10F24000F894DEBF0FBECDBF80916C0B882309F40C
+:10F25000ECC0C090290BD0902A0BE0902B0BF090C3
+:10F260002C0BC701B60120EA36E841E050E00F94CC
+:10F270009DC229873A874B875C873E832D830F94F5
+:10F28000EFB400918A0A10918B0A20918C0A309178
+:10F290008D0A601B710B820B930B28EE33E040E06C
+:10F2A00050E00F949DC229013A01C90160E17EE05E
+:10F2B0000F948AC24B0180EF91EF689F9001699F84
+:10F2C000300D789F300D1124C901840D951D6CE31C
+:10F2D00070E00F948AC28B0144EC46035001479FB3
+:10F2E000B00C1124A20EB31EA40CB51C40E060E0CB
+:10F2F00081E19BE10E94823DE091300BF0E0EE0F56
+:10F30000FF1FE652FF4B859194910F94776741E080
+:10F3100066E081E19BE10E94823DCE0105960F945B
+:10F32000CB57BC0181E19BE10F94AEB760EB78E075
+:10F3300081E19BE10F94AEB7A985BA8520E639E754
+:10F340004EEF5FEF0F9400C36C0D7D1D8E1D9F1D52
+:10F350002AE030E040E050E00F949DC2B9018827D8
+:10F3600077FD8095982F0F9468BE69837A838B838D
+:10F370009C83CE0101960F947A55BC0181E19BE1FB
+:10F380000F94AEB763EB78E081E19BE10F94AEB7E9
+:10F3900042E060E081E19BE10E94823DE091300B20
+:10F3A000F0E0EE0FFF1FEA52FF4B859194910F940E
+:10F3B000776743E068E081E19BE10E94823D8982BA
+:10F3C000CE0101960F949254BC0181E19BE10F9410
+:10F3D000AEB763EE76E081E19BE10F94AEB70983AF
+:10F3E000CE0101960F949254BC0181E19BE10F94F0
+:10F3F000AEB760EB78E081E19BE10F94AEB7A982F4
+:10F40000CE0101960F949254BC0181E19BE10F94CF
+:10F41000AEB762E677E081E19BE10F94AEB70F945F
+:10F420000453882309F474C16FC181EF9FE00F94E6
+:10F430004CCA6B017C018DEE9FE00F944CCA4B01CE
+:10F440005C01C701B6010F9466BE69837A838B8322
+:10F450009C8320EAC21626E8D20621E0E206F104E7
+:10F4600050F0C701B60120EA36E841E050E00F94C1
+:10F470009DC2D90102C0A0E0B0E0B887AF831A16E0
+:10F480001B0684F420E639E74EEF5FEF0F9400C3CC
+:10F490006C0D7D1D8E1D9F1D0F9466BE69837A8342
+:10F4A0008B839C83C501B40120EA35E040E050E045
+:10F4B0000F949DC2122F032FA0EAB5E00F94F6C25D
+:10F4C000A5019401261B370B480B590BCA01B90142
+:10F4D0002CE330E040E050E00F949DC2F22E30E685
+:10F4E000139F800C11244CE3F49E801811240F9478
+:10F4F000665040E060E081E19BE10E94823DE09146
+:10F50000300BF0E0EE0FFF1FEE52FF4B8591949110
+:10F510000F947767CE0101960F947A55FC01019004
+:10F520000020E9F7682F6E1B6E5E41E081E19BE1F0
+:10F530000E94823DCE0101960F947A55BC0181E173
+:10F540009BE10F94AEB78F819885181619067CF54C
+:10F55000CE0101960F947A55FC0101900020E9F745
+:10F56000682F6E1B615F41E081E19BE10E94823D5B
+:10F5700066EB78E081E19BE10F94AEB7CE01019696
+:10F580000F947A55FC0101900020E9F7682F6E1B5B
+:10F59000665F41E081E19BE10E94823DCE010796DA
+:10F5A0000F94FD66BC0181E19BE10F94AEB741E091
+:10F5B00062E181E19BE10E94823D64EB78E081E1C0
+:10F5C0009BE10F94AEB742E060E081E19BE10E94D5
+:10F5D000823DE091300BF0E0EE0FFF1FE253FF4B56
+:10F5E000859194910F94776743E062E181E19BE11B
+:10F5F0000E94823D64EB78E081E19BE10F94AEB71D
+:10F6000043E06EE081E19BE10E94823D912C9E826D
+:10F610008D82CE0105960F94CB57BC0181E19BE111
+:10F620000F94AEB743E06EE081E19BE10E94823D22
+:10F630006BE174E081E19BE10F94AEB743E06CE0D5
+:10F6400081E19BE10E94823D69EB78E081E19BE1F1
+:10F650000F94AEB743E069E081E19BE10E94823DF7
+:10F660008F2D90E09E838D83CE0105960F94CB570E
+:10F67000BC0181E19BE10F94AEB743E069E081E119
+:10F680009BE10E94823D6BE174E081E19BE10F947C
+:10F69000AEB743E067E081E19BE10E94823D65E80F
+:10F6A00073E081E19BE10F94AEB743E064E081E158
+:10F6B0009BE10E94823D812F902F9E838D83CE01FE
+:10F6C00005960F94CB57BC0181E19BE10F94AEB737
+:10F6D00084E090E090931602809315020F940453F7
+:10F6E00081110CC00F94F32B81E00E94BD5C64E695
+:10F6F00070E080E090E00F941EB5F0CF81E090E0E4
+:10F7000090931602809315020F94EE410F94574781
+:10F710002C960FB6F894DEBF0FBECDBFDF91CF9110
+:10F720001F910F91FF90EF90DF90CF90BF90AF901F
+:10F730009F908F907F906F905F904F9008950F9360
+:10F740001F93CF93DF93EC018430910524F08C015B
+:10F750000350110902C000E010E040E060E081E1E8
+:10F760009BE10E94823D6BEB78E081E19BE10F948D
+:10F77000AEB740E061E081E19BE10E94823D000F75
+:10F78000111FF801E05AFD4B859194910F94776712
+:10F7900041E060E081E19BE10E94823D6BEB78E01B
+:10F7A00081E19BE10F94AEB741E061E081E19BE133
+:10F7B0000E94823DF801EE59FD4B859194910F9482
+:10F7C000776742E060E081E19BE10E94823D6BEB64
+:10F7D00078E081E19BE10F94AEB743E060E081E126
+:10F7E0009BE10E94823D6BEB78E081E19BE10F940D
+:10F7F000AEB7C130D10511F440E008C0C230D10528
+:10F8000011F441E003C0239734F042E060E081E16D
+:10F810009BE10E94823D6EE477E081E19BE1DF9114
+:10F82000CF911F910F910D94AEB70F931F93CF936C
+:10F83000DF938FEF8093300B0F94DE4F0F94665061
+:10F8400081E090E07CDF0091B81B112707FD109547
+:10F85000C1E0D0E08091300B8F3F09F048C00F9499
+:10F86000F32B81E00E94BD5C2091B81B332727FD5C
+:10F870003095C801821B930B97FF03C0919581952A
+:10F8800091090597F4F0201731070CF4219702171E
+:10F8900013070CF42196C330D1052CF4209729F4DA
+:10F8A000C1E0D0E002C0C2E0D0E0CE0148DF00916C
+:10F8B000B81B112707FD109564E670E080E090E02A
+:10F8C00004C064E170E080E090E00F941EB50F94F6
+:10F8D0000453882309F4BECF8C2F81500F944D41DF
+:10F8E00064EF71E080E090E00F941EB5B3CF80919B
+:10F8F000FF099091000A2091010A3091020A821BAF
+:10F90000930B8F779927029724F01092300B109267
+:10F91000D7020F9442500F946650DF91CF911F9100
+:10F920000F910D945747EF92FF920F931F93CF9330
+:10F93000DF930F94665040E060E081E19BE10E941C
+:10F94000823D60ED78E081E19BE10F94AEB700E08D
+:10F9500010E0C1E0D0E02091B81B422F552741951F
+:10F960000CF45095CA0157FF03C0919581959109F8
+:10F97000039784F027FF02C0219702C0211121962E
+:10F98000C330D1052CF4209729F4C1E0D0E002C0A7
+:10F99000C2E0D0E042E060E081E19BE10E94823D74
+:10F9A00065EC78E081E19BE10F94AEB743E060E065
+:10F9B00081E19BE10E94823D65EC78E081E19BE181
+:10F9C0000F94AEB742E062E081E19BE10E94823D8C
+:10F9D000E091300BF0E0EE0FFF1FE25DFF4B8591F1
+:10F9E00094910F94776743E062E081E19BE10E948C
+:10F9F000823DE091300BF0E0EE0FFF1FE050FE4B38
+:10FA0000859194910F9477674C2F4F5F60E081E16F
+:10FA10009BE10E94823D6EE477E081E19BE10F94DF
+:10FA2000AEB764E670E080E090E00F941EB50F5F23
+:10FA30001F4F0536110534F083E690E00F94FF6008
+:10FA400000E010E00F940453882379F084E190E003
+:10FA5000C130D105D9F40F94FF6084E090E00F9499
+:10FA6000FF60EE24E394F12C02C0E12CF12C0F9402
+:10FA7000F32B80E00E94BD5CEF2809F46CCFDF918E
+:10FA8000CF911F910F91FF90EF9008950F94FF6019
+:10FA900085E090E00F94FF6092E0E92EF12CE7CF33
+:10FAA0000F931F93CF93DF931F92CDB7DEB7142F21
+:10FAB000462F682F81E19BE159830E94823DE12F0F
+:10FAC0005981F52F64918F010F5F1F4F662331F02D
+:10FAD00081E19BE10E944440F801F4CF0F90DF9157
+:10FAE000CF911F910F9108956F927F928F929F9265
+:10FAF000AF92BF92CF92DF92EF92FF920F931F933C
+:10FB0000CF93DF931F92CDB7DEB73C016B017A0133
+:10FB1000580129830F94EFB4605C7D4B8F4F9F4F4A
+:10FB20006093FF1A7093001B8093011B9093021B3C
+:10FB30002981EC14FD042CF450EF852E58E0952E0D
+:10FB400004C04BED842E48E0942E21110F94665092
+:10FB500040E060E081E19BE10E94823D8FEF68160A
+:10FB6000780619F06114710461F4E091300BF0E053
+:10FB7000EE0FFF1FE65EFE4B859194910F94776721
+:10FB800030C0E1E06E16710461F4E091300BF0E0FA
+:10FB9000EE0FFF1FE65EFE4B859194910F94776701
+:10FBA00030C0F2E06F16710461F4E091300BF0E0C8
+:10FBB000EE0FFF1FEE5BFE4B859194910F947767DC
+:10FBC00038C083E06816710461F4E091300BF0E016
+:10FBD000EE0FFF1FE25CFE4B859194910F947767C7
+:10FBE00034C0E4E06E16710461F4E091300BF0E093
+:10FBF000EE0FFF1FE65CFE4B859194910F947767A3
+:10FC000030C0F5E06F16710441F4E091300BF0E084
+:10FC1000EE0FFF1FEA5CFE4B2FC086E068167104F2
+:10FC200041F4E091300BF0E0EE0FFF1FEE5CFE4B75
+:10FC300023C0E7E06E16710441F4E091300BF0E070
+:10FC4000EE0FFF1FEA5BFE4B17C0F8E06F16710462
+:10FC500041F4E091300BF0E0EE0FFF1FE65BFE4B4E
+:10FC60000BC089E06816710459F4E091300BF0E0A4
+:10FC7000EE0FFF1FE25EFE4B859194910F94776724
+:10FC800041E060E081E19BE10E94823D6DED78E022
+:10FC900081E19BE10F94AEB7C3010196039770F524
+:10FCA00046E958E562E080E0FBDE42E06EE081E19B
+:10FCB0009BE10E94823DEFEF6E167E0611F4B401C7
+:10FCC00002C06AE277E081E19BE10F94AEB74BE8B6
+:10FCD00058E563E080E0E4DE43E06EE081E19BE133
+:10FCE0000E94823D6A94672811F0B40102C06AE262
+:10FCF00077E081E19BE10F94AEB782C089E068169E
+:10FD0000710409F47DC0E3E06E16710439F0F3E08C
+:10FD10006F16710434F440E050E005C041E050E05B
+:10FD200002C042E050E0840122EF38E069E070E078
+:10FD300083E090E00F94D74084E06816710439F0B6
+:10FD4000E4E06E16710434F440E050E005C041E098
+:10FD500050E002C042E050E0840129E339E062E073
+:10FD600070E082E090E00F94D740F5E06F167104E8
+:10FD700039F085E06816710434F440E050E005C0C5
+:10FD800041E050E002C042E050E0840124E139E06B
+:10FD900068E070E082E090E00F94D740E6E06E16F5
+:10FDA000710439F0F6E06F16710434F440E050E06D
+:10FDB00005C041E050E002C042E050E0840126E28C
+:10FDC00039E06EE070E082E090E00F94D74087E089
+:10FDD0006816710439F0E7E06E16710434F440E0FF
+:10FDE00050E005C041E050E002C042E050E0840134
+:10FDF00029EF38E060E070E083E090E00F94D740B6
+:10FE00001A141B043CF4B501882777FD8095982FC0
+:10FE10000F941EB5FFEFCF1ADF0AEE0CFF1CEC1497
+:10FE2000FD041CF480E090E001C0C6010F90DF915A
+:10FE3000CF911F910F91FF90EF90DF90CF90BF90E7
+:10FE4000AF909F908F907F906F9008952F923F92E8
+:10FE50004F925F926F927F928F929F92AF92BF92DA
+:10FE6000CF92DF92EF92FF920F931F93CF93DF9386
+:10FE7000CDB7DEB728970FB6F894DEBF0FBECDBF63
+:10FE80000F94665040E060E081E19BE10E94823D7A
+:10FE9000EAE0F1E4859194910F94776760ED77E063
+:10FEA00080E090E00F941EB500ED17E021E043E004
+:10FEB00050E060E070E08FEF9FEF16DE98878F8351
+:10FEC0001092CB0A1092CA0A0F94F32B61E088E0DB
+:10FED00090E00F948A2660ED77E080E090E00F9448
+:10FEE0001EB50F94F32B80910C0B90910D0B892B69
+:10FEF00031F460E070E0AB0186E090E02BC000EDF3
+:10FF000017E021E043E050E06F81788580E090E0E9
+:10FF1000EBDD98878F838FEF90E09093CB0A8093EF
+:10FF2000CA0A80ED97E00E94DE5E1092CB0A109222
+:10FF3000CA0A0F94F32B81E00E94BD5C80910E0BE6
+:10FF400090910F0B892B09F053C060E070E0AB017A
+:10FF500087E090E00F94FB6B08E813E121E043E0B9
+:10FF600050E06F81788589E090E0BEDD312C109201
+:10FF70007A1B61E082EE98E50E9411C30F946650EF
+:10FF80000F94EFB46C597F4F8F4F9F4F6093FF1AC0
+:10FF90007093001B8093011B9093021B332019F078
+:10FFA000E0E1F1E407C0E091300BF0E0EE0FFF1F5D
+:10FFB000E25EFE4B859194910F94A951832D289672
+:10FFC0000FB6F894DEBF0FBECDBFDF91CF911F916A
+:10FFD0000F91FF90EF90DF90CF90BF90AF909F90E8
+:10FFE0008F907F906F905F904F903F902F900895EB
+:10FFF00021E043E050E06F81788581E090E074DD9E
+:020000023000CC
+:1000000008EE13E021E043E050E0BC0183E090E023
+:100010006BDD98878F8360916F1A7091701A809151
+:10002000711A9091721A0F9435BE2B013C016091A8
+:100030005D1A70915E1A80915F1A9091601A0F9408
+:1000400035BE4B015C0188EC90E09093781A809368
+:10005000771A1092761A1092751A0F94F32B81E08A
+:100060000E94BD5C6CE3E62EF12C212C312C0F9408
+:10007000F32B81E00E94BD5C00E911E020E042E04A
+:1000800050E0B10183E090E02FDD1C0121E0E21A95
+:10009000F10869F71092781A1092771A1092761A6E
+:1000A0001092751A0F94F32BC0906F1AD090701A9B
+:1000B000E090711AF090721AB401882777FD80954C
+:1000C000982F0F9468BE9B01AC0160915D1A7091EE
+:1000D0005E1A80915F1A9091601A0F94ECBC0F9495
+:1000E00035BE63307105C4F4B201882777FD809571
+:1000F000982F0F9468BE9B01AC01C701B6010F9405
+:10010000ECBC0F9435BE6A3071057CF44EEF58E0BC
+:10011000BA0181E090E005C04EEF58E0BA0182E0FC
+:1001200090E00F94FB6B10E001C011E00F94F32BF3
+:1001300081E00E94BD5C112309F40ECF00ED17E0B1
+:1001400021E043E050E06F81788584E090E0CCDCF2
+:1001500098878F8380E00F943A6D882309F4FCCE52
+:1001600000E010E021E043E050E06F81788584E01A
+:1001700090E0BADC0CED15E021E043E050E0BC017A
+:1001800085E090E0B1DC98878F8381E00F943A6D31
+:10019000882309F4E1CE00E010E021E043E050E0E4
+:1001A0006F81788585E090E09FDC1C010F94643BB3
+:1001B00080E00F948C1520E030E040E651E460913F
+:1001C000E00A7091E10A8091E20A9091E30A0F94AB
+:1001D000EDBC2B013C016093E00A7093E10A80932F
+:1001E000E20A9093E30A20E030E040E451E46091B9
+:1001F000E40A7091E50A8091E60A9091E70A0F946B
+:10020000EDBC69837A838B839C836093E40A70934B
+:10021000E50A8093E60A9093E70A20E030E040E2A6
+:1002200051E46091E80A7091E90A8091EA0A90919C
+:10023000EB0A0F94EDBC6093E80A7093E90A80938F
+:10024000EA0A9093EB0A2CEC3AE03F932F93812C2F
+:10025000912CB4E3AB2EB2E4BB2E1CEEC12E1AE0FF
+:10026000D12E7B018C0129813A814B815C81C301B4
+:10027000B2010F9458050F94071F0CED15E021E013
+:1002800043E050E0B10186E090E02EDC98878F8358
+:100290000F900F90612C712C1E821D82412C512CCD
+:1002A0001A821982312C2224239420E030E040E885
+:1002B0005FE36091E80A7091E90A8091EA0A9091FF
+:1002C000EB0A0F94ECBC7B018C016093E80A7093FD
+:1002D000E90A8093EA0A9093EB0A2091E40A3091AC
+:1002E000E50A4091E60A5091E70A6091E00A7091B0
+:1002F000E10A8091E20A9091E30AACECBAE0BF9384
+:10030000AF93812C912CF4E3AF2EF2E4BF2EACEE30
+:10031000CA2EAAE0DA2E0F9458050F94071F0F90EB
+:100320000F901C9B0EC033B034FA332430F8809108
+:10033000C2198225282F30E03E832D83FF24F394B9
+:1003400001C0F12C0F94643B36E06316710424F471
+:100350008FEF681A780A0EC000E010E020E043E05A
+:1003600050E069817A8186E090E0BEDB9A838983E0
+:10037000612C712C0F94F32B81E00E94BD5C98EEF0
+:100380004916510431F0AFEF4A1A5A0AFF2009F416
+:100390008CCF311016C0ED81FE81319719F049E301
+:1003A00059E002C044E159E066E279E0F7EE4F1609
+:1003B00051041CF085E090E002C084E090E00F94CE
+:1003C000FB6B8FE59FE00F9444CA813051F061E0F0
+:1003D0008DEE98E50E9411C361E086EE98E50E94DB
+:1003E00011C3332009F4B8CD00ED17E021E043E05C
+:1003F00050E06F81788587E090E076DB98878F8387
+:1004000040905D1A50905E1A60905F1A7090601A6A
+:1004100060916F1A7091701A8091711A9091721A8E
+:100420000F9435BE69837A838B839C831092781AEC
+:100430001092771A84E690E09093761A8093751A5A
+:100440000F94F32B81E00E94BD5CE4EBEE2EF12CC7
+:10045000A12CB12C0F94F32B81E00E94BD5C00E92C
+:1004600011E020E042E050E0B50187E090E03CDBA5
+:100470005C0121E0E21AF10869F71092781A1092F3
+:10048000771A1092761A1092751A0F94F32B8090A7
+:100490005D1A90905E1AA0905F1AB090601AA981C0
+:1004A000BA81BD01882777FD8095982F0F9468BE8B
+:1004B0009B01AC0160916F1A7091701A8091711A52
+:1004C0009091721A0F94ECBC0F9435BE6A3071058E
+:1004D000DCF4C301B2010F9435BE882777FD809507
+:1004E000982F0F9468BE9B01AC01C501B4010F9415
+:1004F000ECBC0F9435BE6330710574F44EEF58E0D8
+:10050000BA0181E090E005C04EEF58E0BA0182E008
+:1005100090E00F94FB6B312C0F94F32B81E00E9441
+:10052000BD5C332009F418CD08E813E121E043E075
+:1005300050E06F81788588E090E0D6DA18CD2F9270
+:100540003F924F925F926F927F928F929F92AF9263
+:10055000BF92CF92DF92EF92FF920F931F93CF93B0
+:10056000DF9300D01F92CDB7DEB78C01212C312C48
+:1005700048EC442E42E4542E5CE3652E712C0C3082
+:100580001105E8F7F801EE56FF4F0D94DBC2E0913C
+:10059000300BF0E0EE0FFF1FEA5BFF4B859194916B
+:1005A00041E060E00F94C99A882309F4BAC161E080
+:1005B0008FE59FE00F9474CA01E010E0E0CF87EF71
+:1005C0009FE00F9444CA863E09F436C020F481307F
+:1005D00009F4A7C105C0803F31F08A3F09F4A7C1E3
+:1005E00002E010E0CCCF04E010E0C9CFE091300B86
+:1005F000F0E0EE0FFF1FEE5AFF4B859194910F94A0
+:100600007EA424DC882309F498C16AEF87EF9FE079
+:100610000F9456CA8CC1E091300BF0E0EE0FFF1F33
+:10062000E25CFF4B859194910F947EA480E00E9440
+:100630007952882309F481C105E010E0A0CFE09150
+:10064000300BF0E0EE0FFF1FE65CFF4B85919491BD
+:100650000F947EA481E00E947952882309F46DC131
+:100660000BE010E08CCF87ED90E09093781A8093A8
+:10067000771A7092761A6092751AE091300BF0E05A
+:10068000EE0FFF1FEE58FF4B8591949140E060E024
+:100690000F94BE9B882309F44DC108E010E06FCF92
+:1006A000E091300BF0E0EE0FFF1FEE5BFF4B85910A
+:1006B00094910E9434482092E80A3092E90A4092CC
+:1006C000EA0A5092EB0A20E030E040E752E4609101
+:1006D00060027091610280916202909163020F94B6
+:1006E000CDBD4B015C012091E40A3091E50A4091B7
+:1006F000E60A5091E70A6091E00A7091E10A809160
+:10070000E20A9091E30AACECBAE0BF93AF93ECEE4F
+:10071000CE2EEAE0DE2EE12CF12C08EC12E40F9450
+:10072000580580ED97E00E94DE5EE091300BF0E02E
+:10073000EE0FFF1FE259FF4B859194910E943448C0
+:100740000F900F9020E030E047E553E460916F1A7E
+:100750007091701A8091711A9091721A0F94ECBC7A
+:100760006B017C0120E030E0A9010F94C9BF18168D
+:100770000CF051C020E030E040E450E4C701B60185
+:100780000F94C9BF18160CF050C0E091300BF0E088
+:10079000EE0FFF1FE259FF4B859194910E94344860
+:1007A00044E060E081E19BE10E94823D62E081E102
+:1007B0009BE10F94AFB780916F1A9091701AA0913E
+:1007C000711AB091721A89839A83AB83BC83CE016C
+:1007D00001960F949566BC0181E19BE10F94AEB741
+:1007E00065E875E081E19BE10F94AEB74AE050E027
+:1007F00067ED70E081E19BE10F9455B86DEF78E013
+:1008000081E19BE10F94AEB70F94C13F88EE93E076
+:100810000E94DE5E97CF20E030E040E450ECC7015C
+:10082000B6010F94C6BD87FDB0CF07E010E0A7CE9C
+:10083000E091300BF0E0EE0FFF1FEA59FF4B85917E
+:1008400094910F947EA480E00F94D1990F946650F8
+:10085000E091300BF0E0EE0FFF1FE05BFD4B4591A8
+:10086000549162E080E01CD981E08093230B0E94C8
+:10087000605454C0E091300BF0E0EE0FFF1FEE59D2
+:10088000FF4B8591949141E060E00F94BE9B8823DB
+:1008900009F453C043C0E091300BF0E0EE0FFF1FAE
+:1008A000E25BFF4B859194910F947EA4E091300B15
+:1008B000F0E0EE0FFF1FE65BFF4B859194910F94E4
+:1008C0007EA488E090E09093971B8093961B35C0A0
+:1008D000E091300BF0E0EE0FFF1FE65AFF4B8591E1
+:1008E000949140E060E00F94C99A882309F4B8CE4F
+:1008F00066EE87EF9FE00F9456CA60E070E088EFE5
+:100900009FE00F949450E091300BF0E0EE0FFF1F4A
+:10091000E658FF4B859194910F947EA409E010E076
+:100920002ECE60E08FE59FE00F9474CA06C003E00E
+:1009300010E025CE06E010E022CEEDECF3E5849148
+:10094000882341F09091C00095FFFCCF8093C600B2
+:100950003196F5CF4AE050E0B8018EE799E00E9469
+:1009600049420C30110508F03BC0F801E256FF4F38
+:100970000D94DBC2E091300BF0E0EE0FFF1FE25A66
+:10098000FF4B17C0E091300BF0E0EE0FFF1FEA586D
+:10099000FF4B0FC0E091300BF0E0EE0FFF1FE2586D
+:1009A000FF4B07C0E091300BF0E0EE0FFF1FE65960
+:1009B000FF4B0591149121C08091300B90E0880F7E
+:1009C000991FFC01EA58FF4B0591149110927A1B74
+:1009D000845E9F4BFC01859194910F947E510DC0D4
+:1009E000E091300BF0E0EE0FFF1FE25AFF4B8591D4
+:1009F00094910930110521F08C01C8010F947EA457
+:100A000081E00F94D1990F94574782E00F940A9791
+:100A10000F900F900F900F90DF91CF911F910F913A
+:100A2000FF90EF90DF90CF90BF90AF909F908F900E
+:100A30007F906F905F904F903F902F900895AF926E
+:100A4000BF92CF92DF92EF92FF920F931F93CF93BB
+:100A5000DF93CDB7DEB7AA970FB6F894DEBF0FBE0F
+:100A6000CDBF8091961B9091971B059761F5809162
+:100A7000941B9091951B892BC1F48AE69BE00E9400
+:100A80002CB8E091300BF0E0EE0FFF1FE056FD4B6D
+:100A9000859194910F947E5183E08093D40281E0FC
+:100AA00090E09093951B8093941B8091941B909160
+:100AB000951B019741F490916413809163139817EB
+:100AC00011F40D94AE8D8091961B9091971B069713
+:100AD00009F08CC08091941B9091951B892B49F44F
+:100AE00083E08093D40284E090E09093951B809300
+:100AF000941B8091941B9091951B019741F49091C8
+:100B0000641380916313981711F40D94C88D80912C
+:100B1000941B9091951B029709F04CC0909164131F
+:100B200080916313981346C08091500B8F938091EE
+:100B30004F0B8F9387E297E59F938F938E010F5F03
+:100B40001F4F1F930F930F9418C860E0C8010E94B5
+:100B500011C363E279E0C8010F94A1C687E49BE06A
+:100B60000F94F654BC01C8010F9482C660E0C8011E
+:100B70000E9411C30F900F900F900F900F900F9045
+:100B80008091650B81110D94158E61E083E297E5EC
+:100B90000E9411C361E08DE197E50E9411C361E0FD
+:100BA00089E197E50E9411C381E090E09093951B45
+:100BB0008093941B8091941B9091951B039741F413
+:100BC0009091641380916313981711F40D941A8E09
+:100BD0008091941B9091951B049741F4909164131C
+:100BE00080916313981711F40D94368E8091961BA3
+:100BF0009091971B089709F0FEC484ED92EEA6E24F
+:100C0000BFE38FA398A7A9A7BAA78FE399EFA9E598
+:100C1000BCE38BA39CA3ADA3BEA30F94EFB4605D14
+:100C20007A488F4F9F4F6093F31A7093F41A809312
+:100C3000F51A9093F61A8091941B9091951B892B2D
+:100C400031F489E090E09093951B8093941B809100
+:100C5000941B9091951B099759F49091641380917E
+:100C60006313981305C00E94EFC381110D94858E04
+:100C70008091941B9091951B089759F4909164135F
+:100C800080916313981305C00E94EFC381110D94E6
+:100C9000C18E8091941B9091951B079759F4909168
+:100CA000641380916313981305C00E94EFC38111F0
+:100CB0000D94068F8091941B9091951B069709F0D7
+:100CC00012C1909164138091631398130CC10E9418
+:100CD000EFC3882309F407C10F94EFB4605D7A482D
+:100CE0008F4F9F4F6093F31A7093F41A8093F51A05
+:100CF0009093F61AAA24A394B12C00E010E06FEFB1
+:100D000078E0CE0101960F94A1C6B801882777FD3F
+:100D10008095982F0F9468BE2DEC3CEC4CEC5EE374
+:100D20000F949BC09B01AC010F94EDBC9B01AC01E7
+:100D300060E070E08CE092E40F94ECBC6F8F78A3DD
+:100D400089A39AA3CE014F960F94F654BC01CE010D
+:100D500001960F9482C665E479E0CE0101960F9466
+:100D600082C6CE0187960F941256BC01CE01019621
+:100D70000F9482C660E0CE0101960E9411C368E024
+:100D800079E0CE0101960F94A1C6B501882777FDC1
+:100D90008095982F0F9468BE2DEC3CEC4CEC5EE3F4
+:100DA0000F949BC09B01AC0160E070E08CE092E48A
+:100DB0000F94ECBC6B017C016F8F78A389A39AA37D
+:100DC000CE014F960F94F654BC01CE0101960F94BC
+:100DD00082C665E479E0CE0101960F9482C6CE0109
+:100DE00083960F941256BC01CE0101960F9482C6D1
+:100DF00060E0CE0101960E9411C36DE079E0CE0162
+:100E000001960F94A1C6CF8ED8A2E9A2FAA2CE0174
+:100E10004F960F94F654BC01CE0101960F9482C6F2
+:100E200065E479E0CE0101960F9482C6CE018796E3
+:100E30000F941256BC01CE0101960F9482C660E059
+:100E4000CE0101960E9411C368E079E0CE010196BF
+:100E50000F94A1C60F5F1F4FB801882777FD8095BB
+:100E6000982F0F9468BE2DEC3CEC4CEC5EE30F9495
+:100E70009BC09B01AC010F94EDBC9B01AC0160E0F9
+:100E800070E08CE092E40F94ECBC6F8F78A389A3A0
+:100E90009AA3CE014F960F94F654BC01CE01019651
+:100EA0000F9482C665E479E0CE0101960F9482C664
+:100EB000CE0183960F941256BC01CE0101960F9479
+:100EC00082C660E0CE0101960E9411C322E0A20E0C
+:100ED000B11C0430110509F012CF85E090E0909329
+:100EE000951B8093941B8091941B9091951B059763
+:100EF00009F012C1909164138091631398130CC18F
+:100F00000E94EFC3882309F407C10F94EFB4605D1A
+:100F10007A488F4F9F4F6093F31A7093F41A80931F
+:100F2000F51A9093F61AE9E0AE2EB12C04E010E029
+:100F30006FEF78E0CE0101960F94A1C6B801882723
+:100F400077FD8095982F0F9468BE2DEC3CEC4CEC0F
+:100F50005EE30F949BC09B01AC010F94EDBC9B0121
+:100F6000AC0160E070E08CE092E40F94ECBC6F8F19
+:100F700078A389A39AA3CE014F960F94F654BC018F
+:100F8000CE0101960F9482C665E479E0CE01019608
+:100F90000F9482C6CE0187960F941256BC01CE01E3
+:100FA00001960F9482C660E0CE0101960E9411C3A3
+:100FB00068E079E0CE0101960F94A1C6B5018827BB
+:100FC00077FD8095982F0F9468BE2DEC3CEC4CEC8F
+:100FD0005EE30F949BC09B01AC0160E070E08CE08D
+:100FE00092E40F94ECBC6B017C016F8F78A389A312
+:100FF0009AA3CE014F960F94F654BC01CE010196F0
+:101000000F9482C665E479E0CE0101960F9482C602
+:10101000CE0183960F941256BC01CE0101960F9417
+:1010200082C660E0CE0101960E9411C36DE079E0B6
+:10103000CE0101960F94A1C6CF8ED8A2E9A2FAA242
+:10104000CE014F960F94F654BC01CE0101960F9439
+:1010500082C665E479E0CE0101960F9482C6CE0186
+:1010600087960F941256BC01CE0101960F9482C64A
+:1010700060E0CE0101960E9411C368E079E0CE01E4
+:1010800001960F94A1C60F5F1F4FB801882777FD07
+:101090008095982F0F9468BE2DEC3CEC4CEC5EE3F1
+:1010A0000F949BC09B01AC010F94EDBC9B01AC0164
+:1010B00060E070E08CE092E40F94ECBC6F8F78A35A
+:1010C00089A39AA3CE014F960F94F654BC01CE018A
+:1010D00001960F9482C665E479E0CE0101960F94E3
+:1010E00082C6CE0183960F941256BC01CE010196A2
+:1010F0000F9482C660E0CE0101960E9411C382E087
+:10110000A80EB11C0830110509F012CF84E090E060
+:101110009093951B8093941B8091941B9091951BA9
+:10112000049709F012C1909164138091631398138E
+:101130000CC10E94EFC3882309F407C10F94EFB4D8
+:10114000605D7A488F4F9F4F6093F31A7093F41A43
+:101150008093F51A9093F61A71E1A72EB12C08E04E
+:1011600010E06FEF78E0CE0101960F94A1C6B801B0
+:10117000882777FD8095982F0F9468BE2DEC3CEC66
+:101180004CEC5EE30F949BC09B01AC010F94EDBC53
+:101190009B01AC0160E070E08CE092E40F94ECBC49
+:1011A0006F8F78A389A39AA3CE014F960F94F6541C
+:1011B000BC01CE0101960F9482C665E479E0CE01B0
+:1011C00001960F9482C6CE0187960F941256BC01E9
+:1011D000CE0101960F9482C660E0CE0101960E9476
+:1011E00011C368E079E0CE0101960F94A1C6B50164
+:1011F000882777FD8095982F0F9468BE2DEC3CECE6
+:101200004CEC5EE30F949BC09B01AC0160E070E08E
+:101210008CE092E40F94ECBC6B017C016F8F78A39F
+:1012200089A39AA3CE014F960F94F654BC01CE0128
+:1012300001960F9482C665E479E0CE0101960F9481
+:1012400082C6CE0183960F941256BC01CE01019640
+:101250000F9482C660E0CE0101960E9411C36DE03A
+:1012600079E0CE0101960F94A1C6CF8ED8A2E9A253
+:10127000FAA2CE014F960F94F654BC01CE0101960E
+:101280000F9482C665E479E0CE0101960F9482C680
+:10129000CE0187960F941256BC01CE0101960F9491
+:1012A00082C660E0CE0101960E9411C368E079E039
+:1012B000CE0101960F94A1C60F5F1F4FB80188277A
+:1012C00077FD8095982F0F9468BE2DEC3CEC4CEC8C
+:1012D0005EE30F949BC09B01AC010F94EDBC9B019E
+:1012E000AC0160E070E08CE092E40F94ECBC6F8F96
+:1012F00078A389A39AA3CE014F960F94F654BC010C
+:10130000CE0101960F9482C665E479E0CE01019684
+:101310000F9482C6CE0183960F941256BC01CE0163
+:1013200001960F9482C660E0CE0101960E9411C31F
+:1013300022E0A20EB11C0C30110509F012CF83E09F
+:1013400090E09093951B8093941B8091941B9091B7
+:10135000951B039709F012C1909164138091631358
+:1013600098130CC10E94EFC3882309F407C10F949E
+:10137000EFB4605D7A488F4F9F4F6093F31A70937C
+:10138000F41A8093F51A9093F61A69E1A62EB12CFF
+:101390000CE010E06FEF78E0CE0101960F94A1C64B
+:1013A000B801882777FD8095982F0F9468BE2DECA3
+:1013B0003CEC4CEC5EE30F949BC09B01AC010F94A2
+:1013C000EDBC9B01AC0160E070E08CE092E40F9416
+:1013D000ECBC6F8F78A389A39AA3CE014F960F948C
+:1013E000F654BC01CE0101960F9482C665E479E003
+:1013F000CE0101960F9482C6CE0187960F941256A5
+:10140000BC01CE0101960F9482C660E0CE01019628
+:101410000E9411C368E079E0CE0101960F94A1C645
+:10142000B501882777FD8095982F0F9468BE2DEC25
+:101430003CEC4CEC5EE30F949BC09B01AC0160E084
+:1014400070E08CE092E40F94ECBC6B017C016F8F38
+:1014500078A389A39AA3CE014F960F94F654BC01AA
+:10146000CE0101960F9482C665E479E0CE01019623
+:101470000F9482C6CE0183960F941256BC01CE0102
+:1014800001960F9482C660E0CE0101960E9411C3BE
+:101490006DE079E0CE0101960F94A1C6CF8ED8A25F
+:1014A000E9A2FAA2CE014F960F94F654BC01CE01E8
+:1014B00001960F9482C665E479E0CE0101960F94FF
+:1014C00082C6CE0187960F941256BC01CE010196BA
+:1014D0000F9482C660E0CE0101960E9411C368E0BD
+:1014E00079E0CE0101960F94A1C60F5F1F4FB8019E
+:1014F000882777FD8095982F0F9468BE2DEC3CECE3
+:101500004CEC5EE30F949BC09B01AC010F94EDBCCF
+:101510009B01AC0160E070E08CE092E40F94ECBCC5
+:101520006F8F78A389A39AA3CE014F960F94F65498
+:10153000BC01CE0101960F9482C665E479E0CE012C
+:1015400001960F9482C6CE0183960F941256BC0169
+:10155000CE0101960F9482C660E0CE0101960E94F2
+:1015600011C382E0A80EB11C0031110509F012CFA1
+:1015700082E090E09093951B8093941B8091941B44
+:101580009091951B029751F490916413809163138D
+:10159000981304C00E94EFC38111ADC48091941BC5
+:1015A0009091951B019739F5909164138091631385
+:1015B000981321C00E94EFC38823E9F0E091300B1B
+:1015C000F0E0EE0FFF1FE45EFF4B859194910F94C6
+:1015D0007E511092951B1092941B1092971B1092A3
+:1015E000961B8FE59FE00F9444CA813021F48AE076
+:1015F00090E00F949F828091961B9091971B029789
+:1016000009F02FC18091941B9091951B892B49F46F
+:1016100086E090E09093951B8093941B81E08093EB
+:10162000240B8091941B9091951B019739F4909114
+:10163000641380916313981709F4A3C48091941BD9
+:101640009091951B029739F49091641380916313E4
+:10165000981709F4B2C48091941B9091951B03973D
+:1016600039F49091641380916313981709F4C4C4FA
+:101670008091941B9091951B049739F49091641379
+:1016800080916313981709F4C3C48091941B9091BF
+:10169000951B059759F590916413809163139813E6
+:1016A00025C0E091300BF0E0EE0FFF1FE855FE4B38
+:1016B000859194910F947E5161E080EB94E50E94B6
+:1016C00011C361E083EA94E50E9411C38091D10ABD
+:1016D000882309F4C2C48091D20A882309F4BDC4C6
+:1016E00084E090E09093951B8093941B8091941BD1
+:1016F0009091951B069739F4909164138091631330
+:10170000981709F4ADC48091941B9091951B07978D
+:1017100009F09AC09091641380916313981394C058
+:101720000F946650E091300BF0E0EE0FFF1FE8568B
+:10173000FF4B4591549160E080E00F94507D6BE148
+:1017400074E081E19BE10F94AEB741E060E081E19C
+:101750009BE10E94823D6EE477E081E19BE10F9482
+:10176000AEB7E091300BF0E0EE0FFF1FEE56FC4BF2
+:101770004591549161E081E00F94507DE091300BF0
+:10178000F0E0EE0FFF1FE057FF4B4591549162E0F0
+:1017900081E00F94507DE091300BF0E0EE0FFF1FE1
+:1017A000EC50FD4B4591549163E081E00F94507DE6
+:1017B00084E090E0909316028093150200E010E020
+:1017C000FF24F3940F94F32B81E00E94BD5C2091E1
+:1017D000B81B332727FD3095C801821B930B97FF59
+:1017E00003C091958195910905970CF068C40F94F9
+:1017F0000453882339F30F9404538111FCCF6AE01A
+:1018000070E080E090E00F941EB50F9404538111B6
+:10181000FCCF82E090E090931602809315028FEF48
+:101820008F0D61E0813009F498C4823009F498C4C6
+:10183000811199C48EE994E50E9411C383E090E080
+:101840009093951B8093941B8091941B9091951B72
+:10185000089739F49091641380916313981709F4F1
+:1018600085C48091961B9091971B039721F4109249
+:10187000971B1092961B8091961B9091971B049733
+:1018800009F05DC08091941B9091951B892B49F4C0
+:1018900086E090E09093951B8093941B81E0809369
+:1018A000240B8091941B9091951B019739F4909192
+:1018B000641380916313981709F45FC48091941B9B
+:1018C0009091951B029739F4909164138091631362
+:1018D000981709F45DC48091941B9091951B039710
+:1018E00039F49091641380916313981709F457C4E5
+:1018F0008091941B9091951B049739F490916413F7
+:1019000080916313981709F451C48091941B9091AE
+:10191000951B059739F49091641380916313981780
+:1019200009F455C48091941B9091951B069739F446
+:101930009091641380916313981709F44FC48091B8
+:10194000961B9091971B079709F081C48091941B77
+:101950009091951B892BA9F483E090E09093220B42
+:101960008093210B21E030E03093200B20931F0B5C
+:101970002093240B23E02093D4029093951B809313
+:10198000941B8091941B9091951B039739F490912F
+:10199000641380916313981709F433C48091941BE6
+:1019A0009091951B029709F098C080914C1A88235A
+:1019B00009F493C010924C1A1092200B10921F0B36
+:1019C000E091300BF0E0EE0FFF1FE652FE4B8591E9
+:1019D00094910F947E5120E030E0A9016091591A52
+:1019E00070915A1A80915B1A90915C1A0F94C6BD3F
+:1019F00081111EC020E030E0A9016091551A70915C
+:101A0000561A8091571A9091581A0F94C6BD811199
+:101A10000FC020E030E0A9016091511A7091521A74
+:101A20008091531A9091541A0F94C6BD8823C1F126
+:101A300066E179E0CE0101960F94A1C689E59AE1AD
+:101A40000F94F654BC01CE0101960F9482C66DE14D
+:101A500079E0CE0101960F9482C685E59AE10F9454
+:101A6000F654BC01CE0101960F9482C660E279E083
+:101A7000CE0101960F9482C681E59AE10F94F65447
+:101A8000BC01CE0101960F9482C660E0CE010196A2
+:101A90000E9411C361E08CE594E50E9411C30DC062
+:101AA000ECE2F4E58491882341F09091C00095FF29
+:101AB000FCCF8093C6003196F5CF0F94EFB46093BE
+:101AC000861B7093871B8093881B9093891B81E0F2
+:101AD00090E09093951B8093941B8091941B909120
+:101AE000951B019709F0B3C30F94EFB40091861BC7
+:101AF0001091871B2091881B3091891B601B710BF3
+:101B0000820B930B613D77408105910508F49FC3DB
+:101B1000E091300BF0E0EE0FFF1FE45EFF4B85918C
+:101B200094910F947E511092220B1092210B1092DF
+:101B3000240B80E090E0A2E5B3E48093D802909378
+:101B4000D902A093DA02B093DB021092951B109297
+:101B5000941B1092971B1092961B79C3E091300B47
+:101B6000F0E0EE0FFF1FEC55FE4B859194910F9422
+:101B70007E5181E08093931B0E94A8641092971B72
+:101B80001092961B1092951B1092941B0D946385D6
+:101B90008091610B8F938091600B8F9380E397E529
+:101BA0009F938F938E010F5F1F4F1F930F930F947F
+:101BB00018C860E0C8010E9411C31092931B0F94D3
+:101BC000EFB4C0903B0BD0903C0BE0903D0BF090FD
+:101BD0003E0B0091370B1091380B2091390B30914F
+:101BE0003A0BC01AD10AE20AF30AC60ED71EE81E43
+:101BF000F91EC0923B0BD0923C0BE0923D0BF09251
+:101C00003E0B8AE69BE00E9425B81092951B10922D
+:101C1000941B1092971B1092961B0F900F900F9091
+:101C20000F900F900F900D94878561E083E197E509
+:101C30000D94D28568E279E0CE0101960F94A1C699
+:101C400081E59BE00F949566BC01CE0101960F944F
+:101C500082C660E0CE0101960E9411C382E090E04E
+:101C60009093951B8093941B0D94E8856FE279E027
+:101C7000CE0101960F94A1C681E59BE00F94956675
+:101C8000BC01CE0101960F9482C660E0CE010196A0
+:101C90000E9411C361E08FE097E50E9411C366E3E3
+:101CA00079E0CE0101960F94A1C68FE39BE00F94DB
+:101CB000F654BC01CE0101960F9482C663E179E02F
+:101CC000CE0101960F9482C683E49BE00F94F654F4
+:101CD000BC01CE0101960F9482C660E0CE01019650
+:101CE0000E9411C3E091300BF0E0EE0FFF1FE258AD
+:101CF000FE4B859194910F947E5183E090E09093F8
+:101D0000951B8093941B0D94F68561E08AE097E51E
+:101D10000E9411C361E080E097E50E9411C361E079
+:101D200087EF96E50E9411C361E08EEE96E50E9472
+:101D300011C361E084EE96E50E9411C3E091300B7F
+:101D4000F0E0EE0FFF1FE45CFD4B8591949161E0A4
+:101D50000E9411C361E080EE96E50E9411C361E02C
+:101D60008CED96E50E9411C361E083ED96E50E943B
+:101D700011C388E090E09093951B8093941B0D9481
+:101D800038860F94665001E020E040E050E0BA0150
+:101D900085EF91E00F94FD4161E08DEB96E50E94A7
+:101DA00011C361E085EA96E50E9411C361E08CE908
+:101DB00096E50E9411C361E088E996E50E9411C38F
+:101DC00061E084E996E50E9411C361E080E996E54F
+:101DD0000E9411C361E087E796E50E9411C361E0AC
+:101DE00083E696E50E9411C361E088E596E50E94CE
+:101DF00011C361E08FE496E50E9411C387E090E093
+:101E00009093951B8093941B0D9449860F94EFB487
+:101E1000605D7A488F4F9F4F6093F31A7093F41A66
+:101E20008093F51A9093F61A61E083E496E50E9498
+:101E300011C361E08AE396E50E9411C361E089E283
+:101E400096E50E9411C361E089E196E50E9411C305
+:101E500061E083E096E50E9411C361E08DEE95E5B7
+:101E60000E9411C361E088ED95E50E9411C361E015
+:101E700083EC95E50E9411C361E08DEA95E50E942F
+:101E800011C361E088E995E50E9411C361E084E82F
+:101E900095E50E9411C361E080E795E50E9411C3BA
+:101EA00061E08BE595E50E9411C361E086E495E56C
+:101EB0000E9411C361E082E395E50E9411C36BE3C8
+:101EC00079E0CE0101960F94A1C6CE0187960F94BA
+:101ED0001256BC01CE0101960F9482C660E0CE017D
+:101EE00001960E9411C386E090E09093951B809329
+:101EF000941B0D945A860F94EFB4605D7A488F4F0F
+:101F00009F4F6093F31A7093F41A8093F51A90938D
+:101F1000F61A61E089E195E50E9411C361E084E170
+:101F200095E50E9411C361E08CE095E50E9411C324
+:101F300061E084E095E50E9411C361E083EF94E5E0
+:101F40000E9411C361E081EE94E50E9411C361E03B
+:101F50008DED94E50E9411C30F94EFB461507109A7
+:101F6000810991096093F31A7093F41A8093F51A1A
+:101F70009093F61A81E090E09093951B8093941BC8
+:101F80000DCB1092951B1092941B1092971B1092E0
+:101F9000961BE091300BF0E0EE0FFF1FE45EFF4B6D
+:101FA000859194910F947E511092220B1092210BE7
+:101FB0001092240B1092931B41CB1092761A109220
+:101FC000751A61E085ED94E50E9411C30F94F32B1F
+:101FD000E091300BF0E0EE0FFF1FE45EFF4B8591C8
+:101FE00094910F947E511092BB0A81E090E09093FF
+:101FF000951B8093941B2FCB61E081ED94E50E94AB
+:1020000011C382E090E09093951B8093941B30CB9A
+:10201000E091300BF0E0EE0FFF1FE054FE4B859196
+:1020200094910F947E5161E08DEC94E50E9411C370
+:1020300061E089EC94E50E9411C361E084EB94E5D2
+:102040000E9411C31092FD1A1092FC1A83E090E0D6
+:102050009093951B8093941B18CB83E090E042CB28
+:10206000E091300BF0E0EE0FFF1FE855FE4B85913D
+:1020700094910F947E5111E01093BB0A1092761A3E
+:102080001092751A1092781A1092771A10927A1A82
+:102090001092791A10927C1A10927B1A0F94F32BDB
+:1020A0001093240B82E090E09093220B8093210BFD
+:1020B00085E090E09093951B8093941B24CB201790
+:1020C00031070CF4FA94021713070CF4F39423E08D
+:1020D0002F152CF01F142CF0FF24F39402C083E082
+:1020E000F82E41E060E081E19BE10E94823D6EECD0
+:1020F00078E081E19BE10F94AEB742E060E081E1DE
+:102100009BE10E94823D6EEC78E081E19BE10F94BF
+:10211000AEB743E060E081E19BE10E94823D6EEC5E
+:1021200078E081E19BE10F94AEB74F2D60E081E153
+:102130009BE10E94823D6EE477E081E19BE10F9498
+:10214000AEB70091B81B112707FD109564E670E04B
+:1021500080E090E00F941EB54ACB87E994E56CCB04
+:1021600080E994E569CB8BE894E566CB87E090E065
+:102170009093951B8093941B74CB0F94937C109237
+:10218000951B1092941B1092971B1092961B96CB46
+:1021900081E090E09093951B8093941B9CCB82E010
+:1021A00090E09093951B8093941BA2CB61E087E80D
+:1021B00094E50E9411C361E082E794E50E9411C397
+:1021C00083E090E09093951B8093941B9ECB84E0DA
+:1021D00090E09093951B8093941BA4CB61E08EE6D6
+:1021E00094E50E9411C361E081E694E50E9411C369
+:1021F0000F94071F85E090E09093951B8093941BAC
+:102200009ECB68E479E0CE0101960F94A1C688EDDB
+:1022100092E00F949566BC01CE0101960F9482C6A0
+:1022200060E0CE0101960E9411C3E091300BF0E016
+:10223000EE0FFF1FEA52FE4B859194910F947E5151
+:1022400082E090E09093951B8093941BA7CBAA9675
+:102250000FB6F894DEBF0FBECDBFDF91CF911F91B7
+:102260000F91FF90EF90DF90CF90BF90AF900895C7
+:102270008F929F92AF92BF92CF92DF92EF92FF9296
+:102280000F931F93CF93DF93CDB7DEB728970FB689
+:10229000F894DEBF0FBECDBF8091D702813009F028
+:1022A0003DC01092D7020F94835080917A1B811108
+:1022B0000FC0E091300BF0E0EE0FFF1FE45EFF4B2C
+:1022C0006591749144E150E085E69BE10F9429C645
+:1022D0008DEE9FE00F9444CA8F3F01F58EEE9FE094
+:1022E0000F9444CA8F3FD1F48FEE9FE00F9444CAFD
+:1022F0008F3FA1F480EF9FE00F9444CA8F3F71F4A9
+:1023000040E050E0BA018DEE9FE00F9468CA40E0D3
+:1023100050E0BA0181EF9FE00F9468CA8091FE1AE5
+:10232000882321F081508093FE1A03C081E08093BE
+:10233000D4028091D402882309F4B6C480919A1BF8
+:102340008F5F80939A1B8E3129F40F944B47109224
+:102350009A1B0EC06AE00F9469C2911109C020E077
+:1023600044E064E181E19BE10E94943E0F94C13F0F
+:1023700020E030E040E05FE360916F1A7091701AE6
+:102380008091711A9091721A0F94EDBC0F9435BE22
+:1023900078876F836091771A7091781A882777FD14
+:1023A0008095982F0F9468BE20E030E040E05FE316
+:1023B0000F94EDBC0F9435BE7E836D8340E060E0EA
+:1023C00081E19BE10E94823D62E081E19BE10F940B
+:1023D000AFB7CE0107960F94CB57BC0181E19BE1CB
+:1023E0000F94AEB76FE281E19BE10F94AFB7CE01DE
+:1023F00005960F94AD66BC0181E19BE10F94AEB7E9
+:102400008FEB97E50F9477678CEB97E50F947767E1
+:1024100040E06AE081E19BE10E94823D88EB97E524
+:102420000F9477678091210B9091220B019729F4EB
+:1024300080EB97E50F94776720C02CEA35EC47E2F4
+:1024400057E36091E80A7091E90A8091EA0A909155
+:10245000EB0A0F94EDBC69837A838B839C83CE0156
+:1024600001960F94F956BC0181E19BE10F94AEB740
+:1024700060E281E19BE10F94AFB741E060E081E170
+:102480009BE10E94823D20E030E040E05FE360910C
+:102490005D1A70915E1A80915F1A9091601A0F9484
+:1024A000EDBC0F9435BE78876F836091751A70917B
+:1024B000761A882777FD8095982F0F9468BE20E0C4
+:1024C00030E040E05FE30F94EDBC0F9435BE7E83B7
+:1024D0006D8360E081E19BE10F94AFB7CE01079679
+:1024E0000F94CB57BC0181E19BE10F94AEB76FE233
+:1024F00081E19BE10F94AFB7CE0105960F94AD66D5
+:10250000BC0181E19BE10F94AEB78DEA97E50F9492
+:1025100077678AEA97E50F94776741E06AE081E19F
+:102520009BE10E94823D87EA97E50F94776766E01A
+:1025300081E19BE10F94AFB786E592E00F94CB5712
+:10254000BC0181E19BE10F94AEB780EA97E50F945F
+:10255000776742E060E081E19BE10E94823D8091EB
+:102560005F0B882319F08DE997E502C08AE997E5AA
+:102570000F94776780916C0B8823A9F18091560D99
+:10258000882319F18091000E9091010EA091020E06
+:10259000B091030E0097A105B105B9F0BC01CD01C2
+:1025A0006D597F4F8F4F9F4F24E630E040E050E061
+:1025B0000F949DC26091080E7091090E80910A0ED1
+:1025C00090910B0E0F949DC201C020E030E03A8341
+:1025D0002983CE0101960F94CB57BC0181E19BE189
+:1025E0000F94AEB70DC080915F0B882329F085E969
+:1025F00097E50F94776709C081E997E50F947767AE
+:1026000065E281E19BE10F94AFB78091921B882333
+:1026100089F18EE897E50F9477676091901B709130
+:10262000911B4AE050E081E19BE10F9455B88BE8A3
+:1026300097E50F94776740E063E181E19BE10E94B9
+:10264000823D0F94EFB4C090590BD0905A0BE0909C
+:102650005B0BF0905C0B6C197D098E099F0960364D
+:102660007A4E8105910518F489E897E50BC087E853
+:1026700097E508C042E06AE081E19BE10E94823D6B
+:1026800085E897E50F94776742E06BE081E19BE195
+:102690000E94823D83E897E50F94776767E081E1C8
+:1026A0009BE10F94AFB780918A0A90918B0AA09119
+:1026B0008C0AB0918D0A892B8A2B8B2BE1F10F9418
+:1026C000EFB420E6C22E2AEED22EE12CF12CA70187
+:1026D00096010F949DC249015A0160918A0A709136
+:1026E0008B0A80918C0A90918D0AA70196010F9414
+:1026F0009DC2C401821B930B6CE370E00F9476C201
+:10270000182F6983CE0101960F949254BC0181E188
+:102710009BE10F94AEB76AE381E19BE10F94AFB701
+:102720001983CE0101960F949254BC0181E19BE183
+:102730000F94AEB704C08DE797E50F9477678AE7EB
+:1027400097E50F94776743E060E081E19BE10E94A9
+:10275000823D8091270B9091280B009719F021E082
+:102760002093240B30916C0B2091240B332309F41C
+:1027700082C0211180C06BE77BE08EE29BE10F9469
+:1027800098C6892B31F10EE21BE1F801019000207F
+:10279000E9F7AF01415051094E525B4160E070E0F2
+:1027A000C8010F9468C68BE79BE09F938F9387E7E0
+:1027B00097E59F938F931F930F930F9418C81092D0
+:1027C000641B1092631B0F900F900F900F900F904F
+:1027D0000F90EBE7FBE001900020E9F7EC57FB409E
+:1027E000759708F445C00091631B1091641BC12CC0
+:1027F000D12C8091631B9091641B9801281B390B8D
+:102800002431310534F001969093641B8093631B4F
+:10281000F9C1C114D104B9F798012659344F79018F
+:10282000F9019189602F681B43E0911114C081E187
+:102830009BE10E94823DF701608981E19BE10F9459
+:10284000AFB71092641B1092631B00E010E0CC2421
+:10285000C394D12CCECF81E19BE10E94823DF70150
+:10286000608981E19BE10F94AFB70F5F1F4FC1CF2C
+:102870006EE27BE1CCC1222309F4C7C1892B09F4A4
+:102880008EC08091250B9091260B01968E3091057C
+:1028900028F49093260B8093250B04C01092260BEE
+:1028A0001092250B43E067E081E19BE10E94823DAD
+:1028B00089E697E50F94776700E010E08091250B9B
+:1028C0009091260B0817190778F467E0600F43E032
+:1028D00081E19BE10E94823D6EE281E19BE10F94E8
+:1028E000AFB70F5F1F4FEACF8091270B9091280B56
+:1028F0008230910531F188F4019709F050C043E02E
+:1029000060E081E19BE10E94823DE091300BF0E0CC
+:10291000EE0FFF1FE657FD4B2FC083309105F9F0F6
+:10292000049709F03CC043E060E081E19BE10E9434
+:10293000823DE091300BF0E0EE0FFF1FE859FC4BB9
+:1029400020C043E060E081E19BE10E94823DE09194
+:10295000300BF0E0EE0FFF1FEA57FD4B12C043E0D3
+:1029600060E081E19BE10E94823DE091300BF0E06C
+:10297000EE0FFF1FEC59FC4B859194910F947767F4
+:102980000EC0859194910F9477671092280B109246
+:10299000270B1092260B1092250B1092240B80917E
+:1029A000210B9091220B019709F07CC080911F0BA5
+:1029B0009091200B8B30910560F143E060E081E164
+:1029C0009BE10E94823D84E597E50F94776743E0A1
+:1029D00060E081E19BE10E94823DE091300BF0E0FC
+:1029E000EE0FFF1FE658FD4B859194910F9477678A
+:1029F00080E597E50F94776760911F0B7091200B2E
+:102A00006A5071094AE050E081E19BE10F9468B897
+:102A100049C00397E1F4E091300BF0E0EE0FFF1FA7
+:102A2000E45EFF4B859194910F947767E091300BB2
+:102A3000F0E0EE0FFF1FE45EFF4B859194910F9441
+:102A40007E511092240B1092220B1092210B809138
+:102A50001F0B9091200B0497079720F543E060E04F
+:102A600081E19BE10E94823D8CE397E50F947767BB
+:102A700043E060E081E19BE10E94823DE091300B08
+:102A8000F0E0EE0FFF1FE258FD4B859194910F94FB
+:102A9000776780911F0B9091200B01979093200BEB
+:102AA00080931F0B8091210B9091220B029731F4A0
+:102AB00065E67BE181E19BE10F94AEB78091210B4C
+:102AC0009091220B0397A1F565E67BE181E19BE103
+:102AD0000F94AEB720914F1A3091501A80914D1A31
+:102AE00090914E1A821793071CF180911F0B9091C1
+:102AF000200B892BE9F043E06AE081E19BE10E9431
+:102B0000823D8FE49AE10F94CB57BC0181E19BE1B8
+:102B10000F94AEB76FE281E19BE10F94AFB78DE404
+:102B20009AE10F94AD66BC0181E19BE10F94AEB7D1
+:102B30008091210B9091220B049799F543E060E07E
+:102B400081E19BE10E94823DE091300BF0E0EE0FCD
+:102B5000FF1FEA54FF4B859194910F94776743E0F0
+:102B60006CE081E19BE10E94823D8091200B8F937C
+:102B700080911F0B8F9382E599E09F938F938E0135
+:102B80000F5F1F4F1F930F930F94EAC7B80181E1A6
+:102B90009BE10F94AEB70F900F900F900F900F9096
+:102BA0000F908091210B9091220B059759F543E0EE
+:102BB00060E081E19BE10E94823DE091300BF0E01A
+:102BC000EE0FFF1FEE52FE4B859194910F947767A5
+:102BD00080911F0B9091200B8937910598F489E320
+:102BE00097E50F94776760911F0B7091200B4AE077
+:102BF00050E081E19BE10F9468B860E281E19BE1E4
+:102C00000F94AFB705E61BE10BC065E67BE181E100
+:102C10009BE10F94AEB7F6CFFBE109371F0759F0E0
+:102C2000F80181918F018032BCF760E281E19BE184
+:102C30000F94AFB7F1CF8091921B882351F180910F
+:102C4000DD029091DE0201979093DE028093DD0217
+:102C50001816190654F084EB90E09093DE028093EE
+:102C6000DD0280E090E00F94FF608091DD029091A2
+:102C7000DE028A30910529F08D9759F485E190E0C4
+:102C800006C080916C0B882321F084E190E00F94C2
+:102C9000FF608AE08093FE1A8091961B9091971BAB
+:102CA000892B11F00F941F858091101B82FB8827C0
+:102CB00080F99091FD1A992399F09091FC1A99232B
+:102CC00039F0811120C01092FC1A1092FD1A1BC01D
+:102CD0008823C9F00F94EE4181E08093FC1A13C061
+:102CE000882389F08091961B9091971B029759F049
+:102CF00001E021E040E050E0BA018DE591E00F9461
+:102D0000FD410F944B4780915602909157022091BC
+:102D10000A1B30910B1B8436910534F4820F931FEC
+:102D2000853691054CF416C08436910599F0820FD2
+:102D3000931F8436910574F410920A1B10920B1B9A
+:102D400010920C1B10920D1B84E690E0909357029A
+:102D500080935602209156023091570280910A1BAF
+:102D600090910B1B2436310569F48B3091051CF0D2
+:102D7000865A9F4F09C0863F2FEF92078CF48259E5
+:102D80009F4F02C0820F931F909357028093560269
+:102D900010920A1B10920B1B10920C1B10920D1B11
+:102DA00080915602909157028A3091051CF48AE076
+:102DB00090E005C0883E934034F087EE93E0909316
+:102DC0005702809356028091921B882381F0809154
+:102DD000DC0281110CC043E060E081E19BE10E94D4
+:102DE000823DECEAF1E4859194910F9477672896FF
+:102DF0000FB6F894DEBF0FBECDBFDF91CF911F910C
+:102E00000F91FF90EF90DF90CF90BF90AF909F9089
+:102E10008F900895CF92DF92EF92FF929091D4021B
+:102E2000981710F48093D4028091D302882309F478
+:102E3000F1C00F94B55180910301817091E0892711
+:102E40002091051B8217F9F082E08093D4028091D3
+:102E50000301817089278093051B0F944B47809154
+:102E6000051B882309F4CAC08AE69BE00E944CB780
+:102E7000E091300BF0E0EE0FFF1FE659FE4B85911D
+:102E800094910F947E51C090FF1AD090001BE09057
+:102E9000011BF090021B0F94EFB4C616D706E8068C
+:102EA000F90608F098C08091B81B482F552747FDB8
+:102EB000509557FF03C05195419551094230510536
+:102EC000A4F19091D402911103C091E09093D402A7
+:102ED00087FD8F5F482F4595552747FD5095652FF6
+:102EE000752F80910A1B90910B1BA0910C1BB09128
+:102EF0000D1B840F951FA61FB71F80930A1B90936D
+:102F00000B1BA0930C1BB0930D1B1092B81B0F94BE
+:102F1000EFB4605D7A488F4F9F4F6093F31A7093C0
+:102F2000F41A8093F51A9093F61A8091101B82FF81
+:102F30000EC00F94EFB4605D7A488F4F9F4F60933F
+:102F4000F31A7093F41A8093F51A9093F61AE0919D
+:102F5000D502F091D6021995C090F31AD090F41AC8
+:102F6000E090F51AF090F61A0F94EFB4C616D70653
+:102F7000E806F906A8F4E091D502F091D60281E0C6
+:102F8000ED3DF80769F0309731F081E080937B1BCD
+:102F9000199510927B1B0F94574782E08093D402BF
+:102FA0008091D402823011F40F9466508091D40243
+:102FB000882319F081508093D4020F94EFB46C5998
+:102FC0007F4F8F4F9F4F6093FF1A7093001B80932A
+:102FD000011B9093021B0E9408B0811101C0A1D473
+:102FE0000F9418518091961B9091971B089791F41C
+:102FF000FF90EF90DF90CF900D941F858AE69BE0C5
+:103000000E9421B8E091300BF0E0EE0FFF1FE05A74
+:10301000FE4B35CFFF90EF90DF90CF900895CF9289
+:10302000DF92EF92FF920F94665040E061E081E101
+:103030009BE10E94823DE091300BF0E0EE0FFF1F1C
+:10304000E250FF4B859194910F94776760910A1B32
+:1030500070910B1B882777FD8095982F0F9468BE81
+:103060002091D8023091D9024091DA025091DB02CE
+:103070000F94EDBC6B017C0120E030E848E953E49B
+:103080000F94C9BF18164CF0C092D802D092D90242
+:10309000E092DA02F092DB020CC080E090E8A8E94E
+:1030A000B3E48093D8029093D902A093DA02B0934C
+:1030B000DB0220E030E040E751E46091D8027091FB
+:1030C000D9028091DA029091DB020F94C6BD87FF8E
+:1030D0000CC080E090E0A0E7B1E48093D802909328
+:1030E000D902A093DA02B093DB0210920A1B10926D
+:1030F0000B1B10920C1B10920D1B42E061E081E152
+:103100009BE10E94823D88ED92E00F949566BC01A0
+:1031100081E19BE10F94AEB70F940453882371F0C3
+:1031200087E090E09093971B8093961B0F945747EE
+:1031300082E0FF90EF90DF90CF906CCEFF90EF9009
+:10314000DF90CF9008950F931F9381E08093BB0A87
+:10315000109277128091320B811108C080915E0B22
+:10316000811104C00F94DD030E9444F90E949BC2A8
+:10317000E091300BF0E0EE0FFF1FE855FE4B85911C
+:1031800094910F947E5182E045DE10926C0B60E0CA
+:103190008AE69BE00E9463BC0F94EFB46093860ABA
+:1031A0007093870A8093880A9093890A00918A0A0B
+:1031B00010918B0A20918C0A30918D0A601B710B43
+:1031C000820B930B00913B0B10913C0B20913D0B1C
+:1031D00030913E0B601B710B820B930B28EE33E09A
+:1031E00040E050E00F949DC210923B0B10923C0BBC
+:1031F00010923D0B10923E0B6091290B70912A0B9F
+:1032000080912B0B90912C0B0E940C5E0F945747D2
+:1032100081E08093FD1A1092FC1A82E090E0909376
+:10322000971B8093961B8091010188608093010118
+:103230009FB7F89480910201877F809302019FBF1E
+:103240001092CB0A1092CA0A1F910F91089540E084
+:1032500060E081E19BE10E94823DE091300BF0E073
+:10326000EE0FFF1FEE53FF4B859194910F947767FC
+:1032700042E062E081E19BE10E94823DE091300BFF
+:10328000F0E0EE0FFF1FE050FE4B859194910F94FC
+:10329000776743E062E081E19BE10E94823DE0913B
+:1032A000300BF0E0EE0FFF1FE25DFF4B8591949134
+:1032B0000F94776742E060E081E19BE10E94823DEC
+:1032C0006EEC78E081E19BE10F94AEB743E060E003
+:1032D00081E19BE10E94823D6EEC78E081E19BE11F
+:1032E0000F94AEB780910A1B90910B1BA0910C1B01
+:1032F000B0910D1B0397A105B10564F082E090E049
+:10330000A0E0B0E080930A1B90930B1BA0930C1BD2
+:10331000B0930D1B80910A1B90910B1BA0910C1B6D
+:10332000B0910D1B181619061A061B0664F081E0F1
+:1033300090E0A0E0B0E080930A1B90930B1BA09359
+:103340000C1BB0930D1B40910A1B4F5F60E081E1A5
+:103350009BE10E94823D6EE477E081E19BE10F9466
+:10336000AEB70F9404538823D9F080910A1B909133
+:103370000B1BA0910C1BB0910D1B0197A105B10572
+:1033800011F40F94574780910A1B90910B1BA09149
+:103390000C1BB0910D1B0297A105B10509F4D3CE0A
+:1033A00008959091D3029817D1F18093D302882386
+:1033B000B1F110920A1B10920B1B10920C1B109271
+:1033C0000D1B1092B81B0F94EFB4605D7A488F4FBD
+:1033D0009F4F6093F31A7093F41A8093F51A9093A9
+:1033E000F61A0F94EFB46150710981099109609345
+:1033F000FF1A7093001B8093011B9093021B0F9484
+:1034000066508091D5029091D6028D5D914019F45D
+:103410000F94425002C00F94DE4F82E0FBCC08951F
+:103420008F929F92AF92BF92CF92DF92EF92FF92D4
+:103430000F931F93CF93DF938C015B0180E0B1DF8B
+:103440000F94665040E060E081E19BE10E94823D84
+:103450007801812C912CC8010F94B23F882319F078
+:103460000F5F1F4FF8CFF8018491882309F467C0DC
+:10347000492D60E081E19BE10E94823DC8010F94EB
+:10348000FAC58431910508F084E17801E80EF11C59
+:10349000F3E0E7019F1214C0843191F4CE010F9440
+:1034A000B23F882311F02196F9CFFE018491882341
+:1034B00031F0E70122977E018824839401C0812C9A
+:1034C000FE018491882309F455C0CE010F94B23FC8
+:1034D000811150C0FE01849192ED980F923008F452
+:1034E00049C08C3209F446C096EC980F923008F42B
+:1034F00041C08F3309F43EC0813209F43BC00C1740
+:103500001D07A8F56E01F1E0CF1AD108C6010F948E
+:10351000B23F81112CC0E601F2CFF80164916E3701
+:1035200009F460E281E19BE10F94AFB70F5F1F4F99
+:103530000E151F0590F39394F4E09F128CCF882012
+:1035400069F00F94025043E063E181E19BE10E9446
+:10355000823D61E081E19BE10F94AFB7F50190827C
+:10356000811003C080E090E007C0C70105C0C0170C
+:10357000D107F1F27E01DCCFDF91CF911F910F9146
+:10358000FF90EF90DF90CF90BF90AF909F908F9083
+:1035900008954F925F926F927F928F929F92AF9217
+:1035A000BF92CF92DF92EF92FF92CF93DF93682E7C
+:1035B000592E462ED42E0E9434487C010F94EFB42D
+:1035C0004B015C01C090B81BE70134E6732E82E327
+:1035D00090E00E94DE5E442069F00F94EFB4681919
+:1035E00079098A099B09613375478105910510F0B6
+:1035F0008FEFB5C00F94F32B81E00E94BD5C8C2D42
+:10360000992787FD90952091B81B821B910927FD72
+:10361000939597FF03C09195819591090597ACF11A
+:10362000209709F097C043E060E081E19BE10E94B0
+:10363000823D8091B81BC81694F4DD2021F18DEFF6
+:1036400093E50F94776743E067E081E19BE10E9497
+:10365000823D8BEF93E50F947767D12C14C08C15C6
+:1036600094F4D11010C089EF93E50F94776743E08D
+:1036700067E081E19BE10E94823D87EF93E50F9433
+:103680007767DD24D394C090B81B0F94045388232C
+:10369000A9F00F9404538111FCCF6AE070E080E040
+:1036A00090E00F941EB50F9404538111FCCF209726
+:1036B00009F050C00F94C13F8D2D51C07A9409F08C
+:1036C00086CFE114F10441F0209711F4C62DD52DD9
+:1036D000CE010E943448EC01209709F076CF43E0F8
+:1036E00060E081E19BE10E94823DDD2021F085EFD9
+:1036F00093E50F94776743E061E081E19BE10E94ED
+:10370000823DE091300BF0E0EE0FFF1FE25DFF4BDA
+:10371000859194910F94776743E067E081E19BE1A5
+:103720000E94823DD11004C083EF93E50F94776728
+:1037300043E068E081E19BE10E94823DE091300B33
+:10374000F0E0EE0FFF1FE050FE4B859194910F9437
+:1037500077673BCFE114F10409F0BACFBDCFDF9119
+:10376000CF91FF90EF90DF90CF90BF90AF909F9060
+:103770008F907F906F905F904F900895BF92CF92FF
+:10378000DF92EF92FF92CF93DF93D62FC42F0E9448
+:10379000344842E0CC23D9F060E081E19BE10E9413
+:1037A000823D81EF93E50F947767E091300BF0E075
+:1037B000EE0FFF1FE25DFF4B859194910F947767A9
+:1037C00043E061E081E19BE10E94823D1AC061E03B
+:1037D00081E19BE10E94823DE091300BF0E0EE0F31
+:1037E000FF1FE25DFF4B859194910F94776743E053
+:1037F00060E081E19BE10E94823D8FEE93E50F94B2
+:103800007767E091300BF0E0EE0FFF1FE050FE4BCA
+:10381000859194910F9477670F94EFB46B017C01BD
+:10382000B090B81B84E090E090931602809315024C
+:10383000DD2369F00F94EFB46C197D098E099F099F
+:10384000613375478105910510F08FEF62C00F94C9
+:10385000F32B81E00E94BD5C2B2D332727FD309593
+:103860008091B81B281B310987FD339537FF03C0B2
+:10387000319521953109253031058CF142E060E028
+:1038800081E19BE10E94823D8091B81BB81694F4BF
+:10389000CC2319F18DEE93E50F94776743E060E058
+:1038A00081E19BE10E94823D8BEE93E50F94776767
+:1038B000C0E013C08B158CF4C1110FC089EE93E5E5
+:1038C0000F94776743E060E081E19BE10E94823DD5
+:1038D00087EE93E50F947767C1E0B090B81B0F9423
+:1038E0000453882309F4A4CF0F9404538111FCCF0F
+:1038F0006AE070E080E090E00F941EB50F940453EE
+:103900008111FCCF82E090E0909316028093150223
+:103910008C2FDF91CF91FF90EF90DF90CF90BF90F1
+:103920000895809101018460809301019FB7F8940C
+:10393000809102018460809302019FBF68EE73E072
+:1039400080E090E00F941EB59FB7F894809102013B
+:103950008B7F809302019FBFE2EEF0E4859194910A
+:103960000E94344888EE93E00E94DE5EFBCF0F9306
+:1039700040E061E086E598E501DF882341F061E001
+:1039800082E598E50E9411C30F94574709C001E0F2
+:1039900021E040E050E0BA0181E491E00F94FD4164
+:1039A00081E0FFDC82E08093D4020F9108954F9272
+:1039B0005F926F927F92AF92BF92CF92DF92EF921F
+:1039C000FF920F931F93CF93DF9341E068E97BE170
+:1039D0008FEF9FE00F94ED5080910A1B90910B1B8D
+:1039E000A0910C1BB0910D1B81309048A105B10531
+:1039F00040F010920A1B10920B1B10920C1B10929D
+:103A00000D1B80910A1B90910B1BA0910C1BB09178
+:103A10000D1BB695A7959795879540910F1B50E084
+:103A200060E070E084179507A607B70710F480934D
+:103A30000F1BE0900F1BD090101BD2FADD24D0F8A2
+:103A4000F12CC8EAD0E406EA10E4CC24C3948091B7
+:103A50000A1B90910B1BA0910C1BB0910D1BE11048
+:103A60003CC02091D4022223A1F0E091300BF0E081
+:103A7000EE0FFF1FE05DFD4B6591749123E002970F
+:103A8000A105B10510F443E001C040E28F2D0F9471
+:103A90005E40DD2009F457C080910A1B90910B1BFA
+:103AA000A0910C1BB0910D1B0297A105B10508F068
+:103AB0004AC00F94EE418DE591E0DF91CF911F91C7
+:103AC0000F91FF90EF90DF90CF90BF90AF907F90DD
+:103AD0006F905F904F900D94A94221E0E21233C0A5
+:103AE0002091D4022223C1F0E091300BF0E0EE0FE0
+:103AF000FF1FE654FF4B65917491B695A795979576
+:103B000087952EE70197A105B10511F44EE301C099
+:103B100040E28F2D0F945E40DD20A9F080910A1BBA
+:103B200090910B1BA0910C1BB0910D1BB695A79506
+:103B3000979587950197A105B10529F40F94EE415A
+:103B40008BEA91E044C080915E0B811150C082E00D
+:103B5000E81619F033E0B32E4CC08091D4028823CC
+:103B600001F1E091300BF0E0EE0FFF1FE65EFD4B40
+:103B70006591749180910A1B90910B1BA0910C1B75
+:103B8000B0910D1BB695A795979587952EE702974F
+:103B9000A105B10511F44EE301C040E28F2D0F9451
+:103BA0005E40DD20B9F280910A1B90910B1BA09121
+:103BB0000C1BB0910D1BB695A7959795879502970D
+:103BC000A105B10539F60F94EE418BED91E0DF913F
+:103BD000CF911F910F91FF90EF90DF90CF90BF900A
+:103BE000AF907F906F905F904F900D94274462E06C
+:103BF000B62E8091931B811158C0BE1055C0809184
+:103C0000D402882329F1E091300BF0E0EE0FFF1F82
+:103C1000E451FD4B6591749180910A1B90910B1BAF
+:103C2000A0910C1BB0910D1BB695A7959795879504
+:103C30004B2C512C612C712C20E284159505A60586
+:103C4000B70511F44EE301C040E28F2D0F945E40A2
+:103C5000DD2051F180910A1B90910B1BA0910C1B50
+:103C6000B0910D1BB695A795979587954B2D50E074
+:103C700060E070E084179507A607B707A9F40F94D2
+:103C8000EE4161E087E898E5DF91CF911F910F91B8
+:103C9000FF90EF90DF90CF90BF90AF907F906F90AC
+:103CA0005F904F900C9411C3B3942091E0028091E7
+:103CB0000A1B90910B1BA0910C1BB0910D1B2111A5
+:103CC0000EC0BE1058C02091D402222349F1E091C9
+:103CD000300BF0E0EE0FFF1FEE56FD4B0DC0BE1097
+:103CE0004AC02091D4022223D9F0E091300BF0E0B9
+:103CF000EE0FFF1FE257FD4B65917491B695A795A6
+:103D0000979587954B2C512C612C712C20E28415B2
+:103D10009505A605B70569F140E28F2D0F945E4029
+:103D2000DD2049F180910A1B90910B1BA0910C1B87
+:103D3000B0910D1BB695A795979587954B2D50E0A3
+:103D400060E070E084179507A607B707A1F40F9409
+:103D5000EE41DF91CF911F910F91FF90EF90DF9097
+:103D6000CF90BF90AF907F906F905F904F900D94E9
+:103D7000F7484EE3D2CFB3942091E10280910A1B21
+:103D800090910B1BA0910C1BB0910D1B222371F085
+:103D9000BE1058C02091D402222349F1E091300B8B
+:103DA000F0E0EE0FFF1FE054FD4B0DC0BE104AC007
+:103DB0002091D4022223D9F0E091300BF0E0EE0FF5
+:103DC000FF1FEC53FD4B65917491B695A7959795A0
+:103DD00087954B2C512C612C712C20E28415950574
+:103DE000A605B70569F140E28F2D0F945E40DD20F6
+:103DF00049F180910A1B90910B1BA0910C1BB09173
+:103E00000D1BB695A795979587954B2D50E060E0D3
+:103E100070E084179507A607B707A1F40F94EE4149
+:103E2000DF91CF911F910F91FF90EF90DF90CF9096
+:103E3000BF90AF907F906F905F904F900D949342A2
+:103E40004EE3D2CFB3948091981B811167C020912B
+:103E5000DF0280910A1B90910B1BA0910C1BB0916B
+:103E60000D1B21110EC0BE1058C02091D402222378
+:103E700049F1E091300BF0E0EE0FFF1FE450FD4BF5
+:103E80000DC0BE104AC02091D4022223D9F0E09187
+:103E9000300BF0E0EE0FFF1FE850FD4B6591749181
+:103EA000B695A795979587954B2C512C612C712C25
+:103EB00020E284159505A605B70569F140E28F2D2E
+:103EC0000F945E40DD2049F180910A1B90910B1BFD
+:103ED000A0910C1BB0910D1BB695A7959795879552
+:103EE0004B2D50E060E070E084179507A607B707F8
+:103EF000A1F40F94EE41DF91CF911F910F91FF90AC
+:103F0000EF90DF90CF90BF90AF907F906F905F90D9
+:103F10004F900D94D2484EE3D2CFB39420915D0BD5
+:103F200080910A1B90910B1BA0910C1BB0910D1B53
+:103F300021110EC0BE1058C02091D402222349F195
+:103F4000E091300BF0E0EE0FFF1FE255FF4B0DC08C
+:103F5000BE104AC02091D4022223D9F0E091300B48
+:103F6000F0E0EE0FFF1FE655FF4B65917491B6959B
+:103F7000A795979587954B2C512C612C712C20E29D
+:103F800084159505A605B70569F140E28F2D0F94BC
+:103F90005E40DD2049F180910A1B90910B1BA0919E
+:103FA0000C1BB0910D1BB695A795979587954B2D3A
+:103FB00050E060E070E084179507A607B707A1F40A
+:103FC0000F94EE41DF91CF911F910F91FF90EF90F1
+:103FD000DF90CF90BF90AF907F906F905F904F90A9
+:103FE0000D94DD464EE3D2CFB3942091981B80917F
+:103FF0000A1B90910B1BA0910C1BB0910D1B211162
+:104000000EC0BE1058C02091D402222349F1E09185
+:10401000300BF0E0EE0FFF1FEE50FF4B0DC0BE1057
+:104020004AC02091D4022223D9F0E091300BF0E075
+:10403000EE0FFF1FE251FF4B65917491B695A79566
+:10404000979587954B2C512C612C712C20E284156F
+:104050009505A605B70569F140E28F2D0F945E40E6
+:10406000DD2049F180910A1B90910B1BA0910C1B44
+:10407000B0910D1BB695A795979587954B2D50E060
+:1040800060E070E084179507A607B707A1F40F94C6
+:10409000EE41DF91CF911F910F91FF90EF90DF9054
+:1040A000CF90BF90AF907F906F905F904F900D94A6
+:1040B000F5464EE3D2CFB3948091931B81114CC04F
+:1040C00080915E0B811148C0BE1045C08091D40222
+:1040D000882329F1E091300BF0E0EE0FFF1FE85745
+:1040E000FC4B6591749180910A1B90910B1BA091E0
+:1040F0000C1BB0910D1BB695A795979587954B2CEA
+:10410000512C612C712C2EE784159505A605B70559
+:1041100011F44EE301C040E28F2D0F945E40DD208C
+:10412000D1F080910A1B90910B1BA0910C1BB091B8
+:104130000D1BB695A795979587954B2D50E060E0A0
+:1041400070E084179507A607B70729F40F94EE418E
+:1041500085EF91E03CCDB394BE1045C08091D40270
+:10416000882329F1E091300BF0E0EE0FFF1FE45AB5
+:10417000FD4B6591749180910A1B90910B1BA0914E
+:104180000C1BB0910D1BB695A795979587954B2C59
+:10419000512C612C712C2EE784159505A605B705C9
+:1041A00011F44EE301C040E28F2D0F945E40DD20FC
+:1041B000D1F080910A1B90910B1BA0910C1BB09128
+:1041C0000D1BB695A795979587954B2D50E060E010
+:1041D00070E084179507A607B70729F40F94EE41FE
+:1041E00081E791E0F4CCAA24A394AB0C2091300D8C
+:1041F00080910A1B90910B1BA0910C1BB0910D1B81
+:10420000222341F0AE104CC02091D4022223E9F0C9
+:10421000F80107C0AE1044C02091D4022223A9F0B7
+:10422000FE0165917491B695A795979587954A2C4F
+:10423000512C612C712C20E284159505A605B7053B
+:1042400069F140E28F2D0F945E40DD2049F18091AD
+:104250000A1B90910B1BA0910C1BB0910D1BB695E6
+:10426000A795979587954A2D50E060E070E08417F8
+:104270009507A607B707A1F40F94EE41DF91CF9100
+:104280001F910F91FF90EF90DF90CF90BF90AF9074
+:104290007F906F905F904F900D945F414EE3D2CF2F
+:1042A000B394B3948091921B882309F491C0BE10FB
+:1042B0003EC08091D4028823F1F080910A1B909136
+:1042C0000B1BA0910C1BB0910D1BB695A795979554
+:1042D00087954B2D50E060E070E02EE7841795073E
+:1042E000A607B70711F44EE301C040E26BE778E59B
+:1042F0008F2D0F945E40DD20D1F080910A1B9091AC
+:104300000B1BA0910C1BB0910D1BB695A795979513
+:1043100087954B2D50E060E070E084179507A60765
+:10432000B70729F40F94EE4183E092E050CCAA2421
+:10433000A394AB0CAE104AC08091D4028823F1F054
+:1043400080910A1B90910B1BA0910C1BB0910D1B2F
+:10435000B695A795979587954E2D50E060E070E053
+:1043600020E284179507A607B70711F44EE301C0B2
+:1043700040E269E678E58F2D0F945E40DD2031F153
+:1043800080910A1B90910B1BA0910C1BB0910D1BEF
+:10439000B695A795979587954A2D50E060E070E017
+:1043A00084179507A607B70789F40F94EE41DF91AC
+:1043B000CF911F910F91FF90EF90DF90CF90BF9022
+:1043C000AF907F906F905F904F90D1CAB394B394A9
+:1043D00040910A1B50910B1B60910C1B70910D1B9F
+:1043E00076956795579547958B2D90E0A0E0B0E0C6
+:1043F000481759076A077B0788F08B2D90E0880FD4
+:10440000991F0197AA2797FDA095BA2F80930A1BA1
+:1044100090930B1BA0930C1BB0930D1B40910A1B98
+:1044200050910B1B60910C1B70910D1B769567953D
+:104430005795479580910F1B90E00396242F30E00D
+:10444000821793075CF48DEF840F80930F1BC0924B
+:10445000D4027CEFE72EE40EFF24FA94F394E39465
+:1044600023E02F1508F0F3CADF91CF911F910F9130
+:10447000FF90EF90DF90CF90BF90AF907F906F90C4
+:104480005F904F900895CF93DF93E091300BF0E071
+:10449000EE0FFF1FE853FE4B8591949141E060E0E1
+:1044A0006DD9882339F088E090E09093971B809332
+:1044B000961B26C0E091300BF0E0EE0FFF1FEC538F
+:1044C000FE4B859194910E943448C4E1D0E084E68B
+:1044D00090E00E94DE5E0F940453882379F00F94DD
+:1044E00004538111FCCF6AE070E080E090E00F940B
+:1044F0001EB50F9404538111FCCF02C0219739F7E8
+:104500000F94574781E0DF91CF910D94D1998F920D
+:104510009F92AF92BF92CF92DF92EF92FF920F9352
+:104520001F93CF93DF930F94665040E060E081E1EA
+:104530009BE10E94823D6EE477E081E19BE10F9474
+:10454000AEB70AE412E0F7EAEF2EFFE0FF2EC0E07C
+:10455000D0E04C2F61E081E19BE10E94823D67E564
+:1045600079E081E19BE10F94AEB74AE050E0BE01F3
+:1045700081E19BE10F9455B868E975E081E19BE129
+:104580000F94AEB7B801C7010F94A550F801608130
+:1045900071810E5F1F4F605371094AE050E081E165
+:1045A0009BE10F9455B8219682E0E80EF11CC430CF
+:1045B000D10579F60091B81B112707FD1095C0E0D1
+:1045C000D0E00F94F32B81E00E94BD5C2091B81BDA
+:1045D000332727FD3095C801821B930B97FF03C03B
+:1045E00091958195910903970CF45BC020173107D1
+:1045F0000CF42197021713070CF42196C430D1054F
+:104600003CF4CF3F9FEFD90729F4C0E0D0E002C0CF
+:10461000C3E0D0E040E060E081E19BE10E94823DA8
+:104620006EEC78E081E19BE10F94AEB741E060E091
+:1046300081E19BE10E94823D6EEC78E081E19BE1AB
+:104640000F94AEB742E060E081E19BE10E94823DC1
+:104650006EEC78E081E19BE10F94AEB743E060E05F
+:1046600081E19BE10E94823D6EEC78E081E19BE17B
+:104670000F94AEB74C2F60E081E19BE10E94823D38
+:104680006EE477E081E19BE10F94AEB70091B81B37
+:10469000112707FD109564E670E080E090E00F942C
+:1046A0001EB50F940453882309F48BCF0F94045341
+:1046B0008111FCCF6AE070E080E090E00F941EB5BD
+:1046C0000F9404538111FCCF0F9466506E01CC0CF3
+:1046D000DD1CF601E65BFD4F5F017F010F94F32BBC
+:1046E00081E00E94BD5C41E061E081E19BE10E94CC
+:1046F000823D67E579E081E19BE10F94AEB74AE046
+:1047000050E0BE0181E19BE10F9455B868E975E086
+:1047100081E19BE10F94AEB741E06DE081E19BE167
+:104720000E94823DF50160817181605371094AE008
+:1047300050E081E19BE10F9455B88091B81B992717
+:1047400087FD90959801281B390B37FF03C03195E1
+:1047500021953109233031050CF443C080179107AE
+:10476000E4F4F7018081918101979183808341E096
+:104770006DE081E19BE10E94823DF70160817181E2
+:10478000605371094AE050E081E19BE10F9455B814
+:104790000091B81B112707FD10958091B81B992730
+:1047A00087FD909508171907E4F4F701808191813E
+:1047B00001969183808341E06DE081E19BE10E945D
+:1047C000823DF70160817181605371094AE050E0D8
+:1047D00081E19BE10F9455B80091B81B112707FDAB
+:1047E000109564E670E080E090E00F941EB50F94A1
+:1047F0000453882309F472CF0F9404538111FCCF22
+:104800006AE070E080E090E00F941EB50F940453CE
+:104810008111FCCFB601665B7D4FC6018955904F73
+:104820000F94945040E061E08FEA93E50F94BE9BB3
+:10483000882309F456C081E00F94D1990F946650F3
+:104840000091B81B112707FD10954C2F60E081E106
+:104850009BE10E94823D6EE477E081E19BE10F9451
+:10486000AEB76AE4C62E62E0D62E77EAA72E7FE0C6
+:10487000B72EE12CF12C4E2D61E081E19BE10E94ED
+:10488000823D67E579E081E19BE10F94AEB74AE0B4
+:1048900050E0B70181E19BE10F9455B868E975E0FC
+:1048A00081E19BE10F94AEB7B601C5010F94A5500D
+:1048B000F60160817181F2E0CF0ED11C6053710965
+:1048C0004AE050E081E19BE10F9455B88FEFE81A80
+:1048D000F80A92E0A90EB11CE4E0EE16F10459F6D4
+:1048E00070CEDF91CF911F910F91FF90EF90DF90ED
+:1048F000CF90BF90AF909F908F900895EF92FF92CE
+:104900000F931F93CF93DF93F82EE92E0E94344824
+:10491000EC0111E0009709F410E00F94025024E03C
+:1049200030E0309316022093150211110BC043E0C2
+:1049300063E181E19BE10E94823D62E081E19BE1D4
+:104940000F94AFB704E682E390E00E94DE5E0F941E
+:104950000453882311F10F9404538111FCCF6AE0B2
+:1049600070E080E090E00F941EB50F940453811125
+:10497000FCCF82E090E090931602809315020F9492
+:10498000C13F81E00F94D19982E0DF91CF911F91D7
+:104990000F91FF90EF900D940A970150A1F611230B
+:1049A00031F2209711F4CF2DDE2DCE010E94344834
+:1049B000EC01009709F0B9CF43E063E181E19BE1AD
+:1049C0000E94823D62E081E19BE10F94AFB7ADCFE1
+:1049D000CF93DF93EC01E091300BCF3F8FEFD807FF
+:1049E00031F4F0E0EE0FFF1FEC5BFC4B4CC0CE3F10
+:1049F0008FEFD80779F4F0E0EE0FFF1F662379F10F
+:104A0000623011F0673019F4EC5AFC4B3CC0E05BAB
+:104A1000FC4B39C061110EC0E091300BC130D105A3
+:104A200039F1C230D10551F1CD2BE1F0F0E0EE0FBC
+:104A3000FF1F15C0F0E0EE0FFF1F623011F067306E
+:104A400019F4E85CFC4B02C0EC5CFC4B8591949142
+:104A500055DF1C161D0604F3DF91CF910895E45B2A
+:104A6000FC4B11C0F0E0EE0FFF1FE85BFC4B0BC0EE
+:104A7000F0E0EE0FFF1FE45CFC4B05C0F0E0EE0F32
+:104A8000FF1FE05CFC4B85919491DF91CF9136CF75
+:104A900087EF9FE00F9444CA8F3F49F46FEF87EF91
+:104AA0009FE00F9456CA80E090E00D949F82E091C1
+:104AB000300BF0E0EE0FFF1FEA5AFF4B8591949107
+:104AC00040E060E00F94C99A8111E8CF0F945747F6
+:104AD00081E00F94D19982E00D940A976F927F92B2
+:104AE0008F929F92BF92DF92EF92FF920F931F934C
+:104AF000CF93DF9380910A1B90910B1BA0910C1B0D
+:104B0000B0910D1B81309048A105B10540F0109285
+:104B10000A1B10920B1B10920C1B10920D1B809104
+:104B20000A1B90910B1BA0910C1BB0910D1BB6950D
+:104B3000A7959795879540910F1B50E060E070E036
+:104B400084179507A607B70710F480930F1BC09131
+:104B50000F1BB090101BB2FABB24B0F8D12CD1E0DF
+:104B60005EE1852E52E4952E68E5662E61E4762E90
+:104B70000EE813E472E8E72E70E4F72EC11140C08E
+:104B80008091D4028823E1F0E091300BF0E0EE0F49
+:104B9000FF1FE05DFD4B6591749180910A1B909120
+:104BA0000B1BA0910C1BB0910D1B23E00297A105DC
+:104BB000B10510F443E001C040E28D2D0F945E403A
+:104BC000BB20F1F080910A1B90910B1BA0910C1B54
+:104BD000B0910D1B0297A105B10590F40F94EE4121
+:104BE0008DE591E0DF91CF911F910F91FF90EF90B4
+:104BF000DF90BF909F908F907F906F900D94A9420F
+:104C00008091931B8111DAC240910A1B50910B1BBA
+:104C100060910C1B70910D1BC13009F03BC080915D
+:104C2000D4028823A1F0F701859194917695679538
+:104C30005795479520E2413051056105710511F402
+:104C40004EE301C040E2BC018D2D0F945E40BB20BD
+:104C500009F40FC280910A1B90910B1BA0910C1BB1
+:104C6000B0910D1BB695A795979587950197A105CE
+:104C7000B10509F0FEC10F94EE41DF91CF911F9174
+:104C80000F91FF90EF90DF90BF909F908F907F905B
+:104C90006F90FECEC230B9F58091D4028823D1F056
+:104CA000E091300BF0E0EE0FFF1FE657FF4B8591D0
+:104CB000949176956795579547952EE74230510523
+:104CC0006105710511F44EE301C040E2BC018D2D78
+:104CD0000F945E40BB2009F4CCC180910A1B9091D7
+:104CE0000B1BA0910C1BB0910D1BB695A79597952A
+:104CF00087950297A105B10509F0BBC10F94EE415C
+:104D000081E092E04DC2C33091F58091D4028823B6
+:104D1000A1F0F801859194917695679557954795FF
+:104D200020E2433051056105710511F44EE301C0E5
+:104D300040E2BC018D2D0F945E40BB2009F499C167
+:104D400080910A1B90910B1BA0910C1BB0910D1B25
+:104D5000B695A795979587950397A105B10509F095
+:104D600088C10F94EE4161E088E199E5D2C1C43079
+:104D700009F03CC08091D4028823A1F0F301859111
+:104D80009491769567955795479520E24430510563
+:104D90006105710511F44EE301C040E2BC018D2DA7
+:104DA0000F945E40BB2009F464C180910A1B90916E
+:104DB0000B1BA0910C1BB0910D1BB695A795979559
+:104DC00087950497A105B10509F053C10F94EE41F1
+:104DD000DF91CF911F910F91FF90EF90DF90BF90E7
+:104DE0009F908F907F906F900D94267FC53009F033
+:104DF00042C08091D4028823D1F0E091300BF0E0E2
+:104E0000EE0FFF1FE45DFC4B8591949176956795BD
+:104E10005795479520E2453051056105710511F41C
+:104E20004EE301C040E2BC018D2D0F945E40BB20DB
+:104E300009F41FC180910A1B90910B1BA0910C1BC0
+:104E4000B0910D1BB695A795979587950597A105E8
+:104E5000B10509F00EC10F94EE41DF91CF911F9182
+:104E60000F91FF90EF90DF90BF909F908F907F9079
+:104E70006F900D947447C630B9F58091D4028823A1
+:104E8000D1F0E091300BF0E0EE0FFF1FEE57FD4B3D
+:104E90008591949176956795579547952EE746307D
+:104EA00051056105710511F44EE301C040E2BC01FA
+:104EB0008D2D0F945E40BB2009F4DBC080910A1B4E
+:104EC00090910B1BA0910C1BB0910D1BB695A79553
+:104ED000979587950697A105B10509F0CAC00F946B
+:104EE000EE4185E192E05CC1C73089F58091D40242
+:104EF0008823A1F0F4018591949176956795579553
+:104F000047952EE7473051056105710511F44EE3D1
+:104F100001C040E2BC018D2D0F945E40BB2009F41E
+:104F2000A8C080910A1B90910B1BA0910C1BB09103
+:104F30000D1BB695A795979587950797A105B10580
+:104F400009F097C00F94EE418DEF91E029C1C83070
+:104F5000B9F58091D4028823D1F0E091300BF0E0D4
+:104F6000EE0FFF1FEA58FC4B85919491769567955B
+:104F7000579547952EE7483051056105710511F4A5
+:104F80004EE301C040E2BC018D2D0F945E40BB207A
+:104F900009F46FC080910A1B90910B1BA0910C1B10
+:104FA000B0910D1BB695A795979587950897A10584
+:104FB000B10509F05EC00F94EE4183EF91E0F0C0BF
+:104FC000C930A9F58091D4028823D1F0E091300B4B
+:104FD000F0E0EE0FFF1FE252FE4B85919491769523
+:104FE0006795579547952EE749305105610571053D
+:104FF00011F44EE301C040E2BC018D2D0F945E40E0
+:10500000BB20B9F180910A1B90910B1BA0910C1B46
+:10501000B0910D1BB695A795979587950997A10512
+:10502000B10539F50F94EE418DE092E0B9C0CA3078
+:10503000B9F58091D4028823D1F0E091300BF0E0F3
+:10504000EE0FFF1FEA50FF4B85919491769567957F
+:10505000579547952EE74A3051056105710511F4C2
+:105060004EE301C040E2BC018D2D0F945E40B110B3
+:1050700002C02DE0A4C080910A1B90910B1BA0914F
+:105080000C1BB0910D1BB695A795979587950A9720
+:10509000A105B10571F70F94EE4181EC91E080C05C
+:1050A000CB3009F044C08091D4028823D1F0E09144
+:1050B000300BF0E0EE0FFF1FE85DFC4B8591949103
+:1050C000769567955795479520E24B3051056105D8
+:1050D000710511F44EE301C040E2BC018D2D0F9427
+:1050E0005E40BB2031F280910A1B90910B1BA09176
+:1050F0000C1BB0910D1BB695A795979587950B97AF
+:10510000A105B10509F0B5CF0F94EE4161E084E14E
+:1051100099E5DF91CF911F910F91FF90EF90DF9074
+:10512000BF909F908F907F906F900C9411C3CC3064
+:1051300009F09FCF8091D4028823D1F0E091300B09
+:10514000F0E0EE0FFF1FE45EFC4BA591B491769565
+:105150006795579547952EE74C30510561057105C8
+:1051600011F44EE301C040E2BD018D2D0F945E406D
+:10517000BB2009F47ECF80910A1B90910B1BA0915C
+:105180000C1BB0910D1BB695A795979587950C971D
+:10519000A105B10509F06DCF0F94EE4183ED91E0CB
+:1051A000DF91CF911F910F91FF90EF90DF90BF9013
+:1051B0009F908F907F906F900D94274421E0809175
+:1051C0000A1B90910B1BA0910C1BB0910D1BB69567
+:1051D000A79597958795422F50E060E070E084177F
+:1051E0009507A607B70788F0822F90E0880F991FD0
+:1051F0000197AA2797FDA095BA2F80930A1B909339
+:105200000B1BA0930C1BB0930D1B40910A1B5091DC
+:105210000B1B60910C1B70910D1B76956795579534
+:10522000479580910F1B90E00396242F30E0821762
+:10523000930754F48DEF840F80930F1BD093D40207
+:10524000CCEFC40FDD24DA94D394CF5F83E08D15C7
+:1052500008F094CCDF91CF911F910F91FF90EF90C8
+:10526000DF90BF909F908F907F906F900895CF9226
+:10527000DF92EF92FF921F93CF93DF930F944250F0
+:105280000E9449F980E69FE00F944CCA6B017C01B3
+:1052900080E00F94D1990F946650E091300BF0E0CC
+:1052A000EE0FFF1FE65DFF4B859194910F9477679A
+:1052B000E091300BF0E0EE0FFF1FE85AFD4B4591F7
+:1052C000549161E080E00F94507DE091300BF0E06C
+:1052D000EE0FFF1FE658FE4B4591549162E080E0CF
+:1052E0000F94507DC6E1DBE011E020E030E048E4BF
+:1052F00053E4688179818A819B810F94C6BD87FFC1
+:1053000021C041E254E5612F8BE00F94507D48812C
+:1053100059816A817B8122E030E081E19BE10F9439
+:1053200046B920E030E0A901688179818A819B81BA
+:105330000F94C6BD881F8827881F4EE154E5612F52
+:10534000805F04C04AE154E5612F8BE00F94507DEB
+:1053500024961F5F133049F684EF91E00E94DE5ED1
+:1053600084E090E090931602809315020F9404530A
+:10537000811105C084E690E00E94DE5EF7CF84EFE5
+:1053800091E00E94DE5E0F946650E091300BF0E0F9
+:10539000EE0FFF1FE45DFD4B859194910F947767AD
+:1053A00020E030E048EC52E4C701B6010F94C6BDDE
+:1053B00087FF23C040E06FE081E19BE10E94823DD6
+:1053C00020E030E044E353E4C701B6010F949BC0F2
+:1053D0002BED3FE049E450E40F94CDBDAB01BC019F
+:1053E00022E030E081E19BE10F9446B96DEF78E077
+:1053F00081E19BE10F94AEB706C046E154E560E061
+:1054000080E10F94507D41E054E561E080E00F942D
+:10541000507DE091300BF0E0EE0FFF1FE651FF4BA7
+:105420004591549162E080E00F94507D40E054E556
+:1054300062E08FE00F94507D20E030E044E353E4DD
+:1054400060913A0670913B0680913C0690913D0632
+:105450000F949BC02BED3FE049E450E40F94CDBD89
+:10546000AB01BC0122E030E081E19BE10F9446B941
+:105470006DEF78E081E19BE10F94AEB7E091300BE6
+:10548000F0E0EE0FFF1FE650FF4B4591549163E0B3
+:1054900080E00F94507D4FEF53E563E08FE00F9471
+:1054A000507D20E030E044E353E460913606709193
+:1054B000370680913806909139060F949BC02BEDEA
+:1054C0003FE049E450E40F94CDBDAB01BC0122E0C4
+:1054D00030E081E19BE10F9446B96DEF78E081E126
+:1054E0009BE10F94AEB784EF91E00E94DE5E0F94D3
+:1054F0000453811103C084E690E0F7CF81E090E08F
+:10550000909316028093150284EF91E00E94DE5E74
+:105510000F94DE4F0F94574781E00F94D19982E0AA
+:10552000DF91CF911F91FF90EF90DF90CF900D947E
+:105530000A978F929F92AF92BF92CF92DF92EF9293
+:10554000FF920F931F93CF93DF9380919B1B882330
+:1055500021F09091D4029230B1F581E080939B1BB1
+:105560008091300D882339F06DE97BE18AE69BE07C
+:105570000E94B1C101C080E080939C1B8823E9F1A7
+:105580008091A01B1F928F9380919F1B1F928F93DE
+:1055900080919E1B1F928F9380919D1B1F928F93D2
+:1055A00080E19AE59F938F9381EA9BE19F938F938C
+:1055B0000F9418C88DB79EB70C960FB6F8949EBF7F
+:1055C0000FBE8DBF1AC090919C1B9923B1F0909192
+:1055D0009D1B911112C090919E1B91110EC0909134
+:1055E0009F1B91110AC09091A01B911106C08F5F63
+:1055F00080939B1B803109F412C580910A1B909106
+:105600000B1BA0910C1BB0910D1B81309048A10584
+:10561000B10540F010920A1B10920B1B10920C1B4C
+:1056200010920D1B80910A1B90910B1BA0910C1BDB
+:10563000B0910D1BB695A7959795879540910F1B37
+:1056400050E060E070E084179507A607B70710F4F4
+:1056500080930F1B00910F1BF090101BF2FAFF2498
+:10566000F0F810E0C0E7D2E4EE24E39440910A1B86
+:1056700050910B1B60910C1B70910D1B01113CC0D4
+:105680008091D4028823B1F0E091300BF0E0EE0F6E
+:10569000FF1FE05DFD4B8591949123E04230510561
+:1056A0006105710510F443E001C040E2BC01812FA7
+:1056B0000F945E40FF2009F457C280910A1B90911D
+:1056C0000B1BA0910C1BB0910D1B0297A105B105FE
+:1056D00008F04AC20F94EE418DE591E0DF91CF9141
+:1056E0001F910F91FF90EF90DF90CF90BF90AF9000
+:1056F0009F908F900D94A942013059F58091D4026A
+:10570000882391F0769567955795479523E041302A
+:1057100051056105710511F443E001C040E266E006
+:105720007AE5812F0F945E40FF2009F41DC280911D
+:105730000A1B90910B1BA0910C1BB0910D1BB695F1
+:10574000A795979587950197A105B10509F00CC21A
+:10575000C1CF023059F58091D402882391F076951B
+:1057600067955795479523E04230510561057105CE
+:1057700011F443E001C040E266EF79E5812F0F9418
+:105780005E40FF2009F4F0C180910A1B90910B1B31
+:10579000A0910C1BB0910D1BB695A7959795879579
+:1057A0000297A105B10509F0DFC194CF033099F547
+:1057B0008091D4028823D1F0E091300BF0E0EE0F1D
+:1057C000FF1FE056FE4B859194917695679557950E
+:1057D000479523E0433051056105710511F443E01D
+:1057E00001C040E2BC01812F0F945E40FF2009F40C
+:1057F000BBC180910A1B90910B1BA0910C1BB09117
+:105800000D1BB695A795979587950397A105B105AB
+:1058100009F0AAC15FCF043099F58091D4028823A2
+:10582000D1F0E091300BF0E0EE0FFF1FE456FE4B9D
+:1058300085919491769567955795479523E04430E7
+:1058400051056105710511F443E001C040E2BC015E
+:10585000812F0F945E40FF2009F486C180910A1BBE
+:1058600090910B1BA0910C1BB0910D1BB695A795A9
+:10587000979587950497A105B10509F075C12ACFC1
+:10588000053099F58091D4028823D1F0E091300B56
+:10589000F0E0EE0FFF1FE856FE4B85919491769550
+:1058A00067955795479523E045305105610571058A
+:1058B00011F443E001C040E2BC01812F0F945E402F
+:1058C000FF2009F451C180910A1B90910B1BA091FC
+:1058D0000C1BB0910D1BB695A795979587950597CD
+:1058E000A105B10509F040C1F5CE063059F580910A
+:1058F000D402882391F0769567955795479523E0D4
+:10590000463051056105710511F443E001C040E2E4
+:1059100069EE79E5812F0F945E40FF2009F424C1E0
+:1059200080910A1B90910B1BA0910C1BB0910D1B39
+:10593000B695A795979587950697A105B10509F0A6
+:1059400013C1C8CE073059F58091D402882391F055
+:10595000769567955795479523E047305105610542
+:10596000710511F443E001C040E26EED79E5812F4D
+:105970000F945E40FF2009F4F7C080910A1B9091BC
+:105980000B1BA0910C1BB0910D1BB695A79597957D
+:1059900087950797A105B10509F0E6C09BCE0830B1
+:1059A00059F58091D402882391F0769567955795A3
+:1059B000479523E0483051056105710511F443E036
+:1059C00001C040E265ED79E5812F0F945E40FF2034
+:1059D00009F4CAC080910A1B90910B1BA0910C1B6B
+:1059E000B0910D1BB695A795979587950897A1053A
+:1059F000B10509F0B9C06ECE093059F58091D402D5
+:105A0000882391F0769567955795479523E049301F
+:105A100051056105710511F443E001C040E26BECF2
+:105A200079E5812F0F945E40FF2009F49DC080919D
+:105A30000A1B90910B1BA0910C1BB0910D1BB695EE
+:105A4000A795979587950997A105B10509F08CC091
+:105A500041CE0A3059F58091D402882391F0769591
+:105A600067955795479523E04A30510561057105C3
+:105A700011F443E001C040E26EEB79E5812F0F9411
+:105A80005E40FF2009F470C080910A1B90910B1BAF
+:105A9000A0910C1BB0910D1BB695A7959795879576
+:105AA0000A97A105B10509F05FC014CE0B3089F546
+:105AB0008091D4028823D1F0E091300BF0E0EE0F1A
+:105AC000FF1FE051FD4B8591949176956795579511
+:105AD000479523E04B3051056105710511F443E012
+:105AE00001C040E2BC01812F0F945E40FF20E1F134
+:105AF00080910A1B90910B1BA0910C1BB0910D1B68
+:105B0000B695A795979587950B97A105B10561F572
+:105B1000E1CD0C3049F58091D402882391F076953F
+:105B200067955795479523E04C3051056105710500
+:105B300011F443E001C040E262EB79E5812F0F945C
+:105B40005E40FF2089F080910A1B90910B1BA09171
+:105B50000C1BB0910D1BB695A795979587950C9743
+:105B6000A105B10509F4B6CD80919C1B882309F4E9
+:105B70008BC080910A1B90910B1BA0910C1BB091C4
+:105B80000D1B0D3059F52091D402222389F0B695D2
+:105B9000A7959795879523E00D97A105B10511F479
+:105BA00043E001C040E265EA79E5812F0F945E4051
+:105BB000F11003C0A0E1CA2E69C080910A1B909128
+:105BC0000B1BA0910C1BB0910D1BB695A79597953B
+:105BD00087950D97A105B10569F77CCD0E3051F57C
+:105BE0002091D402222389F0B695A79597958795A1
+:105BF00023E00E97A105B10511F443E001C040E296
+:105C000063E979E5812F0F945E40FF2009F47AC0A3
+:105C100080910A1B90910B1BA0910C1BB0910D1B46
+:105C2000B695A795979587950E97A105B10509F0AB
+:105C300069C050CD0F3009F0BDCF2091D40222238E
+:105C400071F0B695A795979587950F97A105B10522
+:105C500011F463E001C060E2812F0F941C49FF2022
+:105C600009F450C080910A1B90910B1BA0910C1B52
+:105C7000B0910D1BB695A795979587950F97A105A0
+:105C8000B10509F03FC026CD4DE0C42EC0123CC086
+:105C90008091D4028823F1F080910A1B90910B1B14
+:105CA000A0910C1BB0910D1BB695A7959795879564
+:105CB0004C2D50E060E070E023E084179507A607C4
+:105CC000B70711F443E001C040E266E879E5812FAF
+:105CD0000F945E40FF20C1F080910A1B90910B1B36
+:105CE000A0910C1BB0910D1BB695A7959795879524
+:105CF0004C2D50E060E070E084179507A607B707C9
+:105D000019F4E8CCF0E1CF2EDD24D394DC0C8091A3
+:105D10006C0B811158C080915F0B811154C0D0125F
+:105D20004FC08091D402882329F1E091300BF0E03C
+:105D3000EE0FFF1FEA5CFF4B6591749180910A1B87
+:105D400090910B1BA0910C1BB0910D1BB695A795C4
+:105D5000979587958D2C912CA12CB12C20E288153C
+:105D60009905AA05BB0511F44EE301C040E2812F5D
+:105D70000F945E40FF2021F180910A1B90910B1B34
+:105D8000A0910C1BB0910D1BB695A7959795879583
+:105D90004D2D50E060E070E084179507A607B70727
+:105DA00079F40F94EE41DF91CF911F910F91FF9005
+:105DB000EF90DF90CF90BF90AF909F908F9057CA99
+:105DC00032E0D32EDC0CD0123FC08091D402882365
+:105DD000F9F0FE016591749180910A1B90910B1B63
+:105DE000A0910C1BB0910D1BB695A7959795879523
+:105DF0008D2C912CA12CB12C2EE788159905AA0584
+:105E0000BB0511F44EE301C040E2812F0F945E40C8
+:105E1000FF20D1F080910A1B90910B1BA0910C1BCD
+:105E2000B0910D1BB695A795979587954D2D50E090
+:105E300060E070E084179507A607B70729F40F9470
+:105E4000EE4185E391E085C0CC24C394CD0CC01213
+:105E50003EC08091D4028823F1F080910A1B90917A
+:105E60000B1BA0910C1BB0910D1BB695A795979598
+:105E70008795402F50E060E070E02EE7841795078B
+:105E8000A607B70711F44EE301C040E26AE779E5DF
+:105E9000812F0F945E40FF20D1F080910A1B9091DA
+:105EA0000B1BA0910C1BB0910D1BB695A795979558
+:105EB00087954C2D50E060E070E084179507A607A9
+:105EC000B70729F40F94EE4189E391E042C062E004
+:105ED000C62ECD0CC0124BC08091D4028823F1F0A5
+:105EE00080910A1B90910B1BA0910C1BB0910D1B74
+:105EF000B695A79597958795402F50E060E070E0A4
+:105F00002EE784179507A607B70711F44EE301C0E3
+:105F100040E26DE679E5812F0F945E40FF2039F174
+:105F200080910A1B90910B1BA0910C1BB0910D1B33
+:105F3000B695A795979587954C2D50E060E070E059
+:105F400084179507A607B70791F40F94EE4183EBEA
+:105F500091E0DF91CF911F910F91FF90EF90DF9033
+:105F6000CF90BF90AF909F908F900D94274423E0E7
+:105F70002D0D40910A1B50910B1B60910C1B7091D1
+:105F80000D1B7695679557954795822F90E0A0E079
+:105F9000B0E0481759076A077B0788F0822F90E026
+:105FA000880F991F0197AA2797FDA095BA2F809374
+:105FB0000A1B90930B1BA0930C1BB0930D1B4091DD
+:105FC0000A1B50910B1B60910C1B70910D1B769559
+:105FD00067955795479580910F1B90E00396242F66
+:105FE00030E0821793074CF48DEF840F80930F1BE2
+:105FF000E092D4020CEF040F1FEF1F5F0F5F14300D
+:1060000008F434CBDF91CF911F910F91FF90EF9067
+:10601000DF90CF90BF90AF909F908F900895109297
+:106020009B1BEBCABF92CF92DF92EF92FF920F932E
+:106030001F93CF93DF93E090B81BFF24E7FCF0940D
+:106040000F946650E091300BF0E0EE0FFF1FE05F21
+:10605000FC4B859194910F94776741E060E081E17A
+:106060009BE10E94823D6EE477E081E19BE176D77F
+:1060700011E0CAECD2E49AECC92E92E4D92EFE01CA
+:1060800045915491612F81E00F94507D1F5F143032
+:1060900091F784E090E09093160280931502BB2460
+:1060A000B394C0E0D0E001E010E0F6018591949156
+:1060B0000F94FAC562E0680F402F81E19BE10E94D6
+:1060C000823DB8016C0F7D1F4AE050E081E19BE109
+:1060D000ECD70F5F1F4F0430110539F70F94F32BE6
+:1060E00081E00E94BD5C6091B81B772767FD7095C9
+:1060F0009701261B370B37FF03C0319521953109D6
+:10610000253031050CF47CC06E157F050CF4BA9473
+:10611000E616F7060CF4B39483E08B15E4F42097AD
+:1061200009F098C00F946650E091300BF0E0EE0F4C
+:10613000FF1FE05FFC4B859194910F947767C1E05E
+:10614000F601459154916C2F81E00F94507DCF5F03
+:10615000C430B1F77DC01B14ECF02097C9F0219733
+:106160000F946650E091300BF0E0EE0FFF1FE05F00
+:10617000FC4B859194910F94776711E0F60145915E
+:106180005491612F81E00F94507D1F5F1430B1F75F
+:10619000BB24B39441E060E081E19BE10E94823D39
+:1061A0006EEC78E081E19BE1D9D642E060E081E1EC
+:1061B0009BE10E94823D6EEC78E081E19BE1CED6CE
+:1061C00043E060E081E19BE10E94823D6EEC78E07B
+:1061D00081E19BE1C3D64B2D60E081E19BE10E9410
+:1061E000823D6EE477E081E19BE1B8D6E090B81B98
+:1061F000FF24E7FCF09464E670E080E090E01ED4B9
+:106200000F940453882309F44ECF82E00F940A9729
+:106210000F9404538111FCCF6AE070E080E090E0BD
+:106220000DD40F9404538111FCCF82E090E0909341
+:106230001602809315028C2F8B0D8150DF91CF9128
+:106240001F910F91FF90EF90DF90CF90BF90089536
+:10625000C1E0D0E013E0B12E9DCF682F81E19BE13A
+:106260000C94444080E59AE50895982F9F7D51F065
+:10627000893041F08A3031F091E08D3009F090E0C2
+:10628000892F089581E008955F926F927F928F9297
+:106290009F92AF92BF92CF92DF92EF92FF920F93B5
+:1062A0001F93CF93DF9300D01F92CDB7DEB7582E48
+:1062B0008B01682E792E4301F30181913F0120ED7E
+:1062C000280F2A30C0F38E3211F0712CC6C06F0136
+:1062D0005601F60181916F0120ED280F2A30C0F39D
+:1062E0008E3299F79F017901F90140812F5F3F4F6D
+:1062F00080ED840F8A30B8F3842F4B839C83B5DF05
+:106300004B819C81811102C04D32F9F61A821982AB
+:106310004AE050E0BE016F5F7F4F852D0F949EC411
+:10632000F8017183608389819A818815990569F6DE
+:106330004AE050E0BE016F5F7F4FC3010F949EC4DF
+:10634000F8017383628389819A818A159B0509F01C
+:10635000BCCF4AE050E0BE016F5F7F4FC6010F9493
+:106360009EC4F80175836483A980BA80AE14BF040B
+:1063700009F0ABCF8FE790E0978386836701FFEF4B
+:10638000CF1ADF0AF70180818D3201F546017401D1
+:10639000FFEF8F1A9F0AF701808167DF782E88232D
+:1063A000B1F3EC18FD089E2C9701332723303105FB
+:1063B00081F443E050E062E47AE5C6010F941BC625
+:1063C000892B41F5F8011782168247C07724739410
+:1063D00044C02530310561F445E050E06CE37AE5D6
+:1063E000C6010F941BC6892BA9F481E090E00EC072
+:1063F0002430310579F444E050E067E37AE5C601E2
+:106400000F941BC6892B31F482E090E0F80197834A
+:10641000868323C08EEF8E0D823008F056CFF501B3
+:106420008181823709F051CF8281833609F04DCFC7
+:10643000F2E09F1203C083E090E0E8CFF5012381F2
+:1064400080ED820F8A3008F040CF332727FD30954A
+:106450002E523109F80137832683872D0F900F9034
+:106460000F900F90DF91CF911F910F91FF90EF90C0
+:10647000DF90CF90BF90AF909F908F907F906F9064
+:106480005F9008954423B9F0FC012491FB013491FD
+:10649000231778F0FC012491FB013491321748F066
+:1064A000FC012491222339F0415001966F5F7F4F08
+:1064B000E9CF81E0089580E008956F927F928F92F6
+:1064C0009F92AF92BF92CF92DF92EF92FF920F9383
+:1064D0001F93CF93DF93CDB7DEB727970FB6F8940E
+:1064E000DEBF0FBECDBF4C018B01FC0184918053F8
+:1064F0008A3010F43196FACF84918E3209F0F7C0C9
+:106500005F018FEFA81AB80AF501849180538A3091
+:1065100010F43196FACF84918E3209F0E8C06F0101
+:106520008FEFC81AD80A7601F701849180538A3018
+:1065300020F4EFEFEE1AFE0AF7CFF701849195DE13
+:10654000811105C0F70184918D3209F0D0C0350169
+:10655000681879088FEF860D853008F0C8C0682E5E
+:10656000712CA301B401CE0101960F94DFC5E1E0C7
+:10657000F0E0EC0FFD1FE60DF71D10821F821E825A
+:106580004AE050E0BE016A5F7F4FCE0101960F9452
+:106590009EC4F80171836083EE81FF818081811147
+:1065A000A6C046018A189B088FEF880D853008F039
+:1065B0009EC0882E912CA401B501CE0101960F94A6
+:1065C000DFC5E1E0F0E0EC0FFD1FE80DF91D1082E2
+:1065D0004AE050E0BE016A5F7F4FCE0101960F9402
+:1065E0009EC4F80173836283EE81FF8180818111F3
+:1065F0007EC0C7018C199D09853008F078C05C0108
+:10660000BB24A501B601CE0101960F94DFC5E1E0E0
+:10661000F0E0EC0FFD1FEA0DFB1D10824AE050E098
+:10662000BE016A5F7F4FCE0101960F949EC4F801B0
+:1066300075836483EE81FF818081811158C08FE76B
+:1066400090E0F80197838683F70184918D3289F574
+:106650006701FFEFCF1ADF0A5601F501849105DECD
+:10666000982E811104C08FEFA81AB80AF6CFAC1883
+:10667000BD088A2C950133272330310541F44A2D7A
+:1066800062E47AE5C601FEDE811107C015C025303F
+:106690003105B1F024303105E9F08EEF8A0D8230FA
+:1066A00030F542E064E37AE5C601ECDE81111FC0FB
+:1066B00020C09924939431C0F801178216822DC00E
+:1066C0004A2D6CE37AE5C601DDDE8111E6CF81E07B
+:1066D00090E009C04A2D67E37AE5C601D3DE811157
+:1066E000DCCF82E090E0F8019783868316C0912C7E
+:1066F00014C0F2E08F1203C083E090E0F4CFF70102
+:106700003396849180538A3090F7E490F12CFEE226
+:10671000EF1AF108F801F782E682892D27960FB665
+:10672000F894DEBF0FBECDBFDF91CF911F910F91C7
+:10673000FF90EF90DF90CF90BF90AF909F908F90A1
+:106740007F906F900895DF92EF92FF920F931F93C7
+:10675000CF93DF93CDB7DEB761970FB6F894DEBF66
+:106760000FBECDBFD82EE92EBE01675F7F4F8CDDF7
+:10677000811102C0F12C74C0BE016F5F7F4F80E5B4
+:106780009AE59BDEF82E8823A9F3FE013996DE01F7
+:106790001196BE016F5E7F4F219131918D919D9138
+:1067A0008217930740F02817390708F459C0E617F5
+:1067B000F70791F755C0E091300BF0E0EE0FFF1FA7
+:1067C000E85FFD4B859194910F94109A43E35AE54D
+:1067D00062E080E00F94507D0D2D1E2DF801E190B8
+:1067E0008F018E2D42DDF82E811103C08E2D35DDF7
+:1067F000F5CFE091300BF0E0EE0FFF1FEC5FFD4BAB
+:106800004591549163E080E00F94507D20E030E0AA
+:10681000A90168EE73E084E53AD582E390E00E9436
+:10682000DE5E84E50F946BBC84EF91E00E94DE5E37
+:1068300020E030E0A90168EE73E084E528D582E32A
+:1068400090E00E94DE5E84E50F946BBC0F9476535B
+:1068500081E00F94D1990F94665080E00F940A97CD
+:106860008F2D61960FB6F894DEBF0FBECDBFDF91BE
+:10687000CF911F910F91FF90EF90DF9008950F93AC
+:106880001F93CF93DF93CDB7DEB728970FB6F89459
+:10689000DEBF0FBECDBF00E010E0F801EA5BF54AB5
+:1068A0006491C8010F9456CA0F5F1F4F0A3011053B
+:1068B000A1F7BE016F5F7F4F80E59AE5FEDD88237B
+:1068C000C1F069817A818AE090E00F9470CA6B818F
+:1068D0007C818CE090E00F9470CA6D817E818EE0A7
+:1068E00090E00F9470CA6F81788580E190E00F94FA
+:1068F00070CA28960FB6F894DEBF0FBECDBFDF91E9
+:10690000CF911F910F910895CF93CFB7F8948091B5
+:10691000BC1B811112C061E085E385D261E085E393
+:1069200049D28CB580618CBD8CB580648CBD61E032
+:1069300084E340D261E083E33DD28091BC1B8F5F52
+:106940008093BC1BCFBFCF9108951F920F920FB6BB
+:106950000F9211242F933F938F939F93AF93BF93E5
+:106960008091BE1B9091BF1BA091C01BB091C11B19
+:106970003091BD1B23E0230F2D3720F40196A11D7C
+:10698000B11D05C026E8230F0296A11DB11D20935D
+:10699000BD1B8093BE1B9093BF1BA093C01BB093E5
+:1069A000C11B8091C21B9091C31BA091C41BB091CD
+:1069B000C51B0196A11DB11D8093C21B9093C31BE3
+:1069C000A093C41BB093C51BBF91AF919F918F91B2
+:1069D0003F912F910F900FBE0F901F9018952FB7DA
+:1069E000F8946091BE1B7091BF1B8091C01B909169
+:1069F000C11B2FBF08953FB7F8948091C21B90919F
+:106A0000C31BA091C41BB091C51B26B5A89B05C094
+:106A10002F3F19F00196A11DB11D3FBF6627782FAA
+:106A2000892F9A2F620F711D811D911D42E0660F03
+:106A3000771F881F991F4A95D1F708958F929F92CB
+:106A4000AF92BF92CF92DF92EF92FF926B017C01E7
+:106A5000D2DF4B015C01C114D104E104F104E1F087
+:106A6000BAD7C9DF681979098A099B09683E73405A
+:106A70008105910580F321E0C21AD108E108F108EF
+:106A800088EE880E83E0981EA11CB11CC114D104AD
+:106A9000E104F10431F7DFCFFF90EF90DF90CF906A
+:106AA000BF90AF909F908F9008958230910538F0FD
+:106AB000880F991F880F991F05970197F1F708957F
+:106AC000789484B5826084BD84B5816084BD85B5C9
+:106AD000826085BD85B5816085BDEEE6F0E0808190
+:106AE00081608083E1E8F0E01082808182608083B1
+:106AF000808181608083E0E8F0E080818160808334
+:106B0000E1EBF0E0808184608083E0EBF0E0808165
+:106B100081608083E1E9F0E0808182608083808110
+:106B200081608083E0E9F0E0808181608083E1EA38
+:106B3000F0E0808182608083808181608083E0EAF0
+:106B4000F0E0808181608083E1E2F1E08081826019
+:106B50008083808181608083E0E2F1E080818160D8
+:106B60008083EAE7F0E080818460808380818260B6
+:106B7000808380818160808380818068808310929F
+:106B8000C10008951F93CF93DF93182FEB0161E0AD
+:106B900011D1209711F460E004C0CF3FD10531F44A
+:106BA00061E0812FDF91CF911F913DC1E12FF0E096
+:106BB000E65AF54A449150E0FA013197E231F10585
+:106BC00008F09BC0E655FF4F0D94DBC284B580688A
+:106BD00084BDC7BD97C084B5806284BDC8BD92C066
+:106BE00080918000806880938000D0938900C0935A
+:106BF000880088C080918000806280938000D0935C
+:106C00008B00C0938A007EC0809180008860809352
+:106C10008000D0938D00C0938C0074C08091B00030
+:106C200080688093B000C093B3006CC08091B000C6
+:106C300080628093B000C093B40064C080919000E3
+:106C4000806880939000D0939900C09398005AC0B8
+:106C500080919000806280939000D0939B00C093BD
+:106C60009A0050C080919000886080939000D093EB
+:106C70009D00C0939C0046C08091A00080688093D6
+:106C8000A0008091A0008F7B8093A000D093A900EA
+:106C9000C093A80037C08091A00080628093A000BC
+:106CA000D093AB00C093AA002DC08091A000886053
+:106CB0008093A000D093AD00C093AC0023C080911E
+:106CC0002001806880932001D0932901C09328017E
+:106CD00019C080912001806280932001D0932B0104
+:106CE000C0932A010FC08091200188608093200109
+:106CF000D0932D01C0932C0105C0C038D1050CF0F4
+:106D00004FCF49CFDF91CF911F91089590E0FC01C3
+:106D10003197E231F10508F04CC0E454FF4F0D9477
+:106D2000DBC2809180008F7703C0809180008F7DCF
+:106D300080938000089580918000877FF9CF84B58B
+:106D40008F7702C084B58F7D84BD08958091B00097
+:106D50008F7703C08091B0008F7D8093B00008953D
+:106D6000809190008F7707C0809190008F7D03C045
+:106D700080919000877F8093900008958091A0007B
+:106D80008F7707C08091A0008F7D03C08091A00005
+:106D9000877F8093A0000895809120018F7707C09E
+:106DA000809120018F7D03C080912001877F809397
+:106DB00020010895CF93DF9390E0FC01E055F54A60
+:106DC0002491FC01EA5FF44A8491882349F190E020
+:106DD000880F991FFC01E057F44AA591B4918A5895
+:106DE000944AFC01C591D4919FB7611108C0F894F1
+:106DF0008C91209582238C93888182230AC06230F3
+:106E000051F4F8948C91322F309583238C938881A0
+:106E1000822B888304C0F8948C91822B8C939FBF23
+:106E2000DF91CF9108950F931F93CF93DF931F921C
+:106E3000CDB7DEB7282F30E0F901E65AF54A849144
+:106E4000F901E055F54A1491F901EA5FF44A049119
+:106E50000023C1F0882319F0698358DF6981E02F8E
+:106E6000F0E0EE0FFF1FEA58F44AA591B4919FB7E6
+:106E7000F8948C91611103C01095812301C0812B7E
+:106E80008C939FBF0F90DF91CF911F910F91089529
+:106E9000CF93DF93282F30E0F901E65AF54A849129
+:106EA000F901E055F54AD491F901EA5FF44AC49139
+:106EB000CC2389F081112ADFEC2FF0E0EE0FFF1FC9
+:106EC000E45AF44AA591B4912C912D2381E090E0ED
+:106ED00021F480E002C080E090E0DF91CF9108953E
+:106EE000CF92DF92EF92FF920F931F93CF93DF9396
+:106EF0006C017A01EB01E60EF71E00E010E0CE1502
+:106F0000DF0561F06991D601ED91FC910190F0816E
+:106F1000E02DC6011995080F191FF1CFC801DF91A7
+:106F2000CF911F910F91FF90EF90DF90CF90089538
+:106F30006115710581F0DB010D900020E9F7AD01CD
+:106F400041505109461B570BDC01ED91FC91028029
+:106F5000F381E02D199480E090E00895E9CFDC0101
+:106F6000ED91FC910190F081E02D19948F929F9208
+:106F7000AF92BF92CF92DF92EF92FF920F931F9347
+:106F8000CF93DF93CDB7DEB7A1970FB6F894DEBFEE
+:106F90000FBECDBF7C01C42EE52FCB01D22E19A28E
+:106FA00021E02D1510F02AE0D22E8E010F5D1F4F2B
+:106FB0008D2C912CA12CB12C6C2D7E2FA501940130
+:106FC0000F949DC28C2DD29E80191124015011095D
+:106FD0008A3014F4805D01C0895CF801808321153A
+:106FE00031054105510521F0C22EE32FCA01E4CF3E
+:106FF000B801C7019DDFA1960FB6F894DEBF0FBEA2
+:10700000CDBFDF91CF911F910F91FF90EF90DF9057
+:10701000CF90BF90AF909F908F900895CF92DF92C6
+:10702000EF92FF920F931F93CF93DF93EC016A01CE
+:107030007B012115310579F4E881F9810190F08116
+:10704000E02D642FDF91CF911F910F91FF90EF9072
+:10705000DF90CF9019942A303105D9F477FF18C00A
+:107060006DE27DDF8C0144275527BA014C195D097B
+:107070006E097F092AE0CE0179DF800F911FDF9131
+:10708000CF911F910F91FF90EF90DF90CF900895D7
+:107090002AE0B701A601CE01DF91CF911F910F9198
+:1070A000FF90EF90DF90CF9061CF9A01AB01662700
+:1070B00057FD6095762FB2CF2115310541F4DC01E3
+:1070C000ED91FC910190F081E02D642F19944ECF49
+:1070D0009A01AB0160E070E0EFCF4F925F926F9248
+:1070E0007F928F929F92AF92BF92CF92DF92EF9258
+:1070F000FF920F931F93CF93DF93EC016A017B0103
+:10710000B22E9A01AB01C701B6010F9495C1882335
+:1071100019F061E779E025C026013701E89477F896
+:107120002FEF3FEF4FE75FE7C301B2010F9495C127
+:1071300081110CC02FEF3FEF4FE75FE7C301B201B2
+:1071400025D518161CF465E779E00BC02FEF3FEF4B
+:107150004FE75FE4C701B6011CD71816A4F469E72E
+:1071600079E0CE01DF91CF911F910F91FF90EF90C9
+:10717000DF90CF90BF90AF909F908F907F906F9057
+:107180005F904F90D5CE2FEF3FEF4FE75FECC701F9
+:10719000B601FCD487FDE3CF20E030E0A901C701B0
+:1071A000B601F4D487FF09C06DE2CE01D8DE8C01B0
+:1071B000F7FAF094F7F8F09402C000E010E0A12C88
+:1071C00060E070E080E09FE3AB1439F020E030E055
+:1071D00040E251E4E2D4A394F7CF9B01AC01C70194
+:1071E000B601FBD36B017C0145D52B013C016ED56B
+:1071F0009B01AC01C701B601EFD36B017C012AE012
+:10720000B301A201CE01B2DE080F191FBB2031F07D
+:107210006DEC75E0CE018CDE080F191F7B2C7720FA
+:1072200019F120E030E040E251E4C701B60183D714
+:107230006B017C011AD54B01AA2497FCA094BA2CAF
+:107240002AE030E0B501A401CE01E8DE080F191FE5
+:10725000C501B4013DD59B01AC01C701B601BCD34A
+:107260006B017C017A94DBCFC801DF91CF911F9134
+:107270000F91FF90EF90DF90CF90BF90AF909F90D5
+:107280008F907F906F905F904F90089526CF3F92A0
+:107290004F925F926F927F928F929F92AF92BF9226
+:1072A000CF92DF92EF92FF920F931F93CF93DF93D2
+:1072B00000D01F92CDB7DEB78B0129013A01909122
+:1072C000E202981721F09F3F09F0B5C204C0EAEA34
+:1072D000FBE5349004C18093E202EAEAFBE5E49125
+:1072E000EF3F09F4A8C2E23009F480C074F5EE2340
+:1072F00009F45BC0E13009F0F1C0109280001092F7
+:10730000810090918100986090938100909181001C
+:10731000916090938100282F30E0F901EA5FF44AF0
+:10732000E491F0E0EE0FFF1FEA58F44A45915491C2
+:107330005093E41B4093E31BF901E055F54A249177
+:107340002093E21B33243394CCC0E43009F49EC074
+:107350000CF474C0E53009F0C1C010922001109205
+:107360002101909121019860909321019091210138
+:10737000916090932101282F30E0F901EA5FF44AEF
+:10738000E491F0E0EE0FFF1FEA58F44A4591549162
+:107390005093C81B4093C71BF901E055F54A24914F
+:1073A0002093C61B55E0352E9CC014BC15BC94B56B
+:1073B000926094BD95B5916095BD282F30E0F9019C
+:1073C000EA5FF44AE491F0E0EE0FFF1FEA58F44A56
+:1073D000459154915093EB1B4093EA1BF901E05502
+:1073E000F54A24912093E91B312C7BC01092B00008
+:1073F0001092B1009091B00092609093B000909183
+:10740000B10091609093B100282F30E0F901EA5F5C
+:10741000F44AE491F0E0EE0FFF1FEA58F44A459178
+:1074200054915093DD1B4093DC1BF901E055F54A64
+:1074300024912093DB1B22E0322E53C01092900047
+:10744000109291009091910098609093910090918A
+:107450009100916090939100282F30E0F901EA5F4C
+:10746000F44AE491F0E0EE0FFF1FEA58F44A459128
+:1074700054915093D61B4093D51BF901E055F54A22
+:1074800024912093D41BB3E03B2E2BC01092A0007C
+:107490001092A1009091A10098609093A10090910A
+:1074A000A10091609093A100282F30E0F901EA5FDC
+:1074B000F44AE491F0E0EE0FFF1FEA58F44A4591D8
+:1074C00054915093CF1B4093CE1BF901E055F54AE0
+:1074D00024912093CD1B74E0372E03C03E2E37FC41
+:1074E000AAC161E067DC4801A12CB12C832D8D7FFE
+:1074F00009F0C4C060E072E18AE790E0A501940160
+:107500000F94BFC229833A834B835C8369017A015C
+:1075100081E0C81AD108E108F1089FEFC916D1042B
+:10752000E104F10409F008F497C060E472E48FE02C
+:1075300090E0A50194010F94BFC269017A01E1E0D6
+:10754000CE1AD108E108F108F2E03F1219C08FEF1E
+:10755000C816D104E104F10409F008F487C060E919
+:1075600070ED83E090E0A50194010F94BFC2690122
+:107570007A0191E0C91AD108E108F10883E001C05D
+:1075800082E0EFEFCE16D104E104F10409F008F433
+:1075900064C068E478EE81E090E0A5019401EFD743
+:1075A00069017A01F1E0CF1AD108E108F10833202E
+:1075B000D9F082E038121AC09FEFC916D104E10455
+:1075C000F10409F008F435C164E274EF80E090E062
+:1075D000A5019401D4D769017A01E1E0CE1AD1085E
+:1075E000E108F10885E003C083E001C084E0FFEF1B
+:1075F000CF16D104E104F10481F178F162E17AE778
+:1076000080E090E0A5019401BAD769017A0181E098
+:10761000C81AD108E108F108311002C084E001C0A5
+:1076200086E09FEFC916D104E104F104B1F0A8F09F
+:10763000C980DA80EB80FC809AE0F594E794D794D7
+:10764000C7949A95D1F7E1E0CE1AD108E108F10884
+:10765000332031F087E00BC081E0332011F007C008
+:1076600085E095B5987F982B95BD54C082E09091A8
+:10767000B100987F982B9093B1004CC060E072E10C
+:107680008AE790E0A50194017AD769017A01F1E0D7
+:10769000CF1AD108E108F108C114D10481E0E8064D
+:1076A000F10480F068E478EE81E090E0A5019401B7
+:1076B00066D769017A0191E0C91AD108E108F10899
+:1076C00093E001C091E0E1E03E1207C080918100AB
+:1076D000887F892B809381001DC0F3E03F1207C093
+:1076E00080919100887F892B8093910013C084E062
+:1076F000381207C08091A100887F892B8093A10058
+:1077000009C0E5E03E1206C080912101887F892BE7
+:1077100080932101411451046104710461F0D80186
+:10772000AA0FBB1FA301920161D728EE33E040E00E
+:1077300050E003D703C02FEF3FEFA901F2E03F165F
+:1077400009F443C0F315BCF0332081F181E0381215
+:1077500072C0D0928900C09288002093E51B3093BC
+:10776000E61B4093E71B5093E81B80916F008260FB
+:1077700080936F0060C094E0391609F448C0391650
+:10778000A4F1E5E03E1257C0D0922901C092280131
+:107790002093C91B3093CA1B4093CB1B5093CC1B27
+:1077A0008091730082608093730045C0C7BC2093B2
+:1077B000EC1B3093ED1B4093EE1B5093EF1B80911D
+:1077C0006E00826080936E0036C0C092B30020933A
+:1077D000DE1B3093DF1B4093E01B5093E11B809135
+:1077E000700082608093700026C0D0929900C09291
+:1077F00098002093D71B3093D81B4093D91B5093EC
+:10780000DA1B8091710082608093710014C0D09265
+:10781000A900C092A8002093D01B3093D11B4093A5
+:10782000D21B5093D31B80917200826080937200B0
+:1078300002C084E01CCF0F900F900F900F90DF914B
+:10784000CF911F910F91FF90EF90DF90CF90BF905D
+:10785000AF909F908F907F906F905F904F903F90F0
+:1078600008958230A9F028F4882349F0813051F03E
+:107870000895843021F1E8F0853039F108951092AF
+:107880006E00089580916F008D7F80936F00089542
+:10789000809170008D7F8093700081E08093B000B4
+:1078A0008091B100887F84608093B1001092B30012
+:1078B0000895809171008D7F80937100089580916B
+:1078C00072008D7F809372000895809173008D7F88
+:1078D000809373000895CF93C82F8091E2028C1398
+:1078E00007C0EAEAFBE584919FEF9093E20201C0B2
+:1078F0008FEFB7DF60E08C2FCF9195CA1F920F9268
+:107900000FB60F9211240BB60F922F933F934F9304
+:107910005F936F937F938F939F93AF93BF93EF93F7
+:10792000FF938091DE1B9091DF1BA091E01BB09133
+:10793000E11B892B8A2B8B2B51F19091DB1BE09162
+:10794000DC1BF091DD1B8081892780838091DE1B09
+:107950009091DF1BA091E01BB091E11B1816190656
+:107960001A061B06BCF48091DE1B9091DF1BA091D0
+:10797000E01BB091E11B0197A109B1098093DE1BC7
+:107980009093DF1BA093E01BB093E11B03C0809199
+:10799000E202A1DFFF91EF91BF91AF919F918F9193
+:1079A0007F916F915F914F913F912F910F900BBEFF
+:1079B0000F900FBE0F901F901895089581D8FDDF8E
+:1079C0000E94359FC0E0D0E00E94999B2097E1F390
+:1079D0000E940000F9CF08955058BB27AA270ED067
+:1079E00076C23FD230F044D220F031F49F3F11F400
+:1079F0001EF40FC20EF4E095E7FBDCC1E92F89D23B
+:107A000080F3BA17620773078407950718F071F4BB
+:107A10009EF5B8C20EF4E0950B2EBA2FA02D0B01E7
+:107A2000B90190010C01CA01A0011124FF27591BC3
+:107A300099F0593F50F4503E68F11A16F040A22FC9
+:107A4000232F342F4427585FF3CF4695379527953A
+:107A5000A795F0405395C9F77EF41F16BA0B620B39
+:107A6000730B840BBAF09150A1F0FF0FBB1F661F80
+:107A7000771F881FC2F70EC0BA0F621F731F841FC3
+:107A800048F4879577956795B795F7959E3F08F0E9
+:107A9000B3CF9395880F08F09927EE0F97958795A8
+:107AA0000895DFD158F080E891E009F49EEFE0D12D
+:107AB00028F040E851E059F45EEF09C0AAC162C263
+:107AC000E92FE07826D268F3092E052AC1F326179C
+:107AD00037074807590738F00E2E07F8E02569F0F8
+:107AE000E025E0640AC0EF6307F8009407FADB01C1
+:107AF000B9019D01DC01CA01AD01EF935DD0E7D171
+:107B00000AD05F91552331F02BED3FE049E450FD61
+:107B100049EC63CF0895DF93DD27B92FBF7740E8A5
+:107B20005FE31616170648075B0710F4D92F96D2A5
+:107B30009F938F937F936F93F5D3ECE9F1E06CD132
+:107B4000C6D12F913F914F915F9101D3DD2349F031
+:107B50009058A2EA2AED3FE049EC5FE3D0785D2738
+:107B60004DDFDF91B4C1F7D180F09F3740F4911120
+:107B70000EF409C260E070E080E89FE3089526F00B
+:107B80001B16611D711D811D1BC135C1EFD008F48D
+:107B900081E0089575D1E395ABC10CD098C168D14F
+:107BA00040F05FD130F021F45F3F19F003C1511173
+:107BB000EAC12FC1AED198F39923C9F35523B1F38C
+:107BC000951B550BBB27AA2762177307840738F04C
+:107BD0009F5F5F4F220F331F441FAA1FA9F333D0AB
+:107BE0000E2E3AF0E0E830D091505040E695001C5F
+:107BF000CAF729D0FE2F27D0660F771F881FBB1F1B
+:107C0000261737074807AB07B0E809F0BB0B802DF4
+:107C1000BF01FF2793585F4F2AF09E3F510568F040
+:107C2000C9C0B1C15F3FECF3983EDCF38695779510
+:107C30006795B795F7959F5FC9F7880F911D969542
+:107C4000879597F90895E1E0660F771F881FBB1F9E
+:107C5000621773078407BA0720F0621B730B840B4B
+:107C6000BA0BEE1F88F7E095089504D06894B1111F
+:107C70008AC1089556D188F09F5790F0B92F99275F
+:107C8000B751A0F0D1F0660F771F881F991F1AF027
+:107C9000BA95C9F712C0B13081F074D1B1E008953E
+:107CA00071C1672F782F8827B85F39F0B93FCCF3BF
+:107CB000869577956795B395D9F73EF4909580951D
+:107CC000709561957F4F8F4F9F4F0895E89409C03D
+:107CD00097FB3EF490958095709561957F4F8F4FFF
+:107CE0009F4F9923A9F0F92F96E9BB279395F69515
+:107CF000879577956795B795F111F8CFFAF4BB0F93
+:107D000011F460FF1BC06F5F7F4F8F4F9F4F16C0F6
+:107D1000882311F096E911C0772321F09EE8872F80
+:107D2000762F05C0662371F096E8862F70E060E03C
+:107D30002AF09A95660F771F881FDAF7880F9695B5
+:107D4000879597F9089507D180F09F3740F49111F6
+:107D50000EF019C160E070E080E89FEB089526F412
+:107D60001B16611D711D811D2BC045C0990F000898
+:107D7000550FAA0BE0E8FEEF16161706E807F907FD
+:107D8000C0F012161306E407F50798F0621B730B98
+:107D9000840B950B39F40A2661F0232B242B252B19
+:107DA00021F408950A2609F4A140A6958FEF811DBC
+:107DB000811D089597F99F6780E870E060E008955D
+:107DC000882371F4772321F09850872B762F07C0F2
+:107DD000662311F499270DC09051862B70E060E066
+:107DE0002AF09A95660F771F881FDAF7880F969505
+:107DF000879597F908959F3F31F0915020F487952A
+:107E000077956795B795880F911D9695879597F902
+:107E100008959FEF80EC0895DF93CF931F930F9306
+:107E2000FF92EF92DF927B018C01689405C0DA2EFD
+:107E3000EF018DD1FE01E894A591259135914591F1
+:107E40005591AEF3EF01DADDFE019701A801DA9456
+:107E500079F7DF90EF90FF900F911F91CF91DF9115
+:107E6000089500240A9416161706180609060895A0
+:107E700000240A9412161306140605060895C9CFA5
+:107E800050D0E8F3E894E0E0BB279F57F0F02AEDEC
+:107E90003FE049EC06C0EE0FBB0F661F771F881F3F
+:107EA00028F0B23A62077307840728F0B25A620BCF
+:107EB000730B840BE3959A9572F7803830F49A959A
+:107EC000BB0F661F771F881FD2F7904896CF092EE9
+:107ED0000394000C11F4882352F0BB0F40F4BF2B25
+:107EE00011F460FF04C06F5F7F4F8F4F9F4F089565
+:107EF000EF93E0FF06C0A2EA2AED3FE049EC5FEB1A
+:107F00007DDDE5DF0F90039401FC9058E9ECF1E092
+:107F100048C257FD9058440F551F59F05F3F71F00C
+:107F20004795880F97FB991F61F09F3F79F08795E0
+:107F30000895121613061406551FF2CF4695F1DF69
+:107F400008C0161617061806991FF1CF86957105F9
+:107F5000610508940895E5DFA0F0BEE7B91788F43D
+:107F6000BB279F3860F41616B11D672F782F88271E
+:107F7000985FF7CF869577956795B11D939596395C
+:107F8000C8F30895E894BB2766277727CB0197F9B4
+:107F90000895ECDE08F48FEF089563DF19F068DFD1
+:107FA00009F037CF07CFB901CA0125CF9F775F7797
+:107FB000B0DF98F39923B9F35523B9F3FF27951749
+:107FC00058F4E52FE91BED3070F75E3B10F0F1E45B
+:107FD0001CC09034E0F40AC0E92FE51BED3028F70F
+:107FE0009E3B10F0F1E411C0503488F4F9EA882384
+:107FF0002AF09A95660F771F881FDAF744232AF034
+:108000005A95220F331F441FDAF79F1B5F1BFF9304
+:108010001F930F93FF92EF9279018A01BB27AB2F39
+:108020009B01AC0196D09701A801BF937B018C0105
+:10803000AA27BA2FB901CA018CD0AF919701A80124
+:10804000EF90FF900F911F91D9DC41DF2DD14F911F
+:1080500040FF0895552747FD509509C09B01AC018D
+:1080600060E070E080E89FE398CDA4CEC4CE59DFF5
+:10807000E8F39923D9F3940F511DBBF3915050406D
+:1080800094F059F0882332F0660F771F881F9150C3
+:108090005040C1F79E3F510544F7880F911D9695BA
+:1080A000879597F908955F3FACF0983E9CF0BB2709
+:1080B000869577956795B79508F4B1609395C1F764
+:1080C000BB0F58F711F460FFE8CF6F5F7F4F8F4F02
+:1080D0009F4FE3CF58CF25DF58F19E5758F1985165
+:1080E000A0F0E9F0983020F5092E9927660F771F48
+:1080F000881F991F0A94D1F712C0062E672F782F78
+:108100008827985F11F4000C07C0993FB4F3869557
+:10811000779567959395D9F7611D711D811D3EF483
+:1081200090958095709561957F4F8F4F9F4F0895E3
+:10813000689429CF27CF0BD0CACE93DE28F098DEE3
+:1081400018F0952309F036CE64CE11241CCFE1DE61
+:10815000A0F3959FD1F3950F50E0551F629FF0015A
+:10816000729FBB27F00DB11D639FAA27F00DB11DB3
+:10817000AA1F649F6627B00DA11D661F829F22273C
+:10818000B00DA11D621F739FB00DA11D621F839FC3
+:10819000A00D611D221F749F3327A00D611D231F99
+:1081A000849F600D211D822F762F6A2F11249F57E7
+:1081B00050408AF0E1F088234AF0EE0FFF1FBB1F0A
+:1081C000661F771F881F91505040A9F79E3F5105A9
+:1081D00070F0F0CDD8CE5F3FECF3983EDCF386959F
+:1081E00077956795B795F795E7959F5FC1F7FE2B54
+:1081F000880F911D9695879597F90895FA01EE0FCE
+:10820000FF1F30962105310599F16115710561F463
+:108210008038BFE39B0749F168949038810561F08D
+:108220008038BFEF9B0741F0992342F5FF3FE105FE
+:108230003105210511F1E8940894E795D901AA23A5
+:1082400029F4AB2FBE2FF85FD0F310C0FF5F70F49E
+:10825000A695E0F7F73950F019F0FF3A38F49F7718
+:108260009F930CD00F9007FC905808953EF0D1CD0D
+:1082700060E070E080E89FE308954FE79F775F93A9
+:108280004F933F932F93A3D02F913F914F915F91A5
+:1082900052DF54C09F93F4DD0F9007FCEE5F28CEB1
+:1082A00011F40EF4B6CDA7CD3CDED0F39923D9F36B
+:1082B000CEF39F57550B87FF6DD00024A0E640EA10
+:1082C000900180585695979528F4805C660F771F2B
+:1082D000881F20F026173707480730F4621B730BFE
+:1082E000840B202931294A2BA69517940794202521
+:1082F00031254A2758F7660F771F881F20F0261769
+:108300003707480730F4620B730B840B200D311DC7
+:10831000411DA09581F7B901842F9158880F96953A
+:10832000879508959B01AC0106CF20DD880B990B42
+:10833000089519F40EF03ECD25CE6BCDF2DDC8F3D5
+:108340009638C0F707F80F92E8942BE33AEA48EB27
+:108350005FE7FFDE0F920F920F924DB75EB70F925D
+:1083600076D0E7EEF1E058DD4F915F91EF91FF910C
+:10837000E595EE1FFF1F49F0FE57E0684427EE0F1A
+:10838000441FFA95E1F74195550B71DE0F9007FEFA
+:1083900065CE089591505040660F771F881FD2F721
+:1083A00008959F938F937F936F93FF93EF939B0118
+:1083B000AC01C1DEEF91FF912FDD2F913F914F91E5
+:1083C0005F91B9CE0EF017CD24CD6894F3CCA9DD22
+:1083D000C8F39923D1F3C6F3DF93CF931F930F9381
+:1083E000FF92C92FDD2788232AF02197660F771F78
+:1083F000881FDAF720E030E040E85FEB9FE3883940
+:1084000020F0803E30F021968F77E7DAEFE0F2E05F
+:1084100003C0E3DAECE3F2E0FFDC8B01BE01EC0128
+:10842000FB2E6F5771097595771F880B990B50DCE0
+:1084300028E132E741E35FE38ADEAF2D9801AE0128
+:10844000FF900F911F91CF91DF91D8DA40CDFA01C3
+:10845000DC01AA0FBB1F9B01AC01BF5728F42227E8
+:108460003327442750781FC0B75188F4AB2F00241E
+:10847000469537952795011CA395D2F3002069F006
+:10848000220F331F441FB395DAF30DD0A5CA613014
+:108490007105A0E88A07B94630F49B01AC01662754
+:1084A000772788279078309621F020833183428384
+:1084B00053830895DB018F939F9398D0BF91AF9121
+:1084C000A29F800D911DA39F900DB29F900D11242E
+:1084D000089587FB082E062687FD819567FD619527
+:1084E00099D00EF4919507FC81950895AA1BBB1BAA
+:1084F00051E107C0AA1FBB1FA617B70710F0A61BA4
+:10850000B70B881F991F5A95A9F780959095BC01C4
+:10851000CD01089597FB072E16F4009406D077FD41
+:1085200008D0E4DF07FC05D03EF4909581959F4F7D
+:108530000895709561957F4F0895A1E21A2EAA1BA8
+:10854000BB1BFD010DC0AA1FBB1FEE1FFF1FA21703
+:10855000B307E407F50720F0A21BB30BE40BF50B00
+:10856000661F771F881F991F1A9469F76095709589
+:10857000809590959B01AC01BD01CF010895052E1A
+:1085800097FB16F400940FD057FD05D0D6DF07FCFB
+:1085900002D046F408C050954095309521953F4F44
+:1085A0004F4F5F4F089590958095709561957F4FDF
+:1085B0008F4F9F4F0895EE0FFF1F0590F491E02D10
+:1085C0001994A29FB001B39FC001A39F700D811D9C
+:1085D0001124911DB29F700D811D1124911D0895CC
+:1085E000F0DFB7FF0895821B930B0895EADFA59F84
+:1085F000900DB49F900DA49F800D911D112408959E
+:10860000B7FFF4CFF3DF821B930B08950790F69129
+:10861000E02D1994991B79E004C0991F961708F072
+:10862000961B881F7A95C9F780950895EF920F934E
+:108630001F93CF93DF93E80147FF02C034E101C0ED
+:1086400034E0E42FFF27E7FDF095F7FF03C0F19535
+:10865000E195F109E32E022F2E2FAE0156D7CE0160
+:10866000DF91CF911F910F91EF9008958F929F927C
+:10867000AF92BF92CF92DF92EF92FF920F931F9330
+:10868000CF93DF938B016115710521F0DB018C9392
+:1086900011969C93EC015E01BFEFAB1ABB0A75010A
+:1086A000C8808C2D90E07BD2892B11F0E501F3CFAF
+:1086B000EDE2CE1208C07E01F2E0EF0EF11CC9809F
+:1086C000DD24D39409C02BE2C21205C07E0142E032
+:1086D000E40EF11CC980D12CE701219743E050E062
+:1086E00063EB7BE5CE018FD2892BB9F4239645E06D
+:1086F00050E06EEA7BE5CE0186D2892B09F42596FF
+:108700000115110519F0D801CD93DC93D11000C1EA
+:1087100060E070E080E89FE704C143E050E06BEA6E
+:108720007BE5CE0170D2892B59F40115110509F4AE
+:10873000F4C0B2E0EB0EF11CF801F182E082EDC072
+:10874000F70160E070E0CB01C0E0D0E07F01A0ED78
+:10875000AA2EAC0C29E02A1528F14D2D4260B42E2A
+:108760002D2D2870D2FE04C0211124C0219622C0D4
+:1087700021112197A5E0B0E09B01AC0137DF660F26
+:10878000771F881F991F6A0D711D811D911D683902
+:10879000A9E97A078A07A9E19A0760F0BD2DB660BA
+:1087A000BB2E08C02EEFA2120AC0D3FC50C04D2D24
+:1087B0004860B42E3196D701CC90DB2CC7CF2C2D3E
+:1087C0002F7D253409F043C0A081AD3241F4BD2D89
+:1087D000B061DB2E7F0122E0E20EF11C0CC07F01B4
+:1087E000AB3231F04FEFE41AF40A21E030E006C07A
+:1087F000A2E0EA0EF11CA18122E030E0A053AA30F1
+:1088000018F0E21AF30A23C0F70120E030E0203824
+:10881000BCE03B075CF4A901440F551F440F551FF2
+:10882000240F351F220F331F2A0F311DAF014F5F59
+:108830005F4F7A01A081A053AA3010F4FA01E7CF6C
+:10884000D4FE03C0319521953109C20FD31FD1FE4B
+:1088500009C00115110531F0E1E0EE1AF108D80167
+:10886000ED92FC9233DA2D2D2370233019F04B0159
+:108870005C0106C04B015C01B7FAB094B7F8B09444
+:1088800020E030E0A901C501B40180D9882309F4B2
+:108890003CC0D7FF06C0D195C195D1090AEC1BE5B4
+:1088A00002C002EE1BE56801B8E1CB1AD10890E2E4
+:1088B000E92EF12CCE15DF056CF0F80125913591EC
+:1088C00045915491C501B40136DC4B015C01CE19D0
+:1088D000DF09F0CF04501109F594E7940C151D053C
+:1088E00049F78A2D880F8B2D881F8F3F41F020E09C
+:1088F00030E0A901C501B40149D9811106C082E265
+:1089000090E09093FB1B8093FA1BC501B40109C052
+:1089100060E070E080E89FEF04C060E070E080EC11
+:108920009FE7DF91CF911F910F91FF90EF90DF9024
+:10893000CF90BF90AF909F908F9008952F923F92CD
+:108940005F926F927F928F929F92AF92BF92CF92DF
+:10895000DF92EF92FF920F931F93CF93DF938B01E0
+:10896000EA016115710521F0DB018C9311969C934E
+:10897000209739F09E01225031092332310508F049
+:10898000F8C07C016701BFEFCB1ADB0A5601F70183
+:108990006080862D90E003D1892B11F07601F2CF13
+:1089A000FDE26F120AC0570182E0A80EB11CD70188
+:1089B00011966C90772473940BC0BBE26B1207C0C6
+:1089C0005701E2E0AE0EB11CD70111966C90712CEC
+:1089D000CE018F7E892B89F4B0E36B1222C0F501A2
+:1089E00080818F7D883541F56180F2E0AF0EB11C4A
+:1089F000872D8260782EC0E1D0E0C830D105F1F03B
+:108A00004CF4C230D10511F5C12CD12CE12CB0E4CD
+:108A1000FB2E2EC0CA30D10531F0C031D10519F17D
+:108A200015C0209751F7CAE0D0E0ACECCA2EDC2C80
+:108A3000EC2CACE0FA2E1CC02097F9F6C8E0D0E090
+:108A4000C12CD12CE12CF0E1FF2E12C060E070E0CF
+:108A500080E090E89E01442737FD4095542F6DDD5E
+:108A600069017A0105C0C12CD12CE12CE8E0FE2E71
+:108A7000F50160E020E030E0A9014E01AA2497FC56
+:108A8000A094BA2C1F0170ED572E560CA9E0A51525
+:108A900070F48FEB860D8A3118F499EC592E06C0CC
+:108AA0008FE9860D8A3128F589EA582E560C852DD6
+:108AB00090E08C179D07ECF467FD17C0C216D30633
+:108AC000E406F50678F0C501B401F4DC9B01AC01C5
+:108AD000250D311D411D511D213031054105B0E8E5
+:108AE0005B0710F06FEF01C061E03196D1016C902F
+:108AF000C9CF872D81700115110571F0662329F00A
+:108B00003197D801ED93FC9307C071FE19C03297DD
+:108B1000D801ED93FC9314C067FF12C0882329F09D
+:108B200020E030E040E050E804C02FEF3FEF4FEF8F
+:108B30005FE782E290E09093FB1B8093FA1B16C0E4
+:108B4000882341F050954095309521953F4F4F4FE8
+:108B50005F4F0CC057FF0AC082E290E09093FB1B6E
+:108B60008093FA1B2FEF3FEF4FEF5FE7B901CA0188
+:108B700004C060E070E080E090E0DF91CF911F9151
+:108B80000F91FF90EF90DF90CF90BF90AF909F90AC
+:108B90008F907F906F905F903F902F9008959111EC
+:108BA00009C7803219F089508550D0F70895911186
+:108BB000089581548A5108F4805E855A0895FB0116
+:108BC000DC0102C005900D9241505040D8F7089545
+:108BD000FB01DC010D900020E9F7119705900D9243
+:108BE0000020E1F70895FB01DC0105900D920020C3
+:108BF000E1F70895FC0105900020E9F78095909534
+:108C00008E0F9F1F0895FB01DC014150504088F0FA
+:108C10008D9181341CF08B350CF4805E659161344C
+:108C20001CF06B350CF4605E861B611171F3990BBF
+:108C30000895881BFCCFFB01DC014150504030F00F
+:108C40008D910590801919F40020B9F7881B990BB4
+:108C50000895FB01DC014150504048F005900D9211
+:108C60000020C9F701C01D9241505040E0F708951F
+:108C7000FB0155915523A9F0BF01DC014D9145172A
+:108C80004111E1F759F4CD010590002049F04D91D3
+:108C900040154111C9F3FB014111EFCF81E090E094
+:108CA00001970895FB01DC0104C08D9101908019AA
+:108CB00021F441505040C8F7881B990B0895FB01DF
+:108CC000DC0102C001900D9241505040D8F7089548
+:108CD000DC0101C06D9341505040E0F70895FB0165
+:108CE000DC018D9181341CF08B350CF4805E619138
+:108CF00061341CF06B350CF4605E861B611189F3E6
+:108D0000990B0895FB01DC010D900020E9F7119704
+:108D100001900D920020E1F70895FC0181918617E2
+:108D200021F08823D9F7992708953197CF01089525
+:108D3000FB01DC018D91019080190110D9F3990B91
+:108D40000895FB01DC0101900D920020E1F70895E8
+:108D5000FB01DC014150504030F08D9101908019B1
+:108D600019F40020B9F7881B990B0895FB01DC0169
+:108D70004150504048F001900D920020C9F701C0C9
+:108D80001D9241505040E0F70895FB015191552349
+:108D9000A9F0BF01DC014D9145174111E1F759F4EC
+:108DA000CD010190002049F04D9140154111C9F3CA
+:108DB000FB014111EFCF81E090E0019708950F93FF
+:108DC0001F93CF93DF93CDB7DEB708851985F801E0
+:108DD000838188608383AE01445F5F4F6A857B85B2
+:108DE000C80154D1F8012381277F2383DF91CF91DC
+:108DF0001F910F9108950F931F93CF93DF93182F17
+:108E0000092FEB018B8181FD03C08FEF9FEF20C005
+:108E100082FF10C04E815F812C813D814217530734
+:108E20007CF4E881F9819F012F5F3F4F39832883CC
+:108E3000108306C0E885F985812F1995892B29F7BC
+:108E40002E813F812F5F3F4F3F832E83812F902FB5
+:108E5000DF91CF911F910F910895EF92FF920F93A1
+:108E60001F93CF93DF93EC018B01DB0113968C9161
+:108E700081FF17C0E12CF12CFE018491882379F049
+:108E8000D8011896ED91FC911997B8011995892B85
+:108E900021F0EE24EA94FF24FA942196EDCFC70145
+:108EA00002C08FEF9FEFDF91CF911F910F91FF9045
+:108EB000EF900895CF93DF93CDB7DEB7FE013696DE
+:108EC00061917191AF018091F61B9091F71BDED0FB
+:108ED000DF91CF9108950F931F93CF93DF93CDB779
+:108EE000DEB7FE0138966191719106EF1BE1D80162
+:108EF0008D919C91DC0113962C9113972860139609
+:108F00002C93AF01C3D0D801ED91FC912381277F31
+:108F10002383DF91CF911F910F9108950F931F939A
+:108F2000CF93DF93E091F61BF091F71B238121FF94
+:108F30001BC0EC0100E010E089916091F61B70917C
+:108F4000F71BDB011896ED91FC911997882331F0FE
+:108F50001995892B89F30FEF1FEFEECF8AE0199552
+:108F6000892B11F4C80102C08FEF9FEFDF91CF91E1
+:108F70001F910F9108950F931F93CF93DF93EC01EF
+:108F8000E091F61BF091F71B838181FF1CC000E08C
+:108F900010E0FE0184916091F61B7091F71BDB01DC
+:108FA0001896ED91FC911997882339F01995892B22
+:108FB00011F00FEF1FEF2196ECCF8AE01995892B66
+:108FC00011F4C80102C08FEF9FEFDF91CF911F9185
+:108FD0000F9108950F931F93CF93DF93CDB7DEB713
+:108FE0002E970FB6F894DEBF0FBECDBF0E891F8936
+:108FF00086E08C831A8309838FEF9FE79E838D839E
+:10900000AE01465E5F4F688D798DCE0101963ED0F0
+:10901000EF81F885E00FF11F10822E960FB6F894BD
+:10902000DEBF0FBECDBFDF91CF911F910F9108958D
+:109030000F931F93CF93DF93CDB7DEB72E970FB665
+:10904000F894DEBF0FBECDBF0E891F898EE08C83E2
+:109050001A8309838FEF9FE79E838D83AE01465E5F
+:109060005F4F688D798DCE01019610D0EF81F88524
+:10907000E00FF11F10822E960FB6F894DEBF0FBEE0
+:10908000CDBFDF91CF911F910F9108952F923F9205
+:109090004F925F926F927F928F929F92AF92BF9208
+:1090A000CF92DF92EF92FF920F931F93CF93DF93B4
+:1090B000CDB7DEB72C970FB6F894DEBF0FBECDBF8D
+:1090C0007C016B018A01FC0117821682838181FF7A
+:1090D000B0C1CE0101964C01F7019381F60193FDD9
+:1090E000859193FF81916F01882309F49EC1853298
+:1090F00039F493FD859193FF81916F01853221F4BD
+:10910000B70190E078DEE8CF512C312C20E02032FE
+:10911000A0F48B3269F030F4803259F0833269F474
+:1091200020612CC08D3239F0803339F4216026C0A3
+:109130002260246023C0286021C027FD27C030EDB5
+:10914000380F3A3078F426FF06C0FAE05F9E300D03
+:109150001124532E13C08AE0389E300D1124332E73
+:1091600020620CC08E3221F426FD5FC1206406C04F
+:109170008C3611F4206802C0883641F4F60193FD64
+:10918000859193FF81916F018111C1CF982F9F7DB0
+:109190009554933028F40C5F1F4FFFE3F9830DC003
+:1091A000833631F0833771F0833509F057C021C021
+:1091B000F801808189830E5F1F4F44244394512C12
+:1091C000540114C03801F2E06F0E711CF801A08048
+:1091D000B18026FF03C0652D70E002C06FEF7FEF06
+:1091E000C5012C87F5D32C0183012C852F77222EE6
+:1091F00016C03801F2E06F0E711CF801A080B1803A
+:1092000026FF03C0652D70E002C06FEF7FEFC50140
+:109210002C87D3D32C012C852068222E830123FC9C
+:1092200019C0832D90E048165906A0F4B70180E2DA
+:1092300090E0E1DD3A94F5CFF50127FC859127FE1A
+:1092400081915F01B70190E0D6DD31103A94F1E0F1
+:109250004F1A51084114510479F7DEC0843611F0D9
+:10926000893631F5F80127FF07C06081718182815D
+:1092700093810C5F1F4F08C060817181882777FD43
+:109280008095982F0E5F1F4F2F76B22E97FF09C043
+:1092900090958095709561957F4F8F4F9F4F206877
+:1092A000B22E2AE030E0A4019ED3A82EA81843C015
+:1092B000853729F42F7EB22E2AE030E025C0F22F28
+:1092C000F97FBF2E8F36C1F018F4883579F0ADC024
+:1092D000803719F0883721F0A8C02F2F2061B22ED7
+:1092E000B4FE0DC08B2D8460B82E09C024FF0AC0C7
+:1092F0009F2F9660B92E06C028E030E005C020E11F
+:1093000030E002C020E132E0F801B7FE07C0608122
+:109310007181828193810C5F1F4F06C060817181D2
+:1093200080E090E00E5F1F4FA4015DD3A82EA81827
+:10933000FB2DFF77BF2EB6FE0BC02B2D2E7FA51465
+:1093400050F4B4FE0AC0B2FC08C02B2D2E7E05C01E
+:109350007A2C2B2D03C07A2C01C0752C24FF0DC054
+:10936000FE01EA0DF11D8081803311F4297E09C0D0
+:1093700022FF06C07394739404C0822F867809F08C
+:10938000739423FD12C020FF06C05A2C731418F4E6
+:10939000530C5718732C731460F4B70180E290E0FB
+:1093A0002C8729DD73942C85F6CF731410F43718AD
+:1093B00001C0312C24FF11C0B70180E390E02C875D
+:1093C0001ADD2C8522FF16C021FF03C088E590E03E
+:1093D00002C088E790E0B7010CC0822F867851F078
+:1093E00021FD02C080E201C08BE227FD8DE2B701C2
+:1093F00090E001DDA51430F4B70180E390E0FBDCE0
+:109400005A94F8CFAA94F401EA0DF11D8081B701B6
+:1094100090E0F1DCA110F6CF332009F45DCEB70166
+:1094200080E290E0E8DC3A94F7CFF70186819781FB
+:1094300002C08FEF9FEF2C960FB6F894DEBF0FBEE1
+:10944000CDBFDF91CF911F910F91FF90EF90DF90F3
+:10945000CF90BF90AF909F908F907F906F905F90D4
+:109460004F903F902F900895DC01CB01FC01F999BA
+:10947000FECF06C0F2BDE1BDF89A319600B40D9260
+:1094800041505040B8F70895F999FECF92BD81BD83
+:10949000F89A992780B50895A6E1B0E044E050E03D
+:1094A000E5CFA8E1B0E042E050E0E0CF262FF99907
+:1094B000FECF92BD81BDF89A019700B4021639F033
+:1094C0001FBA20BD0FB6F894FA9AF99A0FBE089504
+:1094D0000396272FECDFEADF252FE9DF242FE7CFE4
+:1094E0000196272FE4DFE2CF262FF999FECF1FBA8E
+:1094F00092BD81BD20BD0FB6F894FA9AF99A0FBEBD
+:1095000001960895F1DF272FF0CF6F927F929F92FF
+:10951000AF92BF92CF92DF92EF92FF920F931F9381
+:10952000CF93DF93CDB7DEB729970FB6F894DEBFA0
+:109530000FBECDBF6A01B22E102F0C3320F4FF24D2
+:10954000F394F00E02C04CE3F42E0F2D27E0AE0191
+:109550004F5F5F4F57D17981272F2970213031F02C
+:10956000E1FC06C0E0FC06C060E005C06DE203C09F
+:109570006BE201C060E2AE2DA07173FF36C06623BE
+:1095800011F084E001C083E08B1510F4B81A01C01B
+:10959000B12CA1110BC0F6018B2D90E2882319F09C
+:1095A00091938150FBCFCB0CD11CB12C662331F0B1
+:1095B000F601608396012F5F3F4F6901C601039654
+:1095C000E2FE05C02EE4F601208331E404C02EE65D
+:1095D000F601208331E631832283FC012B2D30E21A
+:1095E0002223F1F131932150FBCF72FF40C066235B
+:1095F00011F084E001C083E08B1510F4B81A01C0AB
+:10960000B12CA1110BC0F6018B2D90E2882319F02B
+:1096100091938150FBCFCB0CD11CB12C662331F040
+:10962000F601608396012F5F3F4F6901C6010396E3
+:10963000E2FE07C029E4F60120832EE4218326E41C
+:1096400006C029E6F60120832EE6218326E6228342
+:10965000FC012B2D30E2222319F031932150FBCF56
+:10966000FC01EB0DF11D10828EEF9FEFB7C0B1E052
+:10967000611101C0B0E04B2F50E01816190624F418
+:109680009C012F5F3F4F02C021E030E0240F351FC7
+:10969000112329F0412F50E04F5F5F4F02C040E09F
+:1096A00050E0420F531F2B2D30E04217530714F4A4
+:1096B000B41A01C0B12C2E2D287159F4F6012B2DAE
+:1096C00030E2222319F031932150FBCFCB0CD11C77
+:1096D000B12CBB2331F0F601608396012F5F3F4F21
+:1096E0006901A1110BC0F6012B2D30E3222319F0E3
+:1096F00031932150FBCFCB0CD11CB12CF80E0A8139
+:10970000372F3071A32E74FF03C0013309F4FA948C
+:109710001F142CF42F2D293018F028E001C021E06F
+:10972000682F392F97FF02C060E030E0462F532F9B
+:10973000612C712C3EE2932EBC01621B71099B01CE
+:10974000DC01A41BB50BE1E0F0E0EC0FFD1FAE0F58
+:10975000BF1FE12EF12CF194E194F1084F3FFFEF90
+:109760005F0731F4F6019082B6016F5F7F4F6B01A6
+:10977000841795074CF02417350734F4BD01660DA6
+:10978000771DFB01118101C010E341505109FFEF2A
+:109790006F1A7F0AB6016F5F7F4F4E155F0524F089
+:1097A000F60110836B01DACF4817590739F40633F5
+:1097B00020F4053319F4A11001C011E3F601108360
+:1097C000FB018B2D90E2882319F091938150FBCF00
+:1097D000FB01EB0DF11D108280E090E029960FB6A1
+:1097E000F894DEBF0FBECDBFDF91CF911F910F91D7
+:1097F000FF90EF90DF90CF90BF90AF909F907F90C1
+:109800006F900895283008F027E03327DA01990F88
+:10981000311D87FD916000966105710539F4326054
+:109820002E5F3D9330E32A95E1F708959F3F30F096
+:1098300080387105610509F03C5F3C5F3D939130D4
+:1098400008F08068911DDF93CF931F930F93FF92D1
+:10985000EF92192F987F9695E92F96959695E90F97
+:10986000FF27E05CF34A99273327EE24FF24A70162
+:10987000E70105900894079428F4360FE71EF81EB8
+:10988000491F511D660F771F881F991F0694A1F766
+:109890000590079428F4E70EF81E491F561FC11DB6
+:1098A000770F881F991F661F0694A1F705900794EC
+:1098B00028F4F80E491F561FC71FD11D880F991F86
+:1098C000661F771F0694A1F70590079420F4490FAF
+:1098D000561FC71FD81F990F661F771F881F069432
+:1098E000A9F784911095177041F0D695C7955795B3
+:1098F0004795F794E7941A95C1F7E6EEFBE568946F
+:109900001590159135916591959105907FE273952C
+:10991000E118F10A430B560BC90BD009C0F7E10C53
+:10992000F11E431F561FC91FD01D7EF4703311F462
+:109930008A95E6CFE894015030F0080F0AF400272A
+:10994000021708F4202F2395022F7A3328F079E3A9
+:109950007D932A95E9F710C07D932A9589F60694A0
+:1099600097956795379517951794E118F10A430B6A
+:10997000560BC90BD00998F023957E9173957A33D5
+:1099800008F070E37C932013B8F77E9170617D93AB
+:1099900030F0839571E37D9370E32A95E1F711240C
+:1099A000EF90FF900F911F91CF91DF91992787FD45
+:1099B00090950895992788270895FC010590615096
+:1099C00070400110D8F7809590958E0F9F1F0895D5
+:1099D000FC016150704001900110D8F7809590957E
+:1099E0008E0F9F1F0895FA01AA27283051F12031C8
+:1099F00081F1E8946F936E7F6E5F7F4F8F4F9F4F23
+:109A0000AF4FB1E03ED0B4E03CD0670F781F891F64
+:109A10009A1FA11D680F791F8A1F911DA11D6A0F32
+:109A2000711D811D911DA11D20D009F468943F91E5
+:109A30002AE0269F11243019305D3193DEF6CF01E4
+:109A40000895462F4770405D4193B3E00FD0C9F7AA
+:109A5000F6CF462F4F70405D4A3318F0495D31FD17
+:109A60004052419302D0A9F7EACFB4E0A69597956A
+:109A7000879577956795BA95C9F700976105710540
+:109A800008959B01AC010A2E06945795479537958A
+:109A90002795BA95C9F7620F731F841F951FA01DE4
+:109AA00008951CE5CAEEDCE500E006C02297010936
+:109AB000FE010BBF0F9406C3CC3ED10780E0080720
+:069AC000A9F7F894FFCFA6
+:109AC6000000FC1B8000010160EA00000080BB442E
+:109AD60002FFFFFFFF0100010000004100003442C9
+:109AE600000050410000404000007F430000524308
+:109AF6000000524300000000000080C09A99193E01
+:109B06000000803F00004040640081018101810126
+:109B1600810164006400640000401C4500803B45F0
+:109B2600000048440000000001013002000002432A
+:109B3600FFFF01010101019001EE02EE029001EE2C
+:109B460002EE029001EE02EE02B115140E01FF3F85
+:109B5600FF3FFF3F1F4C62B045E65A343F8F42FC41
+:109B6600420000803FB099AB43FF08433E3D0A8167
+:109B76004101FF030303030304030302020101027D
+:109B860002E6EB0A0A140A0D1414230D14142329F1
+:109B96002743420102DD010100005243011E00017C
+:109BA6000101FF0000C8420000C8420000C843008F
+:109BB600000C440000FA430000FA43000040410054
+:109BC60000F042E8030000E8030000C80000008837
+:109BD6001300000000400014005400001F1511156A
+:109BE6001F00000C12120C00000000040A0A0A0AE8
+:109BF60011110E040E1F041C0000000006191803A4
+:109C0600130C00001C1F11111F0000000412091282
+:109C1600040000000E1315110E00000000000000E5
+:109C2600110A040000110A04110A04442D31202DE2
+:109C360020456E646C657373206C6F6F70005049BD
+:109C46004E25643D2564007265735F783D2564206A
+:109C56007265735F793D256420783D256420793DE2
+:109C6600256420623D256420733D25640A000000BA
+:109C7600000044405F0163726173686465745F65E8
+:109C86006E61626C650063726173686465745F64BB
+:109C9600697361626C650043524153485F444554A1
+:109CA6004543544544004D313137004352415348F2
+:109CB6005F5245434F5645520043524153485F4316
+:109CC600414E43454C0050525553410050696E6712
+:109CD6000050524E0046414E0045303A0020525048
+:109CE6004D0050524E303A00666E004E6F74206939
+:109CF6006E206661726D206D6F64652E006676005B
+:109D06004D323800534E003B530046697200332EE5
+:109D1600312E312D5243310052657600315F373591
+:109D26006D6D5F4D4B332D45494E595F3034612D76
+:109D3600453344763666756C6C004C616E67004C34
+:109D46007A0053455249414C204C4F5700534552D7
+:109D560049414C20484947480042656174004652D3
+:109D6600005072757361206933204D4B33002070AB
+:109D76003A0020693A0020643A0020633A00212123
+:109D860021214D3630302121212100746D6332317D
+:109D960033305F73675F7468725B585D3D00746D46
+:109DA60063323133305F73675F7468725B595D3D50
+:109DB60000746D63323133305F73675F7468725B52
+:109DC6005A5D3D00746D63323133305F73675F7483
+:109DD60068725B455D3D00437261736844657465F6
+:109DE600637420454E41424C4544210043726173E1
+:109DF600684465746563742044495341424C454444
+:109E06000000000100250031001D000C0040002468
+:109E16000030001C000B00450023002F001B000A29
+:109E2600001700FFFF0400060022002B001A0003A3
+:109E360000360037003500380058595A45000000F2
+:109E46000018B05F012F006F70656E206661696C47
+:109E560065642C2046696C653A20004E6F7420704C
+:109E660072696E74696E6700416E206572726F72F8
+:109E7600207768696C652077726974696E672074EB
+:109E86006F2074686520534420436172642E00532A
+:109E9600442D5052494E54494E4720202020202020
+:109EA600202020004D313132006673656E736F726B
+:109EB6005F75706461746520286673656E736F7272
+:109EC6005F6572725F636E74203E204653454E5343
+:109ED6004F525F4552525F4D415829006673656E79
+:109EE600736F725F757064617465202D20455252E0
+:109EF6004F522121210035FA8E3B1F42093B504922
+:109F060044204175746F74756E6520737461727444
+:109F160000504944204175746F74756E6520666102
+:109F2600696C65642E20426164206578747275647C
+:109F36006572206E756D6265722E00746D633231C6
+:109F460033305F7072696E745F63757272656E74BA
+:109F5600730009480D52005809005909005A0900B2
+:109F6600450900746D63323133305F7365745F7019
+:109F7600776D5F616D706C2000746D6332313330C4
+:109F86005F7365745F70776D5F67726164200074DC
+:109F96006D63323133305F7365745F6375727265FA
+:109FA6006E745F682000746D63323133305F7365A1
+:109FB600745F63757272656E745F722000746D6390
+:109FC600323133305F696E6974206D6F64653D00B0
+:109FD6007374616E647374696C6C204E47210073F0
+:109FE60074616E647374696C6C204F4B005B5052E5
+:109FF6004E3A005B5354303A005D5B5354423A008C
+:10A006005D5B4154303A005D5B4154423A003E008C
+:10A016004C616E677561676500537461746973742A
+:10A02600696373005368697070696E672070726542
+:10A036007000416C6C2044617461004661696C7506
+:10A046007265207374617473202020202020200004
+:10A0560020506F776572206661696C757265733A18
+:10A066002020202000204372617368206465746597
+:10A07600637465643A20202020002046696C616D77
+:10A08600656E74206661696C733A20202020007B1F
+:10A096005B4552523A345D007B5B4552523A335D22
+:10A0A600007B5B4552523A325D007B5B4552523A29
+:10A0B600315D007B5B50524E3A355D007B007B5B29
+:10A0C60050524E3A305D5B50464E3A007B5B5052E2
+:10A0D6004E3A395D007B5B50524E3A385D007B5BF1
+:10A0E6005245533A305D007B5B5245533A315D0031
+:10A0F6007B5B50524E3A39395D005B5446553A0007
+:10A106005D5B5043443A005D5B46454D3A005D5BFE
+:10A11600464E4D3A005D5B54494D3A005D5B4657ED
+:10A12600523A005D7D004661726D206E6F00300010
+:10A136005E00206D6D0046696C2E2058643A005909
+:10A14600643A00496E743A202020202020202020E6
+:10A156002020202000536875743A20202020004CCF
+:10A166006F6164696E672066696C616D656E740007
+:10A176006D2000636D006B6D00680020202020209C
+:10A1860020202020202020202020202020202000E9
+:10A196005072696E74206F6B203F007C002D2D2D50
+:10A1A6002D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2DD9
+:10A1B6002D00486F74656E640042656400010047B7
+:10A1C6003120583730205900473120590047312077
+:10A1D6005835302059004D33303120500020490089
+:10A1E6002044004731205A004D3130392053004D6C
+:10A1F600313034205300473120580047312058353C
+:10A2060030205933352045004D333033204530203A
+:10A21600530025642F360045787472756465722084
+:10A226000000C0284500C0284500007A440000C848
+:0EA23600426E616E00696E66006F7666000013
+:00000001FF

+ 1 - 1
Firmware/Firmware.sublime-project

@@ -19,7 +19,7 @@
   			// avrdude -F -v -pm168 -cstk500v1 -P\\.\COM4 -b19200 -D -Uflash:w:"file.hex":i
   			// may need add path to avrdude config file: -C"c:\utils\arduino-0016\hardware\tools\avr\etc\avrdude.conf" if Arduino IDE installed in "c:\utils\arduino-0016\"
   			// https://typeunsafe.wordpress.com/2011/07/22/programming-arduino-with-avrdude/
-			"shell_cmd": "\"c:\\Program Files (x86)\\Arduino\\arduino_debug.exe\" --pref build.path=..\\output --upload --port COM6 --board marlinAddon:avr:rambo -v --preserve-temp-files Firmware.ino"
+			"shell_cmd": "\"c:\\Program Files (x86)\\Arduino\\arduino_debug.exe\" --pref build.path=..\\output --upload --port COM9 --board marlinAddon:avr:rambo -v --preserve-temp-files Firmware.ino"
 		},
 		{
 			"name": "map-data",

+ 142 - 1
Firmware/LiquidCrystal.cpp

@@ -156,6 +156,8 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
   command(LCD_ENTRYMODESET | _displaymode);
   delayMicroseconds(60);
 
+  _escape[0] = 0;
+
 }
 
 
@@ -354,10 +356,149 @@ inline void LiquidCrystal::command(uint8_t value) {
 }
 
 inline size_t LiquidCrystal::write(uint8_t value) {
+  if (_escape[0] || (value == 0x1b))
+    return escape_write(value);
   send(value, HIGH);
   return 1; // assume sucess
 }
 
+//Supported VT100 escape codes:
+//EraseScreen  "\x1b[2J"
+//CursorHome   "\x1b[%d;%dH"
+//CursorShow   "\x1b[?25h"
+//CursorHide   "\x1b[?25l"
+
+inline size_t LiquidCrystal::escape_write(uint8_t chr)
+{
+#define escape_cnt (_escape[0])        //escape character counter
+#define is_num_msk (_escape[1])        //numeric character bit mask
+#define chr_is_num (is_num_msk & 0x01) //current character is numeric
+#define e_2_is_num (is_num_msk & 0x04) //escape char 2 is numeric
+#define e_3_is_num (is_num_msk & 0x08) //...
+#define e_4_is_num (is_num_msk & 0x10)
+#define e_5_is_num (is_num_msk & 0x20)
+#define e_6_is_num (is_num_msk & 0x40)
+#define e_7_is_num (is_num_msk & 0x80)
+#define e2_num (_escape[2] - '0')      //number from character 2
+#define e3_num (_escape[3] - '0')      //number from character 3
+#define e23_num (10*e2_num+e3_num)     //number from characters 2 and 3
+#define e4_num (_escape[4] - '0')      //number from character 4
+#define e5_num (_escape[5] - '0')      //number from character 5
+#define e45_num (10*e4_num+e5_num)     //number from characters 4 and 5
+#define e6_num (_escape[6] - '0')      //number from character 6
+#define e56_num (10*e5_num+e6_num)     //number from characters 5 and 6
+	if (escape_cnt > 1) // escape length > 1 = "\x1b["
+	{
+		_escape[escape_cnt] = chr; // store current char
+		if ((chr >= '0') && (chr <= '9')) // char is numeric
+			is_num_msk |= (1 | (1 << escape_cnt)); //set mask
+		else
+			is_num_msk &= ~1; //clear mask
+	}
+	switch (escape_cnt++)
+	{
+	case 0:
+		if (chr == 0x1b) return 1;  // escape = "\x1b"
+		break;
+	case 1:
+		is_num_msk = 0x00; // reset 'is number' bit mask
+		if (chr == '[') return 1; // escape = "\x1b["
+		break;
+	case 2:
+		switch (chr)
+		{
+		case '2': return 1; // escape = "\x1b[2"
+		case '?': return 1; // escape = "\x1b[?"
+		default:
+			if (chr_is_num) return 1; // escape = "\x1b[%1d"
+		}
+		break;
+	case 3:
+		switch (_escape[2])
+		{
+		case '?': // escape = "\x1b[?"
+			if (chr == '2') return 1; // escape = "\x1b[?2"
+			break;
+		case '2':
+			if (chr == 'J') // escape = "\x1b[2J"
+				{ clear(); break; } // EraseScreen
+		default:
+			if (e_2_is_num && // escape = "\x1b[%1d"
+				((chr == ';') || // escape = "\x1b[%1d;"
+				chr_is_num)) // escape = "\x1b[%2d"
+				return 1;
+		}
+		break;
+	case 4:
+		switch (_escape[2])
+		{
+		case '?': // "\x1b[?"
+			if ((_escape[3] == '2') && (chr == '5')) return 1; // escape = "\x1b[?25"
+			break;
+		default:
+			if (e_2_is_num) // escape = "\x1b[%1d"
+			{
+				if ((_escape[3] == ';') && chr_is_num) return 1; // escape = "\x1b[%1d;%1d"
+				else if (e_3_is_num && (chr == ';')) return 1; // escape = "\x1b[%2d;"
+			}
+		}
+		break;
+	case 5:
+		switch (_escape[2])
+		{
+		case '?':
+			if ((_escape[3] == '2') && (_escape[4] == '5')) // escape = "\x1b[?25"
+				switch (chr)
+				{
+				case 'h': // escape = "\x1b[?25h"
+  					void cursor(); // CursorShow
+					break;
+				case 'l': // escape = "\x1b[?25l"
+					noCursor(); // CursorHide
+					break;
+				}
+			break;
+		default:
+			if (e_2_is_num) // escape = "\x1b[%1d"
+			{
+				if ((_escape[3] == ';') && e_4_is_num) // escape = "\x1b%1d;%1dH"
+				{
+					if (chr == 'H') // escape = "\x1b%1d;%1dH"
+						setCursor(e4_num, e2_num); // CursorHome
+					else if (chr_is_num)
+						return 1; // escape = "\x1b%1d;%2d"
+				}
+				else if (e_3_is_num && (_escape[4] == ';') && chr_is_num)
+					return 1; // escape = "\x1b%2d;%1d"
+			}
+		}
+		break;
+	case 6:
+		if (e_2_is_num) // escape = "\x1b[%1d"
+		{
+			if ((_escape[3] == ';') && e_4_is_num && e_5_is_num && (chr == 'H')) // escape = "\x1b%1d;%2dH"
+				setCursor(e45_num, e2_num); // CursorHome
+			else if (e_3_is_num && (_escape[4] == ';') && e_5_is_num) // escape = "\x1b%2d;%1d"
+			{
+				if (chr == 'H') // escape = "\x1b%2d;%1dH"
+					setCursor(e5_num, e23_num); // CursorHome
+				else if (chr_is_num) // "\x1b%2d;%2d"
+					return 1;
+			}
+		}
+		break;
+	case 7:
+		if (e_2_is_num && e_3_is_num && (_escape[4] == ';')) // "\x1b[%2d;"
+			if (e_5_is_num && e_6_is_num && (chr == 'H')) // "\x1b[%2d;%2dH"
+				setCursor(e56_num, e23_num); // CursorHome
+		break;
+	}
+	escape_cnt = 0; // reset escape
+end:
+	return 1; // assume sucess
+}
+
+
 /************ low level data pushing commands **********/
 
 // write either command or data, with automatic 4/8-bit selection
@@ -402,4 +543,4 @@ void LiquidCrystal::write8bits(uint8_t value) {
   }
   
   pulseEnable();
-}
+}

+ 10 - 1
Firmware/LiquidCrystal.h

@@ -103,6 +103,15 @@ private:
   uint8_t _initialized;
 
   uint8_t _numlines,_currline;
+
+  uint8_t _escape[8];
+  size_t escape_write(uint8_t value);
+  
 };
 
-#endif
+#define ESC_2J     "\x1b[2J"
+#define ESC_25h    "\x1b[?25h"
+#define ESC_25l    "\x1b[?25l"
+#define ESC_H(c,r) "\x1b["#r";"#c"H"
+
+#endif

+ 427 - 312
Firmware/Marlin.h

@@ -1,312 +1,427 @@
-// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
-// License: GPL
-
-#ifndef MARLIN_H
-#define MARLIN_H
-
-#define  FORCE_INLINE __attribute__((always_inline)) inline
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include <util/delay.h>
-#include <avr/pgmspace.h>
-#include <avr/eeprom.h>
-#include <avr/interrupt.h>
-
-
-#include "fastio.h"
-#include "Configuration.h"
-#include "pins.h"
-
-#ifndef AT90USB
-#define  HardwareSerial_h // trick to disable the standard HWserial
-#endif
-
-#if (ARDUINO >= 100)
-# include "Arduino.h"
-#else
-# include "WProgram.h"
-#endif
-
-// Arduino < 1.0.0 does not define this, so we need to do it ourselves
-#ifndef analogInputToDigitalPin
-# define analogInputToDigitalPin(p) ((p) + A0)
-#endif
-
-#ifdef AT90USB
-#include "HardwareSerial.h"
-#endif
-
-#include "MarlinSerial.h"
-
-#ifndef cbi
-#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
-#endif
-#ifndef sbi
-#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
-#endif
-
-#include "WString.h"
-
-#ifdef AT90USB
-   #ifdef BTENABLED
-         #define MYSERIAL bt
-   #else
-         #define MYSERIAL Serial
-   #endif // BTENABLED
-#else
-  #define MYSERIAL MSerial
-#endif
-
-#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x))
-#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y))
-#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x)))
-#define SERIAL_PROTOCOLRPGM(x) (serialprintPGM((x)))
-#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n'))
-#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n'))
-#define SERIAL_PROTOCOLLNRPGM(x) (serialprintPGM((x)),MYSERIAL.write('\n'))
-
-
-extern const char errormagic[] PROGMEM;
-extern const char echomagic[] PROGMEM;
-
-#define SERIAL_ERROR_START (serialprintPGM(errormagic))
-#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
-#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
-#define SERIAL_ERRORRPGM(x) SERIAL_PROTOCOLRPGM(x)
-#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
-#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
-#define SERIAL_ERRORLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x)
-
-#define SERIAL_ECHO_START (serialprintPGM(echomagic))
-#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
-#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
-#define SERIAL_ECHORPGM(x) SERIAL_PROTOCOLRPGM(x)
-#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
-#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
-#define SERIAL_ECHOLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x)
-
-#define SERIAL_ECHOPAIR(name,value) (serial_echopair_P(PSTR(name),(value)))
-
-void serial_echopair_P(const char *s_P, float v);
-void serial_echopair_P(const char *s_P, double v);
-void serial_echopair_P(const char *s_P, unsigned long v);
-
-
-//Things to write to serial from Program memory. Saves 400 to 2k of RAM.
-FORCE_INLINE void serialprintPGM(const char *str)
-{
-  char ch=pgm_read_byte(str);
-  while(ch)
-  {
-    MYSERIAL.write(ch);
-    ch=pgm_read_byte(++str);
-  }
-}
-
-
-void get_command();
-void process_commands();
-
-void manage_inactivity(bool ignore_stepper_queue=false);
-
-#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1
-  #define  enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON)
-  #define disable_x() { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); axis_known_position[X_AXIS] = false; }
-#else
-  #define enable_x() ;
-  #define disable_x() ;
-#endif
-
-#if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1
-  #ifdef Y_DUAL_STEPPER_DRIVERS
-    #define  enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN,  Y_ENABLE_ON); }
-    #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
-  #else
-    #define  enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
-    #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
-  #endif
-#else
-  #define enable_y() ;
-  #define disable_y() ;
-#endif
-
-#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 
-	#if defined(Z_AXIS_ALWAYS_ON)
-		  #ifdef Z_DUAL_STEPPER_DRIVERS
-			#define  enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
-			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
-		  #else
-			#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
-			#define  disable_z() ;
-		  #endif
-	#else
-		#ifdef Z_DUAL_STEPPER_DRIVERS
-			#define  enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
-			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
-		#else
-			#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
-			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
-		#endif
-	#endif
-#else
-  #define enable_z() ;
-  #define disable_z() ;
-#endif
-
-
-
-
-//#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
-//#ifdef Z_DUAL_STEPPER_DRIVERS
-//#define  enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
-//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
-//#else
-//#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
-//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
-//#endif
-//#else
-//#define enable_z() ;
-//#define disable_z() ;
-//#endif
-
-
-#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1)
-  #define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON)
-  #define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON)
-#else
-  #define enable_e0()  /* nothing */
-  #define disable_e0() /* nothing */
-#endif
-
-#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
-  #define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON)
-  #define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON)
-#else
-  #define enable_e1()  /* nothing */
-  #define disable_e1() /* nothing */
-#endif
-
-#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
-  #define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON)
-  #define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON)
-#else
-  #define enable_e2()  /* nothing */
-  #define disable_e2() /* nothing */
-#endif
-
-
-enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5};
-
-
-void FlushSerialRequestResend();
-void ClearToSend();
-
-void get_coordinates();
-void prepare_move();
-void kill(const char *full_screen_message = NULL);
-void Stop();
-
-bool IsStopped();
-
-//put an ASCII command at the end of the current buffer.
-void enquecommand(const char *cmd, bool from_progmem = false);
-//put an ASCII command at the end of the current buffer, read from flash
-#define enquecommand_P(cmd) enquecommand(cmd, true)
-void enquecommand_front(const char *cmd, bool from_progmem = false);
-//put an ASCII command at the end of the current buffer, read from flash
-#define enquecommand_P(cmd) enquecommand(cmd, true)
-#define enquecommand_front_P(cmd) enquecommand_front(cmd, true)
-void repeatcommand_front();
-
-void prepare_arc_move(char isclockwise);
-void clamp_to_software_endstops(float target[3]);
-
-void refresh_cmd_timeout(void);
-
-#ifdef FAST_PWM_FAN
-void setPwmFrequency(uint8_t pin, int val);
-#endif
-
-#ifndef CRITICAL_SECTION_START
-  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
-  #define CRITICAL_SECTION_END    SREG = _sreg;
-#endif //CRITICAL_SECTION_START
-
-extern float homing_feedrate[];
-extern bool axis_relative_modes[];
-extern int feedmultiply;
-extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
-extern bool volumetric_enabled;
-extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
-extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
-extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
-extern float current_position[NUM_AXIS] ;
-extern float destination[NUM_AXIS] ;
-extern float add_homing[3];
-extern float min_pos[3];
-extern float max_pos[3];
-extern bool axis_known_position[3];
-extern float zprobe_zoffset;
-extern int fanSpeed;
-extern void homeaxis(int axis);
-
-
-#ifdef FAN_SOFT_PWM
-extern unsigned char fanSpeedSoftPwm;
-#endif
-
-#ifdef FILAMENT_SENSOR
-  extern float filament_width_nominal;  //holds the theoretical filament diameter ie., 3.00 or 1.75
-  extern bool filament_sensor;  //indicates that filament sensor readings should control extrusion
-  extern float filament_width_meas; //holds the filament diameter as accurately measured
-  extern signed char measurement_delay[];  //ring buffer to delay measurement
-  extern int delay_index1, delay_index2;  //index into ring buffer
-  extern float delay_dist; //delay distance counter
-  extern int meas_delay_cm; //delay distance
-#endif
-
-#ifdef FWRETRACT
-extern bool autoretract_enabled;
-extern bool retracted[EXTRUDERS];
-extern float retract_length, retract_length_swap, retract_feedrate, retract_zlift;
-extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate;
-#endif
-
-extern unsigned long starttime;
-extern unsigned long stoptime;
-extern bool is_usb_printing;
-extern unsigned int usb_printing_counter;
-
-extern unsigned long total_filament_used;
-void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time);
-extern unsigned int heating_status;
-extern unsigned int heating_status_counter;
-extern bool custom_message;
-extern unsigned int custom_message_type;
-extern unsigned int custom_message_state;
-
-
-// Handling multiple extruders pins
-extern uint8_t active_extruder;
-
-#ifdef DIGIPOT_I2C
-extern void digipot_i2c_set_current( int channel, float current );
-extern void digipot_i2c_init();
-#endif
-
-#endif
-
-
-
-
-
-extern void calculate_volumetric_multipliers();
-
-// Similar to the default Arduino delay function, 
-// but it keeps the background tasks running.
-extern void delay_keep_alive(int ms);
+// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
+// License: GPL
+
+#ifndef MARLIN_H
+#define MARLIN_H
+
+#define  FORCE_INLINE __attribute__((always_inline)) inline
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <util/delay.h>
+#include <avr/pgmspace.h>
+#include <avr/eeprom.h>
+#include <avr/interrupt.h>
+
+
+#include "fastio.h"
+#include "Configuration.h"
+#include "pins.h"
+
+#ifndef AT90USB
+#define  HardwareSerial_h // trick to disable the standard HWserial
+#endif
+
+#if (ARDUINO >= 100)
+# include "Arduino.h"
+#else
+# include "WProgram.h"
+#endif
+
+// Arduino < 1.0.0 does not define this, so we need to do it ourselves
+#ifndef analogInputToDigitalPin
+# define analogInputToDigitalPin(p) ((p) + A0)
+#endif
+
+#ifdef AT90USB
+#include "HardwareSerial.h"
+#endif
+
+#include "MarlinSerial.h"
+
+#ifndef cbi
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+#ifndef sbi
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+#include "WString.h"
+
+#ifdef AT90USB
+   #ifdef BTENABLED
+         #define MYSERIAL bt
+   #else
+         #define MYSERIAL Serial
+   #endif // BTENABLED
+#else
+  #define MYSERIAL MSerial
+#endif
+
+extern FILE _lcdout;
+#define lcdout (&_lcdout)
+
+extern FILE _uartout;
+#define uartout (&_uartout)
+
+#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x))
+#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y))
+#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x)))
+#define SERIAL_PROTOCOLRPGM(x) (serialprintPGM((x)))
+#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n'))
+#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n'))
+#define SERIAL_PROTOCOLLNRPGM(x) (serialprintPGM((x)),MYSERIAL.write('\n'))
+
+
+extern const char errormagic[] PROGMEM;
+extern const char echomagic[] PROGMEM;
+
+#define SERIAL_ERROR_START (serialprintPGM(errormagic))
+#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
+#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
+#define SERIAL_ERRORRPGM(x) SERIAL_PROTOCOLRPGM(x)
+#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
+#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
+#define SERIAL_ERRORLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x)
+
+#define SERIAL_ECHO_START (serialprintPGM(echomagic))
+#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
+#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
+#define SERIAL_ECHORPGM(x) SERIAL_PROTOCOLRPGM(x)
+#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
+#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
+#define SERIAL_ECHOLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x)
+
+#define SERIAL_ECHOPAIR(name,value) (serial_echopair_P(PSTR(name),(value)))
+
+void serial_echopair_P(const char *s_P, float v);
+void serial_echopair_P(const char *s_P, double v);
+void serial_echopair_P(const char *s_P, unsigned long v);
+
+
+//Things to write to serial from Program memory. Saves 400 to 2k of RAM.
+FORCE_INLINE void serialprintPGM(const char *str)
+{
+  char ch=pgm_read_byte(str);
+  while(ch)
+  {
+    MYSERIAL.write(ch);
+    ch=pgm_read_byte(++str);
+  }
+}
+
+bool is_buffer_empty();
+void get_command();
+void process_commands();
+void ramming();
+
+void manage_inactivity(bool ignore_stepper_queue=false);
+
+#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1
+  #define  enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON)
+  #define disable_x() { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); axis_known_position[X_AXIS] = false; }
+#else
+  #define enable_x() ;
+  #define disable_x() ;
+#endif
+
+#if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1
+  #ifdef Y_DUAL_STEPPER_DRIVERS
+    #define  enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN,  Y_ENABLE_ON); }
+    #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
+  #else
+    #define  enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
+    #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
+  #endif
+#else
+  #define enable_y() ;
+  #define disable_y() ;
+#endif
+
+#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 
+	#if defined(Z_AXIS_ALWAYS_ON)
+		  #ifdef Z_DUAL_STEPPER_DRIVERS
+			#define  enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
+			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
+		  #else
+			#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
+			#define  disable_z() ;
+		  #endif
+	#else
+		#ifdef Z_DUAL_STEPPER_DRIVERS
+			#define  enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
+			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
+		#else
+			#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
+			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
+		#endif
+	#endif
+#else
+  #define enable_z() ;
+  #define disable_z() ;
+#endif
+
+
+
+
+//#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
+//#ifdef Z_DUAL_STEPPER_DRIVERS
+//#define  enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
+//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
+//#else
+//#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
+//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
+//#endif
+//#else
+//#define enable_z() ;
+//#define disable_z() ;
+//#endif
+
+
+#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1)
+  #define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON)
+  #define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON)
+#else
+  #define enable_e0()  /* nothing */
+  #define disable_e0() /* nothing */
+#endif
+
+#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
+  #define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON)
+  #define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON)
+#else
+  #define enable_e1()  /* nothing */
+  #define disable_e1() /* nothing */
+#endif
+
+#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
+  #define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON)
+  #define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON)
+#else
+  #define enable_e2()  /* nothing */
+  #define disable_e2() /* nothing */
+#endif
+
+
+enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5};
+#define X_AXIS_MASK  1
+#define Y_AXIS_MASK  2
+#define Z_AXIS_MASK  4
+#define E_AXIS_MASK  8
+#define X_HEAD_MASK 16
+#define Y_HEAD_MASK 32
+
+
+void FlushSerialRequestResend();
+void ClearToSend();
+
+void get_coordinates();
+void prepare_move();
+void kill(const char *full_screen_message = NULL, unsigned char id = 0);
+void Stop();
+
+bool IsStopped();
+
+//put an ASCII command at the end of the current buffer.
+void enquecommand(const char *cmd, bool from_progmem = false);
+//put an ASCII command at the end of the current buffer, read from flash
+#define enquecommand_P(cmd) enquecommand(cmd, true)
+void enquecommand_front(const char *cmd, bool from_progmem = false);
+//put an ASCII command at the end of the current buffer, read from flash
+#define enquecommand_P(cmd) enquecommand(cmd, true)
+#define enquecommand_front_P(cmd) enquecommand_front(cmd, true)
+void repeatcommand_front();
+// Remove all lines from the command queue.
+void cmdqueue_reset();
+
+void prepare_arc_move(char isclockwise);
+void clamp_to_software_endstops(float target[3]);
+void refresh_cmd_timeout(void);
+
+#ifdef FAST_PWM_FAN
+void setPwmFrequency(uint8_t pin, int val);
+#endif
+
+#ifndef CRITICAL_SECTION_START
+  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
+  #define CRITICAL_SECTION_END    SREG = _sreg;
+#endif //CRITICAL_SECTION_START
+
+extern float homing_feedrate[];
+extern bool axis_relative_modes[];
+extern int feedmultiply;
+extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
+extern bool volumetric_enabled;
+extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
+extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
+extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
+extern float current_position[NUM_AXIS] ;
+extern float destination[NUM_AXIS] ;
+extern float add_homing[3];
+extern float min_pos[3];
+extern float max_pos[3];
+extern bool axis_known_position[3];
+extern float zprobe_zoffset;
+extern int fanSpeed;
+extern void homeaxis(int axis);
+
+
+#ifdef FAN_SOFT_PWM
+extern unsigned char fanSpeedSoftPwm;
+#endif
+
+#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+extern unsigned char lcdSoftPwm;
+extern unsigned char lcdBlinkDelay;
+#endif
+
+#ifdef FILAMENT_SENSOR
+  extern float filament_width_nominal;  //holds the theoretical filament diameter ie., 3.00 or 1.75
+  extern bool filament_sensor;  //indicates that filament sensor readings should control extrusion
+  extern float filament_width_meas; //holds the filament diameter as accurately measured
+  extern signed char measurement_delay[];  //ring buffer to delay measurement
+  extern int delay_index1, delay_index2;  //index into ring buffer
+  extern float delay_dist; //delay distance counter
+  extern int meas_delay_cm; //delay distance
+#endif
+
+#ifdef FWRETRACT
+extern bool autoretract_enabled;
+extern bool retracted[EXTRUDERS];
+extern float retract_length, retract_length_swap, retract_feedrate, retract_zlift;
+extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate;
+#endif
+
+#ifdef HOST_KEEPALIVE_FEATURE
+extern uint8_t host_keepalive_interval;
+#endif
+
+extern unsigned long starttime;
+extern unsigned long stoptime;
+extern int bowden_length[4];
+extern bool is_usb_printing;
+extern bool homing_flag;
+extern bool temp_cal_active;
+extern bool loading_flag;
+extern unsigned int usb_printing_counter;
+
+extern unsigned long kicktime;
+
+extern unsigned long total_filament_used;
+void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time);
+extern unsigned int heating_status;
+extern unsigned int status_number;
+extern unsigned int heating_status_counter;
+extern bool custom_message;
+extern unsigned int custom_message_type;
+extern unsigned int custom_message_state;
+extern char snmm_filaments_used;
+extern unsigned long PingTime;
+
+extern bool fan_state[2];
+extern int fan_edge_counter[2];
+extern int fan_speed[2];
+
+// Handling multiple extruders pins
+extern uint8_t active_extruder;
+
+#ifdef DIGIPOT_I2C
+extern void digipot_i2c_set_current( int channel, float current );
+extern void digipot_i2c_init();
+#endif
+
+#endif
+
+//Long pause
+extern int saved_feedmultiply;
+extern float HotendTempBckp;
+extern int fanSpeedBckp;
+extern float pause_lastpos[4];
+extern unsigned long pause_time;
+extern unsigned long start_pause_print;
+extern unsigned long t_fan_rising_edge;
+
+extern bool mesh_bed_leveling_flag;
+extern bool mesh_bed_run_from_menu;
+
+extern float distance_from_min[2];
+
+extern char dir_names[3][9];
+
+extern void calculate_volumetric_multipliers();
+
+// Similar to the default Arduino delay function, 
+// but it keeps the background tasks running.
+extern void delay_keep_alive(unsigned int ms);
+
+extern void check_babystep();
+
+extern void long_pause();
+
+#ifdef DIS
+
+void d_setup();
+float d_ReadData();
+void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y);
+
+#endif
+float temp_comp_interpolation(float temperature);
+void temp_compensation_apply();
+void temp_compensation_start();
+
+#ifdef PINDA_THERMISTOR
+float temp_compensation_pinda_thermistor_offset(float temperature_pinda);
+#endif //PINDA_THERMISTOR
+
+void wait_for_heater(long codenum);
+void serialecho_temperatures();
+
+void uvlo_();
+void recover_print(uint8_t automatic); 
+void setup_uvlo_interrupt();
+void setup_fan_interrupt();
+
+extern void recover_machine_state_after_power_panic();
+extern void restore_print_from_eeprom();
+extern void position_menu();
+
+extern void print_world_coordinates();
+extern void print_physical_coordinates();
+extern void print_mesh_bed_leveling_table();
+
+#ifdef HOST_KEEPALIVE_FEATURE
+
+// States for managing Marlin and host communication
+// Marlin sends messages if blocked or busy
+/*enum MarlinBusyState {
+	NOT_BUSY,           // Not in a handler
+	IN_HANDLER,         // Processing a GCode
+	IN_PROCESS,         // Known to be blocking command input (as in G29)
+	PAUSED_FOR_USER,    // Blocking pending any input
+	PAUSED_FOR_INPUT    // Blocking pending text input (concept)
+};*/
+
+#define NOT_BUSY          1
+#define IN_HANDLER        2
+#define IN_PROCESS        3
+#define PAUSED_FOR_USER   4
+#define PAUSED_FOR_INPUT  5
+
+#define KEEPALIVE_STATE(n) do { busy_state = n;} while (0)
+extern void host_keepalive();
+//extern MarlinBusyState busy_state;
+extern int busy_state;
+
+#endif //HOST_KEEPALIVE_FEATURE
+
+// G-codes
+bool gcode_M45(bool onlyZ);
+void gcode_M701();
+
+#define UVLO !(PINE & (1<<4))
+
+void extr_unload2();

+ 51 - 4
Firmware/MarlinSerial.cpp

@@ -23,6 +23,8 @@
 #include "Marlin.h"
 #include "MarlinSerial.h"
 
+uint8_t selectedSerialPort = 0;
+
 #ifndef AT90USB
 // this next line disables the entire HardwareSerial.cpp, 
 // this is so I can support Attiny series and any other chip without a UART
@@ -56,14 +58,32 @@ FORCE_INLINE void store_char(unsigned char c)
       // Test for a framing error.
       if (M_UCSRxA & (1<<M_FEx)) {
           // Characters received with the framing errors will be ignored.
-          // The temporary variable "c" was made volatile, so the compiler does not optimize this out.
-          volatile unsigned char c = M_UDRx;
+          // Dummy register read (discard)
+          (void)(*(char *)M_UDRx);
       } else {
           // Read the input register.
           unsigned char c = M_UDRx;
           store_char(c);
       }
   }
+#ifndef SNMM
+  SIGNAL(USART2_RX_vect)
+  {
+      if (selectedSerialPort == 1) {
+        // Test for a framing error.
+        if (UCSR2A & (1<<FE2)) {
+            // Characters received with the framing errors will be ignored.
+            // Dummy register read (discard)
+            (void)(*(char *)UDR2);
+        } else {
+            // Read the input register.
+            unsigned char c = UDR2;
+            store_char(c);
+            
+        }
+      }
+  }
+#endif
 #endif
 
 // Constructors ////////////////////////////////////////////////////////////////
@@ -88,7 +108,7 @@ void MarlinSerial::begin(long baud)
     useU2X = false;
   }
 #endif
-  
+// set up the first (original serial port)
   if (useU2X) {
     M_UCSRxA = 1 << M_U2Xx;
     baud_setting = (F_CPU / 4 / baud - 1) / 2;
@@ -104,13 +124,40 @@ void MarlinSerial::begin(long baud)
   sbi(M_UCSRxB, M_RXENx);
   sbi(M_UCSRxB, M_TXENx);
   sbi(M_UCSRxB, M_RXCIEx);
+  
+#ifndef SNMM
+
+  if (selectedSerialPort == 1) { //set up also the second serial port 
+	  if (useU2X) {
+		  UCSR2A = 1 << U2X2;
+		  baud_setting = (F_CPU / 4 / baud - 1) / 2;
+	  } else {
+		  UCSR2A = 0;
+		  baud_setting = (F_CPU / 8 / baud - 1) / 2;
+	  }
+
+	  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
+	  UBRR2H = baud_setting >> 8;
+	  UBRR2L = baud_setting;
+	  
+	  sbi(UCSR2B, RXEN2);
+	  sbi(UCSR2B, TXEN2);
+	  sbi(UCSR2B, RXCIE2);	  
+  }
+#endif
 }
 
 void MarlinSerial::end()
 {
   cbi(M_UCSRxB, M_RXENx);
   cbi(M_UCSRxB, M_TXENx);
-  cbi(M_UCSRxB, M_RXCIEx);  
+  cbi(M_UCSRxB, M_RXCIEx);
+
+#ifndef SNMM
+  cbi(UCSR2B, RXEN2);
+  cbi(UCSR2B, TXEN2);
+  cbi(UCSR2B, RXCIE2);
+#endif
 }
 
 

+ 42 - 17
Firmware/MarlinSerial.h

@@ -73,6 +73,7 @@
 // is the index of the location from which to read.
 #define RX_BUFFER_SIZE 128
 
+extern uint8_t selectedSerialPort;
 
 struct ring_buffer
 {
@@ -110,24 +111,48 @@ class MarlinSerial //: public Stream
     }
     
     
-    FORCE_INLINE void checkRx(void)
+    void checkRx(void)
     {
-        if((M_UCSRxA & (1<<M_RXCx)) != 0) {
-            // Test for a framing error.
-            if (M_UCSRxA & (1<<M_FEx)) {
-                // Characters received with the framing errors will be ignored.
-                // The temporary variable "c" was made volatile, so the compiler does not optimize this out.
-                volatile unsigned char c = M_UDRx;
-            } else {
-                unsigned char c  =  M_UDRx;
-                int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
-                // if we should be storing the received character into the location
-                // just before the tail (meaning that the head would advance to the
-                // current location of the tail), we're about to overflow the buffer
-                // and so we don't write the character or advance the head.
-                if (i != rx_buffer.tail) {
-                    rx_buffer.buffer[rx_buffer.head] = c;
-                    rx_buffer.head = i;
+        if (selectedSerialPort == 0) {
+            if((M_UCSRxA & (1<<M_RXCx)) != 0) {
+                // Test for a framing error.
+                if (M_UCSRxA & (1<<M_FEx)) {
+                    // Characters received with the framing errors will be ignored.
+                    // The temporary variable "c" was made volatile, so the compiler does not optimize this out.
+                    volatile unsigned char c = M_UDRx;
+                } else {
+                    unsigned char c  =  M_UDRx;
+                    int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
+                    // if we should be storing the received character into the location
+                    // just before the tail (meaning that the head would advance to the
+                    // current location of the tail), we're about to overflow the buffer
+                    // and so we don't write the character or advance the head.
+                    if (i != rx_buffer.tail) {
+                        rx_buffer.buffer[rx_buffer.head] = c;
+                        rx_buffer.head = i;
+                    }
+                    selectedSerialPort = 0;
+                }
+            }
+        } else if(selectedSerialPort == 1) {
+            if((UCSR2A & (1<<RXC2)) != 0) {
+                // Test for a framing error.
+                if (UCSR2A & (1<<FE2)) {
+                    // Characters received with the framing errors will be ignored.
+                    // The temporary variable "c" was made volatile, so the compiler does not optimize this out.
+                    volatile unsigned char c = UDR2;
+                } else {
+                    unsigned char c  =  UDR2;
+                    int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
+                    // if we should be storing the received character into the location
+                    // just before the tail (meaning that the head would advance to the
+                    // current location of the tail), we're about to overflow the buffer
+                    // and so we don't write the character or advance the head.
+                    if (i != rx_buffer.tail) {
+                        rx_buffer.buffer[rx_buffer.head] = c;
+                        rx_buffer.head = i;
+                    }
+                    selectedSerialPort = 1;
                 }
             }
         }

+ 3862 - 1250
Firmware/Marlin_main.cpp

@@ -27,14 +27,6 @@
     http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
  */
 
-
-
-
-
-
-
-
-
 #include "Marlin.h"
 
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -63,6 +55,29 @@
 #include "math.h"
 #include "util.h"
 
+#include <avr/wdt.h>
+
+#include "Dcodes.h"
+
+
+#ifdef SWSPI
+#include "swspi.h"
+#endif //SWSPI
+
+#ifdef SWI2C
+#include "swi2c.h"
+#endif //SWI2C
+
+#ifdef PAT9125
+#include "pat9125.h"
+#include "fsensor.h"
+#endif //PAT9125
+
+#ifdef TMC2130
+#include "tmc2130.h"
+#endif //TMC2130
+
+
 #ifdef BLINKM
 #include "BlinkM.h"
 #include "Wire.h"
@@ -85,11 +100,15 @@
 
 #include "ultralcd.h"
 
+#include "cmdqueue.h"
+
 // Macros for bit masks
 #define BIT(b) (1<<(b))
 #define TEST(n,b) (((n)&BIT(b))!=0)
 #define SET_BIT(n,b,value) (n) ^= ((-value)^(n)) & (BIT(b))
 
+//Macro for print fan speed
+#define FAN_PULSE_WIDTH_LIMIT ((fanSpeed > 100) ? 3 : 4) //time in ms
 
 // look here for descriptions of G-codes: http://linuxcnc.org/handbook/gcode/g-code.html
 // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
@@ -157,6 +176,7 @@
 //        Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling
 //        IF AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F
 // M112 - Emergency stop
+// M113 - Get or set the timeout interval for Host Keepalive "busy" messages
 // M114 - Output current position to serial port
 // M115 - Capabilities string
 // M117 - display message
@@ -206,6 +226,7 @@
 // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
 // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
 // M605 - Set dual x-carriage movement mode: S<mode> [ X<duplication x-offset> R<duplication temp offset> ]
+// M900 - Set LIN_ADVANCE options, if enabled. See Configuration_adv.h for details.
 // M907 - Set digital trimpot motor current using axis codes.
 // M908 - Control digital trimpot directly.
 // M350 - Set microstepping mode.
@@ -228,16 +249,13 @@
 CardReader card;
 #endif
 
-
+unsigned long PingTime = millis();
 union Data
 {
 byte b[2];
 int value;
 };
 
-// Number of baby steps applied
-int babystepLoadZ = 0;
-
 float homing_feedrate[] = HOMING_FEEDRATE;
 // Currently only the extruder axis may be switched to a relative mode.
 // Other axes are always absolute or relative based on the common relative_mode flag.
@@ -254,21 +272,55 @@ int extruder_multiply[EXTRUDERS] = {100
   #endif
 };
 
+int bowden_length[4] = {385, 385, 385, 385};
+
 bool is_usb_printing = false;
+bool homing_flag = false;
+
+bool temp_cal_active = false;
+
+unsigned long kicktime = millis()+100000;
 
 unsigned int  usb_printing_counter;
 
 int lcd_change_fil_state = 0;
+
 int feedmultiplyBckp = 100;
+float HotendTempBckp = 0;
+int fanSpeedBckp = 0;
+float pause_lastpos[4];
+unsigned long pause_time = 0;
+unsigned long start_pause_print = millis();
+unsigned long t_fan_rising_edge = millis();
+
+//unsigned long load_filament_time;
+
+bool mesh_bed_leveling_flag = false;
+bool mesh_bed_run_from_menu = false;
+
 unsigned char lang_selected = 0;
+int8_t FarmMode = 0;
 
+bool prusa_sd_card_upload = false;
+
+unsigned int status_number = 0;
 
 unsigned long total_filament_used;
 unsigned int heating_status;
 unsigned int heating_status_counter;
 bool custom_message;
+bool loading_flag = false;
 unsigned int custom_message_type;
 unsigned int custom_message_state;
+char snmm_filaments_used = 0;
+
+float distance_from_min[2];
+
+bool fan_state[2];
+int fan_edge_counter[2];
+int fan_speed[2];
+
+char dir_names[3][9];
 
 bool volumetric_enabled = false;
 float filament_size[EXTRUDERS] = { DEFAULT_NOMINAL_FILAMENT_DIA
@@ -346,6 +398,16 @@ int fanSpeed=0;
 
 bool cancel_heatup = false ;
 
+#ifdef HOST_KEEPALIVE_FEATURE
+  
+  int busy_state = NOT_BUSY;
+  static long prev_busy_signal_ms = -1;
+  uint8_t host_keepalive_interval = HOST_KEEPALIVE_INTERVAL;
+#else
+  #define host_keepalive();
+  #define KEEPALIVE_STATE(n);
+#endif
+
 #ifdef FILAMENT_SENSOR
   //Variables for Filament Sensor input 
   float filament_width_nominal=DEFAULT_NOMINAL_FILAMENT_DIA;  //Set nominal filament width, can be changed with M404 
@@ -371,60 +433,12 @@ static float delta[3] = {0.0, 0.0, 0.0};
 
 // For tracing an arc
 static float offset[3] = {0.0, 0.0, 0.0};
-static bool home_all_axis = true;
 static float feedrate = 1500.0, next_feedrate, saved_feedrate;
-static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
 
 // Determines Absolute or Relative Coordinates.
 // Also there is bool axis_relative_modes[] per axis flag.
 static bool relative_mode = false;  
 
-// String circular buffer. Commands may be pushed to the buffer from both sides:
-// Chained commands will be pushed to the front, interactive (from LCD menu) 
-// and printing commands (from serial line or from SD card) are pushed to the tail.
-// First character of each entry indicates the type of the entry: 
-#define CMDBUFFER_CURRENT_TYPE_UNKNOWN  0
-// Command in cmdbuffer was sent over USB.
-#define CMDBUFFER_CURRENT_TYPE_USB      1
-// Command in cmdbuffer was read from SDCARD.
-#define CMDBUFFER_CURRENT_TYPE_SDCARD   2
-// Command in cmdbuffer was generated by the UI.
-#define CMDBUFFER_CURRENT_TYPE_UI       3
-// Command in cmdbuffer was generated by another G-code.
-#define CMDBUFFER_CURRENT_TYPE_CHAINED  4
-
-// How much space to reserve for the chained commands
-// of type CMDBUFFER_CURRENT_TYPE_CHAINED,
-// which are pushed to the front of the queue?
-// Maximum 5 commands of max length 20 + null terminator.
-#define CMDBUFFER_RESERVE_FRONT       (5*21)
-// Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT.
-static char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
-// Head of the circular buffer, where to read.
-static int bufindr = 0;
-// Tail of the buffer, where to write.
-static int bufindw = 0;
-// Number of lines in cmdbuffer.
-static int buflen = 0;
-// Flag for processing the current command inside the main Arduino loop().
-// If a new command was pushed to the front of a command buffer while
-// processing another command, this replaces the command on the top.
-// Therefore don't remove the command from the queue in the loop() function.
-static bool cmdbuffer_front_already_processed = false;
-
-// Type of a command, which is to be executed right now.
-#define CMDBUFFER_CURRENT_TYPE   (cmdbuffer[bufindr])
-// String of a command, which is to be executed right now.
-#define CMDBUFFER_CURRENT_STRING (cmdbuffer+bufindr+1)
-
-// Enable debugging of the command buffer.
-// Debugging information will be sent to serial line.
-// #define CMDBUFFER_DEBUG
-
-static int serial_count = 0;
-static boolean comment_mode = false;
-static char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
-
 const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42
 
 //static float tt = 0;
@@ -441,6 +455,8 @@ unsigned long _usb_timer = 0;
 
 static uint8_t tmp_extruder;
 
+bool extruder_under_pressure = true;
+
 
 bool Stopped=false;
 
@@ -493,302 +509,6 @@ void serial_echopair_P(const char *s_P, unsigned long v)
   }
 #endif //!SDSUPPORT
 
-// Pop the currently processed command from the queue.
-// It is expected, that there is at least one command in the queue.
-void cmdqueue_pop_front()
-{
-    if (buflen > 0) {
-#ifdef CMDBUFFER_DEBUG
-        SERIAL_ECHOPGM("Dequeing ");
-        SERIAL_ECHO(cmdbuffer+bufindr+1);
-        SERIAL_ECHOLNPGM("");
-        SERIAL_ECHOPGM("Old indices: buflen ");
-        SERIAL_ECHO(buflen);
-        SERIAL_ECHOPGM(", bufindr ");
-        SERIAL_ECHO(bufindr);
-        SERIAL_ECHOPGM(", bufindw ");
-        SERIAL_ECHO(bufindw);
-        SERIAL_ECHOPGM(", serial_count ");
-        SERIAL_ECHO(serial_count);
-        SERIAL_ECHOPGM(", bufsize ");
-        SERIAL_ECHO(sizeof(cmdbuffer));
-        SERIAL_ECHOLNPGM("");
-#endif /* CMDBUFFER_DEBUG */
-        if (-- buflen == 0) {
-            // Empty buffer.
-            if (serial_count == 0)
-                // No serial communication is pending. Reset both pointers to zero.
-                bufindw = 0;
-            bufindr = bufindw;
-        } else {
-            // There is at least one ready line in the buffer.
-            // First skip the current command ID and iterate up to the end of the string.
-            for (++ bufindr; cmdbuffer[bufindr] != 0; ++ bufindr) ;
-            // Second, skip the end of string null character and iterate until a nonzero command ID is found.
-            for (++ bufindr; bufindr < sizeof(cmdbuffer) && cmdbuffer[bufindr] == 0; ++ bufindr) ;
-            // If the end of the buffer was empty,
-            if (bufindr == sizeof(cmdbuffer)) {
-                // skip to the start and find the nonzero command.
-                for (bufindr = 0; cmdbuffer[bufindr] == 0; ++ bufindr) ;
-            }
-#ifdef CMDBUFFER_DEBUG
-            SERIAL_ECHOPGM("New indices: buflen ");
-            SERIAL_ECHO(buflen);
-            SERIAL_ECHOPGM(", bufindr ");
-            SERIAL_ECHO(bufindr);
-            SERIAL_ECHOPGM(", bufindw ");
-            SERIAL_ECHO(bufindw);
-            SERIAL_ECHOPGM(", serial_count ");
-            SERIAL_ECHO(serial_count);
-            SERIAL_ECHOPGM(" new command on the top: ");
-            SERIAL_ECHO(cmdbuffer+bufindr+1);
-            SERIAL_ECHOLNPGM("");
-#endif /* CMDBUFFER_DEBUG */
-        }
-    }
-}
-
-// How long a string could be pushed to the front of the command queue?
-// If yes, adjust bufindr to the new position, where the new command could be enqued.
-// len_asked does not contain the zero terminator size.
-bool cmdqueue_could_enqueue_front(int len_asked)
-{
-    // MAX_CMD_SIZE has to accommodate the zero terminator.
-    if (len_asked >= MAX_CMD_SIZE)
-        return false;
-    // Remove the currently processed command from the queue.
-    if (! cmdbuffer_front_already_processed) {
-        cmdqueue_pop_front();
-        cmdbuffer_front_already_processed = true;
-    }
-    if (bufindr == bufindw && buflen > 0)
-        // Full buffer.
-        return false;
-    // Adjust the end of the write buffer based on whether a partial line is in the receive buffer.
-    int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw;
-    if (bufindw < bufindr) {
-        int bufindr_new = bufindr - len_asked - 2;
-        // Simple case. There is a contiguous space between the write buffer and the read buffer.
-        if (endw <= bufindr_new) {
-            bufindr = bufindr_new;
-            return true;
-        }
-    } else {
-        // Otherwise the free space is split between the start and end.
-        if (len_asked + 2 <= bufindr) {
-            // Could fit at the start.
-            bufindr -= len_asked + 2;
-            return true;
-        }
-        int bufindr_new = sizeof(cmdbuffer) - len_asked - 2;
-        if (endw <= bufindr_new) {
-            memset(cmdbuffer, 0, bufindr);
-            bufindr = bufindr_new;
-            return true;
-        }
-    }
-    return false;
-}
-
-// Could one enqueue a command of lenthg len_asked into the buffer,
-// while leaving CMDBUFFER_RESERVE_FRONT at the start?
-// If yes, adjust bufindw to the new position, where the new command could be enqued.
-// len_asked does not contain the zero terminator size.
-bool cmdqueue_could_enqueue_back(int len_asked)
-{
-    // MAX_CMD_SIZE has to accommodate the zero terminator.
-    if (len_asked >= MAX_CMD_SIZE)
-        return false;
-
-    if (bufindr == bufindw && buflen > 0)
-        // Full buffer.
-        return false;
-
-    if (serial_count > 0) {
-        // If there is some data stored starting at bufindw, len_asked is certainly smaller than
-        // the allocated data buffer. Try to reserve a new buffer and to move the already received
-        // serial data.
-        // How much memory to reserve for the commands pushed to the front?
-        // End of the queue, when pushing to the end.
-        int endw = bufindw + len_asked + 2;
-        if (bufindw < bufindr)
-            // Simple case. There is a contiguous space between the write buffer and the read buffer.
-            return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
-        // Otherwise the free space is split between the start and end.
-        if (// Could one fit to the end, including the reserve?
-            endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
-            // Could one fit to the end, and the reserve to the start?
-            (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
-            return true;
-        // Could one fit both to the start?
-        if (len_asked + 2 + CMDBUFFER_RESERVE_FRONT <= bufindr) {
-            // Mark the rest of the buffer as used.
-            memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
-            // and point to the start.
-            bufindw = 0;
-            return true;
-        }
-    } else {
-        // How much memory to reserve for the commands pushed to the front?
-        // End of the queue, when pushing to the end.
-        int endw = bufindw + len_asked + 2;
-        if (bufindw < bufindr)
-            // Simple case. There is a contiguous space between the write buffer and the read buffer.
-            return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
-        // Otherwise the free space is split between the start and end.
-        if (// Could one fit to the end, including the reserve?
-            endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
-            // Could one fit to the end, and the reserve to the start?
-            (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
-            return true;
-        // Could one fit both to the start?
-        if (len_asked + 2 + CMDBUFFER_RESERVE_FRONT <= bufindr) {
-            // Mark the rest of the buffer as used.
-            memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
-            // and point to the start.
-            bufindw = 0;
-            return true;
-        }
-    }
-    return false;
-}
-
-#ifdef CMDBUFFER_DEBUG
-static void cmdqueue_dump_to_serial_single_line(int nr, const char *p)
-{
-    SERIAL_ECHOPGM("Entry nr: ");
-    SERIAL_ECHO(nr);
-    SERIAL_ECHOPGM(", type: ");
-    SERIAL_ECHO(int(*p));
-    SERIAL_ECHOPGM(", cmd: ");
-    SERIAL_ECHO(p+1);  
-    SERIAL_ECHOLNPGM("");
-}
-
-static void cmdqueue_dump_to_serial()
-{
-    if (buflen == 0) {
-        SERIAL_ECHOLNPGM("The command buffer is empty.");
-    } else {
-        SERIAL_ECHOPGM("Content of the buffer: entries ");
-        SERIAL_ECHO(buflen);
-        SERIAL_ECHOPGM(", indr ");
-        SERIAL_ECHO(bufindr);
-        SERIAL_ECHOPGM(", indw ");
-        SERIAL_ECHO(bufindw);
-        SERIAL_ECHOLNPGM("");
-        int nr = 0;
-        if (bufindr < bufindw) {
-            for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + bufindw; ++ nr) {
-                cmdqueue_dump_to_serial_single_line(nr, p);
-                // Skip the command.
-                for (++p; *p != 0; ++ p);
-                // Skip the gaps.
-                for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
-            }
-        } else {
-            for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + sizeof(cmdbuffer); ++ nr) {
-                cmdqueue_dump_to_serial_single_line(nr, p);
-                // Skip the command.
-                for (++p; *p != 0; ++ p);
-                // Skip the gaps.
-                for (++p; p < cmdbuffer + sizeof(cmdbuffer) && *p == 0; ++ p);
-            }
-            for (const char *p = cmdbuffer; p < cmdbuffer + bufindw; ++ nr) {
-                cmdqueue_dump_to_serial_single_line(nr, p);
-                // Skip the command.
-                for (++p; *p != 0; ++ p);
-                // Skip the gaps.
-                for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
-            }
-        }
-        SERIAL_ECHOLNPGM("End of the buffer.");
-    }
-}
-#endif /* CMDBUFFER_DEBUG */
-
-//adds an command to the main command buffer
-//thats really done in a non-safe way.
-//needs overworking someday
-// Currently the maximum length of a command piped through this function is around 20 characters
-void enquecommand(const char *cmd, bool from_progmem)
-{
-    int len = from_progmem ? strlen_P(cmd) : strlen(cmd);
-    // Does cmd fit the queue while leaving sufficient space at the front for the chained commands?
-    // If it fits, it may move bufindw, so it points to a contiguous buffer, which fits cmd.
-    if (cmdqueue_could_enqueue_back(len)) {
-        // This is dangerous if a mixing of serial and this happens
-        // This may easily be tested: If serial_count > 0, we have a problem.
-        cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_UI;
-        if (from_progmem)
-            strcpy_P(cmdbuffer + bufindw + 1, cmd);
-        else
-            strcpy(cmdbuffer + bufindw + 1, cmd);
-        SERIAL_ECHO_START;
-        SERIAL_ECHORPGM(MSG_Enqueing);
-        SERIAL_ECHO(cmdbuffer + bufindw + 1);
-        SERIAL_ECHOLNPGM("\"");
-        bufindw += len + 2;
-        if (bufindw == sizeof(cmdbuffer))
-            bufindw = 0;
-        ++ buflen;
-#ifdef CMDBUFFER_DEBUG
-        cmdqueue_dump_to_serial();
-#endif /* CMDBUFFER_DEBUG */
-    } else {
-        SERIAL_ERROR_START;
-        SERIAL_ECHORPGM(MSG_Enqueing);
-        if (from_progmem)
-            SERIAL_PROTOCOLRPGM(cmd);
-        else
-            SERIAL_ECHO(cmd);
-        SERIAL_ECHOLNPGM("\" failed: Buffer full!");
-#ifdef CMDBUFFER_DEBUG
-        cmdqueue_dump_to_serial();
-#endif /* CMDBUFFER_DEBUG */
-    }
-}
-
-void enquecommand_front(const char *cmd, bool from_progmem)
-{
-    int len = from_progmem ? strlen_P(cmd) : strlen(cmd);
-    // Does cmd fit the queue? This call shall move bufindr, so the command may be copied.
-    if (cmdqueue_could_enqueue_front(len)) {
-        cmdbuffer[bufindr] = CMDBUFFER_CURRENT_TYPE_UI;
-        if (from_progmem)
-            strcpy_P(cmdbuffer + bufindr + 1, cmd);
-        else
-            strcpy(cmdbuffer + bufindr + 1, cmd);
-        ++ buflen;
-        SERIAL_ECHO_START;
-        SERIAL_ECHOPGM("Enqueing to the front: \"");
-        SERIAL_ECHO(cmdbuffer + bufindr + 1);
-        SERIAL_ECHOLNPGM("\"");
-#ifdef CMDBUFFER_DEBUG
-        cmdqueue_dump_to_serial();
-#endif /* CMDBUFFER_DEBUG */
-    } else {
-        SERIAL_ERROR_START;
-        SERIAL_ECHOPGM("Enqueing to the front: \"");
-        if (from_progmem)
-            SERIAL_PROTOCOLRPGM(cmd);
-        else
-            SERIAL_ECHO(cmd);
-        SERIAL_ECHOLNPGM("\" failed: Buffer full!");
-#ifdef CMDBUFFER_DEBUG
-        cmdqueue_dump_to_serial();
-#endif /* CMDBUFFER_DEBUG */
-    }
-}
-
-// Mark the command at the top of the command queue as new.
-// Therefore it will not be removed from the queue.
-void repeatcommand_front()
-{
-    cmdbuffer_front_already_processed = true;
-} 
-
-
 void setup_killpin()
 {
   #if defined(KILL_PIN) && KILL_PIN > -1
@@ -859,459 +579,810 @@ void servo_init()
 
 static void lcd_language_menu();
 
+void stop_and_save_print_to_ram(float z_move, float e_move);
+void restore_print_from_ram_and_continue(float e_move);
+
+extern int8_t CrashDetectMenu;
+
+void crashdet_enable()
+{
+	MYSERIAL.println("crashdet_enable"); 
+	tmc2130_sg_stop_on_crash = true;
+	eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0xFF); 
+	CrashDetectMenu = 1;
+
+}
+
+void crashdet_disable()
+{
+	MYSERIAL.println("crashdet_disable"); 
+	tmc2130_sg_stop_on_crash = false;
+	eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0x00); 
+	CrashDetectMenu = 0;
+}
+
+void crashdet_stop_and_save_print()
+{
+	stop_and_save_print_to_ram(10, 0); //XY - no change, Z 10mm up, E - no change
+}
+
+void crashdet_restore_print_and_continue()
+{
+	restore_print_from_ram_and_continue(0); //XYZ = orig, E - no change
+//	babystep_apply();
+}
+
+
+void crashdet_stop_and_save_print2()
+{
+	cli();
+	planner_abort_hard(); //abort printing
+	cmdqueue_reset(); //empty cmdqueue
+	card.sdprinting = false;
+	card.closefile();
+	sei();
+}
+
+void crashdet_detected()
+{
+	printf("CRASH_DETECTED");
+/*	while (!is_buffer_empty())
+	{
+		process_commands();
+	    cmdqueue_pop_front();
+	}*/
+	st_synchronize();
+
+	lcd_update_enable(true);
+	lcd_implementation_clear();
+	lcd_update(2);
+    
+    // Increment crash counter
+    uint8_t crash_count = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT);
+    crash_count++;
+    eeprom_update_byte((uint8_t*)EEPROM_CRASH_COUNT, crash_count);
+    
+#ifdef AUTOMATIC_RECOVERY_AFTER_CRASH
+    bool yesno = true;
+#else
+    bool yesno = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_CRASH_DETECTED, false);
+#endif
+	lcd_update_enable(true);
+	lcd_update(2);
+	lcd_setstatuspgm(WELCOME_MSG);
+	if (yesno)
+	{
+		enquecommand_P(PSTR("G28 X"));
+		enquecommand_P(PSTR("G28 Y"));
+		enquecommand_P(PSTR("CRASH_RECOVER"));
+	}
+	else
+	{
+		enquecommand_P(PSTR("CRASH_CANCEL"));
+	}
+}
+
+void crashdet_recover()
+{
+	crashdet_restore_print_and_continue();
+	tmc2130_sg_stop_on_crash = true;
+}
+
+void crashdet_cancel()
+{
+	card.sdprinting = false;
+	card.closefile();
+	tmc2130_sg_stop_on_crash = true;
+}
+
+
 
 #ifdef MESH_BED_LEVELING
    enum MeshLevelingState { MeshReport, MeshStart, MeshNext, MeshSet };
 #endif
 
-// "Setup" function is called by the Arduino framework on startup.
-// Before startup, the Timers-functions (PWM)/Analog RW and HardwareSerial provided by the Arduino-code 
-// are initialized by the main() routine provided by the Arduino framework.
-void setup()
-{
-  setup_killpin();
-  setup_powerhold();
-  MYSERIAL.begin(BAUDRATE);
-  SERIAL_PROTOCOLLNPGM("start");
-  SERIAL_ECHO_START;
 
-#if 0
-  SERIAL_ECHOLN("Reading eeprom from 0 to 100: start");
-  for (int i = 0; i < 4096; ++ i) {
-      int b = eeprom_read_byte((unsigned char*)i);
-      if (b != 255) {
-          SERIAL_ECHO(i);
-          SERIAL_ECHO(":");
-          SERIAL_ECHO(b);
-          SERIAL_ECHOLN("");
-      }
-  }
-  SERIAL_ECHOLN("Reading eeprom from 0 to 100: done");
-  #endif
+// Factory reset function
+// This function is used to erase parts or whole EEPROM memory which is used for storing calibration and and so on.
+// Level input parameter sets depth of reset
+// Quiet parameter masks all waitings for user interact.
+int  er_progress = 0;
+void factory_reset(char level, bool quiet)
+{	
+	lcd_implementation_clear();
+	int cursor_pos = 0;
+    switch (level) {
+                   
+        // Level 0: Language reset
+        case 0:
+            WRITE(BEEPER, HIGH);
+            _delay_ms(100);
+            WRITE(BEEPER, LOW);
+            
+            lcd_force_language_selection();
+            break;
+         
+		//Level 1: Reset statistics
+		case 1:
+			WRITE(BEEPER, HIGH);
+			_delay_ms(100);
+			WRITE(BEEPER, LOW);
+			eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0);
+			eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0);
+			lcd_menu_statistics();
+            
+			break;
 
-  // Check startup - does nothing if bootloader sets MCUSR to 0
-  byte mcu = MCUSR;
-  if(mcu & 1) SERIAL_ECHOLNRPGM(MSG_POWERUP);
-  if(mcu & 2) SERIAL_ECHOLNRPGM(MSG_EXTERNAL_RESET);
-  if(mcu & 4) SERIAL_ECHOLNRPGM(MSG_BROWNOUT_RESET);
-  if(mcu & 8) SERIAL_ECHOLNRPGM(MSG_WATCHDOG_RESET);
-  if(mcu & 32) SERIAL_ECHOLNRPGM(MSG_SOFTWARE_RESET);
-  MCUSR=0;
-
-  //SERIAL_ECHORPGM(MSG_MARLIN);
-  //SERIAL_ECHOLNRPGM(VERSION_STRING);
-  
-	#ifdef STRING_VERSION_CONFIG_H
-		#ifdef STRING_CONFIG_H_AUTHOR
-		  SERIAL_ECHO_START;
-		  SERIAL_ECHORPGM(MSG_CONFIGURATION_VER);
-		  SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H);
-		  SERIAL_ECHORPGM(MSG_AUTHOR);
-		  SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
-		  SERIAL_ECHOPGM("Compiled: ");
-		  SERIAL_ECHOLNPGM(__DATE__);
-		#endif
-	#endif
-  
-  SERIAL_ECHO_START;
-  SERIAL_ECHORPGM(MSG_FREE_MEMORY);
-  SERIAL_ECHO(freeMemory());
-  SERIAL_ECHORPGM(MSG_PLANNER_BUFFER_BYTES);
-  SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
-  
-  // loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
-  Config_RetrieveSettings();
-
-  tp_init();    // Initialize temperature loop
-  plan_init();  // Initialize planner;
-  watchdog_init();
-  st_init();    // Initialize stepper, this enables interrupts!
-  setup_photpin();
-  servo_init();
-  // Reset the machine correction matrix.
-  // It does not make sense to load the correction matrix until the machine is homed.
-  world2machine_reset();
-
-  lcd_init();
-  if (!READ(BTN_ENC))
-  {
-	  _delay_ms(1000);
-	  if (!READ(BTN_ENC))
-	  {
-		  SET_OUTPUT(BEEPER);
-		  WRITE(BEEPER, HIGH);
+        // Level 2: Prepare for shipping
+        case 2:
+			//lcd_printPGM(PSTR("Factory RESET"));
+            //lcd_print_at_PGM(1,2,PSTR("Shipping prep"));
+            
+            // Force language selection at the next boot up.
+            lcd_force_language_selection();
+            // Force the "Follow calibration flow" message at the next boot up.
+            calibration_status_store(CALIBRATION_STATUS_Z_CALIBRATION);
+            farm_no = 0;
+			farm_mode == false;
+			eeprom_update_byte((uint8_t*)EEPROM_FARM_MODE, farm_mode);
+            EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no);
+                       
+            WRITE(BEEPER, HIGH);
+            _delay_ms(100);
+            WRITE(BEEPER, LOW);
+			//_delay_ms(2000);
+            break;
 
-		  lcd_force_language_selection();
-		  farm_no = 0;
-		  EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-		  farm_mode = false;
+			// Level 3: erase everything, whole EEPROM will be set to 0xFF
 
-		  while (!READ(BTN_ENC));
+		case 3:
+			lcd_printPGM(PSTR("Factory RESET"));
+			lcd_print_at_PGM(1, 2, PSTR("ERASING all data"));
 
-		  WRITE(BEEPER, LOW);
+			WRITE(BEEPER, HIGH);
+			_delay_ms(100);
+			WRITE(BEEPER, LOW);
 
-#ifdef MESH_BED_LEVELING
-		  _delay_ms(2000);
-
-		  if (!READ(BTN_ENC))
-		  {
-			  WRITE(BEEPER, HIGH);
-			  _delay_ms(100);
-			  WRITE(BEEPER, LOW);
-			  _delay_ms(200);
-			  WRITE(BEEPER, HIGH);
-			  _delay_ms(100);
-			  WRITE(BEEPER, LOW);
-
-			  int _z = 0;
-			  eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0x01);
-			  EEPROM_save_B(EEPROM_BABYSTEP_X, &_z);
-			  EEPROM_save_B(EEPROM_BABYSTEP_Y, &_z);
-			  EEPROM_save_B(EEPROM_BABYSTEP_Z, &_z);
-		  }
-		  else
-		  {
+			er_progress = 0;
+			lcd_print_at_PGM(3, 3, PSTR("      "));
+			lcd_implementation_print_at(3, 3, er_progress);
 
-			  WRITE(BEEPER, HIGH);
-			  _delay_ms(100);
-			  WRITE(BEEPER, LOW);
-		  }
-#endif // mesh
+			// Erase EEPROM
+			for (int i = 0; i < 4096; i++) {
+				eeprom_write_byte((uint8_t*)i, 0xFF);
 
-	  }
-  }
-  else
-  {
-	  _delay_ms(1000);  // wait 1sec to display the splash screen
-  }
+				if (i % 41 == 0) {
+					er_progress++;
+					lcd_print_at_PGM(3, 3, PSTR("      "));
+					lcd_implementation_print_at(3, 3, er_progress);
+					lcd_printPGM(PSTR("%"));
+				}
 
-  
+			}
 
-  #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1
-    SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan
-  #endif
 
-  #ifdef DIGIPOT_I2C
-    digipot_i2c_init();
-  #endif
-  setup_homepin();
+			break;
+		case 4:
+			bowden_menu();
+			break;
+        
+        default:
+            break;
+    }
+    
 
-#if defined(Z_AXIS_ALWAYS_ON)
-  enable_z();
-#endif
+}
+#include "LiquidCrystal.h"
+extern LiquidCrystal lcd;
 
-  EEPROM_read_B(EEPROM_FARM_MODE, &farm_no);
-  if (farm_no > 0)
-  {
-	  farm_mode = true;
-	  farm_no = farm_no;
-	  prusa_statistics(8);
-  }
-  else
-  {
-	  farm_mode = false;
-	  farm_no = 0;
-  }
+FILE _lcdout = {0};
 
+int lcd_putchar(char c, FILE *stream)
+{
+	lcd.write(c);
+	return 0;
+}
 
-  // In the future, somewhere here would one compare the current firmware version against the firmware version stored in the EEPROM.
-  // If they differ, an update procedure may need to be performed. At the end of this block, the current firmware version
-  // is being written into the EEPROM, so the update procedure will be triggered only once.
+FILE _uartout = {0};
 
-  if (eeprom_read_byte((uint8_t*)EEPROM_BABYSTEP_Z_SET) == 0x0ff) {
-      // Reset the babystepping values, so the printer will not move the Z axis up when the babystepping is enabled.
-      // eeprom_update_byte((uint8_t*)EEPROM_BABYSTEP_X, 0x0ff);
-      // eeprom_update_byte((uint8_t*)EEPROM_BABYSTEP_Y, 0x0ff);
-      eeprom_update_byte((uint8_t*)EEPROM_BABYSTEP_Z, 0x0ff);
-      // Get the selected laugnage index before display update.
-      lang_selected = eeprom_read_byte((uint8_t*)EEPROM_LANG);
-      if (lang_selected >= LANG_NUM)
-          lang_selected = 1;
-      // Show the message.
-      lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET);
-      lcd_update_enable(true);
-      lcd_implementation_clear();
-  }
+int uart_putchar(char c, FILE *stream)
+{
+	MYSERIAL.write(c);
+	return 0;
+}
 
-  // Store the currently running firmware into an eeprom,
-  // so the next time the firmware gets updated, it will know from which version it has been updated.
-  update_current_firmware_version_to_eeprom();
+void lcd_splash()
+{
+//	lcd_print_at_PGM(0, 1, PSTR("   Original Prusa   "));
+//	lcd_print_at_PGM(0, 2, PSTR("    3D  Printers    "));
+//	lcd.print_P(PSTR("\x1b[1;3HOriginal Prusa\x1b[2;4H3D  Printers"));
+    fputs_P(PSTR(ESC_2J ESC_H(1,1) "Original Prusa i3" ESC_H(3,2) "Prusa Research"), lcdout);
 }
 
-// The loop() function is called in an endless loop by the Arduino framework from the default main() routine.
-// Before loop(), the setup() function is called by the main() routine.
-void loop()
+// "Setup" function is called by the Arduino framework on startup.
+// Before startup, the Timers-functions (PWM)/Analog RW and HardwareSerial provided by the Arduino-code 
+// are initialized by the main() routine provided by the Arduino framework.
+void setup()
 {
+    lcd_init();
+	fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream
+	lcd_splash();
+	setup_killpin();
+	setup_powerhold();
+	farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); 
+	EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no);
+	if ((farm_mode == 0xFF && farm_no == 0) || (farm_no == 0xFFFF)) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode
+	if (farm_no == 0xFFFF) farm_no = 0;
+	if (farm_mode)
+	{ 
+		prusa_statistics(8);
+		selectedSerialPort = 1;
+	}
+	else
+		selectedSerialPort = 0;
+	MYSERIAL.begin(BAUDRATE);
+	fdev_setup_stream(uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); //setup uart out stream
+	stdout = uartout;
+	SERIAL_PROTOCOLLNPGM("start");
+	SERIAL_ECHO_START;
 
-	if (usb_printing_counter > 0 && millis()-_usb_timer > 1000)
+
+#if 0
+	SERIAL_ECHOLN("Reading eeprom from 0 to 100: start");
+	for (int i = 0; i < 4096; ++i) {
+		int b = eeprom_read_byte((unsigned char*)i);
+		if (b != 255) {
+			SERIAL_ECHO(i);
+			SERIAL_ECHO(":");
+			SERIAL_ECHO(b);
+			SERIAL_ECHOLN("");
+		}
+	}
+	SERIAL_ECHOLN("Reading eeprom from 0 to 100: done");
+#endif
+
+	// Check startup - does nothing if bootloader sets MCUSR to 0
+	byte mcu = MCUSR;
+/*	if (mcu & 1) SERIAL_ECHOLNRPGM(MSG_POWERUP);
+	if (mcu & 2) SERIAL_ECHOLNRPGM(MSG_EXTERNAL_RESET);
+	if (mcu & 4) SERIAL_ECHOLNRPGM(MSG_BROWNOUT_RESET);
+	if (mcu & 8) SERIAL_ECHOLNRPGM(MSG_WATCHDOG_RESET);
+	if (mcu & 32) SERIAL_ECHOLNRPGM(MSG_SOFTWARE_RESET);*/
+	if (mcu & 1) puts_P(MSG_POWERUP);
+	if (mcu & 2) puts_P(MSG_EXTERNAL_RESET);
+	if (mcu & 4) puts_P(MSG_BROWNOUT_RESET);
+	if (mcu & 8) puts_P(MSG_WATCHDOG_RESET);
+	if (mcu & 32) puts_P(MSG_SOFTWARE_RESET);
+	MCUSR = 0;
+
+	//SERIAL_ECHORPGM(MSG_MARLIN);
+	//SERIAL_ECHOLNRPGM(VERSION_STRING);
+
+#ifdef STRING_VERSION_CONFIG_H
+#ifdef STRING_CONFIG_H_AUTHOR
+	SERIAL_ECHO_START;
+	SERIAL_ECHORPGM(MSG_CONFIGURATION_VER);
+	SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H);
+	SERIAL_ECHORPGM(MSG_AUTHOR);
+	SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
+	SERIAL_ECHOPGM("Compiled: ");
+	SERIAL_ECHOLNPGM(__DATE__);
+#endif
+#endif
+
+	SERIAL_ECHO_START;
+	SERIAL_ECHORPGM(MSG_FREE_MEMORY);
+	SERIAL_ECHO(freeMemory());
+	SERIAL_ECHORPGM(MSG_PLANNER_BUFFER_BYTES);
+	SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
+	//lcd_update_enable(false); // why do we need this?? - andre
+	// loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
+	Config_RetrieveSettings(EEPROM_OFFSET);
+	SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack
+
+	tp_init();    // Initialize temperature loop
+
+	lcd_splash(); // we need to do this again, because tp_init() kills lcd
+
+	plan_init();  // Initialize planner;
+	watchdog_init();
+
+#ifdef TMC2130
+	uint8_t silentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
+	tmc2130_mode = silentMode?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL;
+	uint8_t crashdet = eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET);
+	if (crashdet)
 	{
-		is_usb_printing = true;
-		usb_printing_counter--;
-		_usb_timer = millis();
+		crashdet_enable();
+	    MYSERIAL.println("CrashDetect ENABLED!");
 	}
-	if (usb_printing_counter == 0)
+	else
 	{
-		is_usb_printing = false;
+		crashdet_disable();
+	    MYSERIAL.println("CrashDetect DISABLED");
 	}
 
-  get_command();
+#endif //TMC2130
 
-  #ifdef SDSUPPORT
-  card.checkautostart(false);
-  #endif
-  if(buflen)
-  {
-    #ifdef SDSUPPORT
-      if(card.saving)
-      {
-        // Saving a G-code file onto an SD-card is in progress.
-        // Saving starts with M28, saving until M29 is seen.
-        if(strstr_P(CMDBUFFER_CURRENT_STRING, PSTR("M29")) == NULL) {
-          card.write_command(CMDBUFFER_CURRENT_STRING);
-          if(card.logging)
-            process_commands();
-          else
-           SERIAL_PROTOCOLLNRPGM(MSG_OK);
-        } else {
-          card.closefile();
-          SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED);
-        }
-      } else {
-        process_commands();
-      }
-    #else
-      process_commands();
-    #endif //SDSUPPORT
-      if (! cmdbuffer_front_already_processed)
-          cmdqueue_pop_front();
-      cmdbuffer_front_already_processed = false;
+#ifdef PAT9125
+	int pat9125 = pat9125_init(PAT9125_XRES, PAT9125_YRES);
+    printf_P(PSTR("PAT9125_init:%d\n"), pat9125);
+	uint8_t fsensor = eeprom_read_byte((uint8_t*)EEPROM_FSENSOR);
+	if (!pat9125) fsensor = 0; //disable sensor
+    puts_P(PSTR("FSensor "));
+	if (fsensor)
+	{
+		puts_P(PSTR("ENABLED\n"));
+		fsensor_enable();
+	}
+	else
+	{
+	    puts_P(PSTR("DISABLED\n"));
+		fsensor_disable();
+	}
+
+#endif //PAT9125
+
+	st_init();    // Initialize stepper, this enables interrupts!
+    
+	setup_photpin();
+
+	servo_init();
+	// Reset the machine correction matrix.
+	// It does not make sense to load the correction matrix until the machine is homed.
+	world2machine_reset();
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	if (!READ(BTN_ENC))
+	{
+		_delay_ms(1000);
+		if (!READ(BTN_ENC))
+		{
+			lcd_implementation_clear();
+
+
+			lcd_printPGM(PSTR("Factory RESET"));
+
+
+			SET_OUTPUT(BEEPER);
+			WRITE(BEEPER, HIGH);
+
+			while (!READ(BTN_ENC));
+
+			WRITE(BEEPER, LOW);
+
+
+
+			_delay_ms(2000);
+
+			char level = reset_menu();
+			factory_reset(level, false);
+
+			switch (level) {
+			case 0: _delay_ms(0); break;
+			case 1: _delay_ms(0); break;
+			case 2: _delay_ms(0); break;
+			case 3: _delay_ms(0); break;
+			}
+			// _delay_ms(100);
+  /*
+  #ifdef MESH_BED_LEVELING
+			_delay_ms(2000);
+
+			if (!READ(BTN_ENC))
+			{
+				WRITE(BEEPER, HIGH);
+				_delay_ms(100);
+				WRITE(BEEPER, LOW);
+				_delay_ms(200);
+				WRITE(BEEPER, HIGH);
+				_delay_ms(100);
+				WRITE(BEEPER, LOW);
+
+				int _z = 0;
+				calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
+				EEPROM_save_B(EEPROM_BABYSTEP_X, &_z);
+				EEPROM_save_B(EEPROM_BABYSTEP_Y, &_z);
+				EEPROM_save_B(EEPROM_BABYSTEP_Z, &_z);
+			}
+			else
+			{
+
+				WRITE(BEEPER, HIGH);
+				_delay_ms(100);
+				WRITE(BEEPER, LOW);
+			}
+  #endif // mesh */
+
+		}
+	}
+	else
+	{
+		//_delay_ms(1000);  // wait 1sec to display the splash screen // what's this and why do we need it?? - andre
+	}
+    
+
+
+
+#if defined(CONTROLLERFAN_PIN) && (CONTROLLERFAN_PIN > -1)
+	SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan
+#endif
+
+#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+	SET_OUTPUT(LCD_PWM_PIN); //Set pin used for driver cooling fan
+#endif
+
+#ifdef DIGIPOT_I2C
+	digipot_i2c_init();
+#endif
+	setup_homepin();
+
+  if (1) {
+    SERIAL_ECHOPGM("initial zsteps on power up: "); MYSERIAL.println(tmc2130_rd_MSCNT(Z_TMC2130_CS));
+    // try to run to zero phase before powering the Z motor.    
+    // Move in negative direction
+    WRITE(Z_DIR_PIN,INVERT_Z_DIR);
+    // Round the current micro-micro steps to micro steps.
+    for (uint16_t phase = (tmc2130_rd_MSCNT(Z_TMC2130_CS) + 8) >> 4; phase > 0; -- phase) {
+      // Until the phase counter is reset to zero.
+      WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
+      delay(2);
+      WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
+      delay(2);
+    }
+    SERIAL_ECHOPGM("initial zsteps after reset: "); MYSERIAL.println(tmc2130_rd_MSCNT(Z_TMC2130_CS));
   }
-  //check heater every n milliseconds
-  manage_heater();
-  manage_inactivity();
-  checkHitEndstops();
-  lcd_update();
+
+#if defined(Z_AXIS_ALWAYS_ON)
+	enable_z();
+#endif
+	farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE);
+	EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no);
+	if ((farm_mode == 0xFF && farm_no == 0) || (farm_no == 0xFFFF)) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode 
+	if (farm_no == 0xFFFF) farm_no = 0;
+	if (farm_mode)
+	{
+		prusa_statistics(8);
+	}
+
+	// Enable Toshiba FlashAir SD card / WiFi enahanced card.
+	card.ToshibaFlashAir_enable(eeprom_read_byte((unsigned char*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY) == 1);
+	// Force SD card update. Otherwise the SD card update is done from loop() on card.checkautostart(false), 
+	// but this times out if a blocking dialog is shown in setup().
+	card.initsd();
+
+	if (eeprom_read_dword((uint32_t*)(EEPROM_TOP - 4)) == 0x0ffffffff &&
+		eeprom_read_dword((uint32_t*)(EEPROM_TOP - 8)) == 0x0ffffffff &&
+		eeprom_read_dword((uint32_t*)(EEPROM_TOP - 12)) == 0x0ffffffff) {
+		// Maiden startup. The firmware has been loaded and first started on a virgin RAMBo board,
+		// where all the EEPROM entries are set to 0x0ff.
+		// Once a firmware boots up, it forces at least a language selection, which changes
+		// EEPROM_LANG to number lower than 0x0ff.
+		// 1) Set a high power mode.
+		eeprom_write_byte((uint8_t*)EEPROM_SILENT, 0);
+		eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard
+	}
+#ifdef SNMM
+	if (eeprom_read_dword((uint32_t*)EEPROM_BOWDEN_LENGTH) == 0x0ffffffff) { //bowden length used for SNMM
+	  int _z = BOWDEN_LENGTH;
+	  for(int i = 0; i<4; i++) EEPROM_save_B(EEPROM_BOWDEN_LENGTH + i * 2, &_z);
+	}
+#endif
+
+  // In the future, somewhere here would one compare the current firmware version against the firmware version stored in the EEPROM.
+  // If they differ, an update procedure may need to be performed. At the end of this block, the current firmware version
+  // is being written into the EEPROM, so the update procedure will be triggered only once.
+    lang_selected = eeprom_read_byte((uint8_t*)EEPROM_LANG);
+    if (lang_selected >= LANG_NUM){
+      lcd_mylang();
+    }
+	
+	if (eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE) == 255) {
+		eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 0);
+		temp_cal_active = false;
+	} else temp_cal_active = eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE);
+
+	if (eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA) == 255) {
+		//eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0);
+		eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1);
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 0,   8); //40C -  20um -   8usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 1,  24); //45C -  60um -  24usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 2,  48); //50C - 120um -  48usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 3,  80); //55C - 200um -  80usteps
+		eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 4, 120); //60C - 300um - 120usteps
+
+		eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 1);
+		temp_cal_active = true;
+	}
+	if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) == 255) {
+		eeprom_write_byte((uint8_t*)EEPROM_UVLO, 0);
+	}
+
+	check_babystep(); //checking if Z babystep is in allowed range
+	setup_uvlo_interrupt();
+	setup_fan_interrupt();
+	fsensor_setup_interrupt();
+	for (int i = 0; i<4; i++) EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); 
+	
+#ifndef DEBUG_DISABLE_STARTMSGS
+  if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
+	  lcd_wizard(0);
+  }
+  if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 0) { //dont show calibration status messages if wizard is currently active
+	  if (calibration_status() == CALIBRATION_STATUS_ASSEMBLED ||
+		  calibration_status() == CALIBRATION_STATUS_UNKNOWN) {
+		  // Reset the babystepping values, so the printer will not move the Z axis up when the babystepping is enabled.
+		  eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
+		  // Show the message.
+		  lcd_show_fullscreen_message_and_wait_P(MSG_FOLLOW_CALIBRATION_FLOW);
+	  }
+	  else if (calibration_status() == CALIBRATION_STATUS_LIVE_ADJUST) {
+		  // Show the message.
+		  lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET);
+		  lcd_update_enable(true);
+	  }
+	  else if (calibration_status() == CALIBRATION_STATUS_CALIBRATED && temp_cal_active == true && calibration_status_pinda() == false) {
+		  //lcd_show_fullscreen_message_and_wait_P(MSG_PINDA_NOT_CALIBRATED);
+		  lcd_update_enable(true);
+	  }
+	  else if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) {
+		  // Show the message.
+		  lcd_show_fullscreen_message_and_wait_P(MSG_FOLLOW_CALIBRATION_FLOW);
+	  }
+  }
+  KEEPALIVE_STATE(IN_PROCESS);
+#endif //DEBUG_DISABLE_STARTMSGS
+  lcd_update_enable(true);
+  lcd_implementation_clear();
+  lcd_update(2);
+  // Store the currently running firmware into an eeprom,
+  // so the next time the firmware gets updated, it will know from which version it has been updated.
+  update_current_firmware_version_to_eeprom();
+  
+  if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) == 1) { //previous print was terminated by UVLO
+/*
+	  if (lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_RECOVER_PRINT, false))	recover_print();
+	  else {
+		  eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0);
+		  lcd_update_enable(true);
+		  lcd_update(2);
+		  lcd_setstatuspgm(WELCOME_MSG);
+	  }
+*/
+      manage_heater(); // Update temperatures 
+#ifdef DEBUG_UVLO_AUTOMATIC_RECOVER 
+      MYSERIAL.println("Power panic detected!"); 
+      MYSERIAL.print("Current bed temp:"); 
+      MYSERIAL.println(degBed()); 
+      MYSERIAL.print("Saved bed temp:"); 
+      MYSERIAL.println((float)eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED)); 
+#endif 
+     if ( degBed() > ( (float)eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED) - AUTOMATIC_UVLO_BED_TEMP_OFFSET) ){ 
+          #ifdef DEBUG_UVLO_AUTOMATIC_RECOVER 
+        MYSERIAL.println("Automatic recovery!"); 
+          #endif 
+         recover_print(1); 
+      } 
+      else{ 
+          #ifdef DEBUG_UVLO_AUTOMATIC_RECOVER 
+        MYSERIAL.println("Normal recovery!"); 
+          #endif 
+          if ( lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_RECOVER_PRINT, false) ) recover_print(0); 
+          else { 
+              eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0); 
+              lcd_update_enable(true); 
+              lcd_update(2); 
+              lcd_setstatuspgm(WELCOME_MSG); 
+          } 
+           
+      } 
+	   
+  }
+  KEEPALIVE_STATE(NOT_BUSY);
+  wdt_enable(WDTO_4S);
 }
 
-void get_command()
-{
-    // Test and reserve space for the new command string.
-    if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
-        return;
+void trace();
 
-  while (MYSERIAL.available() > 0) {
-    char serial_char = MYSERIAL.read();
-    if (serial_char < 0)
-        // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names
-        // and Marlin does not support such file names anyway.
-        // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading
-        // to a hang-up of the print process from an SD card.
-        continue;
-    if(serial_char == '\n' ||
-       serial_char == '\r' ||
-       (serial_char == ':' && comment_mode == false) ||
-       serial_count >= (MAX_CMD_SIZE - 1) )
-    {
-      if(!serial_count) { //if empty line
-        comment_mode = false; //for new command
-        return;
-      }
-      cmdbuffer[bufindw+serial_count+1] = 0; //terminate string
-      if(!comment_mode){
-        comment_mode = false; //for new command
-        if ((strchr_pointer = strchr(cmdbuffer+bufindw+1, 'N')) != NULL)
-        {
-          // Line number met. When sending a G-code over a serial line, each line may be stamped with its index,
-          // and Marlin tests, whether the successive lines are stamped with an increasing line number ID.
-          gcode_N = (strtol(strchr_pointer+1, NULL, 10));
-          if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+1, PSTR("M110")) == NULL) ) {
-            // M110 - set current line number.
-            // Line numbers not sent in succession.
-            SERIAL_ERROR_START;
-            SERIAL_ERRORRPGM(MSG_ERR_LINE_NO);
-            SERIAL_ERRORLN(gcode_LastN);
-            //Serial.println(gcode_N);
-            FlushSerialRequestResend();
-            serial_count = 0;
-            return;
-          }
+#define CHUNK_SIZE 64 // bytes
+#define SAFETY_MARGIN 1
+char chunk[CHUNK_SIZE+SAFETY_MARGIN];
+int chunkHead = 0;
 
-          if((strchr_pointer = strchr(cmdbuffer+bufindw+1, '*')) != NULL)
-          {
-            byte checksum = 0;
-            char *p = cmdbuffer+bufindw+1;
-            while (p != strchr_pointer)
-                checksum = checksum^(*p++);
-            if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) {
-              SERIAL_ERROR_START;
-              SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH);
-              SERIAL_ERRORLN(gcode_LastN);
-              FlushSerialRequestResend();
-              serial_count = 0;
-              return;
-            }
-            // If no errors, remove the checksum and continue parsing.
-            *strchr_pointer = 0;
-          }
-          else
-          {
-            SERIAL_ERROR_START;
-            SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM);
-            SERIAL_ERRORLN(gcode_LastN);
-            FlushSerialRequestResend();
-            serial_count = 0;
-            return;
-          }
+int serial_read_stream() {
 
-          gcode_LastN = gcode_N;
-          //if no errors, continue parsing
-        } // end of 'N' command
-        else  // if we don't receive 'N' but still see '*'
-        {
-          if((strchr(cmdbuffer+bufindw+1, '*') != NULL))
-          {
-            SERIAL_ERROR_START;
-            SERIAL_ERRORRPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
-            SERIAL_ERRORLN(gcode_LastN);
-            serial_count = 0;
-            return;
-          }
-        } // end of '*' command
-        if ((strchr_pointer = strchr(cmdbuffer+bufindw+1, 'G')) != NULL) {
-      		  if (! IS_SD_PRINTING) {
-        			  usb_printing_counter = 10;
-        			  is_usb_printing = true;
-      		  }
-            if (Stopped == true) {
-                int gcode = strtol(strchr_pointer+1, NULL, 10);
-                if (gcode >= 0 && gcode <= 3) {
-                    SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
-                    LCD_MESSAGERPGM(MSG_STOPPED);
-                }
+    setTargetHotend(0, 0);
+    setTargetBed(0);
+
+    lcd_implementation_clear();
+    lcd_printPGM(PSTR(" Upload in progress"));
+
+    // first wait for how many bytes we will receive
+    uint32_t bytesToReceive;
+
+    // receive the four bytes
+    char bytesToReceiveBuffer[4];
+    for (int i=0; i<4; i++) {
+        int data;
+        while ((data = MYSERIAL.read()) == -1) {};
+        bytesToReceiveBuffer[i] = data;
+
+    }
+
+    // make it a uint32
+    memcpy(&bytesToReceive, &bytesToReceiveBuffer, 4);
+
+    // we're ready, notify the sender
+    MYSERIAL.write('+');
+
+    // lock in the routine
+    uint32_t receivedBytes = 0;
+    while (prusa_sd_card_upload) {
+        int i;
+        for (i=0; i<CHUNK_SIZE; i++) {
+            int data;
+
+            // check if we're not done
+            if (receivedBytes == bytesToReceive) {
+                break;
             }
-        } // end of 'G' command
 
-        //If command was e-stop process now
-        if(strcmp(cmdbuffer+bufindw+1, "M112") == 0)
-          kill();
-        
-        // Store the current line into buffer, move to the next line.
-        cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_USB;
-#ifdef CMDBUFFER_DEBUG
+            // read the next byte
+            while ((data = MYSERIAL.read()) == -1) {};
+            receivedBytes++;
+
+            // save it to the chunk
+            chunk[i] = data;
+        }
+
+        // write the chunk to SD
+        card.write_command_no_newline(&chunk[0]);
+
+        // notify the sender we're ready for more data
+        MYSERIAL.write('+');
+
+        // for safety
+        manage_heater();
+
+        // check if we're done
+        if(receivedBytes == bytesToReceive) {
+            trace(); // beep
+            card.closefile();
+            prusa_sd_card_upload = false;
+            SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED);
+            return 0;
+        }
+
+    }
+}
+
+#ifdef HOST_KEEPALIVE_FEATURE
+/**
+* Output a "busy" message at regular intervals
+* while the machine is not accepting commands.
+*/
+void host_keepalive() {
+  if (farm_mode) return;
+  long ms = millis();
+  if (host_keepalive_interval && busy_state != NOT_BUSY) {
+    if ((ms - prev_busy_signal_ms) < (long)(1000L * host_keepalive_interval)) return;
+     switch (busy_state) {
+      case IN_HANDLER:
+      case IN_PROCESS:
         SERIAL_ECHO_START;
-        SERIAL_ECHOPGM("Storing a command line to buffer: ");
-        SERIAL_ECHO(cmdbuffer+bufindw+1);
-        SERIAL_ECHOLNPGM("");
-#endif /* CMDBUFFER_DEBUG */
-        bufindw += strlen(cmdbuffer+bufindw+1) + 2;
-        if (bufindw == sizeof(cmdbuffer))
-            bufindw = 0;
-        ++ buflen;
-#ifdef CMDBUFFER_DEBUG
-        SERIAL_ECHOPGM("Number of commands in the buffer: ");
-        SERIAL_ECHO(buflen);
-        SERIAL_ECHOLNPGM("");
-#endif /* CMDBUFFER_DEBUG */
-      } // end of 'not comment mode'
-      serial_count = 0; //clear buffer
-      // Don't call cmdqueue_could_enqueue_back if there are no characters waiting
-      // in the queue, as this function will reserve the memory.
-      if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
-          return;
-    } // end of "end of line" processing
-    else {
-      // Not an "end of line" symbol. Store the new character into a buffer.
-      if(serial_char == ';') comment_mode = true;
-      if(!comment_mode) cmdbuffer[bufindw+1+serial_count++] = serial_char;
+        SERIAL_ECHOLNPGM("busy: processing");
+        break;
+      case PAUSED_FOR_USER:
+        SERIAL_ECHO_START;
+        SERIAL_ECHOLNPGM("busy: paused for user");
+        break;
+      case PAUSED_FOR_INPUT:
+        SERIAL_ECHO_START;
+        SERIAL_ECHOLNPGM("busy: paused for input");
+        break;
+      default:
+	break;
     }
-  } // end of serial line processing loop
+  }
+  prev_busy_signal_ms = ms;
+}
+#endif
 
+// The loop() function is called in an endless loop by the Arduino framework from the default main() routine.
+// Before loop(), the setup() function is called by the main() routine.
+void loop()
+{
+	KEEPALIVE_STATE(NOT_BUSY);
+	bool stack_integrity = true;
 
-  #ifdef SDSUPPORT
-  if(!card.sdprinting || serial_count!=0){
-    // If there is a half filled buffer from serial line, wait until return before
-    // continuing with the serial line.
-    return;
-  }
+	if (usb_printing_counter > 0 && millis()-_usb_timer > 1000)
+	{
+		is_usb_printing = true;
+		usb_printing_counter--;
+		_usb_timer = millis();
+	}
+	if (usb_printing_counter == 0)
+	{
+		is_usb_printing = false;
+	}
 
-  //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible
-  // if it occurs, stop_buffering is triggered and the buffer is ran dry.
-  // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing
-
-  static bool stop_buffering=false;
-  if(buflen==0) stop_buffering=false;
-
-  // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer.
-  while( !card.eof() && !stop_buffering) {
-    int16_t n=card.get();
-    char serial_char = (char)n;
-    if(serial_char == '\n' ||
-       serial_char == '\r' ||
-       (serial_char == '#' && comment_mode == false) ||
-       (serial_char == ':' && comment_mode == false) ||
-       serial_count >= (MAX_CMD_SIZE - 1)||n==-1)
+    if (prusa_sd_card_upload)
+    {
+        //we read byte-by byte
+        serial_read_stream();
+    } else 
     {
-      if(card.eof()){
-        SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED);
-        stoptime=millis();
-        char time[30];
-        unsigned long t=(stoptime-starttime)/1000;
-        int hours, minutes;
-        minutes=(t/60)%60;
-        hours=t/60/60;
-		save_statistics(total_filament_used, t);
-		sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
-        SERIAL_ECHO_START;
-        SERIAL_ECHOLN(time);
-        lcd_setstatus(time);
-        card.printingHasFinished();
-        card.checkautostart(true);
-
-		if (farm_mode)
-		{
-			prusa_statistics(6);
-			lcd_commands_type = 4;
-		}
 
-      }
-      if(serial_char=='#')
-        stop_buffering=true;
+        get_command();
 
-      if(!serial_count)
+  #ifdef SDSUPPORT
+  card.checkautostart(false);
+  #endif
+  if(buflen)
+  {
+    cmdbuffer_front_already_processed = false;
+    #ifdef SDSUPPORT
+      if(card.saving)
       {
-        comment_mode = false; //for new command
-        return; //if empty line
+        // Saving a G-code file onto an SD-card is in progress.
+        // Saving starts with M28, saving until M29 is seen.
+        if(strstr_P(CMDBUFFER_CURRENT_STRING, PSTR("M29")) == NULL) {
+          card.write_command(CMDBUFFER_CURRENT_STRING);
+          if(card.logging)
+            process_commands();
+          else
+           SERIAL_PROTOCOLLNRPGM(MSG_OK);
+        } else {
+          card.closefile();
+          SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED);
+        }
+      } else {
+        process_commands();
       }
-      cmdbuffer[bufindw+serial_count+1] = 0; //terminate string
-      cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD;
-      ++ buflen;
-      bufindw += strlen(cmdbuffer+bufindw+1) + 2;
-      if (bufindw == sizeof(cmdbuffer))
-          bufindw = 0;
-      comment_mode = false; //for new command
-      serial_count = 0; //clear buffer
-      // The following line will reserve buffer space if available.
-      if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
-          return;
-    }
-    else
-    {
-      if(serial_char == ';') comment_mode = true;
-      if(!comment_mode) cmdbuffer[bufindw+1+serial_count++] = serial_char;
-    }
-  }
+    #else
+      process_commands();
+    #endif //SDSUPPORT
 
-  #endif //SDSUPPORT
+    if (! cmdbuffer_front_already_processed && buflen)
+	  {
+		    cli();
+        union {
+          struct {
+              char lo;
+              char hi;
+          } lohi;
+          uint16_t value;
+        } sdlen;
+        sdlen.value = 0;
+		    if (CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_SDCARD) {
+			      sdlen.lohi.lo = cmdbuffer[bufindr + 1];
+            sdlen.lohi.hi = cmdbuffer[bufindr + 2];
+        }
+	      cmdqueue_pop_front();
+		    planner_add_sd_length(sdlen.value);
+		    sei();
+	  }
+	host_keepalive();
+  }
 }
+  //check heater every n milliseconds
+  manage_heater();
+  isPrintPaused ? manage_inactivity(true) : manage_inactivity(false);
+  checkHitEndstops();
+  lcd_update();
+#ifdef PAT9125
+	fsensor_update();
+#endif //PAT9125
+#ifdef TMC2130
+	tmc2130_check_overtemp();
+	if (tmc2130_sg_crash)
+	{
+		tmc2130_sg_crash = false;
+//		crashdet_stop_and_save_print();
+		enquecommand_P((PSTR("CRASH_DETECTED")));
+	}
+#endif //TMC2130
 
-
-// Return True if a character was found
-static inline bool    code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
-static inline bool    code_seen(const char *code) { return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
-static inline float   code_value()         { return strtod(strchr_pointer+1, NULL); }
-static inline long    code_value_long()    { return strtol(strchr_pointer+1, NULL, 10); }
-static inline int16_t code_value_short()   { return int16_t(strtol(strchr_pointer+1, NULL, 10)); };
-static inline uint8_t code_value_uint8()   { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); };
+}
 
 #define DEFINE_PGM_READ_ANY(type, reader)       \
     static inline type pgm_read_any(const type *p)  \
@@ -1346,13 +1417,13 @@ inline void set_current_to_destination() { memcpy(current_position, destination,
 inline void set_destination_to_current() { memcpy(destination, current_position, sizeof(destination)); }
 
 
-static void setup_for_endstop_move() {
+static void setup_for_endstop_move(bool enable_endstops_now = true) {
     saved_feedrate = feedrate;
     saved_feedmultiply = feedmultiply;
     feedmultiply = 100;
     previous_millis_cmd = millis();
     
-    enable_endstops(true);
+    enable_endstops(enable_endstops_now);
 }
 
 static void clean_up_after_endstop_move() {
@@ -1498,42 +1569,177 @@ static float probe_pt(float x, float y, float z_before) {
 
 #endif // #ifdef ENABLE_AUTO_BED_LEVELING
 
-void homeaxis(int axis) {
+#ifdef LIN_ADVANCE
+   /**
+    * M900: Set and/or Get advance K factor and WH/D ratio
+    *
+    *  K<factor>                  Set advance K factor
+    *  R<ratio>                   Set ratio directly (overrides WH/D)
+    *  W<width> H<height> D<diam> Set ratio from WH/D
+    */
+inline void gcode_M900() {
+    st_synchronize();
+    
+    const float newK = code_seen('K') ? code_value_float() : -1;
+    if (newK >= 0) extruder_advance_k = newK;
+    
+    float newR = code_seen('R') ? code_value_float() : -1;
+    if (newR < 0) {
+        const float newD = code_seen('D') ? code_value_float() : -1,
+        newW = code_seen('W') ? code_value_float() : -1,
+        newH = code_seen('H') ? code_value_float() : -1;
+        if (newD >= 0 && newW >= 0 && newH >= 0)
+            newR = newD ? (newW * newH) / (sq(newD * 0.5) * M_PI) : 0;
+    }
+    if (newR >= 0) advance_ed_ratio = newR;
+    
+    SERIAL_ECHO_START;
+    SERIAL_ECHOPGM("Advance K=");
+    SERIAL_ECHOLN(extruder_advance_k);
+    SERIAL_ECHOPGM(" E/D=");
+    const float ratio = advance_ed_ratio;
+    if (ratio) SERIAL_ECHOLN(ratio); else SERIAL_ECHOLNPGM("Auto");
+    }
+#endif // LIN_ADVANCE
+
+#ifdef TMC2130
+bool calibrate_z_auto()
+{
+	//lcd_display_message_fullscreen_P(MSG_CALIBRATE_Z_AUTO);
+	lcd_implementation_clear();
+	lcd_print_at_PGM(0,1, MSG_CALIBRATE_Z_AUTO);
+	bool endstops_enabled  = enable_endstops(true);
+	int axis_up_dir = -home_dir(Z_AXIS);
+	tmc2130_home_enter(Z_AXIS_MASK);
+	current_position[Z_AXIS] = 0;
+	plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+	set_destination_to_current();
+	destination[Z_AXIS] += (1.1 * max_length(Z_AXIS) * axis_up_dir);
+	feedrate = homing_feedrate[Z_AXIS];
+	plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+	tmc2130_home_restart(Z_AXIS);
+	st_synchronize();
+//	current_position[axis] = 0;
+//	plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+	tmc2130_home_exit();
+    enable_endstops(false);
+	current_position[Z_AXIS] = 0;
+	plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+	set_destination_to_current();
+	destination[Z_AXIS] += 10 * axis_up_dir; //10mm up
+	feedrate = homing_feedrate[Z_AXIS] / 2;
+	plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+	st_synchronize();
+    enable_endstops(endstops_enabled);
+    current_position[Z_AXIS] = Z_MAX_POS+2.0;
+    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+	return true;
+}
+#endif //TMC2130
+
+void homeaxis(int axis)
+{
+	bool endstops_enabled  = enable_endstops(true); //RP: endstops should be allways enabled durring homming
 #define HOMEAXIS_DO(LETTER) \
-  ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))
+((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))
+    if ((axis==X_AXIS)?HOMEAXIS_DO(X):(axis==Y_AXIS)?HOMEAXIS_DO(Y):0)
+	{
+        int axis_home_dir = home_dir(axis);
+        feedrate = homing_feedrate[axis];
 
-  if (axis==X_AXIS ? HOMEAXIS_DO(X) :
-      axis==Y_AXIS ? HOMEAXIS_DO(Y) :
-      axis==Z_AXIS ? HOMEAXIS_DO(Z) :
-      0) {
-    int axis_home_dir = home_dir(axis);
+#ifdef TMC2130
+    		tmc2130_home_enter(X_AXIS_MASK << axis);
+#endif
 
-    current_position[axis] = 0;
-    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+        // Move right a bit, so that the print head does not touch the left end position,
+        // and the following left movement has a chance to achieve the required velocity
+        // for the stall guard to work.
+        current_position[axis] = 0;
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+//        destination[axis] = 11.f;
+        destination[axis] = 3.f;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        // Move left away from the possible collision with the collision detection disabled.
+        endstops_hit_on_purpose();
+        enable_endstops(false);
+        current_position[axis] = 0;
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+        destination[axis] = - 1.;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        // Now continue to move up to the left end stop with the collision detection enabled.
+        enable_endstops(true);
+        destination[axis] = - 1.1 * max_length(axis);
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        // Move right from the collision to a known distance from the left end stop with the collision detection disabled.
+        endstops_hit_on_purpose();
+        enable_endstops(false);
+        current_position[axis] = 0;
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+        destination[axis] = 10.f;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        endstops_hit_on_purpose();
+        // Now move left up to the collision, this time with a repeatable velocity.
+        enable_endstops(true);
+        destination[axis] = - 15.f;
+        feedrate = homing_feedrate[axis]/2;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
 
-    destination[axis] = 1.5 * max_length(axis) * axis_home_dir;
-    feedrate = homing_feedrate[axis];
-    plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-    st_synchronize();
+        axis_is_at_home(axis);
+        axis_known_position[axis] = true;
 
-    current_position[axis] = 0;
-    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-    destination[axis] = -home_retract_mm(axis) * axis_home_dir;
-    plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-    st_synchronize();
+#ifdef TMC2130
+        tmc2130_home_exit();
+#endif
+        // Move the X carriage away from the collision.
+        // If this is not done, the X cariage will jump from the collision at the instant the Trinamic driver reduces power on idle.
+        endstops_hit_on_purpose();
+        enable_endstops(false);
+        {
+          // Two full periods (4 full steps).
+          float gap = 0.32f * 2.f;
+          current_position[axis] -= gap;
+          plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+          current_position[axis] += gap;
+        }
+        destination[axis] = current_position[axis];
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], 0.3f*feedrate/60, active_extruder);
+        st_synchronize();
 
-    destination[axis] = 2*home_retract_mm(axis) * axis_home_dir;
-    feedrate = homing_feedrate[axis]/2 ;
-    plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-    st_synchronize();
-    axis_is_at_home(axis);
-    destination[axis] = current_position[axis];
-    feedrate = 0.0;
-    endstops_hit_on_purpose();
-    axis_known_position[axis] = true;
-  }
+    		feedrate = 0.0;
+    }
+    else if ((axis==Z_AXIS)?HOMEAXIS_DO(Z):0)
+	{
+        int axis_home_dir = home_dir(axis);
+        current_position[axis] = 0;
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+        destination[axis] = 1.5 * max_length(axis) * axis_home_dir;
+        feedrate = homing_feedrate[axis];
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        current_position[axis] = 0;
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+        destination[axis] = -home_retract_mm(axis) * axis_home_dir;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        destination[axis] = 2*home_retract_mm(axis) * axis_home_dir;
+        feedrate = homing_feedrate[axis]/2 ;
+        plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
+        st_synchronize();
+        axis_is_at_home(axis);
+        destination[axis] = current_position[axis];
+        feedrate = 0.0;
+        endstops_hit_on_purpose();
+        axis_known_position[axis] = true;
+    }
+    enable_endstops(endstops_enabled);
 }
 
+/**/
 void home_xy()
 {
     set_destination_to_current();
@@ -1592,6 +1798,271 @@ void refresh_cmd_timeout(void)
   } //retract
 #endif //FWRETRACT
 
+void trace() {
+    tone(BEEPER, 440);
+    delay(25);
+    noTone(BEEPER);
+    delay(20);
+}
+/*
+void ramming() {
+//	  float tmp[4] = DEFAULT_MAX_FEEDRATE;
+	if (current_temperature[0] < 230) {
+		//PLA
+
+		max_feedrate[E_AXIS] = 50;
+		//current_position[E_AXIS] -= 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		//current_position[E_AXIS] += 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		current_position[E_AXIS] += 5.4;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2800 / 60, active_extruder);
+		current_position[E_AXIS] += 3.2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+		current_position[E_AXIS] += 3;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3400 / 60, active_extruder);
+		st_synchronize();
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= 82;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 9500 / 60, active_extruder);
+		max_feedrate[E_AXIS] = 50;//tmp[E_AXIS];
+		current_position[E_AXIS] -= 20;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1200 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 10;
+		st_synchronize();
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] += 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		current_position[E_AXIS] += 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		current_position[E_AXIS] -= 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		st_synchronize();
+	}
+	else {
+		//ABS
+		max_feedrate[E_AXIS] = 50;
+		//current_position[E_AXIS] -= 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		//current_position[E_AXIS] += 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		current_position[E_AXIS] += 3.1;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2000 / 60, active_extruder);
+		current_position[E_AXIS] += 3.1;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+		current_position[E_AXIS] += 4;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+		st_synchronize();
+		//current_position[X_AXIS] += 23; //delay
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay
+		//current_position[X_AXIS] -= 23; //delay
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay
+		delay(4700);
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= 92;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 9900 / 60, active_extruder);
+		max_feedrate[E_AXIS] = 50;//tmp[E_AXIS];
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder);
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		st_synchronize();
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		st_synchronize();
+
+	}
+  }
+*/
+
+bool gcode_M45(bool onlyZ) {
+	bool final_result = false;
+	// Only Z calibration?
+
+
+	if (!onlyZ) {
+		setTargetBed(0);
+		setTargetHotend(0, 0);
+		setTargetHotend(0, 1);
+		setTargetHotend(0, 2);
+		adjust_bed_reset(); //reset bed level correction
+	}
+
+	// Disable the default update procedure of the display. We will do a modal dialog.
+	lcd_update_enable(false);
+	// Let the planner use the uncorrected coordinates.
+	mbl.reset();
+	// Reset world2machine_rotation_and_skew and world2machine_shift, therefore
+	// the planner will not perform any adjustments in the XY plane. 
+	// Wait for the motors to stop and update the current position with the absolute values.
+	world2machine_revert_to_uncorrected();
+	// Reset the baby step value applied without moving the axes.
+	babystep_reset();
+	// Mark all axes as in a need for homing.
+	memset(axis_known_position, 0, sizeof(axis_known_position));
+
+	// Home in the XY plane.
+	//set_destination_to_current();
+	setup_for_endstop_move();
+	lcd_display_message_fullscreen_P(MSG_AUTO_HOME);
+	home_xy();
+
+	// Let the user move the Z axes up to the end stoppers.
+#ifdef TMC2130
+	if (calibrate_z_auto()) {
+#else //TMC2130
+	if (lcd_calibrate_z_end_stop_manual(onlyZ)) {
+#endif //TMC2130
+		refresh_cmd_timeout();
+		//if (((degHotend(0) > MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) && (!onlyZ)) {
+		//	lcd_wait_for_cool_down();
+		//}
+		if(!onlyZ){
+			KEEPALIVE_STATE(PAUSED_FOR_USER);
+			bool result = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_STEEL_SHEET_CHECK, false, false);
+			if(result) lcd_show_fullscreen_message_and_wait_P(MSG_REMOVE_STEEL_SHEET);
+			lcd_show_fullscreen_message_and_wait_P(MSG_CONFIRM_NOZZLE_CLEAN);
+		    lcd_show_fullscreen_message_and_wait_P(MSG_PAPER);
+			KEEPALIVE_STATE(IN_HANDLER);
+			lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1);
+			lcd_implementation_print_at(0, 2, 1);
+			lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2);
+		}
+		// Move the print head close to the bed.
+		current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder);
+		st_synchronize();
+
+
+		//#ifdef TMC2130
+		//		tmc2130_home_enter(X_AXIS_MASK | Y_AXIS_MASK);
+		//#endif
+
+		int8_t verbosity_level = 0;
+		if (code_seen('V')) {
+			// Just 'V' without a number counts as V1.
+			char c = strchr_pointer[1];
+			verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short();
+		}
+
+		if (onlyZ) {
+			clean_up_after_endstop_move();
+			// Z only calibration.
+			// Load the machine correction matrix
+			world2machine_initialize();
+			// and correct the current_position to match the transformed coordinate system.
+			world2machine_update_current();
+			//FIXME
+			bool result = sample_mesh_and_store_reference();
+			if (result) {
+				if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION)
+					// Shipped, the nozzle height has been set already. The user can start printing now.
+					calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
+				// babystep_apply();
+			}
+		}
+		else {
+			// Reset the baby step value and the baby step applied flag.
+			calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
+			eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
+			// Complete XYZ calibration.
+			uint8_t point_too_far_mask = 0;
+			BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level, point_too_far_mask);
+			clean_up_after_endstop_move();
+			// Print head up.
+			current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder);
+			st_synchronize();
+			if (result >= 0) {
+				point_too_far_mask = 0;
+				// Second half: The fine adjustment.
+				// Let the planner use the uncorrected coordinates.
+				mbl.reset();
+				world2machine_reset();
+				// Home in the XY plane.
+				setup_for_endstop_move();
+				home_xy();
+				result = improve_bed_offset_and_skew(1, verbosity_level, point_too_far_mask);
+				clean_up_after_endstop_move();
+				// Print head up.
+				current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder);
+				st_synchronize();
+				// if (result >= 0) babystep_apply();
+			}
+			lcd_bed_calibration_show_result(result, point_too_far_mask);
+			if (result >= 0) {
+				// Calibration valid, the machine should be able to print. Advise the user to run the V2Calibration.gcode.
+				calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
+				if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET);
+				final_result = true;
+			}
+		}
+#ifdef TMC2130
+		tmc2130_home_exit();
+#endif
+	}
+	else {
+		// Timeouted.
+	}
+	lcd_update_enable(true);
+	return final_result;
+	}
+
+void gcode_M701() {
+#ifdef SNMM
+	extr_adj(snmm_extruder);//loads current extruder
+#else
+	enable_z();
+	custom_message = true;
+	custom_message_type = 2;
+
+	lcd_setstatuspgm(MSG_LOADING_FILAMENT);
+	current_position[E_AXIS] += 70;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence
+
+	current_position[E_AXIS] += 25;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 100 / 60, active_extruder); //slow sequence
+	st_synchronize();
+
+	if (!farm_mode && loading_flag) {
+		bool clean = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FILAMENT_CLEAN, false, true);
+
+		while (!clean) {
+			lcd_update_enable(true);
+			lcd_update(2);
+			current_position[E_AXIS] += 25;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 100 / 60, active_extruder); //slow sequence
+			st_synchronize();
+			clean = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FILAMENT_CLEAN, false, true);
+
+		}
+
+	}
+	lcd_update_enable(true);
+	lcd_update(2);
+	lcd_setstatuspgm(WELCOME_MSG);
+	disable_z();
+	loading_flag = false;
+	custom_message = false;
+	custom_message_type = 0;
+#endif
+}
+
 void process_commands()
 {
   #ifdef FILAMENT_RUNOUT_SUPPORT
@@ -1600,7 +2071,7 @@ void process_commands()
 
 #ifdef CMDBUFFER_DEBUG
   SERIAL_ECHOPGM("Processing a GCODE command: ");
-  SERIAL_ECHO(cmdbuffer+bufindr+1);
+  SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE);
   SERIAL_ECHOLNPGM("");
   SERIAL_ECHOPGM("In cmdqueue: ");
   SERIAL_ECHO(buflen);
@@ -1614,9 +2085,102 @@ void process_commands()
 #endif
 
   // PRUSA GCODES
+  KEEPALIVE_STATE(IN_HANDLER);
+
+#ifdef SNMM
+  float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+  float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+  int8_t SilentMode;
+#endif
+  
+  if (code_seen("M117")) { //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^"
+	  starpos = (strchr(strchr_pointer + 5, '*'));
+	  if (starpos != NULL)
+		  *(starpos) = '\0';
+	  lcd_setstatus(strchr_pointer + 5);
+  }
+
+  else if(code_seen("CRASH_DETECTED"))
+	  crashdet_detected();
+  else if(code_seen("CRASH_RECOVER"))
+	  crashdet_recover();
+  else if(code_seen("CRASH_CANCEL"))
+	  crashdet_cancel();
+
+  else if(code_seen("PRUSA")){
+		if (code_seen("Ping")) {  //PRUSA Ping
+			if (farm_mode) {
+				PingTime = millis();
+				//MYSERIAL.print(farm_no); MYSERIAL.println(": OK");
+			}	  
+		}
+		else if (code_seen("PRN")) {
+		  MYSERIAL.println(status_number);
+
+        }else if (code_seen("FAN")) {
+            MYSERIAL.print("E0:");
+            MYSERIAL.print(60*fan_speed[0]);
+            MYSERIAL.println(" RPM");
+            MYSERIAL.print("PRN0:");
+            MYSERIAL.print(60*fan_speed[1]);
+            MYSERIAL.println(" RPM");
+            
+        }else if (code_seen("fn")) {
+		  if (farm_mode) {
+			  MYSERIAL.println(farm_no);
+		  }
+		  else {
+			  MYSERIAL.println("Not in farm mode.");
+		  }
+		  
+		}else if (code_seen("fv")) {
+        // get file version
+        #ifdef SDSUPPORT
+        card.openFile(strchr_pointer + 3,true);
+        while (true) {
+            uint16_t readByte = card.get();
+            MYSERIAL.write(readByte);
+            if (readByte=='\n') {
+                break;
+            }
+        }
+        card.closefile();
 
-  if(code_seen("PRUSA")){
-    if(code_seen("Fir")){
+        #endif // SDSUPPORT
+
+    } else if (code_seen("M28")) {
+        trace();
+        prusa_sd_card_upload = true;
+        card.openFile(strchr_pointer+4,false);
+	} else if (code_seen("SN")) { 
+        if (farm_mode) { 
+            selectedSerialPort = 0; 
+            MSerial.write(";S"); 
+            // S/N is:CZPX0917X003XC13518 
+            int numbersRead = 0; 
+ 
+            while (numbersRead < 19) { 
+                while (MSerial.available() > 0) { 
+                    uint8_t serial_char = MSerial.read(); 
+                    selectedSerialPort = 1; 
+                    MSerial.write(serial_char); 
+                    numbersRead++; 
+                    selectedSerialPort = 0; 
+                } 
+            } 
+            selectedSerialPort = 1; 
+            MSerial.write('\n'); 
+            /*for (int b = 0; b < 3; b++) { 
+                tone(BEEPER, 110); 
+                delay(50); 
+                noTone(BEEPER); 
+                delay(50); 
+            }*/ 
+        } else { 
+            MYSERIAL.println("Not in farm mode."); 
+        } 
+		
+	} else if(code_seen("Fir")){
 
       SERIAL_PROTOCOLLN(FW_version);
 
@@ -1628,14 +2192,31 @@ void process_commands()
       lcd_force_language_selection();
     } else if(code_seen("Lz")) {
       EEPROM_save_B(EEPROM_BABYSTEP_Z,0);
-    } 
+      
+    } else if (code_seen("SERIAL LOW")) {
+        MYSERIAL.println("SERIAL LOW");
+        MYSERIAL.begin(BAUDRATE);
+        return;
+    } else if (code_seen("SERIAL HIGH")) {
+        MYSERIAL.println("SERIAL HIGH");
+        MYSERIAL.begin(1152000);
+        return;
+    } else if(code_seen("Beat")) {
+        // Kick farm link timer
+        kicktime = millis();
+
+    } else if(code_seen("FR")) {
+        // Factory full reset
+        factory_reset(0,true);        
+    }
     //else if (code_seen('Cal')) {
 		//  lcd_calibration();
 	  // }
 
-  }
-  else 
-  if(code_seen('G'))
+  }  
+  else if (code_seen('^')) {
+    // nothing, this is a version line
+  } else if(code_seen('G'))
   {
     switch((int)code_value())
     {
@@ -1818,8 +2399,9 @@ void process_commands()
 
 
         get_coordinates(); // For X Y Z E F
-		total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS])*100);
-
+		if (total_filament_used > ((current_position[E_AXIS] - destination[E_AXIS]) * 100)) { //protection against total_filament_used overflow
+			total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS]) * 100);
+		}
           #ifdef FWRETRACT
             if(autoretract_enabled)
             if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
@@ -1851,12 +2433,11 @@ void process_commands()
         prepare_arc_move(false);
       }
       break;
-    case 4: // G4 dwell
-      LCD_MESSAGERPGM(MSG_DWELL);
+    case 4: // G4 dwell      
       codenum = 0;
       if(code_seen('P')) codenum = code_value(); // milliseconds to wait
       if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
-
+	  if(codenum != 0) LCD_MESSAGERPGM(MSG_DWELL);
       st_synchronize();
       codenum += millis();  // keep track of when we started waiting
       previous_millis_cmd = millis();
@@ -1884,26 +2465,50 @@ void process_commands()
       break;
       #endif //FWRETRACT
     case 28: //G28 Home all Axis one at a time
+    {
+      st_synchronize();
+
+#if 1
+      SERIAL_ECHOPGM("G28, initial ");  print_world_coordinates();
+      SERIAL_ECHOPGM("G28, initial ");  print_physical_coordinates();
+#endif
+
+      // Flag for the display update routine and to disable the print cancelation during homing.
+		  homing_flag = true;
+      
+      // Which axes should be homed?
+      bool home_x = code_seen(axis_codes[X_AXIS]);
+      bool home_y = code_seen(axis_codes[Y_AXIS]);
+      bool home_z = code_seen(axis_codes[Z_AXIS]);
+      // Either all X,Y,Z codes are present, or none of them.
+      bool home_all_axes = home_x == home_y && home_x == home_z;
+      if (home_all_axes)
+        // No X/Y/Z code provided means to home all axes.
+        home_x = home_y = home_z = true;
 
 #ifdef ENABLE_AUTO_BED_LEVELING
       plan_bed_level_matrix.set_to_identity();  //Reset the plane ("erase" all leveling data)
 #endif //ENABLE_AUTO_BED_LEVELING
             
-	      
-        // For mesh bed leveling deactivate the matrix temporarily
-        #ifdef MESH_BED_LEVELING
-            mbl.active = 0;
-        #endif
-
       // Reset world2machine_rotation_and_skew and world2machine_shift, therefore
       // the planner will not perform any adjustments in the XY plane. 
       // Wait for the motors to stop and update the current position with the absolute values.
       world2machine_revert_to_uncorrected();
 
+      // For mesh bed leveling deactivate the matrix temporarily.
+      // It is necessary to disable the bed leveling for the X and Y homing moves, so that the move is performed
+      // in a single axis only.
+      // In case of re-homing the X or Y axes only, the mesh bed leveling is restored after G28.
+#ifdef MESH_BED_LEVELING
+      uint8_t mbl_was_active = mbl.active;
+      mbl.active = 0;
+      current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
+#endif
+
       // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be
       // consumed during the first movements following this statement.
-      babystepsTodoZsubtract(babystepLoadZ);
-      babystepLoadZ = 0;
+      if (home_z)
+        babystep_undo();
 
       saved_feedrate = feedrate;
       saved_feedmultiply = feedmultiply;
@@ -1912,21 +2517,17 @@ void process_commands()
 
       enable_endstops(true);
 
-      for(int8_t i=0; i < NUM_AXIS; i++)
-          destination[i] = current_position[i];
+      memcpy(destination, current_position, sizeof(destination));
       feedrate = 0.0;
 
-      home_all_axis = !((code_seen(axis_codes[X_AXIS])) || (code_seen(axis_codes[Y_AXIS])) || (code_seen(axis_codes[Z_AXIS])));
-
       #if Z_HOME_DIR > 0                      // If homing away from BED do Z first
-      if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
+      if(home_z)
         homeaxis(Z_AXIS);
-      }
       #endif
 
       #ifdef QUICK_HOME
       // In the quick mode, if both x and y are to be homed, a diagonal move will be performed initially.
-      if((home_all_axis)||( code_seen(axis_codes[X_AXIS]) && code_seen(axis_codes[Y_AXIS])) )  //first diagonal move
+      if(home_x && home_y)  //first diagonal move
       {
         current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0;
 
@@ -1962,10 +2563,10 @@ void process_commands()
       #endif /* QUICK_HOME */
 
 	 
-      if((home_all_axis) || (code_seen(axis_codes[X_AXIS])))
+      if(home_x)
         homeaxis(X_AXIS);
 
-      if((home_all_axis) || (code_seen(axis_codes[Y_AXIS])))
+      if(home_y)
         homeaxis(Y_AXIS);
 
       if(code_seen(axis_codes[X_AXIS]) && code_value_long() != 0)
@@ -1976,14 +2577,14 @@ void process_commands()
 
       #if Z_HOME_DIR < 0                      // If homing towards BED do Z last
         #ifndef Z_SAFE_HOMING
-          if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
+          if(home_z) {
             #if defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0)
               destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1);    // Set destination away from bed
               feedrate = max_feedrate[Z_AXIS];
               plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder);
               st_synchronize();
             #endif // defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0)
-            #ifdef MESH_BED_LEVELING // If Mesh bed leveling, moxve X&Y to safe position for home
+            #if (defined(MESH_BED_LEVELING) && !defined(MK1BP))  // If Mesh bed leveling, moxve X&Y to safe position for home
       			  if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] )) 
       			  {
                 homeaxis(X_AXIS);
@@ -2012,7 +2613,7 @@ void process_commands()
             #endif // MESH_BED_LEVELING
           }
         #else // defined(Z_SAFE_HOMING): Z Safe mode activated.
-          if(home_all_axis) {
+          if(home_all_axes) {
             destination[X_AXIS] = round(Z_SAFE_HOMING_X_POINT - X_PROBE_OFFSET_FROM_EXTRUDER);
             destination[Y_AXIS] = round(Z_SAFE_HOMING_Y_POINT - Y_PROBE_OFFSET_FROM_EXTRUDER);
             destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1);    // Set destination away from bed
@@ -2028,7 +2629,7 @@ void process_commands()
             homeaxis(Z_AXIS);
           }
                                                 // Let's see if X and Y are homed and probe is inside bed area.
-          if(code_seen(axis_codes[Z_AXIS])) {
+          if(home_z) {
             if ( (axis_known_position[X_AXIS]) && (axis_known_position[Y_AXIS]) \
               && (current_position[X_AXIS]+X_PROBE_OFFSET_FROM_EXTRUDER >= X_MIN_POS) \
               && (current_position[X_AXIS]+X_PROBE_OFFSET_FROM_EXTRUDER <= X_MAX_POS) \
@@ -2056,17 +2657,16 @@ void process_commands()
         #endif // Z_SAFE_HOMING
       #endif // Z_HOME_DIR < 0
 
-      if(code_seen(axis_codes[Z_AXIS])) {
-        if(code_value_long() != 0) {
-          current_position[Z_AXIS]=code_value()+add_homing[Z_AXIS];
-        }
-      }
+      if(code_seen(axis_codes[Z_AXIS]) && code_value_long() != 0)
+        current_position[Z_AXIS]=code_value()+add_homing[Z_AXIS];
       #ifdef ENABLE_AUTO_BED_LEVELING
-        if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
+        if(home_z)
           current_position[Z_AXIS] += zprobe_zoffset;  //Add Z_Probe offset (the distance is negative)
-        }
       #endif
-  
+      
+      // Set the planner and stepper routine positions.
+      // At this point the mesh bed leveling and world2machine corrections are disabled and current_position
+      // contains the machine coordinates.
       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
 
       #ifdef ENDSTOPS_ONLY_FOR_HOMING
@@ -2080,25 +2680,29 @@ void process_commands()
 #ifndef MESH_BED_LEVELING
       // If MESH_BED_LEVELING is not active, then it is the original Prusa i3.
       // Offer the user to load the baby step value, which has been adjusted at the previous print session.
-      if(card.sdprinting) {
-        EEPROM_read_B(EEPROM_BABYSTEP_Z,&babystepLoadZ);
-        if(babystepLoadZ != 0)
+      if(card.sdprinting && eeprom_read_word((uint16_t *)EEPROM_BABYSTEP_Z))
           lcd_adjust_z();
-      }
 #endif
 
     // Load the machine correction matrix
     world2machine_initialize();
-    // and correct the current_position to match the transformed coordinate system.
+    // and correct the current_position XY axes to match the transformed coordinate system.
     world2machine_update_current();
 
-#ifdef MESH_BED_LEVELING
+#if (defined(MESH_BED_LEVELING) && !defined(MK1BP))
 	if (code_seen(axis_codes[X_AXIS]) || code_seen(axis_codes[Y_AXIS]) || code_seen('W') || code_seen(axis_codes[Z_AXIS]))
 		{
+      if (! home_z && mbl_was_active) {
+        // Re-enable the mesh bed leveling if only the X and Y axes were re-homed.
+        mbl.active = true;
+        // and re-adjust the current logical Z axis with the bed leveling offset applicable at the current XY position.
+        current_position[Z_AXIS] -= mbl.get_z(st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS));
+      }
 		}
 	else
 		{
 			st_synchronize();
+			homing_flag = false;
 			// Push the commands to the front of the message queue in the reverse order!
 			// There shall be always enough space reserved for these commands.
 			// enquecommand_front_P((PSTR("G80")));
@@ -2108,8 +2712,13 @@ void process_commands()
 
 	  if (farm_mode) { prusa_statistics(20); };
 
-      break;
+	  homing_flag = false;
 
+      SERIAL_ECHOPGM("G28, final ");  print_world_coordinates();
+      SERIAL_ECHOPGM("G28, final ");  print_physical_coordinates();
+      SERIAL_ECHOPGM("G28, final ");  print_mesh_bed_leveling_table();
+      break;
+    }
 #ifdef ENABLE_AUTO_BED_LEVELING
     case 29: // G29 Detailed Z-Probe, probes the bed at 3 or more points.
         {
@@ -2286,149 +2895,645 @@ void process_commands()
 #endif // ENABLE_AUTO_BED_LEVELING
             
 #ifdef MESH_BED_LEVELING
-    /**
-     * G80: Mesh-based Z probe, probes a grid and produces a
-     *      mesh to compensate for variable bed height
-     *
-     * The S0 report the points as below
-     *
-     *  +----> X-axis
-     *  |
-     *  |
-     *  v Y-axis
-     *
-     */
-    case 80:
-    case_G80:
+    case 30: // G30 Single Z Probe
         {
-			if (!IS_SD_PRINTING)
-			{
-				custom_message = true;
-				custom_message_type = 1;
-				custom_message_state = (MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) + 10;
-			}
-			
-
-            // Firstly check if we know where we are
-            if ( !( axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS] ) ){
-                // We don't know where we are! HOME!
-                // Push the commands to the front of the message queue in the reverse order!
-                // There shall be always enough space reserved for these commands.
-                repeatcommand_front(); // repeat G80 with all its parameters
-                enquecommand_front_P((PSTR("G28 W0")));
-                break;
-            }
-            
-            mbl.reset();
-
-            // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be
-            // consumed during the first movements following this statement.
-            babystepsTodoZsubtract(babystepLoadZ);
-            babystepLoadZ = 0;
-
-            // Cycle through all points and probe them
-            // First move up. During this first movement, the babystepping will be reverted.
-            current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder);
-            // The move to the first calibration point.
-            current_position[X_AXIS] = pgm_read_float(bed_ref_points);
-            current_position[Y_AXIS] = pgm_read_float(bed_ref_points+1);
-            world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-//            mbl.get_meas_xy(0, 0, current_position[X_AXIS], current_position[Y_AXIS], false);            
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[X_AXIS]/30, active_extruder);
-            // Wait until the move is finished.
             st_synchronize();
-            
-            int mesh_point = 0;
-            
-            int ix = 0;
-            int iy = 0;
-            
-            int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS]/20;
-            int Z_PROBE_FEEDRATE = homing_feedrate[Z_AXIS]/60;
-            int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS]/40;
-            bool has_z = is_bed_z_jitter_data_valid();
+            // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly
             setup_for_endstop_move();
-            const char *kill_message = NULL;
-            while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) {
-                // Get coords of a measuring point.
-                ix = mesh_point % MESH_MEAS_NUM_X_POINTS;
-                iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
-                if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag
-                float z0 = 0.f;
-                if (has_z && mesh_point > 0) {
-                    uint16_t z_offset_u = eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + 2 * (ix + iy * 3 - 1)));
-                    z0 = mbl.z_values[0][0] + *reinterpret_cast<int16_t*>(&z_offset_u) * 0.01;
-                    #if 0
-                    SERIAL_ECHOPGM("Bed leveling, point: ");
-                    MYSERIAL.print(mesh_point);
-                    SERIAL_ECHOPGM(", calibration z: ");
-                    MYSERIAL.print(z0, 5);
-                    SERIAL_ECHOLNPGM("");
-                    #endif
-                }
-            
-                // Move Z to proper distance
-                current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-                plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
-                st_synchronize();
-
-                current_position[X_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point);
-                current_position[Y_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point+1);
-                world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-//                mbl.get_meas_xy(ix, iy, current_position[X_AXIS], current_position[Y_AXIS], false);
-                enable_endstops(false);
-                plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder);
-                st_synchronize();
-                
-                // Go down until endstop is hit
-                const float Z_CALIBRATION_THRESHOLD = 0.5f;
-                if (! find_bed_induction_sensor_point_z((has_z && mesh_point > 0) ? z0 - Z_CALIBRATION_THRESHOLD : -10.f)) {
-                    kill_message = MSG_BED_LEVELING_FAILED_POINT_LOW;
-                    break;
-                }
-                if (has_z && fabs(z0 - current_position[Z_AXIS]) > Z_CALIBRATION_THRESHOLD) {
-                    kill_message = MSG_BED_LEVELING_FAILED_POINT_HIGH;
-                    break;
-                }
 
-                mbl.set_z(ix, iy, current_position[Z_AXIS]);
+            feedrate = homing_feedrate[Z_AXIS];
 
-        				if (!IS_SD_PRINTING)
-        				{
-        					custom_message_state--;
-        				}
-                mesh_point++;
-                
-            }
-            current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
-            if (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) {
-                st_synchronize();
-                kill(kill_message);
-            }
+            find_bed_induction_sensor_point_z(-10.f, 3);
+            SERIAL_PROTOCOLRPGM(MSG_BED);
+            SERIAL_PROTOCOLPGM(" X: ");
+            MYSERIAL.print(current_position[X_AXIS], 5);
+            SERIAL_PROTOCOLPGM(" Y: ");
+            MYSERIAL.print(current_position[Y_AXIS], 5);
+            SERIAL_PROTOCOLPGM(" Z: ");
+            MYSERIAL.print(current_position[Z_AXIS], 5);
+            SERIAL_PROTOCOLPGM("\n");
             clean_up_after_endstop_move();
-            mbl.upsample_3x3();
-            mbl.active = 1;
-            current_position[X_AXIS] = X_MIN_POS+0.2;
-            current_position[Y_AXIS] = Y_MIN_POS+0.2;
-            current_position[Z_AXIS] = Z_MIN_POS;
-            world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-            plan_buffer_line(current_position[X_AXIS], current_position[X_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder);
-            st_synchronize();
-			
-			      if(card.sdprinting || is_usb_printing ) 
-			      {
-                if(eeprom_read_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET) == 0x01)
-				        {
-                    // End of G80: Apply the baby stepping value.
-                    EEPROM_read_B(EEPROM_BABYSTEP_Z,&babystepLoadZ);
-                    babystepsTodoZadd(babystepLoadZ);
-                }
-            }
         }
         break;
-        
+	
+
+	case 75:
+	{
+		for (int i = 40; i <= 110; i++) {
+			MYSERIAL.print(i);
+			MYSERIAL.print("  ");
+			MYSERIAL.println(temp_comp_interpolation(i));// / axis_steps_per_unit[Z_AXIS]);
+		}
+	}
+	break;
+
+	case 76: //PINDA probe temperature calibration
+	{
+#ifdef PINDA_THERMISTOR
+		if (true)
+		{
+			if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) {
+				// We don't know where we are! HOME!
+				// Push the commands to the front of the message queue in the reverse order!
+				// There shall be always enough space reserved for these commands.
+				repeatcommand_front(); // repeat G76 with all its parameters
+				enquecommand_front_P((PSTR("G28 W0")));
+				break;
+			}
+			KEEPALIVE_STATE(NOT_BUSY); //no need to print busy messages as we print current temperatures periodicaly
+			SERIAL_ECHOLNPGM("PINDA probe calibration start");
+
+			float zero_z;
+			int z_shift = 0; //unit: steps
+			float start_temp = 5 * (int)(current_temperature_pinda / 5);
+			if (start_temp < 35) start_temp = 35;
+			if (start_temp < current_temperature_pinda) start_temp += 5;
+			SERIAL_ECHOPGM("start temperature: ");
+			MYSERIAL.println(start_temp);
+
+//			setTargetHotend(200, 0);
+			setTargetBed(70 + (start_temp - 30));
+
+			custom_message = true;
+			custom_message_type = 4;
+			custom_message_state = 1;
+			custom_message = MSG_TEMP_CALIBRATION;
+			current_position[X_AXIS] = PINDA_PREHEAT_X;
+			current_position[Y_AXIS] = PINDA_PREHEAT_Y;
+			current_position[Z_AXIS] = PINDA_PREHEAT_Z;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			st_synchronize();
+
+			while (current_temperature_pinda < start_temp)
+			{
+				delay_keep_alive(1000);
+				serialecho_temperatures();
+			}
+
+			eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process 
+
+			current_position[Z_AXIS] = 5;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+
+			current_position[X_AXIS] = pgm_read_float(bed_ref_points);
+			current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1);
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			st_synchronize();
+
+			find_bed_induction_sensor_point_z(-1.f);
+			zero_z = current_position[Z_AXIS];
+
+			//current_position[Z_AXIS]
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("ZERO: ");
+			MYSERIAL.print(current_position[Z_AXIS]);
+			SERIAL_ECHOLNPGM("");
+
+			int i = -1; for (; i < 5; i++)
+			{
+				float temp = (40 + i * 5);
+				SERIAL_ECHOPGM("Step: ");
+				MYSERIAL.print(i + 2);
+				SERIAL_ECHOLNPGM("/6 (skipped)");
+				SERIAL_ECHOPGM("PINDA temperature: ");
+				MYSERIAL.print((40 + i*5));
+				SERIAL_ECHOPGM(" Z shift (mm):");
+				MYSERIAL.print(0);
+				SERIAL_ECHOLNPGM("");
+				if (i >= 0) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift);
+				if (start_temp <= temp) break;
+			}
+
+			for (i++; i < 5; i++)
+			{
+				float temp = (40 + i * 5);
+				SERIAL_ECHOPGM("Step: ");
+				MYSERIAL.print(i + 2);
+				SERIAL_ECHOLNPGM("/6");
+				custom_message_state = i + 2;
+				setTargetBed(50 + 10 * (temp - 30) / 5);
+//				setTargetHotend(255, 0);
+				current_position[X_AXIS] = PINDA_PREHEAT_X;
+				current_position[Y_AXIS] = PINDA_PREHEAT_Y;
+				current_position[Z_AXIS] = PINDA_PREHEAT_Z;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+				st_synchronize();
+				while (current_temperature_pinda < temp)
+				{
+					delay_keep_alive(1000);
+					serialecho_temperatures();
+				}
+				current_position[Z_AXIS] = 5;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+				current_position[X_AXIS] = pgm_read_float(bed_ref_points);
+				current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1);
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+				st_synchronize();
+				find_bed_induction_sensor_point_z(-1.f);
+				z_shift = (int)((current_position[Z_AXIS] - zero_z)*axis_steps_per_unit[Z_AXIS]);
+
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOPGM("PINDA temperature: ");
+				MYSERIAL.print(current_temperature_pinda);
+				SERIAL_ECHOPGM(" Z shift (mm):");
+				MYSERIAL.print(current_position[Z_AXIS] - zero_z);
+				SERIAL_ECHOLNPGM("");
+
+				EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift);
+
+			}
+			custom_message_type = 0;
+			custom_message = false;
+
+			eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1);
+			SERIAL_ECHOLNPGM("Temperature calibration done. Continue with pressing the knob.");
+			disable_x();
+			disable_y();
+			disable_z();
+			disable_e0();
+			disable_e1();
+			disable_e2();
+			lcd_show_fullscreen_message_and_wait_P(MSG_TEMP_CALIBRATION_DONE);
+			lcd_update_enable(true);
+			lcd_update(2);
+
+			setTargetBed(0); //set bed target temperature back to 0
+//			setTargetHotend(0,0); //set hotend target temperature back to 0
+			break;
+		}
+#endif //PINDA_THERMISTOR
+
+		setTargetBed(PINDA_MIN_T);
+		float zero_z;
+		int z_shift = 0; //unit: steps
+		int t_c; // temperature
+
+		if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) {
+			// We don't know where we are! HOME!
+			// Push the commands to the front of the message queue in the reverse order!
+			// There shall be always enough space reserved for these commands.
+			repeatcommand_front(); // repeat G76 with all its parameters
+			enquecommand_front_P((PSTR("G28 W0")));
+			break;
+		}
+		SERIAL_ECHOLNPGM("PINDA probe calibration start");
+		custom_message = true;
+		custom_message_type = 4;
+		custom_message_state = 1;
+		custom_message = MSG_TEMP_CALIBRATION;
+		current_position[X_AXIS] = PINDA_PREHEAT_X;
+		current_position[Y_AXIS] = PINDA_PREHEAT_Y;
+		current_position[Z_AXIS] = PINDA_PREHEAT_Z;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+		st_synchronize();
+		
+		while (abs(degBed() - PINDA_MIN_T) > 1) {
+			delay_keep_alive(1000);
+			serialecho_temperatures();
+		}
+		
+		//enquecommand_P(PSTR("M190 S50"));
+		for (int i = 0; i < PINDA_HEAT_T; i++) {
+			delay_keep_alive(1000);
+			serialecho_temperatures();
+		}
+		eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process 
+
+		current_position[Z_AXIS] = 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+
+		current_position[X_AXIS] = pgm_read_float(bed_ref_points);
+		current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1);
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+		st_synchronize();
+		
+		find_bed_induction_sensor_point_z(-1.f);
+		zero_z = current_position[Z_AXIS];
+
+		//current_position[Z_AXIS]
+		SERIAL_ECHOLNPGM("");
+		SERIAL_ECHOPGM("ZERO: ");
+		MYSERIAL.print(current_position[Z_AXIS]);
+		SERIAL_ECHOLNPGM("");
+
+		for (int i = 0; i<5; i++) {
+			SERIAL_ECHOPGM("Step: ");
+			MYSERIAL.print(i+2);
+			SERIAL_ECHOLNPGM("/6");
+			custom_message_state = i + 2;
+			t_c = 60 + i * 10;
+
+			setTargetBed(t_c);
+			current_position[X_AXIS] = PINDA_PREHEAT_X;
+			current_position[Y_AXIS] = PINDA_PREHEAT_Y;
+			current_position[Z_AXIS] = PINDA_PREHEAT_Z;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			st_synchronize();
+			while (degBed() < t_c) {
+				delay_keep_alive(1000);
+				serialecho_temperatures();
+			}
+			for (int i = 0; i < PINDA_HEAT_T; i++) {
+				delay_keep_alive(1000);
+				serialecho_temperatures();
+			}
+			current_position[Z_AXIS] = 5;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			current_position[X_AXIS] = pgm_read_float(bed_ref_points);
+			current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1);
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			st_synchronize();
+			find_bed_induction_sensor_point_z(-1.f);
+			z_shift = (int)((current_position[Z_AXIS] - zero_z)*axis_steps_per_unit[Z_AXIS]);
+
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("Temperature: ");
+			MYSERIAL.print(t_c);
+			SERIAL_ECHOPGM(" Z shift (mm):");
+			MYSERIAL.print(current_position[Z_AXIS] - zero_z);
+			SERIAL_ECHOLNPGM("");
+
+			EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i*2, &z_shift);
+			
+		
+		}
+		custom_message_type = 0;
+		custom_message = false;
+
+		eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1);
+		SERIAL_ECHOLNPGM("Temperature calibration done. Continue with pressing the knob.");
+			disable_x();
+			disable_y();
+			disable_z();
+			disable_e0();
+			disable_e1();
+			disable_e2();
+			setTargetBed(0); //set bed target temperature back to 0
+		lcd_show_fullscreen_message_and_wait_P(MSG_TEMP_CALIBRATION_DONE);
+		lcd_update_enable(true);
+		lcd_update(2);		
+
+		
+
+	}
+	break;
+
+#ifdef DIS
+	case 77:
+	{
+		//G77 X200 Y150 XP100 YP15 XO10 Y015
+
+		//for 9 point mesh bed leveling G77 X203 Y196 XP3 YP3 XO0 YO0
+
+
+		//G77 X232 Y218 XP116 YP109 XO-11 YO0 
+
+		float dimension_x = 40;
+		float dimension_y = 40;
+		int points_x = 40;
+		int points_y = 40;
+		float offset_x = 74;
+		float offset_y = 33;
+
+		if (code_seen('X')) dimension_x = code_value();
+		if (code_seen('Y')) dimension_y = code_value();
+		if (code_seen('XP')) points_x = code_value();
+		if (code_seen('YP')) points_y = code_value();
+		if (code_seen('XO')) offset_x = code_value();
+		if (code_seen('YO')) offset_y = code_value();
+		
+		bed_analysis(dimension_x,dimension_y,points_x,points_y,offset_x,offset_y);
+		
+	} break;
+	
+#endif
+
+	case 79: {
+		for (int i = 255; i > 0; i = i - 5) {
+			fanSpeed = i;
+			//delay_keep_alive(2000);
+			for (int j = 0; j < 100; j++) {
+				delay_keep_alive(100);
+
+			}
+			fan_speed[1];
+			MYSERIAL.print(i); SERIAL_ECHOPGM(": "); MYSERIAL.println(fan_speed[1]);
+		}
+	}break;
+
+	/**
+	* G80: Mesh-based Z probe, probes a grid and produces a
+	*      mesh to compensate for variable bed height
+	*
+	* The S0 report the points as below
+	*
+	*  +----> X-axis
+	*  |
+	*  |
+	*  v Y-axis
+	*
+	*/
+
+	case 80:
+#ifdef MK1BP
+		break;
+#endif //MK1BP
+	case_G80:
+	{
+		mesh_bed_leveling_flag = true;
+		int8_t verbosity_level = 0;
+		static bool run = false;
+
+		if (code_seen('V')) {
+			// Just 'V' without a number counts as V1.
+			char c = strchr_pointer[1];
+			verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short();
+		}
+		// Firstly check if we know where we are
+		if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) {
+			// We don't know where we are! HOME!
+			// Push the commands to the front of the message queue in the reverse order!
+			// There shall be always enough space reserved for these commands.
+			if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) {
+				repeatcommand_front(); // repeat G80 with all its parameters
+				enquecommand_front_P((PSTR("G28 W0")));
+			}
+			else {
+				mesh_bed_leveling_flag = false;
+			}
+			break;
+		} 
+		
+		
+		bool temp_comp_start = true;
+#ifdef PINDA_THERMISTOR
+		temp_comp_start = false;
+#endif //PINDA_THERMISTOR
+
+		if (temp_comp_start)
+		if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) {
+			if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) {
+				temp_compensation_start();
+				run = true;
+				repeatcommand_front(); // repeat G80 with all its parameters
+				enquecommand_front_P((PSTR("G28 W0")));
+			}
+			else {
+				mesh_bed_leveling_flag = false;
+			}
+			break;
+		}
+		run = false;
+		if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) {
+			mesh_bed_leveling_flag = false;
+			break;
+		}
+		// Save custom message state, set a new custom message state to display: Calibrating point 9.
+		bool custom_message_old = custom_message;
+		unsigned int custom_message_type_old = custom_message_type;
+		unsigned int custom_message_state_old = custom_message_state;
+		custom_message = true;
+		custom_message_type = 1;
+		custom_message_state = (MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) + 10;
+		lcd_update(1);
+
+		mbl.reset(); //reset mesh bed leveling
+
+					 // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be
+					 // consumed during the first movements following this statement.
+		babystep_undo();
+
+		// Cycle through all points and probe them
+		// First move up. During this first movement, the babystepping will be reverted.
+		current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 60, active_extruder);
+		// The move to the first calibration point.
+		current_position[X_AXIS] = pgm_read_float(bed_ref_points);
+		current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1);
+		bool clamped = world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
+
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 1) {
+			clamped ? SERIAL_PROTOCOLPGM("First calibration point clamped.\n") : SERIAL_PROTOCOLPGM("No clamping for first calibration point.\n");
+		}
+		#endif //SUPPORT_VERBOSITY
+		//            mbl.get_meas_xy(0, 0, current_position[X_AXIS], current_position[Y_AXIS], false);            
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[X_AXIS] / 30, active_extruder);
+		// Wait until the move is finished.
+		st_synchronize();
+
+		int mesh_point = 0; //index number of calibration point
+
+		int ix = 0;
+		int iy = 0;
+
+		int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20;
+		int Z_PROBE_FEEDRATE = homing_feedrate[Z_AXIS] / 60;
+		int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40;
+		bool has_z = is_bed_z_jitter_data_valid(); //checks if we have data from Z calibration (offsets of the Z heiths of the 8 calibration points from the first point)
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 1) {
+			has_z ? SERIAL_PROTOCOLPGM("Z jitter data from Z cal. valid.\n") : SERIAL_PROTOCOLPGM("Z jitter data from Z cal. not valid.\n");
+		}
+		#endif // SUPPORT_VERBOSITY
+		setup_for_endstop_move(false); //save feedrate and feedmultiply, sets feedmultiply to 100
+		const char *kill_message = NULL;
+		while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) {
+			// Get coords of a measuring point.
+			ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
+			iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
+			if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag
+			float z0 = 0.f;
+			if (has_z && mesh_point > 0) {
+				uint16_t z_offset_u = eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + 2 * (ix + iy * 3 - 1)));
+				z0 = mbl.z_values[0][0] + *reinterpret_cast<int16_t*>(&z_offset_u) * 0.01;
+				//#if 0
+				#ifdef SUPPORT_VERBOSITY
+				if (verbosity_level >= 1) {
+					SERIAL_ECHOLNPGM("");
+					SERIAL_ECHOPGM("Bed leveling, point: ");
+					MYSERIAL.print(mesh_point);
+					SERIAL_ECHOPGM(", calibration z: ");
+					MYSERIAL.print(z0, 5);
+					SERIAL_ECHOLNPGM("");
+				}
+				#endif // SUPPORT_VERBOSITY
+				//#endif
+			}
+
+			// Move Z up to MESH_HOME_Z_SEARCH.
+			current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
+			st_synchronize();
+
+			// Move to XY position of the sensor point.
+			current_position[X_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point);
+			current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point + 1);
+
+
+
+			world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 1) {
+
+				SERIAL_PROTOCOL(mesh_point);
+				clamped ? SERIAL_PROTOCOLPGM(": xy clamped.\n") : SERIAL_PROTOCOLPGM(": no xy clamping\n");
+			}
+			#endif // SUPPORT_VERBOSITY
+
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder);
+			st_synchronize();
+
+			// Go down until endstop is hit
+			const float Z_CALIBRATION_THRESHOLD = 1.f;
+			if (!find_bed_induction_sensor_point_z((has_z && mesh_point > 0) ? z0 - Z_CALIBRATION_THRESHOLD : -10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point  
+				kill_message = MSG_BED_LEVELING_FAILED_POINT_LOW;
+				break;
+			}
+			if (MESH_HOME_Z_SEARCH - current_position[Z_AXIS] < 0.1f) {
+				kill_message = MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED;
+				break;
+			}
+			if (has_z && fabs(z0 - current_position[Z_AXIS]) > Z_CALIBRATION_THRESHOLD) { //if we have data from z calibration, max. allowed difference is 1mm for each point
+				kill_message = MSG_BED_LEVELING_FAILED_POINT_HIGH;
+				break;
+			}
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 10) {
+				SERIAL_ECHOPGM("X: ");
+				MYSERIAL.print(current_position[X_AXIS], 5);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOPGM("Y: ");
+				MYSERIAL.print(current_position[Y_AXIS], 5);
+				SERIAL_PROTOCOLPGM("\n");
+			}
+			#endif // SUPPORT_VERBOSITY
+			float offset_z = 0;
+
+#ifdef PINDA_THERMISTOR
+			offset_z = temp_compensation_pinda_thermistor_offset(current_temperature_pinda);
+#endif //PINDA_THERMISTOR
+//			#ifdef SUPPORT_VERBOSITY
+//			if (verbosity_level >= 1)
+			{
+				SERIAL_ECHOPGM("mesh bed leveling: ");
+				MYSERIAL.print(current_position[Z_AXIS], 5);
+				SERIAL_ECHOPGM(" offset: ");
+				MYSERIAL.print(offset_z, 5);
+				SERIAL_ECHOLNPGM("");
+			}
+//			#endif // SUPPORT_VERBOSITY
+			mbl.set_z(ix, iy, current_position[Z_AXIS] - offset_z); //store measured z values z_values[iy][ix] = z - offset_z;
+
+			custom_message_state--;
+			mesh_point++;
+			lcd_update(1);
+		}
+		current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 20) {
+			SERIAL_ECHOLNPGM("Mesh bed leveling while loop finished.");
+			SERIAL_ECHOLNPGM("MESH_HOME_Z_SEARCH: ");
+			MYSERIAL.print(current_position[Z_AXIS], 5);
+		}
+		#endif // SUPPORT_VERBOSITY
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
+		st_synchronize();
+		if (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) {
+			kill(kill_message);
+			SERIAL_ECHOLNPGM("killed");
+		}
+		clean_up_after_endstop_move();
+		SERIAL_ECHOLNPGM("clean up finished ");
+
+		bool apply_temp_comp = true;
+#ifdef PINDA_THERMISTOR
+		apply_temp_comp = false;
+#endif
+		if (apply_temp_comp)
+		if(temp_cal_active == true && calibration_status_pinda() == true) temp_compensation_apply(); //apply PINDA temperature compensation
+		babystep_apply(); // Apply Z height correction aka baby stepping before mesh bed leveing gets activated.
+		SERIAL_ECHOLNPGM("babystep applied");
+		bool eeprom_bed_correction_valid = eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1;
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 1) {
+			eeprom_bed_correction_valid ? SERIAL_PROTOCOLPGM("Bed correction data valid\n") : SERIAL_PROTOCOLPGM("Bed correction data not valid\n");
+		}
+		#endif // SUPPORT_VERBOSITY
+
+		for (uint8_t i = 0; i < 4; ++i) {
+			unsigned char codes[4] = { 'L', 'R', 'F', 'B' };
+			long correction = 0;
+			if (code_seen(codes[i]))
+				correction = code_value_long();
+			else if (eeprom_bed_correction_valid) {
+				unsigned char *addr = (i < 2) ?
+					((i == 0) ? (unsigned char*)EEPROM_BED_CORRECTION_LEFT : (unsigned char*)EEPROM_BED_CORRECTION_RIGHT) :
+					((i == 2) ? (unsigned char*)EEPROM_BED_CORRECTION_FRONT : (unsigned char*)EEPROM_BED_CORRECTION_REAR);
+				correction = eeprom_read_int8(addr);
+			}
+			if (correction == 0)
+				continue;
+			float offset = float(correction) * 0.001f;
+			if (fabs(offset) > 0.101f) {
+				SERIAL_ERROR_START;
+				SERIAL_ECHOPGM("Excessive bed leveling correction: ");
+				SERIAL_ECHO(offset);
+				SERIAL_ECHOLNPGM(" microns");
+			}
+			else {
+				switch (i) {
+				case 0:
+					for (uint8_t row = 0; row < 3; ++row) {
+						mbl.z_values[row][1] += 0.5f * offset;
+						mbl.z_values[row][0] += offset;
+					}
+					break;
+				case 1:
+					for (uint8_t row = 0; row < 3; ++row) {
+						mbl.z_values[row][1] += 0.5f * offset;
+						mbl.z_values[row][2] += offset;
+					}
+					break;
+				case 2:
+					for (uint8_t col = 0; col < 3; ++col) {
+						mbl.z_values[1][col] += 0.5f * offset;
+						mbl.z_values[0][col] += offset;
+					}
+					break;
+				case 3:
+					for (uint8_t col = 0; col < 3; ++col) {
+						mbl.z_values[1][col] += 0.5f * offset;
+						mbl.z_values[2][col] += offset;
+					}
+					break;
+				}
+			}
+		}
+		SERIAL_ECHOLNPGM("Bed leveling correction finished");
+		mbl.upsample_3x3(); //bilinear interpolation from 3x3 to 7x7 points while using the same array z_values[iy][ix] for storing (just coppying measured data to new destination and interpolating between them)
+		SERIAL_ECHOLNPGM("Upsample finished");
+		mbl.active = 1; //activate mesh bed leveling
+		SERIAL_ECHOLNPGM("Mesh bed leveling activated");
+		go_home_with_z_lift();
+		SERIAL_ECHOLNPGM("Go home finished");
+		//unretract (after PINDA preheat retraction)
+		if (degHotend(active_extruder) > EXTRUDE_MINTEMP && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) {
+			current_position[E_AXIS] += DEFAULT_RETRACTION;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder);
+		}
+		KEEPALIVE_STATE(NOT_BUSY);
+		// Restore custom message state
+		custom_message = custom_message_old;
+		custom_message_type = custom_message_type_old;
+		custom_message_state = custom_message_state_old;
+		mesh_bed_leveling_flag = false;
+		mesh_bed_run_from_menu = false;
+		lcd_update(2);
+		
+	}
+	break;
+
         /**
          * G81: Print mesh bed leveling status and bed profile if activated
          */
@@ -2452,6 +3557,8 @@ void process_commands()
             else
                 SERIAL_PROTOCOLLNPGM("Mesh bed leveling not active.");
             break;
+            
+#if 0
         /**
          * G82: Single Z probe at current location
          *
@@ -2467,7 +3574,7 @@ void process_commands()
             SERIAL_PROTOCOL_F(current_position[Z_AXIS], 5);
             SERIAL_PROTOCOLPGM("\n");
             break;
-            
+
             /**
              * G83: Prusa3D specific: Babystep in Z and store to EEPROM
              */
@@ -2507,24 +3614,28 @@ void process_commands()
         case 85:
             lcd_pick_babystep();
             break;
+#endif
             
             /**
              * G86: Prusa3D specific: Disable babystep correction after home.
              * This G-code will be performed at the start of a calibration script.
              */
         case 86:
-            eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0xFF);
+            calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
             break;
             /**
              * G87: Prusa3D specific: Enable babystep correction after home
              * This G-code will be performed at the end of a calibration script.
              */
         case 87:
-            eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0x01);
+			calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
             break;
 
-		case 88:
-			break;
+            /**
+             * G88: Prusa3D specific: Don't know what it is for, it is in V2Calibration.gcode
+             */
+		    case 88:
+			      break;
 
 
 #endif  // ENABLE_MESH_BED_LEVELING
@@ -2553,16 +3664,17 @@ void process_commands()
       }
       break;
 
-	case 98:
-		farm_no = 21;
-		EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-		farm_mode = true;
+	case 98: //activate farm mode
+		farm_mode = 1;
+		PingTime = millis();
+		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
 		break;
 
-	case 99:
-		farm_no = 0;
-		EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-		farm_mode = false;
+	case 99: //deactivate farm mode
+		farm_mode = 0;
+		lcd_printer_connected();
+		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
+		lcd_update(2);
 		break;
 
 
@@ -2576,9 +3688,17 @@ void process_commands()
 
   else if(code_seen('M'))
   {
-    switch( (int)code_value() )
+	  int index;
+	  for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++);
+	   
+	 /*for (++strchr_pointer; *strchr_pointer == ' ' || *strchr_pointer == '\t'; ++strchr_pointer);*/
+	  if (*(strchr_pointer+index) < '0' || *(strchr_pointer+index) > '9') {
+		  SERIAL_ECHOLNPGM("Invalid M code");
+	  } else
+    switch((int)code_value())
     {
 #ifdef ULTIPANEL
+
     case 0: // M0 - Unconditional stop - Wait for user button press on LCD
     case 1: // M1 - Conditional stop - Wait for user button press on LCD
     {
@@ -2604,25 +3724,29 @@ void process_commands()
         LCD_MESSAGERPGM(MSG_USERWAIT);
       }
 
-      lcd_ignore_click();
+      lcd_ignore_click();				//call lcd_ignore_click aslo for else ???
       st_synchronize();
       previous_millis_cmd = millis();
       if (codenum > 0){
         codenum += millis();  // keep track of when we started waiting
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
         while(millis() < codenum && !lcd_clicked()){
           manage_heater();
-          manage_inactivity();
+          manage_inactivity(true);
           lcd_update();
         }
+		KEEPALIVE_STATE(IN_HANDLER);
         lcd_ignore_click(false);
       }else{
           if (!lcd_detected())
             break;
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
         while(!lcd_clicked()){
           manage_heater();
-          manage_inactivity();
+          manage_inactivity(true);
           lcd_update();
         }
+		KEEPALIVE_STATE(IN_HANDLER);
       }
       if (IS_SD_PRINTING)
         LCD_MESSAGERPGM(MSG_RESUMING);
@@ -2665,7 +3789,7 @@ void process_commands()
     case 24: //M24 - Start SD print
       card.startFileprint();
       starttime=millis();
-      break;
+	  break;
     case 25: //M25 - Pause SD print
       card.pauseSDPrint();
       break;
@@ -2793,6 +3917,11 @@ void process_commands()
      break;
 
     case 44: // M44: Prusa3D: Reset the bed skew and offset calibration.
+
+		// Reset the baby step value and the baby step applied flag.
+		calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
+		eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
+
         // Reset the skew and offset in both RAM and EEPROM.
         reset_bed_offset_and_skew();
         // Reset world2machine_rotation_and_skew and world2machine_shift, therefore
@@ -2803,63 +3932,10 @@ void process_commands()
 
     case 45: // M45: Prusa3D: bed skew and offset with manual Z up
     {
-        // Disable the default update procedure of the display. We will do a modal dialog.
-        lcd_update_enable(false);
-        // Let the planner use the uncorrected coordinates.
-        mbl.reset();
-        // Reset world2machine_rotation_and_skew and world2machine_shift, therefore
-        // the planner will not perform any adjustments in the XY plane. 
-        // Wait for the motors to stop and update the current position with the absolute values.
-        world2machine_revert_to_uncorrected();
-        // Let the user move the Z axes up to the end stoppers.
-        if (lcd_calibrate_z_end_stop_manual()) {
-            refresh_cmd_timeout();
-            // Move the print head close to the bed.
-            current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder);
-            st_synchronize();
-            // Home in the XY plane.
-            set_destination_to_current();
-            setup_for_endstop_move();
-            home_xy();
-            int8_t verbosity_level = 0;
-            if (code_seen('V')) {
-                // Just 'V' without a number counts as V1.
-                char c = strchr_pointer[1];
-                verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short();
-            }
-            BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level);
-            uint8_t point_too_far_mask = 0;
-            clean_up_after_endstop_move();
-            // Print head up.
-            current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder);
-            st_synchronize();
-            if (result >= 0) {
-                // Second half: The fine adjustment.
-                // Let the planner use the uncorrected coordinates.
-                mbl.reset();
-                world2machine_reset();
-                // Home in the XY plane.
-                setup_for_endstop_move();
-                home_xy();
-                result = improve_bed_offset_and_skew(1, verbosity_level, point_too_far_mask);
-                clean_up_after_endstop_move();
-                // Print head up.
-                current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-                plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder);
-                st_synchronize();
-            }
-            lcd_bed_calibration_show_result(result, point_too_far_mask);
-        } else {
-            // Timeouted.
-        }
-        lcd_update_enable(true);
-        lcd_implementation_clear();
-        // lcd_return_to_status();
-        lcd_update();
-        break;
+		bool only_Z = code_seen('Z');
+		gcode_M45(only_Z);				
     }
+	break;
 
     /*
     case 46:
@@ -2886,7 +3962,9 @@ void process_commands()
 
     case 47:
         // M47: Prusa3D: Show end stops dialog on the display.
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
         lcd_diag_show_end_stops();
+		KEEPALIVE_STATE(IN_HANDLER);
         break;
 
 #if 0
@@ -2921,9 +3999,6 @@ void process_commands()
         plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder);
         st_synchronize();
         lcd_update_enable(true);
-        lcd_implementation_clear();
-        // lcd_return_to_status();
-        lcd_update();
         break;
     }
 #endif
@@ -3191,7 +4266,7 @@ Sigma_Exit:
       setWatch();
       break;
     case 112: //  M112 -Emergency Stop
-      kill();
+      kill("", 3);
       break;
     case 140: // M140 set bed temp
       if (code_seen('S')) setTargetBed(code_value());
@@ -3240,12 +4315,30 @@ Sigma_Exit:
         SERIAL_PROTOCOL(getHeaterPower(-1));
       #endif
 
+#ifdef PINDA_THERMISTOR
+		SERIAL_PROTOCOLPGM(" P:");
+		SERIAL_PROTOCOL_F(current_temperature_pinda,1);
+#endif //PINDA_THERMISTOR
+
+#ifdef AMBIENT_THERMISTOR
+		SERIAL_PROTOCOLPGM(" A:");
+		SERIAL_PROTOCOL_F(current_temperature_ambient,1);
+#endif //AMBIENT_THERMISTOR
+
+
         #ifdef SHOW_TEMP_ADC_VALUES
+          {float raw = 0.0;
+
           #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1
             SERIAL_PROTOCOLPGM("    ADC B:");
             SERIAL_PROTOCOL_F(degBed(),1);
             SERIAL_PROTOCOLPGM("C->");
-            SERIAL_PROTOCOL_F(rawBedTemp()/OVERSAMPLENR,0);
+            raw = rawBedTemp();
+            SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5);
+            SERIAL_PROTOCOLPGM(" Rb->");
+            SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5);
+            SERIAL_PROTOCOLPGM(" Rxb->");
+            SERIAL_PROTOCOL_F(raw, 5);
           #endif
           for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) {
             SERIAL_PROTOCOLPGM("  T");
@@ -3253,11 +4346,20 @@ Sigma_Exit:
             SERIAL_PROTOCOLPGM(":");
             SERIAL_PROTOCOL_F(degHotend(cur_extruder),1);
             SERIAL_PROTOCOLPGM("C->");
-            SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0);
-          }
+            raw = rawHotendTemp(cur_extruder);
+            SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5);
+            SERIAL_PROTOCOLPGM(" Rt");
+            SERIAL_PROTOCOL(cur_extruder);
+            SERIAL_PROTOCOLPGM("->");
+            SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5);
+            SERIAL_PROTOCOLPGM(" Rx");
+            SERIAL_PROTOCOL(cur_extruder);
+            SERIAL_PROTOCOLPGM("->");
+            SERIAL_PROTOCOL_F(raw, 5);
+          }}
         #endif
-
-        SERIAL_PROTOCOLLN("");
+		SERIAL_PROTOCOLLN("");
+		KEEPALIVE_STATE(NOT_BUSY);
       return;
       break;
     case 109:
@@ -3294,61 +4396,19 @@ Sigma_Exit:
 
       /* See if we are heating up or cooling down */
       target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling
+	  
+	  KEEPALIVE_STATE(NOT_BUSY);
 
       cancel_heatup = false;
 
-      #ifdef TEMP_RESIDENCY_TIME
-        long residencyStart;
-        residencyStart = -1;
-        /* continue to loop until we have reached the target temp
-          _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
-        while((!cancel_heatup)&&((residencyStart == -1) ||
-              (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL)))) ) {
-      #else
-        while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) {
-      #endif //TEMP_RESIDENCY_TIME
-          if( (millis() - codenum) > 1000UL )
-          { //Print Temp Reading and remaining time every 1 second while heating up/cooling down
-            SERIAL_PROTOCOLPGM("T:");
-            SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
-            SERIAL_PROTOCOLPGM(" E:");
-            SERIAL_PROTOCOL((int)tmp_extruder);
-			
-            #ifdef TEMP_RESIDENCY_TIME
-              SERIAL_PROTOCOLPGM(" W:");
-              if(residencyStart > -1)
-              {
-                 codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
-                 SERIAL_PROTOCOLLN( codenum );
-              }
-              else
-              {
-                 SERIAL_PROTOCOLLN( "?" );
-              }
-            #else
-              SERIAL_PROTOCOLLN("");
-            #endif
-            codenum = millis();
-          }
-          manage_heater();
-          manage_inactivity();
-          lcd_update();
-        #ifdef TEMP_RESIDENCY_TIME
-            /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
-              or when current temp falls outside the hysteresis after target temp was reached */
-          if ((residencyStart == -1 &&  target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder)-TEMP_WINDOW))) ||
-              (residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder)+TEMP_WINDOW))) ||
-              (residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS) )
-			  {
-				residencyStart = millis();
-			  }
-        #endif //TEMP_RESIDENCY_TIME
-        }
+	  wait_for_heater(codenum); //loops until target temperature is reached
+
         LCD_MESSAGERPGM(MSG_HEATING_COMPLETE);
+		KEEPALIVE_STATE(IN_HANDLER);
 		heating_status = 2;
 		if (farm_mode) { prusa_statistics(2); };
         
-        starttime=millis();
+        //starttime=millis();
         previous_millis_cmd = millis();
       }
       break;
@@ -3372,25 +4432,30 @@ Sigma_Exit:
         cancel_heatup = false;
         target_direction = isHeatingBed(); // true if heating, false if cooling
 
+		KEEPALIVE_STATE(NOT_BUSY);
         while ( (target_direction)&&(!cancel_heatup) ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) )
         {
           if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
           {
-            float tt=degHotend(active_extruder);
-            SERIAL_PROTOCOLPGM("T:");
-            SERIAL_PROTOCOL(tt);
-            SERIAL_PROTOCOLPGM(" E:");
-            SERIAL_PROTOCOL((int)active_extruder);
-            SERIAL_PROTOCOLPGM(" B:");
-            SERIAL_PROTOCOL_F(degBed(),1);
-            SERIAL_PROTOCOLLN("");
-            codenum = millis();
+			  if (!farm_mode) {
+				  float tt = degHotend(active_extruder);
+				  SERIAL_PROTOCOLPGM("T:");
+				  SERIAL_PROTOCOL(tt);
+				  SERIAL_PROTOCOLPGM(" E:");
+				  SERIAL_PROTOCOL((int)active_extruder);
+				  SERIAL_PROTOCOLPGM(" B:");
+				  SERIAL_PROTOCOL_F(degBed(), 1);
+				  SERIAL_PROTOCOLLN("");
+			  }
+				  codenum = millis();
+			  
           }
           manage_heater();
           manage_inactivity();
           lcd_update();
         }
         LCD_MESSAGERPGM(MSG_BED_DONE);
+		KEEPALIVE_STATE(IN_HANDLER);
 		heating_status = 4;
 
         previous_millis_cmd = millis();
@@ -3488,18 +4553,19 @@ Sigma_Exit:
         else
         {
           st_synchronize();
-          if(code_seen('X')) disable_x();
-          if(code_seen('Y')) disable_y();
-          if(code_seen('Z')) disable_z();
-          #if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS
-            if(code_seen('E')) {
-              disable_e0();
-              disable_e1();
-              disable_e2();
+		  if (code_seen('X')) disable_x();
+		  if (code_seen('Y')) disable_y();
+		  if (code_seen('Z')) disable_z();
+#if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS
+		  if (code_seen('E')) {
+			  disable_e0();
+			  disable_e1();
+			  disable_e2();
             }
           #endif
         }
       }
+	  snmm_filaments_used = 0;
       break;
     case 85: // M85
       if(code_seen('S')) {
@@ -3515,7 +4581,7 @@ Sigma_Exit:
             float value = code_value();
             if(value < 20.0) {
               float factor = axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
-              max_e_jerk *= factor;
+              max_jerk[E_AXIS] *= factor;
               max_feedrate[i] *= factor;
               axis_steps_per_sqr_second[i] *= factor;
             }
@@ -3527,6 +4593,19 @@ Sigma_Exit:
         }
       }
       break;
+#ifdef HOST_KEEPALIVE_FEATURE
+	case 113: // M113 - Get or set Host Keepalive interval
+		if (code_seen('S')) {
+			host_keepalive_interval = (uint8_t)code_value_short();
+//			NOMORE(host_keepalive_interval, 60);
+		}
+		else {
+			SERIAL_ECHO_START;
+			SERIAL_ECHOPAIR("M113 S", (unsigned long)host_keepalive_interval);
+			SERIAL_PROTOCOLLN("");
+		}
+		break;
+#endif
     case 115: // M115
       if (code_seen('V')) {
           // Report the Prusa version number.
@@ -3539,12 +4618,12 @@ Sigma_Exit:
           SERIAL_PROTOCOLRPGM(MSG_M115_REPORT);
       }
       break;
-    case 117: // M117 display message
+/*    case 117: // M117 display message
       starpos = (strchr(strchr_pointer + 5,'*'));
       if(starpos!=NULL)
         *(starpos)='\0';
       lcd_setstatus(strchr_pointer + 5);
-      break;
+      break;*/
     case 114: // M114
       SERIAL_PROTOCOLPGM("X:");
       SERIAL_PROTOCOL(current_position[X_AXIS]);
@@ -3561,6 +4640,8 @@ Sigma_Exit:
       SERIAL_PROTOCOL(float(st_get_position(Y_AXIS))/axis_steps_per_unit[Y_AXIS]);
       SERIAL_PROTOCOLPGM(" Z:");
       SERIAL_PROTOCOL(float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]);
+      SERIAL_PROTOCOLPGM(" E:");
+      SERIAL_PROTOCOL(float(st_get_position(E_AXIS))/axis_steps_per_unit[E_AXIS]);
 
       SERIAL_PROTOCOLLN("");
       break;
@@ -3650,7 +4731,7 @@ Sigma_Exit:
         tmp_extruder = active_extruder;
         if(code_seen('T')) {
           tmp_extruder = code_value();
-          if(tmp_extruder >= EXTRUDERS) {
+		  if(tmp_extruder >= EXTRUDERS) {
             SERIAL_ECHO_START;
             SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER);
             break;
@@ -3718,9 +4799,10 @@ Sigma_Exit:
       if(code_seen('S')) minimumfeedrate = code_value();
       if(code_seen('T')) mintravelfeedrate = code_value();
       if(code_seen('B')) minsegmenttime = code_value() ;
-      if(code_seen('X')) max_xy_jerk = code_value() ;
-      if(code_seen('Z')) max_z_jerk = code_value() ;
-      if(code_seen('E')) max_e_jerk = code_value() ;
+      if(code_seen('X')) max_jerk[X_AXIS] = max_jerk[Y_AXIS] = code_value();
+      if(code_seen('Y')) max_jerk[Y_AXIS] = code_value();
+      if(code_seen('Z')) max_jerk[Z_AXIS] = code_value();
+      if(code_seen('E')) max_jerk[E_AXIS] = code_value();
     }
     break;
     case 206: // M206 additional homing offset
@@ -3789,7 +4871,7 @@ Sigma_Exit:
             SERIAL_ECHO_START;
             SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND);
             SERIAL_ECHO(CMDBUFFER_CURRENT_STRING);
-            SERIAL_ECHOLNPGM("\"");
+            SERIAL_ECHOLNPGM("\"(1)");
         }
       }
 
@@ -3976,7 +5058,7 @@ Sigma_Exit:
         #endif
 
         updatePID();
-        SERIAL_PROTOCOL(MSG_OK);
+        SERIAL_PROTOCOLRPGM(MSG_OK);
         SERIAL_PROTOCOL(" p:");
         SERIAL_PROTOCOL(Kp);
         SERIAL_PROTOCOL(" i:");
@@ -4000,7 +5082,7 @@ Sigma_Exit:
         if(code_seen('D')) bedKd = scalePID_d(code_value());
 
         updatePID();
-        SERIAL_PROTOCOL(MSG_OK);
+       	SERIAL_PROTOCOLRPGM(MSG_OK);
         SERIAL_PROTOCOL(" p:");
         SERIAL_PROTOCOL(bedKp);
         SERIAL_PROTOCOL(" i:");
@@ -4147,12 +5229,12 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
 
     case 500: // M500 Store settings in EEPROM
     {
-        Config_StoreSettings();
+        Config_StoreSettings(EEPROM_OFFSET);
     }
     break;
     case 501: // M501 Read settings from EEPROM
     {
-        Config_RetrieveSettings();
+        Config_RetrieveSettings(EEPROM_OFFSET);
     }
     break;
     case 502: // M502 Revert to default settings
@@ -4219,12 +5301,25 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
     #ifdef FILAMENTCHANGEENABLE
     case 600: //Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
     {
+		MYSERIAL.println("!!!!M600!!!!");
+		bool old_fsensor_enabled = fsensor_enabled;
+		fsensor_enabled = false; //temporary solution for unexpected restarting
+
 		st_synchronize();
+		float target[4];
+		float lastpos[4];
 
+        if (farm_mode)
+            
+        {
+            
+            prusa_statistics(22);
+            
+        }
+        
         feedmultiplyBckp=feedmultiply;
         int8_t TooLowZ = 0;
-        float target[4];
-        float lastpos[4];
+
         target[X_AXIS]=current_position[X_AXIS];
         target[Y_AXIS]=current_position[Y_AXIS];
         target[Z_AXIS]=current_position[Z_AXIS];
@@ -4290,91 +5385,204 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
           #endif
         }
         plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
+		st_synchronize();
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
 
-        // Unload filament
-        if(code_seen('L'))
-        {
-          target[E_AXIS]+= code_value();
-        }
-        else
-        {
-          #ifdef FILAMENTCHANGE_FINALRETRACT
-            target[E_AXIS]+= FILAMENTCHANGE_FINALRETRACT ;
-          #endif
-        }
-        plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
+		uint8_t cnt = 0;
+		int counterBeep = 0;
+		lcd_display_message_fullscreen_P(MSG_PRESS_TO_UNLOAD);
+		while (!lcd_clicked()) {
 
-        //finish moves
-        st_synchronize();
-        //disable extruder steppers so filament can be removed
-        disable_e0();
-        disable_e1();
-        disable_e2();
-        delay(100);
-        
+			cnt++;
+			manage_heater();
+			manage_inactivity(true);
+
+			/*#ifdef SNMM
+			target[E_AXIS] += 0.002;
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder);
+
+			#endif // SNMM*/
+
+			if (cnt == 0)
+			{
+#if BEEPER > 0
+				if (counterBeep == 500) {
+					counterBeep = 0;
+				}
+				SET_OUTPUT(BEEPER);
+				if (counterBeep == 0) {
+					WRITE(BEEPER, HIGH);
+				}
+				if (counterBeep == 20) {
+					WRITE(BEEPER, LOW);
+				}
+				counterBeep++;
+#else
+#if !defined(LCD_FEEDBACK_FREQUENCY_HZ) || !defined(LCD_FEEDBACK_FREQUENCY_DURATION_MS)
+				lcd_buzz(1000 / 6, 100);
+#else
+				lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
+#endif
+#endif
+			}
+
+		}
+		WRITE(BEEPER, LOW);
+		
+		lcd_change_fil_state = 0;
+		while (lcd_change_fil_state == 0) {
+			lcd_display_message_fullscreen_P(MSG_UNLOADING_FILAMENT);
+			KEEPALIVE_STATE(IN_HANDLER);
+			custom_message = true;
+			lcd_setstatuspgm(MSG_UNLOADING_FILAMENT);
+
+			// Unload filament
+			if (code_seen('L'))
+			{
+				target[E_AXIS] += code_value();
+			}
+			else
+			{
+#ifdef SNMM
+
+#else
+#ifdef FILAMENTCHANGE_FINALRETRACT
+				target[E_AXIS] += FILAMENTCHANGE_FINALRETRACT;
+#endif
+#endif // SNMM
+			}
+
+#ifdef SNMM
+			target[E_AXIS] += 12;
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3500, active_extruder);
+			target[E_AXIS] += 6;
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 5000, active_extruder);
+			target[E_AXIS] += (FIL_LOAD_LENGTH * -1);
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 5000, active_extruder);
+			st_synchronize();
+			target[E_AXIS] += (FIL_COOLING);
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder);
+			target[E_AXIS] += (FIL_COOLING*-1);
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder);
+			target[E_AXIS] += (bowden_length[snmm_extruder] * -1);
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3000, active_extruder);
+			st_synchronize();
+
+#else
+			//		plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3500 / 60, active_extruder);
+#endif // SNMM
+
+
+			//finish moves
+			st_synchronize();
+			//disable extruder steppers so filament can be removed
+			disable_e0();
+			disable_e1();
+			disable_e2();
+			delay(100);
+			KEEPALIVE_STATE(PAUSED_FOR_USER);
+			lcd_change_fil_state = !lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_UNLOAD_SUCCESSFULL, false, false);
+			//lcd_return_to_status();
+			lcd_update_enable(true);
+		}
         //Wait for user to insert filament
-        uint8_t cnt=0;
-        int counterBeep = 0;
         lcd_wait_interact();
+		//load_filament_time = millis();
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
         while(!lcd_clicked()){
-          cnt++;
+
+
           manage_heater();
           manage_inactivity(true);
-          if(cnt==0)
-          {
-          #if BEEPER > 0
-            if (counterBeep== 500){
-              counterBeep = 0;  
-            }
-            SET_OUTPUT(BEEPER);
-            if (counterBeep== 0){
-              WRITE(BEEPER,HIGH);
-            }
-            if (counterBeep== 20){
-              WRITE(BEEPER,LOW);
-            }
-            counterBeep++;
-          #else
-			   #if !defined(LCD_FEEDBACK_FREQUENCY_HZ) || !defined(LCD_FEEDBACK_FREQUENCY_DURATION_MS)
-              lcd_buzz(1000/6,100);
-			   #else
-			     lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS,LCD_FEEDBACK_FREQUENCY_HZ);
-			   #endif
-          #endif
-          }
+
+/*#ifdef SNMM
+		  target[E_AXIS] += 0.002;
+		  plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder);
+
+#endif // SNMM*/
+
         }
-        //Filament inserted
-        
-        WRITE(BEEPER,LOW);
-        
-        //Feed the filament to the end of nozzle quickly
-        target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ;
-        plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EFEED, active_extruder); 
+		//WRITE(BEEPER, LOW);
+		KEEPALIVE_STATE(IN_HANDLER);
+
+#ifdef SNMM
+		display_loading();
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
+		do {
+			target[E_AXIS] += 0.002;
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder);
+			delay_keep_alive(2);
+		} while (!lcd_clicked());
+		KEEPALIVE_STATE(IN_HANDLER);
+		/*if (millis() - load_filament_time > 2) {
+			load_filament_time = millis();
+			target[E_AXIS] += 0.001;
+			plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 1000, active_extruder);
+		}*/
+
+        //Filament inserted     
+		//Feed the filament to the end of nozzle quickly   		
+		st_synchronize();
+		target[E_AXIS] += bowden_length[snmm_extruder];
+		plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3000, active_extruder);
+		target[E_AXIS] += FIL_LOAD_LENGTH - 60;
+		plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 1400, active_extruder);
+		target[E_AXIS] += 40;
+		plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder);
+		target[E_AXIS] += 10;
+		plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder);
+#else
+		target[E_AXIS] += FILAMENTCHANGE_FIRSTFEED;
+		plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EFEED, active_extruder);
+#endif // SNMM
         
         //Extrude some filament
         target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ;
         plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder); 
         
  
-        
+
         
         //Wait for user to check the state
         lcd_change_fil_state = 0;
         lcd_loading_filament();
         while ((lcd_change_fil_state == 0)||(lcd_change_fil_state != 1)){
           lcd_change_fil_state = 0;
+		  KEEPALIVE_STATE(PAUSED_FOR_USER);
           lcd_alright();
+		  KEEPALIVE_STATE(IN_HANDLER);
           switch(lcd_change_fil_state){
             
              // Filament failed to load so load it again
              case 2:
+#ifdef SNMM
+				 display_loading();
+				 do {
+					 target[E_AXIS] += 0.002;
+					 plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder);
+					 delay_keep_alive(2);
+				 } while (!lcd_clicked());
+
+				 st_synchronize();
+				 target[E_AXIS] += bowden_length[snmm_extruder];
+				 plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3000, active_extruder);
+				 target[E_AXIS] += FIL_LOAD_LENGTH - 60;
+				 plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 1400, active_extruder);
+				 target[E_AXIS] += 40;
+				 plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder);
+				 target[E_AXIS] += 10;
+				 plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder);
+
+#else
                      target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ;
                      plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EFEED, active_extruder); 
-                
+#endif                
                      target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ;
                      plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder); 
 
                      lcd_loading_filament();
+
                      break;
 
              // Filament loaded properly but color is not clear
@@ -4387,6 +5595,7 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
              // Everything good             
              default:
                      lcd_change_success();
+					 lcd_update_enable(true);
                      break;
           }
           
@@ -4427,11 +5636,48 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
       char cmd[9];
       sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp);
       enquecommand(cmd);
-        
+      
+	  lcd_setstatuspgm(WELCOME_MSG);
+	  custom_message = false;
+	  custom_message_type = 0;
+
+      fsensor_enabled = old_fsensor_enabled; //temporary solution for unexpected restarting
+
+#ifdef PAT9125
+
+	  if (fsensor_M600)
+	  {
+		cmdqueue_pop_front(); //hack because M600 repeated 2x when enqueued to front
+		st_synchronize();
+		while (!is_buffer_empty())
+		{
+			process_commands();
+		    cmdqueue_pop_front();
+		}
+		fsensor_enable();
+		fsensor_restore_print_and_continue();
+	  }
+
+#endif //PAT9125
         
     }
     break;
     #endif //FILAMENTCHANGEENABLE
+	case 601: {
+		if(lcd_commands_type == 0)  lcd_commands_type = LCD_COMMAND_LONG_PAUSE;
+	}
+	break;
+
+	case 602: {
+		if(lcd_commands_type == 0)	lcd_commands_type = LCD_COMMAND_LONG_PAUSE_RESUME;
+	}
+	break;
+            
+#ifdef LIN_ADVANCE
+    case 900: // M900: Set LIN_ADVANCE options.
+        gcode_M900();
+    break;
+#endif
 
     case 907: // M907 Set digital trimpot motor current using axis codes.
     {
@@ -4467,6 +5713,86 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
       #endif
     }
     break;
+
+	case 910: // M910 TMC2130 init
+    {
+		tmc2130_init();
+    }
+    break;
+
+	case 911: // M911 Set TMC2130 holding currents
+    {
+		if (code_seen('X')) tmc2130_set_current_h(0, code_value());
+		if (code_seen('Y')) tmc2130_set_current_h(1, code_value());
+        if (code_seen('Z')) tmc2130_set_current_h(2, code_value());
+        if (code_seen('E')) tmc2130_set_current_h(3, code_value());
+    }
+    break;
+
+	case 912: // M912 Set TMC2130 running currents
+    {
+		if (code_seen('X')) tmc2130_set_current_r(0, code_value());
+		if (code_seen('Y')) tmc2130_set_current_r(1, code_value());
+        if (code_seen('Z')) tmc2130_set_current_r(2, code_value());
+        if (code_seen('E')) tmc2130_set_current_r(3, code_value());
+    }
+    break;
+
+	case 913: // M913 Print TMC2130 currents
+    {
+		tmc2130_print_currents();
+    }
+    break;
+
+	case 914: // M914 Set normal mode
+    {
+		tmc2130_mode = TMC2130_MODE_NORMAL;
+		tmc2130_init();
+    }
+    break;
+
+	case 915: // M915 Set silent mode
+    {
+		tmc2130_mode = TMC2130_MODE_SILENT;
+		tmc2130_init();
+    }
+    break;
+
+	case 916: // M916 Set sg_thrs
+    {
+		if (code_seen('X')) tmc2130_sg_thr[X_AXIS] = code_value();
+		if (code_seen('Y')) tmc2130_sg_thr[Y_AXIS] = code_value();
+		if (code_seen('Z')) tmc2130_sg_thr[Z_AXIS] = code_value();
+		if (code_seen('E')) tmc2130_sg_thr[E_AXIS] = code_value();
+		MYSERIAL.print("tmc2130_sg_thr[X]=");
+		MYSERIAL.println(tmc2130_sg_thr[X_AXIS], DEC);
+		MYSERIAL.print("tmc2130_sg_thr[Y]=");
+		MYSERIAL.println(tmc2130_sg_thr[Y_AXIS], DEC);
+		MYSERIAL.print("tmc2130_sg_thr[Z]=");
+		MYSERIAL.println(tmc2130_sg_thr[Z_AXIS], DEC);
+		MYSERIAL.print("tmc2130_sg_thr[E]=");
+		MYSERIAL.println(tmc2130_sg_thr[E_AXIS], DEC);
+    }
+    break;
+
+	case 917: // M917 Set TMC2130 pwm_ampl
+    {
+		if (code_seen('X')) tmc2130_set_pwm_ampl(0, code_value());
+		if (code_seen('Y')) tmc2130_set_pwm_ampl(1, code_value());
+        if (code_seen('Z')) tmc2130_set_pwm_ampl(2, code_value());
+        if (code_seen('E')) tmc2130_set_pwm_ampl(3, code_value());
+    }
+    break;
+
+	case 918: // M918 Set TMC2130 pwm_grad
+    {
+		if (code_seen('X')) tmc2130_set_pwm_grad(0, code_value());
+		if (code_seen('Y')) tmc2130_set_pwm_grad(1, code_value());
+        if (code_seen('Z')) tmc2130_set_pwm_grad(2, code_value());
+        if (code_seen('E')) tmc2130_set_pwm_grad(3, code_value());
+    }
+    break;
+
     case 350: // M350 Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
     {
       #if defined(X_MS1_PIN) && X_MS1_PIN > -1
@@ -4495,67 +5821,217 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
       #endif
     }
     break;
+	case 701: //M701: load filament
+	{
+		gcode_M701();
+	}
+	break;
+	case 702:
+	{
+#ifdef SNMM
+		if (code_seen('U')) {
+			extr_unload_used(); //unload all filaments which were used in current print
+		}
+		else if (code_seen('C')) {
+			extr_unload(); //unload just current filament 
+		}
+		else {
+			extr_unload_all(); //unload all filaments
+		}
+#else
+		bool old_fsensor_enabled = fsensor_enabled;
+		fsensor_enabled = false;
+		custom_message = true;
+		custom_message_type = 2;
+		lcd_setstatuspgm(MSG_UNLOADING_FILAMENT); 
+
+//		extr_unload2();
+
+		current_position[E_AXIS] -= 80;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 7000 / 60, active_extruder);
+		st_synchronize();
+		lcd_setstatuspgm(WELCOME_MSG);
+		custom_message = false;
+		custom_message_type = 0;
+		fsensor_enabled = old_fsensor_enabled;
+#endif	
+	}
+	break;
+
     case 999: // M999: Restart after being stopped
       Stopped = false;
       lcd_reset_alert_level();
       gcode_LastN = Stopped_gcode_LastN;
       FlushSerialRequestResend();
     break;
+	default: SERIAL_ECHOLNPGM("Invalid M code.");
     }
+	
   } // end if(code_seen('M')) (end of M codes)
 
   else if(code_seen('T'))
   {
-    tmp_extruder = code_value();
-    if(tmp_extruder >= EXTRUDERS) {
-      SERIAL_ECHO_START;
-      SERIAL_ECHO("T");
-      SERIAL_ECHO(tmp_extruder);
-      SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
-    }
-    else {
-      boolean make_move = false;
-      if(code_seen('F')) {
-        make_move = true;
-        next_feedrate = code_value();
-        if(next_feedrate > 0.0) {
-          feedrate = next_feedrate;
-        }
-      }
-      #if EXTRUDERS > 1
-      if(tmp_extruder != active_extruder) {
-        // Save current position to return to after applying extruder offset
-        memcpy(destination, current_position, sizeof(destination));
-        // Offset extruder (only by XY)
-        int i;
-        for(i = 0; i < 2; i++) {
-           current_position[i] = current_position[i] -
-                                 extruder_offset[i][active_extruder] +
-                                 extruder_offset[i][tmp_extruder];
-        }
-        // Set the new active extruder and position
-        active_extruder = tmp_extruder;
-        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-        // Move to the old position if 'F' was in the parameters
-        if(make_move && Stopped == false) {
-           prepare_move();
-        }
-      }
-      #endif
-      SERIAL_ECHO_START;
-      SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
-      SERIAL_PROTOCOLLN((int)active_extruder);
-    }
+	  int index;
+	  st_synchronize();
+	  for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++);
+	   
+	  if ((*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '9') && *(strchr_pointer + index) != '?') {
+		  SERIAL_ECHOLNPGM("Invalid T code.");
+	  }
+	  else {
+		  if (*(strchr_pointer + index) == '?') {
+			  tmp_extruder = choose_extruder_menu();
+		  }
+		  else {
+			  tmp_extruder = code_value();
+		  }
+		  snmm_filaments_used |= (1 << tmp_extruder); //for stop print
+#ifdef SNMM
+          
+    #ifdef LIN_ADVANCE
+          if (snmm_extruder != tmp_extruder)
+            clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so.
+    #endif
+          
+		  snmm_extruder = tmp_extruder;
+
+		  
+		  delay(100);
+
+		  disable_e0();
+		  disable_e1();
+		  disable_e2();
+
+		  pinMode(E_MUX0_PIN, OUTPUT);
+		  pinMode(E_MUX1_PIN, OUTPUT);
+		  pinMode(E_MUX2_PIN, OUTPUT);
+
+		  delay(100);
+		  SERIAL_ECHO_START;
+		  SERIAL_ECHO("T:");
+		  SERIAL_ECHOLN((int)tmp_extruder);
+		  switch (tmp_extruder) {
+		  case 1:
+			  WRITE(E_MUX0_PIN, HIGH);
+			  WRITE(E_MUX1_PIN, LOW);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  case 2:
+			  WRITE(E_MUX0_PIN, LOW);
+			  WRITE(E_MUX1_PIN, HIGH);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  case 3:
+			  WRITE(E_MUX0_PIN, HIGH);
+			  WRITE(E_MUX1_PIN, HIGH);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  default:
+			  WRITE(E_MUX0_PIN, LOW);
+			  WRITE(E_MUX1_PIN, LOW);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  }
+		  delay(100);
+
+#else
+		  if (tmp_extruder >= EXTRUDERS) {
+			  SERIAL_ECHO_START;
+			  SERIAL_ECHOPGM("T");
+			  SERIAL_PROTOCOLLN((int)tmp_extruder);
+			  SERIAL_ECHOLNRPGM(MSG_INVALID_EXTRUDER);
+		  }
+		  else {
+			  boolean make_move = false;
+			  if (code_seen('F')) {
+				  make_move = true;
+				  next_feedrate = code_value();
+				  if (next_feedrate > 0.0) {
+					  feedrate = next_feedrate;
+				  }
+			  }
+#if EXTRUDERS > 1
+			  if (tmp_extruder != active_extruder) {
+				  // Save current position to return to after applying extruder offset
+				  memcpy(destination, current_position, sizeof(destination));
+				  // Offset extruder (only by XY)
+				  int i;
+				  for (i = 0; i < 2; i++) {
+					  current_position[i] = current_position[i] -
+						  extruder_offset[i][active_extruder] +
+						  extruder_offset[i][tmp_extruder];
+				  }
+				  // Set the new active extruder and position
+				  active_extruder = tmp_extruder;
+				  plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+				  // Move to the old position if 'F' was in the parameters
+				  if (make_move && Stopped == false) {
+					  prepare_move();
+				  }
+			  }
+#endif
+			  SERIAL_ECHO_START;
+			  SERIAL_ECHORPGM(MSG_ACTIVE_EXTRUDER);
+			  SERIAL_PROTOCOLLN((int)active_extruder);
+		  }
+
+#endif
+	  }
   } // end if(code_seen('T')) (end of T codes)
 
+#ifdef DEBUG_DCODES
+  else if (code_seen('D')) // D codes (debug)
+  {
+    switch((int)code_value())
+    {
+	case -1: // D-1 - Endless loop
+		dcode__1(); break;
+	case 0: // D0 - Reset
+		dcode_0(); break;
+	case 1: // D1 - Clear EEPROM
+		dcode_1(); break;
+	case 2: // D2 - Read/Write RAM
+		dcode_2(); break;
+	case 3: // D3 - Read/Write EEPROM
+		dcode_3(); break;
+	case 4: // D4 - Read/Write PIN
+		dcode_4(); break;
+	case 5: // D5 - Read/Write FLASH
+//		dcode_5(); break;
+		break;
+	case 6: // D6 - Read/Write external FLASH
+		dcode_6(); break;
+	case 7: // D7 - Read/Write Bootloader
+		dcode_7(); break;
+	case 8: // D8 - Read/Write PINDA
+		dcode_8(); break;
+
+	case 10: // D10 - XYZ calibration = OK
+		dcode_10(); break;
+    
+    case 12: //D12 - Reset failstat counters
+		dcode_12(); break;
+
+	case 2130: // D9125 - TMC2130
+		dcode_2130(); break;
+	case 9125: // D9125 - PAT9125
+		dcode_9125(); break;
+	}
+  }
+#endif //DEBUG_DCODES
+
   else
   {
     SERIAL_ECHO_START;
     SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND);
     SERIAL_ECHO(CMDBUFFER_CURRENT_STRING);
-    SERIAL_ECHOLNPGM("\"");
+    SERIAL_ECHOLNPGM("\"(2)");
   }
-
+  KEEPALIVE_STATE(NOT_BUSY);
   ClearToSend();
 }
 
@@ -4590,6 +6066,10 @@ void get_coordinates()
   }
   if(code_seen('F')) {
     next_feedrate = code_value();
+#ifdef MAX_SILENT_FEEDRATE
+	if (tmc2130_mode == TMC2130_MODE_SILENT)
+		if (next_feedrate > MAX_SILENT_FEEDRATE) next_feedrate = MAX_SILENT_FEEDRATE;
+#endif //MAX_SILENT_FEEDRATE
     if(next_feedrate > 0.0) feedrate = next_feedrate;
   }
 }
@@ -4621,6 +6101,9 @@ void get_arc_coordinates()
 
 void clamp_to_software_endstops(float target[3])
 {
+#ifdef DEBUG_DISABLE_SWLIMITS
+	return;
+#endif //DEBUG_DISABLE_SWLIMITS
     world2machine_clamp(target[0], target[1]);
 
     // Clamp the Z coordinate.
@@ -4645,9 +6128,10 @@ void clamp_to_software_endstops(float target[3])
         int n_segments = 0;
 		
         if (mbl.active) {
-            float len = abs(dx) + abs(dy) + abs(dz);
+            float len = abs(dx) + abs(dy);
             if (len > 0)
-                n_segments = int(floor(len / 30.f));
+                // Split to 3cm segments or shorter.
+                n_segments = int(ceil(len / 30.f));
         }
         
         if (n_segments > 1) {
@@ -4664,7 +6148,10 @@ void clamp_to_software_endstops(float target[3])
         }
         // The rest of the path.
         plan_buffer_line(x, y, z, e, feed_rate, extruder);
-        set_current_to_destination();
+        current_position[X_AXIS] = x;
+        current_position[Y_AXIS] = y;
+        current_position[Z_AXIS] = z;
+        current_position[E_AXIS] = e;
     }
 #endif  // MESH_BED_LEVELING
     
@@ -4675,17 +6162,13 @@ void prepare_move()
 
   // Do not use feedmultiply for E or Z only moves
   if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
-#ifdef MESH_BED_LEVELING
-      mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-#else
       plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-#endif
   }
   else {
 #ifdef MESH_BED_LEVELING
-    mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
+    mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply*(1./(60.f*100.f)), active_extruder);
 #else
-     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
+     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply*(1./(60.f*100.f)), active_extruder);
 #endif
   }
 
@@ -4797,12 +6280,13 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument s
    const int KILL_DELAY = 10000;
 #endif
 	
-  if(buflen < (BUFSIZE-1))
-    get_command();
+    if(buflen < (BUFSIZE-1)){
+        get_command();
+    }
 
   if( (millis() - previous_millis_cmd) >  max_inactive_time )
     if(max_inactive_time)
-      kill();
+      kill("", 4);
   if(stepper_inactive_time)  {
     if( (millis() - previous_millis_cmd) >  stepper_inactive_time )
     {
@@ -4844,7 +6328,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument s
     // ----------------------------------------------------------------
     if ( killCount >= KILL_DELAY)
     {
-       kill();
+       kill("", 5);
     }
   #endif
     
@@ -4876,8 +6360,11 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument s
   check_axes_activity();
 }
 
-void kill(const char *full_screen_message)
+void kill(const char *full_screen_message, unsigned char id)
 {
+	SERIAL_ECHOPGM("KILL: ");
+	MYSERIAL.println(int(id));
+	//return;
   cli(); // Stop interrupts
   disable_heater();
 
@@ -4909,7 +6396,12 @@ void kill(const char *full_screen_message)
   }
   cli();   // disable interrupts
   suicide();
-  while(1) { /* Intentionally left empty */ } // Wait for reset
+  while(1)
+  {
+	wdt_reset();
+	  /* Intentionally left empty */
+	
+  } // Wait for reset
 }
 
 void Stop()
@@ -5004,7 +6496,7 @@ bool setTargetedHotend(int code){
       SERIAL_ECHO_START;
       switch(code){
         case 104:
-          SERIAL_ECHO(MSG_M104_INVALID_EXTRUDER);
+          SERIAL_ECHORPGM(MSG_M104_INVALID_EXTRUDER);
           break;
         case 105:
           SERIAL_ECHO(MSG_M105_INVALID_EXTRUDER);
@@ -5019,14 +6511,14 @@ bool setTargetedHotend(int code){
           SERIAL_ECHO(MSG_M221_INVALID_EXTRUDER);
           break;
       }
-      SERIAL_ECHOLN(tmp_extruder);
+      SERIAL_PROTOCOLLN((int)tmp_extruder);
       return true;
     }
   }
   return false;
 }
 
-void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time)
+void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time) //_total_filament_used unit: mm/100; print time in s
 {
 	if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255)
 	{
@@ -5034,10 +6526,10 @@ void save_statistics(unsigned long _total_filament_used, unsigned long _total_pr
 		eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0);
 	}
 
-	unsigned long _previous_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED);
-	unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME);
+	unsigned long _previous_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); //_previous_filament unit: cm
+	unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //_previous_time unit: min
 
-	eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60));
+	eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60)); //EEPROM_TOTALTIME unit: min
 	eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, _previous_filament + (_total_filament_used / 1000));
 
 	total_filament_used = 0;
@@ -5069,7 +6561,7 @@ void calculate_volumetric_multipliers() {
 #endif
 }
 
-void delay_keep_alive(int ms)
+void delay_keep_alive(unsigned int ms)
 {
     for (;;) {
         manage_heater();
@@ -5087,3 +6579,1123 @@ void delay_keep_alive(int ms)
         }
     }
 }
+
+void wait_for_heater(long codenum) {
+
+#ifdef TEMP_RESIDENCY_TIME
+	long residencyStart;
+	residencyStart = -1;
+	/* continue to loop until we have reached the target temp
+	_and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
+	while ((!cancel_heatup) && ((residencyStart == -1) ||
+		(residencyStart >= 0 && (((unsigned int)(millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))))) {
+#else
+	while (target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder) && (CooldownNoWait == false))) {
+#endif //TEMP_RESIDENCY_TIME
+		if ((millis() - codenum) > 1000UL)
+		{ //Print Temp Reading and remaining time every 1 second while heating up/cooling down
+			if (!farm_mode) {
+				SERIAL_PROTOCOLPGM("T:");
+				SERIAL_PROTOCOL_F(degHotend(tmp_extruder), 1);
+				SERIAL_PROTOCOLPGM(" E:");
+				SERIAL_PROTOCOL((int)tmp_extruder);
+
+#ifdef TEMP_RESIDENCY_TIME
+				SERIAL_PROTOCOLPGM(" W:");
+				if (residencyStart > -1)
+				{
+					codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
+					SERIAL_PROTOCOLLN(codenum);
+				}
+				else
+				{
+					SERIAL_PROTOCOLLN("?");
+				}
+			}
+#else
+				SERIAL_PROTOCOLLN("");
+#endif
+				codenum = millis();
+		}
+			manage_heater();
+			manage_inactivity();
+			lcd_update();
+#ifdef TEMP_RESIDENCY_TIME
+			/* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
+			or when current temp falls outside the hysteresis after target temp was reached */
+			if ((residencyStart == -1 && target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder) - TEMP_WINDOW))) ||
+				(residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder) + TEMP_WINDOW))) ||
+				(residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS))
+			{
+				residencyStart = millis();
+			}
+#endif //TEMP_RESIDENCY_TIME
+	}
+}
+
+void check_babystep() {
+	int babystep_z;
+	EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystep_z);
+	if ((babystep_z < Z_BABYSTEP_MIN) || (babystep_z > Z_BABYSTEP_MAX)) {
+		babystep_z = 0; //if babystep value is out of min max range, set it to 0
+		SERIAL_ECHOLNPGM("Z live adjust out of range. Setting to 0");
+		EEPROM_save_B(EEPROM_BABYSTEP_Z, &babystep_z);
+		lcd_show_fullscreen_message_and_wait_P(PSTR("Z live adjust out of range. Setting to 0. Click to continue."));
+		lcd_update_enable(true);		
+	}	
+}
+#ifdef DIS
+void d_setup()
+{	
+	pinMode(D_DATACLOCK, INPUT_PULLUP);
+	pinMode(D_DATA, INPUT_PULLUP);
+	pinMode(D_REQUIRE, OUTPUT);
+	digitalWrite(D_REQUIRE, HIGH);
+}
+
+
+float d_ReadData()
+{
+	int digit[13];
+	String mergeOutput;
+	float output;
+
+	digitalWrite(D_REQUIRE, HIGH);
+	for (int i = 0; i<13; i++)
+	{
+		for (int j = 0; j < 4; j++)
+		{
+			while (digitalRead(D_DATACLOCK) == LOW) {}
+			while (digitalRead(D_DATACLOCK) == HIGH) {}
+			bitWrite(digit[i], j, digitalRead(D_DATA));
+		}
+	}
+
+	digitalWrite(D_REQUIRE, LOW);
+	mergeOutput = "";
+	output = 0;
+	for (int r = 5; r <= 10; r++) //Merge digits
+	{
+		mergeOutput += digit[r];
+	}
+	output = mergeOutput.toFloat();
+
+	if (digit[4] == 8) //Handle sign
+	{
+		output *= -1;
+	}
+
+	for (int i = digit[11]; i > 0; i--) //Handle floating point
+	{
+		output /= 10;
+	}
+
+	return output;
+
+}
+
+void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y) {
+	int t1 = 0;
+	int t_delay = 0;
+	int digit[13];
+	int m;
+	char str[3];
+	//String mergeOutput;
+	char mergeOutput[15];
+	float output;
+
+	int mesh_point = 0; //index number of calibration point
+	float bed_zero_ref_x = (-22.f + X_PROBE_OFFSET_FROM_EXTRUDER); //shift between zero point on bed and target and between probe and nozzle
+	float bed_zero_ref_y = (-0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER);
+
+	float mesh_home_z_search = 4;
+	float row[x_points_num];
+	int ix = 0;
+	int iy = 0;
+
+	char* filename_wldsd = "wldsd.txt";
+	char data_wldsd[70];
+	char numb_wldsd[10];
+
+	d_setup();
+
+	if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) {
+		// We don't know where we are! HOME!
+		// Push the commands to the front of the message queue in the reverse order!
+		// There shall be always enough space reserved for these commands.
+		repeatcommand_front(); // repeat G80 with all its parameters
+		
+		enquecommand_front_P((PSTR("G28 W0")));
+		enquecommand_front_P((PSTR("G1 Z5")));
+		return;
+	}
+	bool custom_message_old = custom_message;
+	unsigned int custom_message_type_old = custom_message_type;
+	unsigned int custom_message_state_old = custom_message_state;
+	custom_message = true;
+	custom_message_type = 1;
+	custom_message_state = (x_points_num * y_points_num) + 10;
+	lcd_update(1);
+
+	mbl.reset();
+	babystep_undo();
+
+	card.openFile(filename_wldsd, false);
+
+	current_position[Z_AXIS] = mesh_home_z_search;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 60, active_extruder);
+
+	int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20;
+	int Z_PROBE_FEEDRATE = homing_feedrate[Z_AXIS] / 60;
+	int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40;
+
+	setup_for_endstop_move(false);
+
+	SERIAL_PROTOCOLPGM("Num X,Y: ");
+	SERIAL_PROTOCOL(x_points_num);
+	SERIAL_PROTOCOLPGM(",");
+	SERIAL_PROTOCOL(y_points_num);
+	SERIAL_PROTOCOLPGM("\nZ search height: ");
+	SERIAL_PROTOCOL(mesh_home_z_search);
+	SERIAL_PROTOCOLPGM("\nDimension X,Y: ");
+	SERIAL_PROTOCOL(x_dimension);
+	SERIAL_PROTOCOLPGM(",");
+	SERIAL_PROTOCOL(y_dimension);
+	SERIAL_PROTOCOLLNPGM("\nMeasured points:");
+
+	while (mesh_point != x_points_num * y_points_num) {
+		ix = mesh_point % x_points_num; // from 0 to MESH_NUM_X_POINTS - 1
+		iy = mesh_point / x_points_num;
+		if (iy & 1) ix = (x_points_num - 1) - ix; // Zig zag
+		float z0 = 0.f;
+		current_position[Z_AXIS] = mesh_home_z_search;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
+		st_synchronize();
+
+
+		current_position[X_AXIS] = 13.f + ix * (x_dimension / (x_points_num - 1)) - bed_zero_ref_x + shift_x;
+		current_position[Y_AXIS] = 6.4f + iy * (y_dimension / (y_points_num - 1)) - bed_zero_ref_y + shift_y;
+
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder);
+		st_synchronize();
+
+		if (!find_bed_induction_sensor_point_z(-10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point  
+			break;
+			card.closefile();
+		}
+
+
+		//memset(numb_wldsd, 0, sizeof(numb_wldsd));
+		//dtostrf(d_ReadData(), 8, 5, numb_wldsd);
+		//strcat(data_wldsd, numb_wldsd);
+
+
+		
+		//MYSERIAL.println(data_wldsd);
+		//delay(1000);
+		//delay(3000);
+		//t1 = millis();
+		
+		//while (digitalRead(D_DATACLOCK) == LOW) {}
+		//while (digitalRead(D_DATACLOCK) == HIGH) {}
+		memset(digit, 0, sizeof(digit));
+		//cli();
+		digitalWrite(D_REQUIRE, LOW);	
+		
+		for (int i = 0; i<13; i++)
+		{
+			//t1 = millis();
+			for (int j = 0; j < 4; j++)
+			{
+				while (digitalRead(D_DATACLOCK) == LOW) {}				
+				while (digitalRead(D_DATACLOCK) == HIGH) {}
+				bitWrite(digit[i], j, digitalRead(D_DATA));
+			}
+			//t_delay = (millis() - t1);
+			//SERIAL_PROTOCOLPGM(" ");
+			//SERIAL_PROTOCOL_F(t_delay, 5);
+			//SERIAL_PROTOCOLPGM(" ");
+		}
+		//sei();
+		digitalWrite(D_REQUIRE, HIGH);
+		mergeOutput[0] = '\0';
+		output = 0;
+		for (int r = 5; r <= 10; r++) //Merge digits
+		{			
+			sprintf(str, "%d", digit[r]);
+			strcat(mergeOutput, str);
+		}
+		
+		output = atof(mergeOutput);
+
+		if (digit[4] == 8) //Handle sign
+		{
+			output *= -1;
+		}
+
+		for (int i = digit[11]; i > 0; i--) //Handle floating point
+		{
+			output *= 0.1;
+		}
+		
+
+		//output = d_ReadData();
+
+		//row[ix] = current_position[Z_AXIS];
+
+		memset(data_wldsd, 0, sizeof(data_wldsd));
+
+		for (int i = 0; i <3; i++) {
+			memset(numb_wldsd, 0, sizeof(numb_wldsd));
+			dtostrf(current_position[i], 8, 5, numb_wldsd);
+			strcat(data_wldsd, numb_wldsd);
+			strcat(data_wldsd, ";");
+
+		}
+		memset(numb_wldsd, 0, sizeof(numb_wldsd));
+		dtostrf(output, 8, 5, numb_wldsd);
+		strcat(data_wldsd, numb_wldsd);
+		//strcat(data_wldsd, ";");
+		card.write_command(data_wldsd);
+
+		
+		//row[ix] = d_ReadData();
+		
+		row[ix] = output; // current_position[Z_AXIS];
+
+		if (iy % 2 == 1 ? ix == 0 : ix == x_points_num - 1) {
+			for (int i = 0; i < x_points_num; i++) {
+				SERIAL_PROTOCOLPGM(" ");
+				SERIAL_PROTOCOL_F(row[i], 5);
+
+
+			}
+			SERIAL_PROTOCOLPGM("\n");
+		}
+		custom_message_state--;
+		mesh_point++;
+		lcd_update(1);
+
+	}
+	card.closefile();
+
+}
+#endif
+
+void temp_compensation_start() {
+	
+	custom_message = true;
+	custom_message_type = 5;
+	custom_message_state = PINDA_HEAT_T + 1;
+	lcd_update(2);
+	if (degHotend(active_extruder) > EXTRUDE_MINTEMP) {
+		current_position[E_AXIS] -= DEFAULT_RETRACTION;
+	}
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder);
+	
+	current_position[X_AXIS] = PINDA_PREHEAT_X;
+	current_position[Y_AXIS] = PINDA_PREHEAT_Y;
+	current_position[Z_AXIS] = PINDA_PREHEAT_Z;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+	st_synchronize();
+	while (fabs(degBed() - target_temperature_bed) > 1) delay_keep_alive(1000);
+
+	for (int i = 0; i < PINDA_HEAT_T; i++) {
+		delay_keep_alive(1000);
+		custom_message_state = PINDA_HEAT_T - i;
+		if (custom_message_state == 99 || custom_message_state == 9) lcd_update(2); //force whole display redraw if number of digits changed
+		else lcd_update(1);
+	}	
+	custom_message_type = 0;
+	custom_message_state = 0;
+	custom_message = false;
+}
+
+void temp_compensation_apply() {
+	int i_add;
+	int compensation_value;
+	int z_shift = 0;
+	float z_shift_mm;
+
+	if (calibration_status() == CALIBRATION_STATUS_CALIBRATED) {
+		if (target_temperature_bed % 10 == 0 && target_temperature_bed >= 60 && target_temperature_bed <= 100) {
+			i_add = (target_temperature_bed - 60) / 10;
+			EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + i_add * 2, &z_shift);
+			z_shift_mm = z_shift / axis_steps_per_unit[Z_AXIS];
+		}else {
+			//interpolation
+			z_shift_mm = temp_comp_interpolation(target_temperature_bed) / axis_steps_per_unit[Z_AXIS];
+		}
+		SERIAL_PROTOCOLPGM("\n");
+		SERIAL_PROTOCOLPGM("Z shift applied:");
+		MYSERIAL.print(z_shift_mm);
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - z_shift_mm, current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder);
+		st_synchronize();
+		plan_set_z_position(current_position[Z_AXIS]);
+	}
+	else {		
+		//we have no temp compensation data
+	}
+}
+
+float temp_comp_interpolation(float inp_temperature) {
+
+	//cubic spline interpolation
+
+	int n, i, j, k;
+	float h[10], a, b, c, d, sum, s[10] = { 0 }, x[10], F[10], f[10], m[10][10] = { 0 }, temp;
+	int shift[10];
+	int temp_C[10];
+
+	n = 6; //number of measured points
+
+	shift[0] = 0;
+	for (i = 0; i < n; i++) {
+		if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &shift[i]); //read shift in steps from EEPROM
+		temp_C[i] = 50 + i * 10; //temperature in C
+#ifdef PINDA_THERMISTOR
+		temp_C[i] = 35 + i * 5; //temperature in C
+#else
+		temp_C[i] = 50 + i * 10; //temperature in C
+#endif
+		x[i] = (float)temp_C[i];
+		f[i] = (float)shift[i];
+	}
+	if (inp_temperature < x[0]) return 0;
+
+
+	for (i = n - 1; i>0; i--) {
+		F[i] = (f[i] - f[i - 1]) / (x[i] - x[i - 1]);
+		h[i - 1] = x[i] - x[i - 1];
+	}
+	//*********** formation of h, s , f matrix **************
+	for (i = 1; i<n - 1; i++) {
+		m[i][i] = 2 * (h[i - 1] + h[i]);
+		if (i != 1) {
+			m[i][i - 1] = h[i - 1];
+			m[i - 1][i] = h[i - 1];
+		}
+		m[i][n - 1] = 6 * (F[i + 1] - F[i]);
+	}
+	//*********** forward elimination **************
+	for (i = 1; i<n - 2; i++) {
+		temp = (m[i + 1][i] / m[i][i]);
+		for (j = 1; j <= n - 1; j++)
+			m[i + 1][j] -= temp*m[i][j];
+	}
+	//*********** backward substitution *********
+	for (i = n - 2; i>0; i--) {
+		sum = 0;
+		for (j = i; j <= n - 2; j++)
+			sum += m[i][j] * s[j];
+		s[i] = (m[i][n - 1] - sum) / m[i][i];
+	}
+
+		for (i = 0; i<n - 1; i++)
+			if ((x[i] <= inp_temperature && inp_temperature <= x[i + 1]) || (i == n-2 && inp_temperature > x[i + 1])) {
+				a = (s[i + 1] - s[i]) / (6 * h[i]);
+				b = s[i] / 2;
+				c = (f[i + 1] - f[i]) / h[i] - (2 * h[i] * s[i] + s[i + 1] * h[i]) / 6;
+				d = f[i];
+				sum = a*pow((inp_temperature - x[i]), 3) + b*pow((inp_temperature - x[i]), 2) + c*(inp_temperature - x[i]) + d;
+			}
+
+		return sum;
+
+}
+
+#ifdef PINDA_THERMISTOR
+float temp_compensation_pinda_thermistor_offset(float temperature_pinda)
+{
+	if (!temp_cal_active) return 0;
+	if (!calibration_status_pinda()) return 0;
+	return temp_comp_interpolation(temperature_pinda) / axis_steps_per_unit[Z_AXIS];
+}
+#endif //PINDA_THERMISTOR
+
+void long_pause() //long pause print
+{
+	st_synchronize();
+	
+	//save currently set parameters to global variables
+	saved_feedmultiply = feedmultiply; 
+	HotendTempBckp = degTargetHotend(active_extruder);
+	fanSpeedBckp = fanSpeed;
+	start_pause_print = millis();
+		
+
+	//save position
+	pause_lastpos[X_AXIS] = current_position[X_AXIS];
+	pause_lastpos[Y_AXIS] = current_position[Y_AXIS];
+	pause_lastpos[Z_AXIS] = current_position[Z_AXIS];
+	pause_lastpos[E_AXIS] = current_position[E_AXIS];
+
+	//retract
+	current_position[E_AXIS] -= DEFAULT_RETRACTION;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder);
+
+	//lift z
+	current_position[Z_AXIS] += Z_PAUSE_LIFT;
+	if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
+
+	//set nozzle target temperature to 0
+	setTargetHotend(0, 0);
+	setTargetHotend(0, 1);
+	setTargetHotend(0, 2);
+
+	//Move XY to side
+	current_position[X_AXIS] = X_PAUSE_POS;
+	current_position[Y_AXIS] = Y_PAUSE_POS;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
+
+	// Turn off the print fan
+	fanSpeed = 0;
+
+	st_synchronize();
+}
+
+void serialecho_temperatures() {
+	float tt = degHotend(active_extruder);
+	SERIAL_PROTOCOLPGM("T:");
+	SERIAL_PROTOCOL(tt);
+	SERIAL_PROTOCOLPGM(" E:");
+	SERIAL_PROTOCOL((int)active_extruder);
+	SERIAL_PROTOCOLPGM(" B:");
+	SERIAL_PROTOCOL_F(degBed(), 1);
+	SERIAL_PROTOCOLLN("");
+}
+
+extern uint32_t sdpos_atomic;
+
+void uvlo_() 
+{
+	unsigned long time_start = millis();
+	bool sd_print = card.sdprinting;
+    // Conserve power as soon as possible.
+    disable_x();
+    disable_y();
+
+	tmc2130_set_current_h(Z_AXIS, 12);
+	tmc2130_set_current_r(Z_AXIS, 12);
+	tmc2130_set_current_h(E_AXIS, 20);
+	tmc2130_set_current_r(E_AXIS, 20);
+
+
+    // Indicate that the interrupt has been triggered.
+		SERIAL_ECHOLNPGM("UVLO");
+
+    // Read out the current Z motor microstep counter. This will be later used
+    // for reaching the zero full step before powering off.
+    uint16_t z_microsteps = tmc2130_rd_MSCNT(Z_TMC2130_CS);
+
+    // Calculate the file position, from which to resume this print.
+    long sd_position = sdpos_atomic; //atomic sd position of last command added in queue
+    {
+      uint16_t sdlen_planner = planner_calc_sd_length(); //length of sd commands in planner
+      sd_position -= sdlen_planner;
+      uint16_t sdlen_cmdqueue = cmdqueue_calc_sd_length(); //length of sd commands in cmdqueue
+      sd_position -= sdlen_cmdqueue;
+      if (sd_position < 0) sd_position = 0;
+    }
+
+    // Backup the feedrate in mm/min.
+    int feedrate_bckp = blocks_queued() ? (block_buffer[block_buffer_tail].nominal_speed * 60.f) : feedrate;
+
+    // After this call, the planner queue is emptied and the current_position is set to a current logical coordinate.
+    // The logical coordinate will likely differ from the machine coordinate if the skew calibration and mesh bed leveling
+    // are in action.
+    planner_abort_hard();
+
+    // Store the current extruder position.
+    eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E), st_get_position_mm(E_AXIS));
+	eeprom_update_byte((uint8_t*)EEPROM_UVLO_E_ABS, axis_relative_modes[3]?0:1);
+
+    // Clean the input command queue.
+    cmdqueue_reset();
+    card.sdprinting = false;
+//    card.closefile();
+
+    // Enable stepper driver interrupt to move Z axis.
+    // This should be fine as the planner and command queues are empty and the SD card printing is disabled.
+    //FIXME one may want to disable serial lines at this point of time to avoid interfering with the command queue,
+    // though it should not happen that the command queue is touched as the plan_buffer_line always succeed without blocking.
+		sei();
+		plan_buffer_line(
+      current_position[X_AXIS], 
+      current_position[Y_AXIS], 
+      current_position[Z_AXIS], 
+      current_position[E_AXIS] - DEFAULT_RETRACTION, 
+      400, active_extruder);
+		plan_buffer_line(
+      current_position[X_AXIS], 
+      current_position[Y_AXIS], 
+      current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / axis_steps_per_unit[Z_AXIS], 
+      current_position[E_AXIS] - DEFAULT_RETRACTION,
+      40, active_extruder);
+
+    // Move Z up to the next 0th full step.
+    // Write the file position.
+    eeprom_update_dword((uint32_t*)(EEPROM_FILE_POSITION), sd_position);
+    // Store the mesh bed leveling offsets. This is 2*9=18 bytes, which takes 18*3.4us=52us in worst case.
+    for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
+      uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
+      uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
+      // Scale the z value to 1u resolution.
+      int16_t v = mbl.active ? int16_t(floor(mbl.z_values[iy*3][ix*3] * 1000.f + 0.5f)) : 0;
+      eeprom_update_word((uint16_t*)(EEPROM_UVLO_MESH_BED_LEVELING+2*mesh_point), *reinterpret_cast<uint16_t*>(&v));
+    }
+    // Read out the current Z motor microstep counter. This will be later used
+    // for reaching the zero full step before powering off.
+    eeprom_update_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS), z_microsteps);
+    // Store the current position.
+    eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0), current_position[X_AXIS]);
+    eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4), current_position[Y_AXIS]);
+    eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z), current_position[Z_AXIS]);
+    // Store the current feed rate, temperatures and fan speed.
+    EEPROM_save_B(EEPROM_UVLO_FEEDRATE, &feedrate_bckp);
+    eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND, target_temperature[active_extruder]);
+    eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_BED, target_temperature_bed);
+    eeprom_update_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED, fanSpeed);
+    // Finaly store the "power outage" flag.
+	if(sd_print) eeprom_update_byte((uint8_t*)EEPROM_UVLO, 1);
+
+    st_synchronize();
+    SERIAL_ECHOPGM("stps");
+    MYSERIAL.println(tmc2130_rd_MSCNT(Z_TMC2130_CS));
+#if 0
+    // Move the print head to the side of the print until all the power stored in the power supply capacitors is depleted.
+    current_position[X_AXIS] = (current_position[X_AXIS] < 0.5f * (X_MIN_POS + X_MAX_POS)) ? X_MIN_POS : X_MAX_POS;
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+    st_synchronize();
+#endif
+    disable_z();
+    
+    // Increment power failure counter
+    uint8_t power_count = eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT);
+    power_count++;
+    eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, power_count);
+    
+		SERIAL_ECHOLNPGM("UVLO - end");
+		MYSERIAL.println(millis() - time_start);
+		cli();
+		while(1);
+}
+
+void setup_fan_interrupt() {
+//INT7
+	DDRE &= ~(1 << 7); //input pin
+	PORTE &= ~(1 << 7); //no internal pull-up
+
+	//start with sensing rising edge
+	EICRB &= ~(1 << 6);
+	EICRB |= (1 << 7);
+
+	//enable INT7 interrupt
+	EIMSK |= (1 << 7);
+}
+
+ISR(INT7_vect) {
+	//measuring speed now works for fanSpeed > 18 (approximately), which is sufficient because MIN_PRINT_FAN_SPEED is higher
+
+	if (fanSpeed < MIN_PRINT_FAN_SPEED) return;
+	if ((1 << 6) & EICRB) { //interrupt was triggered by rising edge
+		t_fan_rising_edge = millis();
+	}
+	else { //interrupt was triggered by falling edge
+		if ((millis() - t_fan_rising_edge) >= FAN_PULSE_WIDTH_LIMIT) {//this pulse was from sensor and not from pwm
+			fan_edge_counter[1] += 2; //we are currently counting all edges so lets count two edges for one pulse
+		}
+	}	
+	EICRB ^= (1 << 6); //change edge
+}
+
+void setup_uvlo_interrupt() {
+	DDRE &= ~(1 << 4); //input pin
+	PORTE &= ~(1 << 4); //no internal pull-up
+
+						//sensing falling edge
+	EICRB |= (1 << 0);
+	EICRB &= ~(1 << 1);
+
+	//enable INT4 interrupt
+	EIMSK |= (1 << 4);
+}
+
+ISR(INT4_vect) {
+	EIMSK &= ~(1 << 4); //disable INT4 interrupt to make sure that this code will be executed just once 
+	SERIAL_ECHOLNPGM("INT4");
+	if (IS_SD_PRINTING) uvlo_();
+}
+
+void recover_print(uint8_t automatic) {
+	char cmd[30];
+	lcd_update_enable(true);
+	lcd_update(2);
+	lcd_setstatuspgm(MSG_RECOVERING_PRINT);
+
+  recover_machine_state_after_power_panic();
+
+    // Set the target bed and nozzle temperatures. 
+    sprintf_P(cmd, PSTR("M104 S%d"), target_temperature[active_extruder]); 
+    enquecommand(cmd); 
+    sprintf_P(cmd, PSTR("M140 S%d"), target_temperature_bed); 
+    enquecommand(cmd);
+
+  // Lift the print head, so one may remove the excess priming material.
+  if (current_position[Z_AXIS] < 25)
+    enquecommand_P(PSTR("G1 Z25 F800"));
+  // Home X and Y axes. Homing just X and Y shall not touch the babystep and the world2machine transformation status.
+	enquecommand_P(PSTR("G28 X Y"));
+  // Set the target bed and nozzle temperatures and wait.
+	sprintf_P(cmd, PSTR("M109 S%d"), target_temperature[active_extruder]);
+	enquecommand(cmd);
+	sprintf_P(cmd, PSTR("M190 S%d"), target_temperature_bed);
+	enquecommand(cmd);
+	enquecommand_P(PSTR("M83")); //E axis relative mode
+	//enquecommand_P(PSTR("G1 E5 F120")); //Extrude some filament to stabilize pessure
+    // If not automatically recoreverd (long power loss), extrude extra filament to stabilize 
+    if(automatic == 0){ 
+        enquecommand_P(PSTR("G1 E5 F120")); //Extrude some filament to stabilize pessure 
+    } 
+	enquecommand_P(PSTR("G1 E"  STRINGIFY(-DEFAULT_RETRACTION)" F480"));
+	if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS))
+	{
+		float extruder_abs_pos = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E));
+		enquecommand_P(PSTR("M82")); //E axis abslute mode
+//		current_position[E_AXIS] = extruder_abs_pos;
+//		plan_set_e_position(extruder_abs_pos);
+	    sprintf_P(cmd, PSTR("G92 E"));
+		dtostrf(extruder_abs_pos, 6, 3, cmd + strlen(cmd));
+		enquecommand(cmd); 
+	}
+
+  // Mark the power panic status as inactive.
+	eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0);
+	/*while ((abs(degHotend(0)- target_temperature[0])>5) || (abs(degBed() -target_temperature_bed)>3)) { //wait for heater and bed to reach target temp
+		delay_keep_alive(1000);
+	}*/
+	SERIAL_ECHOPGM("After waiting for temp:");
+	SERIAL_ECHOPGM("Current position X_AXIS:");
+	MYSERIAL.println(current_position[X_AXIS]);
+	SERIAL_ECHOPGM("Current position Y_AXIS:");
+	MYSERIAL.println(current_position[Y_AXIS]);
+
+  // Restart the print.
+	restore_print_from_eeprom();
+
+	SERIAL_ECHOPGM("current_position[Z_AXIS]:");
+	MYSERIAL.print(current_position[Z_AXIS]);
+	SERIAL_ECHOPGM("current_position[E_AXIS]:");
+	MYSERIAL.print(current_position[E_AXIS]);
+}
+
+void recover_machine_state_after_power_panic()
+{
+  // 1) Recover the logical cordinates at the time of the power panic.
+  // The logical XY coordinates are needed to recover the machine Z coordinate corrected by the mesh bed leveling.
+  current_position[X_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0));
+  current_position[Y_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4));
+  // Recover the logical coordinate of the Z axis at the time of the power panic.
+  // The current position after power panic is moved to the next closest 0th full step.
+  current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)) + 
+    UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS)) + 7) >> 4) / axis_steps_per_unit[Z_AXIS];
+  memcpy(destination, current_position, sizeof(destination));
+
+  SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial ");
+  print_world_coordinates();
+
+  // 2) Initialize the logical to physical coordinate system transformation.
+  world2machine_initialize();
+
+  // 3) Restore the mesh bed leveling offsets. This is 2*9=18 bytes, which takes 18*3.4us=52us in worst case.
+  mbl.active = false;
+  for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
+    uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
+    uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
+    // Scale the z value to 10u resolution.
+    int16_t v;
+    eeprom_read_block(&v, (void*)(EEPROM_UVLO_MESH_BED_LEVELING+2*mesh_point), 2);
+    if (v != 0)
+      mbl.active = true;
+    mbl.z_values[iy][ix] = float(v) * 0.001f;
+  }
+  if (mbl.active)
+    mbl.upsample_3x3();
+  SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial ");
+  print_mesh_bed_leveling_table();
+
+  // 4) Load the baby stepping value, which is expected to be active at the time of power panic.
+  // The baby stepping value is used to reset the physical Z axis when rehoming the Z axis.
+  babystep_load();
+
+  // 5) Set the physical positions from the logical positions using the world2machine transformation and the active bed leveling.
+  plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+
+  // 6) Power up the motors, mark their positions as known.
+  //FIXME Verfiy, whether the X and Y axes should be powered up here, as they will later be re-homed anyway.
+  axis_known_position[X_AXIS] = true; enable_x();
+  axis_known_position[Y_AXIS] = true; enable_y();
+  axis_known_position[Z_AXIS] = true; enable_z();
+
+  SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial ");
+  print_physical_coordinates();
+
+  // 7) Recover the target temperatures.
+  target_temperature[active_extruder] = eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND);
+  target_temperature_bed = eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED);
+}
+
+void restore_print_from_eeprom() {
+	float x_rec, y_rec, z_pos;
+	int feedrate_rec;
+	uint8_t fan_speed_rec;
+	char cmd[30];
+	char* c;
+	char filename[13];
+	uint8_t depth = 0;
+	char dir_name[9];
+
+	fan_speed_rec = eeprom_read_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED);
+	EEPROM_read_B(EEPROM_UVLO_FEEDRATE, &feedrate_rec);
+	SERIAL_ECHOPGM("Feedrate:");
+	MYSERIAL.println(feedrate_rec);
+
+	depth = eeprom_read_byte((uint8_t*)EEPROM_DIR_DEPTH);
+	
+	MYSERIAL.println(int(depth));
+	for (int i = 0; i < depth; i++) {
+		for (int j = 0; j < 8; j++) {
+			dir_name[j] = eeprom_read_byte((uint8_t*)EEPROM_DIRS + j + 8 * i);
+			
+		}
+		dir_name[8] = '\0';
+		MYSERIAL.println(dir_name);
+		card.chdir(dir_name);
+	}
+
+	for (int i = 0; i < 8; i++) {
+		filename[i] = eeprom_read_byte((uint8_t*)EEPROM_FILENAME + i);
+		
+	}
+	filename[8] = '\0';
+
+	MYSERIAL.print(filename);
+	strcat_P(filename, PSTR(".gco"));
+	sprintf_P(cmd, PSTR("M23 %s"), filename);
+	for (c = &cmd[4]; *c; c++)
+		 *c = tolower(*c);
+	enquecommand(cmd);
+	uint32_t position = eeprom_read_dword((uint32_t*)(EEPROM_FILE_POSITION));
+	SERIAL_ECHOPGM("Position read from eeprom:");
+	MYSERIAL.println(position);
+
+  // E axis relative mode.
+	enquecommand_P(PSTR("M83"));
+  // Move to the XY print position in logical coordinates, where the print has been killed.
+	strcpy_P(cmd, PSTR("G1 X")); strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0))));
+	strcat_P(cmd, PSTR(" Y"));   strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4))));
+	strcat_P(cmd, PSTR(" F2000"));
+	enquecommand(cmd);
+  // Move the Z axis down to the print, in logical coordinates.
+	strcpy_P(cmd, PSTR("G1 Z")); strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z))));
+	enquecommand(cmd);
+  // Unretract.
+	enquecommand_P(PSTR("G1 E"  STRINGIFY(DEFAULT_RETRACTION)" F480"));
+  // Set the feedrate saved at the power panic.
+	sprintf_P(cmd, PSTR("G1 F%d"), feedrate_rec);
+	enquecommand(cmd);
+  // Set the fan speed saved at the power panic.
+	strcpy_P(cmd, PSTR("M106 S"));
+	strcat(cmd, itostr3(int(fan_speed_rec)));
+	enquecommand(cmd);
+
+  // Set a position in the file.
+  sprintf_P(cmd, PSTR("M26 S%lu"), position);
+  enquecommand(cmd);
+  // Start SD print.
+  enquecommand_P(PSTR("M24")); 
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// new save/restore printing
+
+//extern uint32_t sdpos_atomic;
+
+bool saved_printing = false;
+uint32_t saved_sdpos = 0;
+float saved_pos[4] = {0, 0, 0, 0};
+// Feedrate hopefully derived from an active block of the planner at the time the print has been canceled, in mm/min.
+float saved_feedrate2 = 0;
+uint8_t saved_active_extruder = 0;
+bool saved_extruder_under_pressure = false;
+
+void stop_and_save_print_to_ram(float z_move, float e_move)
+{
+	if (saved_printing) return;
+	cli();
+  unsigned char nplanner_blocks = number_of_blocks();
+	saved_sdpos = sdpos_atomic; //atomic sd position of last command added in queue
+	uint16_t sdlen_planner = planner_calc_sd_length(); //length of sd commands in planner
+	saved_sdpos -= sdlen_planner;
+	uint16_t sdlen_cmdqueue = cmdqueue_calc_sd_length(); //length of sd commands in cmdqueue
+	saved_sdpos -= sdlen_cmdqueue;
+
+#if 0
+  SERIAL_ECHOPGM("SDPOS_ATOMIC="); MYSERIAL.println(sdpos_atomic, DEC);
+  SERIAL_ECHOPGM("SDPOS="); MYSERIAL.println(card.get_sdpos(), DEC);
+  SERIAL_ECHOPGM("SDLEN_PLAN="); MYSERIAL.println(sdlen_planner, DEC);
+  SERIAL_ECHOPGM("SDLEN_CMDQ="); MYSERIAL.println(sdlen_cmdqueue, DEC);
+  SERIAL_ECHOPGM("PLANNERBLOCKS="); MYSERIAL.println(int(nplanner_blocks), DEC);
+  SERIAL_ECHOPGM("SDSAVED="); MYSERIAL.println(saved_sdpos, DEC);
+  SERIAL_ECHOPGM("SDFILELEN="); MYSERIAL.println(card.fileSize(), DEC);
+
+  {
+    card.setIndex(saved_sdpos);
+    SERIAL_ECHOLNPGM("Content of planner buffer: ");
+    for (unsigned int idx = 0; idx < sdlen_planner; ++ idx)
+      MYSERIAL.print(char(card.get()));
+    SERIAL_ECHOLNPGM("Content of command buffer: ");
+    for (unsigned int idx = 0; idx < sdlen_cmdqueue; ++ idx)
+      MYSERIAL.print(char(card.get()));
+    SERIAL_ECHOLNPGM("End of command buffer");
+  }
+
+  {
+    // Print the content of the planner buffer, line by line:
+    card.setIndex(saved_sdpos);
+    int8_t iline = 0;
+    for (unsigned char idx = block_buffer_tail; idx != block_buffer_head; idx = (idx + 1) & (BLOCK_BUFFER_SIZE - 1), ++ iline) {
+      SERIAL_ECHOPGM("Planner line (from file): ");
+      MYSERIAL.print(int(iline), DEC);
+      SERIAL_ECHOPGM(", length: ");
+      MYSERIAL.print(block_buffer[idx].sdlen, DEC);
+      SERIAL_ECHOPGM(", steps: (");
+      MYSERIAL.print(block_buffer[idx].steps_x, DEC);
+      SERIAL_ECHOPGM(",");
+      MYSERIAL.print(block_buffer[idx].steps_y, DEC);
+      SERIAL_ECHOPGM(",");
+      MYSERIAL.print(block_buffer[idx].steps_z, DEC);
+      SERIAL_ECHOPGM(",");
+      MYSERIAL.print(block_buffer[idx].steps_e, DEC);
+      SERIAL_ECHOPGM("), events: ");
+      MYSERIAL.println(block_buffer[idx].step_event_count, DEC);
+      for (int len = block_buffer[idx].sdlen; len > 0; -- len)
+        MYSERIAL.print(char(card.get()));
+    }
+  }
+  {
+    // Print the content of the command buffer, line by line:
+    int8_t iline = 0;
+    union {
+        struct {
+            char lo;
+            char hi;
+        } lohi;
+        uint16_t value;
+    } sdlen_single;
+    int _bufindr = bufindr;
+    for (int _buflen  = buflen; _buflen > 0; ++ iline) {
+        if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) {
+            sdlen_single.lohi.lo = cmdbuffer[_bufindr + 1];
+            sdlen_single.lohi.hi = cmdbuffer[_bufindr + 2];
+        }
+        SERIAL_ECHOPGM("Buffer line (from buffer): ");
+        MYSERIAL.print(int(iline), DEC);
+        SERIAL_ECHOPGM(", type: ");
+        MYSERIAL.print(int(cmdbuffer[_bufindr]), DEC);
+        SERIAL_ECHOPGM(", len: ");
+        MYSERIAL.println(sdlen_single.value, DEC);
+        // Print the content of the buffer line.
+        MYSERIAL.println(cmdbuffer + _bufindr + CMDHDRSIZE);
+
+        SERIAL_ECHOPGM("Buffer line (from file): ");
+        MYSERIAL.print(int(iline), DEC);
+        MYSERIAL.println(int(iline), DEC);
+        for (; sdlen_single.value > 0; -- sdlen_single.value)
+          MYSERIAL.print(char(card.get()));
+
+        if (-- _buflen == 0)
+          break;
+        // First skip the current command ID and iterate up to the end of the string.
+        for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ;
+        // Second, skip the end of string null character and iterate until a nonzero command ID is found.
+        for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
+        // If the end of the buffer was empty,
+        if (_bufindr == sizeof(cmdbuffer)) {
+            // skip to the start and find the nonzero command.
+            for (_bufindr = 0; cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
+        }
+    }
+  }
+#endif
+
+#if 0
+  saved_feedrate2 = feedrate; //save feedrate
+#else
+  // Try to deduce the feedrate from the first block of the planner.
+  // Speed is in mm/min.
+  saved_feedrate2 = blocks_queued() ? (block_buffer[block_buffer_tail].nominal_speed * 60.f) : feedrate;
+#endif
+
+	planner_abort_hard(); //abort printing
+	memcpy(saved_pos, current_position, sizeof(saved_pos));
+	saved_active_extruder = active_extruder; //save active_extruder
+
+	saved_extruder_under_pressure = extruder_under_pressure; //extruder under pressure flag - currently unused
+
+	cmdqueue_reset(); //empty cmdqueue
+	card.sdprinting = false;
+//	card.closefile();
+	saved_printing = true;
+	sei();
+	if ((z_move != 0) || (e_move != 0)) { // extruder or z move
+#if 1
+    // Rather than calling plan_buffer_line directly, push the move into the command queue, 
+    char buf[48];
+    strcpy_P(buf, PSTR("G1 Z"));
+    dtostrf(saved_pos[Z_AXIS] + z_move, 8, 3, buf + strlen(buf));
+    strcat_P(buf, PSTR(" E"));
+    // Relative extrusion
+    dtostrf(e_move, 6, 3, buf + strlen(buf));
+    strcat_P(buf, PSTR(" F"));
+    dtostrf(homing_feedrate[Z_AXIS], 8, 3, buf + strlen(buf));
+    // At this point the command queue is empty.
+    enquecommand(buf, false);
+    // If this call is invoked from the main Arduino loop() function, let the caller know that the command
+    // in the command queue is not the original command, but a new one, so it should not be removed from the queue.
+    repeatcommand_front();
+#else
+		plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS] + z_move, saved_pos[E_AXIS] + e_move, homing_feedrate[Z_AXIS], active_extruder);
+    st_synchronize(); //wait moving
+    memcpy(current_position, saved_pos, sizeof(saved_pos));
+    memcpy(destination, current_position, sizeof(destination));
+#endif
+  }
+}
+
+void restore_print_from_ram_and_continue(float e_move)
+{
+	if (!saved_printing) return;
+//	for (int axis = X_AXIS; axis <= E_AXIS; axis++)
+//	    current_position[axis] = st_get_position_mm(axis);
+	active_extruder = saved_active_extruder; //restore active_extruder
+	feedrate = saved_feedrate2; //restore feedrate
+	float e = saved_pos[E_AXIS] - e_move;
+	plan_set_e_position(e);
+	plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], homing_feedrate[Z_AXIS]/13, active_extruder);
+    st_synchronize();
+  memcpy(current_position, saved_pos, sizeof(saved_pos));
+  memcpy(destination, current_position, sizeof(destination));
+	card.setIndex(saved_sdpos);
+  sdpos_atomic = saved_sdpos;
+	card.sdprinting = true;
+	saved_printing = false;
+}
+
+void print_world_coordinates()
+{
+  SERIAL_ECHOPGM("world coordinates: (");
+  MYSERIAL.print(current_position[X_AXIS], 3);
+  SERIAL_ECHOPGM(", ");
+  MYSERIAL.print(current_position[Y_AXIS], 3);
+  SERIAL_ECHOPGM(", ");
+  MYSERIAL.print(current_position[Z_AXIS], 3);
+  SERIAL_ECHOLNPGM(")");
+}
+
+void print_physical_coordinates()
+{
+  SERIAL_ECHOPGM("physical coordinates: (");
+  MYSERIAL.print(st_get_position_mm(X_AXIS), 3);
+  SERIAL_ECHOPGM(", ");
+  MYSERIAL.print(st_get_position_mm(Y_AXIS), 3);
+  SERIAL_ECHOPGM(", ");
+  MYSERIAL.print(st_get_position_mm(Z_AXIS), 3);
+  SERIAL_ECHOLNPGM(")");
+}
+
+void print_mesh_bed_leveling_table()
+{
+  SERIAL_ECHOPGM("mesh bed leveling: ");
+  for (int8_t y = 0; y < MESH_NUM_Y_POINTS; ++ y)
+    for (int8_t x = 0; x < MESH_NUM_Y_POINTS; ++ x) {
+      MYSERIAL.print(mbl.z_values[y][x], 3);
+      SERIAL_ECHOPGM(" ");
+    }
+  SERIAL_ECHOLNPGM("");
+}
+
+
+#define FIL_LOAD_LENGTH 60
+
+void extr_unload2() { //unloads filament
+//	float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+//	float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+//	int8_t SilentMode;
+	uint8_t snmm_extruder = 0;
+	if (degHotend0() > EXTRUDE_MINTEMP) {
+		lcd_implementation_clear();
+		lcd_display_message_fullscreen_P(PSTR(""));
+		max_feedrate[E_AXIS] = 50;
+		lcd.setCursor(0, 0); lcd_printPGM(MSG_UNLOADING_FILAMENT);
+//		lcd.print(" ");
+//		lcd.print(snmm_extruder + 1);
+		lcd.setCursor(0, 2); lcd_printPGM(MSG_PLEASE_WAIT);
+		if (current_position[Z_AXIS] < 15) {
+			current_position[Z_AXIS] += 15; //lifting in Z direction to make space for extrusion
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 25, active_extruder);
+		}
+		
+		current_position[E_AXIS] += 10; //extrusion
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder);
+//		digipot_current(2, E_MOTOR_HIGH_CURRENT);
+		if (current_temperature[0] < 230) { //PLA & all other filaments
+			current_position[E_AXIS] += 5.4;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2800 / 60, active_extruder);
+			current_position[E_AXIS] += 3.2;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			current_position[E_AXIS] += 3;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3400 / 60, active_extruder);
+		}
+		else { //ABS
+			current_position[E_AXIS] += 3.1;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2000 / 60, active_extruder);
+			current_position[E_AXIS] += 3.1;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+			current_position[E_AXIS] += 4;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			/*current_position[X_AXIS] += 23; //delay
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay
+			current_position[X_AXIS] -= 23; //delay
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay*/
+			delay_keep_alive(4700);
+		}
+	
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= (bowden_length[snmm_extruder] + 60 + FIL_LOAD_LENGTH) / 2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		current_position[E_AXIS] -= (bowden_length[snmm_extruder] + 60 + FIL_LOAD_LENGTH) / 2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		st_synchronize();
+		//digipot_init();
+//		if (SilentMode == 1) digipot_current(2, tmp_motor[2]); //set back to normal operation currents
+//		else digipot_current(2, tmp_motor_loud[2]);
+		lcd_update_enable(true);
+//		lcd_return_to_status();
+		max_feedrate[E_AXIS] = 50;
+	}
+	else {
+
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+
+		delay(2000);
+		lcd_implementation_clear();
+	}
+//	lcd_return_to_status();
+}

+ 813 - 811
Firmware/Sd2Card.cpp

@@ -1,811 +1,813 @@
-/* Arduino Sd2Card Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino Sd2Card Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino Sd2Card Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-#include "Marlin.h"
-
-#ifdef SDSUPPORT
-#include "Sd2Card.h"
-//------------------------------------------------------------------------------
-#ifndef SOFTWARE_SPI
-// functions for hardware SPI
-//------------------------------------------------------------------------------
-// make sure SPCR rate is in expected bits
-#if (SPR0 != 0 || SPR1 != 1)
-#error unexpected SPCR bits
-#endif
-/**
- * Initialize hardware SPI
- * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
- */
-static void spiInit(uint8_t spiRate) {
-  // See avr processor documentation
-  SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1);
-  SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X;
-}
-//------------------------------------------------------------------------------
-/** SPI receive a byte */
-static uint8_t spiRec() {
-  SPDR = 0XFF;
-  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-  return SPDR;
-}
-//------------------------------------------------------------------------------
-/** SPI read data - only one call so force inline */
-static inline __attribute__((always_inline))
-void spiRead(uint8_t* buf, uint16_t nbyte) {
-  if (nbyte-- == 0) return;
-  SPDR = 0XFF;
-  for (uint16_t i = 0; i < nbyte; i++) {
-    while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-    buf[i] = SPDR;
-    SPDR = 0XFF;
-  }
-  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-  buf[nbyte] = SPDR;
-}
-//------------------------------------------------------------------------------
-/** SPI send a byte */
-static void spiSend(uint8_t b) {
-  SPDR = b;
-  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-}
-//------------------------------------------------------------------------------
-/** SPI send block - only one call so force inline */
-static inline __attribute__((always_inline))
-  void spiSendBlock(uint8_t token, const uint8_t* buf) {
-  SPDR = token;
-  for (uint16_t i = 0; i < 512; i += 2) {
-    while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-    SPDR = buf[i];
-    while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-    SPDR = buf[i + 1];
-  }
-  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
-}
-//------------------------------------------------------------------------------
-#else  // SOFTWARE_SPI
-//------------------------------------------------------------------------------
-/** nop to tune soft SPI timing */
-#define nop asm volatile ("nop\n\t")
-//------------------------------------------------------------------------------
-/** Soft SPI receive byte */
-static uint8_t spiRec() {
-  uint8_t data = 0;
-  // no interrupts during byte receive - about 8 us
-  cli();
-  // output pin high - like sending 0XFF
-  fastDigitalWrite(SPI_MOSI_PIN, HIGH);
-
-  for (uint8_t i = 0; i < 8; i++) {
-    fastDigitalWrite(SPI_SCK_PIN, HIGH);
-
-    // adjust so SCK is nice
-    nop;
-    nop;
-
-    data <<= 1;
-
-    if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
-
-    fastDigitalWrite(SPI_SCK_PIN, LOW);
-  }
-  // enable interrupts
-  sei();
-  return data;
-}
-//------------------------------------------------------------------------------
-/** Soft SPI read data */
-static void spiRead(uint8_t* buf, uint16_t nbyte) {
-  for (uint16_t i = 0; i < nbyte; i++) {
-    buf[i] = spiRec();
-  }
-}
-//------------------------------------------------------------------------------
-/** Soft SPI send byte */
-static void spiSend(uint8_t data) {
-  // no interrupts during byte send - about 8 us
-  cli();
-  for (uint8_t i = 0; i < 8; i++) {
-    fastDigitalWrite(SPI_SCK_PIN, LOW);
-
-    fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
-
-    data <<= 1;
-
-    fastDigitalWrite(SPI_SCK_PIN, HIGH);
-  }
-  // hold SCK high for a few ns
-  nop;
-  nop;
-  nop;
-  nop;
-
-  fastDigitalWrite(SPI_SCK_PIN, LOW);
-  // enable interrupts
-  sei();
-}
-//------------------------------------------------------------------------------
-/** Soft SPI send block */
-  void spiSendBlock(uint8_t token, const uint8_t* buf) {
-  spiSend(token);
-  for (uint16_t i = 0; i < 512; i++) {
-    spiSend(buf[i]);
-  }
-}
-#endif  // SOFTWARE_SPI
-//------------------------------------------------------------------------------
-// send command and return error code.  Return zero for OK
-uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
-  // select card
-  chipSelectLow();
-
-  // wait up to 300 ms if busy
-  waitNotBusy(300);
-
-  // send command
-  spiSend(cmd | 0x40);
-
-  // send argument
-  for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
-
-  // send CRC
-  uint8_t crc = 0XFF;
-  if (cmd == CMD0) crc = 0X95;  // correct crc for CMD0 with arg 0
-  if (cmd == CMD8) crc = 0X87;  // correct crc for CMD8 with arg 0X1AA
-  spiSend(crc);
-
-  // skip stuff byte for stop read
-  if (cmd == CMD12) spiRec();
-
-  // wait for response
-  for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ }
-  return status_;
-}
-//------------------------------------------------------------------------------
-/**
- * Determine the size of an SD flash memory card.
- *
- * \return The number of 512 byte data blocks in the card
- *         or zero if an error occurs.
- */
-uint32_t Sd2Card::cardSize() {
-  csd_t csd;
-  if (!readCSD(&csd)) return 0;
-  if (csd.v1.csd_ver == 0) {
-    uint8_t read_bl_len = csd.v1.read_bl_len;
-    uint16_t c_size = (csd.v1.c_size_high << 10)
-                      | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
-    uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
-                          | csd.v1.c_size_mult_low;
-    return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
-  } else if (csd.v2.csd_ver == 1) {
-    uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
-                      | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
-    return (c_size + 1) << 10;
-  } else {
-    error(SD_CARD_ERROR_BAD_CSD);
-    return 0;
-  }
-}
-//------------------------------------------------------------------------------
-void Sd2Card::chipSelectHigh() {
-  digitalWrite(chipSelectPin_, HIGH);
-}
-//------------------------------------------------------------------------------
-void Sd2Card::chipSelectLow() {
-#ifndef SOFTWARE_SPI
-  spiInit(spiRate_);
-#endif  // SOFTWARE_SPI
-  digitalWrite(chipSelectPin_, LOW);
-}
-//------------------------------------------------------------------------------
-/** Erase a range of blocks.
- *
- * \param[in] firstBlock The address of the first block in the range.
- * \param[in] lastBlock The address of the last block in the range.
- *
- * \note This function requests the SD card to do a flash erase for a
- * range of blocks.  The data on the card after an erase operation is
- * either 0 or 1, depends on the card vendor.  The card must support
- * single block erase.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
-  csd_t csd;
-  if (!readCSD(&csd)) goto fail;
-  // check for single block erase
-  if (!csd.v1.erase_blk_en) {
-    // erase size mask
-    uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
-    if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
-      // error card can't erase specified area
-      error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
-      goto fail;
-    }
-  }
-  if (type_ != SD_CARD_TYPE_SDHC) {
-    firstBlock <<= 9;
-    lastBlock <<= 9;
-  }
-  if (cardCommand(CMD32, firstBlock)
-    || cardCommand(CMD33, lastBlock)
-    || cardCommand(CMD38, 0)) {
-      error(SD_CARD_ERROR_ERASE);
-      goto fail;
-  }
-  if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
-    error(SD_CARD_ERROR_ERASE_TIMEOUT);
-    goto fail;
-  }
-  chipSelectHigh();
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** Determine if card supports single block erase.
- *
- * \return The value one, true, is returned if single block erase is supported.
- * The value zero, false, is returned if single block erase is not supported.
- */
-bool Sd2Card::eraseSingleBlockEnable() {
-  csd_t csd;
-  return readCSD(&csd) ? csd.v1.erase_blk_en : false;
-}
-//------------------------------------------------------------------------------
-/**
- * Initialize an SD flash memory card.
- *
- * \param[in] sckRateID SPI clock rate selector. See setSckRate().
- * \param[in] chipSelectPin SD chip select pin number.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.  The reason for failure
- * can be determined by calling errorCode() and errorData().
- */
-bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
-  errorCode_ = type_ = 0;
-  chipSelectPin_ = chipSelectPin;
-  // 16-bit init start time allows over a minute
-  uint16_t t0 = (uint16_t)millis();
-  uint32_t arg;
-
-  // set pin modes
-  pinMode(chipSelectPin_, OUTPUT);
-  chipSelectHigh();
-  pinMode(SPI_MISO_PIN, INPUT);
-  pinMode(SPI_MOSI_PIN, OUTPUT);
-  pinMode(SPI_SCK_PIN, OUTPUT);
-
-#ifndef SOFTWARE_SPI
-  // SS must be in output mode even it is not chip select
-  pinMode(SS_PIN, OUTPUT);
-  // set SS high - may be chip select for another SPI device
-#if SET_SPI_SS_HIGH
-  digitalWrite(SS_PIN, HIGH);
-#endif  // SET_SPI_SS_HIGH
-  // set SCK rate for initialization commands
-  spiRate_ = SPI_SD_INIT_RATE;
-  spiInit(spiRate_);
-#endif  // SOFTWARE_SPI
-
-  // must supply min of 74 clock cycles with CS high.
-  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
-
-  // command to go idle in SPI mode
-  while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
-    if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
-      error(SD_CARD_ERROR_CMD0);
-      goto fail;
-    }
-  }
-  // check SD version
-  if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
-    type(SD_CARD_TYPE_SD1);
-  } else {
-    // only need last byte of r7 response
-    for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
-    if (status_ != 0XAA) {
-      error(SD_CARD_ERROR_CMD8);
-      goto fail;
-    }
-    type(SD_CARD_TYPE_SD2);
-  }
-  // initialize card and send host supports SDHC if SD2
-  arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
-
-  while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
-    // check for timeout
-    if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
-      error(SD_CARD_ERROR_ACMD41);
-      goto fail;
-    }
-  }
-  // if SD2 read OCR register to check for SDHC card
-  if (type() == SD_CARD_TYPE_SD2) {
-    if (cardCommand(CMD58, 0)) {
-      error(SD_CARD_ERROR_CMD58);
-      goto fail;
-    }
-    if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
-    // discard rest of ocr - contains allowed voltage range
-    for (uint8_t i = 0; i < 3; i++) spiRec();
-  }
-  chipSelectHigh();
-
-#ifndef SOFTWARE_SPI
-  return setSckRate(sckRateID);
-#else  // SOFTWARE_SPI
-  return true;
-#endif  // SOFTWARE_SPI
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/**
- * Read a 512 byte block from an SD card.
- *
- * \param[in] blockNumber Logical block to be read.
- * \param[out] dst Pointer to the location that will receive the data.
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
-#ifdef SD_CHECK_AND_RETRY
-  uint8_t retryCnt = 3;
-  // use address if not SDHC card
-  if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
- retry2:
-  retryCnt --;
-  if (cardCommand(CMD17, blockNumber)) {
-    error(SD_CARD_ERROR_CMD17);
-    if (retryCnt > 0) goto retry;
-    goto fail;
-  }
-  if (!readData(dst, 512))
-  {
-    if (retryCnt > 0) goto retry;
-    goto fail;
-  }
-  return true;
- retry:
-   chipSelectHigh();
-   cardCommand(CMD12, 0);//Try sending a stop command, but ignore the result.
-   errorCode_ = 0;
-   goto retry2;
-#else
-  // use address if not SDHC card
-  if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
-  if (cardCommand(CMD17, blockNumber)) {
-    error(SD_CARD_ERROR_CMD17);
-    goto fail;
-  }
-  return readData(dst, 512);
-#endif
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** Read one data block in a multiple block read sequence
- *
- * \param[in] dst Pointer to the location for the data to be read.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::readData(uint8_t *dst) {
-  chipSelectLow();
-  return readData(dst, 512);
-}
-
-#ifdef SD_CHECK_AND_RETRY
-static const uint16_t crctab[] PROGMEM = {
-  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
-  0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
-  0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
-  0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
-  0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
-  0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
-  0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
-  0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
-  0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
-  0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
-  0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
-  0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
-  0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
-  0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
-  0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
-  0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
-  0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
-  0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
-  0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
-  0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
-  0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
-  0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
-  0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
-  0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
-  0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
-  0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
-  0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
-  0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
-  0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
-  0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
-  0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
-  0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
-};
-static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
-  uint16_t crc = 0;
-  for (size_t i = 0; i < n; i++) {
-    crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
-  }
-  return crc;
-}
-#endif
-
-//------------------------------------------------------------------------------
-bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
-  // wait for start block token
-  uint16_t t0 = millis();
-  while ((status_ = spiRec()) == 0XFF) {
-    if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
-      error(SD_CARD_ERROR_READ_TIMEOUT);
-      goto fail;
-    }
-  }
-  if (status_ != DATA_START_BLOCK) {
-    error(SD_CARD_ERROR_READ);
-    goto fail;
-  }
-  // transfer data
-  spiRead(dst, count);
-
-#ifdef SD_CHECK_AND_RETRY
-  {
-    uint16_t calcCrc = CRC_CCITT(dst, count);
-    uint16_t recvCrc = spiRec() << 8;
-    recvCrc |= spiRec();
-    if (calcCrc != recvCrc)
-    {
-        error(SD_CARD_ERROR_CRC);
-        goto fail;
-    }
-  }
-#else
-  // discard CRC
-  spiRec();
-  spiRec();
-#endif
-  chipSelectHigh();
-  // Toshiba FlashAir Patch. Purge pending status byte.
-  spiSend(0XFF);
-  return true;
-
- fail:
-  chipSelectHigh();
-  // Toshiba FlashAir Patch. Purge pending status byte.
-  spiSend(0XFF);       
-  return false;
-}
-//------------------------------------------------------------------------------
-/** read CID or CSR register */
-bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
-  uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
-  if (cardCommand(cmd, 0)) {
-    error(SD_CARD_ERROR_READ_REG);
-    goto fail;
-  }
-  return readData(dst, 16);
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** Start a read multiple blocks sequence.
- *
- * \param[in] blockNumber Address of first block in sequence.
- *
- * \note This function is used with readData() and readStop() for optimized
- * multiple block reads.  SPI chipSelect must be low for the entire sequence.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::readStart(uint32_t blockNumber) {
-  if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
-  if (cardCommand(CMD18, blockNumber)) {
-    error(SD_CARD_ERROR_CMD18);
-    goto fail;
-  }
-  chipSelectHigh();
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** End a read multiple blocks sequence.
- *
-* \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::readStop() {
-  chipSelectLow();
-  if (cardCommand(CMD12, 0)) {
-    error(SD_CARD_ERROR_CMD12);
-    goto fail;
-  }
-  chipSelectHigh();
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/**
- * Set the SPI clock rate.
- *
- * \param[in] sckRateID A value in the range [0, 6].
- *
- * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
- * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
- * for \a scsRateID = 6.
- *
- * \return The value one, true, is returned for success and the value zero,
- * false, is returned for an invalid value of \a sckRateID.
- */
-bool Sd2Card::setSckRate(uint8_t sckRateID) {
-  if (sckRateID > 6) {
-    error(SD_CARD_ERROR_SCK_RATE);
-    return false;
-  }
-  spiRate_ = sckRateID;
-  return true;
-}
-//------------------------------------------------------------------------------
-// wait for card to go not busy
-bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
-  uint16_t t0 = millis();
-  while (spiRec() != 0XFF) {
-    if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
-  }
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-/**
- * Writes a 512 byte block to an SD card.
- *
- * \param[in] blockNumber Logical block to be written.
- * \param[in] src Pointer to the location of the data to be written.
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
-  // use address if not SDHC card
-  if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
-  if (cardCommand(CMD24, blockNumber)) {
-    error(SD_CARD_ERROR_CMD24);
-    goto fail;
-  }
-  if (!writeData(DATA_START_BLOCK, src)) goto fail;
-
-  // wait for flash programming to complete
-  if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
-    error(SD_CARD_ERROR_WRITE_TIMEOUT);
-    goto fail;
-  }
-  // response is r2 so get and check two bytes for nonzero
-  if (cardCommand(CMD13, 0) || spiRec()) {
-    error(SD_CARD_ERROR_WRITE_PROGRAMMING);
-    goto fail;
-  }
-  chipSelectHigh();
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** Write one data block in a multiple block write sequence
- * \param[in] src Pointer to the location of the data to be written.
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::writeData(const uint8_t* src) {
-  chipSelectLow();
-  // wait for previous write to finish
-  if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
-  if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail;
-  chipSelectHigh();
-  return true;
-
- fail:
-  error(SD_CARD_ERROR_WRITE_MULTIPLE);
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-// send one block of data for write block or write multiple blocks
-bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
-  spiSendBlock(token, src);
-
-  spiSend(0xff);  // dummy crc
-  spiSend(0xff);  // dummy crc
-
-  status_ = spiRec();
-  if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
-    error(SD_CARD_ERROR_WRITE);
-    goto fail;
-  }
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** Start a write multiple blocks sequence.
- *
- * \param[in] blockNumber Address of first block in sequence.
- * \param[in] eraseCount The number of blocks to be pre-erased.
- *
- * \note This function is used with writeData() and writeStop()
- * for optimized multiple block writes.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
-  // send pre-erase count
-  if (cardAcmd(ACMD23, eraseCount)) {
-    error(SD_CARD_ERROR_ACMD23);
-    goto fail;
-  }
-  // use address if not SDHC card
-  if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
-  if (cardCommand(CMD25, blockNumber)) {
-    error(SD_CARD_ERROR_CMD25);
-    goto fail;
-  }
-  chipSelectHigh();
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-//------------------------------------------------------------------------------
-/** End a write multiple blocks sequence.
- *
-* \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-bool Sd2Card::writeStop() {
-  chipSelectLow();
-  if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
-  spiSend(STOP_TRAN_TOKEN);
-  if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
-  chipSelectHigh();
-  return true;
-
- fail:
-  error(SD_CARD_ERROR_STOP_TRAN);
-  chipSelectHigh();
-  return false;
-}
-
-//------------------------------------------------------------------------------
-/** Wait for start block token */
-//FIXME Vojtech: Copied from a current version of Sd2Card Arduino code.
-// We shall likely upgrade the rest of the Sd2Card.
-uint8_t Sd2Card::waitStartBlock(void) {
-  uint16_t t0 = millis();
-  while ((status_ = spiRec()) == 0XFF) {
-    if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
-      error(SD_CARD_ERROR_READ_TIMEOUT);
-      goto fail;
-    }
-  }
-  if (status_ != DATA_START_BLOCK) {
-    error(SD_CARD_ERROR_READ);
-    goto fail;
-  }
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-
-// Toshiba FlashAir support, copied from 
-// https://flashair-developers.com/en/documents/tutorials/arduino/
-
-//------------------------------------------------------------------------------
-/** Perform Extention Read. */
-uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) {
-  uint16_t i;
-
-  // send command and argument.
-  if (cardCommand(CMD48, arg)) {
-    error(SD_CARD_ERROR_CMD48);
-    goto fail;
-  }
-  
-  // wait for start block token.
-  if (!waitStartBlock()) {
-    goto fail;
-  }
-
-  // receive data
-  for (i = 0; i < count; ++i) {
-    dst[i] = spiRec();
-  }
-  
-  // skip dummy bytes and 16-bit crc.
-  for (; i < 514; ++i) {
-    spiRec();
-  }
-
-  chipSelectHigh();
-  spiSend(0xFF); // dummy clock to force FlashAir finish the command.
-  return true;
-
- fail:
-  chipSelectHigh();
-  return false;
-}
-
-//------------------------------------------------------------------------------
-/**
- * Read an extension register space.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func, 
-    uint32_t addr, uint16_t count, uint8_t* dst) {
-  uint32_t offset = addr & 0x1FF;
-  if (offset + count > 512) count = 512 - offset;
-  
-  if (count == 0) return true;
-  
-  uint32_t arg = 
-      (((uint32_t)mio & 0x1) << 31) | 
-    (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
-    ((addr & 0x1FFFF) << 9) |
-    ((count - 1) & 0x1FF);
-  
-  return readExt(arg, dst, count);
-}
-
-#endif
+/* Arduino Sd2Card Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino Sd2Card Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "Marlin.h"
+
+#ifdef SDSUPPORT
+#include "Sd2Card.h"
+//------------------------------------------------------------------------------
+#ifndef SOFTWARE_SPI
+// functions for hardware SPI
+//------------------------------------------------------------------------------
+// make sure SPCR rate is in expected bits
+#if (SPR0 != 0 || SPR1 != 1)
+#error unexpected SPCR bits
+#endif
+/**
+ * Initialize hardware SPI
+ * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
+ */
+static void spiInit(uint8_t spiRate) {
+  // See avr processor documentation
+  SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1);
+  SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X;
+}
+//------------------------------------------------------------------------------
+/** SPI receive a byte */
+static uint8_t spiRec() {
+  SPDR = 0XFF;
+  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+  return SPDR;
+}
+//------------------------------------------------------------------------------
+/** SPI read data - only one call so force inline */
+static inline __attribute__((always_inline))
+void spiRead(uint8_t* buf, uint16_t nbyte) {
+  if (nbyte-- == 0) return;
+  SPDR = 0XFF;
+  for (uint16_t i = 0; i < nbyte; i++) {
+    while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+    buf[i] = SPDR;
+    SPDR = 0XFF;
+  }
+  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+  buf[nbyte] = SPDR;
+}
+//------------------------------------------------------------------------------
+/** SPI send a byte */
+static void spiSend(uint8_t b) {
+  SPDR = b;
+  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+}
+//------------------------------------------------------------------------------
+/** SPI send block - only one call so force inline */
+static inline __attribute__((always_inline))
+  void spiSendBlock(uint8_t token, const uint8_t* buf) {
+  SPDR = token;
+  for (uint16_t i = 0; i < 512; i += 2) {
+    while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+    SPDR = buf[i];
+    while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+    SPDR = buf[i + 1];
+  }
+  while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ }
+}
+//------------------------------------------------------------------------------
+#else  // SOFTWARE_SPI
+//------------------------------------------------------------------------------
+/** nop to tune soft SPI timing */
+#define nop asm volatile ("nop\n\t")
+//------------------------------------------------------------------------------
+/** Soft SPI receive byte */
+static uint8_t spiRec() {
+  uint8_t data = 0;
+  // no interrupts during byte receive - about 8 us
+  cli();
+  // output pin high - like sending 0XFF
+  fastDigitalWrite(SPI_MOSI_PIN, HIGH);
+
+  for (uint8_t i = 0; i < 8; i++) {
+    fastDigitalWrite(SPI_SCK_PIN, HIGH);
+
+    // adjust so SCK is nice
+    nop;
+    nop;
+
+    data <<= 1;
+
+    if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
+
+    fastDigitalWrite(SPI_SCK_PIN, LOW);
+  }
+  // enable interrupts
+  sei();
+  return data;
+}
+//------------------------------------------------------------------------------
+/** Soft SPI read data */
+static void spiRead(uint8_t* buf, uint16_t nbyte) {
+  for (uint16_t i = 0; i < nbyte; i++) {
+    buf[i] = spiRec();
+  }
+}
+//------------------------------------------------------------------------------
+/** Soft SPI send byte */
+static void spiSend(uint8_t data) {
+  // no interrupts during byte send - about 8 us
+  cli();
+  for (uint8_t i = 0; i < 8; i++) {
+    fastDigitalWrite(SPI_SCK_PIN, LOW);
+
+    fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
+
+    data <<= 1;
+
+    fastDigitalWrite(SPI_SCK_PIN, HIGH);
+  }
+  // hold SCK high for a few ns
+  nop;
+  nop;
+  nop;
+  nop;
+
+  fastDigitalWrite(SPI_SCK_PIN, LOW);
+  // enable interrupts
+  sei();
+}
+//------------------------------------------------------------------------------
+/** Soft SPI send block */
+  void spiSendBlock(uint8_t token, const uint8_t* buf) {
+  spiSend(token);
+  for (uint16_t i = 0; i < 512; i++) {
+    spiSend(buf[i]);
+  }
+}
+#endif  // SOFTWARE_SPI
+//------------------------------------------------------------------------------
+// send command and return error code.  Return zero for OK
+uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
+  // select card
+  chipSelectLow();
+
+  // wait up to 300 ms if busy
+  waitNotBusy(300);
+
+  // send command
+  spiSend(cmd | 0x40);
+
+  // send argument
+  for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
+
+  // send CRC
+  uint8_t crc = 0XFF;
+  if (cmd == CMD0) crc = 0X95;  // correct crc for CMD0 with arg 0
+  if (cmd == CMD8) crc = 0X87;  // correct crc for CMD8 with arg 0X1AA
+  spiSend(crc);
+
+  // skip stuff byte for stop read
+  if (cmd == CMD12) spiRec();
+
+  // wait for response
+  for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ }
+  return status_;
+}
+//------------------------------------------------------------------------------
+/**
+ * Determine the size of an SD flash memory card.
+ *
+ * \return The number of 512 byte data blocks in the card
+ *         or zero if an error occurs.
+ */
+uint32_t Sd2Card::cardSize() {
+  csd_t csd;
+  if (!readCSD(&csd)) return 0;
+  if (csd.v1.csd_ver == 0) {
+    uint8_t read_bl_len = csd.v1.read_bl_len;
+    uint16_t c_size = (csd.v1.c_size_high << 10)
+                      | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
+    uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
+                          | csd.v1.c_size_mult_low;
+    return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
+  } else if (csd.v2.csd_ver == 1) {
+    uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
+                      | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
+    return (c_size + 1) << 10;
+  } else {
+    error(SD_CARD_ERROR_BAD_CSD);
+    return 0;
+  }
+}
+//------------------------------------------------------------------------------
+void Sd2Card::chipSelectHigh() {
+  digitalWrite(chipSelectPin_, HIGH);
+}
+//------------------------------------------------------------------------------
+void Sd2Card::chipSelectLow() {
+#ifndef SOFTWARE_SPI
+  spiInit(spiRate_);
+#endif  // SOFTWARE_SPI
+  digitalWrite(chipSelectPin_, LOW);
+}
+//------------------------------------------------------------------------------
+/** Erase a range of blocks.
+ *
+ * \param[in] firstBlock The address of the first block in the range.
+ * \param[in] lastBlock The address of the last block in the range.
+ *
+ * \note This function requests the SD card to do a flash erase for a
+ * range of blocks.  The data on the card after an erase operation is
+ * either 0 or 1, depends on the card vendor.  The card must support
+ * single block erase.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
+  csd_t csd;
+  if (!readCSD(&csd)) goto fail;
+  // check for single block erase
+  if (!csd.v1.erase_blk_en) {
+    // erase size mask
+    uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
+    if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
+      // error card can't erase specified area
+      error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
+      goto fail;
+    }
+  }
+  if (type_ != SD_CARD_TYPE_SDHC) {
+    firstBlock <<= 9;
+    lastBlock <<= 9;
+  }
+  if (cardCommand(CMD32, firstBlock)
+    || cardCommand(CMD33, lastBlock)
+    || cardCommand(CMD38, 0)) {
+      error(SD_CARD_ERROR_ERASE);
+      goto fail;
+  }
+  if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
+    error(SD_CARD_ERROR_ERASE_TIMEOUT);
+    goto fail;
+  }
+  chipSelectHigh();
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** Determine if card supports single block erase.
+ *
+ * \return The value one, true, is returned if single block erase is supported.
+ * The value zero, false, is returned if single block erase is not supported.
+ */
+bool Sd2Card::eraseSingleBlockEnable() {
+  csd_t csd;
+  return readCSD(&csd) ? csd.v1.erase_blk_en : false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Initialize an SD flash memory card.
+ *
+ * \param[in] sckRateID SPI clock rate selector. See setSckRate().
+ * \param[in] chipSelectPin SD chip select pin number.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.  The reason for failure
+ * can be determined by calling errorCode() and errorData().
+ */
+bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
+  errorCode_ = type_ = 0;
+  chipSelectPin_ = chipSelectPin;
+  // 16-bit init start time allows over a minute
+  uint16_t t0 = (uint16_t)millis();
+  uint32_t arg;
+
+  // set pin modes
+  pinMode(chipSelectPin_, OUTPUT);
+  chipSelectHigh();
+  pinMode(SPI_MISO_PIN, INPUT);
+  pinMode(SPI_MOSI_PIN, OUTPUT);
+  pinMode(SPI_SCK_PIN, OUTPUT);
+
+#ifndef SOFTWARE_SPI
+  // SS must be in output mode even it is not chip select
+  pinMode(SS_PIN, OUTPUT);
+  // set SS high - may be chip select for another SPI device
+#if SET_SPI_SS_HIGH
+  digitalWrite(SS_PIN, HIGH);
+#endif  // SET_SPI_SS_HIGH
+  // set SCK rate for initialization commands
+  spiRate_ = SPI_SD_INIT_RATE;
+  spiInit(spiRate_);
+#endif  // SOFTWARE_SPI
+
+  // must supply min of 74 clock cycles with CS high.
+  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
+
+  // command to go idle in SPI mode
+  while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
+    if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
+      error(SD_CARD_ERROR_CMD0);
+      goto fail;
+    }
+  }
+  // check SD version
+  if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
+    type(SD_CARD_TYPE_SD1);
+  } else {
+    // only need last byte of r7 response
+    for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
+    if (status_ != 0XAA) {
+      error(SD_CARD_ERROR_CMD8);
+      goto fail;
+    }
+    type(SD_CARD_TYPE_SD2);
+  }
+  // initialize card and send host supports SDHC if SD2
+  arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
+
+  while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
+    // check for timeout
+    if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
+      error(SD_CARD_ERROR_ACMD41);
+      goto fail;
+    }
+  }
+  // if SD2 read OCR register to check for SDHC card
+  if (type() == SD_CARD_TYPE_SD2) {
+    if (cardCommand(CMD58, 0)) {
+      error(SD_CARD_ERROR_CMD58);
+      goto fail;
+    }
+    if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
+    // discard rest of ocr - contains allowed voltage range
+    for (uint8_t i = 0; i < 3; i++) spiRec();
+  }
+  chipSelectHigh();
+
+#ifndef SOFTWARE_SPI
+  return setSckRate(sckRateID);
+#else  // SOFTWARE_SPI
+  return true;
+#endif  // SOFTWARE_SPI
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Read a 512 byte block from an SD card.
+ *
+ * \param[in] blockNumber Logical block to be read.
+ * \param[out] dst Pointer to the location that will receive the data.
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
+#ifdef SD_CHECK_AND_RETRY
+  uint8_t retryCnt = 3;
+  // use address if not SDHC card
+  if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
+ retry2:
+  retryCnt --;
+  if (cardCommand(CMD17, blockNumber)) {
+    error(SD_CARD_ERROR_CMD17);
+    if (retryCnt > 0) goto retry;
+    goto fail;
+  }
+  if (!readData(dst, 512))
+  {
+    if (retryCnt > 0) goto retry;
+    goto fail;
+  }
+  return true;
+ retry:
+   chipSelectHigh();
+   cardCommand(CMD12, 0);//Try sending a stop command, but ignore the result.
+   errorCode_ = 0;
+   goto retry2;
+#else
+  // use address if not SDHC card
+  if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
+  if (cardCommand(CMD17, blockNumber)) {
+    error(SD_CARD_ERROR_CMD17);
+    goto fail;
+  }
+  return readData(dst, 512);
+#endif
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** Read one data block in a multiple block read sequence
+ *
+ * \param[in] dst Pointer to the location for the data to be read.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::readData(uint8_t *dst) {
+  chipSelectLow();
+  return readData(dst, 512);
+}
+
+#ifdef SD_CHECK_AND_RETRY
+static const uint16_t crctab[] PROGMEM = {
+  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+  0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+  0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+  0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+  0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+  0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+  0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+  0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+  0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+  0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+  0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+  0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+  0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+  0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+  0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+  0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+  0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+  0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+  0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+  0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+  0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+  0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+  0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+  0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+  0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+  0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+  0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+  0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+  0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+  0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+  0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+  0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
+  uint16_t crc = 0;
+  for (size_t i = 0; i < n; i++) {
+    crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
+  }
+  return crc;
+}
+#endif
+
+//------------------------------------------------------------------------------
+bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
+  // wait for start block token
+  uint16_t t0 = millis();
+  while ((status_ = spiRec()) == 0XFF) {
+    if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
+      error(SD_CARD_ERROR_READ_TIMEOUT);
+      goto fail;
+    }
+  }
+  if (status_ != DATA_START_BLOCK) {
+    error(SD_CARD_ERROR_READ);
+    goto fail;
+  }
+  // transfer data
+  spiRead(dst, count);
+
+#ifdef SD_CHECK_AND_RETRY
+  {
+    uint16_t calcCrc = CRC_CCITT(dst, count);
+    uint16_t recvCrc = spiRec() << 8;
+    recvCrc |= spiRec();
+    if (calcCrc != recvCrc)
+    {
+        error(SD_CARD_ERROR_CRC);
+        goto fail;
+    }
+  }
+#else
+  // discard CRC
+  spiRec();
+  spiRec();
+#endif
+  chipSelectHigh();
+  // Toshiba FlashAir Patch. Purge pending status byte.
+  if (flash_air_compatible_)
+    spiSend(0XFF);
+  return true;
+
+ fail:
+  chipSelectHigh();
+  // Toshiba FlashAir Patch. Purge pending status byte.
+  if (flash_air_compatible_)
+    spiSend(0XFF);
+  return false;
+}
+//------------------------------------------------------------------------------
+/** read CID or CSR register */
+bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
+  uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
+  if (cardCommand(cmd, 0)) {
+    error(SD_CARD_ERROR_READ_REG);
+    goto fail;
+  }
+  return readData(dst, 16);
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** Start a read multiple blocks sequence.
+ *
+ * \param[in] blockNumber Address of first block in sequence.
+ *
+ * \note This function is used with readData() and readStop() for optimized
+ * multiple block reads.  SPI chipSelect must be low for the entire sequence.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::readStart(uint32_t blockNumber) {
+  if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
+  if (cardCommand(CMD18, blockNumber)) {
+    error(SD_CARD_ERROR_CMD18);
+    goto fail;
+  }
+  chipSelectHigh();
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** End a read multiple blocks sequence.
+ *
+* \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::readStop() {
+  chipSelectLow();
+  if (cardCommand(CMD12, 0)) {
+    error(SD_CARD_ERROR_CMD12);
+    goto fail;
+  }
+  chipSelectHigh();
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Set the SPI clock rate.
+ *
+ * \param[in] sckRateID A value in the range [0, 6].
+ *
+ * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
+ * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
+ * for \a scsRateID = 6.
+ *
+ * \return The value one, true, is returned for success and the value zero,
+ * false, is returned for an invalid value of \a sckRateID.
+ */
+bool Sd2Card::setSckRate(uint8_t sckRateID) {
+  if (sckRateID > 6) {
+    error(SD_CARD_ERROR_SCK_RATE);
+    return false;
+  }
+  spiRate_ = sckRateID;
+  return true;
+}
+//------------------------------------------------------------------------------
+// wait for card to go not busy
+bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
+  uint16_t t0 = millis();
+  while (spiRec() != 0XFF) {
+    if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
+  }
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Writes a 512 byte block to an SD card.
+ *
+ * \param[in] blockNumber Logical block to be written.
+ * \param[in] src Pointer to the location of the data to be written.
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
+  // use address if not SDHC card
+  if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
+  if (cardCommand(CMD24, blockNumber)) {
+    error(SD_CARD_ERROR_CMD24);
+    goto fail;
+  }
+  if (!writeData(DATA_START_BLOCK, src)) goto fail;
+
+  // wait for flash programming to complete
+  if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
+    error(SD_CARD_ERROR_WRITE_TIMEOUT);
+    goto fail;
+  }
+  // response is r2 so get and check two bytes for nonzero
+  if (cardCommand(CMD13, 0) || spiRec()) {
+    error(SD_CARD_ERROR_WRITE_PROGRAMMING);
+    goto fail;
+  }
+  chipSelectHigh();
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** Write one data block in a multiple block write sequence
+ * \param[in] src Pointer to the location of the data to be written.
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::writeData(const uint8_t* src) {
+  chipSelectLow();
+  // wait for previous write to finish
+  if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
+  if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail;
+  chipSelectHigh();
+  return true;
+
+ fail:
+  error(SD_CARD_ERROR_WRITE_MULTIPLE);
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+// send one block of data for write block or write multiple blocks
+bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
+  spiSendBlock(token, src);
+
+  spiSend(0xff);  // dummy crc
+  spiSend(0xff);  // dummy crc
+
+  status_ = spiRec();
+  if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
+    error(SD_CARD_ERROR_WRITE);
+    goto fail;
+  }
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** Start a write multiple blocks sequence.
+ *
+ * \param[in] blockNumber Address of first block in sequence.
+ * \param[in] eraseCount The number of blocks to be pre-erased.
+ *
+ * \note This function is used with writeData() and writeStop()
+ * for optimized multiple block writes.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
+  // send pre-erase count
+  if (cardAcmd(ACMD23, eraseCount)) {
+    error(SD_CARD_ERROR_ACMD23);
+    goto fail;
+  }
+  // use address if not SDHC card
+  if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
+  if (cardCommand(CMD25, blockNumber)) {
+    error(SD_CARD_ERROR_CMD25);
+    goto fail;
+  }
+  chipSelectHigh();
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+//------------------------------------------------------------------------------
+/** End a write multiple blocks sequence.
+ *
+* \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+bool Sd2Card::writeStop() {
+  chipSelectLow();
+  if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
+  spiSend(STOP_TRAN_TOKEN);
+  if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
+  chipSelectHigh();
+  return true;
+
+ fail:
+  error(SD_CARD_ERROR_STOP_TRAN);
+  chipSelectHigh();
+  return false;
+}
+
+//------------------------------------------------------------------------------
+/** Wait for start block token */
+//FIXME Vojtech: Copied from a current version of Sd2Card Arduino code.
+// We shall likely upgrade the rest of the Sd2Card.
+uint8_t Sd2Card::waitStartBlock(void) {
+  uint16_t t0 = millis();
+  while ((status_ = spiRec()) == 0XFF) {
+    if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
+      error(SD_CARD_ERROR_READ_TIMEOUT);
+      goto fail;
+    }
+  }
+  if (status_ != DATA_START_BLOCK) {
+    error(SD_CARD_ERROR_READ);
+    goto fail;
+  }
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+
+// Toshiba FlashAir support, copied from 
+// https://flashair-developers.com/en/documents/tutorials/arduino/
+
+//------------------------------------------------------------------------------
+/** Perform Extention Read. */
+uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) {
+  uint16_t i;
+
+  // send command and argument.
+  if (cardCommand(CMD48, arg)) {
+    error(SD_CARD_ERROR_CMD48);
+    goto fail;
+  }
+  
+  // wait for start block token.
+  if (!waitStartBlock()) {
+    goto fail;
+  }
+
+  // receive data
+  for (i = 0; i < count; ++i) {
+    dst[i] = spiRec();
+  }
+  
+  // skip dummy bytes and 16-bit crc.
+  for (; i < 514; ++i) {
+    spiRec();
+  }
+
+  chipSelectHigh();
+  spiSend(0xFF); // dummy clock to force FlashAir finish the command.
+  return true;
+
+ fail:
+  chipSelectHigh();
+  return false;
+}
+
+//------------------------------------------------------------------------------
+/**
+ * Read an extension register space.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func, 
+    uint32_t addr, uint16_t count, uint8_t* dst) {
+  uint32_t offset = addr & 0x1FF;
+  if (offset + count > 512) count = 512 - offset;
+  
+  if (count == 0) return true;
+  
+  uint32_t arg = 
+      (((uint32_t)mio & 0x1) << 31) | 
+    (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
+    ((addr & 0x1FFFF) << 9) |
+    ((count - 1) & 0x1FF);
+  
+  return readExt(arg, dst, count);
+}
+
+#endif

+ 261 - 257
Firmware/Sd2Card.h

@@ -1,258 +1,262 @@
-/* Arduino Sd2Card Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino Sd2Card Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino Sd2Card Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-#include "Marlin.h"
-#ifdef SDSUPPORT
-
-#ifndef Sd2Card_h
-#define Sd2Card_h
-/**
- * \file
- * \brief Sd2Card class for V2 SD/SDHC cards
- */
-#include "SdFatConfig.h"
-#include "Sd2PinMap.h"
-#include "SdInfo.h"
-//------------------------------------------------------------------------------
-// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
-/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
-uint8_t const SPI_FULL_SPEED = 0;
-/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
-uint8_t const SPI_HALF_SPEED = 1;
-/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */
-uint8_t const SPI_QUARTER_SPEED = 2;
-/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */
-uint8_t const SPI_EIGHTH_SPEED = 3;
-/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */
-uint8_t const SPI_SIXTEENTH_SPEED = 4;
-//------------------------------------------------------------------------------
-/** init timeout ms */
-uint16_t const SD_INIT_TIMEOUT = 2000;
-/** erase timeout ms */
-uint16_t const SD_ERASE_TIMEOUT = 10000;
-/** read timeout ms */
-uint16_t const SD_READ_TIMEOUT = 300;
-/** write time out ms */
-uint16_t const SD_WRITE_TIMEOUT = 600;
-//------------------------------------------------------------------------------
-// SD card errors
-/** timeout error for command CMD0 (initialize card in SPI mode) */
-uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
-/** CMD8 was not accepted - not a valid SD card*/
-uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
-/** card returned an error response for CMD12 (write stop) */
-uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
-/** card returned an error response for CMD17 (read block) */
-uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
-/** card returned an error response for CMD18 (read multiple block) */
-uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
-/** card returned an error response for CMD24 (write block) */
-uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
-/**  WRITE_MULTIPLE_BLOCKS command failed */
-uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
-/** card returned an error response for CMD58 (read OCR) */
-uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
-/** SET_WR_BLK_ERASE_COUNT failed */
-uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
-/** ACMD41 initialization process timeout */
-uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
-/** card returned a bad CSR version field */
-uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
-/** erase block group command failed */
-uint8_t const SD_CARD_ERROR_ERASE = 0XC;
-/** card not capable of single block erase */
-uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
-/** Erase sequence timed out */
-uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
-/** card returned an error token instead of read data */
-uint8_t const SD_CARD_ERROR_READ = 0XF;
-/** read CID or CSD failed */
-uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
-/** timeout while waiting for start of read data */
-uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
-/** card did not accept STOP_TRAN_TOKEN */
-uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
-/** card returned an error token as a response to a write operation */
-uint8_t const SD_CARD_ERROR_WRITE = 0X13;
-/** attempt to write protected block zero */
-uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14;  // REMOVE - not used
-/** card did not go ready for a multiple block write */
-uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
-/** card returned an error to a CMD13 status check after a write */
-uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
-/** timeout occurred during write programming */
-uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
-/** incorrect rate selected */
-uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
-/** init() not called */
-uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
-/** crc check error */
-uint8_t const SD_CARD_ERROR_CRC = 0X20;
-
-/** Toshiba FlashAir: iSDIO */
-uint8_t const SD_CARD_ERROR_CMD48 = 0x80;
-/** Toshiba FlashAir: iSDIO */
-uint8_t const SD_CARD_ERROR_CMD49 = 0x81;
-
-//------------------------------------------------------------------------------
-// card types
-/** Standard capacity V1 SD card */
-uint8_t const SD_CARD_TYPE_SD1  = 1;
-/** Standard capacity V2 SD card */
-uint8_t const SD_CARD_TYPE_SD2  = 2;
-/** High Capacity SD card */
-uint8_t const SD_CARD_TYPE_SDHC = 3;
-/**
- * define SOFTWARE_SPI to use bit-bang SPI
- */
-//------------------------------------------------------------------------------
-#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
-#define SOFTWARE_SPI
-#elif USE_SOFTWARE_SPI
-#define SOFTWARE_SPI
-#endif  // MEGA_SOFT_SPI
-//------------------------------------------------------------------------------
-// SPI pin definitions - do not edit here - change in SdFatConfig.h
-//
-#ifndef SOFTWARE_SPI
-// hardware pin defs
-/** The default chip select pin for the SD card is SS. */
-uint8_t const  SD_CHIP_SELECT_PIN = SS_PIN;
-// The following three pins must not be redefined for hardware SPI.
-/** SPI Master Out Slave In pin */
-uint8_t const  SPI_MOSI_PIN = MOSI_PIN;
-/** SPI Master In Slave Out pin */
-uint8_t const  SPI_MISO_PIN = MISO_PIN;
-/** SPI Clock pin */
-uint8_t const  SPI_SCK_PIN = SCK_PIN;
-
-#else  // SOFTWARE_SPI
-
-/** SPI chip select pin */
-uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
-/** SPI Master Out Slave In pin */
-uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN;
-/** SPI Master In Slave Out pin */
-uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN;
-/** SPI Clock pin */
-uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN;
-#endif  // SOFTWARE_SPI
-//------------------------------------------------------------------------------
-/**
- * \class Sd2Card
- * \brief Raw access to SD and SDHC flash memory cards.
- */
-class Sd2Card {
- public:
-  /** Construct an instance of Sd2Card. */
-  Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
-  uint32_t cardSize();
-  bool erase(uint32_t firstBlock, uint32_t lastBlock);
-  bool eraseSingleBlockEnable();
-  /**
-   *  Set SD error code.
-   *  \param[in] code value for error code.
-   */
-  void error(uint8_t code) {errorCode_ = code;}
-  /**
-   * \return error code for last error. See Sd2Card.h for a list of error codes.
-   */
-  int errorCode() const {return errorCode_;}
-  /** \return error data for last error. */
-  int errorData() const {return status_;}
-  /**
-   * Initialize an SD flash memory card with default clock rate and chip
-   * select pin.  See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
-   *
-   * \return true for success or false for failure.
-   */
-  bool init(uint8_t sckRateID = SPI_FULL_SPEED,
-    uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
-  bool readBlock(uint32_t block, uint8_t* dst);
-  /**
-   * Read a card's CID register. The CID contains card identification
-   * information such as Manufacturer ID, Product name, Product serial
-   * number and Manufacturing date. 
-   *
-   * \param[out] cid pointer to area for returned data.
-   *
-   * \return true for success or false for failure.
-   */
-  bool readCID(cid_t* cid) {
-    return readRegister(CMD10, cid);
-  }
-  /**
-   * Read a card's CSD register. The CSD contains Card-Specific Data that
-   * provides information regarding access to the card's contents.
-   *
-   * \param[out] csd pointer to area for returned data.
-   *
-   * \return true for success or false for failure.
-   */
-  bool readCSD(csd_t* csd) {
-    return readRegister(CMD9, csd);
-  }
-  bool readData(uint8_t *dst);
-  bool readStart(uint32_t blockNumber);
-  bool readStop();
-  bool setSckRate(uint8_t sckRateID);
-  /** Return the card type: SD V1, SD V2 or SDHC
-   * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
-   */
-  int type() const {return type_;}
-  bool writeBlock(uint32_t blockNumber, const uint8_t* src);
-  bool writeData(const uint8_t* src);
-  bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
-  bool writeStop();
-
-  // Toshiba FlashAir support
-  uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst);
-
- private:
-  //----------------------------------------------------------------------------
-  uint8_t chipSelectPin_;
-  uint8_t errorCode_;
-  uint8_t spiRate_;
-  uint8_t status_;
-  uint8_t type_;
-  // private functions
-  uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
-    cardCommand(CMD55, 0);
-    return cardCommand(cmd, arg);
-  }
-  uint8_t cardCommand(uint8_t cmd, uint32_t arg);
-
-  bool readData(uint8_t* dst, uint16_t count);
-  bool readRegister(uint8_t cmd, void* buf);
-  void chipSelectHigh();
-  void chipSelectLow();
-  void type(uint8_t value) {type_ = value;}
-  bool waitNotBusy(uint16_t timeoutMillis);
-  bool writeData(uint8_t token, const uint8_t* src);
-
-
-  // Toshiba FlashAir support
-  uint8_t waitStartBlock(void);
-  uint8_t readExt(uint32_t arg, uint8_t* dst, uint16_t count);
-};
-#endif  // Sd2Card_h
-
-
+/* Arduino Sd2Card Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino Sd2Card Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "Marlin.h"
+#ifdef SDSUPPORT
+
+#ifndef Sd2Card_h
+#define Sd2Card_h
+/**
+ * \file
+ * \brief Sd2Card class for V2 SD/SDHC cards
+ */
+#include "SdFatConfig.h"
+#include "Sd2PinMap.h"
+#include "SdInfo.h"
+//------------------------------------------------------------------------------
+// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
+/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
+uint8_t const SPI_FULL_SPEED = 0;
+/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
+uint8_t const SPI_HALF_SPEED = 1;
+/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */
+uint8_t const SPI_QUARTER_SPEED = 2;
+/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */
+uint8_t const SPI_EIGHTH_SPEED = 3;
+/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */
+uint8_t const SPI_SIXTEENTH_SPEED = 4;
+//------------------------------------------------------------------------------
+/** init timeout ms */
+uint16_t const SD_INIT_TIMEOUT = 2000;
+/** erase timeout ms */
+uint16_t const SD_ERASE_TIMEOUT = 10000;
+/** read timeout ms */
+uint16_t const SD_READ_TIMEOUT = 300;
+/** write time out ms */
+uint16_t const SD_WRITE_TIMEOUT = 600;
+//------------------------------------------------------------------------------
+// SD card errors
+/** timeout error for command CMD0 (initialize card in SPI mode) */
+uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
+/** CMD8 was not accepted - not a valid SD card*/
+uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
+/** card returned an error response for CMD12 (write stop) */
+uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
+/** card returned an error response for CMD17 (read block) */
+uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
+/** card returned an error response for CMD18 (read multiple block) */
+uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
+/** card returned an error response for CMD24 (write block) */
+uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
+/**  WRITE_MULTIPLE_BLOCKS command failed */
+uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
+/** card returned an error response for CMD58 (read OCR) */
+uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
+/** SET_WR_BLK_ERASE_COUNT failed */
+uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
+/** ACMD41 initialization process timeout */
+uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
+/** card returned a bad CSR version field */
+uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
+/** erase block group command failed */
+uint8_t const SD_CARD_ERROR_ERASE = 0XC;
+/** card not capable of single block erase */
+uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
+/** Erase sequence timed out */
+uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
+/** card returned an error token instead of read data */
+uint8_t const SD_CARD_ERROR_READ = 0XF;
+/** read CID or CSD failed */
+uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
+/** timeout while waiting for start of read data */
+uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
+/** card did not accept STOP_TRAN_TOKEN */
+uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
+/** card returned an error token as a response to a write operation */
+uint8_t const SD_CARD_ERROR_WRITE = 0X13;
+/** attempt to write protected block zero */
+uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14;  // REMOVE - not used
+/** card did not go ready for a multiple block write */
+uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
+/** card returned an error to a CMD13 status check after a write */
+uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
+/** timeout occurred during write programming */
+uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
+/** incorrect rate selected */
+uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
+/** init() not called */
+uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
+/** crc check error */
+uint8_t const SD_CARD_ERROR_CRC = 0X20;
+
+/** Toshiba FlashAir: iSDIO */
+uint8_t const SD_CARD_ERROR_CMD48 = 0x80;
+/** Toshiba FlashAir: iSDIO */
+uint8_t const SD_CARD_ERROR_CMD49 = 0x81;
+
+//------------------------------------------------------------------------------
+// card types
+/** Standard capacity V1 SD card */
+uint8_t const SD_CARD_TYPE_SD1  = 1;
+/** Standard capacity V2 SD card */
+uint8_t const SD_CARD_TYPE_SD2  = 2;
+/** High Capacity SD card */
+uint8_t const SD_CARD_TYPE_SDHC = 3;
+/**
+ * define SOFTWARE_SPI to use bit-bang SPI
+ */
+//------------------------------------------------------------------------------
+#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
+#define SOFTWARE_SPI
+#elif USE_SOFTWARE_SPI
+#define SOFTWARE_SPI
+#endif  // MEGA_SOFT_SPI
+//------------------------------------------------------------------------------
+// SPI pin definitions - do not edit here - change in SdFatConfig.h
+//
+#ifndef SOFTWARE_SPI
+// hardware pin defs
+/** The default chip select pin for the SD card is SS. */
+uint8_t const  SD_CHIP_SELECT_PIN = SS_PIN;
+// The following three pins must not be redefined for hardware SPI.
+/** SPI Master Out Slave In pin */
+uint8_t const  SPI_MOSI_PIN = MOSI_PIN;
+/** SPI Master In Slave Out pin */
+uint8_t const  SPI_MISO_PIN = MISO_PIN;
+/** SPI Clock pin */
+uint8_t const  SPI_SCK_PIN = SCK_PIN;
+
+#else  // SOFTWARE_SPI
+
+/** SPI chip select pin */
+uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
+/** SPI Master Out Slave In pin */
+uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN;
+/** SPI Master In Slave Out pin */
+uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN;
+/** SPI Clock pin */
+uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN;
+#endif  // SOFTWARE_SPI
+//------------------------------------------------------------------------------
+/**
+ * \class Sd2Card
+ * \brief Raw access to SD and SDHC flash memory cards.
+ */
+class Sd2Card {
+ public:
+  /** Construct an instance of Sd2Card. */
+  Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0), flash_air_compatible_(false) {}
+  uint32_t cardSize();
+  bool erase(uint32_t firstBlock, uint32_t lastBlock);
+  bool eraseSingleBlockEnable();
+  /**
+   *  Set SD error code.
+   *  \param[in] code value for error code.
+   */
+  void error(uint8_t code) {errorCode_ = code;}
+  /**
+   * \return error code for last error. See Sd2Card.h for a list of error codes.
+   */
+  int errorCode() const {return errorCode_;}
+  /** \return error data for last error. */
+  int errorData() const {return status_;}
+  /**
+   * Initialize an SD flash memory card with default clock rate and chip
+   * select pin.  See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
+   *
+   * \return true for success or false for failure.
+   */
+  bool init(uint8_t sckRateID = SPI_FULL_SPEED,
+    uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
+  bool readBlock(uint32_t block, uint8_t* dst);
+  /**
+   * Read a card's CID register. The CID contains card identification
+   * information such as Manufacturer ID, Product name, Product serial
+   * number and Manufacturing date. 
+   *
+   * \param[out] cid pointer to area for returned data.
+   *
+   * \return true for success or false for failure.
+   */
+  bool readCID(cid_t* cid) {
+    return readRegister(CMD10, cid);
+  }
+  /**
+   * Read a card's CSD register. The CSD contains Card-Specific Data that
+   * provides information regarding access to the card's contents.
+   *
+   * \param[out] csd pointer to area for returned data.
+   *
+   * \return true for success or false for failure.
+   */
+  bool readCSD(csd_t* csd) {
+    return readRegister(CMD9, csd);
+  }
+  bool readData(uint8_t *dst);
+  bool readStart(uint32_t blockNumber);
+  bool readStop();
+  bool setSckRate(uint8_t sckRateID);
+  /** Return the card type: SD V1, SD V2 or SDHC
+   * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
+   */
+  int type() const {return type_;}
+  bool writeBlock(uint32_t blockNumber, const uint8_t* src);
+  bool writeData(const uint8_t* src);
+  bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
+  bool writeStop();
+
+  // Toshiba FlashAir support
+  uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst);
+
+  void setFlashAirCompatible(bool flashAirCompatible) { flash_air_compatible_ = flashAirCompatible; }
+  bool getFlashAirCompatible() const { return flash_air_compatible_; }
+
+ private:
+  //----------------------------------------------------------------------------
+  uint8_t chipSelectPin_;
+  uint8_t errorCode_;
+  uint8_t spiRate_;
+  uint8_t status_;
+  uint8_t type_;
+  bool    flash_air_compatible_;
+  // private functions
+  uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
+    cardCommand(CMD55, 0);
+    return cardCommand(cmd, arg);
+  }
+  uint8_t cardCommand(uint8_t cmd, uint32_t arg);
+
+  bool readData(uint8_t* dst, uint16_t count);
+  bool readRegister(uint8_t cmd, void* buf);
+  void chipSelectHigh();
+  void chipSelectLow();
+  void type(uint8_t value) {type_ = value;}
+  bool waitNotBusy(uint16_t timeoutMillis);
+  bool writeData(uint8_t token, const uint8_t* src);
+
+
+  // Toshiba FlashAir support
+  uint8_t waitStartBlock(void);
+  uint8_t readExt(uint32_t arg, uint8_t* dst, uint16_t count);
+};
+#endif  // Sd2Card_h
+
+
 #endif

+ 367 - 367
Firmware/Sd2PinMap.h

@@ -1,368 +1,368 @@
-/* Arduino SdFat Library
- * Copyright (C) 2010 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-// Warning this file was generated by a program.
-#include "Marlin.h"
-#ifdef SDSUPPORT
-
-#ifndef Sd2PinMap_h
-#define Sd2PinMap_h
-#include <avr/io.h>
-//------------------------------------------------------------------------------
-/** struct for mapping digital pins */
-struct pin_map_t {
-  volatile uint8_t* ddr;
-  volatile uint8_t* pin;
-  volatile uint8_t* port;
-  uint8_t bit;
-};
-//------------------------------------------------------------------------------
-#if defined(__AVR_ATmega1280__)\
-|| defined(__AVR_ATmega2560__)
-// Mega
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 20;  // D1
-uint8_t const SCL_PIN = 21;  // D0
-
-#undef MOSI_PIN
-#undef MISO_PIN
-// SPI port
-uint8_t const SS_PIN = 53;    // B0
-uint8_t const MOSI_PIN = 51;  // B2
-uint8_t const MISO_PIN = 50;  // B3
-uint8_t const SCK_PIN = 52;   // B1
-
-static const pin_map_t digitalPinMap[] = {
-  {&DDRE, &PINE, &PORTE, 0},  // E0  0
-  {&DDRE, &PINE, &PORTE, 1},  // E1  1
-  {&DDRE, &PINE, &PORTE, 4},  // E4  2
-  {&DDRE, &PINE, &PORTE, 5},  // E5  3
-  {&DDRG, &PING, &PORTG, 5},  // G5  4
-  {&DDRE, &PINE, &PORTE, 3},  // E3  5
-  {&DDRH, &PINH, &PORTH, 3},  // H3  6
-  {&DDRH, &PINH, &PORTH, 4},  // H4  7
-  {&DDRH, &PINH, &PORTH, 5},  // H5  8
-  {&DDRH, &PINH, &PORTH, 6},  // H6  9
-  {&DDRB, &PINB, &PORTB, 4},  // B4 10
-  {&DDRB, &PINB, &PORTB, 5},  // B5 11
-  {&DDRB, &PINB, &PORTB, 6},  // B6 12
-  {&DDRB, &PINB, &PORTB, 7},  // B7 13
-  {&DDRJ, &PINJ, &PORTJ, 1},  // J1 14
-  {&DDRJ, &PINJ, &PORTJ, 0},  // J0 15
-  {&DDRH, &PINH, &PORTH, 1},  // H1 16
-  {&DDRH, &PINH, &PORTH, 0},  // H0 17
-  {&DDRD, &PIND, &PORTD, 3},  // D3 18
-  {&DDRD, &PIND, &PORTD, 2},  // D2 19
-  {&DDRD, &PIND, &PORTD, 1},  // D1 20
-  {&DDRD, &PIND, &PORTD, 0},  // D0 21
-  {&DDRA, &PINA, &PORTA, 0},  // A0 22
-  {&DDRA, &PINA, &PORTA, 1},  // A1 23
-  {&DDRA, &PINA, &PORTA, 2},  // A2 24
-  {&DDRA, &PINA, &PORTA, 3},  // A3 25
-  {&DDRA, &PINA, &PORTA, 4},  // A4 26
-  {&DDRA, &PINA, &PORTA, 5},  // A5 27
-  {&DDRA, &PINA, &PORTA, 6},  // A6 28
-  {&DDRA, &PINA, &PORTA, 7},  // A7 29
-  {&DDRC, &PINC, &PORTC, 7},  // C7 30
-  {&DDRC, &PINC, &PORTC, 6},  // C6 31
-  {&DDRC, &PINC, &PORTC, 5},  // C5 32
-  {&DDRC, &PINC, &PORTC, 4},  // C4 33
-  {&DDRC, &PINC, &PORTC, 3},  // C3 34
-  {&DDRC, &PINC, &PORTC, 2},  // C2 35
-  {&DDRC, &PINC, &PORTC, 1},  // C1 36
-  {&DDRC, &PINC, &PORTC, 0},  // C0 37
-  {&DDRD, &PIND, &PORTD, 7},  // D7 38
-  {&DDRG, &PING, &PORTG, 2},  // G2 39
-  {&DDRG, &PING, &PORTG, 1},  // G1 40
-  {&DDRG, &PING, &PORTG, 0},  // G0 41
-  {&DDRL, &PINL, &PORTL, 7},  // L7 42
-  {&DDRL, &PINL, &PORTL, 6},  // L6 43
-  {&DDRL, &PINL, &PORTL, 5},  // L5 44
-  {&DDRL, &PINL, &PORTL, 4},  // L4 45
-  {&DDRL, &PINL, &PORTL, 3},  // L3 46
-  {&DDRL, &PINL, &PORTL, 2},  // L2 47
-  {&DDRL, &PINL, &PORTL, 1},  // L1 48
-  {&DDRL, &PINL, &PORTL, 0},  // L0 49
-  {&DDRB, &PINB, &PORTB, 3},  // B3 50
-  {&DDRB, &PINB, &PORTB, 2},  // B2 51
-  {&DDRB, &PINB, &PORTB, 1},  // B1 52
-  {&DDRB, &PINB, &PORTB, 0},  // B0 53
-  {&DDRF, &PINF, &PORTF, 0},  // F0 54
-  {&DDRF, &PINF, &PORTF, 1},  // F1 55
-  {&DDRF, &PINF, &PORTF, 2},  // F2 56
-  {&DDRF, &PINF, &PORTF, 3},  // F3 57
-  {&DDRF, &PINF, &PORTF, 4},  // F4 58
-  {&DDRF, &PINF, &PORTF, 5},  // F5 59
-  {&DDRF, &PINF, &PORTF, 6},  // F6 60
-  {&DDRF, &PINF, &PORTF, 7},  // F7 61
-  {&DDRK, &PINK, &PORTK, 0},  // K0 62
-  {&DDRK, &PINK, &PORTK, 1},  // K1 63
-  {&DDRK, &PINK, &PORTK, 2},  // K2 64
-  {&DDRK, &PINK, &PORTK, 3},  // K3 65
-  {&DDRK, &PINK, &PORTK, 4},  // K4 66
-  {&DDRK, &PINK, &PORTK, 5},  // K5 67
-  {&DDRK, &PINK, &PORTK, 6},  // K6 68
-  {&DDRK, &PINK, &PORTK, 7}   // K7 69
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_ATmega644P__)\
-|| defined(__AVR_ATmega644__)\
-|| defined(__AVR_ATmega1284P__)
-// Sanguino
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 17;  // C1
-uint8_t const SCL_PIN = 18;  // C2
-
-// SPI port
-uint8_t const SS_PIN = 4;    // B4
-uint8_t const MOSI_PIN = 5;  // B5
-uint8_t const MISO_PIN = 6;  // B6
-uint8_t const SCK_PIN = 7;   // B7
-
-static const pin_map_t digitalPinMap[] = {
-  {&DDRB, &PINB, &PORTB, 0},  // B0  0
-  {&DDRB, &PINB, &PORTB, 1},  // B1  1
-  {&DDRB, &PINB, &PORTB, 2},  // B2  2
-  {&DDRB, &PINB, &PORTB, 3},  // B3  3
-  {&DDRB, &PINB, &PORTB, 4},  // B4  4
-  {&DDRB, &PINB, &PORTB, 5},  // B5  5
-  {&DDRB, &PINB, &PORTB, 6},  // B6  6
-  {&DDRB, &PINB, &PORTB, 7},  // B7  7
-  {&DDRD, &PIND, &PORTD, 0},  // D0  8
-  {&DDRD, &PIND, &PORTD, 1},  // D1  9
-  {&DDRD, &PIND, &PORTD, 2},  // D2 10
-  {&DDRD, &PIND, &PORTD, 3},  // D3 11
-  {&DDRD, &PIND, &PORTD, 4},  // D4 12
-  {&DDRD, &PIND, &PORTD, 5},  // D5 13
-  {&DDRD, &PIND, &PORTD, 6},  // D6 14
-  {&DDRD, &PIND, &PORTD, 7},  // D7 15
-  {&DDRC, &PINC, &PORTC, 0},  // C0 16
-  {&DDRC, &PINC, &PORTC, 1},  // C1 17
-  {&DDRC, &PINC, &PORTC, 2},  // C2 18
-  {&DDRC, &PINC, &PORTC, 3},  // C3 19
-  {&DDRC, &PINC, &PORTC, 4},  // C4 20
-  {&DDRC, &PINC, &PORTC, 5},  // C5 21
-  {&DDRC, &PINC, &PORTC, 6},  // C6 22
-  {&DDRC, &PINC, &PORTC, 7},  // C7 23
-  {&DDRA, &PINA, &PORTA, 7},  // A7 24
-  {&DDRA, &PINA, &PORTA, 6},  // A6 25
-  {&DDRA, &PINA, &PORTA, 5},  // A5 26
-  {&DDRA, &PINA, &PORTA, 4},  // A4 27
-  {&DDRA, &PINA, &PORTA, 3},  // A3 28
-  {&DDRA, &PINA, &PORTA, 2},  // A2 29
-  {&DDRA, &PINA, &PORTA, 1},  // A1 30
-  {&DDRA, &PINA, &PORTA, 0}   // A0 31
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_ATmega32U4__)
-// Teensy 2.0
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 6;  // D1
-uint8_t const SCL_PIN = 5;  // D0
-
-// SPI port
-uint8_t const SS_PIN = 0;    // B0
-uint8_t const MOSI_PIN = 2;  // B2
-uint8_t const MISO_PIN = 3;  // B3
-uint8_t const SCK_PIN = 1;   // B1
-
-static const pin_map_t digitalPinMap[] = {
-  {&DDRB, &PINB, &PORTB, 0},  // B0  0
-  {&DDRB, &PINB, &PORTB, 1},  // B1  1
-  {&DDRB, &PINB, &PORTB, 2},  // B2  2
-  {&DDRB, &PINB, &PORTB, 3},  // B3  3
-  {&DDRB, &PINB, &PORTB, 7},  // B7  4
-  {&DDRD, &PIND, &PORTD, 0},  // D0  5
-  {&DDRD, &PIND, &PORTD, 1},  // D1  6
-  {&DDRD, &PIND, &PORTD, 2},  // D2  7
-  {&DDRD, &PIND, &PORTD, 3},  // D3  8
-  {&DDRC, &PINC, &PORTC, 6},  // C6  9
-  {&DDRC, &PINC, &PORTC, 7},  // C7 10
-  {&DDRD, &PIND, &PORTD, 6},  // D6 11
-  {&DDRD, &PIND, &PORTD, 7},  // D7 12
-  {&DDRB, &PINB, &PORTB, 4},  // B4 13
-  {&DDRB, &PINB, &PORTB, 5},  // B5 14
-  {&DDRB, &PINB, &PORTB, 6},  // B6 15
-  {&DDRF, &PINF, &PORTF, 7},  // F7 16
-  {&DDRF, &PINF, &PORTF, 6},  // F6 17
-  {&DDRF, &PINF, &PORTF, 5},  // F5 18
-  {&DDRF, &PINF, &PORTF, 4},  // F4 19
-  {&DDRF, &PINF, &PORTF, 1},  // F1 20
-  {&DDRF, &PINF, &PORTF, 0},  // F0 21
-  {&DDRD, &PIND, &PORTD, 4},  // D4 22
-  {&DDRD, &PIND, &PORTD, 5},  // D5 23
-  {&DDRE, &PINE, &PORTE, 6}   // E6 24
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_AT90USB646__)\
-|| defined(__AVR_AT90USB1286__)
-// Teensy++ 1.0 & 2.0
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 1;  // D1
-uint8_t const SCL_PIN = 0;  // D0
-
-// SPI port
-uint8_t const SS_PIN    = 20;    // B0
-uint8_t const MOSI_PIN  = 22;    // B2
-uint8_t const MISO_PIN  = 23;    // B3
-uint8_t const SCK_PIN   = 21;    // B1
-
-static const pin_map_t digitalPinMap[] = {
-  {&DDRD, &PIND, &PORTD, 0},  // D0  0
-  {&DDRD, &PIND, &PORTD, 1},  // D1  1
-  {&DDRD, &PIND, &PORTD, 2},  // D2  2
-  {&DDRD, &PIND, &PORTD, 3},  // D3  3
-  {&DDRD, &PIND, &PORTD, 4},  // D4  4
-  {&DDRD, &PIND, &PORTD, 5},  // D5  5
-  {&DDRD, &PIND, &PORTD, 6},  // D6  6
-  {&DDRD, &PIND, &PORTD, 7},  // D7  7
-  {&DDRE, &PINE, &PORTE, 0},  // E0  8
-  {&DDRE, &PINE, &PORTE, 1},  // E1  9
-  {&DDRC, &PINC, &PORTC, 0},  // C0 10
-  {&DDRC, &PINC, &PORTC, 1},  // C1 11
-  {&DDRC, &PINC, &PORTC, 2},  // C2 12
-  {&DDRC, &PINC, &PORTC, 3},  // C3 13
-  {&DDRC, &PINC, &PORTC, 4},  // C4 14
-  {&DDRC, &PINC, &PORTC, 5},  // C5 15
-  {&DDRC, &PINC, &PORTC, 6},  // C6 16
-  {&DDRC, &PINC, &PORTC, 7},  // C7 17
-  {&DDRE, &PINE, &PORTE, 6},  // E6 18
-  {&DDRE, &PINE, &PORTE, 7},  // E7 19
-  {&DDRB, &PINB, &PORTB, 0},  // B0 20
-  {&DDRB, &PINB, &PORTB, 1},  // B1 21
-  {&DDRB, &PINB, &PORTB, 2},  // B2 22
-  {&DDRB, &PINB, &PORTB, 3},  // B3 23
-  {&DDRB, &PINB, &PORTB, 4},  // B4 24
-  {&DDRB, &PINB, &PORTB, 5},  // B5 25
-  {&DDRB, &PINB, &PORTB, 6},  // B6 26
-  {&DDRB, &PINB, &PORTB, 7},  // B7 27
-  {&DDRA, &PINA, &PORTA, 0},  // A0 28
-  {&DDRA, &PINA, &PORTA, 1},  // A1 29
-  {&DDRA, &PINA, &PORTA, 2},  // A2 30
-  {&DDRA, &PINA, &PORTA, 3},  // A3 31
-  {&DDRA, &PINA, &PORTA, 4},  // A4 32
-  {&DDRA, &PINA, &PORTA, 5},  // A5 33
-  {&DDRA, &PINA, &PORTA, 6},  // A6 34
-  {&DDRA, &PINA, &PORTA, 7},  // A7 35
-  {&DDRE, &PINE, &PORTE, 4},  // E4 36
-  {&DDRE, &PINE, &PORTE, 5},  // E5 37
-  {&DDRF, &PINF, &PORTF, 0},  // F0 38
-  {&DDRF, &PINF, &PORTF, 1},  // F1 39
-  {&DDRF, &PINF, &PORTF, 2},  // F2 40
-  {&DDRF, &PINF, &PORTF, 3},  // F3 41
-  {&DDRF, &PINF, &PORTF, 4},  // F4 42
-  {&DDRF, &PINF, &PORTF, 5},  // F5 43
-  {&DDRF, &PINF, &PORTF, 6},  // F6 44
-  {&DDRF, &PINF, &PORTF, 7}   // F7 45
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_ATmega168__)\
-||defined(__AVR_ATmega168P__)\
-||defined(__AVR_ATmega328P__)
-// 168 and 328 Arduinos
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 18;  // C4
-uint8_t const SCL_PIN = 19;  // C5
-
-// SPI port
-uint8_t const SS_PIN = 10;    // B2
-uint8_t const MOSI_PIN = 11;  // B3
-uint8_t const MISO_PIN = 12;  // B4
-uint8_t const SCK_PIN = 13;   // B5
-
-static const pin_map_t digitalPinMap[] = {
-  {&DDRD, &PIND, &PORTD, 0},  // D0  0
-  {&DDRD, &PIND, &PORTD, 1},  // D1  1
-  {&DDRD, &PIND, &PORTD, 2},  // D2  2
-  {&DDRD, &PIND, &PORTD, 3},  // D3  3
-  {&DDRD, &PIND, &PORTD, 4},  // D4  4
-  {&DDRD, &PIND, &PORTD, 5},  // D5  5
-  {&DDRD, &PIND, &PORTD, 6},  // D6  6
-  {&DDRD, &PIND, &PORTD, 7},  // D7  7
-  {&DDRB, &PINB, &PORTB, 0},  // B0  8
-  {&DDRB, &PINB, &PORTB, 1},  // B1  9
-  {&DDRB, &PINB, &PORTB, 2},  // B2 10
-  {&DDRB, &PINB, &PORTB, 3},  // B3 11
-  {&DDRB, &PINB, &PORTB, 4},  // B4 12
-  {&DDRB, &PINB, &PORTB, 5},  // B5 13
-  {&DDRC, &PINC, &PORTC, 0},  // C0 14
-  {&DDRC, &PINC, &PORTC, 1},  // C1 15
-  {&DDRC, &PINC, &PORTC, 2},  // C2 16
-  {&DDRC, &PINC, &PORTC, 3},  // C3 17
-  {&DDRC, &PINC, &PORTC, 4},  // C4 18
-  {&DDRC, &PINC, &PORTC, 5}   // C5 19
-};
-#else  // defined(__AVR_ATmega1280__)
-#error unknown chip
-#endif  // defined(__AVR_ATmega1280__)
-//------------------------------------------------------------------------------
-static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
-
-uint8_t badPinNumber(void)
-  __attribute__((error("Pin number is too large or not a constant")));
-
-static inline __attribute__((always_inline))
-  bool getPinMode(uint8_t pin) {
-  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
-    return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
-  } else {
-    return badPinNumber();
-  }
-}
-static inline __attribute__((always_inline))
-  void setPinMode(uint8_t pin, uint8_t mode) {
-  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
-    if (mode) {
-      *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
-    } else {
-      *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
-    }
-  } else {
-    badPinNumber();
-  }
-}
-static inline __attribute__((always_inline))
-  bool fastDigitalRead(uint8_t pin) {
-  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
-    return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
-  } else {
-    return badPinNumber();
-  }
-}
-static inline __attribute__((always_inline))
-  void fastDigitalWrite(uint8_t pin, uint8_t value) {
-  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
-    if (value) {
-      *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
-    } else {
-      *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
-    }
-  } else {
-    badPinNumber();
-  }
-}
-#endif  // Sd2PinMap_h
-
-
+/* Arduino SdFat Library
+ * Copyright (C) 2010 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+// Warning this file was generated by a program.
+#include "Marlin.h"
+#ifdef SDSUPPORT
+
+#ifndef Sd2PinMap_h
+#define Sd2PinMap_h
+#include <avr/io.h>
+//------------------------------------------------------------------------------
+/** struct for mapping digital pins */
+struct pin_map_t {
+  volatile uint8_t* ddr;
+  volatile uint8_t* pin;
+  volatile uint8_t* port;
+  uint8_t bit;
+};
+//------------------------------------------------------------------------------
+#if defined(__AVR_ATmega1280__)\
+|| defined(__AVR_ATmega2560__)
+// Mega
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 20;  // D1
+uint8_t const SCL_PIN = 21;  // D0
+
+#undef MOSI_PIN
+#undef MISO_PIN
+// SPI port
+uint8_t const SS_PIN = 53;    // B0
+uint8_t const MOSI_PIN = 51;  // B2
+uint8_t const MISO_PIN = 50;  // B3
+uint8_t const SCK_PIN = 52;   // B1
+
+static const pin_map_t digitalPinMap[] = {
+  {&DDRE, &PINE, &PORTE, 0},  // E0  0
+  {&DDRE, &PINE, &PORTE, 1},  // E1  1
+  {&DDRE, &PINE, &PORTE, 4},  // E4  2
+  {&DDRE, &PINE, &PORTE, 5},  // E5  3
+  {&DDRG, &PING, &PORTG, 5},  // G5  4
+  {&DDRE, &PINE, &PORTE, 3},  // E3  5
+  {&DDRH, &PINH, &PORTH, 3},  // H3  6
+  {&DDRH, &PINH, &PORTH, 4},  // H4  7
+  {&DDRH, &PINH, &PORTH, 5},  // H5  8
+  {&DDRH, &PINH, &PORTH, 6},  // H6  9
+  {&DDRB, &PINB, &PORTB, 4},  // B4 10
+  {&DDRB, &PINB, &PORTB, 5},  // B5 11
+  {&DDRB, &PINB, &PORTB, 6},  // B6 12
+  {&DDRB, &PINB, &PORTB, 7},  // B7 13
+  {&DDRJ, &PINJ, &PORTJ, 1},  // J1 14
+  {&DDRJ, &PINJ, &PORTJ, 0},  // J0 15
+  {&DDRH, &PINH, &PORTH, 1},  // H1 16
+  {&DDRH, &PINH, &PORTH, 0},  // H0 17
+  {&DDRD, &PIND, &PORTD, 3},  // D3 18
+  {&DDRD, &PIND, &PORTD, 2},  // D2 19
+  {&DDRD, &PIND, &PORTD, 1},  // D1 20
+  {&DDRD, &PIND, &PORTD, 0},  // D0 21
+  {&DDRA, &PINA, &PORTA, 0},  // A0 22
+  {&DDRA, &PINA, &PORTA, 1},  // A1 23
+  {&DDRA, &PINA, &PORTA, 2},  // A2 24
+  {&DDRA, &PINA, &PORTA, 3},  // A3 25
+  {&DDRA, &PINA, &PORTA, 4},  // A4 26
+  {&DDRA, &PINA, &PORTA, 5},  // A5 27
+  {&DDRA, &PINA, &PORTA, 6},  // A6 28
+  {&DDRA, &PINA, &PORTA, 7},  // A7 29
+  {&DDRC, &PINC, &PORTC, 7},  // C7 30
+  {&DDRC, &PINC, &PORTC, 6},  // C6 31
+  {&DDRC, &PINC, &PORTC, 5},  // C5 32
+  {&DDRC, &PINC, &PORTC, 4},  // C4 33
+  {&DDRC, &PINC, &PORTC, 3},  // C3 34
+  {&DDRC, &PINC, &PORTC, 2},  // C2 35
+  {&DDRC, &PINC, &PORTC, 1},  // C1 36
+  {&DDRC, &PINC, &PORTC, 0},  // C0 37
+  {&DDRD, &PIND, &PORTD, 7},  // D7 38
+  {&DDRG, &PING, &PORTG, 2},  // G2 39
+  {&DDRG, &PING, &PORTG, 1},  // G1 40
+  {&DDRG, &PING, &PORTG, 0},  // G0 41
+  {&DDRL, &PINL, &PORTL, 7},  // L7 42
+  {&DDRL, &PINL, &PORTL, 6},  // L6 43
+  {&DDRL, &PINL, &PORTL, 5},  // L5 44
+  {&DDRL, &PINL, &PORTL, 4},  // L4 45
+  {&DDRL, &PINL, &PORTL, 3},  // L3 46
+  {&DDRL, &PINL, &PORTL, 2},  // L2 47
+  {&DDRL, &PINL, &PORTL, 1},  // L1 48
+  {&DDRL, &PINL, &PORTL, 0},  // L0 49
+  {&DDRB, &PINB, &PORTB, 3},  // B3 50
+  {&DDRB, &PINB, &PORTB, 2},  // B2 51
+  {&DDRB, &PINB, &PORTB, 1},  // B1 52
+  {&DDRB, &PINB, &PORTB, 0},  // B0 53
+  {&DDRF, &PINF, &PORTF, 0},  // F0 54
+  {&DDRF, &PINF, &PORTF, 1},  // F1 55
+  {&DDRF, &PINF, &PORTF, 2},  // F2 56
+  {&DDRF, &PINF, &PORTF, 3},  // F3 57
+  {&DDRF, &PINF, &PORTF, 4},  // F4 58
+  {&DDRF, &PINF, &PORTF, 5},  // F5 59
+  {&DDRF, &PINF, &PORTF, 6},  // F6 60
+  {&DDRF, &PINF, &PORTF, 7},  // F7 61
+  {&DDRK, &PINK, &PORTK, 0},  // K0 62
+  {&DDRK, &PINK, &PORTK, 1},  // K1 63
+  {&DDRK, &PINK, &PORTK, 2},  // K2 64
+  {&DDRK, &PINK, &PORTK, 3},  // K3 65
+  {&DDRK, &PINK, &PORTK, 4},  // K4 66
+  {&DDRK, &PINK, &PORTK, 5},  // K5 67
+  {&DDRK, &PINK, &PORTK, 6},  // K6 68
+  {&DDRK, &PINK, &PORTK, 7}   // K7 69
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_ATmega644P__)\
+|| defined(__AVR_ATmega644__)\
+|| defined(__AVR_ATmega1284P__)
+// Sanguino
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 17;  // C1
+uint8_t const SCL_PIN = 18;  // C2
+
+// SPI port
+uint8_t const SS_PIN = 4;    // B4
+uint8_t const MOSI_PIN = 5;  // B5
+uint8_t const MISO_PIN = 6;  // B6
+uint8_t const SCK_PIN = 7;   // B7
+
+static const pin_map_t digitalPinMap[] = {
+  {&DDRB, &PINB, &PORTB, 0},  // B0  0
+  {&DDRB, &PINB, &PORTB, 1},  // B1  1
+  {&DDRB, &PINB, &PORTB, 2},  // B2  2
+  {&DDRB, &PINB, &PORTB, 3},  // B3  3
+  {&DDRB, &PINB, &PORTB, 4},  // B4  4
+  {&DDRB, &PINB, &PORTB, 5},  // B5  5
+  {&DDRB, &PINB, &PORTB, 6},  // B6  6
+  {&DDRB, &PINB, &PORTB, 7},  // B7  7
+  {&DDRD, &PIND, &PORTD, 0},  // D0  8
+  {&DDRD, &PIND, &PORTD, 1},  // D1  9
+  {&DDRD, &PIND, &PORTD, 2},  // D2 10
+  {&DDRD, &PIND, &PORTD, 3},  // D3 11
+  {&DDRD, &PIND, &PORTD, 4},  // D4 12
+  {&DDRD, &PIND, &PORTD, 5},  // D5 13
+  {&DDRD, &PIND, &PORTD, 6},  // D6 14
+  {&DDRD, &PIND, &PORTD, 7},  // D7 15
+  {&DDRC, &PINC, &PORTC, 0},  // C0 16
+  {&DDRC, &PINC, &PORTC, 1},  // C1 17
+  {&DDRC, &PINC, &PORTC, 2},  // C2 18
+  {&DDRC, &PINC, &PORTC, 3},  // C3 19
+  {&DDRC, &PINC, &PORTC, 4},  // C4 20
+  {&DDRC, &PINC, &PORTC, 5},  // C5 21
+  {&DDRC, &PINC, &PORTC, 6},  // C6 22
+  {&DDRC, &PINC, &PORTC, 7},  // C7 23
+  {&DDRA, &PINA, &PORTA, 7},  // A7 24
+  {&DDRA, &PINA, &PORTA, 6},  // A6 25
+  {&DDRA, &PINA, &PORTA, 5},  // A5 26
+  {&DDRA, &PINA, &PORTA, 4},  // A4 27
+  {&DDRA, &PINA, &PORTA, 3},  // A3 28
+  {&DDRA, &PINA, &PORTA, 2},  // A2 29
+  {&DDRA, &PINA, &PORTA, 1},  // A1 30
+  {&DDRA, &PINA, &PORTA, 0}   // A0 31
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_ATmega32U4__)
+// Teensy 2.0
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 6;  // D1
+uint8_t const SCL_PIN = 5;  // D0
+
+// SPI port
+uint8_t const SS_PIN = 0;    // B0
+uint8_t const MOSI_PIN = 2;  // B2
+uint8_t const MISO_PIN = 3;  // B3
+uint8_t const SCK_PIN = 1;   // B1
+
+static const pin_map_t digitalPinMap[] = {
+  {&DDRB, &PINB, &PORTB, 0},  // B0  0
+  {&DDRB, &PINB, &PORTB, 1},  // B1  1
+  {&DDRB, &PINB, &PORTB, 2},  // B2  2
+  {&DDRB, &PINB, &PORTB, 3},  // B3  3
+  {&DDRB, &PINB, &PORTB, 7},  // B7  4
+  {&DDRD, &PIND, &PORTD, 0},  // D0  5
+  {&DDRD, &PIND, &PORTD, 1},  // D1  6
+  {&DDRD, &PIND, &PORTD, 2},  // D2  7
+  {&DDRD, &PIND, &PORTD, 3},  // D3  8
+  {&DDRC, &PINC, &PORTC, 6},  // C6  9
+  {&DDRC, &PINC, &PORTC, 7},  // C7 10
+  {&DDRD, &PIND, &PORTD, 6},  // D6 11
+  {&DDRD, &PIND, &PORTD, 7},  // D7 12
+  {&DDRB, &PINB, &PORTB, 4},  // B4 13
+  {&DDRB, &PINB, &PORTB, 5},  // B5 14
+  {&DDRB, &PINB, &PORTB, 6},  // B6 15
+  {&DDRF, &PINF, &PORTF, 7},  // F7 16
+  {&DDRF, &PINF, &PORTF, 6},  // F6 17
+  {&DDRF, &PINF, &PORTF, 5},  // F5 18
+  {&DDRF, &PINF, &PORTF, 4},  // F4 19
+  {&DDRF, &PINF, &PORTF, 1},  // F1 20
+  {&DDRF, &PINF, &PORTF, 0},  // F0 21
+  {&DDRD, &PIND, &PORTD, 4},  // D4 22
+  {&DDRD, &PIND, &PORTD, 5},  // D5 23
+  {&DDRE, &PINE, &PORTE, 6}   // E6 24
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_AT90USB646__)\
+|| defined(__AVR_AT90USB1286__)
+// Teensy++ 1.0 & 2.0
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 1;  // D1
+uint8_t const SCL_PIN = 0;  // D0
+
+// SPI port
+uint8_t const SS_PIN    = 20;    // B0
+uint8_t const MOSI_PIN  = 22;    // B2
+uint8_t const MISO_PIN  = 23;    // B3
+uint8_t const SCK_PIN   = 21;    // B1
+
+static const pin_map_t digitalPinMap[] = {
+  {&DDRD, &PIND, &PORTD, 0},  // D0  0
+  {&DDRD, &PIND, &PORTD, 1},  // D1  1
+  {&DDRD, &PIND, &PORTD, 2},  // D2  2
+  {&DDRD, &PIND, &PORTD, 3},  // D3  3
+  {&DDRD, &PIND, &PORTD, 4},  // D4  4
+  {&DDRD, &PIND, &PORTD, 5},  // D5  5
+  {&DDRD, &PIND, &PORTD, 6},  // D6  6
+  {&DDRD, &PIND, &PORTD, 7},  // D7  7
+  {&DDRE, &PINE, &PORTE, 0},  // E0  8
+  {&DDRE, &PINE, &PORTE, 1},  // E1  9
+  {&DDRC, &PINC, &PORTC, 0},  // C0 10
+  {&DDRC, &PINC, &PORTC, 1},  // C1 11
+  {&DDRC, &PINC, &PORTC, 2},  // C2 12
+  {&DDRC, &PINC, &PORTC, 3},  // C3 13
+  {&DDRC, &PINC, &PORTC, 4},  // C4 14
+  {&DDRC, &PINC, &PORTC, 5},  // C5 15
+  {&DDRC, &PINC, &PORTC, 6},  // C6 16
+  {&DDRC, &PINC, &PORTC, 7},  // C7 17
+  {&DDRE, &PINE, &PORTE, 6},  // E6 18
+  {&DDRE, &PINE, &PORTE, 7},  // E7 19
+  {&DDRB, &PINB, &PORTB, 0},  // B0 20
+  {&DDRB, &PINB, &PORTB, 1},  // B1 21
+  {&DDRB, &PINB, &PORTB, 2},  // B2 22
+  {&DDRB, &PINB, &PORTB, 3},  // B3 23
+  {&DDRB, &PINB, &PORTB, 4},  // B4 24
+  {&DDRB, &PINB, &PORTB, 5},  // B5 25
+  {&DDRB, &PINB, &PORTB, 6},  // B6 26
+  {&DDRB, &PINB, &PORTB, 7},  // B7 27
+  {&DDRA, &PINA, &PORTA, 0},  // A0 28
+  {&DDRA, &PINA, &PORTA, 1},  // A1 29
+  {&DDRA, &PINA, &PORTA, 2},  // A2 30
+  {&DDRA, &PINA, &PORTA, 3},  // A3 31
+  {&DDRA, &PINA, &PORTA, 4},  // A4 32
+  {&DDRA, &PINA, &PORTA, 5},  // A5 33
+  {&DDRA, &PINA, &PORTA, 6},  // A6 34
+  {&DDRA, &PINA, &PORTA, 7},  // A7 35
+  {&DDRE, &PINE, &PORTE, 4},  // E4 36
+  {&DDRE, &PINE, &PORTE, 5},  // E5 37
+  {&DDRF, &PINF, &PORTF, 0},  // F0 38
+  {&DDRF, &PINF, &PORTF, 1},  // F1 39
+  {&DDRF, &PINF, &PORTF, 2},  // F2 40
+  {&DDRF, &PINF, &PORTF, 3},  // F3 41
+  {&DDRF, &PINF, &PORTF, 4},  // F4 42
+  {&DDRF, &PINF, &PORTF, 5},  // F5 43
+  {&DDRF, &PINF, &PORTF, 6},  // F6 44
+  {&DDRF, &PINF, &PORTF, 7}   // F7 45
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_ATmega168__)\
+||defined(__AVR_ATmega168P__)\
+||defined(__AVR_ATmega328P__)
+// 168 and 328 Arduinos
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 18;  // C4
+uint8_t const SCL_PIN = 19;  // C5
+
+// SPI port
+uint8_t const SS_PIN = 10;    // B2
+uint8_t const MOSI_PIN = 11;  // B3
+uint8_t const MISO_PIN = 12;  // B4
+uint8_t const SCK_PIN = 13;   // B5
+
+static const pin_map_t digitalPinMap[] = {
+  {&DDRD, &PIND, &PORTD, 0},  // D0  0
+  {&DDRD, &PIND, &PORTD, 1},  // D1  1
+  {&DDRD, &PIND, &PORTD, 2},  // D2  2
+  {&DDRD, &PIND, &PORTD, 3},  // D3  3
+  {&DDRD, &PIND, &PORTD, 4},  // D4  4
+  {&DDRD, &PIND, &PORTD, 5},  // D5  5
+  {&DDRD, &PIND, &PORTD, 6},  // D6  6
+  {&DDRD, &PIND, &PORTD, 7},  // D7  7
+  {&DDRB, &PINB, &PORTB, 0},  // B0  8
+  {&DDRB, &PINB, &PORTB, 1},  // B1  9
+  {&DDRB, &PINB, &PORTB, 2},  // B2 10
+  {&DDRB, &PINB, &PORTB, 3},  // B3 11
+  {&DDRB, &PINB, &PORTB, 4},  // B4 12
+  {&DDRB, &PINB, &PORTB, 5},  // B5 13
+  {&DDRC, &PINC, &PORTC, 0},  // C0 14
+  {&DDRC, &PINC, &PORTC, 1},  // C1 15
+  {&DDRC, &PINC, &PORTC, 2},  // C2 16
+  {&DDRC, &PINC, &PORTC, 3},  // C3 17
+  {&DDRC, &PINC, &PORTC, 4},  // C4 18
+  {&DDRC, &PINC, &PORTC, 5}   // C5 19
+};
+#else  // defined(__AVR_ATmega1280__)
+#error unknown chip
+#endif  // defined(__AVR_ATmega1280__)
+//------------------------------------------------------------------------------
+static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
+
+uint8_t badPinNumber(void)
+  __attribute__((error("Pin number is too large or not a constant")));
+
+static inline __attribute__((always_inline))
+  bool getPinMode(uint8_t pin) {
+  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+    return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
+  } else {
+    return badPinNumber();
+  }
+}
+static inline __attribute__((always_inline))
+  void setPinMode(uint8_t pin, uint8_t mode) {
+  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+    if (mode) {
+      *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
+    } else {
+      *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
+    }
+  } else {
+    badPinNumber();
+  }
+}
+static inline __attribute__((always_inline))
+  bool fastDigitalRead(uint8_t pin) {
+  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+    return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
+  } else {
+    return badPinNumber();
+  }
+}
+static inline __attribute__((always_inline))
+  void fastDigitalWrite(uint8_t pin, uint8_t value) {
+  if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+    if (value) {
+      *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
+    } else {
+      *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
+    }
+  } else {
+    badPinNumber();
+  }
+}
+#endif  // Sd2PinMap_h
+
+
 #endif

+ 3 - 3
Firmware/SdBaseFile.cpp

@@ -294,7 +294,7 @@ bool SdBaseFile::getFilename(char* name) {
   return true;
 }
 //------------------------------------------------------------------------------
-void SdBaseFile::getpos(fpos_t* pos) {
+void SdBaseFile::getpos(filepos_t* pos) {
   pos->position = curPosition_;
   pos->cluster = curCluster_;
 }
@@ -925,7 +925,7 @@ bool SdBaseFile::openRoot(SdVolume* vol) {
  * \return The byte if no error and not at eof else -1;
  */
 int SdBaseFile::peek() {
-  fpos_t pos;
+  filepos_t pos;
   getpos(&pos);
   int c = read();
   if (c >= 0) setpos(&pos);
@@ -1492,7 +1492,7 @@ bool SdBaseFile::seekSet(uint32_t pos) {
   return false;
 }
 //------------------------------------------------------------------------------
-void SdBaseFile::setpos(fpos_t* pos) {
+void SdBaseFile::setpos(filepos_t* pos) {
   curPosition_ = pos->position;
   curCluster_ = pos->cluster;
 }

+ 5 - 5
Firmware/SdBaseFile.h

@@ -31,16 +31,16 @@
 #include "SdVolume.h"
 //------------------------------------------------------------------------------
 /**
- * \struct fpos_t
+ * \struct filepos_t
  * \brief internal type for istream
  * do not use in user apps
  */
-struct fpos_t {
+struct filepos_t {
   /** stream position */
   uint32_t position;
   /** cluster for position */
   uint32_t cluster;
-  fpos_t() : position(0), cluster(0) {}
+  filepos_t() : position(0), cluster(0) {}
 };
 
 // use the gnu style oflag in open()
@@ -196,11 +196,11 @@ class SdBaseFile {
   /** get position for streams
    * \param[out] pos struct to receive position
    */
-  void getpos(fpos_t* pos);
+  void getpos(filepos_t* pos);
   /** set position for streams
    * \param[out] pos struct with value for new position
    */
-  void setpos(fpos_t* pos);
+  void setpos(filepos_t* pos);
   //----------------------------------------------------------------------------
   bool close();
   bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);

+ 28 - 0
Firmware/SdFatUtil.cpp

@@ -44,6 +44,34 @@ int SdFatUtil::FreeRam() {
 }
 #endif  // __arm
 
+void SdFatUtil::set_stack_guard()
+{	
+	char i = 0;
+	uint32_t *stack_guard;
+
+	stack_guard = (uint32_t*)&__bss_end;
+	//for (i = 0; i < 10; i++) {
+		*stack_guard = STACK_GUARD_TEST_VALUE;
+	//}
+}
+
+bool SdFatUtil::test_stack_integrity()
+{
+	uint32_t* stack_guard = (uint32_t*)&__bss_end;
+	return (*stack_guard == STACK_GUARD_TEST_VALUE);
+}
+
+uint32_t SdFatUtil::get_stack_guard_test_value()
+{
+	//static char i = 0;
+	uint32_t* stack_guard;
+	uint32_t output;
+	stack_guard = (uint32_t*)&__bss_end;
+	//output = *(stack_guard + i);
+	//i++;
+	output = *stack_guard;
+	return(output);
+}
 //------------------------------------------------------------------------------
 /** %Print a string in flash memory.
  *

+ 50 - 47
Firmware/SdFatUtil.h

@@ -1,48 +1,51 @@
-/* Arduino SdFat Library
- * Copyright (C) 2008 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-#include "Marlin.h"
-#ifdef SDSUPPORT
-
-#ifndef SdFatUtil_h
-#define SdFatUtil_h
-/**
- * \file
- * \brief Useful utility functions.
- */
-#include "Marlin.h"
-#include "MarlinSerial.h"
-/** Store and print a string in flash memory.*/
-#define PgmPrint(x) SerialPrint_P(PSTR(x))
-/** Store and print a string in flash memory followed by a CR/LF.*/
-#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
-
-namespace SdFatUtil {
-  int FreeRam();
-  void print_P( PGM_P str);
-  void println_P( PGM_P str);
-  void SerialPrint_P(PGM_P str);
-  void SerialPrintln_P(PGM_P str);
-}
-
-using namespace SdFatUtil;  // NOLINT
-#endif  // #define SdFatUtil_h
-
-
+/* Arduino SdFat Library
+ * Copyright (C) 2008 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "Marlin.h"
+#ifdef SDSUPPORT
+
+#ifndef SdFatUtil_h
+#define SdFatUtil_h
+/**
+ * \file
+ * \brief Useful utility functions.
+ */
+#include "Marlin.h"
+#include "MarlinSerial.h"
+/** Store and print a string in flash memory.*/
+#define PgmPrint(x) SerialPrint_P(PSTR(x))
+/** Store and print a string in flash memory followed by a CR/LF.*/
+#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
+
+namespace SdFatUtil {
+  int FreeRam();
+  void print_P( PGM_P str);
+  void println_P( PGM_P str);
+  void SerialPrint_P(PGM_P str);
+  void SerialPrintln_P(PGM_P str);
+  void set_stack_guard();
+  bool test_stack_integrity();
+  uint32_t get_stack_guard_test_value();
+}
+
+using namespace SdFatUtil;  // NOLINT
+#endif  // #define SdFatUtil_h
+
+
 #endif

+ 95 - 95
Firmware/SdFile.cpp

@@ -1,95 +1,95 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-#include "Marlin.h"
-
-#ifdef SDSUPPORT
-#include "SdFile.h"
-/**  Create a file object and open it in the current working directory.
- *
- * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
- *
- * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
- * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
- */
-SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) {
-}
-//------------------------------------------------------------------------------
-/** Write data to an open file.
- *
- * \note Data is moved to the cache but may not be written to the
- * storage device until sync() is called.
- *
- * \param[in] buf Pointer to the location of the data to be written.
- *
- * \param[in] nbyte Number of bytes to write.
- *
- * \return For success write() returns the number of bytes written, always
- * \a nbyte.  If an error occurs, write() returns -1.  Possible errors
- * include write() is called before a file has been opened, write is called
- * for a read-only file, device is full, a corrupt file system or an I/O error.
- *
- */
-int16_t SdFile::write(const void* buf, uint16_t nbyte) {
-  return SdBaseFile::write(buf, nbyte);
-}
-//------------------------------------------------------------------------------
-/** Write a byte to a file. Required by the Arduino Print class.
- * \param[in] b the byte to be written.
- * Use writeError to check for errors.
- */
-#if ARDUINO >= 100
-size_t SdFile::write(uint8_t b)
-{
-    return SdBaseFile::write(&b, 1);
-}
-#else
-void SdFile::write(uint8_t b)
-{
-    SdBaseFile::write(&b, 1);
-}
-#endif
-//------------------------------------------------------------------------------
-/** Write a string to a file. Used by the Arduino Print class.
- * \param[in] str Pointer to the string.
- * Use writeError to check for errors.
- */
-void SdFile::write(const char* str) {
-  SdBaseFile::write(str, strlen(str));
-}
-//------------------------------------------------------------------------------
-/** Write a PROGMEM string to a file.
- * \param[in] str Pointer to the PROGMEM string.
- * Use writeError to check for errors.
- */
-void SdFile::write_P(PGM_P str) {
-  for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
-}
-//------------------------------------------------------------------------------
-/** Write a PROGMEM string followed by CR/LF to a file.
- * \param[in] str Pointer to the PROGMEM string.
- * Use writeError to check for errors.
- */
-void SdFile::writeln_P(PGM_P str) {
-  write_P(str);
-  write_P(PSTR("\r\n"));
-}
-
-
-#endif
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "Marlin.h"
+
+#ifdef SDSUPPORT
+#include "SdFile.h"
+/**  Create a file object and open it in the current working directory.
+ *
+ * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
+ */
+SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) {
+}
+//------------------------------------------------------------------------------
+/** Write data to an open file.
+ *
+ * \note Data is moved to the cache but may not be written to the
+ * storage device until sync() is called.
+ *
+ * \param[in] buf Pointer to the location of the data to be written.
+ *
+ * \param[in] nbyte Number of bytes to write.
+ *
+ * \return For success write() returns the number of bytes written, always
+ * \a nbyte.  If an error occurs, write() returns -1.  Possible errors
+ * include write() is called before a file has been opened, write is called
+ * for a read-only file, device is full, a corrupt file system or an I/O error.
+ *
+ */
+int16_t SdFile::write(const void* buf, uint16_t nbyte) {
+  return SdBaseFile::write(buf, nbyte);
+}
+//------------------------------------------------------------------------------
+/** Write a byte to a file. Required by the Arduino Print class.
+ * \param[in] b the byte to be written.
+ * Use writeError to check for errors.
+ */
+#if ARDUINO >= 100
+size_t SdFile::write(uint8_t b)
+{
+    return SdBaseFile::write(&b, 1);
+}
+#else
+void SdFile::write(uint8_t b)
+{
+    SdBaseFile::write(&b, 1);
+}
+#endif
+//------------------------------------------------------------------------------
+/** Write a string to a file. Used by the Arduino Print class.
+ * \param[in] str Pointer to the string.
+ * Use writeError to check for errors.
+ */
+void SdFile::write(const char* str) {
+  SdBaseFile::write(str, strlen(str));
+}
+//------------------------------------------------------------------------------
+/** Write a PROGMEM string to a file.
+ * \param[in] str Pointer to the PROGMEM string.
+ * Use writeError to check for errors.
+ */
+void SdFile::write_P(PGM_P str) {
+  for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
+}
+//------------------------------------------------------------------------------
+/** Write a PROGMEM string followed by CR/LF to a file.
+ * \param[in] str Pointer to the PROGMEM string.
+ * Use writeError to check for errors.
+ */
+void SdFile::writeln_P(PGM_P str) {
+  write_P(str);
+  write_P(PSTR("\r\n"));
+}
+
+
+#endif

+ 285 - 285
Firmware/SdInfo.h

@@ -1,286 +1,286 @@
-/* Arduino Sd2Card Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino Sd2Card Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino Sd2Card Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-#include "Marlin.h"
-#ifdef SDSUPPORT
-
-#ifndef SdInfo_h
-#define SdInfo_h
-#include <stdint.h>
-// Based on the document:
-//
-// SD Specifications
-// Part 1
-// Physical Layer
-// Simplified Specification
-// Version 3.01
-// May 18, 2010
-//
-// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
-//------------------------------------------------------------------------------
-// SD card commands
-/** GO_IDLE_STATE - init card in spi mode if CS low */
-uint8_t const CMD0 = 0X00;
-/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
-uint8_t const CMD8 = 0X08;
-/** SEND_CSD - read the Card Specific Data (CSD register) */
-uint8_t const CMD9 = 0X09;
-/** SEND_CID - read the card identification information (CID register) */
-uint8_t const CMD10 = 0X0A;
-/** STOP_TRANSMISSION - end multiple block read sequence */
-uint8_t const CMD12 = 0X0C;
-/** SEND_STATUS - read the card status register */
-uint8_t const CMD13 = 0X0D;
-/** READ_SINGLE_BLOCK - read a single data block from the card */
-uint8_t const CMD17 = 0X11;
-/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
-uint8_t const CMD18 = 0X12;
-/** WRITE_BLOCK - write a single data block to the card */
-uint8_t const CMD24 = 0X18;
-/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
-uint8_t const CMD25 = 0X19;
-/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
-uint8_t const CMD32 = 0X20;
-/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
-    range to be erased*/
-uint8_t const CMD33 = 0X21;
-/** ERASE - erase all previously selected blocks */
-uint8_t const CMD38 = 0X26;
-
-/** Toshiba FlashAir: iSDIO */
-uint8_t const CMD48 = 0x30;
-/** Toshiba FlashAir: iSDIO */
-uint8_t const CMD49 = 0x31;
-
-/** APP_CMD - escape for application specific command */
-uint8_t const CMD55 = 0X37;
-/** READ_OCR - read the OCR register of a card */
-uint8_t const CMD58 = 0X3A;
-/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
-     pre-erased before writing */
-uint8_t const ACMD23 = 0X17;
-/** SD_SEND_OP_COMD - Sends host capacity support information and
-    activates the card's initialization process */
-uint8_t const ACMD41 = 0X29;
-//------------------------------------------------------------------------------
-/** status for card in the ready state */
-uint8_t const R1_READY_STATE = 0X00;
-/** status for card in the idle state */
-uint8_t const R1_IDLE_STATE = 0X01;
-/** status bit for illegal command */
-uint8_t const R1_ILLEGAL_COMMAND = 0X04;
-/** start data token for read or write single block*/
-uint8_t const DATA_START_BLOCK = 0XFE;
-/** stop token for write multiple blocks*/
-uint8_t const STOP_TRAN_TOKEN = 0XFD;
-/** start data token for write multiple blocks*/
-uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
-/** mask for data response tokens after a write block operation */
-uint8_t const DATA_RES_MASK = 0X1F;
-/** write data accepted token */
-uint8_t const DATA_RES_ACCEPTED = 0X05;
-//------------------------------------------------------------------------------
-/** Card IDentification (CID) register */
-typedef struct CID {
-  // byte 0
-  /** Manufacturer ID */
-  unsigned char mid;
-  // byte 1-2
-  /** OEM/Application ID */
-  char oid[2];
-  // byte 3-7
-  /** Product name */
-  char pnm[5];
-  // byte 8
-  /** Product revision least significant digit */
-  unsigned char prv_m : 4;
-  /** Product revision most significant digit */
-  unsigned char prv_n : 4;
-  // byte 9-12
-  /** Product serial number */
-  uint32_t psn;
-  // byte 13
-  /** Manufacturing date year low digit */
-  unsigned char mdt_year_high : 4;
-  /** not used */
-  unsigned char reserved : 4;
-  // byte 14
-  /** Manufacturing date month */
-  unsigned char mdt_month : 4;
-  /** Manufacturing date year low digit */
-  unsigned char mdt_year_low :4;
-  // byte 15
-  /** not used always 1 */
-  unsigned char always1 : 1;
-  /** CRC7 checksum */
-  unsigned char crc : 7;
-}cid_t;
-//------------------------------------------------------------------------------
-/** CSD for version 1.00 cards */
-typedef struct CSDV1 {
-  // byte 0
-  unsigned char reserved1 : 6;
-  unsigned char csd_ver : 2;
-  // byte 1
-  unsigned char taac;
-  // byte 2
-  unsigned char nsac;
-  // byte 3
-  unsigned char tran_speed;
-  // byte 4
-  unsigned char ccc_high;
-  // byte 5
-  unsigned char read_bl_len : 4;
-  unsigned char ccc_low : 4;
-  // byte 6
-  unsigned char c_size_high : 2;
-  unsigned char reserved2 : 2;
-  unsigned char dsr_imp : 1;
-  unsigned char read_blk_misalign :1;
-  unsigned char write_blk_misalign : 1;
-  unsigned char read_bl_partial : 1;
-  // byte 7
-  unsigned char c_size_mid;
-  // byte 8
-  unsigned char vdd_r_curr_max : 3;
-  unsigned char vdd_r_curr_min : 3;
-  unsigned char c_size_low :2;
-  // byte 9
-  unsigned char c_size_mult_high : 2;
-  unsigned char vdd_w_cur_max : 3;
-  unsigned char vdd_w_curr_min : 3;
-  // byte 10
-  unsigned char sector_size_high : 6;
-  unsigned char erase_blk_en : 1;
-  unsigned char c_size_mult_low : 1;
-  // byte 11
-  unsigned char wp_grp_size : 7;
-  unsigned char sector_size_low : 1;
-  // byte 12
-  unsigned char write_bl_len_high : 2;
-  unsigned char r2w_factor : 3;
-  unsigned char reserved3 : 2;
-  unsigned char wp_grp_enable : 1;
-  // byte 13
-  unsigned char reserved4 : 5;
-  unsigned char write_partial : 1;
-  unsigned char write_bl_len_low : 2;
-  // byte 14
-  unsigned char reserved5: 2;
-  unsigned char file_format : 2;
-  unsigned char tmp_write_protect : 1;
-  unsigned char perm_write_protect : 1;
-  unsigned char copy : 1;
-  /** Indicates the file format on the card */
-  unsigned char file_format_grp : 1;
-  // byte 15
-  unsigned char always1 : 1;
-  unsigned char crc : 7;
-}csd1_t;
-//------------------------------------------------------------------------------
-/** CSD for version 2.00 cards */
-typedef struct CSDV2 {
-  // byte 0
-  unsigned char reserved1 : 6;
-  unsigned char csd_ver : 2;
-  // byte 1
-  /** fixed to 0X0E */
-  unsigned char taac;
-  // byte 2
-  /** fixed to 0 */
-  unsigned char nsac;
-  // byte 3
-  unsigned char tran_speed;
-  // byte 4
-  unsigned char ccc_high;
-  // byte 5
-  /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
-  unsigned char read_bl_len : 4;
-  unsigned char ccc_low : 4;
-  // byte 6
-  /** not used */
-  unsigned char reserved2 : 4;
-  unsigned char dsr_imp : 1;
-  /** fixed to 0 */
-  unsigned char read_blk_misalign :1;
-  /** fixed to 0 */
-  unsigned char write_blk_misalign : 1;
-  /** fixed to 0 - no partial read */
-  unsigned char read_bl_partial : 1;
-  // byte 7
-  /** not used */
-  unsigned char reserved3 : 2;
-  /** high part of card size */
-  unsigned char c_size_high : 6;
-  // byte 8
-  /** middle part of card size */
-  unsigned char c_size_mid;
-  // byte 9
-  /** low part of card size */
-  unsigned char c_size_low;
-  // byte 10
-  /** sector size is fixed at 64 KB */
-  unsigned char sector_size_high : 6;
-  /** fixed to 1 - erase single is supported */
-  unsigned char erase_blk_en : 1;
-  /** not used */
-  unsigned char reserved4 : 1;
-  // byte 11
-  unsigned char wp_grp_size : 7;
-  /** sector size is fixed at 64 KB */
-  unsigned char sector_size_low : 1;
-  // byte 12
-  /** write_bl_len fixed for 512 byte blocks */
-  unsigned char write_bl_len_high : 2;
-  /** fixed value of 2 */
-  unsigned char r2w_factor : 3;
-  /** not used */
-  unsigned char reserved5 : 2;
-  /** fixed value of 0 - no write protect groups */
-  unsigned char wp_grp_enable : 1;
-  // byte 13
-  unsigned char reserved6 : 5;
-  /** always zero - no partial block read*/
-  unsigned char write_partial : 1;
-  /** write_bl_len fixed for 512 byte blocks */
-  unsigned char write_bl_len_low : 2;
-  // byte 14
-  unsigned char reserved7: 2;
-  /** Do not use always 0 */
-  unsigned char file_format : 2;
-  unsigned char tmp_write_protect : 1;
-  unsigned char perm_write_protect : 1;
-  unsigned char copy : 1;
-  /** Do not use always 0 */
-  unsigned char file_format_grp : 1;
-  // byte 15
-  /** not used always 1 */
-  unsigned char always1 : 1;
-  /** checksum */
-  unsigned char crc : 7;
-}csd2_t;
-//------------------------------------------------------------------------------
-/** union of old and new style CSD register */
-union csd_t {
-  csd1_t v1;
-  csd2_t v2;
-};
-#endif  // SdInfo_h
-
+/* Arduino Sd2Card Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino Sd2Card Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "Marlin.h"
+#ifdef SDSUPPORT
+
+#ifndef SdInfo_h
+#define SdInfo_h
+#include <stdint.h>
+// Based on the document:
+//
+// SD Specifications
+// Part 1
+// Physical Layer
+// Simplified Specification
+// Version 3.01
+// May 18, 2010
+//
+// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
+//------------------------------------------------------------------------------
+// SD card commands
+/** GO_IDLE_STATE - init card in spi mode if CS low */
+uint8_t const CMD0 = 0X00;
+/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
+uint8_t const CMD8 = 0X08;
+/** SEND_CSD - read the Card Specific Data (CSD register) */
+uint8_t const CMD9 = 0X09;
+/** SEND_CID - read the card identification information (CID register) */
+uint8_t const CMD10 = 0X0A;
+/** STOP_TRANSMISSION - end multiple block read sequence */
+uint8_t const CMD12 = 0X0C;
+/** SEND_STATUS - read the card status register */
+uint8_t const CMD13 = 0X0D;
+/** READ_SINGLE_BLOCK - read a single data block from the card */
+uint8_t const CMD17 = 0X11;
+/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
+uint8_t const CMD18 = 0X12;
+/** WRITE_BLOCK - write a single data block to the card */
+uint8_t const CMD24 = 0X18;
+/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
+uint8_t const CMD25 = 0X19;
+/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
+uint8_t const CMD32 = 0X20;
+/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
+    range to be erased*/
+uint8_t const CMD33 = 0X21;
+/** ERASE - erase all previously selected blocks */
+uint8_t const CMD38 = 0X26;
+
+/** Toshiba FlashAir: iSDIO */
+uint8_t const CMD48 = 0x30;
+/** Toshiba FlashAir: iSDIO */
+uint8_t const CMD49 = 0x31;
+
+/** APP_CMD - escape for application specific command */
+uint8_t const CMD55 = 0X37;
+/** READ_OCR - read the OCR register of a card */
+uint8_t const CMD58 = 0X3A;
+/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
+     pre-erased before writing */
+uint8_t const ACMD23 = 0X17;
+/** SD_SEND_OP_COMD - Sends host capacity support information and
+    activates the card's initialization process */
+uint8_t const ACMD41 = 0X29;
+//------------------------------------------------------------------------------
+/** status for card in the ready state */
+uint8_t const R1_READY_STATE = 0X00;
+/** status for card in the idle state */
+uint8_t const R1_IDLE_STATE = 0X01;
+/** status bit for illegal command */
+uint8_t const R1_ILLEGAL_COMMAND = 0X04;
+/** start data token for read or write single block*/
+uint8_t const DATA_START_BLOCK = 0XFE;
+/** stop token for write multiple blocks*/
+uint8_t const STOP_TRAN_TOKEN = 0XFD;
+/** start data token for write multiple blocks*/
+uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
+/** mask for data response tokens after a write block operation */
+uint8_t const DATA_RES_MASK = 0X1F;
+/** write data accepted token */
+uint8_t const DATA_RES_ACCEPTED = 0X05;
+//------------------------------------------------------------------------------
+/** Card IDentification (CID) register */
+typedef struct CID {
+  // byte 0
+  /** Manufacturer ID */
+  unsigned char mid;
+  // byte 1-2
+  /** OEM/Application ID */
+  char oid[2];
+  // byte 3-7
+  /** Product name */
+  char pnm[5];
+  // byte 8
+  /** Product revision least significant digit */
+  unsigned char prv_m : 4;
+  /** Product revision most significant digit */
+  unsigned char prv_n : 4;
+  // byte 9-12
+  /** Product serial number */
+  uint32_t psn;
+  // byte 13
+  /** Manufacturing date year low digit */
+  unsigned char mdt_year_high : 4;
+  /** not used */
+  unsigned char reserved : 4;
+  // byte 14
+  /** Manufacturing date month */
+  unsigned char mdt_month : 4;
+  /** Manufacturing date year low digit */
+  unsigned char mdt_year_low :4;
+  // byte 15
+  /** not used always 1 */
+  unsigned char always1 : 1;
+  /** CRC7 checksum */
+  unsigned char crc : 7;
+}cid_t;
+//------------------------------------------------------------------------------
+/** CSD for version 1.00 cards */
+typedef struct CSDV1 {
+  // byte 0
+  unsigned char reserved1 : 6;
+  unsigned char csd_ver : 2;
+  // byte 1
+  unsigned char taac;
+  // byte 2
+  unsigned char nsac;
+  // byte 3
+  unsigned char tran_speed;
+  // byte 4
+  unsigned char ccc_high;
+  // byte 5
+  unsigned char read_bl_len : 4;
+  unsigned char ccc_low : 4;
+  // byte 6
+  unsigned char c_size_high : 2;
+  unsigned char reserved2 : 2;
+  unsigned char dsr_imp : 1;
+  unsigned char read_blk_misalign :1;
+  unsigned char write_blk_misalign : 1;
+  unsigned char read_bl_partial : 1;
+  // byte 7
+  unsigned char c_size_mid;
+  // byte 8
+  unsigned char vdd_r_curr_max : 3;
+  unsigned char vdd_r_curr_min : 3;
+  unsigned char c_size_low :2;
+  // byte 9
+  unsigned char c_size_mult_high : 2;
+  unsigned char vdd_w_cur_max : 3;
+  unsigned char vdd_w_curr_min : 3;
+  // byte 10
+  unsigned char sector_size_high : 6;
+  unsigned char erase_blk_en : 1;
+  unsigned char c_size_mult_low : 1;
+  // byte 11
+  unsigned char wp_grp_size : 7;
+  unsigned char sector_size_low : 1;
+  // byte 12
+  unsigned char write_bl_len_high : 2;
+  unsigned char r2w_factor : 3;
+  unsigned char reserved3 : 2;
+  unsigned char wp_grp_enable : 1;
+  // byte 13
+  unsigned char reserved4 : 5;
+  unsigned char write_partial : 1;
+  unsigned char write_bl_len_low : 2;
+  // byte 14
+  unsigned char reserved5: 2;
+  unsigned char file_format : 2;
+  unsigned char tmp_write_protect : 1;
+  unsigned char perm_write_protect : 1;
+  unsigned char copy : 1;
+  /** Indicates the file format on the card */
+  unsigned char file_format_grp : 1;
+  // byte 15
+  unsigned char always1 : 1;
+  unsigned char crc : 7;
+}csd1_t;
+//------------------------------------------------------------------------------
+/** CSD for version 2.00 cards */
+typedef struct CSDV2 {
+  // byte 0
+  unsigned char reserved1 : 6;
+  unsigned char csd_ver : 2;
+  // byte 1
+  /** fixed to 0X0E */
+  unsigned char taac;
+  // byte 2
+  /** fixed to 0 */
+  unsigned char nsac;
+  // byte 3
+  unsigned char tran_speed;
+  // byte 4
+  unsigned char ccc_high;
+  // byte 5
+  /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
+  unsigned char read_bl_len : 4;
+  unsigned char ccc_low : 4;
+  // byte 6
+  /** not used */
+  unsigned char reserved2 : 4;
+  unsigned char dsr_imp : 1;
+  /** fixed to 0 */
+  unsigned char read_blk_misalign :1;
+  /** fixed to 0 */
+  unsigned char write_blk_misalign : 1;
+  /** fixed to 0 - no partial read */
+  unsigned char read_bl_partial : 1;
+  // byte 7
+  /** not used */
+  unsigned char reserved3 : 2;
+  /** high part of card size */
+  unsigned char c_size_high : 6;
+  // byte 8
+  /** middle part of card size */
+  unsigned char c_size_mid;
+  // byte 9
+  /** low part of card size */
+  unsigned char c_size_low;
+  // byte 10
+  /** sector size is fixed at 64 KB */
+  unsigned char sector_size_high : 6;
+  /** fixed to 1 - erase single is supported */
+  unsigned char erase_blk_en : 1;
+  /** not used */
+  unsigned char reserved4 : 1;
+  // byte 11
+  unsigned char wp_grp_size : 7;
+  /** sector size is fixed at 64 KB */
+  unsigned char sector_size_low : 1;
+  // byte 12
+  /** write_bl_len fixed for 512 byte blocks */
+  unsigned char write_bl_len_high : 2;
+  /** fixed value of 2 */
+  unsigned char r2w_factor : 3;
+  /** not used */
+  unsigned char reserved5 : 2;
+  /** fixed value of 0 - no write protect groups */
+  unsigned char wp_grp_enable : 1;
+  // byte 13
+  unsigned char reserved6 : 5;
+  /** always zero - no partial block read*/
+  unsigned char write_partial : 1;
+  /** write_bl_len fixed for 512 byte blocks */
+  unsigned char write_bl_len_low : 2;
+  // byte 14
+  unsigned char reserved7: 2;
+  /** Do not use always 0 */
+  unsigned char file_format : 2;
+  unsigned char tmp_write_protect : 1;
+  unsigned char perm_write_protect : 1;
+  unsigned char copy : 1;
+  /** Do not use always 0 */
+  unsigned char file_format_grp : 1;
+  // byte 15
+  /** not used always 1 */
+  unsigned char always1 : 1;
+  /** checksum */
+  unsigned char crc : 7;
+}csd2_t;
+//------------------------------------------------------------------------------
+/** union of old and new style CSD register */
+union csd_t {
+  csd1_t v1;
+  csd2_t v2;
+};
+#endif  // SdInfo_h
+
 #endif

+ 404 - 404
Firmware/SdVolume.cpp

@@ -1,405 +1,405 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-#include "Marlin.h"
-#ifdef SDSUPPORT
-
-#include "SdVolume.h"
-//------------------------------------------------------------------------------
-#if !USE_MULTIPLE_CARDS
-// raw block cache
-uint32_t SdVolume::cacheBlockNumber_;  // current block number
-cache_t  SdVolume::cacheBuffer_;       // 512 byte cache for Sd2Card
-Sd2Card* SdVolume::sdCard_;            // pointer to SD card object
-bool     SdVolume::cacheDirty_;        // cacheFlush() will write block if true
-uint32_t SdVolume::cacheMirrorBlock_;  // mirror  block for second FAT
-#endif  // USE_MULTIPLE_CARDS
-//------------------------------------------------------------------------------
-// find a contiguous group of clusters
-bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
-  // start of group
-  uint32_t bgnCluster;
-  // end of group
-  uint32_t endCluster;
-  // last cluster of FAT
-  uint32_t fatEnd = clusterCount_ + 1;
-
-  // flag to save place to start next search
-  bool setStart;
-
-  // set search start cluster
-  if (*curCluster) {
-    // try to make file contiguous
-    bgnCluster = *curCluster + 1;
-
-    // don't save new start location
-    setStart = false;
-  } else {
-    // start at likely place for free cluster
-    bgnCluster = allocSearchStart_;
-
-    // save next search start if one cluster
-    setStart = count == 1;
-  }
-  // end of group
-  endCluster = bgnCluster;
-
-  // search the FAT for free clusters
-  for (uint32_t n = 0;; n++, endCluster++) {
-    // can't find space checked all clusters
-    if (n >= clusterCount_) goto fail;
-
-    // past end - start from beginning of FAT
-    if (endCluster > fatEnd) {
-      bgnCluster = endCluster = 2;
-    }
-    uint32_t f;
-    if (!fatGet(endCluster, &f)) goto fail;
-
-    if (f != 0) {
-      // cluster in use try next cluster as bgnCluster
-      bgnCluster = endCluster + 1;
-    } else if ((endCluster - bgnCluster + 1) == count) {
-      // done - found space
-      break;
-    }
-  }
-  // mark end of chain
-  if (!fatPutEOC(endCluster)) goto fail;
-
-  // link clusters
-  while (endCluster > bgnCluster) {
-    if (!fatPut(endCluster - 1, endCluster)) goto fail;
-    endCluster--;
-  }
-  if (*curCluster != 0) {
-    // connect chains
-    if (!fatPut(*curCluster, bgnCluster)) goto fail;
-  }
-  // return first cluster number to caller
-  *curCluster = bgnCluster;
-
-  // remember possible next free cluster
-  if (setStart) allocSearchStart_ = bgnCluster + 1;
-
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-bool SdVolume::cacheFlush() {
-  if (cacheDirty_) {
-    if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
-      goto fail;
-    }
-    // mirror FAT tables
-    if (cacheMirrorBlock_) {
-      if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
-        goto fail;
-      }
-      cacheMirrorBlock_ = 0;
-    }
-    cacheDirty_ = 0;
-  }
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
-  if (cacheBlockNumber_ != blockNumber) {
-    if (!cacheFlush()) goto fail;
-    if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
-    cacheBlockNumber_ = blockNumber;
-  }
-  if (dirty) cacheDirty_ = true;
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-// return the size in bytes of a cluster chain
-bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
-  uint32_t s = 0;
-  do {
-    if (!fatGet(cluster, &cluster)) goto fail;
-    s += 512UL << clusterSizeShift_;
-  } while (!isEOC(cluster));
-  *size = s;
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-// Fetch a FAT entry
-bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
-  uint32_t lba;
-  if (cluster > (clusterCount_ + 1)) goto fail;
-  if (FAT12_SUPPORT && fatType_ == 12) {
-    uint16_t index = cluster;
-    index += index >> 1;
-    lba = fatStartBlock_ + (index >> 9);
-    if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
-    index &= 0X1FF;
-    uint16_t tmp = cacheBuffer_.data[index];
-    index++;
-    if (index == 512) {
-      if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
-      index = 0;
-    }
-    tmp |= cacheBuffer_.data[index] << 8;
-    *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
-    return true;
-  }
-  if (fatType_ == 16) {
-    lba = fatStartBlock_ + (cluster >> 8);
-  } else if (fatType_ == 32) {
-    lba = fatStartBlock_ + (cluster >> 7);
-  } else {
-    goto fail;
-  }
-  if (lba != cacheBlockNumber_) {
-    if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
-  }
-  if (fatType_ == 16) {
-    *value = cacheBuffer_.fat16[cluster & 0XFF];
-  } else {
-    *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
-  }
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-// Store a FAT entry
-bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
-  uint32_t lba;
-  // error if reserved cluster
-  if (cluster < 2) goto fail;
-
-  // error if not in FAT
-  if (cluster > (clusterCount_ + 1)) goto fail;
-
-  if (FAT12_SUPPORT && fatType_ == 12) {
-    uint16_t index = cluster;
-    index += index >> 1;
-    lba = fatStartBlock_ + (index >> 9);
-    if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
-    // mirror second FAT
-    if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
-    index &= 0X1FF;
-    uint8_t tmp = value;
-    if (cluster & 1) {
-      tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
-    }
-    cacheBuffer_.data[index] = tmp;
-    index++;
-    if (index == 512) {
-      lba++;
-      index = 0;
-      if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
-      // mirror second FAT
-      if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
-    }
-    tmp = value >> 4;
-    if (!(cluster & 1)) {
-      tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
-    }
-    cacheBuffer_.data[index] = tmp;
-    return true;
-  }
-  if (fatType_ == 16) {
-    lba = fatStartBlock_ + (cluster >> 8);
-  } else if (fatType_ == 32) {
-    lba = fatStartBlock_ + (cluster >> 7);
-  } else {
-    goto fail;
-  }
-  if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
-  // store entry
-  if (fatType_ == 16) {
-    cacheBuffer_.fat16[cluster & 0XFF] = value;
-  } else {
-    cacheBuffer_.fat32[cluster & 0X7F] = value;
-  }
-  // mirror second FAT
-  if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-// free a cluster chain
-bool SdVolume::freeChain(uint32_t cluster) {
-  uint32_t next;
-
-  // clear free cluster location
-  allocSearchStart_ = 2;
-
-  do {
-    if (!fatGet(cluster, &next)) goto fail;
-
-    // free cluster
-    if (!fatPut(cluster, 0)) goto fail;
-
-    cluster = next;
-  } while (!isEOC(cluster));
-
-  return true;
-
- fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-/** Volume free space in clusters.
- *
- * \return Count of free clusters for success or -1 if an error occurs.
- */
-int32_t SdVolume::freeClusterCount() {
-  uint32_t free = 0;
-  uint16_t n;
-  uint32_t todo = clusterCount_ + 2;
-
-  if (fatType_ == 16) {
-    n = 256;
-  } else if (fatType_ == 32) {
-    n = 128;
-  } else {
-    // put FAT12 here
-    return -1;
-  }
-
-  for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
-    if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
-    if (todo < n) n = todo;
-    if (fatType_ == 16) {
-      for (uint16_t i = 0; i < n; i++) {
-        if (cacheBuffer_.fat16[i] == 0) free++;
-      }
-    } else {
-      for (uint16_t i = 0; i < n; i++) {
-        if (cacheBuffer_.fat32[i] == 0) free++;
-      }
-    }
-  }
-  return free;
-}
-//------------------------------------------------------------------------------
-/** Initialize a FAT volume.
- *
- * \param[in] dev The SD card where the volume is located.
- *
- * \param[in] part The partition to be used.  Legal values for \a part are
- * 1-4 to use the corresponding partition on a device formatted with
- * a MBR, Master Boot Record, or zero if the device is formatted as
- * a super floppy with the FAT boot sector in block zero.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.  Reasons for
- * failure include not finding a valid partition, not finding a valid
- * FAT file system in the specified partition or an I/O error.
- */
-bool SdVolume::init(Sd2Card* dev, uint8_t part) {
-  uint32_t totalBlocks;
-  uint32_t volumeStartBlock = 0;
-  fat32_boot_t* fbs;
-
-  sdCard_ = dev;
-  fatType_ = 0;
-  allocSearchStart_ = 2;
-  cacheDirty_ = 0;  // cacheFlush() will write block if true
-  cacheMirrorBlock_ = 0;
-  cacheBlockNumber_ = 0XFFFFFFFF;
-
-  // if part == 0 assume super floppy with FAT boot sector in block zero
-  // if part > 0 assume mbr volume with partition table
-  if (part) {
-    if (part > 4)goto fail;
-    if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
-    part_t* p = &cacheBuffer_.mbr.part[part-1];
-    if ((p->boot & 0X7F) !=0  ||
-      p->totalSectors < 100 ||
-      p->firstSector == 0) {
-      // not a valid partition
-      goto fail;
-    }
-    volumeStartBlock = p->firstSector;
-  }
-  if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
-  fbs = &cacheBuffer_.fbs32;
-  if (fbs->bytesPerSector != 512 ||
-    fbs->fatCount == 0 ||
-    fbs->reservedSectorCount == 0 ||
-    fbs->sectorsPerCluster == 0) {
-       // not valid FAT volume
-      goto fail;
-  }
-  fatCount_ = fbs->fatCount;
-  blocksPerCluster_ = fbs->sectorsPerCluster;
-  // determine shift that is same as multiply by blocksPerCluster_
-  clusterSizeShift_ = 0;
-  while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
-    // error if not power of 2
-    if (clusterSizeShift_++ > 7) goto fail;
-  }
-  blocksPerFat_ = fbs->sectorsPerFat16 ?
-                    fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
-
-  fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
-
-  // count for FAT16 zero for FAT32
-  rootDirEntryCount_ = fbs->rootDirEntryCount;
-
-  // directory start for FAT16 dataStart for FAT32
-  rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
-
-  // data start for FAT16 and FAT32
-  dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512);
-
-  // total blocks for FAT16 or FAT32
-  totalBlocks = fbs->totalSectors16 ?
-                           fbs->totalSectors16 : fbs->totalSectors32;
-  // total data blocks
-  clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
-
-  // divide by cluster size to get cluster count
-  clusterCount_ >>= clusterSizeShift_;
-
-  // FAT type is determined by cluster count
-  if (clusterCount_ < 4085) {
-    fatType_ = 12;
-    if (!FAT12_SUPPORT) goto fail;
-  } else if (clusterCount_ < 65525) {
-    fatType_ = 16;
-  } else {
-    rootDirStart_ = fbs->fat32RootCluster;
-    fatType_ = 32;
-  }
-  return true;
-
- fail:
-  return false;
-}
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "Marlin.h"
+#ifdef SDSUPPORT
+
+#include "SdVolume.h"
+//------------------------------------------------------------------------------
+#if !USE_MULTIPLE_CARDS
+// raw block cache
+uint32_t SdVolume::cacheBlockNumber_;  // current block number
+cache_t  SdVolume::cacheBuffer_;       // 512 byte cache for Sd2Card
+Sd2Card* SdVolume::sdCard_;            // pointer to SD card object
+bool     SdVolume::cacheDirty_;        // cacheFlush() will write block if true
+uint32_t SdVolume::cacheMirrorBlock_;  // mirror  block for second FAT
+#endif  // USE_MULTIPLE_CARDS
+//------------------------------------------------------------------------------
+// find a contiguous group of clusters
+bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
+  // start of group
+  uint32_t bgnCluster;
+  // end of group
+  uint32_t endCluster;
+  // last cluster of FAT
+  uint32_t fatEnd = clusterCount_ + 1;
+
+  // flag to save place to start next search
+  bool setStart;
+
+  // set search start cluster
+  if (*curCluster) {
+    // try to make file contiguous
+    bgnCluster = *curCluster + 1;
+
+    // don't save new start location
+    setStart = false;
+  } else {
+    // start at likely place for free cluster
+    bgnCluster = allocSearchStart_;
+
+    // save next search start if one cluster
+    setStart = count == 1;
+  }
+  // end of group
+  endCluster = bgnCluster;
+
+  // search the FAT for free clusters
+  for (uint32_t n = 0;; n++, endCluster++) {
+    // can't find space checked all clusters
+    if (n >= clusterCount_) goto fail;
+
+    // past end - start from beginning of FAT
+    if (endCluster > fatEnd) {
+      bgnCluster = endCluster = 2;
+    }
+    uint32_t f;
+    if (!fatGet(endCluster, &f)) goto fail;
+
+    if (f != 0) {
+      // cluster in use try next cluster as bgnCluster
+      bgnCluster = endCluster + 1;
+    } else if ((endCluster - bgnCluster + 1) == count) {
+      // done - found space
+      break;
+    }
+  }
+  // mark end of chain
+  if (!fatPutEOC(endCluster)) goto fail;
+
+  // link clusters
+  while (endCluster > bgnCluster) {
+    if (!fatPut(endCluster - 1, endCluster)) goto fail;
+    endCluster--;
+  }
+  if (*curCluster != 0) {
+    // connect chains
+    if (!fatPut(*curCluster, bgnCluster)) goto fail;
+  }
+  // return first cluster number to caller
+  *curCluster = bgnCluster;
+
+  // remember possible next free cluster
+  if (setStart) allocSearchStart_ = bgnCluster + 1;
+
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool SdVolume::cacheFlush() {
+  if (cacheDirty_) {
+    if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
+      goto fail;
+    }
+    // mirror FAT tables
+    if (cacheMirrorBlock_) {
+      if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
+        goto fail;
+      }
+      cacheMirrorBlock_ = 0;
+    }
+    cacheDirty_ = 0;
+  }
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
+  if (cacheBlockNumber_ != blockNumber) {
+    if (!cacheFlush()) goto fail;
+    if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
+    cacheBlockNumber_ = blockNumber;
+  }
+  if (dirty) cacheDirty_ = true;
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+// return the size in bytes of a cluster chain
+bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
+  uint32_t s = 0;
+  do {
+    if (!fatGet(cluster, &cluster)) goto fail;
+    s += 512UL << clusterSizeShift_;
+  } while (!isEOC(cluster));
+  *size = s;
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+// Fetch a FAT entry
+bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
+  uint32_t lba;
+  if (cluster > (clusterCount_ + 1)) goto fail;
+  if (FAT12_SUPPORT && fatType_ == 12) {
+    uint16_t index = cluster;
+    index += index >> 1;
+    lba = fatStartBlock_ + (index >> 9);
+    if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
+    index &= 0X1FF;
+    uint16_t tmp = cacheBuffer_.data[index];
+    index++;
+    if (index == 512) {
+      if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
+      index = 0;
+    }
+    tmp |= cacheBuffer_.data[index] << 8;
+    *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
+    return true;
+  }
+  if (fatType_ == 16) {
+    lba = fatStartBlock_ + (cluster >> 8);
+  } else if (fatType_ == 32) {
+    lba = fatStartBlock_ + (cluster >> 7);
+  } else {
+    goto fail;
+  }
+  if (lba != cacheBlockNumber_) {
+    if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
+  }
+  if (fatType_ == 16) {
+    *value = cacheBuffer_.fat16[cluster & 0XFF];
+  } else {
+    *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
+  }
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+// Store a FAT entry
+bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
+  uint32_t lba;
+  // error if reserved cluster
+  if (cluster < 2) goto fail;
+
+  // error if not in FAT
+  if (cluster > (clusterCount_ + 1)) goto fail;
+
+  if (FAT12_SUPPORT && fatType_ == 12) {
+    uint16_t index = cluster;
+    index += index >> 1;
+    lba = fatStartBlock_ + (index >> 9);
+    if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
+    // mirror second FAT
+    if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
+    index &= 0X1FF;
+    uint8_t tmp = value;
+    if (cluster & 1) {
+      tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
+    }
+    cacheBuffer_.data[index] = tmp;
+    index++;
+    if (index == 512) {
+      lba++;
+      index = 0;
+      if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
+      // mirror second FAT
+      if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
+    }
+    tmp = value >> 4;
+    if (!(cluster & 1)) {
+      tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
+    }
+    cacheBuffer_.data[index] = tmp;
+    return true;
+  }
+  if (fatType_ == 16) {
+    lba = fatStartBlock_ + (cluster >> 8);
+  } else if (fatType_ == 32) {
+    lba = fatStartBlock_ + (cluster >> 7);
+  } else {
+    goto fail;
+  }
+  if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
+  // store entry
+  if (fatType_ == 16) {
+    cacheBuffer_.fat16[cluster & 0XFF] = value;
+  } else {
+    cacheBuffer_.fat32[cluster & 0X7F] = value;
+  }
+  // mirror second FAT
+  if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+// free a cluster chain
+bool SdVolume::freeChain(uint32_t cluster) {
+  uint32_t next;
+
+  // clear free cluster location
+  allocSearchStart_ = 2;
+
+  do {
+    if (!fatGet(cluster, &next)) goto fail;
+
+    // free cluster
+    if (!fatPut(cluster, 0)) goto fail;
+
+    cluster = next;
+  } while (!isEOC(cluster));
+
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+/** Volume free space in clusters.
+ *
+ * \return Count of free clusters for success or -1 if an error occurs.
+ */
+int32_t SdVolume::freeClusterCount() {
+  uint32_t free = 0;
+  uint16_t n;
+  uint32_t todo = clusterCount_ + 2;
+
+  if (fatType_ == 16) {
+    n = 256;
+  } else if (fatType_ == 32) {
+    n = 128;
+  } else {
+    // put FAT12 here
+    return -1;
+  }
+
+  for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
+    if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
+    if (todo < n) n = todo;
+    if (fatType_ == 16) {
+      for (uint16_t i = 0; i < n; i++) {
+        if (cacheBuffer_.fat16[i] == 0) free++;
+      }
+    } else {
+      for (uint16_t i = 0; i < n; i++) {
+        if (cacheBuffer_.fat32[i] == 0) free++;
+      }
+    }
+  }
+  return free;
+}
+//------------------------------------------------------------------------------
+/** Initialize a FAT volume.
+ *
+ * \param[in] dev The SD card where the volume is located.
+ *
+ * \param[in] part The partition to be used.  Legal values for \a part are
+ * 1-4 to use the corresponding partition on a device formatted with
+ * a MBR, Master Boot Record, or zero if the device is formatted as
+ * a super floppy with the FAT boot sector in block zero.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.  Reasons for
+ * failure include not finding a valid partition, not finding a valid
+ * FAT file system in the specified partition or an I/O error.
+ */
+bool SdVolume::init(Sd2Card* dev, uint8_t part) {
+  uint32_t totalBlocks;
+  uint32_t volumeStartBlock = 0;
+  fat32_boot_t* fbs;
+
+  sdCard_ = dev;
+  fatType_ = 0;
+  allocSearchStart_ = 2;
+  cacheDirty_ = 0;  // cacheFlush() will write block if true
+  cacheMirrorBlock_ = 0;
+  cacheBlockNumber_ = 0XFFFFFFFF;
+
+  // if part == 0 assume super floppy with FAT boot sector in block zero
+  // if part > 0 assume mbr volume with partition table
+  if (part) {
+    if (part > 4)goto fail;
+    if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
+    part_t* p = &cacheBuffer_.mbr.part[part-1];
+    if ((p->boot & 0X7F) !=0  ||
+      p->totalSectors < 100 ||
+      p->firstSector == 0) {
+      // not a valid partition
+      goto fail;
+    }
+    volumeStartBlock = p->firstSector;
+  }
+  if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
+  fbs = &cacheBuffer_.fbs32;
+  if (fbs->bytesPerSector != 512 ||
+    fbs->fatCount == 0 ||
+    fbs->reservedSectorCount == 0 ||
+    fbs->sectorsPerCluster == 0) {
+       // not valid FAT volume
+      goto fail;
+  }
+  fatCount_ = fbs->fatCount;
+  blocksPerCluster_ = fbs->sectorsPerCluster;
+  // determine shift that is same as multiply by blocksPerCluster_
+  clusterSizeShift_ = 0;
+  while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
+    // error if not power of 2
+    if (clusterSizeShift_++ > 7) goto fail;
+  }
+  blocksPerFat_ = fbs->sectorsPerFat16 ?
+                    fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
+
+  fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
+
+  // count for FAT16 zero for FAT32
+  rootDirEntryCount_ = fbs->rootDirEntryCount;
+
+  // directory start for FAT16 dataStart for FAT32
+  rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
+
+  // data start for FAT16 and FAT32
+  dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512);
+
+  // total blocks for FAT16 or FAT32
+  totalBlocks = fbs->totalSectors16 ?
+                           fbs->totalSectors16 : fbs->totalSectors32;
+  // total data blocks
+  clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
+
+  // divide by cluster size to get cluster count
+  clusterCount_ >>= clusterSizeShift_;
+
+  // FAT type is determined by cluster count
+  if (clusterCount_ < 4085) {
+    fatType_ = 12;
+    if (!FAT12_SUPPORT) goto fail;
+  } else if (clusterCount_ < 65525) {
+    fatType_ = 16;
+  } else {
+    rootDirStart_ = fbs->fat32RootCluster;
+    fatType_ = 32;
+  }
+  return true;
+
+ fail:
+  return false;
+}
 #endif

+ 6 - 5
Firmware/boards.h

@@ -3,13 +3,14 @@
 
 #define BOARD_UNKNOWN -1
 
+#define BOARD_RAMBO             100  // Rambo - 100 (orig 301)
 
-#define BOARD_RAMBO             301  // Rambo
-#define BOARD_RAMBO_MINI_1_3    302  // Rambo-mini 1.3
-#define BOARD_RAMBO_MINI_1_0    102  // Rambo-mini 1.0
+#define BOARD_RAMBO_MINI_1_0    200  // Rambo-mini 1.0 - 200 (orig 102)
+#define BOARD_RAMBO_MINI_1_3    203  // Rambo-mini 1.3 - 203 (orig 302)
 
-
-#define BOARD_99                99   // This is in pins.h but...?
+#define BOARD_EISNY_0_3a         303  // EINY 0.3a - 303 (orig 300)
+#define BOARD_EINSY_0_4a         304  // EINY 0.4a - 304 (orig 299)
+#define BOARD_EINSY_0_5a         305  // EINY 0.5a - 305 (orig 298)
 
 #define MB(board) (MOTHERBOARD==BOARD_##board)
 #define IS_RAMPS (MB(RAMPS_OLD) || MB(RAMPS_13_EFB) || MB(RAMPS_13_EEB) || MB(RAMPS_13_EFF) || MB(RAMPS_13_EEF))

+ 25 - 3
Firmware/cardreader.cpp

@@ -81,7 +81,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
         if(lsAction==LS_SerialPrint)
         {
           SERIAL_ECHO_START;
-          SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
+          SERIAL_ECHORPGM(MSG_SD_CANT_ENTER_SUBDIR);
           SERIAL_ECHOLN(lfilename);
         }
       }
@@ -233,6 +233,15 @@ void CardReader::openLogFile(char* name)
   openFile(name, false);
 }
 
+void CardReader::getDirName(char* name, uint8_t level)
+{	
+		workDirParents[level].getFilename(name);
+}
+
+uint16_t CardReader::getWorkDirDepth() {
+	return workDirDepth;
+}
+
 void CardReader::getAbsFilename(char *t)
 {
   uint8_t cnt=0;
@@ -262,7 +271,7 @@ void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/)
        SERIAL_ERROR_START;
        SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
        SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
-       kill();
+       kill("", 1);
        return;
      }
      
@@ -501,6 +510,19 @@ void CardReader::write_command(char *buf)
   }
 }
 
+#define CHUNK_SIZE 64
+
+void CardReader::write_command_no_newline(char *buf)
+{
+  file.write(buf, CHUNK_SIZE);
+  if (file.writeError)
+  {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLNRPGM(MSG_SD_ERR_WRITE_TO_FILE);
+    MYSERIAL.println("An error while writing to the SD Card.");
+  }
+}
+
 
 void CardReader::checkautostart(bool force)
 {
@@ -622,7 +644,7 @@ void CardReader::updir()
   {
     --workDirDepth;
     workDir = workDirParents[0];
-    int d;
+	int d;
     for (int d = 0; d < workDirDepth; d++)
       workDirParents[d] = workDirParents[d+1];
   }

+ 6 - 0
Firmware/cardreader.h

@@ -14,6 +14,7 @@ public:
   
   void initsd();
   void write_command(char *buf);
+  void write_command_no_newline(char *buf);
   //files auto[0-9].g on the sd card are performed in a row
   //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset
 
@@ -32,6 +33,8 @@ public:
   uint16_t getnrfilenames();
   
   void getAbsFilename(char *t);
+  void getDirName(char* name, uint8_t level);
+  uint16_t getWorkDirDepth();
   
 
   void ls();
@@ -46,7 +49,10 @@ public:
   FORCE_INLINE void setIndex(long index) {sdpos = index;file.seekSet(index);};
   FORCE_INLINE uint8_t percentDone(){if(!isFileOpen()) return 0; if(filesize) return sdpos/((filesize+99)/100); else return 0;};
   FORCE_INLINE char* getWorkDirName(){workDir.getFilename(filename);return filename;};
+  FORCE_INLINE uint32_t get_sdpos() { if (!isFileOpen()) return 0; else return(sdpos); };
 
+  bool ToshibaFlashAir_isEnabled() const { return card.getFlashAirCompatible(); }
+  void ToshibaFlashAir_enable(bool enable) { card.setFlashAirCompatible(enable); }
   bool ToshibaFlashAir_GetIP(uint8_t *ip);
 
 public:

+ 680 - 0
Firmware/cmdqueue.cpp

@@ -0,0 +1,680 @@
+#include "cmdqueue.h"
+#include "cardreader.h"
+#include "ultralcd.h"
+
+extern bool Stopped;
+
+// Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT.
+char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
+// Head of the circular buffer, where to read.
+int bufindr = 0;
+// Tail of the buffer, where to write.
+int bufindw = 0;
+// Number of lines in cmdbuffer.
+int buflen = 0;
+// Flag for processing the current command inside the main Arduino loop().
+// If a new command was pushed to the front of a command buffer while
+// processing another command, this replaces the command on the top.
+// Therefore don't remove the command from the queue in the loop() function.
+bool cmdbuffer_front_already_processed = false;
+
+int serial_count = 0;  //index of character read from serial line
+boolean comment_mode = false;
+char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
+
+unsigned long TimeSent = millis();
+unsigned long TimeNow = millis();
+
+long gcode_N = 0;
+long gcode_LastN = 0;
+long Stopped_gcode_LastN = 0;
+
+uint32_t sdpos_atomic = 0;
+
+
+// Pop the currently processed command from the queue.
+// It is expected, that there is at least one command in the queue.
+bool cmdqueue_pop_front()
+{
+    if (buflen > 0) {
+#ifdef CMDBUFFER_DEBUG
+        SERIAL_ECHOPGM("Dequeing ");
+        SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE);
+        SERIAL_ECHOLNPGM("");
+        SERIAL_ECHOPGM("Old indices: buflen ");
+        SERIAL_ECHO(buflen);
+        SERIAL_ECHOPGM(", bufindr ");
+        SERIAL_ECHO(bufindr);
+        SERIAL_ECHOPGM(", bufindw ");
+        SERIAL_ECHO(bufindw);
+        SERIAL_ECHOPGM(", serial_count ");
+        SERIAL_ECHO(serial_count);
+        SERIAL_ECHOPGM(", bufsize ");
+        SERIAL_ECHO(sizeof(cmdbuffer));
+        SERIAL_ECHOLNPGM("");
+#endif /* CMDBUFFER_DEBUG */
+        if (-- buflen == 0) {
+            // Empty buffer.
+            if (serial_count == 0)
+                // No serial communication is pending. Reset both pointers to zero.
+                bufindw = 0;
+            bufindr = bufindw;
+        } else {
+            // There is at least one ready line in the buffer.
+            // First skip the current command ID and iterate up to the end of the string.
+            for (bufindr += CMDHDRSIZE; cmdbuffer[bufindr] != 0; ++ bufindr) ;
+            // Second, skip the end of string null character and iterate until a nonzero command ID is found.
+            for (++ bufindr; bufindr < sizeof(cmdbuffer) && cmdbuffer[bufindr] == 0; ++ bufindr) ;
+            // If the end of the buffer was empty,
+            if (bufindr == sizeof(cmdbuffer)) {
+                // skip to the start and find the nonzero command.
+                for (bufindr = 0; cmdbuffer[bufindr] == 0; ++ bufindr) ;
+            }
+#ifdef CMDBUFFER_DEBUG
+            SERIAL_ECHOPGM("New indices: buflen ");
+            SERIAL_ECHO(buflen);
+            SERIAL_ECHOPGM(", bufindr ");
+            SERIAL_ECHO(bufindr);
+            SERIAL_ECHOPGM(", bufindw ");
+            SERIAL_ECHO(bufindw);
+            SERIAL_ECHOPGM(", serial_count ");
+            SERIAL_ECHO(serial_count);
+            SERIAL_ECHOPGM(" new command on the top: ");
+            SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE);
+            SERIAL_ECHOLNPGM("");
+#endif /* CMDBUFFER_DEBUG */
+        }
+        return true;
+    }
+    return false;
+}
+
+void cmdqueue_reset()
+{
+    bufindr = 0;
+    bufindw = 0;
+    buflen = 0;
+    cmdbuffer_front_already_processed = false;
+}
+
+// How long a string could be pushed to the front of the command queue?
+// If yes, adjust bufindr to the new position, where the new command could be enqued.
+// len_asked does not contain the zero terminator size.
+bool cmdqueue_could_enqueue_front(int len_asked)
+{
+    // MAX_CMD_SIZE has to accommodate the zero terminator.
+    if (len_asked >= MAX_CMD_SIZE)
+        return false;
+    // Remove the currently processed command from the queue.
+    if (! cmdbuffer_front_already_processed) {
+        cmdqueue_pop_front();
+        cmdbuffer_front_already_processed = true;
+    }
+    if (bufindr == bufindw && buflen > 0)
+        // Full buffer.
+        return false;
+    // Adjust the end of the write buffer based on whether a partial line is in the receive buffer.
+    int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw;
+    if (bufindw < bufindr) {
+        int bufindr_new = bufindr - len_asked - (1 + CMDHDRSIZE);
+        // Simple case. There is a contiguous space between the write buffer and the read buffer.
+        if (endw <= bufindr_new) {
+            bufindr = bufindr_new;
+            return true;
+        }
+    } else {
+        // Otherwise the free space is split between the start and end.
+        if (len_asked + (1 + CMDHDRSIZE) <= bufindr) {
+            // Could fit at the start.
+            bufindr -= len_asked + (1 + CMDHDRSIZE);
+            return true;
+        }
+        int bufindr_new = sizeof(cmdbuffer) - len_asked - (1 + CMDHDRSIZE);
+        if (endw <= bufindr_new) {
+            memset(cmdbuffer, 0, bufindr);
+            bufindr = bufindr_new;
+            return true;
+        }
+    }
+    return false;
+}
+
+// Could one enqueue a command of length len_asked into the buffer,
+// while leaving CMDBUFFER_RESERVE_FRONT at the start?
+// If yes, adjust bufindw to the new position, where the new command could be enqued.
+// len_asked does not contain the zero terminator size.
+// This function may update bufindw, therefore for the power panic to work, this function must be called
+// with the interrupts disabled!
+bool cmdqueue_could_enqueue_back(int len_asked, bool atomic_update)
+{
+    // MAX_CMD_SIZE has to accommodate the zero terminator.
+    if (len_asked >= MAX_CMD_SIZE)
+        return false;
+
+    if (bufindr == bufindw && buflen > 0)
+        // Full buffer.
+        return false;
+
+    if (serial_count > 0) {
+        // If there is some data stored starting at bufindw, len_asked is certainly smaller than
+        // the allocated data buffer. Try to reserve a new buffer and to move the already received
+        // serial data.
+        // How much memory to reserve for the commands pushed to the front?
+        // End of the queue, when pushing to the end.
+        int endw = bufindw + len_asked + (1 + CMDHDRSIZE);
+        if (bufindw < bufindr)
+            // Simple case. There is a contiguous space between the write buffer and the read buffer.
+            return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
+        // Otherwise the free space is split between the start and end.
+        if (// Could one fit to the end, including the reserve?
+            endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
+            // Could one fit to the end, and the reserve to the start?
+            (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
+            return true;
+        // Could one fit both to the start?
+        if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
+            // Mark the rest of the buffer as used.
+            memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
+            // and point to the start.
+            // Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
+            if (atomic_update)
+                cli();
+            bufindw = 0;
+            if (atomic_update)
+                sei();
+            return true;
+        }
+    } else {
+        // How much memory to reserve for the commands pushed to the front?
+        // End of the queue, when pushing to the end.
+        int endw = bufindw + len_asked + (1 + CMDHDRSIZE);
+        if (bufindw < bufindr)
+            // Simple case. There is a contiguous space between the write buffer and the read buffer.
+            return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
+        // Otherwise the free space is split between the start and end.
+        if (// Could one fit to the end, including the reserve?
+            endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
+            // Could one fit to the end, and the reserve to the start?
+            (endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
+            return true;
+        // Could one fit both to the start?
+        if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
+            // Mark the rest of the buffer as used.
+            memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
+            // and point to the start.
+            // Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
+            if (atomic_update)
+                cli();
+            bufindw = 0;
+            if (atomic_update)
+                sei();
+            return true;
+        }
+    }
+    return false;
+}
+
+#ifdef CMDBUFFER_DEBUG
+void cmdqueue_dump_to_serial_single_line(int nr, const char *p)
+{
+    SERIAL_ECHOPGM("Entry nr: ");
+    SERIAL_ECHO(nr);
+    SERIAL_ECHOPGM(", type: ");
+    SERIAL_ECHO(int(*p));
+    SERIAL_ECHOPGM(", cmd: ");
+    SERIAL_ECHO(p+1);  
+    SERIAL_ECHOLNPGM("");
+}
+
+void cmdqueue_dump_to_serial()
+{
+    if (buflen == 0) {
+        SERIAL_ECHOLNPGM("The command buffer is empty.");
+    } else {
+        SERIAL_ECHOPGM("Content of the buffer: entries ");
+        SERIAL_ECHO(buflen);
+        SERIAL_ECHOPGM(", indr ");
+        SERIAL_ECHO(bufindr);
+        SERIAL_ECHOPGM(", indw ");
+        SERIAL_ECHO(bufindw);
+        SERIAL_ECHOLNPGM("");
+        int nr = 0;
+        if (bufindr < bufindw) {
+            for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + bufindw; ++ nr) {
+                cmdqueue_dump_to_serial_single_line(nr, p);
+                // Skip the command.
+                for (++p; *p != 0; ++ p);
+                // Skip the gaps.
+                for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
+            }
+        } else {
+            for (const char *p = cmdbuffer + bufindr; p < cmdbuffer + sizeof(cmdbuffer); ++ nr) {
+                cmdqueue_dump_to_serial_single_line(nr, p);
+                // Skip the command.
+                for (++p; *p != 0; ++ p);
+                // Skip the gaps.
+                for (++p; p < cmdbuffer + sizeof(cmdbuffer) && *p == 0; ++ p);
+            }
+            for (const char *p = cmdbuffer; p < cmdbuffer + bufindw; ++ nr) {
+                cmdqueue_dump_to_serial_single_line(nr, p);
+                // Skip the command.
+                for (++p; *p != 0; ++ p);
+                // Skip the gaps.
+                for (++p; p < cmdbuffer + bufindw && *p == 0; ++ p);
+            }
+        }
+        SERIAL_ECHOLNPGM("End of the buffer.");
+    }
+}
+#endif /* CMDBUFFER_DEBUG */
+
+//adds an command to the main command buffer
+//thats really done in a non-safe way.
+//needs overworking someday
+// Currently the maximum length of a command piped through this function is around 20 characters
+void enquecommand(const char *cmd, bool from_progmem)
+{
+    int len = from_progmem ? strlen_P(cmd) : strlen(cmd);
+    // Does cmd fit the queue while leaving sufficient space at the front for the chained commands?
+    // If it fits, it may move bufindw, so it points to a contiguous buffer, which fits cmd.
+    if (cmdqueue_could_enqueue_back(len)) {
+        // This is dangerous if a mixing of serial and this happens
+        // This may easily be tested: If serial_count > 0, we have a problem.
+        cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_UI;
+        if (from_progmem)
+            strcpy_P(cmdbuffer + bufindw + CMDHDRSIZE, cmd);
+        else
+            strcpy(cmdbuffer + bufindw + CMDHDRSIZE, cmd);
+        SERIAL_ECHO_START;
+        SERIAL_ECHORPGM(MSG_Enqueing);
+        SERIAL_ECHO(cmdbuffer + bufindw + CMDHDRSIZE);
+        SERIAL_ECHOLNPGM("\"");
+        bufindw += len + (CMDHDRSIZE + 1);
+        if (bufindw == sizeof(cmdbuffer))
+            bufindw = 0;
+        ++ buflen;
+#ifdef CMDBUFFER_DEBUG
+        cmdqueue_dump_to_serial();
+#endif /* CMDBUFFER_DEBUG */
+    } else {
+        SERIAL_ERROR_START;
+        SERIAL_ECHORPGM(MSG_Enqueing);
+        if (from_progmem)
+            SERIAL_PROTOCOLRPGM(cmd);
+        else
+            SERIAL_ECHO(cmd);
+        SERIAL_ECHOLNPGM("\" failed: Buffer full!");
+#ifdef CMDBUFFER_DEBUG
+        cmdqueue_dump_to_serial();
+#endif /* CMDBUFFER_DEBUG */
+    }
+}
+
+bool cmd_buffer_empty()
+{
+	return (buflen == 0);
+}
+
+void enquecommand_front(const char *cmd, bool from_progmem)
+{
+    int len = from_progmem ? strlen_P(cmd) : strlen(cmd);
+    // Does cmd fit the queue? This call shall move bufindr, so the command may be copied.
+    if (cmdqueue_could_enqueue_front(len)) {
+        cmdbuffer[bufindr] = CMDBUFFER_CURRENT_TYPE_UI;
+        if (from_progmem)
+            strcpy_P(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
+        else
+            strcpy(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
+        ++ buflen;
+        SERIAL_ECHO_START;
+        SERIAL_ECHOPGM("Enqueing to the front: \"");
+        SERIAL_ECHO(cmdbuffer + bufindr + CMDHDRSIZE);
+        SERIAL_ECHOLNPGM("\"");
+#ifdef CMDBUFFER_DEBUG
+        cmdqueue_dump_to_serial();
+#endif /* CMDBUFFER_DEBUG */
+    } else {
+        SERIAL_ERROR_START;
+        SERIAL_ECHOPGM("Enqueing to the front: \"");
+        if (from_progmem)
+            SERIAL_PROTOCOLRPGM(cmd);
+        else
+            SERIAL_ECHO(cmd);
+        SERIAL_ECHOLNPGM("\" failed: Buffer full!");
+#ifdef CMDBUFFER_DEBUG
+        cmdqueue_dump_to_serial();
+#endif /* CMDBUFFER_DEBUG */
+    }
+}
+
+// Mark the command at the top of the command queue as new.
+// Therefore it will not be removed from the queue.
+void repeatcommand_front()
+{
+    cmdbuffer_front_already_processed = true;
+} 
+
+bool is_buffer_empty()
+{
+    if (buflen == 0) return true;
+    else return false;
+}
+
+void get_command()
+{
+    // Test and reserve space for the new command string.
+    if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1, true))
+      return;
+    
+    bool rx_buffer_full = false; //flag that serial rx buffer is full
+
+  while (MYSERIAL.available() > 0) {
+      if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size
+          SERIAL_ECHOLNPGM("Full RX Buffer");   //if buffer was full, there is danger that reading of last gcode will not be completed
+          rx_buffer_full = true;                //sets flag that buffer was full    
+      }
+    char serial_char = MYSERIAL.read();
+    if (selectedSerialPort == 1)
+    {
+        selectedSerialPort = 0; 
+        MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode
+        selectedSerialPort = 1; 
+    } 
+      TimeSent = millis();
+      TimeNow = millis();
+
+    if (serial_char < 0)
+        // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names
+        // and Marlin does not support such file names anyway.
+        // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading
+        // to a hang-up of the print process from an SD card.
+        continue;
+    if(serial_char == '\n' ||
+       serial_char == '\r' ||
+       (serial_char == ':' && comment_mode == false) ||
+       serial_count >= (MAX_CMD_SIZE - 1) )
+    {
+      if(!serial_count) { //if empty line
+        comment_mode = false; //for new command
+        return;
+      }
+      cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
+      if(!comment_mode){
+        comment_mode = false; //for new command
+        if ((strchr_pointer = strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA")) == NULL && (strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'N')) != NULL) {
+            if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'N')) != NULL)
+            {
+            // Line number met. When sending a G-code over a serial line, each line may be stamped with its index,
+            // and Marlin tests, whether the successive lines are stamped with an increasing line number ID.
+            gcode_N = (strtol(strchr_pointer+1, NULL, 10));
+            if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) {
+                // M110 - set current line number.
+                // Line numbers not sent in succession.
+                SERIAL_ERROR_START;
+                SERIAL_ERRORRPGM(MSG_ERR_LINE_NO);
+                SERIAL_ERRORLN(gcode_LastN);
+                //Serial.println(gcode_N);
+                FlushSerialRequestResend();
+                serial_count = 0;
+                return;
+            }
+
+            if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL)
+            {
+                byte checksum = 0;
+                char *p = cmdbuffer+bufindw+CMDHDRSIZE;
+                while (p != strchr_pointer)
+                    checksum = checksum^(*p++);
+                if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) {
+                SERIAL_ERROR_START;
+                SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH);
+                SERIAL_ERRORLN(gcode_LastN);
+                FlushSerialRequestResend();
+                serial_count = 0;
+                return;
+                }
+                // If no errors, remove the checksum and continue parsing.
+                *strchr_pointer = 0;
+            }
+            else
+            {
+                SERIAL_ERROR_START;
+                SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM);
+                SERIAL_ERRORLN(gcode_LastN);
+                FlushSerialRequestResend();
+                serial_count = 0;
+                return;
+            }
+
+            gcode_LastN = gcode_N;
+            //if no errors, continue parsing
+            } // end of 'N' command
+        }
+        else  // if we don't receive 'N' but still see '*'
+        {
+          if((strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL))
+          {
+            SERIAL_ERROR_START;
+            SERIAL_ERRORRPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
+            SERIAL_ERRORLN(gcode_LastN);
+            serial_count = 0;
+            return;
+          }
+        } // end of '*' command
+        if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) {
+              if (! IS_SD_PRINTING) {
+                      usb_printing_counter = 10;
+                      is_usb_printing = true;
+              }
+            if (Stopped == true) {
+                int gcode = strtol(strchr_pointer+1, NULL, 10);
+                if (gcode >= 0 && gcode <= 3) {
+                    SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
+                    LCD_MESSAGERPGM(MSG_STOPPED);
+                }
+            }
+        } // end of 'G' command
+
+        //If command was e-stop process now
+        if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0)
+          kill("", 2);
+        
+        // Store the current line into buffer, move to the next line.
+        cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_USB;
+#ifdef CMDBUFFER_DEBUG
+        SERIAL_ECHO_START;
+        SERIAL_ECHOPGM("Storing a command line to buffer: ");
+        SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE);
+        SERIAL_ECHOLNPGM("");
+#endif /* CMDBUFFER_DEBUG */
+        bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
+        if (bufindw == sizeof(cmdbuffer))
+            bufindw = 0;
+        ++ buflen;
+#ifdef CMDBUFFER_DEBUG
+        SERIAL_ECHOPGM("Number of commands in the buffer: ");
+        SERIAL_ECHO(buflen);
+        SERIAL_ECHOLNPGM("");
+#endif /* CMDBUFFER_DEBUG */
+      } // end of 'not comment mode'
+      serial_count = 0; //clear buffer
+      // Don't call cmdqueue_could_enqueue_back if there are no characters waiting
+      // in the queue, as this function will reserve the memory.
+      if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
+          return;
+    } // end of "end of line" processing
+    else {
+      // Not an "end of line" symbol. Store the new character into a buffer.
+      if(serial_char == ';') comment_mode = true;
+      if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
+    }
+  } // end of serial line processing loop
+
+    if(farm_mode){
+        TimeNow = millis();
+        if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) {
+            cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0;
+            
+            bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
+            if (bufindw == sizeof(cmdbuffer))
+                bufindw = 0;
+            ++ buflen;
+            
+            serial_count = 0;
+            
+            SERIAL_ECHOPGM("TIMEOUT:");
+            //memset(cmdbuffer, 0 , sizeof(cmdbuffer));
+            return;
+        }
+    }
+
+    //add comment
+    if (rx_buffer_full == true && serial_count > 0) {   //if rx buffer was full and string was not properly terminated
+        rx_buffer_full = false;
+        bufindw = bufindw - serial_count;               //adjust tail of the buffer to prepare buffer for writing new command
+        serial_count = 0;
+    }
+
+  #ifdef SDSUPPORT
+  if(!card.sdprinting || serial_count!=0){
+    // If there is a half filled buffer from serial line, wait until return before
+    // continuing with the serial line.
+     return;
+  }
+
+  //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible
+  // if it occurs, stop_buffering is triggered and the buffer is ran dry.
+  // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing
+
+  static bool stop_buffering=false;
+  if(buflen==0) stop_buffering=false;
+  union {
+    struct {
+        char lo;
+        char hi;
+    } lohi;
+    uint16_t value;
+  } sd_count;
+  sd_count.value = 0;
+  // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer.
+  while( !card.eof() && !stop_buffering) {
+    int16_t n=card.get();
+    char serial_char = (char)n;
+    if(serial_char == '\n' ||
+       serial_char == '\r' ||
+       ((serial_char == '#' || serial_char == ':') && comment_mode == false) ||
+       serial_count >= (MAX_CMD_SIZE - 1) || n==-1)
+    {
+      if(card.eof()){
+        SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED);
+        stoptime=millis();
+        char time[30];
+        unsigned long t=(stoptime-starttime-pause_time)/1000;
+        pause_time = 0;
+        int hours, minutes;
+        minutes=(t/60)%60;
+        hours=t/60/60;
+        save_statistics(total_filament_used, t);
+        sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
+        SERIAL_ECHO_START;
+        SERIAL_ECHOLN(time);
+        lcd_setstatus(time);
+        card.printingHasFinished();
+        card.checkautostart(true);
+
+        if (farm_mode)
+        {
+            prusa_statistics(6);
+            lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM;
+        }
+
+      }
+      if(serial_char=='#')
+        stop_buffering=true;
+
+      if(!serial_count)
+      {
+        // This is either an empty line, or a line with just a comment.
+        // Continue to the following line, and continue accumulating the number of bytes
+        // read from the sdcard into sd_count, 
+        // so that the lenght of the already read empty lines and comments will be added
+        // to the following non-empty line. 
+        comment_mode = false;
+        continue; //if empty line
+      }
+      // The new command buffer could be updated non-atomically, because it is not yet considered
+      // to be inside the active queue.
+      sd_count.value = (card.get_sdpos()+1) - sdpos_atomic;
+      cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD;
+      cmdbuffer[bufindw+1] = sd_count.lohi.lo;
+      cmdbuffer[bufindw+2] = sd_count.lohi.hi;
+      cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
+      // Calculate the length before disabling the interrupts.
+      uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
+
+//      SERIAL_ECHOPGM("SD cmd(");
+//      MYSERIAL.print(sd_count.value, DEC);
+//      SERIAL_ECHOPGM(") ");
+//      SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);
+//    SERIAL_ECHOPGM("cmdbuffer:");
+//    MYSERIAL.print(cmdbuffer);
+//    SERIAL_ECHOPGM("buflen:");
+//    MYSERIAL.print(buflen+1);
+      sd_count.value = 0;
+
+      cli();
+      ++ buflen;
+      bufindw += len;
+      sdpos_atomic = card.get_sdpos()+1;
+      if (bufindw == sizeof(cmdbuffer))
+          bufindw = 0;
+      sei();
+
+      comment_mode = false; //for new command
+      serial_count = 0; //clear buffer
+      // The following line will reserve buffer space if available.
+      if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
+          return;
+    }
+    else
+    {
+      if(serial_char == ';') comment_mode = true;
+      else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
+    }
+  }
+
+  #endif //SDSUPPORT
+}
+
+uint16_t cmdqueue_calc_sd_length()
+{
+    if (buflen == 0)
+        return 0;
+    union {
+        struct {
+            char lo;
+            char hi;
+        } lohi;
+        uint16_t value;
+    } sdlen_single;
+    uint16_t sdlen = 0;
+    for (int _buflen = buflen, _bufindr = bufindr;;) {
+        if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) {
+            sdlen_single.lohi.lo = cmdbuffer[_bufindr + 1];
+            sdlen_single.lohi.hi = cmdbuffer[_bufindr + 2];
+            sdlen += sdlen_single.value;
+        }
+        if (-- _buflen == 0)
+            break;
+        // First skip the current command ID and iterate up to the end of the string.
+        for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ;
+        // Second, skip the end of string null character and iterate until a nonzero command ID is found.
+        for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
+        // If the end of the buffer was empty,
+        if (_bufindr == sizeof(cmdbuffer)) {
+            // skip to the start and find the nonzero command.
+            for (_bufindr = 0; cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
+        }
+    }
+    return sdlen;
+}

+ 89 - 0
Firmware/cmdqueue.h

@@ -0,0 +1,89 @@
+#ifndef CMDQUEUE_H
+#define CMDQUEUE_H
+
+#include "Marlin.h"
+#include "language_all.h"
+
+
+// String circular buffer. Commands may be pushed to the buffer from both sides:
+// Chained commands will be pushed to the front, interactive (from LCD menu) 
+// and printing commands (from serial line or from SD card) are pushed to the tail.
+// First character of each entry indicates the type of the entry: 
+#define CMDBUFFER_CURRENT_TYPE_UNKNOWN  0
+// Command in cmdbuffer was sent over USB.
+#define CMDBUFFER_CURRENT_TYPE_USB      1
+// Command in cmdbuffer was read from SDCARD.
+#define CMDBUFFER_CURRENT_TYPE_SDCARD   2
+// Command in cmdbuffer was generated by the UI.
+#define CMDBUFFER_CURRENT_TYPE_UI       3
+// Command in cmdbuffer was generated by another G-code.
+#define CMDBUFFER_CURRENT_TYPE_CHAINED  4
+
+// How much space to reserve for the chained commands
+// of type CMDBUFFER_CURRENT_TYPE_CHAINED,
+// which are pushed to the front of the queue?
+// Maximum 5 commands of max length 20 + null terminator.
+#define CMDBUFFER_RESERVE_FRONT       (5*21)
+
+extern char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
+extern int bufindr;
+extern int bufindw;
+extern int buflen;
+extern bool cmdbuffer_front_already_processed;
+
+// Type of a command, which is to be executed right now.
+#define CMDBUFFER_CURRENT_TYPE   (cmdbuffer[bufindr])
+// String of a command, which is to be executed right now.
+#define CMDBUFFER_CURRENT_STRING (cmdbuffer+bufindr+CMDHDRSIZE)
+
+// Enable debugging of the command buffer.
+// Debugging information will be sent to serial line.
+//#define CMDBUFFER_DEBUG
+
+extern int serial_count;
+extern boolean comment_mode;
+extern char *strchr_pointer;
+
+extern unsigned long TimeSent;
+extern unsigned long TimeNow;
+
+extern long gcode_N;
+extern long gcode_LastN;
+extern long Stopped_gcode_LastN;
+
+extern bool cmdqueue_pop_front();
+extern void cmdqueue_reset();
+extern bool cmdqueue_could_enqueue_front(int len_asked);
+extern bool cmdqueue_could_enqueue_back(int len_asked, bool atomic_update = false);
+#ifdef CMDBUFFER_DEBUG
+extern void cmdqueue_dump_to_serial_single_line(int nr, const char *p);
+extern void cmdqueue_dump_to_serial();
+#endif /* CMDBUFFER_DEBUG */
+extern bool cmd_buffer_empty();
+extern void enquecommand(const char *cmd, bool from_progmem);
+extern void enquecommand_front(const char *cmd, bool from_progmem);
+extern void repeatcommand_front();
+extern bool is_buffer_empty();
+extern void get_command();
+extern uint16_t cmdqueue_calc_sd_length();
+
+// Return True if a character was found
+static inline bool    code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
+static inline bool    code_seen(const char *code) { return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
+static inline float   code_value()      { return strtod(strchr_pointer+1, NULL);}
+static inline long    code_value_long()    { return strtol(strchr_pointer+1, NULL, 10); }
+static inline int16_t code_value_short()   { return int16_t(strtol(strchr_pointer+1, NULL, 10)); };
+static inline uint8_t code_value_uint8()   { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); };
+
+static inline float code_value_float()
+{
+    char* e = strchr(strchr_pointer, 'E');
+    if (!e) return strtod(strchr_pointer + 1, NULL);
+    *e = 0;
+    float ret = strtod(strchr_pointer + 1, NULL);
+    *e = 'E';
+    return ret;
+}
+
+
+#endif //CMDQUEUE_H

+ 199 - 0
Firmware/fsensor.cpp

@@ -0,0 +1,199 @@
+#include "Marlin.h"
+
+#ifdef PAT9125
+
+#include "fsensor.h"
+#include "pat9125.h"
+#include "planner.h"
+#include "fastio.h"
+
+//#include "LiquidCrystal.h"
+//extern LiquidCrystal lcd;
+
+
+#define FSENSOR_ERR_MAX          5  //filament sensor max error count
+#define FSENSOR_INT_PIN         63  //filament sensor interrupt pin PK1
+#define FSENSOR_INT_PIN_MSK   0x02  //filament sensor interrupt pin mask (bit1)
+#define FSENSOR_CHUNK_LEN      560  //filament sensor chunk length in steps
+
+extern void stop_and_save_print_to_ram(float z_move, float e_move);
+extern void restore_print_from_ram_and_continue(float e_move);
+extern int8_t FSensorStateMenu;
+
+void fsensor_stop_and_save_print()
+{
+	stop_and_save_print_to_ram(0, 0); //XYZE - no change	
+}
+
+void fsensor_restore_print_and_continue()
+{
+	restore_print_from_ram_and_continue(0); //XYZ = orig, E - no change
+}
+
+//uint8_t fsensor_int_pin = FSENSOR_INT_PIN;
+uint8_t fsensor_int_pin_old = 0;
+int16_t fsensor_chunk_len = FSENSOR_CHUNK_LEN;
+bool fsensor_enabled = true;
+//bool fsensor_ignore_error = true;
+bool fsensor_M600 = false;
+uint8_t fsensor_err_cnt = 0;
+int16_t fsensor_st_cnt = 0;
+uint8_t fsensor_log = 1;
+
+
+bool fsensor_enable()
+{
+	puts_P(PSTR("fsensor_enable\n"));
+	int pat9125 = pat9125_init(PAT9125_XRES, PAT9125_YRES);
+    printf_P(PSTR("PAT9125_init:%d\n"), pat9125);
+	fsensor_enabled = pat9125?true:false;
+//	fsensor_ignore_error = true;
+	fsensor_M600 = false;
+	fsensor_err_cnt = 0;
+	eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, fsensor_enabled?0x01:0x00); 
+	FSensorStateMenu = fsensor_enabled?1:0;
+	return fsensor_enabled;
+}
+
+void fsensor_disable()
+{
+	puts_P(PSTR("fsensor_disable\n"));
+	fsensor_enabled = false;
+	eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, 0x00); 
+	FSensorStateMenu = 0;
+}
+
+void pciSetup(byte pin)
+{
+	*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
+	PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
+	PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group 
+}
+
+void fsensor_setup_interrupt()
+{
+//	uint8_t fsensor_int_pin = FSENSOR_INT_PIN;
+//	uint8_t fsensor_int_pcmsk = digitalPinToPCMSKbit(pin);
+//	uint8_t fsensor_int_pcicr = digitalPinToPCICRbit(pin);
+
+	pinMode(FSENSOR_INT_PIN, OUTPUT);
+	digitalWrite(FSENSOR_INT_PIN, LOW);
+	fsensor_int_pin_old = 0;
+
+	pciSetup(FSENSOR_INT_PIN);
+}
+
+ISR(PCINT2_vect)
+{
+//	return;
+	if (!((fsensor_int_pin_old ^ PINK) & FSENSOR_INT_PIN_MSK)) return;
+//	puts("PCINT2\n");
+//	return;
+
+	int st_cnt = fsensor_st_cnt;
+	fsensor_st_cnt = 0;
+	sei();
+/*	*digitalPinToPCMSK(fsensor_int_pin) &= ~bit(digitalPinToPCMSKbit(fsensor_int_pin));
+	digitalWrite(fsensor_int_pin, HIGH);
+	*digitalPinToPCMSK(fsensor_int_pin) |= bit(digitalPinToPCMSKbit(fsensor_int_pin));*/
+	pat9125_update_y();
+	if (st_cnt != 0)
+	{
+#ifdef DEBUG_FSENSOR_LOG
+		if (fsensor_log)
+		{
+			MYSERIAL.print("cnt=");
+			MYSERIAL.print(st_cnt, DEC);
+			MYSERIAL.print(" dy=");
+			MYSERIAL.print(pat9125_y, DEC);
+		}
+#endif //DEBUG_FSENSOR_LOG
+		if (st_cnt != 0)
+		{
+			if( (pat9125_y == 0) || ((pat9125_y > 0) && (st_cnt < 0)) || ((pat9125_y < 0) && (st_cnt > 0)))
+			{ //invalid movement
+				if (st_cnt > 0) //only positive movements
+					fsensor_err_cnt++;
+#ifdef DEBUG_FSENSOR_LOG
+			if (fsensor_log)
+			{
+				MYSERIAL.print("\tNG ! err=");
+				MYSERIAL.println(fsensor_err_cnt, DEC);
+			}
+#endif //DEBUG_FSENSOR_LOG
+			}
+			else
+			{ //propper movement
+				if (fsensor_err_cnt > 0)
+					fsensor_err_cnt--;
+//					fsensor_err_cnt = 0;
+#ifdef DEBUG_FSENSOR_LOG
+				if (fsensor_log)
+				{
+					MYSERIAL.print("\tOK    err=");
+					MYSERIAL.println(fsensor_err_cnt, DEC);
+				}
+#endif //DEBUG_FSENSOR_LOG
+			}
+		}
+		else
+		{ //no movement
+#ifdef DEBUG_FSENSOR_LOG
+		if (fsensor_log)
+			MYSERIAL.println("\tOK 0");
+#endif //DEBUG_FSENSOR_LOG
+		}
+	}
+	pat9125_y = 0;
+	return;
+}
+
+void fsensor_st_block_begin(block_t* bl)
+{
+	if (!fsensor_enabled) return;
+	if (((fsensor_st_cnt > 0) && (bl->direction_bits & 0x8)) || 
+		((fsensor_st_cnt < 0) && !(bl->direction_bits & 0x8)))
+	{
+		if (_READ(63)) _WRITE(63, LOW);
+		else _WRITE(63, HIGH);
+	}
+//		PINK |= FSENSOR_INT_PIN_MSK; //toggle pin
+//		_WRITE(fsensor_int_pin, LOW);
+}
+
+void fsensor_st_block_chunk(block_t* bl, int cnt)
+{
+	if (!fsensor_enabled) return;
+	fsensor_st_cnt += (bl->direction_bits & 0x8)?-cnt:cnt;
+	if ((fsensor_st_cnt >= fsensor_chunk_len) || (fsensor_st_cnt <= -fsensor_chunk_len))
+	{
+		if (_READ(63)) _WRITE(63, LOW);
+		else _WRITE(63, HIGH);
+	}
+//		PINK |= FSENSOR_INT_PIN_MSK; //toggle pin
+//		_WRITE(fsensor_int_pin, LOW);
+}
+
+void fsensor_update()
+{
+	if (!fsensor_enabled) return;
+	if (fsensor_err_cnt > FSENSOR_ERR_MAX)
+	{
+		MYSERIAL.println("fsensor_update (fsensor_err_cnt > FSENSOR_ERR_MAX)");
+/*		if (fsensor_ignore_error)
+		{
+			MYSERIAL.println("fsensor_update - error ignored)");
+			fsensor_ignore_error = false;
+		}
+		else*/
+		{
+			MYSERIAL.println("fsensor_update - ERROR!!!");
+			fsensor_stop_and_save_print();
+			enquecommand_front_P((PSTR("M600")));
+			fsensor_M600 = true;
+			fsensor_enabled = false;
+		}
+	}
+}
+
+#endif //PAT9125

+ 32 - 0
Firmware/fsensor.h

@@ -0,0 +1,32 @@
+#ifndef FSENSOR_H
+#define FSENSOR_H
+
+#include "planner.h"
+
+//save restore printing
+extern void fsensor_stop_and_save_print();
+extern void fsensor_restore_print_and_continue();
+
+//enable/disable
+extern bool fsensor_enable();
+extern void fsensor_disable();
+
+//update (perform M600 on filament runout)
+extern void fsensor_update();
+
+//setup pin-change interrupt
+extern void fsensor_setup_interrupt();
+
+//callbacks from stepper
+extern void fsensor_st_block_begin(block_t* bl);
+extern void fsensor_st_block_chunk(block_t* bl, int cnt);
+
+//minimum meassured chunk length in steps
+extern int16_t fsensor_chunk_len;
+//M600 in progress
+extern bool fsensor_M600;
+//enable/disable flag
+extern bool fsensor_enabled;
+
+
+#endif //FSENSOR_H

+ 224 - 27
Firmware/langtool.pl

@@ -4,53 +4,168 @@
 use strict;
 use warnings;
 
-my @langs = ("en","cz","it","es","pl");
+#my @langs = ("en","cz","it","es","de");
+my @langs = ("en","cz");
 
 sub parselang 
 {
     my ($filename) = @_;
  	open(my $fh, '<:encoding(UTF-8)', $filename)
+#	open(my $fh, '<', $filename)
   		or die "Could not open file '$filename' $!";
   	# Create a new hash reference.
 	my $out = {};
 	while (my $line = <$fh>) {
 		chomp $line;
-		next if (index($line, 'MSG') == -1);
-    	$line =~ /(?is)\#define\s*(\S*)\s*(.*)/;
-    	my $symbol = $1;
-    	my $v = $2;
+		next if (index($line, 'define') == -1 || index($line, 'MSG') == -1);
+		my $modifiers = {};
+    	my $symbol = '';
+    	my $value = '';
+		if (index($line, 'define(') == -1) {
+			# Extended definition, which specifies the string formatting.
+	    	$line =~ /(?is)define\s*(\S*)\s*(.*)/;
+	    	$symbol = "$1";
+	    	$value = $2;
+		} else {
+			$line =~ /(?is)define\((.*)\)\s*(\S*)\s*(.*)/;
+			my $options = $1;
+			foreach my $key_value (split /,/, $options) {
+				if ($key_value =~ /\s*(\S*)\s*=\s*(\S*)\s*/) {
+					${$modifiers}{$1} = $2;
+				}
+			}
+	    	$symbol = "$2";
+	    	$value = $3;
+		}
     	next if (! defined $symbol or length($symbol) == 0);
     	# Trim whitespaces from both sides
-    	$v =~ s/^\s+|\s+$//g;
+    	$value =~ s/^\s+|\s+$//g;
 		#$string =~ s/" MACHINE_NAME "/Prusa i3/;
-		$v =~ s/" FIRMWARE_URL "/https:\/\/github.com\/prusa3d\/Prusa-i3-Plus\//;
-		$v =~ s/" PROTOCOL_VERSION "/1.0/;
-		$v =~ s/" STRINGIFY\(EXTRUDERS\) "/1/;
-		$v =~ s/" MACHINE_UUID "/00000000-0000-0000-0000-000000000000/;
-		${$out}{$symbol} = $v;
+		$value =~ s/" FIRMWARE_URL "/https:\/\/github.com\/prusa3d\/Prusa-i3-Plus\//;
+		$value =~ s/" PROTOCOL_VERSION "/1.0/;
+		$value =~ s/" STRINGIFY\(EXTRUDERS\) "/1/;
+		$value =~ s/" MACHINE_UUID "/00000000-0000-0000-0000-000000000000/;
+		${$out}{$symbol} = { value=>$value, %$modifiers };
 	}
 	return $out;
 }
 
+sub pgm_is_whitespace
+{
+	my ($c) = @_;
+	if (! defined($c)) {
+		print "pgm_is_whitespace: undefined\n";
+		exit(1);
+	}
+    return $c == ord(' ') || $c == ord('\t') || $c == ord('\r') || $c == ord('\n');
+}
+
+sub pgm_is_interpunction
+{
+	my ($c) = @_;
+    return $c == ord('.') || $c == ord(',') || $c == ord(':') || $c == ord(';') || $c == ord('?') || $c == ord('!') || $c == ord('/');
+}
+
+sub break_text_fullscreen
+{
+    my $lines = [];
+    my ($text_str, $max_linelen) = @_;
+    if (! defined($text_str) || length($text_str) < 2) {
+    	return $lines;
+	}
+	$text_str =~ s/^"//;
+	$text_str =~ s/([^\\])"/$1/;
+	$text_str =~ s/\\"/"/;
+
+	my @msg = unpack("W*", $text_str);
+    #my @msg = split("", $text_str);
+    my $len = $#msg + 1;
+    my $i = 0;
+
+    LINE: 
+    while ($i < $len) {
+        while ($i < $len && pgm_is_whitespace($msg[$i])) {
+            $i += 1;
+        }
+        if ($i == $len) {
+            # End of the message.
+            last LINE;
+        }
+        my $msgend2 = $i + (($max_linelen > $len) ? $len : $max_linelen);
+        my $msgend = $msgend2;
+        if ($msgend < $len && ! pgm_is_whitespace($msg[$msgend]) && ! pgm_is_interpunction($msg[$msgend])) {
+            # Splitting a word. Find the start of the current word.
+            while ($msgend > $i && ! pgm_is_whitespace($msg[$msgend - 1])) {
+                 $msgend -= 1;
+            }
+            if ($msgend == $i) {
+                # Found a single long word, which cannot be split. Just cut it.
+                $msgend = $msgend2;
+            }
+        }
+        my $outstr = substr($text_str, $i, $msgend - $i);
+        $i = $msgend;
+        $outstr =~ s/~/ /g;
+        #print "Output string: $outstr \n";
+        push @$lines, $outstr;
+    }
+
+    return $lines;
+}
+
 my %texts;
+my %attributes;
 my $num_languages = 0;
+if (1)
+{
+	# First load the common strings.
+	my $symbols = parselang("language_common.h");
+ 	foreach my $key (keys %{$symbols}) {
+ 		if (! (exists $texts{$key})) {
+	 		my $symbol_value = ${$symbols}{$key};
+	 		# Store the symbol value for each language.
+	 		$texts{$key} = [ (${$symbol_value}{value}) x ($#langs+1) ];
+	 		# Store the possible attributes.
+			delete ${$symbol_value}{value};
+			# Store an "is common" attribute.
+			${$symbol_value}{common} = 1;
+			# 4x 80 characters, 4 lines sent over serial line.
+			${$symbol_value}{length} = 320;
+			${$symbol_value}{lines} = 1;
+ 			$attributes{$key} = $symbol_value;
+ 		} else {
+ 			print "Duplicate key in language_common.h: $key\n";
+ 		}
+ 	}
+}
 foreach my $lang (@langs) {
 	my $symbols = parselang("language_$lang.h");
  	foreach my $key (keys %{$symbols}) {
  		if (! (exists $texts{$key})) {
 	 		$texts{$key} = [];
  		}
+ 		my $symbol_value = ${$symbols}{$key};
  		my $strings = $texts{$key};
- 		die "Symbol $key defined first in $lang, undefined in the preceding language files."
- 			if (scalar(@$strings) != $num_languages);
- 		push @$strings, ${$symbols}{$key};
+ 		if (defined $attributes{$key} && defined ${$attributes{$key}}{common} && ${$attributes{$key}}{common} == 1) {
+ 			# Common overrides the possible definintions in the language specific files.
+ 		} else {
+	 		die "Symbol $key defined first in $lang, undefined in the preceding language files."
+	 			if (scalar(@$strings) != $num_languages);
+	 		push @$strings, ${$symbol_value}{value};
+	 		if ($lang eq 'en') {
+	 			# The english texts may contain attributes. Store them into %attributes.
+	 			delete ${$symbol_value}{value};
+	 			$attributes{$key} = $symbol_value;
+	 		}
+	 	}
  	}
  	$num_languages += 1;
  	foreach my $key (keys %texts) {
  		my $strings = $texts{$key};
- 		if (scalar(@$strings) != $num_languages) {
+ 		if (scalar(@$strings) < $num_languages) {
  			# die "Symbol $key undefined in $lang."
- 			print "Symbol $key undefined in $lang. Using the english variant.\n";
+ 			print "Symbol $key undefined in language \"$lang\". Using the english variant:\n";
+ 			print "\t", ${$strings}[0], "\n";
  			push @$strings, ${$strings}[0];
  		}
  	}
@@ -66,8 +181,30 @@ print $fh <<END
 #ifndef LANGUAGE_ALL_H
 #define LANGUAGE_ALL_H
 
-#define LANG_NUM (${num_languages})
+#include <avr/pgmspace.h>
+// Language indices into their particular symbol tables.
+END
+;
+
+# Export symbolic IDs of languages.
+for my $i (0 .. $#langs) {
+	my $lang = uc $langs[$i];
+	print $fh "#define LANG_ID_$lang $i\n";
+}
 
+print $fh <<END
+// Language is not defined and it shall be selected from the menu.
+#define LANG_ID_FORCE_SELECTION 254
+// Language is not defined on a virgin RAMBo board.
+#define LANG_ID_UNDEFINED 255
+
+// Default language ID, if no language is selected.
+#define LANG_ID_DEFAULT LANG_ID_CZ
+
+// Number of languages available in the language table.
+#define LANG_NUM ${num_languages}
+
+// Currectly active language selection.
 extern unsigned char lang_selected;
 
 #define LANG_TABLE_SELECT_EXPLICIT(TABLE, LANG) ((const char*)(pgm_read_ptr(TABLE + (LANG))))
@@ -77,10 +214,17 @@ END
 ;
 
 foreach my $key (sort(keys %texts)) {
-    print $fh "extern const char* const ${key}_LANG_TABLE[LANG_NUM];\n";
-	print $fh "#define $key LANG_TABLE_SELECT(${key}_LANG_TABLE)\n";
-	print $fh "#define ${key}_EXPLICIT(LANG) LANG_TABLE_SELECT_EXPLICIT(${key}_LANG_TABLE, LANG)\n"
-		if ($key eq "MSG_LANGUAGE_NAME" || $key eq "MSG_LANGUAGE_SELECT");
+	my $strings = $texts{$key};
+	if (@{$strings} == grep { $_ eq ${$strings}[0] } @{$strings}) {
+		# All strings are English.
+	    print $fh "extern const char* const ${key}_LANG_TABLE[1];\n";
+		print $fh "#define $key LANG_TABLE_SELECT_EXPLICIT(${key}_LANG_TABLE, 0)\n";
+	} else {
+	    print $fh "extern const char* const ${key}_LANG_TABLE[LANG_NUM];\n";
+		print $fh "#define $key LANG_TABLE_SELECT(${key}_LANG_TABLE)\n";
+		print $fh "#define ${key}_EXPLICIT(LANG) LANG_TABLE_SELECT_EXPLICIT(${key}_LANG_TABLE, LANG)\n"
+			if ($key eq "MSG_LANGUAGE_NAME" || $key eq "MSG_LANGUAGE_SELECT");
+	}
 }
 
 print $fh <<END
@@ -100,8 +244,8 @@ $filename = 'language_all.cpp';
 open($fh, '>', $filename) or die "Could not open file '$filename' $!";
 
 print $fh <<'END'
-#include <avr/pgmspace.h>
-#include "configuration_prusa.h"
+
+#include "Configuration_prusa.h"
 #include "language_all.h"
 
 #define LCD_WIDTH 20
@@ -110,16 +254,31 @@ extern unsigned char lang_selected;
 END
 ;
 
-foreach my $key (sort(keys %texts)) {
+my @keys = sort(keys %texts);
+foreach my $key (@keys) {
 	my $strings = $texts{$key};
+	if (@{$strings} == grep { $_ eq ${$strings}[0] } @{$strings}) {
+		# Shrink the array to a single value.
+		$strings = [${$strings}[0]];
+	}
 	for (my $i = 0; $i <= $#{$strings}; $i ++) {
 		my $suffix = uc($langs[$i]);
-		print $fh "const char ${key}_${suffix}[] PROGMEM = ${$strings}[$i];\n";
+		if ($i == 0 || ${$strings}[$i] ne ${$strings}[0]) {
+			print $fh "const char ${key}_${suffix}[] PROGMEM = ${$strings}[$i];\n";
+		}
 	}
-    print $fh "const char * const ${key}_LANG_TABLE[LANG_NUM] PROGMEM = {\n";
+	my $langnum = $#{$strings}+1;
+	if ($langnum == $#langs+1) {
+		$langnum = "LANG_NUM";
+	}
+    print $fh "const char * const ${key}_LANG_TABLE[$langnum] PROGMEM = {\n";
 	for (my $i = 0; $i <= $#{$strings}; $i ++) {
 		my $suffix = uc($langs[$i]);
-		print $fh "\t${key}_${suffix}";
+		if ($i == 0 || ${$strings}[$i] ne ${$strings}[0]) {
+			print $fh "\t${key}_${suffix}";
+		} else {
+			print $fh "\t${key}_EN";
+		}
 		print $fh ',' if $i < $#{$strings};
 		print $fh "\n";
 	}
@@ -151,3 +310,41 @@ END
 ;
 
 print ".cpp created.\nDone!\n";
+
+my $verify_only = 1;
+
+for my $lang (0 .. $#langs) {
+	print "Language: $langs[$lang]\n";
+	foreach my $key (@keys) {
+		my $strings = $texts{$key};
+		my %attrib = %{$attributes{$key}};
+		my $message = ${$strings}[$lang];
+		$message =~ /\S*"(.*)"\S*/;
+		$message = $1;
+		if ($lang == 0 || ${$strings}[0] ne $message) {
+			# If the language is not English, don't show the non-translated message.
+			my $max_nlines = $attrib{lines} // 1;
+			my $max_linelen = $attrib{length} // (($max_nlines > 1) ? 20 : 17);
+#			if (! $verify_only) {
+#				if ($nlines > 1) {
+#					print "Multi-line message: $message. Breaking to $nlines lines:\n";
+#					print "\t$_\n" foreach (@{$lines});
+#				}
+#			}
+			if ($max_nlines <= 1) {
+				my $linelen = length($message);
+				if ($linelen > $max_linelen) {
+					print "Key $key, language $langs[$lang], line length: $linelen, max length: $max_linelen\n";
+					print "\t$message\n";
+				}
+			} else {
+				my $lines = break_text_fullscreen($message, $max_linelen);
+				my $nlines = @{$lines};
+				if ($nlines > $max_nlines) {
+					print "Key $key, language $langs[$lang], lines: $nlines, max lines: $max_nlines\n";
+					print "\t$_\n" foreach (@{$lines});
+				}
+			}
+		}
+	}
+}

+ 0 - 33
Firmware/language.h

@@ -1,32 +1,6 @@
 #ifndef LANGUAGE_H
 #define LANGUAGE_H
 
-#define LANGUAGE_CONCAT(M)       #M
-#define GENERATE_LANGUAGE_INCLUDE(M)  LANGUAGE_CONCAT(language_##M.h)
-
-
-// NOTE: IF YOU CHANGE LANGUAGE FILES OR MERGE A FILE WITH CHANGES
-//
-//   ==> ALWAYS TRY TO COMPILE MARLIN WITH/WITHOUT "ULTIPANEL" / "ULTRALCD" / "SDSUPPORT" #define IN "Configuration.h"
-//   ==> ALSO TRY ALL AVAILABLE LANGUAGE OPTIONS
-
-// Languages
-// en English
-// pl Polish
-// fr French
-// de German
-// es Spanish
-// ru Russian
-// it Italian
-// pt Portuguese
-// fi Finnish
-// an Aragonese
-// nl Dutch
-// ca Catalan
-// eu Basque-Euskera
-
-
-
 #define PROTOCOL_VERSION "1.0"
 
 #if MB(ULTIMAKER)|| MB(ULTIMAKER_OLD)|| MB(ULTIMAIN_2)
@@ -66,10 +40,6 @@
 #define STRINGIFY(n) STRINGIFY_(n)
 
 
-// Common LCD messages
-
-  /* nothing here yet */
-
 // Common serial messages
 #define MSG_MARLIN "Marlin"
 
@@ -77,9 +47,6 @@
 
 
 // LCD Menu Messages
-
-//#include LANGUAGE_INCLUDE
-
 #include "language_all.h"
 
 #endif //__LANGUAGE_H

+ 1260 - 2694
Firmware/language_all.cpp

@@ -1,3661 +1,2227 @@
-#include <avr/pgmspace.h>
-#include "configuration_prusa.h"
+
+#include "Configuration_prusa.h"
 #include "language_all.h"
 
 #define LCD_WIDTH 20
 extern unsigned char lang_selected;
 
-const char MSG_ACC_EN[] PROGMEM = "Accel";
-const char MSG_ACC_CZ[] PROGMEM = "Accel";
-const char MSG_ACC_IT[] PROGMEM = "Accel";
-const char MSG_ACC_ES[] PROGMEM = "Accel";
-const char MSG_ACC_PL[] PROGMEM = "Accel";
-const char * const MSG_ACC_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ACC_EN,
-	MSG_ACC_CZ,
-	MSG_ACC_IT,
-	MSG_ACC_ES,
-	MSG_ACC_PL
+const char MSG_ACTIVE_EXTRUDER_EN[] PROGMEM = "Active Extruder: ";
+const char * const MSG_ACTIVE_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_ACTIVE_EXTRUDER_EN
 };
 
-const char MSG_ACTIVE_EXTRUDER_EN[] PROGMEM = "Active Extruder: ";
-const char MSG_ACTIVE_EXTRUDER_CZ[] PROGMEM = "Active Extruder: ";
-const char MSG_ACTIVE_EXTRUDER_IT[] PROGMEM = "Active Extruder: ";
-const char MSG_ACTIVE_EXTRUDER_ES[] PROGMEM = "Active Extruder: ";
-const char MSG_ACTIVE_EXTRUDER_PL[] PROGMEM = "Active Extruder: ";
-const char * const MSG_ACTIVE_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ACTIVE_EXTRUDER_EN,
-	MSG_ACTIVE_EXTRUDER_CZ,
-	MSG_ACTIVE_EXTRUDER_IT,
-	MSG_ACTIVE_EXTRUDER_ES,
-	MSG_ACTIVE_EXTRUDER_PL
-};
-
-const char MSG_ADJUSTZ_EN[] PROGMEM = "Auto adjust Z ?";
+const char MSG_ADJUSTZ_EN[] PROGMEM = "Auto adjust Z?";
 const char MSG_ADJUSTZ_CZ[] PROGMEM = "Auto doladit Z ?";
-const char MSG_ADJUSTZ_IT[] PROGMEM = "Auto regolare Z ?";
-const char MSG_ADJUSTZ_ES[] PROGMEM = "Auto Micropaso Z?";
-const char MSG_ADJUSTZ_PL[] PROGMEM = "Autodostroic Z?";
 const char * const MSG_ADJUSTZ_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_ADJUSTZ_EN,
-	MSG_ADJUSTZ_CZ,
-	MSG_ADJUSTZ_IT,
-	MSG_ADJUSTZ_ES,
-	MSG_ADJUSTZ_PL
+	MSG_ADJUSTZ_CZ
+};
+
+const char MSG_ALL_EN[] PROGMEM = "All";
+const char MSG_ALL_CZ[] PROGMEM = "Vse";
+const char * const MSG_ALL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_ALL_EN,
+	MSG_ALL_CZ
 };
 
 const char MSG_AMAX_EN[] PROGMEM = "Amax ";
-const char MSG_AMAX_CZ[] PROGMEM = "Amax ";
-const char MSG_AMAX_IT[] PROGMEM = "Amax ";
-const char MSG_AMAX_ES[] PROGMEM = "Amax ";
-const char MSG_AMAX_PL[] PROGMEM = "Amax ";
-const char * const MSG_AMAX_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_AMAX_EN,
-	MSG_AMAX_CZ,
-	MSG_AMAX_IT,
-	MSG_AMAX_ES,
-	MSG_AMAX_PL
+const char * const MSG_AMAX_LANG_TABLE[1] PROGMEM = {
+	MSG_AMAX_EN
 };
 
 const char MSG_AUTHOR_EN[] PROGMEM = " | Author: ";
-const char MSG_AUTHOR_CZ[] PROGMEM = " | Author: ";
-const char MSG_AUTHOR_IT[] PROGMEM = " | Author: ";
-const char MSG_AUTHOR_ES[] PROGMEM = " | Author: ";
-const char MSG_AUTHOR_PL[] PROGMEM = " | Author: ";
-const char * const MSG_AUTHOR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_AUTHOR_EN,
-	MSG_AUTHOR_CZ,
-	MSG_AUTHOR_IT,
-	MSG_AUTHOR_ES,
-	MSG_AUTHOR_PL
-};
-
-const char MSG_AUTORETRACT_EN[] PROGMEM = "AutoRetr.";
-const char MSG_AUTORETRACT_CZ[] PROGMEM = "AutoRetr.";
-const char MSG_AUTORETRACT_IT[] PROGMEM = "AutoRetr.";
-const char MSG_AUTORETRACT_ES[] PROGMEM = "AutoRetr.";
-const char MSG_AUTORETRACT_PL[] PROGMEM = "AutoRetr.";
-const char * const MSG_AUTORETRACT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_AUTORETRACT_EN,
-	MSG_AUTORETRACT_CZ,
-	MSG_AUTORETRACT_IT,
-	MSG_AUTORETRACT_ES,
-	MSG_AUTORETRACT_PL
-};
-
-const char MSG_AUTOSTART_EN[] PROGMEM = "Autostart";
-const char MSG_AUTOSTART_CZ[] PROGMEM = "Autostart";
-const char MSG_AUTOSTART_IT[] PROGMEM = "Autostart";
-const char MSG_AUTOSTART_ES[] PROGMEM = "Autostart";
-const char MSG_AUTOSTART_PL[] PROGMEM = "Autostart";
-const char * const MSG_AUTOSTART_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_AUTOSTART_EN,
-	MSG_AUTOSTART_CZ,
-	MSG_AUTOSTART_IT,
-	MSG_AUTOSTART_ES,
-	MSG_AUTOSTART_PL
-};
-
-const char MSG_AUTOTEMP_EN[] PROGMEM = "Autotemp";
-const char MSG_AUTOTEMP_CZ[] PROGMEM = "Autotemp";
-const char MSG_AUTOTEMP_IT[] PROGMEM = "Autotemp";
-const char MSG_AUTOTEMP_ES[] PROGMEM = "Autotemp";
-const char MSG_AUTOTEMP_PL[] PROGMEM = "Autotemp";
-const char * const MSG_AUTOTEMP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_AUTOTEMP_EN,
-	MSG_AUTOTEMP_CZ,
-	MSG_AUTOTEMP_IT,
-	MSG_AUTOTEMP_ES,
-	MSG_AUTOTEMP_PL
+const char * const MSG_AUTHOR_LANG_TABLE[1] PROGMEM = {
+	MSG_AUTHOR_EN
 };
 
 const char MSG_AUTO_HOME_EN[] PROGMEM = "Auto home";
-const char MSG_AUTO_HOME_CZ[] PROGMEM = "Auto home";
-const char MSG_AUTO_HOME_IT[] PROGMEM = "Auto Home";
-const char MSG_AUTO_HOME_ES[] PROGMEM = "Llevar al origen";
-const char MSG_AUTO_HOME_PL[] PROGMEM = "Auto home";
-const char * const MSG_AUTO_HOME_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_AUTO_HOME_EN,
-	MSG_AUTO_HOME_CZ,
-	MSG_AUTO_HOME_IT,
-	MSG_AUTO_HOME_ES,
-	MSG_AUTO_HOME_PL
+const char * const MSG_AUTO_HOME_LANG_TABLE[1] PROGMEM = {
+	MSG_AUTO_HOME_EN
 };
 
 const char MSG_A_RETRACT_EN[] PROGMEM = "A-retract";
-const char MSG_A_RETRACT_CZ[] PROGMEM = "A-retract";
-const char MSG_A_RETRACT_IT[] PROGMEM = "A-retract";
-const char MSG_A_RETRACT_ES[] PROGMEM = "A-retract";
-const char MSG_A_RETRACT_PL[] PROGMEM = "A-retract";
-const char * const MSG_A_RETRACT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_A_RETRACT_EN,
-	MSG_A_RETRACT_CZ,
-	MSG_A_RETRACT_IT,
-	MSG_A_RETRACT_ES,
-	MSG_A_RETRACT_PL
+const char * const MSG_A_RETRACT_LANG_TABLE[1] PROGMEM = {
+	MSG_A_RETRACT_EN
 };
 
 const char MSG_BABYSTEPPING_X_EN[] PROGMEM = "Babystepping X";
-const char MSG_BABYSTEPPING_X_CZ[] PROGMEM = "Babystepping X";
-const char MSG_BABYSTEPPING_X_IT[] PROGMEM = "Babystepping X";
-const char MSG_BABYSTEPPING_X_ES[] PROGMEM = "Babystepping X";
-const char MSG_BABYSTEPPING_X_PL[] PROGMEM = "Babystepping X";
-const char * const MSG_BABYSTEPPING_X_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BABYSTEPPING_X_EN,
-	MSG_BABYSTEPPING_X_CZ,
-	MSG_BABYSTEPPING_X_IT,
-	MSG_BABYSTEPPING_X_ES,
-	MSG_BABYSTEPPING_X_PL
+const char * const MSG_BABYSTEPPING_X_LANG_TABLE[1] PROGMEM = {
+	MSG_BABYSTEPPING_X_EN
 };
 
 const char MSG_BABYSTEPPING_Y_EN[] PROGMEM = "Babystepping Y";
-const char MSG_BABYSTEPPING_Y_CZ[] PROGMEM = "Babystepping Y";
-const char MSG_BABYSTEPPING_Y_IT[] PROGMEM = "Babystepping Y";
-const char MSG_BABYSTEPPING_Y_ES[] PROGMEM = "Babystepping Y";
-const char MSG_BABYSTEPPING_Y_PL[] PROGMEM = "Babystepping Y";
-const char * const MSG_BABYSTEPPING_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BABYSTEPPING_Y_EN,
-	MSG_BABYSTEPPING_Y_CZ,
-	MSG_BABYSTEPPING_Y_IT,
-	MSG_BABYSTEPPING_Y_ES,
-	MSG_BABYSTEPPING_Y_PL
+const char * const MSG_BABYSTEPPING_Y_LANG_TABLE[1] PROGMEM = {
+	MSG_BABYSTEPPING_Y_EN
 };
 
 const char MSG_BABYSTEPPING_Z_EN[] PROGMEM = "Adjusting Z";
-const char MSG_BABYSTEPPING_Z_CZ[] PROGMEM = "Dostavovani Z";
-const char MSG_BABYSTEPPING_Z_IT[] PROGMEM = "Adjusting Z";
-const char MSG_BABYSTEPPING_Z_ES[] PROGMEM = "Adjusting Z";
-const char MSG_BABYSTEPPING_Z_PL[] PROGMEM = "Dostavovani Z";
-const char * const MSG_BABYSTEPPING_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BABYSTEPPING_Z_EN,
-	MSG_BABYSTEPPING_Z_CZ,
-	MSG_BABYSTEPPING_Z_IT,
-	MSG_BABYSTEPPING_Z_ES,
-	MSG_BABYSTEPPING_Z_PL
+const char * const MSG_BABYSTEPPING_Z_LANG_TABLE[1] PROGMEM = {
+	MSG_BABYSTEPPING_Z_EN
 };
 
 const char MSG_BABYSTEP_X_EN[] PROGMEM = "Babystep X";
-const char MSG_BABYSTEP_X_CZ[] PROGMEM = "Babystep X";
-const char MSG_BABYSTEP_X_IT[] PROGMEM = "Babystep X";
-const char MSG_BABYSTEP_X_ES[] PROGMEM = "Babystep X";
-const char MSG_BABYSTEP_X_PL[] PROGMEM = "Babystep X";
-const char * const MSG_BABYSTEP_X_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BABYSTEP_X_EN,
-	MSG_BABYSTEP_X_CZ,
-	MSG_BABYSTEP_X_IT,
-	MSG_BABYSTEP_X_ES,
-	MSG_BABYSTEP_X_PL
+const char * const MSG_BABYSTEP_X_LANG_TABLE[1] PROGMEM = {
+	MSG_BABYSTEP_X_EN
 };
 
 const char MSG_BABYSTEP_Y_EN[] PROGMEM = "Babystep Y";
-const char MSG_BABYSTEP_Y_CZ[] PROGMEM = "Babystep Y";
-const char MSG_BABYSTEP_Y_IT[] PROGMEM = "Babystep Y";
-const char MSG_BABYSTEP_Y_ES[] PROGMEM = "Babystep Y";
-const char MSG_BABYSTEP_Y_PL[] PROGMEM = "Babystep Y";
-const char * const MSG_BABYSTEP_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BABYSTEP_Y_EN,
-	MSG_BABYSTEP_Y_CZ,
-	MSG_BABYSTEP_Y_IT,
-	MSG_BABYSTEP_Y_ES,
-	MSG_BABYSTEP_Y_PL
+const char * const MSG_BABYSTEP_Y_LANG_TABLE[1] PROGMEM = {
+	MSG_BABYSTEP_Y_EN
 };
 
 const char MSG_BABYSTEP_Z_EN[] PROGMEM = "Live adjust Z";
 const char MSG_BABYSTEP_Z_CZ[] PROGMEM = "Doladeni osy Z";
-const char MSG_BABYSTEP_Z_IT[] PROGMEM = "Babystep Z";
-const char MSG_BABYSTEP_Z_ES[] PROGMEM = "Micropaso Z";
-const char MSG_BABYSTEP_Z_PL[] PROGMEM = "Dostrojenie osy Z";
 const char * const MSG_BABYSTEP_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BABYSTEP_Z_EN,
-	MSG_BABYSTEP_Z_CZ,
-	MSG_BABYSTEP_Z_IT,
-	MSG_BABYSTEP_Z_ES,
-	MSG_BABYSTEP_Z_PL
+	MSG_BABYSTEP_Z_CZ
 };
 
-const char MSG_BABYSTEP_Z_NOT_SET_EN[] PROGMEM = "Printer has not been calibrated yet. Run calibration G-code to adjust Z height.";
-const char MSG_BABYSTEP_Z_NOT_SET_CZ[] PROGMEM = "Tiskarna nebyla jeste zkalibrovana. Spustte kalibracni G-kod a doladte Z.";
-const char MSG_BABYSTEP_Z_NOT_SET_IT[] PROGMEM = "Printer has not been calibrated yet. Run calibration G-code to adjust Z height.";
-const char MSG_BABYSTEP_Z_NOT_SET_ES[] PROGMEM = "Printer has not been calibrated yet. Run calibration G-code to adjust Z height.";
-const char MSG_BABYSTEP_Z_NOT_SET_PL[] PROGMEM = "Printer has not been calibrated yet. Run calibration G-code to adjust Z height.";
+const char MSG_BABYSTEP_Z_NOT_SET_EN[] PROGMEM = "Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration.";
+const char MSG_BABYSTEP_Z_NOT_SET_CZ[] PROGMEM = "Neni zkalibrovana vzdalenost trysky od tiskove podlozky. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Nastaveni prvni vrstvy.";
 const char * const MSG_BABYSTEP_Z_NOT_SET_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BABYSTEP_Z_NOT_SET_EN,
-	MSG_BABYSTEP_Z_NOT_SET_CZ,
-	MSG_BABYSTEP_Z_NOT_SET_IT,
-	MSG_BABYSTEP_Z_NOT_SET_ES,
-	MSG_BABYSTEP_Z_NOT_SET_PL
+	MSG_BABYSTEP_Z_NOT_SET_CZ
 };
 
 const char MSG_BED_EN[] PROGMEM = "Bed";
-const char MSG_BED_CZ[] PROGMEM = "Bed";
-const char MSG_BED_IT[] PROGMEM = "Piatto";
-const char MSG_BED_ES[] PROGMEM = "Base";
-const char MSG_BED_PL[] PROGMEM = "Stolik";
-const char * const MSG_BED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BED_EN,
-	MSG_BED_CZ,
-	MSG_BED_IT,
-	MSG_BED_ES,
-	MSG_BED_PL
+const char * const MSG_BED_LANG_TABLE[1] PROGMEM = {
+	MSG_BED_EN
+};
+
+const char MSG_BED_CORRECTION_FRONT_EN[] PROGMEM = "Front side[um]";
+const char MSG_BED_CORRECTION_FRONT_CZ[] PROGMEM = "Vpredu [um]";
+const char * const MSG_BED_CORRECTION_FRONT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_BED_CORRECTION_FRONT_EN,
+	MSG_BED_CORRECTION_FRONT_CZ
+};
+
+const char MSG_BED_CORRECTION_LEFT_EN[] PROGMEM = "Left side [um]";
+const char MSG_BED_CORRECTION_LEFT_CZ[] PROGMEM = "Vlevo  [um]";
+const char * const MSG_BED_CORRECTION_LEFT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_BED_CORRECTION_LEFT_EN,
+	MSG_BED_CORRECTION_LEFT_CZ
+};
+
+const char MSG_BED_CORRECTION_MENU_EN[] PROGMEM = "Bed level correct";
+const char MSG_BED_CORRECTION_MENU_CZ[] PROGMEM = "Korekce podlozky";
+const char * const MSG_BED_CORRECTION_MENU_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_BED_CORRECTION_MENU_EN,
+	MSG_BED_CORRECTION_MENU_CZ
+};
+
+const char MSG_BED_CORRECTION_REAR_EN[] PROGMEM = "Rear side [um]";
+const char MSG_BED_CORRECTION_REAR_CZ[] PROGMEM = "Vzadu  [um]";
+const char * const MSG_BED_CORRECTION_REAR_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_BED_CORRECTION_REAR_EN,
+	MSG_BED_CORRECTION_REAR_CZ
+};
+
+const char MSG_BED_CORRECTION_RESET_EN[] PROGMEM = "Reset";
+const char * const MSG_BED_CORRECTION_RESET_LANG_TABLE[1] PROGMEM = {
+	MSG_BED_CORRECTION_RESET_EN
+};
+
+const char MSG_BED_CORRECTION_RIGHT_EN[] PROGMEM = "Right side[um]";
+const char MSG_BED_CORRECTION_RIGHT_CZ[] PROGMEM = "Vpravo [um]";
+const char * const MSG_BED_CORRECTION_RIGHT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_BED_CORRECTION_RIGHT_EN,
+	MSG_BED_CORRECTION_RIGHT_CZ
 };
 
 const char MSG_BED_DONE_EN[] PROGMEM = "Bed done";
 const char MSG_BED_DONE_CZ[] PROGMEM = "Bed OK.";
-const char MSG_BED_DONE_IT[] PROGMEM = "Piatto fatto.";
-const char MSG_BED_DONE_ES[] PROGMEM = "Base listo.";
-const char MSG_BED_DONE_PL[] PROGMEM = "Stolik OK.";
 const char * const MSG_BED_DONE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_DONE_EN,
-	MSG_BED_DONE_CZ,
-	MSG_BED_DONE_IT,
-	MSG_BED_DONE_ES,
-	MSG_BED_DONE_PL
+	MSG_BED_DONE_CZ
 };
 
 const char MSG_BED_HEATING_EN[] PROGMEM = "Bed Heating";
 const char MSG_BED_HEATING_CZ[] PROGMEM = "Zahrivani bed";
-const char MSG_BED_HEATING_IT[] PROGMEM = "Piatto riscaldam.";
-const char MSG_BED_HEATING_ES[] PROGMEM = "Base Calentando";
-const char MSG_BED_HEATING_PL[] PROGMEM = "Grzanie stolika..";
 const char * const MSG_BED_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_HEATING_EN,
-	MSG_BED_HEATING_CZ,
-	MSG_BED_HEATING_IT,
-	MSG_BED_HEATING_ES,
-	MSG_BED_HEATING_PL
+	MSG_BED_HEATING_CZ
 };
 
 const char MSG_BED_LEVELING_FAILED_POINT_HIGH_EN[] PROGMEM = "Bed leveling failed. Sensor triggered too high. Waiting for reset.";
 const char MSG_BED_LEVELING_FAILED_POINT_HIGH_CZ[] PROGMEM = "Kalibrace Z selhala. Sensor sepnul prilis vysoko. Cekam na reset.";
-const char MSG_BED_LEVELING_FAILED_POINT_HIGH_IT[] PROGMEM = "Bed leveling failed. Sensor triggered too high. Waiting for reset.";
-const char MSG_BED_LEVELING_FAILED_POINT_HIGH_ES[] PROGMEM = "Bed leveling failed. Sensor triggered too high. Waiting for reset.";
-const char MSG_BED_LEVELING_FAILED_POINT_HIGH_PL[] PROGMEM = "Bed leveling failed. Sensor triggered too high. Waiting for reset.";
 const char * const MSG_BED_LEVELING_FAILED_POINT_HIGH_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_LEVELING_FAILED_POINT_HIGH_EN,
-	MSG_BED_LEVELING_FAILED_POINT_HIGH_CZ,
-	MSG_BED_LEVELING_FAILED_POINT_HIGH_IT,
-	MSG_BED_LEVELING_FAILED_POINT_HIGH_ES,
-	MSG_BED_LEVELING_FAILED_POINT_HIGH_PL
+	MSG_BED_LEVELING_FAILED_POINT_HIGH_CZ
 };
 
 const char MSG_BED_LEVELING_FAILED_POINT_LOW_EN[] PROGMEM = "Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset.";
 const char MSG_BED_LEVELING_FAILED_POINT_LOW_CZ[] PROGMEM = "Kalibrace Z selhala. Sensor nesepnul. Znecistena tryska? Cekam na reset.";
-const char MSG_BED_LEVELING_FAILED_POINT_LOW_IT[] PROGMEM = "Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset.";
-const char MSG_BED_LEVELING_FAILED_POINT_LOW_ES[] PROGMEM = "Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset.";
-const char MSG_BED_LEVELING_FAILED_POINT_LOW_PL[] PROGMEM = "Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset.";
 const char * const MSG_BED_LEVELING_FAILED_POINT_LOW_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_LEVELING_FAILED_POINT_LOW_EN,
-	MSG_BED_LEVELING_FAILED_POINT_LOW_CZ,
-	MSG_BED_LEVELING_FAILED_POINT_LOW_IT,
-	MSG_BED_LEVELING_FAILED_POINT_LOW_ES,
-	MSG_BED_LEVELING_FAILED_POINT_LOW_PL
+	MSG_BED_LEVELING_FAILED_POINT_LOW_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_EN[] PROGMEM = "X/Y calibration failed. Front calibration points not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ[] PROGMEM = "Kalibrace X/Y selhala. Predni kalibracni body moc vpredu. Srovnejte tiskarnu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_IT[] PROGMEM = "X/Y calibration failed. Front calibration points not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_ES[] PROGMEM = "X/Y calibration failed. Front calibration points not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_PL[] PROGMEM = "X/Y calibration failed. Front calibration points not reachable.";
+const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_EN[] PROGMEM = "Bed leveling failed. Sensor disconnected or cable broken. Waiting for reset.";
+const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_CZ[] PROGMEM = "Kalibrace Z selhala. Sensor je odpojeny nebo preruseny kabel. Cekam na reset.";
+const char * const MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_EN,
+	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_CZ
+};
+
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_EN[] PROGMEM = "XYZ calibration failed. Front calibration points not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ[] PROGMEM = "Kalibrace XYZ selhala. Predni kalibracni body moc vpredu. Srovnejte tiskarnu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_EN[] PROGMEM = "X/Y calibration failed. Left front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ[] PROGMEM = "Kalibrace X/Y selhala. Levy predni bod moc vpredu. Srovnejte tiskarnu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_IT[] PROGMEM = "X/Y calibration failed. Left front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_ES[] PROGMEM = "X/Y calibration failed. Left front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_PL[] PROGMEM = "X/Y calibration failed. Left front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_EN[] PROGMEM = "XYZ calibration failed. Left front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ[] PROGMEM = "Kalibrace XYZ selhala. Levy predni bod moc vpredu. Srovnejte tiskarnu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_EN[] PROGMEM = "X/Y calibration failed. Right front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ[] PROGMEM = "Kalibrace X/Y selhala. Pravy predni bod moc vpredu. Srovnejte tiskarnu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_IT[] PROGMEM = "X/Y calibration failed. Right front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_ES[] PROGMEM = "X/Y calibration failed. Right front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_PL[] PROGMEM = "X/Y calibration failed. Right front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_EN[] PROGMEM = "XYZ calibration failed. Right front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ[] PROGMEM = "Kalibrace XYZ selhala. Pravy predni bod moc vpredu. Srovnejte tiskarnu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_EN[] PROGMEM = "X/Y calibration failed. Please consult the manual.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_CZ[] PROGMEM = "Kalibrace X/Y selhala. Nahlednete do manualu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_IT[] PROGMEM = "X/Y calibration failed. Please consult the manual.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_ES[] PROGMEM = "X/Y calibration failed. Please consult the manual.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_PL[] PROGMEM = "X/Y calibration failed. Please consult the manual.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_EN[] PROGMEM = "XYZ calibration failed. Please consult the manual.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_CZ[] PROGMEM = "Kalibrace XYZ selhala. Nahlednete do manualu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN[] PROGMEM = "X/Y calibration ok. X/Y axes are perpendicular.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ[] PROGMEM = "X/Y calibration ok. X/Y axes are perpendicular.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_IT[] PROGMEM = "X/Y calibration ok. X/Y axes are perpendicular.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_ES[] PROGMEM = "X/Y calibration ok. X/Y axes are perpendicular.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL[] PROGMEM = "X/Y calibration ok. X/Y axes are perpendicular.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN[] PROGMEM = "XYZ calibration ok. X/Y axes are perpendicular. Congratulations!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ[] PROGMEM = "Kalibrace XYZ v poradku. X/Y osy jsou kolme. Gratuluji!";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_EN[] PROGMEM = "X/Y calibration failed. Bed calibration point was not found.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_CZ[] PROGMEM = "Kalibrace X/Y selhala. Kalibracni bod podlozky nenalezen.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_IT[] PROGMEM = "X/Y calibration failed. Bed calibration point was not found.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_ES[] PROGMEM = "X/Y calibration failed. Bed calibration point was not found.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_PL[] PROGMEM = "X/Y calibration failed. Bed calibration point was not found.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_EN[] PROGMEM = "XYZ calibration failed. Bed calibration point was not found.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_CZ[] PROGMEM = "Kalibrace XYZ selhala. Kalibracni bod podlozky nenalezen.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_EN[] PROGMEM = "X/Y skewed severly. Skew will be corrected automatically.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ[] PROGMEM = "X/Y osy jsou silne zkosene. Zkoseni bude automaticky vyrovnano pri tisku.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_IT[] PROGMEM = "X/Y skewed severly. Skew will be corrected automatically.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_ES[] PROGMEM = "X/Y skewed severly. Skew will be corrected automatically.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_PL[] PROGMEM = "X/Y skewed severly. Skew will be corrected automatically.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_EN[] PROGMEM = "XYZ calibration all right. Skew will be corrected automatically.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ[] PROGMEM = "Kalibrace XYZ v poradku. Zkoseni bude automaticky vyrovnano pri tisku.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_EN[] PROGMEM = "X/Y calibration all right. X/Y axes are slightly skewed.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ[] PROGMEM = "Kalibrace X/Y v poradku. X/Y osy mirne zkosene.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_IT[] PROGMEM = "X/Y calibration all right. X/Y axes are slightly skewed.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_ES[] PROGMEM = "X/Y calibration all right. X/Y axes are slightly skewed.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_PL[] PROGMEM = "X/Y calibration all right. X/Y axes are slightly skewed.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_EN[] PROGMEM = "XYZ calibration all right. X/Y axes are slightly skewed. Good job!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ[] PROGMEM = "Kalibrace XYZ v poradku. X/Y osy mirne zkosene. Dobra prace!";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_EN[] PROGMEM = "X/Y calibration compromised. Front calibration points not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ[] PROGMEM = "Kalibrace X/Y nepresna. Predni kalibracni body moc vpredu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_IT[] PROGMEM = "X/Y calibration compromised. Front calibration points not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_ES[] PROGMEM = "X/Y calibration compromised. Front calibration points not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_PL[] PROGMEM = "X/Y calibration compromised. Front calibration points not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_EN[] PROGMEM = "XYZ calibration compromised. Front calibration points not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ[] PROGMEM = "Kalibrace XYZ nepresna. Predni kalibracni body moc vpredu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_EN[] PROGMEM = "X/Y calibration compromised. Left front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ[] PROGMEM = "Kalibrace X/Y nepresna. Levy predni bod moc vpredu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_IT[] PROGMEM = "X/Y calibration compromised. Left front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_ES[] PROGMEM = "X/Y calibration compromised. Left front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_PL[] PROGMEM = "X/Y calibration compromised. Left front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_EN[] PROGMEM = "XYZ calibration compromised. Left front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ[] PROGMEM = "Kalibrace XYZ nepresna. Levy predni bod moc vpredu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_EN[] PROGMEM = "X/Y calibration compromised. Right front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ[] PROGMEM = "Kalibrace X/Y nepresna. Pravy predni bod moc vpredu.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_IT[] PROGMEM = "X/Y calibration compromised. Right front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_ES[] PROGMEM = "X/Y calibration compromised. Right front calibration point not reachable.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_PL[] PROGMEM = "X/Y calibration compromised. Right front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_EN[] PROGMEM = "XYZ calibration compromised. Right front calibration point not reachable.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ[] PROGMEM = "Kalibrace XYZ nepresna. Pravy predni bod moc vpredu.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_EN,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_IT,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ
 };
 
 const char MSG_BEGIN_FILE_LIST_EN[] PROGMEM = "Begin file list";
-const char MSG_BEGIN_FILE_LIST_CZ[] PROGMEM = "Begin file list";
-const char MSG_BEGIN_FILE_LIST_IT[] PROGMEM = "Begin file list";
-const char MSG_BEGIN_FILE_LIST_ES[] PROGMEM = "Begin file list";
-const char MSG_BEGIN_FILE_LIST_PL[] PROGMEM = "Begin file list";
-const char * const MSG_BEGIN_FILE_LIST_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BEGIN_FILE_LIST_EN,
-	MSG_BEGIN_FILE_LIST_CZ,
-	MSG_BEGIN_FILE_LIST_IT,
-	MSG_BEGIN_FILE_LIST_ES,
-	MSG_BEGIN_FILE_LIST_PL
+const char * const MSG_BEGIN_FILE_LIST_LANG_TABLE[1] PROGMEM = {
+	MSG_BEGIN_FILE_LIST_EN
 };
 
 const char MSG_BROWNOUT_RESET_EN[] PROGMEM = " Brown out Reset";
-const char MSG_BROWNOUT_RESET_CZ[] PROGMEM = " Brown out Reset";
-const char MSG_BROWNOUT_RESET_IT[] PROGMEM = " Brown out Reset";
-const char MSG_BROWNOUT_RESET_ES[] PROGMEM = " Brown out Reset";
-const char MSG_BROWNOUT_RESET_PL[] PROGMEM = " Brown out Reset";
-const char * const MSG_BROWNOUT_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_BROWNOUT_RESET_EN,
-	MSG_BROWNOUT_RESET_CZ,
-	MSG_BROWNOUT_RESET_IT,
-	MSG_BROWNOUT_RESET_ES,
-	MSG_BROWNOUT_RESET_PL
-};
-
-const char MSG_CALIBRATE_BED_EN[] PROGMEM = "Calibrate X/Y";
-const char MSG_CALIBRATE_BED_CZ[] PROGMEM = "Kalibrace X/Y";
-const char MSG_CALIBRATE_BED_IT[] PROGMEM = "Calibrate X/Y";
-const char MSG_CALIBRATE_BED_ES[] PROGMEM = "Calibrate X/Y";
-const char MSG_CALIBRATE_BED_PL[] PROGMEM = "Calibrate X/Y";
+const char * const MSG_BROWNOUT_RESET_LANG_TABLE[1] PROGMEM = {
+	MSG_BROWNOUT_RESET_EN
+};
+
+const char MSG_CALIBRATE_BED_EN[] PROGMEM = "Calibrate XYZ";
+const char MSG_CALIBRATE_BED_CZ[] PROGMEM = "Kalibrace XYZ";
 const char * const MSG_CALIBRATE_BED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CALIBRATE_BED_EN,
-	MSG_CALIBRATE_BED_CZ,
-	MSG_CALIBRATE_BED_IT,
-	MSG_CALIBRATE_BED_ES,
-	MSG_CALIBRATE_BED_PL
+	MSG_CALIBRATE_BED_CZ
 };
 
-const char MSG_CALIBRATE_BED_RESET_EN[] PROGMEM = "Reset X/Y calibr.";
-const char MSG_CALIBRATE_BED_RESET_CZ[] PROGMEM = "Reset X/Y kalibr.";
-const char MSG_CALIBRATE_BED_RESET_IT[] PROGMEM = "Reset X/Y calibr.";
-const char MSG_CALIBRATE_BED_RESET_ES[] PROGMEM = "Reset X/Y calibr.";
-const char MSG_CALIBRATE_BED_RESET_PL[] PROGMEM = "Reset X/Y calibr.";
+const char MSG_CALIBRATE_BED_RESET_EN[] PROGMEM = "Reset XYZ calibr.";
+const char MSG_CALIBRATE_BED_RESET_CZ[] PROGMEM = "Reset XYZ kalibr.";
 const char * const MSG_CALIBRATE_BED_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CALIBRATE_BED_RESET_EN,
-	MSG_CALIBRATE_BED_RESET_CZ,
-	MSG_CALIBRATE_BED_RESET_IT,
-	MSG_CALIBRATE_BED_RESET_ES,
-	MSG_CALIBRATE_BED_RESET_PL
+	MSG_CALIBRATE_BED_RESET_CZ
+};
+
+const char MSG_CALIBRATE_E_EN[] PROGMEM = "Calibrate E";
+const char MSG_CALIBRATE_E_CZ[] PROGMEM = "Kalibrovat E";
+const char * const MSG_CALIBRATE_E_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CALIBRATE_E_EN,
+	MSG_CALIBRATE_E_CZ
+};
+
+const char MSG_CALIBRATE_PINDA_EN[] PROGMEM = "Calibrate";
+const char MSG_CALIBRATE_PINDA_CZ[] PROGMEM = "Zkalibrovat";
+const char * const MSG_CALIBRATE_PINDA_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CALIBRATE_PINDA_EN,
+	MSG_CALIBRATE_PINDA_CZ
+};
+
+const char MSG_CALIBRATE_Z_AUTO_EN[] PROGMEM = "Calibrating Z";
+const char MSG_CALIBRATE_Z_AUTO_CZ[] PROGMEM = "Kalibruji Z";
+const char * const MSG_CALIBRATE_Z_AUTO_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CALIBRATE_Z_AUTO_EN,
+	MSG_CALIBRATE_Z_AUTO_CZ
+};
+
+const char MSG_CALIBRATION_PINDA_MENU_EN[] PROGMEM = "Temp. calibration";
+const char MSG_CALIBRATION_PINDA_MENU_CZ[] PROGMEM = "Teplot. kalibrace";
+const char * const MSG_CALIBRATION_PINDA_MENU_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CALIBRATION_PINDA_MENU_EN,
+	MSG_CALIBRATION_PINDA_MENU_CZ
 };
 
 const char MSG_CARD_MENU_EN[] PROGMEM = "Print from SD";
 const char MSG_CARD_MENU_CZ[] PROGMEM = "Tisk z SD";
-const char MSG_CARD_MENU_IT[] PROGMEM = "Menu SD Carta";
-const char MSG_CARD_MENU_ES[] PROGMEM = "Menu de SD";
-const char MSG_CARD_MENU_PL[] PROGMEM = "Druk z SD";
 const char * const MSG_CARD_MENU_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CARD_MENU_EN,
-	MSG_CARD_MENU_CZ,
-	MSG_CARD_MENU_IT,
-	MSG_CARD_MENU_ES,
-	MSG_CARD_MENU_PL
+	MSG_CARD_MENU_CZ
+};
+
+const char MSG_CHANGE_EXTR_EN[] PROGMEM = "Change extruder";
+const char MSG_CHANGE_EXTR_CZ[] PROGMEM = "Zmenit extruder";
+const char * const MSG_CHANGE_EXTR_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CHANGE_EXTR_EN,
+	MSG_CHANGE_EXTR_CZ
 };
 
 const char MSG_CHANGE_SUCCESS_EN[] PROGMEM = "Change success!";
 const char MSG_CHANGE_SUCCESS_CZ[] PROGMEM = "Zmena uspesna!";
-const char MSG_CHANGE_SUCCESS_IT[] PROGMEM = "Cambia. riuscito!";
-const char MSG_CHANGE_SUCCESS_ES[] PROGMEM = "Cambiar bien!";
-const char MSG_CHANGE_SUCCESS_PL[] PROGMEM = "Wymiana ok!";
 const char * const MSG_CHANGE_SUCCESS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CHANGE_SUCCESS_EN,
-	MSG_CHANGE_SUCCESS_CZ,
-	MSG_CHANGE_SUCCESS_IT,
-	MSG_CHANGE_SUCCESS_ES,
-	MSG_CHANGE_SUCCESS_PL
+	MSG_CHANGE_SUCCESS_CZ
 };
 
 const char MSG_CHANGING_FILAMENT_EN[] PROGMEM = "Changing filament!";
 const char MSG_CHANGING_FILAMENT_CZ[] PROGMEM = "Vymena filamentu!";
-const char MSG_CHANGING_FILAMENT_IT[] PROGMEM = "Mutevole fil.!";
-const char MSG_CHANGING_FILAMENT_ES[] PROGMEM = "Cambiando fil.!";
-const char MSG_CHANGING_FILAMENT_PL[] PROGMEM = "Wymiana filamentu";
 const char * const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CHANGING_FILAMENT_EN,
-	MSG_CHANGING_FILAMENT_CZ,
-	MSG_CHANGING_FILAMENT_IT,
-	MSG_CHANGING_FILAMENT_ES,
-	MSG_CHANGING_FILAMENT_PL
+	MSG_CHANGING_FILAMENT_CZ
+};
+
+const char MSG_CHOOSE_EXTRUDER_EN[] PROGMEM = "Choose extruder:";
+const char MSG_CHOOSE_EXTRUDER_CZ[] PROGMEM = "Vyberte extruder:";
+const char * const MSG_CHOOSE_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CHOOSE_EXTRUDER_EN,
+	MSG_CHOOSE_EXTRUDER_CZ
+};
+
+const char MSG_CLEAN_NOZZLE_E_EN[] PROGMEM = "E calibration finished. Please clean the nozzle. Click when done.";
+const char MSG_CLEAN_NOZZLE_E_CZ[] PROGMEM = "E kalibrace ukoncena. Prosim ocistete trysku. Po te potvrdte tlacitkem.";
+const char * const MSG_CLEAN_NOZZLE_E_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CLEAN_NOZZLE_E_EN,
+	MSG_CLEAN_NOZZLE_E_CZ
 };
 
 const char MSG_CNG_SDCARD_EN[] PROGMEM = "Change SD card";
-const char MSG_CNG_SDCARD_CZ[] PROGMEM = "Vymenit SD";
-const char MSG_CNG_SDCARD_IT[] PROGMEM = "Change SD card";
-const char MSG_CNG_SDCARD_ES[] PROGMEM = "Change SD card";
-const char MSG_CNG_SDCARD_PL[] PROGMEM = "Vymenit SD";
-const char * const MSG_CNG_SDCARD_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CNG_SDCARD_EN,
-	MSG_CNG_SDCARD_CZ,
-	MSG_CNG_SDCARD_IT,
-	MSG_CNG_SDCARD_ES,
-	MSG_CNG_SDCARD_PL
+const char * const MSG_CNG_SDCARD_LANG_TABLE[1] PROGMEM = {
+	MSG_CNG_SDCARD_EN
 };
 
 const char MSG_CONFIGURATION_VER_EN[] PROGMEM = " Last Updated: ";
-const char MSG_CONFIGURATION_VER_CZ[] PROGMEM = " Last Updated: ";
-const char MSG_CONFIGURATION_VER_IT[] PROGMEM = " Last Updated: ";
-const char MSG_CONFIGURATION_VER_ES[] PROGMEM = " Last Updated: ";
-const char MSG_CONFIGURATION_VER_PL[] PROGMEM = " Last Updated: ";
-const char * const MSG_CONFIGURATION_VER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONFIGURATION_VER_EN,
-	MSG_CONFIGURATION_VER_CZ,
-	MSG_CONFIGURATION_VER_IT,
-	MSG_CONFIGURATION_VER_ES,
-	MSG_CONFIGURATION_VER_PL
+const char * const MSG_CONFIGURATION_VER_LANG_TABLE[1] PROGMEM = {
+	MSG_CONFIGURATION_VER_EN
 };
 
 const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_EN[] PROGMEM = "Are left and right Z~carriages all up?";
 const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ[] PROGMEM = "Dojely oba Z voziky k~hornimu dorazu?";
-const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_IT[] PROGMEM = "Are left and right Z~carriages all up?";
-const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_ES[] PROGMEM = "Are left and right Z~carriages all up?";
-const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_PL[] PROGMEM = "Are left and right Z~carriages all up?";
 const char * const MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_EN,
-	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ,
-	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_IT,
-	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_ES,
-	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_PL
+	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ
 };
 
 const char MSG_CONFIRM_NOZZLE_CLEAN_EN[] PROGMEM = "Please clean the nozzle for calibration. Click when done.";
 const char MSG_CONFIRM_NOZZLE_CLEAN_CZ[] PROGMEM = "Pro uspesnou kalibraci ocistete prosim tiskovou trysku. Potvrdte tlacitkem.";
-const char MSG_CONFIRM_NOZZLE_CLEAN_IT[] PROGMEM = "Please clean the nozzle for calibration. Click when done.";
-const char MSG_CONFIRM_NOZZLE_CLEAN_ES[] PROGMEM = "Please clean the nozzle for calibration. Click when done.";
-const char MSG_CONFIRM_NOZZLE_CLEAN_PL[] PROGMEM = "Please clean the nozzle for calibration. Click when done.";
 const char * const MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CONFIRM_NOZZLE_CLEAN_EN,
-	MSG_CONFIRM_NOZZLE_CLEAN_CZ,
-	MSG_CONFIRM_NOZZLE_CLEAN_IT,
-	MSG_CONFIRM_NOZZLE_CLEAN_ES,
-	MSG_CONFIRM_NOZZLE_CLEAN_PL
+	MSG_CONFIRM_NOZZLE_CLEAN_CZ
 };
 
-const char MSG_CONTRAST_EN[] PROGMEM = "LCD contrast";
-const char MSG_CONTRAST_CZ[] PROGMEM = "LCD contrast";
-const char MSG_CONTRAST_IT[] PROGMEM = "LCD contrast";
-const char MSG_CONTRAST_ES[] PROGMEM = "LCD contrast";
-const char MSG_CONTRAST_PL[] PROGMEM = "LCD contrast";
-const char * const MSG_CONTRAST_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTRAST_EN,
-	MSG_CONTRAST_CZ,
-	MSG_CONTRAST_IT,
-	MSG_CONTRAST_ES,
-	MSG_CONTRAST_PL
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_EN[] PROGMEM = "Filaments are now adjusted. Please clean the nozzle for calibration. Click when done.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_CZ[] PROGMEM = "Filamenty jsou srovnany. Pro uspesnou kalibraci prosim ocistete trysku. Po te potvrdte tlacitkem.";
+const char * const MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_EN,
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_CZ
 };
 
 const char MSG_CONTROL_EN[] PROGMEM = "Control";
-const char MSG_CONTROL_CZ[] PROGMEM = "Kontrola";
-const char MSG_CONTROL_IT[] PROGMEM = "Control";
-const char MSG_CONTROL_ES[] PROGMEM = "Control";
-const char MSG_CONTROL_PL[] PROGMEM = "Kontrola";
-const char * const MSG_CONTROL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_EN,
-	MSG_CONTROL_CZ,
-	MSG_CONTROL_IT,
-	MSG_CONTROL_ES,
-	MSG_CONTROL_PL
-};
-
-const char MSG_CONTROL_RETRACT_EN[] PROGMEM = "Retract mm";
-const char MSG_CONTROL_RETRACT_CZ[] PROGMEM = "Retract mm";
-const char MSG_CONTROL_RETRACT_IT[] PROGMEM = "Retract mm";
-const char MSG_CONTROL_RETRACT_ES[] PROGMEM = "Retract mm";
-const char MSG_CONTROL_RETRACT_PL[] PROGMEM = "Retract mm";
-const char * const MSG_CONTROL_RETRACT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACT_EN,
-	MSG_CONTROL_RETRACT_CZ,
-	MSG_CONTROL_RETRACT_IT,
-	MSG_CONTROL_RETRACT_ES,
-	MSG_CONTROL_RETRACT_PL
-};
-
-const char MSG_CONTROL_RETRACTF_EN[] PROGMEM = "Retract  V";
-const char MSG_CONTROL_RETRACTF_CZ[] PROGMEM = "Retract  V";
-const char MSG_CONTROL_RETRACTF_IT[] PROGMEM = "Retract  V";
-const char MSG_CONTROL_RETRACTF_ES[] PROGMEM = "Retract  V";
-const char MSG_CONTROL_RETRACTF_PL[] PROGMEM = "Retract  V";
-const char * const MSG_CONTROL_RETRACTF_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACTF_EN,
-	MSG_CONTROL_RETRACTF_CZ,
-	MSG_CONTROL_RETRACTF_IT,
-	MSG_CONTROL_RETRACTF_ES,
-	MSG_CONTROL_RETRACTF_PL
-};
-
-const char MSG_CONTROL_RETRACT_RECOVER_EN[] PROGMEM = "UnRet +mm";
-const char MSG_CONTROL_RETRACT_RECOVER_CZ[] PROGMEM = "UnRet +mm";
-const char MSG_CONTROL_RETRACT_RECOVER_IT[] PROGMEM = "UnRet +mm";
-const char MSG_CONTROL_RETRACT_RECOVER_ES[] PROGMEM = "UnRet +mm";
-const char MSG_CONTROL_RETRACT_RECOVER_PL[] PROGMEM = "UnRet +mm";
-const char * const MSG_CONTROL_RETRACT_RECOVER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACT_RECOVER_EN,
-	MSG_CONTROL_RETRACT_RECOVER_CZ,
-	MSG_CONTROL_RETRACT_RECOVER_IT,
-	MSG_CONTROL_RETRACT_RECOVER_ES,
-	MSG_CONTROL_RETRACT_RECOVER_PL
-};
-
-const char MSG_CONTROL_RETRACT_RECOVERF_EN[] PROGMEM = "UnRet  V";
-const char MSG_CONTROL_RETRACT_RECOVERF_CZ[] PROGMEM = "UnRet  V";
-const char MSG_CONTROL_RETRACT_RECOVERF_IT[] PROGMEM = "UnRet  V";
-const char MSG_CONTROL_RETRACT_RECOVERF_ES[] PROGMEM = "UnRet  V";
-const char MSG_CONTROL_RETRACT_RECOVERF_PL[] PROGMEM = "UnRet  V";
-const char * const MSG_CONTROL_RETRACT_RECOVERF_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACT_RECOVERF_EN,
-	MSG_CONTROL_RETRACT_RECOVERF_CZ,
-	MSG_CONTROL_RETRACT_RECOVERF_IT,
-	MSG_CONTROL_RETRACT_RECOVERF_ES,
-	MSG_CONTROL_RETRACT_RECOVERF_PL
-};
-
-const char MSG_CONTROL_RETRACT_RECOVER_SWAP_EN[] PROGMEM = "S UnRet+mm";
-const char MSG_CONTROL_RETRACT_RECOVER_SWAP_CZ[] PROGMEM = "S UnRet+mm";
-const char MSG_CONTROL_RETRACT_RECOVER_SWAP_IT[] PROGMEM = "S UnRet+mm";
-const char MSG_CONTROL_RETRACT_RECOVER_SWAP_ES[] PROGMEM = "S UnRet+mm";
-const char MSG_CONTROL_RETRACT_RECOVER_SWAP_PL[] PROGMEM = "S UnRet+mm";
-const char * const MSG_CONTROL_RETRACT_RECOVER_SWAP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACT_RECOVER_SWAP_EN,
-	MSG_CONTROL_RETRACT_RECOVER_SWAP_CZ,
-	MSG_CONTROL_RETRACT_RECOVER_SWAP_IT,
-	MSG_CONTROL_RETRACT_RECOVER_SWAP_ES,
-	MSG_CONTROL_RETRACT_RECOVER_SWAP_PL
-};
-
-const char MSG_CONTROL_RETRACT_SWAP_EN[] PROGMEM = "Swap Re.mm";
-const char MSG_CONTROL_RETRACT_SWAP_CZ[] PROGMEM = "Swap Re.mm";
-const char MSG_CONTROL_RETRACT_SWAP_IT[] PROGMEM = "Swap Re.mm";
-const char MSG_CONTROL_RETRACT_SWAP_ES[] PROGMEM = "Swap Re.mm";
-const char MSG_CONTROL_RETRACT_SWAP_PL[] PROGMEM = "Swap Re.mm";
-const char * const MSG_CONTROL_RETRACT_SWAP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACT_SWAP_EN,
-	MSG_CONTROL_RETRACT_SWAP_CZ,
-	MSG_CONTROL_RETRACT_SWAP_IT,
-	MSG_CONTROL_RETRACT_SWAP_ES,
-	MSG_CONTROL_RETRACT_SWAP_PL
-};
-
-const char MSG_CONTROL_RETRACT_ZLIFT_EN[] PROGMEM = "Hop mm";
-const char MSG_CONTROL_RETRACT_ZLIFT_CZ[] PROGMEM = "Hop mm";
-const char MSG_CONTROL_RETRACT_ZLIFT_IT[] PROGMEM = "Hop mm";
-const char MSG_CONTROL_RETRACT_ZLIFT_ES[] PROGMEM = "Hop mm";
-const char MSG_CONTROL_RETRACT_ZLIFT_PL[] PROGMEM = "Hop mm";
-const char * const MSG_CONTROL_RETRACT_ZLIFT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_CONTROL_RETRACT_ZLIFT_EN,
-	MSG_CONTROL_RETRACT_ZLIFT_CZ,
-	MSG_CONTROL_RETRACT_ZLIFT_IT,
-	MSG_CONTROL_RETRACT_ZLIFT_ES,
-	MSG_CONTROL_RETRACT_ZLIFT_PL
+const char * const MSG_CONTROL_LANG_TABLE[1] PROGMEM = {
+	MSG_CONTROL_EN
 };
 
 const char MSG_COOLDOWN_EN[] PROGMEM = "Cooldown";
 const char MSG_COOLDOWN_CZ[] PROGMEM = "Zchladit";
-const char MSG_COOLDOWN_IT[] PROGMEM = "Raffredda";
-const char MSG_COOLDOWN_ES[] PROGMEM = "Enfriar";
-const char MSG_COOLDOWN_PL[] PROGMEM = "Wychlodzic";
 const char * const MSG_COOLDOWN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_COOLDOWN_EN,
-	MSG_COOLDOWN_CZ,
-	MSG_COOLDOWN_IT,
-	MSG_COOLDOWN_ES,
-	MSG_COOLDOWN_PL
+	MSG_COOLDOWN_CZ
 };
 
 const char MSG_CORRECTLY_EN[] PROGMEM = "Changed correctly?";
 const char MSG_CORRECTLY_CZ[] PROGMEM = "Vymena ok?";
-const char MSG_CORRECTLY_IT[] PROGMEM = "Cambiato corr.?";
-const char MSG_CORRECTLY_ES[] PROGMEM = "Cambiado correc.?";
-const char MSG_CORRECTLY_PL[] PROGMEM = "Wymiana ok?";
 const char * const MSG_CORRECTLY_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CORRECTLY_EN,
-	MSG_CORRECTLY_CZ,
-	MSG_CORRECTLY_IT,
-	MSG_CORRECTLY_ES,
-	MSG_CORRECTLY_PL
+	MSG_CORRECTLY_CZ
 };
 
 const char MSG_COUNT_X_EN[] PROGMEM = " Count X: ";
-const char MSG_COUNT_X_CZ[] PROGMEM = " Count X: ";
-const char MSG_COUNT_X_IT[] PROGMEM = " Count X: ";
-const char MSG_COUNT_X_ES[] PROGMEM = " Count X: ";
-const char MSG_COUNT_X_PL[] PROGMEM = " Count X: ";
-const char * const MSG_COUNT_X_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_COUNT_X_EN,
-	MSG_COUNT_X_CZ,
-	MSG_COUNT_X_IT,
-	MSG_COUNT_X_ES,
-	MSG_COUNT_X_PL
+const char * const MSG_COUNT_X_LANG_TABLE[1] PROGMEM = {
+	MSG_COUNT_X_EN
+};
+
+const char MSG_CRASHDETECT_OFF_EN[] PROGMEM = "Crash det.  [off]";
+const char MSG_CRASHDETECT_OFF_CZ[] PROGMEM = "Crash det.  [vyp]";
+const char * const MSG_CRASHDETECT_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CRASHDETECT_OFF_EN,
+	MSG_CRASHDETECT_OFF_CZ
+};
+
+const char MSG_CRASHDETECT_ON_EN[] PROGMEM = "Crash det.   [on]";
+const char MSG_CRASHDETECT_ON_CZ[] PROGMEM = "Crash det.  [zap]";
+const char * const MSG_CRASHDETECT_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CRASHDETECT_ON_EN,
+	MSG_CRASHDETECT_ON_CZ
+};
+
+const char MSG_CRASH_DETECTED_EN[] PROGMEM = "Crash detected. Continue printing?";
+const char * const MSG_CRASH_DETECTED_LANG_TABLE[1] PROGMEM = {
+	MSG_CRASH_DETECTED_EN
+};
+
+const char MSG_CURRENT_EN[] PROGMEM = "Current";
+const char MSG_CURRENT_CZ[] PROGMEM = "Pouze aktualni";
+const char * const MSG_CURRENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CURRENT_EN,
+	MSG_CURRENT_CZ
+};
+
+const char MSG_DATE_EN[] PROGMEM = "Date:";
+const char MSG_DATE_CZ[] PROGMEM = "Datum:";
+const char * const MSG_DATE_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_DATE_EN,
+	MSG_DATE_CZ
 };
 
 const char MSG_DISABLE_STEPPERS_EN[] PROGMEM = "Disable steppers";
 const char MSG_DISABLE_STEPPERS_CZ[] PROGMEM = "Vypnout motory";
-const char MSG_DISABLE_STEPPERS_IT[] PROGMEM = "Disabilita Motori";
-const char MSG_DISABLE_STEPPERS_ES[] PROGMEM = "Apagar motores";
-const char MSG_DISABLE_STEPPERS_PL[] PROGMEM = "Wylaczyc silniki";
 const char * const MSG_DISABLE_STEPPERS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_DISABLE_STEPPERS_EN,
-	MSG_DISABLE_STEPPERS_CZ,
-	MSG_DISABLE_STEPPERS_IT,
-	MSG_DISABLE_STEPPERS_ES,
-	MSG_DISABLE_STEPPERS_PL
+	MSG_DISABLE_STEPPERS_CZ
 };
 
 const char MSG_DWELL_EN[] PROGMEM = "Sleep...";
-const char MSG_DWELL_CZ[] PROGMEM = "Sleep...";
-const char MSG_DWELL_IT[] PROGMEM = "Sospensione...";
-const char MSG_DWELL_ES[] PROGMEM = "Reposo...";
-const char MSG_DWELL_PL[] PROGMEM = "Sleep...";
-const char * const MSG_DWELL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_DWELL_EN,
-	MSG_DWELL_CZ,
-	MSG_DWELL_IT,
-	MSG_DWELL_ES,
-	MSG_DWELL_PL
-};
-
-const char MSG_E_EN[] PROGMEM = "e";
-const char MSG_E_CZ[] PROGMEM = "e";
-const char MSG_E_IT[] PROGMEM = "e";
-const char MSG_E_ES[] PROGMEM = "e";
-const char MSG_E_PL[] PROGMEM = "e";
-const char * const MSG_E_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_E_EN,
-	MSG_E_CZ,
-	MSG_E_IT,
-	MSG_E_ES,
-	MSG_E_PL
+const char * const MSG_DWELL_LANG_TABLE[1] PROGMEM = {
+	MSG_DWELL_EN
 };
 
 const char MSG_ENDSTOPS_HIT_EN[] PROGMEM = "endstops hit: ";
-const char MSG_ENDSTOPS_HIT_CZ[] PROGMEM = "endstops hit: ";
-const char MSG_ENDSTOPS_HIT_IT[] PROGMEM = "endstops hit: ";
-const char MSG_ENDSTOPS_HIT_ES[] PROGMEM = "endstops hit: ";
-const char MSG_ENDSTOPS_HIT_PL[] PROGMEM = "endstops hit: ";
-const char * const MSG_ENDSTOPS_HIT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ENDSTOPS_HIT_EN,
-	MSG_ENDSTOPS_HIT_CZ,
-	MSG_ENDSTOPS_HIT_IT,
-	MSG_ENDSTOPS_HIT_ES,
-	MSG_ENDSTOPS_HIT_PL
-};
-
-const char MSG_ENDSTOP_ABORT_EN[] PROGMEM = "Endstop abort";
-const char MSG_ENDSTOP_ABORT_CZ[] PROGMEM = "Endstop abort";
-const char MSG_ENDSTOP_ABORT_IT[] PROGMEM = "Endstop abort";
-const char MSG_ENDSTOP_ABORT_ES[] PROGMEM = "Endstop abort";
-const char MSG_ENDSTOP_ABORT_PL[] PROGMEM = "Endstop abort";
-const char * const MSG_ENDSTOP_ABORT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ENDSTOP_ABORT_EN,
-	MSG_ENDSTOP_ABORT_CZ,
-	MSG_ENDSTOP_ABORT_IT,
-	MSG_ENDSTOP_ABORT_ES,
-	MSG_ENDSTOP_ABORT_PL
+const char * const MSG_ENDSTOPS_HIT_LANG_TABLE[1] PROGMEM = {
+	MSG_ENDSTOPS_HIT_EN
 };
 
 const char MSG_ENDSTOP_HIT_EN[] PROGMEM = "TRIGGERED";
-const char MSG_ENDSTOP_HIT_CZ[] PROGMEM = "TRIGGERED";
-const char MSG_ENDSTOP_HIT_IT[] PROGMEM = "TRIGGERED";
-const char MSG_ENDSTOP_HIT_ES[] PROGMEM = "TRIGGERED";
-const char MSG_ENDSTOP_HIT_PL[] PROGMEM = "TRIGGERED";
-const char * const MSG_ENDSTOP_HIT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ENDSTOP_HIT_EN,
-	MSG_ENDSTOP_HIT_CZ,
-	MSG_ENDSTOP_HIT_IT,
-	MSG_ENDSTOP_HIT_ES,
-	MSG_ENDSTOP_HIT_PL
+const char * const MSG_ENDSTOP_HIT_LANG_TABLE[1] PROGMEM = {
+	MSG_ENDSTOP_HIT_EN
 };
 
 const char MSG_ENDSTOP_OPEN_EN[] PROGMEM = "open";
-const char MSG_ENDSTOP_OPEN_CZ[] PROGMEM = "open";
-const char MSG_ENDSTOP_OPEN_IT[] PROGMEM = "open";
-const char MSG_ENDSTOP_OPEN_ES[] PROGMEM = "open";
-const char MSG_ENDSTOP_OPEN_PL[] PROGMEM = "open";
-const char * const MSG_ENDSTOP_OPEN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ENDSTOP_OPEN_EN,
-	MSG_ENDSTOP_OPEN_CZ,
-	MSG_ENDSTOP_OPEN_IT,
-	MSG_ENDSTOP_OPEN_ES,
-	MSG_ENDSTOP_OPEN_PL
+const char * const MSG_ENDSTOP_OPEN_LANG_TABLE[1] PROGMEM = {
+	MSG_ENDSTOP_OPEN_EN
 };
 
 const char MSG_END_FILE_LIST_EN[] PROGMEM = "End file list";
-const char MSG_END_FILE_LIST_CZ[] PROGMEM = "End file list";
-const char MSG_END_FILE_LIST_IT[] PROGMEM = "End file list";
-const char MSG_END_FILE_LIST_ES[] PROGMEM = "End file list";
-const char MSG_END_FILE_LIST_PL[] PROGMEM = "End file list";
-const char * const MSG_END_FILE_LIST_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_END_FILE_LIST_EN,
-	MSG_END_FILE_LIST_CZ,
-	MSG_END_FILE_LIST_IT,
-	MSG_END_FILE_LIST_ES,
-	MSG_END_FILE_LIST_PL
+const char * const MSG_END_FILE_LIST_LANG_TABLE[1] PROGMEM = {
+	MSG_END_FILE_LIST_EN
 };
 
 const char MSG_ERROR_EN[] PROGMEM = "ERROR:";
 const char MSG_ERROR_CZ[] PROGMEM = "CHYBA:";
-const char MSG_ERROR_IT[] PROGMEM = "ERROR:";
-const char MSG_ERROR_ES[] PROGMEM = "ERROR:";
-const char MSG_ERROR_PL[] PROGMEM = "BLAD:";
 const char * const MSG_ERROR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_ERROR_EN,
-	MSG_ERROR_CZ,
-	MSG_ERROR_IT,
-	MSG_ERROR_ES,
-	MSG_ERROR_PL
+	MSG_ERROR_CZ
 };
 
 const char MSG_ERR_CHECKSUM_MISMATCH_EN[] PROGMEM = "checksum mismatch, Last Line: ";
-const char MSG_ERR_CHECKSUM_MISMATCH_CZ[] PROGMEM = "checksum mismatch, Last Line: ";
-const char MSG_ERR_CHECKSUM_MISMATCH_IT[] PROGMEM = "checksum mismatch, Last Line: ";
-const char MSG_ERR_CHECKSUM_MISMATCH_ES[] PROGMEM = "checksum mismatch, Last Line: ";
-const char MSG_ERR_CHECKSUM_MISMATCH_PL[] PROGMEM = "checksum mismatch, Last Line: ";
-const char * const MSG_ERR_CHECKSUM_MISMATCH_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_CHECKSUM_MISMATCH_EN,
-	MSG_ERR_CHECKSUM_MISMATCH_CZ,
-	MSG_ERR_CHECKSUM_MISMATCH_IT,
-	MSG_ERR_CHECKSUM_MISMATCH_ES,
-	MSG_ERR_CHECKSUM_MISMATCH_PL
+const char * const MSG_ERR_CHECKSUM_MISMATCH_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_CHECKSUM_MISMATCH_EN
 };
 
 const char MSG_ERR_COLD_EXTRUDE_STOP_EN[] PROGMEM = " cold extrusion prevented";
-const char MSG_ERR_COLD_EXTRUDE_STOP_CZ[] PROGMEM = " cold extrusion prevented";
-const char MSG_ERR_COLD_EXTRUDE_STOP_IT[] PROGMEM = " cold extrusion prevented";
-const char MSG_ERR_COLD_EXTRUDE_STOP_ES[] PROGMEM = " cold extrusion prevented";
-const char MSG_ERR_COLD_EXTRUDE_STOP_PL[] PROGMEM = " cold extrusion prevented";
-const char * const MSG_ERR_COLD_EXTRUDE_STOP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_COLD_EXTRUDE_STOP_EN,
-	MSG_ERR_COLD_EXTRUDE_STOP_CZ,
-	MSG_ERR_COLD_EXTRUDE_STOP_IT,
-	MSG_ERR_COLD_EXTRUDE_STOP_ES,
-	MSG_ERR_COLD_EXTRUDE_STOP_PL
+const char * const MSG_ERR_COLD_EXTRUDE_STOP_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_COLD_EXTRUDE_STOP_EN
 };
 
 const char MSG_ERR_KILLED_EN[] PROGMEM = "Printer halted. kill() called!";
-const char MSG_ERR_KILLED_CZ[] PROGMEM = "Printer halted. kill() called!";
-const char MSG_ERR_KILLED_IT[] PROGMEM = "Printer halted. kill() called!";
-const char MSG_ERR_KILLED_ES[] PROGMEM = "Printer halted. kill() called!";
-const char MSG_ERR_KILLED_PL[] PROGMEM = "Printer halted. kill() called!";
-const char * const MSG_ERR_KILLED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_KILLED_EN,
-	MSG_ERR_KILLED_CZ,
-	MSG_ERR_KILLED_IT,
-	MSG_ERR_KILLED_ES,
-	MSG_ERR_KILLED_PL
+const char * const MSG_ERR_KILLED_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_KILLED_EN
 };
 
 const char MSG_ERR_LINE_NO_EN[] PROGMEM = "Line Number is not Last Line Number+1, Last Line: ";
-const char MSG_ERR_LINE_NO_CZ[] PROGMEM = "Line Number is not Last Line Number+1, Last Line: ";
-const char MSG_ERR_LINE_NO_IT[] PROGMEM = "Line Number is not Last Line Number+1, Last Line: ";
-const char MSG_ERR_LINE_NO_ES[] PROGMEM = "Line Number is not Last Line Number+1, Last Line: ";
-const char MSG_ERR_LINE_NO_PL[] PROGMEM = "Line Number is not Last Line Number+1, Last Line: ";
-const char * const MSG_ERR_LINE_NO_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_LINE_NO_EN,
-	MSG_ERR_LINE_NO_CZ,
-	MSG_ERR_LINE_NO_IT,
-	MSG_ERR_LINE_NO_ES,
-	MSG_ERR_LINE_NO_PL
+const char * const MSG_ERR_LINE_NO_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_LINE_NO_EN
 };
 
 const char MSG_ERR_LONG_EXTRUDE_STOP_EN[] PROGMEM = " too long extrusion prevented";
-const char MSG_ERR_LONG_EXTRUDE_STOP_CZ[] PROGMEM = " too long extrusion prevented";
-const char MSG_ERR_LONG_EXTRUDE_STOP_IT[] PROGMEM = " too long extrusion prevented";
-const char MSG_ERR_LONG_EXTRUDE_STOP_ES[] PROGMEM = " too long extrusion prevented";
-const char MSG_ERR_LONG_EXTRUDE_STOP_PL[] PROGMEM = " too long extrusion prevented";
-const char * const MSG_ERR_LONG_EXTRUDE_STOP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_LONG_EXTRUDE_STOP_EN,
-	MSG_ERR_LONG_EXTRUDE_STOP_CZ,
-	MSG_ERR_LONG_EXTRUDE_STOP_IT,
-	MSG_ERR_LONG_EXTRUDE_STOP_ES,
-	MSG_ERR_LONG_EXTRUDE_STOP_PL
+const char * const MSG_ERR_LONG_EXTRUDE_STOP_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_LONG_EXTRUDE_STOP_EN
 };
 
 const char MSG_ERR_NO_CHECKSUM_EN[] PROGMEM = "No Checksum with line number, Last Line: ";
-const char MSG_ERR_NO_CHECKSUM_CZ[] PROGMEM = "No Checksum with line number, Last Line: ";
-const char MSG_ERR_NO_CHECKSUM_IT[] PROGMEM = "No Checksum with line number, Last Line: ";
-const char MSG_ERR_NO_CHECKSUM_ES[] PROGMEM = "No Checksum with line number, Last Line: ";
-const char MSG_ERR_NO_CHECKSUM_PL[] PROGMEM = "No Checksum with line number, Last Line: ";
-const char * const MSG_ERR_NO_CHECKSUM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_NO_CHECKSUM_EN,
-	MSG_ERR_NO_CHECKSUM_CZ,
-	MSG_ERR_NO_CHECKSUM_IT,
-	MSG_ERR_NO_CHECKSUM_ES,
-	MSG_ERR_NO_CHECKSUM_PL
+const char * const MSG_ERR_NO_CHECKSUM_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_NO_CHECKSUM_EN
 };
 
 const char MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_EN[] PROGMEM = "No Line Number with checksum, Last Line: ";
-const char MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_CZ[] PROGMEM = "No Line Number with checksum, Last Line: ";
-const char MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_IT[] PROGMEM = "No Line Number with checksum, Last Line: ";
-const char MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_ES[] PROGMEM = "No Line Number with checksum, Last Line: ";
-const char MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_PL[] PROGMEM = "No Line Number with checksum, Last Line: ";
-const char * const MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_EN,
-	MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_CZ,
-	MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_IT,
-	MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_ES,
-	MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_PL
+const char * const MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_EN
 };
 
 const char MSG_ERR_NO_THERMISTORS_EN[] PROGMEM = "No thermistors - no temperature";
-const char MSG_ERR_NO_THERMISTORS_CZ[] PROGMEM = "No thermistors - no temperature";
-const char MSG_ERR_NO_THERMISTORS_IT[] PROGMEM = "No thermistors - no temperature";
-const char MSG_ERR_NO_THERMISTORS_ES[] PROGMEM = "No thermistors - no temperature";
-const char MSG_ERR_NO_THERMISTORS_PL[] PROGMEM = "No thermistors - no temperature";
-const char * const MSG_ERR_NO_THERMISTORS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_NO_THERMISTORS_EN,
-	MSG_ERR_NO_THERMISTORS_CZ,
-	MSG_ERR_NO_THERMISTORS_IT,
-	MSG_ERR_NO_THERMISTORS_ES,
-	MSG_ERR_NO_THERMISTORS_PL
+const char * const MSG_ERR_NO_THERMISTORS_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_NO_THERMISTORS_EN
 };
 
 const char MSG_ERR_STOPPED_EN[] PROGMEM = "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)";
-const char MSG_ERR_STOPPED_CZ[] PROGMEM = "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)";
-const char MSG_ERR_STOPPED_IT[] PROGMEM = "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)";
-const char MSG_ERR_STOPPED_ES[] PROGMEM = "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)";
-const char MSG_ERR_STOPPED_PL[] PROGMEM = "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)";
-const char * const MSG_ERR_STOPPED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ERR_STOPPED_EN,
-	MSG_ERR_STOPPED_CZ,
-	MSG_ERR_STOPPED_IT,
-	MSG_ERR_STOPPED_ES,
-	MSG_ERR_STOPPED_PL
-};
-
-const char MSG_ESTEPS_EN[] PROGMEM = "Esteps/mm";
-const char MSG_ESTEPS_CZ[] PROGMEM = "Esteps/mm";
-const char MSG_ESTEPS_IT[] PROGMEM = "Esteps/mm";
-const char MSG_ESTEPS_ES[] PROGMEM = "Esteps/mm";
-const char MSG_ESTEPS_PL[] PROGMEM = "Esteps/mm";
-const char * const MSG_ESTEPS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ESTEPS_EN,
-	MSG_ESTEPS_CZ,
-	MSG_ESTEPS_IT,
-	MSG_ESTEPS_ES,
-	MSG_ESTEPS_PL
+const char * const MSG_ERR_STOPPED_LANG_TABLE[1] PROGMEM = {
+	MSG_ERR_STOPPED_EN
 };
 
 const char MSG_EXTERNAL_RESET_EN[] PROGMEM = " External Reset";
-const char MSG_EXTERNAL_RESET_CZ[] PROGMEM = " External Reset";
-const char MSG_EXTERNAL_RESET_IT[] PROGMEM = " External Reset";
-const char MSG_EXTERNAL_RESET_ES[] PROGMEM = " External Reset";
-const char MSG_EXTERNAL_RESET_PL[] PROGMEM = " External Reset";
-const char * const MSG_EXTERNAL_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_EXTERNAL_RESET_EN,
-	MSG_EXTERNAL_RESET_CZ,
-	MSG_EXTERNAL_RESET_IT,
-	MSG_EXTERNAL_RESET_ES,
-	MSG_EXTERNAL_RESET_PL
-};
-
-const char MSG_EXTRUDE_EN[] PROGMEM = "Extrude";
-const char MSG_EXTRUDE_CZ[] PROGMEM = "Extrudovat";
-const char MSG_EXTRUDE_IT[] PROGMEM = "Extrude";
-const char MSG_EXTRUDE_ES[] PROGMEM = "Extrude";
-const char MSG_EXTRUDE_PL[] PROGMEM = "Extrudovat";
-const char * const MSG_EXTRUDE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_EXTRUDE_EN,
-	MSG_EXTRUDE_CZ,
-	MSG_EXTRUDE_IT,
-	MSG_EXTRUDE_ES,
-	MSG_EXTRUDE_PL
+const char * const MSG_EXTERNAL_RESET_LANG_TABLE[1] PROGMEM = {
+	MSG_EXTERNAL_RESET_EN
+};
+
+const char MSG_EXTRUDER_EN[] PROGMEM = "Extruder";
+const char * const MSG_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_EXTRUDER_EN
+};
+
+const char MSG_EXTRUDER_1_EN[] PROGMEM = "Extruder 1";
+const char * const MSG_EXTRUDER_1_LANG_TABLE[1] PROGMEM = {
+	MSG_EXTRUDER_1_EN
+};
+
+const char MSG_EXTRUDER_2_EN[] PROGMEM = "Extruder 2";
+const char * const MSG_EXTRUDER_2_LANG_TABLE[1] PROGMEM = {
+	MSG_EXTRUDER_2_EN
+};
+
+const char MSG_EXTRUDER_3_EN[] PROGMEM = "Extruder 3";
+const char * const MSG_EXTRUDER_3_LANG_TABLE[1] PROGMEM = {
+	MSG_EXTRUDER_3_EN
+};
+
+const char MSG_EXTRUDER_4_EN[] PROGMEM = "Extruder 4";
+const char * const MSG_EXTRUDER_4_LANG_TABLE[1] PROGMEM = {
+	MSG_EXTRUDER_4_EN
+};
+
+const char MSG_E_CAL_KNOB_EN[] PROGMEM = "Rotate knob until mark reaches extruder body. Click when done.";
+const char MSG_E_CAL_KNOB_CZ[] PROGMEM = "Otacejte tlacitkem dokud znacka nedosahne tela extruderu. Potvrdte tlacitkem.";
+const char * const MSG_E_CAL_KNOB_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_E_CAL_KNOB_EN,
+	MSG_E_CAL_KNOB_CZ
 };
 
 const char MSG_Enqueing_EN[] PROGMEM = "enqueing \"";
-const char MSG_Enqueing_CZ[] PROGMEM = "enqueing \"";
-const char MSG_Enqueing_IT[] PROGMEM = "enqueing \"";
-const char MSG_Enqueing_ES[] PROGMEM = "enqueing \"";
-const char MSG_Enqueing_PL[] PROGMEM = "enqueing \"";
-const char * const MSG_Enqueing_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Enqueing_EN,
-	MSG_Enqueing_CZ,
-	MSG_Enqueing_IT,
-	MSG_Enqueing_ES,
-	MSG_Enqueing_PL
+const char * const MSG_Enqueing_LANG_TABLE[1] PROGMEM = {
+	MSG_Enqueing_EN
 };
 
 const char MSG_FACTOR_EN[] PROGMEM = " \002 Fact";
-const char MSG_FACTOR_CZ[] PROGMEM = " \002 Fact";
-const char MSG_FACTOR_IT[] PROGMEM = " \002 Fact";
-const char MSG_FACTOR_ES[] PROGMEM = " \002 Fact";
-const char MSG_FACTOR_PL[] PROGMEM = " \002 Fact";
-const char * const MSG_FACTOR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FACTOR_EN,
-	MSG_FACTOR_CZ,
-	MSG_FACTOR_IT,
-	MSG_FACTOR_ES,
-	MSG_FACTOR_PL
+const char * const MSG_FACTOR_LANG_TABLE[1] PROGMEM = {
+	MSG_FACTOR_EN
+};
+
+const char MSG_FANS_CHECK_OFF_EN[] PROGMEM = "Fans check  [off]";
+const char MSG_FANS_CHECK_OFF_CZ[] PROGMEM = "Kontr. vent.[vyp]";
+const char * const MSG_FANS_CHECK_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FANS_CHECK_OFF_EN,
+	MSG_FANS_CHECK_OFF_CZ
+};
+
+const char MSG_FANS_CHECK_ON_EN[] PROGMEM = "Fans check   [on]";
+const char MSG_FANS_CHECK_ON_CZ[] PROGMEM = "Kontr. vent.[zap]";
+const char * const MSG_FANS_CHECK_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FANS_CHECK_ON_EN,
+	MSG_FANS_CHECK_ON_CZ
 };
 
 const char MSG_FAN_SPEED_EN[] PROGMEM = "Fan speed";
 const char MSG_FAN_SPEED_CZ[] PROGMEM = "Rychlost vent.";
-const char MSG_FAN_SPEED_IT[] PROGMEM = "Ventola";
-const char MSG_FAN_SPEED_ES[] PROGMEM = "Ventilador";
-const char MSG_FAN_SPEED_PL[] PROGMEM = "Predkosc went.";
 const char * const MSG_FAN_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FAN_SPEED_EN,
-	MSG_FAN_SPEED_CZ,
-	MSG_FAN_SPEED_IT,
-	MSG_FAN_SPEED_ES,
-	MSG_FAN_SPEED_PL
+	MSG_FAN_SPEED_CZ
+};
+
+const char MSG_FARM_CARD_MENU_EN[] PROGMEM = "Farm mode print";
+const char * const MSG_FARM_CARD_MENU_LANG_TABLE[1] PROGMEM = {
+	MSG_FARM_CARD_MENU_EN
 };
 
 const char MSG_FILAMENTCHANGE_EN[] PROGMEM = "Change filament";
 const char MSG_FILAMENTCHANGE_CZ[] PROGMEM = "Vymenit filament";
-const char MSG_FILAMENTCHANGE_IT[] PROGMEM = "Cambiare filamento";
-const char MSG_FILAMENTCHANGE_ES[] PROGMEM = "Cambiar filamento";
-const char MSG_FILAMENTCHANGE_PL[] PROGMEM = "Wymienic filament";
 const char * const MSG_FILAMENTCHANGE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FILAMENTCHANGE_EN,
-	MSG_FILAMENTCHANGE_CZ,
-	MSG_FILAMENTCHANGE_IT,
-	MSG_FILAMENTCHANGE_ES,
-	MSG_FILAMENTCHANGE_PL
-};
-
-const char MSG_FILAMENT_SIZE_EXTRUDER_0_EN[] PROGMEM = "Fil. Dia. 1";
-const char MSG_FILAMENT_SIZE_EXTRUDER_0_CZ[] PROGMEM = "Fil. Dia. 1";
-const char MSG_FILAMENT_SIZE_EXTRUDER_0_IT[] PROGMEM = "Fil. Dia. 1";
-const char MSG_FILAMENT_SIZE_EXTRUDER_0_ES[] PROGMEM = "Fil. Dia. 1";
-const char MSG_FILAMENT_SIZE_EXTRUDER_0_PL[] PROGMEM = "Fil. Dia. 1";
-const char * const MSG_FILAMENT_SIZE_EXTRUDER_0_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FILAMENT_SIZE_EXTRUDER_0_EN,
-	MSG_FILAMENT_SIZE_EXTRUDER_0_CZ,
-	MSG_FILAMENT_SIZE_EXTRUDER_0_IT,
-	MSG_FILAMENT_SIZE_EXTRUDER_0_ES,
-	MSG_FILAMENT_SIZE_EXTRUDER_0_PL
-};
-
-const char MSG_FILAMENT_SIZE_EXTRUDER_1_EN[] PROGMEM = "Fil. Dia. 2";
-const char MSG_FILAMENT_SIZE_EXTRUDER_1_CZ[] PROGMEM = "Fil. Dia. 2";
-const char MSG_FILAMENT_SIZE_EXTRUDER_1_IT[] PROGMEM = "Fil. Dia. 2";
-const char MSG_FILAMENT_SIZE_EXTRUDER_1_ES[] PROGMEM = "Fil. Dia. 2";
-const char MSG_FILAMENT_SIZE_EXTRUDER_1_PL[] PROGMEM = "Fil. Dia. 2";
-const char * const MSG_FILAMENT_SIZE_EXTRUDER_1_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FILAMENT_SIZE_EXTRUDER_1_EN,
-	MSG_FILAMENT_SIZE_EXTRUDER_1_CZ,
-	MSG_FILAMENT_SIZE_EXTRUDER_1_IT,
-	MSG_FILAMENT_SIZE_EXTRUDER_1_ES,
-	MSG_FILAMENT_SIZE_EXTRUDER_1_PL
-};
-
-const char MSG_FILAMENT_SIZE_EXTRUDER_2_EN[] PROGMEM = "Fil. Dia. 3";
-const char MSG_FILAMENT_SIZE_EXTRUDER_2_CZ[] PROGMEM = "Fil. Dia. 3";
-const char MSG_FILAMENT_SIZE_EXTRUDER_2_IT[] PROGMEM = "Fil. Dia. 3";
-const char MSG_FILAMENT_SIZE_EXTRUDER_2_ES[] PROGMEM = "Fil. Dia. 3";
-const char MSG_FILAMENT_SIZE_EXTRUDER_2_PL[] PROGMEM = "Fil. Dia. 3";
-const char * const MSG_FILAMENT_SIZE_EXTRUDER_2_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FILAMENT_SIZE_EXTRUDER_2_EN,
-	MSG_FILAMENT_SIZE_EXTRUDER_2_CZ,
-	MSG_FILAMENT_SIZE_EXTRUDER_2_IT,
-	MSG_FILAMENT_SIZE_EXTRUDER_2_ES,
-	MSG_FILAMENT_SIZE_EXTRUDER_2_PL
+	MSG_FILAMENTCHANGE_CZ
+};
+
+const char MSG_FILAMENT_CLEAN_EN[] PROGMEM = "Is color clear?";
+const char MSG_FILAMENT_CLEAN_CZ[] PROGMEM = "Je barva cista?";
+const char * const MSG_FILAMENT_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_CLEAN_EN,
+	MSG_FILAMENT_CLEAN_CZ
+};
+
+const char MSG_FILAMENT_LOADING_T0_EN[] PROGMEM = "Insert filament into extruder 1. Click when done.";
+const char MSG_FILAMENT_LOADING_T0_CZ[] PROGMEM = "Vlozte filament do extruderu 1. Potvrdte tlacitkem.";
+const char * const MSG_FILAMENT_LOADING_T0_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T0_EN,
+	MSG_FILAMENT_LOADING_T0_CZ
+};
+
+const char MSG_FILAMENT_LOADING_T1_EN[] PROGMEM = "Insert filament into extruder 2. Click when done.";
+const char MSG_FILAMENT_LOADING_T1_CZ[] PROGMEM = "Vlozte filament do extruderu 2. Potvrdte tlacitkem.";
+const char * const MSG_FILAMENT_LOADING_T1_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T1_EN,
+	MSG_FILAMENT_LOADING_T1_CZ
+};
+
+const char MSG_FILAMENT_LOADING_T2_EN[] PROGMEM = "Insert filament into extruder 3. Click when done.";
+const char MSG_FILAMENT_LOADING_T2_CZ[] PROGMEM = "Vlozte filament do extruderu 3. Potvrdte tlacitkem.";
+const char * const MSG_FILAMENT_LOADING_T2_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T2_EN,
+	MSG_FILAMENT_LOADING_T2_CZ
+};
+
+const char MSG_FILAMENT_LOADING_T3_EN[] PROGMEM = "Insert filament into extruder 4. Click when done.";
+const char MSG_FILAMENT_LOADING_T3_CZ[] PROGMEM = "Vlozte filament do extruderu 4. Potvrdte tlacitkem.";
+const char * const MSG_FILAMENT_LOADING_T3_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T3_EN,
+	MSG_FILAMENT_LOADING_T3_CZ
 };
 
 const char MSG_FILE_PRINTED_EN[] PROGMEM = "Done printing file";
-const char MSG_FILE_PRINTED_CZ[] PROGMEM = "Done printing file";
-const char MSG_FILE_PRINTED_IT[] PROGMEM = "Done printing file";
-const char MSG_FILE_PRINTED_ES[] PROGMEM = "Done printing file";
-const char MSG_FILE_PRINTED_PL[] PROGMEM = "Done printing file";
-const char * const MSG_FILE_PRINTED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FILE_PRINTED_EN,
-	MSG_FILE_PRINTED_CZ,
-	MSG_FILE_PRINTED_IT,
-	MSG_FILE_PRINTED_ES,
-	MSG_FILE_PRINTED_PL
+const char * const MSG_FILE_PRINTED_LANG_TABLE[1] PROGMEM = {
+	MSG_FILE_PRINTED_EN
 };
 
 const char MSG_FILE_SAVED_EN[] PROGMEM = "Done saving file.";
-const char MSG_FILE_SAVED_CZ[] PROGMEM = "Done saving file.";
-const char MSG_FILE_SAVED_IT[] PROGMEM = "Done saving file.";
-const char MSG_FILE_SAVED_ES[] PROGMEM = "Done saving file.";
-const char MSG_FILE_SAVED_PL[] PROGMEM = "Done saving file.";
-const char * const MSG_FILE_SAVED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FILE_SAVED_EN,
-	MSG_FILE_SAVED_CZ,
-	MSG_FILE_SAVED_IT,
-	MSG_FILE_SAVED_ES,
-	MSG_FILE_SAVED_PL
-};
-
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_EN[] PROGMEM = "Searching bed";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_CZ[] PROGMEM = "Hledam kalibracni";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_IT[] PROGMEM = "Searching bed";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_ES[] PROGMEM = "Searching bed";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_PL[] PROGMEM = "Searching bed";
+const char * const MSG_FILE_SAVED_LANG_TABLE[1] PROGMEM = {
+	MSG_FILE_SAVED_EN
+};
+
+const char MSG_FIL_ADJUSTING_EN[] PROGMEM = "Adjusting filaments. Please wait.";
+const char MSG_FIL_ADJUSTING_CZ[] PROGMEM = "Probiha srovnani filamentu. Prosim cekejte.";
+const char * const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FIL_ADJUSTING_EN,
+	MSG_FIL_ADJUSTING_CZ
+};
+
+const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_EN[] PROGMEM = "Iteration ";
+const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_CZ[] PROGMEM = "Iterace ";
+const char * const MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_EN,
+	MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_CZ
+};
+
+const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_EN[] PROGMEM = "Searching bed calibration point";
+const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_CZ[] PROGMEM = "Hledam kalibracni bod podlozky";
 const char * const MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_EN,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_CZ,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_IT,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_ES,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_PL
+	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_CZ
 };
 
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_EN[] PROGMEM = "calibration point";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_CZ[] PROGMEM = "bod podlozky";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_IT[] PROGMEM = "calibration point";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_ES[] PROGMEM = "calibration point";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_PL[] PROGMEM = "calibration point";
+const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_EN[] PROGMEM = " of 4";
+const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_CZ[] PROGMEM = " z 4";
 const char * const MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_EN,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_CZ,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_IT,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_ES,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_PL
+	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_CZ
 };
 
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_EN[] PROGMEM = " of 4";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_CZ[] PROGMEM = " z 4";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_IT[] PROGMEM = " of 4";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_ES[] PROGMEM = " of 4";
-const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_PL[] PROGMEM = " of 4";
-const char * const MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_EN,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_CZ,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_IT,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_ES,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_PL
+const char MSG_FINISHING_MOVEMENTS_EN[] PROGMEM = "Finishing movements";
+const char MSG_FINISHING_MOVEMENTS_CZ[] PROGMEM = "Dokoncovani pohybu";
+const char * const MSG_FINISHING_MOVEMENTS_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FINISHING_MOVEMENTS_EN,
+	MSG_FINISHING_MOVEMENTS_CZ
 };
 
 const char MSG_FLOW_EN[] PROGMEM = "Flow";
 const char MSG_FLOW_CZ[] PROGMEM = "Prutok";
-const char MSG_FLOW_IT[] PROGMEM = "Flusso";
-const char MSG_FLOW_ES[] PROGMEM = "Flujo";
-const char MSG_FLOW_PL[] PROGMEM = "Przeplyw";
 const char * const MSG_FLOW_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FLOW_EN,
-	MSG_FLOW_CZ,
-	MSG_FLOW_IT,
-	MSG_FLOW_ES,
-	MSG_FLOW_PL
+	MSG_FLOW_CZ
 };
 
 const char MSG_FLOW0_EN[] PROGMEM = "Flow 0";
-const char MSG_FLOW0_CZ[] PROGMEM = "Prutok 0";
-const char MSG_FLOW0_IT[] PROGMEM = "Flow 0";
-const char MSG_FLOW0_ES[] PROGMEM = "Flow 0";
-const char MSG_FLOW0_PL[] PROGMEM = "Prutok 0";
-const char * const MSG_FLOW0_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FLOW0_EN,
-	MSG_FLOW0_CZ,
-	MSG_FLOW0_IT,
-	MSG_FLOW0_ES,
-	MSG_FLOW0_PL
+const char * const MSG_FLOW0_LANG_TABLE[1] PROGMEM = {
+	MSG_FLOW0_EN
 };
 
 const char MSG_FLOW1_EN[] PROGMEM = "Flow 1";
-const char MSG_FLOW1_CZ[] PROGMEM = "Prutok 1";
-const char MSG_FLOW1_IT[] PROGMEM = "Flow 1";
-const char MSG_FLOW1_ES[] PROGMEM = "Flow 1";
-const char MSG_FLOW1_PL[] PROGMEM = "Prutok 1";
-const char * const MSG_FLOW1_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FLOW1_EN,
-	MSG_FLOW1_CZ,
-	MSG_FLOW1_IT,
-	MSG_FLOW1_ES,
-	MSG_FLOW1_PL
+const char * const MSG_FLOW1_LANG_TABLE[1] PROGMEM = {
+	MSG_FLOW1_EN
 };
 
 const char MSG_FLOW2_EN[] PROGMEM = "Flow 2";
-const char MSG_FLOW2_CZ[] PROGMEM = "Prutok 2";
-const char MSG_FLOW2_IT[] PROGMEM = "Flow 2";
-const char MSG_FLOW2_ES[] PROGMEM = "Flow 2";
-const char MSG_FLOW2_PL[] PROGMEM = "Prutok 2";
-const char * const MSG_FLOW2_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FLOW2_EN,
-	MSG_FLOW2_CZ,
-	MSG_FLOW2_IT,
-	MSG_FLOW2_ES,
-	MSG_FLOW2_PL
+const char * const MSG_FLOW2_LANG_TABLE[1] PROGMEM = {
+	MSG_FLOW2_EN
+};
+
+const char MSG_FOLLOW_CALIBRATION_FLOW_EN[] PROGMEM = "Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow.";
+const char MSG_FOLLOW_CALIBRATION_FLOW_CZ[] PROGMEM = "Tiskarna nebyla jeste zkalibrovana. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Postup kalibrace.";
+const char * const MSG_FOLLOW_CALIBRATION_FLOW_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FOLLOW_CALIBRATION_FLOW_EN,
+	MSG_FOLLOW_CALIBRATION_FLOW_CZ
 };
 
 const char MSG_FREE_MEMORY_EN[] PROGMEM = " Free Memory: ";
-const char MSG_FREE_MEMORY_CZ[] PROGMEM = " Free Memory: ";
-const char MSG_FREE_MEMORY_IT[] PROGMEM = " Free Memory: ";
-const char MSG_FREE_MEMORY_ES[] PROGMEM = " Free Memory: ";
-const char MSG_FREE_MEMORY_PL[] PROGMEM = " Free Memory: ";
-const char * const MSG_FREE_MEMORY_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_FREE_MEMORY_EN,
-	MSG_FREE_MEMORY_CZ,
-	MSG_FREE_MEMORY_IT,
-	MSG_FREE_MEMORY_ES,
-	MSG_FREE_MEMORY_PL
+const char * const MSG_FREE_MEMORY_LANG_TABLE[1] PROGMEM = {
+	MSG_FREE_MEMORY_EN
+};
+
+const char MSG_FSENSOR_OFF_EN[] PROGMEM = "Fil. sensor [off]";
+const char MSG_FSENSOR_OFF_CZ[] PROGMEM = "Fil. senzor [vyp]";
+const char * const MSG_FSENSOR_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FSENSOR_OFF_EN,
+	MSG_FSENSOR_OFF_CZ
+};
+
+const char MSG_FSENSOR_ON_EN[] PROGMEM = "Fil. sensor  [on]";
+const char MSG_FSENSOR_ON_CZ[] PROGMEM = "Fil. senzor [zap]";
+const char * const MSG_FSENSOR_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FSENSOR_ON_EN,
+	MSG_FSENSOR_ON_CZ
 };
 
 const char MSG_HEATING_EN[] PROGMEM = "Heating";
 const char MSG_HEATING_CZ[] PROGMEM = "Zahrivani";
-const char MSG_HEATING_IT[] PROGMEM = "Riscaldamento...";
-const char MSG_HEATING_ES[] PROGMEM = "Calentando...";
-const char MSG_HEATING_PL[] PROGMEM = "Grzanie...";
 const char * const MSG_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HEATING_EN,
-	MSG_HEATING_CZ,
-	MSG_HEATING_IT,
-	MSG_HEATING_ES,
-	MSG_HEATING_PL
+	MSG_HEATING_CZ
 };
 
 const char MSG_HEATING_COMPLETE_EN[] PROGMEM = "Heating done.";
 const char MSG_HEATING_COMPLETE_CZ[] PROGMEM = "Zahrivani OK.";
-const char MSG_HEATING_COMPLETE_IT[] PROGMEM = "Riscaldamento fatto.";
-const char MSG_HEATING_COMPLETE_ES[] PROGMEM = "Calentando listo.";
-const char MSG_HEATING_COMPLETE_PL[] PROGMEM = "Grzanie OK.";
 const char * const MSG_HEATING_COMPLETE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HEATING_COMPLETE_EN,
-	MSG_HEATING_COMPLETE_CZ,
-	MSG_HEATING_COMPLETE_IT,
-	MSG_HEATING_COMPLETE_ES,
-	MSG_HEATING_COMPLETE_PL
+	MSG_HEATING_COMPLETE_CZ
 };
 
 const char MSG_HOMEYZ_EN[] PROGMEM = "Calibrate Z";
 const char MSG_HOMEYZ_CZ[] PROGMEM = "Kalibrovat Z";
-const char MSG_HOMEYZ_IT[] PROGMEM = "Calibra Z";
-const char MSG_HOMEYZ_ES[] PROGMEM = "Calibrar Z";
-const char MSG_HOMEYZ_PL[] PROGMEM = "Kalibruj Z";
 const char * const MSG_HOMEYZ_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HOMEYZ_EN,
-	MSG_HOMEYZ_CZ,
-	MSG_HOMEYZ_IT,
-	MSG_HOMEYZ_ES,
-	MSG_HOMEYZ_PL
+	MSG_HOMEYZ_CZ
 };
 
 const char MSG_HOMEYZ_DONE_EN[] PROGMEM = "Calibration done";
 const char MSG_HOMEYZ_DONE_CZ[] PROGMEM = "Kalibrace OK";
-const char MSG_HOMEYZ_DONE_IT[] PROGMEM = "Calibratura OK";
-const char MSG_HOMEYZ_DONE_ES[] PROGMEM = "Calibracion OK";
-const char MSG_HOMEYZ_DONE_PL[] PROGMEM = "Kalibracja OK";
 const char * const MSG_HOMEYZ_DONE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HOMEYZ_DONE_EN,
-	MSG_HOMEYZ_DONE_CZ,
-	MSG_HOMEYZ_DONE_IT,
-	MSG_HOMEYZ_DONE_ES,
-	MSG_HOMEYZ_DONE_PL
+	MSG_HOMEYZ_DONE_CZ
 };
 
 const char MSG_HOMEYZ_PROGRESS_EN[] PROGMEM = "Calibrating Z";
 const char MSG_HOMEYZ_PROGRESS_CZ[] PROGMEM = "Kalibruji Z";
-const char MSG_HOMEYZ_PROGRESS_IT[] PROGMEM = "Calibrando Z";
-const char MSG_HOMEYZ_PROGRESS_ES[] PROGMEM = "Calibrando Z";
-const char MSG_HOMEYZ_PROGRESS_PL[] PROGMEM = "Kalibruje Z";
 const char * const MSG_HOMEYZ_PROGRESS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HOMEYZ_PROGRESS_EN,
-	MSG_HOMEYZ_PROGRESS_CZ,
-	MSG_HOMEYZ_PROGRESS_IT,
-	MSG_HOMEYZ_PROGRESS_ES,
-	MSG_HOMEYZ_PROGRESS_PL
+	MSG_HOMEYZ_PROGRESS_CZ
 };
 
 const char MSG_HOTEND_OFFSET_EN[] PROGMEM = "Hotend offsets:";
-const char MSG_HOTEND_OFFSET_CZ[] PROGMEM = "Hotend offsets:";
-const char MSG_HOTEND_OFFSET_IT[] PROGMEM = "Hotend offsets:";
-const char MSG_HOTEND_OFFSET_ES[] PROGMEM = "Hotend offsets:";
-const char MSG_HOTEND_OFFSET_PL[] PROGMEM = "Hotend offsets:";
-const char * const MSG_HOTEND_OFFSET_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_HOTEND_OFFSET_EN,
-	MSG_HOTEND_OFFSET_CZ,
-	MSG_HOTEND_OFFSET_IT,
-	MSG_HOTEND_OFFSET_ES,
-	MSG_HOTEND_OFFSET_PL
-};
-
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_EN[] PROGMEM = "Improving bed";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_CZ[] PROGMEM = "Zlepsuji presnost";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_IT[] PROGMEM = "Improving bed";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_ES[] PROGMEM = "Improving bed";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_PL[] PROGMEM = "Improving bed";
+const char * const MSG_HOTEND_OFFSET_LANG_TABLE[1] PROGMEM = {
+	MSG_HOTEND_OFFSET_EN
+};
+
+const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_EN[] PROGMEM = "Improving bed calibration point";
+const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_CZ[] PROGMEM = "Zlepsuji presnost kalibracniho bodu";
 const char * const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_EN,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_CZ,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_IT,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_ES,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_PL
+	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_CZ
 };
 
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_EN[] PROGMEM = "calibration point";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_CZ[] PROGMEM = "kalibracniho bodu";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_IT[] PROGMEM = "calibration point";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_ES[] PROGMEM = "calibration point";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_PL[] PROGMEM = "calibration point";
+const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_EN[] PROGMEM = " of 4";
+const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_CZ[] PROGMEM = " z 4";
 const char * const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_EN,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_CZ,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_IT,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_ES,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_PL
+	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_CZ
+};
+
+const char MSG_INFO_EXTRUDER_EN[] PROGMEM = "Extruder info";
+const char * const MSG_INFO_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_INFO_EXTRUDER_EN
+};
+
+const char MSG_INFO_FILAMENT_XDIFF_EN[] PROGMEM = "Fil. Xd:";
+const char * const MSG_INFO_FILAMENT_XDIFF_LANG_TABLE[1] PROGMEM = {
+	MSG_INFO_FILAMENT_XDIFF_EN
+};
+
+const char MSG_INFO_FILAMENT_YDIFF_EN[] PROGMEM = "Fil. Ydiff:";
+const char * const MSG_INFO_FILAMENT_YDIFF_LANG_TABLE[1] PROGMEM = {
+	MSG_INFO_FILAMENT_YDIFF_EN
+};
+
+const char MSG_INFO_NOZZLE_FAN_EN[] PROGMEM = "Nozzle FAN:";
+const char * const MSG_INFO_NOZZLE_FAN_LANG_TABLE[1] PROGMEM = {
+	MSG_INFO_NOZZLE_FAN_EN
 };
 
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_EN[] PROGMEM = " of 9";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_CZ[] PROGMEM = " z 9";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_IT[] PROGMEM = " of 9";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_ES[] PROGMEM = " of 9";
-const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_PL[] PROGMEM = " of 9";
-const char * const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_EN,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_CZ,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_IT,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_ES,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_PL
+const char MSG_INFO_PRINT_FAN_EN[] PROGMEM = "Print FAN: ";
+const char * const MSG_INFO_PRINT_FAN_LANG_TABLE[1] PROGMEM = {
+	MSG_INFO_PRINT_FAN_EN
 };
 
 const char MSG_INIT_SDCARD_EN[] PROGMEM = "Init. SD card";
-const char MSG_INIT_SDCARD_CZ[] PROGMEM = "Inic. SD";
-const char MSG_INIT_SDCARD_IT[] PROGMEM = "Init. SD card";
-const char MSG_INIT_SDCARD_ES[] PROGMEM = "Init. SD card";
-const char MSG_INIT_SDCARD_PL[] PROGMEM = "Inic. SD";
-const char * const MSG_INIT_SDCARD_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_INIT_SDCARD_EN,
-	MSG_INIT_SDCARD_CZ,
-	MSG_INIT_SDCARD_IT,
-	MSG_INIT_SDCARD_ES,
-	MSG_INIT_SDCARD_PL
+const char * const MSG_INIT_SDCARD_LANG_TABLE[1] PROGMEM = {
+	MSG_INIT_SDCARD_EN
 };
 
 const char MSG_INSERT_FILAMENT_EN[] PROGMEM = "Insert filament";
 const char MSG_INSERT_FILAMENT_CZ[] PROGMEM = "Vlozte filament";
-const char MSG_INSERT_FILAMENT_IT[] PROGMEM = "Inserire filamento";
-const char MSG_INSERT_FILAMENT_ES[] PROGMEM = "Inserta filamento";
-const char MSG_INSERT_FILAMENT_PL[] PROGMEM = "Wprowadz filament";
 const char * const MSG_INSERT_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_INSERT_FILAMENT_EN,
-	MSG_INSERT_FILAMENT_CZ,
-	MSG_INSERT_FILAMENT_IT,
-	MSG_INSERT_FILAMENT_ES,
-	MSG_INSERT_FILAMENT_PL
+	MSG_INSERT_FILAMENT_CZ
 };
 
 const char MSG_INVALID_EXTRUDER_EN[] PROGMEM = "Invalid extruder";
-const char MSG_INVALID_EXTRUDER_CZ[] PROGMEM = "Invalid extruder";
-const char MSG_INVALID_EXTRUDER_IT[] PROGMEM = "Invalid extruder";
-const char MSG_INVALID_EXTRUDER_ES[] PROGMEM = "Invalid extruder";
-const char MSG_INVALID_EXTRUDER_PL[] PROGMEM = "Invalid extruder";
-const char * const MSG_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_INVALID_EXTRUDER_EN,
-	MSG_INVALID_EXTRUDER_CZ,
-	MSG_INVALID_EXTRUDER_IT,
-	MSG_INVALID_EXTRUDER_ES,
-	MSG_INVALID_EXTRUDER_PL
+const char * const MSG_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_INVALID_EXTRUDER_EN
 };
 
 const char MSG_KILLED_EN[] PROGMEM = "KILLED. ";
-const char MSG_KILLED_CZ[] PROGMEM = "KILLED. ";
-const char MSG_KILLED_IT[] PROGMEM = "UCCISO ";
-const char MSG_KILLED_ES[] PROGMEM = "PARADA DE EMERG.";
-const char MSG_KILLED_PL[] PROGMEM = "KILLED. ";
-const char * const MSG_KILLED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_KILLED_EN,
-	MSG_KILLED_CZ,
-	MSG_KILLED_IT,
-	MSG_KILLED_ES,
-	MSG_KILLED_PL
+const char * const MSG_KILLED_LANG_TABLE[1] PROGMEM = {
+	MSG_KILLED_EN
 };
 
 const char MSG_LANGUAGE_NAME_EN[] PROGMEM = "English";
 const char MSG_LANGUAGE_NAME_CZ[] PROGMEM = "Cestina";
-const char MSG_LANGUAGE_NAME_IT[] PROGMEM = "Italiano";
-const char MSG_LANGUAGE_NAME_ES[] PROGMEM = "Espanol";
-const char MSG_LANGUAGE_NAME_PL[] PROGMEM = "Polski";
 const char * const MSG_LANGUAGE_NAME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LANGUAGE_NAME_EN,
-	MSG_LANGUAGE_NAME_CZ,
-	MSG_LANGUAGE_NAME_IT,
-	MSG_LANGUAGE_NAME_ES,
-	MSG_LANGUAGE_NAME_PL
+	MSG_LANGUAGE_NAME_CZ
 };
 
-const char MSG_LANGUAGE_SELECT_EN[] PROGMEM = "Select language     ";
-const char MSG_LANGUAGE_SELECT_CZ[] PROGMEM = "Vyber jazyka        ";
-const char MSG_LANGUAGE_SELECT_IT[] PROGMEM = "Selez. la lingua";
-const char MSG_LANGUAGE_SELECT_ES[] PROGMEM = "Cambia la lengua ";
-const char MSG_LANGUAGE_SELECT_PL[] PROGMEM = "Wybor jezyka        ";
+const char MSG_LANGUAGE_SELECT_EN[] PROGMEM = "Select language";
+const char MSG_LANGUAGE_SELECT_CZ[] PROGMEM = "Vyber jazyka";
 const char * const MSG_LANGUAGE_SELECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LANGUAGE_SELECT_EN,
-	MSG_LANGUAGE_SELECT_CZ,
-	MSG_LANGUAGE_SELECT_IT,
-	MSG_LANGUAGE_SELECT_ES,
-	MSG_LANGUAGE_SELECT_PL
+	MSG_LANGUAGE_SELECT_CZ
+};
+
+const char MSG_LEFT_EN[] PROGMEM = "Left:";
+const char MSG_LEFT_CZ[] PROGMEM = "Levy:";
+const char * const MSG_LEFT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LEFT_EN,
+	MSG_LEFT_CZ
 };
 
 const char MSG_LOADING_COLOR_EN[] PROGMEM = "Loading color";
 const char MSG_LOADING_COLOR_CZ[] PROGMEM = "Cisteni barvy";
-const char MSG_LOADING_COLOR_IT[] PROGMEM = "Cargando color";
-const char MSG_LOADING_COLOR_ES[] PROGMEM = "Cargando color";
-const char MSG_LOADING_COLOR_PL[] PROGMEM = "Czyszcz. koloru";
 const char * const MSG_LOADING_COLOR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOADING_COLOR_EN,
-	MSG_LOADING_COLOR_CZ,
-	MSG_LOADING_COLOR_IT,
-	MSG_LOADING_COLOR_ES,
-	MSG_LOADING_COLOR_PL
+	MSG_LOADING_COLOR_CZ
 };
 
 const char MSG_LOADING_FILAMENT_EN[] PROGMEM = "Loading filament";
 const char MSG_LOADING_FILAMENT_CZ[] PROGMEM = "Zavadeni filamentu";
-const char MSG_LOADING_FILAMENT_IT[] PROGMEM = "Cargando fil.";
-const char MSG_LOADING_FILAMENT_ES[] PROGMEM = "Cargando fil.";
-const char MSG_LOADING_FILAMENT_PL[] PROGMEM = "Wprow. filamentu";
 const char * const MSG_LOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOADING_FILAMENT_EN,
-	MSG_LOADING_FILAMENT_CZ,
-	MSG_LOADING_FILAMENT_IT,
-	MSG_LOADING_FILAMENT_ES,
-	MSG_LOADING_FILAMENT_PL
+	MSG_LOADING_FILAMENT_CZ
+};
+
+const char MSG_LOAD_ALL_EN[] PROGMEM = "Load all";
+const char MSG_LOAD_ALL_CZ[] PROGMEM = "Zavest vse";
+const char * const MSG_LOAD_ALL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOAD_ALL_EN,
+	MSG_LOAD_ALL_CZ
 };
 
 const char MSG_LOAD_EPROM_EN[] PROGMEM = "Load memory";
-const char MSG_LOAD_EPROM_CZ[] PROGMEM = "Ulozit pamet";
-const char MSG_LOAD_EPROM_IT[] PROGMEM = "Load memory";
-const char MSG_LOAD_EPROM_ES[] PROGMEM = "Load memory";
-const char MSG_LOAD_EPROM_PL[] PROGMEM = "Ulozit pamet";
-const char * const MSG_LOAD_EPROM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_LOAD_EPROM_EN,
-	MSG_LOAD_EPROM_CZ,
-	MSG_LOAD_EPROM_IT,
-	MSG_LOAD_EPROM_ES,
-	MSG_LOAD_EPROM_PL
+const char * const MSG_LOAD_EPROM_LANG_TABLE[1] PROGMEM = {
+	MSG_LOAD_EPROM_EN
 };
 
 const char MSG_LOAD_FILAMENT_EN[] PROGMEM = "Load filament";
 const char MSG_LOAD_FILAMENT_CZ[] PROGMEM = "Zavest filament";
-const char MSG_LOAD_FILAMENT_IT[] PROGMEM = "Caricare filamento";
-const char MSG_LOAD_FILAMENT_ES[] PROGMEM = "Introducir filamento";
-const char MSG_LOAD_FILAMENT_PL[] PROGMEM = "Wprowadz filament";
 const char * const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOAD_FILAMENT_EN,
-	MSG_LOAD_FILAMENT_CZ,
-	MSG_LOAD_FILAMENT_IT,
-	MSG_LOAD_FILAMENT_ES,
-	MSG_LOAD_FILAMENT_PL
+	MSG_LOAD_FILAMENT_CZ
+};
+
+const char MSG_LOAD_FILAMENT_1_EN[] PROGMEM = "Load filament 1";
+const char MSG_LOAD_FILAMENT_1_CZ[] PROGMEM = "Zavest filament 1";
+const char * const MSG_LOAD_FILAMENT_1_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOAD_FILAMENT_1_EN,
+	MSG_LOAD_FILAMENT_1_CZ
+};
+
+const char MSG_LOAD_FILAMENT_2_EN[] PROGMEM = "Load filament 2";
+const char MSG_LOAD_FILAMENT_2_CZ[] PROGMEM = "Zavest filament 2";
+const char * const MSG_LOAD_FILAMENT_2_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOAD_FILAMENT_2_EN,
+	MSG_LOAD_FILAMENT_2_CZ
+};
+
+const char MSG_LOAD_FILAMENT_3_EN[] PROGMEM = "Load filament 3";
+const char MSG_LOAD_FILAMENT_3_CZ[] PROGMEM = "Zavest filament 3";
+const char * const MSG_LOAD_FILAMENT_3_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOAD_FILAMENT_3_EN,
+	MSG_LOAD_FILAMENT_3_CZ
+};
+
+const char MSG_LOAD_FILAMENT_4_EN[] PROGMEM = "Load filament 4";
+const char MSG_LOAD_FILAMENT_4_CZ[] PROGMEM = "Zavest filament 4";
+const char * const MSG_LOAD_FILAMENT_4_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOAD_FILAMENT_4_EN,
+	MSG_LOAD_FILAMENT_4_CZ
+};
+
+const char MSG_LOOSE_PULLEY_EN[] PROGMEM = "Loose pulley";
+const char MSG_LOOSE_PULLEY_CZ[] PROGMEM = "Uvolnena remenicka";
+const char * const MSG_LOOSE_PULLEY_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOOSE_PULLEY_EN,
+	MSG_LOOSE_PULLEY_CZ
 };
 
 const char MSG_M104_INVALID_EXTRUDER_EN[] PROGMEM = "M104 Invalid extruder ";
-const char MSG_M104_INVALID_EXTRUDER_CZ[] PROGMEM = "M104 Invalid extruder ";
-const char MSG_M104_INVALID_EXTRUDER_IT[] PROGMEM = "M104 Invalid extruder ";
-const char MSG_M104_INVALID_EXTRUDER_ES[] PROGMEM = "M104 Invalid extruder ";
-const char MSG_M104_INVALID_EXTRUDER_PL[] PROGMEM = "M104 Invalid extruder ";
-const char * const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M104_INVALID_EXTRUDER_EN,
-	MSG_M104_INVALID_EXTRUDER_CZ,
-	MSG_M104_INVALID_EXTRUDER_IT,
-	MSG_M104_INVALID_EXTRUDER_ES,
-	MSG_M104_INVALID_EXTRUDER_PL
+const char * const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_M104_INVALID_EXTRUDER_EN
 };
 
 const char MSG_M105_INVALID_EXTRUDER_EN[] PROGMEM = "M105 Invalid extruder ";
-const char MSG_M105_INVALID_EXTRUDER_CZ[] PROGMEM = "M105 Invalid extruder ";
-const char MSG_M105_INVALID_EXTRUDER_IT[] PROGMEM = "M105 Invalid extruder ";
-const char MSG_M105_INVALID_EXTRUDER_ES[] PROGMEM = "M105 Invalid extruder ";
-const char MSG_M105_INVALID_EXTRUDER_PL[] PROGMEM = "M105 Invalid extruder ";
-const char * const MSG_M105_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M105_INVALID_EXTRUDER_EN,
-	MSG_M105_INVALID_EXTRUDER_CZ,
-	MSG_M105_INVALID_EXTRUDER_IT,
-	MSG_M105_INVALID_EXTRUDER_ES,
-	MSG_M105_INVALID_EXTRUDER_PL
+const char * const MSG_M105_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_M105_INVALID_EXTRUDER_EN
 };
 
 const char MSG_M109_INVALID_EXTRUDER_EN[] PROGMEM = "M109 Invalid extruder ";
-const char MSG_M109_INVALID_EXTRUDER_CZ[] PROGMEM = "M109 Invalid extruder ";
-const char MSG_M109_INVALID_EXTRUDER_IT[] PROGMEM = "M109 Invalid extruder ";
-const char MSG_M109_INVALID_EXTRUDER_ES[] PROGMEM = "M109 Invalid extruder ";
-const char MSG_M109_INVALID_EXTRUDER_PL[] PROGMEM = "M109 Invalid extruder ";
-const char * const MSG_M109_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M109_INVALID_EXTRUDER_EN,
-	MSG_M109_INVALID_EXTRUDER_CZ,
-	MSG_M109_INVALID_EXTRUDER_IT,
-	MSG_M109_INVALID_EXTRUDER_ES,
-	MSG_M109_INVALID_EXTRUDER_PL
+const char * const MSG_M109_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_M109_INVALID_EXTRUDER_EN
 };
 
 const char MSG_M115_REPORT_EN[] PROGMEM = "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:https://github.com/prusa3d/Prusa-i3-Plus/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000\n";
-const char MSG_M115_REPORT_CZ[] PROGMEM = "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:https://github.com/prusa3d/Prusa-i3-Plus/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000\n";
-const char MSG_M115_REPORT_IT[] PROGMEM = "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:https://github.com/prusa3d/Prusa-i3-Plus/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000\n";
-const char MSG_M115_REPORT_ES[] PROGMEM = "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:https://github.com/prusa3d/Prusa-i3-Plus/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000\n";
-const char MSG_M115_REPORT_PL[] PROGMEM = "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:https://github.com/prusa3d/Prusa-i3-Plus/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000\n";
-const char * const MSG_M115_REPORT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M115_REPORT_EN,
-	MSG_M115_REPORT_CZ,
-	MSG_M115_REPORT_IT,
-	MSG_M115_REPORT_ES,
-	MSG_M115_REPORT_PL
+const char * const MSG_M115_REPORT_LANG_TABLE[1] PROGMEM = {
+	MSG_M115_REPORT_EN
+};
+
+const char MSG_M117_V2_CALIBRATION_EN[] PROGMEM = "M117 First layer cal.";
+const char MSG_M117_V2_CALIBRATION_CZ[] PROGMEM = "M117 Kal. prvni vrstvy";
+const char * const MSG_M117_V2_CALIBRATION_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_M117_V2_CALIBRATION_EN,
+	MSG_M117_V2_CALIBRATION_CZ
 };
 
 const char MSG_M119_REPORT_EN[] PROGMEM = "Reporting endstop status";
-const char MSG_M119_REPORT_CZ[] PROGMEM = "Reporting endstop status";
-const char MSG_M119_REPORT_IT[] PROGMEM = "Reporting endstop status";
-const char MSG_M119_REPORT_ES[] PROGMEM = "Reporting endstop status";
-const char MSG_M119_REPORT_PL[] PROGMEM = "Reporting endstop status";
-const char * const MSG_M119_REPORT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M119_REPORT_EN,
-	MSG_M119_REPORT_CZ,
-	MSG_M119_REPORT_IT,
-	MSG_M119_REPORT_ES,
-	MSG_M119_REPORT_PL
+const char * const MSG_M119_REPORT_LANG_TABLE[1] PROGMEM = {
+	MSG_M119_REPORT_EN
 };
 
 const char MSG_M200_INVALID_EXTRUDER_EN[] PROGMEM = "M200 Invalid extruder ";
-const char MSG_M200_INVALID_EXTRUDER_CZ[] PROGMEM = "M200 Invalid extruder ";
-const char MSG_M200_INVALID_EXTRUDER_IT[] PROGMEM = "M200 Invalid extruder ";
-const char MSG_M200_INVALID_EXTRUDER_ES[] PROGMEM = "M200 Invalid extruder ";
-const char MSG_M200_INVALID_EXTRUDER_PL[] PROGMEM = "M200 Invalid extruder ";
-const char * const MSG_M200_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M200_INVALID_EXTRUDER_EN,
-	MSG_M200_INVALID_EXTRUDER_CZ,
-	MSG_M200_INVALID_EXTRUDER_IT,
-	MSG_M200_INVALID_EXTRUDER_ES,
-	MSG_M200_INVALID_EXTRUDER_PL
+const char * const MSG_M200_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_M200_INVALID_EXTRUDER_EN
 };
 
 const char MSG_M218_INVALID_EXTRUDER_EN[] PROGMEM = "M218 Invalid extruder ";
-const char MSG_M218_INVALID_EXTRUDER_CZ[] PROGMEM = "M218 Invalid extruder ";
-const char MSG_M218_INVALID_EXTRUDER_IT[] PROGMEM = "M218 Invalid extruder ";
-const char MSG_M218_INVALID_EXTRUDER_ES[] PROGMEM = "M218 Invalid extruder ";
-const char MSG_M218_INVALID_EXTRUDER_PL[] PROGMEM = "M218 Invalid extruder ";
-const char * const MSG_M218_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M218_INVALID_EXTRUDER_EN,
-	MSG_M218_INVALID_EXTRUDER_CZ,
-	MSG_M218_INVALID_EXTRUDER_IT,
-	MSG_M218_INVALID_EXTRUDER_ES,
-	MSG_M218_INVALID_EXTRUDER_PL
+const char * const MSG_M218_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_M218_INVALID_EXTRUDER_EN
 };
 
 const char MSG_M221_INVALID_EXTRUDER_EN[] PROGMEM = "M221 Invalid extruder ";
-const char MSG_M221_INVALID_EXTRUDER_CZ[] PROGMEM = "M221 Invalid extruder ";
-const char MSG_M221_INVALID_EXTRUDER_IT[] PROGMEM = "M221 Invalid extruder ";
-const char MSG_M221_INVALID_EXTRUDER_ES[] PROGMEM = "M221 Invalid extruder ";
-const char MSG_M221_INVALID_EXTRUDER_PL[] PROGMEM = "M221 Invalid extruder ";
-const char * const MSG_M221_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_M221_INVALID_EXTRUDER_EN,
-	MSG_M221_INVALID_EXTRUDER_CZ,
-	MSG_M221_INVALID_EXTRUDER_IT,
-	MSG_M221_INVALID_EXTRUDER_ES,
-	MSG_M221_INVALID_EXTRUDER_PL
+const char * const MSG_M221_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
+	MSG_M221_INVALID_EXTRUDER_EN
 };
 
 const char MSG_MAIN_EN[] PROGMEM = "Main";
 const char MSG_MAIN_CZ[] PROGMEM = "Hlavni nabidka";
-const char MSG_MAIN_IT[] PROGMEM = "Menu principale";
-const char MSG_MAIN_ES[] PROGMEM = "Menu principal";
-const char MSG_MAIN_PL[] PROGMEM = "Menu glowne";
 const char * const MSG_MAIN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MAIN_EN,
-	MSG_MAIN_CZ,
-	MSG_MAIN_IT,
-	MSG_MAIN_ES,
-	MSG_MAIN_PL
+	MSG_MAIN_CZ
+};
+
+const char MSG_MARK_FIL_EN[] PROGMEM = "Mark filament 100mm from extruder body. Click when done.";
+const char MSG_MARK_FIL_CZ[] PROGMEM = "Oznacte filament 100 mm od tela extruderu a po te potvrdte tlacitkem.";
+const char * const MSG_MARK_FIL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MARK_FIL_EN,
+	MSG_MARK_FIL_CZ
 };
 
 const char MSG_MAX_EN[] PROGMEM = " \002 Max";
-const char MSG_MAX_CZ[] PROGMEM = " \002 Max";
-const char MSG_MAX_IT[] PROGMEM = " \002 Max";
-const char MSG_MAX_ES[] PROGMEM = " \002 Max";
-const char MSG_MAX_PL[] PROGMEM = " \002 Max";
-const char * const MSG_MAX_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MAX_EN,
-	MSG_MAX_CZ,
-	MSG_MAX_IT,
-	MSG_MAX_ES,
-	MSG_MAX_PL
+const char * const MSG_MAX_LANG_TABLE[1] PROGMEM = {
+	MSG_MAX_EN
+};
+
+const char MSG_MEASURED_SKEW_EN[] PROGMEM = "Measured skew:";
+const char MSG_MEASURED_SKEW_CZ[] PROGMEM = "Merene zkoseni:";
+const char * const MSG_MEASURED_SKEW_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MEASURED_SKEW_EN,
+	MSG_MEASURED_SKEW_CZ
+};
+
+const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_EN[] PROGMEM = "Measuring reference height of calibration point";
+const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_CZ[] PROGMEM = "Merim referencni vysku kalibracniho bodu";
+const char * const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_EN,
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_CZ
+};
+
+const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_EN[] PROGMEM = " of 9";
+const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_CZ[] PROGMEM = " z 9";
+const char * const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_EN,
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_CZ
+};
+
+const char MSG_MENU_CALIBRATION_EN[] PROGMEM = "Calibration";
+const char MSG_MENU_CALIBRATION_CZ[] PROGMEM = "Kalibrace";
+const char * const MSG_MENU_CALIBRATION_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MENU_CALIBRATION_EN,
+	MSG_MENU_CALIBRATION_CZ
+};
+
+const char MSG_MESH_BED_LEVELING_EN[] PROGMEM = "Mesh Bed Leveling";
+const char * const MSG_MESH_BED_LEVELING_LANG_TABLE[1] PROGMEM = {
+	MSG_MESH_BED_LEVELING_EN
 };
 
 const char MSG_MIN_EN[] PROGMEM = " \002 Min";
-const char MSG_MIN_CZ[] PROGMEM = " \002 Min";
-const char MSG_MIN_IT[] PROGMEM = " \002 Min";
-const char MSG_MIN_ES[] PROGMEM = " \002 Min";
-const char MSG_MIN_PL[] PROGMEM = " \002 Min";
-const char * const MSG_MIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MIN_EN,
-	MSG_MIN_CZ,
-	MSG_MIN_IT,
-	MSG_MIN_ES,
-	MSG_MIN_PL
+const char * const MSG_MIN_LANG_TABLE[1] PROGMEM = {
+	MSG_MIN_EN
 };
 
 const char MSG_MOTION_EN[] PROGMEM = "Motion";
-const char MSG_MOTION_CZ[] PROGMEM = "Pohyb";
-const char MSG_MOTION_IT[] PROGMEM = "Motion";
-const char MSG_MOTION_ES[] PROGMEM = "Motion";
-const char MSG_MOTION_PL[] PROGMEM = "Pohyb";
-const char * const MSG_MOTION_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOTION_EN,
-	MSG_MOTION_CZ,
-	MSG_MOTION_IT,
-	MSG_MOTION_ES,
-	MSG_MOTION_PL
+const char * const MSG_MOTION_LANG_TABLE[1] PROGMEM = {
+	MSG_MOTION_EN
 };
 
 const char MSG_MOVE_01MM_EN[] PROGMEM = "Move 0.1mm";
-const char MSG_MOVE_01MM_CZ[] PROGMEM = "Posunout o 0.1mm";
-const char MSG_MOVE_01MM_IT[] PROGMEM = "Move 0.1mm";
-const char MSG_MOVE_01MM_ES[] PROGMEM = "Move 0.1mm";
-const char MSG_MOVE_01MM_PL[] PROGMEM = "Posunout o 0.1mm";
-const char * const MSG_MOVE_01MM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOVE_01MM_EN,
-	MSG_MOVE_01MM_CZ,
-	MSG_MOVE_01MM_IT,
-	MSG_MOVE_01MM_ES,
-	MSG_MOVE_01MM_PL
+const char * const MSG_MOVE_01MM_LANG_TABLE[1] PROGMEM = {
+	MSG_MOVE_01MM_EN
 };
 
 const char MSG_MOVE_10MM_EN[] PROGMEM = "Move 10mm";
-const char MSG_MOVE_10MM_CZ[] PROGMEM = "Posunout o 10mm";
-const char MSG_MOVE_10MM_IT[] PROGMEM = "Move 10mm";
-const char MSG_MOVE_10MM_ES[] PROGMEM = "Move 10mm";
-const char MSG_MOVE_10MM_PL[] PROGMEM = "Posunout o 10mm";
-const char * const MSG_MOVE_10MM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOVE_10MM_EN,
-	MSG_MOVE_10MM_CZ,
-	MSG_MOVE_10MM_IT,
-	MSG_MOVE_10MM_ES,
-	MSG_MOVE_10MM_PL
+const char * const MSG_MOVE_10MM_LANG_TABLE[1] PROGMEM = {
+	MSG_MOVE_10MM_EN
 };
 
 const char MSG_MOVE_1MM_EN[] PROGMEM = "Move 1mm";
-const char MSG_MOVE_1MM_CZ[] PROGMEM = "Posunout o 1mm";
-const char MSG_MOVE_1MM_IT[] PROGMEM = "Move 1mm";
-const char MSG_MOVE_1MM_ES[] PROGMEM = "Move 1mm";
-const char MSG_MOVE_1MM_PL[] PROGMEM = "Posunout o 1mm";
-const char * const MSG_MOVE_1MM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOVE_1MM_EN,
-	MSG_MOVE_1MM_CZ,
-	MSG_MOVE_1MM_IT,
-	MSG_MOVE_1MM_ES,
-	MSG_MOVE_1MM_PL
+const char * const MSG_MOVE_1MM_LANG_TABLE[1] PROGMEM = {
+	MSG_MOVE_1MM_EN
 };
 
 const char MSG_MOVE_AXIS_EN[] PROGMEM = "Move axis";
 const char MSG_MOVE_AXIS_CZ[] PROGMEM = "Posunout osu";
-const char MSG_MOVE_AXIS_IT[] PROGMEM = "Muovi Asse";
-const char MSG_MOVE_AXIS_ES[] PROGMEM = "Mover ejes";
-const char MSG_MOVE_AXIS_PL[] PROGMEM = "Ruch osi";
 const char * const MSG_MOVE_AXIS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_AXIS_EN,
-	MSG_MOVE_AXIS_CZ,
-	MSG_MOVE_AXIS_IT,
-	MSG_MOVE_AXIS_ES,
-	MSG_MOVE_AXIS_PL
+	MSG_MOVE_AXIS_CZ
 };
 
-const char MSG_MOVE_CARRIAGE_TO_THE_TOP_EN[] PROGMEM = "Calibrating X/Y. Move Z carriage up to the end stoppers. Click when done.";
-const char MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ[] PROGMEM = "Kalibrace X/Y. Posunte prosim Z osu az k~hornimu dorazu. Potvrdte tlacitkem.";
-const char MSG_MOVE_CARRIAGE_TO_THE_TOP_IT[] PROGMEM = "Calibrating X/Y. Move Z carriage up to the end stoppers. Click when done.";
-const char MSG_MOVE_CARRIAGE_TO_THE_TOP_ES[] PROGMEM = "Calibrating X/Y. Move Z carriage up to the end stoppers. Click when done.";
-const char MSG_MOVE_CARRIAGE_TO_THE_TOP_PL[] PROGMEM = "Calibrating X/Y. Move Z carriage up to the end stoppers. Click when done.";
+const char MSG_MOVE_CARRIAGE_TO_THE_TOP_EN[] PROGMEM = "Calibrating XYZ. Rotate the knob to move the Z carriage up to the end stoppers. Click when done.";
+const char MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ[] PROGMEM = "Kalibrace XYZ. Otacenim tlacitka posunte Z osu az k~hornimu dorazu. Potvrdte tlacitkem.";
 const char * const MSG_MOVE_CARRIAGE_TO_THE_TOP_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_EN,
-	MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ,
-	MSG_MOVE_CARRIAGE_TO_THE_TOP_IT,
-	MSG_MOVE_CARRIAGE_TO_THE_TOP_ES,
-	MSG_MOVE_CARRIAGE_TO_THE_TOP_PL
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ
+};
+
+const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_EN[] PROGMEM = "Calibrating Z. Rotate the knob to move the Z carriage up to the end stoppers. Click when done.";
+const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_CZ[] PROGMEM = "Kalibrace Z. Otacenim tlacitka posunte Z osu az k~hornimu dorazu. Potvrdte tlacitkem.";
+const char * const MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_EN,
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_CZ
 };
 
 const char MSG_MOVE_E_EN[] PROGMEM = "Extruder";
-const char MSG_MOVE_E_CZ[] PROGMEM = "Extruder";
-const char MSG_MOVE_E_IT[] PROGMEM = "Estrusore";
-const char MSG_MOVE_E_ES[] PROGMEM = "Extrusor";
-const char MSG_MOVE_E_PL[] PROGMEM = "Extruder";
-const char * const MSG_MOVE_E_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOVE_E_EN,
-	MSG_MOVE_E_CZ,
-	MSG_MOVE_E_IT,
-	MSG_MOVE_E_ES,
-	MSG_MOVE_E_PL
-};
-
-const char MSG_MOVE_E1_EN[] PROGMEM = "Extruder2";
-const char MSG_MOVE_E1_CZ[] PROGMEM = "Extruder2";
-const char MSG_MOVE_E1_IT[] PROGMEM = "Extruder2";
-const char MSG_MOVE_E1_ES[] PROGMEM = "Extruder2";
-const char MSG_MOVE_E1_PL[] PROGMEM = "Extruder2";
-const char * const MSG_MOVE_E1_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOVE_E1_EN,
-	MSG_MOVE_E1_CZ,
-	MSG_MOVE_E1_IT,
-	MSG_MOVE_E1_ES,
-	MSG_MOVE_E1_PL
-};
-
-const char MSG_MOVE_E2_EN[] PROGMEM = "Extruder3";
-const char MSG_MOVE_E2_CZ[] PROGMEM = "Extruder3";
-const char MSG_MOVE_E2_IT[] PROGMEM = "Extruder3";
-const char MSG_MOVE_E2_ES[] PROGMEM = "Extruder3";
-const char MSG_MOVE_E2_PL[] PROGMEM = "Extruder3";
-const char * const MSG_MOVE_E2_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_MOVE_E2_EN,
-	MSG_MOVE_E2_CZ,
-	MSG_MOVE_E2_IT,
-	MSG_MOVE_E2_ES,
-	MSG_MOVE_E2_PL
+const char * const MSG_MOVE_E_LANG_TABLE[1] PROGMEM = {
+	MSG_MOVE_E_EN
 };
 
 const char MSG_MOVE_X_EN[] PROGMEM = "Move X";
 const char MSG_MOVE_X_CZ[] PROGMEM = "Posunout X";
-const char MSG_MOVE_X_IT[] PROGMEM = "Muovi X";
-const char MSG_MOVE_X_ES[] PROGMEM = "Mover X";
-const char MSG_MOVE_X_PL[] PROGMEM = "Przesunac X";
 const char * const MSG_MOVE_X_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_X_EN,
-	MSG_MOVE_X_CZ,
-	MSG_MOVE_X_IT,
-	MSG_MOVE_X_ES,
-	MSG_MOVE_X_PL
+	MSG_MOVE_X_CZ
 };
 
 const char MSG_MOVE_Y_EN[] PROGMEM = "Move Y";
 const char MSG_MOVE_Y_CZ[] PROGMEM = "Posunout Y";
-const char MSG_MOVE_Y_IT[] PROGMEM = "Muovi Y";
-const char MSG_MOVE_Y_ES[] PROGMEM = "Mover Y";
-const char MSG_MOVE_Y_PL[] PROGMEM = "Przesunac Y";
 const char * const MSG_MOVE_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_Y_EN,
-	MSG_MOVE_Y_CZ,
-	MSG_MOVE_Y_IT,
-	MSG_MOVE_Y_ES,
-	MSG_MOVE_Y_PL
+	MSG_MOVE_Y_CZ
 };
 
 const char MSG_MOVE_Z_EN[] PROGMEM = "Move Z";
 const char MSG_MOVE_Z_CZ[] PROGMEM = "Posunout Z";
-const char MSG_MOVE_Z_IT[] PROGMEM = "Muovi Z";
-const char MSG_MOVE_Z_ES[] PROGMEM = "Mover Z";
-const char MSG_MOVE_Z_PL[] PROGMEM = "Przesunac Z";
 const char * const MSG_MOVE_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_Z_EN,
-	MSG_MOVE_Z_CZ,
-	MSG_MOVE_Z_IT,
-	MSG_MOVE_Z_ES,
-	MSG_MOVE_Z_PL
+	MSG_MOVE_Z_CZ
 };
 
 const char MSG_NEW_FIRMWARE_AVAILABLE_EN[] PROGMEM = "New firmware version available:";
 const char MSG_NEW_FIRMWARE_AVAILABLE_CZ[] PROGMEM = "Vysla nova verze firmware:";
-const char MSG_NEW_FIRMWARE_AVAILABLE_IT[] PROGMEM = "New firmware version available:";
-const char MSG_NEW_FIRMWARE_AVAILABLE_ES[] PROGMEM = "New firmware version available:";
-const char MSG_NEW_FIRMWARE_AVAILABLE_PL[] PROGMEM = "New firmware version available:";
 const char * const MSG_NEW_FIRMWARE_AVAILABLE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NEW_FIRMWARE_AVAILABLE_EN,
-	MSG_NEW_FIRMWARE_AVAILABLE_CZ,
-	MSG_NEW_FIRMWARE_AVAILABLE_IT,
-	MSG_NEW_FIRMWARE_AVAILABLE_ES,
-	MSG_NEW_FIRMWARE_AVAILABLE_PL
+	MSG_NEW_FIRMWARE_AVAILABLE_CZ
 };
 
 const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_EN[] PROGMEM = "Please upgrade.";
 const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ[] PROGMEM = "Prosim aktualizujte.";
-const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_IT[] PROGMEM = "Please upgrade.";
-const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_ES[] PROGMEM = "Please upgrade.";
-const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL[] PROGMEM = "Please upgrade.";
 const char * const MSG_NEW_FIRMWARE_PLEASE_UPGRADE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_EN,
-	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ,
-	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_IT,
-	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_ES,
-	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL
+	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ
 };
 
 const char MSG_NO_EN[] PROGMEM = "No";
 const char MSG_NO_CZ[] PROGMEM = "Ne";
-const char MSG_NO_IT[] PROGMEM = "No";
-const char MSG_NO_ES[] PROGMEM = "No";
-const char MSG_NO_PL[] PROGMEM = "Nie";
 const char * const MSG_NO_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NO_EN,
-	MSG_NO_CZ,
-	MSG_NO_IT,
-	MSG_NO_ES,
-	MSG_NO_PL
+	MSG_NO_CZ
 };
 
 const char MSG_NOT_COLOR_EN[] PROGMEM = "Color not clear";
 const char MSG_NOT_COLOR_CZ[] PROGMEM = "Barva neni cista";
-const char MSG_NOT_COLOR_IT[] PROGMEM = "Color no claro";
-const char MSG_NOT_COLOR_ES[] PROGMEM = "Color no claro";
-const char MSG_NOT_COLOR_PL[] PROGMEM = "Kolor zanieczysz.";
 const char * const MSG_NOT_COLOR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NOT_COLOR_EN,
-	MSG_NOT_COLOR_CZ,
-	MSG_NOT_COLOR_IT,
-	MSG_NOT_COLOR_ES,
-	MSG_NOT_COLOR_PL
+	MSG_NOT_COLOR_CZ
 };
 
 const char MSG_NOT_LOADED_EN[] PROGMEM = "Filament not loaded";
 const char MSG_NOT_LOADED_CZ[] PROGMEM = "Filament nezaveden";
-const char MSG_NOT_LOADED_IT[] PROGMEM = "Fil. no cargado";
-const char MSG_NOT_LOADED_ES[] PROGMEM = "Fil. no cargado";
-const char MSG_NOT_LOADED_PL[] PROGMEM = "Brak filamentu";
 const char * const MSG_NOT_LOADED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NOT_LOADED_EN,
-	MSG_NOT_LOADED_CZ,
-	MSG_NOT_LOADED_IT,
-	MSG_NOT_LOADED_ES,
-	MSG_NOT_LOADED_PL
+	MSG_NOT_LOADED_CZ
 };
 
 const char MSG_NOZZLE_EN[] PROGMEM = "Nozzle";
 const char MSG_NOZZLE_CZ[] PROGMEM = "Tryska";
-const char MSG_NOZZLE_IT[] PROGMEM = "Ugello";
-const char MSG_NOZZLE_ES[] PROGMEM = "Fusor";
-const char MSG_NOZZLE_PL[] PROGMEM = "Dysza";
 const char * const MSG_NOZZLE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NOZZLE_EN,
-	MSG_NOZZLE_CZ,
-	MSG_NOZZLE_IT,
-	MSG_NOZZLE_ES,
-	MSG_NOZZLE_PL
+	MSG_NOZZLE_CZ
 };
 
 const char MSG_NOZZLE1_EN[] PROGMEM = "Nozzle2";
-const char MSG_NOZZLE1_CZ[] PROGMEM = "Tryska2";
-const char MSG_NOZZLE1_IT[] PROGMEM = "Nozzle2";
-const char MSG_NOZZLE1_ES[] PROGMEM = "Nozzle2";
-const char MSG_NOZZLE1_PL[] PROGMEM = "Tryska2";
-const char * const MSG_NOZZLE1_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_NOZZLE1_EN,
-	MSG_NOZZLE1_CZ,
-	MSG_NOZZLE1_IT,
-	MSG_NOZZLE1_ES,
-	MSG_NOZZLE1_PL
+const char * const MSG_NOZZLE1_LANG_TABLE[1] PROGMEM = {
+	MSG_NOZZLE1_EN
 };
 
 const char MSG_NOZZLE2_EN[] PROGMEM = "Nozzle3";
-const char MSG_NOZZLE2_CZ[] PROGMEM = "Tryska3";
-const char MSG_NOZZLE2_IT[] PROGMEM = "Nozzle3";
-const char MSG_NOZZLE2_ES[] PROGMEM = "Nozzle3";
-const char MSG_NOZZLE2_PL[] PROGMEM = "Tryska3";
-const char * const MSG_NOZZLE2_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_NOZZLE2_EN,
-	MSG_NOZZLE2_CZ,
-	MSG_NOZZLE2_IT,
-	MSG_NOZZLE2_ES,
-	MSG_NOZZLE2_PL
+const char * const MSG_NOZZLE2_LANG_TABLE[1] PROGMEM = {
+	MSG_NOZZLE2_EN
 };
 
 const char MSG_NO_CARD_EN[] PROGMEM = "No SD card";
 const char MSG_NO_CARD_CZ[] PROGMEM = "Zadna SD karta";
-const char MSG_NO_CARD_IT[] PROGMEM = "No SD Carta";
-const char MSG_NO_CARD_ES[] PROGMEM = "No hay tarjeta SD";
-const char MSG_NO_CARD_PL[] PROGMEM = "Brak karty SD";
 const char * const MSG_NO_CARD_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NO_CARD_EN,
-	MSG_NO_CARD_CZ,
-	MSG_NO_CARD_IT,
-	MSG_NO_CARD_ES,
-	MSG_NO_CARD_PL
+	MSG_NO_CARD_CZ
 };
 
 const char MSG_NO_MOVE_EN[] PROGMEM = "No move.";
-const char MSG_NO_MOVE_CZ[] PROGMEM = "No move.";
-const char MSG_NO_MOVE_IT[] PROGMEM = "Nessun Movimento";
-const char MSG_NO_MOVE_ES[] PROGMEM = "Sin movimiento";
-const char MSG_NO_MOVE_PL[] PROGMEM = "No move.";
-const char * const MSG_NO_MOVE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_NO_MOVE_EN,
-	MSG_NO_MOVE_CZ,
-	MSG_NO_MOVE_IT,
-	MSG_NO_MOVE_ES,
-	MSG_NO_MOVE_PL
+const char * const MSG_NO_MOVE_LANG_TABLE[1] PROGMEM = {
+	MSG_NO_MOVE_EN
 };
 
 const char MSG_OFF_EN[] PROGMEM = "Off";
-const char MSG_OFF_CZ[] PROGMEM = "Off";
-const char MSG_OFF_IT[] PROGMEM = "Off";
-const char MSG_OFF_ES[] PROGMEM = "Off";
-const char MSG_OFF_PL[] PROGMEM = "Off";
-const char * const MSG_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_OFF_EN,
-	MSG_OFF_CZ,
-	MSG_OFF_IT,
-	MSG_OFF_ES,
-	MSG_OFF_PL
+const char * const MSG_OFF_LANG_TABLE[1] PROGMEM = {
+	MSG_OFF_EN
 };
 
 const char MSG_OK_EN[] PROGMEM = "ok";
-const char MSG_OK_CZ[] PROGMEM = "ok";
-const char MSG_OK_IT[] PROGMEM = "ok";
-const char MSG_OK_ES[] PROGMEM = "ok";
-const char MSG_OK_PL[] PROGMEM = "ok";
-const char * const MSG_OK_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_OK_EN,
-	MSG_OK_CZ,
-	MSG_OK_IT,
-	MSG_OK_ES,
-	MSG_OK_PL
+const char * const MSG_OK_LANG_TABLE[1] PROGMEM = {
+	MSG_OK_EN
 };
 
 const char MSG_ON_EN[] PROGMEM = "On ";
-const char MSG_ON_CZ[] PROGMEM = "On ";
-const char MSG_ON_IT[] PROGMEM = "On ";
-const char MSG_ON_ES[] PROGMEM = "On ";
-const char MSG_ON_PL[] PROGMEM = "On ";
-const char * const MSG_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ON_EN,
-	MSG_ON_CZ,
-	MSG_ON_IT,
-	MSG_ON_ES,
-	MSG_ON_PL
+const char * const MSG_ON_LANG_TABLE[1] PROGMEM = {
+	MSG_ON_EN
+};
+
+const char MSG_PAPER_EN[] PROGMEM = "Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately.";
+const char MSG_PAPER_CZ[] PROGMEM = "Umistete list papiru na podlozku a udrzujte jej pod tryskou behem mereni prvnich 4 bodu. Pokud tryska zachyti papir, vypnete tiskarnu.";
+const char * const MSG_PAPER_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PAPER_EN,
+	MSG_PAPER_CZ
 };
 
 const char MSG_PAUSE_PRINT_EN[] PROGMEM = "Pause print";
 const char MSG_PAUSE_PRINT_CZ[] PROGMEM = "Pozastavit tisk";
-const char MSG_PAUSE_PRINT_IT[] PROGMEM = "Pausa";
-const char MSG_PAUSE_PRINT_ES[] PROGMEM = "Pausar impresion";
-const char MSG_PAUSE_PRINT_PL[] PROGMEM = "Przerwac druk";
 const char * const MSG_PAUSE_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PAUSE_PRINT_EN,
-	MSG_PAUSE_PRINT_CZ,
-	MSG_PAUSE_PRINT_IT,
-	MSG_PAUSE_PRINT_ES,
-	MSG_PAUSE_PRINT_PL
+	MSG_PAUSE_PRINT_CZ
 };
 
 const char MSG_PICK_Z_EN[] PROGMEM = "Pick print";
 const char MSG_PICK_Z_CZ[] PROGMEM = "Vyberte vytisk";
-const char MSG_PICK_Z_IT[] PROGMEM = "Vyberte vytisk";
-const char MSG_PICK_Z_ES[] PROGMEM = "Vyberte vytisk";
-const char MSG_PICK_Z_PL[] PROGMEM = "Vyberte vytisk";
 const char * const MSG_PICK_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PICK_Z_EN,
-	MSG_PICK_Z_CZ,
-	MSG_PICK_Z_IT,
-	MSG_PICK_Z_ES,
-	MSG_PICK_Z_PL
-};
-
-const char MSG_PID_C_EN[] PROGMEM = "PID-C";
-const char MSG_PID_C_CZ[] PROGMEM = "PID-C";
-const char MSG_PID_C_IT[] PROGMEM = "PID-C";
-const char MSG_PID_C_ES[] PROGMEM = "PID-C";
-const char MSG_PID_C_PL[] PROGMEM = "PID-C";
-const char * const MSG_PID_C_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PID_C_EN,
-	MSG_PID_C_CZ,
-	MSG_PID_C_IT,
-	MSG_PID_C_ES,
-	MSG_PID_C_PL
-};
-
-const char MSG_PID_D_EN[] PROGMEM = "PID-D";
-const char MSG_PID_D_CZ[] PROGMEM = "PID-D";
-const char MSG_PID_D_IT[] PROGMEM = "PID-D";
-const char MSG_PID_D_ES[] PROGMEM = "PID-D";
-const char MSG_PID_D_PL[] PROGMEM = "PID-D";
-const char * const MSG_PID_D_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PID_D_EN,
-	MSG_PID_D_CZ,
-	MSG_PID_D_IT,
-	MSG_PID_D_ES,
-	MSG_PID_D_PL
-};
-
-const char MSG_PID_I_EN[] PROGMEM = "PID-I";
-const char MSG_PID_I_CZ[] PROGMEM = "PID-I";
-const char MSG_PID_I_IT[] PROGMEM = "PID-I";
-const char MSG_PID_I_ES[] PROGMEM = "PID-I";
-const char MSG_PID_I_PL[] PROGMEM = "PID-I";
-const char * const MSG_PID_I_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PID_I_EN,
-	MSG_PID_I_CZ,
-	MSG_PID_I_IT,
-	MSG_PID_I_ES,
-	MSG_PID_I_PL
-};
-
-const char MSG_PID_P_EN[] PROGMEM = "PID-P";
-const char MSG_PID_P_CZ[] PROGMEM = "PID-P";
-const char MSG_PID_P_IT[] PROGMEM = "PID-P";
-const char MSG_PID_P_ES[] PROGMEM = "PID-P";
-const char MSG_PID_P_PL[] PROGMEM = "PID-P";
-const char * const MSG_PID_P_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PID_P_EN,
-	MSG_PID_P_CZ,
-	MSG_PID_P_IT,
-	MSG_PID_P_ES,
-	MSG_PID_P_PL
+	MSG_PICK_Z_CZ
+};
+
+const char MSG_PID_EXTRUDER_EN[] PROGMEM = "PID calibration";
+const char MSG_PID_EXTRUDER_CZ[] PROGMEM = "PID kalibrace";
+const char * const MSG_PID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PID_EXTRUDER_EN,
+	MSG_PID_EXTRUDER_CZ
+};
+
+const char MSG_PID_FINISHED_EN[] PROGMEM = "PID cal. finished";
+const char MSG_PID_FINISHED_CZ[] PROGMEM = "PID kal. ukoncena";
+const char * const MSG_PID_FINISHED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PID_FINISHED_EN,
+	MSG_PID_FINISHED_CZ
+};
+
+const char MSG_PID_RUNNING_EN[] PROGMEM = "PID cal.           ";
+const char MSG_PID_RUNNING_CZ[] PROGMEM = "PID kal.           ";
+const char * const MSG_PID_RUNNING_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PID_RUNNING_EN,
+	MSG_PID_RUNNING_CZ
+};
+
+const char MSG_PINDA_NOT_CALIBRATED_EN[] PROGMEM = "Temperature calibration has not been run yet";
+const char MSG_PINDA_NOT_CALIBRATED_CZ[] PROGMEM = "Tiskarna nebyla teplotne zkalibrovana";
+const char * const MSG_PINDA_NOT_CALIBRATED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PINDA_NOT_CALIBRATED_EN,
+	MSG_PINDA_NOT_CALIBRATED_CZ
+};
+
+const char MSG_PINDA_PREHEAT_EN[] PROGMEM = "PINDA Heating";
+const char MSG_PINDA_PREHEAT_CZ[] PROGMEM = "Nahrivani PINDA";
+const char * const MSG_PINDA_PREHEAT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PINDA_PREHEAT_EN,
+	MSG_PINDA_PREHEAT_CZ
+};
+
+const char MSG_PLACE_STEEL_SHEET_EN[] PROGMEM = "Please place steel sheet on heatbed.";
+const char MSG_PLACE_STEEL_SHEET_CZ[] PROGMEM = "Umistete prosim tiskovy plat na heatbed";
+const char * const MSG_PLACE_STEEL_SHEET_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PLACE_STEEL_SHEET_EN,
+	MSG_PLACE_STEEL_SHEET_CZ
 };
 
 const char MSG_PLANNER_BUFFER_BYTES_EN[] PROGMEM = "  PlannerBufferBytes: ";
-const char MSG_PLANNER_BUFFER_BYTES_CZ[] PROGMEM = "  PlannerBufferBytes: ";
-const char MSG_PLANNER_BUFFER_BYTES_IT[] PROGMEM = "  PlannerBufferBytes: ";
-const char MSG_PLANNER_BUFFER_BYTES_ES[] PROGMEM = "  PlannerBufferBytes: ";
-const char MSG_PLANNER_BUFFER_BYTES_PL[] PROGMEM = "  PlannerBufferBytes: ";
-const char * const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PLANNER_BUFFER_BYTES_EN,
-	MSG_PLANNER_BUFFER_BYTES_CZ,
-	MSG_PLANNER_BUFFER_BYTES_IT,
-	MSG_PLANNER_BUFFER_BYTES_ES,
-	MSG_PLANNER_BUFFER_BYTES_PL
+const char * const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[1] PROGMEM = {
+	MSG_PLANNER_BUFFER_BYTES_EN
+};
+
+const char MSG_PLA_FILAMENT_LOADED_EN[] PROGMEM = "Is PLA filament loaded?";
+const char MSG_PLA_FILAMENT_LOADED_CZ[] PROGMEM = "Je PLA filament zaveden?";
+const char * const MSG_PLA_FILAMENT_LOADED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PLA_FILAMENT_LOADED_EN,
+	MSG_PLA_FILAMENT_LOADED_CZ
+};
+
+const char MSG_PLEASE_LOAD_PLA_EN[] PROGMEM = "Please load PLA filament first.";
+const char MSG_PLEASE_LOAD_PLA_CZ[] PROGMEM = "Nejdrive zavedte PLA filament prosim.";
+const char * const MSG_PLEASE_LOAD_PLA_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PLEASE_LOAD_PLA_EN,
+	MSG_PLEASE_LOAD_PLA_CZ
 };
 
 const char MSG_PLEASE_WAIT_EN[] PROGMEM = "Please wait";
 const char MSG_PLEASE_WAIT_CZ[] PROGMEM = "Prosim cekejte";
-const char MSG_PLEASE_WAIT_IT[] PROGMEM = "Aspetta";
-const char MSG_PLEASE_WAIT_ES[] PROGMEM = "Espera";
-const char MSG_PLEASE_WAIT_PL[] PROGMEM = "Prosze czekac";
 const char * const MSG_PLEASE_WAIT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PLEASE_WAIT_EN,
-	MSG_PLEASE_WAIT_CZ,
-	MSG_PLEASE_WAIT_IT,
-	MSG_PLEASE_WAIT_ES,
-	MSG_PLEASE_WAIT_PL
+	MSG_PLEASE_WAIT_CZ
 };
 
 const char MSG_POSITION_UNKNOWN_EN[] PROGMEM = "Home X/Y before Z";
-const char MSG_POSITION_UNKNOWN_CZ[] PROGMEM = "Home X/Y before Z";
-const char MSG_POSITION_UNKNOWN_IT[] PROGMEM = "Home X/Y before Z";
-const char MSG_POSITION_UNKNOWN_ES[] PROGMEM = "Home X/Y before Z";
-const char MSG_POSITION_UNKNOWN_PL[] PROGMEM = "Home X/Y before Z";
-const char * const MSG_POSITION_UNKNOWN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_POSITION_UNKNOWN_EN,
-	MSG_POSITION_UNKNOWN_CZ,
-	MSG_POSITION_UNKNOWN_IT,
-	MSG_POSITION_UNKNOWN_ES,
-	MSG_POSITION_UNKNOWN_PL
+const char * const MSG_POSITION_UNKNOWN_LANG_TABLE[1] PROGMEM = {
+	MSG_POSITION_UNKNOWN_EN
 };
 
 const char MSG_POWERUP_EN[] PROGMEM = "PowerUp";
-const char MSG_POWERUP_CZ[] PROGMEM = "PowerUp";
-const char MSG_POWERUP_IT[] PROGMEM = "PowerUp";
-const char MSG_POWERUP_ES[] PROGMEM = "PowerUp";
-const char MSG_POWERUP_PL[] PROGMEM = "PowerUp";
-const char * const MSG_POWERUP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_POWERUP_EN,
-	MSG_POWERUP_CZ,
-	MSG_POWERUP_IT,
-	MSG_POWERUP_ES,
-	MSG_POWERUP_PL
+const char * const MSG_POWERUP_LANG_TABLE[1] PROGMEM = {
+	MSG_POWERUP_EN
 };
 
 const char MSG_PREHEAT_EN[] PROGMEM = "Preheat";
 const char MSG_PREHEAT_CZ[] PROGMEM = "Predehrev";
-const char MSG_PREHEAT_IT[] PROGMEM = "Preriscalda";
-const char MSG_PREHEAT_ES[] PROGMEM = "Precalentar";
-const char MSG_PREHEAT_PL[] PROGMEM = "Grzanie";
 const char * const MSG_PREHEAT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PREHEAT_EN,
-	MSG_PREHEAT_CZ,
-	MSG_PREHEAT_IT,
-	MSG_PREHEAT_ES,
-	MSG_PREHEAT_PL
-};
-
-const char MSG_PREHEAT_ABS_EN[] PROGMEM = "Preheat ABS";
-const char MSG_PREHEAT_ABS_CZ[] PROGMEM = "Predehrev ABS";
-const char MSG_PREHEAT_ABS_IT[] PROGMEM = "Preheat ABS";
-const char MSG_PREHEAT_ABS_ES[] PROGMEM = "Preheat ABS";
-const char MSG_PREHEAT_ABS_PL[] PROGMEM = "Predehrev ABS";
-const char * const MSG_PREHEAT_ABS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS_EN,
-	MSG_PREHEAT_ABS_CZ,
-	MSG_PREHEAT_ABS_IT,
-	MSG_PREHEAT_ABS_ES,
-	MSG_PREHEAT_ABS_PL
-};
-
-const char MSG_PREHEAT_ABS0_EN[] PROGMEM = "Preheat ABS 1";
-const char MSG_PREHEAT_ABS0_CZ[] PROGMEM = "Predehrev ABS 1";
-const char MSG_PREHEAT_ABS0_IT[] PROGMEM = "Preheat ABS 1";
-const char MSG_PREHEAT_ABS0_ES[] PROGMEM = "Preheat ABS 1";
-const char MSG_PREHEAT_ABS0_PL[] PROGMEM = "Predehrev ABS 1";
-const char * const MSG_PREHEAT_ABS0_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS0_EN,
-	MSG_PREHEAT_ABS0_CZ,
-	MSG_PREHEAT_ABS0_IT,
-	MSG_PREHEAT_ABS0_ES,
-	MSG_PREHEAT_ABS0_PL
-};
-
-const char MSG_PREHEAT_ABS012_EN[] PROGMEM = "Preheat ABS All";
-const char MSG_PREHEAT_ABS012_CZ[] PROGMEM = "Predehrev ABS All";
-const char MSG_PREHEAT_ABS012_IT[] PROGMEM = "Preheat ABS All";
-const char MSG_PREHEAT_ABS012_ES[] PROGMEM = "Preheat ABS All";
-const char MSG_PREHEAT_ABS012_PL[] PROGMEM = "Predehrev ABS All";
-const char * const MSG_PREHEAT_ABS012_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS012_EN,
-	MSG_PREHEAT_ABS012_CZ,
-	MSG_PREHEAT_ABS012_IT,
-	MSG_PREHEAT_ABS012_ES,
-	MSG_PREHEAT_ABS012_PL
-};
-
-const char MSG_PREHEAT_ABS1_EN[] PROGMEM = "Preheat ABS 2";
-const char MSG_PREHEAT_ABS1_CZ[] PROGMEM = "Predehrev ABS 2";
-const char MSG_PREHEAT_ABS1_IT[] PROGMEM = "Preheat ABS 2";
-const char MSG_PREHEAT_ABS1_ES[] PROGMEM = "Preheat ABS 2";
-const char MSG_PREHEAT_ABS1_PL[] PROGMEM = "Predehrev ABS 2";
-const char * const MSG_PREHEAT_ABS1_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS1_EN,
-	MSG_PREHEAT_ABS1_CZ,
-	MSG_PREHEAT_ABS1_IT,
-	MSG_PREHEAT_ABS1_ES,
-	MSG_PREHEAT_ABS1_PL
-};
-
-const char MSG_PREHEAT_ABS2_EN[] PROGMEM = "Preheat ABS 3";
-const char MSG_PREHEAT_ABS2_CZ[] PROGMEM = "Predehrev ABS 3";
-const char MSG_PREHEAT_ABS2_IT[] PROGMEM = "Preheat ABS 3";
-const char MSG_PREHEAT_ABS2_ES[] PROGMEM = "Preheat ABS 3";
-const char MSG_PREHEAT_ABS2_PL[] PROGMEM = "Predehrev ABS 3";
-const char * const MSG_PREHEAT_ABS2_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS2_EN,
-	MSG_PREHEAT_ABS2_CZ,
-	MSG_PREHEAT_ABS2_IT,
-	MSG_PREHEAT_ABS2_ES,
-	MSG_PREHEAT_ABS2_PL
-};
-
-const char MSG_PREHEAT_ABS_BEDONLY_EN[] PROGMEM = "Preheat ABS Bed";
-const char MSG_PREHEAT_ABS_BEDONLY_CZ[] PROGMEM = "Predehrev ABS Bed";
-const char MSG_PREHEAT_ABS_BEDONLY_IT[] PROGMEM = "Preheat ABS Bed";
-const char MSG_PREHEAT_ABS_BEDONLY_ES[] PROGMEM = "Preheat ABS Bed";
-const char MSG_PREHEAT_ABS_BEDONLY_PL[] PROGMEM = "Predehrev ABS Bed";
-const char * const MSG_PREHEAT_ABS_BEDONLY_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS_BEDONLY_EN,
-	MSG_PREHEAT_ABS_BEDONLY_CZ,
-	MSG_PREHEAT_ABS_BEDONLY_IT,
-	MSG_PREHEAT_ABS_BEDONLY_ES,
-	MSG_PREHEAT_ABS_BEDONLY_PL
-};
-
-const char MSG_PREHEAT_ABS_SETTINGS_EN[] PROGMEM = "Preheat ABS conf";
-const char MSG_PREHEAT_ABS_SETTINGS_CZ[] PROGMEM = "Predehrev ABS conf";
-const char MSG_PREHEAT_ABS_SETTINGS_IT[] PROGMEM = "Preheat ABS conf";
-const char MSG_PREHEAT_ABS_SETTINGS_ES[] PROGMEM = "Preheat ABS conf";
-const char MSG_PREHEAT_ABS_SETTINGS_PL[] PROGMEM = "Predehrev ABS conf";
-const char * const MSG_PREHEAT_ABS_SETTINGS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_ABS_SETTINGS_EN,
-	MSG_PREHEAT_ABS_SETTINGS_CZ,
-	MSG_PREHEAT_ABS_SETTINGS_IT,
-	MSG_PREHEAT_ABS_SETTINGS_ES,
-	MSG_PREHEAT_ABS_SETTINGS_PL
+	MSG_PREHEAT_CZ
 };
 
 const char MSG_PREHEAT_NOZZLE_EN[] PROGMEM = "Preheat the nozzle!";
 const char MSG_PREHEAT_NOZZLE_CZ[] PROGMEM = "Predehrejte trysku!";
-const char MSG_PREHEAT_NOZZLE_IT[] PROGMEM = "Preris. ugello!";
-const char MSG_PREHEAT_NOZZLE_ES[] PROGMEM = "Precal. extrusor!";
-const char MSG_PREHEAT_NOZZLE_PL[] PROGMEM = "Nagrzej dysze!";
 const char * const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PREHEAT_NOZZLE_EN,
-	MSG_PREHEAT_NOZZLE_CZ,
-	MSG_PREHEAT_NOZZLE_IT,
-	MSG_PREHEAT_NOZZLE_ES,
-	MSG_PREHEAT_NOZZLE_PL
-};
-
-const char MSG_PREHEAT_PLA_EN[] PROGMEM = "Preheat PLA";
-const char MSG_PREHEAT_PLA_CZ[] PROGMEM = "Predehrev PLA";
-const char MSG_PREHEAT_PLA_IT[] PROGMEM = "Preheat PLA";
-const char MSG_PREHEAT_PLA_ES[] PROGMEM = "Preheat PLA";
-const char MSG_PREHEAT_PLA_PL[] PROGMEM = "Predehrev PLA";
-const char * const MSG_PREHEAT_PLA_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA_EN,
-	MSG_PREHEAT_PLA_CZ,
-	MSG_PREHEAT_PLA_IT,
-	MSG_PREHEAT_PLA_ES,
-	MSG_PREHEAT_PLA_PL
-};
-
-const char MSG_PREHEAT_PLA0_EN[] PROGMEM = "Preheat PLA 1";
-const char MSG_PREHEAT_PLA0_CZ[] PROGMEM = "Predehrev PLA 1";
-const char MSG_PREHEAT_PLA0_IT[] PROGMEM = "Preheat PLA 1";
-const char MSG_PREHEAT_PLA0_ES[] PROGMEM = "Preheat PLA 1";
-const char MSG_PREHEAT_PLA0_PL[] PROGMEM = "Predehrev PLA 1";
-const char * const MSG_PREHEAT_PLA0_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA0_EN,
-	MSG_PREHEAT_PLA0_CZ,
-	MSG_PREHEAT_PLA0_IT,
-	MSG_PREHEAT_PLA0_ES,
-	MSG_PREHEAT_PLA0_PL
-};
-
-const char MSG_PREHEAT_PLA012_EN[] PROGMEM = "Preheat PLA All";
-const char MSG_PREHEAT_PLA012_CZ[] PROGMEM = "Predehrev PLA All";
-const char MSG_PREHEAT_PLA012_IT[] PROGMEM = "Preheat PLA All";
-const char MSG_PREHEAT_PLA012_ES[] PROGMEM = "Preheat PLA All";
-const char MSG_PREHEAT_PLA012_PL[] PROGMEM = "Predehrev PLA All";
-const char * const MSG_PREHEAT_PLA012_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA012_EN,
-	MSG_PREHEAT_PLA012_CZ,
-	MSG_PREHEAT_PLA012_IT,
-	MSG_PREHEAT_PLA012_ES,
-	MSG_PREHEAT_PLA012_PL
-};
-
-const char MSG_PREHEAT_PLA1_EN[] PROGMEM = "Preheat PLA 2";
-const char MSG_PREHEAT_PLA1_CZ[] PROGMEM = "Predehrev PLA 2";
-const char MSG_PREHEAT_PLA1_IT[] PROGMEM = "Preheat PLA 2";
-const char MSG_PREHEAT_PLA1_ES[] PROGMEM = "Preheat PLA 2";
-const char MSG_PREHEAT_PLA1_PL[] PROGMEM = "Predehrev PLA 2";
-const char * const MSG_PREHEAT_PLA1_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA1_EN,
-	MSG_PREHEAT_PLA1_CZ,
-	MSG_PREHEAT_PLA1_IT,
-	MSG_PREHEAT_PLA1_ES,
-	MSG_PREHEAT_PLA1_PL
-};
-
-const char MSG_PREHEAT_PLA2_EN[] PROGMEM = "Preheat PLA 3";
-const char MSG_PREHEAT_PLA2_CZ[] PROGMEM = "Predehrev PLA 3";
-const char MSG_PREHEAT_PLA2_IT[] PROGMEM = "Preheat PLA 3";
-const char MSG_PREHEAT_PLA2_ES[] PROGMEM = "Preheat PLA 3";
-const char MSG_PREHEAT_PLA2_PL[] PROGMEM = "Predehrev PLA 3";
-const char * const MSG_PREHEAT_PLA2_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA2_EN,
-	MSG_PREHEAT_PLA2_CZ,
-	MSG_PREHEAT_PLA2_IT,
-	MSG_PREHEAT_PLA2_ES,
-	MSG_PREHEAT_PLA2_PL
-};
-
-const char MSG_PREHEAT_PLA_BEDONLY_EN[] PROGMEM = "Preheat PLA Bed";
-const char MSG_PREHEAT_PLA_BEDONLY_CZ[] PROGMEM = "Predehrev PLA Bed";
-const char MSG_PREHEAT_PLA_BEDONLY_IT[] PROGMEM = "Preheat PLA Bed";
-const char MSG_PREHEAT_PLA_BEDONLY_ES[] PROGMEM = "Preheat PLA Bed";
-const char MSG_PREHEAT_PLA_BEDONLY_PL[] PROGMEM = "Predehrev PLA Bed";
-const char * const MSG_PREHEAT_PLA_BEDONLY_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA_BEDONLY_EN,
-	MSG_PREHEAT_PLA_BEDONLY_CZ,
-	MSG_PREHEAT_PLA_BEDONLY_IT,
-	MSG_PREHEAT_PLA_BEDONLY_ES,
-	MSG_PREHEAT_PLA_BEDONLY_PL
-};
-
-const char MSG_PREHEAT_PLA_SETTINGS_EN[] PROGMEM = "Preheat PLA conf";
-const char MSG_PREHEAT_PLA_SETTINGS_CZ[] PROGMEM = "Predehrev PLA conf";
-const char MSG_PREHEAT_PLA_SETTINGS_IT[] PROGMEM = "Preheat PLA conf";
-const char MSG_PREHEAT_PLA_SETTINGS_ES[] PROGMEM = "Preheat PLA conf";
-const char MSG_PREHEAT_PLA_SETTINGS_PL[] PROGMEM = "Predehrev PLA conf";
-const char * const MSG_PREHEAT_PLA_SETTINGS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREHEAT_PLA_SETTINGS_EN,
-	MSG_PREHEAT_PLA_SETTINGS_CZ,
-	MSG_PREHEAT_PLA_SETTINGS_IT,
-	MSG_PREHEAT_PLA_SETTINGS_ES,
-	MSG_PREHEAT_PLA_SETTINGS_PL
-};
-
-const char MSG_PREPARE_EN[] PROGMEM = "Prepare";
-const char MSG_PREPARE_CZ[] PROGMEM = "Priprava";
-const char MSG_PREPARE_IT[] PROGMEM = "Prepare";
-const char MSG_PREPARE_ES[] PROGMEM = "Prepare";
-const char MSG_PREPARE_PL[] PROGMEM = "Priprava";
-const char * const MSG_PREPARE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_PREPARE_EN,
-	MSG_PREPARE_CZ,
-	MSG_PREPARE_IT,
-	MSG_PREPARE_ES,
-	MSG_PREPARE_PL
-};
-
-const char MSG_PRESS_EN[] PROGMEM = "And press the knob";
-const char MSG_PRESS_CZ[] PROGMEM = "A stisknete tlacitko";
-const char MSG_PRESS_IT[] PROGMEM = "Y pulse el mando";
-const char MSG_PRESS_ES[] PROGMEM = "Y pulse el mando";
-const char MSG_PRESS_PL[] PROGMEM = "Nacisnij przycisk";
+	MSG_PREHEAT_NOZZLE_CZ
+};
+
+const char MSG_PREPARE_FILAMENT_EN[] PROGMEM = "Prepare new filament";
+const char MSG_PREPARE_FILAMENT_CZ[] PROGMEM = "Pripravte filament";
+const char * const MSG_PREPARE_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PREPARE_FILAMENT_EN,
+	MSG_PREPARE_FILAMENT_CZ
+};
+
+const char MSG_PRESS_EN[] PROGMEM = "and press the knob";
+const char MSG_PRESS_CZ[] PROGMEM = "a stisknete tlacitko";
 const char * const MSG_PRESS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRESS_EN,
-	MSG_PRESS_CZ,
-	MSG_PRESS_IT,
-	MSG_PRESS_ES,
-	MSG_PRESS_PL
+	MSG_PRESS_CZ
+};
+
+const char MSG_PRESS_TO_UNLOAD_EN[] PROGMEM = "Please press the knob to unload filament";
+const char MSG_PRESS_TO_UNLOAD_CZ[] PROGMEM = "Pro vysunuti filamentu stisknete prosim tlacitko";
+const char * const MSG_PRESS_TO_UNLOAD_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PRESS_TO_UNLOAD_EN,
+	MSG_PRESS_TO_UNLOAD_CZ
+};
+
+const char MSG_PRINTER_DISCONNECTED_EN[] PROGMEM = "Printer disconnected";
+const char * const MSG_PRINTER_DISCONNECTED_LANG_TABLE[1] PROGMEM = {
+	MSG_PRINTER_DISCONNECTED_EN
 };
 
 const char MSG_PRINT_ABORTED_EN[] PROGMEM = "Print aborted";
 const char MSG_PRINT_ABORTED_CZ[] PROGMEM = "Tisk prerusen";
-const char MSG_PRINT_ABORTED_IT[] PROGMEM = "Stampa abortita";
-const char MSG_PRINT_ABORTED_ES[] PROGMEM = "Print aborted";
-const char MSG_PRINT_ABORTED_PL[] PROGMEM = "Druk przerwany";
 const char * const MSG_PRINT_ABORTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRINT_ABORTED_EN,
-	MSG_PRINT_ABORTED_CZ,
-	MSG_PRINT_ABORTED_IT,
-	MSG_PRINT_ABORTED_ES,
-	MSG_PRINT_ABORTED_PL
+	MSG_PRINT_ABORTED_CZ
+};
+
+const char MSG_PRINT_PAUSED_EN[] PROGMEM = "Print paused";
+const char MSG_PRINT_PAUSED_CZ[] PROGMEM = "Tisk pozastaven";
+const char * const MSG_PRINT_PAUSED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PRINT_PAUSED_EN,
+	MSG_PRINT_PAUSED_CZ
 };
 
 const char MSG_PRUSA3D_EN[] PROGMEM = "prusa3d.com";
 const char MSG_PRUSA3D_CZ[] PROGMEM = "prusa3d.cz";
-const char MSG_PRUSA3D_IT[] PROGMEM = "prusa3d.com";
-const char MSG_PRUSA3D_ES[] PROGMEM = "prusa3d.com";
-const char MSG_PRUSA3D_PL[] PROGMEM = "prusa3d.cz";
 const char * const MSG_PRUSA3D_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRUSA3D_EN,
-	MSG_PRUSA3D_CZ,
-	MSG_PRUSA3D_IT,
-	MSG_PRUSA3D_ES,
-	MSG_PRUSA3D_PL
+	MSG_PRUSA3D_CZ
 };
 
 const char MSG_PRUSA3D_FORUM_EN[] PROGMEM = "forum.prusa3d.com";
 const char MSG_PRUSA3D_FORUM_CZ[] PROGMEM = "forum.prusa3d.cz";
-const char MSG_PRUSA3D_FORUM_IT[] PROGMEM = "forum.prusa3d.com";
-const char MSG_PRUSA3D_FORUM_ES[] PROGMEM = "forum.prusa3d.com";
-const char MSG_PRUSA3D_FORUM_PL[] PROGMEM = "forum.prusa3d.cz";
 const char * const MSG_PRUSA3D_FORUM_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRUSA3D_FORUM_EN,
-	MSG_PRUSA3D_FORUM_CZ,
-	MSG_PRUSA3D_FORUM_IT,
-	MSG_PRUSA3D_FORUM_ES,
-	MSG_PRUSA3D_FORUM_PL
+	MSG_PRUSA3D_FORUM_CZ
 };
 
 const char MSG_PRUSA3D_HOWTO_EN[] PROGMEM = "howto.prusa3d.com";
 const char MSG_PRUSA3D_HOWTO_CZ[] PROGMEM = "howto.prusa3d.cz";
-const char MSG_PRUSA3D_HOWTO_IT[] PROGMEM = "howto.prusa3d.com";
-const char MSG_PRUSA3D_HOWTO_ES[] PROGMEM = "howto.prusa3d.com";
-const char MSG_PRUSA3D_HOWTO_PL[] PROGMEM = "howto.prusa3d.cz";
 const char * const MSG_PRUSA3D_HOWTO_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRUSA3D_HOWTO_EN,
-	MSG_PRUSA3D_HOWTO_CZ,
-	MSG_PRUSA3D_HOWTO_IT,
-	MSG_PRUSA3D_HOWTO_ES,
-	MSG_PRUSA3D_HOWTO_PL
+	MSG_PRUSA3D_HOWTO_CZ
 };
 
 const char MSG_REBOOT_EN[] PROGMEM = "Reboot the printer";
 const char MSG_REBOOT_CZ[] PROGMEM = "Restartujte tiskarnu";
-const char MSG_REBOOT_IT[] PROGMEM = "Riavvio la stamp.";
-const char MSG_REBOOT_ES[] PROGMEM = "Reiniciar la imp.";
-const char MSG_REBOOT_PL[] PROGMEM = "Restart drukarki";
 const char * const MSG_REBOOT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_REBOOT_EN,
-	MSG_REBOOT_CZ,
-	MSG_REBOOT_IT,
-	MSG_REBOOT_ES,
-	MSG_REBOOT_PL
+	MSG_REBOOT_CZ
+};
+
+const char MSG_RECOVERING_PRINT_EN[] PROGMEM = "Recovering print    ";
+const char MSG_RECOVERING_PRINT_CZ[] PROGMEM = "Obnovovani tisku    ";
+const char * const MSG_RECOVERING_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_RECOVERING_PRINT_EN,
+	MSG_RECOVERING_PRINT_CZ
+};
+
+const char MSG_RECOVER_PRINT_EN[] PROGMEM = "Blackout occurred. Recover print?";
+const char MSG_RECOVER_PRINT_CZ[] PROGMEM = "Detekovan vypadek proudu.Obnovit tisk?";
+const char * const MSG_RECOVER_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_RECOVER_PRINT_EN,
+	MSG_RECOVER_PRINT_CZ
 };
 
 const char MSG_RECTRACT_EN[] PROGMEM = "Rectract";
-const char MSG_RECTRACT_CZ[] PROGMEM = "Rectract";
-const char MSG_RECTRACT_IT[] PROGMEM = "Rectract";
-const char MSG_RECTRACT_ES[] PROGMEM = "Rectract";
-const char MSG_RECTRACT_PL[] PROGMEM = "Rectract";
-const char * const MSG_RECTRACT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_RECTRACT_EN,
-	MSG_RECTRACT_CZ,
-	MSG_RECTRACT_IT,
-	MSG_RECTRACT_ES,
-	MSG_RECTRACT_PL
+const char * const MSG_RECTRACT_LANG_TABLE[1] PROGMEM = {
+	MSG_RECTRACT_EN
 };
 
 const char MSG_REFRESH_EN[] PROGMEM = "\xF8" "Refresh";
-const char MSG_REFRESH_CZ[] PROGMEM = "\xF8" "Obnovit";
-const char MSG_REFRESH_IT[] PROGMEM = "\xF8" "Refresh";
-const char MSG_REFRESH_ES[] PROGMEM = "\xF8" "Refresh";
-const char MSG_REFRESH_PL[] PROGMEM = "\xF8" "Obnovit";
-const char * const MSG_REFRESH_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_REFRESH_EN,
-	MSG_REFRESH_CZ,
-	MSG_REFRESH_IT,
-	MSG_REFRESH_ES,
-	MSG_REFRESH_PL
+const char * const MSG_REFRESH_LANG_TABLE[1] PROGMEM = {
+	MSG_REFRESH_EN
+};
+
+const char MSG_REMOVE_STEEL_SHEET_EN[] PROGMEM = "Please remove steel sheet from heatbed.";
+const char MSG_REMOVE_STEEL_SHEET_CZ[] PROGMEM = "Odstrante tiskovy plat z heatbed prosim.";
+const char * const MSG_REMOVE_STEEL_SHEET_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_REMOVE_STEEL_SHEET_EN,
+	MSG_REMOVE_STEEL_SHEET_CZ
 };
 
 const char MSG_RESEND_EN[] PROGMEM = "Resend: ";
-const char MSG_RESEND_CZ[] PROGMEM = "Resend: ";
-const char MSG_RESEND_IT[] PROGMEM = "Resend: ";
-const char MSG_RESEND_ES[] PROGMEM = "Resend: ";
-const char MSG_RESEND_PL[] PROGMEM = "Resend: ";
-const char * const MSG_RESEND_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_RESEND_EN,
-	MSG_RESEND_CZ,
-	MSG_RESEND_IT,
-	MSG_RESEND_ES,
-	MSG_RESEND_PL
+const char * const MSG_RESEND_LANG_TABLE[1] PROGMEM = {
+	MSG_RESEND_EN
+};
+
+const char MSG_RESET_CALIBRATE_E_EN[] PROGMEM = "Reset E Cal.";
+const char * const MSG_RESET_CALIBRATE_E_LANG_TABLE[1] PROGMEM = {
+	MSG_RESET_CALIBRATE_E_EN
 };
 
 const char MSG_RESTORE_FAILSAFE_EN[] PROGMEM = "Restore failsafe";
-const char MSG_RESTORE_FAILSAFE_CZ[] PROGMEM = "Obnovit vychozi";
-const char MSG_RESTORE_FAILSAFE_IT[] PROGMEM = "Restore failsafe";
-const char MSG_RESTORE_FAILSAFE_ES[] PROGMEM = "Restore failsafe";
-const char MSG_RESTORE_FAILSAFE_PL[] PROGMEM = "Obnovit vychozi";
-const char * const MSG_RESTORE_FAILSAFE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_RESTORE_FAILSAFE_EN,
-	MSG_RESTORE_FAILSAFE_CZ,
-	MSG_RESTORE_FAILSAFE_IT,
-	MSG_RESTORE_FAILSAFE_ES,
-	MSG_RESTORE_FAILSAFE_PL
+const char * const MSG_RESTORE_FAILSAFE_LANG_TABLE[1] PROGMEM = {
+	MSG_RESTORE_FAILSAFE_EN
 };
 
 const char MSG_RESUME_PRINT_EN[] PROGMEM = "Resume print";
 const char MSG_RESUME_PRINT_CZ[] PROGMEM = "Pokracovat";
-const char MSG_RESUME_PRINT_IT[] PROGMEM = "Riprendi stampa";
-const char MSG_RESUME_PRINT_ES[] PROGMEM = "Reanudar impres.";
-const char MSG_RESUME_PRINT_PL[] PROGMEM = "Kontynuowac";
 const char * const MSG_RESUME_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_RESUME_PRINT_EN,
-	MSG_RESUME_PRINT_CZ,
-	MSG_RESUME_PRINT_IT,
-	MSG_RESUME_PRINT_ES,
-	MSG_RESUME_PRINT_PL
+	MSG_RESUME_PRINT_CZ
 };
 
 const char MSG_RESUMING_EN[] PROGMEM = "Resuming print";
 const char MSG_RESUMING_CZ[] PROGMEM = "Obnoveni tisku";
-const char MSG_RESUMING_IT[] PROGMEM = "Riprendi Stampa";
-const char MSG_RESUMING_ES[] PROGMEM = "Resumiendo impre.";
-const char MSG_RESUMING_PL[] PROGMEM = "Wznowienie druku";
 const char * const MSG_RESUMING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_RESUMING_EN,
-	MSG_RESUMING_CZ,
-	MSG_RESUMING_IT,
-	MSG_RESUMING_ES,
-	MSG_RESUMING_PL
+	MSG_RESUMING_CZ
+};
+
+const char MSG_RESUMING_PRINT_EN[] PROGMEM = "Resuming print";
+const char MSG_RESUMING_PRINT_CZ[] PROGMEM = "Obnovovani tisku";
+const char * const MSG_RESUMING_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_RESUMING_PRINT_EN,
+	MSG_RESUMING_PRINT_CZ
 };
 
-const char MSG_RETRACT_EN[] PROGMEM = "Retract";
-const char MSG_RETRACT_CZ[] PROGMEM = "Retract";
-const char MSG_RETRACT_IT[] PROGMEM = "Retract";
-const char MSG_RETRACT_ES[] PROGMEM = "Retract";
-const char MSG_RETRACT_PL[] PROGMEM = "Retract";
-const char * const MSG_RETRACT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_RETRACT_EN,
-	MSG_RETRACT_CZ,
-	MSG_RETRACT_IT,
-	MSG_RETRACT_ES,
-	MSG_RETRACT_PL
+const char MSG_RIGHT_EN[] PROGMEM = "Right:";
+const char MSG_RIGHT_CZ[] PROGMEM = "Pravy:";
+const char * const MSG_RIGHT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_RIGHT_EN,
+	MSG_RIGHT_CZ
 };
 
 const char MSG_SD_CANT_ENTER_SUBDIR_EN[] PROGMEM = "Cannot enter subdir: ";
-const char MSG_SD_CANT_ENTER_SUBDIR_CZ[] PROGMEM = "Cannot enter subdir: ";
-const char MSG_SD_CANT_ENTER_SUBDIR_IT[] PROGMEM = "Cannot enter subdir: ";
-const char MSG_SD_CANT_ENTER_SUBDIR_ES[] PROGMEM = "Cannot enter subdir: ";
-const char MSG_SD_CANT_ENTER_SUBDIR_PL[] PROGMEM = "Cannot enter subdir: ";
-const char * const MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_CANT_ENTER_SUBDIR_EN,
-	MSG_SD_CANT_ENTER_SUBDIR_CZ,
-	MSG_SD_CANT_ENTER_SUBDIR_IT,
-	MSG_SD_CANT_ENTER_SUBDIR_ES,
-	MSG_SD_CANT_ENTER_SUBDIR_PL
+const char * const MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_CANT_ENTER_SUBDIR_EN
 };
 
 const char MSG_SD_CANT_OPEN_SUBDIR_EN[] PROGMEM = "Cannot open subdir";
-const char MSG_SD_CANT_OPEN_SUBDIR_CZ[] PROGMEM = "Cannot open subdir";
-const char MSG_SD_CANT_OPEN_SUBDIR_IT[] PROGMEM = "Cannot open subdir";
-const char MSG_SD_CANT_OPEN_SUBDIR_ES[] PROGMEM = "Cannot open subdir";
-const char MSG_SD_CANT_OPEN_SUBDIR_PL[] PROGMEM = "Cannot open subdir";
-const char * const MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_CANT_OPEN_SUBDIR_EN,
-	MSG_SD_CANT_OPEN_SUBDIR_CZ,
-	MSG_SD_CANT_OPEN_SUBDIR_IT,
-	MSG_SD_CANT_OPEN_SUBDIR_ES,
-	MSG_SD_CANT_OPEN_SUBDIR_PL
+const char * const MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_CANT_OPEN_SUBDIR_EN
 };
 
 const char MSG_SD_CARD_OK_EN[] PROGMEM = "SD card ok";
-const char MSG_SD_CARD_OK_CZ[] PROGMEM = "SD card ok";
-const char MSG_SD_CARD_OK_IT[] PROGMEM = "SD card ok";
-const char MSG_SD_CARD_OK_ES[] PROGMEM = "SD card ok";
-const char MSG_SD_CARD_OK_PL[] PROGMEM = "SD card ok";
-const char * const MSG_SD_CARD_OK_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_CARD_OK_EN,
-	MSG_SD_CARD_OK_CZ,
-	MSG_SD_CARD_OK_IT,
-	MSG_SD_CARD_OK_ES,
-	MSG_SD_CARD_OK_PL
+const char * const MSG_SD_CARD_OK_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_CARD_OK_EN
 };
 
 const char MSG_SD_ERR_WRITE_TO_FILE_EN[] PROGMEM = "error writing to file";
-const char MSG_SD_ERR_WRITE_TO_FILE_CZ[] PROGMEM = "error writing to file";
-const char MSG_SD_ERR_WRITE_TO_FILE_IT[] PROGMEM = "error writing to file";
-const char MSG_SD_ERR_WRITE_TO_FILE_ES[] PROGMEM = "error writing to file";
-const char MSG_SD_ERR_WRITE_TO_FILE_PL[] PROGMEM = "error writing to file";
-const char * const MSG_SD_ERR_WRITE_TO_FILE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_ERR_WRITE_TO_FILE_EN,
-	MSG_SD_ERR_WRITE_TO_FILE_CZ,
-	MSG_SD_ERR_WRITE_TO_FILE_IT,
-	MSG_SD_ERR_WRITE_TO_FILE_ES,
-	MSG_SD_ERR_WRITE_TO_FILE_PL
+const char * const MSG_SD_ERR_WRITE_TO_FILE_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_ERR_WRITE_TO_FILE_EN
 };
 
 const char MSG_SD_FILE_OPENED_EN[] PROGMEM = "File opened: ";
-const char MSG_SD_FILE_OPENED_CZ[] PROGMEM = "File opened: ";
-const char MSG_SD_FILE_OPENED_IT[] PROGMEM = "File opened: ";
-const char MSG_SD_FILE_OPENED_ES[] PROGMEM = "File opened: ";
-const char MSG_SD_FILE_OPENED_PL[] PROGMEM = "File opened: ";
-const char * const MSG_SD_FILE_OPENED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_FILE_OPENED_EN,
-	MSG_SD_FILE_OPENED_CZ,
-	MSG_SD_FILE_OPENED_IT,
-	MSG_SD_FILE_OPENED_ES,
-	MSG_SD_FILE_OPENED_PL
+const char * const MSG_SD_FILE_OPENED_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_FILE_OPENED_EN
 };
 
 const char MSG_SD_FILE_SELECTED_EN[] PROGMEM = "File selected";
-const char MSG_SD_FILE_SELECTED_CZ[] PROGMEM = "File selected";
-const char MSG_SD_FILE_SELECTED_IT[] PROGMEM = "File selected";
-const char MSG_SD_FILE_SELECTED_ES[] PROGMEM = "File selected";
-const char MSG_SD_FILE_SELECTED_PL[] PROGMEM = "File selected";
-const char * const MSG_SD_FILE_SELECTED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_FILE_SELECTED_EN,
-	MSG_SD_FILE_SELECTED_CZ,
-	MSG_SD_FILE_SELECTED_IT,
-	MSG_SD_FILE_SELECTED_ES,
-	MSG_SD_FILE_SELECTED_PL
+const char * const MSG_SD_FILE_SELECTED_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_FILE_SELECTED_EN
 };
 
 const char MSG_SD_INIT_FAIL_EN[] PROGMEM = "SD init fail";
-const char MSG_SD_INIT_FAIL_CZ[] PROGMEM = "SD init fail";
-const char MSG_SD_INIT_FAIL_IT[] PROGMEM = "SD init fail";
-const char MSG_SD_INIT_FAIL_ES[] PROGMEM = "SD init fail";
-const char MSG_SD_INIT_FAIL_PL[] PROGMEM = "SD init fail";
-const char * const MSG_SD_INIT_FAIL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_INIT_FAIL_EN,
-	MSG_SD_INIT_FAIL_CZ,
-	MSG_SD_INIT_FAIL_IT,
-	MSG_SD_INIT_FAIL_ES,
-	MSG_SD_INIT_FAIL_PL
+const char * const MSG_SD_INIT_FAIL_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_INIT_FAIL_EN
 };
 
 const char MSG_SD_INSERTED_EN[] PROGMEM = "Card inserted";
 const char MSG_SD_INSERTED_CZ[] PROGMEM = "Karta vlozena";
-const char MSG_SD_INSERTED_IT[] PROGMEM = "SD Card inserita";
-const char MSG_SD_INSERTED_ES[] PROGMEM = "Tarjeta colocada";
-const char MSG_SD_INSERTED_PL[] PROGMEM = "Karta wlozona";
 const char * const MSG_SD_INSERTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SD_INSERTED_EN,
-	MSG_SD_INSERTED_CZ,
-	MSG_SD_INSERTED_IT,
-	MSG_SD_INSERTED_ES,
-	MSG_SD_INSERTED_PL
+	MSG_SD_INSERTED_CZ
 };
 
 const char MSG_SD_NOT_PRINTING_EN[] PROGMEM = "Not SD printing";
-const char MSG_SD_NOT_PRINTING_CZ[] PROGMEM = "Not SD printing";
-const char MSG_SD_NOT_PRINTING_IT[] PROGMEM = "Not SD printing";
-const char MSG_SD_NOT_PRINTING_ES[] PROGMEM = "Not SD printing";
-const char MSG_SD_NOT_PRINTING_PL[] PROGMEM = "Not SD printing";
-const char * const MSG_SD_NOT_PRINTING_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_NOT_PRINTING_EN,
-	MSG_SD_NOT_PRINTING_CZ,
-	MSG_SD_NOT_PRINTING_IT,
-	MSG_SD_NOT_PRINTING_ES,
-	MSG_SD_NOT_PRINTING_PL
+const char * const MSG_SD_NOT_PRINTING_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_NOT_PRINTING_EN
 };
 
 const char MSG_SD_OPENROOT_FAIL_EN[] PROGMEM = "openRoot failed";
-const char MSG_SD_OPENROOT_FAIL_CZ[] PROGMEM = "openRoot failed";
-const char MSG_SD_OPENROOT_FAIL_IT[] PROGMEM = "openRoot failed";
-const char MSG_SD_OPENROOT_FAIL_ES[] PROGMEM = "openRoot failed";
-const char MSG_SD_OPENROOT_FAIL_PL[] PROGMEM = "openRoot failed";
-const char * const MSG_SD_OPENROOT_FAIL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_OPENROOT_FAIL_EN,
-	MSG_SD_OPENROOT_FAIL_CZ,
-	MSG_SD_OPENROOT_FAIL_IT,
-	MSG_SD_OPENROOT_FAIL_ES,
-	MSG_SD_OPENROOT_FAIL_PL
+const char * const MSG_SD_OPENROOT_FAIL_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_OPENROOT_FAIL_EN
 };
 
 const char MSG_SD_OPEN_FILE_FAIL_EN[] PROGMEM = "open failed, File: ";
-const char MSG_SD_OPEN_FILE_FAIL_CZ[] PROGMEM = "open failed, File: ";
-const char MSG_SD_OPEN_FILE_FAIL_IT[] PROGMEM = "open failed, File: ";
-const char MSG_SD_OPEN_FILE_FAIL_ES[] PROGMEM = "open failed, File: ";
-const char MSG_SD_OPEN_FILE_FAIL_PL[] PROGMEM = "open failed, File: ";
-const char * const MSG_SD_OPEN_FILE_FAIL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_OPEN_FILE_FAIL_EN,
-	MSG_SD_OPEN_FILE_FAIL_CZ,
-	MSG_SD_OPEN_FILE_FAIL_IT,
-	MSG_SD_OPEN_FILE_FAIL_ES,
-	MSG_SD_OPEN_FILE_FAIL_PL
+const char * const MSG_SD_OPEN_FILE_FAIL_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_OPEN_FILE_FAIL_EN
 };
 
 const char MSG_SD_PRINTING_BYTE_EN[] PROGMEM = "SD printing byte ";
-const char MSG_SD_PRINTING_BYTE_CZ[] PROGMEM = "SD printing byte ";
-const char MSG_SD_PRINTING_BYTE_IT[] PROGMEM = "SD printing byte ";
-const char MSG_SD_PRINTING_BYTE_ES[] PROGMEM = "SD printing byte ";
-const char MSG_SD_PRINTING_BYTE_PL[] PROGMEM = "SD printing byte ";
-const char * const MSG_SD_PRINTING_BYTE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_PRINTING_BYTE_EN,
-	MSG_SD_PRINTING_BYTE_CZ,
-	MSG_SD_PRINTING_BYTE_IT,
-	MSG_SD_PRINTING_BYTE_ES,
-	MSG_SD_PRINTING_BYTE_PL
+const char * const MSG_SD_PRINTING_BYTE_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_PRINTING_BYTE_EN
 };
 
 const char MSG_SD_REMOVED_EN[] PROGMEM = "Card removed";
 const char MSG_SD_REMOVED_CZ[] PROGMEM = "Karta vyjmuta";
-const char MSG_SD_REMOVED_IT[] PROGMEM = "SD Card rimossa";
-const char MSG_SD_REMOVED_ES[] PROGMEM = "Tarjeta retirada";
-const char MSG_SD_REMOVED_PL[] PROGMEM = "Karta wyjeta";
 const char * const MSG_SD_REMOVED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SD_REMOVED_EN,
-	MSG_SD_REMOVED_CZ,
-	MSG_SD_REMOVED_IT,
-	MSG_SD_REMOVED_ES,
-	MSG_SD_REMOVED_PL
+	MSG_SD_REMOVED_CZ
 };
 
 const char MSG_SD_SIZE_EN[] PROGMEM = " Size: ";
-const char MSG_SD_SIZE_CZ[] PROGMEM = " Size: ";
-const char MSG_SD_SIZE_IT[] PROGMEM = " Size: ";
-const char MSG_SD_SIZE_ES[] PROGMEM = " Size: ";
-const char MSG_SD_SIZE_PL[] PROGMEM = " Size: ";
-const char * const MSG_SD_SIZE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_SIZE_EN,
-	MSG_SD_SIZE_CZ,
-	MSG_SD_SIZE_IT,
-	MSG_SD_SIZE_ES,
-	MSG_SD_SIZE_PL
+const char * const MSG_SD_SIZE_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_SIZE_EN
 };
 
 const char MSG_SD_VOL_INIT_FAIL_EN[] PROGMEM = "volume.init failed";
-const char MSG_SD_VOL_INIT_FAIL_CZ[] PROGMEM = "volume.init failed";
-const char MSG_SD_VOL_INIT_FAIL_IT[] PROGMEM = "volume.init failed";
-const char MSG_SD_VOL_INIT_FAIL_ES[] PROGMEM = "volume.init failed";
-const char MSG_SD_VOL_INIT_FAIL_PL[] PROGMEM = "volume.init failed";
-const char * const MSG_SD_VOL_INIT_FAIL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_VOL_INIT_FAIL_EN,
-	MSG_SD_VOL_INIT_FAIL_CZ,
-	MSG_SD_VOL_INIT_FAIL_IT,
-	MSG_SD_VOL_INIT_FAIL_ES,
-	MSG_SD_VOL_INIT_FAIL_PL
+const char * const MSG_SD_VOL_INIT_FAIL_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_VOL_INIT_FAIL_EN
 };
 
 const char MSG_SD_WORKDIR_FAIL_EN[] PROGMEM = "workDir open failed";
-const char MSG_SD_WORKDIR_FAIL_CZ[] PROGMEM = "workDir open failed";
-const char MSG_SD_WORKDIR_FAIL_IT[] PROGMEM = "workDir open failed";
-const char MSG_SD_WORKDIR_FAIL_ES[] PROGMEM = "workDir open failed";
-const char MSG_SD_WORKDIR_FAIL_PL[] PROGMEM = "workDir open failed";
-const char * const MSG_SD_WORKDIR_FAIL_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_WORKDIR_FAIL_EN,
-	MSG_SD_WORKDIR_FAIL_CZ,
-	MSG_SD_WORKDIR_FAIL_IT,
-	MSG_SD_WORKDIR_FAIL_ES,
-	MSG_SD_WORKDIR_FAIL_PL
+const char * const MSG_SD_WORKDIR_FAIL_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_WORKDIR_FAIL_EN
 };
 
 const char MSG_SD_WRITE_TO_FILE_EN[] PROGMEM = "Writing to file: ";
-const char MSG_SD_WRITE_TO_FILE_CZ[] PROGMEM = "Writing to file: ";
-const char MSG_SD_WRITE_TO_FILE_IT[] PROGMEM = "Writing to file: ";
-const char MSG_SD_WRITE_TO_FILE_ES[] PROGMEM = "Writing to file: ";
-const char MSG_SD_WRITE_TO_FILE_PL[] PROGMEM = "Writing to file: ";
-const char * const MSG_SD_WRITE_TO_FILE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SD_WRITE_TO_FILE_EN,
-	MSG_SD_WRITE_TO_FILE_CZ,
-	MSG_SD_WRITE_TO_FILE_IT,
-	MSG_SD_WRITE_TO_FILE_ES,
-	MSG_SD_WRITE_TO_FILE_PL
+const char * const MSG_SD_WRITE_TO_FILE_LANG_TABLE[1] PROGMEM = {
+	MSG_SD_WRITE_TO_FILE_EN
 };
 
 const char MSG_SELFTEST_EN[] PROGMEM = "Selftest         ";
-const char MSG_SELFTEST_CZ[] PROGMEM = "Selftest         ";
-const char MSG_SELFTEST_IT[] PROGMEM = "Autotest";
-const char MSG_SELFTEST_ES[] PROGMEM = "Autotest";
-const char MSG_SELFTEST_PL[] PROGMEM = "Selftest         ";
-const char * const MSG_SELFTEST_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_EN,
-	MSG_SELFTEST_CZ,
-	MSG_SELFTEST_IT,
-	MSG_SELFTEST_ES,
-	MSG_SELFTEST_PL
+const char * const MSG_SELFTEST_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_EN
+};
+
+const char MSG_SELFTEST_AXIS_EN[] PROGMEM = "Axis";
+const char MSG_SELFTEST_AXIS_CZ[] PROGMEM = "Osa";
+const char * const MSG_SELFTEST_AXIS_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_AXIS_EN,
+	MSG_SELFTEST_AXIS_CZ
+};
+
+const char MSG_SELFTEST_AXIS_LENGTH_EN[] PROGMEM = "Axis length";
+const char MSG_SELFTEST_AXIS_LENGTH_CZ[] PROGMEM = "Delka osy";
+const char * const MSG_SELFTEST_AXIS_LENGTH_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_AXIS_LENGTH_EN,
+	MSG_SELFTEST_AXIS_LENGTH_CZ
 };
 
 const char MSG_SELFTEST_BEDHEATER_EN[] PROGMEM = "Bed / Heater";
-const char MSG_SELFTEST_BEDHEATER_CZ[] PROGMEM = "Bed / Heater";
-const char MSG_SELFTEST_BEDHEATER_IT[] PROGMEM = "Piastra/Riscaldatore";
-const char MSG_SELFTEST_BEDHEATER_ES[] PROGMEM = "Cama/Calentador";
-const char MSG_SELFTEST_BEDHEATER_PL[] PROGMEM = "Bed / Heater";
-const char * const MSG_SELFTEST_BEDHEATER_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_BEDHEATER_EN,
-	MSG_SELFTEST_BEDHEATER_CZ,
-	MSG_SELFTEST_BEDHEATER_IT,
-	MSG_SELFTEST_BEDHEATER_ES,
-	MSG_SELFTEST_BEDHEATER_PL
+const char * const MSG_SELFTEST_BEDHEATER_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_BEDHEATER_EN
 };
 
 const char MSG_SELFTEST_CHECK_ALLCORRECT_EN[] PROGMEM = "All correct      ";
 const char MSG_SELFTEST_CHECK_ALLCORRECT_CZ[] PROGMEM = "Vse OK           ";
-const char MSG_SELFTEST_CHECK_ALLCORRECT_IT[] PROGMEM = "Nessun errore";
-const char MSG_SELFTEST_CHECK_ALLCORRECT_ES[] PROGMEM = "Todo bie ";
-const char MSG_SELFTEST_CHECK_ALLCORRECT_PL[] PROGMEM = "Wszystko OK      ";
 const char * const MSG_SELFTEST_CHECK_ALLCORRECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_ALLCORRECT_EN,
-	MSG_SELFTEST_CHECK_ALLCORRECT_CZ,
-	MSG_SELFTEST_CHECK_ALLCORRECT_IT,
-	MSG_SELFTEST_CHECK_ALLCORRECT_ES,
-	MSG_SELFTEST_CHECK_ALLCORRECT_PL
+	MSG_SELFTEST_CHECK_ALLCORRECT_CZ
 };
 
 const char MSG_SELFTEST_CHECK_BED_EN[] PROGMEM = "Checking bed     ";
 const char MSG_SELFTEST_CHECK_BED_CZ[] PROGMEM = "Kontrola bed     ";
-const char MSG_SELFTEST_CHECK_BED_IT[] PROGMEM = "Verifica piastra";
-const char MSG_SELFTEST_CHECK_BED_ES[] PROGMEM = "Control de cama";
-const char MSG_SELFTEST_CHECK_BED_PL[] PROGMEM = "Kontrola bed     ";
 const char * const MSG_SELFTEST_CHECK_BED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_BED_EN,
-	MSG_SELFTEST_CHECK_BED_CZ,
-	MSG_SELFTEST_CHECK_BED_IT,
-	MSG_SELFTEST_CHECK_BED_ES,
-	MSG_SELFTEST_CHECK_BED_PL
+	MSG_SELFTEST_CHECK_BED_CZ
 };
 
 const char MSG_SELFTEST_CHECK_ENDSTOPS_EN[] PROGMEM = "Checking endstops";
 const char MSG_SELFTEST_CHECK_ENDSTOPS_CZ[] PROGMEM = "Kontrola endstops";
-const char MSG_SELFTEST_CHECK_ENDSTOPS_IT[] PROGMEM = "Verifica limiti";
-const char MSG_SELFTEST_CHECK_ENDSTOPS_ES[] PROGMEM = "Cont. topes final";
-const char MSG_SELFTEST_CHECK_ENDSTOPS_PL[] PROGMEM = "Kontrola endstops";
 const char * const MSG_SELFTEST_CHECK_ENDSTOPS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_ENDSTOPS_EN,
-	MSG_SELFTEST_CHECK_ENDSTOPS_CZ,
-	MSG_SELFTEST_CHECK_ENDSTOPS_IT,
-	MSG_SELFTEST_CHECK_ENDSTOPS_ES,
-	MSG_SELFTEST_CHECK_ENDSTOPS_PL
+	MSG_SELFTEST_CHECK_ENDSTOPS_CZ
 };
 
 const char MSG_SELFTEST_CHECK_HOTEND_EN[] PROGMEM = "Checking hotend  ";
 const char MSG_SELFTEST_CHECK_HOTEND_CZ[] PROGMEM = "Kontrola hotend  ";
-const char MSG_SELFTEST_CHECK_HOTEND_IT[] PROGMEM = "Verifica lim temp";
-const char MSG_SELFTEST_CHECK_HOTEND_ES[] PROGMEM = "Control hotend ";
-const char MSG_SELFTEST_CHECK_HOTEND_PL[] PROGMEM = "Kontrola hotend  ";
 const char * const MSG_SELFTEST_CHECK_HOTEND_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_HOTEND_EN,
-	MSG_SELFTEST_CHECK_HOTEND_CZ,
-	MSG_SELFTEST_CHECK_HOTEND_IT,
-	MSG_SELFTEST_CHECK_HOTEND_ES,
-	MSG_SELFTEST_CHECK_HOTEND_PL
+	MSG_SELFTEST_CHECK_HOTEND_CZ
 };
 
 const char MSG_SELFTEST_CHECK_X_EN[] PROGMEM = "Checking X axis  ";
 const char MSG_SELFTEST_CHECK_X_CZ[] PROGMEM = "Kontrola X axis  ";
-const char MSG_SELFTEST_CHECK_X_IT[] PROGMEM = "Verifica asse X";
-const char MSG_SELFTEST_CHECK_X_ES[] PROGMEM = "Control del eje X";
-const char MSG_SELFTEST_CHECK_X_PL[] PROGMEM = "Kontrola X axis  ";
 const char * const MSG_SELFTEST_CHECK_X_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_X_EN,
-	MSG_SELFTEST_CHECK_X_CZ,
-	MSG_SELFTEST_CHECK_X_IT,
-	MSG_SELFTEST_CHECK_X_ES,
-	MSG_SELFTEST_CHECK_X_PL
+	MSG_SELFTEST_CHECK_X_CZ
 };
 
 const char MSG_SELFTEST_CHECK_Y_EN[] PROGMEM = "Checking Y axis  ";
 const char MSG_SELFTEST_CHECK_Y_CZ[] PROGMEM = "Kontrola Y axis  ";
-const char MSG_SELFTEST_CHECK_Y_IT[] PROGMEM = "Verifica asse Y";
-const char MSG_SELFTEST_CHECK_Y_ES[] PROGMEM = "Control del eje Y";
-const char MSG_SELFTEST_CHECK_Y_PL[] PROGMEM = "Kontrola Y axis  ";
 const char * const MSG_SELFTEST_CHECK_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_Y_EN,
-	MSG_SELFTEST_CHECK_Y_CZ,
-	MSG_SELFTEST_CHECK_Y_IT,
-	MSG_SELFTEST_CHECK_Y_ES,
-	MSG_SELFTEST_CHECK_Y_PL
+	MSG_SELFTEST_CHECK_Y_CZ
 };
 
 const char MSG_SELFTEST_CHECK_Z_EN[] PROGMEM = "Checking Z axis  ";
 const char MSG_SELFTEST_CHECK_Z_CZ[] PROGMEM = "Kontrola Z axis  ";
-const char MSG_SELFTEST_CHECK_Z_IT[] PROGMEM = "Verifica asse Z";
-const char MSG_SELFTEST_CHECK_Z_ES[] PROGMEM = "Control del eje Z";
-const char MSG_SELFTEST_CHECK_Z_PL[] PROGMEM = "Kontrola Z axis  ";
 const char * const MSG_SELFTEST_CHECK_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_Z_EN,
-	MSG_SELFTEST_CHECK_Z_CZ,
-	MSG_SELFTEST_CHECK_Z_IT,
-	MSG_SELFTEST_CHECK_Z_ES,
-	MSG_SELFTEST_CHECK_Z_PL
+	MSG_SELFTEST_CHECK_Z_CZ
+};
+
+const char MSG_SELFTEST_COOLING_FAN_EN[] PROGMEM = "Front print fan?";
+const char MSG_SELFTEST_COOLING_FAN_CZ[] PROGMEM = "Predni tiskovy vent?";
+const char * const MSG_SELFTEST_COOLING_FAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_COOLING_FAN_EN,
+	MSG_SELFTEST_COOLING_FAN_CZ
 };
 
 const char MSG_SELFTEST_ENDSTOP_EN[] PROGMEM = "Endstop";
-const char MSG_SELFTEST_ENDSTOP_CZ[] PROGMEM = "Endstop";
-const char MSG_SELFTEST_ENDSTOP_IT[] PROGMEM = "Limite corsa";
-const char MSG_SELFTEST_ENDSTOP_ES[] PROGMEM = "Tope final";
-const char MSG_SELFTEST_ENDSTOP_PL[] PROGMEM = "Endstop";
-const char * const MSG_SELFTEST_ENDSTOP_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_ENDSTOP_EN,
-	MSG_SELFTEST_ENDSTOP_CZ,
-	MSG_SELFTEST_ENDSTOP_IT,
-	MSG_SELFTEST_ENDSTOP_ES,
-	MSG_SELFTEST_ENDSTOP_PL
+const char * const MSG_SELFTEST_ENDSTOP_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_ENDSTOP_EN
 };
 
 const char MSG_SELFTEST_ENDSTOPS_EN[] PROGMEM = "Endstops";
-const char MSG_SELFTEST_ENDSTOPS_CZ[] PROGMEM = "Endstops";
-const char MSG_SELFTEST_ENDSTOPS_IT[] PROGMEM = "Limiti corsa";
-const char MSG_SELFTEST_ENDSTOPS_ES[] PROGMEM = "Topes final";
-const char MSG_SELFTEST_ENDSTOPS_PL[] PROGMEM = "Endstops";
-const char * const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_ENDSTOPS_EN,
-	MSG_SELFTEST_ENDSTOPS_CZ,
-	MSG_SELFTEST_ENDSTOPS_IT,
-	MSG_SELFTEST_ENDSTOPS_ES,
-	MSG_SELFTEST_ENDSTOPS_PL
+const char * const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_ENDSTOPS_EN
 };
 
 const char MSG_SELFTEST_ENDSTOP_NOTHIT_EN[] PROGMEM = "Endstop not hit";
-const char MSG_SELFTEST_ENDSTOP_NOTHIT_CZ[] PROGMEM = "Endstop not hit";
-const char MSG_SELFTEST_ENDSTOP_NOTHIT_IT[] PROGMEM = "Lim. fuoriportata";
-const char MSG_SELFTEST_ENDSTOP_NOTHIT_ES[] PROGMEM = "Tope fin. no toc.";
-const char MSG_SELFTEST_ENDSTOP_NOTHIT_PL[] PROGMEM = "Endstop not hit";
-const char * const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_ENDSTOP_NOTHIT_EN,
-	MSG_SELFTEST_ENDSTOP_NOTHIT_CZ,
-	MSG_SELFTEST_ENDSTOP_NOTHIT_IT,
-	MSG_SELFTEST_ENDSTOP_NOTHIT_ES,
-	MSG_SELFTEST_ENDSTOP_NOTHIT_PL
+const char * const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_ENDSTOP_NOTHIT_EN
 };
 
 const char MSG_SELFTEST_ERROR_EN[] PROGMEM = "Selftest error !";
-const char MSG_SELFTEST_ERROR_CZ[] PROGMEM = "Selftest error !";
-const char MSG_SELFTEST_ERROR_IT[] PROGMEM = "Autotest negativo";
-const char MSG_SELFTEST_ERROR_ES[] PROGMEM = "Autotest error!";
-const char MSG_SELFTEST_ERROR_PL[] PROGMEM = "Selftest error !";
-const char * const MSG_SELFTEST_ERROR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_ERROR_EN,
-	MSG_SELFTEST_ERROR_CZ,
-	MSG_SELFTEST_ERROR_IT,
-	MSG_SELFTEST_ERROR_ES,
-	MSG_SELFTEST_ERROR_PL
+const char * const MSG_SELFTEST_ERROR_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_ERROR_EN
+};
+
+const char MSG_SELFTEST_EXTRUDER_FAN_EN[] PROGMEM = "Left hotend fan?";
+const char MSG_SELFTEST_EXTRUDER_FAN_CZ[] PROGMEM = "Levy vent na trysce?";
+const char * const MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_EXTRUDER_FAN_EN,
+	MSG_SELFTEST_EXTRUDER_FAN_CZ
 };
 
 const char MSG_SELFTEST_FAILED_EN[] PROGMEM = "Selftest failed  ";
 const char MSG_SELFTEST_FAILED_CZ[] PROGMEM = "Selftest selhal  ";
-const char MSG_SELFTEST_FAILED_IT[] PROGMEM = "Autotest fallito";
-const char MSG_SELFTEST_FAILED_ES[] PROGMEM = "Autotest fallado";
-const char MSG_SELFTEST_FAILED_PL[] PROGMEM = "Selftest nieudany";
 const char * const MSG_SELFTEST_FAILED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_FAILED_EN,
-	MSG_SELFTEST_FAILED_CZ,
-	MSG_SELFTEST_FAILED_IT,
-	MSG_SELFTEST_FAILED_ES,
-	MSG_SELFTEST_FAILED_PL
+	MSG_SELFTEST_FAILED_CZ
+};
+
+const char MSG_SELFTEST_FAN_EN[] PROGMEM = "Fan test";
+const char MSG_SELFTEST_FAN_CZ[] PROGMEM = "Test ventilatoru";
+const char * const MSG_SELFTEST_FAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_FAN_EN,
+	MSG_SELFTEST_FAN_CZ
+};
+
+const char MSG_SELFTEST_FAN_NO_EN[] PROGMEM = "Not spinning";
+const char MSG_SELFTEST_FAN_NO_CZ[] PROGMEM = "Netoci se";
+const char * const MSG_SELFTEST_FAN_NO_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_FAN_NO_EN,
+	MSG_SELFTEST_FAN_NO_CZ
+};
+
+const char MSG_SELFTEST_FAN_YES_EN[] PROGMEM = "Spinning";
+const char MSG_SELFTEST_FAN_YES_CZ[] PROGMEM = "Toci se";
+const char * const MSG_SELFTEST_FAN_YES_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_FAN_YES_EN,
+	MSG_SELFTEST_FAN_YES_CZ
 };
 
 const char MSG_SELFTEST_HEATERTHERMISTOR_EN[] PROGMEM = "Heater/Thermistor";
-const char MSG_SELFTEST_HEATERTHERMISTOR_CZ[] PROGMEM = "Heater/Thermistor";
-const char MSG_SELFTEST_HEATERTHERMISTOR_IT[] PROGMEM = "Riscald./Termistore";
-const char MSG_SELFTEST_HEATERTHERMISTOR_ES[] PROGMEM = "Calent./Termistor";
-const char MSG_SELFTEST_HEATERTHERMISTOR_PL[] PROGMEM = "Heater/Thermistor";
-const char * const MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_HEATERTHERMISTOR_EN,
-	MSG_SELFTEST_HEATERTHERMISTOR_CZ,
-	MSG_SELFTEST_HEATERTHERMISTOR_IT,
-	MSG_SELFTEST_HEATERTHERMISTOR_ES,
-	MSG_SELFTEST_HEATERTHERMISTOR_PL
+const char * const MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_HEATERTHERMISTOR_EN
 };
 
 const char MSG_SELFTEST_MOTOR_EN[] PROGMEM = "Motor";
-const char MSG_SELFTEST_MOTOR_CZ[] PROGMEM = "Motor";
-const char MSG_SELFTEST_MOTOR_IT[] PROGMEM = "Motore";
-const char MSG_SELFTEST_MOTOR_ES[] PROGMEM = "Motor";
-const char MSG_SELFTEST_MOTOR_PL[] PROGMEM = "Silnik";
-const char * const MSG_SELFTEST_MOTOR_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_MOTOR_EN,
-	MSG_SELFTEST_MOTOR_CZ,
-	MSG_SELFTEST_MOTOR_IT,
-	MSG_SELFTEST_MOTOR_ES,
-	MSG_SELFTEST_MOTOR_PL
+const char * const MSG_SELFTEST_MOTOR_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_MOTOR_EN
 };
 
 const char MSG_SELFTEST_NOTCONNECTED_EN[] PROGMEM = "Not connected";
 const char MSG_SELFTEST_NOTCONNECTED_CZ[] PROGMEM = "Nezapojeno    ";
-const char MSG_SELFTEST_NOTCONNECTED_IT[] PROGMEM = "Non connesso";
-const char MSG_SELFTEST_NOTCONNECTED_ES[] PROGMEM = "No hay conexion  ";
-const char MSG_SELFTEST_NOTCONNECTED_PL[] PROGMEM = "Nie podlaczono   ";
 const char * const MSG_SELFTEST_NOTCONNECTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_NOTCONNECTED_EN,
-	MSG_SELFTEST_NOTCONNECTED_CZ,
-	MSG_SELFTEST_NOTCONNECTED_IT,
-	MSG_SELFTEST_NOTCONNECTED_ES,
-	MSG_SELFTEST_NOTCONNECTED_PL
+	MSG_SELFTEST_NOTCONNECTED_CZ
 };
 
 const char MSG_SELFTEST_OK_EN[] PROGMEM = "Self test OK";
-const char MSG_SELFTEST_OK_CZ[] PROGMEM = "Self test OK";
-const char MSG_SELFTEST_OK_IT[] PROGMEM = "Autotest OK";
-const char MSG_SELFTEST_OK_ES[] PROGMEM = "Self test OK";
-const char MSG_SELFTEST_OK_PL[] PROGMEM = "Self test OK";
-const char * const MSG_SELFTEST_OK_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_OK_EN,
-	MSG_SELFTEST_OK_CZ,
-	MSG_SELFTEST_OK_IT,
-	MSG_SELFTEST_OK_ES,
-	MSG_SELFTEST_OK_PL
+const char * const MSG_SELFTEST_OK_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_OK_EN
 };
 
 const char MSG_SELFTEST_PLEASECHECK_EN[] PROGMEM = "Please check :";
 const char MSG_SELFTEST_PLEASECHECK_CZ[] PROGMEM = "Zkontrolujte :";
-const char MSG_SELFTEST_PLEASECHECK_IT[] PROGMEM = "Verifica:";
-const char MSG_SELFTEST_PLEASECHECK_ES[] PROGMEM = "Controla :";
-const char MSG_SELFTEST_PLEASECHECK_PL[] PROGMEM = "Skontroluj :";
 const char * const MSG_SELFTEST_PLEASECHECK_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_PLEASECHECK_EN,
-	MSG_SELFTEST_PLEASECHECK_CZ,
-	MSG_SELFTEST_PLEASECHECK_IT,
-	MSG_SELFTEST_PLEASECHECK_ES,
-	MSG_SELFTEST_PLEASECHECK_PL
+	MSG_SELFTEST_PLEASECHECK_CZ
 };
 
 const char MSG_SELFTEST_START_EN[] PROGMEM = "Self test start  ";
-const char MSG_SELFTEST_START_CZ[] PROGMEM = "Self test start  ";
-const char MSG_SELFTEST_START_IT[] PROGMEM = "Inizia autotest";
-const char MSG_SELFTEST_START_ES[] PROGMEM = "Autotest salida";
-const char MSG_SELFTEST_START_PL[] PROGMEM = "Self test start  ";
-const char * const MSG_SELFTEST_START_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SELFTEST_START_EN,
-	MSG_SELFTEST_START_CZ,
-	MSG_SELFTEST_START_IT,
-	MSG_SELFTEST_START_ES,
-	MSG_SELFTEST_START_PL
+const char * const MSG_SELFTEST_START_LANG_TABLE[1] PROGMEM = {
+	MSG_SELFTEST_START_EN
 };
 
 const char MSG_SELFTEST_WIRINGERROR_EN[] PROGMEM = "Wiring error";
 const char MSG_SELFTEST_WIRINGERROR_CZ[] PROGMEM = "Chyba zapojeni";
-const char MSG_SELFTEST_WIRINGERROR_IT[] PROGMEM = "Errore cablaggio";
-const char MSG_SELFTEST_WIRINGERROR_ES[] PROGMEM = "Error de conexión";
-const char MSG_SELFTEST_WIRINGERROR_PL[] PROGMEM = "Blad polaczenia";
 const char * const MSG_SELFTEST_WIRINGERROR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_WIRINGERROR_EN,
-	MSG_SELFTEST_WIRINGERROR_CZ,
-	MSG_SELFTEST_WIRINGERROR_IT,
-	MSG_SELFTEST_WIRINGERROR_ES,
-	MSG_SELFTEST_WIRINGERROR_PL
+	MSG_SELFTEST_WIRINGERROR_CZ
 };
 
 const char MSG_SERIAL_ERROR_MENU_STRUCTURE_EN[] PROGMEM = "Error in menu structure";
-const char MSG_SERIAL_ERROR_MENU_STRUCTURE_CZ[] PROGMEM = "Error in menu structure";
-const char MSG_SERIAL_ERROR_MENU_STRUCTURE_IT[] PROGMEM = "Error in menu structure";
-const char MSG_SERIAL_ERROR_MENU_STRUCTURE_ES[] PROGMEM = "Error in menu structure";
-const char MSG_SERIAL_ERROR_MENU_STRUCTURE_PL[] PROGMEM = "Error in menu structure";
-const char * const MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SERIAL_ERROR_MENU_STRUCTURE_EN,
-	MSG_SERIAL_ERROR_MENU_STRUCTURE_CZ,
-	MSG_SERIAL_ERROR_MENU_STRUCTURE_IT,
-	MSG_SERIAL_ERROR_MENU_STRUCTURE_ES,
-	MSG_SERIAL_ERROR_MENU_STRUCTURE_PL
+const char * const MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE[1] PROGMEM = {
+	MSG_SERIAL_ERROR_MENU_STRUCTURE_EN
 };
 
 const char MSG_SETTINGS_EN[] PROGMEM = "Settings";
 const char MSG_SETTINGS_CZ[] PROGMEM = "Nastaveni";
-const char MSG_SETTINGS_IT[] PROGMEM = "Impostazioni";
-const char MSG_SETTINGS_ES[] PROGMEM = "Ajuste";
-const char MSG_SETTINGS_PL[] PROGMEM = "Ustawienia";
 const char * const MSG_SETTINGS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SETTINGS_EN,
-	MSG_SETTINGS_CZ,
-	MSG_SETTINGS_IT,
-	MSG_SETTINGS_ES,
-	MSG_SETTINGS_PL
+	MSG_SETTINGS_CZ
 };
 
 const char MSG_SET_HOME_OFFSETS_EN[] PROGMEM = "Set home offsets";
-const char MSG_SET_HOME_OFFSETS_CZ[] PROGMEM = "Nastav pocatek home";
-const char MSG_SET_HOME_OFFSETS_IT[] PROGMEM = "Set home offsets";
-const char MSG_SET_HOME_OFFSETS_ES[] PROGMEM = "Set home offsets";
-const char MSG_SET_HOME_OFFSETS_PL[] PROGMEM = "Nastav pocatek home";
-const char * const MSG_SET_HOME_OFFSETS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SET_HOME_OFFSETS_EN,
-	MSG_SET_HOME_OFFSETS_CZ,
-	MSG_SET_HOME_OFFSETS_IT,
-	MSG_SET_HOME_OFFSETS_ES,
-	MSG_SET_HOME_OFFSETS_PL
+const char * const MSG_SET_HOME_OFFSETS_LANG_TABLE[1] PROGMEM = {
+	MSG_SET_HOME_OFFSETS_EN
 };
 
 const char MSG_SET_ORIGIN_EN[] PROGMEM = "Set origin";
-const char MSG_SET_ORIGIN_CZ[] PROGMEM = "Nastav pocatek";
-const char MSG_SET_ORIGIN_IT[] PROGMEM = "Set origin";
-const char MSG_SET_ORIGIN_ES[] PROGMEM = "Set origin";
-const char MSG_SET_ORIGIN_PL[] PROGMEM = "Nastav pocatek";
-const char * const MSG_SET_ORIGIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SET_ORIGIN_EN,
-	MSG_SET_ORIGIN_CZ,
-	MSG_SET_ORIGIN_IT,
-	MSG_SET_ORIGIN_ES,
-	MSG_SET_ORIGIN_PL
+const char * const MSG_SET_ORIGIN_LANG_TABLE[1] PROGMEM = {
+	MSG_SET_ORIGIN_EN
+};
+
+const char MSG_SET_TEMPERATURE_EN[] PROGMEM = "Set temperature:";
+const char MSG_SET_TEMPERATURE_CZ[] PROGMEM = "Nastavte teplotu:";
+const char * const MSG_SET_TEMPERATURE_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SET_TEMPERATURE_EN,
+	MSG_SET_TEMPERATURE_CZ
+};
+
+const char MSG_SEVERE_SKEW_EN[] PROGMEM = "Severe skew:";
+const char MSG_SEVERE_SKEW_CZ[] PROGMEM = "Tezke zkoseni:";
+const char * const MSG_SEVERE_SKEW_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SEVERE_SKEW_EN,
+	MSG_SEVERE_SKEW_CZ
 };
 
 const char MSG_SHOW_END_STOPS_EN[] PROGMEM = "Show end stops";
-const char MSG_SHOW_END_STOPS_CZ[] PROGMEM = "Zobraz konc. spinace";
-const char MSG_SHOW_END_STOPS_IT[] PROGMEM = "Show end stops";
-const char MSG_SHOW_END_STOPS_ES[] PROGMEM = "Show end stops";
-const char MSG_SHOW_END_STOPS_PL[] PROGMEM = "Show end stops";
+const char MSG_SHOW_END_STOPS_CZ[] PROGMEM = "Stav konc. spin.";
 const char * const MSG_SHOW_END_STOPS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SHOW_END_STOPS_EN,
-	MSG_SHOW_END_STOPS_CZ,
-	MSG_SHOW_END_STOPS_IT,
-	MSG_SHOW_END_STOPS_ES,
-	MSG_SHOW_END_STOPS_PL
+	MSG_SHOW_END_STOPS_CZ
 };
 
-const char MSG_SILENT_MODE_OFF_EN[] PROGMEM = "Mode [high power]";
-const char MSG_SILENT_MODE_OFF_CZ[] PROGMEM = "Mod  [vys. vykon]";
-const char MSG_SILENT_MODE_OFF_IT[] PROGMEM = "Modo [piu forza]";
-const char MSG_SILENT_MODE_OFF_ES[] PROGMEM = "Modo [mas fuerza]";
-const char MSG_SILENT_MODE_OFF_PL[] PROGMEM = "Mod [w wydajnosc]";
+const char MSG_SILENT_MODE_OFF_EN[] PROGMEM = "Mode     [Normal]";
+const char MSG_SILENT_MODE_OFF_CZ[] PROGMEM = "Mod      [Normal]";
 const char * const MSG_SILENT_MODE_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SILENT_MODE_OFF_EN,
-	MSG_SILENT_MODE_OFF_CZ,
-	MSG_SILENT_MODE_OFF_IT,
-	MSG_SILENT_MODE_OFF_ES,
-	MSG_SILENT_MODE_OFF_PL
+	MSG_SILENT_MODE_OFF_CZ
 };
 
-const char MSG_SILENT_MODE_ON_EN[] PROGMEM = "Mode     [silent]";
-const char MSG_SILENT_MODE_ON_CZ[] PROGMEM = "Mod       [tichy]";
-const char MSG_SILENT_MODE_ON_IT[] PROGMEM = "Modo     [silenzioso]";
-const char MSG_SILENT_MODE_ON_ES[] PROGMEM = "Modo     [silencio]";
-const char MSG_SILENT_MODE_ON_PL[] PROGMEM = "Mod       [cichy]";
+const char MSG_SILENT_MODE_ON_EN[] PROGMEM = "Mode    [Stealth]";
+const char MSG_SILENT_MODE_ON_CZ[] PROGMEM = "Mod     [Stealth]";
 const char * const MSG_SILENT_MODE_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SILENT_MODE_ON_EN,
-	MSG_SILENT_MODE_ON_CZ,
-	MSG_SILENT_MODE_ON_IT,
-	MSG_SILENT_MODE_ON_ES,
-	MSG_SILENT_MODE_ON_PL
+	MSG_SILENT_MODE_ON_CZ
+};
+
+const char MSG_SLIGHT_SKEW_EN[] PROGMEM = "Slight skew:";
+const char MSG_SLIGHT_SKEW_CZ[] PROGMEM = "Lehke zkoseni:";
+const char * const MSG_SLIGHT_SKEW_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SLIGHT_SKEW_EN,
+	MSG_SLIGHT_SKEW_CZ
 };
 
 const char MSG_SOFTWARE_RESET_EN[] PROGMEM = " Software Reset";
-const char MSG_SOFTWARE_RESET_CZ[] PROGMEM = " Software Reset";
-const char MSG_SOFTWARE_RESET_IT[] PROGMEM = " Software Reset";
-const char MSG_SOFTWARE_RESET_ES[] PROGMEM = " Software Reset";
-const char MSG_SOFTWARE_RESET_PL[] PROGMEM = " Software Reset";
-const char * const MSG_SOFTWARE_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_SOFTWARE_RESET_EN,
-	MSG_SOFTWARE_RESET_CZ,
-	MSG_SOFTWARE_RESET_IT,
-	MSG_SOFTWARE_RESET_ES,
-	MSG_SOFTWARE_RESET_PL
+const char * const MSG_SOFTWARE_RESET_LANG_TABLE[1] PROGMEM = {
+	MSG_SOFTWARE_RESET_EN
 };
 
 const char MSG_SPEED_EN[] PROGMEM = "Speed";
 const char MSG_SPEED_CZ[] PROGMEM = "Rychlost";
-const char MSG_SPEED_IT[] PROGMEM = "Velcità";
-const char MSG_SPEED_ES[] PROGMEM = "Velocidad";
-const char MSG_SPEED_PL[] PROGMEM = "Predkosc";
 const char * const MSG_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SPEED_EN,
-	MSG_SPEED_CZ,
-	MSG_SPEED_IT,
-	MSG_SPEED_ES,
-	MSG_SPEED_PL
+	MSG_SPEED_CZ
+};
+
+const char MSG_STACK_ERROR_EN[] PROGMEM = "Error - static memory has been overwritten";
+const char * const MSG_STACK_ERROR_LANG_TABLE[1] PROGMEM = {
+	MSG_STACK_ERROR_EN
 };
 
 const char MSG_STATISTICS_EN[] PROGMEM = "Statistics  ";
 const char MSG_STATISTICS_CZ[] PROGMEM = "Statistika  ";
-const char MSG_STATISTICS_IT[] PROGMEM = "Statistiche";
-const char MSG_STATISTICS_ES[] PROGMEM = "Estadistica  ";
-const char MSG_STATISTICS_PL[] PROGMEM = "Statystyka  ";
 const char * const MSG_STATISTICS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATISTICS_EN,
-	MSG_STATISTICS_CZ,
-	MSG_STATISTICS_IT,
-	MSG_STATISTICS_ES,
-	MSG_STATISTICS_PL
+	MSG_STATISTICS_CZ
 };
 
 const char MSG_STATS_FILAMENTUSED_EN[] PROGMEM = "Filament used:  ";
 const char MSG_STATS_FILAMENTUSED_CZ[] PROGMEM = "Filament :  ";
-const char MSG_STATS_FILAMENTUSED_IT[] PROGMEM = "Filamento:";
-const char MSG_STATS_FILAMENTUSED_ES[] PROGMEM = "Filamento :  ";
-const char MSG_STATS_FILAMENTUSED_PL[] PROGMEM = "Filament :  ";
 const char * const MSG_STATS_FILAMENTUSED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_FILAMENTUSED_EN,
-	MSG_STATS_FILAMENTUSED_CZ,
-	MSG_STATS_FILAMENTUSED_IT,
-	MSG_STATS_FILAMENTUSED_ES,
-	MSG_STATS_FILAMENTUSED_PL
+	MSG_STATS_FILAMENTUSED_CZ
 };
 
 const char MSG_STATS_PRINTTIME_EN[] PROGMEM = "Print time:  ";
 const char MSG_STATS_PRINTTIME_CZ[] PROGMEM = "Cas tisku :  ";
-const char MSG_STATS_PRINTTIME_IT[] PROGMEM = "Tempo stampa:";
-const char MSG_STATS_PRINTTIME_ES[] PROGMEM = "Tiempo de imp.:";
-const char MSG_STATS_PRINTTIME_PL[] PROGMEM = "Czas druku :  ";
 const char * const MSG_STATS_PRINTTIME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_PRINTTIME_EN,
-	MSG_STATS_PRINTTIME_CZ,
-	MSG_STATS_PRINTTIME_IT,
-	MSG_STATS_PRINTTIME_ES,
-	MSG_STATS_PRINTTIME_PL
+	MSG_STATS_PRINTTIME_CZ
 };
 
 const char MSG_STATS_TOTALFILAMENT_EN[] PROGMEM = "Total filament :";
 const char MSG_STATS_TOTALFILAMENT_CZ[] PROGMEM = "Filament celkem :";
-const char MSG_STATS_TOTALFILAMENT_IT[] PROGMEM = "Filamento tot:";
-const char MSG_STATS_TOTALFILAMENT_ES[] PROGMEM = "Filamento total:";
-const char MSG_STATS_TOTALFILAMENT_PL[] PROGMEM = "Filament lacznie :";
 const char * const MSG_STATS_TOTALFILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_TOTALFILAMENT_EN,
-	MSG_STATS_TOTALFILAMENT_CZ,
-	MSG_STATS_TOTALFILAMENT_IT,
-	MSG_STATS_TOTALFILAMENT_ES,
-	MSG_STATS_TOTALFILAMENT_PL
+	MSG_STATS_TOTALFILAMENT_CZ
 };
 
 const char MSG_STATS_TOTALPRINTTIME_EN[] PROGMEM = "Total print time :";
 const char MSG_STATS_TOTALPRINTTIME_CZ[] PROGMEM = "Celkovy cas :";
-const char MSG_STATS_TOTALPRINTTIME_IT[] PROGMEM = "Tempo stampa tot:";
-const char MSG_STATS_TOTALPRINTTIME_ES[] PROGMEM = "Tiempo total :";
-const char MSG_STATS_TOTALPRINTTIME_PL[] PROGMEM = "Czas calkowity :";
 const char * const MSG_STATS_TOTALPRINTTIME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_TOTALPRINTTIME_EN,
-	MSG_STATS_TOTALPRINTTIME_CZ,
-	MSG_STATS_TOTALPRINTTIME_IT,
-	MSG_STATS_TOTALPRINTTIME_ES,
-	MSG_STATS_TOTALPRINTTIME_PL
+	MSG_STATS_TOTALPRINTTIME_CZ
+};
+
+const char MSG_STEEL_SHEET_CHECK_EN[] PROGMEM = "Is steel sheet on heatbed?";
+const char MSG_STEEL_SHEET_CHECK_CZ[] PROGMEM = "Je tiskovy plat na heatbed?";
+const char * const MSG_STEEL_SHEET_CHECK_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_STEEL_SHEET_CHECK_EN,
+	MSG_STEEL_SHEET_CHECK_CZ
 };
 
 const char MSG_STEPPER_TOO_HIGH_EN[] PROGMEM = "Steprate too high: ";
-const char MSG_STEPPER_TOO_HIGH_CZ[] PROGMEM = "Steprate too high: ";
-const char MSG_STEPPER_TOO_HIGH_IT[] PROGMEM = "Steprate too high: ";
-const char MSG_STEPPER_TOO_HIGH_ES[] PROGMEM = "Steprate too high: ";
-const char MSG_STEPPER_TOO_HIGH_PL[] PROGMEM = "Steprate too high: ";
-const char * const MSG_STEPPER_TOO_HIGH_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_STEPPER_TOO_HIGH_EN,
-	MSG_STEPPER_TOO_HIGH_CZ,
-	MSG_STEPPER_TOO_HIGH_IT,
-	MSG_STEPPER_TOO_HIGH_ES,
-	MSG_STEPPER_TOO_HIGH_PL
+const char * const MSG_STEPPER_TOO_HIGH_LANG_TABLE[1] PROGMEM = {
+	MSG_STEPPER_TOO_HIGH_EN
 };
 
 const char MSG_STOPPED_EN[] PROGMEM = "STOPPED. ";
-const char MSG_STOPPED_CZ[] PROGMEM = "STOPPED. ";
-const char MSG_STOPPED_IT[] PROGMEM = "ARRESTATO ";
-const char MSG_STOPPED_ES[] PROGMEM = "PARADA";
-const char MSG_STOPPED_PL[] PROGMEM = "STOPPED. ";
-const char * const MSG_STOPPED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_STOPPED_EN,
-	MSG_STOPPED_CZ,
-	MSG_STOPPED_IT,
-	MSG_STOPPED_ES,
-	MSG_STOPPED_PL
+const char * const MSG_STOPPED_LANG_TABLE[1] PROGMEM = {
+	MSG_STOPPED_EN
 };
 
 const char MSG_STOP_PRINT_EN[] PROGMEM = "Stop print";
 const char MSG_STOP_PRINT_CZ[] PROGMEM = "Zastavit tisk";
-const char MSG_STOP_PRINT_IT[] PROGMEM = "Arresta stampa";
-const char MSG_STOP_PRINT_ES[] PROGMEM = "Detener impresion";
-const char MSG_STOP_PRINT_PL[] PROGMEM = "Zatrzymac druk";
 const char * const MSG_STOP_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STOP_PRINT_EN,
-	MSG_STOP_PRINT_CZ,
-	MSG_STOP_PRINT_IT,
-	MSG_STOP_PRINT_ES,
-	MSG_STOP_PRINT_PL
+	MSG_STOP_PRINT_CZ
 };
 
 const char MSG_STORE_EPROM_EN[] PROGMEM = "Store memory";
-const char MSG_STORE_EPROM_CZ[] PROGMEM = "Store memory";
-const char MSG_STORE_EPROM_IT[] PROGMEM = "Store memory";
-const char MSG_STORE_EPROM_ES[] PROGMEM = "Store memory";
-const char MSG_STORE_EPROM_PL[] PROGMEM = "Store memory";
-const char * const MSG_STORE_EPROM_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_STORE_EPROM_EN,
-	MSG_STORE_EPROM_CZ,
-	MSG_STORE_EPROM_IT,
-	MSG_STORE_EPROM_ES,
-	MSG_STORE_EPROM_PL
+const char * const MSG_STORE_EPROM_LANG_TABLE[1] PROGMEM = {
+	MSG_STORE_EPROM_EN
 };
 
 const char MSG_SUPPORT_EN[] PROGMEM = "Support";
 const char MSG_SUPPORT_CZ[] PROGMEM = "Podpora";
-const char MSG_SUPPORT_IT[] PROGMEM = "Support";
-const char MSG_SUPPORT_ES[] PROGMEM = "Support";
-const char MSG_SUPPORT_PL[] PROGMEM = "Pomoc";
 const char * const MSG_SUPPORT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SUPPORT_EN,
-	MSG_SUPPORT_CZ,
-	MSG_SUPPORT_IT,
-	MSG_SUPPORT_ES,
-	MSG_SUPPORT_PL
+	MSG_SUPPORT_CZ
 };
 
 const char MSG_SWITCH_PS_OFF_EN[] PROGMEM = "Switch power off";
 const char MSG_SWITCH_PS_OFF_CZ[] PROGMEM = "Zapnout zdroj";
-const char MSG_SWITCH_PS_OFF_IT[] PROGMEM = "Switch power off";
-const char MSG_SWITCH_PS_OFF_ES[] PROGMEM = "Switch power off";
-const char MSG_SWITCH_PS_OFF_PL[] PROGMEM = "Zapnout zdroj";
 const char * const MSG_SWITCH_PS_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SWITCH_PS_OFF_EN,
-	MSG_SWITCH_PS_OFF_CZ,
-	MSG_SWITCH_PS_OFF_IT,
-	MSG_SWITCH_PS_OFF_ES,
-	MSG_SWITCH_PS_OFF_PL
+	MSG_SWITCH_PS_OFF_CZ
 };
 
 const char MSG_SWITCH_PS_ON_EN[] PROGMEM = "Switch power on";
 const char MSG_SWITCH_PS_ON_CZ[] PROGMEM = "Vypnout zdroj";
-const char MSG_SWITCH_PS_ON_IT[] PROGMEM = "Switch power on";
-const char MSG_SWITCH_PS_ON_ES[] PROGMEM = "Switch power on";
-const char MSG_SWITCH_PS_ON_PL[] PROGMEM = "Vypnout zdroj";
 const char * const MSG_SWITCH_PS_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SWITCH_PS_ON_EN,
-	MSG_SWITCH_PS_ON_CZ,
-	MSG_SWITCH_PS_ON_IT,
-	MSG_SWITCH_PS_ON_ES,
-	MSG_SWITCH_PS_ON_PL
+	MSG_SWITCH_PS_ON_CZ
 };
 
 const char MSG_TAKE_EFFECT_EN[] PROGMEM = " for take effect";
 const char MSG_TAKE_EFFECT_CZ[] PROGMEM = " pro projeveni zmen";
-const char MSG_TAKE_EFFECT_IT[] PROGMEM = " per mostrare i camb.";
-const char MSG_TAKE_EFFECT_ES[] PROGMEM = "para tomar efecto";
-const char MSG_TAKE_EFFECT_PL[] PROGMEM = "wprow. zmian";
 const char * const MSG_TAKE_EFFECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_TAKE_EFFECT_EN,
-	MSG_TAKE_EFFECT_CZ,
-	MSG_TAKE_EFFECT_IT,
-	MSG_TAKE_EFFECT_ES,
-	MSG_TAKE_EFFECT_PL
+	MSG_TAKE_EFFECT_CZ
 };
 
 const char MSG_TEMPERATURE_EN[] PROGMEM = "Temperature";
 const char MSG_TEMPERATURE_CZ[] PROGMEM = "Teplota";
-const char MSG_TEMPERATURE_IT[] PROGMEM = "Temperatura";
-const char MSG_TEMPERATURE_ES[] PROGMEM = "Temperatura";
-const char MSG_TEMPERATURE_PL[] PROGMEM = "Temperatura";
 const char * const MSG_TEMPERATURE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_TEMPERATURE_EN,
-	MSG_TEMPERATURE_CZ,
-	MSG_TEMPERATURE_IT,
-	MSG_TEMPERATURE_ES,
-	MSG_TEMPERATURE_PL
+	MSG_TEMPERATURE_CZ
+};
+
+const char MSG_TEMP_CALIBRATION_EN[] PROGMEM = "Temp. cal.          ";
+const char MSG_TEMP_CALIBRATION_CZ[] PROGMEM = "Tepl. kal.          ";
+const char * const MSG_TEMP_CALIBRATION_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_TEMP_CALIBRATION_EN,
+	MSG_TEMP_CALIBRATION_CZ
+};
+
+const char MSG_TEMP_CALIBRATION_DONE_EN[] PROGMEM = "Temperature calibration is finished. Click to continue.";
+const char MSG_TEMP_CALIBRATION_DONE_CZ[] PROGMEM = "Teplotni kalibrace dokoncena. Pokracujte stiskem tlacitka.";
+const char * const MSG_TEMP_CALIBRATION_DONE_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_TEMP_CALIBRATION_DONE_EN,
+	MSG_TEMP_CALIBRATION_DONE_CZ
+};
+
+const char MSG_TEMP_CALIBRATION_OFF_EN[] PROGMEM = "Temp. cal.  [off]";
+const char MSG_TEMP_CALIBRATION_OFF_CZ[] PROGMEM = "Tepl. kal.  [vyp]";
+const char * const MSG_TEMP_CALIBRATION_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_TEMP_CALIBRATION_OFF_EN,
+	MSG_TEMP_CALIBRATION_OFF_CZ
+};
+
+const char MSG_TEMP_CALIBRATION_ON_EN[] PROGMEM = "Temp. cal.   [on]";
+const char MSG_TEMP_CALIBRATION_ON_CZ[] PROGMEM = "Tepl. kal.  [zap]";
+const char * const MSG_TEMP_CALIBRATION_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_TEMP_CALIBRATION_ON_EN,
+	MSG_TEMP_CALIBRATION_ON_CZ
+};
+
+const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN[] PROGMEM = "SD card [normal]";
+const char * const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE[1] PROGMEM = {
+	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN
+};
+
+const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN[] PROGMEM = "SD card [FlshAir]";
+const char * const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_LANG_TABLE[1] PROGMEM = {
+	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN
 };
 
 const char MSG_TUNE_EN[] PROGMEM = "Tune";
 const char MSG_TUNE_CZ[] PROGMEM = "Ladit";
-const char MSG_TUNE_IT[] PROGMEM = "Adatta";
-const char MSG_TUNE_ES[] PROGMEM = "Ajustar";
-const char MSG_TUNE_PL[] PROGMEM = "Nastroic";
 const char * const MSG_TUNE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_TUNE_EN,
-	MSG_TUNE_CZ,
-	MSG_TUNE_IT,
-	MSG_TUNE_ES,
-	MSG_TUNE_PL
+	MSG_TUNE_CZ
 };
 
 const char MSG_UNKNOWN_COMMAND_EN[] PROGMEM = "Unknown command: \"";
-const char MSG_UNKNOWN_COMMAND_CZ[] PROGMEM = "Unknown command: \"";
-const char MSG_UNKNOWN_COMMAND_IT[] PROGMEM = "Unknown command: \"";
-const char MSG_UNKNOWN_COMMAND_ES[] PROGMEM = "Unknown command: \"";
-const char MSG_UNKNOWN_COMMAND_PL[] PROGMEM = "Unknown command: \"";
-const char * const MSG_UNKNOWN_COMMAND_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_UNKNOWN_COMMAND_EN,
-	MSG_UNKNOWN_COMMAND_CZ,
-	MSG_UNKNOWN_COMMAND_IT,
-	MSG_UNKNOWN_COMMAND_ES,
-	MSG_UNKNOWN_COMMAND_PL
+const char * const MSG_UNKNOWN_COMMAND_LANG_TABLE[1] PROGMEM = {
+	MSG_UNKNOWN_COMMAND_EN
+};
+
+const char MSG_UNLOADING_FILAMENT_EN[] PROGMEM = "Unloading filament";
+const char MSG_UNLOADING_FILAMENT_CZ[] PROGMEM = "Vysouvam filament";
+const char * const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOADING_FILAMENT_EN,
+	MSG_UNLOADING_FILAMENT_CZ
+};
+
+const char MSG_UNLOAD_ALL_EN[] PROGMEM = "Unload all";
+const char MSG_UNLOAD_ALL_CZ[] PROGMEM = "Vyjmout vse";
+const char * const MSG_UNLOAD_ALL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOAD_ALL_EN,
+	MSG_UNLOAD_ALL_CZ
 };
 
 const char MSG_UNLOAD_FILAMENT_EN[] PROGMEM = "Unload filament";
 const char MSG_UNLOAD_FILAMENT_CZ[] PROGMEM = "Vyjmout filament";
-const char MSG_UNLOAD_FILAMENT_IT[] PROGMEM = "Scaricare fil.";
-const char MSG_UNLOAD_FILAMENT_ES[] PROGMEM = "Sacar filamento";
-const char MSG_UNLOAD_FILAMENT_PL[] PROGMEM = "Wyjac filament";
 const char * const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_UNLOAD_FILAMENT_EN,
-	MSG_UNLOAD_FILAMENT_CZ,
-	MSG_UNLOAD_FILAMENT_IT,
-	MSG_UNLOAD_FILAMENT_ES,
-	MSG_UNLOAD_FILAMENT_PL
+	MSG_UNLOAD_FILAMENT_CZ
+};
+
+const char MSG_UNLOAD_FILAMENT_1_EN[] PROGMEM = "Unload filament 1";
+const char MSG_UNLOAD_FILAMENT_1_CZ[] PROGMEM = "Vyjmout filam. 1";
+const char * const MSG_UNLOAD_FILAMENT_1_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOAD_FILAMENT_1_EN,
+	MSG_UNLOAD_FILAMENT_1_CZ
+};
+
+const char MSG_UNLOAD_FILAMENT_2_EN[] PROGMEM = "Unload filament 2";
+const char MSG_UNLOAD_FILAMENT_2_CZ[] PROGMEM = "Vyjmout filam. 2";
+const char * const MSG_UNLOAD_FILAMENT_2_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOAD_FILAMENT_2_EN,
+	MSG_UNLOAD_FILAMENT_2_CZ
+};
+
+const char MSG_UNLOAD_FILAMENT_3_EN[] PROGMEM = "Unload filament 3";
+const char MSG_UNLOAD_FILAMENT_3_CZ[] PROGMEM = "Vyjmout filam. 3";
+const char * const MSG_UNLOAD_FILAMENT_3_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOAD_FILAMENT_3_EN,
+	MSG_UNLOAD_FILAMENT_3_CZ
+};
+
+const char MSG_UNLOAD_FILAMENT_4_EN[] PROGMEM = "Unload filament 4";
+const char MSG_UNLOAD_FILAMENT_4_CZ[] PROGMEM = "Vyjmout filam. 4";
+const char * const MSG_UNLOAD_FILAMENT_4_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOAD_FILAMENT_4_EN,
+	MSG_UNLOAD_FILAMENT_4_CZ
+};
+
+const char MSG_UNLOAD_SUCCESSFULL_EN[] PROGMEM = "Repeat unloading filament?";
+const char MSG_UNLOAD_SUCCESSFULL_CZ[] PROGMEM = "Opakovat vysunuti filamentu?";
+const char * const MSG_UNLOAD_SUCCESSFULL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOAD_SUCCESSFULL_EN,
+	MSG_UNLOAD_SUCCESSFULL_CZ
 };
 
 const char MSG_USB_PRINTING_EN[] PROGMEM = "USB printing  ";
 const char MSG_USB_PRINTING_CZ[] PROGMEM = "Tisk z USB  ";
-const char MSG_USB_PRINTING_IT[] PROGMEM = "Stampa da USB";
-const char MSG_USB_PRINTING_ES[] PROGMEM = "Impresion de USB ";
-const char MSG_USB_PRINTING_PL[] PROGMEM = "Druk z USB  ";
 const char * const MSG_USB_PRINTING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_USB_PRINTING_EN,
-	MSG_USB_PRINTING_CZ,
-	MSG_USB_PRINTING_IT,
-	MSG_USB_PRINTING_ES,
-	MSG_USB_PRINTING_PL
+	MSG_USB_PRINTING_CZ
+};
+
+const char MSG_USED_EN[] PROGMEM = "Used during print";
+const char MSG_USED_CZ[] PROGMEM = "Pouzite behem tisku";
+const char * const MSG_USED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_USED_EN,
+	MSG_USED_CZ
 };
 
 const char MSG_USERWAIT_EN[] PROGMEM = "Wait for user...";
-const char MSG_USERWAIT_CZ[] PROGMEM = "Wait for user...";
-const char MSG_USERWAIT_IT[] PROGMEM = "Attendi Utente...";
-const char MSG_USERWAIT_ES[] PROGMEM = "Esperando ordenes";
-const char MSG_USERWAIT_PL[] PROGMEM = "Wait for user...";
-const char * const MSG_USERWAIT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_USERWAIT_EN,
-	MSG_USERWAIT_CZ,
-	MSG_USERWAIT_IT,
-	MSG_USERWAIT_ES,
-	MSG_USERWAIT_PL
-};
-
-const char MSG_VE_JERK_EN[] PROGMEM = "Ve-jerk";
-const char MSG_VE_JERK_CZ[] PROGMEM = "Ve-jerk";
-const char MSG_VE_JERK_IT[] PROGMEM = "Ve-jerk";
-const char MSG_VE_JERK_ES[] PROGMEM = "Ve-jerk";
-const char MSG_VE_JERK_PL[] PROGMEM = "Ve-jerk";
-const char * const MSG_VE_JERK_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VE_JERK_EN,
-	MSG_VE_JERK_CZ,
-	MSG_VE_JERK_IT,
-	MSG_VE_JERK_ES,
-	MSG_VE_JERK_PL
-};
-
-const char MSG_VMAX_EN[] PROGMEM = "Vmax ";
-const char MSG_VMAX_CZ[] PROGMEM = "Vmax ";
-const char MSG_VMAX_IT[] PROGMEM = "Vmax ";
-const char MSG_VMAX_ES[] PROGMEM = "Vmax ";
-const char MSG_VMAX_PL[] PROGMEM = "Vmax ";
-const char * const MSG_VMAX_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VMAX_EN,
-	MSG_VMAX_CZ,
-	MSG_VMAX_IT,
-	MSG_VMAX_ES,
-	MSG_VMAX_PL
+const char * const MSG_USERWAIT_LANG_TABLE[1] PROGMEM = {
+	MSG_USERWAIT_EN
+};
+
+const char MSG_V2_CALIBRATION_EN[] PROGMEM = "First layer cal.";
+const char MSG_V2_CALIBRATION_CZ[] PROGMEM = "Kal. prvni vrstvy";
+const char * const MSG_V2_CALIBRATION_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_V2_CALIBRATION_EN,
+	MSG_V2_CALIBRATION_CZ
 };
 
 const char MSG_VMIN_EN[] PROGMEM = "Vmin";
-const char MSG_VMIN_CZ[] PROGMEM = "Vmin";
-const char MSG_VMIN_IT[] PROGMEM = "Vmin";
-const char MSG_VMIN_ES[] PROGMEM = "Vmin";
-const char MSG_VMIN_PL[] PROGMEM = "Vmin";
-const char * const MSG_VMIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VMIN_EN,
-	MSG_VMIN_CZ,
-	MSG_VMIN_IT,
-	MSG_VMIN_ES,
-	MSG_VMIN_PL
+const char * const MSG_VMIN_LANG_TABLE[1] PROGMEM = {
+	MSG_VMIN_EN
 };
 
 const char MSG_VOLUMETRIC_EN[] PROGMEM = "Filament";
-const char MSG_VOLUMETRIC_CZ[] PROGMEM = "Filament";
-const char MSG_VOLUMETRIC_IT[] PROGMEM = "Filament";
-const char MSG_VOLUMETRIC_ES[] PROGMEM = "Filament";
-const char MSG_VOLUMETRIC_PL[] PROGMEM = "Filament";
-const char * const MSG_VOLUMETRIC_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VOLUMETRIC_EN,
-	MSG_VOLUMETRIC_CZ,
-	MSG_VOLUMETRIC_IT,
-	MSG_VOLUMETRIC_ES,
-	MSG_VOLUMETRIC_PL
+const char * const MSG_VOLUMETRIC_LANG_TABLE[1] PROGMEM = {
+	MSG_VOLUMETRIC_EN
 };
 
 const char MSG_VOLUMETRIC_ENABLED_EN[] PROGMEM = "E in mm3";
-const char MSG_VOLUMETRIC_ENABLED_CZ[] PROGMEM = "E in mm3";
-const char MSG_VOLUMETRIC_ENABLED_IT[] PROGMEM = "E in mm3";
-const char MSG_VOLUMETRIC_ENABLED_ES[] PROGMEM = "E in mm3";
-const char MSG_VOLUMETRIC_ENABLED_PL[] PROGMEM = "E in mm3";
-const char * const MSG_VOLUMETRIC_ENABLED_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VOLUMETRIC_ENABLED_EN,
-	MSG_VOLUMETRIC_ENABLED_CZ,
-	MSG_VOLUMETRIC_ENABLED_IT,
-	MSG_VOLUMETRIC_ENABLED_ES,
-	MSG_VOLUMETRIC_ENABLED_PL
+const char * const MSG_VOLUMETRIC_ENABLED_LANG_TABLE[1] PROGMEM = {
+	MSG_VOLUMETRIC_ENABLED_EN
 };
 
 const char MSG_VTRAV_MIN_EN[] PROGMEM = "VTrav min";
-const char MSG_VTRAV_MIN_CZ[] PROGMEM = "VTrav min";
-const char MSG_VTRAV_MIN_IT[] PROGMEM = "VTrav min";
-const char MSG_VTRAV_MIN_ES[] PROGMEM = "VTrav min";
-const char MSG_VTRAV_MIN_PL[] PROGMEM = "VTrav min";
-const char * const MSG_VTRAV_MIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VTRAV_MIN_EN,
-	MSG_VTRAV_MIN_CZ,
-	MSG_VTRAV_MIN_IT,
-	MSG_VTRAV_MIN_ES,
-	MSG_VTRAV_MIN_PL
-};
-
-const char MSG_VXY_JERK_EN[] PROGMEM = "Vxy-jerk";
-const char MSG_VXY_JERK_CZ[] PROGMEM = "Vxy-jerk";
-const char MSG_VXY_JERK_IT[] PROGMEM = "Vxy-jerk";
-const char MSG_VXY_JERK_ES[] PROGMEM = "Vxy-jerk";
-const char MSG_VXY_JERK_PL[] PROGMEM = "Vxy-jerk";
-const char * const MSG_VXY_JERK_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VXY_JERK_EN,
-	MSG_VXY_JERK_CZ,
-	MSG_VXY_JERK_IT,
-	MSG_VXY_JERK_ES,
-	MSG_VXY_JERK_PL
-};
-
-const char MSG_VZ_JERK_EN[] PROGMEM = "Vz-jerk";
-const char MSG_VZ_JERK_CZ[] PROGMEM = "Vz-jerk";
-const char MSG_VZ_JERK_IT[] PROGMEM = "Vz-jerk";
-const char MSG_VZ_JERK_ES[] PROGMEM = "Vz-jerk";
-const char MSG_VZ_JERK_PL[] PROGMEM = "Vz-jerk";
-const char * const MSG_VZ_JERK_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_VZ_JERK_EN,
-	MSG_VZ_JERK_CZ,
-	MSG_VZ_JERK_IT,
-	MSG_VZ_JERK_ES,
-	MSG_VZ_JERK_PL
+const char * const MSG_VTRAV_MIN_LANG_TABLE[1] PROGMEM = {
+	MSG_VTRAV_MIN_EN
+};
+
+const char MSG_WAITING_TEMP_EN[] PROGMEM = "Waiting for nozzle and bed cooling";
+const char MSG_WAITING_TEMP_CZ[] PROGMEM = "Cekani na zchladnuti trysky a podlozky.";
+const char * const MSG_WAITING_TEMP_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WAITING_TEMP_EN,
+	MSG_WAITING_TEMP_CZ
 };
 
 const char MSG_WATCH_EN[] PROGMEM = "Info screen";
 const char MSG_WATCH_CZ[] PROGMEM = "Informace";
-const char MSG_WATCH_IT[] PROGMEM = "Guarda";
-const char MSG_WATCH_ES[] PROGMEM = "Monitorizar";
-const char MSG_WATCH_PL[] PROGMEM = "Informacje";
 const char * const MSG_WATCH_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_WATCH_EN,
-	MSG_WATCH_CZ,
-	MSG_WATCH_IT,
-	MSG_WATCH_ES,
-	MSG_WATCH_PL
+	MSG_WATCH_CZ
 };
 
 const char MSG_WATCHDOG_RESET_EN[] PROGMEM = " Watchdog Reset";
-const char MSG_WATCHDOG_RESET_CZ[] PROGMEM = " Watchdog Reset";
-const char MSG_WATCHDOG_RESET_IT[] PROGMEM = " Watchdog Reset";
-const char MSG_WATCHDOG_RESET_ES[] PROGMEM = " Watchdog Reset";
-const char MSG_WATCHDOG_RESET_PL[] PROGMEM = " Watchdog Reset";
-const char * const MSG_WATCHDOG_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_WATCHDOG_RESET_EN,
-	MSG_WATCHDOG_RESET_CZ,
-	MSG_WATCHDOG_RESET_IT,
-	MSG_WATCHDOG_RESET_ES,
-	MSG_WATCHDOG_RESET_PL
-};
-
-const char MSG_X_EN[] PROGMEM = "x";
-const char MSG_X_CZ[] PROGMEM = "x";
-const char MSG_X_IT[] PROGMEM = "x";
-const char MSG_X_ES[] PROGMEM = "x";
-const char MSG_X_PL[] PROGMEM = "x";
-const char * const MSG_X_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_X_EN,
-	MSG_X_CZ,
-	MSG_X_IT,
-	MSG_X_ES,
-	MSG_X_PL
-};
-
-const char MSG_XSTEPS_EN[] PROGMEM = "Xsteps/mm";
-const char MSG_XSTEPS_CZ[] PROGMEM = "Xsteps/mm";
-const char MSG_XSTEPS_IT[] PROGMEM = "Xsteps/mm";
-const char MSG_XSTEPS_ES[] PROGMEM = "Xsteps/mm";
-const char MSG_XSTEPS_PL[] PROGMEM = "Xsteps/mm";
-const char * const MSG_XSTEPS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_XSTEPS_EN,
-	MSG_XSTEPS_CZ,
-	MSG_XSTEPS_IT,
-	MSG_XSTEPS_ES,
-	MSG_XSTEPS_PL
+const char * const MSG_WATCHDOG_RESET_LANG_TABLE[1] PROGMEM = {
+	MSG_WATCHDOG_RESET_EN
+};
+
+const char MSG_WIZARD_EN[] PROGMEM = "Wizard";
+const char * const MSG_WIZARD_LANG_TABLE[1] PROGMEM = {
+	MSG_WIZARD_EN
+};
+
+const char MSG_WIZARD_CALIBRATION_FAILED_EN[] PROGMEM = "Please check our handbook and fix the problem. Then resume the Wizard by rebooting the printer.";
+const char MSG_WIZARD_CALIBRATION_FAILED_CZ[] PROGMEM = "Prosim nahlednete do manualu a opravte problem. Po te obnovte Wizarda rebootovanim tiskarny.";
+const char * const MSG_WIZARD_CALIBRATION_FAILED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_CALIBRATION_FAILED_EN,
+	MSG_WIZARD_CALIBRATION_FAILED_CZ
+};
+
+const char MSG_WIZARD_CLEAN_HEATBED_EN[] PROGMEM = "Please clean heatbed and then press the knob.";
+const char MSG_WIZARD_CLEAN_HEATBED_CZ[] PROGMEM = "Prosim ocistete heatbed a stisknete tlacitko.";
+const char * const MSG_WIZARD_CLEAN_HEATBED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_CLEAN_HEATBED_EN,
+	MSG_WIZARD_CLEAN_HEATBED_CZ
+};
+
+const char MSG_WIZARD_DONE_EN[] PROGMEM = "All is done. Happy printing!";
+const char MSG_WIZARD_DONE_CZ[] PROGMEM = "Vse je hotovo.";
+const char * const MSG_WIZARD_DONE_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_DONE_EN,
+	MSG_WIZARD_DONE_CZ
+};
+
+const char MSG_WIZARD_FILAMENT_LOADED_EN[] PROGMEM = "Is filament loaded?";
+const char MSG_WIZARD_FILAMENT_LOADED_CZ[] PROGMEM = "Je filament zaveden?";
+const char * const MSG_WIZARD_FILAMENT_LOADED_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_FILAMENT_LOADED_EN,
+	MSG_WIZARD_FILAMENT_LOADED_CZ
+};
+
+const char MSG_WIZARD_HEATING_EN[] PROGMEM = "Preheating nozzle. Please wait.";
+const char MSG_WIZARD_HEATING_CZ[] PROGMEM = "Predehrivam trysku. Prosim cekejte.";
+const char * const MSG_WIZARD_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_HEATING_EN,
+	MSG_WIZARD_HEATING_CZ
+};
+
+const char MSG_WIZARD_INSERT_CORRECT_FILAMENT_EN[] PROGMEM = "Please load PLA filament and then resume Wizard by rebooting the printer.";
+const char MSG_WIZARD_INSERT_CORRECT_FILAMENT_CZ[] PROGMEM = "Prosim zavedte PLA filament a po te obnovte Wizarda stisknutim reset tlacitka.";
+const char * const MSG_WIZARD_INSERT_CORRECT_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_INSERT_CORRECT_FILAMENT_EN,
+	MSG_WIZARD_INSERT_CORRECT_FILAMENT_CZ
+};
+
+const char MSG_WIZARD_LOAD_FILAMENT_EN[] PROGMEM = "Please insert PLA filament to the extruder, then press knob to load it.";
+const char MSG_WIZARD_LOAD_FILAMENT_CZ[] PROGMEM = "Prosim vlozte PLA filament do extruderu, po te stisknete tlacitko pro zavedeni filamentu.";
+const char * const MSG_WIZARD_LOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_LOAD_FILAMENT_EN,
+	MSG_WIZARD_LOAD_FILAMENT_CZ
+};
+
+const char MSG_WIZARD_PLA_FILAMENT_EN[] PROGMEM = "Is it PLA filament?";
+const char MSG_WIZARD_PLA_FILAMENT_CZ[] PROGMEM = "Je to PLA filament?";
+const char * const MSG_WIZARD_PLA_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_PLA_FILAMENT_EN,
+	MSG_WIZARD_PLA_FILAMENT_CZ
+};
+
+const char MSG_WIZARD_QUIT_EN[] PROGMEM = "You can always resume the Wizard from Calibration -> Wizard.";
+const char MSG_WIZARD_QUIT_CZ[] PROGMEM = "Wizarda muzete kdykoliv znovu spustit z menu Calibration -> Wizard";
+const char * const MSG_WIZARD_QUIT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_QUIT_EN,
+	MSG_WIZARD_QUIT_CZ
+};
+
+const char MSG_WIZARD_REPEAT_V2_CAL_EN[] PROGMEM = "Do you want to repeat last step to readjust distance between nozzle and heatbed?";
+const char MSG_WIZARD_REPEAT_V2_CAL_CZ[] PROGMEM = "Chcete opakovat posledni krok a pozmenit vzdalenost mezi tryskou a heatbed?";
+const char * const MSG_WIZARD_REPEAT_V2_CAL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_REPEAT_V2_CAL_EN,
+	MSG_WIZARD_REPEAT_V2_CAL_CZ
+};
+
+const char MSG_WIZARD_RERUN_EN[] PROGMEM = "Running Wizard will delete current calibration results and start from the beginning. Continue?";
+const char MSG_WIZARD_RERUN_CZ[] PROGMEM = "Spusteni Wizarda vymaze ulozene vysledky vsech kalibraci a spusti kalibracni proces od zacatku. Pokracovat?";
+const char * const MSG_WIZARD_RERUN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_RERUN_EN,
+	MSG_WIZARD_RERUN_CZ
+};
+
+const char MSG_WIZARD_SELFTEST_EN[] PROGMEM = "First, I will run the selftest to check most common assembly problems.";
+const char MSG_WIZARD_SELFTEST_CZ[] PROGMEM = "Nejdriv pomoci selftestu zkontoluji nejcastejsi chyby vznikajici pri sestaveni tiskarny.";
+const char * const MSG_WIZARD_SELFTEST_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_SELFTEST_EN,
+	MSG_WIZARD_SELFTEST_CZ
+};
+
+const char MSG_WIZARD_V2_CAL_EN[] PROGMEM = "Now I will calibrate distance between tip of the nozzle and heatbed surface.";
+const char MSG_WIZARD_V2_CAL_CZ[] PROGMEM = "Nyni zkalibruji vzdalenost mezi koncem trysky a povrchem heatbedu.";
+const char * const MSG_WIZARD_V2_CAL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_V2_CAL_EN,
+	MSG_WIZARD_V2_CAL_CZ
+};
+
+const char MSG_WIZARD_V2_CAL_2_EN[] PROGMEM = "I will start to print line and you will gradually lower the nozzle by rotating the knob, until you reach optimal height. Check the pictures in our handbook in chapter Calibration.";
+const char MSG_WIZARD_V2_CAL_2_CZ[] PROGMEM = "Zacnu tisknout linku a Vy budete postupne snizovat trysku otacenim tlacitka dokud nedosahnete optimalni vysky. Prohlednete si obrazky v nasi prirucce v kapitole Kalibrace";
+const char * const MSG_WIZARD_V2_CAL_2_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_V2_CAL_2_EN,
+	MSG_WIZARD_V2_CAL_2_CZ
+};
+
+const char MSG_WIZARD_WELCOME_EN[] PROGMEM = "Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?";
+const char MSG_WIZARD_WELCOME_CZ[] PROGMEM = "Dobry den, jsem vase tiskarna Original Prusa i3. Chcete abych Vas provedla kalibracnim procesem?";
+const char * const MSG_WIZARD_WELCOME_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_WELCOME_EN,
+	MSG_WIZARD_WELCOME_CZ
+};
+
+const char MSG_WIZARD_WILL_PREHEAT_EN[] PROGMEM = "Now I will preheat nozzle for PLA.";
+const char MSG_WIZARD_WILL_PREHEAT_CZ[] PROGMEM = "Nyni predehreji trysku pro PLA.";
+const char * const MSG_WIZARD_WILL_PREHEAT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_WILL_PREHEAT_EN,
+	MSG_WIZARD_WILL_PREHEAT_CZ
+};
+
+const char MSG_WIZARD_XYZ_CAL_EN[] PROGMEM = "I will run xyz calibration now. It will take approx. 12 mins.";
+const char MSG_WIZARD_XYZ_CAL_CZ[] PROGMEM = "Nyni provedu xyz kalibraci. Zabere to priblizne 12 min.";
+const char * const MSG_WIZARD_XYZ_CAL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_XYZ_CAL_EN,
+	MSG_WIZARD_XYZ_CAL_CZ
+};
+
+const char MSG_WIZARD_Z_CAL_EN[] PROGMEM = "I will run z calibration now.";
+const char MSG_WIZARD_Z_CAL_CZ[] PROGMEM = "Nyni provedu z kalibraci.";
+const char * const MSG_WIZARD_Z_CAL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WIZARD_Z_CAL_EN,
+	MSG_WIZARD_Z_CAL_CZ
+};
+
+const char MSG_XYZ_DETAILS_EN[] PROGMEM = "XYZ cal. details";
+const char MSG_XYZ_DETAILS_CZ[] PROGMEM = "Detaily XYZ kal.";
+const char * const MSG_XYZ_DETAILS_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_XYZ_DETAILS_EN,
+	MSG_XYZ_DETAILS_CZ
 };
 
 const char MSG_X_MAX_EN[] PROGMEM = "x_max: ";
-const char MSG_X_MAX_CZ[] PROGMEM = "x_max: ";
-const char MSG_X_MAX_IT[] PROGMEM = "x_max: ";
-const char MSG_X_MAX_ES[] PROGMEM = "x_max: ";
-const char MSG_X_MAX_PL[] PROGMEM = "x_max: ";
-const char * const MSG_X_MAX_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_X_MAX_EN,
-	MSG_X_MAX_CZ,
-	MSG_X_MAX_IT,
-	MSG_X_MAX_ES,
-	MSG_X_MAX_PL
+const char * const MSG_X_MAX_LANG_TABLE[1] PROGMEM = {
+	MSG_X_MAX_EN
 };
 
 const char MSG_X_MIN_EN[] PROGMEM = "x_min: ";
-const char MSG_X_MIN_CZ[] PROGMEM = "x_min: ";
-const char MSG_X_MIN_IT[] PROGMEM = "x_min: ";
-const char MSG_X_MIN_ES[] PROGMEM = "x_min: ";
-const char MSG_X_MIN_PL[] PROGMEM = "x_min: ";
-const char * const MSG_X_MIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_X_MIN_EN,
-	MSG_X_MIN_CZ,
-	MSG_X_MIN_IT,
-	MSG_X_MIN_ES,
-	MSG_X_MIN_PL
-};
-
-const char MSG_Y_EN[] PROGMEM = "y";
-const char MSG_Y_CZ[] PROGMEM = "y";
-const char MSG_Y_IT[] PROGMEM = "y";
-const char MSG_Y_ES[] PROGMEM = "y";
-const char MSG_Y_PL[] PROGMEM = "y";
-const char * const MSG_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Y_EN,
-	MSG_Y_CZ,
-	MSG_Y_IT,
-	MSG_Y_ES,
-	MSG_Y_PL
+const char * const MSG_X_MIN_LANG_TABLE[1] PROGMEM = {
+	MSG_X_MIN_EN
 };
 
 const char MSG_YES_EN[] PROGMEM = "Yes";
 const char MSG_YES_CZ[] PROGMEM = "Ano";
-const char MSG_YES_IT[] PROGMEM = "Si";
-const char MSG_YES_ES[] PROGMEM = "Si";
-const char MSG_YES_PL[] PROGMEM = "Tak";
 const char * const MSG_YES_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_YES_EN,
-	MSG_YES_CZ,
-	MSG_YES_IT,
-	MSG_YES_ES,
-	MSG_YES_PL
+	MSG_YES_CZ
 };
 
-const char MSG_YSTEPS_EN[] PROGMEM = "Ysteps/mm";
-const char MSG_YSTEPS_CZ[] PROGMEM = "Ysteps/mm";
-const char MSG_YSTEPS_IT[] PROGMEM = "Ysteps/mm";
-const char MSG_YSTEPS_ES[] PROGMEM = "Ysteps/mm";
-const char MSG_YSTEPS_PL[] PROGMEM = "Ysteps/mm";
-const char * const MSG_YSTEPS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_YSTEPS_EN,
-	MSG_YSTEPS_CZ,
-	MSG_YSTEPS_IT,
-	MSG_YSTEPS_ES,
-	MSG_YSTEPS_PL
+const char MSG_Y_DISTANCE_FROM_MIN_EN[] PROGMEM = "Y distance from min:";
+const char MSG_Y_DISTANCE_FROM_MIN_CZ[] PROGMEM = "Y vzdalenost od min:";
+const char * const MSG_Y_DISTANCE_FROM_MIN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_Y_DISTANCE_FROM_MIN_EN,
+	MSG_Y_DISTANCE_FROM_MIN_CZ
 };
 
 const char MSG_Y_MAX_EN[] PROGMEM = "y_max: ";
-const char MSG_Y_MAX_CZ[] PROGMEM = "y_max: ";
-const char MSG_Y_MAX_IT[] PROGMEM = "y_max: ";
-const char MSG_Y_MAX_ES[] PROGMEM = "y_max: ";
-const char MSG_Y_MAX_PL[] PROGMEM = "y_max: ";
-const char * const MSG_Y_MAX_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Y_MAX_EN,
-	MSG_Y_MAX_CZ,
-	MSG_Y_MAX_IT,
-	MSG_Y_MAX_ES,
-	MSG_Y_MAX_PL
+const char * const MSG_Y_MAX_LANG_TABLE[1] PROGMEM = {
+	MSG_Y_MAX_EN
 };
 
 const char MSG_Y_MIN_EN[] PROGMEM = "y_min: ";
-const char MSG_Y_MIN_CZ[] PROGMEM = "y_min: ";
-const char MSG_Y_MIN_IT[] PROGMEM = "y_min: ";
-const char MSG_Y_MIN_ES[] PROGMEM = "y_min: ";
-const char MSG_Y_MIN_PL[] PROGMEM = "y_min: ";
-const char * const MSG_Y_MIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Y_MIN_EN,
-	MSG_Y_MIN_CZ,
-	MSG_Y_MIN_IT,
-	MSG_Y_MIN_ES,
-	MSG_Y_MIN_PL
-};
-
-const char MSG_Z_EN[] PROGMEM = "z";
-const char MSG_Z_CZ[] PROGMEM = "z";
-const char MSG_Z_IT[] PROGMEM = "z";
-const char MSG_Z_ES[] PROGMEM = "z";
-const char MSG_Z_PL[] PROGMEM = "z";
-const char * const MSG_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Z_EN,
-	MSG_Z_CZ,
-	MSG_Z_IT,
-	MSG_Z_ES,
-	MSG_Z_PL
+const char * const MSG_Y_MIN_LANG_TABLE[1] PROGMEM = {
+	MSG_Y_MIN_EN
 };
 
 const char MSG_ZPROBE_OUT_EN[] PROGMEM = "Z probe out. bed";
-const char MSG_ZPROBE_OUT_CZ[] PROGMEM = "Z probe out. bed";
-const char MSG_ZPROBE_OUT_IT[] PROGMEM = "Z probe out. bed";
-const char MSG_ZPROBE_OUT_ES[] PROGMEM = "Z probe out. bed";
-const char MSG_ZPROBE_OUT_PL[] PROGMEM = "Z probe out. bed";
-const char * const MSG_ZPROBE_OUT_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ZPROBE_OUT_EN,
-	MSG_ZPROBE_OUT_CZ,
-	MSG_ZPROBE_OUT_IT,
-	MSG_ZPROBE_OUT_ES,
-	MSG_ZPROBE_OUT_PL
+const char * const MSG_ZPROBE_OUT_LANG_TABLE[1] PROGMEM = {
+	MSG_ZPROBE_OUT_EN
 };
 
 const char MSG_ZPROBE_ZOFFSET_EN[] PROGMEM = "Z Offset";
-const char MSG_ZPROBE_ZOFFSET_CZ[] PROGMEM = "Z Offset";
-const char MSG_ZPROBE_ZOFFSET_IT[] PROGMEM = "Z Offset";
-const char MSG_ZPROBE_ZOFFSET_ES[] PROGMEM = "Z Offset";
-const char MSG_ZPROBE_ZOFFSET_PL[] PROGMEM = "Z Offset";
-const char * const MSG_ZPROBE_ZOFFSET_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ZPROBE_ZOFFSET_EN,
-	MSG_ZPROBE_ZOFFSET_CZ,
-	MSG_ZPROBE_ZOFFSET_IT,
-	MSG_ZPROBE_ZOFFSET_ES,
-	MSG_ZPROBE_ZOFFSET_PL
-};
-
-const char MSG_ZSTEPS_EN[] PROGMEM = "Zsteps/mm";
-const char MSG_ZSTEPS_CZ[] PROGMEM = "Zsteps/mm";
-const char MSG_ZSTEPS_IT[] PROGMEM = "Zsteps/mm";
-const char MSG_ZSTEPS_ES[] PROGMEM = "Zsteps/mm";
-const char MSG_ZSTEPS_PL[] PROGMEM = "Zsteps/mm";
-const char * const MSG_ZSTEPS_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_ZSTEPS_EN,
-	MSG_ZSTEPS_CZ,
-	MSG_ZSTEPS_IT,
-	MSG_ZSTEPS_ES,
-	MSG_ZSTEPS_PL
+const char * const MSG_ZPROBE_ZOFFSET_LANG_TABLE[1] PROGMEM = {
+	MSG_ZPROBE_ZOFFSET_EN
 };
 
 const char MSG_Z_MAX_EN[] PROGMEM = "z_max: ";
-const char MSG_Z_MAX_CZ[] PROGMEM = "z_max: ";
-const char MSG_Z_MAX_IT[] PROGMEM = "z_max: ";
-const char MSG_Z_MAX_ES[] PROGMEM = "z_max: ";
-const char MSG_Z_MAX_PL[] PROGMEM = "z_max: ";
-const char * const MSG_Z_MAX_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Z_MAX_EN,
-	MSG_Z_MAX_CZ,
-	MSG_Z_MAX_IT,
-	MSG_Z_MAX_ES,
-	MSG_Z_MAX_PL
+const char * const MSG_Z_MAX_LANG_TABLE[1] PROGMEM = {
+	MSG_Z_MAX_EN
 };
 
 const char MSG_Z_MIN_EN[] PROGMEM = "z_min: ";
-const char MSG_Z_MIN_CZ[] PROGMEM = "z_min: ";
-const char MSG_Z_MIN_IT[] PROGMEM = "z_min: ";
-const char MSG_Z_MIN_ES[] PROGMEM = "z_min: ";
-const char MSG_Z_MIN_PL[] PROGMEM = "z_min: ";
-const char * const MSG_Z_MIN_LANG_TABLE[LANG_NUM] PROGMEM = {
-	MSG_Z_MIN_EN,
-	MSG_Z_MIN_CZ,
-	MSG_Z_MIN_IT,
-	MSG_Z_MIN_ES,
-	MSG_Z_MIN_PL
+const char * const MSG_Z_MIN_LANG_TABLE[1] PROGMEM = {
+	MSG_Z_MIN_EN
 };
 
 const char WELCOME_MSG_EN[] PROGMEM = CUSTOM_MENDEL_NAME " ready.";
 const char WELCOME_MSG_CZ[] PROGMEM = CUSTOM_MENDEL_NAME " ok";
-const char WELCOME_MSG_IT[] PROGMEM = CUSTOM_MENDEL_NAME " pronto.";
-const char WELCOME_MSG_ES[] PROGMEM = CUSTOM_MENDEL_NAME " lista";
-const char WELCOME_MSG_PL[] PROGMEM = CUSTOM_MENDEL_NAME " gotowa";
 const char * const WELCOME_MSG_LANG_TABLE[LANG_NUM] PROGMEM = {
 	WELCOME_MSG_EN,
-	WELCOME_MSG_CZ,
-	WELCOME_MSG_IT,
-	WELCOME_MSG_ES,
-	WELCOME_MSG_PL
+	WELCOME_MSG_CZ
 };
 
 

+ 513 - 347
Firmware/language_all.h

@@ -1,49 +1,69 @@
 #ifndef LANGUAGE_ALL_H
 #define LANGUAGE_ALL_H
 
-#define LANG_NUM (5)
+#include <avr/pgmspace.h>
+// Language indices into their particular symbol tables.
+#define LANG_ID_EN 0
+#define LANG_ID_CZ 1
+// Language is not defined and it shall be selected from the menu.
+#define LANG_ID_FORCE_SELECTION 254
+// Language is not defined on a virgin RAMBo board.
+#define LANG_ID_UNDEFINED 255
 
+// Default language ID, if no language is selected.
+#define LANG_ID_DEFAULT LANG_ID_CZ
+
+// Number of languages available in the language table.
+#define LANG_NUM 2
+
+// Currectly active language selection.
 extern unsigned char lang_selected;
 
 #define LANG_TABLE_SELECT_EXPLICIT(TABLE, LANG) ((const char*)(pgm_read_ptr(TABLE + (LANG))))
 #define LANG_TABLE_SELECT(TABLE) LANG_TABLE_SELECT_EXPLICIT(TABLE, lang_selected)
 
-extern const char* const MSG_ACC_LANG_TABLE[LANG_NUM];
-#define MSG_ACC LANG_TABLE_SELECT(MSG_ACC_LANG_TABLE)
-extern const char* const MSG_ACTIVE_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_ACTIVE_EXTRUDER LANG_TABLE_SELECT(MSG_ACTIVE_EXTRUDER_LANG_TABLE)
+extern const char* const MSG_ACTIVE_EXTRUDER_LANG_TABLE[1];
+#define MSG_ACTIVE_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_ACTIVE_EXTRUDER_LANG_TABLE, 0)
 extern const char* const MSG_ADJUSTZ_LANG_TABLE[LANG_NUM];
 #define MSG_ADJUSTZ LANG_TABLE_SELECT(MSG_ADJUSTZ_LANG_TABLE)
-extern const char* const MSG_AMAX_LANG_TABLE[LANG_NUM];
-#define MSG_AMAX LANG_TABLE_SELECT(MSG_AMAX_LANG_TABLE)
-extern const char* const MSG_AUTHOR_LANG_TABLE[LANG_NUM];
-#define MSG_AUTHOR LANG_TABLE_SELECT(MSG_AUTHOR_LANG_TABLE)
-extern const char* const MSG_AUTORETRACT_LANG_TABLE[LANG_NUM];
-#define MSG_AUTORETRACT LANG_TABLE_SELECT(MSG_AUTORETRACT_LANG_TABLE)
-extern const char* const MSG_AUTOSTART_LANG_TABLE[LANG_NUM];
-#define MSG_AUTOSTART LANG_TABLE_SELECT(MSG_AUTOSTART_LANG_TABLE)
-extern const char* const MSG_AUTOTEMP_LANG_TABLE[LANG_NUM];
-#define MSG_AUTOTEMP LANG_TABLE_SELECT(MSG_AUTOTEMP_LANG_TABLE)
-extern const char* const MSG_AUTO_HOME_LANG_TABLE[LANG_NUM];
-#define MSG_AUTO_HOME LANG_TABLE_SELECT(MSG_AUTO_HOME_LANG_TABLE)
-extern const char* const MSG_A_RETRACT_LANG_TABLE[LANG_NUM];
-#define MSG_A_RETRACT LANG_TABLE_SELECT(MSG_A_RETRACT_LANG_TABLE)
-extern const char* const MSG_BABYSTEPPING_X_LANG_TABLE[LANG_NUM];
-#define MSG_BABYSTEPPING_X LANG_TABLE_SELECT(MSG_BABYSTEPPING_X_LANG_TABLE)
-extern const char* const MSG_BABYSTEPPING_Y_LANG_TABLE[LANG_NUM];
-#define MSG_BABYSTEPPING_Y LANG_TABLE_SELECT(MSG_BABYSTEPPING_Y_LANG_TABLE)
-extern const char* const MSG_BABYSTEPPING_Z_LANG_TABLE[LANG_NUM];
-#define MSG_BABYSTEPPING_Z LANG_TABLE_SELECT(MSG_BABYSTEPPING_Z_LANG_TABLE)
-extern const char* const MSG_BABYSTEP_X_LANG_TABLE[LANG_NUM];
-#define MSG_BABYSTEP_X LANG_TABLE_SELECT(MSG_BABYSTEP_X_LANG_TABLE)
-extern const char* const MSG_BABYSTEP_Y_LANG_TABLE[LANG_NUM];
-#define MSG_BABYSTEP_Y LANG_TABLE_SELECT(MSG_BABYSTEP_Y_LANG_TABLE)
+extern const char* const MSG_ALL_LANG_TABLE[LANG_NUM];
+#define MSG_ALL LANG_TABLE_SELECT(MSG_ALL_LANG_TABLE)
+extern const char* const MSG_AMAX_LANG_TABLE[1];
+#define MSG_AMAX LANG_TABLE_SELECT_EXPLICIT(MSG_AMAX_LANG_TABLE, 0)
+extern const char* const MSG_AUTHOR_LANG_TABLE[1];
+#define MSG_AUTHOR LANG_TABLE_SELECT_EXPLICIT(MSG_AUTHOR_LANG_TABLE, 0)
+extern const char* const MSG_AUTO_HOME_LANG_TABLE[1];
+#define MSG_AUTO_HOME LANG_TABLE_SELECT_EXPLICIT(MSG_AUTO_HOME_LANG_TABLE, 0)
+extern const char* const MSG_A_RETRACT_LANG_TABLE[1];
+#define MSG_A_RETRACT LANG_TABLE_SELECT_EXPLICIT(MSG_A_RETRACT_LANG_TABLE, 0)
+extern const char* const MSG_BABYSTEPPING_X_LANG_TABLE[1];
+#define MSG_BABYSTEPPING_X LANG_TABLE_SELECT_EXPLICIT(MSG_BABYSTEPPING_X_LANG_TABLE, 0)
+extern const char* const MSG_BABYSTEPPING_Y_LANG_TABLE[1];
+#define MSG_BABYSTEPPING_Y LANG_TABLE_SELECT_EXPLICIT(MSG_BABYSTEPPING_Y_LANG_TABLE, 0)
+extern const char* const MSG_BABYSTEPPING_Z_LANG_TABLE[1];
+#define MSG_BABYSTEPPING_Z LANG_TABLE_SELECT_EXPLICIT(MSG_BABYSTEPPING_Z_LANG_TABLE, 0)
+extern const char* const MSG_BABYSTEP_X_LANG_TABLE[1];
+#define MSG_BABYSTEP_X LANG_TABLE_SELECT_EXPLICIT(MSG_BABYSTEP_X_LANG_TABLE, 0)
+extern const char* const MSG_BABYSTEP_Y_LANG_TABLE[1];
+#define MSG_BABYSTEP_Y LANG_TABLE_SELECT_EXPLICIT(MSG_BABYSTEP_Y_LANG_TABLE, 0)
 extern const char* const MSG_BABYSTEP_Z_LANG_TABLE[LANG_NUM];
 #define MSG_BABYSTEP_Z LANG_TABLE_SELECT(MSG_BABYSTEP_Z_LANG_TABLE)
 extern const char* const MSG_BABYSTEP_Z_NOT_SET_LANG_TABLE[LANG_NUM];
 #define MSG_BABYSTEP_Z_NOT_SET LANG_TABLE_SELECT(MSG_BABYSTEP_Z_NOT_SET_LANG_TABLE)
-extern const char* const MSG_BED_LANG_TABLE[LANG_NUM];
-#define MSG_BED LANG_TABLE_SELECT(MSG_BED_LANG_TABLE)
+extern const char* const MSG_BED_LANG_TABLE[1];
+#define MSG_BED LANG_TABLE_SELECT_EXPLICIT(MSG_BED_LANG_TABLE, 0)
+extern const char* const MSG_BED_CORRECTION_FRONT_LANG_TABLE[LANG_NUM];
+#define MSG_BED_CORRECTION_FRONT LANG_TABLE_SELECT(MSG_BED_CORRECTION_FRONT_LANG_TABLE)
+extern const char* const MSG_BED_CORRECTION_LEFT_LANG_TABLE[LANG_NUM];
+#define MSG_BED_CORRECTION_LEFT LANG_TABLE_SELECT(MSG_BED_CORRECTION_LEFT_LANG_TABLE)
+extern const char* const MSG_BED_CORRECTION_MENU_LANG_TABLE[LANG_NUM];
+#define MSG_BED_CORRECTION_MENU LANG_TABLE_SELECT(MSG_BED_CORRECTION_MENU_LANG_TABLE)
+extern const char* const MSG_BED_CORRECTION_REAR_LANG_TABLE[LANG_NUM];
+#define MSG_BED_CORRECTION_REAR LANG_TABLE_SELECT(MSG_BED_CORRECTION_REAR_LANG_TABLE)
+extern const char* const MSG_BED_CORRECTION_RESET_LANG_TABLE[1];
+#define MSG_BED_CORRECTION_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_BED_CORRECTION_RESET_LANG_TABLE, 0)
+extern const char* const MSG_BED_CORRECTION_RIGHT_LANG_TABLE[LANG_NUM];
+#define MSG_BED_CORRECTION_RIGHT LANG_TABLE_SELECT(MSG_BED_CORRECTION_RIGHT_LANG_TABLE)
 extern const char* const MSG_BED_DONE_LANG_TABLE[LANG_NUM];
 #define MSG_BED_DONE LANG_TABLE_SELECT(MSG_BED_DONE_LANG_TABLE)
 extern const char* const MSG_BED_HEATING_LANG_TABLE[LANG_NUM];
@@ -52,6 +72,8 @@ extern const char* const MSG_BED_LEVELING_FAILED_POINT_HIGH_LANG_TABLE[LANG_NUM]
 #define MSG_BED_LEVELING_FAILED_POINT_HIGH LANG_TABLE_SELECT(MSG_BED_LEVELING_FAILED_POINT_HIGH_LANG_TABLE)
 extern const char* const MSG_BED_LEVELING_FAILED_POINT_LOW_LANG_TABLE[LANG_NUM];
 #define MSG_BED_LEVELING_FAILED_POINT_LOW LANG_TABLE_SELECT(MSG_BED_LEVELING_FAILED_POINT_LOW_LANG_TABLE)
+extern const char* const MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_LANG_TABLE[LANG_NUM];
+#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED LANG_TABLE_SELECT(MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_LANG_TABLE)
 extern const char* const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM];
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR LANG_TABLE_SELECT(MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_LANG_TABLE)
 extern const char* const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM];
@@ -74,128 +96,162 @@ extern const char* const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_LA
 #define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR LANG_TABLE_SELECT(MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_LANG_TABLE)
 extern const char* const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM];
 #define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR LANG_TABLE_SELECT(MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_LANG_TABLE)
-extern const char* const MSG_BEGIN_FILE_LIST_LANG_TABLE[LANG_NUM];
-#define MSG_BEGIN_FILE_LIST LANG_TABLE_SELECT(MSG_BEGIN_FILE_LIST_LANG_TABLE)
-extern const char* const MSG_BROWNOUT_RESET_LANG_TABLE[LANG_NUM];
-#define MSG_BROWNOUT_RESET LANG_TABLE_SELECT(MSG_BROWNOUT_RESET_LANG_TABLE)
+extern const char* const MSG_BEGIN_FILE_LIST_LANG_TABLE[1];
+#define MSG_BEGIN_FILE_LIST LANG_TABLE_SELECT_EXPLICIT(MSG_BEGIN_FILE_LIST_LANG_TABLE, 0)
+extern const char* const MSG_BROWNOUT_RESET_LANG_TABLE[1];
+#define MSG_BROWNOUT_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_BROWNOUT_RESET_LANG_TABLE, 0)
 extern const char* const MSG_CALIBRATE_BED_LANG_TABLE[LANG_NUM];
 #define MSG_CALIBRATE_BED LANG_TABLE_SELECT(MSG_CALIBRATE_BED_LANG_TABLE)
 extern const char* const MSG_CALIBRATE_BED_RESET_LANG_TABLE[LANG_NUM];
 #define MSG_CALIBRATE_BED_RESET LANG_TABLE_SELECT(MSG_CALIBRATE_BED_RESET_LANG_TABLE)
+extern const char* const MSG_CALIBRATE_E_LANG_TABLE[LANG_NUM];
+#define MSG_CALIBRATE_E LANG_TABLE_SELECT(MSG_CALIBRATE_E_LANG_TABLE)
+extern const char* const MSG_CALIBRATE_PINDA_LANG_TABLE[LANG_NUM];
+#define MSG_CALIBRATE_PINDA LANG_TABLE_SELECT(MSG_CALIBRATE_PINDA_LANG_TABLE)
+extern const char* const MSG_CALIBRATE_Z_AUTO_LANG_TABLE[LANG_NUM];
+#define MSG_CALIBRATE_Z_AUTO LANG_TABLE_SELECT(MSG_CALIBRATE_Z_AUTO_LANG_TABLE)
+extern const char* const MSG_CALIBRATION_PINDA_MENU_LANG_TABLE[LANG_NUM];
+#define MSG_CALIBRATION_PINDA_MENU LANG_TABLE_SELECT(MSG_CALIBRATION_PINDA_MENU_LANG_TABLE)
 extern const char* const MSG_CARD_MENU_LANG_TABLE[LANG_NUM];
 #define MSG_CARD_MENU LANG_TABLE_SELECT(MSG_CARD_MENU_LANG_TABLE)
+extern const char* const MSG_CHANGE_EXTR_LANG_TABLE[LANG_NUM];
+#define MSG_CHANGE_EXTR LANG_TABLE_SELECT(MSG_CHANGE_EXTR_LANG_TABLE)
 extern const char* const MSG_CHANGE_SUCCESS_LANG_TABLE[LANG_NUM];
 #define MSG_CHANGE_SUCCESS LANG_TABLE_SELECT(MSG_CHANGE_SUCCESS_LANG_TABLE)
 extern const char* const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_CHANGING_FILAMENT LANG_TABLE_SELECT(MSG_CHANGING_FILAMENT_LANG_TABLE)
-extern const char* const MSG_CNG_SDCARD_LANG_TABLE[LANG_NUM];
-#define MSG_CNG_SDCARD LANG_TABLE_SELECT(MSG_CNG_SDCARD_LANG_TABLE)
-extern const char* const MSG_CONFIGURATION_VER_LANG_TABLE[LANG_NUM];
-#define MSG_CONFIGURATION_VER LANG_TABLE_SELECT(MSG_CONFIGURATION_VER_LANG_TABLE)
+extern const char* const MSG_CHOOSE_EXTRUDER_LANG_TABLE[LANG_NUM];
+#define MSG_CHOOSE_EXTRUDER LANG_TABLE_SELECT(MSG_CHOOSE_EXTRUDER_LANG_TABLE)
+extern const char* const MSG_CLEAN_NOZZLE_E_LANG_TABLE[LANG_NUM];
+#define MSG_CLEAN_NOZZLE_E LANG_TABLE_SELECT(MSG_CLEAN_NOZZLE_E_LANG_TABLE)
+extern const char* const MSG_CNG_SDCARD_LANG_TABLE[1];
+#define MSG_CNG_SDCARD LANG_TABLE_SELECT_EXPLICIT(MSG_CNG_SDCARD_LANG_TABLE, 0)
+extern const char* const MSG_CONFIGURATION_VER_LANG_TABLE[1];
+#define MSG_CONFIGURATION_VER LANG_TABLE_SELECT_EXPLICIT(MSG_CONFIGURATION_VER_LANG_TABLE, 0)
 extern const char* const MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE[LANG_NUM];
 #define MSG_CONFIRM_CARRIAGE_AT_THE_TOP LANG_TABLE_SELECT(MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE)
 extern const char* const MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE[LANG_NUM];
 #define MSG_CONFIRM_NOZZLE_CLEAN LANG_TABLE_SELECT(MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE)
-extern const char* const MSG_CONTRAST_LANG_TABLE[LANG_NUM];
-#define MSG_CONTRAST LANG_TABLE_SELECT(MSG_CONTRAST_LANG_TABLE)
-extern const char* const MSG_CONTROL_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL LANG_TABLE_SELECT(MSG_CONTROL_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACT_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACT LANG_TABLE_SELECT(MSG_CONTROL_RETRACT_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACTF_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACTF LANG_TABLE_SELECT(MSG_CONTROL_RETRACTF_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACT_RECOVER_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACT_RECOVER LANG_TABLE_SELECT(MSG_CONTROL_RETRACT_RECOVER_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACT_RECOVERF_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACT_RECOVERF LANG_TABLE_SELECT(MSG_CONTROL_RETRACT_RECOVERF_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACT_RECOVER_SWAP_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACT_RECOVER_SWAP LANG_TABLE_SELECT(MSG_CONTROL_RETRACT_RECOVER_SWAP_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACT_SWAP_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACT_SWAP LANG_TABLE_SELECT(MSG_CONTROL_RETRACT_SWAP_LANG_TABLE)
-extern const char* const MSG_CONTROL_RETRACT_ZLIFT_LANG_TABLE[LANG_NUM];
-#define MSG_CONTROL_RETRACT_ZLIFT LANG_TABLE_SELECT(MSG_CONTROL_RETRACT_ZLIFT_LANG_TABLE)
+extern const char* const MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE[LANG_NUM];
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ LANG_TABLE_SELECT(MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE)
+extern const char* const MSG_CONTROL_LANG_TABLE[1];
+#define MSG_CONTROL LANG_TABLE_SELECT_EXPLICIT(MSG_CONTROL_LANG_TABLE, 0)
 extern const char* const MSG_COOLDOWN_LANG_TABLE[LANG_NUM];
 #define MSG_COOLDOWN LANG_TABLE_SELECT(MSG_COOLDOWN_LANG_TABLE)
 extern const char* const MSG_CORRECTLY_LANG_TABLE[LANG_NUM];
 #define MSG_CORRECTLY LANG_TABLE_SELECT(MSG_CORRECTLY_LANG_TABLE)
-extern const char* const MSG_COUNT_X_LANG_TABLE[LANG_NUM];
-#define MSG_COUNT_X LANG_TABLE_SELECT(MSG_COUNT_X_LANG_TABLE)
+extern const char* const MSG_COUNT_X_LANG_TABLE[1];
+#define MSG_COUNT_X LANG_TABLE_SELECT_EXPLICIT(MSG_COUNT_X_LANG_TABLE, 0)
+extern const char* const MSG_CRASHDETECT_OFF_LANG_TABLE[LANG_NUM];
+#define MSG_CRASHDETECT_OFF LANG_TABLE_SELECT(MSG_CRASHDETECT_OFF_LANG_TABLE)
+extern const char* const MSG_CRASHDETECT_ON_LANG_TABLE[LANG_NUM];
+#define MSG_CRASHDETECT_ON LANG_TABLE_SELECT(MSG_CRASHDETECT_ON_LANG_TABLE)
+extern const char* const MSG_CRASH_DETECTED_LANG_TABLE[1];
+#define MSG_CRASH_DETECTED LANG_TABLE_SELECT_EXPLICIT(MSG_CRASH_DETECTED_LANG_TABLE, 0)
+extern const char* const MSG_CURRENT_LANG_TABLE[LANG_NUM];
+#define MSG_CURRENT LANG_TABLE_SELECT(MSG_CURRENT_LANG_TABLE)
+extern const char* const MSG_DATE_LANG_TABLE[LANG_NUM];
+#define MSG_DATE LANG_TABLE_SELECT(MSG_DATE_LANG_TABLE)
 extern const char* const MSG_DISABLE_STEPPERS_LANG_TABLE[LANG_NUM];
 #define MSG_DISABLE_STEPPERS LANG_TABLE_SELECT(MSG_DISABLE_STEPPERS_LANG_TABLE)
-extern const char* const MSG_DWELL_LANG_TABLE[LANG_NUM];
-#define MSG_DWELL LANG_TABLE_SELECT(MSG_DWELL_LANG_TABLE)
-extern const char* const MSG_E_LANG_TABLE[LANG_NUM];
-#define MSG_E LANG_TABLE_SELECT(MSG_E_LANG_TABLE)
-extern const char* const MSG_ENDSTOPS_HIT_LANG_TABLE[LANG_NUM];
-#define MSG_ENDSTOPS_HIT LANG_TABLE_SELECT(MSG_ENDSTOPS_HIT_LANG_TABLE)
-extern const char* const MSG_ENDSTOP_ABORT_LANG_TABLE[LANG_NUM];
-#define MSG_ENDSTOP_ABORT LANG_TABLE_SELECT(MSG_ENDSTOP_ABORT_LANG_TABLE)
-extern const char* const MSG_ENDSTOP_HIT_LANG_TABLE[LANG_NUM];
-#define MSG_ENDSTOP_HIT LANG_TABLE_SELECT(MSG_ENDSTOP_HIT_LANG_TABLE)
-extern const char* const MSG_ENDSTOP_OPEN_LANG_TABLE[LANG_NUM];
-#define MSG_ENDSTOP_OPEN LANG_TABLE_SELECT(MSG_ENDSTOP_OPEN_LANG_TABLE)
-extern const char* const MSG_END_FILE_LIST_LANG_TABLE[LANG_NUM];
-#define MSG_END_FILE_LIST LANG_TABLE_SELECT(MSG_END_FILE_LIST_LANG_TABLE)
+extern const char* const MSG_DWELL_LANG_TABLE[1];
+#define MSG_DWELL LANG_TABLE_SELECT_EXPLICIT(MSG_DWELL_LANG_TABLE, 0)
+extern const char* const MSG_ENDSTOPS_HIT_LANG_TABLE[1];
+#define MSG_ENDSTOPS_HIT LANG_TABLE_SELECT_EXPLICIT(MSG_ENDSTOPS_HIT_LANG_TABLE, 0)
+extern const char* const MSG_ENDSTOP_HIT_LANG_TABLE[1];
+#define MSG_ENDSTOP_HIT LANG_TABLE_SELECT_EXPLICIT(MSG_ENDSTOP_HIT_LANG_TABLE, 0)
+extern const char* const MSG_ENDSTOP_OPEN_LANG_TABLE[1];
+#define MSG_ENDSTOP_OPEN LANG_TABLE_SELECT_EXPLICIT(MSG_ENDSTOP_OPEN_LANG_TABLE, 0)
+extern const char* const MSG_END_FILE_LIST_LANG_TABLE[1];
+#define MSG_END_FILE_LIST LANG_TABLE_SELECT_EXPLICIT(MSG_END_FILE_LIST_LANG_TABLE, 0)
 extern const char* const MSG_ERROR_LANG_TABLE[LANG_NUM];
 #define MSG_ERROR LANG_TABLE_SELECT(MSG_ERROR_LANG_TABLE)
-extern const char* const MSG_ERR_CHECKSUM_MISMATCH_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_CHECKSUM_MISMATCH LANG_TABLE_SELECT(MSG_ERR_CHECKSUM_MISMATCH_LANG_TABLE)
-extern const char* const MSG_ERR_COLD_EXTRUDE_STOP_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_COLD_EXTRUDE_STOP LANG_TABLE_SELECT(MSG_ERR_COLD_EXTRUDE_STOP_LANG_TABLE)
-extern const char* const MSG_ERR_KILLED_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_KILLED LANG_TABLE_SELECT(MSG_ERR_KILLED_LANG_TABLE)
-extern const char* const MSG_ERR_LINE_NO_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_LINE_NO LANG_TABLE_SELECT(MSG_ERR_LINE_NO_LANG_TABLE)
-extern const char* const MSG_ERR_LONG_EXTRUDE_STOP_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_LONG_EXTRUDE_STOP LANG_TABLE_SELECT(MSG_ERR_LONG_EXTRUDE_STOP_LANG_TABLE)
-extern const char* const MSG_ERR_NO_CHECKSUM_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_NO_CHECKSUM LANG_TABLE_SELECT(MSG_ERR_NO_CHECKSUM_LANG_TABLE)
-extern const char* const MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM LANG_TABLE_SELECT(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_LANG_TABLE)
-extern const char* const MSG_ERR_NO_THERMISTORS_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_NO_THERMISTORS LANG_TABLE_SELECT(MSG_ERR_NO_THERMISTORS_LANG_TABLE)
-extern const char* const MSG_ERR_STOPPED_LANG_TABLE[LANG_NUM];
-#define MSG_ERR_STOPPED LANG_TABLE_SELECT(MSG_ERR_STOPPED_LANG_TABLE)
-extern const char* const MSG_ESTEPS_LANG_TABLE[LANG_NUM];
-#define MSG_ESTEPS LANG_TABLE_SELECT(MSG_ESTEPS_LANG_TABLE)
-extern const char* const MSG_EXTERNAL_RESET_LANG_TABLE[LANG_NUM];
-#define MSG_EXTERNAL_RESET LANG_TABLE_SELECT(MSG_EXTERNAL_RESET_LANG_TABLE)
-extern const char* const MSG_EXTRUDE_LANG_TABLE[LANG_NUM];
-#define MSG_EXTRUDE LANG_TABLE_SELECT(MSG_EXTRUDE_LANG_TABLE)
-extern const char* const MSG_Enqueing_LANG_TABLE[LANG_NUM];
-#define MSG_Enqueing LANG_TABLE_SELECT(MSG_Enqueing_LANG_TABLE)
-extern const char* const MSG_FACTOR_LANG_TABLE[LANG_NUM];
-#define MSG_FACTOR LANG_TABLE_SELECT(MSG_FACTOR_LANG_TABLE)
+extern const char* const MSG_ERR_CHECKSUM_MISMATCH_LANG_TABLE[1];
+#define MSG_ERR_CHECKSUM_MISMATCH LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_CHECKSUM_MISMATCH_LANG_TABLE, 0)
+extern const char* const MSG_ERR_COLD_EXTRUDE_STOP_LANG_TABLE[1];
+#define MSG_ERR_COLD_EXTRUDE_STOP LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_COLD_EXTRUDE_STOP_LANG_TABLE, 0)
+extern const char* const MSG_ERR_KILLED_LANG_TABLE[1];
+#define MSG_ERR_KILLED LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_KILLED_LANG_TABLE, 0)
+extern const char* const MSG_ERR_LINE_NO_LANG_TABLE[1];
+#define MSG_ERR_LINE_NO LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_LINE_NO_LANG_TABLE, 0)
+extern const char* const MSG_ERR_LONG_EXTRUDE_STOP_LANG_TABLE[1];
+#define MSG_ERR_LONG_EXTRUDE_STOP LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_LONG_EXTRUDE_STOP_LANG_TABLE, 0)
+extern const char* const MSG_ERR_NO_CHECKSUM_LANG_TABLE[1];
+#define MSG_ERR_NO_CHECKSUM LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_NO_CHECKSUM_LANG_TABLE, 0)
+extern const char* const MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_LANG_TABLE[1];
+#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM_LANG_TABLE, 0)
+extern const char* const MSG_ERR_NO_THERMISTORS_LANG_TABLE[1];
+#define MSG_ERR_NO_THERMISTORS LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_NO_THERMISTORS_LANG_TABLE, 0)
+extern const char* const MSG_ERR_STOPPED_LANG_TABLE[1];
+#define MSG_ERR_STOPPED LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_STOPPED_LANG_TABLE, 0)
+extern const char* const MSG_EXTERNAL_RESET_LANG_TABLE[1];
+#define MSG_EXTERNAL_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_EXTERNAL_RESET_LANG_TABLE, 0)
+extern const char* const MSG_EXTRUDER_LANG_TABLE[1];
+#define MSG_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_EXTRUDER_1_LANG_TABLE[1];
+#define MSG_EXTRUDER_1 LANG_TABLE_SELECT_EXPLICIT(MSG_EXTRUDER_1_LANG_TABLE, 0)
+extern const char* const MSG_EXTRUDER_2_LANG_TABLE[1];
+#define MSG_EXTRUDER_2 LANG_TABLE_SELECT_EXPLICIT(MSG_EXTRUDER_2_LANG_TABLE, 0)
+extern const char* const MSG_EXTRUDER_3_LANG_TABLE[1];
+#define MSG_EXTRUDER_3 LANG_TABLE_SELECT_EXPLICIT(MSG_EXTRUDER_3_LANG_TABLE, 0)
+extern const char* const MSG_EXTRUDER_4_LANG_TABLE[1];
+#define MSG_EXTRUDER_4 LANG_TABLE_SELECT_EXPLICIT(MSG_EXTRUDER_4_LANG_TABLE, 0)
+extern const char* const MSG_E_CAL_KNOB_LANG_TABLE[LANG_NUM];
+#define MSG_E_CAL_KNOB LANG_TABLE_SELECT(MSG_E_CAL_KNOB_LANG_TABLE)
+extern const char* const MSG_Enqueing_LANG_TABLE[1];
+#define MSG_Enqueing LANG_TABLE_SELECT_EXPLICIT(MSG_Enqueing_LANG_TABLE, 0)
+extern const char* const MSG_FACTOR_LANG_TABLE[1];
+#define MSG_FACTOR LANG_TABLE_SELECT_EXPLICIT(MSG_FACTOR_LANG_TABLE, 0)
+extern const char* const MSG_FANS_CHECK_OFF_LANG_TABLE[LANG_NUM];
+#define MSG_FANS_CHECK_OFF LANG_TABLE_SELECT(MSG_FANS_CHECK_OFF_LANG_TABLE)
+extern const char* const MSG_FANS_CHECK_ON_LANG_TABLE[LANG_NUM];
+#define MSG_FANS_CHECK_ON LANG_TABLE_SELECT(MSG_FANS_CHECK_ON_LANG_TABLE)
 extern const char* const MSG_FAN_SPEED_LANG_TABLE[LANG_NUM];
 #define MSG_FAN_SPEED LANG_TABLE_SELECT(MSG_FAN_SPEED_LANG_TABLE)
+extern const char* const MSG_FARM_CARD_MENU_LANG_TABLE[1];
+#define MSG_FARM_CARD_MENU LANG_TABLE_SELECT_EXPLICIT(MSG_FARM_CARD_MENU_LANG_TABLE, 0)
 extern const char* const MSG_FILAMENTCHANGE_LANG_TABLE[LANG_NUM];
 #define MSG_FILAMENTCHANGE LANG_TABLE_SELECT(MSG_FILAMENTCHANGE_LANG_TABLE)
-extern const char* const MSG_FILAMENT_SIZE_EXTRUDER_0_LANG_TABLE[LANG_NUM];
-#define MSG_FILAMENT_SIZE_EXTRUDER_0 LANG_TABLE_SELECT(MSG_FILAMENT_SIZE_EXTRUDER_0_LANG_TABLE)
-extern const char* const MSG_FILAMENT_SIZE_EXTRUDER_1_LANG_TABLE[LANG_NUM];
-#define MSG_FILAMENT_SIZE_EXTRUDER_1 LANG_TABLE_SELECT(MSG_FILAMENT_SIZE_EXTRUDER_1_LANG_TABLE)
-extern const char* const MSG_FILAMENT_SIZE_EXTRUDER_2_LANG_TABLE[LANG_NUM];
-#define MSG_FILAMENT_SIZE_EXTRUDER_2 LANG_TABLE_SELECT(MSG_FILAMENT_SIZE_EXTRUDER_2_LANG_TABLE)
-extern const char* const MSG_FILE_PRINTED_LANG_TABLE[LANG_NUM];
-#define MSG_FILE_PRINTED LANG_TABLE_SELECT(MSG_FILE_PRINTED_LANG_TABLE)
-extern const char* const MSG_FILE_SAVED_LANG_TABLE[LANG_NUM];
-#define MSG_FILE_SAVED LANG_TABLE_SELECT(MSG_FILE_SAVED_LANG_TABLE)
+extern const char* const MSG_FILAMENT_CLEAN_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_CLEAN LANG_TABLE_SELECT(MSG_FILAMENT_CLEAN_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T0_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T0 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T0_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T1_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T1 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T1_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T2_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T2 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T2_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T3_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T3 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T3_LANG_TABLE)
+extern const char* const MSG_FILE_PRINTED_LANG_TABLE[1];
+#define MSG_FILE_PRINTED LANG_TABLE_SELECT_EXPLICIT(MSG_FILE_PRINTED_LANG_TABLE, 0)
+extern const char* const MSG_FILE_SAVED_LANG_TABLE[1];
+#define MSG_FILE_SAVED LANG_TABLE_SELECT_EXPLICIT(MSG_FILE_SAVED_LANG_TABLE, 0)
+extern const char* const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM];
+#define MSG_FIL_ADJUSTING LANG_TABLE_SELECT(MSG_FIL_ADJUSTING_LANG_TABLE)
+extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_LANG_TABLE[LANG_NUM];
+#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_LANG_TABLE)
 extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM];
 #define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE)
 extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM];
 #define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2 LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE)
-extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_LANG_TABLE[LANG_NUM];
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE3 LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_LINE3_LANG_TABLE)
+extern const char* const MSG_FINISHING_MOVEMENTS_LANG_TABLE[LANG_NUM];
+#define MSG_FINISHING_MOVEMENTS LANG_TABLE_SELECT(MSG_FINISHING_MOVEMENTS_LANG_TABLE)
 extern const char* const MSG_FLOW_LANG_TABLE[LANG_NUM];
 #define MSG_FLOW LANG_TABLE_SELECT(MSG_FLOW_LANG_TABLE)
-extern const char* const MSG_FLOW0_LANG_TABLE[LANG_NUM];
-#define MSG_FLOW0 LANG_TABLE_SELECT(MSG_FLOW0_LANG_TABLE)
-extern const char* const MSG_FLOW1_LANG_TABLE[LANG_NUM];
-#define MSG_FLOW1 LANG_TABLE_SELECT(MSG_FLOW1_LANG_TABLE)
-extern const char* const MSG_FLOW2_LANG_TABLE[LANG_NUM];
-#define MSG_FLOW2 LANG_TABLE_SELECT(MSG_FLOW2_LANG_TABLE)
-extern const char* const MSG_FREE_MEMORY_LANG_TABLE[LANG_NUM];
-#define MSG_FREE_MEMORY LANG_TABLE_SELECT(MSG_FREE_MEMORY_LANG_TABLE)
+extern const char* const MSG_FLOW0_LANG_TABLE[1];
+#define MSG_FLOW0 LANG_TABLE_SELECT_EXPLICIT(MSG_FLOW0_LANG_TABLE, 0)
+extern const char* const MSG_FLOW1_LANG_TABLE[1];
+#define MSG_FLOW1 LANG_TABLE_SELECT_EXPLICIT(MSG_FLOW1_LANG_TABLE, 0)
+extern const char* const MSG_FLOW2_LANG_TABLE[1];
+#define MSG_FLOW2 LANG_TABLE_SELECT_EXPLICIT(MSG_FLOW2_LANG_TABLE, 0)
+extern const char* const MSG_FOLLOW_CALIBRATION_FLOW_LANG_TABLE[LANG_NUM];
+#define MSG_FOLLOW_CALIBRATION_FLOW LANG_TABLE_SELECT(MSG_FOLLOW_CALIBRATION_FLOW_LANG_TABLE)
+extern const char* const MSG_FREE_MEMORY_LANG_TABLE[1];
+#define MSG_FREE_MEMORY LANG_TABLE_SELECT_EXPLICIT(MSG_FREE_MEMORY_LANG_TABLE, 0)
+extern const char* const MSG_FSENSOR_OFF_LANG_TABLE[LANG_NUM];
+#define MSG_FSENSOR_OFF LANG_TABLE_SELECT(MSG_FSENSOR_OFF_LANG_TABLE)
+extern const char* const MSG_FSENSOR_ON_LANG_TABLE[LANG_NUM];
+#define MSG_FSENSOR_ON LANG_TABLE_SELECT(MSG_FSENSOR_ON_LANG_TABLE)
 extern const char* const MSG_HEATING_LANG_TABLE[LANG_NUM];
 #define MSG_HEATING LANG_TABLE_SELECT(MSG_HEATING_LANG_TABLE)
 extern const char* const MSG_HEATING_COMPLETE_LANG_TABLE[LANG_NUM];
@@ -206,76 +262,110 @@ extern const char* const MSG_HOMEYZ_DONE_LANG_TABLE[LANG_NUM];
 #define MSG_HOMEYZ_DONE LANG_TABLE_SELECT(MSG_HOMEYZ_DONE_LANG_TABLE)
 extern const char* const MSG_HOMEYZ_PROGRESS_LANG_TABLE[LANG_NUM];
 #define MSG_HOMEYZ_PROGRESS LANG_TABLE_SELECT(MSG_HOMEYZ_PROGRESS_LANG_TABLE)
-extern const char* const MSG_HOTEND_OFFSET_LANG_TABLE[LANG_NUM];
-#define MSG_HOTEND_OFFSET LANG_TABLE_SELECT(MSG_HOTEND_OFFSET_LANG_TABLE)
+extern const char* const MSG_HOTEND_OFFSET_LANG_TABLE[1];
+#define MSG_HOTEND_OFFSET LANG_TABLE_SELECT_EXPLICIT(MSG_HOTEND_OFFSET_LANG_TABLE, 0)
 extern const char* const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM];
 #define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1 LANG_TABLE_SELECT(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE)
 extern const char* const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM];
 #define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 LANG_TABLE_SELECT(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE)
-extern const char* const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_LANG_TABLE[LANG_NUM];
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3 LANG_TABLE_SELECT(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3_LANG_TABLE)
-extern const char* const MSG_INIT_SDCARD_LANG_TABLE[LANG_NUM];
-#define MSG_INIT_SDCARD LANG_TABLE_SELECT(MSG_INIT_SDCARD_LANG_TABLE)
+extern const char* const MSG_INFO_EXTRUDER_LANG_TABLE[1];
+#define MSG_INFO_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_INFO_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_INFO_FILAMENT_XDIFF_LANG_TABLE[1];
+#define MSG_INFO_FILAMENT_XDIFF LANG_TABLE_SELECT_EXPLICIT(MSG_INFO_FILAMENT_XDIFF_LANG_TABLE, 0)
+extern const char* const MSG_INFO_FILAMENT_YDIFF_LANG_TABLE[1];
+#define MSG_INFO_FILAMENT_YDIFF LANG_TABLE_SELECT_EXPLICIT(MSG_INFO_FILAMENT_YDIFF_LANG_TABLE, 0)
+extern const char* const MSG_INFO_NOZZLE_FAN_LANG_TABLE[1];
+#define MSG_INFO_NOZZLE_FAN LANG_TABLE_SELECT_EXPLICIT(MSG_INFO_NOZZLE_FAN_LANG_TABLE, 0)
+extern const char* const MSG_INFO_PRINT_FAN_LANG_TABLE[1];
+#define MSG_INFO_PRINT_FAN LANG_TABLE_SELECT_EXPLICIT(MSG_INFO_PRINT_FAN_LANG_TABLE, 0)
+extern const char* const MSG_INIT_SDCARD_LANG_TABLE[1];
+#define MSG_INIT_SDCARD LANG_TABLE_SELECT_EXPLICIT(MSG_INIT_SDCARD_LANG_TABLE, 0)
 extern const char* const MSG_INSERT_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_INSERT_FILAMENT LANG_TABLE_SELECT(MSG_INSERT_FILAMENT_LANG_TABLE)
-extern const char* const MSG_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_INVALID_EXTRUDER_LANG_TABLE)
-extern const char* const MSG_KILLED_LANG_TABLE[LANG_NUM];
-#define MSG_KILLED LANG_TABLE_SELECT(MSG_KILLED_LANG_TABLE)
+extern const char* const MSG_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_INVALID_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_KILLED_LANG_TABLE[1];
+#define MSG_KILLED LANG_TABLE_SELECT_EXPLICIT(MSG_KILLED_LANG_TABLE, 0)
 extern const char* const MSG_LANGUAGE_NAME_LANG_TABLE[LANG_NUM];
 #define MSG_LANGUAGE_NAME LANG_TABLE_SELECT(MSG_LANGUAGE_NAME_LANG_TABLE)
 #define MSG_LANGUAGE_NAME_EXPLICIT(LANG) LANG_TABLE_SELECT_EXPLICIT(MSG_LANGUAGE_NAME_LANG_TABLE, LANG)
 extern const char* const MSG_LANGUAGE_SELECT_LANG_TABLE[LANG_NUM];
 #define MSG_LANGUAGE_SELECT LANG_TABLE_SELECT(MSG_LANGUAGE_SELECT_LANG_TABLE)
 #define MSG_LANGUAGE_SELECT_EXPLICIT(LANG) LANG_TABLE_SELECT_EXPLICIT(MSG_LANGUAGE_SELECT_LANG_TABLE, LANG)
+extern const char* const MSG_LEFT_LANG_TABLE[LANG_NUM];
+#define MSG_LEFT LANG_TABLE_SELECT(MSG_LEFT_LANG_TABLE)
 extern const char* const MSG_LOADING_COLOR_LANG_TABLE[LANG_NUM];
 #define MSG_LOADING_COLOR LANG_TABLE_SELECT(MSG_LOADING_COLOR_LANG_TABLE)
 extern const char* const MSG_LOADING_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_LOADING_FILAMENT LANG_TABLE_SELECT(MSG_LOADING_FILAMENT_LANG_TABLE)
-extern const char* const MSG_LOAD_EPROM_LANG_TABLE[LANG_NUM];
-#define MSG_LOAD_EPROM LANG_TABLE_SELECT(MSG_LOAD_EPROM_LANG_TABLE)
+extern const char* const MSG_LOAD_ALL_LANG_TABLE[LANG_NUM];
+#define MSG_LOAD_ALL LANG_TABLE_SELECT(MSG_LOAD_ALL_LANG_TABLE)
+extern const char* const MSG_LOAD_EPROM_LANG_TABLE[1];
+#define MSG_LOAD_EPROM LANG_TABLE_SELECT_EXPLICIT(MSG_LOAD_EPROM_LANG_TABLE, 0)
 extern const char* const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_LOAD_FILAMENT LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_LANG_TABLE)
-extern const char* const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_M104_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_M104_INVALID_EXTRUDER_LANG_TABLE)
-extern const char* const MSG_M105_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_M105_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_M105_INVALID_EXTRUDER_LANG_TABLE)
-extern const char* const MSG_M109_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_M109_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_M109_INVALID_EXTRUDER_LANG_TABLE)
-extern const char* const MSG_M115_REPORT_LANG_TABLE[LANG_NUM];
-#define MSG_M115_REPORT LANG_TABLE_SELECT(MSG_M115_REPORT_LANG_TABLE)
-extern const char* const MSG_M119_REPORT_LANG_TABLE[LANG_NUM];
-#define MSG_M119_REPORT LANG_TABLE_SELECT(MSG_M119_REPORT_LANG_TABLE)
-extern const char* const MSG_M200_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_M200_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_M200_INVALID_EXTRUDER_LANG_TABLE)
-extern const char* const MSG_M218_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_M218_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_M218_INVALID_EXTRUDER_LANG_TABLE)
-extern const char* const MSG_M221_INVALID_EXTRUDER_LANG_TABLE[LANG_NUM];
-#define MSG_M221_INVALID_EXTRUDER LANG_TABLE_SELECT(MSG_M221_INVALID_EXTRUDER_LANG_TABLE)
+extern const char* const MSG_LOAD_FILAMENT_1_LANG_TABLE[LANG_NUM];
+#define MSG_LOAD_FILAMENT_1 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_1_LANG_TABLE)
+extern const char* const MSG_LOAD_FILAMENT_2_LANG_TABLE[LANG_NUM];
+#define MSG_LOAD_FILAMENT_2 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_2_LANG_TABLE)
+extern const char* const MSG_LOAD_FILAMENT_3_LANG_TABLE[LANG_NUM];
+#define MSG_LOAD_FILAMENT_3 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_3_LANG_TABLE)
+extern const char* const MSG_LOAD_FILAMENT_4_LANG_TABLE[LANG_NUM];
+#define MSG_LOAD_FILAMENT_4 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_4_LANG_TABLE)
+extern const char* const MSG_LOOSE_PULLEY_LANG_TABLE[LANG_NUM];
+#define MSG_LOOSE_PULLEY LANG_TABLE_SELECT(MSG_LOOSE_PULLEY_LANG_TABLE)
+extern const char* const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_M104_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M104_INVALID_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_M105_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_M105_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M105_INVALID_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_M109_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_M109_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M109_INVALID_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_M115_REPORT_LANG_TABLE[1];
+#define MSG_M115_REPORT LANG_TABLE_SELECT_EXPLICIT(MSG_M115_REPORT_LANG_TABLE, 0)
+extern const char* const MSG_M117_V2_CALIBRATION_LANG_TABLE[LANG_NUM];
+#define MSG_M117_V2_CALIBRATION LANG_TABLE_SELECT(MSG_M117_V2_CALIBRATION_LANG_TABLE)
+extern const char* const MSG_M119_REPORT_LANG_TABLE[1];
+#define MSG_M119_REPORT LANG_TABLE_SELECT_EXPLICIT(MSG_M119_REPORT_LANG_TABLE, 0)
+extern const char* const MSG_M200_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_M200_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M200_INVALID_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_M218_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_M218_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M218_INVALID_EXTRUDER_LANG_TABLE, 0)
+extern const char* const MSG_M221_INVALID_EXTRUDER_LANG_TABLE[1];
+#define MSG_M221_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M221_INVALID_EXTRUDER_LANG_TABLE, 0)
 extern const char* const MSG_MAIN_LANG_TABLE[LANG_NUM];
 #define MSG_MAIN LANG_TABLE_SELECT(MSG_MAIN_LANG_TABLE)
-extern const char* const MSG_MAX_LANG_TABLE[LANG_NUM];
-#define MSG_MAX LANG_TABLE_SELECT(MSG_MAX_LANG_TABLE)
-extern const char* const MSG_MIN_LANG_TABLE[LANG_NUM];
-#define MSG_MIN LANG_TABLE_SELECT(MSG_MIN_LANG_TABLE)
-extern const char* const MSG_MOTION_LANG_TABLE[LANG_NUM];
-#define MSG_MOTION LANG_TABLE_SELECT(MSG_MOTION_LANG_TABLE)
-extern const char* const MSG_MOVE_01MM_LANG_TABLE[LANG_NUM];
-#define MSG_MOVE_01MM LANG_TABLE_SELECT(MSG_MOVE_01MM_LANG_TABLE)
-extern const char* const MSG_MOVE_10MM_LANG_TABLE[LANG_NUM];
-#define MSG_MOVE_10MM LANG_TABLE_SELECT(MSG_MOVE_10MM_LANG_TABLE)
-extern const char* const MSG_MOVE_1MM_LANG_TABLE[LANG_NUM];
-#define MSG_MOVE_1MM LANG_TABLE_SELECT(MSG_MOVE_1MM_LANG_TABLE)
+extern const char* const MSG_MARK_FIL_LANG_TABLE[LANG_NUM];
+#define MSG_MARK_FIL LANG_TABLE_SELECT(MSG_MARK_FIL_LANG_TABLE)
+extern const char* const MSG_MAX_LANG_TABLE[1];
+#define MSG_MAX LANG_TABLE_SELECT_EXPLICIT(MSG_MAX_LANG_TABLE, 0)
+extern const char* const MSG_MEASURED_SKEW_LANG_TABLE[LANG_NUM];
+#define MSG_MEASURED_SKEW LANG_TABLE_SELECT(MSG_MEASURED_SKEW_LANG_TABLE)
+extern const char* const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_LANG_TABLE[LANG_NUM];
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 LANG_TABLE_SELECT(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_LANG_TABLE)
+extern const char* const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_LANG_TABLE[LANG_NUM];
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 LANG_TABLE_SELECT(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_LANG_TABLE)
+extern const char* const MSG_MENU_CALIBRATION_LANG_TABLE[LANG_NUM];
+#define MSG_MENU_CALIBRATION LANG_TABLE_SELECT(MSG_MENU_CALIBRATION_LANG_TABLE)
+extern const char* const MSG_MESH_BED_LEVELING_LANG_TABLE[1];
+#define MSG_MESH_BED_LEVELING LANG_TABLE_SELECT_EXPLICIT(MSG_MESH_BED_LEVELING_LANG_TABLE, 0)
+extern const char* const MSG_MIN_LANG_TABLE[1];
+#define MSG_MIN LANG_TABLE_SELECT_EXPLICIT(MSG_MIN_LANG_TABLE, 0)
+extern const char* const MSG_MOTION_LANG_TABLE[1];
+#define MSG_MOTION LANG_TABLE_SELECT_EXPLICIT(MSG_MOTION_LANG_TABLE, 0)
+extern const char* const MSG_MOVE_01MM_LANG_TABLE[1];
+#define MSG_MOVE_01MM LANG_TABLE_SELECT_EXPLICIT(MSG_MOVE_01MM_LANG_TABLE, 0)
+extern const char* const MSG_MOVE_10MM_LANG_TABLE[1];
+#define MSG_MOVE_10MM LANG_TABLE_SELECT_EXPLICIT(MSG_MOVE_10MM_LANG_TABLE, 0)
+extern const char* const MSG_MOVE_1MM_LANG_TABLE[1];
+#define MSG_MOVE_1MM LANG_TABLE_SELECT_EXPLICIT(MSG_MOVE_1MM_LANG_TABLE, 0)
 extern const char* const MSG_MOVE_AXIS_LANG_TABLE[LANG_NUM];
 #define MSG_MOVE_AXIS LANG_TABLE_SELECT(MSG_MOVE_AXIS_LANG_TABLE)
 extern const char* const MSG_MOVE_CARRIAGE_TO_THE_TOP_LANG_TABLE[LANG_NUM];
 #define MSG_MOVE_CARRIAGE_TO_THE_TOP LANG_TABLE_SELECT(MSG_MOVE_CARRIAGE_TO_THE_TOP_LANG_TABLE)
-extern const char* const MSG_MOVE_E_LANG_TABLE[LANG_NUM];
-#define MSG_MOVE_E LANG_TABLE_SELECT(MSG_MOVE_E_LANG_TABLE)
-extern const char* const MSG_MOVE_E1_LANG_TABLE[LANG_NUM];
-#define MSG_MOVE_E1 LANG_TABLE_SELECT(MSG_MOVE_E1_LANG_TABLE)
-extern const char* const MSG_MOVE_E2_LANG_TABLE[LANG_NUM];
-#define MSG_MOVE_E2 LANG_TABLE_SELECT(MSG_MOVE_E2_LANG_TABLE)
+extern const char* const MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_LANG_TABLE[LANG_NUM];
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z LANG_TABLE_SELECT(MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_LANG_TABLE)
+extern const char* const MSG_MOVE_E_LANG_TABLE[1];
+#define MSG_MOVE_E LANG_TABLE_SELECT_EXPLICIT(MSG_MOVE_E_LANG_TABLE, 0)
 extern const char* const MSG_MOVE_X_LANG_TABLE[LANG_NUM];
 #define MSG_MOVE_X LANG_TABLE_SELECT(MSG_MOVE_X_LANG_TABLE)
 extern const char* const MSG_MOVE_Y_LANG_TABLE[LANG_NUM];
@@ -294,78 +384,66 @@ extern const char* const MSG_NOT_LOADED_LANG_TABLE[LANG_NUM];
 #define MSG_NOT_LOADED LANG_TABLE_SELECT(MSG_NOT_LOADED_LANG_TABLE)
 extern const char* const MSG_NOZZLE_LANG_TABLE[LANG_NUM];
 #define MSG_NOZZLE LANG_TABLE_SELECT(MSG_NOZZLE_LANG_TABLE)
-extern const char* const MSG_NOZZLE1_LANG_TABLE[LANG_NUM];
-#define MSG_NOZZLE1 LANG_TABLE_SELECT(MSG_NOZZLE1_LANG_TABLE)
-extern const char* const MSG_NOZZLE2_LANG_TABLE[LANG_NUM];
-#define MSG_NOZZLE2 LANG_TABLE_SELECT(MSG_NOZZLE2_LANG_TABLE)
+extern const char* const MSG_NOZZLE1_LANG_TABLE[1];
+#define MSG_NOZZLE1 LANG_TABLE_SELECT_EXPLICIT(MSG_NOZZLE1_LANG_TABLE, 0)
+extern const char* const MSG_NOZZLE2_LANG_TABLE[1];
+#define MSG_NOZZLE2 LANG_TABLE_SELECT_EXPLICIT(MSG_NOZZLE2_LANG_TABLE, 0)
 extern const char* const MSG_NO_CARD_LANG_TABLE[LANG_NUM];
 #define MSG_NO_CARD LANG_TABLE_SELECT(MSG_NO_CARD_LANG_TABLE)
-extern const char* const MSG_NO_MOVE_LANG_TABLE[LANG_NUM];
-#define MSG_NO_MOVE LANG_TABLE_SELECT(MSG_NO_MOVE_LANG_TABLE)
-extern const char* const MSG_OFF_LANG_TABLE[LANG_NUM];
-#define MSG_OFF LANG_TABLE_SELECT(MSG_OFF_LANG_TABLE)
-extern const char* const MSG_OK_LANG_TABLE[LANG_NUM];
-#define MSG_OK LANG_TABLE_SELECT(MSG_OK_LANG_TABLE)
-extern const char* const MSG_ON_LANG_TABLE[LANG_NUM];
-#define MSG_ON LANG_TABLE_SELECT(MSG_ON_LANG_TABLE)
+extern const char* const MSG_NO_MOVE_LANG_TABLE[1];
+#define MSG_NO_MOVE LANG_TABLE_SELECT_EXPLICIT(MSG_NO_MOVE_LANG_TABLE, 0)
+extern const char* const MSG_OFF_LANG_TABLE[1];
+#define MSG_OFF LANG_TABLE_SELECT_EXPLICIT(MSG_OFF_LANG_TABLE, 0)
+extern const char* const MSG_OK_LANG_TABLE[1];
+#define MSG_OK LANG_TABLE_SELECT_EXPLICIT(MSG_OK_LANG_TABLE, 0)
+extern const char* const MSG_ON_LANG_TABLE[1];
+#define MSG_ON LANG_TABLE_SELECT_EXPLICIT(MSG_ON_LANG_TABLE, 0)
+extern const char* const MSG_PAPER_LANG_TABLE[LANG_NUM];
+#define MSG_PAPER LANG_TABLE_SELECT(MSG_PAPER_LANG_TABLE)
 extern const char* const MSG_PAUSE_PRINT_LANG_TABLE[LANG_NUM];
 #define MSG_PAUSE_PRINT LANG_TABLE_SELECT(MSG_PAUSE_PRINT_LANG_TABLE)
 extern const char* const MSG_PICK_Z_LANG_TABLE[LANG_NUM];
 #define MSG_PICK_Z LANG_TABLE_SELECT(MSG_PICK_Z_LANG_TABLE)
-extern const char* const MSG_PID_C_LANG_TABLE[LANG_NUM];
-#define MSG_PID_C LANG_TABLE_SELECT(MSG_PID_C_LANG_TABLE)
-extern const char* const MSG_PID_D_LANG_TABLE[LANG_NUM];
-#define MSG_PID_D LANG_TABLE_SELECT(MSG_PID_D_LANG_TABLE)
-extern const char* const MSG_PID_I_LANG_TABLE[LANG_NUM];
-#define MSG_PID_I LANG_TABLE_SELECT(MSG_PID_I_LANG_TABLE)
-extern const char* const MSG_PID_P_LANG_TABLE[LANG_NUM];
-#define MSG_PID_P LANG_TABLE_SELECT(MSG_PID_P_LANG_TABLE)
-extern const char* const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[LANG_NUM];
-#define MSG_PLANNER_BUFFER_BYTES LANG_TABLE_SELECT(MSG_PLANNER_BUFFER_BYTES_LANG_TABLE)
+extern const char* const MSG_PID_EXTRUDER_LANG_TABLE[LANG_NUM];
+#define MSG_PID_EXTRUDER LANG_TABLE_SELECT(MSG_PID_EXTRUDER_LANG_TABLE)
+extern const char* const MSG_PID_FINISHED_LANG_TABLE[LANG_NUM];
+#define MSG_PID_FINISHED LANG_TABLE_SELECT(MSG_PID_FINISHED_LANG_TABLE)
+extern const char* const MSG_PID_RUNNING_LANG_TABLE[LANG_NUM];
+#define MSG_PID_RUNNING LANG_TABLE_SELECT(MSG_PID_RUNNING_LANG_TABLE)
+extern const char* const MSG_PINDA_NOT_CALIBRATED_LANG_TABLE[LANG_NUM];
+#define MSG_PINDA_NOT_CALIBRATED LANG_TABLE_SELECT(MSG_PINDA_NOT_CALIBRATED_LANG_TABLE)
+extern const char* const MSG_PINDA_PREHEAT_LANG_TABLE[LANG_NUM];
+#define MSG_PINDA_PREHEAT LANG_TABLE_SELECT(MSG_PINDA_PREHEAT_LANG_TABLE)
+extern const char* const MSG_PLACE_STEEL_SHEET_LANG_TABLE[LANG_NUM];
+#define MSG_PLACE_STEEL_SHEET LANG_TABLE_SELECT(MSG_PLACE_STEEL_SHEET_LANG_TABLE)
+extern const char* const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[1];
+#define MSG_PLANNER_BUFFER_BYTES LANG_TABLE_SELECT_EXPLICIT(MSG_PLANNER_BUFFER_BYTES_LANG_TABLE, 0)
+extern const char* const MSG_PLA_FILAMENT_LOADED_LANG_TABLE[LANG_NUM];
+#define MSG_PLA_FILAMENT_LOADED LANG_TABLE_SELECT(MSG_PLA_FILAMENT_LOADED_LANG_TABLE)
+extern const char* const MSG_PLEASE_LOAD_PLA_LANG_TABLE[LANG_NUM];
+#define MSG_PLEASE_LOAD_PLA LANG_TABLE_SELECT(MSG_PLEASE_LOAD_PLA_LANG_TABLE)
 extern const char* const MSG_PLEASE_WAIT_LANG_TABLE[LANG_NUM];
 #define MSG_PLEASE_WAIT LANG_TABLE_SELECT(MSG_PLEASE_WAIT_LANG_TABLE)
-extern const char* const MSG_POSITION_UNKNOWN_LANG_TABLE[LANG_NUM];
-#define MSG_POSITION_UNKNOWN LANG_TABLE_SELECT(MSG_POSITION_UNKNOWN_LANG_TABLE)
-extern const char* const MSG_POWERUP_LANG_TABLE[LANG_NUM];
-#define MSG_POWERUP LANG_TABLE_SELECT(MSG_POWERUP_LANG_TABLE)
+extern const char* const MSG_POSITION_UNKNOWN_LANG_TABLE[1];
+#define MSG_POSITION_UNKNOWN LANG_TABLE_SELECT_EXPLICIT(MSG_POSITION_UNKNOWN_LANG_TABLE, 0)
+extern const char* const MSG_POWERUP_LANG_TABLE[1];
+#define MSG_POWERUP LANG_TABLE_SELECT_EXPLICIT(MSG_POWERUP_LANG_TABLE, 0)
 extern const char* const MSG_PREHEAT_LANG_TABLE[LANG_NUM];
 #define MSG_PREHEAT LANG_TABLE_SELECT(MSG_PREHEAT_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS LANG_TABLE_SELECT(MSG_PREHEAT_ABS_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS0_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS0 LANG_TABLE_SELECT(MSG_PREHEAT_ABS0_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS012_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS012 LANG_TABLE_SELECT(MSG_PREHEAT_ABS012_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS1_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS1 LANG_TABLE_SELECT(MSG_PREHEAT_ABS1_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS2_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS2 LANG_TABLE_SELECT(MSG_PREHEAT_ABS2_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS_BEDONLY_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS_BEDONLY LANG_TABLE_SELECT(MSG_PREHEAT_ABS_BEDONLY_LANG_TABLE)
-extern const char* const MSG_PREHEAT_ABS_SETTINGS_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_ABS_SETTINGS LANG_TABLE_SELECT(MSG_PREHEAT_ABS_SETTINGS_LANG_TABLE)
 extern const char* const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM];
 #define MSG_PREHEAT_NOZZLE LANG_TABLE_SELECT(MSG_PREHEAT_NOZZLE_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA LANG_TABLE_SELECT(MSG_PREHEAT_PLA_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA0_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA0 LANG_TABLE_SELECT(MSG_PREHEAT_PLA0_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA012_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA012 LANG_TABLE_SELECT(MSG_PREHEAT_PLA012_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA1_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA1 LANG_TABLE_SELECT(MSG_PREHEAT_PLA1_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA2_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA2 LANG_TABLE_SELECT(MSG_PREHEAT_PLA2_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA_BEDONLY_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA_BEDONLY LANG_TABLE_SELECT(MSG_PREHEAT_PLA_BEDONLY_LANG_TABLE)
-extern const char* const MSG_PREHEAT_PLA_SETTINGS_LANG_TABLE[LANG_NUM];
-#define MSG_PREHEAT_PLA_SETTINGS LANG_TABLE_SELECT(MSG_PREHEAT_PLA_SETTINGS_LANG_TABLE)
-extern const char* const MSG_PREPARE_LANG_TABLE[LANG_NUM];
-#define MSG_PREPARE LANG_TABLE_SELECT(MSG_PREPARE_LANG_TABLE)
+extern const char* const MSG_PREPARE_FILAMENT_LANG_TABLE[LANG_NUM];
+#define MSG_PREPARE_FILAMENT LANG_TABLE_SELECT(MSG_PREPARE_FILAMENT_LANG_TABLE)
 extern const char* const MSG_PRESS_LANG_TABLE[LANG_NUM];
 #define MSG_PRESS LANG_TABLE_SELECT(MSG_PRESS_LANG_TABLE)
+extern const char* const MSG_PRESS_TO_UNLOAD_LANG_TABLE[LANG_NUM];
+#define MSG_PRESS_TO_UNLOAD LANG_TABLE_SELECT(MSG_PRESS_TO_UNLOAD_LANG_TABLE)
+extern const char* const MSG_PRINTER_DISCONNECTED_LANG_TABLE[1];
+#define MSG_PRINTER_DISCONNECTED LANG_TABLE_SELECT_EXPLICIT(MSG_PRINTER_DISCONNECTED_LANG_TABLE, 0)
 extern const char* const MSG_PRINT_ABORTED_LANG_TABLE[LANG_NUM];
 #define MSG_PRINT_ABORTED LANG_TABLE_SELECT(MSG_PRINT_ABORTED_LANG_TABLE)
+extern const char* const MSG_PRINT_PAUSED_LANG_TABLE[LANG_NUM];
+#define MSG_PRINT_PAUSED LANG_TABLE_SELECT(MSG_PRINT_PAUSED_LANG_TABLE)
 extern const char* const MSG_PRUSA3D_LANG_TABLE[LANG_NUM];
 #define MSG_PRUSA3D LANG_TABLE_SELECT(MSG_PRUSA3D_LANG_TABLE)
 extern const char* const MSG_PRUSA3D_FORUM_LANG_TABLE[LANG_NUM];
@@ -374,58 +452,72 @@ extern const char* const MSG_PRUSA3D_HOWTO_LANG_TABLE[LANG_NUM];
 #define MSG_PRUSA3D_HOWTO LANG_TABLE_SELECT(MSG_PRUSA3D_HOWTO_LANG_TABLE)
 extern const char* const MSG_REBOOT_LANG_TABLE[LANG_NUM];
 #define MSG_REBOOT LANG_TABLE_SELECT(MSG_REBOOT_LANG_TABLE)
-extern const char* const MSG_RECTRACT_LANG_TABLE[LANG_NUM];
-#define MSG_RECTRACT LANG_TABLE_SELECT(MSG_RECTRACT_LANG_TABLE)
-extern const char* const MSG_REFRESH_LANG_TABLE[LANG_NUM];
-#define MSG_REFRESH LANG_TABLE_SELECT(MSG_REFRESH_LANG_TABLE)
-extern const char* const MSG_RESEND_LANG_TABLE[LANG_NUM];
-#define MSG_RESEND LANG_TABLE_SELECT(MSG_RESEND_LANG_TABLE)
-extern const char* const MSG_RESTORE_FAILSAFE_LANG_TABLE[LANG_NUM];
-#define MSG_RESTORE_FAILSAFE LANG_TABLE_SELECT(MSG_RESTORE_FAILSAFE_LANG_TABLE)
+extern const char* const MSG_RECOVERING_PRINT_LANG_TABLE[LANG_NUM];
+#define MSG_RECOVERING_PRINT LANG_TABLE_SELECT(MSG_RECOVERING_PRINT_LANG_TABLE)
+extern const char* const MSG_RECOVER_PRINT_LANG_TABLE[LANG_NUM];
+#define MSG_RECOVER_PRINT LANG_TABLE_SELECT(MSG_RECOVER_PRINT_LANG_TABLE)
+extern const char* const MSG_RECTRACT_LANG_TABLE[1];
+#define MSG_RECTRACT LANG_TABLE_SELECT_EXPLICIT(MSG_RECTRACT_LANG_TABLE, 0)
+extern const char* const MSG_REFRESH_LANG_TABLE[1];
+#define MSG_REFRESH LANG_TABLE_SELECT_EXPLICIT(MSG_REFRESH_LANG_TABLE, 0)
+extern const char* const MSG_REMOVE_STEEL_SHEET_LANG_TABLE[LANG_NUM];
+#define MSG_REMOVE_STEEL_SHEET LANG_TABLE_SELECT(MSG_REMOVE_STEEL_SHEET_LANG_TABLE)
+extern const char* const MSG_RESEND_LANG_TABLE[1];
+#define MSG_RESEND LANG_TABLE_SELECT_EXPLICIT(MSG_RESEND_LANG_TABLE, 0)
+extern const char* const MSG_RESET_CALIBRATE_E_LANG_TABLE[1];
+#define MSG_RESET_CALIBRATE_E LANG_TABLE_SELECT_EXPLICIT(MSG_RESET_CALIBRATE_E_LANG_TABLE, 0)
+extern const char* const MSG_RESTORE_FAILSAFE_LANG_TABLE[1];
+#define MSG_RESTORE_FAILSAFE LANG_TABLE_SELECT_EXPLICIT(MSG_RESTORE_FAILSAFE_LANG_TABLE, 0)
 extern const char* const MSG_RESUME_PRINT_LANG_TABLE[LANG_NUM];
 #define MSG_RESUME_PRINT LANG_TABLE_SELECT(MSG_RESUME_PRINT_LANG_TABLE)
 extern const char* const MSG_RESUMING_LANG_TABLE[LANG_NUM];
 #define MSG_RESUMING LANG_TABLE_SELECT(MSG_RESUMING_LANG_TABLE)
-extern const char* const MSG_RETRACT_LANG_TABLE[LANG_NUM];
-#define MSG_RETRACT LANG_TABLE_SELECT(MSG_RETRACT_LANG_TABLE)
-extern const char* const MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE[LANG_NUM];
-#define MSG_SD_CANT_ENTER_SUBDIR LANG_TABLE_SELECT(MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE)
-extern const char* const MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE[LANG_NUM];
-#define MSG_SD_CANT_OPEN_SUBDIR LANG_TABLE_SELECT(MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE)
-extern const char* const MSG_SD_CARD_OK_LANG_TABLE[LANG_NUM];
-#define MSG_SD_CARD_OK LANG_TABLE_SELECT(MSG_SD_CARD_OK_LANG_TABLE)
-extern const char* const MSG_SD_ERR_WRITE_TO_FILE_LANG_TABLE[LANG_NUM];
-#define MSG_SD_ERR_WRITE_TO_FILE LANG_TABLE_SELECT(MSG_SD_ERR_WRITE_TO_FILE_LANG_TABLE)
-extern const char* const MSG_SD_FILE_OPENED_LANG_TABLE[LANG_NUM];
-#define MSG_SD_FILE_OPENED LANG_TABLE_SELECT(MSG_SD_FILE_OPENED_LANG_TABLE)
-extern const char* const MSG_SD_FILE_SELECTED_LANG_TABLE[LANG_NUM];
-#define MSG_SD_FILE_SELECTED LANG_TABLE_SELECT(MSG_SD_FILE_SELECTED_LANG_TABLE)
-extern const char* const MSG_SD_INIT_FAIL_LANG_TABLE[LANG_NUM];
-#define MSG_SD_INIT_FAIL LANG_TABLE_SELECT(MSG_SD_INIT_FAIL_LANG_TABLE)
+extern const char* const MSG_RESUMING_PRINT_LANG_TABLE[LANG_NUM];
+#define MSG_RESUMING_PRINT LANG_TABLE_SELECT(MSG_RESUMING_PRINT_LANG_TABLE)
+extern const char* const MSG_RIGHT_LANG_TABLE[LANG_NUM];
+#define MSG_RIGHT LANG_TABLE_SELECT(MSG_RIGHT_LANG_TABLE)
+extern const char* const MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE[1];
+#define MSG_SD_CANT_ENTER_SUBDIR LANG_TABLE_SELECT_EXPLICIT(MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE, 0)
+extern const char* const MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE[1];
+#define MSG_SD_CANT_OPEN_SUBDIR LANG_TABLE_SELECT_EXPLICIT(MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE, 0)
+extern const char* const MSG_SD_CARD_OK_LANG_TABLE[1];
+#define MSG_SD_CARD_OK LANG_TABLE_SELECT_EXPLICIT(MSG_SD_CARD_OK_LANG_TABLE, 0)
+extern const char* const MSG_SD_ERR_WRITE_TO_FILE_LANG_TABLE[1];
+#define MSG_SD_ERR_WRITE_TO_FILE LANG_TABLE_SELECT_EXPLICIT(MSG_SD_ERR_WRITE_TO_FILE_LANG_TABLE, 0)
+extern const char* const MSG_SD_FILE_OPENED_LANG_TABLE[1];
+#define MSG_SD_FILE_OPENED LANG_TABLE_SELECT_EXPLICIT(MSG_SD_FILE_OPENED_LANG_TABLE, 0)
+extern const char* const MSG_SD_FILE_SELECTED_LANG_TABLE[1];
+#define MSG_SD_FILE_SELECTED LANG_TABLE_SELECT_EXPLICIT(MSG_SD_FILE_SELECTED_LANG_TABLE, 0)
+extern const char* const MSG_SD_INIT_FAIL_LANG_TABLE[1];
+#define MSG_SD_INIT_FAIL LANG_TABLE_SELECT_EXPLICIT(MSG_SD_INIT_FAIL_LANG_TABLE, 0)
 extern const char* const MSG_SD_INSERTED_LANG_TABLE[LANG_NUM];
 #define MSG_SD_INSERTED LANG_TABLE_SELECT(MSG_SD_INSERTED_LANG_TABLE)
-extern const char* const MSG_SD_NOT_PRINTING_LANG_TABLE[LANG_NUM];
-#define MSG_SD_NOT_PRINTING LANG_TABLE_SELECT(MSG_SD_NOT_PRINTING_LANG_TABLE)
-extern const char* const MSG_SD_OPENROOT_FAIL_LANG_TABLE[LANG_NUM];
-#define MSG_SD_OPENROOT_FAIL LANG_TABLE_SELECT(MSG_SD_OPENROOT_FAIL_LANG_TABLE)
-extern const char* const MSG_SD_OPEN_FILE_FAIL_LANG_TABLE[LANG_NUM];
-#define MSG_SD_OPEN_FILE_FAIL LANG_TABLE_SELECT(MSG_SD_OPEN_FILE_FAIL_LANG_TABLE)
-extern const char* const MSG_SD_PRINTING_BYTE_LANG_TABLE[LANG_NUM];
-#define MSG_SD_PRINTING_BYTE LANG_TABLE_SELECT(MSG_SD_PRINTING_BYTE_LANG_TABLE)
+extern const char* const MSG_SD_NOT_PRINTING_LANG_TABLE[1];
+#define MSG_SD_NOT_PRINTING LANG_TABLE_SELECT_EXPLICIT(MSG_SD_NOT_PRINTING_LANG_TABLE, 0)
+extern const char* const MSG_SD_OPENROOT_FAIL_LANG_TABLE[1];
+#define MSG_SD_OPENROOT_FAIL LANG_TABLE_SELECT_EXPLICIT(MSG_SD_OPENROOT_FAIL_LANG_TABLE, 0)
+extern const char* const MSG_SD_OPEN_FILE_FAIL_LANG_TABLE[1];
+#define MSG_SD_OPEN_FILE_FAIL LANG_TABLE_SELECT_EXPLICIT(MSG_SD_OPEN_FILE_FAIL_LANG_TABLE, 0)
+extern const char* const MSG_SD_PRINTING_BYTE_LANG_TABLE[1];
+#define MSG_SD_PRINTING_BYTE LANG_TABLE_SELECT_EXPLICIT(MSG_SD_PRINTING_BYTE_LANG_TABLE, 0)
 extern const char* const MSG_SD_REMOVED_LANG_TABLE[LANG_NUM];
 #define MSG_SD_REMOVED LANG_TABLE_SELECT(MSG_SD_REMOVED_LANG_TABLE)
-extern const char* const MSG_SD_SIZE_LANG_TABLE[LANG_NUM];
-#define MSG_SD_SIZE LANG_TABLE_SELECT(MSG_SD_SIZE_LANG_TABLE)
-extern const char* const MSG_SD_VOL_INIT_FAIL_LANG_TABLE[LANG_NUM];
-#define MSG_SD_VOL_INIT_FAIL LANG_TABLE_SELECT(MSG_SD_VOL_INIT_FAIL_LANG_TABLE)
-extern const char* const MSG_SD_WORKDIR_FAIL_LANG_TABLE[LANG_NUM];
-#define MSG_SD_WORKDIR_FAIL LANG_TABLE_SELECT(MSG_SD_WORKDIR_FAIL_LANG_TABLE)
-extern const char* const MSG_SD_WRITE_TO_FILE_LANG_TABLE[LANG_NUM];
-#define MSG_SD_WRITE_TO_FILE LANG_TABLE_SELECT(MSG_SD_WRITE_TO_FILE_LANG_TABLE)
-extern const char* const MSG_SELFTEST_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST LANG_TABLE_SELECT(MSG_SELFTEST_LANG_TABLE)
-extern const char* const MSG_SELFTEST_BEDHEATER_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_BEDHEATER LANG_TABLE_SELECT(MSG_SELFTEST_BEDHEATER_LANG_TABLE)
+extern const char* const MSG_SD_SIZE_LANG_TABLE[1];
+#define MSG_SD_SIZE LANG_TABLE_SELECT_EXPLICIT(MSG_SD_SIZE_LANG_TABLE, 0)
+extern const char* const MSG_SD_VOL_INIT_FAIL_LANG_TABLE[1];
+#define MSG_SD_VOL_INIT_FAIL LANG_TABLE_SELECT_EXPLICIT(MSG_SD_VOL_INIT_FAIL_LANG_TABLE, 0)
+extern const char* const MSG_SD_WORKDIR_FAIL_LANG_TABLE[1];
+#define MSG_SD_WORKDIR_FAIL LANG_TABLE_SELECT_EXPLICIT(MSG_SD_WORKDIR_FAIL_LANG_TABLE, 0)
+extern const char* const MSG_SD_WRITE_TO_FILE_LANG_TABLE[1];
+#define MSG_SD_WRITE_TO_FILE LANG_TABLE_SELECT_EXPLICIT(MSG_SD_WRITE_TO_FILE_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_LANG_TABLE[1];
+#define MSG_SELFTEST LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_AXIS_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_AXIS LANG_TABLE_SELECT(MSG_SELFTEST_AXIS_LANG_TABLE)
+extern const char* const MSG_SELFTEST_AXIS_LENGTH_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_AXIS_LENGTH LANG_TABLE_SELECT(MSG_SELFTEST_AXIS_LENGTH_LANG_TABLE)
+extern const char* const MSG_SELFTEST_BEDHEATER_LANG_TABLE[1];
+#define MSG_SELFTEST_BEDHEATER LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_BEDHEATER_LANG_TABLE, 0)
 extern const char* const MSG_SELFTEST_CHECK_ALLCORRECT_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_CHECK_ALLCORRECT LANG_TABLE_SELECT(MSG_SELFTEST_CHECK_ALLCORRECT_LANG_TABLE)
 extern const char* const MSG_SELFTEST_CHECK_BED_LANG_TABLE[LANG_NUM];
@@ -440,48 +532,66 @@ extern const char* const MSG_SELFTEST_CHECK_Y_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_CHECK_Y LANG_TABLE_SELECT(MSG_SELFTEST_CHECK_Y_LANG_TABLE)
 extern const char* const MSG_SELFTEST_CHECK_Z_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_CHECK_Z LANG_TABLE_SELECT(MSG_SELFTEST_CHECK_Z_LANG_TABLE)
-extern const char* const MSG_SELFTEST_ENDSTOP_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_ENDSTOP LANG_TABLE_SELECT(MSG_SELFTEST_ENDSTOP_LANG_TABLE)
-extern const char* const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_ENDSTOPS LANG_TABLE_SELECT(MSG_SELFTEST_ENDSTOPS_LANG_TABLE)
-extern const char* const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_ENDSTOP_NOTHIT LANG_TABLE_SELECT(MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE)
-extern const char* const MSG_SELFTEST_ERROR_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_ERROR LANG_TABLE_SELECT(MSG_SELFTEST_ERROR_LANG_TABLE)
+extern const char* const MSG_SELFTEST_COOLING_FAN_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_COOLING_FAN LANG_TABLE_SELECT(MSG_SELFTEST_COOLING_FAN_LANG_TABLE)
+extern const char* const MSG_SELFTEST_ENDSTOP_LANG_TABLE[1];
+#define MSG_SELFTEST_ENDSTOP LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_ENDSTOP_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[1];
+#define MSG_SELFTEST_ENDSTOPS LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_ENDSTOPS_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[1];
+#define MSG_SELFTEST_ENDSTOP_NOTHIT LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_ERROR_LANG_TABLE[1];
+#define MSG_SELFTEST_ERROR LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_ERROR_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_EXTRUDER_FAN LANG_TABLE_SELECT(MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE)
 extern const char* const MSG_SELFTEST_FAILED_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_FAILED LANG_TABLE_SELECT(MSG_SELFTEST_FAILED_LANG_TABLE)
-extern const char* const MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_HEATERTHERMISTOR LANG_TABLE_SELECT(MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE)
-extern const char* const MSG_SELFTEST_MOTOR_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_MOTOR LANG_TABLE_SELECT(MSG_SELFTEST_MOTOR_LANG_TABLE)
+extern const char* const MSG_SELFTEST_FAN_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_FAN LANG_TABLE_SELECT(MSG_SELFTEST_FAN_LANG_TABLE)
+extern const char* const MSG_SELFTEST_FAN_NO_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_FAN_NO LANG_TABLE_SELECT(MSG_SELFTEST_FAN_NO_LANG_TABLE)
+extern const char* const MSG_SELFTEST_FAN_YES_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_FAN_YES LANG_TABLE_SELECT(MSG_SELFTEST_FAN_YES_LANG_TABLE)
+extern const char* const MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE[1];
+#define MSG_SELFTEST_HEATERTHERMISTOR LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE, 0)
+extern const char* const MSG_SELFTEST_MOTOR_LANG_TABLE[1];
+#define MSG_SELFTEST_MOTOR LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_MOTOR_LANG_TABLE, 0)
 extern const char* const MSG_SELFTEST_NOTCONNECTED_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_NOTCONNECTED LANG_TABLE_SELECT(MSG_SELFTEST_NOTCONNECTED_LANG_TABLE)
-extern const char* const MSG_SELFTEST_OK_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_OK LANG_TABLE_SELECT(MSG_SELFTEST_OK_LANG_TABLE)
+extern const char* const MSG_SELFTEST_OK_LANG_TABLE[1];
+#define MSG_SELFTEST_OK LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_OK_LANG_TABLE, 0)
 extern const char* const MSG_SELFTEST_PLEASECHECK_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_PLEASECHECK LANG_TABLE_SELECT(MSG_SELFTEST_PLEASECHECK_LANG_TABLE)
-extern const char* const MSG_SELFTEST_START_LANG_TABLE[LANG_NUM];
-#define MSG_SELFTEST_START LANG_TABLE_SELECT(MSG_SELFTEST_START_LANG_TABLE)
+extern const char* const MSG_SELFTEST_START_LANG_TABLE[1];
+#define MSG_SELFTEST_START LANG_TABLE_SELECT_EXPLICIT(MSG_SELFTEST_START_LANG_TABLE, 0)
 extern const char* const MSG_SELFTEST_WIRINGERROR_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_WIRINGERROR LANG_TABLE_SELECT(MSG_SELFTEST_WIRINGERROR_LANG_TABLE)
-extern const char* const MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE[LANG_NUM];
-#define MSG_SERIAL_ERROR_MENU_STRUCTURE LANG_TABLE_SELECT(MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE)
+extern const char* const MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE[1];
+#define MSG_SERIAL_ERROR_MENU_STRUCTURE LANG_TABLE_SELECT_EXPLICIT(MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE, 0)
 extern const char* const MSG_SETTINGS_LANG_TABLE[LANG_NUM];
 #define MSG_SETTINGS LANG_TABLE_SELECT(MSG_SETTINGS_LANG_TABLE)
-extern const char* const MSG_SET_HOME_OFFSETS_LANG_TABLE[LANG_NUM];
-#define MSG_SET_HOME_OFFSETS LANG_TABLE_SELECT(MSG_SET_HOME_OFFSETS_LANG_TABLE)
-extern const char* const MSG_SET_ORIGIN_LANG_TABLE[LANG_NUM];
-#define MSG_SET_ORIGIN LANG_TABLE_SELECT(MSG_SET_ORIGIN_LANG_TABLE)
+extern const char* const MSG_SET_HOME_OFFSETS_LANG_TABLE[1];
+#define MSG_SET_HOME_OFFSETS LANG_TABLE_SELECT_EXPLICIT(MSG_SET_HOME_OFFSETS_LANG_TABLE, 0)
+extern const char* const MSG_SET_ORIGIN_LANG_TABLE[1];
+#define MSG_SET_ORIGIN LANG_TABLE_SELECT_EXPLICIT(MSG_SET_ORIGIN_LANG_TABLE, 0)
+extern const char* const MSG_SET_TEMPERATURE_LANG_TABLE[LANG_NUM];
+#define MSG_SET_TEMPERATURE LANG_TABLE_SELECT(MSG_SET_TEMPERATURE_LANG_TABLE)
+extern const char* const MSG_SEVERE_SKEW_LANG_TABLE[LANG_NUM];
+#define MSG_SEVERE_SKEW LANG_TABLE_SELECT(MSG_SEVERE_SKEW_LANG_TABLE)
 extern const char* const MSG_SHOW_END_STOPS_LANG_TABLE[LANG_NUM];
 #define MSG_SHOW_END_STOPS LANG_TABLE_SELECT(MSG_SHOW_END_STOPS_LANG_TABLE)
 extern const char* const MSG_SILENT_MODE_OFF_LANG_TABLE[LANG_NUM];
 #define MSG_SILENT_MODE_OFF LANG_TABLE_SELECT(MSG_SILENT_MODE_OFF_LANG_TABLE)
 extern const char* const MSG_SILENT_MODE_ON_LANG_TABLE[LANG_NUM];
 #define MSG_SILENT_MODE_ON LANG_TABLE_SELECT(MSG_SILENT_MODE_ON_LANG_TABLE)
-extern const char* const MSG_SOFTWARE_RESET_LANG_TABLE[LANG_NUM];
-#define MSG_SOFTWARE_RESET LANG_TABLE_SELECT(MSG_SOFTWARE_RESET_LANG_TABLE)
+extern const char* const MSG_SLIGHT_SKEW_LANG_TABLE[LANG_NUM];
+#define MSG_SLIGHT_SKEW LANG_TABLE_SELECT(MSG_SLIGHT_SKEW_LANG_TABLE)
+extern const char* const MSG_SOFTWARE_RESET_LANG_TABLE[1];
+#define MSG_SOFTWARE_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_SOFTWARE_RESET_LANG_TABLE, 0)
 extern const char* const MSG_SPEED_LANG_TABLE[LANG_NUM];
 #define MSG_SPEED LANG_TABLE_SELECT(MSG_SPEED_LANG_TABLE)
+extern const char* const MSG_STACK_ERROR_LANG_TABLE[1];
+#define MSG_STACK_ERROR LANG_TABLE_SELECT_EXPLICIT(MSG_STACK_ERROR_LANG_TABLE, 0)
 extern const char* const MSG_STATISTICS_LANG_TABLE[LANG_NUM];
 #define MSG_STATISTICS LANG_TABLE_SELECT(MSG_STATISTICS_LANG_TABLE)
 extern const char* const MSG_STATS_FILAMENTUSED_LANG_TABLE[LANG_NUM];
@@ -492,14 +602,16 @@ extern const char* const MSG_STATS_TOTALFILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_STATS_TOTALFILAMENT LANG_TABLE_SELECT(MSG_STATS_TOTALFILAMENT_LANG_TABLE)
 extern const char* const MSG_STATS_TOTALPRINTTIME_LANG_TABLE[LANG_NUM];
 #define MSG_STATS_TOTALPRINTTIME LANG_TABLE_SELECT(MSG_STATS_TOTALPRINTTIME_LANG_TABLE)
-extern const char* const MSG_STEPPER_TOO_HIGH_LANG_TABLE[LANG_NUM];
-#define MSG_STEPPER_TOO_HIGH LANG_TABLE_SELECT(MSG_STEPPER_TOO_HIGH_LANG_TABLE)
-extern const char* const MSG_STOPPED_LANG_TABLE[LANG_NUM];
-#define MSG_STOPPED LANG_TABLE_SELECT(MSG_STOPPED_LANG_TABLE)
+extern const char* const MSG_STEEL_SHEET_CHECK_LANG_TABLE[LANG_NUM];
+#define MSG_STEEL_SHEET_CHECK LANG_TABLE_SELECT(MSG_STEEL_SHEET_CHECK_LANG_TABLE)
+extern const char* const MSG_STEPPER_TOO_HIGH_LANG_TABLE[1];
+#define MSG_STEPPER_TOO_HIGH LANG_TABLE_SELECT_EXPLICIT(MSG_STEPPER_TOO_HIGH_LANG_TABLE, 0)
+extern const char* const MSG_STOPPED_LANG_TABLE[1];
+#define MSG_STOPPED LANG_TABLE_SELECT_EXPLICIT(MSG_STOPPED_LANG_TABLE, 0)
 extern const char* const MSG_STOP_PRINT_LANG_TABLE[LANG_NUM];
 #define MSG_STOP_PRINT LANG_TABLE_SELECT(MSG_STOP_PRINT_LANG_TABLE)
-extern const char* const MSG_STORE_EPROM_LANG_TABLE[LANG_NUM];
-#define MSG_STORE_EPROM LANG_TABLE_SELECT(MSG_STORE_EPROM_LANG_TABLE)
+extern const char* const MSG_STORE_EPROM_LANG_TABLE[1];
+#define MSG_STORE_EPROM LANG_TABLE_SELECT_EXPLICIT(MSG_STORE_EPROM_LANG_TABLE, 0)
 extern const char* const MSG_SUPPORT_LANG_TABLE[LANG_NUM];
 #define MSG_SUPPORT LANG_TABLE_SELECT(MSG_SUPPORT_LANG_TABLE)
 extern const char* const MSG_SWITCH_PS_OFF_LANG_TABLE[LANG_NUM];
@@ -510,66 +622,120 @@ extern const char* const MSG_TAKE_EFFECT_LANG_TABLE[LANG_NUM];
 #define MSG_TAKE_EFFECT LANG_TABLE_SELECT(MSG_TAKE_EFFECT_LANG_TABLE)
 extern const char* const MSG_TEMPERATURE_LANG_TABLE[LANG_NUM];
 #define MSG_TEMPERATURE LANG_TABLE_SELECT(MSG_TEMPERATURE_LANG_TABLE)
+extern const char* const MSG_TEMP_CALIBRATION_LANG_TABLE[LANG_NUM];
+#define MSG_TEMP_CALIBRATION LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_LANG_TABLE)
+extern const char* const MSG_TEMP_CALIBRATION_DONE_LANG_TABLE[LANG_NUM];
+#define MSG_TEMP_CALIBRATION_DONE LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_DONE_LANG_TABLE)
+extern const char* const MSG_TEMP_CALIBRATION_OFF_LANG_TABLE[LANG_NUM];
+#define MSG_TEMP_CALIBRATION_OFF LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_OFF_LANG_TABLE)
+extern const char* const MSG_TEMP_CALIBRATION_ON_LANG_TABLE[LANG_NUM];
+#define MSG_TEMP_CALIBRATION_ON LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_ON_LANG_TABLE)
+extern const char* const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE[1];
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF LANG_TABLE_SELECT_EXPLICIT(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE, 0)
+extern const char* const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_LANG_TABLE[1];
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON LANG_TABLE_SELECT_EXPLICIT(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_LANG_TABLE, 0)
 extern const char* const MSG_TUNE_LANG_TABLE[LANG_NUM];
 #define MSG_TUNE LANG_TABLE_SELECT(MSG_TUNE_LANG_TABLE)
-extern const char* const MSG_UNKNOWN_COMMAND_LANG_TABLE[LANG_NUM];
-#define MSG_UNKNOWN_COMMAND LANG_TABLE_SELECT(MSG_UNKNOWN_COMMAND_LANG_TABLE)
+extern const char* const MSG_UNKNOWN_COMMAND_LANG_TABLE[1];
+#define MSG_UNKNOWN_COMMAND LANG_TABLE_SELECT_EXPLICIT(MSG_UNKNOWN_COMMAND_LANG_TABLE, 0)
+extern const char* const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOADING_FILAMENT LANG_TABLE_SELECT(MSG_UNLOADING_FILAMENT_LANG_TABLE)
+extern const char* const MSG_UNLOAD_ALL_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOAD_ALL LANG_TABLE_SELECT(MSG_UNLOAD_ALL_LANG_TABLE)
 extern const char* const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_UNLOAD_FILAMENT LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_LANG_TABLE)
+extern const char* const MSG_UNLOAD_FILAMENT_1_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOAD_FILAMENT_1 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_1_LANG_TABLE)
+extern const char* const MSG_UNLOAD_FILAMENT_2_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOAD_FILAMENT_2 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_2_LANG_TABLE)
+extern const char* const MSG_UNLOAD_FILAMENT_3_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOAD_FILAMENT_3 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_3_LANG_TABLE)
+extern const char* const MSG_UNLOAD_FILAMENT_4_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOAD_FILAMENT_4 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_4_LANG_TABLE)
+extern const char* const MSG_UNLOAD_SUCCESSFULL_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOAD_SUCCESSFULL LANG_TABLE_SELECT(MSG_UNLOAD_SUCCESSFULL_LANG_TABLE)
 extern const char* const MSG_USB_PRINTING_LANG_TABLE[LANG_NUM];
 #define MSG_USB_PRINTING LANG_TABLE_SELECT(MSG_USB_PRINTING_LANG_TABLE)
-extern const char* const MSG_USERWAIT_LANG_TABLE[LANG_NUM];
-#define MSG_USERWAIT LANG_TABLE_SELECT(MSG_USERWAIT_LANG_TABLE)
-extern const char* const MSG_VE_JERK_LANG_TABLE[LANG_NUM];
-#define MSG_VE_JERK LANG_TABLE_SELECT(MSG_VE_JERK_LANG_TABLE)
-extern const char* const MSG_VMAX_LANG_TABLE[LANG_NUM];
-#define MSG_VMAX LANG_TABLE_SELECT(MSG_VMAX_LANG_TABLE)
-extern const char* const MSG_VMIN_LANG_TABLE[LANG_NUM];
-#define MSG_VMIN LANG_TABLE_SELECT(MSG_VMIN_LANG_TABLE)
-extern const char* const MSG_VOLUMETRIC_LANG_TABLE[LANG_NUM];
-#define MSG_VOLUMETRIC LANG_TABLE_SELECT(MSG_VOLUMETRIC_LANG_TABLE)
-extern const char* const MSG_VOLUMETRIC_ENABLED_LANG_TABLE[LANG_NUM];
-#define MSG_VOLUMETRIC_ENABLED LANG_TABLE_SELECT(MSG_VOLUMETRIC_ENABLED_LANG_TABLE)
-extern const char* const MSG_VTRAV_MIN_LANG_TABLE[LANG_NUM];
-#define MSG_VTRAV_MIN LANG_TABLE_SELECT(MSG_VTRAV_MIN_LANG_TABLE)
-extern const char* const MSG_VXY_JERK_LANG_TABLE[LANG_NUM];
-#define MSG_VXY_JERK LANG_TABLE_SELECT(MSG_VXY_JERK_LANG_TABLE)
-extern const char* const MSG_VZ_JERK_LANG_TABLE[LANG_NUM];
-#define MSG_VZ_JERK LANG_TABLE_SELECT(MSG_VZ_JERK_LANG_TABLE)
+extern const char* const MSG_USED_LANG_TABLE[LANG_NUM];
+#define MSG_USED LANG_TABLE_SELECT(MSG_USED_LANG_TABLE)
+extern const char* const MSG_USERWAIT_LANG_TABLE[1];
+#define MSG_USERWAIT LANG_TABLE_SELECT_EXPLICIT(MSG_USERWAIT_LANG_TABLE, 0)
+extern const char* const MSG_V2_CALIBRATION_LANG_TABLE[LANG_NUM];
+#define MSG_V2_CALIBRATION LANG_TABLE_SELECT(MSG_V2_CALIBRATION_LANG_TABLE)
+extern const char* const MSG_VMIN_LANG_TABLE[1];
+#define MSG_VMIN LANG_TABLE_SELECT_EXPLICIT(MSG_VMIN_LANG_TABLE, 0)
+extern const char* const MSG_VOLUMETRIC_LANG_TABLE[1];
+#define MSG_VOLUMETRIC LANG_TABLE_SELECT_EXPLICIT(MSG_VOLUMETRIC_LANG_TABLE, 0)
+extern const char* const MSG_VOLUMETRIC_ENABLED_LANG_TABLE[1];
+#define MSG_VOLUMETRIC_ENABLED LANG_TABLE_SELECT_EXPLICIT(MSG_VOLUMETRIC_ENABLED_LANG_TABLE, 0)
+extern const char* const MSG_VTRAV_MIN_LANG_TABLE[1];
+#define MSG_VTRAV_MIN LANG_TABLE_SELECT_EXPLICIT(MSG_VTRAV_MIN_LANG_TABLE, 0)
+extern const char* const MSG_WAITING_TEMP_LANG_TABLE[LANG_NUM];
+#define MSG_WAITING_TEMP LANG_TABLE_SELECT(MSG_WAITING_TEMP_LANG_TABLE)
 extern const char* const MSG_WATCH_LANG_TABLE[LANG_NUM];
 #define MSG_WATCH LANG_TABLE_SELECT(MSG_WATCH_LANG_TABLE)
-extern const char* const MSG_WATCHDOG_RESET_LANG_TABLE[LANG_NUM];
-#define MSG_WATCHDOG_RESET LANG_TABLE_SELECT(MSG_WATCHDOG_RESET_LANG_TABLE)
-extern const char* const MSG_X_LANG_TABLE[LANG_NUM];
-#define MSG_X LANG_TABLE_SELECT(MSG_X_LANG_TABLE)
-extern const char* const MSG_XSTEPS_LANG_TABLE[LANG_NUM];
-#define MSG_XSTEPS LANG_TABLE_SELECT(MSG_XSTEPS_LANG_TABLE)
-extern const char* const MSG_X_MAX_LANG_TABLE[LANG_NUM];
-#define MSG_X_MAX LANG_TABLE_SELECT(MSG_X_MAX_LANG_TABLE)
-extern const char* const MSG_X_MIN_LANG_TABLE[LANG_NUM];
-#define MSG_X_MIN LANG_TABLE_SELECT(MSG_X_MIN_LANG_TABLE)
-extern const char* const MSG_Y_LANG_TABLE[LANG_NUM];
-#define MSG_Y LANG_TABLE_SELECT(MSG_Y_LANG_TABLE)
+extern const char* const MSG_WATCHDOG_RESET_LANG_TABLE[1];
+#define MSG_WATCHDOG_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_WATCHDOG_RESET_LANG_TABLE, 0)
+extern const char* const MSG_WIZARD_LANG_TABLE[1];
+#define MSG_WIZARD LANG_TABLE_SELECT_EXPLICIT(MSG_WIZARD_LANG_TABLE, 0)
+extern const char* const MSG_WIZARD_CALIBRATION_FAILED_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_CALIBRATION_FAILED LANG_TABLE_SELECT(MSG_WIZARD_CALIBRATION_FAILED_LANG_TABLE)
+extern const char* const MSG_WIZARD_CLEAN_HEATBED_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_CLEAN_HEATBED LANG_TABLE_SELECT(MSG_WIZARD_CLEAN_HEATBED_LANG_TABLE)
+extern const char* const MSG_WIZARD_DONE_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_DONE LANG_TABLE_SELECT(MSG_WIZARD_DONE_LANG_TABLE)
+extern const char* const MSG_WIZARD_FILAMENT_LOADED_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_FILAMENT_LOADED LANG_TABLE_SELECT(MSG_WIZARD_FILAMENT_LOADED_LANG_TABLE)
+extern const char* const MSG_WIZARD_HEATING_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_HEATING LANG_TABLE_SELECT(MSG_WIZARD_HEATING_LANG_TABLE)
+extern const char* const MSG_WIZARD_INSERT_CORRECT_FILAMENT_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_INSERT_CORRECT_FILAMENT LANG_TABLE_SELECT(MSG_WIZARD_INSERT_CORRECT_FILAMENT_LANG_TABLE)
+extern const char* const MSG_WIZARD_LOAD_FILAMENT_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_LOAD_FILAMENT LANG_TABLE_SELECT(MSG_WIZARD_LOAD_FILAMENT_LANG_TABLE)
+extern const char* const MSG_WIZARD_PLA_FILAMENT_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_PLA_FILAMENT LANG_TABLE_SELECT(MSG_WIZARD_PLA_FILAMENT_LANG_TABLE)
+extern const char* const MSG_WIZARD_QUIT_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_QUIT LANG_TABLE_SELECT(MSG_WIZARD_QUIT_LANG_TABLE)
+extern const char* const MSG_WIZARD_REPEAT_V2_CAL_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_REPEAT_V2_CAL LANG_TABLE_SELECT(MSG_WIZARD_REPEAT_V2_CAL_LANG_TABLE)
+extern const char* const MSG_WIZARD_RERUN_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_RERUN LANG_TABLE_SELECT(MSG_WIZARD_RERUN_LANG_TABLE)
+extern const char* const MSG_WIZARD_SELFTEST_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_SELFTEST LANG_TABLE_SELECT(MSG_WIZARD_SELFTEST_LANG_TABLE)
+extern const char* const MSG_WIZARD_V2_CAL_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_V2_CAL LANG_TABLE_SELECT(MSG_WIZARD_V2_CAL_LANG_TABLE)
+extern const char* const MSG_WIZARD_V2_CAL_2_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_V2_CAL_2 LANG_TABLE_SELECT(MSG_WIZARD_V2_CAL_2_LANG_TABLE)
+extern const char* const MSG_WIZARD_WELCOME_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_WELCOME LANG_TABLE_SELECT(MSG_WIZARD_WELCOME_LANG_TABLE)
+extern const char* const MSG_WIZARD_WILL_PREHEAT_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_WILL_PREHEAT LANG_TABLE_SELECT(MSG_WIZARD_WILL_PREHEAT_LANG_TABLE)
+extern const char* const MSG_WIZARD_XYZ_CAL_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_XYZ_CAL LANG_TABLE_SELECT(MSG_WIZARD_XYZ_CAL_LANG_TABLE)
+extern const char* const MSG_WIZARD_Z_CAL_LANG_TABLE[LANG_NUM];
+#define MSG_WIZARD_Z_CAL LANG_TABLE_SELECT(MSG_WIZARD_Z_CAL_LANG_TABLE)
+extern const char* const MSG_XYZ_DETAILS_LANG_TABLE[LANG_NUM];
+#define MSG_XYZ_DETAILS LANG_TABLE_SELECT(MSG_XYZ_DETAILS_LANG_TABLE)
+extern const char* const MSG_X_MAX_LANG_TABLE[1];
+#define MSG_X_MAX LANG_TABLE_SELECT_EXPLICIT(MSG_X_MAX_LANG_TABLE, 0)
+extern const char* const MSG_X_MIN_LANG_TABLE[1];
+#define MSG_X_MIN LANG_TABLE_SELECT_EXPLICIT(MSG_X_MIN_LANG_TABLE, 0)
 extern const char* const MSG_YES_LANG_TABLE[LANG_NUM];
 #define MSG_YES LANG_TABLE_SELECT(MSG_YES_LANG_TABLE)
-extern const char* const MSG_YSTEPS_LANG_TABLE[LANG_NUM];
-#define MSG_YSTEPS LANG_TABLE_SELECT(MSG_YSTEPS_LANG_TABLE)
-extern const char* const MSG_Y_MAX_LANG_TABLE[LANG_NUM];
-#define MSG_Y_MAX LANG_TABLE_SELECT(MSG_Y_MAX_LANG_TABLE)
-extern const char* const MSG_Y_MIN_LANG_TABLE[LANG_NUM];
-#define MSG_Y_MIN LANG_TABLE_SELECT(MSG_Y_MIN_LANG_TABLE)
-extern const char* const MSG_Z_LANG_TABLE[LANG_NUM];
-#define MSG_Z LANG_TABLE_SELECT(MSG_Z_LANG_TABLE)
-extern const char* const MSG_ZPROBE_OUT_LANG_TABLE[LANG_NUM];
-#define MSG_ZPROBE_OUT LANG_TABLE_SELECT(MSG_ZPROBE_OUT_LANG_TABLE)
-extern const char* const MSG_ZPROBE_ZOFFSET_LANG_TABLE[LANG_NUM];
-#define MSG_ZPROBE_ZOFFSET LANG_TABLE_SELECT(MSG_ZPROBE_ZOFFSET_LANG_TABLE)
-extern const char* const MSG_ZSTEPS_LANG_TABLE[LANG_NUM];
-#define MSG_ZSTEPS LANG_TABLE_SELECT(MSG_ZSTEPS_LANG_TABLE)
-extern const char* const MSG_Z_MAX_LANG_TABLE[LANG_NUM];
-#define MSG_Z_MAX LANG_TABLE_SELECT(MSG_Z_MAX_LANG_TABLE)
-extern const char* const MSG_Z_MIN_LANG_TABLE[LANG_NUM];
-#define MSG_Z_MIN LANG_TABLE_SELECT(MSG_Z_MIN_LANG_TABLE)
+extern const char* const MSG_Y_DISTANCE_FROM_MIN_LANG_TABLE[LANG_NUM];
+#define MSG_Y_DISTANCE_FROM_MIN LANG_TABLE_SELECT(MSG_Y_DISTANCE_FROM_MIN_LANG_TABLE)
+extern const char* const MSG_Y_MAX_LANG_TABLE[1];
+#define MSG_Y_MAX LANG_TABLE_SELECT_EXPLICIT(MSG_Y_MAX_LANG_TABLE, 0)
+extern const char* const MSG_Y_MIN_LANG_TABLE[1];
+#define MSG_Y_MIN LANG_TABLE_SELECT_EXPLICIT(MSG_Y_MIN_LANG_TABLE, 0)
+extern const char* const MSG_ZPROBE_OUT_LANG_TABLE[1];
+#define MSG_ZPROBE_OUT LANG_TABLE_SELECT_EXPLICIT(MSG_ZPROBE_OUT_LANG_TABLE, 0)
+extern const char* const MSG_ZPROBE_ZOFFSET_LANG_TABLE[1];
+#define MSG_ZPROBE_ZOFFSET LANG_TABLE_SELECT_EXPLICIT(MSG_ZPROBE_ZOFFSET_LANG_TABLE, 0)
+extern const char* const MSG_Z_MAX_LANG_TABLE[1];
+#define MSG_Z_MAX LANG_TABLE_SELECT_EXPLICIT(MSG_Z_MAX_LANG_TABLE, 0)
+extern const char* const MSG_Z_MIN_LANG_TABLE[1];
+#define MSG_Z_MIN LANG_TABLE_SELECT_EXPLICIT(MSG_Z_MIN_LANG_TABLE, 0)
 extern const char* const WELCOME_MSG_LANG_TABLE[LANG_NUM];
 #define WELCOME_MSG LANG_TABLE_SELECT(WELCOME_MSG_LANG_TABLE)
 

+ 110 - 0
Firmware/language_common.h

@@ -0,0 +1,110 @@
+// These are the system messages, which shall always be in English.
+
++define MSG_Enqueing                        "enqueing \""
++define MSG_POWERUP                         "PowerUp"
+define MSG_EXTERNAL_RESET                  " External Reset"
+define MSG_BROWNOUT_RESET                  " Brown out Reset"
+define MSG_WATCHDOG_RESET                  " Watchdog Reset"
+define MSG_SOFTWARE_RESET                  " Software Reset"
+define MSG_AUTHOR                          " | Author: "
++define MSG_CONFIGURATION_VER               " Last Updated: "
++define MSG_FREE_MEMORY                     " Free Memory: "
++define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
++define MSG_OK                              "ok"
+define MSG_FILE_SAVED                      "Done saving file."
+define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
++define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
++define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
+define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
+define MSG_FILE_PRINTED                    "Done printing file"
++define MSG_BEGIN_FILE_LIST                 "Begin file list"
++define MSG_END_FILE_LIST                   "End file list"
++define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
++define MSG_M105_INVALID_EXTRUDER           "M105 Invalid extruder "
++define MSG_M200_INVALID_EXTRUDER           "M200 Invalid extruder "
++define MSG_M218_INVALID_EXTRUDER           "M218 Invalid extruder "
++define MSG_M221_INVALID_EXTRUDER           "M221 Invalid extruder "
++define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
++define MSG_M109_INVALID_EXTRUDER           "M109 Invalid extruder "
++define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
+define MSG_COUNT_X                         " Count X: "
++define MSG_ERR_KILLED                      "Printer halted. kill() called!"
++define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
++define MSG_RESEND                          "Resend: "
+define MSG_UNKNOWN_COMMAND                 "Unknown command: \""
+define MSG_ACTIVE_EXTRUDER                 "Active Extruder: "
+define MSG_INVALID_EXTRUDER                "Invalid extruder"
+
+define MSG_X_MIN                           "x_min: "
+define MSG_X_MAX                           "x_max: "
+define MSG_Y_MIN                           "y_min: "
+define MSG_Y_MAX                           "y_max: "
+define MSG_Z_MIN                           "z_min: "
+define MSG_Z_MAX                           "z_max: "
+
++define MSG_M119_REPORT                     "Reporting endstop status"
++define MSG_ENDSTOP_HIT                     "TRIGGERED"
++define MSG_ENDSTOP_OPEN                    "open"
++define MSG_HOTEND_OFFSET                   "Hotend offsets:"
++define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
++define MSG_SD_INIT_FAIL                    "SD init fail"
++define MSG_SD_VOL_INIT_FAIL                "volume.init failed"
++define MSG_SD_OPENROOT_FAIL                "openRoot failed"
++define MSG_SD_CARD_OK                      "SD card ok"
++define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
++define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
++define MSG_SD_FILE_OPENED                  "File opened: "
+define MSG_SD_SIZE                         " Size: "
++define MSG_SD_FILE_SELECTED                "File selected"
++define MSG_SD_WRITE_TO_FILE                "Writing to file: "
++define MSG_SD_PRINTING_BYTE                "SD printing byte "
++define MSG_SD_NOT_PRINTING                 "Not SD printing"
++define MSG_SD_ERR_WRITE_TO_FILE            "error writing to file"
++define MSG_SD_CANT_ENTER_SUBDIR            "Cannot enter subdir: "
++define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
++define MSG_ENDSTOPS_HIT                    "endstops hit: "
++define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
+define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
++define MSG_BABYSTEPPING_X                  "Babystepping X"
++define MSG_BABYSTEPPING_Y                  "Babystepping Y"
++define MSG_BABYSTEPPING_Z                  "Adjusting Z"
++define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
++define MSG_SET_HOME_OFFSETS                "Set home offsets"
++define MSG_SET_ORIGIN                      "Set origin"
+define MSG_ON                              "On "
+define MSG_OFF                             "Off"
+
++define MSG_VMIN                            "Vmin"
++define MSG_VTRAV_MIN                       "VTrav min"
++define MSG_AMAX                            "Amax "
++define MSG_A_RETRACT                       "A-retract"
++define MSG_MOVE_01MM                       "Move 0.1mm"
++define MSG_MOVE_1MM                        "Move 1mm"
++define MSG_MOVE_10MM                       "Move 10mm"
+
+
++define MSG_NOZZLE1                         "Nozzle2"
++define MSG_NOZZLE2                         "Nozzle3"
++define MSG_FLOW0                           "Flow 0"
++define MSG_FLOW1                           "Flow 1"
++define MSG_FLOW2                           "Flow 2"
++define MSG_CONTROL                         "Control"
++define MSG_MIN                             " \002 Min"
++define MSG_MAX                             " \002 Max"
++define MSG_FACTOR                          " \002 Fact"
++define MSG_MOTION                          "Motion"
++define MSG_VOLUMETRIC                      "Filament"
++define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
++define MSG_STORE_EPROM                     "Store memory"
++define MSG_LOAD_EPROM                      "Load memory"
++define MSG_RESTORE_FAILSAFE                "Restore failsafe"
++define MSG_REFRESH                         "\xF8" "Refresh"
+
++define MSG_INIT_SDCARD                     "Init. SD card"
++define MSG_CNG_SDCARD                      "Change SD card"
+define MSG_ZPROBE_OUT                      "Z probe out. bed"
+define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
+define MSG_ZPROBE_ZOFFSET                  "Z Offset"
++define MSG_BABYSTEP_X                      "Babystep X"
++define MSG_BABYSTEP_Y                      "Babystep Y"
++define MSG_RECTRACT                        "Rectract"

+ 155 - 116
Firmware/language_cz.h

@@ -5,47 +5,22 @@
  * Please note these are limited to 17 characters!
  *
  */
-#ifndef LANGUAGE_CZ_H
-#define LANGUAGE_CZ_H
-
 #define WELCOME_MSG                         CUSTOM_MENDEL_NAME " ok"
 #define MSG_SD_INSERTED                     "Karta vlozena"
 #define MSG_SD_REMOVED                      "Karta vyjmuta"
 #define MSG_MAIN                            "Hlavni nabidka"
-#define MSG_AUTOSTART                       "Autostart"
 #define MSG_DISABLE_STEPPERS                "Vypnout motory"
 #define MSG_AUTO_HOME                       "Auto home"
 #define MSG_SET_HOME_OFFSETS                "Nastav pocatek home"
 #define MSG_SET_ORIGIN                      "Nastav pocatek"
-#define MSG_PREHEAT_PLA                     "Predehrev PLA"
-#define MSG_PREHEAT_PLA0                    "Predehrev PLA 1"
-#define MSG_PREHEAT_PLA1                    "Predehrev PLA 2"
-#define MSG_PREHEAT_PLA2                    "Predehrev PLA 3"
-#define MSG_PREHEAT_PLA012                  "Predehrev PLA All"
-#define MSG_PREHEAT_PLA_BEDONLY             "Predehrev PLA Bed"
-#define MSG_PREHEAT_PLA_SETTINGS            "Predehrev PLA conf"
-#define MSG_PREHEAT_ABS                     "Predehrev ABS"
-#define MSG_PREHEAT_ABS0                    "Predehrev ABS 1"
-#define MSG_PREHEAT_ABS1                    "Predehrev ABS 2"
-#define MSG_PREHEAT_ABS2                    "Predehrev ABS 3"
-#define MSG_PREHEAT_ABS012                  "Predehrev ABS All"
-#define MSG_PREHEAT_ABS_BEDONLY             "Predehrev ABS Bed"
-#define MSG_PREHEAT_ABS_SETTINGS            "Predehrev ABS conf"
 #define MSG_COOLDOWN                        "Zchladit"
 #define MSG_SWITCH_PS_ON                    "Vypnout zdroj"
 #define MSG_SWITCH_PS_OFF                   "Zapnout zdroj"
-#define MSG_EXTRUDE                         "Extrudovat"
-#define MSG_RETRACT                         "Retract"
 #define MSG_MOVE_AXIS                       "Posunout osu"
 #define MSG_MOVE_X                          "Posunout X"
 #define MSG_MOVE_Y                          "Posunout Y"
 #define MSG_MOVE_Z                          "Posunout Z"
 #define MSG_MOVE_E                          "Extruder"
-#define MSG_MOVE_E1                         "Extruder2"
-#define MSG_MOVE_E2                         "Extruder3"
-#define MSG_MOVE_01MM                       "Posunout o 0.1mm"
-#define MSG_MOVE_1MM                        "Posunout o 1mm"
-#define MSG_MOVE_10MM                       "Posunout o 10mm"
 #define MSG_SPEED                           "Rychlost"
 #define MSG_NOZZLE                          "Tryska"
 #define MSG_NOZZLE1                         "Tryska2"
@@ -60,44 +35,15 @@
 #define MSG_MIN                             " \002 Min"
 #define MSG_MAX                             " \002 Max"
 #define MSG_FACTOR                          " \002 Fact"
-#define MSG_AUTOTEMP                        "Autotemp"
-#define MSG_ON                              "On "
-#define MSG_OFF                             "Off"
-#define MSG_PID_P                           "PID-P"
-#define MSG_PID_I                           "PID-I"
-#define MSG_PID_D                           "PID-D"
-#define MSG_PID_C                           "PID-C"
-#define MSG_ACC                             "Accel"
-#define MSG_VXY_JERK                        "Vxy-jerk"
-#define MSG_VZ_JERK                         "Vz-jerk"
-#define MSG_VE_JERK                         "Ve-jerk"
-#define MSG_VMAX                            "Vmax "
-#define MSG_X                               "x"
-#define MSG_Y                               "y"
-#define MSG_Z                               "z"
-#define MSG_E                               "e"
-#define MSG_VMIN                            "Vmin"
-#define MSG_VTRAV_MIN                       "VTrav min"
-#define MSG_AMAX                            "Amax "
-#define MSG_A_RETRACT                       "A-retract"
-#define MSG_XSTEPS                          "Xsteps/mm"
-#define MSG_YSTEPS                          "Ysteps/mm"
-#define MSG_ZSTEPS                          "Zsteps/mm"
-#define MSG_ESTEPS                          "Esteps/mm"
 #define MSG_TEMPERATURE                     "Teplota"
 #define MSG_MOTION                          "Pohyb"
 #define MSG_VOLUMETRIC                      "Filament"
 #define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
-#define MSG_FILAMENT_SIZE_EXTRUDER_0        "Fil. Dia. 1"
-#define MSG_FILAMENT_SIZE_EXTRUDER_1        "Fil. Dia. 2"
-#define MSG_FILAMENT_SIZE_EXTRUDER_2        "Fil. Dia. 3"
-#define MSG_CONTRAST                        "LCD contrast"
 #define MSG_STORE_EPROM                     "Store memory"
 #define MSG_LOAD_EPROM                      "Ulozit pamet"
 #define MSG_RESTORE_FAILSAFE                "Obnovit vychozi"
 #define MSG_REFRESH                         "\xF8" "Obnovit"
 #define MSG_WATCH                           "Informace"
-#define MSG_PREPARE                         "Priprava"
 #define MSG_TUNE                            "Ladit"
 #define MSG_PAUSE_PRINT                     "Pozastavit tisk"
 #define MSG_RESUME_PRINT                    "Pokracovat"
@@ -111,24 +57,12 @@
 #define MSG_NO_MOVE                         "No move."
 #define MSG_KILLED                          "KILLED. "
 #define MSG_STOPPED                         "STOPPED. "
-#define MSG_CONTROL_RETRACT                 "Retract mm"
-#define MSG_CONTROL_RETRACT_SWAP            "Swap Re.mm"
-#define MSG_CONTROL_RETRACTF                "Retract  V"
-#define MSG_CONTROL_RETRACT_ZLIFT           "Hop mm"
-#define MSG_CONTROL_RETRACT_RECOVER         "UnRet +mm"
-#define MSG_CONTROL_RETRACT_RECOVER_SWAP    "S UnRet+mm"
-#define MSG_CONTROL_RETRACT_RECOVERF        "UnRet  V"
-#define MSG_AUTORETRACT                     "AutoRetr."
 #define MSG_FILAMENTCHANGE                  "Vymenit filament"
 #define MSG_INIT_SDCARD                     "Inic. SD"
 #define MSG_CNG_SDCARD                      "Vymenit SD"
-#define MSG_ZPROBE_OUT                      "Z probe out. bed"
-#define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
-#define MSG_ZPROBE_ZOFFSET                  "Z Offset"
 #define MSG_BABYSTEP_X                      "Babystep X"
 #define MSG_BABYSTEP_Y                      "Babystep Y"
 #define MSG_BABYSTEP_Z                      "Doladeni osy Z"
-#define MSG_ENDSTOP_ABORT                   "Endstop abort"
 #define MSG_ADJUSTZ							"Auto doladit Z ?"
 #define MSG_PICK_Z							"Vyberte vytisk"
 
@@ -139,7 +73,17 @@
 #define MSG_SETTINGS                         "Nastaveni"
 #define MSG_PREHEAT                         "Predehrev"
 #define MSG_UNLOAD_FILAMENT                 "Vyjmout filament"
-#define MSG_LOAD_FILAMENT                 "Zavest filament"
+#define MSG_LOAD_FILAMENT					"Zavest filament"
+#define MSG_LOAD_FILAMENT_1					"Zavest filament 1"
+#define MSG_LOAD_FILAMENT_2					"Zavest filament 2"
+#define MSG_LOAD_FILAMENT_3					"Zavest filament 3"
+#define MSG_LOAD_FILAMENT_4					"Zavest filament 4"
+#define MSG_UNLOAD_FILAMENT_1				"Vyjmout filam. 1"
+#define MSG_UNLOAD_FILAMENT_2				"Vyjmout filam. 2"
+#define MSG_UNLOAD_FILAMENT_3				"Vyjmout filam. 3"
+#define MSG_UNLOAD_FILAMENT_4				"Vyjmout filam. 4"
+#define MSG_UNLOAD_ALL						"Vyjmout vse"
+#define MSG_LOAD_ALL						"Zavest vse"
 
 #define MSG_RECTRACT                        "Rectract"
 #define MSG_ERROR                       "CHYBA:"
@@ -154,32 +98,23 @@
 #define MSG_PLEASE_WAIT			"Prosim cekejte"
 #define MSG_LOADING_COLOR		"Cisteni barvy"
 #define MSG_CHANGE_SUCCESS		"Zmena uspesna!"
-#define MSG_PRESS				"A stisknete tlacitko"
+#define MSG_PRESS				"a stisknete tlacitko"
 #define MSG_INSERT_FILAMENT		"Vlozte filament"
 #define MSG_CHANGING_FILAMENT	"Vymena filamentu!"
 
-#define MSG_SILENT_MODE_ON					"Mod       [tichy]"
-#define MSG_SILENT_MODE_OFF					"Mod  [vys. vykon]" 
+#define MSG_SILENT_MODE_ON					"Mod     [Stealth]"
+#define MSG_SILENT_MODE_OFF					"Mod      [Normal]" 
 #define MSG_REBOOT							"Restartujte tiskarnu"
 #define MSG_TAKE_EFFECT						" pro projeveni zmen"	
 
 #define MSG_Enqueing                        "enqueing \""
 #define MSG_POWERUP                         "PowerUp"
-#define MSG_EXTERNAL_RESET                  " External Reset"
-#define MSG_BROWNOUT_RESET                  " Brown out Reset"
-#define MSG_WATCHDOG_RESET                  " Watchdog Reset"
-#define MSG_SOFTWARE_RESET                  " Software Reset"
-#define MSG_AUTHOR                          " | Author: "
 #define MSG_CONFIGURATION_VER               " Last Updated: "
 #define MSG_FREE_MEMORY                     " Free Memory: "
 #define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
 #define MSG_OK                              "ok"
-#define MSG_FILE_SAVED                      "Done saving file."
-#define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
 #define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
 #define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
-#define MSG_FILE_PRINTED                    "Done printing file"
 #define MSG_BEGIN_FILE_LIST                 "Begin file list"
 #define MSG_END_FILE_LIST                   "End file list"
 #define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
@@ -194,23 +129,12 @@
 #define MSG_BED_HEATING                     "Zahrivani bed"
 #define MSG_BED_DONE                        "Bed OK."
 #define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
-#define MSG_COUNT_X                         " Count X: "
 #define MSG_ERR_KILLED                      "Printer halted. kill() called!"
 #define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
 #define MSG_RESEND                          "Resend: "
-#define MSG_UNKNOWN_COMMAND                 "Unknown command: \""
-#define MSG_ACTIVE_EXTRUDER                 "Active Extruder: "
-#define MSG_INVALID_EXTRUDER                "Invalid extruder"
-#define MSG_X_MIN                           "x_min: "
-#define MSG_X_MAX                           "x_max: "
-#define MSG_Y_MIN                           "y_min: "
-#define MSG_Y_MAX                           "y_max: "
-#define MSG_Z_MIN                           "z_min: "
-#define MSG_Z_MAX                           "z_max: "
 #define MSG_M119_REPORT                     "Reporting endstop status"
 #define MSG_ENDSTOP_HIT                     "TRIGGERED"
 #define MSG_ENDSTOP_OPEN                    "open"
-#define MSG_HOTEND_OFFSET                   "Hotend offsets:"
 
 #define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
 #define MSG_SD_INIT_FAIL                    "SD init fail"
@@ -220,7 +144,6 @@
 #define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
 #define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
 #define MSG_SD_FILE_OPENED                  "File opened: "
-#define MSG_SD_SIZE                         " Size: "
 #define MSG_SD_FILE_SELECTED                "File selected"
 #define MSG_SD_WRITE_TO_FILE                "Writing to file: "
 #define MSG_SD_PRINTING_BYTE                "SD printing byte "
@@ -231,14 +154,13 @@
 #define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
 #define MSG_ENDSTOPS_HIT                    "endstops hit: "
 #define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
-#define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
 #define MSG_BABYSTEPPING_X                  "Babystepping X"
 #define MSG_BABYSTEPPING_Y                  "Babystepping Y"
 #define MSG_BABYSTEPPING_Z                  "Dostavovani Z"
 #define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
 
 #define MSG_LANGUAGE_NAME					"Cestina"
-#define MSG_LANGUAGE_SELECT					"Vyber jazyka        "
+#define MSG_LANGUAGE_SELECT					"Vyber jazyka"
  #define MSG_PRUSA3D						"prusa3d.cz"
  #define MSG_PRUSA3D_FORUM					"forum.prusa3d.cz"
  #define MSG_PRUSA3D_HOWTO					"howto.prusa3d.cz"
@@ -259,6 +181,12 @@
 #define MSG_SELFTEST_ENDSTOP_NOTHIT			"Endstop not hit"
 #define MSG_SELFTEST_OK						"Self test OK"
 
+#define MSG_SELFTEST_FAN					"Test ventilatoru"
+#define MSG_SELFTEST_COOLING_FAN			"Predni tiskovy vent?"
+#define MSG_SELFTEST_EXTRUDER_FAN			"Levy vent na trysce?"
+#define MSG_SELFTEST_FAN_YES				"Toci se"
+#define MSG_SELFTEST_FAN_NO					"Netoci se"
+
 #define MSG_STATS_TOTALFILAMENT				"Filament celkem :"
 #define MSG_STATS_TOTALPRINTTIME			"Celkovy cas :"
 #define MSG_STATS_FILAMENTUSED				"Filament :  "
@@ -278,38 +206,149 @@
 #define MSG_STATISTICS						"Statistika  "
 #define MSG_USB_PRINTING					"Tisk z USB  "
 
-#define MSG_SHOW_END_STOPS					"Zobraz konc. spinace"
-#define MSG_CALIBRATE_BED					"Kalibrace X/Y"
-#define MSG_CALIBRATE_BED_RESET				"Reset X/Y kalibr."
+#define MSG_SHOW_END_STOPS					"Stav konc. spin."
+#define MSG_CALIBRATE_BED					"Kalibrace XYZ"
+#define MSG_CALIBRATE_BED_RESET				"Reset XYZ kalibr."
+
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP		"Kalibrace XYZ. Otacenim tlacitka posunte Z osu az k~hornimu dorazu. Potvrdte tlacitkem."
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z		"Kalibrace Z. Otacenim tlacitka posunte Z osu az k~hornimu dorazu. Potvrdte tlacitkem."
 
-#define MSG_MOVE_CARRIAGE_TO_THE_TOP		"Kalibrace X/Y. Posunte prosim Z osu az k~hornimu dorazu. Potvrdte tlacitkem."
 #define MSG_CONFIRM_NOZZLE_CLEAN			"Pro uspesnou kalibraci ocistete prosim tiskovou trysku. Potvrdte tlacitkem."
 #define MSG_CONFIRM_CARRIAGE_AT_THE_TOP		"Dojely oba Z voziky k~hornimu dorazu?"
 
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1	"Hledam kalibracni"
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2	"bod podlozky"
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE3	" z 4"
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1	"Zlepsuji presnost"
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2	"kalibracniho bodu"
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3	" z 9"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1	"Hledam kalibracni bod podlozky"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2	" z 4"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1	"Zlepsuji presnost kalibracniho bodu"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2	" z 4"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1	"Merim referencni vysku kalibracniho bodu"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2	" z 9"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION	"Iterace "
 
-#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"Kalibrace X/Y selhala. Kalibracni bod podlozky nenalezen."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED			"Kalibrace X/Y selhala. Nahlednete do manualu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"X/Y calibration ok. X/Y axes are perpendicular."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"Kalibrace X/Y v poradku. X/Y osy mirne zkosene."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"X/Y osy jsou silne zkosene. Zkoseni bude automaticky vyrovnano pri tisku."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"Kalibrace X/Y selhala. Levy predni bod moc vpredu. Srovnejte tiskarnu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR	"Kalibrace X/Y selhala. Pravy predni bod moc vpredu. Srovnejte tiskarnu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"Kalibrace X/Y selhala. Predni kalibracni body moc vpredu. Srovnejte tiskarnu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR	"Kalibrace X/Y nepresna. Levy predni bod moc vpredu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR	"Kalibrace X/Y nepresna. Pravy predni bod moc vpredu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR	"Kalibrace X/Y nepresna. Predni kalibracni body moc vpredu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"Kalibrace XYZ selhala. Kalibracni bod podlozky nenalezen."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED			"Kalibrace XYZ selhala. Nahlednete do manualu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"Kalibrace XYZ v poradku. X/Y osy jsou kolme. Gratuluji!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"Kalibrace XYZ v poradku. X/Y osy mirne zkosene. Dobra prace!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"Kalibrace XYZ v poradku. Zkoseni bude automaticky vyrovnano pri tisku."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"Kalibrace XYZ selhala. Levy predni bod moc vpredu. Srovnejte tiskarnu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR	"Kalibrace XYZ selhala. Pravy predni bod moc vpredu. Srovnejte tiskarnu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"Kalibrace XYZ selhala. Predni kalibracni body moc vpredu. Srovnejte tiskarnu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR	"Kalibrace XYZ nepresna. Levy predni bod moc vpredu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR	"Kalibrace XYZ nepresna. Pravy predni bod moc vpredu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR	"Kalibrace XYZ nepresna. Predni kalibracni body moc vpredu."
 
 #define MSG_BED_LEVELING_FAILED_POINT_LOW						"Kalibrace Z selhala. Sensor nesepnul. Znecistena tryska? Cekam na reset."
 #define MSG_BED_LEVELING_FAILED_POINT_HIGH						"Kalibrace Z selhala. Sensor sepnul prilis vysoko. Cekam na reset."
+#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED				"Kalibrace Z selhala. Sensor je odpojeny nebo preruseny kabel. Cekam na reset."
 
 #define MSG_NEW_FIRMWARE_AVAILABLE								"Vysla nova verze firmware:"
 #define MSG_NEW_FIRMWARE_PLEASE_UPGRADE							"Prosim aktualizujte."
-#define MSG_BABYSTEP_Z_NOT_SET                          		"Tiskarna nebyla jeste zkalibrovana. Spustte kalibracni G-kod a doladte Z."
+#define MSG_FOLLOW_CALIBRATION_FLOW                        		"Tiskarna nebyla jeste zkalibrovana. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Postup kalibrace."
+#define MSG_BABYSTEP_Z_NOT_SET                          		"Neni zkalibrovana vzdalenost trysky od tiskove podlozky. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Nastaveni prvni vrstvy."
+
+#define MSG_BED_CORRECTION_MENU									"Korekce podlozky"
+#define MSG_BED_CORRECTION_LEFT									"Vlevo  [um]"
+#define MSG_BED_CORRECTION_RIGHT								"Vpravo [um]"
+#define MSG_BED_CORRECTION_FRONT								"Vpredu [um]"
+#define MSG_BED_CORRECTION_REAR									"Vzadu  [um]"
+#define MSG_BED_CORRECTION_RESET								"Reset"
+
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
+#define MSG_MENU_CALIBRATION									"Kalibrace"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+
+#define MSG_LOOSE_PULLEY								"Uvolnena remenicka"
+#define MSG_FILAMENT_LOADING_T0							"Vlozte filament do extruderu 1. Potvrdte tlacitkem."
+#define MSG_FILAMENT_LOADING_T1							"Vlozte filament do extruderu 2. Potvrdte tlacitkem."
+#define MSG_FILAMENT_LOADING_T2							"Vlozte filament do extruderu 3. Potvrdte tlacitkem."
+#define MSG_FILAMENT_LOADING_T3							"Vlozte filament do extruderu 4. Potvrdte tlacitkem."
+#define MSG_CHANGE_EXTR									"Zmenit extruder"
+
+#define MSG_FIL_ADJUSTING								"Probiha srovnani filamentu. Prosim cekejte."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ				"Filamenty jsou srovnany. Pro uspesnou kalibraci prosim ocistete trysku. Po te potvrdte tlacitkem."
+#define MSG_CALIBRATE_E									"Kalibrovat E"
+#define MSG_E_CAL_KNOB									"Otacejte tlacitkem dokud znacka nedosahne tela extruderu. Potvrdte tlacitkem."
+#define MSG_MARK_FIL									"Oznacte filament 100 mm od tela extruderu a po te potvrdte tlacitkem."
+#define MSG_CLEAN_NOZZLE_E								"E kalibrace ukoncena. Prosim ocistete trysku. Po te potvrdte tlacitkem."
+#define MSG_WAITING_TEMP								"Cekani na zchladnuti trysky a podlozky."
+#define MSG_FILAMENT_CLEAN								"Je barva cista?" 
+#define MSG_UNLOADING_FILAMENT							"Vysouvam filament"
+
+#define MSG_PAPER										"Umistete list papiru na podlozku a udrzujte jej pod tryskou behem mereni prvnich 4 bodu. Pokud tryska zachyti papir, vypnete tiskarnu."
+
+#define MSG_FINISHING_MOVEMENTS							"Dokoncovani pohybu"
+#define MSG_PRINT_PAUSED								"Tisk pozastaven"
+#define MSG_RESUMING_PRINT								"Obnovovani tisku"
+#define MSG_PID_EXTRUDER								"PID kalibrace"
+#define MSG_SET_TEMPERATURE								"Nastavte teplotu:"
+#define MSG_PID_FINISHED								"PID kal. ukoncena"
+#define MSG_PID_RUNNING									"PID kal.           "
+
+#define MSG_CALIBRATE_PINDA								"Zkalibrovat"
+#define MSG_CALIBRATION_PINDA_MENU						"Teplot. kalibrace"
+#define MSG_PINDA_NOT_CALIBRATED						"Tiskarna nebyla teplotne zkalibrovana"
+#define MSG_PINDA_PREHEAT								"Nahrivani PINDA"
+#define MSG_TEMP_CALIBRATION							"Tepl. kal.          "
+#define MSG_TEMP_CALIBRATION_DONE						"Teplotni kalibrace dokoncena. Pokracujte stiskem tlacitka."
+#define MSG_TEMP_CALIBRATION_ON							"Tepl. kal.  [zap]"
+#define MSG_TEMP_CALIBRATION_OFF						"Tepl. kal.  [vyp]"
+#define MSG_PREPARE_FILAMENT							"Pripravte filament"
+#define MSG_ALL											"Vse"
+#define MSG_USED										"Pouzite behem tisku"
+#define MSG_CURRENT										"Pouze aktualni"
+#define MSG_CHOOSE_EXTRUDER								"Vyberte extruder:"
+#define MSG_EXTRUDER									"Extruder"
+#define MSG_EXTRUDER_1									"Extruder 1"
+#define MSG_EXTRUDER_2									"Extruder 2"
+#define MSG_EXTRUDER_3									"Extruder 3"
+#define MSG_EXTRUDER_4									"Extruder 4"
+
+#define MSG_WIZARD							"Wizard"
+#define MSG_WIZARD_WELCOME					"Dobry den, jsem vase tiskarna Original Prusa i3. Chcete abych Vas provedla kalibracnim procesem?"
+#define MSG_WIZARD_QUIT						"Wizarda muzete kdykoliv znovu spustit z menu Calibration -> Wizard"
+#define MSG_WIZARD_SELFTEST					"Nejdriv pomoci selftestu zkontoluji nejcastejsi chyby vznikajici pri sestaveni tiskarny."
+#define MSG_WIZARD_CALIBRATION_FAILED		"Prosim nahlednete do manualu a opravte problem. Po te obnovte Wizarda rebootovanim tiskarny."
+#define MSG_WIZARD_XYZ_CAL					"Nyni provedu xyz kalibraci. Zabere to priblizne 12 min."
+#define MSG_WIZARD_FILAMENT_LOADED			"Je filament zaveden?"
+#define MSG_WIZARD_Z_CAL					"Nyni provedu z kalibraci."
+#define MSG_WIZARD_WILL_PREHEAT				"Nyni predehreji trysku pro PLA."
+#define MSG_WIZARD_V2_CAL					"Nyni zkalibruji vzdalenost mezi koncem trysky a povrchem heatbedu."
+#define MSG_WIZARD_V2_CAL_2					"Zacnu tisknout linku a Vy budete postupne snizovat trysku otacenim tlacitka dokud nedosahnete optimalni vysky. Prohlednete si obrazky v nasi prirucce v kapitole Kalibrace"
+#define MSG_V2_CALIBRATION					"Kal. prvni vrstvy"
+#define MSG_WIZARD_DONE						"Vse je hotovo."
+#define MSG_WIZARD_LOAD_FILAMENT			"Prosim vlozte PLA filament do extruderu, po te stisknete tlacitko pro zavedeni filamentu."
+#define MSG_WIZARD_RERUN					"Spusteni Wizarda vymaze ulozene vysledky vsech kalibraci a spusti kalibracni proces od zacatku. Pokracovat?"
+#define MSG_WIZARD_REPEAT_V2_CAL			"Chcete opakovat posledni krok a pozmenit vzdalenost mezi tryskou a heatbed?"
+#define MSG_WIZARD_CLEAN_HEATBED			"Prosim ocistete heatbed a stisknete tlacitko."
+#define MSG_WIZARD_PLA_FILAMENT				"Je to PLA filament?"		
+#define MSG_WIZARD_INSERT_CORRECT_FILAMENT	"Prosim zavedte PLA filament a po te obnovte Wizarda stisknutim reset tlacitka."
+#define MSG_PLA_FILAMENT_LOADED				"Je PLA filament zaveden?"
+#define MSG_PLEASE_LOAD_PLA					"Nejdrive zavedte PLA filament prosim."
+#define MSG_WIZARD_HEATING					"Predehrivam trysku. Prosim cekejte."
+#define MSG_M117_V2_CALIBRATION				"M117 Kal. prvni vrstvy"
+
+#define MSG_DATE							"Datum:"
+#define MSG_XYZ_DETAILS						"Detaily XYZ kal."
+#define	MSG_Y_DISTANCE_FROM_MIN				"Y vzdalenost od min:"
+#define	MSG_LEFT							"Levy:"
+#define MSG_RIGHT							"Pravy:"
+#define MSG_MEASURED_SKEW					"Merene zkoseni:"
+#define MSG_SLIGHT_SKEW						"Lehke zkoseni:"
+#define MSG_SEVERE_SKEW						"Tezke zkoseni:"
 
-#endif // LANGUAGE_EN_H
+#define MSG_CALIBRATE_Z_AUTO				"Kalibruji Z"
+#define MSG_FSENSOR_OFF						"Fil. senzor [vyp]"
+#define MSG_FSENSOR_ON						"Fil. senzor [zap]" 
+#define MSG_CRASHDETECT_ON					"Crash det.  [zap]"
+#define MSG_CRASHDETECT_OFF					"Crash det.  [vyp]"
+#define MSG_FANS_CHECK_ON					"Kontr. vent.[zap]"
+#define MSG_FANS_CHECK_OFF					"Kontr. vent.[vyp]"
+#define MSG_RECOVERING_PRINT				"Obnovovani tisku    "
+#define MSG_SELFTEST_AXIS					"Osa"
+#define MSG_SELFTEST_AXIS_LENGTH			"Delka osy"
+#define MSG_STEEL_SHEET_CHECK				"Je tiskovy plat na heatbed?"
+#define MSG_REMOVE_STEEL_SHEET				"Odstrante tiskovy plat z heatbed prosim."
+#define MSG_PLACE_STEEL_SHEET				"Umistete prosim tiskovy plat na heatbed"
+#define MSG_RECOVER_PRINT					"Detekovan vypadek proudu.Obnovit tisk?"
+#define MSG_PRESS_TO_UNLOAD					"Pro vysunuti filamentu stisknete prosim tlacitko"	
+#define MSG_UNLOAD_SUCCESSFULL				"Opakovat vysunuti filamentu?"

+ 350 - 0
Firmware/language_de.h

@@ -0,0 +1,350 @@
++/**
+ + * German
+ + *
+ + * LCD Menu Messages
+ + * Please note these are limited to 17 characters!
+ + *
+ + */
+	+
+	+#define(length = 20) WELCOME_MSG              CUSTOM_MENDEL_NAME " bereit."
+	+ #define MSG_SD_INSERTED                     "SD eingesetzt"
+	+ #define MSG_SD_REMOVED                      "SD entfernt "
+	+ #define MSG_MAIN                            "Hauptmenue"
+	+ #define MSG_DISABLE_STEPPERS                "Motoren aus"
+	+ #define MSG_AUTO_HOME                       "Startposition"
+	+ #define MSG_SET_HOME_OFFSETS                "Abstand vom Ursprung einstellen"
+	+ #define MSG_SET_ORIGIN                      "Ursprung einstellen"
+	+ #define MSG_COOLDOWN                        "Abkuehlen"
+	+ #define MSG_SWITCH_PS_ON                    "Netzteil EIN"
+	+ #define MSG_SWITCH_PS_OFF                   "Netzteil AUS"
+	+ #define MSG_MOVE_AXIS                       "Achsbewegung"
+	+ #define MSG_MOVE_X                          "Bewege X"
+	+ #define MSG_MOVE_Y                          "Bewege Y"
+	+ #define MSG_MOVE_Z                          "Bewege Z"
+	+ #define MSG_MOVE_E                          "Extruder"
+	+ #define MSG_SPEED                           "Geschwindigkeit"
+	+ #define MSG_NOZZLE                          "Duese"
+	+ #define MSG_NOZZLE1                         "Duese2"
+	+ #define MSG_NOZZLE2                         "Duese3"
+	+ #define MSG_BED                             "Bett"
+	+ #define MSG_FAN_SPEED                       "Luefter-Tempo"
+	+ #define MSG_FLOW                            "Durchfluss"
+	+ #define MSG_FLOW0                           "Durchfluss 0"
+	+ #define MSG_FLOW1                           "Durchfluss 1"
+	+ #define MSG_FLOW2                           "Durchfluss 2"
+	+ #define MSG_CONTROL                         "Kontrolle"
+	+ #define MSG_MIN                             " \002 Min"
+	+ #define MSG_MAX                             " \002 Max"
+	+ #define MSG_FACTOR                          " \002 Fakt"
+	+ #define MSG_TEMPERATURE                     "Temperatur"
+	+ #define MSG_MOTION                          "Bewegung"
+	+ #define MSG_VOLUMETRIC                      "Filament"
+	+ #define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
+	+ #define MSG_STORE_EPROM                     "Abspeichern"
+	+ #define MSG_LOAD_EPROM                      "Lade Speicher"
+	+ #define MSG_RESTORE_FAILSAFE                "Standardwerte setzen"
+	+ #define MSG_REFRESH                         "\xF8" "Erneuern"
+	+ #define MSG_WATCH                           "Information"
+	+ #define MSG_TUNE                            "Feineinstellung"
+	+ #define MSG_PAUSE_PRINT                     "Druck unterbrech."
+	+ #define MSG_RESUME_PRINT                    "Fortsetzen"
+	+ #define MSG_STOP_PRINT                      "Druck abbrechen"
+	+ #define MSG_CARD_MENU                       "Drucken von SD"
+	+ #define MSG_NO_CARD                         "Keine SD Karte"
+	+ #define MSG_DWELL                           "Einen Moment bitte."
+	+ #define MSG_USERWAIT                        "Warte auf user..."
+	+ #define MSG_RESUMING                        "Druck fortgesetzt"
+	+ #define(length = 20) MSG_PRINT_ABORTED        "Druck abgebrochen"
+	+ #define MSG_NO_MOVE                         "Keine Bewegung."
+	+ #define MSG_KILLED                          "ABGEBROCHEN. "
+	+ #define MSG_STOPPED                         "GESTOPPT. "
+	+ #define MSG_FILAMENTCHANGE                  "Filament-Wechsel"
+	+ #define MSG_INIT_SDCARD                     "Init SD Karte"
+	+ #define MSG_CNG_SDCARD                      "Wechsel SD Karte"
+	+ #define MSG_BABYSTEP_X                      "Babystep X"
+	+ #define MSG_BABYSTEP_Y                      "Babystep Y"
+	+ #define MSG_BABYSTEP_Z                      "Z einstellen"
+	+ #define MSG_ADJUSTZ							"Auto Z einstellen?"
+	+ #define MSG_PICK_Z							"Waehle Abdruck"
+	+
+	+#define MSG_SETTINGS                        "Einstellungen"
+	+ #define MSG_PREHEAT                         "Vorwaermen"
+	+ #define MSG_UNLOAD_FILAMENT                 "Filament entladen"
+	+ #define MSG_LOAD_FILAMENT                 "Filament laden"
+	+
+	+#define MSG_RECTRACT                        "Retract"
+	+ #define MSG_ERROR                        "FEHLER:"
+	+ #define(length = 20) MSG_PREHEAT_NOZZLE       "Duese Vorwaermen"
+	+ #define MSG_SUPPORT "Support"
+	+ #define(length = 20) MSG_CORRECTLY			"Wechsel ok?"
+	+ #define MSG_YES					"Ja"
+	+ #define MSG_NO					"Nein"
+	+ #define(length = 19) MSG_NOT_LOADED 			"Fil. nicht geladen"
+	+ #define MSG_NOT_COLOR 				"Farbe unklar"
+	+ #define(length = 20) MSG_LOADING_FILAMENT		"Filament leadt"
+	+ #define(length = 20) MSG_PLEASE_WAIT			"Bitte warten"
+	+ #define MSG_LOADING_COLOR		"Lade Farbe"
+	+ #define MSG_CHANGE_SUCCESS		"Wechsel erfolgr.!"
+	+ #define(length = 20) MSG_PRESS				"und Knopf druecken"
+	+ #define(length = 20) MSG_INSERT_FILAMENT		"Filament einlegen"
+	+ #define(length = 20) MSG_CHANGING_FILAMENT	"Filament-Wechsel!"
+	+
+	+
+	+#define MSG_SILENT_MODE_ON					"Mode     [leise]"
+	+ #define MSG_SILENT_MODE_OFF					"Mode [Hohe Leist]"
+	+ #define(length = 20) MSG_REBOOT				"Zum Uebernehmen "
+	+ #define(length = 22) MSG_TAKE_EFFECT			"Drucker neu starten"
+	+
+	+#define MSG_Enqueing                        "enqueuing \"
+	+ #define MSG_POWERUP                         "Einschalten"
+	+ #define MSG_CONFIGURATION_VER               " Letztes Update:"
+	+ #define MSG_FREE_MEMORY                     " Freier Speicher: "
+	+ #define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
+	+ #define MSG_OK                              "ok"
+	+ #define MSG_ERR_CHECKSUM_MISMATCH           "Pruefsummenfehler, Letzte Zeile: " //Checksum Fehler, Letzte Zeile: "
+	+ #define MSG_ERR_NO_CHECKSUM                 "Keine Pruefsumme mit Zeilennummer, Letzte Zeile: " //Keine Checksum mit Zeilennummer, Letzte Zeile: "
+	+ #define MSG_BEGIN_FILE_LIST                 "Beginn Dateiliste"
+	+ #define MSG_END_FILE_LIST                   "Ende Dateiliste"
+	+ #define MSG_M104_INVALID_EXTRUDER           "M104 Falscher Extruder"
+	+ #define MSG_M105_INVALID_EXTRUDER           "M105 Falscher Extruder"
+	+ #define MSG_M200_INVALID_EXTRUDER           "M200 Falscher Extruder"
+	+ #define MSG_M218_INVALID_EXTRUDER           "M218 Falscher Extruder"
+	+ #define MSG_M221_INVALID_EXTRUDER           "M221 Falscher Extruder"
+	+ #define MSG_ERR_NO_THERMISTORS              "Keine Thermistoren - keine Temperatur"
+	+ #define MSG_M109_INVALID_EXTRUDER           "M109 Falscher Extruder"
+	+ #define MSG_HEATING                         "Aufwaermen"
+	+ #define(length = 20) MSG_HEATING_COMPLETE   "Aufwaermen OK"
+	+ #define MSG_BED_HEATING                     "Bett aufwaermen"
+	+ #define MSG_BED_DONE                        "Bett OK"
+	+ #define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
+	+ #define MSG_ERR_KILLED                      "Printer gestoppt. kill() aufgerufen!"
+	+ #define MSG_ERR_STOPPED                     "Drucker aufgrund von Fehlern gestoppt. Fehler beheben und mit M999 neu starten. (Temperatur wird zurueckgesetzt. Nach dem Neustart neu einstellen!)"
+	+ #define MSG_RESEND                          "Wiederholen: "
+	+ #define MSG_M119_REPORT                     "Statusbericht Endanschlag"
+	+ #define MSG_ENDSTOP_HIT                     "AUSGELOEST"
+	+ #define MSG_ENDSTOP_OPEN                    "offen"
+	+
+	+#define MSG_SD_CANT_OPEN_SUBDIR             "Kann Unterverz. nicht oeffnen"
+	+ #define MSG_SD_INIT_FAIL                    "SD Init fehlerhaft"
+	+ #define MSG_SD_VOL_INIT_FAIL                "Dateisystem Init fehlerhaft"
+	+ #define MSG_SD_OPENROOT_FAIL                "Zugriff auf Basisverzeichnis misslungen"
+	+ #define MSG_SD_CARD_OK                      "SD Karte ok"
+	+ #define MSG_SD_WORKDIR_FAIL                 "Oeffnen Arbeitsverzeichnis misslungen"
+	+ #define MSG_SD_OPEN_FILE_FAIL               "Fehler beim Oeffnen der Datei: "
+	+ #define MSG_SD_FILE_OPENED                  "Datei geoeffnet: "
+	+ #define MSG_SD_FILE_SELECTED                "Datei ausgewaehlt"
+	+ #define MSG_SD_WRITE_TO_FILE                "Schreiben der Datei: "
+	+ #define MSG_SD_PRINTING_BYTE                "SD printing byte "
+	+ #define MSG_SD_NOT_PRINTING                 "Kein SD Print"
+	+ #define MSG_SD_ERR_WRITE_TO_FILE            "Fehler beim Schreiben in Datei"
+	+ #define MSG_SD_CANT_ENTER_SUBDIR            "Zugangsproblem Unterverzeichnis: "
+	+ #define MSG_STEPPER_TOO_HIGH                "Schrittrate zu hoch"
+	+ #define MSG_ENDSTOPS_HIT                    "Endanschlag erreicht"
+	+ #define MSG_ERR_COLD_EXTRUDE_STOP           "Stopp, Extruder kalt!"
+	+ #define MSG_BABYSTEPPING_X                  "Babystepping X"
+	+ #define MSG_BABYSTEPPING_Y                  "Babystepping Y"
+	+ #define MSG_BABYSTEPPING_Z                  "Z wurde eingestellt"
+	+ #define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Menuestruktur fehlerhaft"
+	+
+	+#define MSG_LANGUAGE_NAME					"Deutsch"
+	+ #define MSG_LANGUAGE_SELECT					"Waehle Sprache"
+	+ #define MSG_PRUSA3D							"prusa3d.com"
+	+ #define MSG_PRUSA3D_FORUM					"forum.prusa3d.com"
+	+ #define MSG_PRUSA3D_HOWTO					"howto.prusa3d.com"
+	+
+	+#define MSG_SELFTEST_ERROR					"Selbtest Fehler!"
+	+ #define MSG_SELFTEST_PLEASECHECK			"Bitte pruefe:"
+	+ #define MSG_SELFTEST_NOTCONNECTED			"Nicht angeschlossen"
+	+ #define MSG_SELFTEST_HEATERTHERMISTOR		"Heater/Thermistor"
+	+ #define MSG_SELFTEST_BEDHEATER				"Bett / Heater"
+	+ #define MSG_SELFTEST_WIRINGERROR			"Verdrahtungfehler"
+	+ #define MSG_SELFTEST_ENDSTOPS				"Endschalter"
+	+ #define MSG_SELFTEST_MOTOR					"Motor"
+	+ #define MSG_SELFTEST_ENDSTOP				"Endstop"
+	+ #define MSG_SELFTEST_ENDSTOP_NOTHIT			"Ende nicht getrof."
+	+ #define MSG_SELFTEST_OK						"Selbsttest OK"
+	+ #define MSG_LOOSE_PULLEY					"Lose Riemenscheibe"
+	+
+	+#define MSG_SELFTEST_FAN					"Lueftertest"
++#define(length = 20) MSG_SELFTEST_COOLING_FAN			"Vorderer Luefter?"
++#define(length = 20) MSG_SELFTEST_EXTRUDER_FAN			"Linker Luefter?"
++#define MSG_SELFTEST_FAN_YES				"Dreht"
++#define MSG_SELFTEST_FAN_NO					"Dreht nicht"
++
++#define(length = 20) MSG_STATS_TOTALFILAMENT	"Gesamtfilament:"
++ #define(length = 20) MSG_STATS_TOTALPRINTTIME "Totale Druckzeit:"
++ #define(length = 20) MSG_STATS_FILAMENTUSED	"Filamentverbrauch:"
++ #define(length = 20) MSG_STATS_PRINTTIME		"Druckzeit:  "
++ #define(length = 20) MSG_SELFTEST_START				"Selbsttest start "
++ #define(length = 20) MSG_SELFTEST_CHECK_ENDSTOPS	"Pruefe Endschalter  "
++ #define(length = 20) MSG_SELFTEST_CHECK_HOTEND		"Pruefe Duese" 
++ #define(length = 20) MSG_SELFTEST_CHECK_X				"Pruefe X Achse    "
++ #define(length = 20) MSG_SELFTEST_CHECK_Y				"Pruefe Y Achse    "
++ #define(length = 20) MSG_SELFTEST_CHECK_Z				"Pruefe Z Achse    "
++ #define(length = 20) MSG_SELFTEST_CHECK_BED			"Pruefe Bett        "
++ #define(length = 20) MSG_SELFTEST_CHECK_ALLCORRECT	"Alles richtig    "
++ #define MSG_SELFTEST						"Selbsttest       "
++ #define(length = 20) MSG_SELFTEST_FAILED		"Selbsttest misslung."
++ #define MSG_STATISTICS						"Statistiken "
++ #define MSG_USB_PRINTING					"Drucken ueber USB"
++ #define MSG_HOMEYZ                          "Kalibrieren Z"
++ #define MSG_HOMEYZ_PROGRESS                 "Kalibriere Z"
++ #define MSG_HOMEYZ_DONE		                "Kalibrierung OK"
++
++#define MSG_SHOW_END_STOPS					"Endschalter Stat."
++ #define MSG_CALIBRATE_BED					"Kalibrierung XYZ"
++ #define MSG_CALIBRATE_BED_RESET				"Reset XYZ Kalibr."
++
+
++#define(length = 20, lines = 8) MSG_MOVE_CARRIAGE_TO_THE_TOP 	"Kalibrieren von XYZ. Drehen Sie den Knopf bis der obere Anschlag erreicht wird. Klicken Sie den Knopf wenn es ganz oben wird."
++ #define(length = 20, lines = 8) MSG_MOVE_CARRIAGE_TO_THE_TOP_Z 	"Kalibrieren von Z. Drehen Sie den Knopf bis der obere Anschlag erreicht wird. Klicken Sie den Knopf wenn es ganz oben wird."
++
+
++#define(length = 20, lines = 8) MSG_CONFIRM_NOZZLE_CLEAN			"Bitte entfernen Sie ueberstehendes Filament von der Duese. Klicken wenn sauber."
++ #define(length = 20, lines = 2) MSG_CONFIRM_CARRIAGE_AT_THE_TOP	"Ist der Schlitten ganz oben?"
++
++#define(length = 60) MSG_FIND_BED_OFFSET_AND_SKEW_LINE1		"Suchen Bett Kalibrierpunkt"
++ #define(length = 14) MSG_FIND_BED_OFFSET_AND_SKEW_LINE2		" von 4"
++ #define(length = 60) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1	"Verbesserung Bett Kalibrierpunkt"
++ #define(length = 14) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2	" von 4"
++ #define(length = 60) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1	"Messen der Referenzhoehe des Kalibrierpunktes"
++ #define(length = 14) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2	" von 9"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION	"Iteration "
++
++#define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"XYZ-Kalibrierung fehlgeschlagen. Bett-Kalibrierpunkt nicht gefunden."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED				"XYZ-Kalibrierung fehlgeschlagen. Bitte schauen Sie in das Handbuch."
+
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"XYZ-Kalibrierung ok. X/Y-Achsen sind senkrecht zueinander. Glueckwunsch!"
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"XYZ Kalibrierung in Ordnung. X/Y Achsen sind etwas schief."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME					"XYZ Kalibrierung in Ordnung. Schiefheit wird automatisch korrigiert."
+
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"XYZ-Kalibrierung fehlgeschlagen. Linker vorderer Kalibrierpunkt ist zu weit vorne."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR		"XYZ-Kalibrierung fehlgeschlagen. Rechter vorderer Kalibrierpunkt ist zu weit vorne."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"XYZ-Kalibrierung fehlgeschlagen. Vordere Kalibrierpunkte sind zu weit vorne."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR		"XYZ-Kalibrierung ungenau. Linker vorderer Kalibrierpunkt ist zu weit vorne."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR		"XYZ-Kalibrierung ungenau. Rechter vorderer Kalibrierpunkt ist zu weit vorne."
++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR		"XYZ-Kalibrierung ungenau. Vordere Kalibrierpunkte sind zu weit vorne."
++
++#define(length = 20, lines = 4) MSG_BED_LEVELING_FAILED_POINT_LOW						"Z-Kal. fehlgeschlg. Sensor nicht ausgeloest. Schmutzige Duese? Warte auf Reset"
+
++ #define(length = 20, lines = 4) MSG_BED_LEVELING_FAILED_POINT_HIGH						"Z-Kalibrierung fehlgeschlg. Sensor zu hoch ausgeloest. Warte auf Reset."
++ #define(length = 20, lines = 4) MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED				"Z-Kalibrierung fehlgeschlg. Sensor nicht angeschlossen. Warte auf Reset."
++
++#define(length = 20, lines = 2) MSG_NEW_FIRMWARE_AVAILABLE								"Neue Firmware Version verfuegbar:"
++ #define(length = 20) MSG_NEW_FIRMWARE_PLEASE_UPGRADE									"Bitte aktualisieren."
++
++ #define(length = 20, lines = 8) MSG_FOLLOW_CALIBRATION_FLOW								"Der Drucker wurde noch nicht kalibriert. Bitte folgen Sie das Handbuch, Kapitel First steps, Abschnitt Calibration flow."
++ #define(length = 20, lines = 12) MSG_BABYSTEP_Z_NOT_SET									"Der Abstand zwischen der Spitze der Duese und der Bett ist noch nicht eingestellt. Bitte folgen Sie dem Handbuch, First steps, section First layer calibration."
++ 
++
+
++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T0							"Filament in extruder 1 einlegen. Klicken wenn fertig."
++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T1							"Filament in extruder 2 einlegen. Klicken wenn fertig."
++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T2							"Filament in extruder 3 einlegen. Klicken wenn fertig."
++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T3							"Filament in extruder 4 einlegen. Klicken wenn fertig."
++ #define(length = 20, lines = 1) MSG_CHANGE_EXTR									"Wechsel extruder"
++
+
+
++ #define(length = 20, lines = 4) MSG_FIL_ADJUSTING								"Filament positionieren. Bitte warten."
++ #define(length = 20, lines = 8) MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ			"Filamente sind jetzt eingestellt. Bitte reinigen Sie die Duese zur Kalibrierung. Klicken wenn fertig."
++ 
++ #define(length = 20, lines = 1) MSG_CALIBRATE_E						"Kalibriere E"
++//#define(length=20, lines=1)				"Reset E Cal."
+
++#define(length = 20, lines = 8) MSG_E_CAL_KNOB						"Knopf drehen bis die Filamentmarkierung erreicht ist. Klicken wenn fertig."
++
++//#define(length=20, lines=1) MSG_FARM_CARD_MENU					"Farm mode print"
+
++#define(length = 20, lines = 8) MSG_MARK_FIL						"Filament 100mm vom Extrudergehaeuse markieren. Klicken wenn Fertig."
++ #define(length = 20, lines = 8) MSG_CLEAN_NOZZLE_E				"E-Kalibrierung beendet. Bitte reinigen Sie die Duese. Klicken wenn fertig."
++ #define(length = 20, lines = 3) MSG_WAITING_TEMP				"Warten auf Abkuehlung von Heater und Bett."
+
++ #define(length = 20, lines = 2) MSG_FILAMENT_CLEAN				"Ist Farbe rein?"
++ #define(lenght = 20, lines = 1) MSG_UNLOADING_FILAMENT			"Filament auswerfen"
++ #define(length = 20, lines = 8) MSG_PAPER						"Legen ein Blatt Papier unter die Duese waehrend der Kalibrierung der ersten 4 Punkte. Wenn die Duese das Papier einklemmt, Drucker sofort ausschalten"
++
++#define MSG_BED_CORRECTION_MENU									"Bett level Korrekt"
+
++ #define MSG_BED_CORRECTION_LEFT									"Links     [um]"
++ #define MSG_BED_CORRECTION_RIGHT								"Rechts    [um]"
++ #define MSG_BED_CORRECTION_FRONT								"Vorne     [um]"
++ #define MSG_BED_CORRECTION_REAR									"Hinten    [um]"
++ #define MSG_BED_CORRECTION_RESET								"Ruecksetzen"
++
++#define MSG_MESH_BED_LEVELING									"Mesh Bett Leveling"
++ #define MSG_MENU_CALIBRATION									"Kalibrierung"
+
++ #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD Karte [normal]"
++ #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD Karte [FlashAir]"
+
+#define MSG_FINISHING_MOVEMENTS							"Bewegung beenden"
+#define MSG_PRINT_PAUSED								"Druck pausiert"
+#define MSG_RESUMING_PRINT								"Druck weitergehen"
+#define MSG_PID_EXTRUDER								"PID Kalibrierung"
+#define MSG_SET_TEMPERATURE								"Temp. einsetzen"
+#define MSG_PID_FINISHED								"PID Kalib. fertig"
+#define MSG_PID_RUNNING									"PID Kalib."
+
+#define MSG_CALIBRATE_PINDA								"Kalibrieren"
+#define MSG_CALIBRATION_PINDA_MENU						"Temp. kalibrieren"
+#define MSG_PINDA_NOT_CALIBRATED						"Temperatur wurde nicht kalibriert"
+#define MSG_PINDA_PREHEAT								"PINDA erwaermen"
+#define MSG_TEMP_CALIBRATION							"Temp Kalib.         "
+#define MSG_TEMP_CALIBRATION_DONE						"Temp. Kalibrierung fertig. Klicken um weiter zu gehen."
+#define MSG_TEMP_CALIBRATION_ON							"Temp. Kal. [ON]"
+#define MSG_TEMP_CALIBRATION_OFF						"Temp. Kal. [OFF]"
+
+#define MSG_LOAD_ALL									"Alle laden"
+#define MSG_LOAD_FILAMENT_1								"Filament 1 laden"
+#define MSG_LOAD_FILAMENT_2								"Filament 2 laden"
+#define MSG_LOAD_FILAMENT_3								"Filament 3 laden"
+#define MSG_LOAD_FILAMENT_4								"Filament 4 laden"
+#define MSG_UNLOAD_FILAMENT_1							"Filam. 1 entladen"
+#define MSG_UNLOAD_FILAMENT_2							"Filam. 2 entladen"
+#define MSG_UNLOAD_FILAMENT_3							"Filam. 3 entladen"
+#define MSG_UNLOAD_FILAMENT_4							"Filam. 4 entladen"
+#define MSG_UNLOAD_ALL									"Alles entladen"
+#define MSG_PREPARE_FILAMENT							"Filam. bereithalten"
+#define MSG_ALL											"Alle"
+#define MSG_USED										"Beim Druck benutzte"
+#define MSG_CURRENT										"Aktuelles"
+#define MSG_CHOOSE_EXTRUDER								"Waehlen Sie Extruder"
+#define MSG_EXTRUDER									"Extruder"
+#define MSG_EXTRUDER_1									"Extruder 1"
+#define MSG_EXTRUDER_2									"Extruder 2"
+#define MSG_EXTRUDER_3									"Extruder 3"
+#define MSG_EXTRUDER_4									"Extruder 4"
+
+#define MSG_WIZARD							"Wizard"
+#define MSG_WIZARD_WELCOME					"Hallo, ich bin dein Original Prusa i3 Drucker. Moechten Sie meine Hilfe durch den Setup-Prozess?"
+#define MSG_WIZARD_QUIT						"Sie koennen immer den Asistenten im Menu neu aufrufen: Kalibrierung -> Assistant"
+#define MSG_WIZARD_SELFTEST					"Zunaechst fuehre ich den Selbsttest durch um die haeufigsten Probleme bei der Aufbau zu ueberpruefen."
+#define MSG_WIZARD_CALIBRATION_FAILED		"Bitte ueberpruefen Sie unser Handbuch und beheben Sie das Problem. Fahren Sie dann mit dem Assistenten fort, indem Sie den Drucker neu starten."
+#define MSG_WIZARD_XYZ_CAL					"Ich werde jetzt die XYZ-Kalibrierung durchfuehren. Es wird ca. 12 Minuten dauern"
+#define MSG_WIZARD_FILAMENT_LOADED			"Ist das Filament geladen?"
+#define MSG_WIZARD_Z_CAL					"Ich werde jetzt die Z Kalibrierung durchfuehren."
+#define MSG_WIZARD_WILL_PREHEAT				"Jetzt werde ich die Duese fuer PLA vorheizen. "
+#define MSG_WIZARD_V2_CAL					"Jetzt werde ich den Abstand zwischen Duesenspitze und Druckbett kalibrieren."
+#define MSG_WIZARD_V2_CAL_2					"Ich werde jetzt erste Linie drucken. Waehrend des Druckes koennen Sie die Duese allmaehlich senken indem Sie den Knopf drehen, bis Sie die optimale Hoehe erreichen. Ueberpruefen Sie die Bilder in unserem Handbuch im Kapitel Kalibrierung"
+#define MSG_V2_CALIBRATION					"Erste-Schicht Kal"
+#define MSG_WIZARD_DONE						"Alles wurde getan. Viel Spass beim Drucken!"
+#define MSG_WIZARD_LOAD_FILAMENT			"Fuehren Sie bitte PLA Filament in den Extruder und bestaetigen Sie den Knopf um es zu laden."
+#define MSG_WIZARD_RERUN					"Der laufende Assistent loescht die aktuelle Kalibrierergebnisse und wird von Anfang an beginnen. Fortsetzen?"
+#define MSG_WIZARD_REPEAT_V2_CAL			"Moechten Sie den letzten Schritt wiederholen um den Abstand zwischen Duese und Druckbett neu einzustellen?"
+#define MSG_WIZARD_CLEAN_HEATBED			"Bitte reinigen Sie das Heizbett und druecken Sie dann den Knopf."
+#define MSG_WIZARD_PLA_FILAMENT				"Ist es wirklich PLA Filament?"
+#define MSG_WIZARD_INSERT_CORRECT_FILAMENT	"Bitte laden Sie PLA-Filament und fahren Sie mit dem Assistenten fort, indem Sie den Drucker neu starten."
+#define MSG_PLA_FILAMENT_LOADED				"Ist PLA Filament geladen?"
+#define MSG_PLEASE_LOAD_PLA					"Bitte laden Sie zuerst PLA Filament."
+#define MSG_WIZARD_HEATING					"Vorheizen der Duese. Bitte warten."
+#define MSG_M117_V2_CALIBRATION				"M117 Erste-Schicht Kal."
+
+#define MSG_DATE							"Datum"
+#define MSG_XYZ_DETAILS						"XYZ Kal. Details"
+#define	MSG_Y_DISTANCE_FROM_MIN				"Y Entfernung vom min"
+#define	MSG_LEFT							"Links:"
+#define MSG_RIGHT							"Rechts:"
+#define MSG_MEASURED_SKEW					"Schraeglauf:"
+#define MSG_SLIGHT_SKEW						"Leichter Schr.:"
+#define MSG_SEVERE_SKEW						"Schwerer Schr.:"

+ 219 - 158
Firmware/language_en.h

@@ -5,53 +5,29 @@
  * Please note these are limited to 17 characters!
  *
  */
-#ifndef LANGUAGE_EN_H
-#define LANGUAGE_EN_H
 
-#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " ready."
+#define(length=20) WELCOME_MSG              CUSTOM_MENDEL_NAME " ready."
 #define MSG_SD_INSERTED                     "Card inserted"
 #define MSG_SD_REMOVED                      "Card removed"
 #define MSG_MAIN                            "Main"
-#define MSG_AUTOSTART                       "Autostart"
 #define MSG_DISABLE_STEPPERS                "Disable steppers"
 #define MSG_AUTO_HOME                       "Auto home"
 #define MSG_SET_HOME_OFFSETS                "Set home offsets"
 #define MSG_SET_ORIGIN                      "Set origin"
-#define MSG_PREHEAT_PLA                     "Preheat PLA"
-#define MSG_PREHEAT_PLA0                    "Preheat PLA 1"
-#define MSG_PREHEAT_PLA1                    "Preheat PLA 2"
-#define MSG_PREHEAT_PLA2                    "Preheat PLA 3"
-#define MSG_PREHEAT_PLA012                  "Preheat PLA All"
-#define MSG_PREHEAT_PLA_BEDONLY             "Preheat PLA Bed"
-#define MSG_PREHEAT_PLA_SETTINGS            "Preheat PLA conf"
-#define MSG_PREHEAT_ABS                     "Preheat ABS"
-#define MSG_PREHEAT_ABS0                    "Preheat ABS 1"
-#define MSG_PREHEAT_ABS1                    "Preheat ABS 2"
-#define MSG_PREHEAT_ABS2                    "Preheat ABS 3"
-#define MSG_PREHEAT_ABS012                  "Preheat ABS All"
-#define MSG_PREHEAT_ABS_BEDONLY             "Preheat ABS Bed"
-#define MSG_PREHEAT_ABS_SETTINGS            "Preheat ABS conf"
 #define MSG_COOLDOWN                        "Cooldown"
 #define MSG_SWITCH_PS_ON                    "Switch power on"
 #define MSG_SWITCH_PS_OFF                   "Switch power off"
-#define MSG_EXTRUDE                         "Extrude"
-#define MSG_RETRACT                         "Retract"
 #define MSG_MOVE_AXIS                       "Move axis"
 #define MSG_MOVE_X                          "Move X"
 #define MSG_MOVE_Y                          "Move Y"
 #define MSG_MOVE_Z                          "Move Z"
 #define MSG_MOVE_E                          "Extruder"
-#define MSG_MOVE_E1                         "Extruder2"
-#define MSG_MOVE_E2                         "Extruder3"
-#define MSG_MOVE_01MM                       "Move 0.1mm"
-#define MSG_MOVE_1MM                        "Move 1mm"
-#define MSG_MOVE_10MM                       "Move 10mm"
 #define MSG_SPEED                           "Speed"
 #define MSG_NOZZLE                          "Nozzle"
 #define MSG_NOZZLE1                         "Nozzle2"
 #define MSG_NOZZLE2                         "Nozzle3"
 #define MSG_BED                             "Bed"
-#define MSG_FAN_SPEED                       "Fan speed"
+#define(length=14) MSG_FAN_SPEED                       "Fan speed"
 #define MSG_FLOW                            "Flow"
 #define MSG_FLOW0                           "Flow 0"
 #define MSG_FLOW1                           "Flow 1"
@@ -60,44 +36,15 @@
 #define MSG_MIN                             " \002 Min"
 #define MSG_MAX                             " \002 Max"
 #define MSG_FACTOR                          " \002 Fact"
-#define MSG_AUTOTEMP                        "Autotemp"
-#define MSG_ON                              "On "
-#define MSG_OFF                             "Off"
-#define MSG_PID_P                           "PID-P"
-#define MSG_PID_I                           "PID-I"
-#define MSG_PID_D                           "PID-D"
-#define MSG_PID_C                           "PID-C"
-#define MSG_ACC                             "Accel"
-#define MSG_VXY_JERK                        "Vxy-jerk"
-#define MSG_VZ_JERK                         "Vz-jerk"
-#define MSG_VE_JERK                         "Ve-jerk"
-#define MSG_VMAX                            "Vmax "
-#define MSG_X                               "x"
-#define MSG_Y                               "y"
-#define MSG_Z                               "z"
-#define MSG_E                               "e"
-#define MSG_VMIN                            "Vmin"
-#define MSG_VTRAV_MIN                       "VTrav min"
-#define MSG_AMAX                            "Amax "
-#define MSG_A_RETRACT                       "A-retract"
-#define MSG_XSTEPS                          "Xsteps/mm"
-#define MSG_YSTEPS                          "Ysteps/mm"
-#define MSG_ZSTEPS                          "Zsteps/mm"
-#define MSG_ESTEPS                          "Esteps/mm"
 #define MSG_TEMPERATURE                     "Temperature"
 #define MSG_MOTION                          "Motion"
 #define MSG_VOLUMETRIC                      "Filament"
 #define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
-#define MSG_FILAMENT_SIZE_EXTRUDER_0        "Fil. Dia. 1"
-#define MSG_FILAMENT_SIZE_EXTRUDER_1        "Fil. Dia. 2"
-#define MSG_FILAMENT_SIZE_EXTRUDER_2        "Fil. Dia. 3"
-#define MSG_CONTRAST                        "LCD contrast"
 #define MSG_STORE_EPROM                     "Store memory"
 #define MSG_LOAD_EPROM                      "Load memory"
 #define MSG_RESTORE_FAILSAFE                "Restore failsafe"
 #define MSG_REFRESH                         "\xF8" "Refresh"
 #define MSG_WATCH                           "Info screen"
-#define MSG_PREPARE                         "Prepare"
 #define MSG_TUNE                            "Tune"
 #define MSG_PAUSE_PRINT                     "Pause print"
 #define MSG_RESUME_PRINT                    "Resume print"
@@ -107,76 +54,66 @@
 #define MSG_DWELL                           "Sleep..."
 #define MSG_USERWAIT                        "Wait for user..."
 #define MSG_RESUMING                        "Resuming print"
-#define MSG_PRINT_ABORTED                   "Print aborted"
+#define(length=20) MSG_PRINT_ABORTED        "Print aborted"
 #define MSG_NO_MOVE                         "No move."
 #define MSG_KILLED                          "KILLED. "
 #define MSG_STOPPED                         "STOPPED. "
-#define MSG_CONTROL_RETRACT                 "Retract mm"
-#define MSG_CONTROL_RETRACT_SWAP            "Swap Re.mm"
-#define MSG_CONTROL_RETRACTF                "Retract  V"
-#define MSG_CONTROL_RETRACT_ZLIFT           "Hop mm"
-#define MSG_CONTROL_RETRACT_RECOVER         "UnRet +mm"
-#define MSG_CONTROL_RETRACT_RECOVER_SWAP    "S UnRet+mm"
-#define MSG_CONTROL_RETRACT_RECOVERF        "UnRet  V"
-#define MSG_AUTORETRACT                     "AutoRetr."
 #define MSG_FILAMENTCHANGE                  "Change filament"
 #define MSG_INIT_SDCARD                     "Init. SD card"
 #define MSG_CNG_SDCARD                      "Change SD card"
-#define MSG_ZPROBE_OUT                      "Z probe out. bed"
-#define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
-#define MSG_ZPROBE_ZOFFSET                  "Z Offset"
 #define MSG_BABYSTEP_X                      "Babystep X"
 #define MSG_BABYSTEP_Y                      "Babystep Y"
 #define MSG_BABYSTEP_Z                      "Live adjust Z"
-#define MSG_ENDSTOP_ABORT                   "Endstop abort"
-#define MSG_ADJUSTZ							"Auto adjust Z ?"
+#define MSG_ADJUSTZ							"Auto adjust Z?"
 #define MSG_PICK_Z							"Pick print"
 
 #define MSG_SETTINGS                         "Settings"
 #define MSG_PREHEAT                         "Preheat"
-#define MSG_UNLOAD_FILAMENT                 "Unload filament"
-#define MSG_LOAD_FILAMENT                 "Load filament"
+#define(length=17) MSG_UNLOAD_FILAMENT               "Unload filament"
+#define(length=17) MSG_LOAD_FILAMENT                 "Load filament"
+#define(length=17) MSG_LOAD_FILAMENT_1				"Load filament 1"
+#define(length=17) MSG_LOAD_FILAMENT_2				"Load filament 2"
+#define(length=17) MSG_LOAD_FILAMENT_3				"Load filament 3"
+#define(length=17) MSG_LOAD_FILAMENT_4				"Load filament 4"
+#define(length=17) MSG_UNLOAD_FILAMENT_1				"Unload filament 1"
+#define(length=17) MSG_UNLOAD_FILAMENT_2				"Unload filament 2"
+#define(length=17) MSG_UNLOAD_FILAMENT_3				"Unload filament 3"
+#define(length=17) MSG_UNLOAD_FILAMENT_4				"Unload filament 4"
+#define MSG_UNLOAD_ALL						"Unload all"
+#define MSG_LOAD_ALL						"Load all"
+
 
 #define MSG_RECTRACT                        "Rectract"
 #define MSG_ERROR                        "ERROR:"
-#define MSG_PREHEAT_NOZZLE                       "Preheat the nozzle!"
+#define(length=20) MSG_PREHEAT_NOZZLE       "Preheat the nozzle!"
 #define MSG_SUPPORT "Support"
-#define MSG_CORRECTLY			"Changed correctly?"
+#define(length=20) MSG_CORRECTLY			"Changed correctly?"
 #define MSG_YES					"Yes"
 #define MSG_NO					"No"
-#define MSG_NOT_LOADED 			"Filament not loaded"
+#define(length=19) MSG_NOT_LOADED 			"Filament not loaded"
 #define MSG_NOT_COLOR 			"Color not clear"
-#define MSG_LOADING_FILAMENT	"Loading filament"
-#define MSG_PLEASE_WAIT			"Please wait"
+#define(length=20) MSG_LOADING_FILAMENT		"Loading filament"
+#define(length=20) MSG_PLEASE_WAIT			"Please wait"
 #define MSG_LOADING_COLOR		"Loading color"
 #define MSG_CHANGE_SUCCESS		"Change success!"
-#define MSG_PRESS				"And press the knob"
-#define MSG_INSERT_FILAMENT		"Insert filament"
-#define MSG_CHANGING_FILAMENT	"Changing filament!"
+#define(length=20) MSG_PRESS				"and press the knob"
+#define(length=20) MSG_INSERT_FILAMENT		"Insert filament"
+#define(length=20) MSG_CHANGING_FILAMENT	"Changing filament!"
 
 
-#define MSG_SILENT_MODE_ON					"Mode     [silent]"
-#define MSG_SILENT_MODE_OFF					"Mode [high power]" 
-#define MSG_REBOOT							"Reboot the printer"
-#define MSG_TAKE_EFFECT						" for take effect"											
+#define MSG_SILENT_MODE_ON					"Mode    [Stealth]"
+#define MSG_SILENT_MODE_OFF					"Mode     [Normal]" 
+#define(length=20) MSG_REBOOT				"Reboot the printer"
+#define(length=20) MSG_TAKE_EFFECT			" for take effect"											
 
 #define MSG_Enqueing                        "enqueing \""
 #define MSG_POWERUP                         "PowerUp"
-#define MSG_EXTERNAL_RESET                  " External Reset"
-#define MSG_BROWNOUT_RESET                  " Brown out Reset"
-#define MSG_WATCHDOG_RESET                  " Watchdog Reset"
-#define MSG_SOFTWARE_RESET                  " Software Reset"
-#define MSG_AUTHOR                          " | Author: "
 #define MSG_CONFIGURATION_VER               " Last Updated: "
 #define MSG_FREE_MEMORY                     " Free Memory: "
 #define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
 #define MSG_OK                              "ok"
-#define MSG_FILE_SAVED                      "Done saving file."
-#define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
 #define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
 #define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
-#define MSG_FILE_PRINTED                    "Done printing file"
 #define MSG_BEGIN_FILE_LIST                 "Begin file list"
 #define MSG_END_FILE_LIST                   "End file list"
 #define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
@@ -187,27 +124,16 @@
 #define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
 #define MSG_M109_INVALID_EXTRUDER           "M109 Invalid extruder "
 #define MSG_HEATING                         "Heating"
-#define MSG_HEATING_COMPLETE                "Heating done."
+#define(length=20) MSG_HEATING_COMPLETE     "Heating done."
 #define MSG_BED_HEATING                     "Bed Heating"
 #define MSG_BED_DONE                        "Bed done"
 #define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
-#define MSG_COUNT_X                         " Count X: "
 #define MSG_ERR_KILLED                      "Printer halted. kill() called!"
 #define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
 #define MSG_RESEND                          "Resend: "
-#define MSG_UNKNOWN_COMMAND                 "Unknown command: \""
-#define MSG_ACTIVE_EXTRUDER                 "Active Extruder: "
-#define MSG_INVALID_EXTRUDER                "Invalid extruder"
-#define MSG_X_MIN                           "x_min: "
-#define MSG_X_MAX                           "x_max: "
-#define MSG_Y_MIN                           "y_min: "
-#define MSG_Y_MAX                           "y_max: "
-#define MSG_Z_MIN                           "z_min: "
-#define MSG_Z_MAX                           "z_max: "
 #define MSG_M119_REPORT                     "Reporting endstop status"
 #define MSG_ENDSTOP_HIT                     "TRIGGERED"
 #define MSG_ENDSTOP_OPEN                    "open"
-#define MSG_HOTEND_OFFSET                   "Hotend offsets:"
 
 #define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
 #define MSG_SD_INIT_FAIL                    "SD init fail"
@@ -217,7 +143,6 @@
 #define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
 #define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
 #define MSG_SD_FILE_OPENED                  "File opened: "
-#define MSG_SD_SIZE                         " Size: "
 #define MSG_SD_FILE_SELECTED                "File selected"
 #define MSG_SD_WRITE_TO_FILE                "Writing to file: "
 #define MSG_SD_PRINTING_BYTE                "SD printing byte "
@@ -228,14 +153,13 @@
 #define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
 #define MSG_ENDSTOPS_HIT                    "endstops hit: "
 #define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
-#define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
 #define MSG_BABYSTEPPING_X                  "Babystepping X"
 #define MSG_BABYSTEPPING_Y                  "Babystepping Y"
-#define MSG_BABYSTEPPING_Z                  "Adjusting Z"
+#define(length=20) MSG_BABYSTEPPING_Z       "Adjusting Z"
 #define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
 
 #define MSG_LANGUAGE_NAME					"English"
-#define MSG_LANGUAGE_SELECT					"Select language     "
+#define MSG_LANGUAGE_SELECT					"Select language"
 #define MSG_PRUSA3D							"prusa3d.com"
 #define MSG_PRUSA3D_FORUM					"forum.prusa3d.com"
 #define MSG_PRUSA3D_HOWTO					"howto.prusa3d.com"
@@ -249,61 +173,198 @@
 #define MSG_SELFTEST_ENDSTOPS				"Endstops"
 #define MSG_SELFTEST_MOTOR					"Motor"
 #define MSG_SELFTEST_ENDSTOP				"Endstop"
-#define MSG_SELFTEST_ENDSTOP_NOTHIT			"Endstop not hit"
+
+#define(length=20,lines=1) MSG_SELFTEST_ENDSTOP_NOTHIT			"Endstop not hit"
 #define MSG_SELFTEST_OK						"Self test OK"
-#define MSG_STATS_TOTALFILAMENT				"Total filament :"
-#define MSG_STATS_TOTALPRINTTIME			"Total print time :"
-#define MSG_STATS_FILAMENTUSED				"Filament used:  "
-#define MSG_STATS_PRINTTIME					"Print time:  "
-#define MSG_SELFTEST_START					"Self test start  "
-#define MSG_SELFTEST_CHECK_ENDSTOPS			"Checking endstops"
-#define MSG_SELFTEST_CHECK_HOTEND			"Checking hotend  "  
-#define MSG_SELFTEST_CHECK_X				"Checking X axis  "
-#define MSG_SELFTEST_CHECK_Y				"Checking Y axis  "
-#define MSG_SELFTEST_CHECK_Z				"Checking Z axis  "
-#define MSG_SELFTEST_CHECK_BED				"Checking bed     "
-#define MSG_SELFTEST_CHECK_ALLCORRECT		"All correct      "
+#define(length=20,lines=1) MSG_LOOSE_PULLEY					"Loose pulley"
+
+#define(length=20) MSG_SELFTEST_FAN					"Fan test"
+#define(length=20) MSG_SELFTEST_COOLING_FAN			"Front print fan?"
+#define(length=20) MSG_SELFTEST_EXTRUDER_FAN		"Left hotend fan?"
+#define(length=19) MSG_SELFTEST_FAN_YES				"Spinning"
+#define(length=19) MSG_SELFTEST_FAN_NO				"Not spinning"
+
+#define(length=20) MSG_STATS_TOTALFILAMENT	"Total filament :"
+#define(length=20) MSG_STATS_TOTALPRINTTIME "Total print time :"
+#define(length=20) MSG_STATS_FILAMENTUSED	"Filament used:  "
+#define(length=20) MSG_STATS_PRINTTIME		"Print time:  "
+#define(length=20) MSG_SELFTEST_START				"Self test start  "
+#define(length=20) MSG_SELFTEST_CHECK_ENDSTOPS		"Checking endstops"
+#define(length=20) MSG_SELFTEST_CHECK_HOTEND		"Checking hotend  "  
+#define(length=20) MSG_SELFTEST_CHECK_X				"Checking X axis  "
+#define(length=20) MSG_SELFTEST_CHECK_Y				"Checking Y axis  "
+#define(length=20) MSG_SELFTEST_CHECK_Z				"Checking Z axis  "
+#define(length=20) MSG_SELFTEST_CHECK_BED			"Checking bed     "
+#define(length=20) MSG_SELFTEST_CHECK_ALLCORRECT	"All correct      "
 #define MSG_SELFTEST						"Selftest         "
-#define MSG_SELFTEST_FAILED					"Selftest failed  "
+#define(length=20) MSG_SELFTEST_FAILED		"Selftest failed  "
 #define MSG_STATISTICS						"Statistics  "
 #define MSG_USB_PRINTING					"USB printing  "
 #define MSG_HOMEYZ                          "Calibrate Z"
 #define MSG_HOMEYZ_PROGRESS                 "Calibrating Z"
 #define MSG_HOMEYZ_DONE		                "Calibration done"
 
-#define MSG_SHOW_END_STOPS					"Show end stops"
-#define MSG_CALIBRATE_BED					"Calibrate X/Y"
-#define MSG_CALIBRATE_BED_RESET				"Reset X/Y calibr."
-
-#define MSG_MOVE_CARRIAGE_TO_THE_TOP 		"Calibrating X/Y. Move Z carriage up to the end stoppers. Click when done."
-#define MSG_CONFIRM_NOZZLE_CLEAN			"Please clean the nozzle for calibration. Click when done."
-#define MSG_CONFIRM_CARRIAGE_AT_THE_TOP		"Are left and right Z~carriages all up?"
-
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1	"Searching bed"
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2	"calibration point"
-#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE3	" of 4"
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1	"Improving bed"
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2	"calibration point"
-#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3	" of 9"
-
-#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"X/Y calibration failed. Bed calibration point was not found."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED			"X/Y calibration failed. Please consult the manual."
-#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"X/Y calibration ok. X/Y axes are perpendicular."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"X/Y calibration all right. X/Y axes are slightly skewed."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"X/Y skewed severly. Skew will be corrected automatically."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"X/Y calibration failed. Left front calibration point not reachable."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR	"X/Y calibration failed. Right front calibration point not reachable."
-#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"X/Y calibration failed. Front calibration points not reachable."
-#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR	"X/Y calibration compromised. Left front calibration point not reachable."
-#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR	"X/Y calibration compromised. Right front calibration point not reachable."
-#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR	"X/Y calibration compromised. Front calibration points not reachable."
-
-#define MSG_BED_LEVELING_FAILED_POINT_LOW						"Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset."
-#define MSG_BED_LEVELING_FAILED_POINT_HIGH						"Bed leveling failed. Sensor triggered too high. Waiting for reset."
-
-#define MSG_NEW_FIRMWARE_AVAILABLE								"New firmware version available:"
-#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE							"Please upgrade."
-
-#define MSG_BABYSTEP_Z_NOT_SET									"Printer has not been calibrated yet. Run calibration G-code to adjust Z height."
-
-#endif // LANGUAGE_EN_H
+#define(length=17,lines=1) MSG_SHOW_END_STOPS					"Show end stops"
+#define MSG_CALIBRATE_BED					"Calibrate XYZ"
+#define MSG_CALIBRATE_BED_RESET				"Reset XYZ calibr."
+
+#define(length=20,lines=8) MSG_MOVE_CARRIAGE_TO_THE_TOP 	"Calibrating XYZ. Rotate the knob to move the Z carriage up to the end stoppers. Click when done."
+#define(length=20,lines=8) MSG_MOVE_CARRIAGE_TO_THE_TOP_Z 	"Calibrating Z. Rotate the knob to move the Z carriage up to the end stoppers. Click when done."
+
+#define(length=20,lines=8) MSG_CONFIRM_NOZZLE_CLEAN			"Please clean the nozzle for calibration. Click when done."
+#define(length=20,lines=2) MSG_CONFIRM_CARRIAGE_AT_THE_TOP	"Are left and right Z~carriages all up?"
+
+#define(length=60) MSG_FIND_BED_OFFSET_AND_SKEW_LINE1		"Searching bed calibration point"
+#define(length=14) MSG_FIND_BED_OFFSET_AND_SKEW_LINE2		" of 4"
+#define(length=60) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1	"Improving bed calibration point"
+#define(length=14) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2	" of 4"
+#define(length=60) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1	"Measuring reference height of calibration point"
+#define(length=14) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2	" of 9"
+#define(length=20) MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION	"Iteration "
+
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"XYZ calibration failed. Bed calibration point was not found."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED				"XYZ calibration failed. Please consult the manual."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"XYZ calibration ok. X/Y axes are perpendicular. Congratulations!"
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"XYZ calibration all right. X/Y axes are slightly skewed. Good job!"
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"XYZ calibration all right. Skew will be corrected automatically."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"XYZ calibration failed. Left front calibration point not reachable."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR		"XYZ calibration failed. Right front calibration point not reachable."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"XYZ calibration failed. Front calibration points not reachable."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR		"XYZ calibration compromised. Left front calibration point not reachable."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR	"XYZ calibration compromised. Right front calibration point not reachable."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR		"XYZ calibration compromised. Front calibration points not reachable."
+
+#define(length=20,lines=4) MSG_BED_LEVELING_FAILED_POINT_LOW						"Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset."
+#define(length=20,lines=4) MSG_BED_LEVELING_FAILED_POINT_HIGH						"Bed leveling failed. Sensor triggered too high. Waiting for reset."
+#define(length=20,lines=4) MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED				"Bed leveling failed. Sensor disconnected or cable broken. Waiting for reset."
+
+#define(length=20,lines=2) MSG_NEW_FIRMWARE_AVAILABLE								"New firmware version available:"
+#define(length=20) MSG_NEW_FIRMWARE_PLEASE_UPGRADE									"Please upgrade."
+
+#define(length=20,lines=8) MSG_FOLLOW_CALIBRATION_FLOW								"Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow."
+#define(length=20,lines=12) MSG_BABYSTEP_Z_NOT_SET									"Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration."
+
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T0							"Insert filament into extruder 1. Click when done."
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T1							"Insert filament into extruder 2. Click when done."
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T2							"Insert filament into extruder 3. Click when done."
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T3							"Insert filament into extruder 4. Click when done."
+#define(length=20, lines=1) MSG_CHANGE_EXTR									"Change extruder"
+
+#define(length=20, lines=4) MSG_FIL_ADJUSTING								"Adjusting filaments. Please wait."
+#define(length=20,lines=8) MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ			"Filaments are now adjusted. Please clean the nozzle for calibration. Click when done."
+#define(length=20, lines=4) MSG_STACK_ERROR						"Error - static memory has been overwritten"
+#define(length=20, lines=1) MSG_CALIBRATE_E						"Calibrate E"
+//#define(length=20, lines=1) MSG_RESET_CALIBRATE_E				"Reset E Cal."
+#define(length=20, lines=8) MSG_E_CAL_KNOB						"Rotate knob until mark reaches extruder body. Click when done."
+
+//#define(length=20, lines=1) MSG_FARM_CARD_MENU					"Farm mode print"
+#define(length=20, lines=8) MSG_MARK_FIL						"Mark filament 100mm from extruder body. Click when done."
+#define(length=20, lines=8) MSG_CLEAN_NOZZLE_E				"E calibration finished. Please clean the nozzle. Click when done."
+#define(length=20, lines=3) MSG_WAITING_TEMP				"Waiting for nozzle and bed cooling"
+#define(length=20, lines=2) MSG_FILAMENT_CLEAN				"Is color clear?"
+#define(lenght=18, lines=1) MSG_UNLOADING_FILAMENT			"Unloading filament"
+#define(length=20, lines=8) MSG_PAPER						"Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately."
+
+#define MSG_BED_CORRECTION_MENU									"Bed level correct"
+#define(length=14,lines=1) MSG_BED_CORRECTION_LEFT								"Left side [um]"
+#define(length=14,lines=1) MSG_BED_CORRECTION_RIGHT								"Right side[um]"
+#define(length=14,lines=1) MSG_BED_CORRECTION_FRONT								"Front side[um]"
+#define(length=14,lines=1) MSG_BED_CORRECTION_REAR								"Rear side [um]"
+#define MSG_BED_CORRECTION_RESET								"Reset"
+
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
+#define MSG_MENU_CALIBRATION									"Calibration"
+#define(length=19, lines=1) MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define(length=19, lines=1) MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+#define(length=20, lines=1) MSG_PRINTER_DISCONNECTED			"Printer disconnected"
+#define(length=20, lines=1) MSG_FINISHING_MOVEMENTS				"Finishing movements"
+#define(length=20, lines=1) MSG_PRINT_PAUSED					"Print paused"
+#define(length=20, lines=1) MSG_RESUMING_PRINT					"Resuming print"
+#define(length=17, lines=1) MSG_PID_EXTRUDER					"PID calibration"
+#define(length=19, lines=1) MSG_SET_TEMPERATURE					"Set temperature:"
+#define(length=20, lines=1) MSG_PID_FINISHED					"PID cal. finished"
+#define(length=20, lines=1) MSG_PID_RUNNING						"PID cal.           "
+
+#define(length=17, lines=1) MSG_CALIBRATE_PINDA					"Calibrate"
+#define(length=17, lines=1) MSG_CALIBRATION_PINDA_MENU			"Temp. calibration"
+#define(length=20, lines=4) MSG_PINDA_NOT_CALIBRATED			"Temperature calibration has not been run yet"
+#define(length=20, lines=1) MSG_PINDA_PREHEAT					"PINDA Heating"
+#define(length=20, lines=1) MSG_TEMP_CALIBRATION				"Temp. cal.          "
+#define(length=20, lines=4) MSG_TEMP_CALIBRATION_DONE			"Temperature calibration is finished. Click to continue."
+#define(length=20, lines=1) MSG_TEMP_CALIBRATION_ON				"Temp. cal.   [on]"
+#define(length=20, lines=1) MSG_TEMP_CALIBRATION_OFF			"Temp. cal.  [off]"
+#define(length=20, lines=1) MSG_PREPARE_FILAMENT				"Prepare new filament"
+#define(length=19, lines=1) MSG_ALL								"All"
+#define(length=19, lines=1) MSG_USED							"Used during print"
+#define(length=19, lines=1) MSG_CURRENT							"Current"
+#define(length=20, lines=1)	MSG_CHOOSE_EXTRUDER					"Choose extruder:"
+#define(length=17, lines=1) MSG_EXTRUDER						"Extruder"
+#define(length=17, lines=1) MSG_EXTRUDER_1						"Extruder 1"
+#define(length=17, lines=1) MSG_EXTRUDER_2						"Extruder 2"
+#define(length=17, lines=1) MSG_EXTRUDER_3						"Extruder 3"
+#define(length=17, lines=1) MSG_EXTRUDER_4						"Extruder 4"
+
+//Wizard messages which has tranlsations
+
+#define(length=17, lines=1) MSG_WIZARD							"Wizard"
+#define(length=20, lines=7)	MSG_WIZARD_WELCOME					"Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"
+#define(length=20, lines=8) MSG_WIZARD_QUIT						"You can always resume the Wizard from Calibration -> Wizard."
+#define(length=20, lines=8) MSG_WIZARD_SELFTEST					"First, I will run the selftest to check most common assembly problems."
+#define(length=20, lines=8) MSG_WIZARD_CALIBRATION_FAILED		"Please check our handbook and fix the problem. Then resume the Wizard by rebooting the printer."
+#define(length=20, lines=8) MSG_WIZARD_XYZ_CAL					"I will run xyz calibration now. It will take approx. 12 mins."
+#define(length=20, lines=2) MSG_WIZARD_FILAMENT_LOADED			"Is filament loaded?"
+#define(length=20, lines=8) MSG_WIZARD_Z_CAL					"I will run z calibration now."
+#define(length=20, lines=4) MSG_WIZARD_WILL_PREHEAT				"Now I will preheat nozzle for PLA."
+#define(length=20, lines=3) MSG_WIZARD_HEATING					"Preheating nozzle. Please wait."
+#define(lenght=20, lines=8) MSG_WIZARD_V2_CAL					"Now I will calibrate distance between tip of the nozzle and heatbed surface."
+#define(lenght=20, lines=12) MSG_WIZARD_V2_CAL_2				"I will start to print line and you will gradually lower the nozzle by rotating the knob, until you reach optimal height. Check the pictures in our handbook in chapter Calibration."
+#define(lenght=17, lines=1) MSG_V2_CALIBRATION					"First layer cal."
+#define(lenght=20, lines=8) MSG_WIZARD_DONE						"All is done. Happy printing!"
+#define(lenght=20, lines=8) MSG_WIZARD_LOAD_FILAMENT			"Please insert PLA filament to the extruder, then press knob to load it."
+#define(lenght=20, lines=7) MSG_WIZARD_RERUN					"Running Wizard will delete current calibration results and start from the beginning. Continue?"
+#define(lenght=20, lines=7) MSG_WIZARD_REPEAT_V2_CAL			"Do you want to repeat last step to readjust distance between nozzle and heatbed?"
+#define(lenght=20, lines=8) MSG_WIZARD_CLEAN_HEATBED			"Please clean heatbed and then press the knob."
+#define(lenght=20, lines=2) MSG_WIZARD_PLA_FILAMENT				"Is it PLA filament?"
+#define(lenght=20, lines=8) MSG_WIZARD_INSERT_CORRECT_FILAMENT	"Please load PLA filament and then resume Wizard by rebooting the printer."
+#define(lenght=20, lines=2) MSG_PLA_FILAMENT_LOADED				"Is PLA filament loaded?"
+#define(lenght=20, lines=4) MSG_PLEASE_LOAD_PLA					"Please load PLA filament first."
+#define(length=25, lines=1) MSG_M117_V2_CALIBRATION				"M117 First layer cal."
+
+#define(length=17, lines=1) MSG_DATE							"Date:"
+#define(length=19, lines=1) MSG_XYZ_DETAILS						"XYZ cal. details"
+#define(length=20, lines=1)	MSG_Y_DISTANCE_FROM_MIN				"Y distance from min:"
+#define(length=12, lines=1)	MSG_LEFT							"Left:"
+#define(length=12, lines=1) MSG_RIGHT							"Right:"
+#define(length=15, lines=1) MSG_MEASURED_SKEW					"Measured skew:"
+#define(length=15, lines=1) MSG_SLIGHT_SKEW						"Slight skew:"
+#define(length=15, lines=1) MSG_SEVERE_SKEW						"Severe skew:"
+
+//messages bellow has no translation yet
+
+#define MSG_CRASHDETECT_OFF										"Crash det.  [off]"
+#define MSG_CRASHDETECT_ON										"Crash det.   [on]"
+#define MSG_FSENSOR_OFF											"Fil. sensor [off]"
+#define MSG_FSENSOR_ON											"Fil. sensor  [on]"
+
+#define(length=20, lines=4) MSG_PLACE_STEEL_SHEET				"Please place steel sheet on heatbed."
+#define(length=20, lines=4) MSG_REMOVE_STEEL_SHEET				"Please remove steel sheet from heatbed."
+#define(length=20, lines=2) MSG_CALIBRATE_Z_AUTO				"Calibrating Z"
+#define(length=20, lines=2) MSG_STEEL_SHEET_CHECK				"Is steel sheet on heatbed?"
+
+#define MSG_SELFTEST_AXIS					"Axis"
+#define MSG_SELFTEST_AXIS_LENGTH			"Axis length"
+
+#define(length=20, lines=2) MSG_RECOVER_PRINT					"Blackout occurred. Recover print?"
+#define(length=20, lines=1) MSG_RECOVERING_PRINT				"Recovering print    "
+#define(length=20, lines=2) MSG_CRASH_DETECTED					"Crash detected. Continue printing?"
+
+#define(length=15, lines=1) MSG_INFO_EXTRUDER				"Extruder info"
+
+#define(length=11, lines=1) MSG_INFO_NOZZLE_FAN				"Nozzle FAN:"
+#define(length=11, lines=1) MSG_INFO_PRINT_FAN				"Print FAN: "
+#define(length=11, lines=1) MSG_INFO_FILAMENT_XDIFF				"Fil. Xd:"
+#define(length=11, lines=1) MSG_INFO_FILAMENT_YDIFF				"Fil. Ydiff:"
+#define(length=17, lines=1) MSG_FANS_CHECK_ON					"Fans check   [on]"
+#define(length=17, lines=1) MSG_FANS_CHECK_OFF					"Fans check  [off]"
+#define(length=20, lines=4) MSG_PRESS_TO_UNLOAD					"Please press the knob to unload filament"
+#define(length=20, lines=2) MSG_UNLOAD_SUCCESSFULL				"Repeat unloading filament?"

+ 189 - 143
Firmware/language_es.h

@@ -5,11 +5,9 @@
  * Please note these are limited to 17 characters!
  *
  */
-#ifndef LANGUAGE_ES_H
-#define LANGUAGE_ES_H
 
-#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " lista"
-#define MSG_SD_INSERTED                     "Tarjeta colocada"
+#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " prep."
+#define MSG_SD_INSERTED                     "Tarjeta insertada"
 #define MSG_SD_REMOVED                      "Tarjeta retirada"
 #define MSG_MAIN                            "Menu principal"
 #define MSG_DISABLE_STEPPERS                "Apagar motores"
@@ -19,11 +17,11 @@
 #define MSG_MOVE_X                          "Mover X"
 #define MSG_MOVE_Y                          "Mover Y"
 #define MSG_MOVE_Z                          "Mover Z"
-#define MSG_MOVE_E                          "Extrusor"
+#define MSG_MOVE_E                          "Extruir"
 #define MSG_SPEED                           "Velocidad"
-#define MSG_NOZZLE                          "Fusor"
-#define MSG_BED                             "Base"
-#define MSG_FAN_SPEED                       "Ventilador"
+#define MSG_NOZZLE                          "Nozzle"
+#define MSG_BED                             "Heatbed"
+#define MSG_FAN_SPEED                       "Velocidad Vent."
 #define MSG_FLOW                            "Flujo"
 #define MSG_TEMPERATURE                     "Temperatura"
 #define MSG_WATCH                           "Monitorizar"
@@ -31,49 +29,49 @@
 #define MSG_PAUSE_PRINT                     "Pausar impresion"
 #define MSG_RESUME_PRINT                    "Reanudar impres."
 #define MSG_STOP_PRINT                      "Detener impresion"
-#define MSG_CARD_MENU                       "Menu de SD"
+#define MSG_CARD_MENU                       "Menu tarjeta SD"
 #define MSG_NO_CARD                         "No hay tarjeta SD"
-#define MSG_DWELL                           "Reposo..."
+#define MSG_DWELL                           "En espera"
 #define MSG_USERWAIT                        "Esperando ordenes"
-#define MSG_RESUMING                        "Resumiendo impre."
-#define MSG_PRINT_ABORTED                   "Print aborted"
+#define MSG_RESUMING                        "Resumiendo impresion"
+#define MSG_PRINT_ABORTED                   "Impresion cancelada" 
 #define MSG_NO_MOVE                         "Sin movimiento"
-#define MSG_KILLED                          "PARADA DE EMERG."
+#define MSG_KILLED                          "PARADA DE EMERGENCIA"
 #define MSG_STOPPED                         "PARADA"
 #define MSG_FILAMENTCHANGE                  "Cambiar filamento"
-#define MSG_BABYSTEP_Z                      "Micropaso Z"
-#define MSG_ADJUSTZ							"Auto Micropaso Z?"
-#define MSG_PICK_Z							"Vyberte vytisk"
+#define MSG_BABYSTEP_Z                      "Micropaso Eje Z"
+#define MSG_ADJUSTZ			    "Ajustar Eje Z"			
+#define MSG_PICK_Z			    "Esc. Modelo Adecuado"
 
-#define MSG_SETTINGS                        "Ajuste"
+#define MSG_SETTINGS                        "Configuracion"
 #define MSG_PREHEAT                         "Precalentar"
-#define MSG_UNLOAD_FILAMENT                 "Sacar filamento"
-#define MSG_LOAD_FILAMENT					"Introducir filamento"
+#define MSG_UNLOAD_FILAMENT                 "Soltar filamento"
+#define MSG_LOAD_FILAMENT		    "Introducir filam."
 #define MSG_ERROR							"ERROR:"
-#define MSG_PREHEAT_NOZZLE                  "Precal. extrusor!"
-#define MSG_SUPPORT							"Support"
-#define MSG_CORRECTLY						"Cambiado correc.?"
+#define MSG_PREHEAT_NOZZLE                  "Precalentar extrusor"
+#define MSG_SUPPORT			    "Soporte"
+#define MSG_CORRECTLY			    "Cambiado correct.?"
 #define MSG_YES								"Si"
 #define MSG_NO								"No"
-#define MSG_NOT_LOADED 						"Fil. no cargado"
-#define MSG_NOT_COLOR 						"Color no claro"
-#define MSG_LOADING_FILAMENT				"Cargando fil."
-#define MSG_PLEASE_WAIT						"Espera"
-#define MSG_LOADING_COLOR					"Cargando color"
-#define MSG_CHANGE_SUCCESS					"Cambiar bien!"
-#define MSG_PRESS							"Y pulse el mando"
-#define MSG_INSERT_FILAMENT					"Inserta filamento"
-#define MSG_CHANGING_FILAMENT				"Cambiando fil.!"
-#define MSG_SILENT_MODE_ON					"Modo     [silencio]"
-#define MSG_SILENT_MODE_OFF					"Modo [mas fuerza]" 
-#define MSG_REBOOT							"Reiniciar la imp."
-#define MSG_TAKE_EFFECT						"para tomar efecto"											
+#define MSG_NOT_LOADED 			    "Fil. no introducido"
+#define MSG_NOT_COLOR 			    "Color no homogeneo"
+#define MSG_LOADING_FILAMENT		    "Introduciendo filam."
+#define MSG_PLEASE_WAIT			    "Por Favor Esperar"
+#define MSG_LOADING_COLOR                   "Cambiando color" 
+#define MSG_CHANGE_SUCCESS		    "Cambio correcto"
+#define MSG_PRESS			    "Haz clic"
+#define MSG_INSERT_FILAMENT		    "Introducir filamento"
+#define MSG_CHANGING_FILAMENT		    "Cambiando filamento"
+#define MSG_SILENT_MODE_ON					"Modo   [silencio]"
+#define MSG_SILENT_MODE_OFF		    "Modo [rend.pleno]" 
+#define MSG_REBOOT			    "Reiniciar impresora"
+#define MSG_TAKE_EFFECT			    " para aplicar cambios" 
 #define MSG_HEATING                         "Calentando..."
-#define MSG_HEATING_COMPLETE                "Calentando listo."
-#define MSG_BED_HEATING                     "Base Calentando"
-#define MSG_BED_DONE                        "Base listo."
+#define MSG_HEATING_COMPLETE                "Calentamiento final."
+#define MSG_BED_HEATING                     "Calentando Base"
+#define MSG_BED_DONE                        "Base preparada"
 #define MSG_LANGUAGE_NAME					"Espanol"
-#define MSG_LANGUAGE_SELECT					"Cambia la lengua "
+#define MSG_LANGUAGE_SELECT		    "Cambiae el idioma"
 #define MSG_PRUSA3D							"prusa3d.com"
 #define MSG_PRUSA3D_FORUM					"forum.prusa3d.com"
 #define MSG_PRUSA3D_HOWTO					"howto.prusa3d.com"
@@ -83,21 +81,12 @@
 
 #define MSG_Enqueing                        "enqueing \""
 #define MSG_POWERUP                         "PowerUp"
-#define MSG_EXTERNAL_RESET                  " External Reset"
-#define MSG_BROWNOUT_RESET                  " Brown out Reset"
-#define MSG_WATCHDOG_RESET                  " Watchdog Reset"
-#define MSG_SOFTWARE_RESET                  " Software Reset"
-#define MSG_AUTHOR                          " | Author: "
 #define MSG_CONFIGURATION_VER               " Last Updated: "
 #define MSG_FREE_MEMORY                     " Free Memory: "
 #define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
 #define MSG_OK                              "ok"
-#define MSG_FILE_SAVED                      "Done saving file."
-#define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
 #define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
 #define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
-#define MSG_FILE_PRINTED                    "Done printing file"
 #define MSG_BEGIN_FILE_LIST                 "Begin file list"
 #define MSG_END_FILE_LIST                   "End file list"
 #define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
@@ -108,23 +97,12 @@
 #define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
 #define MSG_M109_INVALID_EXTRUDER           "M109 Invalid extruder "
 #define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
-#define MSG_COUNT_X                         " Count X: "
 #define MSG_ERR_KILLED                      "Printer halted. kill() called!"
 #define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
 #define MSG_RESEND                          "Resend: "
-#define MSG_UNKNOWN_COMMAND                 "Unknown command: \""
-#define MSG_ACTIVE_EXTRUDER                 "Active Extruder: "
-#define MSG_INVALID_EXTRUDER                "Invalid extruder"
-#define MSG_X_MIN                           "x_min: "
-#define MSG_X_MAX                           "x_max: "
-#define MSG_Y_MIN                           "y_min: "
-#define MSG_Y_MAX                           "y_max: "
-#define MSG_Z_MIN                           "z_min: "
-#define MSG_Z_MAX                           "z_max: "
 #define MSG_M119_REPORT                     "Reporting endstop status"
 #define MSG_ENDSTOP_HIT                     "TRIGGERED"
 #define MSG_ENDSTOP_OPEN                    "open"
-#define MSG_HOTEND_OFFSET                   "Hotend offsets:"
 #define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
 #define MSG_SD_INIT_FAIL                    "SD init fail"
 #define MSG_SD_VOL_INIT_FAIL                "volume.init failed"
@@ -133,7 +111,6 @@
 #define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
 #define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
 #define MSG_SD_FILE_OPENED                  "File opened: "
-#define MSG_SD_SIZE                         " Size: "
 #define MSG_SD_FILE_SELECTED                "File selected"
 #define MSG_SD_WRITE_TO_FILE                "Writing to file: "
 #define MSG_SD_PRINTING_BYTE                "SD printing byte "
@@ -143,61 +120,14 @@
 #define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
 #define MSG_ENDSTOPS_HIT                    "endstops hit: "
 #define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
-#define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
 #define MSG_BABYSTEPPING_X                  "Babystepping X"
 #define MSG_BABYSTEPPING_Y                  "Babystepping Y"
-#define MSG_BABYSTEPPING_Z                  "Adjusting Z"
+#define MSG_BABYSTEPPING_Z                  "Ajustar Z"
 #define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
 #define MSG_SET_HOME_OFFSETS                "Set home offsets"
 #define MSG_SET_ORIGIN                      "Set origin"
-#define MSG_PREHEAT_PLA                     "Preheat PLA"
-#define MSG_PREHEAT_PLA0                    "Preheat PLA 1"
-#define MSG_PREHEAT_PLA1                    "Preheat PLA 2"
-#define MSG_PREHEAT_PLA2                    "Preheat PLA 3"
-#define MSG_PREHEAT_PLA012                  "Preheat PLA All"
-#define MSG_PREHEAT_PLA_BEDONLY             "Preheat PLA Bed"
-#define MSG_PREHEAT_PLA_SETTINGS            "Preheat PLA conf"
-#define MSG_PREHEAT_ABS                     "Preheat ABS"
-#define MSG_PREHEAT_ABS0                    "Preheat ABS 1"
-#define MSG_PREHEAT_ABS1                    "Preheat ABS 2"
-#define MSG_PREHEAT_ABS2                    "Preheat ABS 3"
-#define MSG_PREHEAT_ABS012                  "Preheat ABS All"
-#define MSG_PREHEAT_ABS_BEDONLY             "Preheat ABS Bed"
-#define MSG_PREHEAT_ABS_SETTINGS            "Preheat ABS conf"
 #define MSG_SWITCH_PS_ON                    "Switch power on"
 #define MSG_SWITCH_PS_OFF                   "Switch power off"
-#define MSG_AUTOTEMP                        "Autotemp"
-#define MSG_ON                              "On "
-#define MSG_OFF                             "Off"
-#define MSG_PID_P                           "PID-P"
-#define MSG_PID_I                           "PID-I"
-#define MSG_PID_D                           "PID-D"
-#define MSG_PID_C                           "PID-C"
-#define MSG_ACC                             "Accel"
-#define MSG_VXY_JERK                        "Vxy-jerk"
-#define MSG_VZ_JERK                         "Vz-jerk"
-#define MSG_VE_JERK                         "Ve-jerk"
-#define MSG_VMAX                            "Vmax "
-#define MSG_X                               "x"
-#define MSG_Y                               "y"
-#define MSG_Z                               "z"
-#define MSG_E                               "e"
-#define MSG_VMIN                            "Vmin"
-#define MSG_VTRAV_MIN                       "VTrav min"
-#define MSG_AMAX                            "Amax "
-#define MSG_A_RETRACT                       "A-retract"
-#define MSG_XSTEPS                          "Xsteps/mm"
-#define MSG_YSTEPS                          "Ysteps/mm"
-#define MSG_ZSTEPS                          "Zsteps/mm"
-#define MSG_ESTEPS                          "Esteps/mm"
-#define MSG_RETRACT                         "Retract"
-#define MSG_EXTRUDE                         "Extrude"
-#define MSG_AUTOSTART                       "Autostart"
-#define MSG_MOVE_E1                         "Extruder2"
-#define MSG_MOVE_E2                         "Extruder3"
-#define MSG_MOVE_01MM                       "Move 0.1mm"
-#define MSG_MOVE_1MM                        "Move 1mm"
-#define MSG_MOVE_10MM                       "Move 10mm"
 #define MSG_NOZZLE1                         "Nozzle2"
 #define MSG_NOZZLE2                         "Nozzle3"
 #define MSG_FLOW0                           "Flow 0"
@@ -210,31 +140,14 @@
 #define MSG_MOTION                          "Motion"
 #define MSG_VOLUMETRIC                      "Filament"
 #define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
-#define MSG_FILAMENT_SIZE_EXTRUDER_0        "Fil. Dia. 1"
-#define MSG_FILAMENT_SIZE_EXTRUDER_1        "Fil. Dia. 2"
-#define MSG_FILAMENT_SIZE_EXTRUDER_2        "Fil. Dia. 3"
-#define MSG_CONTRAST                        "LCD contrast"
 #define MSG_STORE_EPROM                     "Store memory"
 #define MSG_LOAD_EPROM                      "Load memory"
 #define MSG_RESTORE_FAILSAFE                "Restore failsafe"
 #define MSG_REFRESH                         "\xF8" "Refresh"
-#define MSG_PREPARE                         "Prepare"
-#define MSG_CONTROL_RETRACT                 "Retract mm"
-#define MSG_CONTROL_RETRACT_SWAP            "Swap Re.mm"
-#define MSG_CONTROL_RETRACTF                "Retract  V"
-#define MSG_CONTROL_RETRACT_ZLIFT           "Hop mm"
-#define MSG_CONTROL_RETRACT_RECOVER         "UnRet +mm"
-#define MSG_CONTROL_RETRACT_RECOVER_SWAP    "S UnRet+mm"
-#define MSG_CONTROL_RETRACT_RECOVERF        "UnRet  V"
-#define MSG_AUTORETRACT                     "AutoRetr."
 #define MSG_INIT_SDCARD                     "Init. SD card"
 #define MSG_CNG_SDCARD                      "Change SD card"
-#define MSG_ZPROBE_OUT                      "Z probe out. bed"
-#define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
-#define MSG_ZPROBE_ZOFFSET                  "Z Offset"
 #define MSG_BABYSTEP_X                      "Babystep X"
 #define MSG_BABYSTEP_Y                      "Babystep Y"
-#define MSG_ENDSTOP_ABORT                   "Endstop abort"
 #define MSG_RECTRACT                        "Rectract"
 
 #define MSG_HOMEYZ                          "Calibrar Z"
@@ -244,33 +157,166 @@
 #define MSG_SELFTEST_ERROR                  "Autotest error!"
 #define MSG_SELFTEST_PLEASECHECK            "Controla :"   
 #define MSG_SELFTEST_NOTCONNECTED           "No hay conexion  "
-#define MSG_SELFTEST_HEATERTHERMISTOR       "Calent./Termistor"
-#define MSG_SELFTEST_BEDHEATER              "Cama/Calentador"
-#define MSG_SELFTEST_WIRINGERROR            "Error de conexión"
-#define MSG_SELFTEST_ENDSTOPS               "Topes final"
+#define MSG_SELFTEST_HEATERTHERMISTOR       "Hotend"
+#define MSG_SELFTEST_BEDHEATER              "Heatbed"
+#define MSG_SELFTEST_WIRINGERROR            "Error de conexion"
+#define MSG_SELFTEST_ENDSTOPS               "Topes finales"
 #define MSG_SELFTEST_MOTOR                  "Motor"
 #define MSG_SELFTEST_ENDSTOP                "Tope final"
-#define MSG_SELFTEST_ENDSTOP_NOTHIT         "Tope fin. no toc."
+#define MSG_SELFTEST_ENDSTOP_NOTHIT         "Tope no alcanzado"
 #define MSG_SELFTEST_OK                     "Self test OK"
 
+#define MSG_SELFTEST_FAN					"Test ventiladores"
+#define MSG_SELFTEST_COOLING_FAN			"Vent. frontal?"
+#define MSG_SELFTEST_EXTRUDER_FAN			"Vent. izquierdo?"
+#define MSG_SELFTEST_FAN_YES				"Ventilador gira"
+#define MSG_SELFTEST_FAN_NO					"Ventilador no gira"
+
 #define MSG_STATS_TOTALFILAMENT             "Filamento total:"
 #define MSG_STATS_TOTALPRINTTIME            "Tiempo total :"
-#define MSG_STATS_FILAMENTUSED              "Filamento :  "
+#define MSG_STATS_FILAMENTUSED              "Filamento usado:  "
 #define MSG_STATS_PRINTTIME                 "Tiempo de imp.:"
 
-#define MSG_SELFTEST_START                  "Autotest salida"
-#define MSG_SELFTEST_CHECK_ENDSTOPS         "Cont. topes final"
+#define MSG_SELFTEST_START                  "Inicio Selftest"
+#define MSG_SELFTEST_CHECK_ENDSTOPS         "Control topes"
 #define MSG_SELFTEST_CHECK_HOTEND           "Control hotend " 
-#define MSG_SELFTEST_CHECK_X                "Control del eje X"
-#define MSG_SELFTEST_CHECK_Y                "Control del eje Y"
-#define MSG_SELFTEST_CHECK_Z                "Control del eje Z"
-#define MSG_SELFTEST_CHECK_BED              "Control de cama"
-#define MSG_SELFTEST_CHECK_ALLCORRECT       "Todo bie "
-#define MSG_SELFTEST                        "Autotest"
-#define MSG_SELFTEST_FAILED                 "Autotest fallado"
+#define MSG_SELFTEST_CHECK_X                "Control tope X"
+#define MSG_SELFTEST_CHECK_Y                "Control tope Y"
+#define MSG_SELFTEST_CHECK_Z                "Control tope Z"
+#define MSG_SELFTEST_CHECK_BED              "Control heatbed"
+#define MSG_SELFTEST_CHECK_ALLCORRECT       "Todo bien"
+#define MSG_SELFTEST                        "Selftest"
+#define MSG_SELFTEST_FAILED                 "Fallo Selftest"
+
+#define MSG_STATISTICS                      "Estadisticas  "
+#define MSG_USB_PRINTING                    "Impresion con USB "
+
+#define MSG_SHOW_END_STOPS                  "Ensena tope final"
+#define MSG_CALIBRATE_BED                   "Calibra XYZ"
+#define MSG_CALIBRATE_BED_RESET             "Reset XYZ calibr."
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP        "Calibrando XYZ. Gira el boton para subir el extrusor hasta tocar los topes superiores. Despues haz clic."
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z       "Calibrando Z. Gira el boton para subir el extrusor hasta tocar los topes superiores. Despues haz clic."
+
+#define MSG_CONFIRM_NOZZLE_CLEAN            "Limpia nozzle para calibracion. Click cuando acabes."
+#define MSG_CONFIRM_CARRIAGE_AT_THE_TOP     "Carros Z izq./der. estan arriba maximo?"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1  "Buscando punto de calibracion heatbed"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2  " de 4"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1   "Mejorando punto de calibracion heatbed"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2   " de 4"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1	"Midiendo altura del punto de calibracion"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2	" de 9"
+
+#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION	"Reiteracion "
+#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND           "Calibracion XYZ fallada. Puntos de calibracion en heatbed no encontrados."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED            "Calibracion XYZ fallada. Consulta el manual por favor."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT               "Calibracion XYZ ok. Ejes X/Y perpendiculares. Enhorabuena!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD             "Calibracion XYZ correcta. Los ejes X / Y estan ligeramente inclinados. Buen trabajo!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME          "Calibracion XYZ correcta. La inclinacion se corregira automaticamente."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR     "Calibracion XYZ fallada. Punto frontal izquierdo no alcanzable."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR        "Calibracion XYZ fallad. Punto frontal derecho no alcanzable."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR     "Calibracion XYZ fallada. Puntos frontales no alcanzables."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR        "Calibrazion XYZ comprometida. Punto frontal izquierdo no alcanzable."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR       "Calibrazion XYZ comprometida. Punto frontal derecho no alcanzable."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR        "Calibrazion XYZ comprometida. Puntos frontales no alcanzables."
+#define MSG_BED_LEVELING_FAILED_POINT_LOW           				"Nivelacion fallada. Sensor no funciona. Escombros en nozzle? Esperando reset."
+#define MSG_BED_LEVELING_FAILED_POINT_HIGH          				"Nivelacion fallada. Sensor funciona demasiado temprano. Esperando reset."
+#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED      			"Nivelacion fallada. Sensor desconectado o cables danados. Esperando reset."
+#define MSG_NEW_FIRMWARE_AVAILABLE                  				"Nuevo firmware disponible:"
+#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE                 			"Actualizar por favor"
+#define MSG_FOLLOW_CALIBRATION_FLOW                    			"Impresora no esta calibrada todavia. Por favor usa el manual, capitulo First steps, Calibration flow."
+#define MSG_BABYSTEP_Z_NOT_SET                      			"Distancia entre la punta del nozzle y la superficie de la heatbed aun no fijada. Por favor siga el manual, capitulo First steps, First layer calibration."
+#define MSG_BED_CORRECTION_MENU                                 "Corr. de la cama"
+#define MSG_BED_CORRECTION_LEFT                                 "Izquierda [um]"
+#define MSG_BED_CORRECTION_RIGHT                                "Derecha   [um]"
+#define MSG_BED_CORRECTION_FRONT                                "Frontal   [um]"
+#define MSG_BED_CORRECTION_REAR                                 "Trasera   [um]"
+#define MSG_BED_CORRECTION_RESET                                "Reset"
+
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
+#define MSG_MENU_CALIBRATION									"Calibracion"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+
+#define MSG_LOOSE_PULLEY								"Polea suelta"
+#define MSG_FILAMENT_LOADING_T0							"Insertar filamento en el extrusor 1. Haz clic una vez terminado."
+#define MSG_FILAMENT_LOADING_T1							"Insertar filamento en el extrusor 2. Haz clic una vez terminado."
+#define MSG_FILAMENT_LOADING_T2							"Insertar filamento en el extrusor 3. Haz clic una vez terminado."
+#define MSG_FILAMENT_LOADING_T3							"Insertar filamento en el extrusor 4. Haz clic una vez terminado."
+#define MSG_CHANGE_EXTR									"Cambiar extrusor."
+
+#define MSG_FIL_ADJUSTING								"Ajustando filamentos. Espera por favor."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ				"Filamentos ajustados. Limpia nozzle para calibracion. Haz clic una vez terminado."
+#define MSG_CALIBRATE_E									"Calibrar E"
+#define MSG_E_CAL_KNOB									"Rotar el mando hasta que la marca llegue al cuerpo del extrusor. Haz clic una vez terminado."
+#define MSG_MARK_FIL									"Marque el filamento 100 mm por encima del final del extrusor. Haz clic una vez terminado."
+#define MSG_CLEAN_NOZZLE_E								"E calibrado. Limpia nozzle. Haz clic una vez terminado."
+#define MSG_WAITING_TEMP								"Esperando enfriamiento de heatbed y extrusor."
+#define MSG_FILAMENT_CLEAN								"Es el nuevo color nitido?"
+#define MSG_UNLOADING_FILAMENT							"Soltando filamento"
+#define MSG_PAPER										"Colocar una hoja de papel sobre la superficie de impresion durante la calibracion de los primeros 4 puntos. Si la boquilla mueve el papel, apagar impresora inmediatamente."
+
+#define MSG_FINISHING_MOVEMENTS							"Term. movimientos"
+#define MSG_PRINT_PAUSED								"Impresion en pausa"
+#define MSG_RESUMING_PRINT								"Reanudar impresion"
+#define MSG_PID_EXTRUDER								"Calibracion PID"
+#define MSG_SET_TEMPERATURE								"Establecer temp.:"
+#define MSG_PID_FINISHED								"Cal. PID terminada"
+#define MSG_PID_RUNNING									"Cal. PID           "
+
+#define MSG_CALIBRATE_PINDA								"Calibrar"
+#define MSG_CALIBRATION_PINDA_MENU						"Calibracion temp."
+#define MSG_PINDA_NOT_CALIBRATED						"La temperatura de calibracion no ha sido ajustada"
+#define MSG_PINDA_PREHEAT								"Calentando PINDA"
+#define MSG_TEMP_CALIBRATION							"Cal. temp.          "
+#define MSG_TEMP_CALIBRATION_DONE						"Calibracon temperatura terminada. Haz clic para continuar."
+#define MSG_TEMP_CALIBRATION_ON							"Cal. temp. [ON]"
+#define MSG_TEMP_CALIBRATION_OFF						"Cal. temp. [OFF]"
+
+#define MSG_PREPARE_FILAMENT							"Preparar filamento"
+
 
-#define MSG_STATISTICS                      "Estadistica  "
-#define MSG_USB_PRINTING                    "Impresion de USB "
 
-#endif // LANGUAGE_EN_H
+#define MSG_LOAD_ALL									"Intr. todos fil."
+#define MSG_LOAD_FILAMENT_1								"Introducir fil. 1"
+#define MSG_LOAD_FILAMENT_2								"Introducir fil. 2"
+#define MSG_LOAD_FILAMENT_3								"Introducir fil. 3"
+#define MSG_LOAD_FILAMENT_4								"Introducir fil. 4"
+#define MSG_UNLOAD_FILAMENT_1							"Soltar fil. 1"
+#define MSG_UNLOAD_FILAMENT_2							"Soltar fil. 2"
+#define MSG_UNLOAD_FILAMENT_3							"Soltar fil. 3"
+#define MSG_UNLOAD_FILAMENT_4							"Soltar fil. 4"
+#define MSG_UNLOAD_ALL									"Soltar todos fil."
+#define MSG_PREPARE_FILAMENT							"Preparar filamento"
+#define MSG_ALL											"Todos"
+#define MSG_USED										"Usado en impresion"
+#define MSG_CURRENT										"Actual"
+#define MSG_CHOOSE_EXTRUDER								"Elegir extrusor:"
+#define MSG_EXTRUDER									"Extrusor"
+#define MSG_EXTRUDER_1									"Extrusor 1"
+#define MSG_EXTRUDER_2									"Extrusor 2"
+#define MSG_EXTRUDER_3									"Extrusor 3"
+#define MSG_EXTRUDER_4									"Extrusor 4"
 
+#define MSG_WIZARD							"Wizard"
+#define MSG_WIZARD_WELCOME					"Hola, soy tu impresora Original Prusa i3. Quieres que te guie a traves de la configuracion?"
+#define MSG_WIZARD_QUIT						"Siempre puedes acceder al asistente desde Calibracion -> Wizard"
+#define MSG_WIZARD_SELFTEST					"Primero, hare el Selftest para comprobar los problemas de montaje mas comunes."
+#define MSG_WIZARD_CALIBRATION_FAILED		"Lee el manual y resuelve el problema. Despues, reinicia la impresora y continua con el Wizard"
+#define MSG_WIZARD_XYZ_CAL					"Hare la calibracion XYZ. Tardara 12 min. aproximadamente."
+#define MSG_WIZARD_FILAMENT_LOADED			"Esta el filamento cargado?"
+#define MSG_WIZARD_Z_CAL					"Voy a hacer Calibracion Z ahora."
+#define MSG_WIZARD_WILL_PREHEAT				"Voy a precalentar el nozzle para PLA ahora."
+#define MSG_WIZARD_V2_CAL					"Voy a calibrar la distancia entre la punta del nozzle y la superficie de la heatbed."
+#define MSG_WIZARD_V2_CAL_2					"Voy a comenzar a imprimir la linea y tu bajaras el nozzle gradualmente al rotar el mando, hasta que llegues a la altura optima. Mira las imagenes del capitulo Calibracion en el manual."
+#define MSG_V2_CALIBRATION					"Cal. primera cap."
+#define MSG_WIZARD_DONE						"Terminado! Feliz impresion!"
+#define MSG_WIZARD_LOAD_FILAMENT			"Inserta, por favor, filamento PLA en el extrusor. Despues haz clic para cargarlo."
+#define MSG_WIZARD_RERUN					"Ejecutar el Wizard borrara los valores de calibracion actuales y comenzara de nuevo. Continuar?"
+#define MSG_WIZARD_REPEAT_V2_CAL			"Quieres repetir el ultimo paso para reajustar la distancia nozzle-heatbed?"
+#define MSG_WIZARD_CLEAN_HEATBED			"Limpia la superficie de la heatbed, por favor, y haz clic"
+#define MSG_WIZARD_PLA_FILAMENT				"Es el filamento PLA?"
+#define MSG_WIZARD_INSERT_CORRECT_FILAMENT	"Carga filamento PLA, por favor, y reinicia la impresora para continuar con el Wizard"
+#define MSG_PLA_FILAMENT_LOADED				"Esta el filamento PLA cargado?"
+#define MSG_PLEASE_LOAD_PLA					"Carga el filamento PLA primero por favor."
+#define MSG_WIZARD_HEATING					"Precalentando nozzle. Espera por favor."
+#define MSG_M117_V2_CALIBRATION				"M117 Cal. primera cap."

+ 322 - 275
Firmware/language_it.h

@@ -1,275 +1,322 @@
-/**
- * Italian
- *
- * LCD Menu Messages
- * Please note these are limited to 17 characters!
- *
- */
-#ifndef LANGUAGE_IT_H
-#define LANGUAGE_IT_H
-
-#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " pronto."
-#define MSG_SD_INSERTED                     "SD Card inserita"
-#define MSG_SD_REMOVED                      "SD Card rimossa"
-#define MSG_MAIN                            "Menu principale"
-#define MSG_DISABLE_STEPPERS                "Disabilita Motori"
-#define MSG_AUTO_HOME                       "Auto Home"
-#define MSG_COOLDOWN                        "Raffredda"
-#define MSG_MOVE_AXIS                       "Muovi Asse"
-#define MSG_MOVE_X                          "Muovi X"
-#define MSG_MOVE_Y                          "Muovi Y"
-#define MSG_MOVE_Z                          "Muovi Z"
-#define MSG_MOVE_E                          "Estrusore"
-#define MSG_SPEED                           "Velcità"
-#define MSG_NOZZLE                          "Ugello"
-#define MSG_BED                             "Piatto"
-#define MSG_FAN_SPEED                       "Ventola"
-#define MSG_FLOW                            "Flusso"
-#define MSG_TEMPERATURE                     "Temperatura"
-#define MSG_WATCH                           "Guarda"
-#define MSG_TUNE                            "Adatta"
-#define MSG_PAUSE_PRINT                     "Pausa"
-#define MSG_RESUME_PRINT                    "Riprendi stampa"
-#define MSG_STOP_PRINT                      "Arresta stampa"
-#define MSG_CARD_MENU                       "Menu SD Carta"
-#define MSG_NO_CARD                         "No SD Carta"
-#define MSG_DWELL                           "Sospensione..."
-#define MSG_USERWAIT                        "Attendi Utente..."
-#define MSG_RESUMING                        "Riprendi Stampa"
-#define MSG_PRINT_ABORTED                   "Stampa abortita"
-#define MSG_NO_MOVE                         "Nessun Movimento"
-#define MSG_KILLED                          "UCCISO "
-#define MSG_STOPPED                         "ARRESTATO "
-#define MSG_FILAMENTCHANGE                  "Cambiare filamento"
-#define MSG_BABYSTEP_Z                      "Babystep Z"
-#define MSG_ADJUSTZ							"Auto regolare Z ?"
-#define MSG_PICK_Z							"Vyberte vytisk"
-#define MSG_SETTINGS                         "Impostazioni"
-#define MSG_PREHEAT                         "Preriscalda"
-#define MSG_UNLOAD_FILAMENT                 "Scaricare fil."
-#define MSG_LOAD_FILAMENT                 "Caricare filamento"
-#define MSG_ERROR                        "ERROR:"
-#define MSG_PREHEAT_NOZZLE                       "Preris. ugello!"
-#define MSG_SUPPORT "Support"
-#define MSG_CORRECTLY			"Cambiato corr.?"
-#define MSG_YES					"Si"
-#define MSG_NO					"No"
-#define MSG_NOT_LOADED 			"Fil. no cargado"
-#define MSG_NOT_COLOR 			"Color no claro"
-#define MSG_LOADING_FILAMENT	"Cargando fil."
-#define MSG_PLEASE_WAIT			"Aspetta"
-#define MSG_LOADING_COLOR		"Cargando color"
-#define MSG_CHANGE_SUCCESS		"Cambia. riuscito!"
-#define MSG_PRESS				"Y pulse el mando"
-#define MSG_INSERT_FILAMENT		"Inserire filamento"
-#define MSG_CHANGING_FILAMENT	"Mutevole fil.!"
-#define MSG_SILENT_MODE_ON					"Modo     [silenzioso]"
-#define MSG_SILENT_MODE_OFF					"Modo [piu forza]" 
-#define MSG_REBOOT							"Riavvio la stamp."
-#define MSG_TAKE_EFFECT						" per mostrare i camb."											
-#define MSG_HEATING                         "Riscaldamento..."
-#define MSG_HEATING_COMPLETE                "Riscaldamento fatto."
-#define MSG_BED_HEATING                     "Piatto riscaldam."
-#define MSG_BED_DONE                        "Piatto fatto."
-#define MSG_LANGUAGE_NAME					"Italiano"
-#define MSG_LANGUAGE_SELECT					"Selez. la lingua"
-#define MSG_PRUSA3D					"prusa3d.com"
-#define MSG_PRUSA3D_FORUM					"forum.prusa3d.com"
-#define MSG_PRUSA3D_HOWTO					"howto.prusa3d.com"
-
-
-// Do not translate those!
-
-#define MSG_Enqueing                        "enqueing \""
-#define MSG_POWERUP                         "PowerUp"
-#define MSG_EXTERNAL_RESET                  " External Reset"
-#define MSG_BROWNOUT_RESET                  " Brown out Reset"
-#define MSG_WATCHDOG_RESET                  " Watchdog Reset"
-#define MSG_SOFTWARE_RESET                  " Software Reset"
-#define MSG_AUTHOR                          " | Author: "
-#define MSG_CONFIGURATION_VER               " Last Updated: "
-#define MSG_FREE_MEMORY                     " Free Memory: "
-#define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
-#define MSG_OK                              "ok"
-#define MSG_FILE_SAVED                      "Done saving file."
-#define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
-#define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
-#define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
-#define MSG_FILE_PRINTED                    "Done printing file"
-#define MSG_BEGIN_FILE_LIST                 "Begin file list"
-#define MSG_END_FILE_LIST                   "End file list"
-#define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
-#define MSG_M105_INVALID_EXTRUDER           "M105 Invalid extruder "
-#define MSG_M200_INVALID_EXTRUDER           "M200 Invalid extruder "
-#define MSG_M218_INVALID_EXTRUDER           "M218 Invalid extruder "
-#define MSG_M221_INVALID_EXTRUDER           "M221 Invalid extruder "
-#define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
-#define MSG_M109_INVALID_EXTRUDER           "M109 Invalid extruder "
-#define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
-#define MSG_COUNT_X                         " Count X: "
-#define MSG_ERR_KILLED                      "Printer halted. kill() called!"
-#define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
-#define MSG_RESEND                          "Resend: "
-#define MSG_UNKNOWN_COMMAND                 "Unknown command: \""
-#define MSG_ACTIVE_EXTRUDER                 "Active Extruder: "
-#define MSG_INVALID_EXTRUDER                "Invalid extruder"
-#define MSG_X_MIN                           "x_min: "
-#define MSG_X_MAX                           "x_max: "
-#define MSG_Y_MIN                           "y_min: "
-#define MSG_Y_MAX                           "y_max: "
-#define MSG_Z_MIN                           "z_min: "
-#define MSG_Z_MAX                           "z_max: "
-#define MSG_M119_REPORT                     "Reporting endstop status"
-#define MSG_ENDSTOP_HIT                     "TRIGGERED"
-#define MSG_ENDSTOP_OPEN                    "open"
-#define MSG_HOTEND_OFFSET                   "Hotend offsets:"
-#define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
-#define MSG_SD_INIT_FAIL                    "SD init fail"
-#define MSG_SD_VOL_INIT_FAIL                "volume.init failed"
-#define MSG_SD_OPENROOT_FAIL                "openRoot failed"
-#define MSG_SD_CARD_OK                      "SD card ok"
-#define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
-#define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
-#define MSG_SD_FILE_OPENED                  "File opened: "
-#define MSG_SD_SIZE                         " Size: "
-#define MSG_SD_FILE_SELECTED                "File selected"
-#define MSG_SD_WRITE_TO_FILE                "Writing to file: "
-#define MSG_SD_PRINTING_BYTE                "SD printing byte "
-#define MSG_SD_NOT_PRINTING                 "Not SD printing"
-#define MSG_SD_ERR_WRITE_TO_FILE            "error writing to file"
-#define MSG_SD_CANT_ENTER_SUBDIR            "Cannot enter subdir: "
-#define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
-#define MSG_ENDSTOPS_HIT                    "endstops hit: "
-#define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
-#define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
-#define MSG_BABYSTEPPING_X                  "Babystepping X"
-#define MSG_BABYSTEPPING_Y                  "Babystepping Y"
-#define MSG_BABYSTEPPING_Z                  "Adjusting Z"
-#define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
-#define MSG_SET_HOME_OFFSETS                "Set home offsets"
-#define MSG_SET_ORIGIN                      "Set origin"
-#define MSG_PREHEAT_PLA                     "Preheat PLA"
-#define MSG_PREHEAT_PLA0                    "Preheat PLA 1"
-#define MSG_PREHEAT_PLA1                    "Preheat PLA 2"
-#define MSG_PREHEAT_PLA2                    "Preheat PLA 3"
-#define MSG_PREHEAT_PLA012                  "Preheat PLA All"
-#define MSG_PREHEAT_PLA_BEDONLY             "Preheat PLA Bed"
-#define MSG_PREHEAT_PLA_SETTINGS            "Preheat PLA conf"
-#define MSG_PREHEAT_ABS                     "Preheat ABS"
-#define MSG_PREHEAT_ABS0                    "Preheat ABS 1"
-#define MSG_PREHEAT_ABS1                    "Preheat ABS 2"
-#define MSG_PREHEAT_ABS2                    "Preheat ABS 3"
-#define MSG_PREHEAT_ABS012                  "Preheat ABS All"
-#define MSG_PREHEAT_ABS_BEDONLY             "Preheat ABS Bed"
-#define MSG_PREHEAT_ABS_SETTINGS            "Preheat ABS conf"
-#define MSG_SWITCH_PS_ON                    "Switch power on"
-#define MSG_SWITCH_PS_OFF                   "Switch power off"
-#define MSG_AUTOTEMP                        "Autotemp"
-#define MSG_ON                              "On "
-#define MSG_OFF                             "Off"
-#define MSG_PID_P                           "PID-P"
-#define MSG_PID_I                           "PID-I"
-#define MSG_PID_D                           "PID-D"
-#define MSG_PID_C                           "PID-C"
-#define MSG_ACC                             "Accel"
-#define MSG_VXY_JERK                        "Vxy-jerk"
-#define MSG_VZ_JERK                         "Vz-jerk"
-#define MSG_VE_JERK                         "Ve-jerk"
-#define MSG_VMAX                            "Vmax "
-#define MSG_X                               "x"
-#define MSG_Y                               "y"
-#define MSG_Z                               "z"
-#define MSG_E                               "e"
-#define MSG_VMIN                            "Vmin"
-#define MSG_VTRAV_MIN                       "VTrav min"
-#define MSG_AMAX                            "Amax "
-#define MSG_A_RETRACT                       "A-retract"
-#define MSG_XSTEPS                          "Xsteps/mm"
-#define MSG_YSTEPS                          "Ysteps/mm"
-#define MSG_ZSTEPS                          "Zsteps/mm"
-#define MSG_ESTEPS                          "Esteps/mm"
-#define MSG_RETRACT                         "Retract"
-#define MSG_EXTRUDE                         "Extrude"
-#define MSG_AUTOSTART                       "Autostart"
-#define MSG_MOVE_E1                         "Extruder2"
-#define MSG_MOVE_E2                         "Extruder3"
-#define MSG_MOVE_01MM                       "Move 0.1mm"
-#define MSG_MOVE_1MM                        "Move 1mm"
-#define MSG_MOVE_10MM                       "Move 10mm"
-#define MSG_NOZZLE1                         "Nozzle2"
-#define MSG_NOZZLE2                         "Nozzle3"
-#define MSG_FLOW0                           "Flow 0"
-#define MSG_FLOW1                           "Flow 1"
-#define MSG_FLOW2                           "Flow 2"
-#define MSG_CONTROL                         "Control"
-#define MSG_MIN                             " \002 Min"
-#define MSG_MAX                             " \002 Max"
-#define MSG_FACTOR                          " \002 Fact"
-#define MSG_MOTION                          "Motion"
-#define MSG_VOLUMETRIC                      "Filament"
-#define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
-#define MSG_FILAMENT_SIZE_EXTRUDER_0        "Fil. Dia. 1"
-#define MSG_FILAMENT_SIZE_EXTRUDER_1        "Fil. Dia. 2"
-#define MSG_FILAMENT_SIZE_EXTRUDER_2        "Fil. Dia. 3"
-#define MSG_CONTRAST                        "LCD contrast"
-#define MSG_STORE_EPROM                     "Store memory"
-#define MSG_LOAD_EPROM                      "Load memory"
-#define MSG_RESTORE_FAILSAFE                "Restore failsafe"
-#define MSG_REFRESH                         "\xF8" "Refresh"
-#define MSG_PREPARE                         "Prepare"
-#define MSG_CONTROL_RETRACT                 "Retract mm"
-#define MSG_CONTROL_RETRACT_SWAP            "Swap Re.mm"
-#define MSG_CONTROL_RETRACTF                "Retract  V"
-#define MSG_CONTROL_RETRACT_ZLIFT           "Hop mm"
-#define MSG_CONTROL_RETRACT_RECOVER         "UnRet +mm"
-#define MSG_CONTROL_RETRACT_RECOVER_SWAP    "S UnRet+mm"
-#define MSG_CONTROL_RETRACT_RECOVERF        "UnRet  V"
-#define MSG_AUTORETRACT                     "AutoRetr."
-#define MSG_INIT_SDCARD                     "Init. SD card"
-#define MSG_CNG_SDCARD                      "Change SD card"
-#define MSG_ZPROBE_OUT                      "Z probe out. bed"
-#define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
-#define MSG_ZPROBE_ZOFFSET                  "Z Offset"
-#define MSG_BABYSTEP_X                      "Babystep X"
-#define MSG_BABYSTEP_Y                      "Babystep Y"
-#define MSG_ENDSTOP_ABORT                   "Endstop abort"
-#define MSG_RECTRACT                        "Rectract"
-
-#define MSG_HOMEYZ                          "Calibra Z"
-#define MSG_HOMEYZ_PROGRESS                 "Calibrando Z"
-#define MSG_HOMEYZ_DONE                     "Calibratura OK"
-
-#define MSG_SELFTEST_ERROR                  "Autotest negativo"
-#define MSG_SELFTEST_PLEASECHECK            "Verifica:"   
-#define MSG_SELFTEST_NOTCONNECTED           "Non connesso"
-#define MSG_SELFTEST_HEATERTHERMISTOR       "Riscald./Termistore"
-#define MSG_SELFTEST_BEDHEATER              "Piastra/Riscaldatore"
-#define MSG_SELFTEST_WIRINGERROR            "Errore cablaggio"
-#define MSG_SELFTEST_ENDSTOPS               "Limiti corsa"
-#define MSG_SELFTEST_MOTOR                  "Motore"
-#define MSG_SELFTEST_ENDSTOP                "Limite corsa"
-#define MSG_SELFTEST_ENDSTOP_NOTHIT         "Lim. fuoriportata"
-#define MSG_SELFTEST_OK                     "Autotest OK"
-
-#define MSG_STATS_TOTALFILAMENT             "Filamento tot:"
-#define MSG_STATS_TOTALPRINTTIME            "Tempo stampa tot:"
-#define MSG_STATS_FILAMENTUSED              "Filamento:"
-#define MSG_STATS_PRINTTIME                 "Tempo stampa:"
-
-#define MSG_SELFTEST_START                  "Inizia autotest"
-#define MSG_SELFTEST_CHECK_ENDSTOPS         "Verifica limiti"
-#define MSG_SELFTEST_CHECK_HOTEND           "Verifica lim temp" 
-#define MSG_SELFTEST_CHECK_X                "Verifica asse X"
-#define MSG_SELFTEST_CHECK_Y                "Verifica asse Y"
-#define MSG_SELFTEST_CHECK_Z                "Verifica asse Z"
-#define MSG_SELFTEST_CHECK_BED              "Verifica piastra"
-#define MSG_SELFTEST_CHECK_ALLCORRECT       "Nessun errore"
-#define MSG_SELFTEST                        "Autotest"
-#define MSG_SELFTEST_FAILED                 "Autotest fallito"
-
-#define MSG_STATISTICS                      "Statistiche"
-#define MSG_USB_PRINTING                    "Stampa da USB"
-
-
-#endif // LANGUAGE_EN_H
+#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " pronta."
+#define MSG_SD_INSERTED                     "SD inserita"
+#define MSG_SD_REMOVED                      "SD rimossa"
+#define MSG_MAIN                            "Menu principale"
+#define MSG_DISABLE_STEPPERS                "Disabilit motori"
+#define MSG_AUTO_HOME                       "Trova origine"
+#define MSG_SET_HOME_OFFSETS                "Set home offsets"
+#define MSG_SET_ORIGIN                      "Set origin"
+#define MSG_COOLDOWN                        "Raffredda"
+#define MSG_SWITCH_PS_ON                    "Switch power on"
+#define MSG_SWITCH_PS_OFF                   "Switch power off"
+#define MSG_MOVE_AXIS                       "Muovi asse"
+#define MSG_MOVE_X                          "Muovi X"
+#define MSG_MOVE_Y                          "Muovi Y"
+#define MSG_MOVE_Z                          "Muovi Z"
+#define MSG_MOVE_E                          "Muovi Estrusore"
+#define MSG_MOVE_01MM                       "Move 0.1mm"
+#define MSG_MOVE_1MM                        "Move 1mm"
+#define MSG_MOVE_10MM                       "Move 10mm"
+#define MSG_SPEED                           "Velocita"
+#define MSG_NOZZLE                          "Ugello"
+#define MSG_NOZZLE1                         "Nozzle2"
+#define MSG_NOZZLE2                         "Nozzle3"
+#define MSG_BED                             "Letto"
+#define MSG_FAN_SPEED                       "Velocita vent."
+#define MSG_FLOW                            "Flusso"
+#define MSG_TEMPERATURE                     "Temperatura"
+#define MSG_MOTION                          "Motion"
+#define MSG_VOLUMETRIC                      "Filament"
+#define MSG_VOLUMETRIC_ENABLED		    	"E in mm3"
+#define MSG_STORE_EPROM                     "Store memory"
+#define MSG_LOAD_EPROM                      "Load memory"
+#define MSG_RESTORE_FAILSAFE                "Restore failsafe"
+#define MSG_REFRESH                         "\xF8" "Refresh"
+#define MSG_WATCH                           "Schermata info"
+#define MSG_TUNE                            "Regola"
+#define MSG_PAUSE_PRINT                     "Metti in pausa"
+#define MSG_RESUME_PRINT                    "Riprendi stampa"
+#define MSG_STOP_PRINT                      "Arresta stampa"
+#define MSG_CARD_MENU                       "Stampa da SD"
+#define MSG_NO_CARD                         "Nessuna SD"
+#define MSG_DWELL                           "Sospensione..."
+#define MSG_USERWAIT                        "Attendendo utente"
+#define MSG_RESUMING                        "Riprendi stampa"
+#define MSG_PRINT_ABORTED                   "Stampa abortita"
+#define MSG_NO_MOVE                         "Nessun movimento."
+#define MSG_KILLED                          "IN TILT."
+#define MSG_STOPPED                         "ARRESTATO."
+#define MSG_FILAMENTCHANGE                  "Camb. filamento"
+#define MSG_INIT_SDCARD                     "Init. SD card"
+#define MSG_CNG_SDCARD                      "Change SD card"
+#define MSG_ZPROBE_OUT                      "Z probe out. bed"
+#define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
+#define MSG_ZPROBE_ZOFFSET                  "Z Offset"
+#define MSG_BABYSTEP_X                      "Babystep X"
+#define MSG_BABYSTEP_Y                      "Babystep Y"
+#define MSG_BABYSTEP_Z                      "Compensazione Z"
+#define MSG_ADJUSTZ			    			"Autoregolare Z?"
+#define MSG_PICK_Z			    			"Pick print"
+
+#define MSG_SETTINGS                        "Impostazioni"
+#define MSG_PREHEAT                         "Preriscalda"
+#define MSG_HEATING                         "Riscaldamento..."
+#define MSG_SUPPORT 						"Support"
+#define MSG_YES								"Si"
+#define MSG_NO								"No"
+#define MSG_NOT_LOADED 						"Fil. non caricato"
+#define MSG_NOT_COLOR 						"Colore non puro"
+#define MSG_LOADING_COLOR					"Caricando colore"
+#define MSG_CHANGE_SUCCESS					"Cambio riuscito!"
+#define MSG_PRESS							"e cliccare manopola"
+#define MSG_INSERT_FILAMENT					"Inserire filamento"
+#define MSG_CHANGING_FILAMENT				"Cambiando filam."
+
+#define MSG_PLEASE_WAIT						"Aspetta"
+#define MSG_PREHEAT_NOZZLE                  "Preris. ugello!"
+#define MSG_HEATING_COMPLETE                "Riscald. completo"
+#define MSG_BED_HEATING                     "Riscald. letto"
+#define MSG_BED_DONE                        "Piatto fatto."
+#define MSG_ERROR                        	"ERRORE:"
+#define MSG_CORRECTLY						"Cambiato corr.?"
+#define MSG_LOADING_FILAMENT				"Caricando filam."
+#define MSG_UNLOAD_FILAMENT                 "Scarica filamento"
+#define MSG_LOAD_FILAMENT                   "Carica filamento"
+
+#define MSG_SILENT_MODE_ON		    "Modo [silenzioso]"
+#define MSG_SILENT_MODE_OFF		    "Mode      [forte]" 
+#define MSG_REBOOT			    "Riavvia stampante"
+#define MSG_TAKE_EFFECT			    " per attualizzare"
+
+#define MSG_Enqueing                        "enqueing \""
+#define MSG_POWERUP                         "PowerUp"
+#define MSG_CONFIGURATION_VER               " Last Updated: "
+#define MSG_FREE_MEMORY                     " Free Memory: "
+#define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
+#define MSG_OK                              "ok"
+#define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
+#define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
+#define MSG_BEGIN_FILE_LIST                 "Begin file list"
+#define MSG_END_FILE_LIST                   "End file list"
+#define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
+#define MSG_M105_INVALID_EXTRUDER           "M105 Invalid extruder "
+#define MSG_M200_INVALID_EXTRUDER           "M200 Invalid extruder "
+#define MSG_M218_INVALID_EXTRUDER           "M218 Invalid extruder "
+#define MSG_M221_INVALID_EXTRUDER           "M221 Invalid extruder "
+#define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
+#define MSG_M109_INVALID_EXTRUDER           "M109 Invalid extruder "
+#define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
+#define MSG_ERR_KILLED                      "Printer halted. kill() called!"
+#define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
+#define MSG_RESEND                          "Resend: "
+#define MSG_M119_REPORT                     "Reporting endstop status"
+#define MSG_ENDSTOP_HIT                     "TRIGGERED"
+#define MSG_ENDSTOP_OPEN                    "open"
+#define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
+#define MSG_SD_INIT_FAIL                    "SD init fail"
+#define MSG_SD_VOL_INIT_FAIL                "volume.init failed"
+#define MSG_SD_OPENROOT_FAIL                "openRoot failed"
+#define MSG_SD_CARD_OK                      "SD card ok"
+#define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
+#define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
+#define MSG_SD_FILE_OPENED                  "File opened: "
+#define MSG_SD_FILE_SELECTED                "File selected"
+#define MSG_SD_WRITE_TO_FILE                "Writing to file: "
+#define MSG_SD_PRINTING_BYTE                "SD printing byte "
+#define MSG_SD_NOT_PRINTING                 "Not SD printing"
+#define MSG_SD_ERR_WRITE_TO_FILE            "error writing to file"
+#define MSG_SD_CANT_ENTER_SUBDIR            "Cannot enter subdir: "
+#define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
+#define MSG_ENDSTOPS_HIT                    "endstops hit: "
+#define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
+#define MSG_BABYSTEPPING_X                  "Babystepping X"
+#define MSG_BABYSTEPPING_Y                  "Babystepping Y"
+#define MSG_BABYSTEPPING_Z                  "Compensazione Z"
+#define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
+
+#define MSG_LANGUAGE_NAME		    "Italiano"
+#define MSG_LANGUAGE_SELECT		    "Seleziona lingua"
+#define MSG_PRUSA3D			    "prusa3d.com"
+#define MSG_PRUSA3D_FORUM		    "forum.prusa3d.com"
+#define MSG_PRUSA3D_HOWTO		    "howto.prusa3d.com"
+
+#define MSG_SELFTEST_ERROR		    "Autotest negativo"
+#define MSG_SELFTEST_PLEASECHECK	    "Verificare:"	
+#define MSG_SELFTEST_NOTCONNECTED	    "Non connesso"
+#define MSG_SELFTEST_HEATERTHERMISTOR	    "Riscald./Termist."
+#define MSG_SELFTEST_BEDHEATER		    "Letto/Riscald."
+#define MSG_SELFTEST_WIRINGERROR	    "Errore cablaggio"
+#define MSG_SELFTEST_ENDSTOPS		    "Finecorsa (2)"
+#define MSG_SELFTEST_MOTOR		    "Motore"
+#define MSG_SELFTEST_ENDSTOP		    "Finecorsa"
+#define MSG_SELFTEST_ENDSTOP_NOTHIT	    "Finec. fuori por."
+#define MSG_SELFTEST_OK			    "Autotest OK"
+
+#define MSG_SELFTEST_FAN					"Prova del ventilator"
+#define MSG_SELFTEST_COOLING_FAN			"Vent di stampa ant.?"
+#define MSG_SELFTEST_EXTRUDER_FAN        "Vent SX sull'ugello?"
+#define MSG_SELFTEST_FAN_YES				"Gira"
+#define MSG_SELFTEST_FAN_NO					"Non si gira"
+
+#define MSG_STATS_TOTALFILAMENT		    "Filamento tot:"
+#define MSG_STATS_TOTALPRINTTIME	    "Tempo stampa tot:"
+#define MSG_STATS_FILAMENTUSED		    "Filamento usato:"
+#define MSG_STATS_PRINTTIME		    "Tempo di stampa:"
+#define MSG_SELFTEST_START		    "Avvia autotest"
+#define MSG_SELFTEST_CHECK_ENDSTOPS	    "Verifica finecorsa"
+#define MSG_SELFTEST_CHECK_HOTEND	    "Verifica ugello"  
+#define MSG_SELFTEST_CHECK_X		    "Verifica asse X"
+#define MSG_SELFTEST_CHECK_Y		    "Verifica asse Y"
+#define MSG_SELFTEST_CHECK_Z		    "Verifica asse Z"
+#define MSG_SELFTEST_CHECK_BED		    "Verifica letto"
+#define MSG_SELFTEST_CHECK_ALLCORRECT	    "Nessun errore"
+#define MSG_SELFTEST			    "Autotest"
+#define MSG_SELFTEST_FAILED		    "Autotest fallito"
+#define MSG_STATISTICS			    "Statistiche"
+#define MSG_USB_PRINTING		    "Stampa da USB"
+#define MSG_HOMEYZ                          "Calibra Z"
+#define MSG_HOMEYZ_PROGRESS                 "Calibrando Z"
+#define MSG_HOMEYZ_DONE		            "Calibrazione OK"
+
+
+
+#define MSG_SHOW_END_STOPS					"Stato finecorsa"
+#define MSG_CALIBRATE_BED					"Calibra XYZ"
+#define MSG_CALIBRATE_BED_RESET					"Reset XYZ calibr."
+
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP 				"Calibrazione XYZ. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare."
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z 				"Calibrazione Z. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare."
+
+#define MSG_CONFIRM_NOZZLE_CLEAN					"Pulire l'ugello per la calibrazione, poi fare click."
+#define MSG_CONFIRM_CARRIAGE_AT_THE_TOP				"I carrelli Z sin/des sono altezza max?"
+
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1			"Ricerca del letto punto di calibraz."
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2			" su 4"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1		"Perfezion. il letto punto di calibraz."
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2		" su 4"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1		"Misurare l'altezza di riferimento del punto di calibrazione"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2		" su 9"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION	"Reiterazione "
+
+#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND		"Calibrazione XYZ fallita. Il punto di calibrazione sul letto non e' stato trovato."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED		"Calibrazione XYZ fallita. Si prega di consultare il manuale."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT			"Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari. Complimenti!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD			"Calibrazion XYZ corretta. Assi X/Y leggermente storti. Ben fatto!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME		"Calibrazion XYZ corretta. La distorsione verra' automaticamente compensata."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR	"Calibrazione XYZ fallita. Punto anteriore sinistro non raggiungibile."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR	"Calibrazione XYZ fallita. Punto anteriore destro non raggiungibile."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR	"Calibrazione XYZ fallita. Punti anteriori non raggiungibili."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR	"Calibrazione XYZ compromessa. Punto anteriore sinistro non raggiungibile."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR	"Calibrazione XYZ compromessa. Punto anteriore destro non raggiungibile."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR	"Calibrazione XYZ compromessa. Punti anteriori non raggiungibili."
+
+#define MSG_BED_LEVELING_FAILED_POINT_LOW				"Livellamento letto fallito.NoRispSensor Residui su ugello? In attesa di reset."
+#define MSG_BED_LEVELING_FAILED_POINT_HIGH				"Livellamento letto fallito.Risp sensore troppo prestoIn attesa di reset."
+#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED		"Livellamento letto fallito. Sensore discon. o Cavo Dann. In attesa di reset."
+
+#define MSG_NEW_FIRMWARE_AVAILABLE						"Nuova versione del firmware disponibile"
+#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE					"Prega aggiorna."
+
+#define MSG_FOLLOW_CALIBRATION_FLOW						"Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione."
+#define MSG_BABYSTEP_Z_NOT_SET							"Distanza tra la punta dell'ugello e la superficie del letto non ancora imposta. Si prega di seguire il manuale, capitolo First steps, sezione First layer calibration."
+
+#define MSG_BED_CORRECTION_MENU							"Correz. liv.letto"
+#define MSG_BED_CORRECTION_LEFT							"Sinistra  [um]"
+#define MSG_BED_CORRECTION_RIGHT						"Destra    [um]"
+#define MSG_BED_CORRECTION_FRONT						"Fronte    [um]"
+#define MSG_BED_CORRECTION_REAR							"Retro     [um]"
+#define MSG_BED_CORRECTION_RESET						"Reset"			
+
+#define MSG_MESH_BED_LEVELING							"Mesh livel. letto"
+#define MSG_MENU_CALIBRATION							"Calibrazione"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+
+#define MSG_LOOSE_PULLEY								"Puleggia lenta"
+#define MSG_FILAMENT_LOADING_T0							"Inserire filamento nell'estrusore 1. Click per continuare."
+#define MSG_FILAMENT_LOADING_T1							"Inserire filamento nell'estrusore 2. Click per continuare."
+#define MSG_FILAMENT_LOADING_T2							"Inserire filamento nell'estrusore 3. Click per continuare."
+#define MSG_FILAMENT_LOADING_T3							"Inserire filamento nell'estrusore 4. Click per continuare."
+#define MSG_CHANGE_EXTR									"Cambio estrusore."
+
+#define MSG_FIL_ADJUSTING								"Filamento in fase di regolazione. Attendere prego."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ				"I filamenti sono regolati. Si prega di pulire l'ugello per la calibrazione. Click per continuare."
+#define MSG_CALIBRATE_E									"Calibra E"
+#define MSG_E_CAL_KNOB									"Girare la manopola affinche' il segno raggiunga il corpo dell'estrusore. Click per continuare."
+#define MSG_MARK_FIL									"Segnare il filamento a 100 mm di distanza dal corpo dell'estrusore. Click per continuare."
+#define MSG_CLEAN_NOZZLE_E								"Calibrazione E terminata. Si prega di pulire l'ugello. Click per continuare."
+#define MSG_WAITING_TEMP								"In attesa del raffreddamento della testina e del piatto"
+#define MSG_FILAMENT_CLEAN								"Il colore e' nitido?"
+#define MSG_UNLOADING_FILAMENT							"Rilasc. filamento"
+#define MSG_PAPER										"Porre un foglio sotto l'ugello durante la calibrazione dei primi 4 punti. In caso l'ugello muova il foglio spegnere prontamente la stampante."
+
+#define MSG_FINISHING_MOVEMENTS							"Arresto in corso"
+#define MSG_PRINT_PAUSED								"Stampa in pausa"
+#define MSG_RESUMING_PRINT								"Stampa in ripresa"
+#define MSG_PID_EXTRUDER								"Calibrazione PID"
+#define MSG_SET_TEMPERATURE								"Imposta temperatura"
+#define MSG_PID_FINISHED								"Cal. PID completa"
+#define MSG_PID_RUNNING									"Cal. PID"
+
+#define MSG_CALIBRATE_PINDA								"Calibrare"
+#define MSG_CALIBRATION_PINDA_MENU						"Taratura temp."
+#define MSG_PINDA_NOT_CALIBRATED						"Taratura della temperatura non ancora eseguita"
+#define MSG_PINDA_PREHEAT								"Riscald. PINDA"
+#define MSG_TEMP_CALIBRATION							"Cal. temp.          "
+#define MSG_TEMP_CALIBRATION_DONE						"Taratura temperatura terminata. Fare click per continuare."
+#define MSG_TEMP_CALIBRATION_ON							"Cal. temp. [ON]"
+#define MSG_TEMP_CALIBRATION_OFF						"Cal. temp. [OFF]"
+
+#define MSG_LOAD_ALL									"Caricare tutti"
+#define MSG_LOAD_FILAMENT_1								"Caricare fil. 1"
+#define MSG_LOAD_FILAMENT_2								"Caricare fil. 2"
+#define MSG_LOAD_FILAMENT_3								"Caricare fil. 3"
+#define MSG_LOAD_FILAMENT_4								"Caricare fil. 4"
+#define MSG_UNLOAD_FILAMENT_1							"Rilasciare fil. 1"
+#define MSG_UNLOAD_FILAMENT_2							"Rilasciare fil. 1"
+#define MSG_UNLOAD_FILAMENT_3							"Rilasciare fil. 1"
+#define MSG_UNLOAD_FILAMENT_4							"Rilasciare fil. 1"
+#define MSG_UNLOAD_ALL									"Rilasciare tutti"
+#define MSG_PREPARE_FILAMENT							"Preparare filamento"
+#define MSG_ALL											"Tutti"
+#define MSG_USED										"Usati nella stampa"
+#define MSG_CURRENT										"Attuale"
+#define MSG_CHOOSE_EXTRUDER								"Seleziona estrusore:"
+#define MSG_EXTRUDER									"Estrusore"
+#define MSG_EXTRUDER_1									"Estrusore 1"
+#define MSG_EXTRUDER_2									"Estrusore 2"
+#define MSG_EXTRUDER_3									"Estrusore 3"
+#define MSG_EXTRUDER_4									"Estrusore 4"
+
+#define MSG_WIZARD							"Wizard"
+#define MSG_WIZARD_WELCOME					"Ciao, sono la tua stampante Original Prusa i3. Gradiresti aiuto attraverso il processo di configurazione?"
+#define MSG_WIZARD_QUIT						"E possibile proseguire la guide Wizard in qualsiasi momento attraverso Calibrazione -> Wizard."
+#define MSG_WIZARD_SELFTEST					"Anzitutto avviero il Self Test per controllare gli errori di assemblaggio piu comuni."
+#define MSG_WIZARD_CALIBRATION_FAILED		"Per favore consulta il nostro manuale per risolvere il problema. Poi riprendi il Wizard dopo aver riavviato la stampante."
+#define MSG_WIZARD_XYZ_CAL					"Adesso avviero una Calibrazione XYZ. Puo durare circa 12 min."
+#define MSG_WIZARD_FILAMENT_LOADED			"Il filamento e stato caricato?"
+#define MSG_WIZARD_Z_CAL					"Adesso avviero una Calibrazione Z."
+#define MSG_WIZARD_WILL_PREHEAT				"Adesso preriscaldero l'ugello per PLA."
+#define MSG_WIZARD_V2_CAL					"Adesso tarero lo stacco fra ugello e superfice del piatto."
+#define MSG_WIZARD_V2_CAL_2					"Adesso iniziero a stampare una linea e tu dovrai abbassare l'ugello poco per volta ruotando la manopola sino a raggiungere una altezza ottimale. Per favore dai uno sguardo all'immagine del nostro manuale, cap.Calibrazione."
+#define MSG_V2_CALIBRATION					"Cal. primo layer."
+#define MSG_WIZARD_DONE						"Ben fatto. Buona stampa!"
+#define MSG_WIZARD_LOAD_FILAMENT			"Per favore inserisci il filamento di PLA nell'estrusore, poi premi la manopola per caricare."
+#define MSG_WIZARD_RERUN					"Se avvi il Wizard perderai la calibrazione preesistente e dovrai ricominciare dall'inizio. Continuare?"
+#define MSG_WIZARD_REPEAT_V2_CAL			"Desideri ripetere l'ultimo passaggio per migliorare la distanza fra ugello e piatto?"
+#define MSG_WIZARD_CLEAN_HEATBED			"Per favore pulisci il piatto, poi premi la manopola."
+#define MSG_WIZARD_PLA_FILAMENT				"E questo un filamento di PLA?"
+#define MSG_WIZARD_INSERT_CORRECT_FILAMENT	"Per favore carica filamento di PLA e riprendi il Wizard dopo aver riavviato la stampante."
+#define MSG_PLA_FILAMENT_LOADED				"Il PLA e stato caricato?"
+#define MSG_PLEASE_LOAD_PLA					"Per favore prima caricare filamento di PLA."
+#define MSG_WIZARD_HEATING					"Sto preriscaldando l'ugello. Per favore attendi."
+#define MSG_M117_V2_CALIBRATION				"M117 Cal. primo layer."
+
+#define MSG_DATE							"Data"
+#define MSG_XYZ_DETAILS						"XYZ Cal. dettagli"
+#define	MSG_Y_DISTANCE_FROM_MIN				"Distanza Y da min:"
+#define	MSG_LEFT							"Sinistra:"
+#define MSG_RIGHT							"Destra:"
+#define MSG_MEASURED_SKEW					"Incl. misurata:"
+#define MSG_SLIGHT_SKEW						"Incl. leggera:"
+#define MSG_SEVERE_SKEW						"Inc. rilevante:"

+ 148 - 105
Firmware/language_pl.h

@@ -5,8 +5,6 @@
  * Please note these are limited to 17 characters!
  *
  */
-#ifndef LANGUAGE_PL_H
-#define LANGUAGE_PL_H
 
 #define WELCOME_MSG                         CUSTOM_MENDEL_NAME " gotowa"
 #define MSG_SD_INSERTED                     "Karta wlozona"
@@ -63,16 +61,17 @@
 #define MSG_PRESS                               "Nacisnij przycisk"
 #define MSG_INSERT_FILAMENT             "Wprowadz filament"
 #define MSG_CHANGING_FILAMENT   "Wymiana filamentu"
-#define MSG_SILENT_MODE_ON                                      "Mod       [cichy]"
-#define MSG_SILENT_MODE_OFF                                     "Mod [w wydajnosc]" 
+#define MSG_SILENT_MODE_ON                                      "Tryb      [cichy]"
+#define MSG_SILENT_MODE_OFF                                     "Tryb[w wydajnosc]"
+
 #define MSG_REBOOT                                                      "Restart drukarki"
-#define MSG_TAKE_EFFECT                                         "wprow. zmian"   
+#define MSG_TAKE_EFFECT                                         " wprow. zmian"   
 #define MSG_HEATING                         "Grzanie..."
 #define MSG_HEATING_COMPLETE                "Grzanie OK."
 #define MSG_BED_HEATING                     "Grzanie stolika.."
 #define MSG_BED_DONE                        "Stolik OK."
 #define MSG_LANGUAGE_NAME                                       "Polski"
-#define MSG_LANGUAGE_SELECT                                     "Wybor jezyka        "
+#define MSG_LANGUAGE_SELECT                                     "Wybor jezyka"
 #define MSG_PRUSA3D                                     "prusa3d.cz"
 #define MSG_PRUSA3D_FORUM                                       "forum.prusa3d.cz"
 #define MSG_PRUSA3D_HOWTO                                       "howto.prusa3d.cz"
@@ -82,21 +81,12 @@
  
 #define MSG_Enqueing                        "enqueing \""
 #define MSG_POWERUP                         "PowerUp"
-#define MSG_EXTERNAL_RESET                  " External Reset"
-#define MSG_BROWNOUT_RESET                  " Brown out Reset"
-#define MSG_WATCHDOG_RESET                  " Watchdog Reset"
-#define MSG_SOFTWARE_RESET                  " Software Reset"
-#define MSG_AUTHOR                          " | Author: "
 #define MSG_CONFIGURATION_VER               " Last Updated: "
 #define MSG_FREE_MEMORY                     " Free Memory: "
 #define MSG_PLANNER_BUFFER_BYTES            "  PlannerBufferBytes: "
 #define MSG_OK                              "ok"
-#define MSG_FILE_SAVED                      "Done saving file."
-#define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
 #define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
 #define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
-#define MSG_FILE_PRINTED                    "Done printing file"
 #define MSG_BEGIN_FILE_LIST                 "Begin file list"
 #define MSG_END_FILE_LIST                   "End file list"
 #define MSG_M104_INVALID_EXTRUDER           "M104 Invalid extruder "
@@ -107,23 +97,12 @@
 #define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
 #define MSG_M109_INVALID_EXTRUDER           "M109 Invalid extruder "
 #define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n"
-#define MSG_COUNT_X                         " Count X: "
 #define MSG_ERR_KILLED                      "Printer halted. kill() called!"
 #define MSG_ERR_STOPPED                     "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
 #define MSG_RESEND                          "Resend: "
-#define MSG_UNKNOWN_COMMAND                 "Unknown command: \""
-#define MSG_ACTIVE_EXTRUDER                 "Active Extruder: "
-#define MSG_INVALID_EXTRUDER                "Invalid extruder"
-#define MSG_X_MIN                           "x_min: "
-#define MSG_X_MAX                           "x_max: "
-#define MSG_Y_MIN                           "y_min: "
-#define MSG_Y_MAX                           "y_max: "
-#define MSG_Z_MIN                           "z_min: "
-#define MSG_Z_MAX                           "z_max: "
 #define MSG_M119_REPORT                     "Reporting endstop status"
 #define MSG_ENDSTOP_HIT                     "TRIGGERED"
 #define MSG_ENDSTOP_OPEN                    "open"
-#define MSG_HOTEND_OFFSET                   "Hotend offsets:"
 #define MSG_SD_CANT_OPEN_SUBDIR             "Cannot open subdir"
 #define MSG_SD_INIT_FAIL                    "SD init fail"
 #define MSG_SD_VOL_INIT_FAIL                "volume.init failed"
@@ -132,7 +111,6 @@
 #define MSG_SD_WORKDIR_FAIL                 "workDir open failed"
 #define MSG_SD_OPEN_FILE_FAIL               "open failed, File: "
 #define MSG_SD_FILE_OPENED                  "File opened: "
-#define MSG_SD_SIZE                         " Size: "
 #define MSG_SD_FILE_SELECTED                "File selected"
 #define MSG_SD_WRITE_TO_FILE                "Writing to file: "
 #define MSG_SD_PRINTING_BYTE                "SD printing byte "
@@ -142,71 +120,17 @@
 #define MSG_STEPPER_TOO_HIGH                "Steprate too high: "
 #define MSG_ENDSTOPS_HIT                    "endstops hit: "
 #define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
-#define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
 #define MSG_BABYSTEPPING_X                  "Babystepping X"
 #define MSG_BABYSTEPPING_Y                  "Babystepping Y"
-#define MSG_BABYSTEPPING_Z                  "Dostavovani Z"
+#define MSG_BABYSTEPPING_Z                  "Dostrojenie Z"
 #define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
 #define MSG_SET_HOME_OFFSETS                "Nastav pocatek home"
 #define MSG_SET_ORIGIN                      "Nastav pocatek"
-#define MSG_PREHEAT_PLA                     "Predehrev PLA"
-#define MSG_PREHEAT_PLA0                    "Predehrev PLA 1"
-#define MSG_PREHEAT_PLA1                    "Predehrev PLA 2"
-#define MSG_PREHEAT_PLA2                    "Predehrev PLA 3"
-#define MSG_PREHEAT_PLA012                  "Predehrev PLA All"
-#define MSG_PREHEAT_PLA_BEDONLY             "Predehrev PLA Bed"
-#define MSG_PREHEAT_PLA_SETTINGS            "Predehrev PLA conf"
-#define MSG_PREHEAT_ABS                     "Predehrev ABS"
-#define MSG_PREHEAT_ABS0                    "Predehrev ABS 1"
-#define MSG_PREHEAT_ABS1                    "Predehrev ABS 2"
-#define MSG_PREHEAT_ABS2                    "Predehrev ABS 3"
-#define MSG_PREHEAT_ABS012                  "Predehrev ABS All"
-#define MSG_PREHEAT_ABS_BEDONLY             "Predehrev ABS Bed"
-#define MSG_PREHEAT_ABS_SETTINGS            "Predehrev ABS conf"
 
 #define MSG_SWITCH_PS_ON                    "Vypnout zdroj"
 #define MSG_SWITCH_PS_OFF                   "Zapnout zdroj"
 
-#define MSG_AUTOTEMP                        "Autotemp"
-#define MSG_ON                              "On "
-#define MSG_OFF                             "Off"
-#define MSG_PID_P                           "PID-P"
-#define MSG_PID_I                           "PID-I"
-#define MSG_PID_D                           "PID-D"
-#define MSG_PID_C                           "PID-C"
-#define MSG_ACC                             "Accel"
-#define MSG_VXY_JERK                        "Vxy-jerk"
-#define MSG_VZ_JERK                         "Vz-jerk"
-#define MSG_VE_JERK                         "Ve-jerk"
-#define MSG_VMAX                            "Vmax "
-#define MSG_X                               "x"
-#define MSG_Y                               "y"
-#define MSG_Z                               "z"
-#define MSG_E                               "e"
-#define MSG_VMIN                            "Vmin"
-#define MSG_VTRAV_MIN                       "VTrav min"
-#define MSG_AMAX                            "Amax "
-#define MSG_A_RETRACT                       "A-retract"
-#define MSG_XSTEPS                          "Xsteps/mm"
-#define MSG_YSTEPS                          "Ysteps/mm"
-#define MSG_ZSTEPS                          "Zsteps/mm"
-#define MSG_ESTEPS                          "Esteps/mm"
-
-#define MSG_RETRACT                         "Retract"
-
-#define MSG_EXTRUDE                         "Extrudovat"
-
-#define MSG_AUTOSTART                       "Autostart"
-
-
-#define MSG_MOVE_E1                         "Extruder2"
-#define MSG_MOVE_E2                         "Extruder3"
-
-#define MSG_MOVE_01MM                       "Posunout o 0.1mm"
-#define MSG_MOVE_1MM                        "Posunout o 1mm"
-#define MSG_MOVE_10MM                       "Posunout o 10mm"
-
- #define MSG_NOZZLE1                         "Tryska2"
+#define MSG_NOZZLE1                         "Tryska2"
 #define MSG_NOZZLE2                         "Tryska3"
 
 
@@ -221,36 +145,16 @@
  #define MSG_MOTION                          "Pohyb"
 #define MSG_VOLUMETRIC                      "Filament"
 #define MSG_VOLUMETRIC_ENABLED                  "E in mm3"
-#define MSG_FILAMENT_SIZE_EXTRUDER_0        "Fil. Dia. 1"
-#define MSG_FILAMENT_SIZE_EXTRUDER_1        "Fil. Dia. 2"
-#define MSG_FILAMENT_SIZE_EXTRUDER_2        "Fil. Dia. 3"
-#define MSG_CONTRAST                        "LCD contrast"
 #define MSG_STORE_EPROM                     "Store memory"
 #define MSG_LOAD_EPROM                      "Ulozit pamet"
 #define MSG_RESTORE_FAILSAFE                "Obnovit vychozi"
 #define MSG_REFRESH                         "\xF8" "Obnovit"
 
- #define MSG_PREPARE                         "Priprava"
-
- #define MSG_CONTROL_RETRACT                 "Retract mm"
-#define MSG_CONTROL_RETRACT_SWAP            "Swap Re.mm"
-#define MSG_CONTROL_RETRACTF                "Retract  V"
-#define MSG_CONTROL_RETRACT_ZLIFT           "Hop mm"
-#define MSG_CONTROL_RETRACT_RECOVER         "UnRet +mm"
-#define MSG_CONTROL_RETRACT_RECOVER_SWAP    "S UnRet+mm"
-#define MSG_CONTROL_RETRACT_RECOVERF        "UnRet  V"
-#define MSG_AUTORETRACT                     "AutoRetr."
-
- #define MSG_INIT_SDCARD                     "Inic. SD"
+#define MSG_INIT_SDCARD                     "Inic. SD"
 #define MSG_CNG_SDCARD                      "Vymenit SD"
-#define MSG_ZPROBE_OUT                      "Z probe out. bed"
-#define MSG_POSITION_UNKNOWN                "Home X/Y before Z"
-#define MSG_ZPROBE_ZOFFSET                  "Z Offset"
 #define MSG_BABYSTEP_X                      "Babystep X"
 #define MSG_BABYSTEP_Y                      "Babystep Y"
 
- #define MSG_ENDSTOP_ABORT                   "Endstop abort"
-
  #define MSG_RECTRACT                        "Rectract"
 
 #define MSG_HOMEYZ                          "Kalibruj Z"
@@ -269,6 +173,12 @@
 #define MSG_SELFTEST_ENDSTOP_NOTHIT         "Endstop not hit"
 #define MSG_SELFTEST_OK                     "Self test OK"
 
+#define MSG_SELFTEST_FAN					"Test wentylatora"
+#define MSG_SELFTEST_COOLING_FAN			"Przedni went. druku?"
+#define MSG_SELFTEST_EXTRUDER_FAN			"Lewy went na dysze?"
+#define MSG_SELFTEST_FAN_YES				"Kreci sie"
+#define MSG_SELFTEST_FAN_NO					"Nie kreci sie"
+
 #define MSG_STATS_TOTALFILAMENT             "Filament lacznie :"
 #define MSG_STATS_TOTALPRINTTIME            "Czas calkowity :"
 #define MSG_STATS_FILAMENTUSED              "Filament :  "
@@ -288,5 +198,138 @@
 #define MSG_STATISTICS                      "Statystyka  "
 #define MSG_USB_PRINTING                    "Druk z USB  "
 
+#define MSG_SHOW_END_STOPS                  "Pokaz krancowki"
+#define MSG_CALIBRATE_BED                   "Kalibracja XYZ"
+#define MSG_CALIBRATE_BED_RESET             "Reset kalibr. XYZ"
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP        "Kalibracja XYZ. Przekrec galke, aby przesunac os Z do gornych krancowek. Nacisnij, by potwierdzic."
+#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z      "Kalibracja Z. Przekrec galke, aby przesunac os Z do gornych krancowek. Nacisnij, by potwierdzic."
+
+#define MSG_CONFIRM_NOZZLE_CLEAN            		"Dla prawidl. kalibracji prosze oczyscic dysze. Potw. guzikiem."
+#define MSG_CONFIRM_CARRIAGE_AT_THE_TOP     		"Oba wozki dojechaly do gornej ramy?"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1  		"Szukam punktu kalibracyjnego podkladki"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2  		" z 4"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1   	"Poprawiam precyzyjnosc punktu kalibracyjnego"
+#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2   	" z 4"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1		"Okreslam wysokosc odniesienia punktu kalibracyjnego"
+#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2		" z 9"
+#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION	"Iteracja "
+
+#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND           "Kalibr. XYZ nieudana. Kalibracyjny punkt podkladki nieznaleziony."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED            "Kalibracja XYZ niepowiedziona. Sprawdzic w instrukcji."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT                   "Kalibracja XYZ ok. Osie X/Y sa prostopadle. Gratulacje!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD                 "Kalibracja XYZ prawidlowa. Osie X/Y lekko skosne. Dobra robota!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME              "Kalibracja XYZ prawidlowa. Skosy beda automatycznie wyrownane przy druku."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR     "Kalibr. XYZ nieudana. Lewy przedni punkt zbyt do przodu. Wyrownac drukarke."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR    "Kalibr. XYZ nieudana. Prawy przedni punkt zbyt do przodu. Wyrownac drukarke."
+#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR     "Kalibr. XYZ nieudana. Przed. punkty kalibr. zbyt do przodu. Wyrownac drukarke."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR    "Kalibracja XYZ niedokladna. Lewy przedni punkt zbyt wysuniety do przodu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR   "Kalibracja XYZ niedokladna. Prawy przedni punkt zbyt wysuniety do przodu."
+#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR    "Kalibr. XYZ niedokladna. Przednie punkty kalibr. Zbyt wys. do przodu."
+#define MSG_BED_LEVELING_FAILED_POINT_LOW                       "Kalibracja nieudana. Sensor nie dotknal. Zanieczysz. dysza? Czekam na reset."
+#define MSG_BED_LEVELING_FAILED_POINT_HIGH                      "Kalibracja Z nieudana. Sensor dotk. za wysoko. Czekam na reset."
+#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED              "Kalibracja nieudana. Sensor odlaczony lub uszkodz. kabel. Czekam na reset."
+#define MSG_NEW_FIRMWARE_AVAILABLE                              "Wyszla nowa wersja firmware:"
+#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE                         "Prosze zaktualizowac"
+#define MSG_FOLLOW_CALIBRATION_FLOW                             "Drukarka nie zostala jeszcze skalibrowana. Prosze kierowac sie instrukcja, rozdzial Zaczynamy, podrozdzial Selftest."
+#define MSG_BABYSTEP_Z_NOT_SET                                  "Odleglosc dyszy od podkladki nie jest skalibrowana. Postepuj zgodnie z instrukcja rozdzial Zaczynamy, podrozdzial Kalibracja pierwszej warstwy."
+#define MSG_BED_CORRECTION_MENU                                 "Korekta podkladki"
+#define MSG_BED_CORRECTION_LEFT                                 "W lewo  [um]"
+#define MSG_BED_CORRECTION_RIGHT                                "W prawo [um]"
+#define MSG_BED_CORRECTION_FRONT                                "Do przodu [um]"
+#define MSG_BED_CORRECTION_REAR                                 "Do tylu  [um]"
+#define MSG_BED_CORRECTION_RESET                                "Reset"
+
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
+#define MSG_MENU_CALIBRATION									"Kalibracja"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"karta SD [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"karta SD[FlshAir]"
+
+#define MSG_LOOSE_PULLEY										"Kolo pasowe"
+#define MSG_FILAMENT_LOADING_T0									"Wloz filament do ekstrudera 1. Potwierdz przyciskiem."
+#define MSG_FILAMENT_LOADING_T1									"Wloz filament do ekstrudera 2. Potwierdz przyciskiem."
+#define MSG_FILAMENT_LOADING_T2									"Wloz filament do ekstrudera 3. Potwierdz przyciskiem."
+#define MSG_FILAMENT_LOADING_T3									"Wloz filament do ekstrudera 4. Potwierdz przyciskiem."
+#define MSG_CHANGE_EXTR											"Zmienic ekstruder"
+
+#define MSG_FIL_ADJUSTING										"Przebiega wyrownanie filamentow. Prosze czekac."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ						"Dla prawidlowej kalibracji prosze oczyscic dysze. Potem potwierdzic przyciskiem."
+#define MSG_CALIBRATE_E											"Kalibruj E"
+#define MSG_E_CAL_KNOB											"Prosze otaczac przycisk poki znacznik nie dosiegnie ciala ekstrudera. Potwierdzic przyciskiem."
+#define MSG_MARK_FIL											"Prosze oznaczyc filament 100 mm od ciala ekstrudera. Potwierdzic przyciskiem."
+#define MSG_CLEAN_NOZZLE_E										"Kalibracja E skonczona. Prosze oczyscic dysze. Potem potwierdzic przyciskiem. "
+#define MSG_WAITING_TEMP										"Oczekiwanie na wychlodzenie dyszy i podkladki."
+#define MSG_FILAMENT_CLEAN										"Czy kolor jest czysty?"
+#define MSG_UNLOADING_FILAMENT									"Wysuwam filament"
+#define MSG_PAPER												"Umiesc kartke papieru na podkladce i trzymaj pod dysza podczas pomiaru pierwszych 4 punktow. Jesli dysza zahaczy o papier, wylacz drukarke."
+
+#define MSG_FINISHING_MOVEMENTS									"Konczenie druku"
+#define MSG_PRINT_PAUSED										"Druk zatrzymany"
+#define MSG_RESUMING_PRINT										"Wznawianie druku"
+#define MSG_PID_EXTRUDER										"Kalibracja PID"
+#define MSG_SET_TEMPERATURE										"Ustawic temperature"
+#define MSG_PID_FINISHED										"Kal. PID zakonczona"
+#define MSG_PID_RUNNING											"Kal. PID"
+
+#define MSG_CALIBRATE_PINDA										"Skalibrowac"
+#define MSG_CALIBRATION_PINDA_MENU								"Cieplna kalibr."
+#define MSG_PINDA_NOT_CALIBRATED								"Cieplna kalibracja nie byla przeprowadzona"
+#define MSG_PINDA_PREHEAT										"Grzanie PINDA"
+#define MSG_TEMP_CALIBRATION									"Ciepl. kal.         "
+#define MSG_TEMP_CALIBRATION_DONE								"Cieplna kalibracja zakonczona. Kontynuuj przyciskiem"
+#define MSG_TEMP_CALIBRATION_ON									"Ciepl. kal. [ON]"
+#define MSG_TEMP_CALIBRATION_OFF								"Ciepl. kal. [OFF]"
+#define MSG_PREPARE_FILAMENT									"Przygotuj filament"
+
+#define MSG_LOAD_ALL											"Zalad. wszystkie"
+#define MSG_LOAD_FILAMENT_1										"Zaladowac fil. 1"
+#define MSG_LOAD_FILAMENT_2										"Zaladowac fil. 2"
+#define MSG_LOAD_FILAMENT_3										"Zaladowac fil. 3"
+#define MSG_LOAD_FILAMENT_4										"Zaladowac fil. 4"
+#define MSG_UNLOAD_FILAMENT_1									"Wyjac filament 1"
+#define MSG_UNLOAD_FILAMENT_2									"Wyjac filament 2"
+#define MSG_UNLOAD_FILAMENT_3									"Wyjac filament 3"
+#define MSG_UNLOAD_FILAMENT_4									"Wyjac filament 4"
+#define MSG_UNLOAD_ALL											"Wyjac wszystkie"
+#define MSG_PREPARE_FILAMENT									"Przygotuj filament"
+#define MSG_ALL													"Wszystko"
+#define MSG_USED												"Uzyte przy druku"
+#define MSG_CURRENT												"Tylko aktualne"
+#define MSG_CHOOSE_EXTRUDER										"Wybierz ekstruder"
+#define MSG_EXTRUDER											"Ekstruder"
+#define MSG_EXTRUDER_1											"Ekstruder 1"
+#define MSG_EXTRUDER_2											"Ekstruder 2"
+#define MSG_EXTRUDER_3											"Ekstruder 3"
+#define MSG_EXTRUDER_4											"Ekstruder 4"
+
+#define MSG_WIZARD							"Wizard"
+#define MSG_WIZARD_WELCOME					"Czesc, jestem Twoja drukarka Original Prusa i3. Czy potrzebujesz pomocy z instalacja?"
+#define MSG_WIZARD_QUIT						"Zawsze mozesz przywrocic Wizard przez Kalibracja -> Wizard."
+#define MSG_WIZARD_SELFTEST					"Najpierw wlacze autotest w celu kontrolli najczestszych problemow z montazem."
+#define MSG_WIZARD_CALIBRATION_FAILED		"Prosze sprawdz nasz poradnik i napraw problem. Potem przywroc Wizard restartujac drukarke."
+#define MSG_WIZARD_XYZ_CAL					"Wlaczam kalibracje xyz. Zajmie to ok. 12 min."
+#define MSG_WIZARD_FILAMENT_LOADED			"Filament jest zaladowany?"
+#define MSG_WIZARD_Z_CAL					"Wlaczam kalibracje z."
+#define MSG_WIZARD_WILL_PREHEAT				"Nagrzewam dysze dla PLA."
+#define MSG_WIZARD_V2_CAL					"Kalibruje odleglosc miedzy koncowka dyszy a stolikiem."
+#define MSG_WIZARD_V2_CAL_2					"Zaczne drukowac linie. Stopniowo opuszczaj dysze przekrecajac guzik, poki nie uzyskasz optymalnej wysokosci. Sprawdz obrazki w naszym poradniku w rozdz. Kalibracja"
+#define MSG_V2_CALIBRATION					"Kal. 1. warstwy"
+#define MSG_WIZARD_DONE						"Gotowe. Udanego druku!"
+#define MSG_WIZARD_LOAD_FILAMENT			"Prosze umiesc filament PLA w ekstruderze i nacisnij przycisk by zaladowac."
+#define MSG_WIZARD_RERUN					"Wlaczenie Wizard usunie obecne dane kalibracyjne i zacznie od nowa. Kontynuowac?"
+#define MSG_WIZARD_REPEAT_V2_CAL			"Chcesz powtorzyc ostatni krok i przestawic odleglosc miedzy dysza a stolikiem?"
+#define MSG_WIZARD_CLEAN_HEATBED			"Prosze oczysc stolik i nacisnij guzik."
+#define MSG_WIZARD_PLA_FILAMENT				"Czy to filament PLA?"
+#define MSG_WIZARD_INSERT_CORRECT_FILAMENT	"Prosze zaladuj filament PLA i przywroc Wizard przez restart drukarki."
+#define MSG_PLA_FILAMENT_LOADED				"Fialment PLA jest zaladowany?"
+#define MSG_PLEASE_LOAD_PLA					"Prosze, najpierw zaladuj filament PLA."
+#define MSG_WIZARD_HEATING					"Nagrzewanie dyszy. Prosze czekac."
+#define MSG_M117_V2_CALIBRATION				"M117 Kal. 1. warstwy"
 
-#endif // LANGUAGE_EN_H
+#define MSG_DATE							"Data:"
+#define MSG_XYZ_DETAILS						"Szczegoly kal.XYZ"
+#define	MSG_Y_DISTANCE_FROM_MIN				"Odleglosc Y od min.:"
+#define	MSG_LEFT							"Lewy:"
+#define MSG_RIGHT							"Prawy:"
+#define MSG_MEASURED_SKEW					"Zmier. sciecie:"
+#define MSG_SLIGHT_SKEW						"Lekkie sciecie:"
+#define MSG_SEVERE_SKEW						"Ostre sciecie:"

+ 29 - 0
Firmware/le.sh

@@ -0,0 +1,29 @@
+# line ending management script
+# CRLF - windows default ('\r\n')
+# LF   - unix default ('\n')
+# arguments:
+# ?crlf - print all .cpp and .h files with CRLF line endings
+# ?lf   - print all .cpp and .h files with LF line endings
+# crlf - replace line endings in all .cpp and .h files to CRLF
+# lf   - replace line endings in all .cpp and .h files to LF
+
+if [ "$1" == "?crlf" ] || [ $# -eq 0 ]; then
+ echo 'cpp and h files with CRLF line endings:'
+ find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep CRLF | sed 's/:.*//g'
+elif [ "$1" == "?lf" ]; then
+ echo 'cpp and h files with LF line endings:'
+ find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep -v CRLF | sed 's/:.*//g'
+fi
+if [ "$1" == "crlf" ]; then
+ echo 'replacing LF with CRLF in all cpp and h files:'
+ find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep -v CRLF | sed 's/:.*//g' | while read fn; do
+  echo "$fn"
+  sed -i 's/$/\r/g' $fn
+ done
+elif [ "$1" == "lf" ]; then
+ echo 'replacing CRLF with LF in all cpp and h files:'
+ find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep CRLF | sed 's/:.*//g' | while read fn; do
+  echo "$fn"
+  sed -i 's/\r\n/\n/g' $fn
+ done
+fi

+ 2613 - 2066
Firmware/mesh_bed_calibration.cpp

@@ -1,2066 +1,2613 @@
-#include "Marlin.h"
-#include "Configuration.h"
-#include "language_all.h"
-#include "mesh_bed_calibration.h"
-#include "mesh_bed_leveling.h"
-#include "stepper.h"
-#include "ultralcd.h"
-
-uint8_t world2machine_correction_mode;
-float   world2machine_rotation_and_skew[2][2];
-float   world2machine_rotation_and_skew_inv[2][2];
-float   world2machine_shift[2];
-
-// Weight of the Y coordinate for the least squares fitting of the bed induction sensor targets.
-// Only used for the first row of the points, which may not befully in reach of the sensor.
-#define WEIGHT_FIRST_ROW_X_HIGH (1.f)
-#define WEIGHT_FIRST_ROW_X_LOW  (0.35f)
-#define WEIGHT_FIRST_ROW_Y_HIGH (0.3f)
-#define WEIGHT_FIRST_ROW_Y_LOW  (0.0f)
-
-#define BED_ZERO_REF_X (- 22.f + X_PROBE_OFFSET_FROM_EXTRUDER)
-#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER)
-
-// Scaling of the real machine axes against the programmed dimensions in the firmware.
-// The correction is tiny, here around 0.5mm on 250mm length.
-//#define MACHINE_AXIS_SCALE_X ((250.f - 0.5f) / 250.f)
-//#define MACHINE_AXIS_SCALE_Y ((250.f - 0.5f) / 250.f)
-#define MACHINE_AXIS_SCALE_X 1.f
-#define MACHINE_AXIS_SCALE_Y 1.f
-
-// 0.12 degrees equals to an offset of 0.5mm on 250mm length. 
-#define BED_SKEW_ANGLE_MILD         (0.12f * M_PI / 180.f)
-// 0.25 degrees equals to an offset of 1.1mm on 250mm length.
-#define BED_SKEW_ANGLE_EXTREME      (0.25f * M_PI / 180.f)
-
-#define BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN  (0.8f)
-#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X  (0.8f)
-#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y  (1.5f)
-
-#define MIN_BED_SENSOR_POINT_RESPONSE_DMR           (2.0f)
-
-//#define Y_MIN_POS_FOR_BED_CALIBRATION (MANUAL_Y_HOME_POS-0.2f)
-#define Y_MIN_POS_FOR_BED_CALIBRATION (Y_MIN_POS)
-// Distances toward the print bed edge may not be accurate.
-#define Y_MIN_POS_CALIBRATION_POINT_ACCURATE (Y_MIN_POS + 3.f)
-// When the measured point center is out of reach of the sensor, Y coordinate will be ignored
-// by the Least Squares fitting and the X coordinate will be weighted low.
-#define Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH (Y_MIN_POS - 0.5f)
-
-// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor.
-// The points are ordered in a zig-zag fashion to speed up the calibration.
-const float bed_ref_points[] PROGMEM = {
-    13.f  - BED_ZERO_REF_X,   6.4f - BED_ZERO_REF_Y,
-    115.f - BED_ZERO_REF_X,   6.4f - BED_ZERO_REF_Y,
-    216.f - BED_ZERO_REF_X,   6.4f - BED_ZERO_REF_Y,
-
-    216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
-    115.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
-    13.f  - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
-
-    13.f  - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
-    115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
-    216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y
-};
-
-// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor.
-// The points are the following: center front, center right, center rear, center left.
-const float bed_ref_points_4[] PROGMEM = {
-    115.f - BED_ZERO_REF_X,   6.4f - BED_ZERO_REF_Y,
-    216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
-    115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
-    13.f  - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y
-};
-
-static inline float sqr(float x) { return x * x; }
-
-// Weight of a point coordinate in a least squares optimization.
-// The first row of points may not be fully reachable
-// and the y values may be shortened a bit by the bed carriage
-// pulling the belt up.
-static inline float point_weight_x(const uint8_t i, const float &y)
-{
-    float w = 1.f;
-    if (i < 3) {
-        if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) {
-            w = WEIGHT_FIRST_ROW_X_HIGH;
-        } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) {
-            // If the point is fully outside, give it some weight.
-            w = WEIGHT_FIRST_ROW_X_LOW;
-        } else {
-            // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X.
-            float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
-            w = (1.f - t) * WEIGHT_FIRST_ROW_X_LOW + t * WEIGHT_FIRST_ROW_X_HIGH;
-        }
-    }
-    return w;
-}
-
-// Weight of a point coordinate in a least squares optimization.
-// The first row of points may not be fully reachable
-// and the y values may be shortened a bit by the bed carriage
-// pulling the belt up.
-static inline float point_weight_y(const uint8_t i, const float &y)
-{
-    float w = 1.f;
-    if (i < 3) {
-        if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) {
-            w = WEIGHT_FIRST_ROW_Y_HIGH;
-        } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) {
-            // If the point is fully outside, give it some weight.
-            w = WEIGHT_FIRST_ROW_Y_LOW;
-        } else {
-            // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X.
-            float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
-            w = (1.f - t) * WEIGHT_FIRST_ROW_Y_LOW + t * WEIGHT_FIRST_ROW_Y_HIGH;
-        }
-    }
-    return w;
-}
-
-// Non-Linear Least Squares fitting of the bed to the measured induction points
-// using the Gauss-Newton method.
-// This method will maintain a unity length of the machine axes,
-// which is the correct approach if the sensor points are not measured precisely.
-BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
-    // Matrix of maximum 9 2D points (18 floats)
-    const float  *measured_pts,
-    uint8_t       npts,
-    const float  *true_pts,
-    // Resulting correction matrix.
-    float        *vec_x,
-    float        *vec_y,
-    float        *cntr,
-    // Temporary values, 49-18-(2*3)=25 floats
-    //    , float *temp
-    int8_t        verbosity_level
-    )
-{
-    if (verbosity_level >= 10) {
-        // Show the initial state, before the fitting.
-        SERIAL_ECHOPGM("X vector, initial: ");
-        MYSERIAL.print(vec_x[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(vec_x[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        SERIAL_ECHOPGM("Y vector, initial: ");
-        MYSERIAL.print(vec_y[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(vec_y[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        SERIAL_ECHOPGM("center, initial: ");
-        MYSERIAL.print(cntr[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(cntr[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        for (uint8_t i = 0; i < npts; ++i) {
-            SERIAL_ECHOPGM("point #");
-            MYSERIAL.print(int(i));
-            SERIAL_ECHOPGM(" measured: (");
-            MYSERIAL.print(measured_pts[i * 2], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(measured_pts[i * 2 + 1], 5);
-            SERIAL_ECHOPGM("); target: (");
-            MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
-            SERIAL_ECHOPGM("), error: ");
-            MYSERIAL.print(sqrt(
-                sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) +
-                sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5);
-            SERIAL_ECHOLNPGM("");
-        }
-        delay_keep_alive(100);
-    }
-
-    // Run some iterations of the Gauss-Newton method of non-linear least squares.
-    // Initial set of parameters:
-    // X,Y offset
-    cntr[0] = 0.f;
-    cntr[1] = 0.f;
-    // Rotation of the machine X axis from the bed X axis.
-    float a1 = 0;
-    // Rotation of the machine Y axis from the bed Y axis.
-    float a2 = 0;
-    for (int8_t iter = 0; iter < 100; ++iter) {
-        float c1 = cos(a1) * MACHINE_AXIS_SCALE_X;
-        float s1 = sin(a1) * MACHINE_AXIS_SCALE_X;
-        float c2 = cos(a2) * MACHINE_AXIS_SCALE_Y;
-        float s2 = sin(a2) * MACHINE_AXIS_SCALE_Y;
-        // Prepare the Normal equation for the Gauss-Newton method.
-        float A[4][4] = { 0.f };
-        float b[4] = { 0.f };
-        float acc;
-        for (uint8_t r = 0; r < 4; ++r) {
-            for (uint8_t c = 0; c < 4; ++c) {
-                acc = 0;
-                // J^T times J
-                for (uint8_t i = 0; i < npts; ++i) {
-                    // First for the residuum in the x axis:
-                    if (r != 1 && c != 1) {
-                        float a = 
-                             (r == 0) ? 1.f :
-                            ((r == 2) ? (-s1 * measured_pts[2 * i]) :
-                                        (-c2 * measured_pts[2 * i + 1]));
-                        float b = 
-                             (c == 0) ? 1.f :
-                            ((c == 2) ? (-s1 * measured_pts[2 * i]) :
-                                        (-c2 * measured_pts[2 * i + 1]));
-                        float w = point_weight_x(i, measured_pts[2 * i + 1]);
-                        acc += a * b * w;
-                    }
-                    // Second for the residuum in the y axis. 
-                    // The first row of the points have a low weight, because their position may not be known
-                    // with a sufficient accuracy.
-                    if (r != 0 && c != 0) {
-                        float a = 
-                             (r == 1) ? 1.f :
-                            ((r == 2) ? ( c1 * measured_pts[2 * i]) :
-                                        (-s2 * measured_pts[2 * i + 1]));
-                        float b = 
-                             (c == 1) ? 1.f :
-                            ((c == 2) ? ( c1 * measured_pts[2 * i]) :
-                                        (-s2 * measured_pts[2 * i + 1]));
-                        float w = point_weight_y(i, measured_pts[2 * i + 1]);
-                        acc += a * b * w;
-                    }
-                }
-                A[r][c] = acc;
-            }
-            // J^T times f(x)
-            acc = 0.f;
-            for (uint8_t i = 0; i < npts; ++i) {
-                {
-                    float j = 
-                         (r == 0) ? 1.f :
-                        ((r == 1) ? 0.f :
-                        ((r == 2) ? (-s1 * measured_pts[2 * i]) :
-                                    (-c2 * measured_pts[2 * i + 1])));
-                    float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2);
-                    float w = point_weight_x(i, measured_pts[2 * i + 1]);
-                    acc += j * fx * w;
-                }
-                {
-                    float j = 
-                         (r == 0) ? 0.f :
-                        ((r == 1) ? 1.f :
-                        ((r == 2) ? ( c1 * measured_pts[2 * i]) :
-                                    (-s2 * measured_pts[2 * i + 1])));
-                    float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1);
-                    float w = point_weight_y(i, measured_pts[2 * i + 1]);
-                    acc += j * fy * w;
-                }
-            }
-            b[r] = -acc;
-        }
-
-        // Solve for h by a Gauss iteration method.
-        float h[4] = { 0.f };
-        for (uint8_t gauss_iter = 0; gauss_iter < 100; ++gauss_iter) {
-            h[0] = (b[0] - A[0][1] * h[1] - A[0][2] * h[2] - A[0][3] * h[3]) / A[0][0];
-            h[1] = (b[1] - A[1][0] * h[0] - A[1][2] * h[2] - A[1][3] * h[3]) / A[1][1];
-            h[2] = (b[2] - A[2][0] * h[0] - A[2][1] * h[1] - A[2][3] * h[3]) / A[2][2];
-            h[3] = (b[3] - A[3][0] * h[0] - A[3][1] * h[1] - A[3][2] * h[2]) / A[3][3];
-        }
-
-        // and update the current position with h.
-        // It may be better to use the Levenberg-Marquart method here,
-        // but because we are very close to the solution alread,
-        // the simple Gauss-Newton non-linear Least Squares method works well enough.
-        cntr[0] += h[0];
-        cntr[1] += h[1];
-        a1 += h[2];
-        a2 += h[3];
-
-        if (verbosity_level >= 20) {
-            SERIAL_ECHOPGM("iteration: ");
-            MYSERIAL.print(iter, 0);
-            SERIAL_ECHOPGM("correction vector: ");
-            MYSERIAL.print(h[0], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(h[1], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(h[2], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(h[3], 5);
-            SERIAL_ECHOLNPGM("");
-            SERIAL_ECHOPGM("corrected x/y: ");
-            MYSERIAL.print(cntr[0], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(cntr[0], 5);
-            SERIAL_ECHOLNPGM("");
-            SERIAL_ECHOPGM("corrected angles: ");
-            MYSERIAL.print(180.f * a1 / M_PI, 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(180.f * a2 / M_PI, 5);
-            SERIAL_ECHOLNPGM("");
-        }
-    }
-
-    vec_x[0] =  cos(a1) * MACHINE_AXIS_SCALE_X;
-    vec_x[1] =  sin(a1) * MACHINE_AXIS_SCALE_X;
-    vec_y[0] = -sin(a2) * MACHINE_AXIS_SCALE_Y;
-    vec_y[1] =  cos(a2) * MACHINE_AXIS_SCALE_Y;
-
-    BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT;
-    {
-        float angleDiff = fabs(a2 - a1);
-        if (angleDiff > BED_SKEW_ANGLE_MILD)
-            result = (angleDiff > BED_SKEW_ANGLE_EXTREME) ?
-                BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME :
-                BED_SKEW_OFFSET_DETECTION_SKEW_MILD;
-        if (fabs(a1) > BED_SKEW_ANGLE_EXTREME ||
-            fabs(a2) > BED_SKEW_ANGLE_EXTREME)
-            result = BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME;
-    }
-
-    if (verbosity_level >= 1) {
-        SERIAL_ECHOPGM("correction angles: ");
-        MYSERIAL.print(180.f * a1 / M_PI, 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(180.f * a2 / M_PI, 5);
-        SERIAL_ECHOLNPGM("");
-    }
-
-    if (verbosity_level >= 10) {
-        // Show the adjusted state, before the fitting.
-        SERIAL_ECHOPGM("X vector new, inverted: ");
-        MYSERIAL.print(vec_x[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(vec_x[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        SERIAL_ECHOPGM("Y vector new, inverted: ");
-        MYSERIAL.print(vec_y[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(vec_y[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        SERIAL_ECHOPGM("center new, inverted: ");
-        MYSERIAL.print(cntr[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(cntr[1], 5);
-        SERIAL_ECHOLNPGM("");
-        delay_keep_alive(100);
-
-        SERIAL_ECHOLNPGM("Error after correction: ");
-    }
-
-    // Measure the error after correction.
-    for (uint8_t i = 0; i < npts; ++i) {
-        float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0];
-        float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1] + cntr[1];
-        float errX = sqr(pgm_read_float(true_pts + i * 2) - x);
-        float errY = sqr(pgm_read_float(true_pts + i * 2 + 1) - y);
-        float err = sqrt(errX + errY);
-        if (i < 3) {
-            float w = point_weight_y(i, measured_pts[2 * i + 1]);
-            if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X ||
-                (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y))
-                result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
-        } else {
-            if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN)
-                result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
-        }
-        if (verbosity_level >= 10) {
-            SERIAL_ECHOPGM("point #");
-            MYSERIAL.print(int(i));
-            SERIAL_ECHOPGM(" measured: (");
-            MYSERIAL.print(measured_pts[i * 2], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(measured_pts[i * 2 + 1], 5);
-            SERIAL_ECHOPGM("); corrected: (");
-            MYSERIAL.print(x, 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(y, 5);
-            SERIAL_ECHOPGM("); target: (");
-            MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
-            SERIAL_ECHOPGM("), error: ");
-            MYSERIAL.print(err);
-            SERIAL_ECHOLNPGM("");
-        }
-    }
-
-    #if 0
-    if (result == BED_SKEW_OFFSET_DETECTION_PERFECT && fabs(a1) < BED_SKEW_ANGLE_MILD && fabs(a2) < BED_SKEW_ANGLE_MILD) {
-        if (verbosity_level > 0)
-            SERIAL_ECHOLNPGM("Very little skew detected. Disabling skew correction.");
-        // Just disable the skew correction.
-        vec_x[0] = MACHINE_AXIS_SCALE_X;
-        vec_x[1] = 0.f;
-        vec_y[0] = 0.f;
-        vec_y[1] = MACHINE_AXIS_SCALE_Y;
-    }
-    #else
-    if (result == BED_SKEW_OFFSET_DETECTION_PERFECT) {
-        if (verbosity_level > 0)
-            SERIAL_ECHOLNPGM("Very little skew detected. Orthogonalizing the axes.");
-        // Orthogonalize the axes.
-        a1 = 0.5f * (a1 + a2);
-        vec_x[0] =  cos(a1) * MACHINE_AXIS_SCALE_X;
-        vec_x[1] =  sin(a1) * MACHINE_AXIS_SCALE_X;
-        vec_y[0] = -sin(a1) * MACHINE_AXIS_SCALE_Y;
-        vec_y[1] =  cos(a1) * MACHINE_AXIS_SCALE_Y;
-        // Refresh the offset.
-        cntr[0] = 0.f;
-        cntr[1] = 0.f;
-        float wx = 0.f;
-        float wy = 0.f;
-        for (int8_t i = 0; i < 9; ++ i) {
-            float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1];
-            float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1];
-            float w = point_weight_x(i, y);
-            cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x);
-            wx += w;
-            w = point_weight_y(i, y);
-            cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y);
-            wy += w;
-        }
-        cntr[0] /= wx;
-        cntr[1] /= wy;
-    }
-    #endif
-
-    // Invert the transformation matrix made of vec_x, vec_y and cntr.
-    {
-        float d = vec_x[0] * vec_y[1] - vec_x[1] * vec_y[0];
-        float Ainv[2][2] = {
-            { vec_y[1] / d, -vec_y[0] / d },
-            { -vec_x[1] / d, vec_x[0] / d }
-        };
-        float cntrInv[2] = {
-            -Ainv[0][0] * cntr[0] - Ainv[0][1] * cntr[1],
-            -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1]
-        };
-        vec_x[0] = Ainv[0][0];
-        vec_x[1] = Ainv[1][0];
-        vec_y[0] = Ainv[0][1];
-        vec_y[1] = Ainv[1][1];
-        cntr[0] = cntrInv[0];
-        cntr[1] = cntrInv[1];
-    }
-
-    if (verbosity_level >= 1) {
-        // Show the adjusted state, before the fitting.
-        SERIAL_ECHOPGM("X vector, adjusted: ");
-        MYSERIAL.print(vec_x[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(vec_x[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        SERIAL_ECHOPGM("Y vector, adjusted: ");
-        MYSERIAL.print(vec_y[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(vec_y[1], 5);
-        SERIAL_ECHOLNPGM("");
-
-        SERIAL_ECHOPGM("center, adjusted: ");
-        MYSERIAL.print(cntr[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(cntr[1], 5);
-        SERIAL_ECHOLNPGM("");
-        delay_keep_alive(100);
-    }
-
-    if (verbosity_level >= 2) {
-        SERIAL_ECHOLNPGM("Difference after correction: ");
-        for (uint8_t i = 0; i < npts; ++i) {
-            float x = vec_x[0] * pgm_read_float(true_pts + i * 2) + vec_y[0] * pgm_read_float(true_pts + i * 2 + 1) + cntr[0];
-            float y = vec_x[1] * pgm_read_float(true_pts + i * 2) + vec_y[1] * pgm_read_float(true_pts + i * 2 + 1) + cntr[1];
-            SERIAL_ECHOPGM("point #");
-            MYSERIAL.print(int(i));
-            SERIAL_ECHOPGM("measured: (");
-            MYSERIAL.print(measured_pts[i * 2], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(measured_pts[i * 2 + 1], 5);
-            SERIAL_ECHOPGM("); measured-corrected: (");
-            MYSERIAL.print(x, 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(y, 5);
-            SERIAL_ECHOPGM("); target: (");
-            MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
-            SERIAL_ECHOPGM("), error: ");
-            MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y)));
-            SERIAL_ECHOLNPGM("");
-        }
-        delay_keep_alive(100);
-    }
-
-    return result;
-}
-
-void reset_bed_offset_and_skew()
-{
-    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF);
-    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+4), 0x0FFFFFFFF);
-    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +0), 0x0FFFFFFFF);
-    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +4), 0x0FFFFFFFF);
-    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +0), 0x0FFFFFFFF);
-    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +4), 0x0FFFFFFFF);
-
-    // Reset the 8 16bit offsets.
-    for (int8_t i = 0; i < 4; ++ i)
-        eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*4), 0x0FFFFFFFF);
-}
-
-bool is_bed_z_jitter_data_valid()
-{
-    for (int8_t i = 0; i < 8; ++ i)
-        if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*2)) == 0x0FFFF)
-            return false;
-    return true;
-}
-
-static void world2machine_update(const float vec_x[2], const float vec_y[2], const float cntr[2])
-{
-    world2machine_rotation_and_skew[0][0] = vec_x[0];
-    world2machine_rotation_and_skew[1][0] = vec_x[1];
-    world2machine_rotation_and_skew[0][1] = vec_y[0];
-    world2machine_rotation_and_skew[1][1] = vec_y[1];
-    world2machine_shift[0] = cntr[0];
-    world2machine_shift[1] = cntr[1];
-    // No correction.
-    world2machine_correction_mode = WORLD2MACHINE_CORRECTION_NONE;
-    if (world2machine_shift[0] != 0.f || world2machine_shift[1] != 0.f)
-        // Shift correction.
-        world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SHIFT;
-    if (world2machine_rotation_and_skew[0][0] != 1.f || world2machine_rotation_and_skew[0][1] != 0.f ||
-        world2machine_rotation_and_skew[1][0] != 0.f || world2machine_rotation_and_skew[1][1] != 1.f) {
-        // Rotation & skew correction.
-        world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SKEW;
-        // Invert the world2machine matrix.
-        float d = world2machine_rotation_and_skew[0][0] * world2machine_rotation_and_skew[1][1] - world2machine_rotation_and_skew[1][0] * world2machine_rotation_and_skew[0][1];
-        world2machine_rotation_and_skew_inv[0][0] =  world2machine_rotation_and_skew[1][1] / d;
-        world2machine_rotation_and_skew_inv[0][1] = -world2machine_rotation_and_skew[0][1] / d;
-        world2machine_rotation_and_skew_inv[1][0] = -world2machine_rotation_and_skew[1][0] / d;
-        world2machine_rotation_and_skew_inv[1][1] =  world2machine_rotation_and_skew[0][0] / d;
-    } else {
-        world2machine_rotation_and_skew_inv[0][0] = 1.f;
-        world2machine_rotation_and_skew_inv[0][1] = 0.f;
-        world2machine_rotation_and_skew_inv[1][0] = 0.f;
-        world2machine_rotation_and_skew_inv[1][1] = 1.f;
-    }
-}
-
-void world2machine_reset()
-{
-    const float vx[] = { 1.f, 0.f };
-    const float vy[] = { 0.f, 1.f };
-    const float cntr[] = { 0.f, 0.f };
-    world2machine_update(vx, vy, cntr);
-}
-
-void world2machine_revert_to_uncorrected()
-{
-    if (world2machine_correction_mode != WORLD2MACHINE_CORRECTION_NONE) {
-        // Reset the machine correction matrix.
-        const float vx[] = { 1.f, 0.f };
-        const float vy[] = { 0.f, 1.f };
-        const float cntr[] = { 0.f, 0.f };
-        world2machine_update(vx, vy, cntr);
-        // Wait for the motors to stop and update the current position with the absolute values.
-        st_synchronize();
-        current_position[X_AXIS] = st_get_position_mm(X_AXIS);
-        current_position[Y_AXIS] = st_get_position_mm(Y_AXIS);
-    }
-}
-
-static inline bool vec_undef(const float v[2])
-{
-    const uint32_t *vx = (const uint32_t*)v;
-    return vx[0] == 0x0FFFFFFFF || vx[1] == 0x0FFFFFFFF;
-}
-
-void world2machine_initialize()
-{
-//    SERIAL_ECHOLNPGM("world2machine_initialize()");
-    float cntr[2] = {
-        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0)),
-        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4))
-    };
-    float vec_x[2] = {
-        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0)),
-        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4))
-    };
-    float vec_y[2] = {
-        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0)),
-        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4))
-    };
-
-    bool reset = false;
-    if (vec_undef(cntr) || vec_undef(vec_x) || vec_undef(vec_y)) {
-        // SERIAL_ECHOLNPGM("Undefined bed correction matrix.");
-        reset = true;
-    }
-    else {
-        // Length of the vec_x shall be close to unity.
-        float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
-        if (l < 0.9 || l > 1.1) {
-            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range.");
-            reset = true;
-        }
-        // Length of the vec_y shall be close to unity.
-        l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
-        if (l < 0.9 || l > 1.1) {
-            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range.");
-            reset = true;
-        }
-        // Correction of the zero point shall be reasonably small.
-        l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
-        if (l > 15.f) {
-            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Shift out of range.");
-            reset = true;
-        }
-        // vec_x and vec_y shall be nearly perpendicular.
-        l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1];
-        if (fabs(l) > 0.1f) {
-            SERIAL_ECHOLNPGM("Invalid bed correction matrix. X/Y axes are far from being perpendicular.");
-            reset = true;
-        }
-    }
-
-    if (reset) {
-        SERIAL_ECHOLNPGM("Invalid bed correction matrix. Resetting to identity.");
-        reset_bed_offset_and_skew();
-        world2machine_reset();
-    } else {
-        world2machine_update(vec_x, vec_y, cntr);
-        /*
-        SERIAL_ECHOPGM("world2machine_initialize() loaded: ");
-        MYSERIAL.print(world2machine_rotation_and_skew[0][0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(world2machine_rotation_and_skew[0][1], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(world2machine_rotation_and_skew[1][0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(world2machine_rotation_and_skew[1][1], 5);
-        SERIAL_ECHOPGM(", offset ");
-        MYSERIAL.print(world2machine_shift[0], 5);
-        SERIAL_ECHOPGM(", ");
-        MYSERIAL.print(world2machine_shift[1], 5);
-        SERIAL_ECHOLNPGM("");
-        */
-    }
-}
-
-// When switching from absolute to corrected coordinates,
-// this will get the absolute coordinates from the servos,
-// applies the inverse world2machine transformation
-// and stores the result into current_position[x,y].
-void world2machine_update_current()
-{
-    float x = current_position[X_AXIS] - world2machine_shift[0];
-    float y = current_position[Y_AXIS] - world2machine_shift[1];
-    current_position[X_AXIS] = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y;
-    current_position[Y_AXIS] = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y;
-}
-
-static inline void go_xyz(float x, float y, float z, float fr)
-{
-    plan_buffer_line(x, y, z, current_position[E_AXIS], fr, active_extruder);
-    st_synchronize();
-}
-
-static inline void go_xy(float x, float y, float fr)
-{
-    plan_buffer_line(x, y, current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder);
-    st_synchronize();
-}
-
-static inline void go_to_current(float fr)
-{
-    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder);
-    st_synchronize();
-}
-
-static inline void update_current_position_xyz()
-{
-      current_position[X_AXIS] = st_get_position_mm(X_AXIS);
-      current_position[Y_AXIS] = st_get_position_mm(Y_AXIS);
-      current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
-      plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-}
-
-static inline void update_current_position_z()
-{
-      current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
-      plan_set_z_position(current_position[Z_AXIS]);
-}
-
-// At the current position, find the Z stop.
-inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter) 
-{
-//    SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 1");
-    bool endstops_enabled  = enable_endstops(true);
-    bool endstop_z_enabled = enable_z_endstop(false);
-    float z = 0.f;
-    endstop_z_hit_on_purpose();
-
-    // move down until you find the bed
-    current_position[Z_AXIS] = minimum_z;
-    go_to_current(homing_feedrate[Z_AXIS]/60);
-    // we have to let the planner know where we are right now as it is not where we said to go.
-    update_current_position_z();
-    if (! endstop_z_hit_on_purpose())
-        goto error;
-
-    for (uint8_t i = 0; i < n_iter; ++ i) {
-        // Move up the retract distance.
-        current_position[Z_AXIS] += .5f;
-        go_to_current(homing_feedrate[Z_AXIS]/60);
-        // Move back down slowly to find bed.
-        current_position[Z_AXIS] = minimum_z;
-        go_to_current(homing_feedrate[Z_AXIS]/(4*60));
-        // we have to let the planner know where we are right now as it is not where we said to go.
-        update_current_position_z();
-        if (! endstop_z_hit_on_purpose())
-            goto error;
-//        SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: ");
-//        MYSERIAL.print(current_position[Z_AXIS], 5);
-//        SERIAL_ECHOLNPGM("");
-        z += current_position[Z_AXIS];
-    }
-    current_position[Z_AXIS] = z;
-    if (n_iter > 1)
-        current_position[Z_AXIS] /= float(n_iter);
-
-    enable_endstops(endstops_enabled);
-    enable_z_endstop(endstop_z_enabled);
-//    SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 3");
-    return true;
-
-error:
-//    SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 4");
-    enable_endstops(endstops_enabled);
-    enable_z_endstop(endstop_z_enabled);
-    return false;
-}
-
-// Search around the current_position[X,Y],
-// look for the induction sensor response.
-// Adjust the  current_position[X,Y,Z] to the center of the target dot and its response Z coordinate.
-#define FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS (8.f)
-#define FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS (6.f)
-#define FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP  (1.f)
-#define FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP   (0.5f)
-inline bool find_bed_induction_sensor_point_xy()
-{
-    float feedrate = homing_feedrate[X_AXIS] / 60.f;
-    bool found = false;
-
-    {
-        float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS;
-        float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS;
-        float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS;
-        float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS;
-        uint8_t nsteps_y;
-        uint8_t i;
-        if (x0 < X_MIN_POS)
-            x0 = X_MIN_POS;
-        if (x1 > X_MAX_POS)
-            x1 = X_MAX_POS;
-        if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
-            y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
-        if (y1 > Y_MAX_POS)
-            y1 = Y_MAX_POS;
-        nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP));
-
-        enable_endstops(false);
-        bool  dir_positive = true;
-
-//        go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60);
-        go_xyz(x0, y0, current_position[Z_AXIS], feedrate);
-        // Continously lower the Z axis.
-        endstops_hit_on_purpose();
-        enable_z_endstop(true);
-        while (current_position[Z_AXIS] > -10.f) {
-            // Do nsteps_y zig-zag movements.
-            current_position[Y_AXIS] = y0;
-            for (i = 0; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i) {
-                // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop.
-                current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y);
-                go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate);
-                dir_positive = ! dir_positive;
-                if (endstop_z_hit_on_purpose())
-                    goto endloop;
-            }
-            for (i = 0; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i) {
-                // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop.
-                current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y);
-                go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate);
-                dir_positive = ! dir_positive;
-                if (endstop_z_hit_on_purpose())
-                    goto endloop;
-            }
-        }
-        endloop:
-//        SERIAL_ECHOLN("First hit");
-
-        // we have to let the planner know where we are right now as it is not where we said to go.
-        update_current_position_xyz();
-
-        // Search in this plane for the first hit. Zig-zag first in X, then in Y axis.
-        for (int8_t iter = 0; iter < 3; ++ iter) {
-            if (iter > 0) {
-                // Slightly lower the Z axis to get a reliable trigger.
-                current_position[Z_AXIS] -= 0.02f;
-                go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60);
-            }
-
-            // Do nsteps_y zig-zag movements.
-            float a, b;
-            enable_endstops(false);
-            enable_z_endstop(false);
-            current_position[Y_AXIS] = y0;
-            go_xy(x0, current_position[Y_AXIS], feedrate);
-            enable_z_endstop(true);
-            found = false;
-            for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) {
-                go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate);
-                if (endstop_z_hit_on_purpose()) {
-                    found = true;
-                    break;
-                }
-            }
-            update_current_position_xyz();
-            if (! found) {
-//                SERIAL_ECHOLN("Search in Y - not found");
-                continue;
-            }
-//            SERIAL_ECHOLN("Search in Y - found");
-            a = current_position[Y_AXIS];
-
-            enable_z_endstop(false);
-            current_position[Y_AXIS] = y1;
-            go_xy(x0, current_position[Y_AXIS], feedrate);
-            enable_z_endstop(true);
-            found = false;
-            for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) {
-                go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate);
-                if (endstop_z_hit_on_purpose()) {
-                    found = true;
-                    break;
-                }
-            }
-            update_current_position_xyz();
-            if (! found) {
-//                SERIAL_ECHOLN("Search in Y2 - not found");
-                continue;
-            }
-//            SERIAL_ECHOLN("Search in Y2 - found");
-            b = current_position[Y_AXIS];
-            current_position[Y_AXIS] = 0.5f * (a + b);
-
-            // Search in the X direction along a cross.
-            found = false;
-            enable_z_endstop(false);
-            go_xy(x0, current_position[Y_AXIS], feedrate);
-            enable_z_endstop(true);
-            go_xy(x1, current_position[Y_AXIS], feedrate);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-//                SERIAL_ECHOLN("Search X span 0 - not found");
-                continue;
-            }
-//            SERIAL_ECHOLN("Search X span 0 - found");
-            a = current_position[X_AXIS];
-            enable_z_endstop(false);
-            go_xy(x1, current_position[Y_AXIS], feedrate);
-            enable_z_endstop(true);
-            go_xy(x0, current_position[Y_AXIS], feedrate);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-//                SERIAL_ECHOLN("Search X span 1 - not found");
-                continue;
-            }
-//            SERIAL_ECHOLN("Search X span 1 - found");
-            b = current_position[X_AXIS];
-            // Go to the center.
-            enable_z_endstop(false);
-            current_position[X_AXIS] = 0.5f * (a + b);
-            go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate);
-            found = true;
-
-#if 1
-            // Search in the Y direction along a cross.
-            found = false;
-            enable_z_endstop(false);
-            go_xy(current_position[X_AXIS], y0, feedrate);
-            enable_z_endstop(true);
-            go_xy(current_position[X_AXIS], y1, feedrate);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-//                SERIAL_ECHOLN("Search Y2 span 0 - not found");
-                continue;
-            }
-//            SERIAL_ECHOLN("Search Y2 span 0 - found");
-            a = current_position[Y_AXIS];
-            enable_z_endstop(false);
-            go_xy(current_position[X_AXIS], y1, feedrate);
-            enable_z_endstop(true);
-            go_xy(current_position[X_AXIS], y0, feedrate);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-//                SERIAL_ECHOLN("Search Y2 span 1 - not found");
-                continue;
-            }
-//            SERIAL_ECHOLN("Search Y2 span 1 - found");
-            b = current_position[Y_AXIS];
-            // Go to the center.
-            enable_z_endstop(false);
-            current_position[Y_AXIS] = 0.5f * (a + b);
-            go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate);
-            found = true;
-#endif
-            break;
-        }
-    }
-
-    enable_z_endstop(false);
-    return found;
-}
-
-// Search around the current_position[X,Y,Z].
-// It is expected, that the induction sensor is switched on at the current position.
-// Look around this center point by painting a star around the point.
-inline bool improve_bed_induction_sensor_point()
-{
-    static const float search_radius = 8.f;
-
-    bool  endstops_enabled  = enable_endstops(false);
-    bool  endstop_z_enabled = enable_z_endstop(false);
-    bool  found = false;
-    float feedrate = homing_feedrate[X_AXIS] / 60.f;
-    float center_old_x = current_position[X_AXIS];
-    float center_old_y = current_position[Y_AXIS];
-    float center_x = 0.f;
-    float center_y = 0.f;
-
-    for (uint8_t iter = 0; iter < 4; ++ iter) {
-        switch (iter) {
-        case 0:
-            destination[X_AXIS] = center_old_x - search_radius * 0.707;
-            destination[Y_AXIS] = center_old_y - search_radius * 0.707;
-            break;
-        case 1:
-            destination[X_AXIS] = center_old_x + search_radius * 0.707;
-            destination[Y_AXIS] = center_old_y + search_radius * 0.707;
-            break;
-        case 2:
-            destination[X_AXIS] = center_old_x + search_radius * 0.707;
-            destination[Y_AXIS] = center_old_y - search_radius * 0.707;
-            break;
-        case 3:
-        default:
-            destination[X_AXIS] = center_old_x - search_radius * 0.707;
-            destination[Y_AXIS] = center_old_y + search_radius * 0.707;
-            break;
-        }
-
-        // Trim the vector from center_old_[x,y] to destination[x,y] by the bed dimensions.
-        float vx = destination[X_AXIS] - center_old_x;
-        float vy = destination[Y_AXIS] - center_old_y;
-        float l  = sqrt(vx*vx+vy*vy);
-        float t;
-        if (destination[X_AXIS] < X_MIN_POS) {
-            // Exiting the bed at xmin.
-            t = (center_x - X_MIN_POS) / l;
-            destination[X_AXIS] = X_MIN_POS;
-            destination[Y_AXIS] = center_old_y + t * vy;
-        } else if (destination[X_AXIS] > X_MAX_POS) {
-            // Exiting the bed at xmax.
-            t = (X_MAX_POS - center_x) / l;
-            destination[X_AXIS] = X_MAX_POS;
-            destination[Y_AXIS] = center_old_y + t * vy;
-        }
-        if (destination[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) {
-            // Exiting the bed at ymin.
-            t = (center_y - Y_MIN_POS_FOR_BED_CALIBRATION) / l;
-            destination[X_AXIS] = center_old_x + t * vx;
-            destination[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
-        } else if (destination[Y_AXIS] > Y_MAX_POS) {
-            // Exiting the bed at xmax.
-            t = (Y_MAX_POS - center_y) / l;
-            destination[X_AXIS] = center_old_x + t * vx;
-            destination[Y_AXIS] = Y_MAX_POS;
-        }
-
-        // Move away from the measurement point.
-        enable_endstops(false);
-        go_xy(destination[X_AXIS], destination[Y_AXIS], feedrate);
-        // Move towards the measurement point, until the induction sensor triggers.
-        enable_endstops(true);
-        go_xy(center_old_x, center_old_y, feedrate);
-        update_current_position_xyz();
-//        if (! endstop_z_hit_on_purpose()) return false;
-        center_x += current_position[X_AXIS];
-        center_y += current_position[Y_AXIS];
-    }
-
-    // Calculate the new center, move to the new center.
-    center_x /= 4.f;
-    center_y /= 4.f;
-    current_position[X_AXIS] = center_x;
-    current_position[Y_AXIS] = center_y;
-    enable_endstops(false);
-    go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate);
-
-    enable_endstops(endstops_enabled);
-    enable_z_endstop(endstop_z_enabled);
-    return found;
-}
-
-static inline void debug_output_point(const char *type, const float &x, const float &y, const float &z)
-{
-    SERIAL_ECHOPGM("Measured ");
-    SERIAL_ECHORPGM(type);
-    SERIAL_ECHOPGM(" ");
-    MYSERIAL.print(x, 5);
-    SERIAL_ECHOPGM(", ");
-    MYSERIAL.print(y, 5);
-    SERIAL_ECHOPGM(", ");
-    MYSERIAL.print(z, 5);
-    SERIAL_ECHOLNPGM("");
-}
-
-// Search around the current_position[X,Y,Z].
-// It is expected, that the induction sensor is switched on at the current position.
-// Look around this center point by painting a star around the point.
-#define IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS (8.f)
-inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t verbosity_level)
-{
-    float center_old_x = current_position[X_AXIS];
-    float center_old_y = current_position[Y_AXIS];
-    float a, b;
-
-    enable_endstops(false);
-
-    {
-        float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
-        float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
-        if (x0 < X_MIN_POS)
-            x0 = X_MIN_POS;
-        if (x1 > X_MAX_POS)
-            x1 = X_MAX_POS;
-
-        // Search in the X direction along a cross.
-        enable_z_endstop(false);
-        go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-        enable_z_endstop(true);
-        go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-        update_current_position_xyz();
-        if (! endstop_z_hit_on_purpose()) {
-            current_position[X_AXIS] = center_old_x;
-            goto canceled;
-        }
-        a = current_position[X_AXIS];
-        enable_z_endstop(false);
-        go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-        enable_z_endstop(true);
-        go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-        update_current_position_xyz();
-        if (! endstop_z_hit_on_purpose()) {
-            current_position[X_AXIS] = center_old_x;
-            goto canceled;
-        }
-        b = current_position[X_AXIS];
-        if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
-            if (verbosity_level >= 5) {
-                SERIAL_ECHOPGM("Point width too small: ");
-                SERIAL_ECHO(b - a);
-                SERIAL_ECHOLNPGM("");
-            }
-            // We force the calibration routine to move the Z axis slightly down to make the response more pronounced.
-            current_position[X_AXIS] = center_old_x;
-            goto canceled;            
-        }
-        if (verbosity_level >= 5) {
-            debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
-            debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
-        }
-
-        // Go to the center.
-        enable_z_endstop(false);
-        current_position[X_AXIS] = 0.5f * (a + b);
-        go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-    }
-
-    {
-        float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
-        float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
-        if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
-            y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
-        if (y1 > Y_MAX_POS)
-            y1 = Y_MAX_POS;
-
-        // Search in the Y direction along a cross.
-        enable_z_endstop(false);
-        go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f);
-        if (lift_z_on_min_y) {
-            // The first row of points are very close to the end stop.
-            // Lift the sensor to disengage the trigger. This is necessary because of the sensor hysteresis.
-            go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS]+1.5f, homing_feedrate[Z_AXIS] / 60.f);
-            // and go back.
-            go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS], homing_feedrate[Z_AXIS] / 60.f);
-        }
-        if (lift_z_on_min_y && (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) {
-            // Already triggering before we started the move.
-            // Shift the trigger point slightly outwards.
-            // a = current_position[Y_AXIS] - 1.5f;
-            a = current_position[Y_AXIS];
-        } else {
-            enable_z_endstop(true);
-            go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                current_position[Y_AXIS] = center_old_y;
-                goto canceled;
-            }
-            a = current_position[Y_AXIS];
-        }
-        enable_z_endstop(false);
-        go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f);
-        enable_z_endstop(true);
-        go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f);
-        update_current_position_xyz();
-        if (! endstop_z_hit_on_purpose()) {
-            current_position[Y_AXIS] = center_old_y;
-            goto canceled;
-        }
-        b = current_position[Y_AXIS];
-        if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
-            // We force the calibration routine to move the Z axis slightly down to make the response more pronounced.
-            if (verbosity_level >= 5) {
-                SERIAL_ECHOPGM("Point height too small: ");
-                SERIAL_ECHO(b - a);
-                SERIAL_ECHOLNPGM("");
-            }
-            current_position[Y_AXIS] = center_old_y;
-            goto canceled;
-        }
-        if (verbosity_level >= 5) {
-            debug_output_point(PSTR("top" ), current_position[X_AXIS], a, current_position[Z_AXIS]);
-            debug_output_point(PSTR("bottom"), current_position[X_AXIS], b, current_position[Z_AXIS]);
-        }
-
-        // Go to the center.
-        enable_z_endstop(false);
-        current_position[Y_AXIS] = 0.5f * (a + b);
-        go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-    }
-
-    return true;
-
-canceled:
-    // Go back to the center.
-    enable_z_endstop(false);
-    go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-    return false;
-}
-
-// Searching the front points, where one cannot move the sensor head in front of the sensor point.
-// Searching in a zig-zag movement in a plane for the maximum width of the response.
-// This function may set the current_position[Y_AXIS] below Y_MIN_POS, if the function succeeded.
-// If this function failed, the Y coordinate will never be outside the working space.
-#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (4.f)
-#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f)
-inline bool improve_bed_induction_sensor_point3(int verbosity_level)
-{
-    float center_old_x = current_position[X_AXIS];
-    float center_old_y = current_position[Y_AXIS];
-    float a, b;
-    bool  result = true;
-
-    // Was the sensor point detected too far in the minus Y axis?
-    // If yes, the center of the induction point cannot be reached by the machine.
-    {
-        float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-        float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-        float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-        float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-        float y = y0;
-
-        if (x0 < X_MIN_POS)
-            x0 = X_MIN_POS;
-        if (x1 > X_MAX_POS)
-            x1 = X_MAX_POS;
-        if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
-            y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
-        if (y1 > Y_MAX_POS)
-            y1 = Y_MAX_POS;
-
-        if (verbosity_level >= 20) {
-            SERIAL_ECHOPGM("Initial position: ");
-            SERIAL_ECHO(center_old_x);
-            SERIAL_ECHOPGM(", ");
-            SERIAL_ECHO(center_old_y);
-            SERIAL_ECHOLNPGM("");
-        }
-
-        // Search in the positive Y direction, until a maximum diameter is found.
-        // (the next diameter is smaller than the current one.)
-        float dmax = 0.f;
-        float xmax1 = 0.f;
-        float xmax2 = 0.f;
-        for (y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
-            enable_z_endstop(false);
-            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-            enable_z_endstop(true);
-            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                continue;
-                // SERIAL_PROTOCOLPGM("Failed 1\n");
-                // current_position[X_AXIS] = center_old_x;
-                // goto canceled;
-            }
-            a = current_position[X_AXIS];
-            enable_z_endstop(false);
-            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-            enable_z_endstop(true);
-            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                continue;
-                // SERIAL_PROTOCOLPGM("Failed 2\n");
-                // current_position[X_AXIS] = center_old_x;
-                // goto canceled;
-            }
-            b = current_position[X_AXIS];
-            if (verbosity_level >= 5) {
-                debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
-                debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
-            }
-            float d = b - a;
-            if (d > dmax) {
-                xmax1 = 0.5f * (a + b);
-                dmax = d;
-            } else if (dmax > 0.) {
-                y0 = y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
-                break;
-            }
-        }
-        if (dmax == 0.) {
-            if (verbosity_level > 0)
-                SERIAL_PROTOCOLPGM("failed - not found\n");
-            current_position[X_AXIS] = center_old_x;
-            current_position[Y_AXIS] = center_old_y;
-            goto canceled;
-        }
-
-        {
-            // Find the positive Y hit. This gives the extreme Y value for the search of the maximum diameter in the -Y direction.
-            enable_z_endstop(false);
-            go_xy(xmax1, y0 + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f);
-            enable_z_endstop(true);
-            go_xy(xmax1, max(y0 - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                current_position[Y_AXIS] = center_old_y;
-                goto canceled;
-            }
-            if (verbosity_level >= 5)
-                debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
-            y1 = current_position[Y_AXIS];
-        }
-
-        if (y1 <= y0) {
-            // Either the induction sensor is too high, or the induction sensor target is out of reach.
-            current_position[Y_AXIS] = center_old_y;
-            goto canceled;
-        }
-
-        // Search in the negative Y direction, until a maximum diameter is found.
-        dmax = 0.f;
-        // if (y0 + 1.f < y1)
-        //    y1 = y0 + 1.f;
-        for (y = y1; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
-            enable_z_endstop(false);
-            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-            enable_z_endstop(true);
-            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                continue;
-                /*
-                current_position[X_AXIS] = center_old_x;
-                SERIAL_PROTOCOLPGM("Failed 3\n");
-                goto canceled;
-                */
-            }
-            a = current_position[X_AXIS];
-            enable_z_endstop(false);
-            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-            enable_z_endstop(true);
-            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                continue;
-                /*
-                current_position[X_AXIS] = center_old_x;
-                SERIAL_PROTOCOLPGM("Failed 4\n");
-                goto canceled;
-                */
-            }
-            b = current_position[X_AXIS];
-            if (verbosity_level >= 5) {
-                debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
-                debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
-            }
-            float d = b - a;
-            if (d > dmax) {
-                xmax2 = 0.5f * (a + b);
-                dmax = d;
-            } else if (dmax > 0.) {
-                y1 = y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
-                break;
-            }
-        }
-        float xmax, ymax;
-        if (dmax == 0.f) {
-            // Only the hit in the positive direction found.
-            xmax = xmax1;
-            ymax = y0;
-        } else {
-            // Both positive and negative directions found.
-            xmax = xmax2;
-            ymax = 0.5f * (y0 + y1);
-            for (; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
-                enable_z_endstop(false);
-                go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-                enable_z_endstop(true);
-                go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-                update_current_position_xyz();
-                if (! endstop_z_hit_on_purpose()) {
-                    continue;
-                    /*
-                    current_position[X_AXIS] = center_old_x;
-                    SERIAL_PROTOCOLPGM("Failed 3\n");
-                    goto canceled;
-                    */
-                }
-                a = current_position[X_AXIS];
-                enable_z_endstop(false);
-                go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-                enable_z_endstop(true);
-                go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-                update_current_position_xyz();
-                if (! endstop_z_hit_on_purpose()) {
-                    continue;
-                    /*
-                    current_position[X_AXIS] = center_old_x;
-                    SERIAL_PROTOCOLPGM("Failed 4\n");
-                    goto canceled;
-                    */
-                }
-                b = current_position[X_AXIS];
-                if (verbosity_level >= 5) {
-                    debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
-                    debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
-                }
-                float d = b - a;
-                if (d > dmax) {
-                    xmax = 0.5f * (a + b);
-                    ymax = y;
-                    dmax = d;
-                }
-            }
-        }
-
-        {
-            // Compare the distance in the Y+ direction with the diameter in the X direction.
-            // Find the positive Y hit once again, this time along the Y axis going through the X point with the highest diameter.
-            enable_z_endstop(false);
-            go_xy(xmax, ymax + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f);
-            enable_z_endstop(true);
-            go_xy(xmax, max(ymax - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f);
-            update_current_position_xyz();
-            if (! endstop_z_hit_on_purpose()) {
-                current_position[Y_AXIS] = center_old_y;
-                goto canceled;
-            }
-            if (verbosity_level >= 5)
-                debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
-            if (current_position[Y_AXIS] - Y_MIN_POS_FOR_BED_CALIBRATION < 0.5f * dmax) {
-                // Probably not even a half circle was detected. The induction point is likely too far in the minus Y direction.
-                // First verify, if the measurement has been done at a sufficient height. If no, lower the Z axis a bit.
-                if (current_position[Y_AXIS] < ymax || dmax < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
-                    if (verbosity_level >= 5) {
-                        SERIAL_ECHOPGM("Partial point diameter too small: ");
-                        SERIAL_ECHO(dmax);
-                        SERIAL_ECHOLNPGM("");
-                    }
-                    result = false;
-                } else {
-                    // Estimate the circle radius from the maximum diameter and height:
-                    float h = current_position[Y_AXIS] - ymax;
-                    float r = dmax * dmax / (8.f * h) + 0.5f * h;
-                    if (r < 0.8f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
-                        if (verbosity_level >= 5) {
-                            SERIAL_ECHOPGM("Partial point estimated radius too small: ");
-                            SERIAL_ECHO(r);
-                            SERIAL_ECHOPGM(", dmax:");
-                            SERIAL_ECHO(dmax);
-                            SERIAL_ECHOPGM(", h:");
-                            SERIAL_ECHO(h);
-                            SERIAL_ECHOLNPGM("");
-                        }
-                        result = false;
-                    } else {
-                        // The point may end up outside of the machine working space.
-                        // That is all right as it helps to improve the accuracy of the measurement point
-                        // due to averaging.
-                        // For the y correction, use an average of dmax/2 and the estimated radius.
-                        r = 0.5f * (0.5f * dmax + r);
-                        ymax = current_position[Y_AXIS] - r;
-                    }
-                }
-            } else {
-                // If the diameter of the detected spot was smaller than a minimum allowed,
-                // the induction sensor is probably too high. Returning false will force
-                // the sensor to be lowered a tiny bit.
-                result = xmax >= MIN_BED_SENSOR_POINT_RESPONSE_DMR;
-                if (y0 > Y_MIN_POS_FOR_BED_CALIBRATION + 0.2f)
-                    // Only in case both left and right y tangents are known, use them.
-                    // If y0 is close to the bed edge, it may not be symmetric to the right tangent.
-                    ymax = 0.5f * ymax + 0.25f * (y0 + y1);
-            }
-        }
-
-        // Go to the center.
-        enable_z_endstop(false);
-        current_position[X_AXIS] = xmax;
-        current_position[Y_AXIS] = ymax;
-        if (verbosity_level >= 20) {
-            SERIAL_ECHOPGM("Adjusted position: ");
-            SERIAL_ECHO(current_position[X_AXIS]);
-            SERIAL_ECHOPGM(", ");
-            SERIAL_ECHO(current_position[Y_AXIS]);
-            SERIAL_ECHOLNPGM("");
-        }
-
-        // Don't clamp current_position[Y_AXIS], because the out-of-reach Y coordinate may actually be true.
-        // Only clamp the coordinate to go.
-        go_xy(current_position[X_AXIS], max(Y_MIN_POS, current_position[Y_AXIS]), homing_feedrate[X_AXIS] / 60.f);
-        // delay_keep_alive(3000);
-    }
-
-    if (result)
-        return true;
-    // otherwise clamp the Y coordinate
-
-canceled:
-    // Go back to the center.
-    enable_z_endstop(false);
-    if (current_position[Y_AXIS] < Y_MIN_POS)
-        current_position[Y_AXIS] = Y_MIN_POS;
-    go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-    return false;
-}
-
-// Scan the mesh bed induction points one by one by a left-right zig-zag movement,
-// write the trigger coordinates to the serial line.
-// Useful for visualizing the behavior of the bed induction detector.
-inline void scan_bed_induction_sensor_point()
-{
-    float center_old_x = current_position[X_AXIS];
-    float center_old_y = current_position[Y_AXIS];
-    float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-    float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-    float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-    float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
-    float y = y0;
-
-    if (x0 < X_MIN_POS)
-        x0 = X_MIN_POS;
-    if (x1 > X_MAX_POS)
-        x1 = X_MAX_POS;
-    if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
-        y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
-    if (y1 > Y_MAX_POS)
-        y1 = Y_MAX_POS;
-
-    for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
-        enable_z_endstop(false);
-        go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-        enable_z_endstop(true);
-        go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-        update_current_position_xyz();
-        if (endstop_z_hit_on_purpose())
-            debug_output_point(PSTR("left" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
-        enable_z_endstop(false);
-        go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
-        enable_z_endstop(true);
-        go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
-        update_current_position_xyz();
-        if (endstop_z_hit_on_purpose())
-            debug_output_point(PSTR("right"), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
-    }
-
-    enable_z_endstop(false);
-    current_position[X_AXIS] = center_old_x;
-    current_position[Y_AXIS] = center_old_y;
-    go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
-}
-
-#define MESH_BED_CALIBRATION_SHOW_LCD
-
-BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level)
-{
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    // Reusing the z_values memory for the measurement cache.
-    // 7x7=49 floats, good for 16 (x,y,z) vectors.
-    float *pts = &mbl.z_values[0][0];
-    float *vec_x = pts + 2 * 4;
-    float *vec_y = vec_x + 2;
-    float *cntr  = vec_y + 2;
-    memset(pts, 0, sizeof(float) * 7 * 7);
-
-//    SERIAL_ECHOLNPGM("find_bed_offset_and_skew verbosity level: ");
-//    SERIAL_ECHO(int(verbosity_level));
-//    SERIAL_ECHOPGM("");
-
-#ifdef MESH_BED_CALIBRATION_SHOW_LCD
-    lcd_implementation_clear();
-    lcd_print_at_PGM(0, 0, MSG_FIND_BED_OFFSET_AND_SKEW_LINE1);
-#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
-
-    // Collect the rear 2x3 points.
-    current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-    for (int k = 0; k < 4; ++ k) {
-        // Don't let the manage_inactivity() function remove power from the motors.
-        refresh_cmd_timeout();
-#ifdef MESH_BED_CALIBRATION_SHOW_LCD
-        lcd_print_at_PGM(0, 1, MSG_FIND_BED_OFFSET_AND_SKEW_LINE2);
-        lcd_implementation_print_at(0, 2, k+1);
-        lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE3);
-#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
-        float *pt = pts + k * 2;
-        // Go up to z_initial.
-        go_to_current(homing_feedrate[Z_AXIS] / 60.f);
-        if (verbosity_level >= 20) {
-            // Go to Y0, wait, then go to Y-4.
-            current_position[Y_AXIS] = 0.f;
-            go_to_current(homing_feedrate[X_AXIS] / 60.f);
-            SERIAL_ECHOLNPGM("At Y0");
-            delay_keep_alive(5000);
-            current_position[Y_AXIS] = Y_MIN_POS;
-            go_to_current(homing_feedrate[X_AXIS] / 60.f);
-            SERIAL_ECHOLNPGM("At Y-4");
-            delay_keep_alive(5000);
-        }
-        // Go to the measurement point position.
-        current_position[X_AXIS] = pgm_read_float(bed_ref_points_4+k*2);
-        current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4+k*2+1);
-        go_to_current(homing_feedrate[X_AXIS] / 60.f);
-        if (verbosity_level >= 10)
-            delay_keep_alive(3000);
-        if (! find_bed_induction_sensor_point_xy())
-            return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
-#if 1
-        if (k == 0) {
-            // Improve the position of the 1st row sensor points by a zig-zag movement.
-            find_bed_induction_sensor_point_z();
-            int8_t i = 4;
-            for (;;) {
-                if (improve_bed_induction_sensor_point3(verbosity_level))
-                    break;
-                if (-- i == 0)
-                    return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
-                // Try to move the Z axis down a bit to increase a chance of the sensor to trigger.
-                current_position[Z_AXIS] -= 0.025f;
-                enable_endstops(false);
-                enable_z_endstop(false);
-                go_to_current(homing_feedrate[Z_AXIS]);
-            }
-            if (i == 0)
-                // not found
-                return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
-        }
-#endif
-        if (verbosity_level >= 10)
-            delay_keep_alive(3000);
-        // Save the detected point position and then clamp the Y coordinate, which may have been estimated
-        // to lie outside the machine working space.
-        pt[0] = current_position[X_AXIS];
-        pt[1] = current_position[Y_AXIS];
-        if (current_position[Y_AXIS] < Y_MIN_POS)
-            current_position[Y_AXIS] = Y_MIN_POS;
-        // Start searching for the other points at 3mm above the last point.
-        current_position[Z_AXIS] += 3.f;
-        cntr[0] += pt[0];
-        cntr[1] += pt[1];
-        if (verbosity_level >= 10 && k == 0) {
-            // Show the zero. Test, whether the Y motor skipped steps.
-            current_position[Y_AXIS] = MANUAL_Y_HOME_POS;
-            go_to_current(homing_feedrate[X_AXIS] / 60.f);
-            delay_keep_alive(3000);
-        }
-    }
-
-    if (verbosity_level >= 20) {
-        // Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
-        delay_keep_alive(3000);
-        for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) {
-            // Don't let the manage_inactivity() function remove power from the motors.
-            refresh_cmd_timeout();
-            // Go to the measurement point.
-            // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
-            current_position[X_AXIS] = pts[mesh_point*2];
-            current_position[Y_AXIS] = pts[mesh_point*2+1];
-            go_to_current(homing_feedrate[X_AXIS]/60);
-            delay_keep_alive(3000);
-        }
-    }
-
-    BedSkewOffsetDetectionResultType result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level);
-    if (result >= 0) {
-        world2machine_update(vec_x, vec_y, cntr);
-    #if 1
-        // Fearlessly store the calibration values into the eeprom.
-        eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]);
-        eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]);
-        eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]);
-        eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]);
-        eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]);
-        eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]);
-    #endif
-
-        // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set.
-        world2machine_update_current();
-
-        if (verbosity_level >= 20) {
-            // Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
-            delay_keep_alive(3000);
-            for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
-                // Don't let the manage_inactivity() function remove power from the motors.
-                refresh_cmd_timeout();
-                // Go to the measurement point.
-                // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
-                current_position[X_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2);
-                current_position[Y_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2+1);
-                go_to_current(homing_feedrate[X_AXIS]/60);
-                delay_keep_alive(3000);
-            }
-        }
-    }
-
-    return result;
-}
-
-BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask)
-{
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    // Mask of the first three points. Are they too far?
-    too_far_mask = 0;
-
-    // Reusing the z_values memory for the measurement cache.
-    // 7x7=49 floats, good for 16 (x,y,z) vectors.
-    float *pts = &mbl.z_values[0][0];
-    float *vec_x = pts + 2 * 9;
-    float *vec_y = vec_x + 2;
-    float *cntr  = vec_y + 2;
-    memset(pts, 0, sizeof(float) * 7 * 7);
-
-    // Cache the current correction matrix.
-    world2machine_initialize();
-    vec_x[0] = world2machine_rotation_and_skew[0][0];
-    vec_x[1] = world2machine_rotation_and_skew[1][0];
-    vec_y[0] = world2machine_rotation_and_skew[0][1];
-    vec_y[1] = world2machine_rotation_and_skew[1][1];
-    cntr[0] = world2machine_shift[0];
-    cntr[1] = world2machine_shift[1];
-    // and reset the correction matrix, so the planner will not do anything.
-    world2machine_reset();
-
-    bool endstops_enabled  = enable_endstops(false);
-    bool endstop_z_enabled = enable_z_endstop(false);
-
-#ifdef MESH_BED_CALIBRATION_SHOW_LCD
-    lcd_implementation_clear();
-    lcd_print_at_PGM(0, 0, MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1);
-#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
-
-    // Collect a matrix of 9x9 points.
-    BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT;
-    for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
-        // Don't let the manage_inactivity() function remove power from the motors.
-        refresh_cmd_timeout();
-        // Print the decrasing ID of the measurement point.
-#ifdef MESH_BED_CALIBRATION_SHOW_LCD
-        lcd_print_at_PGM(0, 1, MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2);
-        lcd_implementation_print_at(0, 2, mesh_point+1);
-        lcd_printPGM(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE3);
-#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
-
-        // Move up.
-        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-        enable_endstops(false);
-        enable_z_endstop(false);
-        go_to_current(homing_feedrate[Z_AXIS]/60);
-        if (verbosity_level >= 20) {
-            // Go to Y0, wait, then go to Y-4.
-            current_position[Y_AXIS] = 0.f;
-            go_to_current(homing_feedrate[X_AXIS] / 60.f);
-            SERIAL_ECHOLNPGM("At Y0");
-            delay_keep_alive(5000);
-            current_position[Y_AXIS] = Y_MIN_POS;
-            go_to_current(homing_feedrate[X_AXIS] / 60.f);
-            SERIAL_ECHOLNPGM("At Y-4");
-            delay_keep_alive(5000);
-        }
-        // Go to the measurement point.
-        // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
-        current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0];
-        current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1];
-        // The calibration points are very close to the min Y.
-        if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION)
-            current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
-        go_to_current(homing_feedrate[X_AXIS]/60);
-        // Find its Z position by running the normal vertical search.
-        if (verbosity_level >= 10)
-            delay_keep_alive(3000);
-        find_bed_induction_sensor_point_z();
-        if (verbosity_level >= 10)
-            delay_keep_alive(3000);
-        // Try to move the Z axis down a bit to increase a chance of the sensor to trigger.
-        current_position[Z_AXIS] -= 0.025f;
-        // Improve the point position by searching its center in a current plane.
-        int8_t n_errors = 3;
-        for (int8_t iter = 0; iter < 8; ) {
-            if (verbosity_level > 20) {
-                SERIAL_ECHOPGM("Improving bed point ");
-                SERIAL_ECHO(mesh_point);
-                SERIAL_ECHOPGM(", iteration ");
-                SERIAL_ECHO(iter);
-                SERIAL_ECHOPGM(", z");
-                MYSERIAL.print(current_position[Z_AXIS], 5);
-                SERIAL_ECHOLNPGM("");
-            }
-            bool found = false;
-            if (mesh_point < 3) {
-                // Because the sensor cannot move in front of the first row
-                // of the sensor points, the y position cannot be measured
-                // by a cross center method.
-                // Use a zig-zag search for the first row of the points.
-                found = improve_bed_induction_sensor_point3(verbosity_level);
-            } else {
-                switch (method) {
-                    case 0: found = improve_bed_induction_sensor_point(); break;
-                    case 1: found = improve_bed_induction_sensor_point2(mesh_point < 3, verbosity_level); break;
-                    default: break;
-                }
-            }
-            if (found) {
-                if (iter > 3) {
-                    // Average the last 4 measurements.
-                    pts[mesh_point*2  ] += current_position[X_AXIS];
-                    pts[mesh_point*2+1] += current_position[Y_AXIS];
-                }
-                if (current_position[Y_AXIS] < Y_MIN_POS)
-                    current_position[Y_AXIS] = Y_MIN_POS;
-                ++ iter;
-            } else if (n_errors -- == 0) {
-                // Give up.
-                result = BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
-                goto canceled;
-            } else {
-                // Try to move the Z axis down a bit to increase a chance of the sensor to trigger.
-                current_position[Z_AXIS] -= 0.05f;
-                enable_endstops(false);
-                enable_z_endstop(false);
-                go_to_current(homing_feedrate[Z_AXIS]);
-                if (verbosity_level >= 5) {
-                    SERIAL_ECHOPGM("Improving bed point ");
-                    SERIAL_ECHO(mesh_point);
-                    SERIAL_ECHOPGM(", iteration ");
-                    SERIAL_ECHO(iter);
-                    SERIAL_ECHOPGM(" failed. Lowering z to ");
-                    MYSERIAL.print(current_position[Z_AXIS], 5);
-                    SERIAL_ECHOLNPGM("");
-                }
-            }
-        }
-        if (verbosity_level >= 10)
-            delay_keep_alive(3000);
-    }
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    // Average the last 4 measurements.
-    for (int8_t i = 0; i < 18; ++ i)
-        pts[i] *= (1.f/4.f);
-
-    enable_endstops(false);
-    enable_z_endstop(false);
-
-    if (verbosity_level >= 5) {
-        // Test the positions. Are the positions reproducible?
-        for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
-            // Don't let the manage_inactivity() function remove power from the motors.
-            refresh_cmd_timeout();
-            // Go to the measurement point.
-            // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
-            current_position[X_AXIS] = pts[mesh_point*2];
-            current_position[Y_AXIS] = pts[mesh_point*2+1];
-            if (verbosity_level >= 10) {
-                go_to_current(homing_feedrate[X_AXIS]/60);
-                delay_keep_alive(3000);
-            }
-            SERIAL_ECHOPGM("Final measured bed point ");
-            SERIAL_ECHO(mesh_point);
-            SERIAL_ECHOPGM(": ");
-            MYSERIAL.print(current_position[X_AXIS], 5);
-            SERIAL_ECHOPGM(", ");
-            MYSERIAL.print(current_position[Y_AXIS], 5);
-            SERIAL_ECHOLNPGM("");
-        }
-    }
-
-    {
-        // First fill in the too_far_mask from the measured points.
-        for (uint8_t mesh_point = 0; mesh_point < 3; ++ mesh_point)
-            if (pts[mesh_point * 2 + 1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH)
-                too_far_mask |= 1 << mesh_point;
-        result = calculate_machine_skew_and_offset_LS(pts, 9, bed_ref_points, vec_x, vec_y, cntr, verbosity_level);
-        if (result < 0) {
-            SERIAL_ECHOLNPGM("Calculation of the machine skew and offset failed.");
-            goto canceled;
-        }
-        // In case of success, update the too_far_mask from the calculated points.
-        for (uint8_t mesh_point = 0; mesh_point < 3; ++ mesh_point) {
-            float y = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1];
-            if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH)
-                too_far_mask |= 1 << mesh_point;
-        }
-    }
-
-    world2machine_update(vec_x, vec_y, cntr);
-#if 1
-    // Fearlessly store the calibration values into the eeprom.
-    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]);
-    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]);
-    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]);
-    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]);
-    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]);
-    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]);
-#endif
-
-    // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set.
-    world2machine_update_current();
-
-    enable_endstops(false);
-    enable_z_endstop(false);
-
-    if (verbosity_level >= 5) {
-        // Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
-        delay_keep_alive(3000);
-        for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
-            // Don't let the manage_inactivity() function remove power from the motors.
-            refresh_cmd_timeout();
-            // Go to the measurement point.
-            // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
-            current_position[X_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2);
-            current_position[Y_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2+1);
-            if (verbosity_level >= 10) {
-                go_to_current(homing_feedrate[X_AXIS]/60);
-                delay_keep_alive(3000);
-            }
-            {
-                float x, y;
-                world2machine(current_position[X_AXIS], current_position[Y_AXIS], x, y);
-                SERIAL_ECHOPGM("Final calculated bed point ");
-                SERIAL_ECHO(mesh_point);
-                SERIAL_ECHOPGM(": ");
-                MYSERIAL.print(x, 5);
-                SERIAL_ECHOPGM(", ");
-                MYSERIAL.print(y, 5);
-                SERIAL_ECHOLNPGM("");
-            }
-        }
-    }
-
-    // Sample Z heights for the mesh bed leveling.
-    // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process.
-    {
-        // The first point defines the reference.
-        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-        go_to_current(homing_feedrate[Z_AXIS]/60);
-        current_position[X_AXIS] = pgm_read_float(bed_ref_points);
-        current_position[Y_AXIS] = pgm_read_float(bed_ref_points+1);
-        world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-        go_to_current(homing_feedrate[X_AXIS]/60);
-        memcpy(destination, current_position, sizeof(destination));
-        enable_endstops(true);
-        homeaxis(Z_AXIS);
-        enable_endstops(false);
-        find_bed_induction_sensor_point_z();
-        mbl.set_z(0, 0, current_position[Z_AXIS]);
-    }
-    for (int8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) {
-        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-        go_to_current(homing_feedrate[Z_AXIS]/60);
-        current_position[X_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point);
-        current_position[Y_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point+1);
-        world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-        go_to_current(homing_feedrate[X_AXIS]/60);
-        find_bed_induction_sensor_point_z();
-        // Get cords of measuring point
-        int8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS;
-        int8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
-        if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag
-        mbl.set_z(ix, iy, current_position[Z_AXIS]);
-    }
-    {
-        // Verify the span of the Z values.
-        float zmin = mbl.z_values[0][0];
-        float zmax = zmax;
-        for (int8_t j = 0; j < 3; ++ j)
-           for (int8_t i = 0; i < 3; ++ i) {
-                zmin = min(zmin, mbl.z_values[j][i]);
-                zmax = min(zmax, mbl.z_values[j][i]);
-           }
-        if (zmax - zmin > 3.f) {
-            // The span of the Z offsets is extreme. Give up.
-            // Homing failed on some of the points.
-            SERIAL_PROTOCOLLNPGM("Exreme span of the Z values!");
-            goto canceled;
-        }
-    }
-
-    // Store the correction values to EEPROM.
-    // Offsets of the Z heiths of the calibration points from the first point.
-    // The offsets are saved as 16bit signed int, scaled to tenths of microns.
-    {
-        uint16_t addr = EEPROM_BED_CALIBRATION_Z_JITTER;
-        for (int8_t j = 0; j < 3; ++ j)
-            for (int8_t i = 0; i < 3; ++ i) {
-                if (i == 0 && j == 0)
-                    continue;
-                float dif = mbl.z_values[j][i] - mbl.z_values[0][0];
-                int16_t dif_quantized = int16_t(floor(dif * 100.f + 0.5f));
-                eeprom_update_word((uint16_t*)addr, *reinterpret_cast<uint16_t*>(&dif_quantized));
-                {
-                    uint16_t z_offset_u = eeprom_read_word((uint16_t*)addr);
-                    float dif2 = *reinterpret_cast<int16_t*>(&z_offset_u) * 0.01;
-
-                    SERIAL_ECHOPGM("Bed point ");
-                    SERIAL_ECHO(i);
-                    SERIAL_ECHOPGM(",");
-                    SERIAL_ECHO(j);
-                    SERIAL_ECHOPGM(", differences: written ");
-                    MYSERIAL.print(dif, 5);
-                    SERIAL_ECHOPGM(", read: ");
-                    MYSERIAL.print(dif2, 5);
-                    SERIAL_ECHOLNPGM("");
-                }
-                addr += 2;
-            }
-    }
-
-    mbl.upsample_3x3();
-    mbl.active = true;
-
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    // Go home.
-    current_position[Z_AXIS] = Z_MIN_POS;
-    go_to_current(homing_feedrate[Z_AXIS]/60);
-    current_position[X_AXIS] = X_MIN_POS+0.2;
-    current_position[Y_AXIS] = Y_MIN_POS+0.2;
-    // Clamp to the physical coordinates.
-    world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-    go_to_current(homing_feedrate[X_AXIS]/60);
-
-    enable_endstops(endstops_enabled);
-    enable_z_endstop(endstop_z_enabled);
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-    return result;
-
-canceled:
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-    // Print head up.
-    current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-    go_to_current(homing_feedrate[Z_AXIS]/60);
-    // Store the identity matrix to EEPROM.
-    reset_bed_offset_and_skew();
-    enable_endstops(endstops_enabled);
-    enable_z_endstop(endstop_z_enabled);
-    return result;
-}
-
-bool scan_bed_induction_points(int8_t verbosity_level)
-{
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    // Reusing the z_values memory for the measurement cache.
-    // 7x7=49 floats, good for 16 (x,y,z) vectors.
-    float *pts = &mbl.z_values[0][0];
-    float *vec_x = pts + 2 * 9;
-    float *vec_y = vec_x + 2;
-    float *cntr  = vec_y + 2;
-    memset(pts, 0, sizeof(float) * 7 * 7);
-
-    // Cache the current correction matrix.
-    world2machine_initialize();
-    vec_x[0] = world2machine_rotation_and_skew[0][0];
-    vec_x[1] = world2machine_rotation_and_skew[1][0];
-    vec_y[0] = world2machine_rotation_and_skew[0][1];
-    vec_y[1] = world2machine_rotation_and_skew[1][1];
-    cntr[0] = world2machine_shift[0];
-    cntr[1] = world2machine_shift[1];
-    // and reset the correction matrix, so the planner will not do anything.
-    world2machine_reset();
-
-    bool endstops_enabled  = enable_endstops(false);
-    bool endstop_z_enabled = enable_z_endstop(false);
-
-    // Collect a matrix of 9x9 points.
-    for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
-        // Don't let the manage_inactivity() function remove power from the motors.
-        refresh_cmd_timeout();
-
-        // Move up.
-        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
-        enable_endstops(false);
-        enable_z_endstop(false);
-        go_to_current(homing_feedrate[Z_AXIS]/60);
-        // Go to the measurement point.
-        // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
-        current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0];
-        current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1];
-        // The calibration points are very close to the min Y.
-        if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION)
-            current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
-        go_to_current(homing_feedrate[X_AXIS]/60);
-        find_bed_induction_sensor_point_z();
-        scan_bed_induction_sensor_point();
-    }
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    enable_endstops(false);
-    enable_z_endstop(false);
-
-    // Don't let the manage_inactivity() function remove power from the motors.
-    refresh_cmd_timeout();
-
-    enable_endstops(endstops_enabled);
-    enable_z_endstop(endstop_z_enabled);
-    return true;
-}
+#include "Marlin.h"
+#include "Configuration.h"
+#include "ConfigurationStore.h"
+#include "language_all.h"
+#include "mesh_bed_calibration.h"
+#include "mesh_bed_leveling.h"
+#include "stepper.h"
+#include "ultralcd.h"
+
+uint8_t world2machine_correction_mode;
+float   world2machine_rotation_and_skew[2][2];
+float   world2machine_rotation_and_skew_inv[2][2];
+float   world2machine_shift[2];
+
+// Weight of the Y coordinate for the least squares fitting of the bed induction sensor targets.
+// Only used for the first row of the points, which may not befully in reach of the sensor.
+#define WEIGHT_FIRST_ROW_X_HIGH (1.f)
+#define WEIGHT_FIRST_ROW_X_LOW  (0.35f)
+#define WEIGHT_FIRST_ROW_Y_HIGH (0.3f)
+#define WEIGHT_FIRST_ROW_Y_LOW  (0.0f)
+
+#define BED_ZERO_REF_X (- 22.f + X_PROBE_OFFSET_FROM_EXTRUDER) // -22 + 23 = 1
+#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER) // -0.6 + 5 = 4.4
+
+// Scaling of the real machine axes against the programmed dimensions in the firmware.
+// The correction is tiny, here around 0.5mm on 250mm length.
+//#define MACHINE_AXIS_SCALE_X ((250.f - 0.5f) / 250.f)
+//#define MACHINE_AXIS_SCALE_Y ((250.f - 0.5f) / 250.f)
+#define MACHINE_AXIS_SCALE_X 1.f
+#define MACHINE_AXIS_SCALE_Y 1.f
+
+#define BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN  (0.8f)
+#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X  (0.8f)
+#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y  (1.5f)
+
+#define MIN_BED_SENSOR_POINT_RESPONSE_DMR           (2.0f)
+
+//#define Y_MIN_POS_FOR_BED_CALIBRATION (MANUAL_Y_HOME_POS-0.2f)
+#define Y_MIN_POS_FOR_BED_CALIBRATION (Y_MIN_POS)
+// Distances toward the print bed edge may not be accurate.
+#define Y_MIN_POS_CALIBRATION_POINT_ACCURATE (Y_MIN_POS + 3.f)
+// When the measured point center is out of reach of the sensor, Y coordinate will be ignored
+// by the Least Squares fitting and the X coordinate will be weighted low.
+#define Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH (Y_MIN_POS - 0.5f)
+
+// 0.12 degrees equals to an offset of 0.5mm on 250mm length.
+const float bed_skew_angle_mild = (0.12f * M_PI / 180.f);
+// 0.25 degrees equals to an offset of 1.1mm on 250mm length.
+const float bed_skew_angle_extreme = (0.25f * M_PI / 180.f);
+
+// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor.
+// The points are ordered in a zig-zag fashion to speed up the calibration.
+
+#ifdef HEATBED_V2
+
+// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor.
+// The points are the following: center front, center right, center rear, center left.
+const float bed_ref_points_4[] PROGMEM = {
+	13.f - BED_ZERO_REF_X,   10.4f - BED_ZERO_REF_Y,
+	221.f - BED_ZERO_REF_X,  10.4f - BED_ZERO_REF_Y,
+	221.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
+	13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y
+};
+
+const float bed_ref_points[] PROGMEM = {
+	13.f - BED_ZERO_REF_X,   10.4f - BED_ZERO_REF_Y,
+	115.f - BED_ZERO_REF_X,   10.4f - BED_ZERO_REF_Y,
+	216.f - BED_ZERO_REF_X,   10.4f - BED_ZERO_REF_Y,
+
+	216.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y,
+	115.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y,
+	13.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y,
+
+	13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
+	115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
+	216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y
+};
+#else
+
+// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor.
+// The points are the following: center front, center right, center rear, center left.
+const float bed_ref_points_4[] PROGMEM = {
+	115.f - BED_ZERO_REF_X,   8.4f - BED_ZERO_REF_Y,
+	216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
+	115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
+	13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y
+};
+
+const float bed_ref_points[] PROGMEM = {
+    13.f  - BED_ZERO_REF_X,   8.4f - BED_ZERO_REF_Y,
+    115.f - BED_ZERO_REF_X,   8.4f - BED_ZERO_REF_Y,
+    216.f - BED_ZERO_REF_X,   8.4f - BED_ZERO_REF_Y,
+    
+    216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
+    115.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
+    13.f  - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y,
+
+    13.f  - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
+    115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y,
+    216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y
+};
+
+#endif //not HEATBED_V2
+
+static inline float sqr(float x) { return x * x; }
+
+static inline bool point_on_1st_row(const uint8_t i)
+{
+	return (i < 2);
+}
+
+// Weight of a point coordinate in a least squares optimization.
+// The first row of points may not be fully reachable
+// and the y values may be shortened a bit by the bed carriage
+// pulling the belt up.
+static inline float point_weight_x(const uint8_t i, const uint8_t npts, const float &y)
+{
+    float w = 1.f;
+    if (point_on_1st_row(i)) {
+		if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) {
+            w = WEIGHT_FIRST_ROW_X_HIGH;
+        } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) {
+            // If the point is fully outside, give it some weight.
+            w = WEIGHT_FIRST_ROW_X_LOW;
+        } else {
+            // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X.
+            float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
+            w = (1.f - t) * WEIGHT_FIRST_ROW_X_LOW + t * WEIGHT_FIRST_ROW_X_HIGH;
+        }
+    }
+    return w;
+}
+
+// Weight of a point coordinate in a least squares optimization.
+// The first row of points may not be fully reachable
+// and the y values may be shortened a bit by the bed carriage
+// pulling the belt up.
+static inline float point_weight_y(const uint8_t i, const uint8_t npts, const float &y)
+{
+    float w = 1.f;
+    if (point_on_1st_row(i)) {
+        if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) {
+            w = WEIGHT_FIRST_ROW_Y_HIGH;
+        } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) {
+            // If the point is fully outside, give it some weight.
+            w = WEIGHT_FIRST_ROW_Y_LOW;
+        } else {
+            // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X.
+            float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
+            w = (1.f - t) * WEIGHT_FIRST_ROW_Y_LOW + t * WEIGHT_FIRST_ROW_Y_HIGH;
+        }
+    }
+    return w;
+}
+
+// Non-Linear Least Squares fitting of the bed to the measured induction points
+// using the Gauss-Newton method.
+// This method will maintain a unity length of the machine axes,
+// which is the correct approach if the sensor points are not measured precisely.
+BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
+    // Matrix of maximum 9 2D points (18 floats)
+    const float  *measured_pts,
+    uint8_t       npts,
+    const float  *true_pts,
+    // Resulting correction matrix.
+    float        *vec_x,
+    float        *vec_y,
+    float        *cntr,
+    // Temporary values, 49-18-(2*3)=25 floats
+    //    , float *temp
+    int8_t        verbosity_level
+    )
+{
+	float angleDiff;
+	#ifdef SUPPORT_VERBOSITY
+    if (verbosity_level >= 10) {
+		SERIAL_ECHOLNPGM("calculate machine skew and offset LS");
+
+        // Show the initial state, before the fitting.
+        SERIAL_ECHOPGM("X vector, initial: ");
+        MYSERIAL.print(vec_x[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(vec_x[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        SERIAL_ECHOPGM("Y vector, initial: ");
+        MYSERIAL.print(vec_y[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(vec_y[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        SERIAL_ECHOPGM("center, initial: ");
+        MYSERIAL.print(cntr[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(cntr[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        for (uint8_t i = 0; i < npts; ++i) {
+            SERIAL_ECHOPGM("point #");
+            MYSERIAL.print(int(i));
+            SERIAL_ECHOPGM(" measured: (");
+            MYSERIAL.print(measured_pts[i * 2], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(measured_pts[i * 2 + 1], 5);
+            SERIAL_ECHOPGM("); target: (");
+            MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
+            SERIAL_ECHOPGM("), error: ");
+            MYSERIAL.print(sqrt(
+                sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) +
+                sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5);
+            SERIAL_ECHOLNPGM("");
+        }
+        delay_keep_alive(100);
+    }
+	#endif // SUPPORT_VERBOSITY
+
+    // Run some iterations of the Gauss-Newton method of non-linear least squares.
+    // Initial set of parameters:
+    // X,Y offset
+    cntr[0] = 0.f;
+    cntr[1] = 0.f;
+    // Rotation of the machine X axis from the bed X axis.
+    float a1 = 0;
+    // Rotation of the machine Y axis from the bed Y axis.
+    float a2 = 0;
+    for (int8_t iter = 0; iter < 100; ++iter) {
+        float c1 = cos(a1) * MACHINE_AXIS_SCALE_X;
+        float s1 = sin(a1) * MACHINE_AXIS_SCALE_X;
+        float c2 = cos(a2) * MACHINE_AXIS_SCALE_Y;
+        float s2 = sin(a2) * MACHINE_AXIS_SCALE_Y;
+        // Prepare the Normal equation for the Gauss-Newton method.
+        float A[4][4] = { 0.f };
+        float b[4] = { 0.f };
+        float acc;
+        for (uint8_t r = 0; r < 4; ++r) {
+            for (uint8_t c = 0; c < 4; ++c) {
+                acc = 0;
+                // J^T times J
+                for (uint8_t i = 0; i < npts; ++i) {
+                    // First for the residuum in the x axis:
+                    if (r != 1 && c != 1) {
+                        float a = 
+                             (r == 0) ? 1.f :
+                            ((r == 2) ? (-s1 * measured_pts[2 * i]) :
+                                        (-c2 * measured_pts[2 * i + 1]));
+                        float b = 
+                             (c == 0) ? 1.f :
+                            ((c == 2) ? (-s1 * measured_pts[2 * i]) :
+                                        (-c2 * measured_pts[2 * i + 1]));
+                        float w = point_weight_x(i, npts, measured_pts[2 * i + 1]);
+                        acc += a * b * w;
+                    }
+                    // Second for the residuum in the y axis. 
+                    // The first row of the points have a low weight, because their position may not be known
+                    // with a sufficient accuracy.
+                    if (r != 0 && c != 0) {
+                        float a = 
+                             (r == 1) ? 1.f :
+                            ((r == 2) ? ( c1 * measured_pts[2 * i]) :
+                                        (-s2 * measured_pts[2 * i + 1]));
+                        float b = 
+                             (c == 1) ? 1.f :
+                            ((c == 2) ? ( c1 * measured_pts[2 * i]) :
+                                        (-s2 * measured_pts[2 * i + 1]));
+                        float w = point_weight_y(i, npts, measured_pts[2 * i + 1]);
+                        acc += a * b * w;
+                    }
+                }
+                A[r][c] = acc;
+            }
+            // J^T times f(x)
+            acc = 0.f;
+            for (uint8_t i = 0; i < npts; ++i) {
+                {
+                    float j = 
+                         (r == 0) ? 1.f :
+                        ((r == 1) ? 0.f :
+                        ((r == 2) ? (-s1 * measured_pts[2 * i]) :
+                                    (-c2 * measured_pts[2 * i + 1])));
+                    float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2);
+                    float w = point_weight_x(i, npts, measured_pts[2 * i + 1]);
+                    acc += j * fx * w;
+                }
+                {
+                    float j = 
+                         (r == 0) ? 0.f :
+                        ((r == 1) ? 1.f :
+                        ((r == 2) ? ( c1 * measured_pts[2 * i]) :
+                                    (-s2 * measured_pts[2 * i + 1])));
+                    float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1);
+                    float w = point_weight_y(i, npts, measured_pts[2 * i + 1]);
+                    acc += j * fy * w;
+                }
+            }
+            b[r] = -acc;
+        }
+
+        // Solve for h by a Gauss iteration method.
+        float h[4] = { 0.f };
+        for (uint8_t gauss_iter = 0; gauss_iter < 100; ++gauss_iter) {
+            h[0] = (b[0] - A[0][1] * h[1] - A[0][2] * h[2] - A[0][3] * h[3]) / A[0][0];
+            h[1] = (b[1] - A[1][0] * h[0] - A[1][2] * h[2] - A[1][3] * h[3]) / A[1][1];
+            h[2] = (b[2] - A[2][0] * h[0] - A[2][1] * h[1] - A[2][3] * h[3]) / A[2][2];
+            h[3] = (b[3] - A[3][0] * h[0] - A[3][1] * h[1] - A[3][2] * h[2]) / A[3][3];
+        }
+
+        // and update the current position with h.
+        // It may be better to use the Levenberg-Marquart method here,
+        // but because we are very close to the solution alread,
+        // the simple Gauss-Newton non-linear Least Squares method works well enough.
+        cntr[0] += h[0];
+        cntr[1] += h[1];
+        a1 += h[2];
+        a2 += h[3];
+
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 20) {
+            SERIAL_ECHOPGM("iteration: ");
+            MYSERIAL.print(int(iter));
+			SERIAL_ECHOPGM("; correction vector: ");
+            MYSERIAL.print(h[0], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(h[1], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(h[2], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(h[3], 5);
+            SERIAL_ECHOLNPGM("");
+            SERIAL_ECHOPGM("corrected x/y: ");
+            MYSERIAL.print(cntr[0], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(cntr[0], 5);
+            SERIAL_ECHOLNPGM("");
+            SERIAL_ECHOPGM("corrected angles: ");
+            MYSERIAL.print(180.f * a1 / M_PI, 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(180.f * a2 / M_PI, 5);
+            SERIAL_ECHOLNPGM("");
+        }
+		#endif // SUPPORT_VERBOSITY
+    }
+
+    vec_x[0] =  cos(a1) * MACHINE_AXIS_SCALE_X;
+    vec_x[1] =  sin(a1) * MACHINE_AXIS_SCALE_X;
+    vec_y[0] = -sin(a2) * MACHINE_AXIS_SCALE_Y;
+    vec_y[1] =  cos(a2) * MACHINE_AXIS_SCALE_Y;
+
+    BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT;
+    {
+        angleDiff = fabs(a2 - a1);
+		eeprom_update_float((float*)(EEPROM_XYZ_CAL_SKEW), angleDiff); //storing xyz cal. skew to be able to show in support menu later 
+        if (angleDiff > bed_skew_angle_mild)
+            result = (angleDiff > bed_skew_angle_extreme) ?
+                BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME :
+                BED_SKEW_OFFSET_DETECTION_SKEW_MILD;
+        if (fabs(a1) > bed_skew_angle_extreme ||
+            fabs(a2) > bed_skew_angle_extreme)
+            result = BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME;
+    }
+	#ifdef SUPPORT_VERBOSITY
+    if (verbosity_level >= 1) {
+        SERIAL_ECHOPGM("correction angles: ");
+        MYSERIAL.print(180.f * a1 / M_PI, 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(180.f * a2 / M_PI, 5);
+        SERIAL_ECHOLNPGM("");
+    }
+
+    if (verbosity_level >= 10) {
+        // Show the adjusted state, before the fitting.
+        SERIAL_ECHOPGM("X vector new, inverted: ");
+        MYSERIAL.print(vec_x[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(vec_x[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        SERIAL_ECHOPGM("Y vector new, inverted: ");
+        MYSERIAL.print(vec_y[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(vec_y[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        SERIAL_ECHOPGM("center new, inverted: ");
+        MYSERIAL.print(cntr[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(cntr[1], 5);
+        SERIAL_ECHOLNPGM("");
+        delay_keep_alive(100);
+
+        SERIAL_ECHOLNPGM("Error after correction: ");
+    }
+	#endif // SUPPORT_VERBOSITY
+    // Measure the error after correction.
+    for (uint8_t i = 0; i < npts; ++i) {
+        float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0];
+        float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1] + cntr[1];
+        float errX = sqr(pgm_read_float(true_pts + i * 2) - x);
+        float errY = sqr(pgm_read_float(true_pts + i * 2 + 1) - y);
+        float err = sqrt(errX + errY);
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 10) {
+			SERIAL_ECHOPGM("point #");
+			MYSERIAL.print(int(i));
+			SERIAL_ECHOLNPGM(":");
+		}
+		#endif // SUPPORT_VERBOSITY
+
+		if (point_on_1st_row(i)) {
+				#ifdef SUPPORT_VERBOSITY
+				if(verbosity_level >= 20) SERIAL_ECHOPGM("Point on first row");
+				#endif // SUPPORT_VERBOSITY
+				float w = point_weight_y(i, npts, measured_pts[2 * i + 1]);
+				if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X ||
+					(w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) {
+					result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
+					#ifdef SUPPORT_VERBOSITY
+					if (verbosity_level >= 20) {
+						SERIAL_ECHOPGM(", weigth Y: ");
+						MYSERIAL.print(w);
+						if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X) SERIAL_ECHOPGM(", error X > max. error X");
+						if (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y) SERIAL_ECHOPGM(", error Y > max. error Y");
+					}
+					#endif // SUPPORT_VERBOSITY
+				}
+		}
+		else {
+			#ifdef SUPPORT_VERBOSITY
+			if(verbosity_level >=20 ) SERIAL_ECHOPGM("Point not on first row");
+			#endif // SUPPORT_VERBOSITY
+			if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN) {
+				result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
+				#ifdef SUPPORT_VERBOSITY
+				if(verbosity_level >= 20) SERIAL_ECHOPGM(", error > max. error euclidian"); 
+				#endif // SUPPORT_VERBOSITY
+			}
+        }
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 10) {
+			SERIAL_ECHOLNPGM("");
+            SERIAL_ECHOPGM("measured: (");
+            MYSERIAL.print(measured_pts[i * 2], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(measured_pts[i * 2 + 1], 5);
+            SERIAL_ECHOPGM("); corrected: (");
+            MYSERIAL.print(x, 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(y, 5);
+            SERIAL_ECHOPGM("); target: (");
+            MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
+			SERIAL_ECHOLNPGM(")");
+			SERIAL_ECHOPGM("error: ");
+            MYSERIAL.print(err);
+			SERIAL_ECHOPGM(", error X: ");
+			MYSERIAL.print(sqrt(errX));
+			SERIAL_ECHOPGM(", error Y: ");
+			MYSERIAL.print(sqrt(errY));
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("");
+        }
+		#endif // SUPPORT_VERBOSITY
+    }
+	#ifdef SUPPORT_VERBOSITY
+	if (verbosity_level >= 20) {
+		SERIAL_ECHOLNPGM("Max. errors:");
+		SERIAL_ECHOPGM("Max. error X:");
+		MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X);
+		SERIAL_ECHOPGM("Max. error Y:");
+		MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y);
+		SERIAL_ECHOPGM("Max. error euclidian:");
+		MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN);
+		SERIAL_ECHOLNPGM("");
+	}
+	#endif // SUPPORT_VERBOSITY
+
+    #if 0
+    if (result == BED_SKEW_OFFSET_DETECTION_PERFECT && fabs(a1) < bed_skew_angle_mild && fabs(a2) < bed_skew_angle_mild) {
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level > 0)
+            SERIAL_ECHOLNPGM("Very little skew detected. Disabling skew correction.");
+		#endif // SUPPORT_VERBOSITY
+        // Just disable the skew correction.
+        vec_x[0] = MACHINE_AXIS_SCALE_X;
+        vec_x[1] = 0.f;
+        vec_y[0] = 0.f;
+        vec_y[1] = MACHINE_AXIS_SCALE_Y;
+    }
+    #else
+    if (result == BED_SKEW_OFFSET_DETECTION_PERFECT) {
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level > 0)
+            SERIAL_ECHOLNPGM("Very little skew detected. Orthogonalizing the axes.");
+		#endif // SUPPORT_VERBOSITY
+		// Orthogonalize the axes.
+        a1 = 0.5f * (a1 + a2);
+        vec_x[0] =  cos(a1) * MACHINE_AXIS_SCALE_X;
+        vec_x[1] =  sin(a1) * MACHINE_AXIS_SCALE_X;
+        vec_y[0] = -sin(a1) * MACHINE_AXIS_SCALE_Y;
+        vec_y[1] =  cos(a1) * MACHINE_AXIS_SCALE_Y;
+        // Refresh the offset.
+        cntr[0] = 0.f;
+        cntr[1] = 0.f;
+        float wx = 0.f;
+        float wy = 0.f;
+        for (int8_t i = 0; i < npts; ++ i) {
+            float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1];
+            float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1];
+            float w = point_weight_x(i, npts, y);
+			cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x);
+			wx += w;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				MYSERIAL.print(i);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("Weight_x:");
+				MYSERIAL.print(w);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("cntr[0]:");
+				MYSERIAL.print(cntr[0]);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("wx:");
+				MYSERIAL.print(wx);
+			}
+			#endif // SUPPORT_VERBOSITY
+            w = point_weight_y(i, npts, y);
+			cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y);
+			wy += w;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("Weight_y:");
+				MYSERIAL.print(w);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("cntr[1]:");
+				MYSERIAL.print(cntr[1]);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("wy:");
+				MYSERIAL.print(wy);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("");
+			}
+			#endif // SUPPORT_VERBOSITY
+
+		}
+        cntr[0] /= wx;
+        cntr[1] /= wy;
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 20) {
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("Final cntr values:");
+			SERIAL_ECHOLNPGM("cntr[0]:");
+			MYSERIAL.print(cntr[0]);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("cntr[1]:");
+			MYSERIAL.print(cntr[1]);
+			SERIAL_ECHOLNPGM("");
+		}
+		#endif // SUPPORT_VERBOSITY
+    }
+    #endif
+
+    // Invert the transformation matrix made of vec_x, vec_y and cntr.
+    {
+        float d = vec_x[0] * vec_y[1] - vec_x[1] * vec_y[0];
+        float Ainv[2][2] = {
+            { vec_y[1] / d, -vec_y[0] / d },
+            { -vec_x[1] / d, vec_x[0] / d }
+        };
+        float cntrInv[2] = {
+            -Ainv[0][0] * cntr[0] - Ainv[0][1] * cntr[1],
+            -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1]
+        };
+        vec_x[0] = Ainv[0][0];
+        vec_x[1] = Ainv[1][0];
+        vec_y[0] = Ainv[0][1];
+        vec_y[1] = Ainv[1][1];
+        cntr[0] = cntrInv[0];
+        cntr[1] = cntrInv[1];
+    }
+	#ifdef SUPPORT_VERBOSITY
+    if (verbosity_level >= 1) {
+        // Show the adjusted state, before the fitting.
+        SERIAL_ECHOPGM("X vector, adjusted: ");
+        MYSERIAL.print(vec_x[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(vec_x[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        SERIAL_ECHOPGM("Y vector, adjusted: ");
+        MYSERIAL.print(vec_y[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(vec_y[1], 5);
+        SERIAL_ECHOLNPGM("");
+
+        SERIAL_ECHOPGM("center, adjusted: ");
+        MYSERIAL.print(cntr[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(cntr[1], 5);
+        SERIAL_ECHOLNPGM("");
+        delay_keep_alive(100);
+    }
+
+    if (verbosity_level >= 2) {
+        SERIAL_ECHOLNPGM("Difference after correction: ");
+        for (uint8_t i = 0; i < npts; ++i) {
+            float x = vec_x[0] * pgm_read_float(true_pts + i * 2) + vec_y[0] * pgm_read_float(true_pts + i * 2 + 1) + cntr[0];
+            float y = vec_x[1] * pgm_read_float(true_pts + i * 2) + vec_y[1] * pgm_read_float(true_pts + i * 2 + 1) + cntr[1];
+            SERIAL_ECHOPGM("point #");
+            MYSERIAL.print(int(i));
+            SERIAL_ECHOPGM("measured: (");
+            MYSERIAL.print(measured_pts[i * 2], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(measured_pts[i * 2 + 1], 5);
+            SERIAL_ECHOPGM("); measured-corrected: (");
+            MYSERIAL.print(x, 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(y, 5);
+            SERIAL_ECHOPGM("); target: (");
+            MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
+            SERIAL_ECHOPGM("), error: ");
+            MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y)));
+            SERIAL_ECHOLNPGM("");
+        }
+		if (verbosity_level >= 20) {
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("Calculate offset and skew returning result:");
+			MYSERIAL.print(int(result));
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("");
+		}
+        delay_keep_alive(100);
+    }
+	#endif // SUPPORT_VERBOSITY
+
+
+    return result;
+}
+
+void reset_bed_offset_and_skew()
+{
+    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF);
+    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+4), 0x0FFFFFFFF);
+    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +0), 0x0FFFFFFFF);
+    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +4), 0x0FFFFFFFF);
+    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +0), 0x0FFFFFFFF);
+    eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +4), 0x0FFFFFFFF);
+
+    // Reset the 8 16bit offsets.
+    for (int8_t i = 0; i < 4; ++ i)
+        eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*4), 0x0FFFFFFFF);
+}
+
+bool is_bed_z_jitter_data_valid()
+// offsets of the Z heiths of the calibration points from the first point are saved as 16bit signed int, scaled to tenths of microns
+{
+    for (int8_t i = 0; i < 8; ++ i)
+        if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*2)) == 0x0FFFF)
+            return false;
+    return true;
+}
+
+static void world2machine_update(const float vec_x[2], const float vec_y[2], const float cntr[2])
+{
+    world2machine_rotation_and_skew[0][0] = vec_x[0];
+    world2machine_rotation_and_skew[1][0] = vec_x[1];
+    world2machine_rotation_and_skew[0][1] = vec_y[0];
+    world2machine_rotation_and_skew[1][1] = vec_y[1];
+    world2machine_shift[0] = cntr[0];
+    world2machine_shift[1] = cntr[1];
+    // No correction.
+    world2machine_correction_mode = WORLD2MACHINE_CORRECTION_NONE;
+    if (world2machine_shift[0] != 0.f || world2machine_shift[1] != 0.f)
+        // Shift correction.
+        world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SHIFT;
+    if (world2machine_rotation_and_skew[0][0] != 1.f || world2machine_rotation_and_skew[0][1] != 0.f ||
+        world2machine_rotation_and_skew[1][0] != 0.f || world2machine_rotation_and_skew[1][1] != 1.f) {
+        // Rotation & skew correction.
+        world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SKEW;
+        // Invert the world2machine matrix.
+        float d = world2machine_rotation_and_skew[0][0] * world2machine_rotation_and_skew[1][1] - world2machine_rotation_and_skew[1][0] * world2machine_rotation_and_skew[0][1];
+        world2machine_rotation_and_skew_inv[0][0] =  world2machine_rotation_and_skew[1][1] / d;
+        world2machine_rotation_and_skew_inv[0][1] = -world2machine_rotation_and_skew[0][1] / d;
+        world2machine_rotation_and_skew_inv[1][0] = -world2machine_rotation_and_skew[1][0] / d;
+        world2machine_rotation_and_skew_inv[1][1] =  world2machine_rotation_and_skew[0][0] / d;
+    } else {
+        world2machine_rotation_and_skew_inv[0][0] = 1.f;
+        world2machine_rotation_and_skew_inv[0][1] = 0.f;
+        world2machine_rotation_and_skew_inv[1][0] = 0.f;
+        world2machine_rotation_and_skew_inv[1][1] = 1.f;
+    }
+}
+
+void world2machine_reset()
+{
+    const float vx[] = { 1.f, 0.f };
+    const float vy[] = { 0.f, 1.f };
+    const float cntr[] = { 0.f, 0.f };
+    world2machine_update(vx, vy, cntr);
+}
+
+void world2machine_revert_to_uncorrected()
+{
+    if (world2machine_correction_mode != WORLD2MACHINE_CORRECTION_NONE) {
+        // Reset the machine correction matrix.
+        const float vx[] = { 1.f, 0.f };
+        const float vy[] = { 0.f, 1.f };
+        const float cntr[] = { 0.f, 0.f };
+        world2machine_update(vx, vy, cntr);
+        // Wait for the motors to stop and update the current position with the absolute values.
+        st_synchronize();
+        current_position[X_AXIS] = st_get_position_mm(X_AXIS);
+        current_position[Y_AXIS] = st_get_position_mm(Y_AXIS);
+    }
+}
+
+static inline bool vec_undef(const float v[2])
+{
+    const uint32_t *vx = (const uint32_t*)v;
+    return vx[0] == 0x0FFFFFFFF || vx[1] == 0x0FFFFFFFF;
+}
+
+void world2machine_initialize()
+{
+    //SERIAL_ECHOLNPGM("world2machine_initialize");
+    float cntr[2] = {
+        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0)),
+        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4))
+    };
+    float vec_x[2] = {
+        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0)),
+        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4))
+    };
+    float vec_y[2] = {
+        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0)),
+        eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4))
+    };
+
+    bool reset = false;
+    if (vec_undef(cntr) || vec_undef(vec_x) || vec_undef(vec_y)) {
+        SERIAL_ECHOLNPGM("Undefined bed correction matrix.");
+        reset = true;
+    }
+    else {
+        // Length of the vec_x shall be close to unity.
+        float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
+        if (l < 0.9 || l > 1.1) {
+			SERIAL_ECHOLNPGM("X vector length:");
+			MYSERIAL.println(l);
+            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range.");
+            reset = true;
+        }
+        // Length of the vec_y shall be close to unity.
+        l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
+        if (l < 0.9 || l > 1.1) {
+			SERIAL_ECHOLNPGM("Y vector length:");
+			MYSERIAL.println(l);
+            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the Y vector out of range.");
+            reset = true;
+        }
+        // Correction of the zero point shall be reasonably small.
+        l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
+        if (l > 15.f) {
+			SERIAL_ECHOLNPGM("Zero point correction:");
+			MYSERIAL.println(l);
+            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Shift out of range.");
+            reset = true;
+        }
+        // vec_x and vec_y shall be nearly perpendicular.
+        l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1];
+        if (fabs(l) > 0.1f) {
+            SERIAL_ECHOLNPGM("Invalid bed correction matrix. X/Y axes are far from being perpendicular.");
+            reset = true;
+        }
+    }
+
+    if (reset) {
+        SERIAL_ECHOLNPGM("Invalid bed correction matrix. Resetting to identity.");
+        reset_bed_offset_and_skew();
+        world2machine_reset();
+    } else {
+        world2machine_update(vec_x, vec_y, cntr);
+        /*
+        SERIAL_ECHOPGM("world2machine_initialize() loaded: ");
+        MYSERIAL.print(world2machine_rotation_and_skew[0][0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(world2machine_rotation_and_skew[0][1], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(world2machine_rotation_and_skew[1][0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(world2machine_rotation_and_skew[1][1], 5);
+        SERIAL_ECHOPGM(", offset ");
+        MYSERIAL.print(world2machine_shift[0], 5);
+        SERIAL_ECHOPGM(", ");
+        MYSERIAL.print(world2machine_shift[1], 5);
+        SERIAL_ECHOLNPGM("");
+        */
+    }
+}
+
+// When switching from absolute to corrected coordinates,
+// this will get the absolute coordinates from the servos,
+// applies the inverse world2machine transformation
+// and stores the result into current_position[x,y].
+void world2machine_update_current()
+{
+    float x = current_position[X_AXIS] - world2machine_shift[0];
+    float y = current_position[Y_AXIS] - world2machine_shift[1];
+    current_position[X_AXIS] = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y;
+    current_position[Y_AXIS] = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y;
+}
+
+static inline void go_xyz(float x, float y, float z, float fr)
+{
+    plan_buffer_line(x, y, z, current_position[E_AXIS], fr, active_extruder);
+    st_synchronize();
+}
+
+static inline void go_xy(float x, float y, float fr)
+{
+    plan_buffer_line(x, y, current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder);
+    st_synchronize();
+}
+
+static inline void go_to_current(float fr)
+{
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder);
+    st_synchronize();
+}
+
+static inline void update_current_position_xyz()
+{
+      current_position[X_AXIS] = st_get_position_mm(X_AXIS);
+      current_position[Y_AXIS] = st_get_position_mm(Y_AXIS);
+      current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
+      plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+}
+
+static inline void update_current_position_z()
+{
+      current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
+      plan_set_z_position(current_position[Z_AXIS]);
+}
+
+// At the current position, find the Z stop.
+inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int verbosity_level)
+{
+	#ifdef SUPPORT_VERBOSITY
+    if(verbosity_level >= 10) SERIAL_ECHOLNPGM("find bed induction sensor point z");
+	#endif // SUPPORT_VERBOSITY
+	bool endstops_enabled  = enable_endstops(true);
+    bool endstop_z_enabled = enable_z_endstop(false);
+    float z = 0.f;
+    endstop_z_hit_on_purpose();
+
+    // move down until you find the bed
+    current_position[Z_AXIS] = minimum_z;
+    go_to_current(homing_feedrate[Z_AXIS]/60);
+    // we have to let the planner know where we are right now as it is not where we said to go.
+    update_current_position_z();
+    if (! endstop_z_hit_on_purpose())
+        goto error;
+
+    for (uint8_t i = 0; i < n_iter; ++ i) {
+        // Move up the retract distance.
+        current_position[Z_AXIS] += .5f;
+        go_to_current(homing_feedrate[Z_AXIS]/60);
+        // Move back down slowly to find bed.
+        current_position[Z_AXIS] = minimum_z;
+        go_to_current(homing_feedrate[Z_AXIS]/(4*60));
+        // we have to let the planner know where we are right now as it is not where we said to go.
+        update_current_position_z();
+        if (! endstop_z_hit_on_purpose())
+            goto error;
+//        SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: ");
+//        MYSERIAL.print(current_position[Z_AXIS], 5);
+//        SERIAL_ECHOLNPGM("");
+        z += current_position[Z_AXIS];
+    }
+    current_position[Z_AXIS] = z;
+    if (n_iter > 1)
+        current_position[Z_AXIS] /= float(n_iter);
+
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+//    SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 3");
+    return true;
+
+error:
+//    SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 4");
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+    return false;
+}
+
+// Search around the current_position[X,Y],
+// look for the induction sensor response.
+// Adjust the  current_position[X,Y,Z] to the center of the target dot and its response Z coordinate.
+#define FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS (8.f)
+#define FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS (6.f)
+#define FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP  (1.f)
+#define FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP   (0.2f)
+inline bool find_bed_induction_sensor_point_xy(int verbosity_level)
+{
+	#ifdef SUPPORT_VERBOSITY
+	if(verbosity_level >= 10) MYSERIAL.println("find bed induction sensor point xy");
+	#endif // SUPPORT_VERBOSITY
+	float feedrate = homing_feedrate[X_AXIS] / 60.f;
+    bool found = false;
+
+    {
+        float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS;
+        float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS;
+        float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS;
+        float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS;
+        uint8_t nsteps_y;
+        uint8_t i;
+		if (x0 < X_MIN_POS) {
+			x0 = X_MIN_POS;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius lower than X_MIN. Clamping was done.");
+			#endif // SUPPORT_VERBOSITY
+		}
+		if (x1 > X_MAX_POS) {
+			x1 = X_MAX_POS;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius higher than X_MAX. Clamping was done.");
+			#endif // SUPPORT_VERBOSITY
+		}
+		if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) {
+			y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius lower than Y_MIN. Clamping was done.");
+			#endif // SUPPORT_VERBOSITY
+		}
+		if (y1 > Y_MAX_POS) {
+			y1 = Y_MAX_POS;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius higher than X_MAX. Clamping was done.");
+			#endif // SUPPORT_VERBOSITY
+		}
+        nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP));
+
+        enable_endstops(false);
+        bool  dir_positive = true;
+
+//        go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60);
+        go_xyz(x0, y0, current_position[Z_AXIS], feedrate);
+        // Continously lower the Z axis.
+        endstops_hit_on_purpose();
+        enable_z_endstop(true);
+        while (current_position[Z_AXIS] > -10.f) {
+            // Do nsteps_y zig-zag movements.
+            current_position[Y_AXIS] = y0;
+            for (i = 0; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i) {
+                // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop.
+                current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y);
+                go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate);
+                dir_positive = ! dir_positive;
+                if (endstop_z_hit_on_purpose())
+                    goto endloop;
+            }
+            for (i = 0; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i) {
+                // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop.
+                current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y);
+                go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate);
+                dir_positive = ! dir_positive;
+                if (endstop_z_hit_on_purpose())
+                    goto endloop;
+            }
+        }
+        endloop:
+//        SERIAL_ECHOLN("First hit");
+
+        // we have to let the planner know where we are right now as it is not where we said to go.
+        update_current_position_xyz();
+
+        // Search in this plane for the first hit. Zig-zag first in X, then in Y axis.
+        for (int8_t iter = 0; iter < 3; ++ iter) {
+            if (iter > 0) {
+                // Slightly lower the Z axis to get a reliable trigger.
+                current_position[Z_AXIS] -= 0.02f;
+                go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60);
+            }
+
+            // Do nsteps_y zig-zag movements.
+            float a, b;
+            enable_endstops(false);
+            enable_z_endstop(false);
+            current_position[Y_AXIS] = y0;
+            go_xy(x0, current_position[Y_AXIS], feedrate);
+            enable_z_endstop(true);
+            found = false;
+            for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) {
+                go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate);
+                if (endstop_z_hit_on_purpose()) {
+                    found = true;
+                    break;
+                }
+            }
+            update_current_position_xyz();
+            if (! found) {
+//                SERIAL_ECHOLN("Search in Y - not found");
+                continue;
+            }
+//            SERIAL_ECHOLN("Search in Y - found");
+            a = current_position[Y_AXIS];
+
+            enable_z_endstop(false);
+            current_position[Y_AXIS] = y1;
+            go_xy(x0, current_position[Y_AXIS], feedrate);
+            enable_z_endstop(true);
+            found = false;
+            for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) {
+                go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate);
+                if (endstop_z_hit_on_purpose()) {
+                    found = true;
+                    break;
+                }
+            }
+            update_current_position_xyz();
+            if (! found) {
+//                SERIAL_ECHOLN("Search in Y2 - not found");
+                continue;
+            }
+//            SERIAL_ECHOLN("Search in Y2 - found");
+            b = current_position[Y_AXIS];
+            current_position[Y_AXIS] = 0.5f * (a + b);
+
+            // Search in the X direction along a cross.
+            found = false;
+            enable_z_endstop(false);
+            go_xy(x0, current_position[Y_AXIS], feedrate);
+            enable_z_endstop(true);
+            go_xy(x1, current_position[Y_AXIS], feedrate);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+//                SERIAL_ECHOLN("Search X span 0 - not found");
+                continue;
+            }
+//            SERIAL_ECHOLN("Search X span 0 - found");
+            a = current_position[X_AXIS];
+            enable_z_endstop(false);
+            go_xy(x1, current_position[Y_AXIS], feedrate);
+            enable_z_endstop(true);
+            go_xy(x0, current_position[Y_AXIS], feedrate);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+//                SERIAL_ECHOLN("Search X span 1 - not found");
+                continue;
+            }
+//            SERIAL_ECHOLN("Search X span 1 - found");
+            b = current_position[X_AXIS];
+            // Go to the center.
+            enable_z_endstop(false);
+            current_position[X_AXIS] = 0.5f * (a + b);
+            go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate);
+            found = true;
+
+#if 1
+            // Search in the Y direction along a cross.
+            found = false;
+            enable_z_endstop(false);
+            go_xy(current_position[X_AXIS], y0, feedrate);
+            enable_z_endstop(true);
+            go_xy(current_position[X_AXIS], y1, feedrate);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+//                SERIAL_ECHOLN("Search Y2 span 0 - not found");
+                continue;
+            }
+//            SERIAL_ECHOLN("Search Y2 span 0 - found");
+            a = current_position[Y_AXIS];
+            enable_z_endstop(false);
+            go_xy(current_position[X_AXIS], y1, feedrate);
+            enable_z_endstop(true);
+            go_xy(current_position[X_AXIS], y0, feedrate);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+//                SERIAL_ECHOLN("Search Y2 span 1 - not found");
+                continue;
+            }
+//            SERIAL_ECHOLN("Search Y2 span 1 - found");
+            b = current_position[Y_AXIS];
+            // Go to the center.
+            enable_z_endstop(false);
+            current_position[Y_AXIS] = 0.5f * (a + b);
+            go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate);
+            found = true;
+#endif
+            break;
+        }
+    }
+
+    enable_z_endstop(false);
+    return found;
+}
+
+// Search around the current_position[X,Y,Z].
+// It is expected, that the induction sensor is switched on at the current position.
+// Look around this center point by painting a star around the point.
+inline bool improve_bed_induction_sensor_point()
+{
+    static const float search_radius = 8.f;
+
+    bool  endstops_enabled  = enable_endstops(false);
+    bool  endstop_z_enabled = enable_z_endstop(false);
+    bool  found = false;
+    float feedrate = homing_feedrate[X_AXIS] / 60.f;
+    float center_old_x = current_position[X_AXIS];
+    float center_old_y = current_position[Y_AXIS];
+    float center_x = 0.f;
+    float center_y = 0.f;
+
+    for (uint8_t iter = 0; iter < 4; ++ iter) {
+        switch (iter) {
+        case 0:
+            destination[X_AXIS] = center_old_x - search_radius * 0.707;
+            destination[Y_AXIS] = center_old_y - search_radius * 0.707;
+            break;
+        case 1:
+            destination[X_AXIS] = center_old_x + search_radius * 0.707;
+            destination[Y_AXIS] = center_old_y + search_radius * 0.707;
+            break;
+        case 2:
+            destination[X_AXIS] = center_old_x + search_radius * 0.707;
+            destination[Y_AXIS] = center_old_y - search_radius * 0.707;
+            break;
+        case 3:
+        default:
+            destination[X_AXIS] = center_old_x - search_radius * 0.707;
+            destination[Y_AXIS] = center_old_y + search_radius * 0.707;
+            break;
+        }
+
+        // Trim the vector from center_old_[x,y] to destination[x,y] by the bed dimensions.
+        float vx = destination[X_AXIS] - center_old_x;
+        float vy = destination[Y_AXIS] - center_old_y;
+        float l  = sqrt(vx*vx+vy*vy);
+        float t;
+        if (destination[X_AXIS] < X_MIN_POS) {
+            // Exiting the bed at xmin.
+            t = (center_x - X_MIN_POS) / l;
+            destination[X_AXIS] = X_MIN_POS;
+            destination[Y_AXIS] = center_old_y + t * vy;
+        } else if (destination[X_AXIS] > X_MAX_POS) {
+            // Exiting the bed at xmax.
+            t = (X_MAX_POS - center_x) / l;
+            destination[X_AXIS] = X_MAX_POS;
+            destination[Y_AXIS] = center_old_y + t * vy;
+        }
+        if (destination[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) {
+            // Exiting the bed at ymin.
+            t = (center_y - Y_MIN_POS_FOR_BED_CALIBRATION) / l;
+            destination[X_AXIS] = center_old_x + t * vx;
+            destination[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
+        } else if (destination[Y_AXIS] > Y_MAX_POS) {
+            // Exiting the bed at xmax.
+            t = (Y_MAX_POS - center_y) / l;
+            destination[X_AXIS] = center_old_x + t * vx;
+            destination[Y_AXIS] = Y_MAX_POS;
+        }
+
+        // Move away from the measurement point.
+        enable_endstops(false);
+        go_xy(destination[X_AXIS], destination[Y_AXIS], feedrate);
+        // Move towards the measurement point, until the induction sensor triggers.
+        enable_endstops(true);
+        go_xy(center_old_x, center_old_y, feedrate);
+        update_current_position_xyz();
+//        if (! endstop_z_hit_on_purpose()) return false;
+        center_x += current_position[X_AXIS];
+        center_y += current_position[Y_AXIS];
+    }
+
+    // Calculate the new center, move to the new center.
+    center_x /= 4.f;
+    center_y /= 4.f;
+    current_position[X_AXIS] = center_x;
+    current_position[Y_AXIS] = center_y;
+    enable_endstops(false);
+    go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate);
+
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+    return found;
+}
+
+static inline void debug_output_point(const char *type, const float &x, const float &y, const float &z)
+{
+    SERIAL_ECHOPGM("Measured ");
+    SERIAL_ECHORPGM(type);
+    SERIAL_ECHOPGM(" ");
+    MYSERIAL.print(x, 5);
+    SERIAL_ECHOPGM(", ");
+    MYSERIAL.print(y, 5);
+    SERIAL_ECHOPGM(", ");
+    MYSERIAL.print(z, 5);
+    SERIAL_ECHOLNPGM("");
+}
+
+// Search around the current_position[X,Y,Z].
+// It is expected, that the induction sensor is switched on at the current position.
+// Look around this center point by painting a star around the point.
+#define IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS (8.f)
+inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t verbosity_level)
+{
+    float center_old_x = current_position[X_AXIS];
+    float center_old_y = current_position[Y_AXIS];
+    float a, b;
+    bool  point_small = false;
+
+    enable_endstops(false);
+
+    {
+        float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
+        float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
+        if (x0 < X_MIN_POS)
+            x0 = X_MIN_POS;
+        if (x1 > X_MAX_POS)
+            x1 = X_MAX_POS;
+
+        // Search in the X direction along a cross.
+        enable_z_endstop(false);
+        go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+        enable_z_endstop(true);
+        go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+        update_current_position_xyz();
+        if (! endstop_z_hit_on_purpose()) {
+            current_position[X_AXIS] = center_old_x;
+            goto canceled;
+        }
+        a = current_position[X_AXIS];
+        enable_z_endstop(false);
+        go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+        enable_z_endstop(true);
+        go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+        update_current_position_xyz();
+        if (! endstop_z_hit_on_purpose()) {
+            current_position[X_AXIS] = center_old_x;
+            goto canceled;
+        }
+        b = current_position[X_AXIS];
+        if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level >= 5) {
+                SERIAL_ECHOPGM("Point width too small: ");
+                SERIAL_ECHO(b - a);
+                SERIAL_ECHOLNPGM("");
+            }
+			#endif // SUPPORT_VERBOSITY
+            // We force the calibration routine to move the Z axis slightly down to make the response more pronounced.
+            if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
+                // Don't use the new X value.
+                current_position[X_AXIS] = center_old_x;
+                goto canceled;
+            } else {
+                // Use the new value, but force the Z axis to go a bit lower.
+                point_small = true;
+            }
+        }
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 5) {
+            debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
+            debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
+        }
+		#endif // SUPPORT_VERBOSITY
+
+        // Go to the center.
+        enable_z_endstop(false);
+        current_position[X_AXIS] = 0.5f * (a + b);
+        go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+    }
+
+    {
+        float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
+        float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS;
+        if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
+            y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
+        if (y1 > Y_MAX_POS)
+            y1 = Y_MAX_POS;
+
+        // Search in the Y direction along a cross.
+        enable_z_endstop(false);
+        go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f);
+        if (lift_z_on_min_y) {
+            // The first row of points are very close to the end stop.
+            // Lift the sensor to disengage the trigger. This is necessary because of the sensor hysteresis.
+            go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS]+1.5f, homing_feedrate[Z_AXIS] / 60.f);
+            // and go back.
+            go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS], homing_feedrate[Z_AXIS] / 60.f);
+        }
+        if (lift_z_on_min_y && (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) {
+            // Already triggering before we started the move.
+            // Shift the trigger point slightly outwards.
+            // a = current_position[Y_AXIS] - 1.5f;
+            a = current_position[Y_AXIS];
+        } else {
+            enable_z_endstop(true);
+            go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                current_position[Y_AXIS] = center_old_y;
+                goto canceled;
+            }
+            a = current_position[Y_AXIS];
+        }
+        enable_z_endstop(false);
+        go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f);
+        enable_z_endstop(true);
+        go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f);
+        update_current_position_xyz();
+        if (! endstop_z_hit_on_purpose()) {
+            current_position[Y_AXIS] = center_old_y;
+            goto canceled;
+        }
+        b = current_position[Y_AXIS];
+        if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
+            // We force the calibration routine to move the Z axis slightly down to make the response more pronounced.
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 5) {
+                SERIAL_ECHOPGM("Point height too small: ");
+                SERIAL_ECHO(b - a);
+                SERIAL_ECHOLNPGM("");
+            }
+			#endif // SUPPORT_VERBOSITY
+            if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
+                // Don't use the new Y value.
+                current_position[Y_AXIS] = center_old_y;
+                goto canceled;
+            } else {
+                // Use the new value, but force the Z axis to go a bit lower.
+                point_small = true;
+            }
+        }
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 5) {
+            debug_output_point(PSTR("top" ), current_position[X_AXIS], a, current_position[Z_AXIS]);
+            debug_output_point(PSTR("bottom"), current_position[X_AXIS], b, current_position[Z_AXIS]);
+        }
+		#endif // SUPPORT_VERBOSITY
+
+        // Go to the center.
+        enable_z_endstop(false);
+        current_position[Y_AXIS] = 0.5f * (a + b);
+        go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+    }
+
+    // If point is small but not too small, then force the Z axis to be lowered a bit,
+    // but use the new value. This is important when the initial position was off in one axis,
+    // for example if the initial calibration was shifted in the Y axis systematically.
+    // Then this first step will center.
+    return ! point_small;
+
+canceled:
+    // Go back to the center.
+    enable_z_endstop(false);
+    go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+    return false;
+}
+
+// Searching the front points, where one cannot move the sensor head in front of the sensor point.
+// Searching in a zig-zag movement in a plane for the maximum width of the response.
+// This function may set the current_position[Y_AXIS] below Y_MIN_POS, if the function succeeded.
+// If this function failed, the Y coordinate will never be outside the working space.
+#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (4.f)
+#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f)
+inline bool improve_bed_induction_sensor_point3(int verbosity_level)
+{	
+    float center_old_x = current_position[X_AXIS];
+    float center_old_y = current_position[Y_AXIS];
+    float a, b;
+    bool  result = true;
+	#ifdef SUPPORT_VERBOSITY
+	if (verbosity_level >= 20) MYSERIAL.println("Improve bed induction sensor point3");
+	#endif // SUPPORT_VERBOSITY
+    // Was the sensor point detected too far in the minus Y axis?
+    // If yes, the center of the induction point cannot be reached by the machine.
+    {
+        float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+        float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+        float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+        float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+        float y = y0;
+
+        if (x0 < X_MIN_POS)
+            x0 = X_MIN_POS;
+        if (x1 > X_MAX_POS)
+            x1 = X_MAX_POS;
+        if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
+            y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
+        if (y1 > Y_MAX_POS)
+            y1 = Y_MAX_POS;
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 20) {
+            SERIAL_ECHOPGM("Initial position: ");
+            SERIAL_ECHO(center_old_x);
+            SERIAL_ECHOPGM(", ");
+            SERIAL_ECHO(center_old_y);
+            SERIAL_ECHOLNPGM("");
+        }
+		#endif // SUPPORT_VERBOSITY
+
+        // Search in the positive Y direction, until a maximum diameter is found.
+        // (the next diameter is smaller than the current one.)
+        float dmax = 0.f;
+        float xmax1 = 0.f;
+        float xmax2 = 0.f;
+        for (y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
+            enable_z_endstop(false);
+            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+            enable_z_endstop(true);
+            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                continue;
+                // SERIAL_PROTOCOLPGM("Failed 1\n");
+                // current_position[X_AXIS] = center_old_x;
+                // goto canceled;
+            }
+            a = current_position[X_AXIS];
+            enable_z_endstop(false);
+            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+            enable_z_endstop(true);
+            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                continue;
+                // SERIAL_PROTOCOLPGM("Failed 2\n");
+                // current_position[X_AXIS] = center_old_x;
+                // goto canceled;
+            }
+            b = current_position[X_AXIS];
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level >= 5) {
+                debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
+                debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
+            }
+			#endif // SUPPORT_VERBOSITY
+            float d = b - a;
+            if (d > dmax) {
+                xmax1 = 0.5f * (a + b);
+                dmax = d;
+            } else if (dmax > 0.) {
+                y0 = y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
+                break;
+            }
+        }
+        if (dmax == 0.) {
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level > 0)
+                SERIAL_PROTOCOLPGM("failed - not found\n");
+			#endif // SUPPORT_VERBOSITY
+			current_position[X_AXIS] = center_old_x;
+            current_position[Y_AXIS] = center_old_y;
+            goto canceled;
+        }
+
+        {
+            // Find the positive Y hit. This gives the extreme Y value for the search of the maximum diameter in the -Y direction.
+            enable_z_endstop(false);
+            go_xy(xmax1, y0 + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f);
+            enable_z_endstop(true);
+            go_xy(xmax1, max(y0 - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                current_position[Y_AXIS] = center_old_y;
+                goto canceled;
+            }
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level >= 5)
+                debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
+			#endif // SUPPORT_VERBOSITY
+			y1 = current_position[Y_AXIS];
+        }
+
+        if (y1 <= y0) {
+            // Either the induction sensor is too high, or the induction sensor target is out of reach.
+            current_position[Y_AXIS] = center_old_y;
+            goto canceled;
+        }
+
+        // Search in the negative Y direction, until a maximum diameter is found.
+        dmax = 0.f;
+        // if (y0 + 1.f < y1)
+        //    y1 = y0 + 1.f;
+        for (y = y1; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
+            enable_z_endstop(false);
+            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+            enable_z_endstop(true);
+            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                continue;
+                /*
+                current_position[X_AXIS] = center_old_x;
+                SERIAL_PROTOCOLPGM("Failed 3\n");
+                goto canceled;
+                */
+            }
+            a = current_position[X_AXIS];
+            enable_z_endstop(false);
+            go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+            enable_z_endstop(true);
+            go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                continue;
+                /*
+                current_position[X_AXIS] = center_old_x;
+                SERIAL_PROTOCOLPGM("Failed 4\n");
+                goto canceled;
+                */
+            }
+            b = current_position[X_AXIS];
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level >= 5) {
+                debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
+                debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
+            }
+			#endif // SUPPORT_VERBOSITY
+            float d = b - a;
+            if (d > dmax) {
+                xmax2 = 0.5f * (a + b);
+                dmax = d;
+            } else if (dmax > 0.) {
+                y1 = y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y;
+                break;
+            }
+        }
+        float xmax, ymax;
+        if (dmax == 0.f) {
+            // Only the hit in the positive direction found.
+            xmax = xmax1;
+            ymax = y0;
+        } else {
+            // Both positive and negative directions found.
+            xmax = xmax2;
+            ymax = 0.5f * (y0 + y1);
+            for (; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
+                enable_z_endstop(false);
+                go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+                enable_z_endstop(true);
+                go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+                update_current_position_xyz();
+                if (! endstop_z_hit_on_purpose()) {
+                    continue;
+                    /*
+                    current_position[X_AXIS] = center_old_x;
+                    SERIAL_PROTOCOLPGM("Failed 3\n");
+                    goto canceled;
+                    */
+                }
+                a = current_position[X_AXIS];
+                enable_z_endstop(false);
+                go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+                enable_z_endstop(true);
+                go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+                update_current_position_xyz();
+                if (! endstop_z_hit_on_purpose()) {
+                    continue;
+                    /*
+                    current_position[X_AXIS] = center_old_x;
+                    SERIAL_PROTOCOLPGM("Failed 4\n");
+                    goto canceled;
+                    */
+                }
+                b = current_position[X_AXIS];
+				#ifdef SUPPORT_VERBOSITY
+                if (verbosity_level >= 5) {
+                    debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]);
+                    debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]);
+                }
+				#endif // SUPPORT_VERBOSITY
+                float d = b - a;
+                if (d > dmax) {
+                    xmax = 0.5f * (a + b);
+                    ymax = y;
+                    dmax = d;
+                }
+            }
+        }
+
+        {
+            // Compare the distance in the Y+ direction with the diameter in the X direction.
+            // Find the positive Y hit once again, this time along the Y axis going through the X point with the highest diameter.
+            enable_z_endstop(false);
+            go_xy(xmax, ymax + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f);
+            enable_z_endstop(true);
+            go_xy(xmax, max(ymax - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f);
+            update_current_position_xyz();
+            if (! endstop_z_hit_on_purpose()) {
+                current_position[Y_AXIS] = center_old_y;
+                goto canceled;
+            }
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level >= 5)
+                debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
+			#endif // SUPPORT_VERBOSITY
+			if (current_position[Y_AXIS] - Y_MIN_POS_FOR_BED_CALIBRATION < 0.5f * dmax) {
+                // Probably not even a half circle was detected. The induction point is likely too far in the minus Y direction.
+                // First verify, if the measurement has been done at a sufficient height. If no, lower the Z axis a bit.
+                if (current_position[Y_AXIS] < ymax || dmax < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
+					#ifdef SUPPORT_VERBOSITY
+					if (verbosity_level >= 5) {
+                        SERIAL_ECHOPGM("Partial point diameter too small: ");
+                        SERIAL_ECHO(dmax);
+                        SERIAL_ECHOLNPGM("");
+                    }
+					#endif // SUPPORT_VERBOSITY
+                    result = false;
+                } else {
+                    // Estimate the circle radius from the maximum diameter and height:
+                    float h = current_position[Y_AXIS] - ymax;
+                    float r = dmax * dmax / (8.f * h) + 0.5f * h;
+                    if (r < 0.8f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) {
+						#ifdef SUPPORT_VERBOSITY
+						if (verbosity_level >= 5) {
+                            SERIAL_ECHOPGM("Partial point estimated radius too small: ");
+                            SERIAL_ECHO(r);
+                            SERIAL_ECHOPGM(", dmax:");
+                            SERIAL_ECHO(dmax);
+                            SERIAL_ECHOPGM(", h:");
+                            SERIAL_ECHO(h);
+                            SERIAL_ECHOLNPGM("");
+                        }
+						#endif // SUPPORT_VERBOSITY
+                        result = false;
+                    } else {
+                        // The point may end up outside of the machine working space.
+                        // That is all right as it helps to improve the accuracy of the measurement point
+                        // due to averaging.
+                        // For the y correction, use an average of dmax/2 and the estimated radius.
+                        r = 0.5f * (0.5f * dmax + r);
+                        ymax = current_position[Y_AXIS] - r;
+                    }
+                }
+            } else {
+                // If the diameter of the detected spot was smaller than a minimum allowed,
+                // the induction sensor is probably too high. Returning false will force
+                // the sensor to be lowered a tiny bit.
+                result = xmax >= MIN_BED_SENSOR_POINT_RESPONSE_DMR;
+                if (y0 > Y_MIN_POS_FOR_BED_CALIBRATION + 0.2f)
+                    // Only in case both left and right y tangents are known, use them.
+                    // If y0 is close to the bed edge, it may not be symmetric to the right tangent.
+                    ymax = 0.5f * ymax + 0.25f * (y0 + y1);
+            }
+        }
+
+        // Go to the center.
+        enable_z_endstop(false);
+        current_position[X_AXIS] = xmax;
+        current_position[Y_AXIS] = ymax;
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 20) {
+            SERIAL_ECHOPGM("Adjusted position: ");
+            SERIAL_ECHO(current_position[X_AXIS]);
+            SERIAL_ECHOPGM(", ");
+            SERIAL_ECHO(current_position[Y_AXIS]);
+            SERIAL_ECHOLNPGM("");
+        }
+		#endif // SUPPORT_VERBOSITY
+
+        // Don't clamp current_position[Y_AXIS], because the out-of-reach Y coordinate may actually be true.
+        // Only clamp the coordinate to go.
+        go_xy(current_position[X_AXIS], max(Y_MIN_POS, current_position[Y_AXIS]), homing_feedrate[X_AXIS] / 60.f);
+        // delay_keep_alive(3000);
+    }
+
+    if (result)
+        return true;
+    // otherwise clamp the Y coordinate
+
+canceled:
+    // Go back to the center.
+    enable_z_endstop(false);
+    if (current_position[Y_AXIS] < Y_MIN_POS)
+        current_position[Y_AXIS] = Y_MIN_POS;
+    go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+    return false;
+}
+
+// Scan the mesh bed induction points one by one by a left-right zig-zag movement,
+// write the trigger coordinates to the serial line.
+// Useful for visualizing the behavior of the bed induction detector.
+inline void scan_bed_induction_sensor_point()
+{
+    float center_old_x = current_position[X_AXIS];
+    float center_old_y = current_position[Y_AXIS];
+    float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+    float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+    float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+    float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS;
+    float y = y0;
+
+    if (x0 < X_MIN_POS)
+        x0 = X_MIN_POS;
+    if (x1 > X_MAX_POS)
+        x1 = X_MAX_POS;
+    if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION)
+        y0 = Y_MIN_POS_FOR_BED_CALIBRATION;
+    if (y1 > Y_MAX_POS)
+        y1 = Y_MAX_POS;
+
+    for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) {
+        enable_z_endstop(false);
+        go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+        enable_z_endstop(true);
+        go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+        update_current_position_xyz();
+        if (endstop_z_hit_on_purpose())
+            debug_output_point(PSTR("left" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
+        enable_z_endstop(false);
+        go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f);
+        enable_z_endstop(true);
+        go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f);
+        update_current_position_xyz();
+        if (endstop_z_hit_on_purpose())
+            debug_output_point(PSTR("right"), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
+    }
+
+    enable_z_endstop(false);
+    current_position[X_AXIS] = center_old_x;
+    current_position[Y_AXIS] = center_old_y;
+    go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f);
+}
+
+#define MESH_BED_CALIBRATION_SHOW_LCD
+
+BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask)
+{	
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+    // Reusing the z_values memory for the measurement cache.
+    // 7x7=49 floats, good for 16 (x,y,z) vectors.
+    float *pts = &mbl.z_values[0][0];
+    float *vec_x = pts + 2 * 4;
+    float *vec_y = vec_x + 2;
+    float *cntr  = vec_y + 2;
+    memset(pts, 0, sizeof(float) * 7 * 7);
+	uint8_t iteration = 0; 
+	BedSkewOffsetDetectionResultType result;
+
+//    SERIAL_ECHOLNPGM("find_bed_offset_and_skew verbosity level: ");
+//    SERIAL_ECHO(int(verbosity_level));
+//    SERIAL_ECHOPGM("");
+	
+	while (iteration < 3) {
+
+		SERIAL_ECHOPGM("Iteration: ");
+		MYSERIAL.println(int(iteration + 1));
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 20) {
+		SERIAL_ECHOLNPGM("Vectors: ");
+		
+			SERIAL_ECHOPGM("vec_x[0]:");
+			MYSERIAL.print(vec_x[0], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("vec_x[1]:");
+			MYSERIAL.print(vec_x[1], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("vec_y[0]:");
+			MYSERIAL.print(vec_y[0], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("vec_y[1]:");
+			MYSERIAL.print(vec_y[1], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("cntr[0]:");
+			MYSERIAL.print(cntr[0], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("cntr[1]:");
+			MYSERIAL.print(cntr[1], 5);
+			SERIAL_ECHOLNPGM("");
+		}
+		#endif // SUPPORT_VERBOSITY
+#ifdef MESH_BED_CALIBRATION_SHOW_LCD
+    uint8_t next_line;
+    lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1, next_line);
+    if (next_line > 3)
+        next_line = 3;
+#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
+
+    // Collect the rear 2x3 points.
+	current_position[Z_AXIS] = MESH_HOME_Z_SEARCH + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3;
+	for (int k = 0; k < 4; ++k) {
+		// Don't let the manage_inactivity() function remove power from the motors.
+		refresh_cmd_timeout();
+#ifdef MESH_BED_CALIBRATION_SHOW_LCD
+		lcd_implementation_print_at(0, next_line, k + 1);
+		lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2);
+
+		if (iteration > 0) {
+			lcd_print_at_PGM(0, next_line + 1, MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION);
+			lcd_implementation_print(int(iteration + 1));
+		}
+#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
+		float *pt = pts + k * 2;
+		// Go up to z_initial.
+
+		go_to_current(homing_feedrate[Z_AXIS] / 60.f);
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 20) {
+			// Go to Y0, wait, then go to Y-4.
+			current_position[Y_AXIS] = 0.f;
+			go_to_current(homing_feedrate[X_AXIS] / 60.f);
+			SERIAL_ECHOLNPGM("At Y0");
+			delay_keep_alive(5000);
+			current_position[Y_AXIS] = Y_MIN_POS;
+			go_to_current(homing_feedrate[X_AXIS] / 60.f);
+			SERIAL_ECHOLNPGM("At Y-4");
+			delay_keep_alive(5000);
+		}
+		#endif // SUPPORT_VERBOSITY
+		// Go to the measurement point position.
+		//if (iteration == 0) {
+			current_position[X_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2);
+			current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2 + 1);
+		/*}
+		else {
+			// if first iteration failed, count corrected point coordinates as initial
+			// Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+			
+			current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[0] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[0];
+			current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[1];
+
+			// The calibration points are very close to the min Y.
+			if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION)
+				current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
+
+		}*/
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 20) {
+			SERIAL_ECHOPGM("current_position[X_AXIS]:");
+			MYSERIAL.print(current_position[X_AXIS], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("current_position[Y_AXIS]:");
+			MYSERIAL.print(current_position[Y_AXIS], 5);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOPGM("current_position[Z_AXIS]:");
+			MYSERIAL.print(current_position[Z_AXIS], 5);
+			SERIAL_ECHOLNPGM("");
+		}
+		#endif // SUPPORT_VERBOSITY
+
+		go_to_current(homing_feedrate[X_AXIS] / 60.f);
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 10)
+			delay_keep_alive(3000);
+		#endif // SUPPORT_VERBOSITY
+		if (!find_bed_induction_sensor_point_xy(verbosity_level))
+			return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
+#if 1
+		
+			if (k == 0 || k == 1) {
+				// Improve the position of the 1st row sensor points by a zig-zag movement.
+				find_bed_induction_sensor_point_z();
+				int8_t i = 4;
+				for (;;) {
+					if (improve_bed_induction_sensor_point3(verbosity_level))
+						break;
+					if (--i == 0)
+						return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
+					// Try to move the Z axis down a bit to increase a chance of the sensor to trigger.
+					current_position[Z_AXIS] -= 0.025f;
+					enable_endstops(false);
+					enable_z_endstop(false);
+					go_to_current(homing_feedrate[Z_AXIS]);
+				}
+				if (i == 0)
+					// not found
+					return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
+			}
+#endif
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 10)
+				delay_keep_alive(3000);
+			#endif // SUPPORT_VERBOSITY
+			// Save the detected point position and then clamp the Y coordinate, which may have been estimated
+			// to lie outside the machine working space.
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				SERIAL_ECHOLNPGM("Measured:");
+				MYSERIAL.println(current_position[X_AXIS]);
+				MYSERIAL.println(current_position[Y_AXIS]);
+			}
+			#endif // SUPPORT_VERBOSITY
+			pt[0] = (pt[0] * iteration) / (iteration + 1);
+			pt[0] += (current_position[X_AXIS]/(iteration + 1)); //count average
+			pt[1] = (pt[1] * iteration) / (iteration + 1);
+			pt[1] += (current_position[Y_AXIS] / (iteration + 1));
+			
+			
+			//pt[0] += current_position[X_AXIS];
+			//if(iteration > 0) pt[0] = pt[0] / 2;
+						
+			//pt[1] += current_position[Y_AXIS];
+			//if (iteration > 0) pt[1] = pt[1] / 2;
+
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOPGM("pt[0]:");
+				MYSERIAL.println(pt[0]);
+				SERIAL_ECHOPGM("pt[1]:");
+				MYSERIAL.println(pt[1]);
+			}
+			#endif // SUPPORT_VERBOSITY
+
+			if (current_position[Y_AXIS] < Y_MIN_POS)
+				current_position[Y_AXIS] = Y_MIN_POS;
+			// Start searching for the other points at 3mm above the last point.
+			current_position[Z_AXIS] += 3.f + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3;
+			//cntr[0] += pt[0];
+			//cntr[1] += pt[1];
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 10 && k == 0) {
+				// Show the zero. Test, whether the Y motor skipped steps.
+				current_position[Y_AXIS] = MANUAL_Y_HOME_POS;
+				go_to_current(homing_feedrate[X_AXIS] / 60.f);
+				delay_keep_alive(3000);
+			}
+			#endif // SUPPORT_VERBOSITY
+		}
+
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 20) {
+			// Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
+			delay_keep_alive(3000);
+			for (int8_t mesh_point = 0; mesh_point < 4; ++mesh_point) {
+				// Don't let the manage_inactivity() function remove power from the motors.
+				refresh_cmd_timeout();
+				// Go to the measurement point.
+				// Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+				current_position[X_AXIS] = pts[mesh_point * 2];
+				current_position[Y_AXIS] = pts[mesh_point * 2 + 1];
+				go_to_current(homing_feedrate[X_AXIS] / 60);
+				delay_keep_alive(3000);
+			}
+		}
+		#endif // SUPPORT_VERBOSITY
+		if (pts[1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) {
+			too_far_mask |= 1 << 1; //front center point is out of reach
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOPGM("WARNING: Front point not reachable. Y coordinate:");
+				MYSERIAL.print(pts[1]);
+				SERIAL_ECHOPGM(" < ");
+				MYSERIAL.println(Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
+		}
+
+		result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level);
+		if (result >= 0) {
+			world2machine_update(vec_x, vec_y, cntr);
+#if 1
+			// Fearlessly store the calibration values into the eeprom.
+			eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0), cntr[0]);
+			eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4), cntr[1]);
+			eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0), vec_x[0]);
+			eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4), vec_x[1]);
+			eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0), vec_y[0]);
+			eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4), vec_y[1]);
+#endif
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 10) {
+				// Length of the vec_x
+				float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
+				SERIAL_ECHOLNPGM("X vector length:");
+				MYSERIAL.println(l);
+
+				// Length of the vec_y
+				l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
+				SERIAL_ECHOLNPGM("Y vector length:");
+				MYSERIAL.println(l);
+				// Zero point correction
+				l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
+				SERIAL_ECHOLNPGM("Zero point correction:");
+				MYSERIAL.println(l);
+
+				// vec_x and vec_y shall be nearly perpendicular.
+				l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1];
+				SERIAL_ECHOLNPGM("Perpendicularity");
+				MYSERIAL.println(fabs(l));
+				SERIAL_ECHOLNPGM("Saving bed calibration vectors to EEPROM");
+			}
+			#endif // SUPPORT_VERBOSITY
+			// Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set.
+			world2machine_update_current();
+
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				// Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
+				delay_keep_alive(3000);
+				for (int8_t mesh_point = 0; mesh_point < 9; ++mesh_point) {
+					// Don't let the manage_inactivity() function remove power from the motors.
+					refresh_cmd_timeout();
+					// Go to the measurement point.
+					// Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+					current_position[X_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2);
+					current_position[Y_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2 + 1);
+					go_to_current(homing_feedrate[X_AXIS] / 60);
+					delay_keep_alive(3000);
+				}
+			}
+			#endif // SUPPORT_VERBOSITY
+			return result;
+		}		
+		if (result == BED_SKEW_OFFSET_DETECTION_FITTING_FAILED && too_far_mask == 2) return result; //if fitting failed and front center point is out of reach, terminate calibration and inform user
+		iteration++;
+	}
+	return result;    
+}
+
+BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask)
+{
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+    // Mask of the first three points. Are they too far?
+    too_far_mask = 0;
+
+    // Reusing the z_values memory for the measurement cache.
+    // 7x7=49 floats, good for 16 (x,y,z) vectors.
+    float *pts = &mbl.z_values[0][0];
+    float *vec_x = pts + 2 * 9;
+    float *vec_y = vec_x + 2;
+    float *cntr  = vec_y + 2;
+    memset(pts, 0, sizeof(float) * 7 * 7);
+	#ifdef SUPPORT_VERBOSITY
+	if (verbosity_level >= 10) SERIAL_ECHOLNPGM("Improving bed offset and skew");
+	#endif // SUPPORT_VERBOSITY
+    // Cache the current correction matrix.
+    world2machine_initialize();
+    vec_x[0] = world2machine_rotation_and_skew[0][0];
+    vec_x[1] = world2machine_rotation_and_skew[1][0];
+    vec_y[0] = world2machine_rotation_and_skew[0][1];
+    vec_y[1] = world2machine_rotation_and_skew[1][1];
+    cntr[0] = world2machine_shift[0];
+    cntr[1] = world2machine_shift[1];
+    // and reset the correction matrix, so the planner will not do anything.
+    world2machine_reset();
+
+    bool endstops_enabled  = enable_endstops(false);
+    bool endstop_z_enabled = enable_z_endstop(false);
+
+#ifdef MESH_BED_CALIBRATION_SHOW_LCD
+    uint8_t next_line;
+    lcd_display_message_fullscreen_P(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1, next_line);
+    if (next_line > 3)
+        next_line = 3;
+#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
+
+    // Collect a matrix of 9x9 points.
+    BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT;
+    for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) {
+        // Don't let the manage_inactivity() function remove power from the motors.
+        refresh_cmd_timeout();
+        // Print the decrasing ID of the measurement point.
+#ifdef MESH_BED_CALIBRATION_SHOW_LCD
+        lcd_implementation_print_at(0, next_line, mesh_point+1);
+        lcd_printPGM(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2);
+#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
+
+        // Move up.
+        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+        enable_endstops(false);
+        enable_z_endstop(false);
+        go_to_current(homing_feedrate[Z_AXIS]/60);
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 20) {
+            // Go to Y0, wait, then go to Y-4.
+            current_position[Y_AXIS] = 0.f;
+            go_to_current(homing_feedrate[X_AXIS] / 60.f);
+            SERIAL_ECHOLNPGM("At Y0");
+            delay_keep_alive(5000);
+            current_position[Y_AXIS] = Y_MIN_POS;
+            go_to_current(homing_feedrate[X_AXIS] / 60.f);
+			SERIAL_ECHOLNPGM("At Y_MIN_POS");
+            delay_keep_alive(5000);
+        }
+		#endif // SUPPORT_VERBOSITY
+        // Go to the measurement point.
+        // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+        current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points_4+mesh_point*2+1) + cntr[0];
+        current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points_4+mesh_point*2+1) + cntr[1];
+        // The calibration points are very close to the min Y.
+        if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION){
+            current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				SERIAL_ECHOPGM("Calibration point ");
+				SERIAL_ECHO(mesh_point);
+				SERIAL_ECHOPGM("lower than Ymin. Y coordinate clamping was used.");
+				SERIAL_ECHOLNPGM("");
+			}
+			#endif // SUPPORT_VERBOSITY
+		}
+        go_to_current(homing_feedrate[X_AXIS]/60);
+        // Find its Z position by running the normal vertical search.
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 10)
+            delay_keep_alive(3000);
+		#endif // SUPPORT_VERBOSITY
+		find_bed_induction_sensor_point_z();
+		#ifdef SUPPORT_VERBOSITY
+		if (verbosity_level >= 10)
+            delay_keep_alive(3000);
+		#endif // SUPPORT_VERBOSITY
+		// Try to move the Z axis down a bit to increase a chance of the sensor to trigger.
+        current_position[Z_AXIS] -= 0.025f;
+        // Improve the point position by searching its center in a current plane.
+        int8_t n_errors = 3;
+        for (int8_t iter = 0; iter < 8; ) {
+			#ifdef SUPPORT_VERBOSITY
+            if (verbosity_level > 20) {
+                SERIAL_ECHOPGM("Improving bed point ");
+                SERIAL_ECHO(mesh_point);
+                SERIAL_ECHOPGM(", iteration ");
+                SERIAL_ECHO(iter);
+                SERIAL_ECHOPGM(", z");
+                MYSERIAL.print(current_position[Z_AXIS], 5);
+                SERIAL_ECHOLNPGM("");
+            }
+			#endif // SUPPORT_VERBOSITY
+            bool found = false;
+            if (mesh_point < 2) {
+                // Because the sensor cannot move in front of the first row
+                // of the sensor points, the y position cannot be measured
+                // by a cross center method.
+                // Use a zig-zag search for the first row of the points.
+                found = improve_bed_induction_sensor_point3(verbosity_level);
+            } else {
+                switch (method) {
+                    case 0: found = improve_bed_induction_sensor_point(); break;
+                    case 1: found = improve_bed_induction_sensor_point2(mesh_point < 2, verbosity_level); break;
+                    default: break;
+                }
+            }
+            if (found) {
+                if (iter > 3) {
+                    // Average the last 4 measurements.
+                    pts[mesh_point*2  ] += current_position[X_AXIS];
+                    pts[mesh_point*2+1] += current_position[Y_AXIS];
+                }
+                if (current_position[Y_AXIS] < Y_MIN_POS)
+                    current_position[Y_AXIS] = Y_MIN_POS;
+                ++ iter;
+            } else if (n_errors -- == 0) {
+                // Give up.
+                result = BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
+                goto canceled;
+            } else {
+                // Try to move the Z axis down a bit to increase a chance of the sensor to trigger.
+                current_position[Z_AXIS] -= 0.05f;
+                enable_endstops(false);
+                enable_z_endstop(false);
+                go_to_current(homing_feedrate[Z_AXIS]);
+				#ifdef SUPPORT_VERBOSITY
+                if (verbosity_level >= 5) {
+                    SERIAL_ECHOPGM("Improving bed point ");
+                    SERIAL_ECHO(mesh_point);
+                    SERIAL_ECHOPGM(", iteration ");
+                    SERIAL_ECHO(iter);
+                    SERIAL_ECHOPGM(" failed. Lowering z to ");
+                    MYSERIAL.print(current_position[Z_AXIS], 5);
+                    SERIAL_ECHOLNPGM("");
+                }
+				#endif // SUPPORT_VERBOSITY
+            }
+        }
+		#ifdef SUPPORT_VERBOSITY
+        if (verbosity_level >= 10)
+            delay_keep_alive(3000);
+		#endif // SUPPORT_VERBOSITY
+    }
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+    // Average the last 4 measurements.
+    for (int8_t i = 0; i < 8; ++ i)
+        pts[i] *= (1.f/4.f);
+
+    enable_endstops(false);
+    enable_z_endstop(false);
+
+	#ifdef SUPPORT_VERBOSITY
+    if (verbosity_level >= 5) {
+        // Test the positions. Are the positions reproducible?
+		current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+        for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) {
+            // Don't let the manage_inactivity() function remove power from the motors.
+            refresh_cmd_timeout();
+            // Go to the measurement point.
+            // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+            current_position[X_AXIS] = pts[mesh_point*2];
+            current_position[Y_AXIS] = pts[mesh_point*2+1];
+            if (verbosity_level >= 10) {
+                go_to_current(homing_feedrate[X_AXIS]/60);
+                delay_keep_alive(3000);
+            }
+            SERIAL_ECHOPGM("Final measured bed point ");
+            SERIAL_ECHO(mesh_point);
+            SERIAL_ECHOPGM(": ");
+            MYSERIAL.print(current_position[X_AXIS], 5);
+            SERIAL_ECHOPGM(", ");
+            MYSERIAL.print(current_position[Y_AXIS], 5);
+            SERIAL_ECHOLNPGM("");
+        }
+    }
+	#endif // SUPPORT_VERBOSITY
+
+    {
+        // First fill in the too_far_mask from the measured points.
+        for (uint8_t mesh_point = 0; mesh_point < 2; ++ mesh_point)
+            if (pts[mesh_point * 2 + 1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH)
+                too_far_mask |= 1 << mesh_point;
+        result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level);
+        if (result < 0) {
+            SERIAL_ECHOLNPGM("Calculation of the machine skew and offset failed.");
+            goto canceled;
+        }
+        // In case of success, update the too_far_mask from the calculated points.
+        for (uint8_t mesh_point = 0; mesh_point < 2; ++ mesh_point) {
+            float y = vec_x[1] * pgm_read_float(bed_ref_points_4+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points_4+mesh_point*2+1) + cntr[1];
+			distance_from_min[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
+			#ifdef SUPPORT_VERBOSITY
+			if (verbosity_level >= 20) {
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOPGM("Distance from min:");
+				MYSERIAL.print(distance_from_min[mesh_point]);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOPGM("y:");
+				MYSERIAL.print(y);
+				SERIAL_ECHOLNPGM("");
+			}
+			#endif // SUPPORT_VERBOSITY
+			if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH)
+                too_far_mask |= 1 << mesh_point;
+        }
+    }
+
+    world2machine_update(vec_x, vec_y, cntr);
+#if 1
+    // Fearlessly store the calibration values into the eeprom.
+    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]);
+    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]);
+    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]);
+    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]);
+    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]);
+    eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]);
+#endif
+
+    // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set.
+    world2machine_update_current();
+
+    enable_endstops(false);
+    enable_z_endstop(false);
+	#ifdef SUPPORT_VERBOSITY
+    if (verbosity_level >= 5) {
+        // Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
+        delay_keep_alive(3000);
+		current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+        for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) {
+            // Don't let the manage_inactivity() function remove power from the motors.
+            refresh_cmd_timeout();
+            // Go to the measurement point.
+            // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+            current_position[X_AXIS] = pgm_read_float(bed_ref_points_4+mesh_point*2);
+            current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4+mesh_point*2+1);
+            if (verbosity_level >= 10) {
+                go_to_current(homing_feedrate[X_AXIS]/60);
+                delay_keep_alive(3000);
+            }
+            {
+                float x, y;
+                world2machine(current_position[X_AXIS], current_position[Y_AXIS], x, y);
+                SERIAL_ECHOPGM("Final calculated bed point ");
+                SERIAL_ECHO(mesh_point);
+                SERIAL_ECHOPGM(": ");
+                MYSERIAL.print(x, 5);
+                SERIAL_ECHOPGM(", ");
+                MYSERIAL.print(y, 5);
+                SERIAL_ECHOLNPGM("");
+            }
+        }
+    }
+	#endif // SUPPORT_VERBOSITY
+
+	//make space
+	current_position[Z_AXIS] += 150;
+	go_to_current(homing_feedrate[Z_AXIS] / 60);
+	//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder););
+
+	lcd_show_fullscreen_message_and_wait_P(MSG_PLACE_STEEL_SHEET);
+
+    // Sample Z heights for the mesh bed leveling.
+    // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process.
+    if (! sample_mesh_and_store_reference())
+        goto canceled;
+
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+    return result;
+
+canceled:
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+    // Print head up.
+    current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+    go_to_current(homing_feedrate[Z_AXIS]/60);
+    // Store the identity matrix to EEPROM.
+    reset_bed_offset_and_skew();
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+    return result;
+}
+
+void go_home_with_z_lift()
+{
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+    // Go home.
+    // First move up to a safe height.
+    current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+    go_to_current(homing_feedrate[Z_AXIS]/60);
+    // Second move to XY [0, 0].
+    current_position[X_AXIS] = X_MIN_POS+0.2;
+    current_position[Y_AXIS] = Y_MIN_POS+0.2;
+    // Clamp to the physical coordinates.
+    world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
+    go_to_current(homing_feedrate[X_AXIS]/60);
+    // Third move up to a safe height.
+    current_position[Z_AXIS] = Z_MIN_POS;
+    go_to_current(homing_feedrate[Z_AXIS]/60);    
+}
+
+// Sample the 9 points of the bed and store them into the EEPROM as a reference.
+// When calling this function, the X, Y, Z axes should be already homed,
+// and the world2machine correction matrix should be active.
+// Returns false if the reference values are more than 3mm far away.
+bool sample_mesh_and_store_reference()
+{
+    bool endstops_enabled  = enable_endstops(false);
+    bool endstop_z_enabled = enable_z_endstop(false);
+
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+#ifdef MESH_BED_CALIBRATION_SHOW_LCD
+    uint8_t next_line;
+    lcd_display_message_fullscreen_P(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1, next_line);
+    if (next_line > 3)
+        next_line = 3;
+    // display "point xx of yy"
+    lcd_implementation_print_at(0, next_line, 1);
+    lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2);
+#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
+
+    // Sample Z heights for the mesh bed leveling.
+    // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process.
+    {
+        // The first point defines the reference.
+        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+        go_to_current(homing_feedrate[Z_AXIS]/60);
+        current_position[X_AXIS] = pgm_read_float(bed_ref_points);
+        current_position[Y_AXIS] = pgm_read_float(bed_ref_points+1);
+        world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
+        go_to_current(homing_feedrate[X_AXIS]/60);
+        memcpy(destination, current_position, sizeof(destination));
+        enable_endstops(true);
+        homeaxis(Z_AXIS);
+        enable_endstops(false);
+        find_bed_induction_sensor_point_z();
+        mbl.set_z(0, 0, current_position[Z_AXIS]);
+    }
+    for (int8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) {
+        // Don't let the manage_inactivity() function remove power from the motors.
+        refresh_cmd_timeout();
+        // Print the decrasing ID of the measurement point.
+        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+        go_to_current(homing_feedrate[Z_AXIS]/60);
+        current_position[X_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point);
+        current_position[Y_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point+1);
+        world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
+        go_to_current(homing_feedrate[X_AXIS]/60);
+#ifdef MESH_BED_CALIBRATION_SHOW_LCD
+        // display "point xx of yy"
+        lcd_implementation_print_at(0, next_line, mesh_point+1);
+        lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2);
+#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
+        find_bed_induction_sensor_point_z();
+        // Get cords of measuring point
+        int8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS;
+        int8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
+        if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag
+        mbl.set_z(ix, iy, current_position[Z_AXIS]);
+    }
+    {
+        // Verify the span of the Z values.
+        float zmin = mbl.z_values[0][0];
+        float zmax = zmax;
+        for (int8_t j = 0; j < 3; ++ j)
+           for (int8_t i = 0; i < 3; ++ i) {
+                zmin = min(zmin, mbl.z_values[j][i]);
+                zmax = min(zmax, mbl.z_values[j][i]);
+           }
+        if (zmax - zmin > 3.f) {
+            // The span of the Z offsets is extreme. Give up.
+            // Homing failed on some of the points.
+            SERIAL_PROTOCOLLNPGM("Exreme span of the Z values!");
+            return false;
+        }
+    }
+
+    // Store the correction values to EEPROM.
+    // Offsets of the Z heiths of the calibration points from the first point.
+    // The offsets are saved as 16bit signed int, scaled to tenths of microns.
+    {
+        uint16_t addr = EEPROM_BED_CALIBRATION_Z_JITTER;
+        for (int8_t j = 0; j < 3; ++ j)
+            for (int8_t i = 0; i < 3; ++ i) {
+                if (i == 0 && j == 0)
+                    continue;
+                float dif = mbl.z_values[j][i] - mbl.z_values[0][0];
+                int16_t dif_quantized = int16_t(floor(dif * 100.f + 0.5f));
+                eeprom_update_word((uint16_t*)addr, *reinterpret_cast<uint16_t*>(&dif_quantized));
+                #if 0
+                {
+                    uint16_t z_offset_u = eeprom_read_word((uint16_t*)addr);
+                    float dif2 = *reinterpret_cast<int16_t*>(&z_offset_u) * 0.01;
+
+                    SERIAL_ECHOPGM("Bed point ");
+                    SERIAL_ECHO(i);
+                    SERIAL_ECHOPGM(",");
+                    SERIAL_ECHO(j);
+                    SERIAL_ECHOPGM(", differences: written ");
+                    MYSERIAL.print(dif, 5);
+                    SERIAL_ECHOPGM(", read: ");
+                    MYSERIAL.print(dif2, 5);
+                    SERIAL_ECHOLNPGM("");
+                }
+                #endif
+                addr += 2;
+            }
+    }
+
+    mbl.upsample_3x3();
+    mbl.active = true;
+
+    go_home_with_z_lift();
+
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+    return true;
+}
+
+bool scan_bed_induction_points(int8_t verbosity_level)
+{
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+    // Reusing the z_values memory for the measurement cache.
+    // 7x7=49 floats, good for 16 (x,y,z) vectors.
+    float *pts = &mbl.z_values[0][0];
+    float *vec_x = pts + 2 * 9;
+    float *vec_y = vec_x + 2;
+    float *cntr  = vec_y + 2;
+    memset(pts, 0, sizeof(float) * 7 * 7);
+
+    // Cache the current correction matrix.
+    world2machine_initialize();
+    vec_x[0] = world2machine_rotation_and_skew[0][0];
+    vec_x[1] = world2machine_rotation_and_skew[1][0];
+    vec_y[0] = world2machine_rotation_and_skew[0][1];
+    vec_y[1] = world2machine_rotation_and_skew[1][1];
+    cntr[0] = world2machine_shift[0];
+    cntr[1] = world2machine_shift[1];
+    // and reset the correction matrix, so the planner will not do anything.
+    world2machine_reset();
+
+    bool endstops_enabled  = enable_endstops(false);
+    bool endstop_z_enabled = enable_z_endstop(false);
+
+    // Collect a matrix of 9x9 points.
+    for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) {
+        // Don't let the manage_inactivity() function remove power from the motors.
+        refresh_cmd_timeout();
+
+        // Move up.
+        current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
+        enable_endstops(false);
+        enable_z_endstop(false);
+        go_to_current(homing_feedrate[Z_AXIS]/60);
+        // Go to the measurement point.
+        // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew().
+        current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0];
+        current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1];
+        // The calibration points are very close to the min Y.
+        if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION)
+            current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION;
+        go_to_current(homing_feedrate[X_AXIS]/60);
+        find_bed_induction_sensor_point_z();
+        scan_bed_induction_sensor_point();
+    }
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+    enable_endstops(false);
+    enable_z_endstop(false);
+
+    // Don't let the manage_inactivity() function remove power from the motors.
+    refresh_cmd_timeout();
+
+    enable_endstops(endstops_enabled);
+    enable_z_endstop(endstop_z_enabled);
+    return true;
+}
+
+// Shift a Z axis by a given delta.
+// To replace loading of the babystep correction.
+static void shift_z(float delta)
+{
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - delta, current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder);
+    st_synchronize();
+    plan_set_z_position(current_position[Z_AXIS]);
+}
+
+#define BABYSTEP_LOADZ_BY_PLANNER
+
+// Number of baby steps applied
+static int babystepLoadZ = 0;
+
+void babystep_load()
+{
+    // Apply Z height correction aka baby stepping before mesh bed leveling gets activated.
+    if(calibration_status() < CALIBRATION_STATUS_LIVE_ADJUST)
+    {
+        check_babystep(); //checking if babystep is in allowed range, otherwise setting babystep to 0
+        
+        // End of G80: Apply the baby stepping value.
+        EEPROM_read_B(EEPROM_BABYSTEP_Z,&babystepLoadZ);
+                            
+    #if 0
+        SERIAL_ECHO("Z baby step: ");
+        SERIAL_ECHO(babystepLoadZ);
+        SERIAL_ECHO(", current Z: ");
+        SERIAL_ECHO(current_position[Z_AXIS]);
+        SERIAL_ECHO("correction: ");
+        SERIAL_ECHO(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS]));
+        SERIAL_ECHOLN("");
+    #endif
+    }
+}
+
+void babystep_apply()
+{
+    babystep_load();
+#ifdef BABYSTEP_LOADZ_BY_PLANNER
+    shift_z(- float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS]));
+#else
+    babystepsTodoZadd(babystepLoadZ);
+#endif /* BABYSTEP_LOADZ_BY_PLANNER */
+}
+
+void babystep_undo()
+{
+#ifdef BABYSTEP_LOADZ_BY_PLANNER
+      shift_z(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS]));
+#else
+      babystepsTodoZsubtract(babystepLoadZ);
+#endif /* BABYSTEP_LOADZ_BY_PLANNER */
+      babystepLoadZ = 0;
+}
+
+void babystep_reset()
+{
+      babystepLoadZ = 0;    
+}
+
+void count_xyz_details() {
+	float a1, a2;
+	float cntr[2] = {
+		eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0)),
+		eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4))
+	};
+	float vec_x[2] = {
+		eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0)),
+		eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4))
+	};
+	float vec_y[2] = {
+		eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0)),
+		eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4))
+	};
+	a2 = -1 * asin(vec_y[0] / MACHINE_AXIS_SCALE_Y);
+	a1 = asin(vec_x[1] / MACHINE_AXIS_SCALE_X);
+	//angleDiff = fabs(a2 - a1);
+	for (uint8_t mesh_point = 0; mesh_point < 2; ++mesh_point) {
+		float y = vec_x[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2 + 1) + cntr[1];
+		distance_from_min[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
+	}
+}
+
+/*countDistanceFromMin() {
+
+}*/
+
+
+

+ 191 - 170
Firmware/mesh_bed_calibration.h

@@ -1,170 +1,191 @@
-#ifndef MESH_BED_CALIBRATION_H
-#define MESH_BED_CALIBRATION_H
-
-// Exact positions of the print head above the bed reference points, in the world coordinates.
-// The world coordinates match the machine coordinates only in case, when the machine
-// is built properly, the end stops are at the correct positions and the axes are perpendicular.
-extern const float bed_ref_points[] PROGMEM;
-
-// Is the world2machine correction activated?
-enum World2MachineCorrectionMode
-{
-	WORLD2MACHINE_CORRECTION_NONE  = 0,
-	WORLD2MACHINE_CORRECTION_SHIFT = 1,
-	WORLD2MACHINE_CORRECTION_SKEW  = 2,
-};
-extern uint8_t world2machine_correction_mode;
-// 2x2 transformation matrix from the world coordinates to the machine coordinates.
-// Corrects for the rotation and skew of the machine axes.
-// Used by the planner's plan_buffer_line() and plan_set_position().
-extern float world2machine_rotation_and_skew[2][2];
-extern float world2machine_rotation_and_skew_inv[2][2];
-// Shift of the machine zero point, in the machine coordinates.
-extern float world2machine_shift[2];
-
-// Resets the transformation to identity.
-extern void world2machine_reset();
-// Resets the transformation to identity and update current_position[X,Y] from the servos.
-extern void world2machine_revert_to_uncorrected();
-// Loads the transformation from the EEPROM, if available.
-extern void world2machine_initialize();
-
-// When switching from absolute to corrected coordinates,
-// this will apply an inverse world2machine transformation
-// to current_position[x,y].
-extern void world2machine_update_current();
-
-inline void world2machine(const float &x, const float &y, float &out_x, float &out_y)
-{
-	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
-		// No correction.
-		out_x = x;
-		out_y = y;
-	} else {
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
-			// Firs the skew & rotation correction.
-			out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y;
-			out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y;
-		}
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
-			// Then add the offset.
-			out_x += world2machine_shift[0];
-			out_y += world2machine_shift[1];
-		}
-	}
-}
-
-inline void world2machine(float &x, float &y)
-{
-	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
-		// No correction.
-	} else {
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
-			// Firs the skew & rotation correction.
-			float out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y;
-			float out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y;
-			x = out_x;
-			y = out_y;
-		}
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
-			// Then add the offset.
-			x += world2machine_shift[0];
-			y += world2machine_shift[1];
-		}
-	}
-}
-
-inline void machine2world(float x, float y, float &out_x, float &out_y)
-{
-	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
-		// No correction.
-		out_x = x;
-		out_y = y;
-	} else {
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
-			// Then add the offset.
-			x -= world2machine_shift[0];
-			y -= world2machine_shift[1];
-		}
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
-			// Firs the skew & rotation correction.
-			out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y;
-			out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y;
-		}
-	}
-}
-
-inline void machine2world(float &x, float &y)
-{
-	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
-		// No correction.
-	} else {
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
-			// Then add the offset.
-			x -= world2machine_shift[0];
-			y -= world2machine_shift[1];
-		}
-		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
-			// Firs the skew & rotation correction.
-			float out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y;
-			float out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y;
-			x = out_x;
-			y = out_y;
-		}
-	}
-}
-
-inline bool world2machine_clamp(float &x, float &y)
-{
-	bool clamped = false;
-	float tmpx, tmpy;
-    world2machine(x, y, tmpx, tmpy);
-    if (tmpx < X_MIN_POS) {
-        tmpx = X_MIN_POS;
-        clamped = true;
-    }
-    if (tmpy < Y_MIN_POS) {
-        tmpy = Y_MIN_POS;
-        clamped = true;
-    }
-    if (tmpx > X_MAX_POS) {
-        tmpx = X_MAX_POS;
-        clamped = true;
-    }
-    if (tmpy > Y_MAX_POS) {
-        tmpy = Y_MAX_POS;
-        clamped = true;
-    }
-    if (clamped)
-        machine2world(tmpx, tmpy, x, y);
-    return clamped;
-}
-
-extern bool find_bed_induction_sensor_point_z(float minimum_z = -10.f, uint8_t n_iter = 3);
-extern bool find_bed_induction_sensor_point_xy();
-
-// Positive or zero: ok
-// Negative: failed
-enum BedSkewOffsetDetectionResultType {
-	// Detection failed, some point was not found.
-	BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND   = -1,
-	BED_SKEW_OFFSET_DETECTION_FITTING_FAILED    = -2,
-
-	// Detection finished with success.
-	BED_SKEW_OFFSET_DETECTION_PERFECT 			= 0,
-	BED_SKEW_OFFSET_DETECTION_SKEW_MILD			= 1,
-	BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME		= 2
-};
-
-extern BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level);
-extern BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask);
-
-extern void reset_bed_offset_and_skew();
-extern bool is_bed_z_jitter_data_valid();
-
-// Scan the mesh bed induction points one by one by a left-right zig-zag movement,
-// write the trigger coordinates to the serial line.
-// Useful for visualizing the behavior of the bed induction detector.
-extern bool scan_bed_induction_points(int8_t verbosity_level);
-
-#endif /* MESH_BED_CALIBRATION_H */
+#ifndef MESH_BED_CALIBRATION_H
+#define MESH_BED_CALIBRATION_H
+
+// Exact positions of the print head above the bed reference points, in the world coordinates.
+// The world coordinates match the machine coordinates only in case, when the machine
+// is built properly, the end stops are at the correct positions and the axes are perpendicular.
+extern const float bed_ref_points[] PROGMEM;
+
+extern const float bed_skew_angle_mild;
+extern const float bed_skew_angle_extreme;
+
+// Is the world2machine correction activated?
+enum World2MachineCorrectionMode
+{
+	WORLD2MACHINE_CORRECTION_NONE  = 0,
+	WORLD2MACHINE_CORRECTION_SHIFT = 1,
+	WORLD2MACHINE_CORRECTION_SKEW  = 2,
+};
+extern uint8_t world2machine_correction_mode;
+// 2x2 transformation matrix from the world coordinates to the machine coordinates.
+// Corrects for the rotation and skew of the machine axes.
+// Used by the planner's plan_buffer_line() and plan_set_position().
+extern float world2machine_rotation_and_skew[2][2];
+extern float world2machine_rotation_and_skew_inv[2][2];
+// Shift of the machine zero point, in the machine coordinates.
+extern float world2machine_shift[2];
+
+// Resets the transformation to identity.
+extern void world2machine_reset();
+// Resets the transformation to identity and update current_position[X,Y] from the servos.
+extern void world2machine_revert_to_uncorrected();
+// Loads the transformation from the EEPROM, if available.
+extern void world2machine_initialize();
+
+// When switching from absolute to corrected coordinates,
+// this will apply an inverse world2machine transformation
+// to current_position[x,y].
+extern void world2machine_update_current();
+
+inline void world2machine(const float &x, const float &y, float &out_x, float &out_y)
+{
+	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
+		// No correction.
+		out_x = x;
+		out_y = y;
+	} else {
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
+			// Firs the skew & rotation correction.
+			out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y;
+			out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y;
+		}
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
+			// Then add the offset.
+			out_x += world2machine_shift[0];
+			out_y += world2machine_shift[1];
+		}
+	}
+}
+
+inline void world2machine(float &x, float &y)
+{
+	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
+		// No correction.
+	} else {
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
+			// Firs the skew & rotation correction.
+			float out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y;
+			float out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y;
+			x = out_x;
+			y = out_y;
+		}
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
+			// Then add the offset.
+			x += world2machine_shift[0];
+			y += world2machine_shift[1];
+		}
+	}
+}
+
+inline void machine2world(float x, float y, float &out_x, float &out_y)
+{
+	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
+		// No correction.
+		out_x = x;
+		out_y = y;
+	} else {
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
+			// Then add the offset.
+			x -= world2machine_shift[0];
+			y -= world2machine_shift[1];
+		}
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
+			// Firs the skew & rotation correction.
+			out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y;
+			out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y;
+		}
+	}
+}
+
+inline void machine2world(float &x, float &y)
+{
+	if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) {
+		// No correction.
+	} else {
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) {
+			// Then add the offset.
+			x -= world2machine_shift[0];
+			y -= world2machine_shift[1];
+		}
+		if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) {
+			// Firs the skew & rotation correction.
+			float out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y;
+			float out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y;
+			x = out_x;
+			y = out_y;
+		}
+	}
+}
+
+inline bool world2machine_clamp(float &x, float &y)
+{
+	bool clamped = false;
+	float tmpx, tmpy;
+    world2machine(x, y, tmpx, tmpy);
+    if (tmpx < X_MIN_POS) {
+        tmpx = X_MIN_POS;
+        clamped = true;
+    }
+    if (tmpy < Y_MIN_POS) {
+        tmpy = Y_MIN_POS;
+        clamped = true;
+    }
+    if (tmpx > X_MAX_POS) {
+        tmpx = X_MAX_POS;
+        clamped = true;
+    }
+    if (tmpy > Y_MAX_POS) {
+        tmpy = Y_MAX_POS;
+        clamped = true;
+    }
+    if (clamped)
+        machine2world(tmpx, tmpy, x, y);
+    return clamped;
+}
+
+extern bool find_bed_induction_sensor_point_z(float minimum_z = -10.f, uint8_t n_iter = 3, int verbosity_level = 0);
+extern bool find_bed_induction_sensor_point_xy(int verbosity_level = 0);
+extern void go_home_with_z_lift();
+
+// Positive or zero: ok
+// Negative: failed
+enum BedSkewOffsetDetectionResultType {
+	// Detection failed, some point was not found.
+	BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND   = -1,
+	BED_SKEW_OFFSET_DETECTION_FITTING_FAILED    = -2,
+	
+	// Detection finished with success.
+	BED_SKEW_OFFSET_DETECTION_PERFECT 			= 0,
+	BED_SKEW_OFFSET_DETECTION_SKEW_MILD			= 1,
+	BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME		= 2
+};
+
+extern BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask);
+extern BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask);
+
+extern bool sample_mesh_and_store_reference();
+
+extern void reset_bed_offset_and_skew();
+extern bool is_bed_z_jitter_data_valid();
+
+// Scan the mesh bed induction points one by one by a left-right zig-zag movement,
+// write the trigger coordinates to the serial line.
+// Useful for visualizing the behavior of the bed induction detector.
+extern bool scan_bed_induction_points(int8_t verbosity_level);
+
+// Load Z babystep value from the EEPROM into babystepLoadZ, 
+// but don't apply it through the planner. This is useful on wake up
+// after power panic, when it is expected, that the baby step has been already applied.
+extern void babystep_load();
+
+// Apply Z babystep value from the EEPROM through the planner.
+extern void babystep_apply();
+
+// Undo the current Z babystep value.
+extern void babystep_undo();
+
+// Reset the current babystep counter without moving the axes.
+extern void babystep_reset();
+extern void count_xyz_details();
+
+#endif /* MESH_BED_CALIBRATION_H */

+ 139 - 0
Firmware/pat9125.cpp

@@ -0,0 +1,139 @@
+#include "uni_avr_rpi.h"
+
+#ifdef PAT9125
+
+#include "pat9125.h"
+
+#ifdef PAT9125_SWSPI
+#include "swspi.h"
+#endif //PAT9125_SWSPI
+#ifdef PAT9125_SWI2C
+#include "swi2c.h"
+#endif //PAT9125_SWI2C
+#ifdef PAT9125_HWI2C
+#include <Wire.h>
+#endif //PAT9125_HWI2C
+
+
+unsigned char pat9125_PID1 = 0;
+unsigned char pat9125_PID2 = 0;
+unsigned char pat9125_xres = 0;
+unsigned char pat9125_yres = 0;
+int pat9125_x = 0;
+int pat9125_y = 0;
+unsigned char pat9125_b = 0;
+unsigned char pat9125_s = 0;
+
+int pat9125_init(unsigned char xres, unsigned char yres)
+{
+#ifdef PAT9125_SWSPI
+	swspi_init();
+#endif //PAT9125_SWSPI
+#ifdef PAT9125_SWI2C
+	swi2c_init(PAT9125_SWI2C_SDA, PAT9125_SWI2C_SCL, PAT9125_SWI2C_CFG);
+#endif //PAT9125_SWI2C
+#ifdef PAT9125_HWI2C
+	Wire.begin();
+#endif //PAT9125_HWI2C
+	pat9125_xres = xres;
+	pat9125_yres = yres;
+	pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1);
+	pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2);
+//	pat9125_PID1 = 0x31;
+//	pat9125_PID2 = 0x91;
+	if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91))
+	{
+		return 0;
+	}
+    pat9125_wr_reg(PAT9125_RES_X, pat9125_xres);
+    pat9125_wr_reg(PAT9125_RES_Y, pat9125_yres);
+//	pat9125_wr_reg(PAT9125_ORIENTATION, 0x04 | (xinv?0x08:0) | (yinv?0x10:0)); //!? direction switching does not work
+	return 1;
+}
+
+int pat9125_update()
+{
+	if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91))
+	{
+		unsigned char ucMotion = pat9125_rd_reg(PAT9125_MOTION);
+		pat9125_b = pat9125_rd_reg(PAT9125_FRAME);
+		pat9125_s = pat9125_rd_reg(PAT9125_SHUTTER);
+		if (ucMotion & 0x80)
+		{
+			unsigned char ucXL = pat9125_rd_reg(PAT9125_DELTA_XL);
+			unsigned char ucYL = pat9125_rd_reg(PAT9125_DELTA_YL);
+			unsigned char ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH);
+			int iDX = ucXL | ((ucXYH << 4) & 0xf00);
+			int iDY = ucYL | ((ucXYH << 8) & 0xf00);
+			if (iDX & 0x800) iDX -= 4096;
+			if (iDY & 0x800) iDY -= 4096;
+			pat9125_x += iDX;
+			pat9125_y -= iDY; //negative number, because direction switching does not work
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int pat9125_update_y()
+{
+	if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91))
+	{
+		unsigned char ucMotion = pat9125_rd_reg(PAT9125_MOTION);
+		if (ucMotion & 0x80)
+		{
+			unsigned char ucYL = pat9125_rd_reg(PAT9125_DELTA_YL);
+			unsigned char ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH);
+			int iDY = ucYL | ((ucXYH << 8) & 0xf00);
+			if (iDY & 0x800) iDY -= 4096;
+			pat9125_y -= iDY; //negative number, because direction switching does not work
+			return 1;
+		}
+	}
+	return 0;
+}
+
+unsigned char pat9125_rd_reg(unsigned char addr)
+{
+	unsigned char data = 0;
+#ifdef PAT9125_SWSPI
+	swspi_start();
+	swspi_tx(addr & 0x7f);
+	data = swspi_rx();
+	swspi_stop();
+#endif //PAT9125_SWSPI
+#ifdef PAT9125_SWI2C
+	int iret = swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data);
+#endif //PAT9125_SWI2C
+#ifdef PAT9125_HWI2C
+	Wire.beginTransmission(PAT9125_I2C_ADDR);
+	Wire.write(addr);
+	Wire.endTransmission();
+	if (Wire.requestFrom(PAT9125_I2C_ADDR, 1) == 1)
+//	if (Wire.available())
+		data = Wire.read();
+#endif //PAT9125_HWI2C
+	return data;
+}
+
+void pat9125_wr_reg(unsigned char addr, unsigned char data)
+{
+#ifdef PAT9125_SWSPI
+	swspi_start();
+	swspi_tx(addr | 0x80);
+	swspi_tx(data);
+	swspi_stop();
+#endif //PAT9125_SWSPI
+#ifdef PAT9125_SWI2C
+	int iret = swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data);
+#endif //PAT9125_SWI2C
+#ifdef PAT9125_HWI2C
+	Wire.beginTransmission(PAT9125_I2C_ADDR);
+	Wire.write(addr);
+	Wire.write(data);
+	Wire.endTransmission();
+#endif //PAT9125_HWI2C
+
+}
+
+#endif //PAT9125

+ 46 - 0
Firmware/pat9125.h

@@ -0,0 +1,46 @@
+#ifndef PAT9125_H
+#define PAT9125_H
+
+//PAT9125 I2C
+#define PAT9125_I2C_ADDR        0x75  //ID=LO
+//#define PAT9125_I2C_ADDR        0x79  //ID=HI
+//#define PAT9125_I2C_ADDR        0x73  //ID=NC
+
+//PAT9125 registers
+#define PAT9125_PID1			0x00
+#define PAT9125_PID2			0x01
+#define PAT9125_MOTION			0x02
+#define PAT9125_DELTA_XL		0x03
+#define PAT9125_DELTA_YL		0x04
+#define PAT9125_MODE			0x05
+#define PAT9125_CONFIG			0x06
+#define PAT9125_WP				0x09
+#define PAT9125_SLEEP1			0x0a
+#define PAT9125_SLEEP2			0x0b
+#define PAT9125_RES_X			0x0d
+#define PAT9125_RES_Y			0x0e
+#define PAT9125_DELTA_XYH		0x12
+#define PAT9125_SHUTTER			0x14
+#define PAT9125_FRAME			0x17
+#define PAT9125_ORIENTATION		0x19
+
+extern unsigned char pat9125_PID1;
+extern unsigned char pat9125_PID2;
+
+extern unsigned char pat9125_xres;
+extern unsigned char pat9125_yres;
+
+extern int pat9125_x;
+extern int pat9125_y;
+extern unsigned char pat9125_b;
+extern unsigned char pat9125_s;
+
+extern int pat9125_init(unsigned char xres, unsigned char yres);
+extern int pat9125_update();
+extern int pat9125_update_y();
+
+extern unsigned char pat9125_rd_reg(unsigned char addr);
+extern void pat9125_wr_reg(unsigned char addr, unsigned char data);
+
+
+#endif //PAT9125_H

+ 18 - 266
Firmware/pins.h

@@ -22,278 +22,30 @@
 /*****************************************************************
 * Rambo Pin Assignments 1.3
 ******************************************************************/
-#if MOTHERBOARD == 302
-  #define MINI_RAMBO
-  
-#endif
-#if MOTHERBOARD == 301 || MOTHERBOARD == 302
-  #define KNOWN_BOARD
-  #ifndef __AVR_ATmega2560__
-    #error Oops!  Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu.
-  #endif
-  
-
-  #define FR_SENS 21
-
-
-  #define X_STEP_PIN 37
-  #define X_DIR_PIN 48
-  #define X_MIN_PIN 12
-  #define X_MAX_PIN 24
-  #define X_ENABLE_PIN 29
-  #define X_MS1_PIN 40
-  #define X_MS2_PIN 41
-  #define Y_STEP_PIN 36
-  #define Y_DIR_PIN 49
-  #define Y_MIN_PIN 11
-  #define Y_MAX_PIN 23
-  #define Y_ENABLE_PIN 28
-  #define Y_MS1_PIN 69
-  #define Y_MS2_PIN 39
-  #define Z_STEP_PIN 35
-  #define Z_DIR_PIN 47
-  #define Z_MIN_PIN 10
-  #define Z_MAX_PIN 30
-  #define Z_ENABLE_PIN 27
-  #define Z_MS1_PIN 68
-  #define Z_MS2_PIN 67
-  #define TEMP_BED_PIN 2
-  #define TEMP_0_PIN 0
-  #define HEATER_1_PIN 7
-  #define TEMP_1_PIN 1
-  #define TEMP_2_PIN -1
-  
-  // The SDSS pin uses a different pin mapping from file Sd2PinMap.h
-#define SDSS               53
-
-#ifndef SDSUPPORT
-// these pins are defined in the SD library if building with SD support
-  #define SCK_PIN           52
-  #define MISO_PIN         50
-  #define MOSI_PIN         51
-#endif
-  
-    #define BEEPER 84
-
-        #define BTN_EN1 72
-        #define BTN_EN2 14
-        #define BTN_ENC 9
-
-        #define SDCARDDETECT 15
-        
-        #define LCD_PINS_RS 82
-        #define LCD_PINS_ENABLE 18
-        #define LCD_PINS_D4 19
-        #define LCD_PINS_D5 70
-        #define LCD_PINS_D6 85
-        #define LCD_PINS_D7 71
-  
-  
-  
-  #define E0_STEP_PIN         34
-  #define E0_DIR_PIN          43
-  #define E0_ENABLE_PIN       26
-  #define E0_MS1_PIN 65
-  #define E0_MS2_PIN 66
-  #define LED_PIN            13
-  #ifdef THREEMM_PRINTER
-      #define FAN_PIN            8
-  #else
-      #define FAN_PIN            6
-  #endif
-  #define KILL_PIN           -1 //80 with Smart Controller LCD
-  #define SUICIDE_PIN        -1  //PIN that has to be turned on right after start, to keep power flowing.
-  #define SDPOWER            -1
-  #define HEATER_2_PIN -1
-  #ifdef MINI_RAMBO
-
-    #define ELECTRONICS "RAMBo13a"
-
-    #define HEATER_0_PIN 3
-    #define HEATER_BED_PIN 4
-    #define FAN_1_PIN -1 //6
-    #define PS_ON_PIN 71
-    #define MOTOR_CURRENT_PWM_XY_PIN 46
-    #define MOTOR_CURRENT_PWM_Z_PIN 45
-    #define MOTOR_CURRENT_PWM_E_PIN 44
-    
-  #else //RAMBo
-    #define ELECTRONICS "RAMBoBig"
-
-    #define E1_STEP_PIN         33
-    #define E1_DIR_PIN          42
-    #define E1_ENABLE_PIN       25
-    #define E1_MS1_PIN 63
-    #define E1_MS2_PIN 64
-    #define DIGIPOTSS_PIN 38
-    #define DIGIPOT_CHANNELS {4,5,3,0,1} // X Y Z E0 E1 digipot channels to stepper driver mapping
-    #define HEATER_0_PIN  9
-    #define HEATER_BED_PIN 3
-    #define PS_ON_PIN          4
-    #define SDSS               53
-    #ifdef ULTRA_LCD
-      #define KILL_PIN 80
-      #ifdef NEWPANEL
-        //arduino pin which triggers an piezzo beeper
-        #define BEEPER 84      // Beeper on AUX-4
-        #define LCD_PINS_RS 82
-        #define LCD_PINS_ENABLE 18
-        #define LCD_PINS_D4 19
-        #define LCD_PINS_D5 70
-        #define LCD_PINS_D6 85
-        #define LCD_PINS_D7 71
-        //buttons are directly attached using AUX-2
-        #define BTN_EN1 76
-        #define BTN_EN2 77
-        #define BTN_ENC 78  //the click
-        #define BLEN_C 2
-        #define BLEN_B 1
-        #define BLEN_A 0
-        #define SDCARDDETECT 81    // Ramps does not use this port
-        //encoder rotation values
-        #define encrot0 0
-        #define encrot1 2
-        #define encrot2 3
-        #define encrot3 1
-      #else //old style panel with shift register
-        //arduino pin witch triggers an piezzo beeper
-        #define BEEPER 84    //No Beeper added
-        //buttons are attached to a shift register
-        // Not wired this yet
-        // #define SHIFT_CLK 38
-        // #define SHIFT_LD 42
-        // #define SHIFT_OUT 40
-        // #define SHIFT_EN 17
-        #define LCD_PINS_RS 82
-        #define LCD_PINS_ENABLE 18
-        #define LCD_PINS_D4 19
-        #define LCD_PINS_D5 70
-        #define LCD_PINS_D6 85
-        #define LCD_PINS_D7 71
-        //encoder rotation values
-        #define encrot0 0
-        #define encrot1 2
-        #define encrot2 3
-        #define encrot3 1
-        //bits in the shift register that carry the buttons for:
-        // left up center down right red
-        #define BL_LE 7
-        #define BL_UP 6
-        #define BL_MI 5
-        #define BL_DW 4
-        #define BL_RI 3
-        #define BL_ST 2
-        #define BLEN_B 1
-        #define BLEN_A 0
-      #endif
-    #endif //ULTRA_LCD
-  #endif //RAMBo/MiniRambo option
-#endif
-
-
-
 
+#if MOTHERBOARD == 100 //100 - orig 301
+#include "pins_Rambo.h"
+#endif //MOTHERBOARD == 100
 
+#if MOTHERBOARD == 200 //200 - orig 102
+#include "pins_Rambo_1_0.h"
+#endif //MOTHERBOARD == 200
 
+#if MOTHERBOARD == 203 //203 - orig 302
+#include "pins_Rambo_1_3.h"
+#endif //MOTHERBOARD == 203
 
+#if MOTHERBOARD == 303 //303 - orig 300
+#include "pins_Einy_0_3.h"
+#endif //MOTHERBOARD == 303
 
-/*****************************************************************
-* Rambo mini Pin Assignments 1.0
-******************************************************************/
-#if MOTHERBOARD == 102
-  #define ELECTRONICS "RAMBo10a"
-  #define KNOWN_BOARD
-  #ifndef __AVR_ATmega2560__
-    #error Oops!  Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu.
-  #endif
-
-  #define FR_SENS 21
-
-  #define LARGE_FLASH true
-  #define X_STEP_PIN 37
-  #define X_DIR_PIN 48
-  #define X_MIN_PIN 12
-  #define X_MAX_PIN 24
-  #define X_ENABLE_PIN 29
-  #define X_MS1_PIN 40
-  #define X_MS2_PIN 41
-  #define Y_STEP_PIN 36
-  #define Y_DIR_PIN 49
-  #define Y_MIN_PIN 11
-  #define Y_MAX_PIN 23
-  #define Y_ENABLE_PIN 28
-  #define Y_MS1_PIN 69
-  #define Y_MS2_PIN 39
-  #define Z_STEP_PIN 35
-  #define Z_DIR_PIN 47
-  #define Z_MIN_PIN 10
-  #define Z_MAX_PIN 30
-  #define Z_ENABLE_PIN 27
-  #define Z_MS1_PIN 68
-  #define Z_MS2_PIN 67
-  #define TEMP_BED_PIN 2
-  #define TEMP_0_PIN 0
-  #define HEATER_1_PIN 7
-  #define TEMP_1_PIN 1
-  #define TEMP_2_PIN -1
-  
-  // The SDSS pin uses a different pin mapping from file Sd2PinMap.h
-#define SDSS               53
-
-#ifndef SDSUPPORT
-// these pins are defined in the SD library if building with SD support
-  #define SCK_PIN           52
-  #define MISO_PIN         50
-  #define MOSI_PIN         51
-#endif
-  
-    #define BEEPER 78
-
-        #define BTN_EN1 80
-        #define BTN_EN2 73
-        #define BTN_ENC 21
-
-        #define SDCARDDETECT 72
-        
-        #define LCD_PINS_RS 38
-        #define LCD_PINS_ENABLE 5
-        #define LCD_PINS_D4 14
-        #define LCD_PINS_D5 15
-        #define LCD_PINS_D6 32
-        #define LCD_PINS_D7 31
-  
-  
-  
-  #define E0_STEP_PIN         34
-  #define E0_DIR_PIN          43
-  #define E0_ENABLE_PIN       26
-  #define E0_MS1_PIN 65
-  #define E0_MS2_PIN 66
-  #define LED_PIN            13
-  #ifdef THREEMM_PRINTER
-      #define FAN_PIN            8
-  #else
-      #define FAN_PIN            6
-  #endif
-  #define KILL_PIN           -1 //80 with Smart Controller LCD
-  #define SUICIDE_PIN        -1  //PIN that has to be turned on right after start, to keep power flowing.
-  #define SDPOWER            -1
-  #define HEATER_2_PIN -1
-
-    #define HEATER_0_PIN 3
-    #define HEATER_BED_PIN 4
-    #define FAN_1_PIN -1 //6
-    #define PS_ON_PIN 71
-    #define MOTOR_CURRENT_PWM_XY_PIN 46
-    #define MOTOR_CURRENT_PWM_Z_PIN 45
-    #define MOTOR_CURRENT_PWM_E_PIN 44
-    
-
-#endif
-
-
-
+#if MOTHERBOARD == 304 //304 - orig 299
+#include "pins_Einy_0_4.h"
+#endif //MOTHERBOARD == 304
 
+#if MOTHERBOARD == 305 //305 - orig 298
+#include "pins_Einy_0_4.h"
+#endif //MOTHERBOARD == 305
 
 #ifndef KNOWN_BOARD
 #error Unknown MOTHERBOARD value in configuration.h

+ 129 - 0
Firmware/pins_Einy_0_3.h

@@ -0,0 +1,129 @@
+/*****************************************************************
+* EINY Rambo 0.3a Pin Assignments
+******************************************************************/
+
+#define ELECTRONICS "EINY_03a"
+
+#define KNOWN_BOARD
+#ifndef __AVR_ATmega2560__
+  #error Oops!  Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu.
+#endif
+
+#define TMC2130
+#define PAT9125
+
+#define SWI2C                    // enable software i2c
+#define SWI2C_A8                 // 8bit address functions
+
+#define PAT9125_SWI2C
+#define PAT9125_SWI2C_SDA   20 //SDA on P3
+#define PAT9125_SWI2C_SCL   21 //SCL on P3
+#define PAT9125_SWI2C_CFG   0xb1 //2us clock delay, 2048 cycles timeout
+
+//#define SWSPI_MISO          16 //RX2
+//#define SWSPI_MOSI          16 //RX2
+//#define SWSPI_SCK           17 //TX2
+//#define SWSPI_CS            20 //SDA
+
+////#define SWI2C_SDA           20 //SDA
+////#define SWI2C_SCL           21 //SCL
+//#define SWI2C_SDA           16 //RX2
+//#define SWI2C_SCL           17 //TX2
+
+#define X_TMC2130_CS        41
+#define X_TMC2130_DIAG      40
+#define X_STEP_PIN          37
+#define X_DIR_PIN           49
+//#define X_MIN_PIN           12
+//#define X_MAX_PIN           30
+#define X_MIN_PIN           X_TMC2130_DIAG
+#define X_MAX_PIN           X_TMC2130_DIAG
+#define X_ENABLE_PIN        29
+#define X_MS1_PIN           -1
+#define X_MS2_PIN           -1
+
+#define Y_TMC2130_CS        39
+#define Y_TMC2130_DIAG      69
+#define Y_STEP_PIN          36
+#define Y_DIR_PIN           48
+//#define Y_MIN_PIN           11
+//#define Y_MAX_PIN           24
+#define Y_MIN_PIN           Y_TMC2130_DIAG
+#define Y_MAX_PIN           Y_TMC2130_DIAG
+#define Y_ENABLE_PIN        28
+#define Y_MS1_PIN           -1
+#define Y_MS2_PIN           -1
+
+#define Z_TMC2130_CS        67
+#define Z_TMC2130_DIAG      68
+#define Z_STEP_PIN          35
+#define Z_DIR_PIN           47
+#define Z_MIN_PIN           10
+#define Z_MAX_PIN           23
+//#define Z_MAX_PIN           Z_TMC2130_DIAG
+#define Z_ENABLE_PIN        27
+#define Z_MS1_PIN           -1
+#define Z_MS2_PIN           -1
+
+#define HEATER_BED_PIN       4 //PG5
+#define TEMP_BED_PIN         2 //A2
+
+#define HEATER_0_PIN         3 //PE5
+#define TEMP_0_PIN           0 //A0
+
+#define HEATER_1_PIN        -1
+#define TEMP_1_PIN           1 //A1
+
+#define HEATER_2_PIN        -1
+#define TEMP_2_PIN          -1
+
+#define TEMP_AMBIENT_PIN     6 //A6
+
+#define TEMP_PINDA_PIN       3 //A3
+
+#define E0_TMC2130_CS       66
+#define E0_TMC2130_DIAG     65
+#define E0_STEP_PIN         34
+#define E0_DIR_PIN          43
+#define E0_ENABLE_PIN       26
+#define E0_MS1_PIN          -1
+#define E0_MS2_PIN          -1
+
+#define MOTOR_CURRENT_PWM_XY_PIN 46
+#define MOTOR_CURRENT_PWM_Z_PIN  45
+#define MOTOR_CURRENT_PWM_E_PIN  44
+#define SDPOWER             -1
+#define SDSS                53
+#define LED_PIN             13
+#define FAN_PIN              6
+#define FAN_1_PIN           -1
+#define PS_ON_PIN           -1
+#define KILL_PIN            -1  // 80 with Smart Controller LCD
+#define SUICIDE_PIN         -1  // PIN that has to be turned on right after start, to keep power flowing.
+
+#ifdef ULTRA_LCD
+
+//#define KILL_PIN            32
+
+#ifdef NEWPANEL
+
+#define BEEPER              84  // Beeper on AUX-4
+#define LCD_PINS_RS         82
+#define LCD_PINS_ENABLE     18
+#define LCD_PINS_D4         19
+#define LCD_PINS_D5         70
+#define LCD_PINS_D6         85
+#define LCD_PINS_D7         71
+
+//buttons are directly attached using AUX-2
+#define BTN_EN1             72
+#define BTN_EN2             14
+#define BTN_ENC              9  // the click
+
+#define SDCARDDETECT        15
+
+#define TACH_0              81
+#define TACH_1              80 
+
+#endif //NEWPANEL
+#endif //ULTRA_LCD

+ 124 - 0
Firmware/pins_Einy_0_4.h

@@ -0,0 +1,124 @@
+/*****************************************************************
+* EINY Rambo 0.4a Pin Assignments
+******************************************************************/
+
+#define ELECTRONICS "EINY_04a"
+
+#define KNOWN_BOARD
+#ifndef __AVR_ATmega2560__
+  #error Oops!  Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu.
+#endif
+
+#define TMC2130
+#define PAT9125
+
+#define SWI2C                    // enable software i2c
+#define SWI2C_A8                 // 8bit address functions
+
+#define PAT9125_SWI2C
+#define PAT9125_SWI2C_SDA      20 //SDA on P3
+#define PAT9125_SWI2C_SCL      21 //SCL on P3
+#define PAT9125_SWI2C_CFG    0xb1 //2us clock delay, 2048 cycles timeout
+
+//#define PAT9125_HWI2C
+
+#define X_TMC2130_CS           41
+#define X_TMC2130_DIAG         64 // !!! changed from 40 (EINY03)
+#define X_STEP_PIN             37
+#define X_DIR_PIN              49
+#define X_MIN_PIN            12
+//#define X_MAX_PIN            30
+//#define X_MIN_PIN              X_TMC2130_DIAG
+#define X_MAX_PIN              X_TMC2130_DIAG
+#define X_ENABLE_PIN           29
+#define X_MS1_PIN           -1
+#define X_MS2_PIN           -1
+
+#define Y_TMC2130_CS        39
+#define Y_TMC2130_DIAG      69
+#define Y_STEP_PIN          36
+#define Y_DIR_PIN           48
+#define Y_MIN_PIN           11
+//#define Y_MAX_PIN           24
+//#define Y_MIN_PIN           Y_TMC2130_DIAG
+#define Y_MAX_PIN           Y_TMC2130_DIAG
+#define Y_ENABLE_PIN        28
+#define Y_MS1_PIN           -1
+#define Y_MS2_PIN           -1
+
+#define Z_TMC2130_CS        67
+#define Z_TMC2130_DIAG      68
+#define Z_STEP_PIN          35
+#define Z_DIR_PIN           47
+#define Z_MIN_PIN           10
+#define Z_MAX_PIN           23
+//#define Z_MAX_PIN           Z_TMC2130_DIAG
+#define Z_ENABLE_PIN        27
+#define Z_MS1_PIN           -1
+#define Z_MS2_PIN           -1
+
+#define HEATER_BED_PIN       4 //PG5
+#define TEMP_BED_PIN         2 //A2
+
+#define HEATER_0_PIN         3 //PE5
+#define TEMP_0_PIN           0 //A0
+
+#define HEATER_1_PIN        -1
+#define TEMP_1_PIN           1 //A1
+
+#define HEATER_2_PIN        -1
+#define TEMP_2_PIN          -1
+
+#define TEMP_AMBIENT_PIN     6 //A6
+
+#define TEMP_PINDA_PIN       3 //A3
+
+#define E0_TMC2130_CS       66
+#define E0_TMC2130_DIAG     65
+#define E0_STEP_PIN         34
+#define E0_DIR_PIN          43
+#define E0_ENABLE_PIN       26
+#define E0_MS1_PIN          -1
+#define E0_MS2_PIN          -1
+
+#define MOTOR_CURRENT_PWM_XY_PIN 46
+#define MOTOR_CURRENT_PWM_Z_PIN  45
+#define MOTOR_CURRENT_PWM_E_PIN  44
+#define SDPOWER             -1
+#define SDSS                77
+#define LED_PIN             13
+#define FAN_PIN              6
+#define FAN_1_PIN           -1
+#define PS_ON_PIN           -1
+#define KILL_PIN            -1  // 80 with Smart Controller LCD
+#define SUICIDE_PIN         -1  // PIN that has to be turned on right after start, to keep power flowing.
+
+#ifdef ULTRA_LCD
+
+//#define KILL_PIN            32
+
+#ifdef NEWPANEL
+
+#define LCD_PWM_PIN         32  // lcd backlight brightnes pwm control pin
+#define LCD_PWM_MAX       0x0f  // lcd pwm maximum value (0x07=64Hz, 0x0f=32Hz, 0x1f=16Hz)
+
+#define BEEPER              84  // Beeper on AUX-4
+#define LCD_PINS_RS         82
+#define LCD_PINS_ENABLE     61 // !!! changed from 18 (EINY03)
+#define LCD_PINS_D4	        59 // !!! changed from 19 (EINY03)
+#define LCD_PINS_D5         70
+#define LCD_PINS_D6         85
+#define LCD_PINS_D7         71
+
+//buttons are directly attached using AUX-2
+#define BTN_EN1                72
+#define BTN_EN2                14
+#define BTN_ENC                 9  // the click
+
+#define SDCARDDETECT           15
+
+#define TACH_0                 79 // !!! changed from 81 (EINY03)
+#define TACH_1                 80 
+
+#endif //NEWPANEL
+#endif //ULTRA_LCD

+ 162 - 0
Firmware/pins_Rambo.h

@@ -0,0 +1,162 @@
+/*****************************************************************
+* Rambo Pin Assignments
+******************************************************************/
+
+#define ELECTRONICS "RAMBoBig"
+
+#define KNOWN_BOARD
+#ifndef __AVR_ATmega2560__
+  #error Oops!  Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu.
+#endif
+
+#define FR_SENS                21
+
+#define X_STEP_PIN             37
+#define X_DIR_PIN              48
+#define X_MIN_PIN              12
+#define X_MAX_PIN              30
+#define X_ENABLE_PIN           29
+#define X_MS1_PIN              40
+#define X_MS2_PIN              41
+#define Y_STEP_PIN             36
+#define Y_DIR_PIN              49
+#define Y_MIN_PIN              11
+#define Y_MAX_PIN              24
+#define Y_ENABLE_PIN           28
+#define Y_MS1_PIN              69
+#define Y_MS2_PIN              39
+#define Z_STEP_PIN             35
+#define Z_DIR_PIN              47
+#define Z_MIN_PIN              10
+#define Z_MAX_PIN              23
+#define Z_ENABLE_PIN           27
+#define Z_MS1_PIN              68
+#define Z_MS2_PIN              67
+#define TEMP_BED_PIN            2
+#define TEMP_0_PIN              0
+#define HEATER_1_PIN            7
+#define TEMP_1_PIN              1
+#define TEMP_2_PIN             -1
+
+#ifdef SNMM 
+  #define E_MUX0_PIN           17
+  #define E_MUX1_PIN           16
+  #define E_MUX2_PIN           84
+#endif
+
+#ifdef DIS
+  #define D_REQUIRE            30
+  #define D_DATA               20
+  #define D_DATACLOCK          21
+#endif
+
+// The SDSS pin uses a different pin mapping from file Sd2PinMap.h
+#define SDSS                   53
+
+#ifndef SDSUPPORT
+// these pins are defined in the SD library if building with SD support
+  #define SCK_PIN              52
+  #define MISO_PIN             50
+  #define MOSI_PIN             51
+#endif
+
+#define BEEPER                 84
+
+#define BTN_EN1                72
+#define BTN_EN2                14
+#define BTN_ENC                 9
+
+#define SDCARDDETECT           15
+
+#define LCD_PINS_RS            82
+#define LCD_PINS_ENABLE        18
+#define LCD_PINS_D4            19
+#define LCD_PINS_D5            70
+#define LCD_PINS_D6            85
+#define LCD_PINS_D7            71
+
+#define E0_STEP_PIN            34
+#define E0_DIR_PIN             43
+#define E0_ENABLE_PIN          26
+#define E0_MS1_PIN             65
+#define E0_MS2_PIN             66
+#define LED_PIN                13
+
+#ifdef THREEMM_PRINTER
+  #define FAN_PIN               8
+#else
+  #define FAN_PIN               6
+#endif
+
+#define KILL_PIN               -1 //80 with Smart Controller LCD
+#define SUICIDE_PIN            -1  //PIN that has to be turned on right after start, to keep power flowing.
+#define SDPOWER                -1
+#define HEATER_2_PIN           -1
+
+#define E1_STEP_PIN            33
+#define E1_DIR_PIN             42
+#define E1_ENABLE_PIN          25
+#define E1_MS1_PIN             63
+#define E1_MS2_PIN             64
+#define DIGIPOTSS_PIN          38
+#define DIGIPOT_CHANNELS       {4,5,3,0,1} // X Y Z E0 E1 digipot channels to stepper driver mapping
+#define HEATER_0_PIN            9
+#define HEATER_BED_PIN          3
+#define PS_ON_PIN               4
+#define SDSS                   53
+#ifdef ULTRA_LCD
+ #define KILL_PIN              80
+ #ifdef NEWPANEL
+  //arduino pin which triggers an piezzo beeper
+  #define BEEPER               84      // Beeper on AUX-4
+  #define LCD_PINS_RS          82
+  #define LCD_PINS_ENABLE      18
+  #define LCD_PINS_D4          19
+  #define LCD_PINS_D5          70
+  #define LCD_PINS_D6          85
+  #define LCD_PINS_D7          71
+  //buttons are directly attached using AUX-2
+  #define BTN_EN1              76
+  #define BTN_EN2              77
+  #define BTN_ENC              78  //the click
+  #define BLEN_C                2
+  #define BLEN_B                1
+  #define BLEN_A                0
+  #define SDCARDDETECT         81    // Ramps does not use this port
+  //encoder rotation values
+  #define encrot0               0
+  #define encrot1               2
+  #define encrot2               3
+  #define encrot3               1
+ #else //old style panel with shift register
+  //arduino pin witch triggers an piezzo beeper
+  #define BEEPER               84    //No Beeper added
+  //buttons are attached to a shift register
+  // Not wired this yet
+  // #define SHIFT_CLK 38
+  // #define SHIFT_LD 42
+  // #define SHIFT_OUT 40
+  // #define SHIFT_EN 17
+  #define LCD_PINS_RS          82
+  #define LCD_PINS_ENABLE      18
+  #define LCD_PINS_D4          19
+  #define LCD_PINS_D5          70
+  #define LCD_PINS_D6          85
+  #define LCD_PINS_D7          71
+  //encoder rotation values
+  #define encrot0               0
+  #define encrot1               2
+  #define encrot2               3
+  #define encrot3               1
+  //bits in the shift register that carry the buttons for:
+  // left up center down right red
+  #define BL_LE                 7
+  #define BL_UP                 6
+  #define BL_MI                 5
+  #define BL_DW                 4
+  #define BL_RI                 3
+  #define BL_ST                 2
+  #define BLEN_B                1
+  #define BLEN_A                0
+ #endif
+#endif //ULTRA_LCD

+ 94 - 0
Firmware/pins_Rambo_1_0.h

@@ -0,0 +1,94 @@
+/*****************************************************************
+* Rambo mini 1.0 Pin Assignments
+******************************************************************/
+
+#define ELECTRONICS "RAMBo10a"
+
+#define KNOWN_BOARD
+#ifndef __AVR_ATmega2560__
+  #error Oops!  Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu.
+#endif
+
+#define FR_SENS                21
+
+#define X_STEP_PIN             37
+#define X_DIR_PIN              48
+#define X_MIN_PIN              12
+#define X_MAX_PIN              30
+#define X_ENABLE_PIN           29
+#define X_MS1_PIN              40
+#define X_MS2_PIN              41
+#define Y_STEP_PIN             36
+#define Y_DIR_PIN              49
+#define Y_MIN_PIN              11
+#define Y_MAX_PIN              24
+#define Y_ENABLE_PIN           28
+#define Y_MS1_PIN              69
+#define Y_MS2_PIN              39
+#define Z_STEP_PIN             35
+#define Z_DIR_PIN              47
+#define Z_MIN_PIN              10
+#define Z_MAX_PIN              23
+#define Z_ENABLE_PIN           27
+#define Z_MS1_PIN              68
+#define Z_MS2_PIN              67
+#define TEMP_BED_PIN            2
+#define TEMP_0_PIN              0
+#define HEATER_1_PIN            7
+#define TEMP_1_PIN              1
+#define TEMP_2_PIN             -1
+
+#ifdef SNMM
+  #define E_MUX0_PIN           17
+  #define E_MUX1_PIN           16
+  #define E_MUX2_PIN           84
+#endif
+
+// The SDSS pin uses a different pin mapping from file Sd2PinMap.h
+#define SDSS                   53
+
+#ifndef SDSUPPORT
+// these pins are defined in the SD library if building with SD support
+  #define SCK_PIN              52
+  #define MISO_PIN             50
+  #define MOSI_PIN             51
+#endif
+  
+#define BEEPER                 78
+
+#define BTN_EN1                80
+#define BTN_EN2                73
+#define BTN_ENC                21
+
+#define SDCARDDETECT           72
+
+#define LCD_PINS_RS            38
+#define LCD_PINS_ENABLE         5
+#define LCD_PINS_D4            14
+#define LCD_PINS_D5            15
+#define LCD_PINS_D6            32
+#define LCD_PINS_D7            31
+
+#define E0_STEP_PIN            34
+#define E0_DIR_PIN             43
+#define E0_ENABLE_PIN          26
+#define E0_MS1_PIN             65
+#define E0_MS2_PIN             66
+#define LED_PIN                13
+#ifdef THREEMM_PRINTER
+  #define FAN_PIN               8
+#else
+  #define FAN_PIN               6
+#endif
+#define KILL_PIN               -1 //80 with Smart Controller LCD
+#define SUICIDE_PIN            -1  //PIN that has to be turned on right after start, to keep power flowing.
+#define SDPOWER                -1
+#define HEATER_2_PIN           -1
+
+#define HEATER_0_PIN            3
+#define HEATER_BED_PIN          4
+#define FAN_1_PIN              -1 //6
+#define PS_ON_PIN              71
+#define MOTOR_CURRENT_PWM_XY_PIN   46
+#define MOTOR_CURRENT_PWM_Z_PIN    45
+#define MOTOR_CURRENT_PWM_E_PIN    44

+ 102 - 0
Firmware/pins_Rambo_1_3.h

@@ -0,0 +1,102 @@
+/*****************************************************************
+* Rambo mini 1.3 Pin Assignments
+******************************************************************/
+
+#define ELECTRONICS "RAMBo13a"
+
+#define KNOWN_BOARD
+#ifndef __AVR_ATmega2560__
+  #error Oops!  Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu.
+#endif
+
+#define FR_SENS                21
+
+#define X_STEP_PIN             37
+#define X_DIR_PIN              48
+#define X_MIN_PIN              12
+#define X_MAX_PIN              30
+#define X_ENABLE_PIN           29
+#define X_MS1_PIN              40
+#define X_MS2_PIN              41
+#define Y_STEP_PIN             36
+#define Y_DIR_PIN              49
+#define Y_MIN_PIN              11
+#define Y_MAX_PIN              24
+#define Y_ENABLE_PIN           28
+#define Y_MS1_PIN              69
+#define Y_MS2_PIN              39
+#define Z_STEP_PIN             35
+#define Z_DIR_PIN              47
+#define Z_MIN_PIN              10
+#define Z_MAX_PIN              23
+#define Z_ENABLE_PIN           27
+#define Z_MS1_PIN              68
+#define Z_MS2_PIN              67
+#define TEMP_BED_PIN            2
+#define TEMP_0_PIN              0
+#define HEATER_1_PIN            7
+#define TEMP_1_PIN              1
+#define TEMP_2_PIN             -1
+
+#ifdef SNMM 
+  #define E_MUX0_PIN           17
+  #define E_MUX1_PIN           16
+  #define E_MUX2_PIN           84
+#endif
+
+#ifdef DIS
+  #define D_REQUIRE            30
+  #define D_DATA               20
+  #define D_DATACLOCK          21
+#endif
+
+// The SDSS pin uses a different pin mapping from file Sd2PinMap.h
+#define SDSS                   53
+
+#ifndef SDSUPPORT
+// these pins are defined in the SD library if building with SD support
+  #define SCK_PIN              52
+  #define MISO_PIN             50
+  #define MOSI_PIN             51
+#endif
+
+#define BEEPER                 84
+
+#define BTN_EN1                72
+#define BTN_EN2                14
+#define BTN_ENC                 9
+
+#define SDCARDDETECT           15
+
+#define LCD_PINS_RS            82
+#define LCD_PINS_ENABLE        18
+#define LCD_PINS_D4            19
+#define LCD_PINS_D5            70
+#define LCD_PINS_D6            85
+#define LCD_PINS_D7            71
+
+#define E0_STEP_PIN            34
+#define E0_DIR_PIN             43
+#define E0_ENABLE_PIN          26
+#define E0_MS1_PIN             65
+#define E0_MS2_PIN             66
+#define LED_PIN                13
+
+#ifdef THREEMM_PRINTER
+  #define FAN_PIN               8
+#else
+  #define FAN_PIN               6
+#endif
+
+#define KILL_PIN               -1 //80 with Smart Controller LCD
+#define SUICIDE_PIN            -1  //PIN that has to be turned on right after start, to keep power flowing.
+#define SDPOWER                -1
+#define HEATER_2_PIN           -1
+
+#define HEATER_0_PIN            3
+#define HEATER_BED_PIN          4
+#define FAN_1_PIN              -1 //6
+#define PS_ON_PIN              71
+#define MOTOR_CURRENT_PWM_XY_PIN   46
+#define MOTOR_CURRENT_PWM_Z_PIN    45
+#define MOTOR_CURRENT_PWM_E_PIN    44

+ 447 - 221
Firmware/planner.cpp

@@ -74,9 +74,8 @@ unsigned long max_acceleration_units_per_sq_second[NUM_AXIS]; // Use M201 to ove
 float minimumfeedrate;
 float acceleration;         // Normal acceleration mm/s^2  THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
 float retract_acceleration; //  mm/s^2   filament pull-pack and push-forward  while standing still in the other axis M204 TXXXX
-float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.
-float max_z_jerk;
-float max_e_jerk;
+// Jerk is a maximum immediate velocity change.
+float max_jerk[NUM_AXIS];
 float mintravelfeedrate;
 unsigned long axis_steps_per_sqr_second[NUM_AXIS];
 
@@ -93,6 +92,7 @@ matrix_3x3 plan_bed_level_matrix = {
 long position[NUM_AXIS];   //rescaled from extern when axis_steps_per_unit are changed by gcode
 static float previous_speed[NUM_AXIS]; // Speed of previous path line segment
 static float previous_nominal_speed; // Nominal speed of previous path line segment
+static float previous_safe_speed; // Exit speed limited by a jerk to full halt of a previous last segment.
 
 #ifdef AUTOTEMP
 float autotemp_max=250;
@@ -110,6 +110,11 @@ block_t block_buffer[BLOCK_BUFFER_SIZE];            // A ring buffer for motion
 volatile unsigned char block_buffer_head;           // Index of the next block to be pushed
 volatile unsigned char block_buffer_tail;           // Index of the block to process now
 
+#ifdef PLANNER_DIAGNOSTICS
+// Diagnostic function: Minimum number of planned moves since the last 
+static uint8_t g_cntr_planner_queue_min = 0;
+#endif /* PLANNER_DIAGNOSTICS */
+
 //===========================================================================
 //=============================private variables ============================
 //===========================================================================
@@ -121,6 +126,12 @@ float extrude_min_temp=EXTRUDE_MINTEMP;
  static char meas_sample; //temporary variable to hold filament measurement sample
 #endif
 
+#ifdef LIN_ADVANCE
+    float extruder_advance_k = LIN_ADVANCE_K,
+    advance_ed_ratio = LIN_ADVANCE_E_D_RATIO,
+    position_float[NUM_AXIS] = { 0 };
+#endif
+
 // Returns the index of the next block in the ring buffer
 // NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication.
 static inline int8_t next_block_index(int8_t block_index) {
@@ -171,59 +182,92 @@ FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, f
   }
 }
 
-// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
+#define MINIMAL_STEP_RATE 120
 
-void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor) {
-  unsigned long initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min)
-  unsigned long final_rate = ceil(block->nominal_rate*exit_factor); // (step/min)
+// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
+void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) 
+{
+  // These two lines are the only floating point calculations performed in this routine.
+  uint32_t initial_rate = ceil(entry_speed * block->speed_factor); // (step/min)
+  uint32_t final_rate   = ceil(exit_speed  * block->speed_factor); // (step/min)
 
   // Limit minimal step rate (Otherwise the timer will overflow.)
-  if(initial_rate <120) {
-    initial_rate=120; 
-  }
-  if(final_rate < 120) {
-    final_rate=120;  
-  }
-
-  long acceleration = block->acceleration_st;
-  int32_t accelerate_steps =
-    ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration));
-  int32_t decelerate_steps =
-    floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration));
-
-  // Calculate the size of Plateau of Nominal Rate.
-  int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
+  if (initial_rate < MINIMAL_STEP_RATE)
+      initial_rate = MINIMAL_STEP_RATE;
+  if (initial_rate > block->nominal_rate)
+      initial_rate = block->nominal_rate;
+  if (final_rate < MINIMAL_STEP_RATE)
+      final_rate = MINIMAL_STEP_RATE;
+  if (final_rate > block->nominal_rate)
+      final_rate = block->nominal_rate;
+
+  uint32_t acceleration      = block->acceleration_st;
+  if (acceleration == 0)
+      // Don't allow zero acceleration.
+      acceleration = 1;
+  // estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
+  // (target_rate*target_rate-initial_rate*initial_rate)/(2.0*acceleration));
+  uint32_t initial_rate_sqr  = initial_rate*initial_rate;
+  //FIXME assert that this result fits a 64bit unsigned int.
+  uint32_t nominal_rate_sqr  = block->nominal_rate*block->nominal_rate;
+  uint32_t final_rate_sqr    = final_rate*final_rate;
+  uint32_t acceleration_x2   = acceleration << 1;
+  // ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration));
+  uint32_t accelerate_steps  = (nominal_rate_sqr - initial_rate_sqr + acceleration_x2 - 1) / acceleration_x2;
+  // floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration));
+  uint32_t decelerate_steps  = (nominal_rate_sqr - final_rate_sqr) / acceleration_x2;
+  uint32_t accel_decel_steps = accelerate_steps + decelerate_steps;
+  // Size of Plateau of Nominal Rate.
+  uint32_t plateau_steps     = 0;
 
   // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
   // have to use intersection_distance() to calculate when to abort acceleration and start braking
   // in order to reach the final_rate exactly at the end of this block.
-  if (plateau_steps < 0) {
-    accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count));
-    accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off
-    accelerate_steps = min((uint32_t)accelerate_steps,block->step_event_count);//(We can cast here to unsigned, because the above line ensures that we are above zero)
-    plateau_steps = 0;
+  if (accel_decel_steps < block->step_event_count) {
+    plateau_steps = block->step_event_count - accel_decel_steps;
+  } else {
+    uint32_t acceleration_x4  = acceleration << 2;
+    // Avoid negative numbers
+    if (final_rate_sqr >= initial_rate_sqr) {
+        // accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count));
+        // intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) 
+        // (2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4.0*acceleration);
+#if 0
+        accelerate_steps = (block->step_event_count >> 1) + (final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1 + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4;
+#else
+        accelerate_steps = final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1;
+        if (block->step_event_count & 1)
+            accelerate_steps += acceleration_x2;
+        accelerate_steps /= acceleration_x4;
+        accelerate_steps += (block->step_event_count >> 1);
+#endif
+        if (accelerate_steps > block->step_event_count)
+            accelerate_steps = block->step_event_count;
+    } else {
+#if 0
+        decelerate_steps = (block->step_event_count >> 1) + (initial_rate_sqr - final_rate_sqr + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4;
+#else
+        decelerate_steps = initial_rate_sqr - final_rate_sqr;
+        if (block->step_event_count & 1)
+            decelerate_steps += acceleration_x2;
+        decelerate_steps /= acceleration_x4;
+        decelerate_steps += (block->step_event_count >> 1);
+#endif
+        if (decelerate_steps > block->step_event_count)
+            decelerate_steps = block->step_event_count;
+        accelerate_steps = block->step_event_count - decelerate_steps;
+    }
   }
 
-#ifdef ADVANCE
-  volatile long initial_advance = block->advance*entry_factor*entry_factor; 
-  volatile long final_advance = block->advance*exit_factor*exit_factor;
-#endif // ADVANCE
-
-  // block->accelerate_until = accelerate_steps;
-  // block->decelerate_after = accelerate_steps+plateau_steps;
   CRITICAL_SECTION_START;  // Fill variables used by the stepper in a critical section
   if (! block->busy) { // Don't update variables if block is busy.
     block->accelerate_until = accelerate_steps;
     block->decelerate_after = accelerate_steps+plateau_steps;
     block->initial_rate = initial_rate;
     block->final_rate = final_rate;
-#ifdef ADVANCE
-    block->initial_advance = initial_advance;
-    block->final_advance = final_advance;
-#endif //ADVANCE
   }
   CRITICAL_SECTION_END;
-}                    
+}
 
 // Calculates the maximum allowable entry speed, when you must be able to reach target_velocity using the 
 // decceleration within the allotted distance.
@@ -249,6 +293,27 @@ FORCE_INLINE float max_allowable_entry_speed(float decceleration, float target_v
 // the set limit. Finally it will:
 //
 //   3. Recalculate trapezoids for all blocks.
+//
+//FIXME This routine is called 15x every time a new line is added to the planner,
+// therefore it is a bottle neck and it shall be rewritten into a Fixed Point arithmetics,
+// if the CPU is found lacking computational power.
+//
+// Following sources may be used to optimize the 8-bit AVR code:
+// http://www.mikrocontroller.net/articles/AVR_Arithmetik
+// http://darcy.rsgc.on.ca/ACES/ICE4M/FixedPoint/avrfix.pdf
+// 
+// https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/avr/lib1funcs-fixed.S
+// https://gcc.gnu.org/onlinedocs/gcc/Fixed-Point.html
+// https://gcc.gnu.org/onlinedocs/gccint/Fixed-point-fractional-library-routines.html
+// 
+// https://ucexperiment.wordpress.com/2015/04/04/arduino-s15-16-fixed-point-math-routines/
+// https://mekonik.wordpress.com/2009/03/18/arduino-avr-gcc-multiplication/
+// https://github.com/rekka/avrmultiplication
+// 
+// https://people.ece.cornell.edu/land/courses/ece4760/Math/Floating_point/
+// https://courses.cit.cornell.edu/ee476/Math/
+// https://courses.cit.cornell.edu/ee476/Math/GCC644/fixedPt/multASM.S
+//
 void planner_recalculate(const float &safe_final_speed) 
 {
     // Reverse pass
@@ -279,7 +344,7 @@ void planner_recalculate(const float &safe_final_speed)
                 tail = block_index;
                 // Update the number of blocks to process.
                 n_blocks = (block_buffer_head + BLOCK_BUFFER_SIZE - tail) & (BLOCK_BUFFER_SIZE - 1);
-                SERIAL_ECHOLNPGM("BLOCK_FLAG_START_FROM_FULL_HALT");
+                // SERIAL_ECHOLNPGM("START");
                 break;
             }
             // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
@@ -291,8 +356,12 @@ void planner_recalculate(const float &safe_final_speed)
                 // segment and the maximum acceleration allowed for this segment.
                 // If nominal length true, max junction speed is guaranteed to be reached even if decelerating to a jerk-from-zero velocity.
                 // Only compute for max allowable speed if block is decelerating and nominal length is false.
+                // entry_speed is uint16_t, 24 bits would be sufficient for block->acceleration and block->millimiteres, if scaled to um.
+                // therefore an optimized assembly 24bit x 24bit -> 32bit multiply would be more than sufficient
+                // together with an assembly 32bit->16bit sqrt function.
                 current->entry_speed = ((current->flag & BLOCK_FLAG_NOMINAL_LENGTH) || current->max_entry_speed <= next->entry_speed) ?
                     current->max_entry_speed :
+                    // min(current->max_entry_speed, sqrt(next->entry_speed*next->entry_speed+2*current->acceleration*current->millimeters));
                     min(current->max_entry_speed, max_allowable_entry_speed(-current->acceleration,next->entry_speed,current->millimeters));
                 current->flag |= BLOCK_FLAG_RECALCULATE;
             }
@@ -325,7 +394,7 @@ void planner_recalculate(const float &safe_final_speed)
             // Recalculate if current block entry or exit junction speed has changed.
             if ((prev->flag | current->flag) & BLOCK_FLAG_RECALCULATE) {
                 // NOTE: Entry and exit factors always > 0 by all previous logic operations.
-                calculate_trapezoid_for_block(prev, prev->entry_speed/prev->nominal_speed, current->entry_speed/prev->nominal_speed);
+                calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed);
                 // Reset current only to ensure next trapezoid is computed.
                 prev->flag &= ~BLOCK_FLAG_RECALCULATE;
             }
@@ -338,7 +407,7 @@ void planner_recalculate(const float &safe_final_speed)
 
     // Last/newest block in buffer. Exit speed is set with safe_final_speed. Always recalculated.
     current = block_buffer + prev_block_index(block_buffer_head);
-    calculate_trapezoid_for_block(current, current->entry_speed/current->nominal_speed, safe_final_speed/current->nominal_speed);
+    calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed);
     current->flag &= ~BLOCK_FLAG_RECALCULATE;
 
 //    SERIAL_ECHOLNPGM("planner_recalculate - 4");
@@ -348,6 +417,9 @@ void plan_init() {
   block_buffer_head = 0;
   block_buffer_tail = 0;
   memset(position, 0, sizeof(position)); // clear position
+#ifdef LIN_ADVANCE
+  memset(position_float, 0, sizeof(position)); // clear position
+#endif
   previous_speed[0] = 0.0;
   previous_speed[1] = 0.0;
   previous_speed[2] = 0.0;
@@ -459,6 +531,96 @@ void check_axes_activity()
 #endif
 }
 
+bool waiting_inside_plan_buffer_line_print_aborted = false;
+/*
+void planner_abort_soft()
+{
+    // Empty the queue.
+    while (blocks_queued()) plan_discard_current_block();
+    // Relay to planner wait routine, that the current line shall be canceled.
+    waiting_inside_plan_buffer_line_print_aborted = true;
+    //current_position[i]
+}
+*/
+
+#ifdef PLANNER_DIAGNOSTICS
+static inline void planner_update_queue_min_counter()
+{
+  uint8_t new_counter = moves_planned();
+  if (new_counter < g_cntr_planner_queue_min)
+    g_cntr_planner_queue_min = new_counter;
+}
+#endif /* PLANNER_DIAGNOSTICS */
+
+extern volatile uint32_t step_events_completed; // The number of step events executed in the current block
+
+void planner_abort_hard()
+{
+    // Abort the stepper routine and flush the planner queue.
+    // DISABLE_STEPPER_DRIVER_INTERRUPT
+    TIMSK1 &= ~(1<<OCIE1A);
+
+    // Now the front-end (the Marlin_main.cpp with its current_position) is out of sync.
+    // First update the planner's current position in the physical motor steps.
+    position[X_AXIS] = st_get_position(X_AXIS);
+    position[Y_AXIS] = st_get_position(Y_AXIS);
+    position[Z_AXIS] = st_get_position(Z_AXIS);
+    position[E_AXIS] = st_get_position(E_AXIS);
+
+    // Second update the current position of the front end.
+    current_position[X_AXIS] = st_get_position_mm(X_AXIS);
+    current_position[Y_AXIS] = st_get_position_mm(Y_AXIS);
+    current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
+    current_position[E_AXIS] = st_get_position_mm(E_AXIS);
+    // Apply the mesh bed leveling correction to the Z axis.
+#ifdef MESH_BED_LEVELING
+    if (mbl.active) {
+#if 1
+        // Undo the bed level correction so the current Z position is reversible wrt. the machine coordinates.
+        // This does not necessary mean that the Z position will be the same as linearly interpolated from the source G-code line.
+        current_position[Z_AXIS] -= mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS]);
+#else
+        // Undo the bed level correction so that the current Z position is the same as linearly interpolated from the source G-code line.
+        if (current_block == NULL || (current_block->steps_x == 0 && current_block->steps_y == 0))
+            current_position[Z_AXIS] -= mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS]);
+        else {
+            float t = float(step_events_completed) / float(current_block->step_event_count);
+            float vec[3] = { 
+              current_block->steps_x / axis_steps_per_unit[X_AXIS],
+              current_block->steps_y / axis_steps_per_unit[Y_AXIS],
+              current_block->steps_z / axis_steps_per_unit[Z_AXIS]
+            };
+            float pos1[3], pos2[3];
+            for (int8_t i = 0; i < 3; ++ i) {
+              if (current_block->direction_bits & (1<<i))
+                vec[i] = - vec[i];
+              pos1[i] = current_position[i] - vec[i] * t;
+              pos2[i] = current_position[i] + vec[i] * (1.f - t);
+            }
+            pos1[Z_AXIS] -= mbl.get_z(pos1[X_AXIS], pos1[Y_AXIS]);
+            pos2[Z_AXIS] -= mbl.get_z(pos2[X_AXIS], pos2[Y_AXIS]);
+            current_position[Z_AXIS] = pos1[Z_AXIS] * t + pos2[Z_AXIS] * (1.f - t);
+        }
+#endif
+    }
+#endif
+    // Clear the planner queue.
+    quickStop();
+
+    // Apply inverse world correction matrix.
+    machine2world(current_position[X_AXIS], current_position[Y_AXIS]);
+    memcpy(destination, current_position, sizeof(destination));
+
+    // Resets planner junction speeds. Assumes start from rest.
+    previous_nominal_speed = 0.0;
+    previous_speed[0] = 0.0;
+    previous_speed[1] = 0.0;
+    previous_speed[2] = 0.0;
+    previous_speed[3] = 0.0;
+
+    // Relay to planner wait routine, that the current line shall be canceled.
+    waiting_inside_plan_buffer_line_print_aborted = true;
+}
 
 float junction_deviation = 0.1;
 // Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in 
@@ -471,13 +633,26 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
 
   // If the buffer is full: good! That means we are well ahead of the robot. 
   // Rest here until there is room in the buffer.
-  while(block_buffer_tail == next_buffer_head)
-  {
-    manage_heater(); 
-    // Vojtech: Don't disable motors inside the planner!
-    manage_inactivity(false); 
-    lcd_update();
+  if (block_buffer_tail == next_buffer_head) {
+      waiting_inside_plan_buffer_line_print_aborted = false;
+      do {
+          manage_heater(); 
+          // Vojtech: Don't disable motors inside the planner!
+          manage_inactivity(false); 
+          lcd_update();
+      } while (block_buffer_tail == next_buffer_head);
+      if (waiting_inside_plan_buffer_line_print_aborted) {
+          // Inside the lcd_update() routine the print has been aborted.
+          // Cancel the print, do not plan the current line this routine is waiting on.
+#ifdef PLANNER_DIAGNOSTICS
+          planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTICS */
+          return;
+      }
   }
+#ifdef PLANNER_DIAGNOSTICS
+  planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTICS */
 
 #ifdef ENABLE_AUTO_BED_LEVELING
   apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
@@ -543,12 +718,22 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
     target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
 #endif // ENABLE_MESH_BED_LEVELING
   target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
+  
+#ifdef LIN_ADVANCE
+    const float mm_D_float = sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS]));
+    float de_float = e - position_float[E_AXIS];
+#endif
+    
   #ifdef PREVENT_DANGEROUS_EXTRUDE
   if(target[E_AXIS]!=position[E_AXIS])
   {
     if(degHotend(active_extruder)<extrude_min_temp)
     {
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
+#ifdef LIN_ADVANCE
+      position_float[E_AXIS] = e;
+      de_float = 0;
+#endif
       SERIAL_ECHO_START;
       SERIAL_ECHOLNRPGM(MSG_ERR_COLD_EXTRUDE_STOP);
     }
@@ -557,6 +742,10 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
     if(labs(target[E_AXIS]-position[E_AXIS])>axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
     {
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
+#ifdef LIN_ADVANCE
+        position_float[E_AXIS] = e;
+        de_float = 0;
+#endif
       SERIAL_ECHO_START;
       SERIAL_ECHOLNRPGM(MSG_ERR_LONG_EXTRUDE_STOP);
     }
@@ -567,6 +756,9 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
   // Prepare to set up new block
   block_t *block = &block_buffer[block_buffer_head];
 
+  // Set sdlen for calculating sd position
+  block->sdlen = 0;
+
   // Mark block as not busy (Not executed by the stepper interrupt, could be still tinkered with.)
   block->busy = false;
 
@@ -583,14 +775,20 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi
 #endif
   block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
   block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
-  block->steps_e *= volumetric_multiplier[active_extruder];
-  block->steps_e *= extrudemultiply;
-  block->steps_e /= 100;
+  if (volumetric_multiplier[active_extruder] != 1.f)
+    block->steps_e *= volumetric_multiplier[active_extruder];
+  if (extrudemultiply != 100) {
+    block->steps_e *= extrudemultiply;
+    block->steps_e /= 100;
+  }
   block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e)));
 
   // Bail if this is a zero-length block
   if (block->step_event_count <= dropsegments)
   { 
+#ifdef PLANNER_DIAGNOSTICS
+    planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTICS */
     return; 
   }
 
@@ -815,6 +1013,8 @@ Having the real displacement of the head, we can calculate the total movement le
   }
 
   // Compute and limit the acceleration rate for the trapezoid generator.  
+  // block->step_event_count ... event count of the fastest axis
+  // block->millimeters ... Euclidian length of the XYZ movement or the E length, if no XYZ movement.
   float steps_per_mm = block->step_event_count/block->millimeters;
   if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)
   {
@@ -834,88 +1034,62 @@ Having the real displacement of the head, we can calculate the total movement le
     if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS])
       block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS];
   }
+  // Acceleration of the segment, in mm/sec^2
   block->acceleration = block->acceleration_st / steps_per_mm;
-  block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
 
-#if 0  // Use old jerk for now
-  // Compute path unit vector
-  double unit_vec[3];
-
-  unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
-  unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
-  unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
-
-  // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
-  // Let a circle be tangent to both previous and current path line segments, where the junction
-  // deviation is defined as the distance from the junction to the closest edge of the circle,
-  // colinear with the circle center. The circular segment joining the two paths represents the
-  // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
-  // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
-  // path width or max_jerk in the previous grbl version. This approach does not actually deviate
-  // from path, but used as a robust way to compute cornering speeds, as it takes into account the
-  // nonlinearities of both the junction angle and junction velocity.
-  double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
-
-  // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
-  if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
-    // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
-    // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
-    double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
-      - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
-      - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
-
-    // Skip and use default max junction speed for 0 degree acute junction.
-    if (cos_theta < 0.95) {
-      vmax_junction = min(previous_nominal_speed,block->nominal_speed);
-      // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
-      if (cos_theta > -0.95) {
-        // Compute maximum junction velocity based on maximum acceleration and junction deviation
-        double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
-        vmax_junction = min(vmax_junction,
-        sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
-      }
-    }
+#if 0
+  // Oversample diagonal movements by a power of 2 up to 8x
+  // to achieve more accurate diagonal movements.
+  uint8_t bresenham_oversample = 1;
+  for (uint8_t i = 0; i < 3; ++ i) {
+    if (block->nominal_rate >= 5000) // 5kHz
+      break;
+    block->nominal_rate << 1;
+    bresenham_oversample << 1;
+    block->step_event_count << 1;
   }
+  if (bresenham_oversample > 1)
+    // Lower the acceleration steps/sec^2 to account for the oversampling.
+    block->acceleration_st = (block->acceleration_st + (bresenham_oversample >> 1)) / bresenham_oversample;
 #endif
+
+  block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
+
   // Start with a safe speed.
-  //Vojtech: This code tries to limit the initial jerk to half of the maximum jerk value.
-  //The code is not quite correct. It is pessimistic as it shall limit a projection of the jerk into each axis,
-  //but when the current code clamps, it clamps as if the movement is done in a single axis only.
-  float vmax_junction = max_xy_jerk/2.f;
-  if(fabs(current_speed[Z_AXIS]) > max_z_jerk/2.f)
-    vmax_junction = min(vmax_junction, max_z_jerk/2.f);
-  if(fabs(current_speed[E_AXIS]) > max_e_jerk/2.f)
-    vmax_junction = min(vmax_junction, max_e_jerk/2.f);
-  vmax_junction = min(vmax_junction, block->nominal_speed);
   // Safe speed is the speed, from which the machine may halt to stop immediately.
-  float safe_speed = vmax_junction;
+  float safe_speed = block->nominal_speed;
+  bool  limited = false;
+  for (uint8_t axis = 0; axis < 4; ++ axis) {
+      float jerk = fabs(current_speed[axis]);
+      if (jerk > max_jerk[axis]) {
+          // The actual jerk is lower, if it has been limited by the XY jerk.
+          if (limited) {
+              // Spare one division by a following gymnastics:
+              // Instead of jerk *= safe_speed / block->nominal_speed,
+              // multiply max_jerk[axis] by the divisor.
+              jerk *= safe_speed;
+              float mjerk = max_jerk[axis] * block->nominal_speed;
+              if (jerk > mjerk) {
+                  safe_speed *= mjerk / jerk;
+                  limited = true;
+              }
+          } else {
+              safe_speed = max_jerk[axis];
+              limited = true;
+          }
+      }
+  }
+
+  // Reset the block flag.
+  block->flag = 0;
+
+  // Initial limit on the segment entry velocity.
+  float vmax_junction;
 
   //FIXME Vojtech: Why only if at least two lines are planned in the queue?
   // Is it because we don't want to tinker with the first buffer line, which
   // is likely to be executed by the stepper interrupt routine soon?
   if (moves_queued > 1 && previous_nominal_speed > 0.0001f) {
-#if 1
-      float jerk;
-      {
-          float dx = current_speed[X_AXIS]-previous_speed[X_AXIS];
-          float dy = current_speed[Y_AXIS]-previous_speed[Y_AXIS];
-          jerk = sqrt(dx*dx+dy*dy);
-      }
-      float vmax_junction_factor = 1.0; 
-      //    if((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
-      vmax_junction = block->nominal_speed;
-      //    }
-      if (jerk > max_xy_jerk)
-          vmax_junction_factor = max_xy_jerk/jerk;
-      jerk = fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]);
-      if (jerk > max_z_jerk)
-          vmax_junction_factor = min(vmax_junction_factor, max_z_jerk/jerk);
-      jerk = fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]);
-      if (jerk > max_e_jerk)
-          vmax_junction_factor = min(vmax_junction_factor, max_e_jerk/jerk);
-      //FIXME Vojtech: Why is this asymmetric in regard to the previous nominal speed and the current nominal speed?
-      vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
-#else
       // Estimate a maximum velocity allowed at a joint of two successive segments.
       // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities,
       // then the machine is not coasting anymore and the safe entry / exit velocities shall be used.
@@ -926,72 +1100,54 @@ Having the real displacement of the head, we can calculate the total movement le
       // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
       vmax_junction = prev_speed_larger ? block->nominal_speed : previous_nominal_speed;
       // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities.
-      float v_factor_exit  = prev_speed_larger ? smaller_speed_factor : 1.f;
-      float v_factor_entry = prev_speed_larger ? 1.f : smaller_speed_factor;
-      // First limit the jerk in the XY plane.
-      float jerk;
-      {
-          // Estimate the jerk as if the entry / exit velocity of the two successive segment was limited to the minimum of their nominal velocities.
-          // If coasting, then the segment transition velocity will define the exit / entry velocities of the successive segments
-          // and the jerk defined by the following formula will be always lower.
-          float dx = prev_speed_larger ? (current_speed[X_AXIS] - smaller_speed_factor * previous_speed[X_AXIS]) : (smaller_speed_factor * current_speed[X_AXIS] - previous_speed[X_AXIS]);
-          float dy = prev_speed_larger ? (current_speed[Y_AXIS] - smaller_speed_factor * previous_speed[Y_AXIS]) : (smaller_speed_factor * current_speed[Y_AXIS] - previous_speed[Y_AXIS]);
-          jerk = sqrt(dx*dx+dy*dy);
-      }
-      if (jerk > max_xy_jerk) {
-          // Limit the entry / exit velocities to respect the XY jerk limits.
-          v_factor_exit = v_factor_entry = max_xy_jerk / jerk;
+      float v_factor = 1.f;
+      limited = false;
+      // Now limit the jerk in all axes.
+      for (uint8_t axis = 0; axis < 4; ++ axis) {
+          // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop.
+          float v_exit  = previous_speed[axis];
+          float v_entry = current_speed [axis];
           if (prev_speed_larger)
-              v_factor_exit *= smaller_speed_factor;
-          else
-              v_factor_entry *= smaller_speed_factor;
-      }
-      // Now limit the Z and E axes. We have to differentiate coasting from the reversal of an axis movement, or a full stop.
-      float v_exit  = previous_speed[Z_AXIS] * v_factor_exit;
-      float v_entry = current_speed [Z_AXIS] * v_factor_entry;
-      jerk = (v_exit > v_entry) ?
-          ((v_entry > 0.f || v_exit < 0.f) ?
-              // coasting
-              (v_exit - v_entry) : 
-              // axis reversal
-              max(v_exit, - v_entry)) :
-          // v_exit <= v_entry
-          ((v_entry < 0.f || v_exit > 0.f) ?
-              // coasting
-              (v_entry - v_exit) :
-              // axis reversal
-              max(- v_exit, v_entry));
-      if (jerk > max_z_jerk / 2.f) {
-          float c = (max_z_jerk / 2.f) / jerk;
-          v_factor_exit *= c;
-          v_factor_entry *= c;
+              v_exit *= smaller_speed_factor;
+          if (limited) {
+              v_exit  *= v_factor;
+              v_entry *= v_factor;
+          }
+          // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction.
+          float jerk = 
+              (v_exit > v_entry) ?
+                  ((v_entry > 0.f || v_exit < 0.f) ?
+                      // coasting
+                      (v_exit - v_entry) : 
+                      // axis reversal
+                      max(v_exit, - v_entry)) :
+                  // v_exit <= v_entry
+                  ((v_entry < 0.f || v_exit > 0.f) ?
+                      // coasting
+                      (v_entry - v_exit) :
+                      // axis reversal
+                      max(- v_exit, v_entry));
+          if (jerk > max_jerk[axis]) {
+              v_factor *= max_jerk[axis] / jerk;
+              limited = true;
+          }
       }
-      // Limit the E axis.
-      v_exit  = previous_speed[E_AXIS] * v_factor_exit;
-      v_entry = current_speed [E_AXIS] * v_factor_entry;
-      jerk = (v_exit > v_entry) ?
-          ((v_entry > 0.f || v_exit < 0.f) ?
-              // coasting
-              (v_exit - v_entry) : 
-              // axis reversal
-              max(v_exit, - v_entry)) :
-          // v_exit <= v_entry
-          ((v_entry < 0.f || v_exit > 0.f) ?
-              // coasting
-              (v_entry - v_exit) :
-              // axis reversal
-              max(- v_exit, v_entry));
-      if (jerk > max_e_jerk / 2.f) {
-          float c = (max_e_jerk / 2.f) / jerk;
-          v_factor_exit *= c;
-          v_factor_entry *= c;
+      if (limited)
+          vmax_junction *= v_factor;
+      // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
+      // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
+      float vmax_junction_threshold = vmax_junction * 0.99f;
+      if (previous_safe_speed > vmax_junction_threshold && safe_speed > vmax_junction_threshold) {
+          // Not coasting. The machine will stop and start the movements anyway,
+          // better to start the segment from start.
+          block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT;
+          vmax_junction = safe_speed;
       }
-
-      // Now the transition velocity is known as nominal * v_factor. Compare the transition velocity against the "safe" velocoties.
-      // If the transition velocity is below the exit / enter safe velocity, the machine is no more cruising, therefore
-      // the safe velocities shall be used.
-#endif
+  } else {
+      block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT;
+      vmax_junction = safe_speed;
   }
+
   // Max entry speed of this block equals the max exit speed of the previous block.
   block->max_entry_speed = vmax_junction;
 
@@ -1008,41 +1164,47 @@ Having the real displacement of the head, we can calculate the total movement le
   // the reverse and forward planners, the corresponding block junction speed will always be at the
   // the maximum junction speed and may always be ignored for any speed reduction checks.
   // Always calculate trapezoid for new block
-  block->flag = (block->nominal_speed <= v_allowable) ? (BLOCK_FLAG_NOMINAL_LENGTH | BLOCK_FLAG_RECALCULATE) : BLOCK_FLAG_RECALCULATE;
+  block->flag |= (block->nominal_speed <= v_allowable) ? (BLOCK_FLAG_NOMINAL_LENGTH | BLOCK_FLAG_RECALCULATE) : BLOCK_FLAG_RECALCULATE;
 
   // Update previous path unit_vector and nominal speed
   memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]
   previous_nominal_speed = block->nominal_speed;
-
-
-#ifdef ADVANCE
-  // Calculate advance rate
-  if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) {
-    block->advance_rate = 0;
-    block->advance = 0;
-  }
-  else {
-    long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
-    float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * 
-      (current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUSION_AREA * EXTRUSION_AREA)*256;
-    block->advance = advance;
-    if(acc_dist == 0) {
-      block->advance_rate = 0;
-    } 
-    else {
-      block->advance_rate = advance / (float)acc_dist;
-    }
-  }
-  /*
-    SERIAL_ECHO_START;
-   SERIAL_ECHOPGM("advance :");
-   SERIAL_ECHO(block->advance/256.0);
-   SERIAL_ECHOPGM("advance rate :");
-   SERIAL_ECHOLN(block->advance_rate/256.0);
-   */
-#endif // ADVANCE
-
-  calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed, safe_speed/block->nominal_speed);
+  previous_safe_speed = safe_speed;
+
+#ifdef LIN_ADVANCE
+
+    //
+    // Use LIN_ADVANCE for blocks if all these are true:
+    //
+    // esteps                                          : We have E steps todo (a printing move)
+    //
+    // block->steps[X_AXIS] || block->steps[Y_AXIS]    : We have a movement in XY direction (i.e., not retract / prime).
+    //
+    // extruder_advance_k                              : There is an advance factor set.
+    //
+    // block->steps[E_AXIS] != block->step_event_count : A problem occurs if the move before a retract is too small.
+    //                                                   In that case, the retract and move will be executed together.
+    //                                                   This leads to too many advance steps due to a huge e_acceleration.
+    //                                                   The math is good, but we must avoid retract moves with advance!
+    // de_float > 0.0                                  : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
+    //
+    block->use_advance_lead =  block->steps_e
+                           && (block->steps_x || block->steps_y)
+                           && extruder_advance_k
+                           && (uint32_t)block->steps_e != block->step_event_count
+                           && de_float > 0.0;
+    if (block->use_advance_lead)
+        block->abs_adv_steps_multiplier8 = lround(
+                          extruder_advance_k
+                          * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set
+                          * (block->nominal_speed / (float)block->nominal_rate)
+                          * axis_steps_per_unit[E_AXIS] * 256.0
+                          );
+#endif
+    
+  // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated.
+  block->speed_factor = block->nominal_rate / block->nominal_speed;
+  calculate_trapezoid_for_block(block, block->entry_speed, safe_speed);
 
   // Move the buffer head. From now the block may be picked up by the stepper interrupt controller.
   block_buffer_head = next_buffer_head;
@@ -1050,12 +1212,26 @@ Having the real displacement of the head, we can calculate the total movement le
   // Update position
   memcpy(position, target, sizeof(target)); // position[] = target[]
 
+#ifdef LIN_ADVANCE
+  position_float[X_AXIS] = x;
+  position_float[Y_AXIS] = y;
+  position_float[Z_AXIS] = z;
+  position_float[E_AXIS] = e;
+#endif
+    
   // Recalculate the trapezoids to maximize speed at the segment transitions while respecting
   // the machine limits (maximum acceleration and maximum jerk).
   // This runs asynchronously with the stepper interrupt controller, which may
   // interfere with the process.
   planner_recalculate(safe_speed);
 
+//  SERIAL_ECHOPGM("Q");
+//  SERIAL_ECHO(int(moves_planned()));
+//  SERIAL_ECHOLNPGM("");
+
+#ifdef PLANNER_DIAGNOSTICS
+  planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTIC */
   st_wake_up();
 }
 
@@ -1081,6 +1257,7 @@ void plan_set_position(float x, float y, float z, const float &e)
 #endif // ENABLE_AUTO_BED_LEVELING
 
     // Apply the machine correction matrix.
+    if (world2machine_correction_mode != WORLD2MACHINE_CORRECTION_NONE)
     {
         float tmpx = x;
         float tmpy = y;
@@ -1091,15 +1268,19 @@ void plan_set_position(float x, float y, float z, const float &e)
   position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
   position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
 #ifdef MESH_BED_LEVELING
-    if (mbl.active){
-      position[Z_AXIS] = lround((z+mbl.get_z(x, y))*axis_steps_per_unit[Z_AXIS]);
-    }else{
-        position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
-    }
+  position[Z_AXIS] = mbl.active ? 
+    lround((z+mbl.get_z(x, y))*axis_steps_per_unit[Z_AXIS]) :
+    lround(z*axis_steps_per_unit[Z_AXIS]);
 #else
   position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
 #endif // ENABLE_MESH_BED_LEVELING
-  position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);  
+  position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
+#ifdef LIN_ADVANCE
+  position_float[X_AXIS] = x;
+  position_float[Y_AXIS] = y;
+  position_float[Z_AXIS] = z;
+  position_float[E_AXIS] = e;
+#endif
   st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
   previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
   previous_speed[0] = 0.0;
@@ -1111,12 +1292,18 @@ void plan_set_position(float x, float y, float z, const float &e)
 // Only useful in the bed leveling routine, when the mesh bed leveling is off.
 void plan_set_z_position(const float &z)
 {
+	#ifdef LIN_ADVANCE
+	position_float[Z_AXIS] = z;
+	#endif
     position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
     st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
 }
 
 void plan_set_e_position(const float &e)
 {
+  #ifdef LIN_ADVANCE
+  position_float[E_AXIS] = e;
+  #endif
   position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);  
   st_set_e_position(position[E_AXIS]);
 }
@@ -1136,3 +1323,42 @@ void reset_acceleration_rates()
         axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
         }
 }
+unsigned char number_of_blocks() {
+	return (block_buffer_head + BLOCK_BUFFER_SIZE - block_buffer_tail) & (BLOCK_BUFFER_SIZE - 1);
+}
+#ifdef PLANNER_DIAGNOSTICS
+uint8_t planner_queue_min()
+{
+  return g_cntr_planner_queue_min;
+}
+
+void planner_queue_min_reset()
+{
+  g_cntr_planner_queue_min = moves_planned();
+}
+#endif /* PLANNER_DIAGNOSTICS */
+
+void planner_add_sd_length(uint16_t sdlen)
+{
+  if (block_buffer_head != block_buffer_tail) {
+    // The planner buffer is not empty. Get the index of the last buffer line entered,
+    // which is (block_buffer_head - 1) modulo BLOCK_BUFFER_SIZE.
+    block_buffer[prev_block_index(block_buffer_head)].sdlen += sdlen;
+  } else {
+    // There is no line stored in the planner buffer, which means the last command does not need to be revertible,
+    // at a power panic, so the length of this command may be forgotten.
+  }
+}
+
+uint16_t planner_calc_sd_length()
+{
+	unsigned char _block_buffer_head = block_buffer_head;
+	unsigned char _block_buffer_tail = block_buffer_tail;
+	uint16_t sdlen = 0;
+	while (_block_buffer_head != _block_buffer_tail)
+	{
+		sdlen += block_buffer[_block_buffer_tail].sdlen;
+	    _block_buffer_tail = (_block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1);  
+	}
+	return sdlen;
+}

+ 58 - 16
Firmware/planner.h

@@ -37,12 +37,9 @@ enum BlockFlag {
     // Planner flag for nominal speed always reached. That means, the segment is long enough, that the nominal speed
     // may be reached if accelerating from a safe speed (in the regard of jerking from zero speed).
     BLOCK_FLAG_NOMINAL_LENGTH = 2,
-    // If set, the machine will stop to a full halt at the end of this block,
-    // respecting the maximum allowed jerk.
-    BLOCK_FLAG_FULL_HALT_AT_END = 4,
     // If set, the machine will start from a halt at the start of this block,
     // respecting the maximum allowed jerk.
-    BLOCK_FLAG_START_FROM_FULL_HALT = 8,
+    BLOCK_FLAG_START_FROM_FULL_HALT = 4,
 };
 
 // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in 
@@ -58,12 +55,6 @@ typedef struct {
   // accelerate_until and decelerate_after are set by calculate_trapezoid_for_block() and they need to be synchronized with the stepper interrupt controller.
   long accelerate_until;                    // The index of the step event on which to stop acceleration
   long decelerate_after;                    // The index of the step event on which to start decelerating
-  #ifdef ADVANCE
-    long advance_rate;
-    volatile long initial_advance;
-    volatile long final_advance;
-    float advance;
-  #endif
 
   // Fields used by the motion planner to manage acceleration
 //  float speed_x, speed_y, speed_z, speed_e;        // Nominal mm/sec for each axis
@@ -85,14 +76,31 @@ typedef struct {
 
   // Settings for the trapezoid generator (runs inside an interrupt handler).
   // Changing the following values in the planner needs to be synchronized with the interrupt handler by disabling the interrupts.
+  //FIXME nominal_rate, initial_rate and final_rate are limited to uint16_t by MultiU24X24toH16 in the stepper interrupt anyway!
   unsigned long nominal_rate;                        // The nominal step rate for this block in step_events/sec 
   unsigned long initial_rate;                        // The jerk-adjusted step rate at start of block  
   unsigned long final_rate;                          // The minimal rate at exit
   unsigned long acceleration_st;                     // acceleration steps/sec^2
+  //FIXME does it have to be unsigned long? Probably uint8_t would be just fine.
   unsigned long fan_speed;
   volatile char busy;
+
+
+  // Pre-calculated division for the calculate_trapezoid_for_block() routine to run faster.
+  float speed_factor;
+    
+#ifdef LIN_ADVANCE
+  bool use_advance_lead;
+  unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float
+#endif
+
+  uint16_t sdlen;
 } block_t;
 
+#ifdef LIN_ADVANCE
+  extern float extruder_advance_k, advance_ed_ratio;
+#endif
+
 #ifdef ENABLE_AUTO_BED_LEVELING
 // this holds the required transform to compensate for bed level
 extern matrix_3x3 plan_bed_level_matrix;
@@ -135,9 +143,8 @@ extern unsigned long max_acceleration_units_per_sq_second[NUM_AXIS]; // Use M201
 extern float minimumfeedrate;
 extern float acceleration;         // Normal acceleration mm/s^2  THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
 extern float retract_acceleration; //  mm/s^2   filament pull-pack and push-forward  while standing still in the other axis M204 TXXXX
-extern float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.
-extern float max_z_jerk;
-extern float max_e_jerk;
+// Jerk is a maximum immediate velocity change.
+extern float max_jerk[NUM_AXIS];
 extern float mintravelfeedrate;
 extern unsigned long axis_steps_per_sqr_second[NUM_AXIS];
 
@@ -152,7 +159,11 @@ extern unsigned long axis_steps_per_sqr_second[NUM_AXIS];
 
 
 extern block_t block_buffer[BLOCK_BUFFER_SIZE];            // A ring buffer for motion instfructions
-extern volatile unsigned char block_buffer_head;           // Index of the next block to be pushed
+// Index of the next block to be pushed into the planner queue.
+extern volatile unsigned char block_buffer_head;
+// Index of the first block in the planner queue.
+// This is the block, which is being currently processed by the stepper routine, 
+// or which is first to be processed by the stepper routine.
 extern volatile unsigned char block_buffer_tail; 
 // Called when the current block is no longer needed. Discards the block and makes the memory
 // available for new blocks.    
@@ -163,7 +174,10 @@ FORCE_INLINE void plan_discard_current_block()
   }
 }
 
-// Gets the current block. Returns NULL if buffer empty
+// Gets the current block. This is the block to be exectuted by the stepper routine.
+// Mark this block as busy, so its velocities and acceperations will be no more recalculated
+// by the planner routine.
+// Returns NULL if buffer empty
 FORCE_INLINE block_t *plan_get_current_block() 
 {
   if (block_buffer_head == block_buffer_tail) { 
@@ -175,16 +189,44 @@ FORCE_INLINE block_t *plan_get_current_block()
 }
 
 // Returns true if the buffer has a queued block, false otherwise
-FORCE_INLINE bool blocks_queued() { return (block_buffer_head != block_buffer_tail); }
+FORCE_INLINE bool blocks_queued() { 
+	return (block_buffer_head != block_buffer_tail); 
+}
 
 //return the nr of buffered moves
 FORCE_INLINE uint8_t moves_planned() {
     return (block_buffer_head + BLOCK_BUFFER_SIZE - block_buffer_tail) & (BLOCK_BUFFER_SIZE - 1);
 }
 
+FORCE_INLINE bool planner_queue_full() {
+    unsigned char next_block_index = block_buffer_head;
+    if (++ next_block_index == BLOCK_BUFFER_SIZE)
+        next_block_index = 0; 
+    return block_buffer_tail == next_block_index;
+}
+
+// Abort the stepper routine, clean up the block queue,
+// wait for the steppers to stop,
+// update planner's current position and the current_position of the front end.
+extern void planner_abort_hard();
+
 #ifdef PREVENT_DANGEROUS_EXTRUDE
 void set_extrude_min_temp(float temp);
 #endif
 
 void reset_acceleration_rates();
 #endif
+
+unsigned char number_of_blocks();
+
+// #define PLANNER_DIAGNOSTICS
+#ifdef PLANNER_DIAGNOSTICS
+// Diagnostic functions to display planner buffer underflow on the display.
+extern uint8_t planner_queue_min();
+// Diagnostic function: Reset the minimum planner segments.
+extern void planner_queue_min_reset();
+#endif /* PLANNER_DIAGNOSTICS */
+
+extern void planner_add_sd_length(uint16_t sdlen);
+
+extern uint16_t planner_calc_sd_length();

+ 403 - 186
Firmware/stepper.cpp

@@ -32,14 +32,25 @@
 #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
 #include <SPI.h>
 #endif
+#ifdef TMC2130
+#include "tmc2130.h"
+#endif //TMC2130
 
+#ifdef PAT9125
+#include "fsensor.h"
+int fsensor_counter = 0; //counter for e-steps
+#endif //PAT9125
 
 //===========================================================================
 //=============================public variables  ============================
 //===========================================================================
 block_t *current_block;  // A pointer to the block currently being traced
-
-
+bool x_min_endstop = false;
+bool x_max_endstop = false;
+bool y_min_endstop = false;
+bool y_max_endstop = false;
+bool z_min_endstop = false;
+bool z_max_endstop = false;
 //===========================================================================
 //=============================private variables ============================
 //===========================================================================
@@ -47,22 +58,17 @@ block_t *current_block;  // A pointer to the block currently being traced
 
 // Variables used by The Stepper Driver Interrupt
 static unsigned char out_bits;        // The next stepping-bits to be output
-static long counter_x,       // Counter variables for the bresenham line tracer
-            counter_y,
-            counter_z,
-            counter_e;
-volatile static unsigned long step_events_completed; // The number of step events executed in the current block
-#ifdef ADVANCE
-  static long advance_rate, advance, final_advance = 0;
-  static long old_advance = 0;
-  static long e_steps[3];
-#endif
-static long acceleration_time, deceleration_time;
+static int32_t counter_x,       // Counter variables for the bresenham line tracer
+               counter_y,
+               counter_z,
+               counter_e;
+volatile uint32_t step_events_completed; // The number of step events executed in the current block
+static int32_t  acceleration_time, deceleration_time;
 //static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
-static unsigned short acc_step_rate; // needed for deccelaration start point
-static char step_loops;
-static unsigned short OCR1A_nominal;
-static unsigned short step_loops_nominal;
+static uint16_t acc_step_rate; // needed for deccelaration start point
+static uint8_t  step_loops;
+static uint16_t OCR1A_nominal;
+static uint8_t  step_loops_nominal;
 
 volatile long endstops_trigsteps[3]={0,0,0};
 volatile long endstops_stepsTotal,endstops_stepsDone;
@@ -86,19 +92,44 @@ static bool old_z_min_endstop=false;
 static bool old_z_max_endstop=false;
 
 static bool check_endstops = true;
+
 static bool check_z_endstop = false;
 
-int8_t SilentMode;
+int8_t SilentMode = 0;
 
 volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0};
 volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
 
+uint8_t LastStepMask = 0;
+
+#ifdef LIN_ADVANCE
+
+  uint16_t ADV_NEVER = 65535;
+
+  static uint16_t nextMainISR = 0;
+  static uint16_t nextAdvanceISR = ADV_NEVER;
+  static uint16_t eISR_Rate = ADV_NEVER;
+
+  static volatile int e_steps; //Extrusion steps to be executed by the stepper
+  static int final_estep_rate; //Speed of extruder at cruising speed
+  static int current_estep_rate; //The current speed of the extruder
+  static int current_adv_steps; //The current pretension of filament expressed in steps
+
+  #define ADV_RATE(T, L) (e_steps ? (T) * (L) / abs(e_steps) : ADV_NEVER)
+  #define _NEXT_ISR(T) nextMainISR = T
+
+#else
+  #define _NEXT_ISR(T) OCR1A = T
+#endif
+
 //===========================================================================
 //=============================functions         ============================
 //===========================================================================
 
 #define CHECK_ENDSTOPS  if(check_endstops)
 
+#ifndef _NO_ASM
+
 // intRes = intIn1 * intIn2 >> 16
 // uses:
 // r26 to store 0
@@ -169,6 +200,18 @@ asm volatile ( \
 "r26" , "r27" \
 )
 
+#else //_NO_ASM
+
+void MultiU16X8toH16(unsigned short& intRes, unsigned char& charIn1, unsigned short& intIn2)
+{
+}
+
+void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2)
+{
+}
+
+#endif //_NO_ASM
+
 // Some useful constants
 
 #define ENABLE_STEPPER_DRIVER_INTERRUPT()  TIMSK1 |= (1<<OCIE1A)
@@ -283,6 +326,7 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
   else {
     step_loops = 1;
   }
+//    step_loops = 1;
 
   if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
   step_rate -= (F_CPU/500000); // Correct for minimal speed
@@ -306,13 +350,6 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
 // Initializes the trapezoid generator from the current block. Called whenever a new
 // block begins.
 FORCE_INLINE void trapezoid_generator_reset() {
-  #ifdef ADVANCE
-    advance = current_block->initial_advance;
-    final_advance = current_block->final_advance;
-    // Do E steps + advance steps
-    e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
-    old_advance = advance >>8;
-  #endif
   deceleration_time = 0;
   // step_rate to timer interval
   OCR1A_nominal = calc_timer(current_block->nominal_rate);
@@ -320,30 +357,39 @@ FORCE_INLINE void trapezoid_generator_reset() {
   step_loops_nominal = step_loops;
   acc_step_rate = current_block->initial_rate;
   acceleration_time = calc_timer(acc_step_rate);
-  OCR1A = acceleration_time;
-
-//    SERIAL_ECHO_START;
-//    SERIAL_ECHOPGM("advance :");
-//    SERIAL_ECHO(current_block->advance/256.0);
-//    SERIAL_ECHOPGM("advance rate :");
-//    SERIAL_ECHO(current_block->advance_rate/256.0);
-//    SERIAL_ECHOPGM("initial advance :");
-//  SERIAL_ECHO(current_block->initial_advance/256.0);
-//    SERIAL_ECHOPGM("final advance :");
-//    SERIAL_ECHOLN(current_block->final_advance/256.0);
+  _NEXT_ISR(acceleration_time);
+
+  #ifdef LIN_ADVANCE
+    if (current_block->use_advance_lead) {
+        current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
+        final_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17;
+        }
+   #endif
 
 }
 
 // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
 // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
-ISR(TIMER1_COMPA_vect)
-{
+ISR(TIMER1_COMPA_vect) {
+  #ifdef LIN_ADVANCE
+    advance_isr_scheduler();
+  #else
+      isr();
+  #endif
+}
+
+void isr() {
+	//if (UVLO) uvlo();
   // If there is no current block, attempt to pop one from the buffer
   if (current_block == NULL) {
     // Anything in the buffer?
     current_block = plan_get_current_block();
     if (current_block != NULL) {
-      // The busy flag is set by the plan_get_current_block() call.
+#ifdef PAT9125
+	  fsensor_counter = 0;
+      fsensor_st_block_begin(current_block);
+#endif //PAT9125
+	  // The busy flag is set by the plan_get_current_block() call.
       // current_block->busy = true;
       trapezoid_generator_reset();
       counter_x = -(current_block->step_event_count >> 1);
@@ -355,20 +401,18 @@ ISR(TIMER1_COMPA_vect)
       #ifdef Z_LATE_ENABLE
         if(current_block->steps_z > 0) {
           enable_z();
-          OCR1A = 2000; //1ms wait
+          _NEXT_ISR(2000); //1ms wait
           return;
         }
       #endif
-
-//      #ifdef ADVANCE
-//      e_steps[current_block->active_extruder] = 0;
-//      #endif
     }
     else {
-        OCR1A=2000; // 1kHz.
+        _NEXT_ISR(2000); // 1kHz.
     }
   }
 
+	LastStepMask = 0;
+
   if (current_block != NULL) {
     // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt
     out_bits = current_block->direction_bits;
@@ -411,8 +455,19 @@ ISR(TIMER1_COMPA_vect)
       CHECK_ENDSTOPS
       {
         {
-          #if defined(X_MIN_PIN) && X_MIN_PIN > -1
-            bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING);
+          #if ( (defined(X_MIN_PIN) && (X_MIN_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMINLIMIT)
+            
+            #ifdef TMC2130_SG_HOMING
+            // Stall guard homing turned on, now decide if software or hardware one
+                #ifndef TMC2130_SG_HOMING_SW_XY
+                x_min_endstop = (READ(X_TMC2130_DIAG) != X_MIN_ENDSTOP_INVERTING);
+                #else //TMC2130_SG_HOMING_SW_XY
+                x_min_endstop = tmc2130_axis_stalled[X_AXIS];
+                #endif //TMC2130_SG_HOMING_SW_XY
+            #else
+            // Normal homing
+            x_min_endstop = (READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING);
+            #endif
             if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) {
               endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
               endstop_x_hit=true;
@@ -427,8 +482,19 @@ ISR(TIMER1_COMPA_vect)
       CHECK_ENDSTOPS
       {
         {
-          #if defined(X_MAX_PIN) && X_MAX_PIN > -1
-            bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING);
+          #if ( (defined(X_MAX_PIN) && (X_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMAXLIMIT)
+            
+            #ifdef TMC2130_SG_HOMING
+            // Stall guard homing turned on, now decide if software or hardware one
+                #ifndef TMC2130_SG_HOMING_SW_XY
+                x_max_endstop = (READ(X_TMC2130_DIAG) != X_MAX_ENDSTOP_INVERTING);
+                #else //TMC2130_SG_HOMING_SW_XY
+                x_max_endstop = tmc2130_axis_stalled[X_AXIS];
+                #endif //TMC2130_SG_HOMING_SW_XY
+            #else
+            // Normal homing
+            x_max_endstop = (READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING);
+            #endif
             if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){
               endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
               endstop_x_hit=true;
@@ -447,8 +513,20 @@ ISR(TIMER1_COMPA_vect)
     #endif
       CHECK_ENDSTOPS
       {
-        #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
-          bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING);
+          
+        #if ( (defined(Y_MIN_PIN) && (Y_MIN_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMINLIMIT)
+                  
+        #ifdef TMC2130_SG_HOMING
+        // Stall guard homing turned on, now decide if software or hardware one
+            #ifndef TMC2130_SG_HOMING_SW_XY
+            y_min_endstop = (READ(Y_TMC2130_DIAG) != Y_MIN_ENDSTOP_INVERTING);
+            #else //TMC2130_SG_HOMING_SW_XY
+            y_min_endstop = tmc2130_axis_stalled[Y_AXIS];
+            #endif //TMC2130_SG_HOMING_SW_XY
+        #else
+        // Normal homing
+        y_min_endstop = (READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING);
+        #endif
           if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) {
             endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
             endstop_y_hit=true;
@@ -461,8 +539,19 @@ ISR(TIMER1_COMPA_vect)
     else { // +direction
       CHECK_ENDSTOPS
       {
-        #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
-          bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING);
+        #if ( (defined(Y_MAX_PIN) && (Y_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMAXLIMIT)
+                  
+        #ifdef TMC2130_SG_HOMING
+        // Stall guard homing turned on, now decide if software or hardware one
+            #ifndef TMC2130_SG_HOMING_SW_XY
+            y_max_endstop = (READ(Y_TMC2130_DIAG) != Y_MAX_ENDSTOP_INVERTING);
+            #else //TMC2130_SG_HOMING_SW_XY
+            y_max_endstop = tmc2130_axis_stalled[Y_AXIS];
+            #endif //TMC2130_SG_HOMING_SW_XY
+        #else
+        // Normal homing
+        y_max_endstop = (READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING);
+        #endif
           if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){
             endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
             endstop_y_hit=true;
@@ -483,8 +572,8 @@ ISR(TIMER1_COMPA_vect)
       count_direction[Z_AXIS]=-1;
       if(check_endstops && ! check_z_endstop)
       {
-        #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1
-          bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
+        #if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT)
+          z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
           if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) {
             endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
             endstop_z_hit=true;
@@ -504,8 +593,12 @@ ISR(TIMER1_COMPA_vect)
       count_direction[Z_AXIS]=1;
       CHECK_ENDSTOPS
       {
-        #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1
-          bool z_max_endstop=(READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING);
+        #if defined(Z_MAX_PIN) && (Z_MAX_PIN > -1) && !defined(DEBUG_DISABLE_ZMAXLIMIT)
+			#ifndef TMC2130_SG_HOMING_SW_Z
+				z_max_endstop = (READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING);
+			#else //TMC2130_SG_HOMING_SW_Z
+				z_max_endstop = tmc2130_axis_stalled[Z_AXIS];
+			#endif //TMC2130_SG_HOMING_SW_Z
           if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) {
             endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
             endstop_z_hit=true;
@@ -517,11 +610,11 @@ ISR(TIMER1_COMPA_vect)
     }
 
     // Supporting stopping on a trigger of the Z-stop induction sensor, not only for the Z-minus movements.
-    #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1
+    #if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT)
     if(check_z_endstop) {
         // Check the Z min end-stop no matter what.
         // Good for searching for the center of an induction target.
-        bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
+        z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
         if(z_min_endstop && old_z_min_endstop) {
           endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
           endstop_z_hit=true;
@@ -531,48 +624,76 @@ ISR(TIMER1_COMPA_vect)
     }
     #endif
 
-    #ifndef ADVANCE
-      if ((out_bits & (1<<E_AXIS)) != 0) {  // -direction
-        REV_E_DIR();
-        count_direction[E_AXIS]=-1;
-      }
-      else { // +direction
-        NORM_E_DIR();
-        count_direction[E_AXIS]=1;
-      }
-    #endif //!ADVANCE
-
-
-
-    for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves)
+	if ((out_bits & (1 << E_AXIS)) != 0)
+	{	// -direction
+		//AKU
+#ifdef SNMM
+		if (snmm_extruder == 0 || snmm_extruder == 2)
+		{
+			NORM_E_DIR();
+		}
+		else
+		{
+			REV_E_DIR();
+		}
+#else
+		REV_E_DIR();
+#endif // SNMM
+		count_direction[E_AXIS] = -1;
+	}
+	else
+	{	// +direction
+#ifdef SNMM
+		if (snmm_extruder == 0 || snmm_extruder == 2)
+		{
+			REV_E_DIR();
+		}
+		else
+		{
+			NORM_E_DIR();
+		}
+#else
+		NORM_E_DIR();
+#endif // SNMM
+		count_direction[E_AXIS] = 1;
+	}
+
+    for(uint8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves)
       #ifndef AT90USB
       MSerial.checkRx(); // Check for serial chars.
       #endif
 
-      #ifdef ADVANCE
-      counter_e += current_block->steps_e;
-      if (counter_e > 0) {
-        counter_e -= current_block->step_event_count;
-        if ((out_bits & (1<<E_AXIS)) != 0) { // - direction
-          e_steps[current_block->active_extruder]--;
-        }
-        else {
-          e_steps[current_block->active_extruder]++;
+#ifdef LIN_ADVANCE
+        counter_e += current_block->steps_e;
+        if (counter_e > 0) {
+          counter_e -= current_block->step_event_count;
+          count_position[E_AXIS] += count_direction[E_AXIS];
+          ((out_bits&(1<<E_AXIS))!=0) ? --e_steps : ++e_steps;
         }
-      }
-      #endif //ADVANCE
-
+#endif
+        
         counter_x += current_block->steps_x;
         if (counter_x > 0) {
           WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
+		  LastStepMask |= X_AXIS_MASK;
+#ifdef DEBUG_XSTEP_DUP_PIN
+    WRITE(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
+#endif //DEBUG_XSTEP_DUP_PIN
           counter_x -= current_block->step_event_count;
           count_position[X_AXIS]+=count_direction[X_AXIS];   
           WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
+#ifdef DEBUG_XSTEP_DUP_PIN
+    WRITE(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
+#endif //DEBUG_XSTEP_DUP_PIN
         }
 
         counter_y += current_block->steps_y;
         if (counter_y > 0) {
           WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
+		  LastStepMask |= Y_AXIS_MASK;
+#ifdef DEBUG_YSTEP_DUP_PIN
+    WRITE(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
+#endif //DEBUG_YSTEP_DUP_PIN
 		  
 		  #ifdef Y_DUAL_STEPPER_DRIVERS
 			WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN);
@@ -581,6 +702,9 @@ ISR(TIMER1_COMPA_vect)
           counter_y -= current_block->step_event_count;
           count_position[Y_AXIS]+=count_direction[Y_AXIS];
           WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+#ifdef DEBUG_YSTEP_DUP_PIN
+    WRITE(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
+#endif //DEBUG_YSTEP_DUP_PIN
 		  
 		  #ifdef Y_DUAL_STEPPER_DRIVERS
 			WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN);
@@ -590,7 +714,7 @@ ISR(TIMER1_COMPA_vect)
       counter_z += current_block->steps_z;
       if (counter_z > 0) {
         WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
-        
+        LastStepMask |= Z_AXIS_MASK;
         #ifdef Z_DUAL_STEPPER_DRIVERS
           WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
         #endif
@@ -604,23 +728,37 @@ ISR(TIMER1_COMPA_vect)
         #endif
       }
 
-      #ifndef ADVANCE
+#ifndef LIN_ADVANCE
         counter_e += current_block->steps_e;
         if (counter_e > 0) {
           WRITE_E_STEP(!INVERT_E_STEP_PIN);
           counter_e -= current_block->step_event_count;
           count_position[E_AXIS]+=count_direction[E_AXIS];
           WRITE_E_STEP(INVERT_E_STEP_PIN);
+#ifdef PAT9125
+          fsensor_counter++;
+#endif //PAT9125
         }
-      #endif //!ADVANCE
+#endif
+        
       step_events_completed += 1;
       if(step_events_completed >= current_block->step_event_count) break;
     }
+#ifdef LIN_ADVANCE
+      if (current_block->use_advance_lead) {
+        const int delta_adv_steps = current_estep_rate - current_adv_steps;
+        current_adv_steps += delta_adv_steps;
+        e_steps += delta_adv_steps;
+      }
+      // If we have esteps to execute, fire the next advance_isr "now"
+      if (e_steps) nextAdvanceISR = 0;
+#endif
+        
     // Calculare new timer value
     unsigned short timer;
-    unsigned short step_rate;
+    uint16_t step_rate;
     if (step_events_completed <= (unsigned long int)current_block->accelerate_until) {
-
+      // v = t * a   ->   acc_step_rate = acceleration_time * current_block->acceleration_rate
       MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate);
       acc_step_rate += current_block->initial_rate;
 
@@ -630,18 +768,15 @@ ISR(TIMER1_COMPA_vect)
 
       // step_rate to timer interval
       timer = calc_timer(acc_step_rate);
-      OCR1A = timer;
+      _NEXT_ISR(timer);
       acceleration_time += timer;
-      #ifdef ADVANCE
-        for(int8_t i=0; i < step_loops; i++) {
-          advance += advance_rate;
+        
+#ifdef LIN_ADVANCE
+        if (current_block->use_advance_lead) {
+         current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
         }
-        //if(advance > current_block->advance) advance = current_block->advance;
-        // Do E steps + advance steps
-        e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
-        old_advance = advance >>8;
-
-      #endif // ADVANCE
+        eISR_Rate = ADV_RATE(timer, step_loops);
+#endif
     }
     else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {
       MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);
@@ -659,91 +794,127 @@ ISR(TIMER1_COMPA_vect)
 
       // step_rate to timer interval
       timer = calc_timer(step_rate);
-      OCR1A = timer;
+      _NEXT_ISR(timer);
       deceleration_time += timer;
-      #ifdef ADVANCE
-        for(int8_t i=0; i < step_loops; i++) {
-          advance -= advance_rate;
+        
+#ifdef LIN_ADVANCE
+        if (current_block->use_advance_lead) {
+          current_estep_rate = ((uint32_t)step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
         }
-        if(advance < final_advance) advance = final_advance;
-        // Do E steps + advance steps
-        e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
-        old_advance = advance >>8;
-      #endif //ADVANCE
+        eISR_Rate = ADV_RATE(timer, step_loops);
+#endif
     }
     else {
-      OCR1A = OCR1A_nominal;
+#ifdef LIN_ADVANCE
+        if (current_block->use_advance_lead)
+          current_estep_rate = final_estep_rate;
+
+        eISR_Rate = ADV_RATE(OCR1A_nominal, step_loops_nominal);
+#endif
+
+      _NEXT_ISR(OCR1A_nominal);
       // ensure we're running at the correct step rate, even if we just came off an acceleration
       step_loops = step_loops_nominal;
     }
 
     // If current block is finished, reset pointer
     if (step_events_completed >= current_block->step_event_count) {
+
+#ifdef PAT9125
+      fsensor_st_block_chunk(current_block, fsensor_counter);
+	  fsensor_counter = 0;
+#endif //PAT9125
+
       current_block = NULL;
       plan_discard_current_block();
     }
+#ifdef PAT9125
+	else if (fsensor_counter >= fsensor_chunk_len)
+	{
+      fsensor_st_block_chunk(current_block, fsensor_counter);
+	  fsensor_counter = 0;
+	}
+#endif //PAT9125
   }
+#ifdef TMC2130
+	tmc2130_st_isr(LastStepMask);
+#endif //TMC2130
 }
 
-#ifdef ADVANCE
-  unsigned char old_OCR0A;
-  // Timer interrupt for E. e_steps is set in the main routine;
-  // Timer 0 is shared with millies
-  ISR(TIMER0_COMPA_vect)
-  {
-    old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz)
-    OCR0A = old_OCR0A;
-    // Set E direction (Depends on E direction + advance)
-    for(unsigned char i=0; i<4;i++) {
-      if (e_steps[0] != 0) {
-        WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
-        if (e_steps[0] < 0) {
-          WRITE(E0_DIR_PIN, INVERT_E0_DIR);
-          e_steps[0]++;
-          WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-        else if (e_steps[0] > 0) {
-          WRITE(E0_DIR_PIN, !INVERT_E0_DIR);
-          e_steps[0]--;
+#ifdef LIN_ADVANCE
+      
+      // Timer interrupt for E. e_steps is set in the main routine.
+      
+void advance_isr() {
+  if (e_steps) {
+      bool dir =
+#ifdef SNMM
+      ((e_steps < 0) == (snmm_extruder & 1))
+#else
+      (e_steps < 0)
+#endif
+      ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder.
+      WRITE(E0_DIR_PIN, dir);
+      
+      for (uint8_t i = step_loops; e_steps && i--;) {
           WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-      }
- #if EXTRUDERS > 1
-      if (e_steps[1] != 0) {
-        WRITE(E1_STEP_PIN, INVERT_E_STEP_PIN);
-        if (e_steps[1] < 0) {
-          WRITE(E1_DIR_PIN, INVERT_E1_DIR);
-          e_steps[1]++;
-          WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-        else if (e_steps[1] > 0) {
-          WRITE(E1_DIR_PIN, !INVERT_E1_DIR);
-          e_steps[1]--;
-          WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-      }
- #endif
- #if EXTRUDERS > 2
-      if (e_steps[2] != 0) {
-        WRITE(E2_STEP_PIN, INVERT_E_STEP_PIN);
-        if (e_steps[2] < 0) {
-          WRITE(E2_DIR_PIN, INVERT_E2_DIR);
-          e_steps[2]++;
-          WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-        else if (e_steps[2] > 0) {
-          WRITE(E2_DIR_PIN, !INVERT_E2_DIR);
-          e_steps[2]--;
-          WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
+          e_steps < 0 ? ++e_steps : --e_steps;
+          WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
+#ifdef PAT9125
+		  fsensor_counter++;
+#endif //PAT9125
+
       }
- #endif
-    }
   }
-#endif // ADVANCE
+  else {
+    eISR_Rate = ADV_NEVER;
+  }
+  nextAdvanceISR = eISR_Rate;
+}
 
+void advance_isr_scheduler() {
+  // Run main stepping ISR if flagged
+  if (!nextMainISR) isr();
+  
+  // Run Advance stepping ISR if flagged
+  if (!nextAdvanceISR) advance_isr();
+  
+  // Is the next advance ISR scheduled before the next main ISR?
+  if (nextAdvanceISR <= nextMainISR) {
+      // Set up the next interrupt
+      OCR1A = nextAdvanceISR;
+      // New interval for the next main ISR
+      if (nextMainISR) nextMainISR -= nextAdvanceISR;
+      // Will call Stepper::advance_isr on the next interrupt
+      nextAdvanceISR = 0;
+  }
+  else {
+      // The next main ISR comes first
+      OCR1A = nextMainISR;
+      // New interval for the next advance ISR, if any
+      if (nextAdvanceISR && nextAdvanceISR != ADV_NEVER)
+          nextAdvanceISR -= nextMainISR;
+      // Will call Stepper::isr on the next interrupt
+      nextMainISR = 0;
+  }
+  
+  // Don't run the ISR faster than possible
+  if (OCR1A < TCNT1 + 16) OCR1A = TCNT1 + 16;
+}
+
+void clear_current_adv_vars() {
+  e_steps = 0; //Should be already 0 at an filament change event, but just to be sure..
+  current_adv_steps = 0;
+}
+
+#endif // LIN_ADVANCE
+      
 void st_init()
 {
+#ifdef TMC2130
+	tmc2130_init();
+#endif //TMC2130
+
   digipot_init(); //Initialize Digipot Motor Current
   microstep_init(); //Initialize Microstepping Pins
 
@@ -821,6 +992,18 @@ void st_init()
 
   //endstops and pullups
 
+  #ifdef TMC2130_SG_HOMING
+    SET_INPUT(X_TMC2130_DIAG);
+    WRITE(X_TMC2130_DIAG,HIGH);
+    
+    SET_INPUT(Y_TMC2130_DIAG);
+    WRITE(Y_TMC2130_DIAG,HIGH);
+    
+    SET_INPUT(Z_TMC2130_DIAG);
+    WRITE(Z_TMC2130_DIAG,HIGH);
+    
+  #endif
+    
   #if defined(X_MIN_PIN) && X_MIN_PIN > -1
     SET_INPUT(X_MIN_PIN);
     #ifdef ENDSTOPPULLUP_XMIN
@@ -865,9 +1048,13 @@ void st_init()
 
 
   //Initialize Step Pins
-  #if defined(X_STEP_PIN) && (X_STEP_PIN > -1)
+#if defined(X_STEP_PIN) && (X_STEP_PIN > -1)
     SET_OUTPUT(X_STEP_PIN);
     WRITE(X_STEP_PIN,INVERT_X_STEP_PIN);
+#ifdef DEBUG_XSTEP_DUP_PIN
+    SET_OUTPUT(DEBUG_XSTEP_DUP_PIN);
+    WRITE(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
+#endif //DEBUG_XSTEP_DUP_PIN
     disable_x();
   #endif
   #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1)
@@ -878,6 +1065,10 @@ void st_init()
   #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1)
     SET_OUTPUT(Y_STEP_PIN);
     WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN);
+#ifdef DEBUG_YSTEP_DUP_PIN
+    SET_OUTPUT(DEBUG_YSTEP_DUP_PIN);
+    WRITE(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
+#endif //DEBUG_YSTEP_DUP_PIN
     #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_STEP_PIN) && (Y2_STEP_PIN > -1)
       SET_OUTPUT(Y2_STEP_PIN);
       WRITE(Y2_STEP_PIN,INVERT_Y_STEP_PIN);
@@ -930,17 +1121,11 @@ void st_init()
   TCNT1 = 0;
   ENABLE_STEPPER_DRIVER_INTERRUPT();
 
-  #ifdef ADVANCE
-  #if defined(TCCR0A) && defined(WGM01)
-    TCCR0A &= ~(1<<WGM01);
-    TCCR0A &= ~(1<<WGM00);
-  #endif
-    e_steps[0] = 0;
-    e_steps[1] = 0;
-    e_steps[2] = 0;
-    TIMSK0 |= (1<<OCIE0A);
-  #endif //ADVANCE
-
+#ifdef LIN_ADVANCE
+    e_steps = 0;
+    current_adv_steps = 0;
+#endif
+    
   enable_endstops(true); // Start with endstops active. After homing they can be disabled
   sei();
 }
@@ -949,12 +1134,23 @@ void st_init()
 // Block until all buffered steps are executed
 void st_synchronize()
 {
-    while( blocks_queued()) {
-    manage_heater();
-    // Vojtech: Don't disable motors inside the planner!
-    manage_inactivity(true);
-    lcd_update();
-  }
+	while(blocks_queued())
+	{
+#ifdef TMC2130
+		manage_heater();
+		// Vojtech: Don't disable motors inside the planner!
+		if (!tmc2130_update_sg())
+		{
+			manage_inactivity(true);
+			lcd_update();
+		}
+#else //TMC2130
+		manage_heater();
+		// Vojtech: Don't disable motors inside the planner!
+		manage_inactivity(true);
+		lcd_update();
+#endif //TMC2130
+	}
 }
 
 void st_set_position(const long &x, const long &y, const long &z, const long &e)
@@ -983,6 +1179,13 @@ long st_get_position(uint8_t axis)
   return count_pos;
 }
 
+void st_get_position_xy(long &x, long &y)
+{
+  CRITICAL_SECTION_START;
+  x = count_position[X_AXIS];
+  y = count_position[Y_AXIS];
+  CRITICAL_SECTION_END;
+}
 
 float st_get_position_mm(uint8_t axis)
 {
@@ -1029,10 +1232,17 @@ void babystep(const uint8_t axis,const bool direction)
     
     //perform step 
     WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); 
+	LastStepMask |= X_AXIS_MASK;
+#ifdef DEBUG_XSTEP_DUP_PIN
+    WRITE(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
+#endif //DEBUG_XSTEP_DUP_PIN
     {
-    float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
+    volatile float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
     }
     WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
+#ifdef DEBUG_XSTEP_DUP_PIN
+    WRITE(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
+#endif //DEBUG_XSTEP_DUP_PIN
 
     //get old pin state back.
     WRITE(X_DIR_PIN,old_x_dir_pin);
@@ -1048,10 +1258,17 @@ void babystep(const uint8_t axis,const bool direction)
     
     //perform step 
     WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); 
+	LastStepMask |= Y_AXIS_MASK;
+#ifdef DEBUG_YSTEP_DUP_PIN
+    WRITE(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
+#endif //DEBUG_YSTEP_DUP_PIN
     {
-    float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
+    volatile float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
     }
     WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+#ifdef DEBUG_YSTEP_DUP_PIN
+    WRITE(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
+#endif //DEBUG_YSTEP_DUP_PIN
 
     //get old pin state back.
     WRITE(Y_DIR_PIN,old_y_dir_pin);
@@ -1070,12 +1287,13 @@ void babystep(const uint8_t axis,const bool direction)
     #endif
     //perform step 
     WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); 
+	LastStepMask |= Z_AXIS_MASK;
     #ifdef Z_DUAL_STEPPER_DRIVERS
       WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
     #endif
     //wait a tiny bit
     {
-    float x=1./float(axis+1); //absolutely useless
+    volatile float x=1./float(axis+1); //absolutely useless
     }
     WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
     #ifdef Z_DUAL_STEPPER_DRIVERS
@@ -1139,7 +1357,7 @@ void digipot_init() //Initialize Digipot Motor Current
     pinMode(MOTOR_CURRENT_PWM_XY_PIN, OUTPUT);
     pinMode(MOTOR_CURRENT_PWM_Z_PIN, OUTPUT);
     pinMode(MOTOR_CURRENT_PWM_E_PIN, OUTPUT);
-    if(SilentMode == 0){
+    if((SilentMode == 0) || (farm_mode) ){
 
      motor_current_setting[0] = motor_current_setting_loud[0];
      motor_current_setting[1] = motor_current_setting_loud[1];
@@ -1255,4 +1473,3 @@ void microstep_readings()
       SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN));
       #endif
 }
-

+ 16 - 0
Firmware/stepper.h

@@ -44,6 +44,16 @@ extern bool abort_on_endstop_hit;
 // Initialize and start the stepper motor subsystem
 void st_init();
 
+// Interrupt Service Routines
+
+void isr();
+
+#ifdef LIN_ADVANCE
+  void advance_isr();
+  void advance_isr_scheduler();
+  void clear_current_adv_vars(); //Used to reset the built up pretension and remaining esteps on filament change.
+#endif
+
 // Block until all buffered steps are executed
 void st_synchronize();
 
@@ -54,6 +64,8 @@ void st_set_e_position(const long &e);
 // Get current position in steps
 long st_get_position(uint8_t axis);
 
+// Get current x and y position in steps
+void st_get_position_xy(long &x, long &y);
 
 // Get current position in mm
 float st_get_position_mm(uint8_t axis);
@@ -77,6 +89,10 @@ void checkStepperErrors(); //Print errors detected by the stepper
 void finishAndDisableSteppers();
 
 extern block_t *current_block;  // A pointer to the block currently being traced
+extern bool x_min_endstop;
+extern bool x_max_endstop;
+extern bool y_min_endstop;
+extern bool y_max_endstop;
 
 void quickStop();
 

+ 209 - 0
Firmware/swi2c.cpp

@@ -0,0 +1,209 @@
+#include "uni_avr_rpi.h"
+
+#ifdef SWI2C
+#include "swi2c.h"
+
+#ifdef __AVR
+unsigned char swi2c_sda = 20; // SDA pin
+unsigned char swi2c_scl = 21; // SCL pin
+#endif //__AVR
+
+#ifdef __RPI
+unsigned char swi2c_sda = 2; // SDA pin
+unsigned char swi2c_scl = 3; // SCL pin
+#endif //__RPI
+
+unsigned char swi2c_cfg = 0xb1; // config
+//  bit0..3 = clock delay factor = 1 << 1 = 2 [us]
+//  bit4..7 = ack timeout factor = 1 << 11 = 2048 [cycles]
+
+#define SWI2C_SDA    swi2c_sda
+#define SWI2C_SCL    swi2c_scl
+#define SWI2C_RMSK   0x01 //read mask (bit0 = 1)
+#define SWI2C_WMSK   0x00 //write mask (bit0 = 0)
+#define SWI2C_ASHF   0x01 //address shift (<< 1)
+#define SWI2C_DMSK   0x7f //device address mask
+
+
+void swi2c_init(unsigned char sda, unsigned char scl, unsigned char cfg)
+{
+	swi2c_sda = sda;
+	swi2c_scl = scl;
+	swi2c_cfg = cfg;
+	GPIO_OUT(SWI2C_SDA);
+	GPIO_OUT(SWI2C_SCL);
+	GPIO_SET(SWI2C_SDA);
+	GPIO_SET(SWI2C_SCL);
+	DELAY(1000);
+}
+
+void swi2c_start(int delay)
+{
+	GPIO_CLR(SWI2C_SDA);
+	DELAY(delay);
+	GPIO_CLR(SWI2C_SCL);
+	DELAY(delay);
+}
+
+void swi2c_stop(int delay)
+{
+	GPIO_SET(SWI2C_SCL);
+	DELAY(delay);
+	GPIO_SET(SWI2C_SDA);
+	DELAY(delay);
+}
+
+void swi2c_ack(int delay)
+{
+	GPIO_CLR(SWI2C_SDA);
+	DELAY(delay);
+	GPIO_SET(SWI2C_SCL);
+	DELAY(delay);
+	GPIO_CLR(SWI2C_SCL);
+	DELAY(delay);
+}
+
+int swi2c_wait_ack(int delay, int ackto)
+{
+	GPIO_INP(SWI2C_SDA);
+	DELAY(delay);
+//	GPIO_SET(SWI2C_SDA);
+	DELAY(delay);
+	GPIO_SET(SWI2C_SCL);
+//	DELAY(delay);
+	int ack = 0;
+	while (!(ack = !GPIO_GET(SWI2C_SDA)) && ackto--) DELAY(delay);
+	GPIO_CLR(SWI2C_SCL);
+	DELAY(delay);
+	GPIO_OUT(SWI2C_SDA);
+	DELAY(delay);
+	GPIO_CLR(SWI2C_SDA);
+	DELAY(delay);
+	return ack;
+}
+
+unsigned char swi2c_read(int delay)
+{
+	GPIO_SET(SWI2C_SDA);
+	DELAY(delay);
+	GPIO_INP(SWI2C_SDA);
+	unsigned char data = 0;
+	int bit; for (bit = 7; bit >= 0; bit--)
+	{
+		GPIO_SET(SWI2C_SCL);
+		DELAY(delay);
+		data |= GPIO_GET(SWI2C_SDA) << bit;
+		GPIO_CLR(SWI2C_SCL);
+		DELAY(delay);
+	}
+	GPIO_OUT(SWI2C_SDA);
+	return data;
+}
+
+void swi2c_write(int delay, unsigned char data)
+{
+	int bit; for (bit = 7; bit >= 0; bit--)
+	{
+		if (data & (1 << bit)) GPIO_SET(SWI2C_SDA);
+		else GPIO_CLR(SWI2C_SDA);
+		DELAY(delay);
+		GPIO_SET(SWI2C_SCL);
+		DELAY(delay);
+		GPIO_CLR(SWI2C_SCL);
+		DELAY(delay);
+	}
+}
+
+int swi2c_check(unsigned char dev_addr)
+{
+	int delay = 1 << (swi2c_cfg & 0xf);
+	int tmout = 1 << (swi2c_cfg >> 4);
+	swi2c_start(delay);
+	swi2c_write(delay, (dev_addr & SWI2C_DMSK) << SWI2C_ASHF);
+	if (!swi2c_wait_ack(delay, tmout)) { swi2c_stop(delay); return 0; }
+	swi2c_stop(delay);
+	return 1;
+}
+
+#ifdef SWI2C_A8 //8bit address
+
+int swi2c_readByte_A8(unsigned char dev_addr, unsigned char addr, unsigned char* pbyte)
+{
+	int delay = 1 << (swi2c_cfg & 0xf);
+	int tmout = 1 << (swi2c_cfg >> 4);
+	swi2c_start(delay);
+	swi2c_write(delay, SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF));
+	if (!swi2c_wait_ack(delay, tmout)) { swi2c_stop(delay); return 0; }
+	swi2c_write(delay, addr & 0xff);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_stop(delay);
+	swi2c_start(delay);
+	swi2c_write(delay, SWI2C_RMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF));
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	unsigned char byte = swi2c_read(delay);
+	swi2c_stop(delay);
+	if (pbyte) *pbyte = byte;
+	return 1;
+}
+
+int swi2c_writeByte_A8(unsigned char dev_addr, unsigned char addr, unsigned char* pbyte)
+{
+	int delay = 1 << (swi2c_cfg & 0xf);
+	int tmout = 1 << (swi2c_cfg >> 4);
+	swi2c_start(delay);
+	swi2c_write(delay, SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF));
+	if (!swi2c_wait_ack(delay, tmout)) { swi2c_stop(delay); return 0; }
+	swi2c_write(delay, addr & 0xff);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_write(delay, *pbyte);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_stop(delay);
+	return 1;
+}
+
+#endif //SWI2C_A8
+
+#ifdef SWI2C_A16 //16bit address
+
+int swi2c_readByte_A16(unsigned char dev_addr, unsigned short addr, unsigned char* pbyte)
+{
+	int delay = 1 << (swi2c_cfg & 0xf);
+	int tmout = 1 << (swi2c_cfg >> 4);
+	swi2c_start(delay);
+	swi2c_write(delay, SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF));
+	if (!swi2c_wait_ack(delay, tmout)) { swi2c_stop(delay); return 0; }
+	swi2c_write(delay, addr >> 8);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_write(delay, addr & 0xff);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_stop(delay);
+	swi2c_start(delay);
+	swi2c_write(delay, SWI2C_RMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF));
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	unsigned char byte = swi2c_read(delay);
+	swi2c_stop(delay);
+	if (pbyte) *pbyte = byte;
+	return 1;
+}
+
+int swi2c_writeByte_A16(unsigned char dev_addr, unsigned short addr, unsigned char* pbyte)
+{
+	int delay = 1 << (swi2c_cfg & 0xf);
+	int tmout = 1 << (swi2c_cfg >> 4);
+	swi2c_start(delay);
+	swi2c_write(delay, SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF));
+	if (!swi2c_wait_ack(delay, tmout)) { swi2c_stop(delay); return 0; }
+	swi2c_write(delay, addr >> 8);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_write(delay, addr & 0xff);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_write(delay, *pbyte);
+	if (!swi2c_wait_ack(delay, tmout)) return 0;
+	swi2c_stop(delay);
+	return 1;
+}
+
+#endif //SWI2C_A16
+
+
+#endif //SWI2C

+ 22 - 0
Firmware/swi2c.h

@@ -0,0 +1,22 @@
+#ifndef SWI2C_H
+#define SWI2C_H
+
+//initialize
+extern void swi2c_init(unsigned char sda, unsigned char scl, unsigned char cfg);
+
+//check device address acknowledge
+extern int swi2c_check(unsigned char dev_addr);
+
+//read write functions - 8bit address (most i2c chips)
+#ifdef SWI2C_A8
+extern int swi2c_readByte_A8(unsigned char dev_addr, unsigned char addr, unsigned char* pbyte);
+extern int swi2c_writeByte_A8(unsigned char dev_addr, unsigned char addr, unsigned char* pbyte);
+#endif //SWI2C_A8
+
+//read write functions - 16bit address (e.g. serial eeprom AT24C256)
+#ifdef SWI2C_A16
+extern int swi2c_readByte_A16(unsigned char dev_addr, unsigned short addr, unsigned char* pbyte);
+extern int swi2c_writeByte_A16(unsigned char dev_addr, unsigned short addr, unsigned char* pbyte);
+#endif //SWI2C_A16
+
+#endif //SWI2C_H

+ 93 - 0
Firmware/swspi.cpp

@@ -0,0 +1,93 @@
+#include "uni_avr_rpi.h"
+
+#ifdef __SWSPI
+#include "swspi.h"
+
+#ifdef __RPI
+//#define swspi_miso	9
+#define swspi_miso	10
+#define swspi_mosi	10
+#define swspi_sck	11
+#define SWSPI_CS	7
+#endif //__RPI
+
+
+#define SWSPI_DEL	0x0f //delay mask (0-3. bit, delay = 1 << DEL [us])
+#define SWSPI_POL	0x10 //polarity mask (4. bit, 1=inverted)
+#define SWSPI_PHA	0x20 //phase mask (5. bit)
+#define SWSPI_DOR	0x40 //data order mask (6. bit, 0=MSB first, 1=LSB first)
+
+#define SWSPI_SCK_UP if (swspi_cfg & SWSPI_POL) GPIO_CLR(swspi_sck); else GPIO_SET(swspi_sck);
+#define SWSPI_SCK_DN if (swspi_cfg & SWSPI_POL) GPIO_SET(swspi_sck); else GPIO_CLR(swspi_sck);
+
+unsigned char swspi_miso = 0;
+unsigned char swspi_mosi = 0;
+unsigned char swspi_sck = 0;
+unsigned char swspi_cfg = 0;
+
+void swspi_init(unsigned char miso, unsigned char mosi, unsigned char sck, unsigned char cfg)
+{
+	swspi_miso = miso;
+	swspi_mosi = mosi;
+	swspi_sck = sck;
+	swspi_cfg = cfg;
+	GPIO_INP(swspi_miso);
+	GPIO_OUT(swspi_mosi);
+	GPIO_OUT(swspi_sck);
+	GPIO_CLR(swspi_mosi);
+	SWSPI_SCK_DN;
+}
+
+void swspi_tx(unsigned char tx)
+{
+	int delay = 1 << (swspi_cfg & SWSPI_DEL));
+	if (swspi_miso == swspi_mosi) GPIO_OUT(swspi_mosi);
+	unsigned char i = 0; for (; i < 8; i++)
+	{
+		if (tx & 0x80) GPIO_SET(swspi_mosi);
+		else GPIO_CLR(swspi_mosi);
+	    DELAY(delay);
+		SWSPI_SCK_UP;
+	    DELAY(delay);
+		SWSPI_SCK_DN;
+		tx <<= 1;
+	}
+}
+
+unsigned char swspi_rx()
+{
+	int delay = 1 << (swspi_cfg & SWSPI_DEL));
+	if (swspi_miso == swspi_mosi) GPIO_OUT(swspi_mosi);
+	unsigned char rx = 0;
+	unsigned char i = 0; for (; i < 8; i++)
+	{
+		rx <<= 1;
+	    DELAY(delay);
+		SWSPI_SCK_UP;
+	    DELAY(delay);
+		rx |= GPIO_GET(swspi_miso)?1:0;
+		SWSPI_SCK_DN;
+	}
+	return rx;
+}
+
+unsigned char swspi_txrx(unsigned char tx)
+{
+	int delay = 1 << (swspi_cfg & SWSPI_DEL));
+	unsigned char rx = 0;
+	unsigned char i = 0; for (; i < 8; i++)
+	{
+		rx <<= 1;
+		if (tx & 0x80) GPIO_SET(swspi_mosi);
+		else GPIO_CLR(swspi_mosi);
+	    DELAY(delay);
+		SWSPI_SCK_UP;
+	    DELAY(delay);
+		rx |= GPIO_GET(swspi_miso)?1:0;
+		SWSPI_SCK_DN;
+		tx <<= 1;
+	}
+	return rx;
+}
+
+#endif //__SWSPI

+ 14 - 0
Firmware/swspi.h

@@ -0,0 +1,14 @@
+// Software SPI
+#ifndef SWSPI_H
+#define SWSPI_H
+
+//initialize gpio
+extern void swspi_init(unsigned char miso, unsigned char mosi, unsigned char sck, unsigned char cfg);
+//transmit and receive (full duplex mode)
+extern unsigned char swspi_txrx(unsigned char tx);
+//transmit (half dublex mode, miso == mosi)
+extern void swspi_tx(unsigned char tx);
+//receive (half dublex mode, miso == mosi)
+extern unsigned char swspi_rx();
+
+#endif //SWSPI_H

+ 2244 - 1861
Firmware/temperature.cpp

@@ -1,1861 +1,2244 @@
-/*
-  temperature.c - temperature control
-  Part of Marlin
-  
- Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
- 
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
- 
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- This firmware is a mashup between Sprinter and grbl.
-  (https://github.com/kliment/Sprinter)
-  (https://github.com/simen/grbl/tree)
- 
- It has preliminary support for Matthew Roberts advance algorithm 
-    http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
-
- */
-
-
-#include "Marlin.h"
-#include "ultralcd.h"
-#include "temperature.h"
-#include "watchdog.h"
-#include "cardreader.h"
-
-#include "Sd2PinMap.h"
-
-
-//===========================================================================
-//=============================public variables============================
-//===========================================================================
-int target_temperature[EXTRUDERS] = { 0 };
-int target_temperature_bed = 0;
-int current_temperature_raw[EXTRUDERS] = { 0 };
-float current_temperature[EXTRUDERS] = { 0.0 };
-int current_temperature_bed_raw = 0;
-float current_temperature_bed = 0.0;
-#ifdef TEMP_SENSOR_1_AS_REDUNDANT
-  int redundant_temperature_raw = 0;
-  float redundant_temperature = 0.0;
-#endif
-#ifdef PIDTEMP
-  float Kp=DEFAULT_Kp;
-  float Ki=(DEFAULT_Ki*PID_dT);
-  float Kd=(DEFAULT_Kd/PID_dT);
-  #ifdef PID_ADD_EXTRUSION_RATE
-    float Kc=DEFAULT_Kc;
-  #endif
-#endif //PIDTEMP
-
-#ifdef PIDTEMPBED
-  float bedKp=DEFAULT_bedKp;
-  float bedKi=(DEFAULT_bedKi*PID_dT);
-  float bedKd=(DEFAULT_bedKd/PID_dT);
-#endif //PIDTEMPBED
-  
-#ifdef FAN_SOFT_PWM
-  unsigned char fanSpeedSoftPwm;
-#endif
-
-unsigned char soft_pwm_bed;
-  
-#ifdef BABYSTEPPING
-  volatile int babystepsTodo[3]={0,0,0};
-#endif
-
-#ifdef FILAMENT_SENSOR
-  int current_raw_filwidth = 0;  //Holds measured filament diameter - one extruder only
-#endif  
-//===========================================================================
-//=============================private variables============================
-//===========================================================================
-static volatile bool temp_meas_ready = false;
-
-#ifdef PIDTEMP
-  //static cannot be external:
-  static float temp_iState[EXTRUDERS] = { 0 };
-  static float temp_dState[EXTRUDERS] = { 0 };
-  static float pTerm[EXTRUDERS];
-  static float iTerm[EXTRUDERS];
-  static float dTerm[EXTRUDERS];
-  //int output;
-  static float pid_error[EXTRUDERS];
-  static float temp_iState_min[EXTRUDERS];
-  static float temp_iState_max[EXTRUDERS];
-  // static float pid_input[EXTRUDERS];
-  // static float pid_output[EXTRUDERS];
-  static bool pid_reset[EXTRUDERS];
-#endif //PIDTEMP
-#ifdef PIDTEMPBED
-  //static cannot be external:
-  static float temp_iState_bed = { 0 };
-  static float temp_dState_bed = { 0 };
-  static float pTerm_bed;
-  static float iTerm_bed;
-  static float dTerm_bed;
-  //int output;
-  static float pid_error_bed;
-  static float temp_iState_min_bed;
-  static float temp_iState_max_bed;
-#else //PIDTEMPBED
-	static unsigned long  previous_millis_bed_heater;
-#endif //PIDTEMPBED
-  static unsigned char soft_pwm[EXTRUDERS];
-
-#ifdef FAN_SOFT_PWM
-  static unsigned char soft_pwm_fan;
-#endif
-#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
-    (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
-    (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
-  static unsigned long extruder_autofan_last_check;
-#endif  
-
-#if EXTRUDERS > 3
-  # error Unsupported number of extruders
-#elif EXTRUDERS > 2
-  # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2, v3 }
-#elif EXTRUDERS > 1
-  # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2 }
-#else
-  # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 }
-#endif
-
-// Init min and max temp with extreme values to prevent false errors during startup
-static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP );
-static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP );
-static int minttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 0, 0, 0 );
-static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 16383, 16383, 16383 );
-//static int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP; /* No bed mintemp error implemented?!? */
-#ifdef BED_MAXTEMP
-static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP;
-#endif
-
-#ifdef TEMP_SENSOR_1_AS_REDUNDANT
-  static void *heater_ttbl_map[2] = {(void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE };
-  static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN };
-#else
-  static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE );
-  static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN );
-#endif
-
-static float analog2temp(int raw, uint8_t e);
-static float analog2tempBed(int raw);
-static void updateTemperaturesFromRawValues();
-
-#ifdef WATCH_TEMP_PERIOD
-int watch_start_temp[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
-unsigned long watchmillis[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
-#endif //WATCH_TEMP_PERIOD
-
-#ifndef SOFT_PWM_SCALE
-#define SOFT_PWM_SCALE 0
-#endif
-
-#ifdef FILAMENT_SENSOR
-  static int meas_shift_index;  //used to point to a delayed sample in buffer for filament width sensor
-#endif
-//===========================================================================
-//=============================   functions      ============================
-//===========================================================================
-
-void PID_autotune(float temp, int extruder, int ncycles)
-{
-  float input = 0.0;
-  int cycles=0;
-  bool heating = true;
-
-  unsigned long temp_millis = millis();
-  unsigned long t1=temp_millis;
-  unsigned long t2=temp_millis;
-  long t_high = 0;
-  long t_low = 0;
-
-  long bias, d;
-  float Ku, Tu;
-  float Kp, Ki, Kd;
-  float max = 0, min = 10000;
-
-#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
-    (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
-    (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
-  unsigned long extruder_autofan_last_check = millis();
-#endif
-
-  if ((extruder >= EXTRUDERS)
-  #if (TEMP_BED_PIN <= -1)
-       ||(extruder < 0)
-  #endif
-       ){
-          SERIAL_ECHOLN("PID Autotune failed. Bad extruder number.");
-          return;
-        }
-	
-  SERIAL_ECHOLN("PID Autotune start");
-  
-  disable_heater(); // switch off all heaters.
-
-  if (extruder<0)
-  {
-     soft_pwm_bed = (MAX_BED_POWER)/2;
-     bias = d = (MAX_BED_POWER)/2;
-   }
-   else
-   {
-     soft_pwm[extruder] = (PID_MAX)/2;
-     bias = d = (PID_MAX)/2;
-  }
-
-
-
-
- for(;;) {
-
-    if(temp_meas_ready == true) { // temp sample ready
-      updateTemperaturesFromRawValues();
-
-      input = (extruder<0)?current_temperature_bed:current_temperature[extruder];
-
-      max=max(max,input);
-      min=min(min,input);
-
-      #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
-          (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
-          (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
-      if(millis() - extruder_autofan_last_check > 2500) {
-        checkExtruderAutoFans();
-        extruder_autofan_last_check = millis();
-      }
-      #endif
-
-      if(heating == true && input > temp) {
-        if(millis() - t2 > 5000) { 
-          heating=false;
-          if (extruder<0)
-            soft_pwm_bed = (bias - d) >> 1;
-          else
-            soft_pwm[extruder] = (bias - d) >> 1;
-          t1=millis();
-          t_high=t1 - t2;
-          max=temp;
-        }
-      }
-      if(heating == false && input < temp) {
-        if(millis() - t1 > 5000) {
-          heating=true;
-          t2=millis();
-          t_low=t2 - t1;
-          if(cycles > 0) {
-            bias += (d*(t_high - t_low))/(t_low + t_high);
-            bias = constrain(bias, 20 ,(extruder<0?(MAX_BED_POWER):(PID_MAX))-20);
-            if(bias > (extruder<0?(MAX_BED_POWER):(PID_MAX))/2) d = (extruder<0?(MAX_BED_POWER):(PID_MAX)) - 1 - bias;
-            else d = bias;
-
-            SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias);
-            SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d);
-            SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min);
-            SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max);
-            if(cycles > 2) {
-              Ku = (4.0*d)/(3.14159*(max-min)/2.0);
-              Tu = ((float)(t_low + t_high)/1000.0);
-              SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku);
-              SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu);
-              Kp = 0.6*Ku;
-              Ki = 2*Kp/Tu;
-              Kd = Kp*Tu/8;
-              SERIAL_PROTOCOLLNPGM(" Classic PID ");
-              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
-              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
-              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
-              /*
-              Kp = 0.33*Ku;
-              Ki = Kp/Tu;
-              Kd = Kp*Tu/3;
-              SERIAL_PROTOCOLLNPGM(" Some overshoot ");
-              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
-              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
-              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
-              Kp = 0.2*Ku;
-              Ki = 2*Kp/Tu;
-              Kd = Kp*Tu/3;
-              SERIAL_PROTOCOLLNPGM(" No overshoot ");
-              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
-              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
-              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
-              */
-            }
-          }
-          if (extruder<0)
-            soft_pwm_bed = (bias + d) >> 1;
-          else
-            soft_pwm[extruder] = (bias + d) >> 1;
-          cycles++;
-          min=temp;
-        }
-      } 
-    }
-    if(input > (temp + 20)) {
-      SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature too high");
-      return;
-    }
-    if(millis() - temp_millis > 2000) {
-      int p;
-      if (extruder<0){
-        p=soft_pwm_bed;       
-        SERIAL_PROTOCOLPGM("ok B:");
-      }else{
-        p=soft_pwm[extruder];       
-        SERIAL_PROTOCOLPGM("ok T:");
-      }
-			
-      SERIAL_PROTOCOL(input);   
-      SERIAL_PROTOCOLPGM(" @:");
-      SERIAL_PROTOCOLLN(p);       
-
-      temp_millis = millis();
-    }
-    if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) {
-      SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout");
-      return;
-    }
-    if(cycles > ncycles) {
-      SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h");
-      return;
-    }
-    lcd_update();
-  }
-}
-
-void updatePID()
-{
-#ifdef PIDTEMP
-  for(int e = 0; e < EXTRUDERS; e++) { 
-     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;  
-  }
-#endif
-#ifdef PIDTEMPBED
-  temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi;  
-#endif
-}
-  
-int getHeaterPower(int heater) {
-	if (heater<0)
-		return soft_pwm_bed;
-  return soft_pwm[heater];
-}
-
-#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
-    (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
-    (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
-
-  #if defined(FAN_PIN) && FAN_PIN > -1
-    #if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN 
-       #error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN"
-    #endif
-    #if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN 
-       #error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN"
-    #endif
-    #if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN 
-       #error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN"
-    #endif
-  #endif 
-
-void setExtruderAutoFanState(int pin, bool state)
-{
-  unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0;
-  // this idiom allows both digital and PWM fan outputs (see M42 handling).
-  pinMode(pin, OUTPUT);
-  digitalWrite(pin, newFanSpeed);
-  analogWrite(pin, newFanSpeed);
-}
-
-void checkExtruderAutoFans()
-{
-  uint8_t fanState = 0;
-
-  // which fan pins need to be turned on?      
-  #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
-    if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) 
-      fanState |= 1;
-  #endif
-  #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1
-    if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) 
-    {
-      if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) 
-        fanState |= 1;
-      else
-        fanState |= 2;
-    }
-  #endif
-  #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1
-    if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) 
-    {
-      if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) 
-        fanState |= 1;
-      else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) 
-        fanState |= 2;
-      else
-        fanState |= 4;
-    }
-  #endif
-  
-  // update extruder auto fan states
-  #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
-    setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0);
-  #endif 
-  #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1
-    if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) 
-      setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0);
-  #endif 
-  #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1
-    if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN 
-        && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN)
-      setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0);
-  #endif 
-}
-
-#endif // any extruder auto fan pins set
-
-void manage_heater()
-{
-  float pid_input;
-  float pid_output;
-
-  if(temp_meas_ready != true)   //better readability
-    return; 
-
-  updateTemperaturesFromRawValues();
-
-#ifdef TEMP_RUNAWAY_BED_HYSTERESIS
-  temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true);
-#endif
-
-  for(int e = 0; e < EXTRUDERS; e++) 
-  {
-
-#ifdef TEMP_RUNAWAY_EXTRUDER_HYSTERESIS
-	  temp_runaway_check(e+1, target_temperature[e], current_temperature[e], (int)soft_pwm[e], false);
-#endif
-
-  #ifdef PIDTEMP
-    pid_input = current_temperature[e];
-
-    #ifndef PID_OPENLOOP
-        pid_error[e] = target_temperature[e] - pid_input;
-        if(pid_error[e] > PID_FUNCTIONAL_RANGE) {
-          pid_output = BANG_MAX;
-          pid_reset[e] = true;
-        }
-        else if(pid_error[e] < -PID_FUNCTIONAL_RANGE || target_temperature[e] == 0) {
-          pid_output = 0;
-          pid_reset[e] = true;
-        }
-        else {
-          if(pid_reset[e] == true) {
-            temp_iState[e] = 0.0;
-            pid_reset[e] = false;
-          }
-          pTerm[e] = Kp * pid_error[e];
-          temp_iState[e] += pid_error[e];
-          temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]);
-          iTerm[e] = Ki * temp_iState[e];
-
-          //K1 defined in Configuration.h in the PID settings
-          #define K2 (1.0-K1)
-          dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
-          pid_output = pTerm[e] + iTerm[e] - dTerm[e];
-          if (pid_output > PID_MAX) {
-            if (pid_error[e] > 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
-            pid_output=PID_MAX;
-          } else if (pid_output < 0){
-            if (pid_error[e] < 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
-            pid_output=0;
-          }
-        }
-        temp_dState[e] = pid_input;
-    #else 
-          pid_output = constrain(target_temperature[e], 0, PID_MAX);
-    #endif //PID_OPENLOOP
-    #ifdef PID_DEBUG
-    SERIAL_ECHO_START;
-    SERIAL_ECHO(" PID_DEBUG ");
-    SERIAL_ECHO(e);
-    SERIAL_ECHO(": Input ");
-    SERIAL_ECHO(pid_input);
-    SERIAL_ECHO(" Output ");
-    SERIAL_ECHO(pid_output);
-    SERIAL_ECHO(" pTerm ");
-    SERIAL_ECHO(pTerm[e]);
-    SERIAL_ECHO(" iTerm ");
-    SERIAL_ECHO(iTerm[e]);
-    SERIAL_ECHO(" dTerm ");
-    SERIAL_ECHOLN(dTerm[e]);
-    #endif //PID_DEBUG
-  #else /* PID off */
-    pid_output = 0;
-    if(current_temperature[e] < target_temperature[e]) {
-      pid_output = PID_MAX;
-    }
-  #endif
-
-    // Check if temperature is within the correct range
-    if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) 
-    {
-      soft_pwm[e] = (int)pid_output >> 1;
-    }
-    else {
-      soft_pwm[e] = 0;
-    }
-
-    #ifdef WATCH_TEMP_PERIOD
-    if(watchmillis[e] && millis() - watchmillis[e] > WATCH_TEMP_PERIOD)
-    {
-        if(degHotend(e) < watch_start_temp[e] + WATCH_TEMP_INCREASE)
-        {
-            setTargetHotend(0, e);
-            LCD_MESSAGEPGM("Heating failed");
-            SERIAL_ECHO_START;
-            SERIAL_ECHOLN("Heating failed");
-        }else{
-            watchmillis[e] = 0;
-        }
-    }
-    #endif
-    #ifdef TEMP_SENSOR_1_AS_REDUNDANT
-      if(fabs(current_temperature[0] - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF) {
-        disable_heater();
-        if(IsStopped() == false) {
-          SERIAL_ERROR_START;
-          SERIAL_ERRORLNPGM("Extruder switched off. Temperature difference between temp sensors is too high !");
-          LCD_ALERTMESSAGEPGM("Err: REDUNDANT TEMP ERROR");
-        }
-        #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
-          Stop();
-        #endif
-      }
-    #endif
-  } // End extruder for loop
-
-  #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
-      (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
-      (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
-  if(millis() - extruder_autofan_last_check > 2500)  // only need to check fan state very infrequently
-  {
-    checkExtruderAutoFans();
-    extruder_autofan_last_check = millis();
-  }  
-  #endif       
-  
-  #ifndef PIDTEMPBED
-  if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL)
-    return;
-  previous_millis_bed_heater = millis();
-  #endif
-
-  #if TEMP_SENSOR_BED != 0
-
-  #ifdef PIDTEMPBED
-    pid_input = current_temperature_bed;
-
-    #ifndef PID_OPENLOOP
-		  pid_error_bed = target_temperature_bed - pid_input;
-		  pTerm_bed = bedKp * pid_error_bed;
-		  temp_iState_bed += pid_error_bed;
-		  temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed);
-		  iTerm_bed = bedKi * temp_iState_bed;
-
-		  //K1 defined in Configuration.h in the PID settings
-		  #define K2 (1.0-K1)
-		  dTerm_bed= (bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed);
-		  temp_dState_bed = pid_input;
-
-		  pid_output = pTerm_bed + iTerm_bed - dTerm_bed;
-          	  if (pid_output > MAX_BED_POWER) {
-            	    if (pid_error_bed > 0 )  temp_iState_bed -= pid_error_bed; // conditional un-integration
-                    pid_output=MAX_BED_POWER;
-          	  } else if (pid_output < 0){
-            	    if (pid_error_bed < 0 )  temp_iState_bed -= pid_error_bed; // conditional un-integration
-                    pid_output=0;
-                  }
-
-    #else 
-      pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER);
-    #endif //PID_OPENLOOP
-
-	  if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) 
-	  {
-	    soft_pwm_bed = (int)pid_output >> 1;
-	  }
-	  else {
-	    soft_pwm_bed = 0;
-	  }
-
-    #elif !defined(BED_LIMIT_SWITCHING)
-      // Check if temperature is within the correct range
-      if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP))
-      {
-        if(current_temperature_bed >= target_temperature_bed)
-        {
-          soft_pwm_bed = 0;
-        }
-        else 
-        {
-          soft_pwm_bed = MAX_BED_POWER>>1;
-        }
-      }
-      else
-      {
-        soft_pwm_bed = 0;
-        WRITE(HEATER_BED_PIN,LOW);
-      }
-    #else //#ifdef BED_LIMIT_SWITCHING
-      // Check if temperature is within the correct band
-      if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP))
-      {
-        if(current_temperature_bed > target_temperature_bed + BED_HYSTERESIS)
-        {
-          soft_pwm_bed = 0;
-        }
-        else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS)
-        {
-          soft_pwm_bed = MAX_BED_POWER>>1;
-        }
-      }
-      else
-      {
-        soft_pwm_bed = 0;
-        WRITE(HEATER_BED_PIN,LOW);
-      }
-    #endif
-  #endif
-  
-//code for controlling the extruder rate based on the width sensor 
-#ifdef FILAMENT_SENSOR
-  if(filament_sensor) 
-	{
-	meas_shift_index=delay_index1-meas_delay_cm;
-		  if(meas_shift_index<0)
-			  meas_shift_index = meas_shift_index + (MAX_MEASUREMENT_DELAY+1);  //loop around buffer if needed
-		  
-		  //get the delayed info and add 100 to reconstitute to a percent of the nominal filament diameter
-		  //then square it to get an area
-		  
-		  if(meas_shift_index<0)
-			  meas_shift_index=0;
-		  else if (meas_shift_index>MAX_MEASUREMENT_DELAY)
-			  meas_shift_index=MAX_MEASUREMENT_DELAY;
-		  
-		     volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] = pow((float)(100+measurement_delay[meas_shift_index])/100.0,2);
-		     if (volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] <0.01)
-		    	 volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]=0.01;
-	}
-#endif
-}
-
-#define PGM_RD_W(x)   (short)pgm_read_word(&x)
-// Derived from RepRap FiveD extruder::getTemperature()
-// For hot end temperature measurement.
-static float analog2temp(int raw, uint8_t e) {
-#ifdef TEMP_SENSOR_1_AS_REDUNDANT
-  if(e > EXTRUDERS)
-#else
-  if(e >= EXTRUDERS)
-#endif
-  {
-      SERIAL_ERROR_START;
-      SERIAL_ERROR((int)e);
-      SERIAL_ERRORLNPGM(" - Invalid extruder number !");
-      kill();
-      return 0.0;
-  } 
-  #ifdef HEATER_0_USES_MAX6675
-    if (e == 0)
-    {
-      return 0.25 * raw;
-    }
-  #endif
-
-  if(heater_ttbl_map[e] != NULL)
-  {
-    float celsius = 0;
-    uint8_t i;
-    short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
-
-    for (i=1; i<heater_ttbllen_map[e]; i++)
-    {
-      if (PGM_RD_W((*tt)[i][0]) > raw)
-      {
-        celsius = PGM_RD_W((*tt)[i-1][1]) + 
-          (raw - PGM_RD_W((*tt)[i-1][0])) * 
-          (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) /
-          (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0]));
-        break;
-      }
-    }
-
-    // Overflow: Set to last value in the table
-    if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]);
-
-    return celsius;
-  }
-  return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
-}
-
-// Derived from RepRap FiveD extruder::getTemperature()
-// For bed temperature measurement.
-static float analog2tempBed(int raw) {
-  #ifdef BED_USES_THERMISTOR
-    float celsius = 0;
-    byte i;
-
-    for (i=1; i<BEDTEMPTABLE_LEN; i++)
-    {
-      if (PGM_RD_W(BEDTEMPTABLE[i][0]) > raw)
-      {
-        celsius  = PGM_RD_W(BEDTEMPTABLE[i-1][1]) + 
-          (raw - PGM_RD_W(BEDTEMPTABLE[i-1][0])) * 
-          (float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i-1][1])) /
-          (float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i-1][0]));
-        break;
-      }
-    }
-
-    // Overflow: Set to last value in the table
-    if (i == BEDTEMPTABLE_LEN) celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]);
-
-
-	// temperature offset adjustment
-#ifdef BED_OFFSET
-	float _offset = BED_OFFSET;
-	float _offset_center = BED_OFFSET_CENTER;
-	float _offset_start = BED_OFFSET_START;
-	float _first_koef = (_offset / 2) / (_offset_center - _offset_start);
-	float _second_koef = (_offset / 2) / (100 - _offset_center);
-
-
-	if (celsius >= _offset_start && celsius <= _offset_center)
-	{
-		celsius = celsius + (_first_koef * (celsius - _offset_start));
-	}
-	else if (celsius > _offset_center && celsius <= 100)
-	{
-		celsius = celsius + (_first_koef * (_offset_center - _offset_start)) + ( _second_koef * ( celsius - ( 100 - _offset_center ) )) ;
-	}
-	else if (celsius > 100)
-	{
-		celsius = celsius + _offset;
-	}
-#endif
-
-
-    return celsius;
-  #elif defined BED_USES_AD595
-    return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
-  #else
-    return 0;
-  #endif
-}
-
-/* Called to get the raw values into the the actual temperatures. The raw values are created in interrupt context,
-    and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */
-static void updateTemperaturesFromRawValues()
-{
-    for(uint8_t e=0;e<EXTRUDERS;e++)
-    {
-        current_temperature[e] = analog2temp(current_temperature_raw[e], e);
-    }
-    
-	current_temperature_bed = analog2tempBed(current_temperature_bed_raw);
-
-    #ifdef TEMP_SENSOR_1_AS_REDUNDANT
-      redundant_temperature = analog2temp(redundant_temperature_raw, 1);
-    #endif
-    #if defined (FILAMENT_SENSOR) && (FILWIDTH_PIN > -1)    //check if a sensor is supported 
-      filament_width_meas = analog2widthFil();
-    #endif  
-    //Reset the watchdog after we know we have a temperature measurement.
-    watchdog_reset();
-
-    CRITICAL_SECTION_START;
-    temp_meas_ready = false;
-    CRITICAL_SECTION_END;
-}
-
-
-// For converting raw Filament Width to milimeters 
-#ifdef FILAMENT_SENSOR
-float analog2widthFil() { 
-return current_raw_filwidth/16383.0*5.0; 
-//return current_raw_filwidth; 
-} 
- 
-// For converting raw Filament Width to a ratio 
-int widthFil_to_size_ratio() { 
- 
-float temp; 
-      
-temp=filament_width_meas;
-if(filament_width_meas<MEASURED_LOWER_LIMIT)
-	temp=filament_width_nominal;  //assume sensor cut out
-else if (filament_width_meas>MEASURED_UPPER_LIMIT)
-	temp= MEASURED_UPPER_LIMIT;
-
-
-return(filament_width_nominal/temp*100); 
-
-
-} 
-#endif
-
-
-
-
-
-void tp_init()
-{
-#if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1))
-  //disable RUMBA JTAG in case the thermocouple extension is plugged on top of JTAG connector
-  MCUCR=(1<<JTD); 
-  MCUCR=(1<<JTD);
-#endif
-  
-  // Finish init of mult extruder arrays 
-  for(int e = 0; e < EXTRUDERS; e++) {
-    // populate with the first value 
-    maxttemp[e] = maxttemp[0];
-#ifdef PIDTEMP
-    temp_iState_min[e] = 0.0;
-    temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
-#endif //PIDTEMP
-#ifdef PIDTEMPBED
-    temp_iState_min_bed = 0.0;
-    temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi;
-#endif //PIDTEMPBED
-  }
-
-  #if defined(HEATER_0_PIN) && (HEATER_0_PIN > -1) 
-    SET_OUTPUT(HEATER_0_PIN);
-  #endif  
-  #if defined(HEATER_1_PIN) && (HEATER_1_PIN > -1) 
-    SET_OUTPUT(HEATER_1_PIN);
-  #endif  
-  #if defined(HEATER_2_PIN) && (HEATER_2_PIN > -1) 
-    SET_OUTPUT(HEATER_2_PIN);
-  #endif  
-  #if defined(HEATER_BED_PIN) && (HEATER_BED_PIN > -1) 
-    SET_OUTPUT(HEATER_BED_PIN);
-  #endif  
-  #if defined(FAN_PIN) && (FAN_PIN > -1) 
-    SET_OUTPUT(FAN_PIN);
-    #ifdef FAST_PWM_FAN
-    setPwmFrequency(FAN_PIN, 1); // No prescaling. Pwm frequency = F_CPU/256/8
-    #endif
-    #ifdef FAN_SOFT_PWM
-    soft_pwm_fan = fanSpeedSoftPwm / 2;
-    #endif
-  #endif  
-
-  #ifdef HEATER_0_USES_MAX6675
-    #ifndef SDSUPPORT
-      SET_OUTPUT(SCK_PIN);
-      WRITE(SCK_PIN,0);
-    
-      SET_OUTPUT(MOSI_PIN);
-      WRITE(MOSI_PIN,1);
-    
-      SET_INPUT(MISO_PIN);
-      WRITE(MISO_PIN,1);
-    #endif
-    /* Using pinMode and digitalWrite, as that was the only way I could get it to compile */
-    
-    //Have to toggle SD card CS pin to low first, to enable firmware to talk with SD card
-	pinMode(SS_PIN, OUTPUT);
-	digitalWrite(SS_PIN,0);  
-	pinMode(MAX6675_SS, OUTPUT);
-	digitalWrite(MAX6675_SS,1);
-  #endif
-
-  // Set analog inputs
-  ADCSRA = 1<<ADEN | 1<<ADSC | 1<<ADIF | 0x07;
-  DIDR0 = 0;
-  #ifdef DIDR2
-    DIDR2 = 0;
-  #endif
-  #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1)
-    #if TEMP_0_PIN < 8
-       DIDR0 |= 1 << TEMP_0_PIN; 
-    #else
-       DIDR2 |= 1<<(TEMP_0_PIN - 8); 
-    #endif
-  #endif
-  #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1)
-    #if TEMP_1_PIN < 8
-       DIDR0 |= 1<<TEMP_1_PIN; 
-    #else
-       DIDR2 |= 1<<(TEMP_1_PIN - 8); 
-    #endif
-  #endif
-  #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
-    #if TEMP_2_PIN < 8
-       DIDR0 |= 1 << TEMP_2_PIN; 
-    #else
-       DIDR2 |= 1<<(TEMP_2_PIN - 8); 
-    #endif
-  #endif
-  #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1)
-    #if TEMP_BED_PIN < 8
-       DIDR0 |= 1<<TEMP_BED_PIN; 
-    #else
-       DIDR2 |= 1<<(TEMP_BED_PIN - 8); 
-    #endif
-  #endif
-  
-  //Added for Filament Sensor 
-  #ifdef FILAMENT_SENSOR
-   #if defined(FILWIDTH_PIN) && (FILWIDTH_PIN > -1) 
-	#if FILWIDTH_PIN < 8 
-       	   DIDR0 |= 1<<FILWIDTH_PIN;  
-	#else 
-       	   DIDR2 |= 1<<(FILWIDTH_PIN - 8);  
-	#endif 
-   #endif
-  #endif
-  
-  // Use timer0 for temperature measurement
-  // Interleave temperature interrupt with millies interrupt
-  OCR0B = 128;
-  TIMSK0 |= (1<<OCIE0B);  
-  
-  // Wait for temperature measurement to settle
-  delay(250);
-
-#ifdef HEATER_0_MINTEMP
-  minttemp[0] = HEATER_0_MINTEMP;
-  while(analog2temp(minttemp_raw[0], 0) < HEATER_0_MINTEMP) {
-#if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP
-    minttemp_raw[0] += OVERSAMPLENR;
-#else
-    minttemp_raw[0] -= OVERSAMPLENR;
-#endif
-  }
-#endif //MINTEMP
-#ifdef HEATER_0_MAXTEMP
-  maxttemp[0] = HEATER_0_MAXTEMP;
-  while(analog2temp(maxttemp_raw[0], 0) > HEATER_0_MAXTEMP) {
-#if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP
-    maxttemp_raw[0] -= OVERSAMPLENR;
-#else
-    maxttemp_raw[0] += OVERSAMPLENR;
-#endif
-  }
-#endif //MAXTEMP
-
-#if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP)
-  minttemp[1] = HEATER_1_MINTEMP;
-  while(analog2temp(minttemp_raw[1], 1) < HEATER_1_MINTEMP) {
-#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP
-    minttemp_raw[1] += OVERSAMPLENR;
-#else
-    minttemp_raw[1] -= OVERSAMPLENR;
-#endif
-  }
-#endif // MINTEMP 1
-#if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP)
-  maxttemp[1] = HEATER_1_MAXTEMP;
-  while(analog2temp(maxttemp_raw[1], 1) > HEATER_1_MAXTEMP) {
-#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP
-    maxttemp_raw[1] -= OVERSAMPLENR;
-#else
-    maxttemp_raw[1] += OVERSAMPLENR;
-#endif
-  }
-#endif //MAXTEMP 1
-
-#if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP)
-  minttemp[2] = HEATER_2_MINTEMP;
-  while(analog2temp(minttemp_raw[2], 2) < HEATER_2_MINTEMP) {
-#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP
-    minttemp_raw[2] += OVERSAMPLENR;
-#else
-    minttemp_raw[2] -= OVERSAMPLENR;
-#endif
-  }
-#endif //MINTEMP 2
-#if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP)
-  maxttemp[2] = HEATER_2_MAXTEMP;
-  while(analog2temp(maxttemp_raw[2], 2) > HEATER_2_MAXTEMP) {
-#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP
-    maxttemp_raw[2] -= OVERSAMPLENR;
-#else
-    maxttemp_raw[2] += OVERSAMPLENR;
-#endif
-  }
-#endif //MAXTEMP 2
-
-#ifdef BED_MINTEMP
-  /* No bed MINTEMP error implemented?!? */ /*
-  while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) {
-#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP
-    bed_minttemp_raw += OVERSAMPLENR;
-#else
-    bed_minttemp_raw -= OVERSAMPLENR;
-#endif
-  }
-  */
-#endif //BED_MINTEMP
-#ifdef BED_MAXTEMP
-  while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) {
-#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP
-    bed_maxttemp_raw -= OVERSAMPLENR;
-#else
-    bed_maxttemp_raw += OVERSAMPLENR;
-#endif
-  }
-#endif //BED_MAXTEMP
-}
-
-void setWatch() 
-{  
-#ifdef WATCH_TEMP_PERIOD
-  for (int e = 0; e < EXTRUDERS; e++)
-  {
-    if(degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE * 2))
-    {
-      watch_start_temp[e] = degHotend(e);
-      watchmillis[e] = millis();
-    } 
-  }
-#endif 
-}
-
-#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0)
-void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed)
-{
-	float __hysteresis = 0;
-	int __timeout = 0;
-	bool temp_runaway_check_active = false;
-
-	_heater_id = (_isbed) ? _heater_id++ : _heater_id;
-
-#ifdef 	TEMP_RUNAWAY_BED_TIMEOUT
-	if (_isbed)
-	{
-		__hysteresis = TEMP_RUNAWAY_BED_HYSTERESIS;
-		__timeout = TEMP_RUNAWAY_BED_TIMEOUT;
-	}
-#endif
-#ifdef 	TEMP_RUNAWAY_EXTRUDER_TIMEOUT
-	if (!_isbed)
-	{
-		__hysteresis = TEMP_RUNAWAY_EXTRUDER_HYSTERESIS;
-		__timeout = TEMP_RUNAWAY_EXTRUDER_TIMEOUT;
-	}
-#endif
-
-	if (millis() - temp_runaway_timer[_heater_id] > 2000)
-	{
-		temp_runaway_timer[_heater_id] = millis();
-
-		if (_output == 0)
-		{
-			temp_runaway_check_active = false;
-			temp_runaway_error_counter[_heater_id] = 0;
-		}
-
-		if (temp_runaway_target[_heater_id] != _target_temperature)
-		{
-			if (_target_temperature > 0)
-			{
-				temp_runaway_status[_heater_id] = 1;
-				temp_runaway_target[_heater_id] = _target_temperature;
-			}
-			else
-			{
-				temp_runaway_status[_heater_id] = 0;
-				temp_runaway_target[_heater_id] = _target_temperature;
-			}
-		}
-
-		if (_current_temperature >= _target_temperature  && temp_runaway_status[_heater_id] == 1)
-		{
-			temp_runaway_status[_heater_id] = 2;
-			temp_runaway_check_active = false;
-		}
-
-		if (!temp_runaway_check_active && _output > 0)
-		{
-			temp_runaway_check_active = true;
-		}
-
-
-		if (temp_runaway_check_active)
-		{
-			//	we are in range
-			if (_target_temperature - __hysteresis < _current_temperature && _current_temperature < _target_temperature + __hysteresis)
-			{
-				temp_runaway_check_active = false;
-			}
-			else
-			{
-				if (temp_runaway_status[_heater_id] > 1)
-				{
-					temp_runaway_error_counter[_heater_id]++;
-
-					if (temp_runaway_error_counter[_heater_id] * 2 > __timeout)
-					{
-						temp_runaway_stop();
-					}
-				}
-			}
-		}
-
-	}
-}
-
-void temp_runaway_stop()
-{
-	cancel_heatup = true;
-	quickStop();
-	if (card.sdprinting)
-	{
-		card.sdprinting = false;
-		card.closefile();
-	}
-	LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY");
-	disable_heater();
-	disable_x();
-	disable_y();
-	disable_e0();
-	disable_e1();
-	disable_e2();
-	manage_heater();
-	lcd_update();
-	WRITE(BEEPER, HIGH);
-	delayMicroseconds(500);
-	WRITE(BEEPER, LOW);
-	delayMicroseconds(100);
-}
-#endif
-
-
-void disable_heater()
-{
-  for(int i=0;i<EXTRUDERS;i++)
-    setTargetHotend(0,i);
-  setTargetBed(0);
-  #if defined(TEMP_0_PIN) && TEMP_0_PIN > -1
-  target_temperature[0]=0;
-  soft_pwm[0]=0;
-   #if defined(HEATER_0_PIN) && HEATER_0_PIN > -1  
-     WRITE(HEATER_0_PIN,LOW);
-   #endif
-  #endif
-     
-  #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 && EXTRUDERS > 1
-    target_temperature[1]=0;
-    soft_pwm[1]=0;
-    #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 
-      WRITE(HEATER_1_PIN,LOW);
-    #endif
-  #endif
-      
-  #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 && EXTRUDERS > 2
-    target_temperature[2]=0;
-    soft_pwm[2]=0;
-    #if defined(HEATER_2_PIN) && HEATER_2_PIN > -1  
-      WRITE(HEATER_2_PIN,LOW);
-    #endif
-  #endif 
-
-  #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1
-    target_temperature_bed=0;
-    soft_pwm_bed=0;
-    #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1  
-      WRITE(HEATER_BED_PIN,LOW);
-    #endif
-  #endif 
-}
-
-void max_temp_error(uint8_t e) {
-  disable_heater();
-  if(IsStopped() == false) {
-    SERIAL_ERROR_START;
-    SERIAL_ERRORLN((int)e);
-    SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !");
-    LCD_ALERTMESSAGEPGM("Err: MAXTEMP");
-  }
-  #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
-  Stop();
-  #endif
-}
-
-void min_temp_error(uint8_t e) {
-  disable_heater();
-  if(IsStopped() == false) {
-    SERIAL_ERROR_START;
-    SERIAL_ERRORLN((int)e);
-    SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
-    LCD_ALERTMESSAGEPGM("Err: MINTEMP");
-  }
-  #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
-  Stop();
-  #endif
-}
-
-void bed_max_temp_error(void) {
-#if HEATER_BED_PIN > -1
-  WRITE(HEATER_BED_PIN, 0);
-#endif
-  if(IsStopped() == false) {
-    SERIAL_ERROR_START;
-    SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !");
-    LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED");
-  }
-  #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
-  Stop();
-  #endif
-}
-
-#ifdef HEATER_0_USES_MAX6675
-#define MAX6675_HEAT_INTERVAL 250
-long max6675_previous_millis = MAX6675_HEAT_INTERVAL;
-int max6675_temp = 2000;
-
-int read_max6675()
-{
-  if (millis() - max6675_previous_millis < MAX6675_HEAT_INTERVAL) 
-    return max6675_temp;
-  
-  max6675_previous_millis = millis();
-  max6675_temp = 0;
-    
-  #ifdef	PRR
-    PRR &= ~(1<<PRSPI);
-  #elif defined PRR0
-    PRR0 &= ~(1<<PRSPI);
-  #endif
-  
-  SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0);
-  
-  // enable TT_MAX6675
-  WRITE(MAX6675_SS, 0);
-  
-  // ensure 100ns delay - a bit extra is fine
-  asm("nop");//50ns on 20Mhz, 62.5ns on 16Mhz
-  asm("nop");//50ns on 20Mhz, 62.5ns on 16Mhz
-  
-  // read MSB
-  SPDR = 0;
-  for (;(SPSR & (1<<SPIF)) == 0;);
-  max6675_temp = SPDR;
-  max6675_temp <<= 8;
-  
-  // read LSB
-  SPDR = 0;
-  for (;(SPSR & (1<<SPIF)) == 0;);
-  max6675_temp |= SPDR;
-  
-  // disable TT_MAX6675
-  WRITE(MAX6675_SS, 1);
-
-  if (max6675_temp & 4) 
-  {
-    // thermocouple open
-    max6675_temp = 2000;
-  }
-  else 
-  {
-    max6675_temp = max6675_temp >> 3;
-  }
-
-  return max6675_temp;
-}
-#endif
-
-
-// Timer 0 is shared with millies
-ISR(TIMER0_COMPB_vect)
-{
-  //these variables are only accesible from the ISR, but static, so they don't lose their value
-  static unsigned char temp_count = 0;
-  static unsigned long raw_temp_0_value = 0;
-  static unsigned long raw_temp_1_value = 0;
-  static unsigned long raw_temp_2_value = 0;
-  static unsigned long raw_temp_bed_value = 0;
-  static unsigned char temp_state = 10;
-  static unsigned char pwm_count = (1 << SOFT_PWM_SCALE);
-  static unsigned char soft_pwm_0;
-#ifdef SLOW_PWM_HEATERS
-  static unsigned char slow_pwm_count = 0;
-  static unsigned char state_heater_0 = 0;
-  static unsigned char state_timer_heater_0 = 0;
-#endif 
-#if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL)
-  static unsigned char soft_pwm_1;
-#ifdef SLOW_PWM_HEATERS
-  static unsigned char state_heater_1 = 0;
-  static unsigned char state_timer_heater_1 = 0;
-#endif 
-#endif
-#if EXTRUDERS > 2
-  static unsigned char soft_pwm_2;
-#ifdef SLOW_PWM_HEATERS
-  static unsigned char state_heater_2 = 0;
-  static unsigned char state_timer_heater_2 = 0;
-#endif 
-#endif
-#if HEATER_BED_PIN > -1
-  static unsigned char soft_pwm_b;
-#ifdef SLOW_PWM_HEATERS
-  static unsigned char state_heater_b = 0;
-  static unsigned char state_timer_heater_b = 0;
-#endif 
-#endif
-  
-#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
-  static unsigned long raw_filwidth_value = 0;  //added for filament width sensor
-#endif
-  
-#ifndef SLOW_PWM_HEATERS
-  /*
-   * standard PWM modulation
-   */
-  if(pwm_count == 0){
-    soft_pwm_0 = soft_pwm[0];
-    if(soft_pwm_0 > 0) { 
-      WRITE(HEATER_0_PIN,1);
-#ifdef HEATERS_PARALLEL
-      WRITE(HEATER_1_PIN,1);
-#endif
-    } else WRITE(HEATER_0_PIN,0);
-    
-#if EXTRUDERS > 1
-    soft_pwm_1 = soft_pwm[1];
-    if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); else WRITE(HEATER_1_PIN,0);
-#endif
-#if EXTRUDERS > 2
-    soft_pwm_2 = soft_pwm[2];
-    if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); else WRITE(HEATER_2_PIN,0);
-#endif
-#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
-    soft_pwm_b = soft_pwm_bed;
-    if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0);
-#endif
-#ifdef FAN_SOFT_PWM
-    soft_pwm_fan = fanSpeedSoftPwm / 2;
-    if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0);
-#endif
-  }
-  if(soft_pwm_0 < pwm_count) { 
-    WRITE(HEATER_0_PIN,0);
-#ifdef HEATERS_PARALLEL
-    WRITE(HEATER_1_PIN,0);
-#endif
-  }
-#if EXTRUDERS > 1
-  if(soft_pwm_1 < pwm_count) WRITE(HEATER_1_PIN,0);
-#endif
-#if EXTRUDERS > 2
-  if(soft_pwm_2 < pwm_count) WRITE(HEATER_2_PIN,0);
-#endif
-#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
-  if(soft_pwm_b < pwm_count) WRITE(HEATER_BED_PIN,0);
-#endif
-#ifdef FAN_SOFT_PWM
-  if(soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0);
-#endif
-  
-  pwm_count += (1 << SOFT_PWM_SCALE);
-  pwm_count &= 0x7f;
-  
-#else //ifndef SLOW_PWM_HEATERS
-  /*
-   * SLOW PWM HEATERS
-   *
-   * for heaters drived by relay
-   */
-#ifndef MIN_STATE_TIME
-#define MIN_STATE_TIME 16 // MIN_STATE_TIME * 65.5 = time in milliseconds
-#endif
-  if (slow_pwm_count == 0) {
-    // EXTRUDER 0 
-    soft_pwm_0 = soft_pwm[0];
-    if (soft_pwm_0 > 0) {
-      // turn ON heather only if the minimum time is up 
-      if (state_timer_heater_0 == 0) { 
-	// if change state set timer 
-	if (state_heater_0 == 0) {
-	  state_timer_heater_0 = MIN_STATE_TIME;
-	}
-	state_heater_0 = 1;
-	WRITE(HEATER_0_PIN, 1);
-#ifdef HEATERS_PARALLEL
-	WRITE(HEATER_1_PIN, 1);
-#endif
-      }
-    } else {
-      // turn OFF heather only if the minimum time is up 
-      if (state_timer_heater_0 == 0) {
-	// if change state set timer 
-	if (state_heater_0 == 1) {
-	  state_timer_heater_0 = MIN_STATE_TIME;
-	}
-	state_heater_0 = 0;
-	WRITE(HEATER_0_PIN, 0);
-#ifdef HEATERS_PARALLEL
-	WRITE(HEATER_1_PIN, 0);
-#endif
-      }
-    }
-    
-#if EXTRUDERS > 1
-    // EXTRUDER 1
-    soft_pwm_1 = soft_pwm[1];
-    if (soft_pwm_1 > 0) {
-      // turn ON heather only if the minimum time is up 
-      if (state_timer_heater_1 == 0) { 
-	// if change state set timer 
-	if (state_heater_1 == 0) {
-	  state_timer_heater_1 = MIN_STATE_TIME;
-	}
-	state_heater_1 = 1;
-	WRITE(HEATER_1_PIN, 1);
-      }
-    } else {
-      // turn OFF heather only if the minimum time is up 
-      if (state_timer_heater_1 == 0) {
-	// if change state set timer 
-	if (state_heater_1 == 1) {
-	  state_timer_heater_1 = MIN_STATE_TIME;
-	}
-	state_heater_1 = 0;
-	WRITE(HEATER_1_PIN, 0);
-      }
-    }
-#endif
-    
-#if EXTRUDERS > 2
-    // EXTRUDER 2
-    soft_pwm_2 = soft_pwm[2];
-    if (soft_pwm_2 > 0) {
-      // turn ON heather only if the minimum time is up 
-      if (state_timer_heater_2 == 0) { 
-	// if change state set timer 
-	if (state_heater_2 == 0) {
-	  state_timer_heater_2 = MIN_STATE_TIME;
-	}
-	state_heater_2 = 1;
-	WRITE(HEATER_2_PIN, 1);
-      }
-    } else {
-      // turn OFF heather only if the minimum time is up 
-      if (state_timer_heater_2 == 0) {
-	// if change state set timer 
-	if (state_heater_2 == 1) {
-	  state_timer_heater_2 = MIN_STATE_TIME;
-	}
-	state_heater_2 = 0;
-	WRITE(HEATER_2_PIN, 0);
-      }
-    }
-#endif
-    
-#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
-    // BED
-    soft_pwm_b = soft_pwm_bed;
-    if (soft_pwm_b > 0) {
-      // turn ON heather only if the minimum time is up 
-      if (state_timer_heater_b == 0) { 
-	// if change state set timer 
-	if (state_heater_b == 0) {
-	  state_timer_heater_b = MIN_STATE_TIME;
-	}
-	state_heater_b = 1;
-	WRITE(HEATER_BED_PIN, 1);
-      }
-    } else {
-      // turn OFF heather only if the minimum time is up 
-      if (state_timer_heater_b == 0) {
-	// if change state set timer 
-	if (state_heater_b == 1) {
-	  state_timer_heater_b = MIN_STATE_TIME;
-	}
-	state_heater_b = 0;
-	WRITE(HEATER_BED_PIN, 0);
-      }
-    }
-#endif
-  } // if (slow_pwm_count == 0)
-  
-  // EXTRUDER 0 
-  if (soft_pwm_0 < slow_pwm_count) {
-    // turn OFF heather only if the minimum time is up 
-    if (state_timer_heater_0 == 0) { 
-      // if change state set timer 
-      if (state_heater_0 == 1) {
-	state_timer_heater_0 = MIN_STATE_TIME;
-      }
-      state_heater_0 = 0;
-      WRITE(HEATER_0_PIN, 0);
-#ifdef HEATERS_PARALLEL
-      WRITE(HEATER_1_PIN, 0);
-#endif
-    }
-  }
-    
-#if EXTRUDERS > 1
-  // EXTRUDER 1 
-  if (soft_pwm_1 < slow_pwm_count) {
-    // turn OFF heather only if the minimum time is up 
-    if (state_timer_heater_1 == 0) { 
-      // if change state set timer 
-      if (state_heater_1 == 1) {
-	state_timer_heater_1 = MIN_STATE_TIME;
-      }
-      state_heater_1 = 0;
-      WRITE(HEATER_1_PIN, 0);
-    }
-  }
-#endif
-  
-#if EXTRUDERS > 2
-  // EXTRUDER 2
-  if (soft_pwm_2 < slow_pwm_count) {
-    // turn OFF heather only if the minimum time is up 
-    if (state_timer_heater_2 == 0) { 
-      // if change state set timer 
-      if (state_heater_2 == 1) {
-	state_timer_heater_2 = MIN_STATE_TIME;
-      }
-      state_heater_2 = 0;
-      WRITE(HEATER_2_PIN, 0);
-    }
-  }
-#endif
-  
-#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
-  // BED
-  if (soft_pwm_b < slow_pwm_count) {
-    // turn OFF heather only if the minimum time is up 
-    if (state_timer_heater_b == 0) { 
-      // if change state set timer 
-      if (state_heater_b == 1) {
-	state_timer_heater_b = MIN_STATE_TIME;
-      }
-      state_heater_b = 0;
-      WRITE(HEATER_BED_PIN, 0);
-    }
-  }
-#endif
-  
-#ifdef FAN_SOFT_PWM
-  if (pwm_count == 0){
-    soft_pwm_fan = fanSpeedSoftPwm / 2;
-    if (soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0);
-  }
-  if (soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0);
-#endif
-  
-  pwm_count += (1 << SOFT_PWM_SCALE);
-  pwm_count &= 0x7f;
-  
-  // increment slow_pwm_count only every 64 pwm_count circa 65.5ms
-  if ((pwm_count % 64) == 0) {
-    slow_pwm_count++;
-    slow_pwm_count &= 0x7f;
-    
-    // Extruder 0
-    if (state_timer_heater_0 > 0) {
-      state_timer_heater_0--;
-    } 
-  
-#if EXTRUDERS > 1
-    // Extruder 1
-    if (state_timer_heater_1 > 0) 
-      state_timer_heater_1--;
-#endif
-    
-#if EXTRUDERS > 2
-    // Extruder 2
-    if (state_timer_heater_2 > 0) 
-      state_timer_heater_2--;
-#endif
-    
-#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
-    // Bed   
-    if (state_timer_heater_b > 0) 
-      state_timer_heater_b--;
-#endif
-  } //if ((pwm_count % 64) == 0) {
-  
-#endif //ifndef SLOW_PWM_HEATERS
-  
-  switch(temp_state) {
-    case 0: // Prepare TEMP_0
-      #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1)
-        #if TEMP_0_PIN > 7
-          ADCSRB = 1<<MUX5;
-        #else
-          ADCSRB = 0;
-        #endif
-        ADMUX = ((1 << REFS0) | (TEMP_0_PIN & 0x07));
-        ADCSRA |= 1<<ADSC; // Start conversion
-      #endif
-      lcd_buttons_update();
-      temp_state = 1;
-      break;
-    case 1: // Measure TEMP_0
-      #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1)
-        raw_temp_0_value += ADC;
-      #endif
-      #ifdef HEATER_0_USES_MAX6675 // TODO remove the blocking
-        raw_temp_0_value = read_max6675();
-      #endif
-      temp_state = 2;
-      break;
-    case 2: // Prepare TEMP_BED
-      #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1)
-        #if TEMP_BED_PIN > 7
-          ADCSRB = 1<<MUX5;
-        #else
-          ADCSRB = 0;
-        #endif
-        ADMUX = ((1 << REFS0) | (TEMP_BED_PIN & 0x07));
-        ADCSRA |= 1<<ADSC; // Start conversion
-      #endif
-      lcd_buttons_update();
-      temp_state = 3;
-      break;
-    case 3: // Measure TEMP_BED
-      #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1)
-        raw_temp_bed_value += ADC;
-      #endif
-      temp_state = 4;
-      break;
-    case 4: // Prepare TEMP_1
-      #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1)
-        #if TEMP_1_PIN > 7
-          ADCSRB = 1<<MUX5;
-        #else
-          ADCSRB = 0;
-        #endif
-        ADMUX = ((1 << REFS0) | (TEMP_1_PIN & 0x07));
-        ADCSRA |= 1<<ADSC; // Start conversion
-      #endif
-      lcd_buttons_update();
-      temp_state = 5;
-      break;
-    case 5: // Measure TEMP_1
-      #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1)
-        raw_temp_1_value += ADC;
-      #endif
-      temp_state = 6;
-      break;
-    case 6: // Prepare TEMP_2
-      #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
-        #if TEMP_2_PIN > 7
-          ADCSRB = 1<<MUX5;
-        #else
-          ADCSRB = 0;
-        #endif
-        ADMUX = ((1 << REFS0) | (TEMP_2_PIN & 0x07));
-        ADCSRA |= 1<<ADSC; // Start conversion
-      #endif
-      lcd_buttons_update();
-      temp_state = 7;
-      break;
-    case 7: // Measure TEMP_2
-      #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
-        raw_temp_2_value += ADC;
-      #endif
-      temp_state = 8;//change so that Filament Width is also measured
-      
-      break;
-    case 8: //Prepare FILWIDTH 
-     #if defined(FILWIDTH_PIN) && (FILWIDTH_PIN> -1) 
-      #if FILWIDTH_PIN>7 
-         ADCSRB = 1<<MUX5;
-      #else
-         ADCSRB = 0; 
-      #endif 
-      ADMUX = ((1 << REFS0) | (FILWIDTH_PIN & 0x07)); 
-      ADCSRA |= 1<<ADSC; // Start conversion 
-     #endif 
-     lcd_buttons_update();       
-     temp_state = 9; 
-     break; 
-    case 9:   //Measure FILWIDTH 
-     #if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1) 
-     //raw_filwidth_value += ADC;  //remove to use an IIR filter approach 
-      if(ADC>102)  //check that ADC is reading a voltage > 0.5 volts, otherwise don't take in the data.
-        {
-    	raw_filwidth_value= raw_filwidth_value-(raw_filwidth_value>>7);  //multipliy raw_filwidth_value by 127/128
-        
-        raw_filwidth_value= raw_filwidth_value + ((unsigned long)ADC<<7);  //add new ADC reading 
-        }
-     #endif 
-     temp_state = 0;   
-      
-     temp_count++;
-     break;      
-      
-      
-    case 10: //Startup, delay initial temp reading a tiny bit so the hardware can settle.
-      temp_state = 0;
-      break;
-//    default:
-//      SERIAL_ERROR_START;
-//      SERIAL_ERRORLNPGM("Temp measurement error!");
-//      break;
-  }
-    
-  if(temp_count >= OVERSAMPLENR) // 10 * 16 * 1/(16000000/64/256)  = 164ms.
-  {
-    if (!temp_meas_ready) //Only update the raw values if they have been read. Else we could be updating them during reading.
-    {
-      current_temperature_raw[0] = raw_temp_0_value;
-#if EXTRUDERS > 1
-      current_temperature_raw[1] = raw_temp_1_value;
-#endif
-#ifdef TEMP_SENSOR_1_AS_REDUNDANT
-      redundant_temperature_raw = raw_temp_1_value;
-#endif
-#if EXTRUDERS > 2
-      current_temperature_raw[2] = raw_temp_2_value;
-#endif
-      current_temperature_bed_raw = raw_temp_bed_value;
-    }
-
-//Add similar code for Filament Sensor - can be read any time since IIR filtering is used 
-#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
-  current_raw_filwidth = raw_filwidth_value>>10;  //need to divide to get to 0-16384 range since we used 1/128 IIR filter approach 
-#endif
-    
-    
-    temp_meas_ready = true;
-    temp_count = 0;
-    raw_temp_0_value = 0;
-    raw_temp_1_value = 0;
-    raw_temp_2_value = 0;
-    raw_temp_bed_value = 0;
-
-#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP
-    if(current_temperature_raw[0] <= maxttemp_raw[0]) {
-#else
-    if(current_temperature_raw[0] >= maxttemp_raw[0]) {
-#endif
-        max_temp_error(0);
-    }
-#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP
-    if(current_temperature_raw[0] >= minttemp_raw[0]) {
-#else
-    if(current_temperature_raw[0] <= minttemp_raw[0]) {
-#endif
-        min_temp_error(0);
-    }
-#if EXTRUDERS > 1
-#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP
-    if(current_temperature_raw[1] <= maxttemp_raw[1]) {
-#else
-    if(current_temperature_raw[1] >= maxttemp_raw[1]) {
-#endif
-        max_temp_error(1);
-    }
-#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP
-    if(current_temperature_raw[1] >= minttemp_raw[1]) {
-#else
-    if(current_temperature_raw[1] <= minttemp_raw[1]) {
-#endif
-        min_temp_error(1);
-    }
-#endif
-#if EXTRUDERS > 2
-#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP
-    if(current_temperature_raw[2] <= maxttemp_raw[2]) {
-#else
-    if(current_temperature_raw[2] >= maxttemp_raw[2]) {
-#endif
-        max_temp_error(2);
-    }
-#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP
-    if(current_temperature_raw[2] >= minttemp_raw[2]) {
-#else
-    if(current_temperature_raw[2] <= minttemp_raw[2]) {
-#endif
-        min_temp_error(2);
-    }
-#endif
-  
-  /* No bed MINTEMP error? */
-#if defined(BED_MAXTEMP) && (TEMP_SENSOR_BED != 0)
-# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP
-    if(current_temperature_bed_raw <= bed_maxttemp_raw) {
-#else
-    if(current_temperature_bed_raw >= bed_maxttemp_raw) {
-#endif
-       target_temperature_bed = 0;
-       bed_max_temp_error();
-    }
-#endif
-  }
-  
-#ifdef BABYSTEPPING
-  for(uint8_t axis=0;axis<3;axis++)
-  {
-    int curTodo=babystepsTodo[axis]; //get rid of volatile for performance
-   
-    if(curTodo>0)
-    {
-      babystep(axis,/*fwd*/true);
-      babystepsTodo[axis]--; //less to do next time
-    }
-    else
-    if(curTodo<0)
-    {
-      babystep(axis,/*fwd*/false);
-      babystepsTodo[axis]++; //less to do next time
-    }
-  }
-#endif //BABYSTEPPING
-}
-
-#ifdef PIDTEMP
-// Apply the scale factors to the PID values
-
-
-float scalePID_i(float i)
-{
-	return i*PID_dT;
-}
-
-float unscalePID_i(float i)
-{
-	return i/PID_dT;
-}
-
-float scalePID_d(float d)
-{
-    return d/PID_dT;
-}
-
-float unscalePID_d(float d)
-{
-	return d*PID_dT;
-}
-
-#endif //PIDTEMP
-
-
+/*
+  temperature.c - temperature control
+  Part of Marlin
+  
+ Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ 
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ 
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ This firmware is a mashup between Sprinter and grbl.
+  (https://github.com/kliment/Sprinter)
+  (https://github.com/simen/grbl/tree)
+ 
+ It has preliminary support for Matthew Roberts advance algorithm 
+    http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
+
+ */
+
+
+#include "Marlin.h"
+#include "ultralcd.h"
+#include "temperature.h"
+#include "watchdog.h"
+#include "cardreader.h"
+
+#include "Sd2PinMap.h"
+
+#include <avr/wdt.h>
+
+
+//===========================================================================
+//=============================public variables============================
+//===========================================================================
+int target_temperature[EXTRUDERS] = { 0 };
+int target_temperature_bed = 0;
+int current_temperature_raw[EXTRUDERS] = { 0 };
+float current_temperature[EXTRUDERS] = { 0.0 };
+
+#ifdef PINDA_THERMISTOR
+int current_temperature_raw_pinda =  0 ;
+float current_temperature_pinda = 0.0;
+#endif //PINDA_THERMISTOR
+
+#ifdef AMBIENT_THERMISTOR
+int current_temperature_raw_ambient =  0 ;
+float current_temperature_ambient = 0.0;
+#endif //AMBIENT_THERMISTOR
+
+int current_temperature_bed_raw = 0;
+float current_temperature_bed = 0.0;
+#ifdef TEMP_SENSOR_1_AS_REDUNDANT
+  int redundant_temperature_raw = 0;
+  float redundant_temperature = 0.0;
+#endif
+  
+
+#ifdef PIDTEMP
+  float _Kp, _Ki, _Kd;
+  int pid_cycle, pid_number_of_cycles;
+  bool pid_tuning_finished = false;
+  float Kp=DEFAULT_Kp;
+  float Ki=(DEFAULT_Ki*PID_dT);
+  float Kd=(DEFAULT_Kd/PID_dT);
+  #ifdef PID_ADD_EXTRUSION_RATE
+    float Kc=DEFAULT_Kc;
+  #endif
+#endif //PIDTEMP
+
+#ifdef PIDTEMPBED
+  float bedKp=DEFAULT_bedKp;
+  float bedKi=(DEFAULT_bedKi*PID_dT);
+  float bedKd=(DEFAULT_bedKd/PID_dT);
+#endif //PIDTEMPBED
+  
+#ifdef FAN_SOFT_PWM
+  unsigned char fanSpeedSoftPwm;
+#endif
+
+#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+  unsigned char lcdSoftPwm = (LCD_PWM_MAX * 2 + 1); //set default value to maximum
+  unsigned char lcdBlinkDelay = 0; //lcd blinking delay (0 = no blink)
+#endif
+
+unsigned char soft_pwm_bed;
+
+#ifdef BABYSTEPPING
+  volatile int babystepsTodo[3]={0,0,0};
+#endif
+
+#ifdef FILAMENT_SENSOR
+  int current_raw_filwidth = 0;  //Holds measured filament diameter - one extruder only
+#endif  
+//===========================================================================
+//=============================private variables============================
+//===========================================================================
+static volatile bool temp_meas_ready = false;
+
+#ifdef PIDTEMP
+  //static cannot be external:
+  static float temp_iState[EXTRUDERS] = { 0 };
+  static float temp_dState[EXTRUDERS] = { 0 };
+  static float pTerm[EXTRUDERS];
+  static float iTerm[EXTRUDERS];
+  static float dTerm[EXTRUDERS];
+  //int output;
+  static float pid_error[EXTRUDERS];
+  static float temp_iState_min[EXTRUDERS];
+  static float temp_iState_max[EXTRUDERS];
+  // static float pid_input[EXTRUDERS];
+  // static float pid_output[EXTRUDERS];
+  static bool pid_reset[EXTRUDERS];
+#endif //PIDTEMP
+#ifdef PIDTEMPBED
+  //static cannot be external:
+  static float temp_iState_bed = { 0 };
+  static float temp_dState_bed = { 0 };
+  static float pTerm_bed;
+  static float iTerm_bed;
+  static float dTerm_bed;
+  //int output;
+  static float pid_error_bed;
+  static float temp_iState_min_bed;
+  static float temp_iState_max_bed;
+#else //PIDTEMPBED
+	static unsigned long  previous_millis_bed_heater;
+#endif //PIDTEMPBED
+  static unsigned char soft_pwm[EXTRUDERS];
+
+#ifdef FAN_SOFT_PWM
+  static unsigned char soft_pwm_fan;
+#endif
+#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
+    (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
+    (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
+  static unsigned long extruder_autofan_last_check;
+#endif  
+
+#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+  static unsigned char soft_pwm_lcd = 0;
+  static unsigned char lcd_blink_delay = 0;
+  static bool lcd_blink_on = false;
+#endif
+
+#if EXTRUDERS > 3
+  # error Unsupported number of extruders
+#elif EXTRUDERS > 2
+  # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2, v3 }
+#elif EXTRUDERS > 1
+  # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2 }
+#else
+  # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 }
+#endif
+
+// Init min and max temp with extreme values to prevent false errors during startup
+static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP );
+static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP );
+static int minttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 0, 0, 0 );
+static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 16383, 16383, 16383 );
+#ifdef BED_MINTEMP
+static int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP;
+#endif
+#ifdef BED_MAXTEMP
+static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP;
+#endif
+
+#ifdef TEMP_SENSOR_1_AS_REDUNDANT
+  static void *heater_ttbl_map[2] = {(void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE };
+  static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN };
+#else
+  static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE );
+  static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN );
+#endif
+
+static float analog2temp(int raw, uint8_t e);
+static float analog2tempBed(int raw);
+static float analog2tempAmbient(int raw);
+static void updateTemperaturesFromRawValues();
+
+enum TempRunawayStates
+{
+	TempRunaway_INACTIVE = 0,
+	TempRunaway_PREHEAT = 1,
+	TempRunaway_ACTIVE = 2,
+};
+
+#ifdef WATCH_TEMP_PERIOD
+int watch_start_temp[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
+unsigned long watchmillis[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
+#endif //WATCH_TEMP_PERIOD
+
+#ifndef SOFT_PWM_SCALE
+#define SOFT_PWM_SCALE 0
+#endif
+
+#ifdef FILAMENT_SENSOR
+  static int meas_shift_index;  //used to point to a delayed sample in buffer for filament width sensor
+#endif
+//===========================================================================
+//=============================   functions      ============================
+//===========================================================================
+
+  void PID_autotune(float temp, int extruder, int ncycles)
+  {
+  pid_number_of_cycles = ncycles;
+  pid_tuning_finished = false;
+  float input = 0.0;
+  pid_cycle=0;
+  bool heating = true;
+
+  unsigned long temp_millis = millis();
+  unsigned long t1=temp_millis;
+  unsigned long t2=temp_millis;
+  long t_high = 0;
+  long t_low = 0;
+
+  long bias, d;
+  float Ku, Tu;
+  float max = 0, min = 10000;
+  uint8_t safety_check_cycles = 0;
+  const uint8_t safety_check_cycles_count = (extruder < 0) ? 45 : 10; //10 cycles / 20s delay for extruder and 45 cycles / 90s for heatbed
+  float temp_ambient;
+
+#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
+    (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
+    (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
+  unsigned long extruder_autofan_last_check = millis();
+#endif
+
+  if ((extruder >= EXTRUDERS)
+  #if (TEMP_BED_PIN <= -1)
+       ||(extruder < 0)
+  #endif
+       ){
+          SERIAL_ECHOLN("PID Autotune failed. Bad extruder number.");
+		  pid_tuning_finished = true;
+		  pid_cycle = 0;
+          return;
+        }
+	
+  SERIAL_ECHOLN("PID Autotune start");
+  
+  disable_heater(); // switch off all heaters.
+
+  if (extruder<0)
+  {
+     soft_pwm_bed = (MAX_BED_POWER)/2;
+     bias = d = (MAX_BED_POWER)/2;
+   }
+   else
+   {
+     soft_pwm[extruder] = (PID_MAX)/2;
+     bias = d = (PID_MAX)/2;
+  }
+
+
+
+
+ for(;;) {
+
+    if(temp_meas_ready == true) { // temp sample ready
+      updateTemperaturesFromRawValues();
+
+      input = (extruder<0)?current_temperature_bed:current_temperature[extruder];
+
+      max=max(max,input);
+      min=min(min,input);
+
+      #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
+          (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
+          (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
+      if(millis() - extruder_autofan_last_check > 2500) {
+        checkExtruderAutoFans();
+        extruder_autofan_last_check = millis();
+      }
+      #endif
+
+      if(heating == true && input > temp) {
+        if(millis() - t2 > 5000) { 
+          heating=false;
+          if (extruder<0)
+            soft_pwm_bed = (bias - d) >> 1;
+          else
+            soft_pwm[extruder] = (bias - d) >> 1;
+          t1=millis();
+          t_high=t1 - t2;
+          max=temp;
+        }
+      }
+      if(heating == false && input < temp) {
+        if(millis() - t1 > 5000) {
+          heating=true;
+          t2=millis();
+          t_low=t2 - t1;
+          if(pid_cycle > 0) {
+            bias += (d*(t_high - t_low))/(t_low + t_high);
+            bias = constrain(bias, 20 ,(extruder<0?(MAX_BED_POWER):(PID_MAX))-20);
+            if(bias > (extruder<0?(MAX_BED_POWER):(PID_MAX))/2) d = (extruder<0?(MAX_BED_POWER):(PID_MAX)) - 1 - bias;
+            else d = bias;
+
+            SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias);
+            SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d);
+            SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min);
+            SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max);
+            if(pid_cycle > 2) {
+              Ku = (4.0*d)/(3.14159*(max-min)/2.0);
+              Tu = ((float)(t_low + t_high)/1000.0);
+              SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku);
+              SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu);
+              _Kp = 0.6*Ku;
+              _Ki = 2*_Kp/Tu;
+              _Kd = _Kp*Tu/8;
+              SERIAL_PROTOCOLLNPGM(" Classic PID ");
+              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp);
+              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki);
+              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd);
+              /*
+              _Kp = 0.33*Ku;
+              _Ki = _Kp/Tu;
+              _Kd = _Kp*Tu/3;
+              SERIAL_PROTOCOLLNPGM(" Some overshoot ");
+              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp);
+              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki);
+              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd);
+              _Kp = 0.2*Ku;
+              _Ki = 2*_Kp/Tu;
+              _Kd = _Kp*Tu/3;
+              SERIAL_PROTOCOLLNPGM(" No overshoot ");
+              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp);
+              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki);
+              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd);
+              */
+            }
+          }
+          if (extruder<0)
+            soft_pwm_bed = (bias + d) >> 1;
+          else
+            soft_pwm[extruder] = (bias + d) >> 1;
+          pid_cycle++;
+          min=temp;
+        }
+      } 
+    }
+    if(input > (temp + 20)) {
+      SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature too high");
+	  pid_tuning_finished = true;
+	  pid_cycle = 0;
+      return;
+    }
+    if(millis() - temp_millis > 2000) {
+      int p;
+      if (extruder<0){
+        p=soft_pwm_bed;       
+        SERIAL_PROTOCOLPGM("ok B:");
+      }else{
+        p=soft_pwm[extruder];       
+        SERIAL_PROTOCOLPGM("ok T:");
+      }
+			
+      SERIAL_PROTOCOL(input);   
+      SERIAL_PROTOCOLPGM(" @:");
+      SERIAL_PROTOCOLLN(p);       
+		if (safety_check_cycles == 0) { //save ambient temp
+			temp_ambient = input;
+			//SERIAL_ECHOPGM("Ambient T: ");
+			//MYSERIAL.println(temp_ambient);
+			safety_check_cycles++;
+		}
+		else if (safety_check_cycles < safety_check_cycles_count) { //delay
+			safety_check_cycles++;		
+		}
+		else if (safety_check_cycles == safety_check_cycles_count){ //check that temperature is rising
+			safety_check_cycles++;
+			//SERIAL_ECHOPGM("Time from beginning: ");
+			//MYSERIAL.print(safety_check_cycles_count * 2);
+			//SERIAL_ECHOPGM("s. Difference between current and ambient T: ");
+			//MYSERIAL.println(input - temp_ambient);
+
+			if (abs(input - temp_ambient) < 5.0) { 
+				temp_runaway_stop(false, (extruder<0));
+				pid_tuning_finished = true;
+				return;
+			}
+		}
+      temp_millis = millis();
+    }
+    if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) {
+      SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout");
+	  pid_tuning_finished = true;
+	  pid_cycle = 0;
+      return;
+    }
+    if(pid_cycle > ncycles) {
+      SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h");
+	  pid_tuning_finished = true;
+	  pid_cycle = 0;
+      return;
+    }
+    lcd_update();
+  }
+}
+
+void updatePID()
+{
+#ifdef PIDTEMP
+  for(int e = 0; e < EXTRUDERS; e++) { 
+     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;  
+  }
+#endif
+#ifdef PIDTEMPBED
+  temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi;  
+#endif
+}
+  
+int getHeaterPower(int heater) {
+	if (heater<0)
+		return soft_pwm_bed;
+  return soft_pwm[heater];
+}
+
+#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
+    (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
+    (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
+
+  #if defined(FAN_PIN) && FAN_PIN > -1
+    #if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN 
+       #error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN"
+    #endif
+    #if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN 
+       #error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN"
+    #endif
+    #if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN 
+       #error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN"
+    #endif
+  #endif 
+
+void setExtruderAutoFanState(int pin, bool state)
+{
+  unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0;
+  // this idiom allows both digital and PWM fan outputs (see M42 handling).
+  pinMode(pin, OUTPUT);
+  digitalWrite(pin, newFanSpeed);
+  analogWrite(pin, newFanSpeed);
+}
+
+void countFanSpeed()
+{
+	//SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]);
+	fan_speed[0] = (fan_edge_counter[0] * (float(250) / (millis() - extruder_autofan_last_check)));
+	fan_speed[1] = (fan_edge_counter[1] * (float(250) / (millis() - extruder_autofan_last_check)));
+	/*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(millis() - extruder_autofan_last_check);
+	SERIAL_ECHOPGM("extruder fan speed:"); MYSERIAL.print(fan_speed[0]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[0]);
+	SERIAL_ECHOPGM("print fan speed:"); MYSERIAL.print(fan_speed[1]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[1]);
+	SERIAL_ECHOLNPGM(" ");*/
+	fan_edge_counter[0] = 0;
+	fan_edge_counter[1] = 0;
+}
+
+void checkFanSpeed()
+{
+	bool fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0);
+	static unsigned char fan_speed_errors[2] = { 0,0 };
+
+	if (fan_speed[0] == 0 && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)) fan_speed_errors[0]++;
+	else fan_speed_errors[0] = 0;
+
+	if ((fan_speed[1] == 0)&& (fanSpeed > MIN_PRINT_FAN_SPEED)) fan_speed_errors[1]++;
+	else fan_speed_errors[1] = 0;
+
+	if ((fan_speed_errors[0] > 5) && fans_check_enabled) fanSpeedError(0); //extruder fan
+	if ((fan_speed_errors[1] > 15) && fans_check_enabled) fanSpeedError(1); //print fan
+}
+
+extern void stop_and_save_print_to_ram(float z_move, float e_move);
+extern void restore_print_from_ram_and_continue(float e_move);
+
+void fanSpeedError(unsigned char _fan) {
+	if (get_message_level() != 0 && isPrintPaused) return; 
+	//to ensure that target temp. is not set to zero in case taht we are resuming print 
+	if (card.sdprinting) {
+		if (heating_status != 0) {
+			lcd_print_stop();
+		}
+		else {
+			isPrintPaused = true;
+			lcd_sdcard_pause();
+		}
+	}
+	else {
+		setTargetHotend0(0);
+	}
+	SERIAL_ERROR_START;
+	switch (_fan) {
+	case 0:
+			SERIAL_ERRORLNPGM("ERROR: Extruder fan speed is lower then expected");
+			if (get_message_level() == 0) {
+				WRITE(BEEPER, HIGH);
+				delayMicroseconds(200);
+				WRITE(BEEPER, LOW);
+				delayMicroseconds(100);
+				LCD_ALERTMESSAGEPGM("Err: EXTR. FAN ERROR");
+			}
+		break;
+	case 1:
+			SERIAL_ERRORLNPGM("ERROR: Print fan speed is lower then expected");
+			if (get_message_level() == 0) {
+				WRITE(BEEPER, HIGH);
+				delayMicroseconds(200);
+				WRITE(BEEPER, LOW);
+				delayMicroseconds(100);
+				LCD_ALERTMESSAGEPGM("Err: PRINT FAN ERROR");
+			}
+		break;
+	}
+}
+
+
+void checkExtruderAutoFans()
+{
+  uint8_t fanState = 0;
+
+  // which fan pins need to be turned on?      
+  #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
+  if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)
+	  fanState |= 1;
+  #endif
+  #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1
+    if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) 
+    {
+      if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) 
+        fanState |= 1;
+      else
+        fanState |= 2;
+    }
+  #endif
+  #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1
+    if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) 
+    {
+      if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) 
+        fanState |= 1;
+      else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) 
+        fanState |= 2;
+      else
+        fanState |= 4;
+    }
+  #endif
+  
+  // update extruder auto fan states
+  #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
+    setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0);
+  #endif 
+  #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1
+    if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) 
+      setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0);
+  #endif 
+  #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1
+    if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN 
+        && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN)
+      setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0);
+  #endif 
+}
+
+#endif // any extruder auto fan pins set
+
+void manage_heater()
+{
+	wdt_reset();
+
+  float pid_input;
+  float pid_output;
+
+  if(temp_meas_ready != true)   //better readability
+    return; 
+
+  updateTemperaturesFromRawValues();
+
+#ifdef TEMP_RUNAWAY_BED_HYSTERESIS
+  temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true);
+#endif
+
+  for(int e = 0; e < EXTRUDERS; e++) 
+  {
+
+#ifdef TEMP_RUNAWAY_EXTRUDER_HYSTERESIS
+	  temp_runaway_check(e+1, target_temperature[e], current_temperature[e], (int)soft_pwm[e], false);
+#endif
+
+  #ifdef PIDTEMP
+    pid_input = current_temperature[e];
+
+    #ifndef PID_OPENLOOP
+        pid_error[e] = target_temperature[e] - pid_input;
+        if(pid_error[e] > PID_FUNCTIONAL_RANGE) {
+          pid_output = BANG_MAX;
+          pid_reset[e] = true;
+        }
+        else if(pid_error[e] < -PID_FUNCTIONAL_RANGE || target_temperature[e] == 0) {
+          pid_output = 0;
+          pid_reset[e] = true;
+        }
+        else {
+          if(pid_reset[e] == true) {
+            temp_iState[e] = 0.0;
+            pid_reset[e] = false;
+          }
+          pTerm[e] = Kp * pid_error[e];
+          temp_iState[e] += pid_error[e];
+          temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]);
+          iTerm[e] = Ki * temp_iState[e];
+
+          //K1 defined in Configuration.h in the PID settings
+          #define K2 (1.0-K1)
+          dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
+          pid_output = pTerm[e] + iTerm[e] - dTerm[e];
+          if (pid_output > PID_MAX) {
+            if (pid_error[e] > 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
+            pid_output=PID_MAX;
+          } else if (pid_output < 0){
+            if (pid_error[e] < 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
+            pid_output=0;
+          }
+        }
+        temp_dState[e] = pid_input;
+    #else 
+          pid_output = constrain(target_temperature[e], 0, PID_MAX);
+    #endif //PID_OPENLOOP
+    #ifdef PID_DEBUG
+    SERIAL_ECHO_START;
+    SERIAL_ECHO(" PID_DEBUG ");
+    SERIAL_ECHO(e);
+    SERIAL_ECHO(": Input ");
+    SERIAL_ECHO(pid_input);
+    SERIAL_ECHO(" Output ");
+    SERIAL_ECHO(pid_output);
+    SERIAL_ECHO(" pTerm ");
+    SERIAL_ECHO(pTerm[e]);
+    SERIAL_ECHO(" iTerm ");
+    SERIAL_ECHO(iTerm[e]);
+    SERIAL_ECHO(" dTerm ");
+    SERIAL_ECHOLN(dTerm[e]);
+    #endif //PID_DEBUG
+  #else /* PID off */
+    pid_output = 0;
+    if(current_temperature[e] < target_temperature[e]) {
+      pid_output = PID_MAX;
+    }
+  #endif
+
+    // Check if temperature is within the correct range
+    if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) 
+    {
+      soft_pwm[e] = (int)pid_output >> 1;
+    }
+    else {
+      soft_pwm[e] = 0;
+    }
+
+    #ifdef WATCH_TEMP_PERIOD
+    if(watchmillis[e] && millis() - watchmillis[e] > WATCH_TEMP_PERIOD)
+    {
+        if(degHotend(e) < watch_start_temp[e] + WATCH_TEMP_INCREASE)
+        {
+            setTargetHotend(0, e);
+            LCD_MESSAGEPGM("Heating failed");
+            SERIAL_ECHO_START;
+            SERIAL_ECHOLN("Heating failed");
+        }else{
+            watchmillis[e] = 0;
+        }
+    }
+    #endif
+    #ifdef TEMP_SENSOR_1_AS_REDUNDANT
+      if(fabs(current_temperature[0] - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF) {
+        disable_heater();
+        if(IsStopped() == false) {
+          SERIAL_ERROR_START;
+          SERIAL_ERRORLNPGM("Extruder switched off. Temperature difference between temp sensors is too high !");
+          LCD_ALERTMESSAGEPGM("Err: REDUNDANT TEMP ERROR");
+        }
+        #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+          Stop();
+        #endif
+      }
+    #endif
+  } // End extruder for loop
+
+  #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \
+      (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \
+      (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1)
+  if(millis() - extruder_autofan_last_check > 1000)  // only need to check fan state very infrequently
+  {
+	countFanSpeed();
+	checkFanSpeed();
+    checkExtruderAutoFans();
+    extruder_autofan_last_check = millis();
+  }  
+  #endif       
+  
+  #ifndef PIDTEMPBED
+  if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL)
+    return;
+  previous_millis_bed_heater = millis();
+  #endif
+
+  #if TEMP_SENSOR_BED != 0
+
+  #ifdef PIDTEMPBED
+    pid_input = current_temperature_bed;
+
+    #ifndef PID_OPENLOOP
+		  pid_error_bed = target_temperature_bed - pid_input;
+		  pTerm_bed = bedKp * pid_error_bed;
+		  temp_iState_bed += pid_error_bed;
+		  temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed);
+		  iTerm_bed = bedKi * temp_iState_bed;
+
+		  //K1 defined in Configuration.h in the PID settings
+		  #define K2 (1.0-K1)
+		  dTerm_bed= (bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed);
+		  temp_dState_bed = pid_input;
+
+		  pid_output = pTerm_bed + iTerm_bed - dTerm_bed;
+          	  if (pid_output > MAX_BED_POWER) {
+            	    if (pid_error_bed > 0 )  temp_iState_bed -= pid_error_bed; // conditional un-integration
+                    pid_output=MAX_BED_POWER;
+          	  } else if (pid_output < 0){
+            	    if (pid_error_bed < 0 )  temp_iState_bed -= pid_error_bed; // conditional un-integration
+                    pid_output=0;
+                  }
+
+    #else 
+      pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER);
+    #endif //PID_OPENLOOP
+
+	  if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) 
+	  {
+	    soft_pwm_bed = (int)pid_output >> 1;
+	  }
+	  else {
+	    soft_pwm_bed = 0;
+	  }
+
+    #elif !defined(BED_LIMIT_SWITCHING)
+      // Check if temperature is within the correct range
+      if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP))
+      {
+        if(current_temperature_bed >= target_temperature_bed)
+        {
+          soft_pwm_bed = 0;
+        }
+        else 
+        {
+          soft_pwm_bed = MAX_BED_POWER>>1;
+        }
+      }
+      else
+      {
+        soft_pwm_bed = 0;
+        WRITE(HEATER_BED_PIN,LOW);
+      }
+    #else //#ifdef BED_LIMIT_SWITCHING
+      // Check if temperature is within the correct band
+      if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP))
+      {
+        if(current_temperature_bed > target_temperature_bed + BED_HYSTERESIS)
+        {
+          soft_pwm_bed = 0;
+        }
+        else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS)
+        {
+          soft_pwm_bed = MAX_BED_POWER>>1;
+        }
+      }
+      else
+      {
+        soft_pwm_bed = 0;
+        WRITE(HEATER_BED_PIN,LOW);
+      }
+    #endif
+  #endif
+  
+//code for controlling the extruder rate based on the width sensor 
+#ifdef FILAMENT_SENSOR
+  if(filament_sensor) 
+	{
+	meas_shift_index=delay_index1-meas_delay_cm;
+		  if(meas_shift_index<0)
+			  meas_shift_index = meas_shift_index + (MAX_MEASUREMENT_DELAY+1);  //loop around buffer if needed
+		  
+		  //get the delayed info and add 100 to reconstitute to a percent of the nominal filament diameter
+		  //then square it to get an area
+		  
+		  if(meas_shift_index<0)
+			  meas_shift_index=0;
+		  else if (meas_shift_index>MAX_MEASUREMENT_DELAY)
+			  meas_shift_index=MAX_MEASUREMENT_DELAY;
+		  
+		     volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] = pow((float)(100+measurement_delay[meas_shift_index])/100.0,2);
+		     if (volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] <0.01)
+		    	 volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]=0.01;
+	}
+#endif
+#ifdef HOST_KEEPALIVE_FEATURE
+  host_keepalive();
+#endif
+}
+
+#define PGM_RD_W(x)   (short)pgm_read_word(&x)
+// Derived from RepRap FiveD extruder::getTemperature()
+// For hot end temperature measurement.
+static float analog2temp(int raw, uint8_t e) {
+#ifdef TEMP_SENSOR_1_AS_REDUNDANT
+  if(e > EXTRUDERS)
+#else
+  if(e >= EXTRUDERS)
+#endif
+  {
+      SERIAL_ERROR_START;
+      SERIAL_ERROR((int)e);
+      SERIAL_ERRORLNPGM(" - Invalid extruder number !");
+      kill("", 6);
+      return 0.0;
+  } 
+  #ifdef HEATER_0_USES_MAX6675
+    if (e == 0)
+    {
+      return 0.25 * raw;
+    }
+  #endif
+
+  if(heater_ttbl_map[e] != NULL)
+  {
+    float celsius = 0;
+    uint8_t i;
+    short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
+
+    for (i=1; i<heater_ttbllen_map[e]; i++)
+    {
+      if (PGM_RD_W((*tt)[i][0]) > raw)
+      {
+        celsius = PGM_RD_W((*tt)[i-1][1]) + 
+          (raw - PGM_RD_W((*tt)[i-1][0])) * 
+          (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) /
+          (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0]));
+        break;
+      }
+    }
+
+    // Overflow: Set to last value in the table
+    if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]);
+
+    return celsius;
+  }
+  return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
+}
+
+// Derived from RepRap FiveD extruder::getTemperature()
+// For bed temperature measurement.
+static float analog2tempBed(int raw) {
+  #ifdef BED_USES_THERMISTOR
+    float celsius = 0;
+    byte i;
+
+    for (i=1; i<BEDTEMPTABLE_LEN; i++)
+    {
+      if (PGM_RD_W(BEDTEMPTABLE[i][0]) > raw)
+      {
+        celsius  = PGM_RD_W(BEDTEMPTABLE[i-1][1]) + 
+          (raw - PGM_RD_W(BEDTEMPTABLE[i-1][0])) * 
+          (float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i-1][1])) /
+          (float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i-1][0]));
+        break;
+      }
+    }
+
+    // Overflow: Set to last value in the table
+    if (i == BEDTEMPTABLE_LEN) celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]);
+
+
+	// temperature offset adjustment
+#ifdef BED_OFFSET
+	float _offset = BED_OFFSET;
+	float _offset_center = BED_OFFSET_CENTER;
+	float _offset_start = BED_OFFSET_START;
+	float _first_koef = (_offset / 2) / (_offset_center - _offset_start);
+	float _second_koef = (_offset / 2) / (100 - _offset_center);
+
+
+	if (celsius >= _offset_start && celsius <= _offset_center)
+	{
+		celsius = celsius + (_first_koef * (celsius - _offset_start));
+	}
+	else if (celsius > _offset_center && celsius <= 100)
+	{
+		celsius = celsius + (_first_koef * (_offset_center - _offset_start)) + ( _second_koef * ( celsius - ( 100 - _offset_center ) )) ;
+	}
+	else if (celsius > 100)
+	{
+		celsius = celsius + _offset;
+	}
+#endif
+
+
+    return celsius;
+  #elif defined BED_USES_AD595
+    return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
+  #else
+    return 0;
+  #endif
+}
+
+static float analog2tempAmbient(int raw)
+{
+    float celsius = 0;
+    byte i;
+
+    for (i=1; i<AMBIENTTEMPTABLE_LEN; i++)
+    {
+      if (PGM_RD_W(AMBIENTTEMPTABLE[i][0]) > raw)
+      {
+        celsius  = PGM_RD_W(AMBIENTTEMPTABLE[i-1][1]) + 
+          (raw - PGM_RD_W(AMBIENTTEMPTABLE[i-1][0])) * 
+          (float)(PGM_RD_W(AMBIENTTEMPTABLE[i][1]) - PGM_RD_W(AMBIENTTEMPTABLE[i-1][1])) /
+          (float)(PGM_RD_W(AMBIENTTEMPTABLE[i][0]) - PGM_RD_W(AMBIENTTEMPTABLE[i-1][0]));
+        break;
+      }
+    }
+    // Overflow: Set to last value in the table
+    if (i == AMBIENTTEMPTABLE_LEN) celsius = PGM_RD_W(AMBIENTTEMPTABLE[i-1][1]);
+    return celsius;
+}
+
+/* Called to get the raw values into the the actual temperatures. The raw values are created in interrupt context,
+    and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */
+static void updateTemperaturesFromRawValues()
+{
+    for(uint8_t e=0;e<EXTRUDERS;e++)
+    {
+        current_temperature[e] = analog2temp(current_temperature_raw[e], e);
+    }
+
+#ifdef PINDA_THERMISTOR
+	current_temperature_pinda = analog2tempBed(current_temperature_raw_pinda); //thermistor for pinda is the same as for bed
+#endif
+
+#ifdef AMBIENT_THERMISTOR
+	current_temperature_ambient = analog2tempAmbient(current_temperature_raw_ambient); //thermistor for ambient is NTCG104LH104JT1 (2000)
+#endif
+   
+	current_temperature_bed = analog2tempBed(current_temperature_bed_raw);
+
+    #ifdef TEMP_SENSOR_1_AS_REDUNDANT
+      redundant_temperature = analog2temp(redundant_temperature_raw, 1);
+    #endif
+    #if defined (FILAMENT_SENSOR) && (FILWIDTH_PIN > -1)    //check if a sensor is supported 
+      filament_width_meas = analog2widthFil();
+    #endif  
+    //Reset the watchdog after we know we have a temperature measurement.
+    watchdog_reset();
+
+    CRITICAL_SECTION_START;
+    temp_meas_ready = false;
+    CRITICAL_SECTION_END;
+}
+
+
+// For converting raw Filament Width to milimeters 
+#ifdef FILAMENT_SENSOR
+float analog2widthFil() { 
+return current_raw_filwidth/16383.0*5.0; 
+//return current_raw_filwidth; 
+} 
+ 
+// For converting raw Filament Width to a ratio 
+int widthFil_to_size_ratio() { 
+ 
+float temp; 
+      
+temp=filament_width_meas;
+if(filament_width_meas<MEASURED_LOWER_LIMIT)
+	temp=filament_width_nominal;  //assume sensor cut out
+else if (filament_width_meas>MEASURED_UPPER_LIMIT)
+	temp= MEASURED_UPPER_LIMIT;
+
+
+return(filament_width_nominal/temp*100); 
+
+
+} 
+#endif
+
+
+
+
+
+void tp_init()
+{
+#if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1))
+  //disable RUMBA JTAG in case the thermocouple extension is plugged on top of JTAG connector
+  MCUCR=(1<<JTD); 
+  MCUCR=(1<<JTD);
+#endif
+  
+  // Finish init of mult extruder arrays 
+  for(int e = 0; e < EXTRUDERS; e++) {
+    // populate with the first value 
+    maxttemp[e] = maxttemp[0];
+#ifdef PIDTEMP
+    temp_iState_min[e] = 0.0;
+    temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
+#endif //PIDTEMP
+#ifdef PIDTEMPBED
+    temp_iState_min_bed = 0.0;
+    temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi;
+#endif //PIDTEMPBED
+  }
+
+  #if defined(HEATER_0_PIN) && (HEATER_0_PIN > -1) 
+    SET_OUTPUT(HEATER_0_PIN);
+  #endif  
+  #if defined(HEATER_1_PIN) && (HEATER_1_PIN > -1) 
+    SET_OUTPUT(HEATER_1_PIN);
+  #endif  
+  #if defined(HEATER_2_PIN) && (HEATER_2_PIN > -1) 
+    SET_OUTPUT(HEATER_2_PIN);
+  #endif  
+  #if defined(HEATER_BED_PIN) && (HEATER_BED_PIN > -1) 
+    SET_OUTPUT(HEATER_BED_PIN);
+  #endif  
+  #if defined(FAN_PIN) && (FAN_PIN > -1) 
+    SET_OUTPUT(FAN_PIN);
+    #ifdef FAST_PWM_FAN
+    setPwmFrequency(FAN_PIN, 1); // No prescaling. Pwm frequency = F_CPU/256/8
+    #endif
+    #ifdef FAN_SOFT_PWM
+    soft_pwm_fan = fanSpeedSoftPwm / 2;
+    #endif
+	#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+    soft_pwm_lcd = lcdSoftPwm / 2;
+	lcd_blink_delay = lcdBlinkDelay;
+    lcd_blink_on = true;
+    #endif
+  #endif
+
+  #ifdef HEATER_0_USES_MAX6675
+    #ifndef SDSUPPORT
+      SET_OUTPUT(SCK_PIN);
+      WRITE(SCK_PIN,0);
+    
+      SET_OUTPUT(MOSI_PIN);
+      WRITE(MOSI_PIN,1);
+    
+      SET_INPUT(MISO_PIN);
+      WRITE(MISO_PIN,1);
+    #endif
+    /* Using pinMode and digitalWrite, as that was the only way I could get it to compile */
+    
+    //Have to toggle SD card CS pin to low first, to enable firmware to talk with SD card
+	pinMode(SS_PIN, OUTPUT);
+	digitalWrite(SS_PIN,0);  
+	pinMode(MAX6675_SS, OUTPUT);
+	digitalWrite(MAX6675_SS,1);
+  #endif
+
+  // Set analog inputs
+  ADCSRA = 1<<ADEN | 1<<ADSC | 1<<ADIF | 0x07;
+  DIDR0 = 0;
+  #ifdef DIDR2
+    DIDR2 = 0;
+  #endif
+  #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1)
+    #if TEMP_0_PIN < 8
+       DIDR0 |= 1 << TEMP_0_PIN; 
+    #else
+       DIDR2 |= 1<<(TEMP_0_PIN - 8); 
+    #endif
+  #endif
+  #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1)
+    #if TEMP_1_PIN < 8
+       DIDR0 |= 1<<TEMP_1_PIN; 
+    #else
+       DIDR2 |= 1<<(TEMP_1_PIN - 8); 
+    #endif
+  #endif
+  #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
+    #if TEMP_2_PIN < 8
+       DIDR0 |= 1 << TEMP_2_PIN; 
+    #else
+       DIDR2 |= 1<<(TEMP_2_PIN - 8); 
+    #endif
+  #endif
+  #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1)
+    #if TEMP_BED_PIN < 8
+       DIDR0 |= 1<<TEMP_BED_PIN; 
+    #else
+       DIDR2 |= 1<<(TEMP_BED_PIN - 8); 
+    #endif
+  #endif
+  
+  //Added for Filament Sensor 
+  #ifdef FILAMENT_SENSOR
+   #if defined(FILWIDTH_PIN) && (FILWIDTH_PIN > -1) 
+	#if FILWIDTH_PIN < 8 
+       	   DIDR0 |= 1<<FILWIDTH_PIN;  
+	#else 
+       	   DIDR2 |= 1<<(FILWIDTH_PIN - 8);  
+	#endif 
+   #endif
+  #endif
+  
+  // Use timer0 for temperature measurement
+  // Interleave temperature interrupt with millies interrupt
+  OCR0B = 128;
+  TIMSK0 |= (1<<OCIE0B);  
+  
+  // Wait for temperature measurement to settle
+  delay(250);
+
+#ifdef HEATER_0_MINTEMP
+  minttemp[0] = HEATER_0_MINTEMP;
+  while(analog2temp(minttemp_raw[0], 0) < HEATER_0_MINTEMP) {
+#if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP
+    minttemp_raw[0] += OVERSAMPLENR;
+#else
+    minttemp_raw[0] -= OVERSAMPLENR;
+#endif
+  }
+#endif //MINTEMP
+#ifdef HEATER_0_MAXTEMP
+  maxttemp[0] = HEATER_0_MAXTEMP;
+  while(analog2temp(maxttemp_raw[0], 0) > HEATER_0_MAXTEMP) {
+#if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP
+    maxttemp_raw[0] -= OVERSAMPLENR;
+#else
+    maxttemp_raw[0] += OVERSAMPLENR;
+#endif
+  }
+#endif //MAXTEMP
+
+#if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP)
+  minttemp[1] = HEATER_1_MINTEMP;
+  while(analog2temp(minttemp_raw[1], 1) < HEATER_1_MINTEMP) {
+#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP
+    minttemp_raw[1] += OVERSAMPLENR;
+#else
+    minttemp_raw[1] -= OVERSAMPLENR;
+#endif
+  }
+#endif // MINTEMP 1
+#if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP)
+  maxttemp[1] = HEATER_1_MAXTEMP;
+  while(analog2temp(maxttemp_raw[1], 1) > HEATER_1_MAXTEMP) {
+#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP
+    maxttemp_raw[1] -= OVERSAMPLENR;
+#else
+    maxttemp_raw[1] += OVERSAMPLENR;
+#endif
+  }
+#endif //MAXTEMP 1
+
+#if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP)
+  minttemp[2] = HEATER_2_MINTEMP;
+  while(analog2temp(minttemp_raw[2], 2) < HEATER_2_MINTEMP) {
+#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP
+    minttemp_raw[2] += OVERSAMPLENR;
+#else
+    minttemp_raw[2] -= OVERSAMPLENR;
+#endif
+  }
+#endif //MINTEMP 2
+#if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP)
+  maxttemp[2] = HEATER_2_MAXTEMP;
+  while(analog2temp(maxttemp_raw[2], 2) > HEATER_2_MAXTEMP) {
+#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP
+    maxttemp_raw[2] -= OVERSAMPLENR;
+#else
+    maxttemp_raw[2] += OVERSAMPLENR;
+#endif
+  }
+#endif //MAXTEMP 2
+
+#ifdef BED_MINTEMP
+  /* No bed MINTEMP error implemented?!? */
+  while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) {
+#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP
+    bed_minttemp_raw += OVERSAMPLENR;
+#else
+    bed_minttemp_raw -= OVERSAMPLENR;
+#endif
+  }
+  
+#endif //BED_MINTEMP
+#ifdef BED_MAXTEMP
+  while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) {
+#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP
+    bed_maxttemp_raw -= OVERSAMPLENR;
+#else
+    bed_maxttemp_raw += OVERSAMPLENR;
+#endif
+  }
+#endif //BED_MAXTEMP
+}
+
+void setWatch() 
+{  
+#ifdef WATCH_TEMP_PERIOD
+  for (int e = 0; e < EXTRUDERS; e++)
+  {
+    if(degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE * 2))
+    {
+      watch_start_temp[e] = degHotend(e);
+      watchmillis[e] = millis();
+    } 
+  }
+#endif 
+}
+
+#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0)
+void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed)
+{
+	float __hysteresis = 0;
+	int __timeout = 0;
+	bool temp_runaway_check_active = false;
+	static float __preheat_start[2] = { 0,0}; //currently just bed and one extruder
+	static int __preheat_counter[2] = { 0,0};
+	static int __preheat_errors[2] = { 0,0};
+		
+
+#ifdef 	TEMP_RUNAWAY_BED_TIMEOUT
+	if (_isbed)
+	{
+		__hysteresis = TEMP_RUNAWAY_BED_HYSTERESIS;
+		__timeout = TEMP_RUNAWAY_BED_TIMEOUT;
+	}
+#endif
+#ifdef 	TEMP_RUNAWAY_EXTRUDER_TIMEOUT
+	if (!_isbed)
+	{
+		__hysteresis = TEMP_RUNAWAY_EXTRUDER_HYSTERESIS;
+		__timeout = TEMP_RUNAWAY_EXTRUDER_TIMEOUT;
+	}
+#endif
+
+	if (millis() - temp_runaway_timer[_heater_id] > 2000)
+	{
+
+		temp_runaway_timer[_heater_id] = millis();
+		if (_output == 0)
+		{
+			temp_runaway_check_active = false;
+			temp_runaway_error_counter[_heater_id] = 0;
+		}
+
+		if (temp_runaway_target[_heater_id] != _target_temperature)
+		{
+			if (_target_temperature > 0)
+			{
+				temp_runaway_status[_heater_id] = TempRunaway_PREHEAT;
+				temp_runaway_target[_heater_id] = _target_temperature;
+				__preheat_start[_heater_id] = _current_temperature;
+				__preheat_counter[_heater_id] = 0;
+			}
+			else
+			{
+				temp_runaway_status[_heater_id] = TempRunaway_INACTIVE;
+				temp_runaway_target[_heater_id] = _target_temperature;
+			}
+		}
+
+		if (temp_runaway_status[_heater_id] == TempRunaway_PREHEAT)
+		{
+			if (_current_temperature < ((_isbed) ? (0.8 * _target_temperature) : 150)) //check only in area where temperature is changing fastly for heater, check to 0.8 x target temperature for bed
+			{
+				__preheat_counter[_heater_id]++;
+				if (__preheat_counter[_heater_id] > ((_isbed) ? 16 : 8)) // periodicaly check if current temperature changes
+				{
+					/*SERIAL_ECHOPGM("Heater:");
+					MYSERIAL.print(_heater_id);
+					SERIAL_ECHOPGM(" T:");
+					MYSERIAL.print(_current_temperature);
+					SERIAL_ECHOPGM(" Tstart:");
+					MYSERIAL.print(__preheat_start[_heater_id]);*/
+					
+					if (_current_temperature - __preheat_start[_heater_id] < 2) {
+						__preheat_errors[_heater_id]++;
+						/*SERIAL_ECHOPGM(" Preheat errors:");
+						MYSERIAL.println(__preheat_errors[_heater_id]);*/
+					}
+					else {
+						//SERIAL_ECHOLNPGM("");
+						__preheat_errors[_heater_id] = 0;
+					}
+
+					if (__preheat_errors[_heater_id] > ((_isbed) ? 2 : 5)) 
+					{
+						if (farm_mode) { prusa_statistics(0); }
+						temp_runaway_stop(true, _isbed);
+						if (farm_mode) { prusa_statistics(91); }
+					}
+					__preheat_start[_heater_id] = _current_temperature;
+					__preheat_counter[_heater_id] = 0;
+				}
+			}
+		}
+
+		if (_current_temperature >= _target_temperature  && temp_runaway_status[_heater_id] == TempRunaway_PREHEAT)
+		{
+			temp_runaway_status[_heater_id] = TempRunaway_ACTIVE;
+			temp_runaway_check_active = false;
+		}
+
+		if (!temp_runaway_check_active && _output > 0)
+		{
+			temp_runaway_check_active = true;
+		}
+
+
+		if (temp_runaway_check_active)
+		{			
+			//	we are in range
+			if (_target_temperature - __hysteresis < _current_temperature && _current_temperature < _target_temperature + __hysteresis)
+			{
+				temp_runaway_check_active = false;
+				temp_runaway_error_counter[_heater_id] = 0;
+			}
+			else
+			{
+				if (temp_runaway_status[_heater_id] > TempRunaway_PREHEAT)
+				{
+					temp_runaway_error_counter[_heater_id]++;
+					if (temp_runaway_error_counter[_heater_id] * 2 > __timeout)
+					{
+						if (farm_mode) { prusa_statistics(0); }
+						temp_runaway_stop(false, _isbed);
+						if (farm_mode) { prusa_statistics(90); }
+					}
+				}
+			}
+		}
+
+	}
+}
+
+void temp_runaway_stop(bool isPreheat, bool isBed)
+{
+	cancel_heatup = true;
+	quickStop();
+	if (card.sdprinting)
+	{
+		card.sdprinting = false;
+		card.closefile();
+	}
+	
+	disable_heater();
+	disable_x();
+	disable_y();
+	disable_e0();
+	disable_e1();
+	disable_e2();
+	manage_heater();
+	lcd_update();
+	WRITE(BEEPER, HIGH);
+	delayMicroseconds(500);
+	WRITE(BEEPER, LOW);
+	delayMicroseconds(100);
+
+	if (isPreheat)
+	{
+		Stop();
+		isBed ? LCD_ALERTMESSAGEPGM("BED PREHEAT ERROR") : LCD_ALERTMESSAGEPGM("PREHEAT ERROR");
+		SERIAL_ERROR_START;
+		isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HOTEND)");
+		SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
+		SET_OUTPUT(FAN_PIN);
+		WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
+		analogWrite(FAN_PIN, 255);
+		fanSpeed = 255;
+		delayMicroseconds(2000);
+	}
+	else
+	{
+		isBed ? LCD_ALERTMESSAGEPGM("BED THERMAL RUNAWAY") : LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY");
+		SERIAL_ERROR_START;
+		isBed ? SERIAL_ERRORLNPGM(" HEATBED THERMAL RUNAWAY") : SERIAL_ERRORLNPGM(" HOTEND THERMAL RUNAWAY");
+	}
+}
+#endif
+
+
+void disable_heater()
+{
+  for(int i=0;i<EXTRUDERS;i++)
+    setTargetHotend(0,i);
+  setTargetBed(0);
+  #if defined(TEMP_0_PIN) && TEMP_0_PIN > -1
+  target_temperature[0]=0;
+  soft_pwm[0]=0;
+   #if defined(HEATER_0_PIN) && HEATER_0_PIN > -1  
+     WRITE(HEATER_0_PIN,LOW);
+   #endif
+  #endif
+     
+  #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 && EXTRUDERS > 1
+    target_temperature[1]=0;
+    soft_pwm[1]=0;
+    #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 
+      WRITE(HEATER_1_PIN,LOW);
+    #endif
+  #endif
+      
+  #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 && EXTRUDERS > 2
+    target_temperature[2]=0;
+    soft_pwm[2]=0;
+    #if defined(HEATER_2_PIN) && HEATER_2_PIN > -1  
+      WRITE(HEATER_2_PIN,LOW);
+    #endif
+  #endif 
+
+  #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1
+    target_temperature_bed=0;
+    soft_pwm_bed=0;
+    #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1  
+      WRITE(HEATER_BED_PIN,LOW);
+    #endif
+  #endif 
+}
+
+void max_temp_error(uint8_t e) {
+  disable_heater();
+  if(IsStopped() == false) {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLN((int)e);
+    SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !");
+    LCD_ALERTMESSAGEPGM("Err: MAXTEMP");
+  }
+  #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+  Stop();
+    
+
+    
+  #endif
+    SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
+    SET_OUTPUT(FAN_PIN);
+    SET_OUTPUT(BEEPER);
+    WRITE(FAN_PIN, 1);
+    WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
+    WRITE(BEEPER, 1);
+    // fanSpeed will consumed by the check_axes_activity() routine.
+    fanSpeed=255;
+	if (farm_mode) { prusa_statistics(93); }
+}
+
+void min_temp_error(uint8_t e) {
+#ifdef DEBUG_DISABLE_MINTEMP
+	return;
+#endif
+  disable_heater();
+  if(IsStopped() == false) {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLN((int)e);
+    SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
+    LCD_ALERTMESSAGEPGM("Err: MINTEMP");
+  }
+  #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+  Stop();
+  #endif
+  if (farm_mode) { prusa_statistics(92); }
+
+}
+
+void bed_max_temp_error(void) {
+#if HEATER_BED_PIN > -1
+  WRITE(HEATER_BED_PIN, 0);
+#endif
+  if(IsStopped() == false) {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !");
+    LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED");
+  }
+  #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+  Stop();
+  #endif
+
+}
+
+void bed_min_temp_error(void) {
+#ifdef DEBUG_DISABLE_MINTEMP
+	return;
+#endif
+#if HEATER_BED_PIN > -1
+    WRITE(HEATER_BED_PIN, 0);
+#endif
+    if(IsStopped() == false) {
+        SERIAL_ERROR_START;
+        SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !");
+        LCD_ALERTMESSAGEPGM("Err: MINTEMP BED");
+    }
+#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+    Stop();
+#endif*/
+}
+
+#ifdef HEATER_0_USES_MAX6675
+#define MAX6675_HEAT_INTERVAL 250
+long max6675_previous_millis = MAX6675_HEAT_INTERVAL;
+int max6675_temp = 2000;
+
+int read_max6675()
+{
+  if (millis() - max6675_previous_millis < MAX6675_HEAT_INTERVAL) 
+    return max6675_temp;
+  
+  max6675_previous_millis = millis();
+  max6675_temp = 0;
+    
+  #ifdef	PRR
+    PRR &= ~(1<<PRSPI);
+  #elif defined PRR0
+    PRR0 &= ~(1<<PRSPI);
+  #endif
+  
+  SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0);
+  
+  // enable TT_MAX6675
+  WRITE(MAX6675_SS, 0);
+  
+  // ensure 100ns delay - a bit extra is fine
+  asm("nop");//50ns on 20Mhz, 62.5ns on 16Mhz
+  asm("nop");//50ns on 20Mhz, 62.5ns on 16Mhz
+  
+  // read MSB
+  SPDR = 0;
+  for (;(SPSR & (1<<SPIF)) == 0;);
+  max6675_temp = SPDR;
+  max6675_temp <<= 8;
+  
+  // read LSB
+  SPDR = 0;
+  for (;(SPSR & (1<<SPIF)) == 0;);
+  max6675_temp |= SPDR;
+  
+  // disable TT_MAX6675
+  WRITE(MAX6675_SS, 1);
+
+  if (max6675_temp & 4) 
+  {
+    // thermocouple open
+    max6675_temp = 2000;
+  }
+  else 
+  {
+    max6675_temp = max6675_temp >> 3;
+  }
+
+  return max6675_temp;
+}
+#endif
+
+
+// Timer 0 is shared with millies
+ISR(TIMER0_COMPB_vect)
+{
+//	if (UVLO) uvlo();
+  //these variables are only accesible from the ISR, but static, so they don't lose their value
+  static unsigned char temp_count = 0;
+  static unsigned long raw_temp_0_value = 0;
+  static unsigned long raw_temp_1_value = 0;
+  static unsigned long raw_temp_2_value = 0;
+  static unsigned long raw_temp_bed_value = 0;
+  static unsigned long raw_temp_pinda_value = 0;
+  static unsigned long raw_temp_ambient_value = 0;
+  static unsigned char temp_state = 14;
+  static unsigned char pwm_count = (1 << SOFT_PWM_SCALE);
+  static unsigned char soft_pwm_0;
+#ifdef SLOW_PWM_HEATERS
+  static unsigned char slow_pwm_count = 0;
+  static unsigned char state_heater_0 = 0;
+  static unsigned char state_timer_heater_0 = 0;
+#endif 
+#if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL)
+  static unsigned char soft_pwm_1;
+#ifdef SLOW_PWM_HEATERS
+  static unsigned char state_heater_1 = 0;
+  static unsigned char state_timer_heater_1 = 0;
+#endif 
+#endif
+#if EXTRUDERS > 2
+  static unsigned char soft_pwm_2;
+#ifdef SLOW_PWM_HEATERS
+  static unsigned char state_heater_2 = 0;
+  static unsigned char state_timer_heater_2 = 0;
+#endif 
+#endif
+#if HEATER_BED_PIN > -1
+  static unsigned char soft_pwm_b;
+#ifdef SLOW_PWM_HEATERS
+  static unsigned char state_heater_b = 0;
+  static unsigned char state_timer_heater_b = 0;
+#endif 
+#endif
+  
+#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
+  static unsigned long raw_filwidth_value = 0;  //added for filament width sensor
+#endif
+  
+#ifndef SLOW_PWM_HEATERS
+  /*
+   * standard PWM modulation
+   */
+  if (pwm_count == 0)
+  {
+    soft_pwm_0 = soft_pwm[0];
+    if(soft_pwm_0 > 0)
+	{ 
+      WRITE(HEATER_0_PIN,1);
+#ifdef HEATERS_PARALLEL
+      WRITE(HEATER_1_PIN,1);
+#endif
+    } else WRITE(HEATER_0_PIN,0);
+#if EXTRUDERS > 1
+    soft_pwm_1 = soft_pwm[1];
+    if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); else WRITE(HEATER_1_PIN,0);
+#endif
+#if EXTRUDERS > 2
+    soft_pwm_2 = soft_pwm[2];
+    if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); else WRITE(HEATER_2_PIN,0);
+#endif
+#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
+    soft_pwm_b = soft_pwm_bed;
+    if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0);
+#endif
+#ifdef FAN_SOFT_PWM
+    soft_pwm_fan = fanSpeedSoftPwm / 2;
+    if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0);
+#endif
+  }
+  if(soft_pwm_0 < pwm_count)
+  { 
+    WRITE(HEATER_0_PIN,0);
+#ifdef HEATERS_PARALLEL
+    WRITE(HEATER_1_PIN,0);
+#endif
+  }
+#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+	if ((pwm_count & LCD_PWM_MAX) == 0)
+	{
+		if (lcd_blink_delay)
+		{
+			lcd_blink_delay--;
+			if (lcd_blink_delay == 0)
+			{
+				lcd_blink_delay = lcdBlinkDelay;
+				lcd_blink_on = !lcd_blink_on;
+			}
+		}
+		else
+		{
+			lcd_blink_delay = lcdBlinkDelay;
+			lcd_blink_on = true;
+		}
+		soft_pwm_lcd = (lcd_blink_on) ? (lcdSoftPwm / 2) : 0;
+		if (soft_pwm_lcd > 0) WRITE(LCD_PWM_PIN,1); else WRITE(LCD_PWM_PIN,0);
+	}
+#endif
+
+#if EXTRUDERS > 1
+  if(soft_pwm_1 < pwm_count) WRITE(HEATER_1_PIN,0);
+#endif
+#if EXTRUDERS > 2
+  if(soft_pwm_2 < pwm_count) WRITE(HEATER_2_PIN,0);
+#endif
+#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
+  if(soft_pwm_b < pwm_count) WRITE(HEATER_BED_PIN,0);
+#endif
+#ifdef FAN_SOFT_PWM
+  if(soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0);
+#endif
+#if defined(LCD_PWM_PIN) && (LCD_PWM_PIN > -1)
+  if (soft_pwm_lcd < (pwm_count & LCD_PWM_MAX)) WRITE(LCD_PWM_PIN,0);
+#endif
+  
+  pwm_count += (1 << SOFT_PWM_SCALE);
+  pwm_count &= 0x7f;
+
+#else //ifndef SLOW_PWM_HEATERS
+  /*
+   * SLOW PWM HEATERS
+   *
+   * for heaters drived by relay
+   */
+#ifndef MIN_STATE_TIME
+#define MIN_STATE_TIME 16 // MIN_STATE_TIME * 65.5 = time in milliseconds
+#endif
+  if (slow_pwm_count == 0) {
+    // EXTRUDER 0 
+    soft_pwm_0 = soft_pwm[0];
+    if (soft_pwm_0 > 0) {
+      // turn ON heather only if the minimum time is up 
+      if (state_timer_heater_0 == 0) { 
+	// if change state set timer 
+	if (state_heater_0 == 0) {
+	  state_timer_heater_0 = MIN_STATE_TIME;
+	}
+	state_heater_0 = 1;
+	WRITE(HEATER_0_PIN, 1);
+#ifdef HEATERS_PARALLEL
+	WRITE(HEATER_1_PIN, 1);
+#endif
+      }
+    } else {
+      // turn OFF heather only if the minimum time is up 
+      if (state_timer_heater_0 == 0) {
+	// if change state set timer 
+	if (state_heater_0 == 1) {
+	  state_timer_heater_0 = MIN_STATE_TIME;
+	}
+	state_heater_0 = 0;
+	WRITE(HEATER_0_PIN, 0);
+#ifdef HEATERS_PARALLEL
+	WRITE(HEATER_1_PIN, 0);
+#endif
+      }
+    }
+    
+#if EXTRUDERS > 1
+    // EXTRUDER 1
+    soft_pwm_1 = soft_pwm[1];
+    if (soft_pwm_1 > 0) {
+      // turn ON heather only if the minimum time is up 
+      if (state_timer_heater_1 == 0) { 
+	// if change state set timer 
+	if (state_heater_1 == 0) {
+	  state_timer_heater_1 = MIN_STATE_TIME;
+	}
+	state_heater_1 = 1;
+	WRITE(HEATER_1_PIN, 1);
+      }
+    } else {
+      // turn OFF heather only if the minimum time is up 
+      if (state_timer_heater_1 == 0) {
+	// if change state set timer 
+	if (state_heater_1 == 1) {
+	  state_timer_heater_1 = MIN_STATE_TIME;
+	}
+	state_heater_1 = 0;
+	WRITE(HEATER_1_PIN, 0);
+      }
+    }
+#endif
+    
+#if EXTRUDERS > 2
+    // EXTRUDER 2
+    soft_pwm_2 = soft_pwm[2];
+    if (soft_pwm_2 > 0) {
+      // turn ON heather only if the minimum time is up 
+      if (state_timer_heater_2 == 0) { 
+	// if change state set timer 
+	if (state_heater_2 == 0) {
+	  state_timer_heater_2 = MIN_STATE_TIME;
+	}
+	state_heater_2 = 1;
+	WRITE(HEATER_2_PIN, 1);
+      }
+    } else {
+      // turn OFF heather only if the minimum time is up 
+      if (state_timer_heater_2 == 0) {
+	// if change state set timer 
+	if (state_heater_2 == 1) {
+	  state_timer_heater_2 = MIN_STATE_TIME;
+	}
+	state_heater_2 = 0;
+	WRITE(HEATER_2_PIN, 0);
+      }
+    }
+#endif
+    
+#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
+    // BED
+    soft_pwm_b = soft_pwm_bed;
+    if (soft_pwm_b > 0) {
+      // turn ON heather only if the minimum time is up 
+      if (state_timer_heater_b == 0) { 
+	// if change state set timer 
+	if (state_heater_b == 0) {
+	  state_timer_heater_b = MIN_STATE_TIME;
+	}
+	state_heater_b = 1;
+	WRITE(HEATER_BED_PIN, 1);
+      }
+    } else {
+      // turn OFF heather only if the minimum time is up 
+      if (state_timer_heater_b == 0) {
+	// if change state set timer 
+	if (state_heater_b == 1) {
+	  state_timer_heater_b = MIN_STATE_TIME;
+	}
+	state_heater_b = 0;
+	WRITE(HEATER_BED_PIN, 0);
+      }
+    }
+#endif
+  } // if (slow_pwm_count == 0)
+  
+  // EXTRUDER 0 
+  if (soft_pwm_0 < slow_pwm_count) {
+    // turn OFF heather only if the minimum time is up 
+    if (state_timer_heater_0 == 0) { 
+      // if change state set timer 
+      if (state_heater_0 == 1) {
+	state_timer_heater_0 = MIN_STATE_TIME;
+      }
+      state_heater_0 = 0;
+      WRITE(HEATER_0_PIN, 0);
+#ifdef HEATERS_PARALLEL
+      WRITE(HEATER_1_PIN, 0);
+#endif
+    }
+  }
+    
+#if EXTRUDERS > 1
+  // EXTRUDER 1 
+  if (soft_pwm_1 < slow_pwm_count) {
+    // turn OFF heather only if the minimum time is up 
+    if (state_timer_heater_1 == 0) { 
+      // if change state set timer 
+      if (state_heater_1 == 1) {
+	state_timer_heater_1 = MIN_STATE_TIME;
+      }
+      state_heater_1 = 0;
+      WRITE(HEATER_1_PIN, 0);
+    }
+  }
+#endif
+  
+#if EXTRUDERS > 2
+  // EXTRUDER 2
+  if (soft_pwm_2 < slow_pwm_count) {
+    // turn OFF heather only if the minimum time is up 
+    if (state_timer_heater_2 == 0) { 
+      // if change state set timer 
+      if (state_heater_2 == 1) {
+	state_timer_heater_2 = MIN_STATE_TIME;
+      }
+      state_heater_2 = 0;
+      WRITE(HEATER_2_PIN, 0);
+    }
+  }
+#endif
+  
+#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
+  // BED
+  if (soft_pwm_b < slow_pwm_count) {
+    // turn OFF heather only if the minimum time is up 
+    if (state_timer_heater_b == 0) { 
+      // if change state set timer 
+      if (state_heater_b == 1) {
+	state_timer_heater_b = MIN_STATE_TIME;
+      }
+      state_heater_b = 0;
+      WRITE(HEATER_BED_PIN, 0);
+    }
+  }
+#endif
+  
+#ifdef FAN_SOFT_PWM
+  if (pwm_count == 0){
+    soft_pwm_fan = fanSpeedSoftPwm / 2;
+    if (soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0);
+  }
+  if (soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0);
+#endif
+
+  pwm_count += (1 << SOFT_PWM_SCALE);
+  pwm_count &= 0x7f;
+  
+  // increment slow_pwm_count only every 64 pwm_count circa 65.5ms
+  if ((pwm_count % 64) == 0) {
+    slow_pwm_count++;
+    slow_pwm_count &= 0x7f;
+    
+    // Extruder 0
+    if (state_timer_heater_0 > 0) {
+      state_timer_heater_0--;
+    } 
+  
+#if EXTRUDERS > 1
+    // Extruder 1
+    if (state_timer_heater_1 > 0) 
+      state_timer_heater_1--;
+#endif
+    
+#if EXTRUDERS > 2
+    // Extruder 2
+    if (state_timer_heater_2 > 0) 
+      state_timer_heater_2--;
+#endif
+    
+#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
+    // Bed   
+    if (state_timer_heater_b > 0) 
+      state_timer_heater_b--;
+#endif
+  } //if ((pwm_count % 64) == 0) {
+  
+#endif //ifndef SLOW_PWM_HEATERS
+  
+  switch(temp_state) {
+    case 0: // Prepare TEMP_0
+      #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1)
+        #if TEMP_0_PIN > 7
+          ADCSRB = 1<<MUX5;
+        #else
+          ADCSRB = 0;
+        #endif
+        ADMUX = ((1 << REFS0) | (TEMP_0_PIN & 0x07));
+        ADCSRA |= 1<<ADSC; // Start conversion
+      #endif
+      lcd_buttons_update();
+      temp_state = 1;
+      break;
+    case 1: // Measure TEMP_0
+      #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1)
+        raw_temp_0_value += ADC;
+      #endif
+      #ifdef HEATER_0_USES_MAX6675 // TODO remove the blocking
+        raw_temp_0_value = read_max6675();
+      #endif
+      temp_state = 2;
+      break;
+    case 2: // Prepare TEMP_BED
+      #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1)
+        #if TEMP_BED_PIN > 7
+          ADCSRB = 1<<MUX5;
+        #else
+          ADCSRB = 0;
+        #endif
+        ADMUX = ((1 << REFS0) | (TEMP_BED_PIN & 0x07));
+        ADCSRA |= 1<<ADSC; // Start conversion
+      #endif
+      lcd_buttons_update();
+      temp_state = 3;
+      break;
+    case 3: // Measure TEMP_BED
+      #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1)
+        raw_temp_bed_value += ADC;
+      #endif
+      temp_state = 4;
+      break;
+    case 4: // Prepare TEMP_1
+      #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1)
+        #if TEMP_1_PIN > 7
+          ADCSRB = 1<<MUX5;
+        #else
+          ADCSRB = 0;
+        #endif
+        ADMUX = ((1 << REFS0) | (TEMP_1_PIN & 0x07));
+        ADCSRA |= 1<<ADSC; // Start conversion
+      #endif
+      lcd_buttons_update();
+      temp_state = 5;
+      break;
+    case 5: // Measure TEMP_1
+      #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1)
+        raw_temp_1_value += ADC;
+      #endif
+      temp_state = 6;
+      break;
+    case 6: // Prepare TEMP_2
+      #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
+        #if TEMP_2_PIN > 7
+          ADCSRB = 1<<MUX5;
+        #else
+          ADCSRB = 0;
+        #endif
+        ADMUX = ((1 << REFS0) | (TEMP_2_PIN & 0x07));
+        ADCSRA |= 1<<ADSC; // Start conversion
+      #endif
+      lcd_buttons_update();
+      temp_state = 7;
+      break;
+    case 7: // Measure TEMP_2
+      #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
+        raw_temp_2_value += ADC;
+      #endif
+      temp_state = 8;//change so that Filament Width is also measured
+      
+      break;
+    case 8: //Prepare FILWIDTH 
+     #if defined(FILWIDTH_PIN) && (FILWIDTH_PIN> -1) 
+      #if FILWIDTH_PIN>7 
+         ADCSRB = 1<<MUX5;
+      #else
+         ADCSRB = 0; 
+      #endif 
+      ADMUX = ((1 << REFS0) | (FILWIDTH_PIN & 0x07)); 
+      ADCSRA |= 1<<ADSC; // Start conversion 
+     #endif 
+     lcd_buttons_update();       
+     temp_state = 9; 
+     break; 
+    case 9:   //Measure FILWIDTH 
+     #if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
+     //raw_filwidth_value += ADC;  //remove to use an IIR filter approach 
+      if(ADC>102)  //check that ADC is reading a voltage > 0.5 volts, otherwise don't take in the data.
+        {
+    	raw_filwidth_value= raw_filwidth_value-(raw_filwidth_value>>7);  //multipliy raw_filwidth_value by 127/128
+        
+        raw_filwidth_value= raw_filwidth_value + ((unsigned long)ADC<<7);  //add new ADC reading 
+        }
+     #endif
+      temp_state = 10;
+      break;
+    case 10: // Prepare TEMP_AMBIENT
+      #if defined(TEMP_AMBIENT_PIN) && (TEMP_AMBIENT_PIN > -1)
+        #if TEMP_AMBIENT_PIN > 7
+          ADCSRB = 1<<MUX5;
+        #else
+          ADCSRB = 0;
+        #endif
+        ADMUX = ((1 << REFS0) | (TEMP_AMBIENT_PIN & 0x07));
+        ADCSRA |= 1<<ADSC; // Start conversion
+      #endif
+      lcd_buttons_update();
+      temp_state = 11;
+      break;
+    case 11: // Measure TEMP_AMBIENT
+      #if defined(TEMP_AMBIENT_PIN) && (TEMP_AMBIENT_PIN > -1)
+        raw_temp_ambient_value += ADC;
+      #endif
+      temp_state = 12;
+      break;
+    case 12: // Prepare TEMP_PINDA
+      #if defined(TEMP_PINDA_PIN) && (TEMP_PINDA_PIN > -1)
+        #if TEMP_PINDA_PIN > 7
+          ADCSRB = 1<<MUX5;
+        #else
+          ADCSRB = 0;
+        #endif
+        ADMUX = ((1 << REFS0) | (TEMP_PINDA_PIN & 0x07));
+        ADCSRA |= 1<<ADSC; // Start conversion
+      #endif
+      lcd_buttons_update();
+      temp_state = 13;
+      break;
+    case 13: // Measure TEMP_PINDA
+      #if defined(TEMP_PINDA_PIN) && (TEMP_PINDA_PIN > -1)
+        raw_temp_pinda_value += ADC;
+      #endif
+
+	 temp_state = 0;   
+      
+     temp_count++;
+     break;      
+      
+      
+    case 14: //Startup, delay initial temp reading a tiny bit so the hardware can settle.
+      temp_state = 0;
+      break;
+//    default:
+//      SERIAL_ERROR_START;
+//      SERIAL_ERRORLNPGM("Temp measurement error!");
+//      break;
+  }
+    
+  if(temp_count >= OVERSAMPLENR) // 10 * 16 * 1/(16000000/64/256)  = 164ms.
+  {
+    if (!temp_meas_ready) //Only update the raw values if they have been read. Else we could be updating them during reading.
+    {
+		current_temperature_raw[0] = raw_temp_0_value;
+#if EXTRUDERS > 1
+		current_temperature_raw[1] = raw_temp_1_value;
+#endif
+#ifdef TEMP_SENSOR_1_AS_REDUNDANT
+		redundant_temperature_raw = raw_temp_1_value;
+#endif
+#if EXTRUDERS > 2
+		current_temperature_raw[2] = raw_temp_2_value;
+#endif
+#ifdef PINDA_THERMISTOR
+		current_temperature_raw_pinda = raw_temp_pinda_value;
+#endif //PINDA_THERMISTOR
+#ifdef AMBIENT_THERMISTOR
+		current_temperature_raw_ambient = raw_temp_ambient_value;
+#endif //AMBIENT_THERMISTOR
+		current_temperature_bed_raw = raw_temp_bed_value;
+    }
+
+//Add similar code for Filament Sensor - can be read any time since IIR filtering is used 
+#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
+  current_raw_filwidth = raw_filwidth_value>>10;  //need to divide to get to 0-16384 range since we used 1/128 IIR filter approach 
+#endif
+    
+    
+    temp_meas_ready = true;
+    temp_count = 0;
+    raw_temp_0_value = 0;
+    raw_temp_1_value = 0;
+    raw_temp_2_value = 0;
+    raw_temp_bed_value = 0;
+	raw_temp_pinda_value = 0;
+	raw_temp_ambient_value = 0;
+
+#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP
+    if(current_temperature_raw[0] <= maxttemp_raw[0]) {
+#else
+    if(current_temperature_raw[0] >= maxttemp_raw[0]) {
+#endif
+        max_temp_error(0);
+    }
+#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP
+    if(current_temperature_raw[0] >= minttemp_raw[0]) {
+#else
+    if(current_temperature_raw[0] <= minttemp_raw[0]) {
+#endif
+        min_temp_error(0);
+    }
+#if EXTRUDERS > 1
+#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP
+    if(current_temperature_raw[1] <= maxttemp_raw[1]) {
+#else
+    if(current_temperature_raw[1] >= maxttemp_raw[1]) {
+#endif
+        max_temp_error(1);
+    }
+#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP
+    if(current_temperature_raw[1] >= minttemp_raw[1]) {
+#else
+    if(current_temperature_raw[1] <= minttemp_raw[1]) {
+#endif
+        min_temp_error(1);
+    }
+#endif
+#if EXTRUDERS > 2
+#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP
+    if(current_temperature_raw[2] <= maxttemp_raw[2]) {
+#else
+    if(current_temperature_raw[2] >= maxttemp_raw[2]) {
+#endif
+        max_temp_error(2);
+    }
+#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP
+    if(current_temperature_raw[2] >= minttemp_raw[2]) {
+#else
+    if(current_temperature_raw[2] <= minttemp_raw[2]) {
+#endif
+        min_temp_error(2);
+    }
+#endif
+  
+  /* No bed MINTEMP error? */
+        
+        
+#if defined(BED_MAXTEMP) && (TEMP_SENSOR_BED != 0)
+# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP
+    if(current_temperature_bed_raw <= bed_maxttemp_raw) {
+#else
+    if(current_temperature_bed_raw >= bed_maxttemp_raw) {
+#endif
+       target_temperature_bed = 0;
+       bed_max_temp_error();
+    }
+  }
+        
+# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP
+        if(current_temperature_bed_raw >= bed_minttemp_raw) {
+#else
+            if(current_temperature_bed_raw <= bed_minttemp_raw) {
+#endif
+                bed_min_temp_error();
+            }
+            
+#endif
+  
+#ifdef BABYSTEPPING
+  for(uint8_t axis=0;axis<3;axis++)
+  {
+    int curTodo=babystepsTodo[axis]; //get rid of volatile for performance
+   
+    if(curTodo>0)
+    {
+      babystep(axis,/*fwd*/true);
+      babystepsTodo[axis]--; //less to do next time
+    }
+    else
+    if(curTodo<0)
+    {
+      babystep(axis,/*fwd*/false);
+      babystepsTodo[axis]++; //less to do next time
+    }
+  }
+#endif //BABYSTEPPING
+
+  check_fans();
+}
+
+void check_fans() {
+	if (READ(TACH_0) != fan_state[0]) {
+		fan_edge_counter[0] ++;
+		fan_state[0] = !fan_state[0];
+	}
+	//if (READ(TACH_1) != fan_state[1]) {
+	//	fan_edge_counter[1] ++;
+	//	fan_state[1] = !fan_state[1];
+	//}
+}
+
+#ifdef PIDTEMP
+// Apply the scale factors to the PID values
+
+
+float scalePID_i(float i)
+{
+	return i*PID_dT;
+}
+
+float unscalePID_i(float i)
+{
+	return i/PID_dT;
+}
+
+float scalePID_d(float d)
+{
+    return d/PID_dT;
+}
+
+float unscalePID_d(float d)
+{
+	return d*PID_dT;
+}
+
+#endif //PIDTEMP
+
+

+ 228 - 209
Firmware/temperature.h

@@ -1,209 +1,228 @@
-/*
-  temperature.h - temperature controller
-  Part of Marlin
-
-  Copyright (c) 2011 Erik van der Zalm
-
-  Grbl is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  Grbl is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with Grbl.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef temperature_h
-#define temperature_h 
-
-#include "Marlin.h"
-#include "planner.h"
-#ifdef PID_ADD_EXTRUSION_RATE
-  #include "stepper.h"
-#endif
-
-// public functions
-void tp_init();  //initialize the heating
-void manage_heater(); //it is critical that this is called periodically.
-
-#ifdef FILAMENT_SENSOR
-// For converting raw Filament Width to milimeters 
- float analog2widthFil(); 
- 
-// For converting raw Filament Width to an extrusion ratio 
- int widthFil_to_size_ratio();
-#endif
-
-// low level conversion routines
-// do not use these routines and variables outside of temperature.cpp
-extern int target_temperature[EXTRUDERS];  
-extern float current_temperature[EXTRUDERS];
-#ifdef SHOW_TEMP_ADC_VALUES
-  extern int current_temperature_raw[EXTRUDERS];
-  extern int current_temperature_bed_raw;
-#endif
-extern int target_temperature_bed;
-extern float current_temperature_bed;
-#ifdef TEMP_SENSOR_1_AS_REDUNDANT
-  extern float redundant_temperature;
-#endif
-
-#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1
-  extern unsigned char soft_pwm_bed;
-#endif
-
-#ifdef PIDTEMP
-  extern float Kp,Ki,Kd,Kc;
-  float scalePID_i(float i);
-  float scalePID_d(float d);
-  float unscalePID_i(float i);
-  float unscalePID_d(float d);
-
-#endif
-#ifdef PIDTEMPBED
-  extern float bedKp,bedKi,bedKd;
-#endif
-  
-  
-#ifdef BABYSTEPPING
-  extern volatile int babystepsTodo[3];
-#endif
-
-inline void babystepsTodoZadd(int n)
-{
-    if (n != 0) {
-        CRITICAL_SECTION_START
-        babystepsTodo[Z_AXIS] += n;
-        CRITICAL_SECTION_END
-    }
-}
-
-inline void babystepsTodoZsubtract(int n)
-{
-    if (n != 0) {
-        CRITICAL_SECTION_START
-        babystepsTodo[Z_AXIS] -= n;
-        CRITICAL_SECTION_END
-    }
-}
-
-//high level conversion routines, for use outside of temperature.cpp
-//inline so that there is no performance decrease.
-//deg=degreeCelsius
-
-FORCE_INLINE float degHotend(uint8_t extruder) {  
-  return current_temperature[extruder];
-};
-
-#ifdef SHOW_TEMP_ADC_VALUES
-  FORCE_INLINE float rawHotendTemp(uint8_t extruder) {  
-    return current_temperature_raw[extruder];
-  };
-
-  FORCE_INLINE float rawBedTemp() {  
-    return current_temperature_bed_raw;
-  };
-#endif
-
-FORCE_INLINE float degBed() {
-  return current_temperature_bed;
-};
-
-FORCE_INLINE float degTargetHotend(uint8_t extruder) {  
-  return target_temperature[extruder];
-};
-
-FORCE_INLINE float degTargetBed() {   
-  return target_temperature_bed;
-};
-
-FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {  
-  target_temperature[extruder] = celsius;
-};
-
-FORCE_INLINE void setTargetBed(const float &celsius) {  
-  target_temperature_bed = celsius;
-};
-
-FORCE_INLINE bool isHeatingHotend(uint8_t extruder){  
-  return target_temperature[extruder] > current_temperature[extruder];
-};
-
-FORCE_INLINE bool isHeatingBed() {
-  return target_temperature_bed > current_temperature_bed;
-};
-
-FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {  
-  return target_temperature[extruder] < current_temperature[extruder];
-};
-
-FORCE_INLINE bool isCoolingBed() {
-  return target_temperature_bed < current_temperature_bed;
-};
-
-#define degHotend0() degHotend(0)
-#define degTargetHotend0() degTargetHotend(0)
-#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0)
-#define isHeatingHotend0() isHeatingHotend(0)
-#define isCoolingHotend0() isCoolingHotend(0)
-#if EXTRUDERS > 1
-#define degHotend1() degHotend(1)
-#define degTargetHotend1() degTargetHotend(1)
-#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
-#define isHeatingHotend1() isHeatingHotend(1)
-#define isCoolingHotend1() isCoolingHotend(1)
-#else
-#define setTargetHotend1(_celsius) do{}while(0)
-#endif
-#if EXTRUDERS > 2
-#define degHotend2() degHotend(2)
-#define degTargetHotend2() degTargetHotend(2)
-#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
-#define isHeatingHotend2() isHeatingHotend(2)
-#define isCoolingHotend2() isCoolingHotend(2)
-#else
-#define setTargetHotend2(_celsius) do{}while(0)
-#endif
-#if EXTRUDERS > 3
-#error Invalid number of extruders
-#endif
-
-#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0)
-static float temp_runaway_status[4];
-static float temp_runaway_target[4];
-static float temp_runaway_timer[4];
-static int temp_runaway_error_counter[4];
-
-void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed);
-void temp_runaway_stop();
-#endif
-
-int getHeaterPower(int heater);
-void disable_heater();
-void setWatch();
-void updatePID();
-
-
-FORCE_INLINE void autotempShutdown(){
- #ifdef AUTOTEMP
- if(autotemp_enabled)
- {
-  autotemp_enabled=false;
-  if(degTargetHotend(active_extruder)>autotemp_min)
-    setTargetHotend(0,active_extruder);
- }
- #endif
-}
-
-void PID_autotune(float temp, int extruder, int ncycles);
-
-void setExtruderAutoFanState(int pin, bool state);
-void checkExtruderAutoFans();
-
-#endif
-
+/*
+  temperature.h - temperature controller
+  Part of Marlin
+
+  Copyright (c) 2011 Erik van der Zalm
+
+  Grbl is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Grbl is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Grbl.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef temperature_h
+#define temperature_h 
+
+#include "Marlin.h"
+#include "planner.h"
+#ifdef PID_ADD_EXTRUSION_RATE
+  #include "stepper.h"
+#endif
+
+// public functions
+void tp_init();  //initialize the heating
+void manage_heater(); //it is critical that this is called periodically.
+
+#ifdef FILAMENT_SENSOR
+// For converting raw Filament Width to milimeters 
+ float analog2widthFil(); 
+ 
+// For converting raw Filament Width to an extrusion ratio 
+ int widthFil_to_size_ratio();
+#endif
+
+// low level conversion routines
+// do not use these routines and variables outside of temperature.cpp
+extern int target_temperature[EXTRUDERS];  
+extern float current_temperature[EXTRUDERS];
+#ifdef SHOW_TEMP_ADC_VALUES
+  extern int current_temperature_raw[EXTRUDERS];
+  extern int current_temperature_bed_raw;
+#endif
+extern int target_temperature_bed;
+extern float current_temperature_bed;
+
+#ifdef PINDA_THERMISTOR
+//extern int current_temperature_raw_pinda;
+extern float current_temperature_pinda;
+#endif
+
+#ifdef AMBIENT_THERMISTOR
+//extern int current_temperature_raw_ambient;
+extern float current_temperature_ambient;
+#endif
+
+#ifdef TEMP_SENSOR_1_AS_REDUNDANT
+  extern float redundant_temperature;
+#endif
+
+#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1
+  extern unsigned char soft_pwm_bed;
+#endif
+
+#ifdef PIDTEMP
+  extern int pid_cycle, pid_number_of_cycles;
+  extern float Kp,Ki,Kd,Kc,_Kp,_Ki,_Kd;
+  extern bool pid_tuning_finished;
+  float scalePID_i(float i);
+  float scalePID_d(float d);
+  float unscalePID_i(float i);
+  float unscalePID_d(float d);
+
+#endif
+#ifdef PIDTEMPBED
+  extern float bedKp,bedKi,bedKd;
+#endif
+  
+  
+#ifdef BABYSTEPPING
+  extern volatile int babystepsTodo[3];
+#endif
+
+inline void babystepsTodoZadd(int n)
+{
+    if (n != 0) {
+        CRITICAL_SECTION_START
+        babystepsTodo[Z_AXIS] += n;
+        CRITICAL_SECTION_END
+    }
+}
+
+inline void babystepsTodoZsubtract(int n)
+{
+    if (n != 0) {
+        CRITICAL_SECTION_START
+        babystepsTodo[Z_AXIS] -= n;
+        CRITICAL_SECTION_END
+    }
+}
+
+//high level conversion routines, for use outside of temperature.cpp
+//inline so that there is no performance decrease.
+//deg=degreeCelsius
+
+FORCE_INLINE float degHotend(uint8_t extruder) {  
+  return current_temperature[extruder];
+};
+
+#ifdef SHOW_TEMP_ADC_VALUES
+  FORCE_INLINE float rawHotendTemp(uint8_t extruder) {  
+    return current_temperature_raw[extruder];
+  };
+
+  FORCE_INLINE float rawBedTemp() {  
+    return current_temperature_bed_raw;
+  };
+#endif
+
+FORCE_INLINE float degBed() {
+  return current_temperature_bed;
+};
+
+FORCE_INLINE float degTargetHotend(uint8_t extruder) {  
+  return target_temperature[extruder];
+};
+
+FORCE_INLINE float degTargetBed() {   
+  return target_temperature_bed;
+};
+
+FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {  
+  target_temperature[extruder] = celsius;
+};
+
+FORCE_INLINE void setTargetBed(const float &celsius) {  
+  target_temperature_bed = celsius;
+};
+
+FORCE_INLINE bool isHeatingHotend(uint8_t extruder){  
+  return target_temperature[extruder] > current_temperature[extruder];
+};
+
+FORCE_INLINE bool isHeatingBed() {
+  return target_temperature_bed > current_temperature_bed;
+};
+
+FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {  
+  return target_temperature[extruder] < current_temperature[extruder];
+};
+
+FORCE_INLINE bool isCoolingBed() {
+  return target_temperature_bed < current_temperature_bed;
+};
+
+#define degHotend0() degHotend(0)
+#define degTargetHotend0() degTargetHotend(0)
+#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0)
+#define isHeatingHotend0() isHeatingHotend(0)
+#define isCoolingHotend0() isCoolingHotend(0)
+#if EXTRUDERS > 1
+#define degHotend1() degHotend(1)
+#define degTargetHotend1() degTargetHotend(1)
+#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
+#define isHeatingHotend1() isHeatingHotend(1)
+#define isCoolingHotend1() isCoolingHotend(1)
+#else
+#define setTargetHotend1(_celsius) do{}while(0)
+#endif
+#if EXTRUDERS > 2
+#define degHotend2() degHotend(2)
+#define degTargetHotend2() degTargetHotend(2)
+#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
+#define isHeatingHotend2() isHeatingHotend(2)
+#define isCoolingHotend2() isCoolingHotend(2)
+#else
+#define setTargetHotend2(_celsius) do{}while(0)
+#endif
+#if EXTRUDERS > 3
+#error Invalid number of extruders
+#endif
+
+#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0)
+static float temp_runaway_status[4];
+static float temp_runaway_target[4];
+static float temp_runaway_timer[4];
+static int temp_runaway_error_counter[4];
+
+void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed);
+void temp_runaway_stop(bool isPreheat, bool isBed);
+#endif
+
+int getHeaterPower(int heater);
+void disable_heater();
+void setWatch();
+void updatePID();
+
+
+FORCE_INLINE void autotempShutdown(){
+ #ifdef AUTOTEMP
+ if(autotemp_enabled)
+ {
+  autotemp_enabled=false;
+  if(degTargetHotend(active_extruder)>autotemp_min)
+    setTargetHotend(0,active_extruder);
+ }
+ #endif
+}
+
+void PID_autotune(float temp, int extruder, int ncycles);
+
+void setExtruderAutoFanState(int pin, bool state);
+void checkExtruderAutoFans();
+
+void countFanSpeed();
+void checkFanSpeed();
+void fanSpeedError(unsigned char _fan);
+
+void check_fans();
+
+#endif
+

+ 166 - 0
Firmware/thermistortables.h

@@ -1033,7 +1033,9 @@ const short temptable_12[][2] PROGMEM = {
 
 #define PtA 3.9083E-3
 #define PtB -5.775E-7
+#define PtC -4.183E-12
 #define PtRt(T,R0) ((R0)*(1.0+(PtA)*(T)+(PtB)*(T)*(T)))
+#define PtRtNew(T,R0) ((R0)*(1.0+(PtA)*(T)+(PtB)*(T)*(T) + (T-100)*PtC*(T)*(T)*(T)))
 #define PtAdVal(T,R0,Rup) (short)(1024/(Rup/PtRt(T,R0)+1))
 #define PtLine(T,R0,Rup) { PtAdVal(T,R0,Rup)*OVERSAMPLENR, T },
 
@@ -1061,6 +1063,124 @@ const short temptable_147[][2] PROGMEM = {
   PtLine(300,100,4700)
 };
 #endif
+// E3D Pt100 with 4k7 MiniRambo pullup, no Amp on the MiniRambo v1.3a
+#if (THERMISTORHEATER_0 == 148) || (THERMISTORHEATER_1 == 148) || (THERMISTORHEATER_2 == 148) || (THERMISTORBED == 148)
+const short temptable_148[][2] PROGMEM = {
+// These values have been calculated and tested over many days.  See https://docs.google.com/spreadsheets/d/1MJXa6feEe0mGVCT2TrBwLxVOMoLDkJlvfQ4JXhAdV_E
+// Values that are missing from the 5C gap are missing due to resolution limits.
+{19.00000 * OVERSAMPLENR,  0},
+{19.25000 * OVERSAMPLENR,  5},
+{19.50000 * OVERSAMPLENR, 10},
+{19.87500 * OVERSAMPLENR, 15},
+{20.25000 * OVERSAMPLENR, 20},
+{21.00000 * OVERSAMPLENR, 25},
+{21.75000 * OVERSAMPLENR, 35},
+{22.00000 * OVERSAMPLENR, 40},
+{23.00000 * OVERSAMPLENR, 50},  // 55C is more commonly used.
+{23.75000 * OVERSAMPLENR, 60},
+{24.00000 * OVERSAMPLENR, 65},
+{24.06250 * OVERSAMPLENR, 70},
+{25.00000 * OVERSAMPLENR, 75},
+{25.50000 * OVERSAMPLENR, 85},
+{26.00000 * OVERSAMPLENR, 90},
+{26.93750 * OVERSAMPLENR,100},
+{27.00000 * OVERSAMPLENR,105},
+{27.37500 * OVERSAMPLENR,110},
+{28.00000 * OVERSAMPLENR,115},
+{29.00000 * OVERSAMPLENR,125},
+{29.25000 * OVERSAMPLENR,135},
+{30.00000 * OVERSAMPLENR,140},
+{35.50000 * OVERSAMPLENR,150},
+{31.00000 * OVERSAMPLENR,155},
+{32.00000 * OVERSAMPLENR,165},
+{32.18750 * OVERSAMPLENR,175},
+{33.00000 * OVERSAMPLENR,180},
+{33.62500 * OVERSAMPLENR,190},
+{34.00000 * OVERSAMPLENR,195},
+{35.00000 * OVERSAMPLENR,205},
+{35.50000 * OVERSAMPLENR,215},
+{36.00000 * OVERSAMPLENR,220},
+{36.75000 * OVERSAMPLENR,230},
+{37.00000 * OVERSAMPLENR,235},
+{37.75000 * OVERSAMPLENR,245},
+{38.00000 * OVERSAMPLENR,250},
+{38.12500 * OVERSAMPLENR,255},
+{39.00000 * OVERSAMPLENR,260},
+{40.00000 * OVERSAMPLENR,275},
+{40.25000 * OVERSAMPLENR,285},
+{41.00000 * OVERSAMPLENR,290},
+{41.25000 * OVERSAMPLENR,300},
+{42.00000 * OVERSAMPLENR,305},
+{43.00000 * OVERSAMPLENR,315},
+{43.25000 * OVERSAMPLENR,325},
+{44.00000 * OVERSAMPLENR,330},
+{44.18750 * OVERSAMPLENR,340},
+{45.00000 * OVERSAMPLENR,345},
+{45.25000 * OVERSAMPLENR,355},
+{46.00000 * OVERSAMPLENR,360},
+{46.62500 * OVERSAMPLENR,370},
+{47.00000 * OVERSAMPLENR,375},
+{47.25000 * OVERSAMPLENR,385},
+{48.00000 * OVERSAMPLENR,390},
+{48.75000 * OVERSAMPLENR,400},
+{49.00000 * OVERSAMPLENR,405},
+};
+#endif
+#if (THERMISTORHEATER_0 == 247) || (THERMISTORHEATER_1 == 247) || (THERMISTORHEATER_2 == 247) || (THERMISTORBED == 247) // Pt100 with 4k7 MiniRambo pullup & PT100 Amplifier
+const short temptable_247[][2] PROGMEM = {
+// Calculated from Bob-the-Kuhn's PT100 calculator listed in https://github.com/MarlinFirmware/Marlin/issues/5543
+// and the table provided by E3D at http://wiki.e3d-online.com/wiki/E3D_PT100_Amplifier_Documentation#Output_Characteristics.
+{  0 * OVERSAMPLENR,    0},
+{241 * OVERSAMPLENR,    1},
+{249 * OVERSAMPLENR,   10},
+{259 * OVERSAMPLENR,   20},
+{267 * OVERSAMPLENR,   30},
+{275 * OVERSAMPLENR,   40},
+{283 * OVERSAMPLENR,   50},
+{291 * OVERSAMPLENR,   60},
+{299 * OVERSAMPLENR,   70},
+{307 * OVERSAMPLENR,   80},
+{315 * OVERSAMPLENR,   90},
+{323 * OVERSAMPLENR,  100},
+{331 * OVERSAMPLENR,  110},
+{340 * OVERSAMPLENR,  120},
+{348 * OVERSAMPLENR,  130},
+{354 * OVERSAMPLENR,  140},
+{362 * OVERSAMPLENR,  150},
+{370 * OVERSAMPLENR,  160},
+{378 * OVERSAMPLENR,  170},
+{386 * OVERSAMPLENR,  180},
+{394 * OVERSAMPLENR,  190},
+{402 * OVERSAMPLENR,  200},
+{410 * OVERSAMPLENR,  210},
+{418 * OVERSAMPLENR,  220},
+{426 * OVERSAMPLENR,  230},
+{432 * OVERSAMPLENR,  240},
+{440 * OVERSAMPLENR,  250},
+{448 * OVERSAMPLENR,  260},
+{454 * OVERSAMPLENR,  270},
+{462 * OVERSAMPLENR,  280},
+{469 * OVERSAMPLENR,  290},
+{475 * OVERSAMPLENR,  300},
+{483 * OVERSAMPLENR,  310},
+{491 * OVERSAMPLENR,  320},
+{499 * OVERSAMPLENR,  330},
+{505 * OVERSAMPLENR,  340},
+{513 * OVERSAMPLENR,  350},
+{519 * OVERSAMPLENR,  360},
+{527 * OVERSAMPLENR,  370},
+{533 * OVERSAMPLENR,  380},
+{541 * OVERSAMPLENR,  390},
+{549 * OVERSAMPLENR,  400},
+{616 * OVERSAMPLENR,  500},
+{682 * OVERSAMPLENR,  600},
+{741 * OVERSAMPLENR,  700},
+{801 * OVERSAMPLENR,  800},
+{856 * OVERSAMPLENR,  900},
+{910 * OVERSAMPLENR, 1000},
+{960 * OVERSAMPLENR, 1100},
+};
+#endif
 #if (THERMISTORHEATER_0 == 1010) || (THERMISTORHEATER_1 == 1010) || (THERMISTORHEATER_2 == 1010) || (THERMISTORBED == 1010) // Pt1000 with 1k0 pullup
 const short temptable_1010[][2] PROGMEM = {
   PtLine(0,1000,1000)
@@ -1091,6 +1211,47 @@ const short temptable_1047[][2] PROGMEM = {
 };
 #endif
 
+#if (THERMISTORAMBIENT == 2000) //100k thermistor NTCG104LH104JT1
+const short temptable_2000[][2] PROGMEM = {
+// Source: https://product.tdk.com/info/en/catalog/datasheets/503021/tpd_ntc-thermistor_ntcg_en.pdf
+// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
+{305*OVERSAMPLENR, 125},
+{338*OVERSAMPLENR, 120},
+{374*OVERSAMPLENR, 115},
+{412*OVERSAMPLENR, 110},
+{452*OVERSAMPLENR, 105},
+{494*OVERSAMPLENR, 100},
+{536*OVERSAMPLENR, 95},
+{580*OVERSAMPLENR, 90},
+{623*OVERSAMPLENR, 85},
+{665*OVERSAMPLENR, 80},
+{706*OVERSAMPLENR, 75},
+{744*OVERSAMPLENR, 70},
+{780*OVERSAMPLENR, 65},
+{813*OVERSAMPLENR, 60},
+{843*OVERSAMPLENR, 55},
+{869*OVERSAMPLENR, 50},
+{892*OVERSAMPLENR, 45},
+{912*OVERSAMPLENR, 40},
+{929*OVERSAMPLENR, 35},
+{943*OVERSAMPLENR, 30},
+{955*OVERSAMPLENR, 25},
+{965*OVERSAMPLENR, 20},
+{973*OVERSAMPLENR, 15},
+{979*OVERSAMPLENR, 10},
+{984*OVERSAMPLENR, 5},
+{988*OVERSAMPLENR, 0},
+{991*OVERSAMPLENR, -5},
+{993*OVERSAMPLENR, -10},
+{995*OVERSAMPLENR, -15},
+{996*OVERSAMPLENR, -20},
+{997*OVERSAMPLENR, -25},
+{998*OVERSAMPLENR, -30},
+{999*OVERSAMPLENR, -35},
+{999*OVERSAMPLENR, -40},
+};
+#endif
+
 #define _TT_NAME(_N) temptable_ ## _N
 #define TT_NAME(_N) _TT_NAME(_N)
 
@@ -1172,6 +1333,11 @@ const short temptable_1047[][2] PROGMEM = {
 # endif // BED_USES_THERMISTOR
 #endif
 
+#ifdef THERMISTORAMBIENT
+# define AMBIENTTEMPTABLE TT_NAME(THERMISTORAMBIENT)
+# define AMBIENTTEMPTABLE_LEN (sizeof(AMBIENTTEMPTABLE)/sizeof(*AMBIENTTEMPTABLE))
+#endif
+
 //Set the high and low raw values for the heater, this indicates which raw value is a high or low temperature
 #ifndef HEATER_BED_RAW_HI_TEMP
 # ifdef BED_USES_THERMISTOR   //In case of a thermistor the highest temperature results in the lowest ADC value

+ 780 - 0
Firmware/tmc2130.cpp

@@ -0,0 +1,780 @@
+#include "Marlin.h"
+
+#ifdef TMC2130
+
+#include "tmc2130.h"
+#include <SPI.h>
+#include "LiquidCrystal.h"
+#include "ultralcd.h"
+
+extern LiquidCrystal lcd;
+
+#define TMC2130_GCONF_NORMAL 0x00000000 // spreadCycle
+#define TMC2130_GCONF_SGSENS 0x00003180 // spreadCycle with stallguard (stall activates DIAG0 and DIAG1 [pushpull])
+#define TMC2130_GCONF_SILENT 0x00000004 // stealthChop
+
+//externals for debuging
+extern float current_position[4];
+extern void st_get_position_xy(long &x, long &y);
+extern long st_get_position(uint8_t axis);
+extern void crashdet_stop_and_save_print();
+extern void crashdet_stop_and_save_print2();
+
+//chipselect pins
+uint8_t tmc2130_cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS };
+//diag pins
+uint8_t tmc2130_diag[4] = { X_TMC2130_DIAG, Y_TMC2130_DIAG, Z_TMC2130_DIAG, E0_TMC2130_DIAG };
+//mode
+uint8_t tmc2130_mode = TMC2130_MODE_NORMAL;
+//holding currents
+uint8_t tmc2130_current_h[4] = TMC2130_CURRENTS_H;
+//running currents
+uint8_t tmc2130_current_r[4] = TMC2130_CURRENTS_R;
+//axis stalled flags
+uint8_t tmc2130_axis_stalled[4] = {0, 0, 0, 0};
+
+//running currents for homing
+uint8_t tmc2130_current_r_home[4] = {10, 10, 20, 10};
+
+
+//pwm_ampl
+uint8_t tmc2130_pwm_ampl[2] = {TMC2130_PWM_AMPL_X, TMC2130_PWM_AMPL_Y};
+//pwm_grad
+uint8_t tmc2130_pwm_grad[2] = {TMC2130_PWM_GRAD_X, TMC2130_PWM_GRAD_Y};
+//pwm_auto
+uint8_t tmc2130_pwm_auto[2] = {TMC2130_PWM_AUTO_X, TMC2130_PWM_AUTO_Y};
+//pwm_freq
+uint8_t tmc2130_pwm_freq[2] = {TMC2130_PWM_FREQ_X, TMC2130_PWM_FREQ_Y};
+
+uint8_t tmc2130_mres[4] = {0, 0, 0, 0}; //will be filed at begin of init
+
+
+uint8_t tmc2130_sg_thr[4] = {TMC2130_SG_THRS_X, TMC2130_SG_THRS_Y, TMC2130_SG_THRS_Z, TMC2130_SG_THRS_E};
+uint8_t tmc2130_sg_thr_home[4] = {3, 3, TMC2130_SG_THRS_Z, TMC2130_SG_THRS_E};
+
+uint32_t tmc2130_sg_pos[4] = {0, 0, 0, 0};
+
+uint8_t sg_homing_axes_mask = 0x00;
+
+uint8_t tmc2130_sg_meassure = 0xff;
+uint16_t tmc2130_sg_meassure_cnt = 0;
+uint32_t tmc2130_sg_meassure_val = 0;
+
+
+bool tmc2130_sg_stop_on_crash = true;
+bool tmc2130_sg_crash = false;
+uint8_t tmc2130_diag_mask = 0x00;
+uint16_t tmc2130_sg_err[4] = {0, 0, 0, 0};
+uint16_t tmc2130_sg_cnt[4] = {0, 0, 0, 0};
+bool tmc2130_sg_change = false;
+
+
+bool skip_debug_msg = false;
+
+//TMC2130 registers
+#define TMC2130_REG_GCONF      0x00 // 17 bits
+#define TMC2130_REG_GSTAT      0x01 // 3 bits
+#define TMC2130_REG_IOIN       0x04 // 8+8 bits
+#define TMC2130_REG_IHOLD_IRUN 0x10 // 5+5+4 bits
+#define TMC2130_REG_TPOWERDOWN 0x11 // 8 bits
+#define TMC2130_REG_TSTEP      0x12 // 20 bits
+#define TMC2130_REG_TPWMTHRS   0x13 // 20 bits
+#define TMC2130_REG_TCOOLTHRS  0x14 // 20 bits
+#define TMC2130_REG_THIGH      0x15 // 20 bits
+#define TMC2130_REG_XDIRECT    0x2d // 32 bits
+#define TMC2130_REG_VDCMIN     0x33 // 23 bits
+#define TMC2130_REG_MSLUT0     0x60 // 32 bits
+#define TMC2130_REG_MSLUT1     0x61 // 32 bits
+#define TMC2130_REG_MSLUT2     0x62 // 32 bits
+#define TMC2130_REG_MSLUT3     0x63 // 32 bits
+#define TMC2130_REG_MSLUT4     0x64 // 32 bits
+#define TMC2130_REG_MSLUT5     0x65 // 32 bits
+#define TMC2130_REG_MSLUT6     0x66 // 32 bits
+#define TMC2130_REG_MSLUT7     0x67 // 32 bits
+#define TMC2130_REG_MSLUTSEL   0x68 // 32 bits
+#define TMC2130_REG_MSLUTSTART 0x69 // 8+8 bits
+#define TMC2130_REG_MSCNT      0x6a // 10 bits
+#define TMC2130_REG_MSCURACT   0x6b // 9+9 bits
+#define TMC2130_REG_CHOPCONF   0x6c // 32 bits
+#define TMC2130_REG_COOLCONF   0x6d // 25 bits
+#define TMC2130_REG_DCCTRL     0x6e // 24 bits
+#define TMC2130_REG_DRV_STATUS 0x6f // 32 bits
+#define TMC2130_REG_PWMCONF    0x70 // 22 bits
+#define TMC2130_REG_PWM_SCALE  0x71 // 8 bits
+#define TMC2130_REG_ENCM_CTRL  0x72 // 2 bits
+#define TMC2130_REG_LOST_STEPS 0x73 // 20 bits
+
+
+uint16_t tmc2130_rd_TSTEP(uint8_t cs);
+uint16_t tmc2130_rd_MSCNT(uint8_t cs);
+uint16_t tmc2130_rd_DRV_STATUS(uint8_t cs);
+
+void tmc2130_wr_CHOPCONF(uint8_t cs, uint8_t toff = 3, uint8_t hstrt = 4, uint8_t hend = 1, uint8_t fd3 = 0, uint8_t disfdcc = 0, uint8_t rndtf = 0, uint8_t chm = 0, uint8_t tbl = 2, uint8_t vsense = 0, uint8_t vhighfs = 0, uint8_t vhighchm = 0, uint8_t sync = 0, uint8_t mres = 0b0100, uint8_t intpol = 1, uint8_t dedge = 0, uint8_t diss2g = 0);
+void tmc2130_wr_PWMCONF(uint8_t cs, uint8_t pwm_ampl, uint8_t pwm_grad, uint8_t pwm_freq, uint8_t pwm_auto, uint8_t pwm_symm, uint8_t freewheel);
+void tmc2130_wr_TPWMTHRS(uint8_t cs, uint32_t val32);
+void tmc2130_wr_THIGH(uint8_t cs, uint32_t val32);
+
+uint8_t tmc2130_axis_by_cs(uint8_t cs);
+uint8_t tmc2130_calc_mres(uint16_t microstep_resolution);
+
+uint8_t tmc2130_wr(uint8_t cs, uint8_t addr, uint32_t wval);
+uint8_t tmc2130_rd(uint8_t cs, uint8_t addr, uint32_t* rval);
+uint8_t tmc2130_txrx(uint8_t cs, uint8_t addr, uint32_t wval, uint32_t* rval);
+
+
+void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_t current_r);
+
+
+
+void tmc2130_init()
+{
+	tmc2130_mres[0] = tmc2130_calc_mres(TMC2130_USTEPS_XY);
+	tmc2130_mres[1] = tmc2130_calc_mres(TMC2130_USTEPS_XY);
+	tmc2130_mres[2] = tmc2130_calc_mres(TMC2130_USTEPS_Z);
+	tmc2130_mres[3] = tmc2130_calc_mres(TMC2130_USTEPS_E);
+	MYSERIAL.print("tmc2130_init mode=");
+	MYSERIAL.println(tmc2130_mode, DEC);
+	WRITE(X_TMC2130_CS, HIGH);
+	WRITE(Y_TMC2130_CS, HIGH);
+	WRITE(Z_TMC2130_CS, HIGH);
+	WRITE(E0_TMC2130_CS, HIGH);
+	SET_OUTPUT(X_TMC2130_CS);
+	SET_OUTPUT(Y_TMC2130_CS);
+	SET_OUTPUT(Z_TMC2130_CS);
+	SET_OUTPUT(E0_TMC2130_CS);
+	SET_INPUT(X_TMC2130_DIAG);
+	SET_INPUT(Y_TMC2130_DIAG);
+	SET_INPUT(Z_TMC2130_DIAG);
+	SET_INPUT(E0_TMC2130_DIAG);
+	SPI.begin();
+	for (int axis = 0; axis < 2; axis++) // X Y axes
+	{
+/*		if (tmc2130_current_r[axis] <= 31)
+		{
+			tmc2130_wr_CHOPCONF(tmc2130_cs[axis], 3, 5, 1, 0, 0, 0, 0, 2, 1, 0, 0, 0, mres, TMC2130_INTPOL_XY, 0, 0);
+			tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((tmc2130_current_r[axis] & 0x1f) << 8) | (tmc2130_current_h[axis] & 0x1f));
+		}
+		else
+		{
+			tmc2130_wr_CHOPCONF(tmc2130_cs[axis], 3, 5, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, mres, TMC2130_INTPOL_XY, 0, 0);
+			tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_IHOLD_IRUN, 0x000f0000 | (((tmc2130_current_r[axis] >> 1) & 0x1f) << 8) | ((tmc2130_current_h[axis] >> 1) & 0x1f));
+		}*/
+		tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+
+//		tmc2130_wr_CHOPCONF(tmc2130_cs[axis], 3, 5, 1, 0, 0, 0, 0, 2, 1, 0, 0, 0, mres, TMC2130_INTPOL_XY, 0, 0);
+//		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((tmc2130_current_r[axis] & 0x1f) << 8) | (tmc2130_current_h[axis] & 0x1f));
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_TPOWERDOWN, 0x00000000);
+//		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16) | ((uint32_t)1 << 24));
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16));
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_TCOOLTHRS, (tmc2130_mode == TMC2130_MODE_SILENT)?0:((axis==X_AXIS)?TMC2130_TCOOLTHRS_X:TMC2130_TCOOLTHRS_Y));
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, (tmc2130_mode == TMC2130_MODE_SILENT)?TMC2130_GCONF_SILENT:TMC2130_GCONF_SGSENS);
+		tmc2130_wr_PWMCONF(tmc2130_cs[axis], tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0);
+		tmc2130_wr_TPWMTHRS(tmc2130_cs[axis], TMC2130_TPWMTHRS);
+		//tmc2130_wr_THIGH(tmc2130_cs[axis], TMC2130_THIGH);
+	}
+	for (int axis = 2; axis < 3; axis++) // Z axis
+	{
+//		uint8_t mres = tmc2130_mres(TMC2130_USTEPS_Z);
+/*		if (tmc2130_current_r[axis] <= 31)
+		{
+			tmc2130_wr_CHOPCONF(tmc2130_cs[axis], 3, 5, 1, 0, 0, 0, 0, 2, 1, 0, 0, 0, mres, TMC2130_INTPOL_Z, 0, 0);
+			tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((tmc2130_current_r[axis] & 0x1f) << 8) | (tmc2130_current_h[axis] & 0x1f));
+		}
+		else
+		{
+			tmc2130_wr_CHOPCONF(tmc2130_cs[axis], 3, 5, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, mres, TMC2130_INTPOL_Z, 0, 0);
+			tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_IHOLD_IRUN, 0x000f0000 | (((tmc2130_current_r[axis] >> 1) & 0x1f) << 8) | ((tmc2130_current_h[axis] >> 1) & 0x1f));
+		}*/
+		tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_TPOWERDOWN, 0x00000000);
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS);
+	}
+	for (int axis = 3; axis < 4; axis++) // E axis
+	{
+//		uint8_t mres = tmc2130_mres(TMC2130_USTEPS_E);
+		tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+
+//		tmc2130_wr_CHOPCONF(tmc2130_cs[axis], 3, 5, 1, 0, 0, 0, 0, 2, 1, 0, 0, 0, mres, TMC2130_INTPOL_E, 0, 0);
+//		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((tmc2130_current_r[axis] & 0x1f) << 8) | (tmc2130_current_h[axis] & 0x1f));
+
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_TPOWERDOWN, 0x00000000);
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS);
+	}
+
+	tmc2130_sg_err[0] = 0;
+	tmc2130_sg_err[1] = 0;
+	tmc2130_sg_err[2] = 0;
+	tmc2130_sg_err[3] = 0;
+	tmc2130_sg_cnt[0] = 0;
+	tmc2130_sg_cnt[1] = 0;
+	tmc2130_sg_cnt[2] = 0;
+	tmc2130_sg_cnt[3] = 0;
+}
+
+uint8_t tmc2130_sample_diag()
+{
+	uint8_t mask = 0;
+	if (READ(X_TMC2130_DIAG)) mask |= X_AXIS_MASK;
+	if (READ(Y_TMC2130_DIAG)) mask |= Y_AXIS_MASK;
+//	if (READ(Z_TMC2130_DIAG)) mask |= Z_AXIS_MASK;
+//	if (READ(E0_TMC2130_DIAG)) mask |= E_AXIS_MASK;
+	return mask;
+}
+
+void tmc2130_st_isr(uint8_t last_step_mask)
+{
+	if (tmc2130_mode == TMC2130_MODE_SILENT || tmc2130_sg_stop_on_crash == false) return;
+	bool crash = false;
+	uint8_t diag_mask = tmc2130_sample_diag();
+//	for (uint8_t axis = X_AXIS; axis <= E_AXIS; axis++)
+	for (uint8_t axis = X_AXIS; axis <= Y_AXIS; axis++)
+	{
+		uint8_t mask = (X_AXIS_MASK << axis);
+		if (diag_mask & mask) tmc2130_sg_err[axis]++;
+		else
+			if (tmc2130_sg_err[axis] > 0) tmc2130_sg_err[axis]--;
+		if (tmc2130_sg_cnt[axis] < tmc2130_sg_err[axis])
+		{
+			tmc2130_sg_cnt[axis] = tmc2130_sg_err[axis];
+			tmc2130_sg_change = true;
+			if (tmc2130_sg_err[axis] >= 64)
+			{
+				tmc2130_sg_err[axis] = 0;
+				crash = true;
+			}
+		}
+//		if ((diag_mask & mask)/* && !(tmc2130_diag_mask & mask)*/)
+//			crash = true;
+	}
+	tmc2130_diag_mask = diag_mask;
+	if (sg_homing_axes_mask == 0)
+	{
+/*		if (crash)
+		{
+			if (diag_mask & 0x01) tmc2130_sg_cnt[0]++;
+			if (diag_mask & 0x02) tmc2130_sg_cnt[1]++;
+			if (diag_mask & 0x04) tmc2130_sg_cnt[2]++;
+			if (diag_mask & 0x08) tmc2130_sg_cnt[3]++;
+		}*/
+		if (tmc2130_sg_stop_on_crash && crash)
+		{
+			tmc2130_sg_crash = true;
+			tmc2130_sg_stop_on_crash = false;
+			crashdet_stop_and_save_print();
+		}
+	}
+}
+
+void tmc2130_update_sg_axis(uint8_t axis)
+{
+	if (!tmc2130_axis_stalled[axis])
+	{
+		uint8_t cs = tmc2130_cs[axis];
+		uint16_t tstep = tmc2130_rd_TSTEP(cs);
+		if (tstep < TMC2130_TCOOLTHRS_Z)
+		{
+			long pos = st_get_position(axis);
+			if (abs(pos - tmc2130_sg_pos[axis]) > TMC2130_SG_DELTA)
+			{
+				uint16_t sg = tmc2130_rd_DRV_STATUS(cs) & 0x3ff;
+				if (sg == 0)
+					tmc2130_axis_stalled[axis] = true;
+			}
+		}
+	}
+}
+
+bool tmc2130_update_sg()
+{
+//	uint16_t tstep = tmc2130_rd_TSTEP(tmc2130_cs[0]);
+//	MYSERIAL.print("TSTEP_X=");
+//	MYSERIAL.println((int)tstep);
+	if (tmc2130_sg_meassure <= E_AXIS)
+	{
+		uint8_t cs = tmc2130_cs[tmc2130_sg_meassure];
+		uint16_t sg = tmc2130_rd_DRV_STATUS(cs) & 0x3ff;
+		tmc2130_sg_meassure_val += sg;
+		tmc2130_sg_meassure_cnt++;
+
+//		printf_P(PSTR("tmc2130_update_sg - meassure - sg=%d\n"), sg);
+		return true;
+	}
+#ifdef TMC2130_SG_HOMING_SW_XY
+	if (sg_homing_axes_mask & X_AXIS_MASK) tmc2130_update_sg_axis(X_AXIS);
+	if (sg_homing_axes_mask & Y_AXIS_MASK) tmc2130_update_sg_axis(Y_AXIS);
+#endif //TMC2130_SG_HOMING_SW_XY
+#ifdef TMC2130_SG_HOMING_SW_Z
+	if (sg_homing_axes_mask & Z_AXIS_MASK) tmc2130_update_sg_axis(Z_AXIS);
+#endif //TMC2130_SG_HOMING_SW_Z
+#if (defined(TMC2130_SG_HOMING) && defined(TMC2130_SG_HOMING_SW_XY))
+	if (sg_homing_axes_mask == 0) return false;
+#ifdef TMC2130_DEBUG
+	MYSERIAL.print("tmc2130_update_sg mask=0x");
+	MYSERIAL.print((int)sg_homing_axes_mask, 16);
+	MYSERIAL.print(" stalledX=");
+	MYSERIAL.print((int)tmc2130_axis_stalled[0]);
+	MYSERIAL.print(" stalledY=");
+	MYSERIAL.println((int)tmc2130_axis_stalled[1]);
+#endif //TMC2130_DEBUG
+	for (uint8_t axis = X_AXIS; axis <= Y_AXIS; axis++) //only X and Y axes
+	{
+		uint8_t mask = (X_AXIS_MASK << axis);
+		if (sg_homing_axes_mask & mask)
+		{
+			if (!tmc2130_axis_stalled[axis])
+			{
+				uint8_t cs = tmc2130_cs[axis];
+				uint16_t tstep = tmc2130_rd_TSTEP(cs);
+				if (tstep < TMC2130_TCOOLTHRS)
+				{
+					long pos = st_get_position(axis);
+					if (abs(pos - tmc2130_sg_pos[axis]) > TMC2130_SG_DELTA)
+					{
+						uint16_t sg = tmc2130_rd_DRV_STATUS(cs) & 0x3ff;
+						if (sg == 0)
+						{
+							tmc2130_axis_stalled[axis] = true;
+#ifdef TMC2130_DEBUG
+	MYSERIAL.print("tmc2130_update_sg AXIS STALLED ");
+	MYSERIAL.println((int)axis);
+#endif //TMC2130_DEBUG
+						}
+					}
+				}
+			}
+		}
+	}
+	return true;
+#endif
+	return false;
+}
+
+void tmc2130_home_enter(uint8_t axes_mask)
+{
+#ifdef TMC2130_DEBUG
+	MYSERIAL.print("tmc2130_home_enter mask=0x");
+	MYSERIAL.println((int)axes_mask, 16);
+#endif //TMC2130_DEBUG
+#ifdef TMC2130_SG_HOMING
+	for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) //X Y and Z axes
+	{
+		uint8_t mask = (X_AXIS_MASK << axis);
+		uint8_t cs = tmc2130_cs[axis];
+		if (axes_mask & mask)
+		{
+			sg_homing_axes_mask |= mask;
+			tmc2130_sg_pos[axis] = st_get_position(axis);
+			tmc2130_axis_stalled[axis] = false;
+			//Configuration to spreadCycle
+			tmc2130_wr(cs, TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL);
+			tmc2130_wr(cs, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr_home[axis]) << 16));
+//			tmc2130_wr(cs, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16) | ((uint32_t)1 << 24));
+			tmc2130_wr(cs, TMC2130_REG_TCOOLTHRS, (axis==X_AXIS)?TMC2130_TCOOLTHRS_X:TMC2130_TCOOLTHRS_Y);
+			tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r_home[axis]);
+#ifndef TMC2130_SG_HOMING_SW_XY
+			if (mask & (X_AXIS_MASK | Y_AXIS_MASK))
+				tmc2130_wr(cs, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); //stallguard output DIAG1, DIAG1 = pushpull
+#endif //TMC2130_SG_HOMING_SW_XY
+		}
+	}
+#endif //TMC2130_SG_HOMING
+}
+
+void tmc2130_home_exit()
+{
+#ifdef TMC2130_DEBUG
+	MYSERIAL.print("tmc2130_home_exit mask=0x");
+	MYSERIAL.println((int)sg_homing_axes_mask, 16);
+#endif //TMC2130_DEBUG
+#ifdef TMC2130_SG_HOMING
+	if (sg_homing_axes_mask)
+	{
+		for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) //X Y and Z axes
+		{
+			uint8_t mask = (X_AXIS_MASK << axis);
+			if (sg_homing_axes_mask & mask & (X_AXIS_MASK | Y_AXIS_MASK))
+			{
+				if (tmc2130_mode == TMC2130_MODE_SILENT)
+				{
+					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_SILENT); // Configuration back to stealthChop
+					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_TCOOLTHRS, 0);
+//					tmc2130_wr_PWMCONF(tmc2130_cs[i], tmc2130_pwm_ampl[i], tmc2130_pwm_grad[i], tmc2130_pwm_freq[i], tmc2130_pwm_auto[i], 0, 0);
+				}
+				else
+				{
+#ifdef TMC2130_SG_HOMING_SW_XY
+					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL);
+#else //TMC2130_SG_HOMING_SW_XY
+//					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL);
+					tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+//					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16) | ((uint32_t)1 << 24));
+					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16));
+					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_TCOOLTHRS, (tmc2130_mode == TMC2130_MODE_SILENT)?0:((axis==X_AXIS)?TMC2130_TCOOLTHRS_X:TMC2130_TCOOLTHRS_Y));
+					tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS);
+#endif //TMC2130_SG_HOMING_SW_XY
+				}
+			}
+			tmc2130_axis_stalled[axis] = false;
+		}
+		sg_homing_axes_mask = 0x00;
+	}
+#endif
+}
+
+void tmc2130_home_pause(uint8_t axis)
+{
+	if (tmc2130_mode == TMC2130_MODE_NORMAL)
+	{
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL);
+	}
+}
+
+void tmc2130_home_resume(uint8_t axis)
+{
+	if (tmc2130_mode == TMC2130_MODE_NORMAL)
+	{
+		tmc2130_wr(tmc2130_cs[axis], TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS);
+	}
+}
+
+void tmc2130_home_restart(uint8_t axis)
+{
+	tmc2130_sg_pos[axis] = st_get_position(axis);
+	tmc2130_axis_stalled[axis] = false;
+}
+
+void tmc2130_sg_meassure_start(uint8_t axis)
+{
+	tmc2130_sg_meassure = axis;
+	tmc2130_sg_meassure_cnt = 0;
+	tmc2130_sg_meassure_val = 0;
+}
+
+uint16_t tmc2130_sg_meassure_stop()
+{
+	tmc2130_sg_meassure = 0xff;
+	return tmc2130_sg_meassure_val / tmc2130_sg_meassure_cnt;
+}
+
+
+bool tmc2130_wait_standstill_xy(int timeout)
+{
+//	MYSERIAL.println("tmc2130_wait_standstill_xy");
+	bool standstill = false;
+	while (!standstill && (timeout > 0))
+	{
+		uint32_t drv_status_x = 0;
+		uint32_t drv_status_y = 0;
+		tmc2130_rd(tmc2130_cs[X_AXIS], TMC2130_REG_DRV_STATUS, &drv_status_x);
+		tmc2130_rd(tmc2130_cs[Y_AXIS], TMC2130_REG_DRV_STATUS, &drv_status_y);
+/*		MYSERIAL.print(timeout, 10);
+		MYSERIAL.println(' ');
+		MYSERIAL.print(drv_status_x, 16);
+		MYSERIAL.println(' ');
+		MYSERIAL.print(drv_status_y, 16);
+		MYSERIAL.println('#');*/
+		standstill = (drv_status_x & 0x80000000) && (drv_status_y & 0x80000000);
+		tmc2130_check_overtemp();
+		timeout--;
+	}
+	return standstill;
+}
+
+
+void tmc2130_check_overtemp()
+{
+	const static char TMC_OVERTEMP_MSG[] PROGMEM = "TMC DRIVER OVERTEMP ";
+	static uint32_t checktime = 0;
+	if (millis() - checktime > 1000 )
+	{
+//		MYSERIAL.print("DRV_STATUS ");
+		for (int i = 0; i < 4; i++)
+		{
+			uint32_t drv_status = 0;
+			skip_debug_msg = true;
+			tmc2130_rd(tmc2130_cs[i], TMC2130_REG_DRV_STATUS, &drv_status);
+/*			MYSERIAL.print(i, DEC);
+			MYSERIAL.print(' ');
+			MYSERIAL.print(drv_status, 16);*/
+
+			if (drv_status & ((uint32_t)1 << 26))
+			{ // BIT 26 - over temp prewarning ~120C (+-20C)
+				SERIAL_ERRORRPGM(TMC_OVERTEMP_MSG);
+				SERIAL_ECHOLN(i);
+				for (int j = 0; j < 4; j++)
+					tmc2130_wr(tmc2130_cs[j], TMC2130_REG_CHOPCONF, 0x00010000);
+				kill(TMC_OVERTEMP_MSG);
+			}
+
+		}
+//		MYSERIAL.println('#');
+		checktime = millis();
+		tmc2130_sg_change = true;
+	}
+#ifdef DEBUG_CRASHDET_COUNTERS
+	if (tmc2130_sg_change)
+	{
+		for (int i = 0; i < 4; i++)
+		{
+			tmc2130_sg_change = false;
+			lcd.setCursor(0 + i*4, 3);
+			lcd.print(itostr3(tmc2130_sg_cnt[i]));
+			lcd.print(' ');
+		}
+	}
+#endif DEBUG_CRASHDET_COUNTERS
+}
+
+void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_t current_r)
+{
+	uint8_t cs = tmc2130_cs[axis];
+	uint8_t intpol = 1;
+	if (current_r <= 31)
+	{
+		tmc2130_wr_CHOPCONF(cs, 3, 5, 1, 0, 0, 0, 0, 2, 1, 0, 0, 0, mres, intpol, 0, 0);
+		tmc2130_wr(cs, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((current_r & 0x1f) << 8) | (current_h & 0x1f));
+	}
+	else
+	{
+		tmc2130_wr_CHOPCONF(cs, 3, 5, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, mres, intpol, 0, 0);
+		tmc2130_wr(cs, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | (((current_r >> 1) & 0x1f) << 8) | ((current_h >> 1) & 0x1f));
+	}
+}
+
+void tmc2130_set_current_h(uint8_t axis, uint8_t current)
+{
+	MYSERIAL.print("tmc2130_set_current_h ");
+	MYSERIAL.print((int)axis);
+	MYSERIAL.print(" ");
+	MYSERIAL.println((int)current);
+	tmc2130_current_h[axis] = current;
+	tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+}
+
+void tmc2130_set_current_r(uint8_t axis, uint8_t current)
+{
+	MYSERIAL.print("tmc2130_set_current_r ");
+	MYSERIAL.print((int)axis);
+	MYSERIAL.print(" ");
+	MYSERIAL.println((int)current);
+	tmc2130_current_r[axis] = current;
+	tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+}
+
+void tmc2130_print_currents()
+{
+	MYSERIAL.println("tmc2130_print_currents");
+	MYSERIAL.println("\tH\rR");
+	MYSERIAL.print("X\t");
+	MYSERIAL.print((int)tmc2130_current_h[0]);
+	MYSERIAL.print("\t");
+	MYSERIAL.println((int)tmc2130_current_r[0]);
+	MYSERIAL.print("Y\t");
+	MYSERIAL.print((int)tmc2130_current_h[1]);
+	MYSERIAL.print("\t");
+	MYSERIAL.println((int)tmc2130_current_r[1]);
+	MYSERIAL.print("Z\t");
+	MYSERIAL.print((int)tmc2130_current_h[2]);
+	MYSERIAL.print("\t");
+	MYSERIAL.println((int)tmc2130_current_r[2]);
+	MYSERIAL.print("E\t");
+	MYSERIAL.print((int)tmc2130_current_h[3]);
+	MYSERIAL.print("\t");
+	MYSERIAL.println((int)tmc2130_current_r[3]);
+}
+
+void tmc2130_set_pwm_ampl(uint8_t axis, uint8_t pwm_ampl)
+{
+	MYSERIAL.print("tmc2130_set_pwm_ampl ");
+	MYSERIAL.print((int)axis);
+	MYSERIAL.print(" ");
+	MYSERIAL.println((int)pwm_ampl);
+	tmc2130_pwm_ampl[axis] = pwm_ampl;
+	if (((axis == 0) || (axis == 1)) && (tmc2130_mode == TMC2130_MODE_SILENT))
+		tmc2130_wr_PWMCONF(tmc2130_cs[axis], tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0);
+}
+
+void tmc2130_set_pwm_grad(uint8_t axis, uint8_t pwm_grad)
+{
+	MYSERIAL.print("tmc2130_set_pwm_grad ");
+	MYSERIAL.print((int)axis);
+	MYSERIAL.print(" ");
+	MYSERIAL.println((int)pwm_grad);
+	tmc2130_pwm_grad[axis] = pwm_grad;
+	if (((axis == 0) || (axis == 1)) && (tmc2130_mode == TMC2130_MODE_SILENT))
+		tmc2130_wr_PWMCONF(tmc2130_cs[axis], tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0);
+}
+
+uint16_t tmc2130_rd_TSTEP(uint8_t cs)
+{
+	uint32_t val32 = 0;
+	tmc2130_rd(cs, TMC2130_REG_TSTEP, &val32);
+	if (val32 & 0x000f0000) return 0xffff;
+	return val32 & 0xffff;
+}
+
+uint16_t tmc2130_rd_MSCNT(uint8_t cs)
+{
+	uint32_t val32 = 0;
+	tmc2130_rd(cs, TMC2130_REG_MSCNT, &val32);
+	return val32 & 0x3ff;
+}
+
+uint16_t tmc2130_rd_DRV_STATUS(uint8_t cs)
+{
+	uint32_t val32 = 0;
+	tmc2130_rd(cs, TMC2130_REG_DRV_STATUS, &val32);
+	return val32;
+}
+
+void tmc2130_wr_CHOPCONF(uint8_t cs, uint8_t toff, uint8_t hstrt, uint8_t hend, uint8_t fd3, uint8_t disfdcc, uint8_t rndtf, uint8_t chm, uint8_t tbl, uint8_t vsense, uint8_t vhighfs, uint8_t vhighchm, uint8_t sync, uint8_t mres, uint8_t intpol, uint8_t dedge, uint8_t diss2g)
+{
+	uint32_t val = 0;
+	val |= (uint32_t)(toff & 15);
+	val |= (uint32_t)(hstrt & 7) << 4;
+	val |= (uint32_t)(hend & 15) << 7;
+	val |= (uint32_t)(fd3 & 1) << 11;
+	val |= (uint32_t)(disfdcc & 1) << 12;
+	val |= (uint32_t)(rndtf & 1) << 13;
+	val |= (uint32_t)(chm & 1) << 14;
+	val |= (uint32_t)(tbl & 3) << 15;
+	val |= (uint32_t)(vsense & 1) << 17;
+	val |= (uint32_t)(vhighfs & 1) << 18;
+	val |= (uint32_t)(vhighchm & 1) << 19;
+	val |= (uint32_t)(sync & 15) << 20;
+	val |= (uint32_t)(mres & 15) << 24;
+	val |= (uint32_t)(intpol & 1) << 28;
+	val |= (uint32_t)(dedge & 1) << 29;
+	val |= (uint32_t)(diss2g & 1) << 30;
+	tmc2130_wr(cs, TMC2130_REG_CHOPCONF, val);
+}
+
+//void tmc2130_wr_PWMCONF(uint8_t cs, uint8_t PWMautoScale, uint8_t PWMfreq, uint8_t PWMgrad, uint8_t PWMampl)
+void tmc2130_wr_PWMCONF(uint8_t cs, uint8_t pwm_ampl, uint8_t pwm_grad, uint8_t pwm_freq, uint8_t pwm_auto, uint8_t pwm_symm, uint8_t freewheel)
+{
+	uint32_t val = 0;
+	val |= (uint32_t)(pwm_ampl & 255);
+	val |= (uint32_t)(pwm_grad & 255) << 8;
+	val |= (uint32_t)(pwm_freq & 3) << 16;
+	val |= (uint32_t)(pwm_auto & 1) << 18;
+	val |= (uint32_t)(pwm_symm & 1) << 19;
+	val |= (uint32_t)(freewheel & 3) << 20;
+	tmc2130_wr(cs, TMC2130_REG_PWMCONF, val);
+//	tmc2130_wr(cs, TMC2130_REG_PWMCONF, ((uint32_t)(PWMautoScale+PWMfreq) << 16) | ((uint32_t)PWMgrad << 8) | PWMampl); // TMC LJ -> For better readability changed to 0x00 and added PWMautoScale and PWMfreq
+}
+
+void tmc2130_wr_TPWMTHRS(uint8_t cs, uint32_t val32)
+{
+	tmc2130_wr(cs, TMC2130_REG_TPWMTHRS, val32);
+}
+
+void tmc2130_wr_THIGH(uint8_t cs, uint32_t val32)
+{
+	tmc2130_wr(cs, TMC2130_REG_THIGH, val32);
+}
+
+#if defined(TMC2130_DEBUG_RD) || defined(TMC2130_DEBUG_WR)
+uint8_t tmc2130_axis_by_cs(uint8_t cs)
+{
+	switch (cs)
+	{
+	case X_TMC2130_CS: return 0;
+	case Y_TMC2130_CS: return 1;
+	case Z_TMC2130_CS: return 2;
+	case E0_TMC2130_CS: return 3;
+	}
+	return -1;
+}
+#endif //TMC2130_DEBUG
+
+uint8_t tmc2130_calc_mres(uint16_t microstep_resolution)
+{
+	if (microstep_resolution == 256) return 0b0000;
+	if (microstep_resolution == 128) return 0b0001;
+	if (microstep_resolution == 64)  return 0b0010;
+	if (microstep_resolution == 32)  return 0b0011;
+	if (microstep_resolution == 16)  return 0b0100;
+	if (microstep_resolution == 8)   return 0b0101;
+	if (microstep_resolution == 4)   return 0b0110;
+	if (microstep_resolution == 2)   return 0b0111;
+	if (microstep_resolution == 1)   return 0b1000;
+	return 0;
+}
+
+uint8_t tmc2130_wr(uint8_t cs, uint8_t addr, uint32_t wval)
+{
+	uint8_t stat = tmc2130_txrx(cs, addr | 0x80, wval, 0);
+#ifdef TMC2130_DEBUG_WR
+	MYSERIAL.print("tmc2130_wr(");
+	MYSERIAL.print((unsigned char)tmc2130_axis_by_cs(cs), DEC);
+	MYSERIAL.print(", 0x");
+	MYSERIAL.print((unsigned char)addr, HEX);
+	MYSERIAL.print(", 0x");
+	MYSERIAL.print((unsigned long)wval, HEX);
+	MYSERIAL.print(")=0x");
+	MYSERIAL.println((unsigned char)stat, HEX);
+#endif //TMC2130_DEBUG_WR
+	return stat;
+}
+
+uint8_t tmc2130_rd(uint8_t cs, uint8_t addr, uint32_t* rval)
+{
+	uint32_t val32 = 0;
+	uint8_t stat = tmc2130_txrx(cs, addr, 0x00000000, &val32);
+	if (rval != 0) *rval = val32;
+#ifdef TMC2130_DEBUG_RD
+	if (!skip_debug_msg)
+	{
+		MYSERIAL.print("tmc2130_rd(");
+		MYSERIAL.print((unsigned char)tmc2130_axis_by_cs(cs), DEC);
+		MYSERIAL.print(", 0x");
+		MYSERIAL.print((unsigned char)addr, HEX);
+		MYSERIAL.print(", 0x");
+		MYSERIAL.print((unsigned long)val32, HEX);
+		MYSERIAL.print(")=0x");
+		MYSERIAL.println((unsigned char)stat, HEX);
+	}
+	skip_debug_msg = false;
+#endif //TMC2130_DEBUG_RD
+	return stat;
+}
+
+uint8_t tmc2130_txrx(uint8_t cs, uint8_t addr, uint32_t wval, uint32_t* rval)
+{
+	//datagram1 - request
+	SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));
+	digitalWrite(cs, LOW);
+	SPI.transfer(addr); // address
+	SPI.transfer((wval >> 24) & 0xff); // MSB
+	SPI.transfer((wval >> 16) & 0xff);
+	SPI.transfer((wval >> 8) & 0xff);
+	SPI.transfer(wval & 0xff); // LSB
+	digitalWrite(cs, HIGH);
+	SPI.endTransaction();
+	//datagram2 - response
+	SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));
+	digitalWrite(cs, LOW);
+	uint8_t stat = SPI.transfer(0); // status
+	uint32_t val32 = 0;
+	val32 = SPI.transfer(0); // MSB
+	val32 = (val32 << 8) | SPI.transfer(0);
+	val32 = (val32 << 8) | SPI.transfer(0);
+	val32 = (val32 << 8) | SPI.transfer(0); // LSB
+	digitalWrite(cs, HIGH);
+	SPI.endTransaction();
+	if (rval != 0) *rval = val32;
+	return stat;
+}
+
+void tmc2130_eeprom_load_config()
+{
+}
+
+void tmc2130_eeprom_save_config()
+{
+
+}
+
+
+#endif //TMC2130

+ 97 - 0
Firmware/tmc2130.h

@@ -0,0 +1,97 @@
+#ifndef TMC2130_H
+#define TMC2130_H
+
+extern uint8_t tmc2130_cs[4];
+
+//mode
+extern uint8_t tmc2130_mode;
+//holding and running currents
+extern uint8_t tmc2130_current_h[4];
+extern uint8_t tmc2130_current_r[4];
+//flags for axis stall detection
+extern uint8_t tmc2130_axis_stalled[4];
+
+extern uint8_t tmc2130_sg_thr[4];
+
+extern bool tmc2130_sg_stop_on_crash;
+extern bool tmc2130_sg_crash;
+
+extern uint8_t tmc2130_sg_meassure;
+extern uint16_t tmc2130_sg_meassure_cnt;
+extern uint32_t tmc2130_sg_meassure_val;
+
+#define TMC2130_MODE_NORMAL 0
+#define TMC2130_MODE_SILENT 1
+
+//initialize tmc2130
+extern void tmc2130_init();
+//check diag pins (called from stepper isr)
+extern void tmc2130_st_isr(uint8_t last_step_mask);
+//update stall guard (called from st_synchronize inside the loop)
+extern bool tmc2130_update_sg();
+//temperature watching (called from )
+extern void tmc2130_check_overtemp();
+//enter homing (called from homeaxis before homing starts)
+extern void tmc2130_home_enter(uint8_t axes_mask);
+//exit homing (called from homeaxis after homing ends)
+extern void tmc2130_home_exit();
+//restart homing (called from homeaxis befor move)
+extern void tmc2130_home_restart(uint8_t axis);
+
+//start stallguard meassuring for single axis
+extern void tmc2130_sg_meassure_start(uint8_t axis);
+//stop current stallguard meassuring and report result
+extern uint16_t tmc2130_sg_meassure_stop();
+
+
+//set holding current for any axis (M911)
+extern void tmc2130_set_current_h(uint8_t axis, uint8_t current);
+//set running current for any axis (M912)
+extern void tmc2130_set_current_r(uint8_t axis, uint8_t current);
+//print currents (M913)
+extern void tmc2130_print_currents();
+
+//set PWM_AMPL for any axis (M917)
+extern void tmc2130_set_pwm_ampl(uint8_t axis, uint8_t pwm_ampl);
+//set PWM_GRAD for any axis (M918)
+extern void tmc2130_set_pwm_grad(uint8_t axis, uint8_t pwm_ampl);
+
+
+extern uint16_t tmc2130_rd_MSCNT(uint8_t cs);
+
+extern void tmc2130_home_pause(uint8_t axis);
+extern void tmc2130_home_resume(uint8_t axis);
+extern bool tmc2130_wait_standstill_xy(int timeout);
+
+extern void tmc2130_eeprom_load_config();
+extern void tmc2130_eeprom_save_config();
+
+#pragma pack(push)
+#pragma pack(1)
+struct
+{
+	uint8_t mres:5;             // mres       - byte 0, bit 0..4     microstep resolution
+	uint8_t reserved_0_0:2;     // reserved   - byte 0, bit 5..6
+	uint8_t intpol:1;           // intpol     - byte 0, bit 7        linear interpolation to 255 usteps
+	uint8_t pwm_ampl:8;         // pwm_ampl   - byte 1, bit 0..7     pwm amplitude for silent mode
+	uint8_t pwm_grad:4;         // pwm_grad   - byte 2, bit 0..3     pwm gradient for silent mode
+	uint8_t pwm_freq:2;         // pwm_freq   - byte 2, bit 4..5     pwm frequency for silent mode
+	uint8_t reserved_2_0:2;     // reserved   - byte 2, bit 6..7
+	uint16_t tcoolthrs:16;      // tcoolthrs  - byte 3..4            coolstep threshold / middle sensitivity
+	int8_t  sg_thrs:8;          // sg_thrs    - byte 5, bit 0..7     stallguard sensitivity in high power / middle sensitivity
+	int8_t  current_h:6;        // current_h  - byte 6, bit 0..5     holding current for high power mode
+	uint8_t reserved_6_0:2;     // reserved   - byte 6, bit 6..7
+	int8_t  current_r:6;        // current_r  - byte 7, bit 0..5     running current for high power mode
+	uint8_t reserved_7_0:2;     // reserved   - byte 7, bit 6..7
+	int8_t  home_sg_thrs:8;     // sg_thrs    - byte 8, bit 0..7     stallguard sensitivity for homing
+	int8_t  home_current:6;     // current_r  - byte 9, bit 0..5     running current for homing
+	uint8_t reserved_9_0:2;     // reserved   - byte 9, bit 6..7
+	int8_t  home_dtcoolthrs:8;  // dtcoolthrs - byte 10, bit 0..7    delta tcoolthrs for homing
+	int8_t  dtcoolthrs_low:8;   // dtcoolthrs - byte 11, bit 0..7    delta tcoolthrs for low sensitivity (based on value for middle sensitivity)
+	int8_t  dtcoolthrs_high:8;  // dtcoolthrs - byte 12, bit 0..7    delta tcoolthrs for high sensitivity (based on value for middle sensitivity)
+	int8_t  sg_thrs_low:8;      // sg_thrs    - byte 13, bit 0..7    stallguard sensitivity in high power / low sensitivity
+	int8_t  sg_thrs_high:8;     // sg_thrs    - byte 14, bit 0..7    stallguard sensitivity in high power / high sensitivity
+} tmc2130_axis_config;
+#pragma pack(pop)
+
+#endif //TMC2130_H

+ 3846 - 559
Firmware/ultralcd.cpp

@@ -10,9 +10,19 @@
 #include <string.h>
 
 #include "util.h"
+#include "mesh_bed_leveling.h"
 //#include "Configuration.h"
+#include "cmdqueue.h"
 
+#include "SdFatUtil.h"
 
+#ifdef PAT9125
+#include "pat9125.h"
+#endif //PAT9125
+
+#ifdef TMC2130
+#include "tmc2130.h"
+#endif //TMC2130
 
 #define _STRINGIFY(s) #s
 
@@ -20,9 +30,69 @@
 int8_t encoderDiff; /* encoderDiff is updated from interrupt context and added to encoderPosition every LCD update */
 
 extern int lcd_change_fil_state;
+extern bool fans_check_enabled = true;
+
+//Function pointer to menu functions.
+typedef void (*menuFunc_t)();
+
+static void lcd_sd_updir();
+
+struct EditMenuParentState
+{
+    //prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
+    menuFunc_t prevMenu;
+    uint16_t prevEncoderPosition;
+    //Variables used when editing values.
+    const char* editLabel;
+    void* editValue;
+    int32_t minEditValue, maxEditValue;
+    // menuFunc_t callbackFunc;
+};
 
-int babystepMem[3];
-float babystepMemMM[3];
+union MenuData
+{ 
+    struct BabyStep
+    {
+        // 29B total
+        int8_t status;
+        int babystepMem[3];
+        float babystepMemMM[3];
+    } babyStep;
+
+    struct SupportMenu
+    {
+        // 6B+16B=22B total
+        int8_t status;
+        bool is_flash_air;
+        uint8_t ip[4];
+        char ip_str[3*4+3+1];
+    } supportMenu;
+
+    struct AdjustBed
+    {
+        // 6+13+16=35B
+        // editMenuParentState is used when an edit menu is entered, so it knows
+        // the return menu and encoder state.
+        struct EditMenuParentState editMenuParentState;
+        int8_t status;
+        int8_t left;
+        int8_t right;
+        int8_t front;
+        int8_t rear;
+        int    left2;
+        int    right2;
+        int    front2;
+        int    rear2;
+    } adjustBed;
+
+    // editMenuParentState is used when an edit menu is entered, so it knows
+    // the return menu and encoder state.
+    struct EditMenuParentState editMenuParentState;
+};
+
+// State of the currently active menu.
+// C Union manages sharing of the static memory by all the menus.
+union MenuData menuData = { 0 };
 
 union Data
 {
@@ -36,42 +106,40 @@ int8_t SDscrool = 0;
 
 int8_t SilentModeMenu = 0;
 
-int lcd_commands_type=0;
-int lcd_commands_step=0;
-bool isPrintPaused = false;
-bool farm_mode = false;
-int farm_no = 0;
-int farm_timer = 30;
-int farm_status = 0;
+int8_t FSensorStateMenu = 1;
 
-bool menuExiting = false;
+int8_t CrashDetectMenu = 1;
 
-/* Configuration settings */
-int plaPreheatHotendTemp;
-int plaPreheatHPBTemp;
-int plaPreheatFanSpeed;
+extern bool fsensor_enable();
+extern void fsensor_disable();
 
-int absPreheatHotendTemp;
-int absPreheatHPBTemp;
-int absPreheatFanSpeed;
+extern void crashdet_enable();
+extern void crashdet_disable();
 
-int ppPreheatHotendTemp = PP_PREHEAT_HOTEND_TEMP;
-int ppPreheatHPBTemp = PP_PREHEAT_HPB_TEMP;
-int ppPreheatFanSpeed = PP_PREHEAT_FAN_SPEED;
 
-int petPreheatHotendTemp = PET_PREHEAT_HOTEND_TEMP;
-int petPreheatHPBTemp = PET_PREHEAT_HPB_TEMP;
-int petPreheatFanSpeed = PET_PREHEAT_FAN_SPEED;
+#ifdef SNMM
+uint8_t snmm_extruder = 0;
+#endif
 
-int hipsPreheatHotendTemp = HIPS_PREHEAT_HOTEND_TEMP;
-int hipsPreheatHPBTemp = HIPS_PREHEAT_HPB_TEMP;
-int hipsPreheatFanSpeed = HIPS_PREHEAT_FAN_SPEED;
+int lcd_commands_type=LCD_COMMAND_IDLE;
+int lcd_commands_step=0;
+bool isPrintPaused = false;
+uint8_t farm_mode = 0;
+int farm_no = 0;
+int farm_timer = 30;
+int farm_status = 0;
+unsigned long allert_timer = millis();
+bool printer_connected = true;
 
-int flexPreheatHotendTemp = FLEX_PREHEAT_HOTEND_TEMP;
-int flexPreheatHPBTemp = FLEX_PREHEAT_HPB_TEMP;
-int flexPreheatFanSpeed = FLEX_PREHEAT_FAN_SPEED;
+unsigned long display_time; //just timer for showing pid finished message on lcd;
+float pid_temp = DEFAULT_PID_TEMP;
 
+bool long_press_active = false;
+long long_press_timer = millis();
+long button_blanking_time = millis();
+bool button_pressed = false;
 
+bool menuExiting = false;
 
 #ifdef FILAMENT_LCD_DISPLAY
 unsigned long message_millis = 0;
@@ -83,9 +151,6 @@ static float manual_feedrate[] = MANUAL_FEEDRATE;
 
 /* !Configuration settings */
 
-//Function pointer to menu functions.
-typedef void (*menuFunc_t)();
-
 uint8_t lcd_status_message_level;
 char lcd_status_message[LCD_WIDTH + 1] = ""; //////WELCOME!
 unsigned char firstrun = 1;
@@ -98,8 +163,8 @@ unsigned char firstrun = 1;
 
 /** forward declarations **/
 
-void copy_and_scalePID_i();
-void copy_and_scalePID_d();
+// void copy_and_scalePID_i();
+// void copy_and_scalePID_d();
 
 /* Different menus */
 static void lcd_status_screen();
@@ -108,9 +173,10 @@ extern bool powersupply;
 static void lcd_main_menu();
 static void lcd_tune_menu();
 static void lcd_prepare_menu();
-static void lcd_move_menu();
-static void lcd_control_menu();
+//static void lcd_move_menu();
+static void lcd_crash_menu();
 static void lcd_settings_menu();
+static void lcd_calibration_menu();
 static void lcd_language_menu();
 static void lcd_control_temperature_menu();
 static void lcd_control_temperature_preheat_pla_settings_menu();
@@ -119,9 +185,12 @@ static void lcd_control_motion_menu();
 static void lcd_control_volumetric_menu();
 
 static void prusa_stat_printerstatus(int _status);
+static void prusa_stat_farm_number();
 static void prusa_stat_temperatures();
 static void prusa_stat_printinfo();
 static void lcd_farm_no();
+static void lcd_menu_extruder_info();
+static void lcd_menu_fails_stats();
 
 #ifdef DOGLCD
 static void lcd_set_contrast();
@@ -153,6 +222,8 @@ static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float
 static void menu_action_setting_edit_float51(const char* pstr, float* ptr, float minValue, float maxValue);
 static void menu_action_setting_edit_float52(const char* pstr, float* ptr, float minValue, float maxValue);
 static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue);
+
+/*
 static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callbackFunc);
 static void menu_action_setting_edit_callback_int3(const char* pstr, int* ptr, int minValue, int maxValue, menuFunc_t callbackFunc);
 static void menu_action_setting_edit_callback_float3(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
@@ -162,6 +233,7 @@ static void menu_action_setting_edit_callback_float5(const char* pstr, float* pt
 static void menu_action_setting_edit_callback_float51(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
 static void menu_action_setting_edit_callback_float52(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
 static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue, menuFunc_t callbackFunc);
+*/
 
 #define ENCODER_FEEDRATE_DEADZONE 10
 
@@ -228,37 +300,36 @@ volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad
 volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons.
 #endif
 uint8_t currentMenuViewOffset;              /* scroll offset in the current menu */
-uint32_t blocking_enc;
 uint8_t lastEncoderBits;
 uint32_t encoderPosition;
+uint32_t savedEncoderPosition;
 #if (SDCARDDETECT > 0)
 bool lcd_oldcardstatus;
 #endif
 #endif //ULTIPANEL
 
 menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */
+menuFunc_t savedMenu;
 uint32_t lcd_next_update_millis;
 uint8_t lcd_status_update_delay;
 bool ignore_click = false;
 bool wait_for_unclick;
 uint8_t lcdDrawUpdate = 2;                  /* Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial) */
 
-//prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
-menuFunc_t prevMenu = NULL;
-uint16_t prevEncoderPosition;
-//Variables used when editing values.
-const char* editLabel;
-void* editValue;
-int32_t minEditValue, maxEditValue;
-menuFunc_t callbackFunc;
-
 // place-holders for Ki and Kd edits
-float raw_Ki, raw_Kd;
+#ifdef PIDTEMP
+// float raw_Ki, raw_Kd;
+#endif
 
-static void lcd_goto_menu(menuFunc_t menu, const uint32_t encoder = 0, const bool feedback = true) {
+static void lcd_goto_menu(menuFunc_t menu, const uint32_t encoder = 0, const bool feedback = true, bool reset_menu_state = true) {
   if (currentMenu != menu) {
     currentMenu = menu;
     encoderPosition = encoder;
+    if (reset_menu_state) {
+        // Resets the global shared C union.
+        // This ensures, that the menu entered will find out, that it shall initialize itself.
+        memset(&menuData, 0, sizeof(menuData));
+    }
     if (feedback) lcd_quick_feedback();
 
     // For LCD_PROGRESS_BAR re-initialize the custom characters
@@ -269,30 +340,33 @@ static void lcd_goto_menu(menuFunc_t menu, const uint32_t encoder = 0, const boo
 }
 
 /* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependent */
-/*
-extern char langbuffer[];
-void lcd_printPGM(const char *s1) {
-  strncpy_P(langbuffer,s1,LCD_WIDTH);
-  lcd.print(langbuffer);
-}
-*/
-unsigned char langsel;
+
+// Language selection dialog not active.
+#define LANGSEL_OFF 0
+// Language selection dialog modal, entered from the info screen. This is the case on firmware boot up,
+// if the language index stored in the EEPROM is not valid.
+#define LANGSEL_MODAL 1
+// Language selection dialog entered from the Setup menu.
+#define LANGSEL_ACTIVE 2
+// Language selection dialog status
+unsigned char langsel = LANGSEL_OFF;
 
 void set_language_from_EEPROM() {
   unsigned char eep = eeprom_read_byte((unsigned char*)EEPROM_LANG);
   if (eep < LANG_NUM)
   {
     lang_selected = eep;
-    langsel = 0;
+    // Language is valid, no need to enter the language selection screen.
+    langsel = LANGSEL_OFF;
   }
   else
   {
-    lang_selected = 1;
-    langsel = 1;
+    lang_selected = LANG_ID_DEFAULT;
+    // Invalid language, enter the language selection screen in a modal mode.
+    langsel = LANGSEL_MODAL;
   }
 }
 
-void lcd_mylang();
 static void lcd_status_screen()
 {
 	
@@ -300,8 +374,10 @@ static void lcd_status_screen()
   {
     firstrun = 0;
     set_language_from_EEPROM();
-    strncpy_P(lcd_status_message, WELCOME_MSG, LCD_WIDTH);
-	
+     
+      if(lcd_status_message_level == 0){
+          strncpy_P(lcd_status_message, WELCOME_MSG, LCD_WIDTH);
+      }
 	if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255)
 	{
 		eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0);
@@ -310,7 +386,8 @@ static void lcd_status_screen()
 	
 	if (langsel) {
       //strncpy_P(lcd_status_message, PSTR(">>>>>>>>>>>> PRESS v"), LCD_WIDTH);
-      lcd_mylang();
+      // Entering the language selection screen in a modal mode.
+      
     }
   }
 
@@ -355,7 +432,7 @@ static void lcd_status_screen()
 		farm_timer--;
 		if (farm_timer < 1)
 		{
-			farm_timer = 90;
+			farm_timer = 180;
 			prusa_statistics(0);
 		}
 		switch (farm_timer)
@@ -370,20 +447,20 @@ static void lcd_status_screen()
 			}
 			break;
 		}
-	}
+	} // end of farm_mode
 
 
 
 
 
     lcd_status_update_delay = 10;   /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */
-	if (lcd_commands_type != 0)
+	if (lcd_commands_type != LCD_COMMAND_IDLE)
 	{
 		lcd_commands();
 	}
 	
 
-  }
+  } // end of lcdDrawUpdate
 #ifdef ULTIPANEL
 
   bool current_click = LCD_CLICKED;
@@ -407,7 +484,7 @@ static void lcd_status_screen()
 
   //if (--langsel ==0) {langsel=1;current_click=true;}
 
-  if (current_click)
+  if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes
   {
 
     lcd_goto_menu(lcd_main_menu);
@@ -452,74 +529,632 @@ static void lcd_status_screen()
   else if (feedmultiply > 999)
     feedmultiply = 999;
 #endif //ULTIPANEL
+
+  if (farm_mode && !printer_connected) {
+	  lcd.setCursor(0, 3);
+	  lcd_printPGM(MSG_PRINTER_DISCONNECTED);
+  }
+
+
+//#define FSENS_FACTOR (2580.8/50) //filament sensor factor [steps / encoder counts]
+//#define FSENS_FACTOR (2580.8/45.3) //filament sensor factor [steps / encoder counts]
+  //lcd.setCursor(0, 3);
+  //lcd_implementation_print("                    ");
+  //lcd.setCursor(0, 3);
+  //lcd_implementation_print(pat9125_x);
+  //lcd.setCursor(6, 3);
+  //lcd_implementation_print(pat9125_y);
+  //lcd.setCursor(12, 3);
+  //lcd_implementation_print(pat9125_b);
+
 }
 
 #ifdef ULTIPANEL
 
 void lcd_commands()
-{
-	if (lcd_commands_type == 1)   //// load filament sequence
+{	
+	if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE)
 	{
-		if (lcd_commands_step == 0) { lcd_commands_step = 5; custom_message = true; }
-			if (lcd_commands_step == 1 && !blocks_queued())
-			{
-				lcd_commands_step = 0;
-				lcd_commands_type = 0;
-				lcd_setstatuspgm(WELCOME_MSG);
-				disable_z();
-				custom_message = false;
-				custom_message_type = 0;
+		if(lcd_commands_step == 0) {
+			card.pauseSDPrint();
+			lcd_setstatuspgm(MSG_FINISHING_MOVEMENTS);
+			lcdDrawUpdate = 3;
+			lcd_commands_step = 1;
+		}
+		if (lcd_commands_step == 1 && !blocks_queued()) {
+			lcd_setstatuspgm(MSG_PRINT_PAUSED);
+			isPrintPaused = true;
+			long_pause();
+			lcd_commands_type = 0;
+			lcd_commands_step = 0;
+		}
+
+	}
+
+	if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE_RESUME) {
+		char cmd1[30];
+		if (lcd_commands_step == 0) {
+
+			lcdDrawUpdate = 3;
+			lcd_commands_step = 4;
+		}
+		if (lcd_commands_step == 1 && !blocks_queued()) {	//recover feedmultiply
+			
+			sprintf_P(cmd1, PSTR("M220 S%d"), saved_feedmultiply);
+			enquecommand(cmd1);
+			isPrintPaused = false;
+			pause_time += (millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation
+			card.startFileprint();
+			lcd_commands_step = 0;
+			lcd_commands_type = 0;
+		}
+		if (lcd_commands_step == 2 && !blocks_queued()) {	//turn on fan, move Z and unretract
+			
+			sprintf_P(cmd1, PSTR("M106 S%d"), fanSpeedBckp);
+			enquecommand(cmd1);
+			strcpy(cmd1, "G1 Z");
+			strcat(cmd1, ftostr32(pause_lastpos[Z_AXIS]));
+			enquecommand(cmd1);
+			
+			if (axis_relative_modes[3] == false) {
+				enquecommand_P(PSTR("M83")); // set extruder to relative mode
+			enquecommand_P(PSTR("G1 E"  STRINGIFY(DEFAULT_RETRACTION))); //unretract
+				enquecommand_P(PSTR("M82")); // set extruder to absolute mode
 			}
-			if (lcd_commands_step == 2 && !blocks_queued())
-			{
-				lcd_setstatuspgm(MSG_LOADING_FILAMENT);
-				enquecommand_P(PSTR(LOAD_FILAMENT_2));
-				lcd_commands_step = 1;
+			else {
+				enquecommand_P(PSTR("G1 E"  STRINGIFY(DEFAULT_RETRACTION))); //unretract
 			}
-			if (lcd_commands_step == 3 && !blocks_queued())
-			{
-				enquecommand_P(PSTR(LOAD_FILAMENT_1));
-				lcd_commands_step = 2;
+			
+			lcd_commands_step = 1;
+		}
+		if (lcd_commands_step == 3 && !blocks_queued()) {	//wait for nozzle to reach target temp
+			
+			strcpy(cmd1, "M109 S");
+			strcat(cmd1, ftostr3(HotendTempBckp));
+			enquecommand(cmd1);			
+			lcd_commands_step = 2;
+		}
+		if (lcd_commands_step == 4 && !blocks_queued()) {	//set temperature back and move xy
+			
+			strcpy(cmd1, "M104 S");
+			strcat(cmd1, ftostr3(HotendTempBckp));
+			enquecommand(cmd1);
+			enquecommand_P(PSTR("G90")); //absolute positioning
+			strcpy(cmd1, "G1 X");
+			strcat(cmd1, ftostr32(pause_lastpos[X_AXIS]));
+			strcat(cmd1, " Y");
+			strcat(cmd1, ftostr32(pause_lastpos[Y_AXIS]));
+			enquecommand(cmd1);
+			
+			lcd_setstatuspgm(MSG_RESUMING_PRINT);
+			lcd_commands_step = 3;
+		}
+	}
+
+#ifdef SNMM
+	if (lcd_commands_type == LCD_COMMAND_V2_CAL)
+	{
+		char cmd1[30];
+		float width = 0.4;
+		float length = 20 - width;
+		float extr = count_e(0.2, width, length);
+		float extr_short_segment = count_e(0.2, width, width);
+
+		lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+		if (lcd_commands_step == 0)
+		{
+			lcd_commands_step = 10;
+		}
+		if (lcd_commands_step == 10 && !blocks_queued() && cmd_buffer_empty())
+		{
+			enquecommand_P(PSTR("M107"));
+			enquecommand_P(PSTR("M104 S210"));
+			enquecommand_P(PSTR("M140 S55"));
+			enquecommand_P(PSTR("M190 S55"));
+			enquecommand_P(PSTR("M109 S210"));
+			enquecommand_P(PSTR("T0"));
+			enquecommand_P(MSG_M117_V2_CALIBRATION);
+			enquecommand_P(PSTR("G87")); //sets calibration status
+			enquecommand_P(PSTR("G28"));
+			enquecommand_P(PSTR("G21")); //set units to millimeters
+			enquecommand_P(PSTR("G90")); //use absolute coordinates
+			enquecommand_P(PSTR("M83")); //use relative distances for extrusion
+			enquecommand_P(PSTR("G92 E0"));
+			enquecommand_P(PSTR("M203 E100"));
+			enquecommand_P(PSTR("M92 E140"));
+			lcd_commands_step = 9;
+		}
+		if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			enquecommand_P(PSTR("G1 Z0.250 F7200.000"));
+			enquecommand_P(PSTR("G1 X50.0 E80.0 F1000.0"));
+			enquecommand_P(PSTR("G1 X160.0 E20.0 F1000.0"));
+			enquecommand_P(PSTR("G1 Z0.200 F7200.000"));
+			enquecommand_P(PSTR("G1 X220.0 E13 F1000.0"));
+			enquecommand_P(PSTR("G1 X240.0 E0 F1000.0"));
+			enquecommand_P(PSTR("G92 E0.0"));
+			enquecommand_P(PSTR("G21"));
+			enquecommand_P(PSTR("G90"));
+			enquecommand_P(PSTR("M83"));
+			enquecommand_P(PSTR("G1 E-4 F2100.00000"));
+			enquecommand_P(PSTR("G1 Z0.150 F7200.000"));
+			enquecommand_P(PSTR("M204 S1000"));
+			enquecommand_P(PSTR("G1 F4000"));
+
+			lcd_implementation_clear();
+			lcd_goto_menu(lcd_babystep_z, 0, false);
+
+
+			lcd_commands_step = 8;
+		}
+		if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty()) //draw meander
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+
+
+			enquecommand_P(PSTR("G1 X50 Y155"));
+			enquecommand_P(PSTR("G1 X60 Y155 E4"));
+			enquecommand_P(PSTR("G1 F1080"));
+			enquecommand_P(PSTR("G1 X75 Y155 E2.5"));
+			enquecommand_P(PSTR("G1 X100 Y155 E2"));
+			enquecommand_P(PSTR("G1 X200 Y155 E2.62773"));
+			enquecommand_P(PSTR("G1 X200 Y135 E0.66174"));
+			enquecommand_P(PSTR("G1 X50 Y135 E3.62773"));
+			enquecommand_P(PSTR("G1 X50 Y115 E0.49386"));
+			enquecommand_P(PSTR("G1 X200 Y115 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y95 E0.49386"));
+			enquecommand_P(PSTR("G1 X50 Y95 E3.62773"));
+			enquecommand_P(PSTR("G1 X50 Y75 E0.49386"));
+			enquecommand_P(PSTR("G1 X200 Y75 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y55 E0.49386"));
+			enquecommand_P(PSTR("G1 X50 Y55 E3.62773"));
+
+			lcd_commands_step = 7;
+		}
+
+		if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			strcpy(cmd1, "G1 X50 Y35 E");
+			strcat(cmd1, ftostr43(extr));
+			enquecommand(cmd1);
+
+			for (int i = 0; i < 4; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
 			}
-			if (lcd_commands_step == 4 && !blocks_queued())
-			{
-				lcd_setstatuspgm(MSG_INSERT_FILAMENT);
-				enquecommand_P(PSTR(LOAD_FILAMENT_0));
-				lcd_commands_step = 3;
+
+			lcd_commands_step = 6;
+		}
+
+		if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			for (int i = 4; i < 8; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
 			}
-			if (lcd_commands_step == 5 && !blocks_queued())
-			{
-				lcd_setstatuspgm(MSG_PLEASE_WAIT);
-				enable_z();
-				custom_message = true;
-				custom_message_type = 2;
-				lcd_commands_step = 4;
+
+			lcd_commands_step = 5;
+		}
+
+		if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			for (int i = 8; i < 12; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
 			}
 
- 
-		
-		
-		
+			lcd_commands_step = 4;
+		}
+
+		if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			for (int i = 12; i < 16; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+			}
+
+			lcd_commands_step = 3;
+		}
+
+		if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			enquecommand_P(PSTR("G1 E-0.07500 F2100.00000"));
+			enquecommand_P(PSTR("G4 S0"));
+			enquecommand_P(PSTR("G1 E-4 F2100.00000"));
+			enquecommand_P(PSTR("G1 Z0.5 F7200.000"));
+			enquecommand_P(PSTR("G1 X245 Y1"));
+			enquecommand_P(PSTR("G1 X240 E4"));
+			enquecommand_P(PSTR("G1 F4000"));
+			enquecommand_P(PSTR("G1 X190 E2.7"));
+			enquecommand_P(PSTR("G1 F4600"));
+			enquecommand_P(PSTR("G1 X110 E2.8"));
+			enquecommand_P(PSTR("G1 F5200"));
+			enquecommand_P(PSTR("G1 X40 E3"));
+			enquecommand_P(PSTR("G1 E-15.0000 F5000"));
+			enquecommand_P(PSTR("G1 E-50.0000 F5400"));
+			enquecommand_P(PSTR("G1 E-15.0000 F3000"));
+			enquecommand_P(PSTR("G1 E-12.0000 F2000"));
+			enquecommand_P(PSTR("G1 F1600"));
+
+			lcd_commands_step = 2;
+		}
+		if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+
+			enquecommand_P(PSTR("G1 X0 Y1 E3.0000"));
+			enquecommand_P(PSTR("G1 X50 Y1 E-5.0000"));
+			enquecommand_P(PSTR("G1 F2000"));
+			enquecommand_P(PSTR("G1 X0 Y1 E5.0000"));
+			enquecommand_P(PSTR("G1 X50 Y1 E-5.0000"));
+			enquecommand_P(PSTR("G1 F2400"));
+			enquecommand_P(PSTR("G1 X0 Y1 E5.0000"));
+			enquecommand_P(PSTR("G1 X50 Y1 E-5.0000"));
+			enquecommand_P(PSTR("G1 F2400"));
+			enquecommand_P(PSTR("G1 X0 Y1 E5.0000"));
+			enquecommand_P(PSTR("G1 X50 Y1 E-3.0000"));
+			enquecommand_P(PSTR("G4 S0"));
+			enquecommand_P(PSTR("M107"));
+			enquecommand_P(PSTR("M104 S0"));
+			enquecommand_P(PSTR("M140 S0"));
+			enquecommand_P(PSTR("G1 X10 Y180 F4000"));
+			enquecommand_P(PSTR("G1 Z10 F1300.000"));
+			enquecommand_P(PSTR("M84"));
+
+			lcd_commands_step = 1;
+
+		}
+
+		if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_setstatuspgm(WELCOME_MSG);
+			lcd_commands_step = 0;
+			lcd_commands_type = 0;
+			if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
+				lcd_wizard(10);
+			}
+		}
+
+	}
+
+#else //if not SNMM
+
+	if (lcd_commands_type == LCD_COMMAND_V2_CAL)
+	{
+		char cmd1[30];
+		float width = 0.4;
+		float length = 20 - width;
+		float extr = count_e(0.2, width, length);
+		float extr_short_segment = count_e(0.2, width, width);
+		lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+		if (lcd_commands_step == 0)
+		{
+			lcd_commands_step = 9;
+		}
+		if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty())
+		{
+			enquecommand_P(PSTR("M107"));
+			enquecommand_P(PSTR("M104 S210"));
+			enquecommand_P(PSTR("M140 S55"));
+			enquecommand_P(PSTR("M190 S55"));
+			enquecommand_P(PSTR("M109 S210"));
+			enquecommand_P(MSG_M117_V2_CALIBRATION);
+			enquecommand_P(PSTR("G87")); //sets calibration status
+			enquecommand_P(PSTR("G28"));
+			enquecommand_P(PSTR("G92 E0.0"));
+			lcd_commands_step = 8;
+		}
+		if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty())
+		{
+
+			lcd_implementation_clear();
+			lcd_goto_menu(lcd_babystep_z, 0, false);
+			enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0")); //intro line
+			enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0")); //intro line			
+			enquecommand_P(PSTR("G92 E0.0"));
+			enquecommand_P(PSTR("G21")); //set units to millimeters
+			enquecommand_P(PSTR("G90")); //use absolute coordinates
+			enquecommand_P(PSTR("M83")); //use relative distances for extrusion
+			enquecommand_P(PSTR("G1 E-1.50000 F2100.00000"));
+			enquecommand_P(PSTR("G1 Z0.150 F7200.000"));
+			enquecommand_P(PSTR("M204 S1000")); //set acceleration
+			enquecommand_P(PSTR("G1 F4000"));
+			lcd_commands_step = 7;
+		}
+		if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty()) //draw meander
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+
+
+			//just opposite direction
+			/*enquecommand_P(PSTR("G1 X50 Y55"));
+			enquecommand_P(PSTR("G1 F1080"));
+			enquecommand_P(PSTR("G1 X200 Y55 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y75 E0.49386"));
+			enquecommand_P(PSTR("G1 X50 Y75 E3.62773"));
+			enquecommand_P(PSTR("G1 X50 Y95 E0.49386"));
+			enquecommand_P(PSTR("G1 X200 Y95 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y115 E0.49386"));
+			enquecommand_P(PSTR("G1 X50 Y115 E3.62773"));
+			enquecommand_P(PSTR("G1 X50 Y135 E0.49386"));
+			enquecommand_P(PSTR("G1 X200 Y135 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y155 E0.66174"));
+			enquecommand_P(PSTR("G1 X100 Y155 E2.62773"));
+			enquecommand_P(PSTR("G1 X75 Y155 E2"));
+			enquecommand_P(PSTR("G1 X50 Y155 E2.5"));
+			enquecommand_P(PSTR("G1 E - 0.07500 F2100.00000"));*/
+
+
+			enquecommand_P(PSTR("G1 X50 Y155"));
+			enquecommand_P(PSTR("G1 F1080"));
+			enquecommand_P(PSTR("G1 X75 Y155 E2.5"));
+			enquecommand_P(PSTR("G1 X100 Y155 E2"));
+			enquecommand_P(PSTR("G1 X200 Y155 E2.62773"));
+			enquecommand_P(PSTR("G1 X200 Y135 E0.66174"));
+			enquecommand_P(PSTR("G1 X50 Y135 E3.62773"));
+			enquecommand_P(PSTR("G1 X50 Y115 E0.49386"));
+			enquecommand_P(PSTR("G1 X200 Y115 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y95 E0.49386"));
+			enquecommand_P(PSTR("G1 X50 Y95 E3.62773"));
+			enquecommand_P(PSTR("G1 X50 Y75 E0.49386"));
+			enquecommand_P(PSTR("G1 X200 Y75 E3.62773"));
+			enquecommand_P(PSTR("G1 X200 Y55 E0.49386"));
+			enquecommand_P(PSTR("G1 X50 Y55 E3.62773"));
+
+			strcpy(cmd1, "G1 X50 Y35 E");
+			strcat(cmd1, ftostr43(extr));
+			enquecommand(cmd1);
+
+			lcd_commands_step = 6;
+		}
+
+		if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty())
+		{
+
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+
+			for (int i = 0; i < 4; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+			}
+
+			lcd_commands_step = 5;
+		}
+
+		if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			for (int i = 4; i < 8; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+			}
+
+			lcd_commands_step = 4;
+		}
+
+		if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			for (int i = 8; i < 12; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+			}
+
+			lcd_commands_step = 3;
+		}
+
+		if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			for (int i = 12; i < 16; i++) {
+				strcpy(cmd1, "G1 X70 Y");
+				strcat(cmd1, ftostr32(35 - i*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 X50 Y");
+				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr));
+				enquecommand(cmd1);
+				strcpy(cmd1, "G1 Y");
+				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
+				strcat(cmd1, " E");
+				strcat(cmd1, ftostr43(extr_short_segment));
+				enquecommand(cmd1);
+			}
+
+			lcd_commands_step = 2;
+		}
+
+		if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+			enquecommand_P(PSTR("G1 E-0.07500 F2100.00000"));
+			enquecommand_P(PSTR("M107")); //turn off printer fan
+			enquecommand_P(PSTR("M104 S0")); // turn off temperature
+			enquecommand_P(PSTR("M140 S0")); // turn off heatbed
+			enquecommand_P(PSTR("G1 Z10 F1300.000"));
+			enquecommand_P(PSTR("G1 X10 Y180 F4000")); //home X axis
+			enquecommand_P(PSTR("M84"));// disable motors
+			lcd_timeoutToStatus = millis() - 1; //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
+			lcd_commands_step = 1;
+		}
+		if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty())
+		{
+			lcd_setstatuspgm(WELCOME_MSG);
+			lcd_commands_step = 0;
+			lcd_commands_type = 0;			
+			if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
+				lcd_wizard(10);
+			}
+		}
+
 	}
 
-	if (lcd_commands_type == 2)   /// stop print
+#endif // not SNMM
+
+	if (lcd_commands_type == LCD_COMMAND_STOP_PRINT)   /// stop print
 	{
+		
 
-		if (lcd_commands_step == 0) { lcd_commands_step = 6; custom_message = true;	}
+		if (lcd_commands_step == 0) 
+		{ 
+			lcd_commands_step = 6; 
+			custom_message = true;	
+		}
 
 		if (lcd_commands_step == 1 && !blocks_queued())
 		{
 			lcd_commands_step = 0;
 			lcd_commands_type = 0;
 			lcd_setstatuspgm(WELCOME_MSG);
+			custom_message_type = 0;
 			custom_message = false;
+			isPrintPaused = false;
 		}
 		if (lcd_commands_step == 2 && !blocks_queued())
 		{
 			setTargetBed(0);
-			setTargetHotend(0, 0);
-			setTargetHotend(0, 1);
-			setTargetHotend(0, 2);
+			enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0
+
 			manage_heater();
 			lcd_setstatuspgm(WELCOME_MSG);
 			cancel_heatup = false;
@@ -527,13 +1162,17 @@ void lcd_commands()
 		}
 		if (lcd_commands_step == 3 && !blocks_queued())
 		{
+      // M84: Disable steppers.
 			enquecommand_P(PSTR("M84"));
 			autotempShutdown();
 			lcd_commands_step = 2;
 		}
 		if (lcd_commands_step == 4 && !blocks_queued())
 		{
+			lcd_setstatuspgm(MSG_PLEASE_WAIT);
+      // G90: Absolute positioning.
 			enquecommand_P(PSTR("G90"));
+      // M83: Set extruder to relative mode.
 			enquecommand_P(PSTR("M83"));
 			#ifdef X_CANCEL_POS 
 			enquecommand_P(PSTR("G1 X"  STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000"));
@@ -541,27 +1180,49 @@ void lcd_commands()
 			enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000"));
 			#endif
 			lcd_ignore_click(false);
+			#ifdef SNMM
+			lcd_commands_step = 8;
+			#else
 			lcd_commands_step = 3;
+			#endif
 		}
 		if (lcd_commands_step == 5 && !blocks_queued())
 		{
 			lcd_setstatuspgm(MSG_PRINT_ABORTED);
+      // G91: Set to relative positioning.
 			enquecommand_P(PSTR("G91"));
+      // Lift up.
 			enquecommand_P(PSTR("G1 Z15 F1500"));
-			lcd_commands_step = 4;
+			if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4;
+			else lcd_commands_step = 3;
 		}
 		if (lcd_commands_step == 6 && !blocks_queued())
 		{
 			lcd_setstatuspgm(MSG_PRINT_ABORTED);
 			cancel_heatup = true;
 			setTargetBed(0);
-			setTargetHotend(0, 0);
+			#ifndef SNMM
+			setTargetHotend(0, 0);	//heating when changing filament for multicolor
 			setTargetHotend(0, 1);
 			setTargetHotend(0, 2);
+			#endif
 			manage_heater();
+			custom_message = true;
+			custom_message_type = 2;
 			lcd_commands_step = 5;
 		}
-
+		if (lcd_commands_step == 7 && !blocks_queued()) {
+			switch(snmm_stop_print_menu()) {
+				case 0: enquecommand_P(PSTR("M702")); break;//all 
+				case 1: enquecommand_P(PSTR("M702 U")); break; //used
+				case 2: enquecommand_P(PSTR("M702 C")); break; //current
+				default: enquecommand_P(PSTR("M702")); break;
+			}
+			lcd_commands_step = 3;
+		}
+		if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4)
+			lcd_commands_step = 7; 
+		}
 	}
 
 	if (lcd_commands_type == 3)
@@ -569,7 +1230,7 @@ void lcd_commands()
 		lcd_commands_type = 0;
 	}
 
-	if (lcd_commands_type == 4)   /// farm mode confirm
+	if (lcd_commands_type == LCD_COMMAND_FARM_MODE_CONFIRM)   /// farm mode confirm
 	{
 
 		if (lcd_commands_step == 0) { lcd_commands_step = 6; custom_message = true; }
@@ -603,12 +1264,68 @@ void lcd_commands()
 			enquecommand_P(PSTR("G91"));
 			enquecommand_P(PSTR("G1 Z15 F1500"));
 			st_synchronize();
+			#ifdef SNMM
+			lcd_commands_step = 7;
+			#else
 			lcd_commands_step = 5;
+			#endif
 		}
 
 	}
+	if (lcd_commands_type == LCD_COMMAND_PID_EXTRUDER) {
+		char cmd1[30];
+		
+		if (lcd_commands_step == 0) {
+			custom_message_type = 3;
+			custom_message_state = 1;
+			custom_message = true;
+			lcdDrawUpdate = 3;
+			lcd_commands_step = 3;
+		}
+		if (lcd_commands_step == 3 && !blocks_queued()) { //PID calibration
+			strcpy(cmd1, "M303 E0 S");
+			strcat(cmd1, ftostr3(pid_temp));
+			enquecommand(cmd1);
+			lcd_setstatuspgm(MSG_PID_RUNNING);
+			lcd_commands_step = 2;
+		}
+		if (lcd_commands_step == 2 && pid_tuning_finished) { //saving to eeprom
+			pid_tuning_finished = false;
+			custom_message_state = 0;
+			lcd_setstatuspgm(MSG_PID_FINISHED);
+			if (_Kp != 0 || _Ki != 0 || _Kd != 0) {
+			strcpy(cmd1, "M301 P");
+			strcat(cmd1, ftostr32(_Kp));
+			strcat(cmd1, " I");
+			strcat(cmd1, ftostr32(_Ki));
+			strcat(cmd1, " D");
+			strcat(cmd1, ftostr32(_Kd));
+			enquecommand(cmd1);
+			enquecommand_P(PSTR("M500"));
+			}
+			else {
+				SERIAL_ECHOPGM("Invalid PID cal. results. Not stored to EEPROM.");
+			}
+			display_time = millis();
+			lcd_commands_step = 1;
+		}
+		if ((lcd_commands_step == 1) && ((millis()- display_time)>2000)) { //calibration finished message
+			lcd_setstatuspgm(WELCOME_MSG);
+			custom_message_type = 0;
+			custom_message = false;
+			pid_temp = DEFAULT_PID_TEMP;
+			lcd_commands_step = 0;
+			lcd_commands_type = 0;
+		}
+	}
+
 
+}
 
+static float count_e(float layer_heigth, float extrusion_width, float extrusion_length) {
+	//returns filament length in mm which needs to be extrude to form line with extrusion_length * extrusion_width * layer heigth dimensions
+	float extr = extrusion_length * layer_heigth * extrusion_width / (M_PI * pow(1.75, 2) / 4);
+	return extr;
 }
 
 static void lcd_return_to_status() {
@@ -621,16 +1338,17 @@ static void lcd_return_to_status() {
     lcd_goto_menu(lcd_status_screen, 0, false);
 }
 
-static void lcd_sdcard_pause() {
-  card.pauseSDPrint();
-  isPrintPaused = true;
-  lcdDrawUpdate = 3;
+
+void lcd_sdcard_pause() {
+	lcd_return_to_status();
+	lcd_commands_type = LCD_COMMAND_LONG_PAUSE;
+
 }
 
 static void lcd_sdcard_resume() {
-	card.startFileprint();
-	isPrintPaused = false;
-	lcdDrawUpdate = 3;
+	lcd_return_to_status();
+	lcd_reset_alert_level(); //for fan speed error
+	lcd_commands_type = LCD_COMMAND_LONG_PAUSE_RESUME;
 }
 
 float move_menu_scale;
@@ -640,11 +1358,19 @@ static void lcd_move_menu_axis();
 
 /* Menu implementation */
 
+void lcd_preheat_farm()
+{
+  setTargetHotend0(FARM_PREHEAT_HOTEND_TEMP);
+  setTargetBed(FARM_PREHEAT_HPB_TEMP);
+  fanSpeed = 0;
+  lcd_return_to_status();
+  setWatch(); // heater sanity check timer
+}
 
 void lcd_preheat_pla()
 {
-  setTargetHotend0(plaPreheatHotendTemp);
-  setTargetBed(plaPreheatHPBTemp);
+  setTargetHotend0(PLA_PREHEAT_HOTEND_TEMP);
+  setTargetBed(PLA_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
@@ -652,8 +1378,8 @@ void lcd_preheat_pla()
 
 void lcd_preheat_abs()
 {
-  setTargetHotend0(absPreheatHotendTemp);
-  setTargetBed(absPreheatHPBTemp);
+  setTargetHotend0(ABS_PREHEAT_HOTEND_TEMP);
+  setTargetBed(ABS_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
@@ -661,8 +1387,8 @@ void lcd_preheat_abs()
 
 void lcd_preheat_pp()
 {
-  setTargetHotend0(ppPreheatHotendTemp);
-  setTargetBed(ppPreheatHPBTemp);
+  setTargetHotend0(PP_PREHEAT_HOTEND_TEMP);
+  setTargetBed(PP_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
@@ -670,8 +1396,8 @@ void lcd_preheat_pp()
 
 void lcd_preheat_pet()
 {
-  setTargetHotend0(petPreheatHotendTemp);
-  setTargetBed(petPreheatHPBTemp);
+  setTargetHotend0(PET_PREHEAT_HOTEND_TEMP);
+  setTargetBed(PET_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
@@ -679,8 +1405,8 @@ void lcd_preheat_pet()
 
 void lcd_preheat_hips()
 {
-  setTargetHotend0(hipsPreheatHotendTemp);
-  setTargetBed(hipsPreheatHPBTemp);
+  setTargetHotend0(HIPS_PREHEAT_HOTEND_TEMP);
+  setTargetBed(HIPS_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
@@ -688,8 +1414,8 @@ void lcd_preheat_hips()
 
 void lcd_preheat_flex()
 {
-  setTargetHotend0(flexPreheatHotendTemp);
-  setTargetBed(flexPreheatHPBTemp);
+  setTargetHotend0(FLEX_PREHEAT_HOTEND_TEMP);
+  setTargetBed(FLEX_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
@@ -707,18 +1433,176 @@ void lcd_cooldown()
 }
 
 
-
-static void lcd_preheat_menu()
+static void lcd_menu_extruder_info()
 {
-  START_MENU();
+    int fan_speed_RPM[2];
+    
+    pat9125_update();
+    
+    fan_speed_RPM[0] = 60*fan_speed[0];
+    fan_speed_RPM[1] = 60*fan_speed[1];
+    
+    // Display Nozzle fan RPM
+    
+    lcd.setCursor(0, 0);
+    lcd_printPGM(MSG_INFO_NOZZLE_FAN);
+    
+    lcd.setCursor(11, 0);
+    lcd.print("         ");
+    lcd.setCursor(12, 0);
+    lcd.print(itostr4(fan_speed_RPM[0]));
+    lcd.print(" RPM");
+    
+    // Display Nozzle fan RPM
+    
+    lcd.setCursor(0, 1);
+    lcd_printPGM(MSG_INFO_PRINT_FAN);
+    
+    lcd.setCursor(11, 1);
+    lcd.print("         ");
+    lcd.setCursor(12, 1);
+    lcd.print(itostr4(fan_speed_RPM[1]));
+    lcd.print(" RPM");
 
-  MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+    
+    // Display X and Y difference from Filament sensor
+    
+    lcd.setCursor(0, 2);
+    lcd.print("Fil. Xd:");
+    lcd.print(itostr3(pat9125_x));
+    lcd.print("   ");
+    lcd.setCursor(12, 2);
+    lcd.print("Yd:");
+    lcd.print(itostr3(pat9125_y));
+    
+    // Display Light intensity from Filament sensor
+    /* Frame_Avg register represents the average brightness of all pixels within a frame (324 pixels). This
+     value ranges from 0(darkest) to 255(brightest). */
+    lcd.setCursor(0, 3);
+    
+    lcd.print("Int:             ");
+    lcd.setCursor(5, 3);
+    lcd.print(itostr3(pat9125_b));
+    
+    // Display LASER shutter time from Filament sensor
+    /* Shutter register is an index of LASER shutter time. It is automatically controlled by the chip’s internal
+     auto-exposure algorithm. When the chip is tracking on a good reflection surface, the Shutter is small.
+     When the chip is tracking on a poor reflection surface, the Shutter is large. Value ranges from 0 to
+     46. */
+    
+    lcd.setCursor(10, 3);
+    
+    lcd.print("Shut:    ");
+    lcd.setCursor(15, 3);
+    lcd.print(itostr3(pat9125_s));
 
-  MENU_ITEM(function, PSTR("ABS  -  " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs);
-  MENU_ITEM(function, PSTR("PLA  -  " STRINGIFY(PLA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PLA_PREHEAT_HPB_TEMP)), lcd_preheat_pla);
-  MENU_ITEM(function, PSTR("PET  -  " STRINGIFY(PET_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PET_PREHEAT_HPB_TEMP)), lcd_preheat_pet);
-  MENU_ITEM(function, PSTR("HIPS -  " STRINGIFY(HIPS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(HIPS_PREHEAT_HPB_TEMP)), lcd_preheat_hips);
-  MENU_ITEM(function, PSTR("PP   -  " STRINGIFY(PP_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PP_PREHEAT_HPB_TEMP)), lcd_preheat_pp);
+    
+    if (lcd_clicked())
+    {
+        lcd_quick_feedback();
+        lcd_return_to_status();
+    }
+}
+
+static void lcd_menu_fails_stats()
+{
+    
+    // Display screen info
+    
+    lcd.setCursor(0, 0);
+    lcd.print("Failure stats       ");
+    
+    // Display power failures
+    uint8_t power_count = eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT);
+    lcd.setCursor(0, 1);
+    lcd.print(" Power failures:    ");
+    lcd.setCursor(17, 1);
+    lcd.print(itostr3((int)power_count));
+
+    
+    // Display Crash detected
+    uint8_t crash_count = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT);
+    lcd.setCursor(0, 2);
+    lcd.print(" Crash detected:    ");
+    lcd.setCursor(17, 2);
+    lcd.print(itostr3((int)crash_count));
+    
+    
+    // Display filament failures
+    uint8_t ferror_count = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT);
+    lcd.setCursor(0, 3);
+    lcd.print(" Filament fails:    ");
+    lcd.setCursor(17, 3);
+    lcd.print(itostr3((int)ferror_count));
+    
+
+    
+    if (lcd_clicked())
+    {
+        lcd_quick_feedback();
+        lcd_return_to_status();
+    }
+    
+}
+
+static void lcd_menu_temperatures()
+{
+	fprintf_P(lcdout, PSTR(ESC_H(1,1) "Ambient:  %d%c" ESC_H(1,2) "PINDA:    %d%c"), (int)current_temperature_ambient, '\x01', (int)current_temperature_pinda, '\x01');
+/*
+    lcd.setCursor(1, 1);
+    lcd.print("Ambient: ");
+    lcd.setCursor(12, 1);
+    lcd.print(ftostr31ns(current_temperature_ambient));
+	lcd.print(LCD_STR_DEGREE);
+    lcd.setCursor(1, 2);
+    lcd.print("PINDA: ");
+    lcd.setCursor(12, 2);
+    lcd.print(ftostr31ns(current_temperature_pinda));
+	lcd.print(LCD_STR_DEGREE);*/
+    if (lcd_clicked())
+    {
+        lcd_quick_feedback();
+        lcd_return_to_status();
+    }
+}
+
+static void lcd_menu_belt_status()
+{
+    fprintf_P(lcdout, PSTR(ESC_H(1,0) "Belt status" ESC_H(2,1) "X %d" ESC_H(2,2) "Y %d" ), eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_X)), eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_Y)));
+    if (lcd_clicked())
+    {
+        lcd_quick_feedback();
+        lcd_return_to_status();
+    }
+}
+
+extern void stop_and_save_print_to_ram(float z_move, float e_move);
+extern void restore_print_from_ram_and_continue(float e_move);
+
+static void lcd_menu_test_save()
+{
+	stop_and_save_print_to_ram(10, -0.8);
+}
+
+static void lcd_menu_test_restore()
+{
+	restore_print_from_ram_and_continue(0.8);
+}
+
+static void lcd_preheat_menu()
+{
+  START_MENU();
+
+  MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+
+  if (farm_mode)
+    MENU_ITEM(function, PSTR("farm  -  " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FARM_PREHEAT_HPB_TEMP)), lcd_preheat_farm);
+
+  MENU_ITEM(function, PSTR("PLA  -  " STRINGIFY(PLA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PLA_PREHEAT_HPB_TEMP)), lcd_preheat_pla);
+  MENU_ITEM(function, PSTR("PET  -  " STRINGIFY(PET_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PET_PREHEAT_HPB_TEMP)), lcd_preheat_pet);
+  MENU_ITEM(function, PSTR("ABS  -  " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs);
+  MENU_ITEM(function, PSTR("HIPS -  " STRINGIFY(HIPS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(HIPS_PREHEAT_HPB_TEMP)), lcd_preheat_hips);
+  MENU_ITEM(function, PSTR("PP   -  " STRINGIFY(PP_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PP_PREHEAT_HPB_TEMP)), lcd_preheat_pp);
   MENU_ITEM(function, PSTR("FLEX -  " STRINGIFY(FLEX_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FLEX_PREHEAT_HPB_TEMP)), lcd_preheat_flex);
 
   MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown);
@@ -728,17 +1612,36 @@ static void lcd_preheat_menu()
 
 static void lcd_support_menu()
 {
+    if (menuData.supportMenu.status == 0 || lcdDrawUpdate == 2) {
+        // Menu was entered or SD card status has changed (plugged in or removed).
+        // Initialize its status.
+        menuData.supportMenu.status = 1;
+        menuData.supportMenu.is_flash_air = card.ToshibaFlashAir_isEnabled() && card.ToshibaFlashAir_GetIP(menuData.supportMenu.ip);
+        if (menuData.supportMenu.is_flash_air)
+            sprintf_P(menuData.supportMenu.ip_str, PSTR("%d.%d.%d.%d"), 
+                menuData.supportMenu.ip[0], menuData.supportMenu.ip[1], 
+                menuData.supportMenu.ip[2], menuData.supportMenu.ip[3]);
+    } else if (menuData.supportMenu.is_flash_air && 
+        menuData.supportMenu.ip[0] == 0 && menuData.supportMenu.ip[1] == 0 && 
+        menuData.supportMenu.ip[2] == 0 && menuData.supportMenu.ip[3] == 0 &&
+        ++ menuData.supportMenu.status == 16) {
+        // Waiting for the FlashAir card to get an IP address from a router. Force an update.
+        menuData.supportMenu.status = 0;
+    }
+
   START_MENU();
 
   MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
 
+  MENU_ITEM(back, PSTR("Firmware:"), lcd_main_menu);
+  MENU_ITEM(back, PSTR(" " FW_version_build), lcd_main_menu);
   // Ideally this block would be optimized out by the compiler.
-  const uint8_t fw_string_len = strlen_P(FW_VERSION_STR_P());
+/*  const uint8_t fw_string_len = strlen_P(FW_VERSION_STR_P());
   if (fw_string_len < 6) {
       MENU_ITEM(back, PSTR(MSG_FW_VERSION " - " FW_version), lcd_main_menu);
   } else {
       MENU_ITEM(back, PSTR("FW - " FW_version), lcd_main_menu);
-  }
+  }*/
       
   MENU_ITEM(back, MSG_PRUSA3D, lcd_main_menu);
   MENU_ITEM(back, MSG_PRUSA3D_FORUM, lcd_main_menu);
@@ -748,29 +1651,39 @@ static void lcd_support_menu()
   MENU_ITEM(back, PSTR(ELECTRONICS),lcd_main_menu);
   MENU_ITEM(back, PSTR(NOZZLE_TYPE),lcd_main_menu);
   MENU_ITEM(back, PSTR("------------"), lcd_main_menu);
-  MENU_ITEM(back, PSTR("Date: "), lcd_main_menu);
+  MENU_ITEM(back, MSG_DATE, lcd_main_menu);
   MENU_ITEM(back, PSTR(__DATE__), lcd_main_menu);
 
   // Show the FlashAir IP address, if the card is available.
-  uint8_t ip[4];
-  bool hasIP = card.ToshibaFlashAir_GetIP(ip);
-  if (hasIP) {
+  if (menuData.supportMenu.is_flash_air) {
+      MENU_ITEM(back, PSTR("------------"), lcd_main_menu);
       MENU_ITEM(back, PSTR("FlashAir IP Addr:"), lcd_main_menu);
-      char buf[30];
-      sprintf_P(buf, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
-      MENU_ITEM(back_RAM, buf, lcd_main_menu);
+      MENU_ITEM(back_RAM, menuData.supportMenu.ip_str, lcd_main_menu);
   }
-
+  #ifndef MK1BP
+  MENU_ITEM(back, PSTR("------------"), lcd_main_menu);
+  if (!IS_SD_PRINTING && !is_usb_printing) MENU_ITEM(function, MSG_XYZ_DETAILS, lcd_service_mode_show_result);
+  MENU_ITEM(submenu, MSG_INFO_EXTRUDER, lcd_menu_extruder_info);
+    
+  MENU_ITEM(submenu, PSTR("Belt status"), lcd_menu_belt_status);
+    
+  MENU_ITEM(submenu, PSTR("Temperatures"), lcd_menu_temperatures);
+  #endif //MK1BP
   END_MENU();
 }
 
+void lcd_set_fan_check() {
+	fans_check_enabled = !fans_check_enabled;
+	eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED, fans_check_enabled);
+	lcd_goto_menu(lcd_settings_menu, 8);
+}
+
 void lcd_unLoadFilament()
 {
 
   if (degHotend0() > EXTRUDE_MINTEMP) {
-
-    enquecommand_P(PSTR(UNLOAD_FILAMENT_0));
-    enquecommand_P(PSTR(UNLOAD_FILAMENT_1));
+	
+	  enquecommand_P(PSTR("M702")); //unload filament
 
   } else {
 
@@ -804,8 +1717,11 @@ void lcd_wait_interact() {
   lcd_implementation_clear();
 
   lcd.setCursor(0, 1);
-
+#ifdef SNMM 
+  lcd_printPGM(MSG_PREPARE_FILAMENT);
+#else
   lcd_printPGM(MSG_INSERT_FILAMENT);
+#endif
   lcd.setCursor(0, 2);
   lcd_printPGM(MSG_PRESS);
 
@@ -863,7 +1779,6 @@ void lcd_loading_filament() {
   lcd.setCursor(0, 2);
   lcd_printPGM(MSG_PLEASE_WAIT);
 
-
   for (int i = 0; i < 20; i++) {
 
     lcd.setCursor(i, 3);
@@ -871,7 +1786,11 @@ void lcd_loading_filament() {
     for (int j = 0; j < 10 ; j++) {
       manage_heater();
       manage_inactivity(true);
-      delay(110);
+#ifdef SNMM
+      delay(153);
+#else
+	  delay(137);
+#endif
 
     }
 
@@ -880,6 +1799,9 @@ void lcd_loading_filament() {
 
 }
 
+
+
+
 void lcd_alright() {
   int enc_dif = 0;
   int cursor_pos = 1;
@@ -975,10 +1897,10 @@ void lcd_LoadFilament()
   if (degHotend0() > EXTRUDE_MINTEMP) 
   {
 	  custom_message = true;
-	  lcd_commands_type = 1;
-	  SERIAL_ECHOLN("Loading filament");
-	  // commands() will handle the rest
-  } 
+	  loading_flag = true;
+	  enquecommand_P(PSTR("M701")); //load filament
+	  SERIAL_ECHOLN("Loading filament");	    
+    }
   else 
   {
 
@@ -994,7 +1916,7 @@ void lcd_LoadFilament()
 }
 
 
-static void lcd_menu_statistics()
+void lcd_menu_statistics()
 {
 
 	if (IS_SD_PRINTING)
@@ -1003,7 +1925,6 @@ static void lcd_menu_statistics()
 		int _cm = (total_filament_used - (_met * 100000))/10;
 		
 		int _t = (millis() - starttime) / 1000;
-
 		int _h = _t / 3600;
 		int _m = (_t - (_h * 3600)) / 60;
 		int _s = _t - ((_h * 3600) + (_m * 60));
@@ -1037,8 +1958,10 @@ static void lcd_menu_statistics()
 	else
 	{
 		unsigned long _filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED);
-		unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME);
-		uint8_t _days, _hours, _minutes;
+		unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //in minutes
+		
+		uint8_t _hours, _minutes;
+		uint32_t _days;
 
 		float _filament_m = (float)_filament;
 		int _filament_km = (_filament >= 100000) ? _filament / 100000 : 0;
@@ -1092,13 +2015,14 @@ static void lcd_menu_statistics()
 		lcd.print(itostr3(_days));
 
 
-
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
 		while (!lcd_clicked())
 		{
 			manage_heater();
 			manage_inactivity(true);
 			delay(100);
 		}
+		KEEPALIVE_STATE(NOT_BUSY);
 
 		lcd_quick_feedback();
 		lcd_return_to_status();
@@ -1107,29 +2031,36 @@ static void lcd_menu_statistics()
 
 
 static void _lcd_move(const char *name, int axis, int min, int max) {
-  if (encoderPosition != 0) {
+	if (encoderPosition != 0) {
     refresh_cmd_timeout();
-    current_position[axis] += float((int)encoderPosition) * move_menu_scale;
-    if (min_software_endstops && current_position[axis] < min) current_position[axis] = min;
-    if (max_software_endstops && current_position[axis] > max) current_position[axis] = max;
-    encoderPosition = 0;
-    world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
-    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis] / 60, active_extruder);
-    lcdDrawUpdate = 1;
+    if (! planner_queue_full()) {
+      current_position[axis] += float((int)encoderPosition) * move_menu_scale;
+      if (min_software_endstops && current_position[axis] < min) current_position[axis] = min;
+      if (max_software_endstops && current_position[axis] > max) current_position[axis] = max;
+      encoderPosition = 0;
+      world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
+      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis] / 60, active_extruder);
+      lcdDrawUpdate = 1;
+    }
   }
   if (lcdDrawUpdate) lcd_implementation_drawedit(name, ftostr31(current_position[axis]));
-  if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis);
+  if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis); {
+  }
 }
 
 
 static void lcd_move_e()
 {
+	if (degHotend0() > EXTRUDE_MINTEMP) {
   if (encoderPosition != 0)
   {
-    current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale;
-    encoderPosition = 0;
-    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS] / 60, active_extruder);
-    lcdDrawUpdate = 1;
+    refresh_cmd_timeout();
+    if (! planner_queue_full()) {
+      current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale;
+      encoderPosition = 0;
+      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS] / 60, active_extruder);
+      lcdDrawUpdate = 1;
+    }
   }
   if (lcdDrawUpdate)
   {
@@ -1137,6 +2068,73 @@ static void lcd_move_e()
   }
   if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis);
 }
+	else {
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+
+		delay(2000);
+		lcd_return_to_status();
+	}
+}
+
+void lcd_service_mode_show_result() {
+	float angleDiff;
+	lcd_set_custom_characters_degree();
+	count_xyz_details();
+	angleDiff = eeprom_read_float((float*)(EEPROM_XYZ_CAL_SKEW));
+	lcd_update_enable(false);
+	lcd_implementation_clear();
+	lcd_printPGM(MSG_Y_DISTANCE_FROM_MIN);
+	lcd_print_at_PGM(0, 1, MSG_LEFT);
+	lcd_print_at_PGM(0, 2, MSG_RIGHT);
+
+	for (int i = 0; i < 2; i++) {
+		if(distance_from_min[i] < 200) {
+			lcd_print_at_PGM(11, i + 1, PSTR(""));
+			lcd.print(distance_from_min[i]);
+			lcd_print_at_PGM((distance_from_min[i] < 0) ? 17 : 16, i + 1, PSTR("mm"));		
+		} else lcd_print_at_PGM(11, i + 1, PSTR("N/A"));
+	}
+	delay_keep_alive(500);
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	while (!lcd_clicked()) {
+		delay_keep_alive(100);
+	}
+	delay_keep_alive(500);
+	lcd_implementation_clear();
+	
+
+	lcd_printPGM(MSG_MEASURED_SKEW);
+	if (angleDiff < 100) {
+		lcd.setCursor(15, 0);
+		lcd.print(angleDiff * 180 / M_PI);
+		lcd.print(LCD_STR_DEGREE);
+	}else lcd_print_at_PGM(16, 0, PSTR("N/A"));
+	lcd_print_at_PGM(0, 1, PSTR("--------------------"));
+	lcd_print_at_PGM(0, 2, MSG_SLIGHT_SKEW);
+	lcd_print_at_PGM(15, 2, PSTR(""));
+	lcd.print(bed_skew_angle_mild * 180 / M_PI);
+	lcd.print(LCD_STR_DEGREE);
+	lcd_print_at_PGM(0, 3, MSG_SEVERE_SKEW);
+	lcd_print_at_PGM(15, 3, PSTR(""));
+	lcd.print(bed_skew_angle_extreme * 180 / M_PI);
+	lcd.print(LCD_STR_DEGREE);
+	delay_keep_alive(500);
+	while (!lcd_clicked()) {
+		delay_keep_alive(100);
+	}
+	KEEPALIVE_STATE(NOT_BUSY);
+	delay_keep_alive(500);
+	lcd_set_custom_characters_arrows();
+	lcd_return_to_status();
+	lcd_update_enable(true);
+	lcd_update(2);
+}
+
+
 
 
 // Save a single axis babystep value.
@@ -1171,24 +2169,54 @@ static void lcd_move_z() {
 
 
 
-static void _lcd_babystep(int axis, const char *msg) {
+static void _lcd_babystep(int axis, const char *msg) 
+{
+    if (menuData.babyStep.status == 0) {
+        // Menu was entered.
+        // Initialize its status.
+        menuData.babyStep.status = 1;
+		check_babystep();
+
+		EEPROM_read_B(EEPROM_BABYSTEP_X, &menuData.babyStep.babystepMem[0]);
+        EEPROM_read_B(EEPROM_BABYSTEP_Y, &menuData.babyStep.babystepMem[1]);
+        EEPROM_read_B(EEPROM_BABYSTEP_Z, &menuData.babyStep.babystepMem[2]);
+		
+        menuData.babyStep.babystepMemMM[0] = menuData.babyStep.babystepMem[0]/axis_steps_per_unit[X_AXIS];
+        menuData.babyStep.babystepMemMM[1] = menuData.babyStep.babystepMem[1]/axis_steps_per_unit[Y_AXIS];
+        menuData.babyStep.babystepMemMM[2] = menuData.babyStep.babystepMem[2]/axis_steps_per_unit[Z_AXIS];
+        lcdDrawUpdate = 1;
+		//SERIAL_ECHO("Z baby step: ");
+		//SERIAL_ECHO(menuData.babyStep.babystepMem[2]);
+        // Wait 90 seconds before closing the live adjust dialog.
+        lcd_timeoutToStatus = millis() + 90000;
+    }
+
   if (encoderPosition != 0) 
   {
-    CRITICAL_SECTION_START
-    babystepsTodo[axis] += (int)encoderPosition;
-    CRITICAL_SECTION_END
-    babystepMem[axis] += (int)encoderPosition;
-    babystepMemMM[axis] = babystepMem[axis]/axis_steps_per_unit[Z_AXIS];
+	if (homing_flag) encoderPosition = 0;
+
+    menuData.babyStep.babystepMem[axis] += (int)encoderPosition;
+	if (axis == 2) {
+		if (menuData.babyStep.babystepMem[axis] < Z_BABYSTEP_MIN) menuData.babyStep.babystepMem[axis] = Z_BABYSTEP_MIN; //-3999 -> -9.99 mm
+		else  if (menuData.babyStep.babystepMem[axis] > Z_BABYSTEP_MAX) menuData.babyStep.babystepMem[axis] = Z_BABYSTEP_MAX; //0
+		else {
+			CRITICAL_SECTION_START
+				babystepsTodo[axis] += (int)encoderPosition;
+			CRITICAL_SECTION_END		
+		}
+	}
+    menuData.babyStep.babystepMemMM[axis] = menuData.babyStep.babystepMem[axis]/axis_steps_per_unit[axis]; 
 	  delay(50);
 	  encoderPosition = 0;
     lcdDrawUpdate = 1;
   }
-  if (lcdDrawUpdate) lcd_implementation_drawedit_2(msg, ftostr13ns(babystepMemMM[axis]));
+  if (lcdDrawUpdate)
+    lcd_implementation_drawedit_2(msg, ftostr13ns(menuData.babyStep.babystepMemMM[axis]));
   if (LCD_CLICKED || menuExiting) {
     // Only update the EEPROM when leaving the menu.
     EEPROM_save_B(
       (axis == 0) ? EEPROM_BABYSTEP_X : ((axis == 1) ? EEPROM_BABYSTEP_Y : EEPROM_BABYSTEP_Z), 
-      &babystepMem[axis]);
+      &menuData.babyStep.babystepMem[axis]);
   }
   if (LCD_CLICKED) lcd_goto_menu(lcd_main_menu);
 }
@@ -1203,6 +2231,99 @@ static void lcd_babystep_z() {
 	_lcd_babystep(Z_AXIS, (MSG_BABYSTEPPING_Z));
 }
 
+static void lcd_adjust_bed();
+
+static void lcd_adjust_bed_reset()
+{
+    eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1);
+    eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT , 0);
+    eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0);
+    eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0);
+    eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR , 0);
+    lcd_goto_menu(lcd_adjust_bed, 0, false);
+    // Because we did not leave the menu, the menuData did not reset.
+    // Force refresh of the bed leveling data.
+    menuData.adjustBed.status = 0;
+}
+
+void adjust_bed_reset() {
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT, 0);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR, 0);
+	menuData.adjustBed.left = menuData.adjustBed.left2 = 0;
+	menuData.adjustBed.right = menuData.adjustBed.right2 = 0;
+	menuData.adjustBed.front = menuData.adjustBed.front2 = 0;
+	menuData.adjustBed.rear = menuData.adjustBed.rear2 = 0;
+}
+#define BED_ADJUSTMENT_UM_MAX 50
+
+static void lcd_adjust_bed()
+{
+    if (menuData.adjustBed.status == 0) {
+        // Menu was entered.
+        // Initialize its status.
+        menuData.adjustBed.status = 1;
+        bool valid = false;
+        menuData.adjustBed.left  = menuData.adjustBed.left2  = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT);
+        menuData.adjustBed.right = menuData.adjustBed.right2 = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT);
+        menuData.adjustBed.front = menuData.adjustBed.front2 = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT);
+        menuData.adjustBed.rear  = menuData.adjustBed.rear2  = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR);
+        if (eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1 && 
+            menuData.adjustBed.left  >= -BED_ADJUSTMENT_UM_MAX && menuData.adjustBed.left  <= BED_ADJUSTMENT_UM_MAX &&
+            menuData.adjustBed.right >= -BED_ADJUSTMENT_UM_MAX && menuData.adjustBed.right <= BED_ADJUSTMENT_UM_MAX &&
+            menuData.adjustBed.front >= -BED_ADJUSTMENT_UM_MAX && menuData.adjustBed.front <= BED_ADJUSTMENT_UM_MAX &&
+            menuData.adjustBed.rear  >= -BED_ADJUSTMENT_UM_MAX && menuData.adjustBed.rear  <= BED_ADJUSTMENT_UM_MAX)
+            valid = true;
+        if (! valid) {
+            // Reset the values: simulate an edit.
+            menuData.adjustBed.left2  = 0;
+            menuData.adjustBed.right2 = 0;
+            menuData.adjustBed.front2 = 0;
+            menuData.adjustBed.rear2  = 0;
+        }
+        lcdDrawUpdate = 1;
+        eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1);
+    }
+
+    if (menuData.adjustBed.left  != menuData.adjustBed.left2)
+        eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT,  menuData.adjustBed.left  = menuData.adjustBed.left2);
+    if (menuData.adjustBed.right != menuData.adjustBed.right2)
+        eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, menuData.adjustBed.right = menuData.adjustBed.right2);
+    if (menuData.adjustBed.front != menuData.adjustBed.front2)
+        eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT, menuData.adjustBed.front = menuData.adjustBed.front2);
+    if (menuData.adjustBed.rear  != menuData.adjustBed.rear2)
+        eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR,  menuData.adjustBed.rear  = menuData.adjustBed.rear2);
+
+    START_MENU();
+    MENU_ITEM(back, MSG_SETTINGS, lcd_calibration_menu);
+    MENU_ITEM_EDIT(int3, MSG_BED_CORRECTION_LEFT,  &menuData.adjustBed.left2,  -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);
+    MENU_ITEM_EDIT(int3, MSG_BED_CORRECTION_RIGHT, &menuData.adjustBed.right2, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);
+    MENU_ITEM_EDIT(int3, MSG_BED_CORRECTION_FRONT, &menuData.adjustBed.front2, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);
+    MENU_ITEM_EDIT(int3, MSG_BED_CORRECTION_REAR,  &menuData.adjustBed.rear2,  -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);
+    MENU_ITEM(function, MSG_BED_CORRECTION_RESET, lcd_adjust_bed_reset);
+    END_MENU();
+}
+
+void pid_extruder() {
+
+	lcd_implementation_clear();
+	lcd.setCursor(1, 0);
+	lcd_printPGM(MSG_SET_TEMPERATURE);
+	pid_temp += int(encoderPosition);
+	if (pid_temp > HEATER_0_MAXTEMP) pid_temp = HEATER_0_MAXTEMP;
+	if (pid_temp < HEATER_0_MINTEMP) pid_temp = HEATER_0_MINTEMP;
+	encoderPosition = 0;
+	lcd.setCursor(1, 2);
+	lcd.print(ftostr3(pid_temp));
+	if (lcd_clicked()) {
+		lcd_commands_type = LCD_COMMAND_PID_EXTRUDER;
+		lcd_return_to_status();
+		lcd_update(2);
+	}
+
+}
 
 void lcd_adjust_z() {
   int enc_dif = 0;
@@ -1268,20 +2389,16 @@ void lcd_adjust_z() {
     if (lcd_clicked()) {
       fsm = cursor_pos;
       if (fsm == 1) {
-        EEPROM_read_B(EEPROM_BABYSTEP_X, &babystepMem[0]);
-        EEPROM_read_B(EEPROM_BABYSTEP_Y, &babystepMem[1]);
-        EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystepMem[2]);
+        int babystepLoadZ = 0;
+        EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystepLoadZ);
         CRITICAL_SECTION_START
-        babystepsTodo[Z_AXIS] = babystepMem[2];
+        babystepsTodo[Z_AXIS] = babystepLoadZ;
         CRITICAL_SECTION_END
       } else {
-        babystepMem[0] = 0;
-        babystepMem[1] = 0;
-        babystepMem[2] = 0;
-
-        EEPROM_save_B(EEPROM_BABYSTEP_X, &babystepMem[0]);
-        EEPROM_save_B(EEPROM_BABYSTEP_Y, &babystepMem[1]);
-        EEPROM_save_B(EEPROM_BABYSTEP_Z, &babystepMem[2]);
+        int zero = 0;
+        EEPROM_save_B(EEPROM_BABYSTEP_X, &zero);
+        EEPROM_save_B(EEPROM_BABYSTEP_Y, &zero);
+        EEPROM_save_B(EEPROM_BABYSTEP_Z, &zero);
       }
       delay(500);
     }
@@ -1292,10 +2409,34 @@ void lcd_adjust_z() {
 
 }
 
+/*void lcd_wait_for_cool_down() {
+	lcd_set_custom_characters_degree();
+	while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) {
+		lcd_display_message_fullscreen_P(MSG_WAITING_TEMP);
+
+		lcd.setCursor(0, 4);
+		lcd.print(LCD_STR_THERMOMETER[0]);
+		lcd.print(ftostr3(degHotend(0)));
+		lcd.print("/0");		
+		lcd.print(LCD_STR_DEGREE);
+
+		lcd.setCursor(9, 4);
+		lcd.print(LCD_STR_BEDTEMP[0]);
+		lcd.print(ftostr3(degBed()));
+		lcd.print("/0");		
+		lcd.print(LCD_STR_DEGREE);
+		lcd_set_custom_characters();
+		delay_keep_alive(1000);
+	}
+	lcd_set_custom_characters_arrows();
+}*/
+
 // Lets the user move the Z carriage up to the end stoppers.
 // When done, it sets the current Z to Z_MAX_POS and returns true.
 // Otherwise the Z calibration is not changed and false is returned.
-bool lcd_calibrate_z_end_stop_manual()
+
+#ifndef TMC2130
+bool lcd_calibrate_z_end_stop_manual(bool only_z)
 {
     bool clean_nozzle_asked = false;
 
@@ -1306,13 +2447,16 @@ bool lcd_calibrate_z_end_stop_manual()
     // Until confirmed by the confirmation dialog.
     for (;;) {
         unsigned long previous_millis_cmd = millis();
-        lcd_display_message_fullscreen_P(MSG_MOVE_CARRIAGE_TO_THE_TOP);
+        const char   *msg                 = only_z ? MSG_MOVE_CARRIAGE_TO_THE_TOP_Z : MSG_MOVE_CARRIAGE_TO_THE_TOP;
+        const char   *msg_next            = lcd_display_message_fullscreen_P(msg);
+        const bool    multi_screen        = msg_next != NULL;
+        unsigned long previous_millis_msg = millis();
         // Until the user finishes the z up movement.
         encoderDiff = 0;
         encoderPosition = 0;
         for (;;) {
-            if (millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
-                goto canceled;
+//          if (millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
+//             goto canceled;
             manage_heater();
             manage_inactivity(true);
             if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) {
@@ -1320,33 +2464,37 @@ bool lcd_calibrate_z_end_stop_manual()
                 previous_millis_cmd = millis();
                 encoderPosition += abs(encoderDiff / ENCODER_PULSES_PER_STEP);
                 encoderDiff = 0;
-                // Only move up, whatever the user does.
-                current_position[Z_AXIS] += fabs(encoderPosition);
-                encoderPosition = 0;
-                plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS] / 60, active_extruder);
-                // Wait for the motors to stop.
-                st_synchronize();
-                // Claim we are at Z=0, so the soft end stop will not trigger.
-                current_position[Z_AXIS] = 0;
-                plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+                if (! planner_queue_full()) {
+                    // Only move up, whatever direction the user rotates the encoder.
+                    current_position[Z_AXIS] += fabs(encoderPosition);
+                    encoderPosition = 0;
+                    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS] / 60, active_extruder);
+                }
             }
             if (lcd_clicked()) {
-                // Wait until the Z up movement is finished.
-                st_synchronize();
+                // Abort a move if in progress.
+                planner_abort_hard();
                 while (lcd_clicked()) ;
                 delay(10);
                 while (lcd_clicked()) ;
                 break;
             }
+            if (multi_screen && millis() - previous_millis_msg > 5000) {
+                if (msg_next == NULL)
+                    msg_next = msg;
+                msg_next = lcd_display_message_fullscreen_P(msg_next);
+                previous_millis_msg = millis();
+            }
         }
 
         if (! clean_nozzle_asked) {
             lcd_show_fullscreen_message_and_wait_P(MSG_CONFIRM_NOZZLE_CLEAN);
             clean_nozzle_asked = true;
         }
+		
 
         // Let the user confirm, that the Z carriage is at the top end stoppers.
-        int8_t result = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_CONFIRM_CARRIAGE_AT_THE_TOP);
+        int8_t result = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_CONFIRM_CARRIAGE_AT_THE_TOP, false);
         if (result == -1)
             goto canceled;
         else if (result == 1)
@@ -1359,34 +2507,70 @@ calibrated:
     // during the search for the induction points.
     current_position[Z_AXIS] = Z_MAX_POS-3.f;
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+    
+    
+    if(only_z){
+        lcd_display_message_fullscreen_P(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1);
+        lcd_implementation_print_at(0, 3, 1);
+        lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2);
+    }else{
+		lcd_show_fullscreen_message_and_wait_P(MSG_PAPER);
+        lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1);
+        lcd_implementation_print_at(0, 2, 1);
+        lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2);
+    }
+    
+    
     return true;
 
 canceled:
     return false;
 }
 
-static inline bool pgm_is_whitespace(const char *c)
+#endif // TMC2130
+
+static inline bool pgm_is_whitespace(const char *c_addr)
+{
+    const char c = pgm_read_byte(c_addr);
+    return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+
+static inline bool pgm_is_interpunction(const char *c_addr)
 {
-    return pgm_read_byte(c) == ' ' || pgm_read_byte(c) == '\t' || pgm_read_byte(c) == '\r' || pgm_read_byte(c) == '\n';
+    const char c = pgm_read_byte(c_addr);
+    return c == '.' || c == ',' || c == ':'|| c == ';' || c == '?' || c == '!' || c == '/';
 }
 
-void lcd_display_message_fullscreen_P(const char *msg)
+const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines)
 {
     // Disable update of the screen by the usual lcd_update() routine. 
     lcd_update_enable(false);
     lcd_implementation_clear();
     lcd.setCursor(0, 0);
-    for (int8_t row = 0; row < 4; ++ row) {
+    const char *msgend = msg;
+    uint8_t row = 0;
+    bool multi_screen = false;
+    for (; row < 4; ++ row) {
         while (pgm_is_whitespace(msg))
             ++ msg;
         if (pgm_read_byte(msg) == 0)
             // End of the message.
             break;
         lcd.setCursor(0, row);
-        const char *msgend2 = msg + min(strlen_P(msg), 20);
-        const char *msgend = msgend2;
-        if (pgm_read_byte(msgend) != 0 && ! pgm_is_whitespace(msgend)) {
-              // Splitting a word. Find the start of the current word.
+        uint8_t linelen = min(strlen_P(msg), 20);
+        const char *msgend2 = msg + linelen;
+        msgend = msgend2;
+        if (row == 3 && linelen == 20) {
+            // Last line of the display, full line shall be displayed.
+            // Find out, whether this message will be split into multiple screens.
+            while (pgm_is_whitespace(msgend))
+                ++ msgend;
+            multi_screen = pgm_read_byte(msgend) != 0;
+            if (multi_screen)
+                msgend = (msgend2 -= 2);
+        }
+        if (pgm_read_byte(msgend) != 0 && ! pgm_is_whitespace(msgend) && ! pgm_is_interpunction(msgend)) {
+            // Splitting a word. Find the start of the current word.
             while (msgend > msg && ! pgm_is_whitespace(msgend - 1))
                  -- msgend;
             if (msgend == msg)
@@ -1400,26 +2584,64 @@ void lcd_display_message_fullscreen_P(const char *msg)
             lcd.print(c);
         }
     }
+
+    if (multi_screen) {
+        // Display the "next screen" indicator character.
+        // lcd_set_custom_characters_arrows();
+        lcd_set_custom_characters_nextpage();
+        lcd.setCursor(19, 3);
+        // Display the down arrow.
+        lcd.print(char(1));
+    }
+
+    nlines = row;
+    return multi_screen ? msgend : NULL;
 }
 
 void lcd_show_fullscreen_message_and_wait_P(const char *msg)
 {
-    lcd_display_message_fullscreen_P(msg);
-
-    // Until confirmed by a button click.
-    for (;;) {
-        delay_keep_alive(50);
-        if (lcd_clicked()) {
-            while (lcd_clicked()) ;
-            delay(10);
-            while (lcd_clicked()) ;
-            break;
+    const char *msg_next = lcd_display_message_fullscreen_P(msg);
+    bool multi_screen = msg_next != NULL;
+	lcd_set_custom_characters_nextpage();
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	// Until confirmed by a button click.
+	for (;;) {
+		if (!multi_screen) {
+			lcd.setCursor(19, 3);
+			// Display the confirm char.
+			lcd.print(char(2));
+		}
+        // Wait for 5 seconds before displaying the next text.
+        for (uint8_t i = 0; i < 100; ++ i) {
+            delay_keep_alive(50);
+            if (lcd_clicked()) {
+                while (lcd_clicked()) ;
+                delay(10);
+                while (lcd_clicked()) ;
+				KEEPALIVE_STATE(IN_HANDLER);
+				lcd_set_custom_characters();
+				lcd_update_enable(true);
+				lcd_update(2);
+                return;
+            }
+        }
+        if (multi_screen) {
+            if (msg_next == NULL)
+                msg_next = msg;
+            msg_next = lcd_display_message_fullscreen_P(msg_next);
+			if (msg_next == NULL) {
+
+				lcd.setCursor(19, 3);
+				// Display the confirm char.
+				lcd.print(char(2));
+			}
         }
     }
 }
 
 void lcd_wait_for_click()
 {
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
     for (;;) {
         manage_heater();
         manage_inactivity(true);
@@ -1427,54 +2649,136 @@ void lcd_wait_for_click()
             while (lcd_clicked()) ;
             delay(10);
             while (lcd_clicked()) ;
+			KEEPALIVE_STATE(IN_HANDLER);
             return;
         }
     }
 }
 
-int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting)
+int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes) //currently just max. n*4 + 3 lines supported (set in language header files)
 {
-    lcd_display_message_fullscreen_P(msg);
+	const char *msg_next = lcd_display_message_fullscreen_P(msg);
+	bool multi_screen = msg_next != NULL;
+	bool yes = default_yes ? true : false;
+
+	// Wait for user confirmation or a timeout.
+	unsigned long previous_millis_cmd = millis();
+	int8_t        enc_dif = encoderDiff;
+	//KEEPALIVE_STATE(PAUSED_FOR_USER);
+	for (;;) {
+		for (uint8_t i = 0; i < 100; ++i) {
+			delay_keep_alive(50);
+			if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
+				return -1;
+			manage_heater();
+			manage_inactivity(true);
 
-    lcd.setCursor(1, 2);
-    lcd_printPGM(MSG_YES);
-    lcd.setCursor(0, 3);
-    lcd_printPGM(PSTR(">"));
-    lcd_printPGM(MSG_NO);
-    bool yes = false;
+			if (abs(enc_dif - encoderDiff) > 4) {
+				if (msg_next == NULL) {
+					lcd.setCursor(0, 3);
+					if (enc_dif < encoderDiff && yes) {
+						lcd_printPGM((PSTR(" ")));
+						lcd.setCursor(7, 3);
+						lcd_printPGM((PSTR(">")));
+						yes = false;
+					}
+					else if (enc_dif > encoderDiff && !yes) {
+						lcd_printPGM((PSTR(">")));
+						lcd.setCursor(7, 3);
+						lcd_printPGM((PSTR(" ")));
+						yes = true;
+					}
+					enc_dif = encoderDiff;
+				}
+				else {
+					break; //turning knob skips waiting loop
+				}
+			}
+			if (lcd_clicked()) {
+				while (lcd_clicked());
+				delay(10);
+				while (lcd_clicked());
+				if (msg_next == NULL) {
+					//KEEPALIVE_STATE(IN_HANDLER);
+					lcd_set_custom_characters();
+					return yes;
+				}
+				else break;
+			}
+		}
+		if (multi_screen) {
+			if (msg_next == NULL) {
+				msg_next = msg;
+			}
+			msg_next = lcd_display_message_fullscreen_P(msg_next);
+		}
+		if (msg_next == NULL) {
+			lcd.setCursor(0, 3);
+			if (yes) lcd_printPGM(PSTR(">"));
+			lcd.setCursor(1, 3);
+			lcd_printPGM(MSG_YES);
+			lcd.setCursor(7, 3);
+			if (!yes) lcd_printPGM(PSTR(">"));
+			lcd.setCursor(8, 3);
+			lcd_printPGM(MSG_NO);
+		}
+	}
+}
 
-    // Wait for user confirmation or a timeout.
-    unsigned long previous_millis_cmd = millis();
-    int8_t        enc_dif = encoderDiff;
-    for (;;) {
-        if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
-            return -1;
-        manage_heater();
-        manage_inactivity(true);
-        if (abs((enc_dif - encoderDiff)) > 4) {
-            if (abs(enc_dif - encoderDiff) > 1) {
-                lcd.setCursor(0, 2);
-                if (enc_dif > encoderDiff && yes) {
-                    lcd_printPGM((PSTR(" ")));
-                    lcd.setCursor(0, 3);
-                    lcd_printPGM((PSTR(">")));
-                    yes = false;
-                } else if (enc_dif < encoderDiff && ! yes) {
-                    lcd_printPGM((PSTR(">")));
-                    lcd.setCursor(0, 3);
-                    lcd_printPGM((PSTR(" ")));
-                    yes = true;
-                }
-                enc_dif = encoderDiff;
-            }
-        }
-        if (lcd_clicked()) {
-            while (lcd_clicked()) ;
-            delay(10);
-            while (lcd_clicked()) ;
-            return yes;
-        }
-    }
+int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes)
+{
+
+	lcd_display_message_fullscreen_P(msg);
+	
+	if (default_yes) {
+		lcd.setCursor(0, 2);
+		lcd_printPGM(PSTR(">"));
+		lcd_printPGM(MSG_YES);
+		lcd.setCursor(1, 3);
+		lcd_printPGM(MSG_NO);
+	}
+	else {
+		lcd.setCursor(1, 2);
+		lcd_printPGM(MSG_YES);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(PSTR(">"));
+		lcd_printPGM(MSG_NO);
+	}
+	bool yes = default_yes ? true : false;
+
+	// Wait for user confirmation or a timeout.
+	unsigned long previous_millis_cmd = millis();
+	int8_t        enc_dif = encoderDiff;
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	for (;;) {
+		if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
+			return -1;
+		manage_heater();
+		manage_inactivity(true);
+		if (abs(enc_dif - encoderDiff) > 4) {
+			lcd.setCursor(0, 2);
+				if (enc_dif < encoderDiff && yes) {
+					lcd_printPGM((PSTR(" ")));
+					lcd.setCursor(0, 3);
+					lcd_printPGM((PSTR(">")));
+					yes = false;
+				}
+				else if (enc_dif > encoderDiff && !yes) {
+					lcd_printPGM((PSTR(">")));
+					lcd.setCursor(0, 3);
+					lcd_printPGM((PSTR(" ")));
+					yes = true;
+				}
+				enc_dif = encoderDiff;
+		}
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			KEEPALIVE_STATE(IN_HANDLER);
+			return yes;
+		}
+	}
 }
 
 void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask)
@@ -1530,19 +2834,19 @@ void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, ui
 }
 
 static void lcd_show_end_stops() {
-    lcd.setCursor(0, 0);
-    lcd_printPGM((PSTR("End stops diag")));
-    lcd.setCursor(0, 1);
-    lcd_printPGM((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? (PSTR("X1")) : (PSTR("X0")));
-    lcd.setCursor(0, 2);
-    lcd_printPGM((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? (PSTR("Y1")) : (PSTR("Y0")));
-    lcd.setCursor(0, 3);
-    lcd_printPGM((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? (PSTR("Z1")) : (PSTR("Z0")));
+	lcd.setCursor(0, 0);
+	lcd_printPGM((PSTR("End stops diag")));
+	lcd.setCursor(0, 1);
+	lcd_printPGM((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? (PSTR("X1")) : (PSTR("X0")));
+	lcd.setCursor(0, 2);
+	lcd_printPGM((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? (PSTR("Y1")) : (PSTR("Y0")));
+	lcd.setCursor(0, 3);
+	lcd_printPGM((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? (PSTR("Z1")) : (PSTR("Z0")));
 }
 
 static void menu_show_end_stops() {
     lcd_show_end_stops();
-    if (LCD_CLICKED) lcd_goto_menu(lcd_settings_menu);
+    if (LCD_CLICKED) lcd_goto_menu(lcd_calibration_menu);
 }
 
 // Lets the user move the Z carriage up to the end stoppers.
@@ -1570,7 +2874,9 @@ void lcd_diag_show_end_stops()
 
 
 void prusa_statistics(int _message) {
-
+#ifdef DEBUG_DISABLE_PRUSA_STATISTICS
+	return;
+#endif //DEBUG_DISABLE_PRUSA_STATISTICS
 	switch (_message)
 	{
 
@@ -1579,14 +2885,18 @@ void prusa_statistics(int _message) {
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(4);
+			prusa_stat_farm_number();
 			prusa_stat_printinfo();
 			SERIAL_ECHOLN("}");
+			status_number = 4;
 		}
 		else
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(1);
+			prusa_stat_farm_number();
 			SERIAL_ECHOLN("}");
+			status_number = 1;
 		}
 		break;
 
@@ -1594,7 +2904,9 @@ void prusa_statistics(int _message) {
 		farm_status = 2;
 		SERIAL_ECHO("{");
 		prusa_stat_printerstatus(2);
+		prusa_stat_farm_number();
 		SERIAL_ECHOLN("}");
+		status_number = 2;
 		farm_timer = 1;
 		break;
 
@@ -1602,7 +2914,9 @@ void prusa_statistics(int _message) {
 		farm_status = 3;
 		SERIAL_ECHO("{");
 		prusa_stat_printerstatus(3);
+		prusa_stat_farm_number();
 		SERIAL_ECHOLN("}");
+		status_number = 3;
 		farm_timer = 1;
 
 		if (IS_SD_PRINTING)
@@ -1610,13 +2924,17 @@ void prusa_statistics(int _message) {
 			farm_status = 4;
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(4);
+			prusa_stat_farm_number();
 			SERIAL_ECHOLN("}");
+			status_number = 4;
 		}
 		else
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(3);
-			SERIAL_ECHOLN("}");;
+			prusa_stat_farm_number();
+			SERIAL_ECHOLN("}");
+			status_number = 3;
 		}
 		farm_timer = 1;
 		break;
@@ -1625,41 +2943,91 @@ void prusa_statistics(int _message) {
 
 		break;
 	case 4:		// print succesfull
-		SERIAL_ECHOLN("{[RES:1]}");
+		SERIAL_ECHOLN("{[RES:1]");
+		prusa_stat_printerstatus(status_number);
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		farm_timer = 2;
 		break;
 	case 5:		// print not succesfull
-		SERIAL_ECHOLN("{[RES:0]}");
+		SERIAL_ECHOLN("{[RES:0]");
+		prusa_stat_printerstatus(status_number);
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		farm_timer = 2;
 		break;
 	case 6:		// print done
-		SERIAL_ECHOLN("{[PRN:8]}");
+		SERIAL_ECHOLN("{[PRN:8]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		status_number = 8;
 		farm_timer = 2;
 		break;
 	case 7:		// print done - stopped
-		SERIAL_ECHOLN("{[PRN:9]}");
+		SERIAL_ECHOLN("{[PRN:9]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		status_number = 9;
 		farm_timer = 2;
 		break;
 	case 8:		// printer started
 		SERIAL_ECHO("{[PRN:0][PFN:");
+		status_number = 0;
 		SERIAL_ECHO(farm_no);
 		SERIAL_ECHOLN("]}");
 		farm_timer = 2;
 		break;
 	case 20:		// echo farm no
-		SERIAL_ECHO("{[PFN:");
-		SERIAL_ECHO(farm_no);
-		SERIAL_ECHOLN("]}");
+		SERIAL_ECHOLN("{");
+		prusa_stat_printerstatus(status_number);
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		farm_timer = 5;
 		break;
 	case 21: // temperatures
 		SERIAL_ECHO("{");
 		prusa_stat_temperatures();
+		prusa_stat_farm_number();
+		prusa_stat_printerstatus(status_number);
 		SERIAL_ECHOLN("}");
 		break;
-	case 99:		// heartbeat
-		SERIAL_ECHOLN("{[PRN:99]}");
+    case 22: // waiting for filament change
+        SERIAL_ECHOLN("{[PRN:5]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		status_number = 5;
+        break;
+	
+	case 90: // Error - Thermal Runaway
+		SERIAL_ECHOLN("{[ERR:1]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+	case 91: // Error - Thermal Runaway Preheat
+		SERIAL_ECHOLN("{[ERR:2]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+	case 92: // Error - Min temp
+		SERIAL_ECHOLN("{[ERR:3]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		break;
+	case 93: // Error - Max temp
+		SERIAL_ECHOLN("{[ERR:4]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+
+    case 99:		// heartbeat
+        SERIAL_ECHO("{[PRN:99]");
+        prusa_stat_temperatures();
+		SERIAL_ECHO("[PFN:");
+		SERIAL_ECHO(farm_no);
+		SERIAL_ECHO("]");
+        SERIAL_ECHOLN("}");
+            
+        break;
 	}
 
 }
@@ -1671,6 +3039,12 @@ static void prusa_stat_printerstatus(int _status)
 	SERIAL_ECHO("]");
 }
 
+static void prusa_stat_farm_number() {
+	SERIAL_ECHO("[PFN:");
+	SERIAL_ECHO(farm_no);
+	SERIAL_ECHO("]");
+}
+
 static void prusa_stat_temperatures()
 {
 	SERIAL_ECHO("[ST0:");
@@ -1708,7 +3082,7 @@ static void prusa_stat_printinfo()
 	SERIAL_ECHO("]");
 }
 
-
+/*
 void lcd_pick_babystep(){
     int enc_dif = 0;
     int cursor_pos = 1;
@@ -1796,41 +3170,30 @@ void lcd_pick_babystep(){
             
         }
         
-        
         if (lcd_clicked()) {
             fsm = cursor_pos;
-            
-            EEPROM_read_B(EEPROM_BABYSTEP_Z0+((fsm-1)*2),&babystepMem[2]);
-            EEPROM_save_B(EEPROM_BABYSTEP_Z,&babystepMem[2]);
-            eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0x01);
+            int babyStepZ;
+            EEPROM_read_B(EEPROM_BABYSTEP_Z0+((fsm-1)*2),&babyStepZ);
+            EEPROM_save_B(EEPROM_BABYSTEP_Z,&babyStepZ);
+            calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
             delay(500);
             
         }
-        
-        
-        
     };
     
-    
     lcd_implementation_clear();
     lcd_return_to_status();
 }
-
+*/
 void lcd_move_menu_axis()
 {
-  START_MENU();
-  MENU_ITEM(back, MSG_SETTINGS, lcd_settings_menu);
-  MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
-  MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
-  if (move_menu_scale < 10.0)
-  {
-	  if (!isPrintPaused)
-	  {
-		  MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
-	  }
-	  MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
-  }
-  END_MENU();
+	START_MENU();
+	MENU_ITEM(back, MSG_SETTINGS, lcd_settings_menu);
+	MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
+	MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
+	MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
+	MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
+	END_MENU();
 }
 
 static void lcd_move_menu_1mm()
@@ -1860,43 +3223,82 @@ void EEPROM_read(int pos, uint8_t* value, uint8_t size)
   } while (--size);
 }
 
-
-
 static void lcd_silent_mode_set() {
   SilentModeMenu = !SilentModeMenu;
-  EEPROM_save(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
+  eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu);
+#ifdef TMC2130
+  st_synchronize();
+  if (tmc2130_wait_standstill_xy(1000))
+	  MYSERIAL.print("standstill OK");
+  else
+	  MYSERIAL.print("standstill NG!");
+  cli();
+	tmc2130_mode = SilentModeMenu?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL;
+	tmc2130_init();
+  sei();
+#endif //TMC2130
   digipot_init();
-  lcd_goto_menu(lcd_settings_menu, 7);
+  if (IS_SD_PRINTING || is_usb_printing) lcd_goto_menu(lcd_tune_menu, 8);
+  else lcd_goto_menu(lcd_settings_menu, 7);
+}
+
+static void lcd_crash_mode_set()
+{
+	CrashDetectMenu = !CrashDetectMenu; //set also from crashdet_enable() and crashdet_disable()
+    if (CrashDetectMenu==0) {
+        crashdet_disable();
+    }else{
+        crashdet_enable();
+    }
+	if (IS_SD_PRINTING || is_usb_printing) lcd_goto_menu(lcd_tune_menu, 9);
+	else lcd_goto_menu(lcd_settings_menu, 9);
+    
 }
+
 static void lcd_set_lang(unsigned char lang) {
   lang_selected = lang;
   firstrun = 1;
-  eeprom_write_byte((unsigned char *)EEPROM_LANG, lang);/*langsel=0;*/if (langsel == 1)langsel = 2;
+  eeprom_update_byte((unsigned char *)EEPROM_LANG, lang);
+  /*langsel=0;*/
+  if (langsel == LANGSEL_MODAL)
+    // From modal mode to an active mode? This forces the menu to return to the setup menu.
+    langsel = LANGSEL_ACTIVE;
+}
+
+static void lcd_fsensor_state_set()
+{
+	FSensorStateMenu = !FSensorStateMenu; //set also from fsensor_enable() and fsensor_disable()
+    if (FSensorStateMenu==0) {
+        fsensor_disable();
+    }else{
+        fsensor_enable();
+    }
+	if (IS_SD_PRINTING || is_usb_printing) lcd_goto_menu(lcd_tune_menu, 7);
+	else lcd_goto_menu(lcd_settings_menu, 7);
+    
 }
 
 void lcd_force_language_selection() {
-  eeprom_write_byte((unsigned char *)EEPROM_LANG, 255);
+  eeprom_update_byte((unsigned char *)EEPROM_LANG, LANG_ID_FORCE_SELECTION);
 }
 
 static void lcd_language_menu()
 {
   START_MENU();
-  if (!langsel) {
+  if (langsel == LANGSEL_OFF) {
     MENU_ITEM(back, MSG_SETTINGS, lcd_settings_menu);
-  }
-  if (langsel == 2) {
+  } else if (langsel == LANGSEL_ACTIVE) {
     MENU_ITEM(back, MSG_WATCH, lcd_status_screen);
   }
   for (int i=0;i<LANG_NUM;i++){
     MENU_ITEM(setlang, MSG_LANGUAGE_NAME_EXPLICIT(i), i);
   }
-  //MENU_ITEM(setlang, MSG_LANGUAGE_NAME_EXPLICIT(1), 1);
   END_MENU();
 }
 
 void lcd_mesh_bedleveling()
 {
-
+	mesh_bed_run_from_menu = true;
 	enquecommand_P(PSTR("G80"));
 	lcd_return_to_status();
 }
@@ -1907,6 +3309,342 @@ void lcd_mesh_calibration()
   lcd_return_to_status();
 }
 
+void lcd_mesh_calibration_z()
+{
+  enquecommand_P(PSTR("M45 Z"));
+  lcd_return_to_status();
+}
+
+void lcd_pinda_calibration_menu()
+{
+	START_MENU();
+		MENU_ITEM(back, MSG_MENU_CALIBRATION, lcd_calibration_menu);
+		MENU_ITEM(submenu, MSG_CALIBRATE_PINDA, lcd_calibrate_pinda);
+	END_MENU();
+}
+
+void lcd_temp_calibration_set() {
+	temp_cal_active = !temp_cal_active;
+	eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, temp_cal_active);
+	digipot_init();
+	lcd_goto_menu(lcd_settings_menu, 10);
+}
+
+void lcd_calibrate_pinda() {
+	enquecommand_P(PSTR("G76"));
+	lcd_return_to_status();
+}
+
+#ifndef SNMM
+
+/*void lcd_calibrate_extruder() {
+	
+	if (degHotend0() > EXTRUDE_MINTEMP)
+	{
+		current_position[E_AXIS] = 0;									//set initial position to zero
+		plan_set_e_position(current_position[E_AXIS]);
+		
+		//long steps_start = st_get_position(E_AXIS);
+
+		long steps_final;
+		float e_steps_per_unit;
+		float feedrate = (180 / axis_steps_per_unit[E_AXIS]) * 1;	//3	//initial automatic extrusion feedrate (depends on current value of axis_steps_per_unit to avoid too fast extrusion)
+		float e_shift_calibration = (axis_steps_per_unit[E_AXIS] > 180 ) ? ((180 / axis_steps_per_unit[E_AXIS]) * 70): 70; //length of initial automatic extrusion sequence
+		const char   *msg_e_cal_knob = MSG_E_CAL_KNOB;
+		const char   *msg_next_e_cal_knob = lcd_display_message_fullscreen_P(msg_e_cal_knob);
+		const bool    multi_screen = msg_next_e_cal_knob != NULL;
+		unsigned long msg_millis;
+
+		lcd_show_fullscreen_message_and_wait_P(MSG_MARK_FIL);
+		lcd_implementation_clear();
+		
+		
+		lcd.setCursor(0, 1); lcd_printPGM(MSG_PLEASE_WAIT);
+		current_position[E_AXIS] += e_shift_calibration;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder);
+		st_synchronize();
+
+		lcd_display_message_fullscreen_P(msg_e_cal_knob);
+		msg_millis = millis();
+		while (!LCD_CLICKED) {
+			if (multi_screen && millis() - msg_millis > 5000) {
+				if (msg_next_e_cal_knob == NULL)
+					msg_next_e_cal_knob = msg_e_cal_knob;
+					msg_next_e_cal_knob = lcd_display_message_fullscreen_P(msg_next_e_cal_knob);
+					msg_millis = millis();
+			}
+
+			//manage_inactivity(true);
+			manage_heater();
+			if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) {						//adjusting mark by knob rotation
+				delay_keep_alive(50);
+				//previous_millis_cmd = millis();
+				encoderPosition += (encoderDiff / ENCODER_PULSES_PER_STEP);
+				encoderDiff = 0;
+				if (!planner_queue_full()) {
+					current_position[E_AXIS] += float(abs((int)encoderPosition)) * 0.01; //0.05
+					encoderPosition = 0;
+					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder);
+					
+				}
+			}	
+		}
+		
+		steps_final = current_position[E_AXIS] * axis_steps_per_unit[E_AXIS];
+		//steps_final = st_get_position(E_AXIS);
+		lcdDrawUpdate = 1;
+		e_steps_per_unit = ((float)(steps_final)) / 100.0f;
+		if (e_steps_per_unit < MIN_E_STEPS_PER_UNIT) e_steps_per_unit = MIN_E_STEPS_PER_UNIT;				
+		if (e_steps_per_unit > MAX_E_STEPS_PER_UNIT) e_steps_per_unit = MAX_E_STEPS_PER_UNIT;
+
+		lcd_implementation_clear();
+
+		axis_steps_per_unit[E_AXIS] = e_steps_per_unit;
+		enquecommand_P(PSTR("M500")); //store settings to eeprom
+	
+		//lcd_implementation_drawedit(PSTR("Result"), ftostr31(axis_steps_per_unit[E_AXIS]));
+		//delay_keep_alive(2000);
+		delay_keep_alive(500);
+		lcd_show_fullscreen_message_and_wait_P(MSG_CLEAN_NOZZLE_E);
+		lcd_update_enable(true);
+		lcdDrawUpdate = 2;
+
+	}
+	else
+	{
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+		delay(2000);
+		lcd_implementation_clear();
+	}
+	lcd_return_to_status();
+}
+
+void lcd_extr_cal_reset() {
+	float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT;
+	axis_steps_per_unit[E_AXIS] = tmp1[3];
+	//extrudemultiply = 100;
+	enquecommand_P(PSTR("M500"));
+}*/
+
+#endif
+
+void lcd_toshiba_flash_air_compatibility_toggle()
+{
+   card.ToshibaFlashAir_enable(! card.ToshibaFlashAir_isEnabled());
+   eeprom_update_byte((uint8_t*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY, card.ToshibaFlashAir_isEnabled());
+}
+
+void lcd_v2_calibration() {
+	bool loaded = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_PLA_FILAMENT_LOADED, false, true);
+	if (loaded) {
+		lcd_commands_type = LCD_COMMAND_V2_CAL;
+	}
+	else {
+		lcd_display_message_fullscreen_P(MSG_PLEASE_LOAD_PLA);
+		for (int i = 0; i < 20; i++) { //wait max. 2s
+			delay_keep_alive(100);
+			if (lcd_clicked()) {
+				while (lcd_clicked());
+				delay(10);
+				while (lcd_clicked());
+				break;
+			}
+		}
+	}
+	lcd_return_to_status();
+	lcd_update_enable(true);
+}
+
+void lcd_wizard() {
+	bool result = true;
+	if (calibration_status() != CALIBRATION_STATUS_ASSEMBLED) {
+		result = lcd_show_multiscreen_message_yes_no_and_wait_P(MSG_WIZARD_RERUN, false, false);
+	}
+	if (result) {
+		calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
+		lcd_wizard(0);
+	}
+	else {
+		lcd_return_to_status();
+		lcd_update_enable(true);
+		lcd_update(2);
+	}
+}
+
+void lcd_wizard(int state) {
+
+	bool end = false;
+	int wizard_event;
+	const char *msg = NULL;
+	while (!end) {
+		switch (state) {
+		case 0: // run wizard?
+			wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(MSG_WIZARD_WELCOME, false, true);
+			if (wizard_event) {
+				state = 1;
+				eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1);
+			}
+			else {
+				eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0);
+				end = true;
+			}
+			break;
+		case 1: // restore calibration status
+			switch (calibration_status()) {
+			case CALIBRATION_STATUS_ASSEMBLED: state = 2; break; //run selftest
+			case CALIBRATION_STATUS_XYZ_CALIBRATION: state = 3; break; //run xyz cal.
+			case CALIBRATION_STATUS_Z_CALIBRATION: state = 4; break; //run z cal.
+			case CALIBRATION_STATUS_LIVE_ADJUST: state = 5; break; //run live adjust
+			case CALIBRATION_STATUS_CALIBRATED: end = true; eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); break;
+			default: state = 2; break; //if calibration status is unknown, run wizard from the beginning
+			}
+			break;
+		case 2: //selftest
+			lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_SELFTEST);
+			wizard_event = lcd_selftest();
+			if (wizard_event) {
+				calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION);
+				state = 3;
+			}
+			else end = true;
+			break;
+		case 3: //xyz cal.
+			lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_XYZ_CAL);
+			wizard_event = gcode_M45(false);
+			if (wizard_event) state = 5;
+			else end = true;
+			break;
+		case 4: //z cal.
+			lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_Z_CAL);
+			wizard_event = gcode_M45(true);
+			if (wizard_event) state = 11; //shipped, no need to set first layer, go to final message directly
+			else end = true;
+			break;
+		case 5: //is filament loaded?
+				//start to preheat nozzle and bed to save some time later
+			setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0);
+			setTargetBed(PLA_PREHEAT_HPB_TEMP);
+			wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_WIZARD_FILAMENT_LOADED, false);
+			if (wizard_event) state = 8;
+			else state = 6;
+
+			break;
+		case 6: //waiting for preheat nozzle for PLA;
+#ifndef SNMM
+			lcd_display_message_fullscreen_P(MSG_WIZARD_WILL_PREHEAT);
+			current_position[Z_AXIS] = 100; //move in z axis to make space for loading filament
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 60, active_extruder);
+			delay_keep_alive(2000);
+			lcd_display_message_fullscreen_P(MSG_WIZARD_HEATING);
+			while (abs(degHotend(0) - PLA_PREHEAT_HOTEND_TEMP) > 3) {
+				lcd_display_message_fullscreen_P(MSG_WIZARD_HEATING);
+
+				lcd.setCursor(0, 4);
+				lcd.print(LCD_STR_THERMOMETER[0]);
+				lcd.print(ftostr3(degHotend(0)));
+				lcd.print("/");
+				lcd.print(PLA_PREHEAT_HOTEND_TEMP);
+				lcd.print(LCD_STR_DEGREE);
+				lcd_set_custom_characters();
+				delay_keep_alive(1000);
+			}
+#endif //not SNMM
+			state = 7;
+			break;
+		case 7: //load filament 
+			lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_LOAD_FILAMENT);
+			lcd_update_enable(false);
+			lcd_implementation_clear();
+			lcd_print_at_PGM(0, 2, MSG_LOADING_FILAMENT);
+			loading_flag = true;
+#ifdef SNMM
+			change_extr(0);
+#endif
+			gcode_M701();
+			state = 9;
+			break;
+		case 8:
+			wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_WIZARD_PLA_FILAMENT, false, true);
+			if (wizard_event) state = 9;
+			else end = true;
+			break;
+		case 9:
+			lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_V2_CAL);
+			lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_V2_CAL_2);
+			lcd_commands_type = LCD_COMMAND_V2_CAL;
+			end = true;
+			break;
+		case 10: //repeat first layer cal.?
+			wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(MSG_WIZARD_REPEAT_V2_CAL, false);
+			if (wizard_event) {
+				//reset status and live adjust z value in eeprom
+				calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
+				EEPROM_save_B(EEPROM_BABYSTEP_Z, 0);
+				lcd_show_fullscreen_message_and_wait_P(MSG_WIZARD_CLEAN_HEATBED);
+				state = 9;
+			}
+			else {
+				state = 11;
+			}
+			break;
+		case 11: //we are finished
+			eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0);
+			end = true;
+			break;
+
+		default: break;
+		}
+	}
+
+	SERIAL_ECHOPGM("State: ");
+	MYSERIAL.println(state);
+	switch (state) { //final message
+	case 0: //user dont want to use wizard
+		msg = MSG_WIZARD_QUIT;
+		break;
+
+	case 1: //printer was already calibrated
+		msg = MSG_WIZARD_DONE;
+		break;
+	case 2: //selftest
+		msg = MSG_WIZARD_CALIBRATION_FAILED;
+		break;
+	case 3: //xyz cal.
+		msg = MSG_WIZARD_CALIBRATION_FAILED;
+		break;
+	case 4: //z cal.
+		msg = MSG_WIZARD_CALIBRATION_FAILED;
+		break;
+	case 8:
+		msg = MSG_WIZARD_INSERT_CORRECT_FILAMENT;
+		break;
+	case 9: break; //exit wizard for v2 calibration, which is implemted in lcd_commands (we need lcd_update running)
+	case 11: //we are finished
+
+		msg = MSG_WIZARD_DONE;
+		lcd_reset_alert_level();
+		lcd_setstatuspgm(WELCOME_MSG);
+		break;
+
+	default:
+		msg = MSG_WIZARD_QUIT;
+		break;
+
+	}
+	if (state != 9) lcd_show_fullscreen_message_and_wait_P(msg);
+	lcd_update_enable(true);
+	lcd_return_to_status();
+	lcd_update(2);
+}
+
+static void lcd_crash_menu()
+{
+}
+
 static void lcd_settings_menu()
 {
   EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
@@ -1915,51 +3653,114 @@ static void lcd_settings_menu()
   MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
 
   MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
-  MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu_1mm);
-  
-  if (!isPrintPaused)
+  if (!homing_flag)
   {
-#ifndef MESH_BED_LEVELING
-	  MENU_ITEM(gcode, MSG_HOMEYZ, PSTR("G28 Z"));
-#else
-	  MENU_ITEM(submenu, MSG_HOMEYZ, lcd_mesh_bedleveling);
-#endif
+	  MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu_1mm);
   }
-
   if (!isPrintPaused)
   {
 	  MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));
-	  MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
   }
 
-  if (SilentModeMenu == 0) {
-    MENU_ITEM(function, MSG_SILENT_MODE_OFF, lcd_silent_mode_set);
+  if (FSensorStateMenu == 0) {
+    MENU_ITEM(function, MSG_FSENSOR_OFF, lcd_fsensor_state_set);
   } else {
-    MENU_ITEM(function, MSG_SILENT_MODE_ON, lcd_silent_mode_set);
+    MENU_ITEM(function, MSG_FSENSOR_ON, lcd_fsensor_state_set);
+  }
+  if (fans_check_enabled == true) {
+	  MENU_ITEM(function, MSG_FANS_CHECK_ON, lcd_set_fan_check);
+  }
+  else {
+	  MENU_ITEM(function, MSG_FANS_CHECK_OFF, lcd_set_fan_check);
   }
 
-    EEPROM_read_B(EEPROM_BABYSTEP_X, &babystepMem[0]);
-    EEPROM_read_B(EEPROM_BABYSTEP_Y, &babystepMem[1]);
-    EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystepMem[2]);
-    babystepMemMM[2] = babystepMem[2]/axis_steps_per_unit[Z_AXIS];
-  
-	if (!isPrintPaused)
+
+  if (SilentModeMenu == 0) {
+    if (CrashDetectMenu == 0) {
+      MENU_ITEM(function, MSG_CRASHDETECT_OFF, lcd_crash_mode_set);
+    } else {
+      MENU_ITEM(function, MSG_CRASHDETECT_ON, lcd_crash_mode_set);
+    }
+  }
+  if (temp_cal_active == false) {
+	  MENU_ITEM(function, MSG_TEMP_CALIBRATION_OFF, lcd_temp_calibration_set);
+  }
+  else {
+	  MENU_ITEM(function, MSG_TEMP_CALIBRATION_ON, lcd_temp_calibration_set);
+  }
+  if (SilentModeMenu == 0) {
+	  MENU_ITEM(function, MSG_SILENT_MODE_OFF, lcd_silent_mode_set);
+  }
+  else {
+	  MENU_ITEM(function, MSG_SILENT_MODE_ON, lcd_silent_mode_set);
+  }
+	if (!isPrintPaused && !homing_flag)
 	{
-		MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);//8
+		MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);
 	}
 	MENU_ITEM(submenu, MSG_LANGUAGE_SELECT, lcd_language_menu);
-	if (!isPrintPaused)
-	{
-		MENU_ITEM(submenu, MSG_SELFTEST, lcd_selftest);
+
+  if (card.ToshibaFlashAir_isEnabled()) {
+    MENU_ITEM(function, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON, lcd_toshiba_flash_air_compatibility_toggle);
+  } else {
+    MENU_ITEM(function, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF, lcd_toshiba_flash_air_compatibility_toggle);
+  }
+    
+    if (farm_mode)
+    {
+        MENU_ITEM(submenu, PSTR("Farm number"), lcd_farm_no);
+		MENU_ITEM(function, PSTR("Disable farm mode"), lcd_disable_farm_mode);
+    }
+
+	END_MENU();
+}
+
+static void lcd_selftest_()
+{
+	lcd_selftest();
+}
+
+static void lcd_calibration_menu()
+{
+  START_MENU();
+  MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+  if (!isPrintPaused)
+  {
+	MENU_ITEM(function, MSG_WIZARD, lcd_wizard);
+	MENU_ITEM(submenu, MSG_V2_CALIBRATION, lcd_v2_calibration);
+	MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28 W"));
+	MENU_ITEM(function, MSG_SELFTEST, lcd_selftest_v);
+#ifdef MK1BP
+    // MK1
+    // "Calibrate Z"
+    MENU_ITEM(gcode, MSG_HOMEYZ, PSTR("G28 Z"));
+#else //MK1BP
+    // MK2
+    MENU_ITEM(function, MSG_CALIBRATE_BED, lcd_mesh_calibration);
+    // "Calibrate Z" with storing the reference values to EEPROM.
+    MENU_ITEM(submenu, MSG_HOMEYZ, lcd_mesh_calibration_z);
+#ifndef SNMM
+	//MENU_ITEM(function, MSG_CALIBRATE_E, lcd_calibrate_extruder);
+#endif
+    // "Mesh Bed Leveling"
+    MENU_ITEM(submenu, MSG_MESH_BED_LEVELING, lcd_mesh_bedleveling);
+	
+#endif //MK1BP
+    MENU_ITEM(submenu, MSG_BED_CORRECTION_MENU, lcd_adjust_bed);
+	MENU_ITEM(submenu, MSG_PID_EXTRUDER, pid_extruder);
     MENU_ITEM(submenu, MSG_SHOW_END_STOPS, menu_show_end_stops);
-    MENU_ITEM(submenu, MSG_CALIBRATE_BED, lcd_mesh_calibration);
+#ifndef MK1BP
     MENU_ITEM(gcode, MSG_CALIBRATE_BED_RESET, PSTR("M44"));
-	}
-	if (farm_mode)
-	{
-		MENU_ITEM(submenu, PSTR("Farm number"), lcd_farm_no);
-	}
-	END_MENU();
+#endif //MK1BP
+#ifndef SNMM
+	//MENU_ITEM(function, MSG_RESET_CALIBRATE_E, lcd_extr_cal_reset);
+#endif
+#ifndef MK1BP
+	MENU_ITEM(submenu, MSG_CALIBRATION_PINDA_MENU, lcd_pinda_calibration_menu);
+#endif //MK1BP
+  }
+  
+  END_MENU();
 }
 /*
 void lcd_mylang_top(int hlaska) {
@@ -2054,9 +3855,6 @@ void lcd_mylang_drawmenu(int cursor) {
   }  
 }
  
-void lcd_set_custom_characters_arrows();
-void lcd_set_custom_characters_degree();
-
 void lcd_mylang_drawcursor(int cursor) {
   
   if (cursor==1) lcd.setCursor(0, 1);
@@ -2084,7 +3882,7 @@ void lcd_mylang() {
 
   enc_dif = encoderDiff;
 
-  while ( (lang_selected == 255) && (MYSERIAL.available() < 2) ) {
+  while ( (lang_selected == 255)  ) {
 
     manage_heater();
     manage_inactivity(true);
@@ -2144,10 +3942,708 @@ void lcd_mylang() {
 
 }
 
+void bowden_menu() {
+	int enc_dif = encoderDiff;
+	int cursor_pos = 0;
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0);
+	lcd.print(">");
+	for (int i = 0; i < 4; i++) {
+		lcd.setCursor(1, i);
+		lcd.print("Extruder ");
+		lcd.print(i);
+		lcd.print(": ");
+		EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]);
+		lcd.print(bowden_length[i] - 48);
+
+	}
+	enc_dif = encoderDiff;
+
+	while (1) {
+
+		manage_heater();
+		manage_inactivity(true);
 
+		if (abs((enc_dif - encoderDiff)) > 2) {
+
+			if (enc_dif > encoderDiff) {
+					cursor_pos--;
+				}
+
+				if (enc_dif < encoderDiff) {
+					cursor_pos++;
+				}
+
+				if (cursor_pos > 3) {
+					cursor_pos = 3;
+				}
+
+				if (cursor_pos < 0) {
+					cursor_pos = 0;
+				}
+
+				lcd.setCursor(0, 0);
+				lcd.print(" ");
+				lcd.setCursor(0, 1);
+				lcd.print(" ");
+				lcd.setCursor(0, 2);
+				lcd.print(" ");
+				lcd.setCursor(0, 3);
+				lcd.print(" ");
+				lcd.setCursor(0, cursor_pos);
+				lcd.print(">");
+
+				enc_dif = encoderDiff;
+				delay(100);
+		}
+
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+
+			lcd_implementation_clear();
+			while (1) {
+
+				manage_heater();
+				manage_inactivity(true);
+
+				lcd.setCursor(1, 1);
+				lcd.print("Extruder ");
+				lcd.print(cursor_pos);
+				lcd.print(": ");
+				lcd.setCursor(13, 1);
+				lcd.print(bowden_length[cursor_pos] - 48);
+
+				if (abs((enc_dif - encoderDiff)) > 2) {
+						if (enc_dif > encoderDiff) {
+							bowden_length[cursor_pos]--;
+							lcd.setCursor(13, 1);
+							lcd.print(bowden_length[cursor_pos] - 48);
+							enc_dif = encoderDiff;
+						}
+
+						if (enc_dif < encoderDiff) {
+							bowden_length[cursor_pos]++;
+							lcd.setCursor(13, 1);
+							lcd.print(bowden_length[cursor_pos] - 48);
+							enc_dif = encoderDiff;
+						}
+				}
+				delay(100);
+				if (lcd_clicked()) {
+					while (lcd_clicked());
+					delay(10);
+					while (lcd_clicked());
+					EEPROM_save_B(EEPROM_BOWDEN_LENGTH + cursor_pos * 2, &bowden_length[cursor_pos]);
+					if (lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Continue with another bowden?"))) {
+						lcd_update_enable(true);
+						lcd_implementation_clear();
+						enc_dif = encoderDiff;
+						lcd.setCursor(0, cursor_pos);
+						lcd.print(">");
+						for (int i = 0; i < 4; i++) {
+							lcd.setCursor(1, i);
+							lcd.print("Extruder ");
+							lcd.print(i);
+							lcd.print(": ");
+							EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]);
+							lcd.print(bowden_length[i] - 48);
+
+						}
+						break;
+					}
+					else return;
+				}
+			}
+		}
+	}
+}
+
+static char snmm_stop_print_menu() { //menu for choosing which filaments will be unloaded in stop print
+	lcd_implementation_clear();
+	lcd_print_at_PGM(0,0,MSG_UNLOAD_FILAMENT); lcd.print(":");
+	lcd.setCursor(0, 1); lcd.print(">");
+	lcd_print_at_PGM(1,1,MSG_ALL);
+	lcd_print_at_PGM(1,2,MSG_USED);
+	lcd_print_at_PGM(1,3,MSG_CURRENT);
+	char cursor_pos = 1;
+	int enc_dif = 0;
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	while (1) {
+		manage_heater();
+		manage_inactivity(true);
+		if (abs((enc_dif - encoderDiff)) > 4) {
+
+			if ((abs(enc_dif - encoderDiff)) > 1) {
+				if (enc_dif > encoderDiff) cursor_pos--;
+				if (enc_dif < encoderDiff) cursor_pos++;
+				if (cursor_pos > 3) cursor_pos = 3;
+				if (cursor_pos < 1) cursor_pos = 1;
+
+				lcd.setCursor(0, 1);
+				lcd.print(" ");
+				lcd.setCursor(0, 2);
+				lcd.print(" ");
+				lcd.setCursor(0, 3);
+				lcd.print(" ");
+				lcd.setCursor(0, cursor_pos);
+				lcd.print(">");
+				enc_dif = encoderDiff;
+				delay(100);
+			}
+		}
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			KEEPALIVE_STATE(IN_HANDLER);
+			return(cursor_pos - 1);
+		}
+	}
+	
+}
+
+char choose_extruder_menu() {
+
+	int items_no = 4;
+	int first = 0;
+	int enc_dif = 0;
+	char cursor_pos = 1;
+	
+	enc_dif = encoderDiff;
+	lcd_implementation_clear();
+	
+	lcd_printPGM(MSG_CHOOSE_EXTRUDER);
+	lcd.setCursor(0, 1);
+	lcd.print(">");
+	for (int i = 0; i < 3; i++) {
+		lcd_print_at_PGM(1, i + 1, MSG_EXTRUDER);
+	}
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	while (1) {
+
+		for (int i = 0; i < 3; i++) {
+			lcd.setCursor(2 + strlen_P(MSG_EXTRUDER), i+1);
+			lcd.print(first + i + 1);
+		}
+
+		manage_heater();
+		manage_inactivity(true);
+
+		if (abs((enc_dif - encoderDiff)) > 4) {
+
+			if ((abs(enc_dif - encoderDiff)) > 1) {
+				if (enc_dif > encoderDiff) {
+					cursor_pos--;
+				}
+
+				if (enc_dif < encoderDiff) {
+					cursor_pos++;
+				}
+
+				if (cursor_pos > 3) {
+					cursor_pos = 3;
+					if (first < items_no - 3) {
+						first++;
+						lcd_implementation_clear();
+						lcd_printPGM(MSG_CHOOSE_EXTRUDER);
+						for (int i = 0; i < 3; i++) {
+							lcd_print_at_PGM(1, i + 1, MSG_EXTRUDER);
+						}
+					}
+				}
+
+				if (cursor_pos < 1) {
+					cursor_pos = 1;
+					if (first > 0) {
+						first--;
+						lcd_implementation_clear();
+						lcd_printPGM(MSG_CHOOSE_EXTRUDER);
+						for (int i = 0; i < 3; i++) {
+							lcd_print_at_PGM(1, i + 1, MSG_EXTRUDER);
+						}
+					}
+				}
+				lcd.setCursor(0, 1);
+				lcd.print(" ");
+				lcd.setCursor(0, 2);
+				lcd.print(" ");
+				lcd.setCursor(0, 3);
+				lcd.print(" ");
+				lcd.setCursor(0, cursor_pos);
+				lcd.print(">");
+				enc_dif = encoderDiff;
+				delay(100);
+			}
+
+		}
+
+		if (lcd_clicked()) {
+			lcd_update(2);
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			KEEPALIVE_STATE(IN_HANDLER);
+			return(cursor_pos + first - 1);
+			
+		}
+
+	}
+
+}
+
+
+char reset_menu() {
+#ifdef SNMM
+	int items_no = 5;
+#else
+	int items_no = 4;
+#endif
+	static int first = 0;
+	int enc_dif = 0;
+	char cursor_pos = 0;
+	const char *item [items_no];
+	
+	item[0] = "Language";
+	item[1] = "Statistics";
+	item[2] = "Shipping prep";
+	item[3] = "All Data";
+#ifdef SNMM
+	item[4] = "Bowden length";
+#endif // SNMM
+
+	enc_dif = encoderDiff;
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0);
+	lcd.print(">");
+
+	while (1) {		
+
+		for (int i = 0; i < 4; i++) {
+			lcd.setCursor(1, i);
+			lcd.print(item[first + i]);
+		}
+
+		manage_heater();
+		manage_inactivity(true);
+
+		if (abs((enc_dif - encoderDiff)) > 4) {
+
+			if ((abs(enc_dif - encoderDiff)) > 1) {
+				if (enc_dif > encoderDiff) {
+					cursor_pos--;
+				}
+
+				if (enc_dif < encoderDiff) {
+					cursor_pos++;
+				}
+
+				if (cursor_pos > 3) {
+					cursor_pos = 3;
+					if (first < items_no - 4) {
+						first++;
+						lcd_implementation_clear();
+					}
+				}
+
+				if (cursor_pos < 0) {
+					cursor_pos = 0;
+					if (first > 0) {
+						first--;
+						lcd_implementation_clear();
+					}
+				}
+				lcd.setCursor(0, 0);
+				lcd.print(" ");
+				lcd.setCursor(0, 1);
+				lcd.print(" ");
+				lcd.setCursor(0, 2);
+				lcd.print(" ");
+				lcd.setCursor(0, 3);
+				lcd.print(" ");
+				lcd.setCursor(0, cursor_pos);
+				lcd.print(">");
+				enc_dif = encoderDiff;
+				delay(100);
+			}
+
+		}
+
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			return(cursor_pos + first);
+		}
+
+	}
+
+}
+
+static void lcd_disable_farm_mode() {
+	int8_t disable = lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Disable farm mode?"), true, false); //allow timeouting, default no
+	if (disable) {
+		enquecommand_P(PSTR("G99"));
+		lcd_return_to_status();
+	}
+	else {
+		lcd_goto_menu(lcd_settings_menu);
+	}
+	lcd_update_enable(true);
+	lcdDrawUpdate = 2;
+	
+}
+
+static void lcd_ping_allert() {
+	if ((abs(millis() - allert_timer)*0.001) > PING_ALLERT_PERIOD) {
+		allert_timer = millis();
+		SET_OUTPUT(BEEPER);
+		for (int i = 0; i < 2; i++) {
+			WRITE(BEEPER, HIGH);
+			delay(50);
+			WRITE(BEEPER, LOW);
+			delay(100);
+		}
+	}
+
+};
+
+
+#ifdef SNMM
+
+static void extr_mov(float shift, float feed_rate) { //move extruder no matter what the current heater temperature is
+	set_extrude_min_temp(.0);
+	current_position[E_AXIS] += shift;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feed_rate, active_extruder);
+	set_extrude_min_temp(EXTRUDE_MINTEMP);
+}
+
+
+void change_extr(int extr) { //switches multiplexer for extruders
+	st_synchronize();
+	delay(100);
+
+	disable_e0();
+	disable_e1();
+	disable_e2();
+
+#ifdef SNMM
+	snmm_extruder = extr;
+#endif
+
+	pinMode(E_MUX0_PIN, OUTPUT);
+	pinMode(E_MUX1_PIN, OUTPUT);
+	pinMode(E_MUX2_PIN, OUTPUT);
+
+	switch (extr) {
+	case 1:
+		WRITE(E_MUX0_PIN, HIGH);
+		WRITE(E_MUX1_PIN, LOW);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	case 2:
+		WRITE(E_MUX0_PIN, LOW);
+		WRITE(E_MUX1_PIN, HIGH);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	case 3:
+		WRITE(E_MUX0_PIN, HIGH);
+		WRITE(E_MUX1_PIN, HIGH);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	default:
+		WRITE(E_MUX0_PIN, LOW);
+		WRITE(E_MUX1_PIN, LOW);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	}
+	delay(100);
+}
+
+static int get_ext_nr() { //reads multiplexer input pins and return current extruder number (counted from 0)
+	return(4 * READ(E_MUX2_PIN) + 2 * READ(E_MUX1_PIN) + READ(E_MUX0_PIN));
+}
+
+
+void display_loading() {
+	switch (snmm_extruder) {
+	case 1: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T1); break;
+	case 2: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T2); break;
+	case 3: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T3); break;
+	default: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T0); break;
+	}
+}
+
+static void extr_adj(int extruder) //loading filament for SNMM
+{
+	bool correct;
+	max_feedrate[E_AXIS] =80;
+	//max_feedrate[E_AXIS] = 50;
+	START:
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0); 
+	switch (extruder) {
+	case 1: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T1); break;
+	case 2: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T2); break;
+	case 3: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T3); break;
+	default: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T0); break;   
+	}
+	KEEPALIVE_STATE(PAUSED_FOR_USER);
+	do{
+		extr_mov(0.001,1000);
+		delay_keep_alive(2);
+	} while (!lcd_clicked());
+	//delay_keep_alive(500);
+	KEEPALIVE_STATE(IN_HANDLER);
+	st_synchronize();
+	//correct = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FIL_LOADED_CHECK, false);
+	//if (!correct) goto	START;
+	//extr_mov(BOWDEN_LENGTH/2.f, 500); //dividing by 2 is there because of max. extrusion length limitation (x_max + y_max)
+	//extr_mov(BOWDEN_LENGTH/2.f, 500);
+	extr_mov(bowden_length[extruder], 500);
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0); lcd_printPGM(MSG_LOADING_FILAMENT);
+	if(strlen(MSG_LOADING_FILAMENT)>18) lcd.setCursor(0, 1);
+	else lcd.print(" ");
+	lcd.print(snmm_extruder + 1);
+	lcd.setCursor(0, 2); lcd_printPGM(MSG_PLEASE_WAIT);
+	st_synchronize();
+	max_feedrate[E_AXIS] = 50;
+	lcd_update_enable(true);
+	lcd_return_to_status();
+	lcdDrawUpdate = 2;
+}
+
+
+void extr_unload() { //unloads filament
+	float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+	float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+	int8_t SilentMode;
+
+	if (degHotend0() > EXTRUDE_MINTEMP) {
+		lcd_implementation_clear();
+		lcd_display_message_fullscreen_P(PSTR(""));
+		max_feedrate[E_AXIS] = 50;
+		lcd.setCursor(0, 0); lcd_printPGM(MSG_UNLOADING_FILAMENT);
+		lcd.print(" ");
+		lcd.print(snmm_extruder + 1);
+		lcd.setCursor(0, 2); lcd_printPGM(MSG_PLEASE_WAIT);
+		if (current_position[Z_AXIS] < 15) {
+			current_position[Z_AXIS] += 15; //lifting in Z direction to make space for extrusion
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 25, active_extruder);
+		}
+		
+		current_position[E_AXIS] += 10; //extrusion
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder);
+		digipot_current(2, E_MOTOR_HIGH_CURRENT);
+		if (current_temperature[0] < 230) { //PLA & all other filaments
+			current_position[E_AXIS] += 5.4;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2800 / 60, active_extruder);
+			current_position[E_AXIS] += 3.2;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			current_position[E_AXIS] += 3;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3400 / 60, active_extruder);
+		}
+		else { //ABS
+			current_position[E_AXIS] += 3.1;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2000 / 60, active_extruder);
+			current_position[E_AXIS] += 3.1;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+			current_position[E_AXIS] += 4;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			/*current_position[X_AXIS] += 23; //delay
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay
+			current_position[X_AXIS] -= 23; //delay
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay*/
+			delay_keep_alive(4700);
+		}
+	
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= (bowden_length[snmm_extruder] + 60 + FIL_LOAD_LENGTH) / 2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		current_position[E_AXIS] -= (bowden_length[snmm_extruder] + 60 + FIL_LOAD_LENGTH) / 2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		st_synchronize();
+		//digipot_init();
+		if (SilentMode == 1) digipot_current(2, tmp_motor[2]); //set back to normal operation currents
+		else digipot_current(2, tmp_motor_loud[2]);
+		lcd_update_enable(true);
+		lcd_return_to_status();
+		max_feedrate[E_AXIS] = 50;
+	}
+	else {
+
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+
+		delay(2000);
+		lcd_implementation_clear();
+	}
+
+	lcd_return_to_status();
+
+
+
+
+}
+
+//wrapper functions for loading filament
+static void extr_adj_0(){
+	change_extr(0);
+	extr_adj(0);
+}
+static void extr_adj_1() {
+	change_extr(1);
+	extr_adj(1);
+}
+static void extr_adj_2() {
+	change_extr(2);
+	extr_adj(2);
+}
+static void extr_adj_3() {
+	change_extr(3);
+	extr_adj(3);
+}
+
+static void load_all() {
+	for (int i = 0; i < 4; i++) {
+		change_extr(i);
+		extr_adj(i);
+	}
+}
+
+//wrapper functions for changing extruders
+static void extr_change_0() {
+	change_extr(0);
+	lcd_return_to_status();
+}
+static void extr_change_1() {
+	change_extr(1);
+	lcd_return_to_status();
+}
+static void extr_change_2() {
+	change_extr(2);
+	lcd_return_to_status();
+}
+static void extr_change_3() {
+	change_extr(3);
+	lcd_return_to_status();
+}
+
+//wrapper functions for unloading filament
+void extr_unload_all() {
+	if (degHotend0() > EXTRUDE_MINTEMP) {
+		for (int i = 0; i < 4; i++) {
+			change_extr(i);
+			extr_unload();
+		}
+	}
+	else {
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+		delay(2000);
+		lcd_implementation_clear();
+		lcd_return_to_status();
+	}
+}
+
+//unloading just used filament (for snmm)
+
+void extr_unload_used() {
+	if (degHotend0() > EXTRUDE_MINTEMP) {
+		for (int i = 0; i < 4; i++) {
+			if (snmm_filaments_used & (1 << i)) {
+				change_extr(i);
+				extr_unload();
+			}
+		}
+		snmm_filaments_used = 0;
+	}
+	else {
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+		delay(2000);
+		lcd_implementation_clear();
+		lcd_return_to_status();
+	}
+}
+
+
+
+static void extr_unload_0() {
+	change_extr(0);
+	extr_unload();
+}
+static void extr_unload_1() {
+	change_extr(1);
+	extr_unload();
+}
+static void extr_unload_2() {
+	change_extr(2);
+	extr_unload();
+}
+static void extr_unload_3() {
+	change_extr(3);
+	extr_unload();
+}
+
+
+static void fil_load_menu()
+{
+	START_MENU();
+	MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+	MENU_ITEM(function, MSG_LOAD_ALL, load_all);
+	MENU_ITEM(function, MSG_LOAD_FILAMENT_1, extr_adj_0);
+	MENU_ITEM(function, MSG_LOAD_FILAMENT_2, extr_adj_1);
+	MENU_ITEM(function, MSG_LOAD_FILAMENT_3, extr_adj_2);
+	MENU_ITEM(function, MSG_LOAD_FILAMENT_4, extr_adj_3);
+	
+	END_MENU();
+}
+
+static void fil_unload_menu()
+{
+	START_MENU();
+	MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+	MENU_ITEM(function, MSG_UNLOAD_ALL, extr_unload_all);
+	MENU_ITEM(function, MSG_UNLOAD_FILAMENT_1, extr_unload_0);
+	MENU_ITEM(function, MSG_UNLOAD_FILAMENT_2, extr_unload_1);
+	MENU_ITEM(function, MSG_UNLOAD_FILAMENT_3, extr_unload_2);
+	MENU_ITEM(function, MSG_UNLOAD_FILAMENT_4, extr_unload_3);
+
+	END_MENU();
+}
+
+static void change_extr_menu(){
+	START_MENU();
+	MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+	MENU_ITEM(function, MSG_EXTRUDER_1, extr_change_0);
+	MENU_ITEM(function, MSG_EXTRUDER_2, extr_change_1);
+	MENU_ITEM(function, MSG_EXTRUDER_3, extr_change_2);
+	MENU_ITEM(function, MSG_EXTRUDER_4, extr_change_3);
+
+	END_MENU();
+}
+
+#endif
 
 static void lcd_farm_no()
 {
+	char step = 0;
 	int enc_dif = 0;
 	int _farmno = farm_no;
 	int _ret = 0;
@@ -2161,32 +4657,50 @@ static void lcd_farm_no()
 
 		if (abs((enc_dif - encoderDiff)) > 2) {
 			if (enc_dif > encoderDiff) {
-				_farmno--;
+				switch (step) {
+				case(0): if (_farmno >= 100) _farmno -= 100; break;
+				case(1): if (_farmno % 100 >= 10) _farmno -= 10; break;
+				case(2): if (_farmno % 10 >= 1) _farmno--; break;
+				default: break;
+				}
 			}
 
 			if (enc_dif < encoderDiff) {
-				_farmno++;
+				switch (step) {
+				case(0): if (_farmno < 900) _farmno += 100; break;
+				case(1): if (_farmno % 100 < 90) _farmno += 10; break;
+				case(2): if (_farmno % 10 <= 8)_farmno++; break;
+				default: break;
+				}
 			}
 			enc_dif = 0;
 			encoderDiff = 0;
 		}
 
-		if (_farmno > 254) { _farmno = 1; }
-		if (_farmno < 1) { _farmno = 254; }
-
-
 		lcd.setCursor(0, 2);
+		if (_farmno < 100) lcd.print("0");
+		if (_farmno < 10) lcd.print("0");
 		lcd.print(_farmno);
 		lcd.print("  ");
+		lcd.setCursor(0, 3);
+		lcd.print("   ");
+
+
+		lcd.setCursor(step, 3);
+		lcd.print("^");
 		delay(100);
 
 		if (lcd_clicked())
 		{
-			_ret = 1;
-			farm_no = _farmno;
-			EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-			prusa_statistics(20);
-			lcd_return_to_status();
+			delay(200);
+			step++;
+			if(step == 3) {
+				_ret = 1;
+				farm_no = _farmno;
+				EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no);
+				prusa_statistics(20);
+				lcd_return_to_status();
+			}
 		}
 
 		manage_heater();
@@ -2262,30 +4776,82 @@ void lcd_confirm_print()
 
 }
 
-
+extern bool saved_printing;
 
 static void lcd_main_menu()
 {
 
   SDscrool = 0;
-  /*
-  if (langsel == 1)
-  {
-    lcd_goto_menu(lcd_language_menu);
-  }
-  */
   START_MENU();
 
   // Majkl superawesome menu
 
-  
+
  MENU_ITEM(back, MSG_WATCH, lcd_status_screen);
 
-  if ( ( IS_SD_PRINTING || is_usb_printing ) && (current_position[Z_AXIS] < 0.5) ) 
+#ifdef RESUME_DEBUG 
+ if (!saved_printing) 
+  MENU_ITEM(function, PSTR("tst - Save"), lcd_menu_test_save);
+ else
+  MENU_ITEM(function, PSTR("tst - Restore"), lcd_menu_test_restore);
+#endif //RESUME_DEBUG 
+
+#ifdef TMC2130_DEBUG
+ MENU_ITEM(function, PSTR("recover print"), recover_print);
+ MENU_ITEM(function, PSTR("power panic"), uvlo_);
+#endif //TMC2130_DEBUG
+
+ /* if (farm_mode && !IS_SD_PRINTING )
+    {
+    
+        int tempScrool = 0;
+        if (lcdDrawUpdate == 0 && LCD_CLICKED == 0)
+            //delay(100);
+            return; // nothing to do (so don't thrash the SD card)
+        uint16_t fileCnt = card.getnrfilenames();
+        
+        card.getWorkDirName();
+        if (card.filename[0] == '/')
+        {
+#if SDCARDDETECT == -1
+            MENU_ITEM(function, MSG_REFRESH, lcd_sd_refresh);
+#endif
+        } else {
+            MENU_ITEM(function, PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir);
+        }
+        
+        for (uint16_t i = 0; i < fileCnt; i++)
+        {
+            if (_menuItemNr == _lineNr)
+            {
+#ifndef SDCARD_RATHERRECENTFIRST
+                card.getfilename(i);
+#else
+                card.getfilename(fileCnt - 1 - i);
+#endif
+                if (card.filenameIsDir)
+                {
+                    MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
+                } else {
+                    
+                    MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename);
+                    
+                    
+                    
+                    
+                }
+            } else {
+                MENU_ITEM_DUMMY();
+            }
+        }
+        
+        MENU_ITEM(back, PSTR("- - - - - - - - -"), lcd_status_screen);
+    
+        
+    }*/
+    
+  if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) ) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag)
   {
-    EEPROM_read_B(EEPROM_BABYSTEP_X, &babystepMem[0]);
-	EEPROM_read_B(EEPROM_BABYSTEP_Y, &babystepMem[1]);
-	EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystepMem[2]);
 	MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);//8
   }
 
@@ -2303,21 +4869,24 @@ static void lcd_main_menu()
   {
     if (card.isFileOpen())
     {
-		if (card.sdprinting)
-		{
-			MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
-		}
-		else
-		{
-			MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
+		if (mesh_bed_leveling_flag == false && homing_flag == false) {
+			if (card.sdprinting)
+			{
+				MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
+			}
+			else
+			{
+				MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
+			}
+			MENU_ITEM(submenu, MSG_STOP_PRINT, lcd_sdcard_stop);
 		}
-		MENU_ITEM(submenu, MSG_STOP_PRINT, lcd_sdcard_stop);
 	}
 	else
 	{
 		if (!is_usb_printing)
 		{
-			MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
+			//if (farm_mode) MENU_ITEM(submenu, MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu);
+			/*else*/ MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
 		}
 #if SDCARDDETECT < 1
       MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21"));  // SD-card changed by user
@@ -2335,12 +4904,24 @@ static void lcd_main_menu()
 
   if (IS_SD_PRINTING || is_usb_printing)
   {
+	  if (farm_mode)
+	  {
+		  MENU_ITEM(submenu, PSTR("Farm number"), lcd_farm_no);
+	  }
   } 
   else 
   {
+	#ifndef SNMM
     MENU_ITEM(function, MSG_LOAD_FILAMENT, lcd_LoadFilament);
     MENU_ITEM(function, MSG_UNLOAD_FILAMENT, lcd_unLoadFilament);
-    MENU_ITEM(submenu, MSG_SETTINGS, lcd_settings_menu);
+	#endif
+	#ifdef SNMM
+	MENU_ITEM(submenu, MSG_LOAD_FILAMENT, fil_load_menu);
+	MENU_ITEM(submenu, MSG_UNLOAD_FILAMENT, fil_unload_menu);
+	MENU_ITEM(submenu, MSG_CHANGE_EXTR, change_extr_menu);
+	#endif
+	MENU_ITEM(submenu, MSG_SETTINGS, lcd_settings_menu);
+    if(!isPrintPaused) MENU_ITEM(submenu, MSG_MENU_CALIBRATION, lcd_calibration_menu);
   }
 
   if (!is_usb_printing)
@@ -2348,11 +4929,22 @@ static void lcd_main_menu()
 	  MENU_ITEM(submenu, MSG_STATISTICS, lcd_menu_statistics);
   }
   MENU_ITEM(submenu, MSG_SUPPORT, lcd_support_menu);
-
+    
+  MENU_ITEM(submenu, PSTR("Fail stats"), lcd_menu_fails_stats);
+    
   END_MENU();
-}
 
+}
 
+void stack_error() {
+	SET_OUTPUT(BEEPER);
+	WRITE(BEEPER, HIGH);
+	delay(1000);
+	WRITE(BEEPER, LOW);
+	lcd_display_message_fullscreen_P(MSG_STACK_ERROR);
+	//err_triggered = 1;
+	 while (1) delay_keep_alive(1000);
+}
 
 #ifdef SDSUPPORT
 static void lcd_autostart_sd()
@@ -2367,11 +4959,29 @@ static void lcd_autostart_sd()
 
 static void lcd_silent_mode_set_tune() {
   SilentModeMenu = !SilentModeMenu;
-  EEPROM_save(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
+  eeprom_update_byte((unsigned char*)EEPROM_SILENT, SilentModeMenu);
+#ifdef TMC2130
+  st_synchronize();
+  cli();
+	tmc2130_mode = SilentModeMenu?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL;
+	tmc2130_init();
+  sei();
+#endif //TMC2130
   digipot_init();
   lcd_goto_menu(lcd_tune_menu, 9);
 }
 
+static void lcd_colorprint_change() {
+	
+	enquecommand_P(PSTR("M600"));
+	
+	custom_message = true;
+	custom_message_type = 2; //just print status message
+	lcd_setstatuspgm(MSG_FINISHING_MOVEMENTS);
+	lcd_return_to_status();
+	lcdDrawUpdate = 3;
+}
+
 static void lcd_tune_menu()
 {
   EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
@@ -2388,14 +4998,29 @@ static void lcd_tune_menu()
   MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);//5
   MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999);//6
 #ifdef FILAMENTCHANGEENABLE
-  MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600"));//7
+  MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_colorprint_change);//7
 #endif
   
+  if (FSensorStateMenu == 0) {
+    MENU_ITEM(function, MSG_FSENSOR_OFF, lcd_fsensor_state_set);
+  } else {
+    MENU_ITEM(function, MSG_FSENSOR_ON, lcd_fsensor_state_set);
+  }
+
   if (SilentModeMenu == 0) {
-    MENU_ITEM(function, MSG_SILENT_MODE_OFF, lcd_silent_mode_set_tune);
+    MENU_ITEM(function, MSG_SILENT_MODE_OFF, lcd_silent_mode_set);
   } else {
-    MENU_ITEM(function, MSG_SILENT_MODE_ON, lcd_silent_mode_set_tune);
+    MENU_ITEM(function, MSG_SILENT_MODE_ON, lcd_silent_mode_set);
+  }
+
+  if (SilentModeMenu == 0) {
+    if (CrashDetectMenu == 0) {
+      MENU_ITEM(function, MSG_CRASHDETECT_OFF, lcd_crash_mode_set);
+    } else {
+      MENU_ITEM(function, MSG_CRASHDETECT_ON, lcd_crash_mode_set);
+    }
   }
+
   END_MENU();
 }
 
@@ -2412,13 +5037,12 @@ static void lcd_control_temperature_menu()
 {
 #ifdef PIDTEMP
   // set up temp variables - undo the default scaling
-  raw_Ki = unscalePID_i(Ki);
-  raw_Kd = unscalePID_d(Kd);
+//  raw_Ki = unscalePID_i(Ki);
+//  raw_Kd = unscalePID_d(Kd);
 #endif
 
   START_MENU();
   MENU_ITEM(back, MSG_SETTINGS, lcd_settings_menu);
-  //MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
 #if TEMP_SENSOR_0 != 0
   MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 10);
 #endif
@@ -2457,6 +5081,39 @@ static void lcd_sd_updir()
   currentMenuViewOffset = 0;
 }
 
+void lcd_print_stop() {
+	cancel_heatup = true;
+#ifdef MESH_BED_LEVELING
+	mbl.active = false;
+#endif
+	// Stop the stoppers, update the position from the stoppers.
+	if (mesh_bed_leveling_flag == false && homing_flag == false) {
+		planner_abort_hard();
+		// Because the planner_abort_hard() initialized current_position[Z] from the stepper,
+		// Z baystep is no more applied. Reset it.
+		babystep_reset();
+	}
+	// Clean the input command queue.
+	cmdqueue_reset();
+	lcd_setstatuspgm(MSG_PRINT_ABORTED);
+	lcd_update(2);
+	card.sdprinting = false;
+	card.closefile();
+
+	stoptime = millis();
+	unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s
+	pause_time = 0;
+	save_statistics(total_filament_used, t);
+
+	lcd_return_to_status();
+	lcd_ignore_click(true);
+	lcd_commands_type = LCD_COMMAND_STOP_PRINT;
+
+	// Turn off the print fan
+	SET_OUTPUT(FAN_PIN);
+	WRITE(FAN_PIN, 0);
+	fanSpeed = 0;
+}
 
 void lcd_sdcard_stop()
 {
@@ -2484,23 +5141,40 @@ void lcd_sdcard_stop()
 		}
 		if ((int32_t)encoderPosition == 2)
 		{
-				cancel_heatup = true;
-				quickStop();
-				lcd_setstatuspgm(MSG_PRINT_ABORTED);
-				card.sdprinting = false;
-				card.closefile();
-
-				stoptime = millis();
-				unsigned long t = (stoptime - starttime) / 1000;
-				save_statistics(total_filament_used, t);
-
-				lcd_return_to_status();
-				lcd_ignore_click(true);
-				lcd_commands_type = 2;
+			lcd_print_stop();
 		}
 	}
 
 }
+/*
+void getFileDescription(char *name, char *description) {
+	// get file description, ie the REAL filenam, ie the second line
+	card.openFile(name, true);
+	int i = 0;
+	// skip the first line (which is the version line)
+	while (true) {
+		uint16_t readByte = card.get();
+		if (readByte == '\n') {
+			break;
+		}
+	}
+	// read the second line (which is the description line)
+	while (true) {
+		uint16_t readByte = card.get();
+		if (i == 0) {
+			// skip the first '^'
+			readByte = card.get();
+		}
+		description[i] = readByte;
+		i++;
+		if (readByte == '\n') {
+			break;
+		}
+	}
+	card.closefile();
+	description[i-1] = 0;
+}
+*/
 
 void lcd_sdcard_menu()
 {
@@ -2542,60 +5216,128 @@ void lcd_sdcard_menu()
 
 
 
-      }
-    } else {
-      MENU_ITEM_DUMMY();
-    }
-  }
-  END_MENU();
-}
+      }
+    } else {
+      MENU_ITEM_DUMMY();
+    }
+  }
+  END_MENU();
+}
+
+//char description [10] [31];
+
+/*void get_description() {
+	uint16_t fileCnt = card.getnrfilenames();
+	for (uint16_t i = 0; i < fileCnt; i++)
+	{
+		card.getfilename(fileCnt - 1 - i);
+		getFileDescription(card.filename, description[i]);
+	}
+}*/
+
+/*void lcd_farm_sdcard_menu() 
+{
+	static int i = 0;
+	if (i == 0) {
+		get_description();
+		i++;
+	}
+		//int j;
+		//char description[31];
+		int tempScrool = 0;
+		if (lcdDrawUpdate == 0 && LCD_CLICKED == 0)
+			//delay(100);
+			return; // nothing to do (so don't thrash the SD card)
+		uint16_t fileCnt = card.getnrfilenames();
+
+		START_MENU();
+		MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+		card.getWorkDirName();
+		if (card.filename[0] == '/')
+		{
+#if SDCARDDETECT == -1
+			MENU_ITEM(function, MSG_REFRESH, lcd_sd_refresh);
+#endif
+		}
+		else {
+			MENU_ITEM(function, PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir);
+		}
+
+
+
+		for (uint16_t i = 0; i < fileCnt; i++)
+		{
+			if (_menuItemNr == _lineNr)
+			{
+#ifndef SDCARD_RATHERRECENTFIRST
+				card.getfilename(i);
+#else
+				card.getfilename(fileCnt - 1 - i);
+#endif
+				if (card.filenameIsDir)
+				{
+					MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
+				}
+				else {
+					
+					MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, description[i]);
+				}
+			}
+			else {
+				MENU_ITEM_DUMMY();
+			}
+		}
+		END_MENU();
+
+}*/
 
 #define menu_edit_type(_type, _name, _strFunc, scale) \
   void menu_edit_ ## _name () \
   { \
     if ((int32_t)encoderPosition < 0) encoderPosition = 0; \
-    if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; \
+    if ((int32_t)encoderPosition > menuData.editMenuParentState.maxEditValue) encoderPosition = menuData.editMenuParentState.maxEditValue; \
     if (lcdDrawUpdate) \
-      lcd_implementation_drawedit(editLabel, _strFunc(((_type)((int32_t)encoderPosition + minEditValue)) / scale)); \
+      lcd_implementation_drawedit(menuData.editMenuParentState.editLabel, _strFunc(((_type)((int32_t)encoderPosition + menuData.editMenuParentState.minEditValue)) / scale)); \
     if (LCD_CLICKED) \
     { \
-      *((_type*)editValue) = ((_type)((int32_t)encoderPosition + minEditValue)) / scale; \
-      lcd_goto_menu(prevMenu, prevEncoderPosition); \
+      *((_type*)menuData.editMenuParentState.editValue) = ((_type)((int32_t)encoderPosition + menuData.editMenuParentState.minEditValue)) / scale; \
+      lcd_goto_menu(menuData.editMenuParentState.prevMenu, menuData.editMenuParentState.prevEncoderPosition, true, false); \
     } \
   } \
-  void menu_edit_callback_ ## _name () { \
-    menu_edit_ ## _name (); \
-    if (LCD_CLICKED) (*callbackFunc)(); \
-  } \
   static void menu_action_setting_edit_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue) \
   { \
-    prevMenu = currentMenu; \
-    prevEncoderPosition = encoderPosition; \
+    menuData.editMenuParentState.prevMenu = currentMenu; \
+    menuData.editMenuParentState.prevEncoderPosition = encoderPosition; \
     \
     lcdDrawUpdate = 2; \
-    currentMenu = menu_edit_ ## _name; \
+    menuData.editMenuParentState.editLabel = pstr; \
+    menuData.editMenuParentState.editValue = ptr; \
+    menuData.editMenuParentState.minEditValue = minValue * scale; \
+    menuData.editMenuParentState.maxEditValue = maxValue * scale - menuData.editMenuParentState.minEditValue; \
+    lcd_goto_menu(menu_edit_ ## _name, (*ptr) * scale - menuData.editMenuParentState.minEditValue, true, false); \
     \
-    editLabel = pstr; \
-    editValue = ptr; \
-    minEditValue = minValue * scale; \
-    maxEditValue = maxValue * scale - minEditValue; \
-    encoderPosition = (*ptr) * scale - minEditValue; \
   }\
+  /*
+  void menu_edit_callback_ ## _name () { \
+    menu_edit_ ## _name (); \
+    if (LCD_CLICKED) (*callbackFunc)(); \
+  } \
   static void menu_action_setting_edit_callback_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue, menuFunc_t callback) \
   { \
-    prevMenu = currentMenu; \
-    prevEncoderPosition = encoderPosition; \
+    menuData.editMenuParentState.prevMenu = currentMenu; \
+    menuData.editMenuParentState.prevEncoderPosition = encoderPosition; \
     \
     lcdDrawUpdate = 2; \
-    currentMenu = menu_edit_callback_ ## _name; \
+    lcd_goto_menu(menu_edit_callback_ ## _name, (*ptr) * scale - menuData.editMenuParentState.minEditValue, true, false); \
     \
-    editLabel = pstr; \
-    editValue = ptr; \
-    minEditValue = minValue * scale; \
-    maxEditValue = maxValue * scale - minEditValue; \
-    encoderPosition = (*ptr) * scale - minEditValue; \
+    menuData.editMenuParentState.editLabel = pstr; \
+    menuData.editMenuParentState.editValue = ptr; \
+    menuData.editMenuParentState.minEditValue = minValue * scale; \
+    menuData.editMenuParentState.maxEditValue = maxValue * scale - menuData.editMenuParentState.minEditValue; \
     callbackFunc = callback;\
   }
+  */
+
 menu_edit_type(int, int3, itostr3, 1)
 menu_edit_type(float, float3, ftostr3, 1)
 menu_edit_type(float, float32, ftostr32, 100)
@@ -2605,60 +5347,122 @@ menu_edit_type(float, float51, ftostr51, 10)
 menu_edit_type(float, float52, ftostr52, 100)
 menu_edit_type(unsigned long, long5, ftostr5, 0.01)
 
+static void lcd_selftest_v()
+{
+	(void)lcd_selftest();
+}
 
-static void lcd_selftest()
+static bool lcd_selftest()
 {
 	int _progress = 0;
 	bool _result = false;
 
-	_progress = lcd_selftest_screen(-1, _progress, 4, true, 2000);
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0); lcd_printPGM(MSG_SELFTEST_START);
+	delay(2000);
+
+	_progress = lcd_selftest_screen(-1, _progress, 3, true, 2000);
+	_result = lcd_selftest_fan_dialog(0);
+	
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(0, _progress, 3, true, 2000);
+		_result = lcd_selftest_fan_dialog(1);
+	}
 
-	_progress = lcd_selftest_screen(0, _progress, 3, true, 2000);
-	_result = lcd_selfcheck_endstops();
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(1, _progress, 3, true, 2000);
+		//_progress = lcd_selftest_screen(2, _progress, 3, true, 2000);
+		_result = true;// lcd_selfcheck_endstops();
+	}
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(1, _progress, 3, true, 1000);
+		_progress = lcd_selftest_screen(3, _progress, 3, true, 1000);
 		_result = lcd_selfcheck_check_heater(false);
 	}
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(2, _progress, 3, true, 2000);
-		_result = lcd_selfcheck_axis(0, X_MAX_POS);
+		//current_position[Z_AXIS] += 15;									//move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed
+		_progress = lcd_selftest_screen(4, _progress, 3, true, 2000);
+#ifdef TMC2130
+		_result = lcd_selfcheck_axis_sg(X_AXIS);
+#else
+		_result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS);
+#endif //TMC2130
+	}
+
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(4, _progress, 3, true, 0);
+
+#ifndef TMC2130
+		_result = lcd_selfcheck_pulleys(X_AXIS);
+#endif
+	}
+
+
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(5, _progress, 3, true, 1500);
+#ifdef TMC2130
+		_result = lcd_selfcheck_axis_sg(Y_AXIS);
+#else
+		_result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS);
+#endif // TMC2130
 	}
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(3, _progress, 3, true, 1500);
-		_result = lcd_selfcheck_axis(1, Y_MAX_POS);
+		_progress = lcd_selftest_screen(5, _progress, 3, true, 0);
+#ifndef TMC2130
+		_result = lcd_selfcheck_pulleys(Y_AXIS);
+#endif // TMC2130
 	}
 
+
 	if (_result)
 	{
-		current_position[X_AXIS] = current_position[X_AXIS] - 3;
-		current_position[Y_AXIS] = current_position[Y_AXIS] - 14;
-		_progress = lcd_selftest_screen(4, _progress, 3, true, 1500);
+#ifdef TMC2130
+		tmc2130_home_exit();
+		enable_endstops(false);
+#endif
+		current_position[X_AXIS] = current_position[X_AXIS] + 14;
+		current_position[Y_AXIS] = current_position[Y_AXIS] + 12;
+
+		//homeaxis(X_AXIS);
+		//homeaxis(Y_AXIS);
+		current_position[Z_AXIS] = current_position[Z_AXIS] + 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+		st_synchronize();
+		_progress = lcd_selftest_screen(6, _progress, 3, true, 1500);
 		_result = lcd_selfcheck_axis(2, Z_MAX_POS);
+		if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) {
+			enquecommand_P(PSTR("G28 W"));
+			enquecommand_P(PSTR("G1 Z15"));
+		}
 	}
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(5, _progress, 3, true, 2000);
+		_progress = lcd_selftest_screen(7, _progress, 3, true, 2000);
 		_result = lcd_selfcheck_check_heater(true);
 	}
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(6, _progress, 3, true, 5000);
+		_progress = lcd_selftest_screen(8, _progress, 3, true, 5000);
 	}
 	else
 	{
-		_progress = lcd_selftest_screen(7, _progress, 3, true, 5000);
+		_progress = lcd_selftest_screen(9, _progress, 3, true, 5000);
 	}
-
+	lcd_reset_alert_level();
+	enquecommand_P(PSTR("M84"));
 	lcd_implementation_clear();
 	lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL;
-
+	
 	if (_result)
 	{
 		LCD_ALERTMESSAGERPGM(MSG_SELFTEST_OK);
@@ -2667,34 +5471,146 @@ static void lcd_selftest()
 	{
 		LCD_ALERTMESSAGERPGM(MSG_SELFTEST_FAILED);
 	}
+	return(_result);
 }
-static bool lcd_selfcheck_endstops()
-{
-	bool _result = true;
 
-	if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
-	{
-		current_position[0] = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? current_position[0] = current_position[0] + 10 : current_position[0];
-		current_position[1] = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? current_position[1] = current_position[1] + 10 : current_position[1];
-		current_position[2] = (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? current_position[2] = current_position[2] + 10 : current_position[2];
+#ifdef TMC2130
+
+static void reset_crash_det(char axis) {
+	current_position[axis] += 10;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	st_synchronize();
+	if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET)) tmc2130_sg_stop_on_crash = true;
+}
+
+static bool lcd_selfcheck_axis_sg(char axis) {
+// each axis length is measured twice	
+	float axis_length, current_position_init, current_position_final;
+	float measured_axis_length[2];
+	float margin = 60;
+	float max_error_mm = 5;
+	switch (axis) {
+	case 0: axis_length = X_MAX_POS; break;
+	case 1: axis_length = Y_MAX_POS + 8; break;
+	default: axis_length = 210; break;
 	}
-	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[0] / 60, active_extruder);
-	delay(500);
 
-	if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
-	{
-		_result = false;
-		String  _error = String((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? "X" : "") +
-			String((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? "Y" : "") +
-			String((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? "Z" : "");
-		lcd_selftest_error(3, _error.c_str(), "");
+	tmc2130_sg_stop_on_crash = false;
+	tmc2130_home_exit();
+	enable_endstops(true);
+
+	if (axis == X_AXIS) { //there is collision between cables and PSU cover in X axis if Z coordinate is too low
+		
+		current_position[Z_AXIS] += 17;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+		tmc2130_home_enter(Z_AXIS_MASK);
+		st_synchronize();
+		tmc2130_home_exit();
 	}
-	manage_heater();
-	manage_inactivity();
-	return _result;
+
+// first axis length measurement begin	
+
+	tmc2130_home_enter(X_AXIS_MASK << axis);
+	current_position[axis] -= (axis_length + margin);
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+
+	
+	st_synchronize();
+	tmc2130_home_exit();
+
+	tmc2130_sg_meassure_start(axis);
+
+	current_position_init = st_get_position_mm(axis);
+
+	current_position[axis] += 2 * margin;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	st_synchronize();
+
+	current_position[axis] += axis_length;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+
+	tmc2130_home_enter(X_AXIS_MASK << axis);
+	st_synchronize();
+	tmc2130_home_exit();
+
+	uint16_t sg1 = tmc2130_sg_meassure_stop();
+	printf_P(PSTR("%c AXIS SG1=%d\n"), 'X'+axis, sg1);
+	eeprom_write_word(((uint16_t*)((axis == X_AXIS)?EEPROM_BELTSTATUS_X:EEPROM_BELTSTATUS_Y)), sg1);
+
+	current_position_final = st_get_position_mm(axis);
+	measured_axis_length[0] = abs(current_position_final - current_position_init);
+
+
+// first measurement end and second measurement begin	
+
+
+	current_position[axis] -= margin;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	st_synchronize();	
+
+	tmc2130_home_enter(X_AXIS_MASK << axis);
+	current_position[axis] -= (axis_length + margin);
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+		
+	st_synchronize();
+	tmc2130_home_exit();
+
+	current_position_init = st_get_position_mm(axis);
+
+	measured_axis_length[1] = abs(current_position_final - current_position_init);
+
+
+//end of second measurement, now check for possible errors:
+	
+	for(int i = 0; i < 2; i++){ //check if measured axis length corresponds to expected length
+		SERIAL_ECHOPGM("Measured axis length:");
+		MYSERIAL.println(measured_axis_length[i]);
+		if (abs(measured_axis_length[i] - axis_length) > max_error_mm) {
+			enable_endstops(false);
+
+			const char *_error_1;
+			const char *_error_2;
+
+			if (axis == X_AXIS) _error_1 = "X";
+			if (axis == Y_AXIS) _error_1 = "Y";
+			if (axis == Z_AXIS) _error_1 = "Z";
+
+			lcd_selftest_error(9, _error_1, _error_2);
+			reset_crash_det(axis);
+			return false;
+		}
+	}
+
+	SERIAL_ECHOPGM("Axis length difference:");
+	MYSERIAL.println(abs(measured_axis_length[0] - measured_axis_length[1]));
+	
+		if (abs(measured_axis_length[0] - measured_axis_length[1]) > 1) { //check if difference between first and second measurement is low
+			//loose pulleys
+			const char *_error_1;
+			const char *_error_2;
+
+			if (axis == X_AXIS) _error_1 = "X";
+			if (axis == Y_AXIS) _error_1 = "Y";
+			if (axis == Z_AXIS) _error_1 = "Z";
+
+			lcd_selftest_error(8, _error_1, _error_2);
+
+			reset_crash_det(axis);
+
+			return false;
+		}
+
+		reset_crash_det(axis);
+		return true;
 }
+#endif //TMC2130
+	
+
+
+
 static bool lcd_selfcheck_axis(int _axis, int _travel)
 {
+	
 	bool _stepdone = false;
 	bool _stepresult = false;
 	int _progress = 0;
@@ -2702,43 +5618,41 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 	int _err_endstop = 0;
 	int _lcd_refresh = 0;
 	_travel = _travel + (_travel / 10);
-
 	do {
 
-		if (_axis == 2)
-		{
-			current_position[_axis] = current_position[_axis] - 1;
-		}
-		else
-		{
-			current_position[_axis] = current_position[_axis] - 3;
-		}
+		current_position[_axis] = current_position[_axis] - 1;
+
 
 		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
 		st_synchronize();
-
-		if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
+		
+		if (/*x_min_endstop || y_min_endstop || */(READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1))
 		{
 			if (_axis == 0)
 			{
-				_stepresult = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? true : false;
-				_err_endstop = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? 1 : 2;
-				disable_x();
+				_stepresult = (x_min_endstop) ? true : false;
+				_err_endstop = (y_min_endstop) ? 1 : 2;
+				
 			}
 			if (_axis == 1)
 			{
-				_stepresult = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? true : false;
-				_err_endstop = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? 0 : 2;
-				disable_y();
+				_stepresult = (y_min_endstop) ? true : false;
+				_err_endstop = (x_min_endstop) ? 0 : 2;
+				
 			}
 			if (_axis == 2)
 			{
 				_stepresult = (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? true : false;
-				_err_endstop = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? 0 : 1;
-				disable_z();
+				_err_endstop = (x_min_endstop) ? 0 : 1;
+				/*disable_x();
+				disable_y();
+				disable_z();*/
 			}
 			_stepdone = true;
 		}
+#ifdef TMC2130
+		tmc2130_home_exit();
+#endif
 
 		if (_lcd_refresh < 6)
 		{
@@ -2746,21 +5660,21 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 		}
 		else
 		{
-			_progress = lcd_selftest_screen(2 + _axis, _progress, 3, false, 0);
+			_progress = lcd_selftest_screen(4 + _axis, _progress, 3, false, 0);
 			_lcd_refresh = 0;
 		}
 
 		manage_heater();
-		manage_inactivity();
+		manage_inactivity(true);
 
-		delay(100);
+		//delay(100);
 		(_travel_done <= _travel) ? _travel_done++ : _stepdone = true;
-
+		
 	} while (!_stepdone);
 
 
-	current_position[_axis] = current_position[_axis] + 15;
-	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	//current_position[_axis] = current_position[_axis] + 15;
+	//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
 
 	if (!_stepresult)
 	{
@@ -2785,8 +5699,133 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 		}
 	}
 
+
 	return _stepresult;
 }
+
+static bool lcd_selfcheck_pulleys(int axis)
+{
+	float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+	float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+	float current_position_init, current_position_final;
+	float move;
+	bool endstop_triggered = false;
+	bool result = true;
+	int i;
+	unsigned long timeout_counter;
+	refresh_cmd_timeout();
+	manage_inactivity(true);
+
+	if (axis == 0) move = 50; //X_AXIS 
+		else move = 50; //Y_AXIS
+
+		//current_position_init = current_position[axis];
+		current_position_init = st_get_position_mm(axis);
+		current_position[axis] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+		for (i = 0; i < 5; i++) {
+			refresh_cmd_timeout();
+			current_position[axis] = current_position[axis] + move;
+			//digipot_current(0, 850); //set motor current higher
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 200, active_extruder);
+			st_synchronize();
+			//if (SilentModeMenu == 1) digipot_current(0, tmp_motor[0]); //set back to normal operation currents
+			//else digipot_current(0, tmp_motor_loud[0]); //set motor current back			
+			current_position[axis] = current_position[axis] - move;
+#ifdef TMC2130
+			tmc2130_home_enter(X_AXIS_MASK << axis);
+#endif
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 50, active_extruder);
+			
+			st_synchronize();
+			if ((x_min_endstop) || (y_min_endstop)) {
+				lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+				return(false);
+			}
+#ifdef TMC2130
+			tmc2130_home_exit();
+#endif
+		}
+		timeout_counter = millis() + 2500;
+		endstop_triggered = false;
+		manage_inactivity(true);
+		while (!endstop_triggered) {
+			if ((x_min_endstop) || (y_min_endstop)) {
+#ifdef TMC2130
+				tmc2130_home_exit();
+#endif
+				endstop_triggered = true;
+				current_position_final = st_get_position_mm(axis);
+
+				SERIAL_ECHOPGM("current_pos_init:");
+				MYSERIAL.println(current_position_init);
+				SERIAL_ECHOPGM("current_pos:");
+				MYSERIAL.println(current_position_final);
+				lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+				
+				if (current_position_init - 1 <= current_position_final && current_position_init + 1 >= current_position_final) {
+					current_position[axis] += 15;
+					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+					st_synchronize();
+					return(true);
+				}
+				else {
+
+					return(false);
+				}
+			}
+			else {
+#ifdef TMC2130
+				tmc2130_home_exit();
+#endif
+				//current_position[axis] -= 1;
+				current_position[axis] += 50;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+				current_position[axis] -= 100;
+#ifdef TMC2130
+				tmc2130_home_enter(X_AXIS_MASK << axis);
+#endif
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+				st_synchronize();
+				
+				if (millis() > timeout_counter) {
+					lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+					return(false);
+				}
+			}
+		}		
+
+
+}
+
+static bool lcd_selfcheck_endstops()
+{/*
+	bool _result = true;
+
+	if (x_min_endstop || y_min_endstop || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
+	{
+		current_position[0] = (x_min_endstop) ? current_position[0] = current_position[0] + 10 : current_position[0];
+		current_position[1] = (y_min_endstop) ? current_position[1] = current_position[1] + 10 : current_position[1];
+		current_position[2] = (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? current_position[2] = current_position[2] + 10 : current_position[2];
+	}
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[0] / 60, active_extruder);
+	delay(500);
+
+	if (x_min_endstop || y_min_endstop || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
+	{
+		_result = false;
+		char _error[4] = "";
+		if (x_min_endstop) strcat(_error, "X");
+		if (y_min_endstop) strcat(_error, "Y");
+		if (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) strcat(_error, "Z");
+		lcd_selftest_error(3, _error, "");
+	}
+	manage_heater();
+	manage_inactivity(true);
+	return _result;
+	*/
+}
+
 static bool lcd_selfcheck_check_heater(bool _isbed)
 {
 	int _counter = 0;
@@ -2796,22 +5835,30 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 
 	int _checked_snapshot = (_isbed) ? degBed() : degHotend(0);
 	int _opposite_snapshot = (_isbed) ? degHotend(0) : degBed();
-	int _cycles = (_isbed) ? 120 : 30;
+	int _cycles = (_isbed) ? 180 : 60; //~ 90s / 30s
 
-	target_temperature[0] = (_isbed) ? 0 : 100;
+	target_temperature[0] = (_isbed) ? 0 : 200;
 	target_temperature_bed = (_isbed) ? 100 : 0;
 	manage_heater();
-	manage_inactivity();
+	manage_inactivity(true);
 
 	do {
 		_counter++;
-		(_counter < _cycles) ? _docycle = true : _docycle = false;
+		_docycle = (_counter < _cycles) ? true : false;
 
 		manage_heater();
-		manage_inactivity();
-		_progress = (_isbed) ? lcd_selftest_screen(5, _progress, 2, false, 400) : lcd_selftest_screen(1, _progress, 2, false, 400);
+		manage_inactivity(true);
+		_progress = (_isbed) ? lcd_selftest_screen(7, _progress, 2, false, 400) : lcd_selftest_screen(3, _progress, 2, false, 400);
+		/*if (_isbed) {
+			MYSERIAL.print("Bed temp:");
+			MYSERIAL.println(degBed());
+		}
+		else {
+			MYSERIAL.print("Hotend temp:");
+			MYSERIAL.println(degHotend(0));
+		}*/
 
-	} while (_docycle);
+	} while (_docycle); 
 
 	target_temperature[0] = 0;
 	target_temperature_bed = 0;
@@ -2819,10 +5866,16 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 
 	int _checked_result = (_isbed) ? degBed() - _checked_snapshot : degHotend(0) - _checked_snapshot;
 	int _opposite_result = (_isbed) ? degHotend(0) - _opposite_snapshot : degBed() - _opposite_snapshot;
-
-	if (_opposite_result < (_isbed) ? 10 : 3)
+	/*
+	MYSERIAL.println("");
+	MYSERIAL.print("Checked result:");
+	MYSERIAL.println(_checked_result);
+	MYSERIAL.print("Opposite result:");
+	MYSERIAL.println(_opposite_result);
+	*/
+	if (_opposite_result < ((_isbed) ? 10 : 3))
 	{
-		if (_checked_result >= (_isbed) ? 3 : 10)
+		if (_checked_result >= ((_isbed) ? 3 : 10))
 		{
 			_stepresult = true;
 		}
@@ -2837,7 +5890,7 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 	}
 
 	manage_heater();
-	manage_inactivity();
+	manage_inactivity(true);
 	return _stepresult;
 
 }
@@ -2897,7 +5950,38 @@ static void lcd_selftest_error(int _error_no, const char *_error_1, const char *
 		lcd.setCursor(18, 3);
 		lcd.print(_error_1);
 		break;
-
+	case 6:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_SELFTEST_COOLING_FAN);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_WIRINGERROR);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
+	case 7:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_SELFTEST_EXTRUDER_FAN);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_WIRINGERROR);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
+	case 8:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_LOOSE_PULLEY);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_MOTOR);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
+	case 9:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_SELFTEST_AXIS_LENGTH);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_AXIS);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
 	}
 
 	delay(1000);
@@ -2913,8 +5997,55 @@ static void lcd_selftest_error(int _error_no, const char *_error_1, const char *
 	lcd_return_to_status();
 
 }
+
+static bool lcd_selftest_fan_dialog(int _fan)
+{
+	bool _result = true;
+	int _errno = 6;
+
+	switch (_fan) {
+	case 0:
+		fanSpeed = 0;
+		manage_heater();			//turn off fan
+		setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //extruder fan
+		delay(2000);				//delay_keep_alive would turn off extruder fan, because temerature is too low
+		manage_heater();			//count average fan speed from 2s delay and turn off fans
+		if (!fan_speed[0]) _result = false;
+		/*SERIAL_ECHOPGM("Extruder fan speed: ");
+		MYSERIAL.println(fan_speed[0]);
+		SERIAL_ECHOPGM("Print fan speed: ");
+		MYSERIAL.print(fan_speed[1]);*/
+		break;
+
+	case 1:
+		//will it work with Thotend > 50 C ?
+		fanSpeed = 255;				//print fan
+		delay_keep_alive(2000);
+		fanSpeed = 0;
+		manage_heater();			//turn off fan
+		manage_inactivity(true);	//to turn off print fan
+		if (!fan_speed[1]) {
+			_result = false; _errno = 7;
+		}
+		/*SERIAL_ECHOPGM("Extruder fan speed: ");
+		MYSERIAL.println(fan_speed[0]);
+		SERIAL_ECHOPGM("Print fan speed: ");
+		MYSERIAL.print(fan_speed[1]);*/
+		break;
+	}
+	if (!_result)
+	{
+		const char *_err;
+		lcd_selftest_error(_errno, _err, _err);
+	}
+	return _result;
+}
+
 static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bool _clear, int _delay)
 {
+	//SERIAL_ECHOPGM("Step:");
+	//MYSERIAL.println(_step);
+
 	lcd_next_update_millis = millis() + (LCD_UPDATE_INTERVAL * 10000);
 
 	int _step_block = 0;
@@ -2925,40 +6056,55 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo
 
 	lcd.setCursor(0, 0);
 
-	if (_step == -1) lcd_printPGM(MSG_SELFTEST_START);
-	if (_step == 0) lcd_printPGM(MSG_SELFTEST_CHECK_ENDSTOPS);
-	if (_step == 1) lcd_printPGM(MSG_SELFTEST_CHECK_HOTEND);
-	if (_step == 2) lcd_printPGM(MSG_SELFTEST_CHECK_X);
-	if (_step == 3) lcd_printPGM(MSG_SELFTEST_CHECK_Y);
-	if (_step == 4) lcd_printPGM(MSG_SELFTEST_CHECK_Z);
-	if (_step == 5) lcd_printPGM(MSG_SELFTEST_CHECK_BED);
-	if (_step == 6) lcd_printPGM(MSG_SELFTEST_CHECK_ALLCORRECT);
-	if (_step == 7) lcd_printPGM(MSG_SELFTEST_FAILED);
+	if (_step == -1) lcd_printPGM(MSG_SELFTEST_FAN);
+	if (_step == 0) lcd_printPGM(MSG_SELFTEST_FAN);
+	if (_step == 1) lcd_printPGM(MSG_SELFTEST_FAN);
+	if (_step == 2) lcd_printPGM(MSG_SELFTEST_CHECK_ENDSTOPS);
+	if (_step == 3) lcd_printPGM(MSG_SELFTEST_CHECK_HOTEND);
+	if (_step == 4) lcd_printPGM(MSG_SELFTEST_CHECK_X);
+	if (_step == 5) lcd_printPGM(MSG_SELFTEST_CHECK_Y);
+	if (_step == 6) lcd_printPGM(MSG_SELFTEST_CHECK_Z);
+	if (_step == 7) lcd_printPGM(MSG_SELFTEST_CHECK_BED);
+	if (_step == 8) lcd_printPGM(MSG_SELFTEST_CHECK_ALLCORRECT);
+	if (_step == 9) lcd_printPGM(MSG_SELFTEST_FAILED);
 
 	lcd.setCursor(0, 1);
 	lcd.print("--------------------");
+	if ((_step >= -1) && (_step <= 1))
+	{
+		//SERIAL_ECHOLNPGM("Fan test");
+		lcd_print_at_PGM(0, 2, PSTR("Extruder fan:"));
+		lcd.setCursor(14, 2);
+		(_step < 0) ? lcd.print(_indicator) : lcd.print("OK");
+		lcd_print_at_PGM(0, 3, PSTR("Print fan:"));
+		lcd.setCursor(14, 3);
+		(_step < 1) ? lcd.print(_indicator) : lcd.print("OK");
+	}
+	else if (_step != 9)
+	{
+		//SERIAL_ECHOLNPGM("Other tests");
+		_step_block = 3;
+		lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator);
 
-	_step_block = 1;
-	lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator);
-
-	_step_block = 2;
-	lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator);
-
-	_step_block = 3;
-	lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator);
+		_step_block = 4;
+		lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator);
 
-	_step_block = 4;
-	lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator);
+		_step_block = 5;
+		lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator);
 
-	_step_block = 5;
-	lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator);
+		_step_block = 6;
+		lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator);
 
+		_step_block = 7;
+		lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator);
+	}
 
 	if (_delay > 0) delay(_delay);
 	_progress++;
 
 	return (_progress > _progress_scale * 2) ? 0 : _progress;
 }
+
 static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator)
 {
 	lcd.setCursor(_col, _row);
@@ -2990,7 +6136,7 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char
 static void lcd_quick_feedback()
 {
   lcdDrawUpdate = 2;
-  blocking_enc = millis() + 500;
+  button_pressed = false;  
   lcd_implementation_quick_feedback();
 }
 
@@ -3012,17 +6158,43 @@ static void menu_action_function(menuFunc_t data) {
 }
 static void menu_action_sdfile(const char* filename, char* longFilename)
 {
+  loading_flag = false;
   char cmd[30];
   char* c;
   sprintf_P(cmd, PSTR("M23 %s"), filename);
   for (c = &cmd[4]; *c; c++)
     *c = tolower(*c);
   enquecommand(cmd);
+  for (int i = 0; i < 8; i++) {
+	  eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, filename[i]);
+  }
+
+  uint8_t depth = (uint8_t)card.getWorkDirDepth();
+
+ //char dir_name[9];
+
+  for (uint8_t i = 0; i < depth; i++) {
+	  //card.getDirName(dir_name, i + 1);
+	  //dir_name[8] = '\0';
+	  //MYSERIAL.println(dir_name);
+	  for (int j = 0; j < 8; j++) {
+		  eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8*i, dir_names[i][j]);
+		  //eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_name[j]);
+	  }
+
+  }
+  //MYSERIAL.println(int(depth));
+  eeprom_write_byte((uint8_t*)EEPROM_DIR_DEPTH, depth);
+
   enquecommand_P(PSTR("M24"));
   lcd_return_to_status();
 }
 static void menu_action_sddirectory(const char* filename, char* longFilename)
 {
+	uint8_t depth = (uint8_t)card.getWorkDirDepth();
+
+	strcpy(dir_names[depth], filename);
+	MYSERIAL.println(dir_names[depth]);
   card.chdir(filename);
   encoderPosition = 0;
 }
@@ -3030,14 +6202,17 @@ static void menu_action_setting_edit_bool(const char* pstr, bool* ptr)
 {
   *ptr = !(*ptr);
 }
+/*
 static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callback)
 {
   menu_action_setting_edit_bool(pstr, ptr);
   (*callback)();
 }
+*/
 #endif//ULTIPANEL
 
 /** LCD API **/
+
 void lcd_init()
 {
   lcd_implementation_init();
@@ -3097,23 +6272,51 @@ void lcd_init()
 //#include <avr/pgmspace.h>
 
 static volatile bool lcd_update_enabled = true;
+unsigned long lcd_timeoutToStatus = 0;
 
 void lcd_update_enable(bool enabled)
 {
-    lcd_update_enabled = enabled;
+    if (lcd_update_enabled != enabled) {
+        lcd_update_enabled = enabled;
+        if (enabled) {
+            // Reset encoder position. This is equivalent to re-entering a menu.
+            encoderPosition = 0;
+            encoderDiff = 0;
+            // Enabling the normal LCD update procedure.
+            // Reset the timeout interval.
+            lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+            // Force the keypad update now.
+            lcd_next_update_millis = millis() - 1;
+            // Full update.
+            lcd_implementation_clear();
+      #if defined(LCD_PROGRESS_BAR) && defined(SDSUPPORT)
+            lcd_set_custom_characters(currentMenu == lcd_status_screen);
+      #else
+            if (currentMenu == lcd_status_screen)
+                lcd_set_custom_characters_degree();
+            else
+                lcd_set_custom_characters_arrows();
+      #endif
+            lcd_update(2);
+        } else {
+            // Clear the LCD always, or let it to the caller?
+        }
+    }
 }
 
-void lcd_update()
+void lcd_update(uint8_t lcdDrawUpdateOverride)
 {
-	static unsigned long timeoutToStatus = 0;
 
-  if (! lcd_update_enabled)
-      return;
+	if (lcdDrawUpdate < lcdDrawUpdateOverride)
+		lcdDrawUpdate = lcdDrawUpdateOverride;
+
+	if (!lcd_update_enabled)
+		return;
 
 #ifdef LCD_HAS_SLOW_BUTTONS
   slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context
 #endif
-
+  
   lcd_buttons_update();
 
 #if (SDCARDDETECT > 0)
@@ -3131,6 +6334,7 @@ void lcd_update()
 	  {
 		  card.initsd();
 		  LCD_MESSAGERPGM(MSG_SD_INSERTED);
+		  //get_description();
 	  }
 	  else
 	  {
@@ -3142,6 +6346,13 @@ void lcd_update()
 
   if (lcd_next_update_millis < millis())
   {
+#ifdef DEBUG_BLINK_ACTIVE
+	static bool active_led = false;
+	active_led = !active_led;
+	pinMode(LED_PIN, OUTPUT);
+	digitalWrite(LED_PIN, active_led?HIGH:LOW);
+#endif //DEBUG_BLINK_ACTIVE
+
 #ifdef ULTIPANEL
 #ifdef REPRAPWORLD_KEYPAD
 	  if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) {
@@ -3168,13 +6379,14 @@ void lcd_update()
 #endif
 	  if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP)
 	  {
-		  lcdDrawUpdate = 1;
+      if (lcdDrawUpdate == 0)
+		    lcdDrawUpdate = 1;
 		  encoderPosition += encoderDiff / ENCODER_PULSES_PER_STEP;
 		  encoderDiff = 0;
-		  timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+		  lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
 	  }
-	  if (LCD_CLICKED)
-		  timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+
+	  if (LCD_CLICKED) lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
 #endif//ULTIPANEL
 
 #ifdef DOGLCD        // Changes due to different driver architecture of the DOGM display
@@ -3199,7 +6411,7 @@ void lcd_update()
 #endif
 
 #ifdef ULTIPANEL
-	  if (timeoutToStatus < millis() && currentMenu != lcd_status_screen)
+	  if (lcd_timeoutToStatus < millis() && currentMenu != lcd_status_screen)
 	  {
       // Exiting a menu. Let's call the menu function the last time with menuExiting flag set to true
       // to give it a chance to save its state.
@@ -3217,9 +6429,29 @@ void lcd_update()
 	  if (lcdDrawUpdate) lcdDrawUpdate--;
 	  lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL;
 	  }
-   
+	if (!SdFatUtil::test_stack_integrity()) stack_error();
+	lcd_ping(); //check that we have received ping command if we are in farm mode
+	if (lcd_commands_type == LCD_COMMAND_V2_CAL) lcd_commands();
 }
 
+void lcd_printer_connected() {
+	printer_connected = true;
+}
+
+void lcd_ping() { //chceck if printer is connected to monitoring when in farm mode
+	if (farm_mode) {
+		bool empty = is_buffer_empty();
+		if ((millis() - PingTime) * 0.001 > (empty ? PING_TIME : PING_TIME_LONG)) { //if commands buffer is empty use shorter time period
+																							  //if there are comamnds in buffer, some long gcodes can delay execution of ping command
+																							  //therefore longer period is used
+			printer_connected = false;
+			//lcd_ping_allert(); //acustic signals
+		}
+		else {
+			lcd_printer_connected();
+		}
+	}
+}
 void lcd_ignore_click(bool b)
 {
   ignore_click = b;
@@ -3273,6 +6505,10 @@ void lcd_reset_alert_level()
   lcd_status_message_level = 0;
 }
 
+uint8_t get_message_level()
+{
+	return lcd_status_message_level;
+}
 #ifdef DOGLCD
 void lcd_setcontrast(uint8_t value)
 {
@@ -3290,9 +6526,56 @@ void lcd_buttons_update()
   if (READ(BTN_EN1) == 0)  newbutton |= EN_A;
   if (READ(BTN_EN2) == 0)  newbutton |= EN_B;
 #if BTN_ENC > 0
-  if ((blocking_enc < millis()) && (READ(BTN_ENC) == 0))
-    newbutton |= EN_C;
-#endif
+  if (lcd_update_enabled == true) { //if we are in non-modal mode, long press can be used and short press triggers with button release
+	  if (READ(BTN_ENC) == 0) { //button is pressed	  
+		  lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+		  if (millis() > button_blanking_time) {
+			  button_blanking_time = millis() + BUTTON_BLANKING_TIME;
+			  if (button_pressed == false && long_press_active == false) {
+				  if (currentMenu != lcd_move_z) {
+					  savedMenu = currentMenu;
+					  savedEncoderPosition = encoderPosition;
+				  }
+				  long_press_timer = millis();
+				  button_pressed = true;
+			  }
+			  else {
+				  if (millis() - long_press_timer > LONG_PRESS_TIME) { //long press activated
+
+					  long_press_active = true;
+					  move_menu_scale = 1.0;
+					  lcd_goto_menu(lcd_move_z);
+				  }
+			  }
+		  }
+	  }
+	  else { //button not pressed
+		  if (button_pressed) { //button was released
+			  button_blanking_time = millis() + BUTTON_BLANKING_TIME;
+
+			  if (long_press_active == false) { //button released before long press gets activated
+				  if (currentMenu == lcd_move_z) {
+					  //return to previously active menu and previous encoder position
+					  lcd_goto_menu(savedMenu, savedEncoderPosition);					  
+				  }
+				  else {
+					  newbutton |= EN_C;
+				  }
+			  }
+			  else if (currentMenu == lcd_move_z) lcd_quick_feedback(); 
+			  //button_pressed is set back to false via lcd_quick_feedback function
+		  }
+		  else {			  
+			  long_press_active = false;
+		  }
+	  }
+  }
+  else { //we are in modal mode
+	  if (READ(BTN_ENC) == 0)
+		  newbutton |= EN_C; 
+  }
+  
+#endif  
   buttons = newbutton;
 #ifdef LCD_HAS_SLOW_BUTTONS
   buttons |= slow_buttons;
@@ -3382,7 +6665,9 @@ void lcd_buzz(long duration, uint16_t freq)
 
 bool lcd_clicked()
 {
-  return LCD_CLICKED;
+	bool clicked = LCD_CLICKED;
+	if(clicked) button_pressed = false;
+    return clicked;
 }
 #endif//ULTIPANEL
 
@@ -3671,6 +6956,7 @@ char *ftostr52(const float &x)
   return conv;
 }
 
+/*
 // Callback for after editing PID i value
 // grab the PID i value out of the temp variable; scale it; then update the PID driver
 void copy_and_scalePID_i()
@@ -3690,5 +6976,6 @@ void copy_and_scalePID_d()
   updatePID();
 #endif
 }
+*/
 
 #endif //ULTRA_LCD

+ 102 - 18
Firmware/ultralcd.h

@@ -6,7 +6,7 @@
 
 #ifdef ULTRA_LCD
 
-  void lcd_update();
+  void lcd_update(uint8_t lcdDrawUpdateOverride = 0);
   // Call with a false parameter to suppress the LCD update from various places like the planner or the temp control.
   void lcd_update_enable(bool enable);
   void lcd_init();
@@ -14,6 +14,7 @@
   void lcd_setstatuspgm(const char* message);
   void lcd_setalertstatuspgm(const char* message);
   void lcd_reset_alert_level();
+  uint8_t get_message_level();
   void lcd_adjust_z();
   void lcd_pick_babystep();
   void lcd_alright();
@@ -26,29 +27,44 @@
   void lcd_loading_color();
   void lcd_force_language_selection();
   void lcd_sdcard_stop();
+  void lcd_sdcard_pause();
+  void lcd_print_stop();
   void prusa_statistics(int _message);
   void lcd_confirm_print();
-  
+void lcd_mylang();
   bool lcd_detected(void);
 
-  static void lcd_selftest();
+  static void lcd_selftest_v();
+  static bool lcd_selftest();
   static bool lcd_selfcheck_endstops();
+
+#ifdef TMC2130
+  static void reset_crash_det(char axis);
+  static bool lcd_selfcheck_axis_sg(char axis);
+#endif //TMC2130
   static bool lcd_selfcheck_axis(int _axis, int _travel);
   static bool lcd_selfcheck_check_heater(bool _isbed);
   static int  lcd_selftest_screen(int _step, int _progress, int _progress_scale, bool _clear, int _delay);
   static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator);
+  static bool lcd_selftest_fan_dialog(int _fan);
   static void lcd_selftest_error(int _error_no, const char *_error_1, const char *_error_2);
-  static void lcd_menu_statistics();
+  void lcd_menu_statistics();
+  static bool lcd_selfcheck_pulleys(int axis);
+
+  extern const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines);
+  inline const char* lcd_display_message_fullscreen_P(const char *msg) 
+    { uint8_t nlines; return lcd_display_message_fullscreen_P(msg, nlines); }
 
-  extern void lcd_display_message_fullscreen_P(const char *msg);
   extern void lcd_wait_for_click();
   extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
   // 0: no, 1: yes, -1: timeouted
-  extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true);
-
+  extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);
+  extern int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);
   // Ask the user to move the Z axis up to the end stoppers and let
   // the user confirm that it has been done.
-  extern bool lcd_calibrate_z_end_stop_manual();
+  #ifndef TMC2130
+  extern bool lcd_calibrate_z_end_stop_manual(bool only_z);
+  #endif
   // Show the result of the calibration process on the LCD screen.
   extern void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask);
 
@@ -67,7 +83,7 @@
   #define LCD_ALERTMESSAGERPGM(x) lcd_setalertstatuspgm((x))
 
   #define LCD_UPDATE_INTERVAL 100
-  #define LCD_TIMEOUT_TO_STATUS 15000
+  #define LCD_TIMEOUT_TO_STATUS 30000
 
   #ifdef ULTIPANEL
   void lcd_buttons_update();
@@ -78,22 +94,32 @@
   #else
   FORCE_INLINE void lcd_buttons_update() {}
   #endif
-  extern int lcd_commands_type;
 
-  extern int plaPreheatHotendTemp;
-  extern int plaPreheatHPBTemp;
-  extern int plaPreheatFanSpeed;
 
-  extern int absPreheatHotendTemp;
-  extern int absPreheatHPBTemp;
-  extern int absPreheatFanSpeed;
+  // To be used in lcd_commands_type.
+  #define LCD_COMMAND_IDLE 0
+  #define LCD_COMMAND_LOAD_FILAMENT 1
+  #define LCD_COMMAND_STOP_PRINT 2
+  #define LCD_COMMAND_FARM_MODE_CONFIRM 4
+  #define LCD_COMMAND_LONG_PAUSE 5
+  #define LCD_COMMAND_LONG_PAUSE_RESUME 6
+  #define LCD_COMMAND_PID_EXTRUDER 7 
+  #define LCD_COMMAND_V2_CAL 8
+
+  extern unsigned long lcd_timeoutToStatus;
+  extern int lcd_commands_type;
   
-  extern bool farm_mode;
+  extern uint8_t farm_mode;
   extern int farm_no;
   extern int farm_timer;
   extern int farm_status;
 
+#ifdef SNMM
+  extern uint8_t snmm_extruder;
+#endif // SNMM
+
   extern bool cancel_heatup;
+  extern bool isPrintPaused;
   
   #ifdef FILAMENT_LCD_DISPLAY
         extern unsigned long message_millis;
@@ -191,4 +217,62 @@ extern void lcd_implementation_print_at(uint8_t x, uint8_t y, int i);
 extern void lcd_implementation_print(float f);
 extern void lcd_implementation_print_at(uint8_t x, uint8_t y, const char *str);
 
-#endif //ULTRALCD_H
+
+void change_extr(int extr);
+static void lcd_colorprint_change();
+static int get_ext_nr();
+static void extr_adj(int extruder);
+static void extr_adj_0();
+static void extr_adj_1();
+static void extr_adj_2();
+static void extr_adj_3();
+static void fil_load_menu();
+static void fil_unload_menu();
+static void extr_unload_0();
+static void extr_unload_1();
+static void extr_unload_2();
+static void extr_unload_3();
+static void lcd_disable_farm_mode();
+static void lcd_set_fan_check();
+void extr_unload_all(); 
+void extr_unload_used();
+void extr_unload();
+static char snmm_stop_print_menu();
+static float count_e(float layer_heigth, float extrusion_width, float extrusion_length);
+static void lcd_babystep_z();
+
+void stack_error();
+static void lcd_ping_allert();
+void lcd_printer_connected();
+void lcd_ping();
+
+void lcd_calibrate_extruder();
+void lcd_farm_sdcard_menu();
+
+//void getFileDescription(char *name, char *description);
+
+void lcd_farm_sdcard_menu_w();
+//void get_description();
+
+//void lcd_wait_for_cool_down();
+void adjust_bed_reset();
+void lcd_extr_cal_reset();
+
+union MenuData;
+
+void bowden_menu();
+char reset_menu();
+char choose_extruder_menu();
+
+void lcd_pinda_calibration_menu();
+void lcd_calibrate_pinda();
+void lcd_temp_calibration_set();
+
+void display_loading();
+
+void lcd_service_mode_show_result();
+
+void lcd_wizard();
+void lcd_wizard(int state);
+
+#endif //ULTRALCD_H

+ 184 - 46
Firmware/ultralcd_implementation_hitachi_HD44780.h

@@ -461,6 +461,35 @@ void lcd_set_custom_characters_arrows()
 
     lcd.createChar(1, arrdown);
 }
+
+void lcd_set_custom_characters_nextpage()
+ {
+
+  byte arrdown[8] = {
+    B00000,
+    B00000,
+    B10001,
+    B01010,
+    B00100,
+    B10001,
+    B01010,
+    B00100
+  }; 
+  
+  byte confirm[8] = {
+	  B00000,
+	  B00001,
+	  B00011,
+	  B10110,
+	  B11100,
+	  B01000,
+	  B00000
+  };
+
+    lcd.createChar(1, arrdown);
+	lcd.createChar(2, confirm);
+}
+
 void lcd_set_custom_characters_degree()
  {
   byte degree[8] = {
@@ -655,13 +684,24 @@ static void lcd_implementation_status_screen()
     lcd.print('/');
     lcd.print(itostr3left(tTarget));
     lcd_printPGM(PSTR(LCD_STR_DEGREE " "));
-    lcd.print("  ");
+    lcd_printPGM(PSTR("  "));
 
     //Print the Z coordinates
     lcd.setCursor(LCD_WIDTH - 8-2, 0);
-    lcd.print("  Z");
-    lcd.print(ftostr32sp(current_position[Z_AXIS] + 0.00001));
+#if 1
+    lcd_printPGM(PSTR("  Z"));
+    if (custom_message_type == 1) {
+        // In a bed calibration mode.
+        lcd_printPGM(PSTR("   --- "));
+    } else {
+        lcd.print(ftostr32sp(current_position[Z_AXIS] + 0.00001));
+        lcd.print(' ');
+    }
+#else
+    lcd_printPGM(PSTR(" Queue:"));
+    lcd.print(int(moves_planned()));
     lcd.print(' ');
+#endif
 
     //Print the Bedtemperature
     lcd.setCursor(0, 1);
@@ -672,18 +712,56 @@ static void lcd_implementation_status_screen()
     lcd.print('/');
     lcd.print(itostr3left(tTarget));
     lcd_printPGM(PSTR(LCD_STR_DEGREE " "));
-    lcd.print("  ");
+    lcd_printPGM(PSTR("  "));
 
+#if 1
     //Print Feedrate
     lcd.setCursor(LCD_WIDTH - 8-2, 1);
-    lcd.print("  ");
+    lcd_printPGM(PSTR("  "));
     lcd.print(LCD_STR_FEEDRATE[0]);
     lcd.print(itostr3(feedmultiply));
-    lcd.print('%');
-    lcd.print("     ");
+    lcd_printPGM(PSTR("%     "));
 
+	//lcd.setCursor(8, 0);
+	//lcd.print(itostr3(fan_speed[0]));
+	//lcd.setCursor(8, 1);
+	//lcd.print(itostr3(fan_speed[1]));
 
+#else
+    //Print Feedrate
+    lcd.setCursor(LCD_WIDTH - 8-2, 1);
+    lcd.print(LCD_STR_FEEDRATE[0]);
+    lcd.print(itostr3(feedmultiply));
+    lcd_printPGM(PSTR("%  Q"));
+    {
+      uint8_t queue = planner_queue_min();
+      if (queue < (BLOCK_BUFFER_SIZE >> 1)) {
+        lcd.print('!');
+      } else {
+        lcd.print((char)(queue / 10) + '0');
+        queue %= 10;
+      }
+      lcd.print((char)queue + '0');
+      planner_queue_min_reset();
+    }
+#endif
+	bool print_sd_status = true;
 	
+#ifdef PINDA_THERMISTOR
+//	if (farm_mode && (custom_message_type == 4))
+	if (false)
+	{
+		lcd.setCursor(0, 2);
+		lcd_printPGM(PSTR("P"));
+		lcd.print(ftostr3(current_temperature_pinda));
+		lcd_printPGM(PSTR(LCD_STR_DEGREE " "));
+		print_sd_status = false;
+	}
+#endif //PINDA_THERMISTOR
+
+
+if (print_sd_status)
+{
     //Print SD status
     lcd.setCursor(0, 2);
 	if (is_usb_printing)
@@ -711,41 +789,72 @@ static void lcd_implementation_status_screen()
 			lcd.print('%');
 		}
 	}
+}
+
+	// Farm number display
 	if (farm_mode)
 	{
-		lcd.print(" F");
+		lcd_printPGM(PSTR(" F"));
 		lcd.print(farm_no);
-		lcd.print("  ");
+		lcd_printPGM(PSTR("  "));
+        
+        // Beat display
+        lcd.setCursor(LCD_WIDTH - 1, 0);
+        if ( (millis() - kicktime) < 60000 ) {
+        
+            lcd_printPGM(PSTR("L"));
+        
+        }else{
+            lcd_printPGM(PSTR(" "));
+        }
+        
+	}
+	else {
+#ifdef SNMM
+		lcd_printPGM(PSTR(" E"));
+		lcd.print(get_ext_nr() + 1);
+
+#else
+		lcd.setCursor(LCD_WIDTH - 8 - 2, 2);
+		lcd_printPGM(PSTR(" "));
+#endif
 	}
 
+
+
     //Print time elapsed
-    lcd.setCursor(LCD_WIDTH - 8 -2, 2);
-    lcd.print("  ");
+    lcd.setCursor(LCD_WIDTH - 8 -1, 2);
+    lcd_printPGM(PSTR(" "));
     lcd.print(LCD_STR_CLOCK[0]);
     if(starttime != 0)
     {
-        uint16_t time = millis()/60000 - starttime/60000;
+		uint16_t time = millis() / 60000 - starttime / 60000;
         lcd.print(itostr2(time/60));
         lcd.print(':');
         lcd.print(itostr2(time%60));
     }else{
         lcd_printPGM(PSTR("--:--"));
     }
-    lcd.print("  ");
+    lcd_printPGM(PSTR("  "));
 
+#ifdef DEBUG_DISABLE_LCD_STATUS_LINE
+	return;
+#endif //DEBUG_DISABLE_LCD_STATUS_LINE
 
     //Print status line
     lcd.setCursor(0, 3);
 
+    // If heating in progress, set flag
 	if (heating_status != 0) { custom_message = true; }
 
+    // If printing from SD, show what we are printing
 	if ((IS_SD_PRINTING) && !custom_message)
 	{
 
       if(strcmp(longFilenameOLD, card.longFilename) != 0)
 	  {
         memset(longFilenameOLD,'\0',strlen(longFilenameOLD));
-        sprintf(longFilenameOLD, "%s", card.longFilename);
+        sprintf_P(longFilenameOLD, PSTR("%s"), card.longFilename);
         scrollstuff = 0;
       }
 
@@ -783,10 +892,13 @@ static void lcd_implementation_status_screen()
 
 
     }
+    // If not, check for other special events
 	else
 	{
+        
 		if (custom_message)
 		{
+            // If heating flag, show progress of heating.
 			if (heating_status != 0)
 			{
 				heating_status_counter++;
@@ -800,7 +912,7 @@ static void lcd_implementation_status_screen()
 				for (int dots = 0; dots < heating_status_counter; dots++)
 				{
 					lcd.setCursor(7 + dots, 3);
-					lcd_printPGM(PSTR("."));
+					lcd.print('.');
 				}
 
 				switch (heating_status)
@@ -831,16 +943,18 @@ static void lcd_implementation_status_screen()
 					break;
 				}
 			}
-
-			if (custom_message_type == 1)  //// Z calibration G80 mesh bed leveling
+            
+            // If mesh bed leveling in progress, show the status
+            
+			if (custom_message_type == 1)
 			{
 				if (custom_message_state > 10)
 				{
 					lcd.setCursor(0, 3);
-					lcd.print("                    ");
+					lcd_printPGM(PSTR("                    "));
 					lcd.setCursor(0, 3);
 					lcd_printPGM(MSG_HOMEYZ_PROGRESS);
-					lcd.print(" : ");
+					lcd_printPGM(PSTR(" : "));
 					lcd.print(custom_message_state-10);
 				}
 				else
@@ -852,34 +966,64 @@ static void lcd_implementation_status_screen()
 						custom_message = false;
 						custom_message_type = 0;
 					}
-					if (custom_message_state > 3 && custom_message_state < 10 )
+					if (custom_message_state > 3 && custom_message_state <= 10 )
 					{
 						lcd.setCursor(0, 3);
-						lcd.print("                   ");
+						lcd_printPGM(PSTR("                   "));
 						lcd.setCursor(0, 3);
 						lcd_printPGM(MSG_HOMEYZ_DONE);
 						custom_message_state--;
 					}
-					if (custom_message_state == 10)
-					{
-						lcd_printPGM(MSG_HOMEYZ_DONE);
-						custom_message_state = 9;
-					}
 				}
 
 			}
-
-			if (custom_message_type == 2)  //// load filament
+            // If loading filament, print status
+			if (custom_message_type == 2)
 			{
 				lcd.print(lcd_status_message);
 			}
+			// PID tuning in progress
+			if (custom_message_type == 3) {
+				lcd.print(lcd_status_message);
+				if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0) {
+					lcd.setCursor(10, 3);
+					lcd.print(itostr3(pid_cycle));
+					
+					lcd.print('/');
+					lcd.print(itostr3left(pid_number_of_cycles));
+				}
+			}
+			// PINDA temp calibration in progress
+			if (custom_message_type == 4) {
+				char progress[4];
+				lcd.setCursor(0, 3);
+				lcd_printPGM(MSG_TEMP_CALIBRATION);
+				lcd.setCursor(12, 3);
+				sprintf(progress, "%d/6", custom_message_state);
+				lcd.print(progress);
+			}
+			// temp compensation preheat
+			if (custom_message_type == 5) {
+				lcd.setCursor(0, 3);
+				lcd_printPGM(MSG_PINDA_PREHEAT);
+				if (custom_message_state <= PINDA_HEAT_T) {
+					lcd_printPGM(PSTR(": "));
+					lcd.print(custom_message_state); //seconds
+					lcd.print(' ');
+					
+				}
+			}
+
+
 		}
 	else
 		{
+            // Nothing special, print status message normally
 			lcd.print(lcd_status_message);
 		}
 	}
-
+    
+    // Fill the rest of line to have nice and clean output
     for(int fillspace = 0; fillspace<20;fillspace++)
 	{
       if((lcd_status_message[fillspace] > 31 ))
@@ -1061,21 +1205,12 @@ static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char*
 
     lcd.setCursor(0, row);
     lcd.print('>');
-    if (longFilename[0] != '\0')
-    {
-
-        filename = longFilename;
-        //longFilename[LCD_WIDTH-1] = '\0';
-    }
-
     int i = 1;
     int j = 0;
-    int inter = 0;
     char* longFilenameTMP = longFilename;
 
-    while( ((c = *longFilenameTMP) != '\0') && (inter == 0) )
+    while((c = *longFilenameTMP) != '\0')
     {
-
         lcd.setCursor(i, row);
         lcd.print(c);
         i++;
@@ -1083,20 +1218,23 @@ static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char*
         if(i==LCD_WIDTH){
           i=1;
           j++;
-          longFilenameTMP = longFilename;
-          longFilenameTMP = longFilenameTMP+j;
+          longFilenameTMP = longFilename + j;          
           n = LCD_WIDTH - 1;
-          for(int g = 0; ((g<300)&&(inter == 0)) ;g++){
+          for(int g = 0; g<300 ;g++){
+			  manage_heater();
             if(LCD_CLICKED || ( enc_dif != encoderDiff )){
-                
-            //  inter = 1;
+				longFilenameTMP = longFilename;
+				*(longFilenameTMP + LCD_WIDTH - 2) = '\0';
+				i = 1;
+				j = 0;
+				break;
             }else{
-              delay(1);
+				if (j == 1) delay(3);	//wait around 1.2 s to start scrolling text
+				delay(1);				//then scroll with redrawing every 300 ms 
             }
 
           }
         }
-
     }
     if(c!='\0'){
       lcd.setCursor(i, row);

+ 31 - 0
Firmware/uni_avr_rpi.h

@@ -0,0 +1,31 @@
+// unification for AVR and RPI
+#define __AVR
+
+#ifdef __AVR
+	//#include "Arduino.h"
+	#include "Marlin.h"
+	#define GPIO_INP(gpio) pinMode(gpio, INPUT)
+	#define GPIO_OUT(gpio) pinMode(gpio, OUTPUT)
+	#define GPIO_SET(gpio) digitalWrite(gpio, HIGH)
+	#define GPIO_CLR(gpio) digitalWrite(gpio, LOW)
+	#define GPIO_GET(gpio) (digitalRead(gpio) != LOW)
+	#define DELAY(delay) delayMicroseconds(delay)
+	#define PRINT MYSERIAL.print
+#endif //RC522_AVR
+
+#ifdef __RPI
+	#include <bcm2835.h>
+	#define GPIO_INP(gpio) bcm2835_gpio_fsel(gpio, BCM2835_GPIO_FSEL_INPT)
+	#define GPIO_OUT(gpio) bcm2835_gpio_fsel(gpio, BCM2835_GPIO_FSEL_OUTP)
+	#define GPIO_SET(gpio) bcm2835_gpio_write(gpio, HIGH)
+	#define GPIO_CLR(gpio) bcm2835_gpio_write(gpio, LOW)
+	#define GPIO_GET(gpio) (bcm2835_gpio_lev(gpio) != LOW)
+	#include <unistd.h>
+	#define DELAY(delay) usleep(delay)
+	#define PRINT(p) print(p)
+	#define DEC 10
+	#define HEX 16
+	void print(const char* pc) { printf("%s", pc); }
+	void print(int v) { printf("%d", v); }
+	void print(float v) { printf("%f", v); }
+#endif //RC522_RPI

+ 288 - 288
Firmware/util.cpp

@@ -1,288 +1,288 @@
-#include "Configuration.h"
-
-#include "ultralcd.h"
-#include "language.h"
-#include "util.h"
-
-// Allocate the version string in the program memory. Otherwise the string lands either on the stack or in the global RAM.
-const char FW_VERSION_STR[] PROGMEM = FW_version;
-
-const char* FW_VERSION_STR_P()
-{
-    return FW_VERSION_STR;
-}
-
-const char FW_PRUSA3D_MAGIC_STR[] PROGMEM = FW_PRUSA3D_MAGIC;
-
-const char* FW_PRUSA3D_MAGIC_STR_P()
-{
-    return FW_PRUSA3D_MAGIC_STR;
-}
-
-const char STR_REVISION_DEV  [] PROGMEM = "dev";
-const char STR_REVISION_ALPHA[] PROGMEM = "alpha";
-const char STR_REVISION_BETA [] PROGMEM = "beta";
-const char STR_REVISION_RC   [] PROGMEM = "rc";
-
-inline bool is_whitespace_or_nl(char c)
-{
-    return c == ' ' || c == '\t' || c == '\n' || c == 'r';
-}
-
-inline bool is_whitespace_or_nl_or_eol(char c)
-{
-    return c == 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r';
-}
-
-inline bool is_digit(char c)
-{
-    return c >= '0' && c <= '9';
-}
-
-// Parse a major.minor.revision version number.
-// Return true if valid.
-inline bool parse_version(const char *str, uint16_t version[4])
-{   
-#if 0
-    SERIAL_ECHOPGM("Parsing version string ");
-    SERIAL_ECHO(str);
-    SERIAL_ECHOLNPGM("");
-#endif
-
-    const char *major = str;
-    const char *p = str;
-    while (is_digit(*p)) ++ p;
-    if (*p != '.')
-        return false;
-    const char *minor = ++ p;
-    while (is_digit(*p)) ++ p;
-    if (*p != '.')
-        return false;
-    const char *rev = ++ p;
-    while (is_digit(*p)) ++ p;
-    if (! is_whitespace_or_nl_or_eol(*p) && *p != '-')
-        return false;
-
-    char *endptr = NULL;
-    version[0] = strtol(major, &endptr, 10);
-    if (endptr != minor - 1)
-        return false;
-    version[1] = strtol(minor, &endptr, 10);
-    if (endptr != rev - 1)
-        return false;
-    version[2] = strtol(rev, &endptr, 10);
-    if (endptr != p)
-        return false;
-
-    version[3] = FIRMWARE_REVISION_RELEASED;
-    if (*p ++ == '-') {
-        const char *q = p;
-        while (! is_whitespace_or_nl_or_eol(*q))
-            ++ q;
-        uint8_t n = q - p;
-        if (n == strlen_P(STR_REVISION_DEV) && strncmp_P(p, STR_REVISION_DEV, n) == 0)
-            version[3] = FIRMWARE_REVISION_DEV;
-        else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_P(p, STR_REVISION_ALPHA, n) == 0)
-            version[3] = FIRMWARE_REVISION_ALPHA;
-        else if (n == strlen_P(STR_REVISION_BETA) && strncmp_P(p, STR_REVISION_BETA, n) == 0)
-            version[3] = FIRMWARE_REVISION_BETA;
-        else if ((n == 2 || n == 3) && p[0] == 'r' && p[1] == 'c') {
-            if (n == 2)
-                version[3] = FIRMWARE_REVISION_RC;
-            else {
-                if (is_digit(p[2]))
-                    version[3] = FIRMWARE_REVISION_RC + p[2] - '1';
-                else
-                    return false;
-            }
-        } else
-            return false;
-    }
-
-#if 0
-    SERIAL_ECHOPGM("Version parsed, major: ");
-    SERIAL_ECHO(version[0]);
-    SERIAL_ECHOPGM(", minor: ");
-    SERIAL_ECHO(version[1]);
-    SERIAL_ECHOPGM(", revision: ");
-    SERIAL_ECHO(version[2]);
-    SERIAL_ECHOPGM(", flavor: ");
-    SERIAL_ECHO(version[3]);
-    SERIAL_ECHOLNPGM("");
-#endif
-    return true;
-}
-
-inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n)
-{
-    for (; n > 0; -- n, ++ p1, ++ p2) {
-        if (pgm_read_byte(p1) < pgm_read_byte(p2))
-            return -1;
-        if (pgm_read_byte(p1) > pgm_read_byte(p2))
-            return 1;
-        if (pgm_read_byte(p1) == 0)
-            return 0;
-    }
-    return 0;
-}
-
-// Parse a major.minor.revision version number.
-// Return true if valid.
-inline bool parse_version_P(const char *str, uint16_t version[4])
-{    
-#if 0
-    SERIAL_ECHOPGM("Parsing version string ");
-    SERIAL_ECHORPGM(str);
-    SERIAL_ECHOLNPGM("");
-#endif
-
-    const char *major = str;
-    const char *p = str;
-    while (is_digit(char(pgm_read_byte(p)))) ++ p;
-    if (pgm_read_byte(p) != '.')
-        return false;
-    const char *minor = ++ p;
-    while (is_digit(char(pgm_read_byte(p)))) ++ p;
-    if (pgm_read_byte(p) != '.')
-        return false;
-    const char *rev = ++ p;
-    while (is_digit(char(pgm_read_byte(p)))) ++ p;
-    if (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(p))) && pgm_read_byte(p) != '-')
-        return false;
-
-    char buf[5];
-    uint8_t n = minor - major - 1;
-    if (n > 4)
-        return false;
-    memcpy_P(buf, major, n); buf[n] = 0;
-    char *endptr = NULL;
-    version[0] = strtol(buf, &endptr, 10);
-    if (*endptr != 0)
-        return false;
-    n = rev - minor - 1;
-    if (n > 4)
-        return false;
-    memcpy_P(buf, minor, n); buf[n] = 0;
-    version[1] = strtol(buf, &endptr, 10);
-    if (*endptr != 0)
-        return false;
-    n = p - rev;
-    if (n > 4)
-        return false;
-    memcpy_P(buf, rev, n);
-    buf[n] = 0;
-    version[2] = strtol(buf, &endptr, 10);
-    if (*endptr != 0)
-        return false;
-
-    version[3] = FIRMWARE_REVISION_RELEASED;
-    if (pgm_read_byte(p ++) == '-') {
-        const char *q = p;
-        while (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(q))))
-            ++ q;
-        n = q - p;
-        if (n == strlen_P(STR_REVISION_DEV) && strncmp_PP(p, STR_REVISION_DEV, n) == 0)
-            version[3] = FIRMWARE_REVISION_DEV;
-        else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_PP(p, STR_REVISION_ALPHA, n) == 0)
-            version[3] = FIRMWARE_REVISION_ALPHA;
-        else if (n == strlen_P(STR_REVISION_BETA) && strncmp_PP(p, STR_REVISION_BETA, n) == 0)
-            version[3] = FIRMWARE_REVISION_BETA;
-        else if ((n == 2 || n == 3) && strncmp_PP(p, STR_REVISION_RC, 2) == 0) {
-            if (n == 2)
-                version[3] = FIRMWARE_REVISION_RC;
-            else {
-                p += 2;
-                if (is_digit(pgm_read_byte(p)))
-                    version[3] = FIRMWARE_REVISION_RC + pgm_read_byte(p) - '1';
-                else
-                    return false;
-            }
-        } else
-            return false;
-    }
-
-#if 0
-    SERIAL_ECHOPGM("Version parsed, major: ");
-    SERIAL_ECHO(version[0]);
-    SERIAL_ECHOPGM(", minor: ");
-    SERIAL_ECHO(version[1]);
-    SERIAL_ECHOPGM(", revision: ");
-    SERIAL_ECHO(version[2]);
-    SERIAL_ECHOPGM(", flavor: ");
-    SERIAL_ECHO(version[3]);
-    SERIAL_ECHOLNPGM("");
-#endif
-    return true;
-}
-
-// 1 - yes, 0 - false, -1 - error;
-inline int8_t is_provided_version_newer(const char *version_string)
-{
-    uint16_t ver_gcode[3], ver_current[3];
-    if (! parse_version(version_string, ver_gcode))
-        return -1;
-    if (! parse_version_P(FW_VERSION_STR, ver_current))
-        return 0; // this shall not happen
-    for (uint8_t i = 0; i < 3; ++ i)
-        if (ver_gcode[i] > ver_current[i])
-            return 1;
-    return 0;
-}
-
-bool show_upgrade_dialog_if_version_newer(const char *version_string)
-{
-    uint16_t ver_gcode[4], ver_current[4];
-    if (! parse_version(version_string, ver_gcode)) {
-//        SERIAL_PROTOCOLLNPGM("parse_version failed");
-        return false;
-    }
-    if (! parse_version_P(FW_VERSION_STR, ver_current)) {
-//        SERIAL_PROTOCOLLNPGM("parse_version_P failed");
-        return false; // this shall not happen
-    }
-//    SERIAL_PROTOCOLLNPGM("versions parsed");
-    bool upgrade = false;
-    for (uint8_t i = 0; i < 4; ++ i) {
-        if (ver_gcode[i] > ver_current[i]) {
-            upgrade = true;
-            break;
-        } else if (ver_gcode[i] < ver_current[i])
-            break;
-    }
-
-    if (upgrade) {
-        lcd_display_message_fullscreen_P(MSG_NEW_FIRMWARE_AVAILABLE);
-        lcd_print_at_PGM(0, 2, PSTR(""));
-        for (const char *c = version_string; ! is_whitespace_or_nl_or_eol(*c); ++ c)
-            lcd_implementation_write(*c);
-        lcd_print_at_PGM(0, 3, MSG_NEW_FIRMWARE_PLEASE_UPGRADE);
-        tone(BEEPER, 1000);
-        delay_keep_alive(50);
-        noTone(BEEPER);
-        delay_keep_alive(500);
-        tone(BEEPER, 1000);
-        delay_keep_alive(50);
-        noTone(BEEPER);
-        lcd_wait_for_click();
-        lcd_update_enable(true);
-        lcd_implementation_clear();
-        lcd_update();
-    }
-
-    // Succeeded.
-    return true;
-}
-
-void update_current_firmware_version_to_eeprom()
-{
-    for (int8_t i = 0; i < FW_PRUSA3D_MAGIC_LEN; ++ i)
-        eeprom_update_byte((uint8_t*)(EEPROM_FIRMWARE_PRUSA_MAGIC+i), pgm_read_byte(FW_PRUSA3D_MAGIC_STR+i));
-    uint16_t ver_current[4];
-    if (parse_version_P(FW_VERSION_STR, ver_current)) {
-        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MAJOR,    ver_current[0]);
-        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MINOR,    ver_current[1]);
-        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_REVISION, ver_current[2]);
-        // See FirmwareRevisionFlavorType for the definition of firmware flavors.
-        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR,   ver_current[3]);
-    }
-}
+#include "Configuration.h"
+
+#include "ultralcd.h"
+#include "language.h"
+#include "util.h"
+
+// Allocate the version string in the program memory. Otherwise the string lands either on the stack or in the global RAM.
+const char FW_VERSION_STR[] PROGMEM = FW_version;
+
+const char* FW_VERSION_STR_P()
+{
+    return FW_VERSION_STR;
+}
+
+const char FW_PRUSA3D_MAGIC_STR[] PROGMEM = FW_PRUSA3D_MAGIC;
+
+const char* FW_PRUSA3D_MAGIC_STR_P()
+{
+    return FW_PRUSA3D_MAGIC_STR;
+}
+
+const char STR_REVISION_DEV  [] PROGMEM = "dev";
+const char STR_REVISION_ALPHA[] PROGMEM = "alpha";
+const char STR_REVISION_BETA [] PROGMEM = "beta";
+const char STR_REVISION_RC   [] PROGMEM = "rc";
+
+inline bool is_whitespace_or_nl(char c)
+{
+    return c == ' ' || c == '\t' || c == '\n' || c == 'r';
+}
+
+inline bool is_whitespace_or_nl_or_eol(char c)
+{
+    return c == 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r';
+}
+
+inline bool is_digit(char c)
+{
+    return c >= '0' && c <= '9';
+}
+
+// Parse a major.minor.revision version number.
+// Return true if valid.
+inline bool parse_version(const char *str, uint16_t version[4])
+{   
+#if 0
+    SERIAL_ECHOPGM("Parsing version string ");
+    SERIAL_ECHO(str);
+    SERIAL_ECHOLNPGM("");
+#endif
+
+    const char *major = str;
+    const char *p = str;
+    while (is_digit(*p)) ++ p;
+    if (*p != '.')
+        return false;
+    const char *minor = ++ p;
+    while (is_digit(*p)) ++ p;
+    if (*p != '.')
+        return false;
+    const char *rev = ++ p;
+    while (is_digit(*p)) ++ p;
+    if (! is_whitespace_or_nl_or_eol(*p) && *p != '-')
+        return false;
+
+    char *endptr = NULL;
+    version[0] = strtol(major, &endptr, 10);
+    if (endptr != minor - 1)
+        return false;
+    version[1] = strtol(minor, &endptr, 10);
+    if (endptr != rev - 1)
+        return false;
+    version[2] = strtol(rev, &endptr, 10);
+    if (endptr != p)
+        return false;
+
+    version[3] = FIRMWARE_REVISION_RELEASED;
+    if (*p ++ == '-') {
+        const char *q = p;
+        while (! is_whitespace_or_nl_or_eol(*q))
+            ++ q;
+        uint8_t n = q - p;
+        if (n == strlen_P(STR_REVISION_DEV) && strncmp_P(p, STR_REVISION_DEV, n) == 0)
+            version[3] = FIRMWARE_REVISION_DEV;
+        else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_P(p, STR_REVISION_ALPHA, n) == 0)
+            version[3] = FIRMWARE_REVISION_ALPHA;
+        else if (n == strlen_P(STR_REVISION_BETA) && strncmp_P(p, STR_REVISION_BETA, n) == 0)
+            version[3] = FIRMWARE_REVISION_BETA;
+        else if ((n == 2 || n == 3) && p[0] == 'r' && p[1] == 'c') {
+            if (n == 2)
+                version[3] = FIRMWARE_REVISION_RC;
+            else {
+                if (is_digit(p[2]))
+                    version[3] = FIRMWARE_REVISION_RC + p[2] - '1';
+                else
+                    return false;
+            }
+        } else
+            return false;
+    }
+
+#if 0
+    SERIAL_ECHOPGM("Version parsed, major: ");
+    SERIAL_ECHO(version[0]);
+    SERIAL_ECHOPGM(", minor: ");
+    SERIAL_ECHO(version[1]);
+    SERIAL_ECHOPGM(", revision: ");
+    SERIAL_ECHO(version[2]);
+    SERIAL_ECHOPGM(", flavor: ");
+    SERIAL_ECHO(version[3]);
+    SERIAL_ECHOLNPGM("");
+#endif
+    return true;
+}
+
+inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n)
+{
+    for (; n > 0; -- n, ++ p1, ++ p2) {
+        if (pgm_read_byte(p1) < pgm_read_byte(p2))
+            return -1;
+        if (pgm_read_byte(p1) > pgm_read_byte(p2))
+            return 1;
+        if (pgm_read_byte(p1) == 0)
+            return 0;
+    }
+    return 0;
+}
+
+// Parse a major.minor.revision version number.
+// Return true if valid.
+inline bool parse_version_P(const char *str, uint16_t version[4])
+{    
+#if 0
+    SERIAL_ECHOPGM("Parsing version string ");
+    SERIAL_ECHORPGM(str);
+    SERIAL_ECHOLNPGM("");
+#endif
+
+    const char *major = str;
+    const char *p = str;
+    while (is_digit(char(pgm_read_byte(p)))) ++ p;
+    if (pgm_read_byte(p) != '.')
+        return false;
+    const char *minor = ++ p;
+    while (is_digit(char(pgm_read_byte(p)))) ++ p;
+    if (pgm_read_byte(p) != '.')
+        return false;
+    const char *rev = ++ p;
+    while (is_digit(char(pgm_read_byte(p)))) ++ p;
+    if (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(p))) && pgm_read_byte(p) != '-')
+        return false;
+
+    char buf[5];
+    uint8_t n = minor - major - 1;
+    if (n > 4)
+        return false;
+    memcpy_P(buf, major, n); buf[n] = 0;
+    char *endptr = NULL;
+    version[0] = strtol(buf, &endptr, 10);
+    if (*endptr != 0)
+        return false;
+    n = rev - minor - 1;
+    if (n > 4)
+        return false;
+    memcpy_P(buf, minor, n); buf[n] = 0;
+    version[1] = strtol(buf, &endptr, 10);
+    if (*endptr != 0)
+        return false;
+    n = p - rev;
+    if (n > 4)
+        return false;
+    memcpy_P(buf, rev, n);
+    buf[n] = 0;
+    version[2] = strtol(buf, &endptr, 10);
+    if (*endptr != 0)
+        return false;
+
+    version[3] = FIRMWARE_REVISION_RELEASED;
+    if (pgm_read_byte(p ++) == '-') {
+        const char *q = p;
+        while (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(q))))
+            ++ q;
+        n = q - p;
+        if (n == strlen_P(STR_REVISION_DEV) && strncmp_PP(p, STR_REVISION_DEV, n) == 0)
+            version[3] = FIRMWARE_REVISION_DEV;
+        else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_PP(p, STR_REVISION_ALPHA, n) == 0)
+            version[3] = FIRMWARE_REVISION_ALPHA;
+        else if (n == strlen_P(STR_REVISION_BETA) && strncmp_PP(p, STR_REVISION_BETA, n) == 0)
+            version[3] = FIRMWARE_REVISION_BETA;
+        else if ((n == 2 || n == 3) && strncmp_PP(p, STR_REVISION_RC, 2) == 0) {
+            if (n == 2)
+                version[3] = FIRMWARE_REVISION_RC;
+            else {
+                p += 2;
+                if (is_digit(pgm_read_byte(p)))
+                    version[3] = FIRMWARE_REVISION_RC + pgm_read_byte(p) - '1';
+                else
+                    return false;
+            }
+        } else
+            return false;
+    }
+
+#if 0
+    SERIAL_ECHOPGM("Version parsed, major: ");
+    SERIAL_ECHO(version[0]);
+    SERIAL_ECHOPGM(", minor: ");
+    SERIAL_ECHO(version[1]);
+    SERIAL_ECHOPGM(", revision: ");
+    SERIAL_ECHO(version[2]);
+    SERIAL_ECHOPGM(", flavor: ");
+    SERIAL_ECHO(version[3]);
+    SERIAL_ECHOLNPGM("");
+#endif
+    return true;
+}
+
+// 1 - yes, 0 - false, -1 - error;
+inline int8_t is_provided_version_newer(const char *version_string)
+{
+    uint16_t ver_gcode[3], ver_current[3];
+    if (! parse_version(version_string, ver_gcode))
+        return -1;
+    if (! parse_version_P(FW_VERSION_STR, ver_current))
+        return 0; // this shall not happen
+    for (uint8_t i = 0; i < 3; ++ i)
+        if (ver_gcode[i] > ver_current[i])
+            return 1;
+    return 0;
+}
+
+bool show_upgrade_dialog_if_version_newer(const char *version_string)
+{
+    uint16_t ver_gcode[4], ver_current[4];
+    if (! parse_version(version_string, ver_gcode)) {
+//        SERIAL_PROTOCOLLNPGM("parse_version failed");
+        return false;
+    }
+    if (! parse_version_P(FW_VERSION_STR, ver_current)) {
+//        SERIAL_PROTOCOLLNPGM("parse_version_P failed");
+        return false; // this shall not happen
+    }
+//    SERIAL_PROTOCOLLNPGM("versions parsed");
+    bool upgrade = false;
+    for (uint8_t i = 0; i < 4; ++ i) {
+        if (ver_gcode[i] > ver_current[i]) {
+            upgrade = true;
+            break;
+        } else if (ver_gcode[i] < ver_current[i])
+            break;
+    }
+
+    if (upgrade) {
+        lcd_display_message_fullscreen_P(MSG_NEW_FIRMWARE_AVAILABLE);
+        lcd_print_at_PGM(0, 2, PSTR(""));
+        for (const char *c = version_string; ! is_whitespace_or_nl_or_eol(*c); ++ c)
+            lcd_implementation_write(*c);
+        lcd_print_at_PGM(0, 3, MSG_NEW_FIRMWARE_PLEASE_UPGRADE);
+        tone(BEEPER, 1000);
+        delay_keep_alive(50);
+        noTone(BEEPER);
+        delay_keep_alive(500);
+        tone(BEEPER, 1000);
+        delay_keep_alive(50);
+        noTone(BEEPER);
+        lcd_wait_for_click();
+        lcd_update_enable(true);
+        lcd_implementation_clear();
+        lcd_update();
+    }
+
+    // Succeeded.
+    return true;
+}
+
+void update_current_firmware_version_to_eeprom()
+{
+    for (int8_t i = 0; i < FW_PRUSA3D_MAGIC_LEN; ++ i)
+        eeprom_update_byte((uint8_t*)(EEPROM_FIRMWARE_PRUSA_MAGIC+i), pgm_read_byte(FW_PRUSA3D_MAGIC_STR+i));
+    uint16_t ver_current[4];
+    if (parse_version_P(FW_VERSION_STR, ver_current)) {
+        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MAJOR,    ver_current[0]);
+        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MINOR,    ver_current[1]);
+        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_REVISION, ver_current[2]);
+        // See FirmwareRevisionFlavorType for the definition of firmware flavors.
+        eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR,   ver_current[3]);
+    }
+}

+ 35 - 24
Firmware/util.h

@@ -1,24 +1,35 @@
-#ifndef UTIL_H
-#define UTIL_H
-
-extern const char* FW_VERSION_STR_P();
-
-// Definition of a firmware flavor numerical values.
-enum FirmwareRevisionFlavorType
-{
-    FIRMWARE_REVISION_DEV = 0,
-    FIRMWARE_REVISION_ALPHA = 1,
-    FIRMWARE_REVISION_BETA = 2,
-    FIRMWARE_REVISION_RC,
-    FIRMWARE_REVISION_RC2,
-    FIRMWARE_REVISION_RC3,
-    FIRMWARE_REVISION_RC4,
-    FIRMWARE_REVISION_RC5,
-    FIRMWARE_REVISION_RELEASED = 127
-};
-
-extern bool show_upgrade_dialog_if_version_newer(const char *version_string);
-
-extern void update_current_firmware_version_to_eeprom();
-
-#endif /* UTIL_H */
+#ifndef UTIL_H
+#define UTIL_H
+
+extern const char* FW_VERSION_STR_P();
+
+// Definition of a firmware flavor numerical values.
+enum FirmwareRevisionFlavorType
+{
+    FIRMWARE_REVISION_DEV = 0,
+    FIRMWARE_REVISION_ALPHA = 1,
+    FIRMWARE_REVISION_BETA = 2,
+    FIRMWARE_REVISION_RC,
+    FIRMWARE_REVISION_RC2,
+    FIRMWARE_REVISION_RC3,
+    FIRMWARE_REVISION_RC4,
+    FIRMWARE_REVISION_RC5,
+    FIRMWARE_REVISION_RELEASED = 127
+};
+
+extern bool show_upgrade_dialog_if_version_newer(const char *version_string);
+
+extern void update_current_firmware_version_to_eeprom();
+
+
+
+inline int8_t eeprom_read_int8(unsigned char* addr) {
+	uint8_t v = eeprom_read_byte(addr);
+	return *reinterpret_cast<int8_t*>(&v);
+}
+
+inline void eeprom_update_int8(unsigned char* addr, int8_t v) {
+	eeprom_update_byte(addr, *reinterpret_cast<uint8_t*>(&v));
+}
+
+#endif /* UTIL_H */

+ 485 - 0
Firmware/variants/1_75mm_MK3-EINY03-E3Dv6full.h

@@ -0,0 +1,485 @@
+#ifndef CONFIGURATION_PRUSA_H
+#define CONFIGURATION_PRUSA_H
+
+/*------------------------------------
+ GENERAL SETTINGS
+ *------------------------------------*/
+
+// Printer revision
+#define FILAMENT_SIZE "1_75mm_MK3"
+#define NOZZLE_TYPE "E3Dv6full"
+
+// Developer flag
+#define DEVELOPER
+
+// Printer name
+#define CUSTOM_MENDEL_NAME "Prusa i3 MK3"
+
+// Electronics
+#define MOTHERBOARD BOARD_EINY_0_3a
+
+
+// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier)
+//#define E3D_PT100_EXTRUDER_WITH_AMP
+//#define E3D_PT100_EXTRUDER_NO_AMP
+//#define E3D_PT100_BED_WITH_AMP
+//#define E3D_PT100_BED_NO_AMP
+
+
+/*------------------------------------
+ AXIS SETTINGS
+ *------------------------------------*/
+
+// Steps per unit {X,Y,Z,E}
+//#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,140}
+#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,280} //Extruder motor changed back to 200step type
+
+// Endstop inverting
+const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+
+// Home position
+#define MANUAL_X_HOME_POS 0
+#define MANUAL_Y_HOME_POS -2.2
+#define MANUAL_Z_HOME_POS 0.2
+
+// Travel limits after homing
+#define X_MAX_POS 255
+#define X_MIN_POS 0
+#define Y_MAX_POS 210
+#define Y_MIN_POS -12 //orig -4
+#define Z_MAX_POS 210
+#define Z_MIN_POS 0.15
+
+// Canceled home position
+#define X_CANCEL_POS 50
+#define Y_CANCEL_POS 190
+
+//Pause print position
+#define X_PAUSE_POS 50
+#define Y_PAUSE_POS 190
+#define Z_PAUSE_LIFT 20
+
+#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E
+#define HOMING_FEEDRATE {3000, 3000, 800, 0}  // set the homing speeds (mm/min) // 3000 is also valid for stallGuard homing. Valid range: 2200 - 3000
+
+//#define DEFAULT_MAX_FEEDRATE          {400, 400, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_FEEDRATE          {500, 500, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_ACCELERATION      {1000, 1000, 200, 5000}    // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot.
+
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts
+
+#define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
+//#define MAX_SILENT_FEEDRATE           2700   // 
+
+#define Z_AXIS_ALWAYS_ON 1
+
+//DEBUG
+#if 0
+#define DEBUG_DCODES //D codes
+#define DEBUG_DISABLE_XMINLIMIT  //x min limit ignored
+#define DEBUG_DISABLE_XMAXLIMIT  //x max limit ignored
+#define DEBUG_DISABLE_YMINLIMIT  //y min limit ignored
+#define DEBUG_DISABLE_YMAXLIMIT  //y max limit ignored
+#define DEBUG_DISABLE_ZMINLIMIT  //z min limit ignored
+#define DEBUG_DISABLE_ZMAXLIMIT  //z max limit ignored
+#define DEBUG_DISABLE_STARTMSGS //no startup messages 
+#define DEBUG_DISABLE_MINTEMP   //mintemp error ignored
+#define DEBUG_DISABLE_SWLIMITS  //sw limits ignored
+#define DEBUG_DISABLE_LCD_STATUS_LINE  //empty four lcd line
+#define DEBUG_DISABLE_PREVENT_EXTRUDER //cold extrusion and long extrusion allowed
+#define DEBUG_DISABLE_PRUSA_STATISTICS //disable prusa_statistics() mesages
+//#define DEBUG_XSTEP_DUP_PIN 21   //duplicate x-step output to pin 21 (SCL on P3)
+//#define DEBUG_YSTEP_DUP_PIN 21   //duplicate y-step output to pin 21 (SCL on P3)
+//#define DEBUG_BLINK_ACTIVE
+#endif
+
+/*------------------------------------
+ TMC2130 default settings
+ *------------------------------------*/
+
+#define TMC2130_FCLK 12000000       // fclk = 12MHz
+
+#define TMC2130_USTEPS_XY   16        // microstep resolution for XY axes
+#define TMC2130_USTEPS_Z    16        // microstep resolution for Z axis
+#define TMC2130_USTEPS_E    32        // microstep resolution for E axis (increased from 16 to 32)
+#define TMC2130_INTPOL_XY   1         // extrapolate 256 for XY axes
+#define TMC2130_INTPOL_Z    1         // extrapolate 256 for Z axis
+#define TMC2130_INTPOL_E    1         // extrapolate 256 for E axis
+
+#define TMC2130_PWM_GRAD_X  4         // PWMCONF
+#define TMC2130_PWM_AMPL_X  200       // PWMCONF
+#define TMC2130_PWM_AUTO_X  1         // PWMCONF
+#define TMC2130_PWM_FREQ_X  2         // PWMCONF
+
+#define TMC2130_PWM_GRAD_Y  4         // PWMCONF
+#define TMC2130_PWM_AMPL_Y  210       // PWMCONF
+#define TMC2130_PWM_AUTO_Y  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Y  2         // PWMCONF
+
+/* //not used
+#define TMC2130_PWM_GRAD_Z  4         // PWMCONF
+#define TMC2130_PWM_AMPL_Z  200       // PWMCONF
+#define TMC2130_PWM_AUTO_Z  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Z  2         // PWMCONF
+#define TMC2130_PWM_GRAD_E  4         // PWMCONF
+#define TMC2130_PWM_AMPL_E  200       // PWMCONF
+#define TMC2130_PWM_AUTO_E  1         // PWMCONF
+#define TMC2130_PWM_FREQ_E  2         // PWMCONF
+*/
+
+//#define TMC2130_PWM_DIV   683         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_DIV   512         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_CLK   (2 * TMC2130_FCLK / TMC2130_PWM_DIV) // PWM frequency (23.4kHz, 35.1kHz, 46.9kHz, 58.5kHz for 12MHz fclk)
+
+#define TMC2130_TPWMTHRS  0         // TPWMTHRS - Sets the switching speed threshold based on TSTEP from stealthChop to spreadCycle mode
+#define TMC2130_THIGH     0         // THIGH - unused
+
+#define TMC2130_TCOOLTHRS 239       // TCOOLTHRS - coolstep treshold
+
+#define TMC2130_SG_HOMING       1     // stallguard homing
+//#define TMC2130_SG_HOMING_SW_XY  1    // stallguard "software" homing for XY axes
+#define TMC2130_SG_HOMING_SW_Z  1     // stallguard "software" homing for Z axis
+#define TMC2130_SG_THRS_X       0     // stallguard sensitivity for X axis
+#define TMC2130_SG_THRS_Y       0     // stallguard sensitivity for Y axis
+#define TMC2130_SG_THRS_Z       2     // stallguard sensitivity for Z axis
+#define TMC2130_SG_DELTA      128    // stallguard delta [usteps] (minimum usteps before stallguard readed - SW homing)
+
+//new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only)
+#define TMC2130_CURRENTS_H {3, 3, 5, 8}  // default holding currents for all axes
+#define TMC2130_CURRENTS_R {13, 18, 20, 22}  // default running currents for all axes
+
+//#define TMC2130_DEBUG
+//#define TMC2130_DEBUG_WR
+//#define TMC2130_DEBUG_RD
+
+
+/*------------------------------------
+ EXTRUDER SETTINGS
+ *------------------------------------*/
+
+// Mintemps
+#define HEATER_0_MINTEMP 15
+#define HEATER_1_MINTEMP 5
+#define HEATER_2_MINTEMP 5
+#define BED_MINTEMP 15
+
+// Maxtemps
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define HEATER_0_MAXTEMP 410
+#else
+#define HEATER_0_MAXTEMP 305
+#endif
+#define HEATER_1_MAXTEMP 305
+#define HEATER_2_MAXTEMP 305
+#define BED_MAXTEMP 150
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_Kp 21.70
+#define  DEFAULT_Ki 1.60
+#define  DEFAULT_Kd 73.76
+#else
+// Define PID constants for extruder
+//#define  DEFAULT_Kp 40.925
+//#define  DEFAULT_Ki 4.875
+//#define  DEFAULT_Kd 86.085
+#define  DEFAULT_Kp 16.13
+#define  DEFAULT_Ki 1.1625
+#define  DEFAULT_Kd 56.23
+#endif
+
+// Extrude mintemp
+#define EXTRUDE_MINTEMP 130
+
+// Extruder cooling fans
+#define EXTRUDER_0_AUTO_FAN_PIN   8
+#define EXTRUDER_1_AUTO_FAN_PIN   -1
+#define EXTRUDER_2_AUTO_FAN_PIN   -1
+#define EXTRUDER_AUTO_FAN_TEMPERATURE 50
+#define EXTRUDER_AUTO_FAN_SPEED   255  // == full speed
+
+
+
+/*------------------------------------
+ LOAD/UNLOAD FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Load filament commands
+#define LOAD_FILAMENT_0 "M83"
+#define LOAD_FILAMENT_1 "G1 E70 F400"
+#define LOAD_FILAMENT_2 "G1 E40 F100"
+
+// Unload filament commands
+#define UNLOAD_FILAMENT_0 "M83"
+#define UNLOAD_FILAMENT_1 "G1 E-80 F7000"
+
+/*------------------------------------
+ CHANGE FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Filament change configuration
+#define FILAMENTCHANGEENABLE
+#ifdef FILAMENTCHANGEENABLE
+#define FILAMENTCHANGE_XPOS 211
+#define FILAMENTCHANGE_YPOS 0
+#define FILAMENTCHANGE_ZADD 2
+#define FILAMENTCHANGE_FIRSTRETRACT -2
+#define FILAMENTCHANGE_FINALRETRACT -80
+
+#define FILAMENTCHANGE_FIRSTFEED 70
+#define FILAMENTCHANGE_FINALFEED 50
+#define FILAMENTCHANGE_RECFEED 5
+
+#define FILAMENTCHANGE_XYFEED 50
+#define FILAMENTCHANGE_EFEED 20
+#define FILAMENTCHANGE_RFEED 400
+#define FILAMENTCHANGE_EXFEED 2
+#define FILAMENTCHANGE_ZFEED 15
+
+#endif
+
+/*------------------------------------
+ ADDITIONAL FEATURES SETTINGS
+ *------------------------------------*/
+
+// Define Prusa filament runout sensor
+//#define FILAMENT_RUNOUT_SUPPORT
+
+#ifdef FILAMENT_RUNOUT_SUPPORT
+#define FILAMENT_RUNOUT_SENSOR 1
+#endif
+
+// temperature runaway
+//#define TEMP_RUNAWAY_BED_HYSTERESIS 5
+//#define TEMP_RUNAWAY_BED_TIMEOUT 360
+
+#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15
+#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45
+
+/*------------------------------------
+ MOTOR CURRENT SETTINGS
+ *------------------------------------*/
+
+// Motor Current setting for BIG RAMBo
+#define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A)
+#define DIGIPOT_MOTOR_CURRENT_LOUD {135,135,135,135,135}
+
+// Motor Current settings for RAMBo mini PWM value = MotorCurrentSetting * 255 / range
+#if MOTHERBOARD == 200 || MOTHERBOARD == 203 || MOTHERBOARD == 303 || MOTHERBOARD == 304 || MOTHERBOARD == 305
+#define MOTOR_CURRENT_PWM_RANGE 2000
+#define DEFAULT_PWM_MOTOR_CURRENT  {400, 750, 750} // {XY,Z,E}
+#define DEFAULT_PWM_MOTOR_CURRENT_LOUD  {400, 750, 750} // {XY,Z,E}
+#endif
+
+/*------------------------------------
+ BED SETTINGS
+ *------------------------------------*/
+
+// Define Mesh Bed Leveling system to enable it
+#define MESH_BED_LEVELING
+#ifdef MESH_BED_LEVELING
+
+#define MBL_Z_STEP 0.01
+
+// Mesh definitions
+#define MESH_MIN_X 35
+#define MESH_MAX_X 238
+#define MESH_MIN_Y 6
+#define MESH_MAX_Y 202
+
+// Mesh upsample definition
+#define MESH_NUM_X_POINTS 7
+#define MESH_NUM_Y_POINTS 7
+// Mesh measure definition
+#define MESH_MEAS_NUM_X_POINTS 3
+#define MESH_MEAS_NUM_Y_POINTS 3
+
+#define MESH_HOME_Z_CALIB 0.2
+#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc.
+
+#define X_PROBE_OFFSET_FROM_EXTRUDER 23     // Z probe to nozzle X offset: -left  +right
+#define Y_PROBE_OFFSET_FROM_EXTRUDER 9     // Z probe to nozzle Y offset: -front +behind
+#define Z_PROBE_OFFSET_FROM_EXTRUDER -0.4  // Z probe to nozzle Z offset: -below (always!)
+#endif
+
+// Bed Temperature Control
+// Select PID or bang-bang with PIDTEMPBED. If bang-bang, BED_LIMIT_SWITCHING will enable hysteresis
+//
+// Uncomment this to enable PID on the bed. It uses the same frequency PWM as the extruder.
+// If your PID_dT above is the default, and correct for your hardware/configuration, that means 7.689Hz,
+// which is fine for driving a square wave into a resistive load and does not significantly impact you FET heating.
+// This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W heater.
+// If your configuration is significantly different than this and you don't understand the issues involved, you probably
+// shouldn't use bed PID until someone else verifies your hardware works.
+// If this is enabled, find your own PID constants below.
+#define PIDTEMPBED
+//
+//#define BED_LIMIT_SWITCHING
+
+// This sets the max power delivered to the bed, and replaces the HEATER_BED_DUTY_CYCLE_DIVIDER option.
+// all forms of bed control obey this (PID, bang-bang, bang-bang with hysteresis)
+// setting this to anything other than 255 enables a form of PWM to the bed just like HEATER_BED_DUTY_CYCLE_DIVIDER did,
+// so you shouldn't use it unless you are OK with PWM on your bed.  (see the comment on enabling PIDTEMPBED)
+#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current
+
+// Bed temperature compensation settings
+#define BED_OFFSET 10
+#define BED_OFFSET_START 40
+#define BED_OFFSET_CENTER 50
+
+
+#ifdef PIDTEMPBED
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10)
+#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_bedKp 21.70
+#define  DEFAULT_bedKi 1.60
+#define  DEFAULT_bedKd 73.76
+#else
+#define  DEFAULT_bedKp 126.13
+#define  DEFAULT_bedKi 4.30
+#define  DEFAULT_bedKd 924.76
+#endif
+
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from pidautotune
+//    #define  DEFAULT_bedKp 97.1
+//    #define  DEFAULT_bedKi 1.41
+//    #define  DEFAULT_bedKd 1675.16
+
+// FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles.
+#endif // PIDTEMPBED
+
+
+/*-----------------------------------
+ PREHEAT SETTINGS
+ *------------------------------------*/
+
+#define PLA_PREHEAT_HOTEND_TEMP 215
+#define PLA_PREHEAT_HPB_TEMP 55
+#define PLA_PREHEAT_FAN_SPEED 0
+
+#define ABS_PREHEAT_HOTEND_TEMP 255
+#define ABS_PREHEAT_HPB_TEMP 100
+#define ABS_PREHEAT_FAN_SPEED 0
+
+#define HIPS_PREHEAT_HOTEND_TEMP 220
+#define HIPS_PREHEAT_HPB_TEMP 100
+#define HIPS_PREHEAT_FAN_SPEED 0
+
+#define PP_PREHEAT_HOTEND_TEMP 254
+#define PP_PREHEAT_HPB_TEMP 100
+#define PP_PREHEAT_FAN_SPEED 0
+
+#define PET_PREHEAT_HOTEND_TEMP 240
+#define PET_PREHEAT_HPB_TEMP 90
+#define PET_PREHEAT_FAN_SPEED 0
+
+#define FLEX_PREHEAT_HOTEND_TEMP 230
+#define FLEX_PREHEAT_HPB_TEMP 50
+#define FLEX_PREHEAT_FAN_SPEED 0
+
+/*------------------------------------
+ THERMISTORS SETTINGS
+ *------------------------------------*/
+
+//
+//--NORMAL IS 4.7kohm PULLUP!-- 1kohm pullup can be used on hotend sensor, using correct resistor and table
+//
+//// Temperature sensor settings:
+// -2 is thermocouple with MAX6675 (only for sensor 0)
+// -1 is thermocouple with AD595
+// 0 is not used
+// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
+// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
+// 3 is Mendel-parts thermistor (4.7k pullup)
+// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
+// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup)
+// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
+// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
+// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup)
+// 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup)
+// 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
+// 10 is 100k RS thermistor 198-961 (4.7k pullup)
+// 11 is 100k beta 3950 1% thermistor (4.7k pullup)
+// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed)
+// 13 is 100k Hisens 3950  1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE"
+// 20 is the PT100 circuit found in the Ultimainboard V2.x
+// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950
+//
+//    1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
+//                          (but gives greater accuracy and more stable PID)
+// 51 is 100k thermistor - EPCOS (1k pullup)
+// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
+// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup)
+//
+// 1047 is Pt1000 with 4k7 pullup
+// 1010 is Pt1000 with 1k pullup (non standard)
+// 147 is Pt100 with 4k7 pullup
+// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a
+// 247 is Pt100 with 4k7 pullup and PT100 Amplifier
+// 110 is Pt100 with 1k pullup (non standard)
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP)
+#define TEMP_SENSOR_0 247
+#elif defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define TEMP_SENSOR_0 148
+#else
+#define TEMP_SENSOR_0 5
+#endif
+#define TEMP_SENSOR_1 0
+#define TEMP_SENSOR_2 0
+#if defined(E3D_PT100_BED_WITH_AMP)
+#define TEMP_SENSOR_BED 247
+#elif defined(E3D_PT100_BED_NO_AMP)
+#define TEMP_SENSOR_BED 148
+#else
+#define TEMP_SENSOR_BED 1
+#endif
+#define TEMP_SENSOR_PINDA 1
+#define TEMP_SENSOR_AMBIENT 2000
+
+#define STACK_GUARD_TEST_VALUE 0xA2A2
+
+#define MAX_BED_TEMP_CALIBRATION 50
+#define MAX_HOTEND_TEMP_CALIBRATION 50
+
+#define MAX_E_STEPS_PER_UNIT 250
+#define MIN_E_STEPS_PER_UNIT 100
+
+#define Z_BABYSTEP_MIN -3999
+#define Z_BABYSTEP_MAX 0
+
+#define PINDA_PREHEAT_X 70
+#define PINDA_PREHEAT_Y -3
+#define PINDA_PREHEAT_Z 1
+#define PINDA_HEAT_T 120 //time in s
+
+#define PINDA_MIN_T 50
+#define PINDA_STEP_T 10
+#define PINDA_MAX_T 100
+
+#define PING_TIME 60 //time in s
+#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes
+#define PING_ALLERT_PERIOD 60 //time in s
+
+#define LONG_PRESS_TIME 1000 //time in ms for button long press
+#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release
+
+#define DEFAULT_PID_TEMP 210
+
+#define MIN_PRINT_FAN_SPEED 50
+
+#ifdef SNMM
+#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print
+#else
+#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print
+#endif
+
+#define UVLO_Z_AXIS_SHIFT 2
+
+#endif //__CONFIGURATION_PRUSA_H

+ 493 - 0
Firmware/variants/1_75mm_MK3-EINY04-E3Dv6full.h

@@ -0,0 +1,493 @@
+#ifndef CONFIGURATION_PRUSA_H
+#define CONFIGURATION_PRUSA_H
+
+/*------------------------------------
+ GENERAL SETTINGS
+ *------------------------------------*/
+
+// Printer revision
+#define FILAMENT_SIZE "1_75mm_MK3"
+#define NOZZLE_TYPE "E3Dv6full"
+
+// Developer flag
+#define DEVELOPER
+
+// Printer name
+#define CUSTOM_MENDEL_NAME "Prusa i3 MK3"
+
+// Electronics
+#define MOTHERBOARD BOARD_EINY_0_4a
+
+
+// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier)
+//#define E3D_PT100_EXTRUDER_WITH_AMP
+//#define E3D_PT100_EXTRUDER_NO_AMP
+//#define E3D_PT100_BED_WITH_AMP
+//#define E3D_PT100_BED_NO_AMP
+
+
+/*------------------------------------
+ AXIS SETTINGS
+ *------------------------------------*/
+
+// Steps per unit {X,Y,Z,E}
+//#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,140}
+#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,280}
+
+// Endstop inverting
+const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+
+// Home position
+#define MANUAL_X_HOME_POS 0
+#define MANUAL_Y_HOME_POS -2.2
+#define MANUAL_Z_HOME_POS 0.2
+
+// Travel limits after homing
+#define X_MAX_POS 255
+#define X_MIN_POS 0
+#define Y_MAX_POS 210
+#define Y_MIN_POS -12 //orig -4
+#define Z_MAX_POS 210
+#define Z_MIN_POS 0.15
+
+// Canceled home position
+#define X_CANCEL_POS 50
+#define Y_CANCEL_POS 190
+
+//Pause print position
+#define X_PAUSE_POS 50
+#define Y_PAUSE_POS 190
+#define Z_PAUSE_LIFT 20
+
+#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E
+#define HOMING_FEEDRATE {2500, 3000, 800, 0}  // set the homing speeds (mm/min) // 3000 is also valid for stallGuard homing. Valid range: 2200 - 3000
+
+//#define DEFAULT_MAX_FEEDRATE          {400, 400, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_FEEDRATE          {500, 500, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_ACCELERATION      {1000, 1000, 200, 5000}    // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot.
+
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts
+
+#define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
+//#define MAX_SILENT_FEEDRATE           2700   //
+
+#define Z_AXIS_ALWAYS_ON 1
+
+//DEBUG
+#define DEBUG_DCODES //D codes
+#if 0
+#define DEBUG_DISABLE_XMINLIMIT  //x min limit ignored
+#define DEBUG_DISABLE_XMAXLIMIT  //x max limit ignored
+#define DEBUG_DISABLE_YMINLIMIT  //y min limit ignored
+#define DEBUG_DISABLE_YMAXLIMIT  //y max limit ignored
+#define DEBUG_DISABLE_ZMINLIMIT  //z min limit ignored
+#define DEBUG_DISABLE_ZMAXLIMIT  //z max limit ignored
+#define DEBUG_DISABLE_STARTMSGS //no startup messages
+#define DEBUG_DISABLE_MINTEMP   //mintemp error ignored
+#define DEBUG_DISABLE_SWLIMITS  //sw limits ignored
+#define DEBUG_DISABLE_LCD_STATUS_LINE  //empty four lcd line
+#define DEBUG_DISABLE_PREVENT_EXTRUDER //cold extrusion and long extrusion allowed
+#define DEBUG_DISABLE_PRUSA_STATISTICS //disable prusa_statistics() mesages
+//#define DEBUG_XSTEP_DUP_PIN 21   //duplicate x-step output to pin 21 (SCL on P3)
+//#define DEBUG_YSTEP_DUP_PIN 21   //duplicate y-step output to pin 21 (SCL on P3)
+//#define DEBUG_BLINK_ACTIVE
+#endif
+
+/*------------------------------------
+ TMC2130 default settings
+ *------------------------------------*/
+
+#define TMC2130_FCLK 12000000       // fclk = 12MHz
+
+#define TMC2130_USTEPS_XY   16        // microstep resolution for XY axes
+#define TMC2130_USTEPS_Z    16        // microstep resolution for Z axis
+#define TMC2130_USTEPS_E    32        // microstep resolution for E axis
+#define TMC2130_INTPOL_XY   1         // extrapolate 256 for XY axes
+#define TMC2130_INTPOL_Z    1         // extrapolate 256 for Z axis
+#define TMC2130_INTPOL_E    1         // extrapolate 256 for E axis
+
+#define TMC2130_PWM_GRAD_X  4         // PWMCONF
+#define TMC2130_PWM_AMPL_X  200       // PWMCONF
+#define TMC2130_PWM_AUTO_X  1         // PWMCONF
+#define TMC2130_PWM_FREQ_X  2         // PWMCONF
+
+#define TMC2130_PWM_GRAD_Y  4         // PWMCONF
+#define TMC2130_PWM_AMPL_Y  215       // PWMCONF
+#define TMC2130_PWM_AUTO_Y  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Y  2         // PWMCONF
+
+/* //not used
+ #define TMC2130_PWM_GRAD_Z  4         // PWMCONF
+ #define TMC2130_PWM_AMPL_Z  200       // PWMCONF
+ #define TMC2130_PWM_AUTO_Z  1         // PWMCONF
+ #define TMC2130_PWM_FREQ_Z  2         // PWMCONF
+ #define TMC2130_PWM_GRAD_E  4         // PWMCONF
+ #define TMC2130_PWM_AMPL_E  200       // PWMCONF
+ #define TMC2130_PWM_AUTO_E  1         // PWMCONF
+ #define TMC2130_PWM_FREQ_E  2         // PWMCONF
+ */
+
+//#define TMC2130_PWM_DIV   683         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_DIV   512         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_CLK   (2 * TMC2130_FCLK / TMC2130_PWM_DIV) // PWM frequency (23.4kHz, 35.1kHz, 46.9kHz, 58.5kHz for 12MHz fclk)
+
+#define TMC2130_TPWMTHRS  0         // TPWMTHRS - Sets the switching speed threshold based on TSTEP from stealthChop to spreadCycle mode
+#define TMC2130_THIGH     0         // THIGH - unused
+
+#define TMC2130_TCOOLTHRS 500       // TCOOLTHRS - coolstep treshold
+
+#define TMC2130_SG_HOMING       1     // stallguard homing
+//#define TMC2130_SG_HOMING_SW_XY  1    // stallguard "software" homing for XY axes
+#define TMC2130_SG_HOMING_SW_Z  1     // stallguard "software" homing for Z axis
+#define TMC2130_SG_THRS_X       6     // stallguard sensitivity for X axis
+#define TMC2130_SG_THRS_Y       6     // stallguard sensitivity for Y axis
+#define TMC2130_SG_THRS_Z       3     // stallguard sensitivity for Z axis
+#define TMC2130_SG_DELTA      128    // stallguard delta [usteps] (minimum usteps before stallguard readed - SW homing)
+
+//new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only)
+#define TMC2130_CURRENTS_H {3, 3, 5, 8}  // default holding currents for all axes
+#define TMC2130_CURRENTS_R {13, 31, 20, 22}  // default running currents for all axes
+
+//#define TMC2130_DEBUG
+//#define TMC2130_DEBUG_WR
+//#define TMC2130_DEBUG_RD
+
+
+/*------------------------------------
+ EXTRUDER SETTINGS
+ *------------------------------------*/
+
+// Mintemps
+#define HEATER_0_MINTEMP 15
+#define HEATER_1_MINTEMP 5
+#define HEATER_2_MINTEMP 5
+#define BED_MINTEMP 15
+
+// Maxtemps
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define HEATER_0_MAXTEMP 410
+#else
+#define HEATER_0_MAXTEMP 305
+#endif
+#define HEATER_1_MAXTEMP 305
+#define HEATER_2_MAXTEMP 305
+#define BED_MAXTEMP 150
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_Kp 21.70
+#define  DEFAULT_Ki 1.60
+#define  DEFAULT_Kd 73.76
+#else
+// Define PID constants for extruder
+//#define  DEFAULT_Kp 40.925
+//#define  DEFAULT_Ki 4.875
+//#define  DEFAULT_Kd 86.085
+#define  DEFAULT_Kp 16.13
+#define  DEFAULT_Ki 1.1625
+#define  DEFAULT_Kd 56.23
+#endif
+
+// Extrude mintemp
+#define EXTRUDE_MINTEMP 130
+
+// Extruder cooling fans
+#define EXTRUDER_0_AUTO_FAN_PIN   8
+#define EXTRUDER_1_AUTO_FAN_PIN   -1
+#define EXTRUDER_2_AUTO_FAN_PIN   -1
+#define EXTRUDER_AUTO_FAN_TEMPERATURE 50
+#define EXTRUDER_AUTO_FAN_SPEED   255  // == full speed
+
+
+
+/*------------------------------------
+ LOAD/UNLOAD FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Load filament commands
+#define LOAD_FILAMENT_0 "M83"
+#define LOAD_FILAMENT_1 "G1 E70 F400"
+#define LOAD_FILAMENT_2 "G1 E40 F100"
+
+// Unload filament commands
+#define UNLOAD_FILAMENT_0 "M83"
+#define UNLOAD_FILAMENT_1 "G1 E-80 F7000"
+
+/*------------------------------------
+ CHANGE FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Filament change configuration
+#define FILAMENTCHANGEENABLE
+#ifdef FILAMENTCHANGEENABLE
+#define FILAMENTCHANGE_XPOS 211
+#define FILAMENTCHANGE_YPOS 0
+#define FILAMENTCHANGE_ZADD 2
+#define FILAMENTCHANGE_FIRSTRETRACT -2
+#define FILAMENTCHANGE_FINALRETRACT -80
+
+#define FILAMENTCHANGE_FIRSTFEED 70
+#define FILAMENTCHANGE_FINALFEED 50
+#define FILAMENTCHANGE_RECFEED 5
+
+#define FILAMENTCHANGE_XYFEED 50
+#define FILAMENTCHANGE_EFEED 20
+#define FILAMENTCHANGE_RFEED 400
+#define FILAMENTCHANGE_EXFEED 2
+#define FILAMENTCHANGE_ZFEED 15
+
+#endif
+
+/*------------------------------------
+ ADDITIONAL FEATURES SETTINGS
+ *------------------------------------*/
+
+// Define Prusa filament runout sensor
+//#define FILAMENT_RUNOUT_SUPPORT
+
+#ifdef FILAMENT_RUNOUT_SUPPORT
+#define FILAMENT_RUNOUT_SENSOR 1
+#endif
+
+// temperature runaway
+//#define TEMP_RUNAWAY_BED_HYSTERESIS 5
+//#define TEMP_RUNAWAY_BED_TIMEOUT 360
+
+#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15
+#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45
+
+/*------------------------------------
+ MOTOR CURRENT SETTINGS
+ *------------------------------------*/
+
+// Motor Current setting for BIG RAMBo
+#define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A)
+#define DIGIPOT_MOTOR_CURRENT_LOUD {135,135,135,135,135}
+
+// Motor Current settings for RAMBo mini PWM value = MotorCurrentSetting * 255 / range
+#if MOTHERBOARD == 200 || MOTHERBOARD == 203 || MOTHERBOARD == 303 || MOTHERBOARD == 304 || MOTHERBOARD == 305
+#define MOTOR_CURRENT_PWM_RANGE 2000
+#define DEFAULT_PWM_MOTOR_CURRENT  {400, 750, 750} // {XY,Z,E}
+#define DEFAULT_PWM_MOTOR_CURRENT_LOUD  {400, 750, 750} // {XY,Z,E}
+#endif
+
+/*------------------------------------
+ BED SETTINGS
+ *------------------------------------*/
+
+// Define Mesh Bed Leveling system to enable it
+#define MESH_BED_LEVELING
+#ifdef MESH_BED_LEVELING
+
+#define MBL_Z_STEP 0.01
+
+// Mesh definitions
+#define MESH_MIN_X 35
+#define MESH_MAX_X 238
+#define MESH_MIN_Y 6
+#define MESH_MAX_Y 202
+
+// Mesh upsample definition
+#define MESH_NUM_X_POINTS 7
+#define MESH_NUM_Y_POINTS 7
+// Mesh measure definition
+#define MESH_MEAS_NUM_X_POINTS 3
+#define MESH_MEAS_NUM_Y_POINTS 3
+
+#define MESH_HOME_Z_CALIB 0.2
+#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc.
+
+#define X_PROBE_OFFSET_FROM_EXTRUDER 23     // Z probe to nozzle X offset: -left  +right
+#define Y_PROBE_OFFSET_FROM_EXTRUDER 9     // Z probe to nozzle Y offset: -front +behind
+#define Z_PROBE_OFFSET_FROM_EXTRUDER -0.4  // Z probe to nozzle Z offset: -below (always!)
+#endif
+
+// Bed Temperature Control
+// Select PID or bang-bang with PIDTEMPBED. If bang-bang, BED_LIMIT_SWITCHING will enable hysteresis
+//
+// Uncomment this to enable PID on the bed. It uses the same frequency PWM as the extruder.
+// If your PID_dT above is the default, and correct for your hardware/configuration, that means 7.689Hz,
+// which is fine for driving a square wave into a resistive load and does not significantly impact you FET heating.
+// This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W heater.
+// If your configuration is significantly different than this and you don't understand the issues involved, you probably
+// shouldn't use bed PID until someone else verifies your hardware works.
+// If this is enabled, find your own PID constants below.
+#define PIDTEMPBED
+//
+//#define BED_LIMIT_SWITCHING
+
+// This sets the max power delivered to the bed, and replaces the HEATER_BED_DUTY_CYCLE_DIVIDER option.
+// all forms of bed control obey this (PID, bang-bang, bang-bang with hysteresis)
+// setting this to anything other than 255 enables a form of PWM to the bed just like HEATER_BED_DUTY_CYCLE_DIVIDER did,
+// so you shouldn't use it unless you are OK with PWM on your bed.  (see the comment on enabling PIDTEMPBED)
+#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current
+
+// Bed temperature compensation settings
+#define BED_OFFSET 10
+#define BED_OFFSET_START 40
+#define BED_OFFSET_CENTER 50
+
+
+#ifdef PIDTEMPBED
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10)
+#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_bedKp 21.70
+#define  DEFAULT_bedKi 1.60
+#define  DEFAULT_bedKd 73.76
+#else
+#define  DEFAULT_bedKp 126.13
+#define  DEFAULT_bedKi 4.30
+#define  DEFAULT_bedKd 924.76
+#endif
+
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from pidautotune
+//    #define  DEFAULT_bedKp 97.1
+//    #define  DEFAULT_bedKi 1.41
+//    #define  DEFAULT_bedKd 1675.16
+
+// FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles.
+#endif // PIDTEMPBED
+
+
+/*-----------------------------------
+ PREHEAT SETTINGS
+ *------------------------------------*/
+
+#define PLA_PREHEAT_HOTEND_TEMP 215
+#define PLA_PREHEAT_HPB_TEMP 55
+#define PLA_PREHEAT_FAN_SPEED 0
+
+#define ABS_PREHEAT_HOTEND_TEMP 255
+#define ABS_PREHEAT_HPB_TEMP 100
+#define ABS_PREHEAT_FAN_SPEED 0
+
+#define HIPS_PREHEAT_HOTEND_TEMP 220
+#define HIPS_PREHEAT_HPB_TEMP 100
+#define HIPS_PREHEAT_FAN_SPEED 0
+
+#define PP_PREHEAT_HOTEND_TEMP 254
+#define PP_PREHEAT_HPB_TEMP 100
+#define PP_PREHEAT_FAN_SPEED 0
+
+#define PET_PREHEAT_HOTEND_TEMP 240
+#define PET_PREHEAT_HPB_TEMP 90
+#define PET_PREHEAT_FAN_SPEED 0
+
+#define FLEX_PREHEAT_HOTEND_TEMP 230
+#define FLEX_PREHEAT_HPB_TEMP 50
+#define FLEX_PREHEAT_FAN_SPEED 0
+
+/*------------------------------------
+ THERMISTORS SETTINGS
+ *------------------------------------*/
+
+//
+//--NORMAL IS 4.7kohm PULLUP!-- 1kohm pullup can be used on hotend sensor, using correct resistor and table
+//
+//// Temperature sensor settings:
+// -2 is thermocouple with MAX6675 (only for sensor 0)
+// -1 is thermocouple with AD595
+// 0 is not used
+// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
+// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
+// 3 is Mendel-parts thermistor (4.7k pullup)
+// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
+// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup)
+// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
+// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
+// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup)
+// 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup)
+// 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
+// 10 is 100k RS thermistor 198-961 (4.7k pullup)
+// 11 is 100k beta 3950 1% thermistor (4.7k pullup)
+// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed)
+// 13 is 100k Hisens 3950  1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE"
+// 20 is the PT100 circuit found in the Ultimainboard V2.x
+// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950
+//
+//    1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
+//                          (but gives greater accuracy and more stable PID)
+// 51 is 100k thermistor - EPCOS (1k pullup)
+// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
+// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup)
+//
+// 1047 is Pt1000 with 4k7 pullup
+// 1010 is Pt1000 with 1k pullup (non standard)
+// 147 is Pt100 with 4k7 pullup
+// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a
+// 247 is Pt100 with 4k7 pullup and PT100 Amplifier
+// 110 is Pt100 with 1k pullup (non standard)
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP)
+#define TEMP_SENSOR_0 247
+#elif defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define TEMP_SENSOR_0 148
+#else
+#define TEMP_SENSOR_0 5
+#endif
+#define TEMP_SENSOR_1 0
+#define TEMP_SENSOR_2 0
+#if defined(E3D_PT100_BED_WITH_AMP)
+#define TEMP_SENSOR_BED 247
+#elif defined(E3D_PT100_BED_NO_AMP)
+#define TEMP_SENSOR_BED 148
+#else
+#define TEMP_SENSOR_BED 1
+#endif
+#define TEMP_SENSOR_PINDA 1
+#define TEMP_SENSOR_AMBIENT 2000
+
+#define STACK_GUARD_TEST_VALUE 0xA2A2
+
+#define MAX_BED_TEMP_CALIBRATION 50
+#define MAX_HOTEND_TEMP_CALIBRATION 50
+
+#define MAX_E_STEPS_PER_UNIT 250
+#define MIN_E_STEPS_PER_UNIT 100
+
+#define Z_BABYSTEP_MIN -3999
+#define Z_BABYSTEP_MAX 0
+
+#define PINDA_PREHEAT_X 70
+#define PINDA_PREHEAT_Y -3
+#define PINDA_PREHEAT_Z 1
+#define PINDA_HEAT_T 120 //time in s
+
+#define PINDA_MIN_T 50
+#define PINDA_STEP_T 10
+#define PINDA_MAX_T 100
+
+#define PING_TIME 60 //time in s
+#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes
+#define PING_ALLERT_PERIOD 60 //time in s
+
+#define LONG_PRESS_TIME 1000 //time in ms for button long press
+#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release
+
+#define DEFAULT_PID_TEMP 210
+
+#define MIN_PRINT_FAN_SPEED 75
+
+#ifdef SNMM
+#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print
+#else
+#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print
+#endif
+
+// How much shall the print head be lifted on power panic?
+// Ideally the Z axis will reach a zero phase of the stepper driver on power outage. To simplify this,
+// UVLO_Z_AXIS_SHIFT shall be an integer multiply of the stepper driver cycle, that is 4x full step.
+// For example, the Prusa i3 MK2 with 16 microsteps per full step has Z stepping of 400 microsteps per mm.
+// At 400 microsteps per mm, a full step lifts the Z axis by 0.04mm, and a stepper driver cycle is 0.16mm.
+// The following example, 12 * (4 * 16 / 400) = 12 * 0.16mm = 1.92mm.
+#define UVLO_Z_AXIS_SHIFT 1.92
+
+#define HEATBED_V2
+
+#endif //__CONFIGURATION_PRUSA_H

+ 512 - 0
Firmware/variants/1_75mm_MK3-EINY10a-E3Dv6full.h

@@ -0,0 +1,512 @@
+#ifndef CONFIGURATION_PRUSA_H
+#define CONFIGURATION_PRUSA_H
+
+/*------------------------------------
+ GENERAL SETTINGS
+ *------------------------------------*/
+
+// Printer revision
+#define FILAMENT_SIZE "1_75mm_MK3"
+#define NOZZLE_TYPE "E3Dv6full"
+
+// Developer flag
+#define DEVELOPER
+
+// Printer name
+#define CUSTOM_MENDEL_NAME "Prusa i3 MK3"
+
+// Electronics
+#define MOTHERBOARD BOARD_EINY_0_4a
+
+
+// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier)
+//#define E3D_PT100_EXTRUDER_WITH_AMP
+//#define E3D_PT100_EXTRUDER_NO_AMP
+//#define E3D_PT100_BED_WITH_AMP
+//#define E3D_PT100_BED_NO_AMP
+
+
+/*------------------------------------
+ AXIS SETTINGS
+ *------------------------------------*/
+
+// Steps per unit {X,Y,Z,E}
+//#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,140}
+//#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,280}
+#define DEFAULT_AXIS_STEPS_PER_UNIT   {100,100,3200/8,560}
+
+// Endstop inverting
+const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop.
+
+// Home position
+#define MANUAL_X_HOME_POS 0
+#define MANUAL_Y_HOME_POS -2.2
+#define MANUAL_Z_HOME_POS 0.2
+
+// Travel limits after homing
+#define X_MAX_POS 255
+#define X_MIN_POS 0
+#define Y_MAX_POS 210
+#define Y_MIN_POS -12 //orig -4
+#define Z_MAX_POS 210
+#define Z_MIN_POS 0.15
+
+// Canceled home position
+#define X_CANCEL_POS 50
+#define Y_CANCEL_POS 190
+
+//Pause print position
+#define X_PAUSE_POS 50
+#define Y_PAUSE_POS 190
+#define Z_PAUSE_LIFT 20
+
+#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E
+#define HOMING_FEEDRATE {2500, 3000, 800, 0}  // set the homing speeds (mm/min) // 3000 is also valid for stallGuard homing. Valid range: 2200 - 3000
+
+//#define DEFAULT_MAX_FEEDRATE          {400, 400, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_FEEDRATE          {500, 500, 12, 120}    // (mm/sec)
+#define DEFAULT_MAX_ACCELERATION      {1000, 1000, 200, 5000}    // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot.
+
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts
+
+#define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
+//#define MAX_SILENT_FEEDRATE           2700   // 
+
+#define Z_AXIS_ALWAYS_ON 1
+
+// Automatic recovery after crash is detected
+#define AUTOMATIC_RECOVERY_AFTER_CRASH
+
+//DEBUG
+#define DEBUG_DCODES //D codes
+#if 1
+//#define DEBUG_FSENSOR_LOG          //Reports fsensor status to serial
+//#define DEBUG_CRASHDET_COUNTERS  //Display crash-detection counters on LCD
+//#define DEBUG_RESUME_PRINT       //Resume/save print debug enable 
+//#define DEBUG_UVLO_AUTOMATIC_RECOVER // Power panic automatic recovery debug output 
+//#define DEBUG_DISABLE_XMINLIMIT  //x min limit ignored
+//#define DEBUG_DISABLE_XMAXLIMIT  //x max limit ignored
+//#define DEBUG_DISABLE_YMINLIMIT  //y min limit ignored
+//#define DEBUG_DISABLE_YMAXLIMIT  //y max limit ignored
+//#define DEBUG_DISABLE_ZMINLIMIT  //z min limit ignored
+//#define DEBUG_DISABLE_ZMAXLIMIT  //z max limit ignored
+#define DEBUG_DISABLE_STARTMSGS //no startup messages 
+//#define DEBUG_DISABLE_MINTEMP   //mintemp error ignored
+//#define DEBUG_DISABLE_SWLIMITS  //sw limits ignored
+//#define DEBUG_DISABLE_LCD_STATUS_LINE  //empty four lcd line
+//#define DEBUG_DISABLE_PREVENT_EXTRUDER //cold extrusion and long extrusion allowed
+#define DEBUG_DISABLE_PRUSA_STATISTICS //disable prusa_statistics() mesages
+//#define DEBUG_XSTEP_DUP_PIN 21   //duplicate x-step output to pin 21 (SCL on P3)
+//#define DEBUG_YSTEP_DUP_PIN 21   //duplicate y-step output to pin 21 (SCL on P3)
+//#define DEBUG_BLINK_ACTIVE
+#endif
+
+/*------------------------------------
+ TMC2130 default settings
+ *------------------------------------*/
+
+#define TMC2130_FCLK 12000000       // fclk = 12MHz
+
+#define TMC2130_USTEPS_XY   16        // microstep resolution for XY axes
+#define TMC2130_USTEPS_Z    16        // microstep resolution for Z axis
+#define TMC2130_USTEPS_E    64        // microstep resolution for E axis
+#define TMC2130_INTPOL_XY   1         // extrapolate 256 for XY axes
+#define TMC2130_INTPOL_Z    1         // extrapolate 256 for Z axis
+#define TMC2130_INTPOL_E    1         // extrapolate 256 for E axis
+
+#define TMC2130_PWM_GRAD_X  2         // PWMCONF
+#define TMC2130_PWM_AMPL_X  230       // PWMCONF
+#define TMC2130_PWM_AUTO_X  1         // PWMCONF
+#define TMC2130_PWM_FREQ_X  2         // PWMCONF
+
+#define TMC2130_PWM_GRAD_Y  2         // PWMCONF
+#define TMC2130_PWM_AMPL_Y  235       // PWMCONF
+#define TMC2130_PWM_AUTO_Y  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Y  2         // PWMCONF
+
+/* //not used
+#define TMC2130_PWM_GRAD_Z  4         // PWMCONF
+#define TMC2130_PWM_AMPL_Z  200       // PWMCONF
+#define TMC2130_PWM_AUTO_Z  1         // PWMCONF
+#define TMC2130_PWM_FREQ_Z  2         // PWMCONF
+#define TMC2130_PWM_GRAD_E  4         // PWMCONF
+#define TMC2130_PWM_AMPL_E  200       // PWMCONF
+#define TMC2130_PWM_AUTO_E  1         // PWMCONF
+#define TMC2130_PWM_FREQ_E  2         // PWMCONF
+*/
+
+//#define TMC2130_PWM_DIV   683         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_DIV   512         // PWM frequency divider (1024, 683, 512, 410)
+#define TMC2130_PWM_CLK   (2 * TMC2130_FCLK / TMC2130_PWM_DIV) // PWM frequency (23.4kHz, 35.1kHz, 46.9kHz, 58.5kHz for 12MHz fclk)
+
+#define TMC2130_TPWMTHRS  0         // TPWMTHRS - Sets the switching speed threshold based on TSTEP from stealthChop to spreadCycle mode
+#define TMC2130_THIGH     0         // THIGH - unused
+
+//#define TMC2130_TCOOLTHRS_X 450       // TCOOLTHRS - coolstep treshold
+//#define TMC2130_TCOOLTHRS_Y 450       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_X 430       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_Y 430       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_Z 500       // TCOOLTHRS - coolstep treshold
+#define TMC2130_TCOOLTHRS_E 500       // TCOOLTHRS - coolstep treshold
+
+#define TMC2130_SG_HOMING       1     // stallguard homing
+//#define TMC2130_SG_HOMING_SW_XY  1    // stallguard "software" homing for XY axes
+#define TMC2130_SG_HOMING_SW_Z  1     // stallguard "software" homing for Z axis
+#define TMC2130_SG_THRS_X       1     // stallguard sensitivity for X axis
+#define TMC2130_SG_THRS_Y       3     // stallguard sensitivity for Y axis
+#define TMC2130_SG_THRS_Z       3     // stallguard sensitivity for Z axis
+#define TMC2130_SG_THRS_E       3     // stallguard sensitivity for E axis
+#define TMC2130_SG_DELTA      128    // stallguard delta [usteps] (minimum usteps before stallguard readed - SW homing)
+
+//new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only)
+#define TMC2130_CURRENTS_H {3, 3, 20, 28}  // default holding currents for all axes
+#define TMC2130_CURRENTS_R {13, 20, 20, 28}  // default running currents for all axes
+
+//#define TMC2130_DEBUG
+//#define TMC2130_DEBUG_WR
+//#define TMC2130_DEBUG_RD
+
+
+/*------------------------------------
+ EXTRUDER SETTINGS
+ *------------------------------------*/
+
+// Mintemps
+#define HEATER_0_MINTEMP 15
+#define HEATER_1_MINTEMP 5
+#define HEATER_2_MINTEMP 5
+#define BED_MINTEMP 15
+
+// Maxtemps
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define HEATER_0_MAXTEMP 410
+#else
+#define HEATER_0_MAXTEMP 305
+#endif
+#define HEATER_1_MAXTEMP 305
+#define HEATER_2_MAXTEMP 305
+#define BED_MAXTEMP 150
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_Kp 21.70
+#define  DEFAULT_Ki 1.60
+#define  DEFAULT_Kd 73.76
+#else
+// Define PID constants for extruder
+//#define  DEFAULT_Kp 40.925
+//#define  DEFAULT_Ki 4.875
+//#define  DEFAULT_Kd 86.085
+#define  DEFAULT_Kp 16.13
+#define  DEFAULT_Ki 1.1625
+#define  DEFAULT_Kd 56.23
+#endif
+
+// Extrude mintemp
+#define EXTRUDE_MINTEMP 130
+
+// Extruder cooling fans
+#define EXTRUDER_0_AUTO_FAN_PIN   8
+#define EXTRUDER_1_AUTO_FAN_PIN   -1
+#define EXTRUDER_2_AUTO_FAN_PIN   -1
+#define EXTRUDER_AUTO_FAN_TEMPERATURE 50
+#define EXTRUDER_AUTO_FAN_SPEED   255  // == full speed
+
+
+
+/*------------------------------------
+ LOAD/UNLOAD FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Load filament commands
+#define LOAD_FILAMENT_0 "M83"
+#define LOAD_FILAMENT_1 "G1 E70 F400"
+#define LOAD_FILAMENT_2 "G1 E40 F100"
+
+// Unload filament commands
+#define UNLOAD_FILAMENT_0 "M83"
+#define UNLOAD_FILAMENT_1 "G1 E-80 F7000"
+
+/*------------------------------------
+ CHANGE FILAMENT SETTINGS
+ *------------------------------------*/
+
+// Filament change configuration
+#define FILAMENTCHANGEENABLE
+#ifdef FILAMENTCHANGEENABLE
+#define FILAMENTCHANGE_XPOS 211
+#define FILAMENTCHANGE_YPOS 0
+#define FILAMENTCHANGE_ZADD 2
+#define FILAMENTCHANGE_FIRSTRETRACT -2
+#define FILAMENTCHANGE_FINALRETRACT -80
+
+#define FILAMENTCHANGE_FIRSTFEED 70
+#define FILAMENTCHANGE_FINALFEED 50
+#define FILAMENTCHANGE_RECFEED 5
+
+#define FILAMENTCHANGE_XYFEED 50
+#define FILAMENTCHANGE_EFEED 20
+//#define FILAMENTCHANGE_RFEED 400
+#define FILAMENTCHANGE_RFEED 7000 / 60
+#define FILAMENTCHANGE_EXFEED 2
+#define FILAMENTCHANGE_ZFEED 15
+
+#endif
+
+/*------------------------------------
+ ADDITIONAL FEATURES SETTINGS
+ *------------------------------------*/
+
+// Define Prusa filament runout sensor
+//#define FILAMENT_RUNOUT_SUPPORT
+
+#ifdef FILAMENT_RUNOUT_SUPPORT
+#define FILAMENT_RUNOUT_SENSOR 1
+#endif
+
+// temperature runaway
+//#define TEMP_RUNAWAY_BED_HYSTERESIS 5
+//#define TEMP_RUNAWAY_BED_TIMEOUT 360
+
+#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15
+#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45
+
+/*------------------------------------
+ MOTOR CURRENT SETTINGS
+ *------------------------------------*/
+
+// Motor Current setting for BIG RAMBo
+#define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A)
+#define DIGIPOT_MOTOR_CURRENT_LOUD {135,135,135,135,135}
+
+// Motor Current settings for RAMBo mini PWM value = MotorCurrentSetting * 255 / range
+#if MOTHERBOARD == 200 || MOTHERBOARD == 203 || MOTHERBOARD == 303 || MOTHERBOARD == 304 || MOTHERBOARD == 305
+#define MOTOR_CURRENT_PWM_RANGE 2000
+#define DEFAULT_PWM_MOTOR_CURRENT  {400, 750, 750} // {XY,Z,E}
+#define DEFAULT_PWM_MOTOR_CURRENT_LOUD  {400, 750, 750} // {XY,Z,E}
+#endif
+
+/*------------------------------------
+ BED SETTINGS
+ *------------------------------------*/
+
+// Define Mesh Bed Leveling system to enable it
+#define MESH_BED_LEVELING
+#ifdef MESH_BED_LEVELING
+
+#define MBL_Z_STEP 0.01
+
+// Mesh definitions
+#define MESH_MIN_X 35
+#define MESH_MAX_X 238
+#define MESH_MIN_Y 6
+#define MESH_MAX_Y 202
+
+// Mesh upsample definition
+#define MESH_NUM_X_POINTS 7
+#define MESH_NUM_Y_POINTS 7
+// Mesh measure definition
+#define MESH_MEAS_NUM_X_POINTS 3
+#define MESH_MEAS_NUM_Y_POINTS 3
+
+#define MESH_HOME_Z_CALIB 0.2
+#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc.
+
+#define X_PROBE_OFFSET_FROM_EXTRUDER 23     // Z probe to nozzle X offset: -left  +right
+#define Y_PROBE_OFFSET_FROM_EXTRUDER 9     // Z probe to nozzle Y offset: -front +behind
+#define Z_PROBE_OFFSET_FROM_EXTRUDER -0.4  // Z probe to nozzle Z offset: -below (always!)
+#endif
+
+// Bed Temperature Control
+// Select PID or bang-bang with PIDTEMPBED. If bang-bang, BED_LIMIT_SWITCHING will enable hysteresis
+//
+// Uncomment this to enable PID on the bed. It uses the same frequency PWM as the extruder.
+// If your PID_dT above is the default, and correct for your hardware/configuration, that means 7.689Hz,
+// which is fine for driving a square wave into a resistive load and does not significantly impact you FET heating.
+// This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W heater.
+// If your configuration is significantly different than this and you don't understand the issues involved, you probably
+// shouldn't use bed PID until someone else verifies your hardware works.
+// If this is enabled, find your own PID constants below.
+#define PIDTEMPBED
+//
+//#define BED_LIMIT_SWITCHING
+
+// This sets the max power delivered to the bed, and replaces the HEATER_BED_DUTY_CYCLE_DIVIDER option.
+// all forms of bed control obey this (PID, bang-bang, bang-bang with hysteresis)
+// setting this to anything other than 255 enables a form of PWM to the bed just like HEATER_BED_DUTY_CYCLE_DIVIDER did,
+// so you shouldn't use it unless you are OK with PWM on your bed.  (see the comment on enabling PIDTEMPBED)
+#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current
+
+// Bed temperature compensation settings
+#define BED_OFFSET 10
+#define BED_OFFSET_START 40
+#define BED_OFFSET_CENTER 50
+
+
+#ifdef PIDTEMPBED
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10)
+#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP)
+// Define PID constants for extruder with PT100
+#define  DEFAULT_bedKp 21.70
+#define  DEFAULT_bedKi 1.60
+#define  DEFAULT_bedKd 73.76
+#else
+#define  DEFAULT_bedKp 126.13
+#define  DEFAULT_bedKi 4.30
+#define  DEFAULT_bedKd 924.76
+#endif
+
+//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
+//from pidautotune
+//    #define  DEFAULT_bedKp 97.1
+//    #define  DEFAULT_bedKi 1.41
+//    #define  DEFAULT_bedKd 1675.16
+
+// FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles.
+#endif // PIDTEMPBED
+
+
+/*-----------------------------------
+ PREHEAT SETTINGS
+ *------------------------------------*/
+
+#define PLA_PREHEAT_HOTEND_TEMP 215
+#define PLA_PREHEAT_HPB_TEMP 55
+#define PLA_PREHEAT_FAN_SPEED 0
+
+#define ABS_PREHEAT_HOTEND_TEMP 255
+#define ABS_PREHEAT_HPB_TEMP 100
+#define ABS_PREHEAT_FAN_SPEED 0
+
+#define HIPS_PREHEAT_HOTEND_TEMP 220
+#define HIPS_PREHEAT_HPB_TEMP 100
+#define HIPS_PREHEAT_FAN_SPEED 0
+
+#define PP_PREHEAT_HOTEND_TEMP 254
+#define PP_PREHEAT_HPB_TEMP 100
+#define PP_PREHEAT_FAN_SPEED 0
+
+#define PET_PREHEAT_HOTEND_TEMP 240
+#define PET_PREHEAT_HPB_TEMP 90
+#define PET_PREHEAT_FAN_SPEED 0
+
+#define FLEX_PREHEAT_HOTEND_TEMP 230
+#define FLEX_PREHEAT_HPB_TEMP 50
+#define FLEX_PREHEAT_FAN_SPEED 0
+
+/*------------------------------------
+ THERMISTORS SETTINGS
+ *------------------------------------*/
+
+//
+//--NORMAL IS 4.7kohm PULLUP!-- 1kohm pullup can be used on hotend sensor, using correct resistor and table
+//
+//// Temperature sensor settings:
+// -2 is thermocouple with MAX6675 (only for sensor 0)
+// -1 is thermocouple with AD595
+// 0 is not used
+// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
+// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
+// 3 is Mendel-parts thermistor (4.7k pullup)
+// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
+// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup)
+// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
+// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
+// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup)
+// 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup)
+// 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
+// 10 is 100k RS thermistor 198-961 (4.7k pullup)
+// 11 is 100k beta 3950 1% thermistor (4.7k pullup)
+// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed)
+// 13 is 100k Hisens 3950  1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE"
+// 20 is the PT100 circuit found in the Ultimainboard V2.x
+// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950
+//
+//    1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
+//                          (but gives greater accuracy and more stable PID)
+// 51 is 100k thermistor - EPCOS (1k pullup)
+// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
+// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup)
+//
+// 1047 is Pt1000 with 4k7 pullup
+// 1010 is Pt1000 with 1k pullup (non standard)
+// 147 is Pt100 with 4k7 pullup
+// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a
+// 247 is Pt100 with 4k7 pullup and PT100 Amplifier
+// 110 is Pt100 with 1k pullup (non standard)
+
+#if defined(E3D_PT100_EXTRUDER_WITH_AMP)
+#define TEMP_SENSOR_0 247
+#elif defined(E3D_PT100_EXTRUDER_NO_AMP)
+#define TEMP_SENSOR_0 148
+#else
+#define TEMP_SENSOR_0 5
+#endif
+#define TEMP_SENSOR_1 0
+#define TEMP_SENSOR_2 0
+#if defined(E3D_PT100_BED_WITH_AMP)
+#define TEMP_SENSOR_BED 247
+#elif defined(E3D_PT100_BED_NO_AMP)
+#define TEMP_SENSOR_BED 148
+#else
+#define TEMP_SENSOR_BED 1
+#endif
+#define TEMP_SENSOR_PINDA 1
+#define TEMP_SENSOR_AMBIENT 2000
+
+#define STACK_GUARD_TEST_VALUE 0xA2A2
+
+#define MAX_BED_TEMP_CALIBRATION 50
+#define MAX_HOTEND_TEMP_CALIBRATION 50
+
+#define MAX_E_STEPS_PER_UNIT 250
+#define MIN_E_STEPS_PER_UNIT 100
+
+#define Z_BABYSTEP_MIN -3999
+#define Z_BABYSTEP_MAX 0
+
+#define PINDA_PREHEAT_X 70
+#define PINDA_PREHEAT_Y -3
+#define PINDA_PREHEAT_Z 1
+#define PINDA_HEAT_T 120 //time in s
+
+#define PINDA_MIN_T 50
+#define PINDA_STEP_T 10
+#define PINDA_MAX_T 100
+
+#define PING_TIME 60 //time in s
+#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes
+#define PING_ALLERT_PERIOD 60 //time in s
+
+#define LONG_PRESS_TIME 1000 //time in ms for button long press
+#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release
+
+#define DEFAULT_PID_TEMP 210
+
+#define MIN_PRINT_FAN_SPEED 75
+
+#ifdef SNMM
+#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print
+#else
+#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print
+#endif
+
+// How much shall the print head be lifted on power panic?
+// Ideally the Z axis will reach a zero phase of the stepper driver on power outage. To simplify this,
+// UVLO_Z_AXIS_SHIFT shall be an integer multiply of the stepper driver cycle, that is 4x full step.
+// For example, the Prusa i3 MK2 with 16 microsteps per full step has Z stepping of 400 microsteps per mm.
+// At 400 microsteps per mm, a full step lifts the Z axis by 0.04mm, and a stepper driver cycle is 0.16mm.
+// The following example, 12 * (4 * 16 / 400) = 12 * 0.16mm = 1.92mm.
+#define UVLO_Z_AXIS_SHIFT 1.92
+// If power panic occured, and the current temperature is higher then target temperature before interrupt minus this offset, print will be recovered automatically. 
+#define AUTOMATIC_UVLO_BED_TEMP_OFFSET 5 
+
+#define HEATBED_V2
+
+//#define SUPPORT_VERBOSITY
+
+#endif //__CONFIGURATION_PRUSA_H

+ 5 - 5
README.md

@@ -1,10 +1,10 @@
-# Original Prusa i3 Plus Firmware
+# Original Prusa i3 MK2 Firmware
 
 ## General instructions
 
-Pre-compiled hex files for all printers by PRUSA RESEARCH are available in hex_files folder.
+Pre-compiled hex output on PRUSA RESEARCH site: http://prusa3d.com/downloads/firmware/
 
-Just clone the repo and flash it to the firmware
+Just download and flash it to the electronics
 
 
 ## Build instructions
@@ -19,11 +19,11 @@ Remove Liquid Crystal library from your arduino or rename it
 
 ### Step 3
 
-Install the arduino addon in root of this repo
+Install the arduino addon located in the root of this repo. Don't forget to install correct version!
 
 ### Step 4
 
-Copy one of the configuration from variants folder to the the Firmware folder
+Copy the configuration file matching your printer from variants folder to the the Firmware folder
 
 ### Step 5