2024-06-04 23:32:11 +02:00
|
|
|
export function Name() { return "Logitech G815 Lightsync"; }
|
|
|
|
export function VendorId() { return 0x046d; }
|
|
|
|
export function ProductId() { return 0xc33f; }
|
|
|
|
export function Publisher() { return "WhirlwindFX"; }
|
|
|
|
export function Documentation(){ return "troubleshooting/logitech"; }
|
|
|
|
export function Size() { return [22, 7]; }
|
|
|
|
export function DefaultPosition() {return [75, 70]; }
|
|
|
|
export function DefaultScale(){return 8.0;}
|
|
|
|
/* global
|
|
|
|
shutdownColor:readonly
|
|
|
|
LightingMode:readonly
|
|
|
|
forcedColor:readonly
|
|
|
|
*/
|
|
|
|
export function ControllableParameters(){
|
|
|
|
return [
|
|
|
|
{"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"},
|
|
|
|
{"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"},
|
|
|
|
{"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"},
|
|
|
|
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
const vLedNames = [
|
2024-06-04 23:34:50 +02:00
|
|
|
"Logo", "Brightness",
|
|
|
|
"Esc", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Print Screen", "Scroll Lock", "Pause Break", "MediaRewind", "MediaPlayPause", "MediaFastForward", "MediaStop",
|
|
|
|
"G1", "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-_", "=+", "Backspace", "Insert", "Home", "Page Up", "NumLock", "Num /", "Num *", "Num -",
|
|
|
|
"G2", "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", "End", "Page Down", "Num 7", "Num 8", "Num 9", "Num +",
|
|
|
|
"G3", "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "ISO_#", "Enter", "Num 4", "Num 5", "Num 6",
|
|
|
|
"G4", "Left Shift", "ISO_<", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", "Num 1", "Num 2", "Num 3", "Num Enter",
|
|
|
|
"G5", "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Right Win", "Menu", "Right Ctrl", "Left Arrow", "Down Arrow", "Right Arrow", "Num 0", "Num .",
|
2024-06-04 23:32:11 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
const vKeymap = [
|
|
|
|
|
2024-06-04 23:34:50 +02:00
|
|
|
213, 156,
|
|
|
|
41, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 168, 158, 160, 159,
|
|
|
|
183, 53, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 45, 46, 42, 73, 74, 75, 83, 84, 85, 86,
|
|
|
|
184, 43, 20, 26, 8, 21, 23, 28, 24, 12, 18, 19, 47, 48, 49, 76, 77, 78, 95, 96, 97, 87,
|
|
|
|
185, 57, 4, 22, 7, 9, 10, 11, 13, 14, 15, 51, 52, 50, 40, 92, 93, 94,
|
|
|
|
186, 225, 100, 29, 27, 6, 25, 5, 17, 16, 54, 55, 56, 229, 82, 89, 90, 91, 88,
|
|
|
|
187, 224, 227, 226, 44, 230, 231, 101, 228, 80, 81, 79, 98, 99,
|
2024-06-04 23:32:11 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
const vLedPositions = [
|
2024-06-04 23:34:50 +02:00
|
|
|
[0, 0], [10, 0],
|
|
|
|
[1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], [15, 1], [16, 1], [17, 1], [18, 1], [19, 1], [20, 1], [21, 1],
|
|
|
|
[0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [12, 2], [13, 2], [14, 2], [15, 2], [16, 2], [17, 2], [18, 2], [19, 2], [20, 2], [21, 2],
|
|
|
|
[0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [13, 3], [14, 3], [15, 3], [16, 3], [17, 3], [18, 3], [19, 3], [20, 3], [21, 3],
|
|
|
|
[0, 4], [1, 4], [2, 4], [3, 4], [4, 4], [5, 4], [6, 4], [7, 4], [8, 4], [9, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4], [18, 4], [19, 4], [20, 4],
|
|
|
|
[0, 5], [1, 5], [2, 5], [3, 5], [4, 5], [5, 5], [6, 5], [7, 5], [8, 5], [9, 5], [10, 5], [11, 5], [12, 5], [14, 5], [16, 5], [18, 5], [19, 5], [20, 5], [21, 5],
|
|
|
|
[0, 6], [1, 6], [2, 6], [3, 6], [7, 6], [11, 6], [12, 6], [13, 6], [14, 6], [15, 6], [16, 6], [17, 6], [18, 6], [20, 6],
|
2024-06-04 23:32:11 +02:00
|
|
|
];
|
|
|
|
const vGkeyPositions = [
|
|
|
|
[0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [2, 0], [3, 0], [4, 0], [5, 0]
|
|
|
|
];
|
|
|
|
const vLogoPositions = [
|
|
|
|
[0, 1], [3, 7]
|
|
|
|
];
|
|
|
|
export function LedNames() {
|
|
|
|
return vLedNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function LedPositions() {
|
|
|
|
return vLedPositions;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function Initialize() {
|
|
|
|
GKeySetup();
|
|
|
|
MKeySetup();
|
|
|
|
}
|
|
|
|
|
|
|
|
function GKeySetup()//Controls software modes for the G and M keys
|
|
|
|
{
|
|
|
|
device.set_endpoint(1, 0x0602, 0xff43); // System IF
|
|
|
|
|
|
|
|
let packet = [0x11, 0xFF, 0x08, 0x00]; //Info
|
|
|
|
device.write(packet, 20);
|
|
|
|
|
|
|
|
packet = [0x11, 0xFF, 0x08, 0x20, 0x01]; //Software Enable Flag for GKeys and Mkeys
|
|
|
|
device.write(packet, 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
function MKeySetup()//LED Control for the Mkey lights
|
|
|
|
{
|
|
|
|
|
|
|
|
let packet = [0x11, 0xFF, 0x09, 0x00]; //Probably Info
|
|
|
|
device.write(packet, 20);
|
|
|
|
|
|
|
|
packet = [0x11, 0xFF, 0x09, 0x10, 0x00]; //Led Number Flag in binary
|
|
|
|
device.write(packet, 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
function detectinputs() {
|
|
|
|
do {
|
|
|
|
let packet = [];
|
|
|
|
packet = device.read([0x00], 9, 2);
|
|
|
|
|
|
|
|
const input = processinputs(packet);
|
|
|
|
}
|
|
|
|
while(device.getLastReadSize() > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
function processinputs(packet) {
|
|
|
|
if(packet[0] == 0x11 && packet[1] == 0xff && packet[2] == 0x08)//G-Key Packet
|
|
|
|
{
|
|
|
|
if(packet[4] == 0x01) {
|
|
|
|
device.log("G1 Pressed");
|
|
|
|
|
|
|
|
return "G1";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x02) {
|
|
|
|
device.log("G2 Pressed");
|
|
|
|
|
|
|
|
return "G2";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x04) {
|
|
|
|
device.log("G3 Pressed");
|
|
|
|
|
|
|
|
return "G3";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x08) {
|
|
|
|
device.log("G4 Pressed");
|
|
|
|
|
|
|
|
return "G4";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x10) {
|
|
|
|
device.log("G5 Pressed");
|
|
|
|
|
|
|
|
return "G5";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x20) {
|
|
|
|
device.log("G6 Pressed");
|
|
|
|
|
|
|
|
return "G6";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x40) {
|
|
|
|
device.log("G7 Pressed");
|
|
|
|
|
|
|
|
return "G7";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x80) {
|
|
|
|
device.log("G8 Pressed");
|
|
|
|
|
|
|
|
return "G8";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[5] == 0x01) {
|
|
|
|
device.log("G9 Pressed");
|
|
|
|
|
|
|
|
return "G9";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[0] == 0x11 && packet[1] == 0xff && packet[2] == 0x09)//G-Key Packet
|
|
|
|
{
|
|
|
|
if(packet[4] == 0x01) {
|
|
|
|
device.log("M1 Pressed");
|
|
|
|
|
|
|
|
return "M1";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x02) {
|
|
|
|
device.log("M2 Pressed");
|
|
|
|
|
|
|
|
return "M2";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[4] == 0x04) {
|
|
|
|
device.log("M3 Pressed");
|
|
|
|
|
|
|
|
return "M3";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet[0] == 0x11 && packet[1] == 0xff && packet[2] == 0x0a && packet[4] == 0x01)//G-Key Packet
|
|
|
|
{
|
|
|
|
device.log("MR Pressed");
|
|
|
|
|
|
|
|
return "MR";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function Apply() {
|
|
|
|
const packet = [];
|
|
|
|
|
|
|
|
packet[0] = 0x11;
|
|
|
|
packet[1] = 0xFF;
|
|
|
|
packet[2] = 0x0F;
|
|
|
|
packet[3] = 0x5B;
|
|
|
|
|
|
|
|
device.set_endpoint(1, 0x0602, 0xff43); // System IF
|
|
|
|
device.write(packet, 20);
|
|
|
|
device.pause(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function SendGkeys(overrideColor) {
|
|
|
|
const packet = [];
|
|
|
|
packet[0] = 0x12;
|
|
|
|
packet[1] = 0xFF;
|
|
|
|
packet[2] = 0x0F;
|
|
|
|
packet[3] = 0x3F;
|
|
|
|
packet[4] = 0x00;
|
|
|
|
packet[5] = 4;
|
|
|
|
packet[6] = 0x00;
|
|
|
|
packet[7] = 9; // led count
|
|
|
|
|
|
|
|
for(let iIdx = 0; iIdx < vGkeyPositions.length; iIdx++){
|
|
|
|
const iLedIdx = (iIdx * 4) + 8;
|
|
|
|
const iKeyPosX = vGkeyPositions[iIdx][0];
|
|
|
|
const iKeyPosY = vGkeyPositions[iIdx][1];
|
|
|
|
var color;
|
|
|
|
|
|
|
|
if(overrideColor){
|
|
|
|
color = hexToRgb(overrideColor);
|
|
|
|
}else if (LightingMode === "Forced") {
|
|
|
|
color = hexToRgb(forcedColor);
|
|
|
|
}else{
|
|
|
|
color = device.color(iKeyPosX, iKeyPosY);
|
|
|
|
}
|
|
|
|
|
|
|
|
packet[iLedIdx] = iIdx;
|
|
|
|
packet[iLedIdx+1] = color[0];
|
|
|
|
packet[iLedIdx+2] = color[1];
|
|
|
|
packet[iLedIdx+3] = color[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
device.set_endpoint(1, 0x0604, 0xff43); // Lighting IF
|
|
|
|
device.write(packet, 64);
|
|
|
|
device.pause(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function SendLogoZones(overrideColor){
|
|
|
|
const packet = [];
|
|
|
|
packet[0] = 0x11;
|
|
|
|
packet[1] = 0xFF;
|
|
|
|
packet[2] = 0x0F;
|
|
|
|
packet[3] = 0x3D;
|
|
|
|
packet[4] = 0x00;
|
|
|
|
packet[5] = 0x10;
|
|
|
|
packet[6] = 0x00;
|
|
|
|
packet[7] = 0x02;
|
|
|
|
|
|
|
|
for(let iIdx = 0; iIdx < vLogoPositions.length; iIdx++){
|
|
|
|
const iLedIdx = (iIdx * 4) + 8;
|
|
|
|
const iKeyPosX = vLogoPositions[iIdx][0];
|
|
|
|
const iKeyPosY = vLogoPositions[iIdx][1];
|
|
|
|
var color;
|
|
|
|
|
|
|
|
if(overrideColor){
|
|
|
|
color = hexToRgb(overrideColor);
|
|
|
|
}else if (LightingMode === "Forced") {
|
|
|
|
color = hexToRgb(forcedColor);
|
|
|
|
}else{
|
|
|
|
color = device.color(iKeyPosX, iKeyPosY);
|
|
|
|
}
|
|
|
|
|
|
|
|
packet[iLedIdx] = iIdx+1;
|
|
|
|
packet[iLedIdx+1] = color[0];
|
|
|
|
packet[iLedIdx+2] = color[1];
|
|
|
|
packet[iLedIdx+3] = color[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
//device.set_endpoint(1, 0x0604, 0xff43); // Lighting IF
|
|
|
|
device.set_endpoint(1, 0x0602, 0xff43); // System IF
|
|
|
|
|
|
|
|
device.write(packet, 20);
|
|
|
|
device.pause(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function SendPacket(startIdx, count, overrideColor) {
|
|
|
|
const packet = [];
|
|
|
|
packet[0] = 0x12;
|
|
|
|
packet[1] = 0xFF;
|
|
|
|
packet[2] = 0x0F;
|
|
|
|
packet[3] = 0x3B;
|
|
|
|
packet[4] = 0x00;
|
|
|
|
packet[5] = 0x01; // zone?
|
|
|
|
packet[6] = 0x00;
|
|
|
|
packet[7] = count; // led count
|
|
|
|
|
|
|
|
for(let iIdx = 0; iIdx < count; iIdx++){
|
|
|
|
const iLedIdx = (iIdx * 4) + 8;
|
|
|
|
const iKeyIdx = startIdx + iIdx;
|
|
|
|
const iKeyPosX = vLedPositions[iKeyIdx][0];
|
|
|
|
const iKeyPosY = vLedPositions[iKeyIdx][1];
|
|
|
|
var color;
|
|
|
|
|
|
|
|
if(overrideColor){
|
|
|
|
color = hexToRgb(overrideColor);
|
|
|
|
}else if (LightingMode === "Forced") {
|
|
|
|
color = hexToRgb(forcedColor);
|
|
|
|
}else{
|
|
|
|
color = device.color(iKeyPosX, iKeyPosY);
|
|
|
|
}
|
|
|
|
|
|
|
|
packet[iLedIdx] = vKeymap[iKeyIdx];
|
|
|
|
packet[iLedIdx+1] = color[0];
|
|
|
|
packet[iLedIdx+2] = color[1];
|
|
|
|
packet[iLedIdx+3] = color[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
device.set_endpoint(1, 0x0604, 0xff43); // Lighting IF
|
|
|
|
device.write(packet, 64);
|
|
|
|
device.pause(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function Render() {
|
|
|
|
SendPacket(0, 14);
|
|
|
|
SendPacket(14, 14);
|
|
|
|
SendPacket(28, 14);
|
|
|
|
SendPacket(42, 14);
|
|
|
|
SendPacket(56, 14);
|
|
|
|
SendPacket(70, 14);
|
|
|
|
SendPacket(84, 14);
|
|
|
|
SendPacket(98, 9);
|
|
|
|
SendGkeys();
|
|
|
|
SendLogoZones();
|
|
|
|
Apply();
|
|
|
|
detectinputs();
|
|
|
|
device.pause(5);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function Shutdown(SystemSuspending) {
|
|
|
|
|
|
|
|
if(SystemSuspending){
|
|
|
|
SendPacket(0, 14, "#000000");
|
|
|
|
SendPacket(14, 14, "#000000");
|
|
|
|
SendPacket(28, 14, "#000000");
|
|
|
|
SendPacket(42, 14, "#000000");
|
|
|
|
SendPacket(56, 14, "#000000");
|
|
|
|
SendPacket(70, 14, "#000000");
|
|
|
|
SendPacket(84, 14, "#000000");
|
|
|
|
SendPacket(98, 9, "#000000");
|
|
|
|
SendGkeys("#000000");
|
|
|
|
SendLogoZones("#000000");
|
|
|
|
Apply(); // Go Dark on System Sleep/Shutdown
|
|
|
|
}else{
|
|
|
|
SendPacket(0, 14, shutdownColor);
|
|
|
|
SendPacket(14, 14, shutdownColor);
|
|
|
|
SendPacket(28, 14, shutdownColor);
|
|
|
|
SendPacket(42, 14, shutdownColor);
|
|
|
|
SendPacket(56, 14, shutdownColor);
|
|
|
|
SendPacket(70, 14, shutdownColor);
|
|
|
|
SendPacket(84, 14, shutdownColor);
|
|
|
|
SendPacket(98, 9, shutdownColor);
|
|
|
|
SendGkeys(shutdownColor);
|
|
|
|
SendLogoZones(shutdownColor);
|
|
|
|
Apply();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function hexToRgb(hex) {
|
|
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
|
|
const colors = [];
|
|
|
|
colors[0] = parseInt(result[1], 16);
|
|
|
|
colors[1] = parseInt(result[2], 16);
|
|
|
|
colors[2] = parseInt(result[3], 16);
|
|
|
|
|
|
|
|
return colors;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function Validate(endpoint) {
|
|
|
|
return (endpoint.interface === 1 && endpoint.usage === 0x0602) ||
|
|
|
|
(endpoint.interface === 1 && endpoint.usage === 0x0604);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function Image() {
|
|
|
|
return "iVBORw0KGgoAAAANSUhEUgAAA+gAAAH0CAYAAAHZLze7AAAACXBIWXMAAAsTAAALEwEAmpwYAAAGymlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDYgNzkuMTY0NjQ4LCAyMDIxLzAxLzEyLTE1OjUyOjI5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjIuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIxLTAyLTE2VDEwOjUxOjU1LTA4OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIxLTAyLTE2VDEwOjUxOjU1LTA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMS0wMi0xNlQxMDo1MTo1NS0wODowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowYTI0MDY5MS0xZjcwLTViNDQtOWI4Ni1iYzYwNzNmZjYwYjAiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDowYWYwYjQ2My04NGFhLWE2NDAtOWZkNS00ZWU1ODAxZDNlMDQiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2ZTQ1MmIxOC1iYzljLWNlNDctOGRkMi1mNTQ4N2ZhMTlkYjMiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2ZTQ1MmIxOC1iYzljLWNlNDctOGRkMi1mNTQ4N2ZhMTlkYjMiIHN0RXZ0OndoZW49IjIwMjEtMDItMTZUMTA6NTE6NTUtMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMi4yIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MGEyNDA2OTEtMWY3MC01YjQ0LTliODYtYmM2MDczZmY2MGIwIiBzdEV2dDp3aGVuPSIyMDIxLTAyLTE2VDEwOjUxOjU1LTA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjIuMiAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDxwaG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDxyZGY6QmFnPiA8cmRmOmxpPkE0REMyNDg0QzZCRDQzNjJDRjcxMTFBMzQ4QjA5NjJEPC9yZGY6bGk+IDxyZGY6bGk+QUU4REY0QjQ0NTU2NDMyRkM3REYxQzQxRkRBNDlCRjQ8L3JkZjpsaT4gPHJkZjpsaT5hZG9iZTpkb2NpZDpwaG90b3Nob3A6Yzg1ZTcwMDgtYzBmMi04OTQ2LTgzODQtZjk3YTc5NmY5YjllPC9yZGY6bGk+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+130gIQAG9kxJREFUeJzsvXeYJcV59v2r6u4T5kxOG9gc2CWIHETOsIBEECAksCRQQgJlWbKtYMmyZcmyJMDKmRxEzhmWHJe0gWVz3p0czpkTuqvq+f6onoEXS69tRhbX++0+1zXsDCf16ap68nPfSkTYIduX6Hf6AnbIX192LPp2KDsWfTuUHYu+HcqORd8OZceib4eyY9G3Q9mx6Nuh7Fj07VDCt/tCpdTYr+nPn33qf/H4//Vj8Bvzf/J69ZZ//9z/13/meaMigEt//m9py//uY//Te/Cn3nf0muzo428no/q2Fx3/JZqAWUADf/omKiAAMvz3vvRbn6OB6H94naObTL/l/735sdHr+nOaTuFvapL+wH9eBPkz///NMro4o5/35vf+r2T0taM/o59VA9YBK950bf8jGc+ih8D+f/ORC+5u7+wMAcIwwiYWFYA4QSmF0wpnDYigUDgtKAcO5XepAxm99VZwaBQOqwSxQLqTRcR/cytYnF9FBU5ACeAEpwWN4v51MeUFFxFGAVGgqeoIULhUOykAcYhoQg2OAAkixAqoAKmUCIa7OW39dTgtRCrkqUmnMvnVaznusPmYxLBm9UYU8NTTTxAGAbVqgpWEY44+BiUah+Lee+4mX5dFa0diHQuOP4nFS15mxfJ1EGi0FozzWjMbhmit0UFIGAaEWqN1SKA1BAEasCrD4QfswU/+4/tfAoaBjW934d6u5ICpOghCpeCVV5YRRQGVJMHYBLGOUqVCYy7HQKkISjj2yKO48g9X875TT8VYYdKkTtZt3MjmrVtoa2xh3pxZbOvrwxhDJszS1tbMs88vIghCWpuaaZ7QhuCPjBOHQ6H8vvFnVhQWxbEzMjx8+ZfRyj8QqbeqH4VTDiVvbAKXbipRitBays5i3r0bWhQucKwfyXDRSQcwd9e5LH5+EQ5QxrH/3vuRb5mCTgYZHuoFp0AJQaB49yGHMXPqFPqlmUxlLdZa1q9bz2cuuoCVs8+k9dlfsXjlevZ713yKqoNGeslkAvY8//M8dOdK2rvvJpuLGJg4F715K0nXaxgCPvyRi354xeU/ewzYxH9Pa/wfot5ulU0p1Qp88LyPXvTThuZm3v+xT3H2yQv47j99lfseXEhGa8449xw++fEL+cM1V/G7n/+StpZmSsPD7LnXfozEg/zy57/l4EMOZ968+WRC4Ve/+A0f/MA5nHDoSXzsy5/EVst84CPfZP/dd+OHF3+JuTvPpdDUiFZeNYizoDRWZGxRRQQRQYvzfyuN0grnFEH6OMqBpM9VCoVCKU2Iw6IRMYholFKEoaZ/uEJzfYYok8E4Q6hDjHMoJ0gS46wFFEEYosKIQIEONdVyhUAEggCFI8rmyWQylEvD/h5qwX8FhTWCaItLwLoE57w2S4zBWm/KtQqYNGky3f39XHflrw4HnpC3sYDjOelB+kMuE3HOKSeDCP/4zz/EWEN7YyOPPPZZwjDgwo9+lCQ2nHLKSSgMR8w+loUrH0clhmkdE4k3adRMC9ay3/4fZv89Z2FMjHOWQ3Y7icagAacckvpVQnq8NYhYQjQWQZzgRNDKLzZYjHVopxAUVhx61LQKIA4VaERAlCMWh4gjEEFCQYljYLiItpZisYpCE2qFUxCiEQQdakQUkQJjEpQ1mNSU6TDA/waCplouUY0jdLpJRUYvQ+FEwA
|
|
|
|
}
|