This commit is contained in:
e2002
2022-04-11 13:18:33 +03:00
parent 520b3455d1
commit b840b4418a
41 changed files with 661 additions and 1131 deletions

View File

@@ -47,7 +47,7 @@ You can connect one or two encoders to replace/complete the buttons. One encoder
- ENCODER2\ - ENCODER2\
rotate left: (ENC2_BTNL) if not pressed - switch to PLAYLIST mode and move up, if pressed - volume down\ rotate left: (ENC2_BTNL) if not pressed - switch to PLAYLIST mode and move up, if pressed - volume down\
rotate right: (ENC2_BTNR) if not pressed - switch to PLAYLIST mode and move down, if pressed - volume up\ rotate right: (ENC2_BTNR) if not pressed - switch to PLAYLIST mode and move down, if pressed - volume up\
click, dblclick: (ENC2_BTNB) same as BTN_CENTER click, dblclick: (ENC2_BTNB) toggle between PLAYER/VOLUME mode
--- ---
### IR receiver ### IR receiver

View File

@@ -281,8 +281,15 @@ Work is in progress...
--- ---
## Version history ## Version history
#### v0.6.121 #### v0.6.200
- fixed compiling error with DSP_GC9106 option - please backup your playlist and wifi settings before updating (export)
- accelerated displays up to ~30fps (everything except LCD)
- corrections/additions in the WEB interface (a [full update](#update) is required)
- rewrote [plugin example](https://github.com/e2002/yoradio/blob/main/exsamples/displayhandlers.ino)
- fixed compilation errors on macOS
- changed the logic of the second encoder (switching to the volume control mode by double click)
- optimization, bug fixes
- probably some other things that I forgot about %)
#### v0.6.120 #### v0.6.120
- added support for GC9106 160x80 SPI displays - added support for GC9106 160x80 SPI displays

View File

@@ -5,23 +5,19 @@
**************************************************************/ **************************************************************/
#if DSP_MODEL==DSP_ST7735 #if (DSP_MODEL==DSP_ST7735) || (DSP_MODEL==DSP_ST7789) || (DSP_MODEL==DSP_SSD1327) || (DSP_MODEL==DSP_ILI9341)
// 3600s = 60 minutes to not flooding
#define WEATHER_REQUEST_INTERVAL 3600 // 60min
#include <JSON_Decoder.h> // https://github.com/Bodmer/OpenWeather #define WEATHER_REQUEST_INTERVAL 1800 //30min
#include <OpenWeather.h> // https://github.com/Bodmer/JSON_Decoder #define WEATHER_REQUEST_INTERVAL_FAULTY 30
#include <WiFiClient.h>
#include <Ticker.h> #include <Ticker.h>
String api_key = "********************************"; // openweathermap.org API key const char* host = "api.openweathermap.org";
const char* lat = "55.7512";
const char* lon = "37.6184";
const char* key = "********************************";
String latitude = "55.7512";
String longitude = "37.6184";
String units = "metric";
String language = "ru";
OW_Weather ow;
Ticker ticker; Ticker ticker;
/*********************************************** /***********************************************
@@ -33,14 +29,100 @@ char weather[140] = { 0 };
bool weatherRequest = false; bool weatherRequest = false;
TaskHandle_t weatherUpdateTaskHandle; TaskHandle_t weatherUpdateTaskHandle;
bool getForecast() {
WiFiClient client;
if (!client.connect(host, 80)) {
Serial.println("## OPENWEATHERMAP ###: connection failed");
return false;
}
char httpget[250] = {0};
sprintf(httpget, "GET /data/2.5/weather?lat=%s&lon=%s&units=metric&lang=ru&appid=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", lat, lon, key, host);
client.print(httpget);
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 2000UL) {
Serial.println("## OPENWEATHERMAP ###: client available timeout !");
client.stop();
return false;
}
}
timeout = millis();
String line = "";
if (client.connected()) {
while (client.available())
{
line = client.readStringUntil('\n');
if (strstr(line.c_str(), "\"temp\"") != NULL) {
client.stop();
break;
}
if ((millis() - timeout) > 500)
{
client.stop();
Serial.println("## OPENWEATHERMAP ###: client read timeout !");
return false;
}
}
}
if (strstr(line.c_str(), "\"temp\"") == NULL) {
Serial.println("## OPENWEATHERMAP ###: weather not found !");
return false;
}
char *tmpe;
char *tmps;
const char* cursor = line.c_str();
char desc[120], temp[20], hum[20], press[20];
tmps = strstr(cursor, "\"description\":\"");
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;}
tmps += 15;
tmpe = strstr(tmps, "\",\"");
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;}
strlcpy(desc, tmps, tmpe - tmps + 1);
cursor = tmpe + 3;
tmps = strstr(cursor, "\"temp\":");
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;}
tmps += 7;
tmpe = strstr(tmps, ",\"");
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;}
strlcpy(temp, tmps, tmpe - tmps + 1);
cursor = tmpe + 2;
float tempf = atof(temp);
tmps = strstr(cursor, "\"pressure\":");
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;}
tmps += 11;
tmpe = strstr(tmps, ",\"");
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;}
strlcpy(press, tmps, tmpe - tmps + 1);
cursor = tmpe + 2;
int pressi = (float)atoi(press) / 1.333;
tmps = strstr(cursor, "humidity\":");
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;}
tmps += 10;
tmpe = strstr(tmps, ",\"");
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;}
strlcpy(hum, tmps, tmpe - tmps + 1);
Serial.printf("## OPENWEATHERMAP ###: description: %s, temp:%.1f C, pressure:%dmmHg, humidity:%s%%\n", desc, tempf, pressi, hum);
sprintf(weather, "%s, %.1f C * давление: %d мм * влажность: %s%%", desc, tempf, pressi, hum);
return true;
}
void getWeather( void * pvParameters ) { void getWeather( void * pvParameters ) {
OW_current *current = new OW_current; delay(200);
OW_hourly *hourly = new OW_hourly; if (getForecast()) {
OW_daily *daily = new OW_daily; weatherRequest = true;
delay(5000); ticker.detach();
ow.getForecast(current, hourly, daily, api_key, latitude, longitude, units, language); ticker.attach(WEATHER_REQUEST_INTERVAL, updateWeather);
sprintf(weather, "TEMP: %.1f C * PRESS: %d HG * HUM: %d%%", current->temp, (int)(current->pressure / 1.333), current->humidity); } else {
weatherRequest = true; ticker.detach();
ticker.attach(WEATHER_REQUEST_INTERVAL_FAULTY, updateWeather);
}
vTaskDelete( NULL ); vTaskDelete( NULL );
} }
@@ -48,18 +130,17 @@ void updateWeather() {
xTaskCreatePinnedToCore( xTaskCreatePinnedToCore(
getWeather, /* Task function. */ getWeather, /* Task function. */
"getWeather1", /* name of task. */ "getWeather1", /* name of task. */
8192, /* Stack size of task */ 1024 * 4, /* Stack size of task */
NULL, /* parameter of the task */ NULL, /* parameter of the task */
0, /* priority of the task */ 0, /* priority of the task */
&weatherUpdateTaskHandle, /* Task handle to keep track of created task */ &weatherUpdateTaskHandle, /* Task handle to keep track of created task */
0); /* pin task to core CORE_FOR_LOOP_CONTROLS */ 1); /* pin task to core CORE_FOR_LOOP_CONTROLS */
} }
/*********************************************** /***********************************************
Occurs when the network is connected Occurs when the network is connected
***********************************************/ ***********************************************/
void network_on_connect() { void network_on_connect() {
ticker.attach(WEATHER_REQUEST_INTERVAL, updateWeather);
updateWeather(); updateWeather();
} }
@@ -75,17 +156,20 @@ void dsp_on_start(DspCore *dsp) {
Occurs when the display is initialized Occurs when the display is initialized
***********************************************/ ***********************************************/
void dsp_on_init() { void dsp_on_init() {
hello.init(5, " * ", 1, TFT_LINEHGHT*4+6, 0, ORANGE, TFT_BG); if (DSP_MODEL == DSP_ST7735 || (DSP_MODEL == DSP_SSD1327)) {
Serial.println(TFT_LINEHGHT*4+6); hello.init(5, " * ", 1, TFT_LINEHGHT * 4 + 6, 0, ORANGE, TFT_BG);
} else {
hello.init(5, " * ", 2, TFT_LINEHGHT * 9 + 5, 0, ORANGE, TFT_BG);
}
} }
/************************ /************************
The loop cycle The loop cycle
************************/ ************************/
void dsp_on_loop() { void dsp_on_loop(DspCore *dsp) {
if (weatherRequest) { if (weatherRequest) {
weatherRequest = false; weatherRequest = false;
hello.setText(weather); hello.setText(dsp->utf8Rus(weather, true));
} }
if (display.mode == PLAYER) hello.loop(); if (display.mode == PLAYER) hello.loop();
} }

View File

@@ -1,6 +1,6 @@
void audio_info(const char *info) { void audio_info(const char *info) {
if(config.store.audioinfo) telnet.printf("##AUDIO.INFO#: %s\n", info); if(config.store.audioinfo) telnet.printf("##AUDIO.INFO#: %s\n", info);
if (strstr(info, "failed!") != NULL || strstr(info, "404") != NULL) { if (strstr(info, "failed!") != NULL || strstr(info, " 404") != NULL) {
config.setTitle("[request failed]"); config.setTitle("[request failed]");
//config.setTitle(info); //config.setTitle(info);
player.mode = STOPPED; player.mode = STOPPED;
@@ -28,7 +28,6 @@ bool printable(const char *info) {
void audio_showstation(const char *info) { void audio_showstation(const char *info) {
if (strlen(info) > 0) { if (strlen(info) > 0) {
bool p = printable(info); bool p = printable(info);
//display.title(p?info:"*****");
config.setTitle(p?info:"*****"); config.setTitle(p?info:"*****");
netserver.requestOnChange(TITLE, 0); netserver.requestOnChange(TITLE, 0);
} }
@@ -37,7 +36,6 @@ void audio_showstation(const char *info) {
void audio_showstreamtitle(const char *info) { void audio_showstreamtitle(const char *info) {
if (strlen(info) > 0) { if (strlen(info) > 0) {
bool p = printable(info); bool p = printable(info);
//display.title(p?info:"*****");
config.setTitle(p?info:"*****"); config.setTitle(p?info:"*****");
netserver.requestOnChange(TITLE, 0); netserver.requestOnChange(TITLE, 0);
} }

View File

@@ -132,7 +132,7 @@ byte Config::setLastSSID(byte val) {
void Config::setTitle(const char* title) { void Config::setTitle(const char* title) {
memset(config.station.title, 0, BUFLEN); memset(config.station.title, 0, BUFLEN);
strlcpy(config.station.title, title, BUFLEN); strlcpy(config.station.title, title, BUFLEN);
display.title(); display.putRequest({NEWTITLE, 0});
} }
void Config::setStation(const char* station) { void Config::setStation(const char* station) {

View File

@@ -153,7 +153,7 @@ void encoder2Loop() {
if (ENC2_BTNB != 255) { if (ENC2_BTNB != 255) {
bp = digitalRead(ENC2_BTNB); bp = digitalRead(ENC2_BTNB);
} }
if (bp == HIGH && display.mode != STATIONS) display.swichMode(STATIONS); if (bp == HIGH && display.mode == PLAYER) display.putRequest({NEWMODE, STATIONS}); //display.swichMode(STATIONS);
controlsEvent(encNewPosition > 0); controlsEvent(encNewPosition > 0);
} }
} }
@@ -172,13 +172,12 @@ void irBlink() {
void irNum(byte num) { void irNum(byte num) {
uint16_t s; uint16_t s;
if (display.numOfNextStation == 0 && num == 0) return; if (display.numOfNextStation == 0 && num == 0) return;
//if (display.mode == PLAYER) display.swichMode(NUMBERS); display.putRequest({NEWMODE, NUMBERS});
display.swichMode(NUMBERS);
if (display.numOfNextStation > UINT16_MAX / 10) return; if (display.numOfNextStation > UINT16_MAX / 10) return;
s = display.numOfNextStation * 10 + num; s = display.numOfNextStation * 10 + num;
if (s > config.store.countStation) return; if (s > config.store.countStation) return;
display.numOfNextStation = s; display.numOfNextStation = s;
display.drawNextStationNum(s); display.putRequest({NEXTSTATION, s});
} }
void irLoop() { void irLoop() {
@@ -204,10 +203,8 @@ void irLoop() {
case IR_CODE_PLAY: { case IR_CODE_PLAY: {
irBlink(); irBlink();
if (display.mode == NUMBERS) { if (display.mode == NUMBERS) {
display.swichMode(PLAYER); display.putRequest({NEWMODE, PLAYER});
player.play(display.numOfNextStation); player.play(display.numOfNextStation);
//player.request.station = display.numOfNextStation;
//player.request.doSave = true;
display.numOfNextStation = 0; display.numOfNextStation = 0;
break; break;
} }
@@ -234,12 +231,12 @@ void irLoop() {
} }
case IR_CODE_HASH: { case IR_CODE_HASH: {
if (display.mode == NUMBERS) { if (display.mode == NUMBERS) {
display.returnTile(); display.putRequest({RETURNTITLE, 0});
display.swichMode(PLAYER); display.putRequest({NEWMODE, PLAYER});
display.numOfNextStation = 0; display.numOfNextStation = 0;
break; break;
} }
display.swichMode(display.mode == PLAYER ? STATIONS : PLAYER); display.putRequest({NEWMODE, display.mode == PLAYER ? STATIONS : PLAYER});
break; break;
} }
case IR_CODE_NUM0: { case IR_CODE_NUM0: {
@@ -355,7 +352,7 @@ void touchLoop() {
touchLongPress=millis(); touchLongPress=millis();
if(display.mode==PLAYER || display.mode==VOL){ if(display.mode==PLAYER || display.mode==VOL){
int16_t xDelta = map(abs(touchVol - touchX), 0, display.screenwidth, 0, TS_STEPS); int16_t xDelta = map(abs(touchVol - touchX), 0, display.screenwidth, 0, TS_STEPS);
display.swichMode(VOL); display.putRequest({NEWMODE, VOL});
if (xDelta>1) { if (xDelta>1) {
controlsEvent((touchVol - touchX)<0); controlsEvent((touchVol - touchX)<0);
touchVol = touchX; touchVol = touchX;
@@ -368,7 +365,7 @@ void touchLoop() {
touchLongPress=millis(); touchLongPress=millis();
if(display.mode==PLAYER || display.mode==STATIONS){ if(display.mode==PLAYER || display.mode==STATIONS){
int16_t yDelta = map(abs(touchStation - touchY), 0, display.screenheight, 0, TS_STEPS); int16_t yDelta = map(abs(touchStation - touchY), 0, display.screenheight, 0, TS_STEPS);
display.swichMode(STATIONS); display.putRequest({NEWMODE, STATIONS});
if (yDelta>1) { if (yDelta>1) {
controlsEvent((touchStation - touchY)>0); controlsEvent((touchStation - touchY)>0);
touchStation = touchY; touchStation = touchY;
@@ -390,7 +387,7 @@ void touchLoop() {
if(millis()-touchLongPress < BTN_PRESS_TICKS*2){ if(millis()-touchLongPress < BTN_PRESS_TICKS*2){
onBtnClick(EVT_BTNCENTER); onBtnClick(EVT_BTNCENTER);
}else{ }else{
display.swichMode(display.mode == PLAYER ? STATIONS : PLAYER); display.putRequest({NEWMODE, display.mode == PLAYER ? STATIONS : PLAYER});
} }
} }
direct = TSD_STAY; direct = TSD_STAY;
@@ -411,9 +408,15 @@ void onBtnLongPressStart(int id) {
} }
case EVT_BTNCENTER: case EVT_BTNCENTER:
case EVT_ENCBTNB: { case EVT_ENCBTNB: {
display.swichMode(display.mode == PLAYER ? STATIONS : PLAYER); display.putRequest({NEWMODE, display.mode == PLAYER ? STATIONS : PLAYER});
break; break;
} }
case EVT_ENC2BTNB: {
display.putRequest({NEWMODE, display.mode == PLAYER ? VOL : PLAYER});
break;
}
default:
break;
} }
} }
@@ -426,6 +429,8 @@ void onBtnLongPressStop(int id) {
lpId = -1; lpId = -1;
break; break;
} }
default:
break;
} }
} }
@@ -453,13 +458,15 @@ void onBtnDuringLongPress(int id) {
case EVT_BTNUP: case EVT_BTNUP:
case EVT_BTNDOWN: { case EVT_BTNDOWN: {
if (display.mode == PLAYER) { if (display.mode == PLAYER) {
display.swichMode(STATIONS); display.putRequest({NEWMODE, STATIONS});
} }
if (display.mode == STATIONS) { if (display.mode == STATIONS) {
controlsEvent(id == EVT_BTNDOWN); controlsEvent(id == EVT_BTNDOWN);
} }
break; break;
} }
default:
break;
} }
} }
} }
@@ -467,19 +474,16 @@ void onBtnDuringLongPress(int id) {
void controlsEvent(bool toRight) { void controlsEvent(bool toRight) {
if (display.mode == NUMBERS) { if (display.mode == NUMBERS) {
display.numOfNextStation = 0; display.numOfNextStation = 0;
display.swichMode(PLAYER); display.putRequest({NEWMODE, PLAYER});
} }
if (display.mode != STATIONS) { if (display.mode != STATIONS) {
display.swichMode(VOL); display.putRequest({NEWMODE, VOL});
player.stepVol(toRight); player.stepVol(toRight);
} }
if (display.mode == STATIONS) { if (display.mode == STATIONS) {
int p = toRight ? display.currentPlItem + 1 : display.currentPlItem - 1; display.resetQueue();
if (p < 1) p = config.store.countStation; display.putRequest({DRAWPLAYLIST, toRight});
if (p > config.store.countStation) p = 1;
display.currentPlItem = p;
//display.clear();
display.drawPlaylist();
} }
} }
@@ -494,16 +498,14 @@ void onBtnClick(int id) {
case EVT_ENC2BTNB: { case EVT_ENC2BTNB: {
if (display.mode == NUMBERS) { if (display.mode == NUMBERS) {
display.numOfNextStation = 0; display.numOfNextStation = 0;
display.swichMode(PLAYER); display.putRequest({NEWMODE, PLAYER});
} }
if (display.mode == PLAYER) { if (display.mode == PLAYER) {
player.toggle(); player.toggle();
} }
if (display.mode == STATIONS) { if (display.mode == STATIONS) {
display.swichMode(PLAYER); display.putRequest({NEWMODE, PLAYER});
player.play(display.currentPlItem); player.play(display.currentPlItem);
//player.request.station = display.currentPlItem;
//player.request.doSave = true;
} }
break; break;
} }
@@ -521,7 +523,7 @@ void onBtnClick(int id) {
} }
} else { } else {
if (display.mode == PLAYER) { if (display.mode == PLAYER) {
display.swichMode(STATIONS); display.putRequest({NEWMODE, STATIONS});
} }
if (display.mode == STATIONS) { if (display.mode == STATIONS) {
controlsEvent(id == EVT_BTNDOWN); controlsEvent(id == EVT_BTNDOWN);
@@ -542,7 +544,7 @@ void onBtnDoubleClick(int id) {
case EVT_BTNCENTER: case EVT_BTNCENTER:
case EVT_ENCBTNB: case EVT_ENCBTNB:
case EVT_ENC2BTNB: { case EVT_ENC2BTNB: {
display.swichMode(display.mode == PLAYER ? STATIONS : PLAYER); display.putRequest({NEWMODE, display.mode == PLAYER ? VOL : PLAYER});
break; break;
} }
case EVT_BTNRIGHT: { case EVT_BTNRIGHT: {
@@ -550,5 +552,7 @@ void onBtnDoubleClick(int id) {
player.next(); player.next();
break; break;
} }
default:
break;
} }
} }

View File

@@ -1,40 +0,0 @@
let dragged;
let id;
let index;
let indexDrop;
let list;
document.addEventListener("dragstart", ({target}) => {
dragged = target.parentNode;
id = target.parentNode.id;
list = target.parentNode.parentNode.children;
for(let i = 0; i < list.length; i += 1) {
if(list[i] === dragged){
index = i;
}
}
});
document.addEventListener("dragover", (event) => {
event.preventDefault();
});
document.addEventListener("drop", ({target}) => {
if(target.parentNode.className == "pleitem" && target.parentNode.id !== id) {
dragged.remove( dragged );
for(let i = 0; i < list.length; i += 1) {
if(list[i] === target.parentNode){
indexDrop = i;
}
}
if(index > indexDrop) {
target.parentNode.before( dragged );
} else {
target.parentNode.after( dragged );
}
let items=document.getElementById('pleditorcontent').getElementsByTagName('li');
for (let i = 0; i <= items.length-1; i++) {
items[i].getElementsByTagName('span')[0].innerText=("00"+(i+1)).slice(-3);
}
}
});

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -6,7 +6,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="default"> <meta name="apple-mobile-web-app-status-bar-style" content="default">
<link rel="apple-touch-icon" type="image/png" href="elogo.png"> <link rel="apple-touch-icon" type="image/png" href="elogo.png">
<link rel="icon" type="image/png" href="elogo.png"> <link rel="icon" type="image/png" href="elogo.png">
<link rel="stylesheet" title="base" href="/style.css" type="text/css"> <link rel="stylesheet" title="base" href="style.css" type="text/css">
<title>ёRadio</title> <title>ёRadio</title>
<style> </style> <style> </style>
</head> </head>
@@ -105,7 +105,7 @@
<div id="pleditorwrap" hidden> <div id="pleditorwrap" hidden>
<div id="pleditor"> <div id="pleditor">
<h2>Playlist Editor<span onclick="doCancel()"></span></h2> <h2>Playlist Editor<span onclick="doCancel()"></span></h2>
<div id="pleheader"><span class="space"></span><span class="plename">Name</span><span class="pleurl">URL</span><span class="pleovol">Ovol</span></div> <div id="pleheader"><span class="space"><input type="checkbox" onclick="selectAll(this)" /></span><span class="plename">Name</span><span class="pleurl">URL</span><span class="pleovol">Ovol</span></div>
<ol id="pleditorcontent"> <ol id="pleditorcontent">
<li class="pleitem"> <li class="pleitem">
<span>1.</span> <span>1.</span>

View File

@@ -1,349 +0,0 @@
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
var currentItem = 0;
var wserrcnt = 0;
var wstimeout;
window.addEventListener('load', onLoad);
function initWebSocket() {
clearTimeout(wstimeout);
console.log('Trying to open a WebSocket connection...');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage;
}
function onOpen(event) {
console.log('Connection opened');
wserrcnt=0;
}
function onClose(event) {
//console.log('Connection closed');
wserrcnt++;
document.getElementById('playbutton').setAttribute("class", "stopped");
wstimeout=setTimeout(initWebSocket, wserrcnt<10?2000:120000);
}
function onMessage(event) {
var data = JSON.parse(event.data);
if(data.nameset) document.getElementById('nameset').innerHTML = data.nameset;
if(data.meta) document.getElementById('meta').innerHTML = data.meta;
if(data.vol) {
setVolRangeValue(document.getElementById('volrange'),data.vol);
}
if(data.current) setCurrentItem(data.current);
if(data.file) generatePlaylist(data.file);
if(data.bitrate) document.getElementById('bitinfo').innerText = 'bitrate: '+data.bitrate+'kBits';
if(data.rssi) document.getElementById('rsiinfo').innerText = 'rssi: '+data.rssi+'dBm';
if(data.mode) {
document.getElementById('playbutton').setAttribute("class",data.mode);
}
if(data.bass) {
setVolRangeValue(document.getElementById('eqbass'),data.bass);
setVolRangeValue(document.getElementById('eqmiddle'),data.middle);
setVolRangeValue(document.getElementById('eqtreble'),data.trebble);
}
if(data.balance) {
setVolRangeValue(document.getElementById('eqbal'),data.balance);
}
}
function scrollToCurrent(){
var pl = document.getElementById('playlist');
var lis = pl.getElementsByTagName('li');
var plh = pl.offsetHeight;
var plt = pl.offsetTop;
var topPos = 0;
var lih = 0;
for (var i = 0; i <= lis.length - 1; i++) {
if(i+1==currentItem) {
topPos = lis[i].offsetTop;
lih = lis[i].offsetHeight;
}
}
pl.scrollTo({
top: topPos-plt-plh/2+lih/2,
left: 0,
behavior: 'smooth'
});
}
function setCurrentItem(item){
currentItem=item;
var pl = document.getElementById('playlist');
var lis = pl.getElementsByTagName('li');
for (var i = 0; i <= lis.length - 1; i++) {
lis[i].removeAttribute('class');
if(i+1==currentItem) {
lis[i].setAttribute("class","active");
}
}
scrollToCurrent();
}
function generatePlaylist(lines){
var ul = document.getElementById('playlist');
ul.innerHTML="";
lines.forEach((line, index) => {
li = document.createElement('li');
li.setAttribute('onclick','playStation(this);');
li.setAttribute('attr-id', index+1);
li.setAttribute('attr-name', line.name);
li.setAttribute('attr-url', line.url);
li.setAttribute('attr-ovol', line.ovol);
if(index+1==currentItem){
li.setAttribute("class","active");
}
var span = document.createElement('span');
span.innerHTML = index+1;
li.appendChild(document.createTextNode(line.name));
li.appendChild(span);
ul.appendChild(li);
initPLEditor();
});
scrollToCurrent();
}
function initPLEditor(){
ple= document.getElementById('pleditorcontent');
ple.innerHTML="";
pllines = document.getElementById('playlist').getElementsByTagName('li');
for (let i = 0; i <= pllines.length - 1; i++) {
plitem = document.createElement('li');
plitem.setAttribute('class', 'pleitem');
plitem.setAttribute('id', 'plitem'+i);
let pName = pllines[i].getAttribute('attr-name');
let pUrl = pllines[i].getAttribute('attr-url');
let pOvol = pllines[i].getAttribute('attr-ovol');
plitem.innerHTML = '<span class="grabbable" draggable="true">'+("00"+(i+1)).slice(-3)+'</span>\
<span class="pleinput plecheck"><input type="checkbox" /></span>\
<input class="pleinput plename" type="text" value="'+pName+'" maxlength="140" />\
<input class="pleinput pleurl" type="text" value="'+pUrl+'" maxlength="140" />\
<input class="pleinput pleovol" type="number" min="-30" max="30" step="1" value="'+pOvol+'" />';
ple.appendChild(plitem);
}
}
function playStation(el){
let lis = document.getElementById('playlist').getElementsByTagName('li');
for (let i = 0; i <= lis.length - 1; i++) {
lis[i].removeAttribute('class');
}
el.setAttribute("class","active");
id=el.getAttribute('attr-id');
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("playstation="+id);
}
function setVolRangeValue(el, val=null){
let slave = el.getAttribute('data-slaveid');
if(val){
el.value = val;
document.getElementById(slave).innerText=val;
}
document.getElementById(slave).innerText=el.value;
var value = (el.value-el.min)/(el.max-el.min)*100;
el.style.background = 'linear-gradient(to right, #bfa73e 0%, #bfa73e ' + value + '%, #272727 ' + value + '%, #272727 100%)';
}
function onRangeVolChange(value) {
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("vol=" + value+"&");
}
function onRangeEqChange(el){
let trebble = document.getElementById('eqtreble').value;
let middle = document.getElementById('eqmiddle').value;
let bass = document.getElementById('eqbass').value;
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("trebble=" + trebble + "&middle=" + middle + "&bass=" + bass + "&");
}
function onRangeBalChange(el){
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("ballance=" + el.value+"&");
}
function showSettings(){
document.getElementById('pleditorwrap').hidden=true;
document.getElementById('equalizerbg').setAttribute('class','hidden');
document.getElementById('settings').hidden=false;
}
function showEditor(){
document.getElementById('settings').hidden=true;
document.getElementById('equalizerbg').setAttribute('class','hidden');
initPLEditor();
document.getElementById('pleditorwrap').hidden=false;
}
function doCancel() {
document.getElementById('settings').hidden=true;
document.getElementById('pleditorwrap').hidden=true;
}
function doExport() {
window.open("/data/playlist.csv");
}
function doWifiExport() {
document.getElementById('settings').hidden=true;
window.open("/data/wifi.csv");
}
function doUpload(finput) {
var formData = new FormData();
formData.append("plfile", finput.files[0]);
var xhr = new XMLHttpRequest();
xhr.open("POST","/upload",true);
xhr.send(formData);
}
function doAdd(){
let ple=document.getElementById('pleditorcontent');
let plitem = document.createElement('li');
let cnt=ple.getElementsByTagName('li');
plitem.setAttribute('class', 'pleitem');
plitem.setAttribute('id', 'plitem'+(cnt.length));
plitem.innerHTML = '<span class="grabbable" draggable="true">'+("00"+(cnt.length+1)).slice(-3)+'</span>\
<span class="pleinput plecheck"><input type="checkbox" /></span>\
<input class="pleinput plename" type="text" value="" maxlength="140" />\
<input class="pleinput pleurl" type="text" value="" maxlength="140" />\
<input class="pleinput pleovol" type="number" min="-30" max="30" step="1" value="0" />';
ple.appendChild(plitem);
ple.scrollTo({
top: ple.scrollHeight,
left: 0,
behavior: 'smooth'
});
}
function doRemove(){
let items=document.getElementById('pleditorcontent').getElementsByTagName('li');
let pass=[];
for (let i = 0; i <= items.length - 1; i++) {
if(items[i].getElementsByTagName('span')[1].getElementsByTagName('input')[0].checked) {
pass.push(items[i]);
}
}
if(pass.length==0) {
alert('Choose something first');
return;
}
for (var i = 0; i < pass.length; i++)
{
pass[i].remove();
}
items=document.getElementById('pleditorcontent').getElementsByTagName('li');
for (let i = 0; i <= items.length-1; i++) {
items[i].getElementsByTagName('span')[0].innerText=("00"+(i+1)).slice(-3);
}
}
function showEqualizer(isshowing){
document.getElementById('equalizerbg').classList.toggle('hidden');
}
function submitWiFi(){
var items=document.getElementById("credentialwrap").getElementsByTagName("li");
var output="";
for (var i = 0; i <= items.length - 1; i++) {
inputs=items[i].getElementsByTagName("input");
if(inputs[0].value == "") continue;
let ps=inputs[1].value==""?inputs[1].getAttribute('data-pass'):inputs[1].value;
output+=inputs[0].value+"\t"+ps+"\n";
}
if(output!=""){ // Well, let's say, quack.
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("wifisettings="+output);
document.getElementById("settings").innerHTML="<h2>Settings saved. Rebooting...</h2>";
setTimeout(function(){ window.location.reload(); }, 10000);
}
}
function submitPlaylist(){
var items=document.getElementById("pleditorcontent").getElementsByTagName("li");
var output="";
for (var i = 0; i <= items.length - 1; i++) {
inputs=items[i].getElementsByTagName("input");
if(inputs[1].value == "" || inputs[2].value == "") continue;
let ovol = inputs[3].value;
if(ovol < -30) ovol = -30;
if(ovol > 30) ovol = 30;
output+=inputs[1].value+"\t"+inputs[2].value+"\t"+inputs[3].value+"\n";
}
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("playlist="+output.slice(0, -1));
document.getElementById('pleditorwrap').hidden=true;
}
function initSliers(){
var sliders = document.getElementsByClassName('slider');
for (var i = 0; i <= sliders.length - 1; i++) {
sliders[i].oninput = function() {
setVolRangeValue(this);
};
setVolRangeValue(sliders[i], 0);
}
return;
var volslider = document.getElementById("volrange");
var eqvolslider = document.getElementById("eqvol");
var balslider = document.getElementById("eqbal");
volslider.oninput = function() {
setVolRangeValue(this);
};
eqvolslider.oninput = function() {
setVolRangeValue(this);
};
balslider.oninput = function() {
setVolRangeValue(this);
};
setVolRangeValue(volslider, 0);
setVolRangeValue(eqvolslider, 0);
setVolRangeValue(balslider, 0);
}
function onLoad(event) {
initWebSocket();
initButton();
initSliers();
document.getElementById("volrange").addEventListener("wheel", function(e){
if (e.deltaY < 0){
this.valueAsNumber += 1;
}else{
this.value -= 1;
}
websocket.send('volume='+this.value);
e.preventDefault();
e.stopPropagation();
}, {passive: false});
}
function initButton() {
document.getElementById('playbutton').addEventListener('click', playbutton);
document.getElementById('prevbutton').addEventListener('click', prevbutton);
document.getElementById('nextbutton').addEventListener('click', nextbutton);
document.getElementById('volmbutton').addEventListener('click', volmbutton);
document.getElementById('volpbutton').addEventListener('click', volpbutton);
}
function playercommand(cmd){
xhr = new XMLHttpRequest();
xhr.open("POST","/",true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(cmd+"=1");
}
function playbutton(){
var btn=document.getElementById('playbutton');
if(btn.getAttribute("class")=="stopped") {
btn.setAttribute("class", "playing");
playercommand("start");
return;
}
if(btn.getAttribute("class")=="playing") {
btn.setAttribute("class", "stopped");
playercommand("stop");
}
}
function prevbutton(){
playercommand("prev");
}
function nextbutton(){
playercommand("next");
}
function volmbutton(){
playercommand("volm");
}
function volpbutton(){
playercommand("volp");
}

Binary file not shown.

View File

@@ -1,527 +0,0 @@
html, body {margin: 0; padding: 0; height: 100%; }
body {
background-color: #000;
color: #fff;
font-family: Times, "Times New Roman", serif;
}
a { color: #e3d25f; text-decoration: none; font-weight: bold }
a:hover { text-decoration: underline }
.logo {
display: block;
width: 155px;
height: 100px;
background-color: transparent;
background-image: url(elogo100.png);
background-position: center center;
background-repeat: no-repeat;
overflow: hidden;
text-indent: -2022px;
z-index: 2;
position: relative;
}
#nameset {
text-transform: uppercase;
font-weight: bold;
font-size: 22px;
color: #e3d25f;
margin: 20px 0 8px 0;
}
#meta {
text-transform: uppercase;
font-size: 16px;
margin-bottom: 14px;
text-align: center;
}
.content {
display: flex;
max-width: 960px;
margin: 0 auto;
flex-direction: column;
align-items: center;
padding: 30px;
height: 100%;
box-sizing: border-box;
position: relative;
}
.playerwrap {
width: 100%;
flex: 1;
display: flex;
position: relative;
}
.player {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
max-width: 480px;
margin: 0 auto;
}
#equalizerwrap {
position: relative;
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
}
#equalizerbg {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 2px;
background: rgba(0, 0, 0, 0.3);
z-index: 7;
}
#equalizerbg.hidden {
display: none;
}
#equalizer {
padding: 20px;
background: #000;
box-shadow: #000 0 10px 20px;
list-style-type: none;
margin: 0;
}
#equalizer li {
margin-bottom: 10px;
color: #ccc;
}
#equalizer li input {
width: 100%;
height: 25px!important;
border-radius: 13px;
}
.eqinfo {
float: right;
}
#settings, #pleditorwrap {
position: absolute;
background: rgba(0,0,0,1);
top: 0;
right: 0;
left: 0;
bottom: 0;
padding: 30px 10px 20px 0;
overflow-y: auto;
box-sizing: border-box;
}
#credentialwrap {
max-width: 520px;
margin: 0 auto;
padding: 0;
list-style-type: none;
}
#settings h2, #pleditor h2{
text-align: center;
padding-top: 40px 0;
text-transform: uppercase;
font-weight: bold;
font-size: 26px;
color: #e3d25f;
overflow-y: auto;
}
#pleditor h2 {
line-height: 48px;
margin: 5px 0;
padding-left: 48px;
}
#pleditor h2 span {
display: block;
float: right;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAA2FBMVEUAAAC+pDnm12HXxVHk1l65mjLJskO9oTjo3GPEqD3cylWyljDfz1rOuknBpjq+oDbt4Gjz6W6zli/17HC1mTLw5Wupjyq8nTOuky3Tv07p22PGq0G1mDDx5Wzw42vj1l7ez1nFqUHCpz64mjKzljDx5WzHq0G1lzHby1a2mTHbyla7nTTXxVHUwU/LtEXIr0HFqj3DpzrApDm9nzW5mzKyli/063Dz6G7v5Wvi013g0FvdzVfZx1POuUi+ojjs4Gbo22PVwk/RvkzQu0qvky2skSyqjyvl119lX1m8AAAAKXRSTlMAAgKgoaCfo6KioaGgn5+fLaSko6OioqGhoEItLfX19fX19fX1pEJCLVUTdPcAAAEKSURBVDjL1ZLZdoJADEDJoKCiqHVt7b7DgOybIO72//+o9FSdSeWhr+YtuXdyMjkRLik6BOdwi/Obuy5BfPTygd7fx1GPcFym2ivfg7xFYTggJ656vnYFAm90wyiukQOv5/TImdGLF8sK+eWO5/ePnBmDxTJpkoJLdk6rjDOj9pWkIgHJcjzGkVGZ6cZ1y7LdEePYaOqrzdRy2jzHhmjOp7bK+Lmw/kcDlx8R84axnkuqSzUFynlmbiSAtq8FYyj9gmG2CgDVINgO4XwJabb64YWhbPc7BcqWdCjCeL/TZMBrTtJMPJVgGPh5nTc6DzNd5A+mT92nCTq5xwY+Ofn5HQ/x+fdoJ8IFxTeZ6Bp9c7k3QwAAAABJRU5ErkJggg==');
width: 48px;
height: 48px;
background-position: center center;
background-repeat: no-repeat;
cursor: pointer;
border-radius: 24px;
}
#pleditor h2 span:hover {
background-color: #272727;
}
#pleheader {
display: flex;
}
#pleheader span {
padding: 8px;
font-weight: bold;
box-sizing: border-box;
color: #e3d25f!important;
}
#pleheader .space {
width: 70px;
}
#pleditor {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 900px;
height: 100%;
}
#settings::-webkit-scrollbar, #pleditorcontent::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: #000;
}
#settings, #pleditorcontent {
scrollbar-color: #e3d25f #000;
scrollbar-width: thin;
}
#settings::-webkit-scrollbar-thumb, #pleditorcontent::-webkit-scrollbar-thumb {
background: #e3d25f;
}
#pleditorcontent {
flex: 1 1 auto;
overflow-y: scroll;
height: 0px;
margin: 0;
padding: 0 0px 0 0;
list-style-type: none;
border: #e3d25f 2px solid;
box-sizing: border-box;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAABAAgMAAACrYYWUAAAACVBMVEUnJycAAAAtLS3JOrneAAAAGElEQVQI12NYtYKBZgBoOAiFhtAIAQ0HALK+GReOr3bpAAAAAElFTkSuQmCC');
}
.grabbable {
cursor: move;
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.pleitem {
display: flex;
justify-content: space-between;
background: #000;
}
.pleitem span {
display: flex;
flex-direction: column;
justify-content: center;
text-align: right;
color: #d7d7d7;
width: 40px;
padding: 0 8px;
box-sizing: border-box;
font-size: 14px;
border: #2d2d2d 1px solid;
}
.pleitem input {
font-family: Times, "Times New Roman", serif;
background: #000;
color: #e3d25f;
height: 32px;
line-height: 32px;
text-indent: 8px;
font-size: 18px;
border: #2d2d2d 1px solid;
font-weight: normal;
box-sizing: border-box;
margin-top: 4px;
border-radius: 0px;
outline: none;
margin: 0;
}
#pleditorcontent li:nth-child(odd) input, #pleditorcontent li:nth-child(odd) span {
background: #272727;
}
.plecheck {
width: 30px!important;
}
.plecheck input {
line-height: 10px;
height: auto;
}
.plename {
width: 300px;
}
.pleurl {
flex: 1;
color: #d7d7d7!important;
}
.pleovol {
width: 53px;
font-size: 16px!important;
}
#pleheader .pleovol {
width: 62px;
}
.credentialitem {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 14px;
}
.credentialitem span {
display: flex;
flex-direction: column;
justify-content: center;
font-weight: bold;
}
.credentialitem .textinput {
width: 47%;
}
.credentialitem input {
width: 100%;
box-sizing: border-box;
background: #272727;
color: #e3d25f;
padding: 6px 12px;
font-size: 20px;
border: #2d2d2d 1px solid;
font-weight: normal;
box-sizing: border-box;
margin-top: 4px;
border-radius: 0px;
}
.credentialitem label {
text-transform: uppercase;
color: #ccc;
}
.credentialitem input:focus {
outline: none;
}
.formbuttons {
display: flex;
justify-content: space-around;
max-width: 280px;
width: 100%;
margin: 0 auto;
margin-top: 30px;
}
#pleditor .formbuttons {
max-width: 100%;
}
.button {
padding: 8px 22px;
font-size: 18px;
border: #e3d25f 2px solid;
font-weight: normal;
box-sizing: border-box;
border-radius: 20px;
cursor: pointer;
text-align: center;
min-width: 120px;
margin-left: 20px;
text-transform: uppercase;
color: #e3d25f;
background: #272727;
}
.button:hover {
background: #e3d25f;
color: #000;
}
.button:active {
position: relative;
top: 2px;
}
#save_button {
background: #e3d25f;
color: #000;
}
#navbar {
display: flex;
width: 400px;
justify-content: space-between;
position: absolute;
top: 0;
padding: 30px 0 0;
box-sizing: border-box;
}
.playerbyttonwrap {
display: flex;
width: 400px;
justify-content: space-between;
margin-top: 14px;
}
.playerbytton, .stopped, .playing {
background-color: transparent;
background-position: center center;
background-repeat: no-repeat;
width: 48px;
height: 48px;
cursor: pointer;
border: #e3d25f 2px solid;
border-radius: 26px;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}
.navbutton {
border-color: transparent;
}
.navbutton:hover {
border-color: #e3d25f;
}
.playerbytton:hover, .stopped:hover, .playing:hover {
background-color: #272727;
}
.playerbytton:active, .stopped:active, .playing:active {
position: relative;
top: 2px;
}
.stopped {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAvVBMVEUAAADg0Vvez1fYx1Lr4V/q3l7l2F3o3F/h01nw52rr4WDx53Dez1nZyVL69o707Xju5Gbt42X38oXx6XP584n17X3t42v584fw6HX27nzs4Wzdz1Tx6HTw523h0lvez1naylXl11/m2GHj1V7f0FrdzVjq3WTn2mLZx1L38IDv5Wjo3GPi01zczFfcy1bz6m/s4Wf7+JP69o317nnt4mju42Pu5W7x6Gzw5Wvr32Xl2F/59If07HP38oTj1lmRTpVfAAAAHnRSTlMAEkkE/taStm377SkpKe3t7e3W1ra2tpKSbW1tSQQSPakHAAAA9klEQVQ4y82R2XaCMBRFtdLaWjvXWRMCQkhQQcIkDv//WSaRpWI0vnpe9+aek0XtgfL/fkdYLnt1vUCiz8FEJwQBiX7HOiHLA7Lu3JwSZTmN45SQfv2GkOdxGLpuyr6GjasCjcOV6/sWTtnf0xVhLTm2LGRb6abbVoUjn4Epom8vl1O2kheSw/kC0Z/XRlUQXGAAOTc9EyXPlSnEx4fPp5J73s64EMp66MxNzoHRGlUrGDrj0DCUkcy2geD8/AInzQ/lmWxWcrMQ69RsyvN20pLvUwXJQZiU5UoCfh669FiuCo6D6alcTVbQb16uEcTv0aXZrj1u9gzXJnV9YpvtAAAAAElFTkSuQmCC');
}
.playing {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAP1BMVEUAAADv42vy52369Ivu4Wnz6W7x5Wv162/79o/7+JLt32js3Gb48YP584j484Xn12L17Xv17XHq2mXz6XTk0mCFQY+JAAAAAXRSTlMAQObYZgAAALFJREFUOMvlz90OgyAMhmH+CqJQcXr/17p+3cySsjuwRyTvQ5O6Z815nmOM1pxrzD3KWHBd+/7aBPCaUvLegqEdoGufgfaNAdDzYoH2tTsXPfoEmvYb5BAmgPwFWXqoFqCnFAUgB5qAdgXIVCxgdO8VkPQJ/K5fAvoxA/QMgG433NfjuIr/hRYL0D+gHNJDtAA5KDiK9PwfUMUGku67BchUAChIT2zAgqm16itG5uYeNW/M9AgMwr5N0gAAAABJRU5ErkJggg==');
}
#prevbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABR1BMVEUAAADRu03Zxz7g0Fbn2lvx6Hbp22jXxFC/qTvo2WS2nTXFrkPt4WfbyUHl11rk1Vfs4Wbn11jj1FPYxT/27X/x53LVwj3TwDro2F3Wwz/byUnRvTzp3WbSvz/k1Fvq3GbezVTNuDvOu0DItDnh0FvJszzTv0rErjjezFrWwk7Xw1K/qDjbyVi7pDi3nzbZxVXTvlDBqUHKs0jezETcyUC9pT3t4GPq3FzWwVLj1E7FrUO/pz7u4mbi0F3o2VzcyFjUv1HOt0vIsEa7ojvTvjPNtyv17nzz6XTw5Wvi0l3ey1rax1Xl1VLXw1LSvU/Qu03h0Urgz0jDrEDVwjj38ILz6Xbx5m/q3Wnr3l/fzFvi0ljl1lbZxlLVwkDPu0DXxDvQuy7LtCrl1GHm1mDl1VrYxkzbyUfJs0XIsj/KtT3ItDvBqzvKsin8qlL8AAAAL3RSTlMAFv6t66tWVi0VCwX19e3t7Ozs7Ovr4uLU1MXFsbGvrZ6ejIx2dmRkWVk9PR4eFHLHxygAAAE0SURBVDjL7ZHndoJAFISVJCYxvffeKx0FxIYlKAhI1CT29Pb+v13KXV/C+QFzznyzZ+/d0EhD/feH/m4P2/AYuH4e3MzZHAt+cvwJbB6Amy22Y0M9pgkY6Hm/+yOuXeWtoJ4sUxjo5dzvxQrxrcq06NdfKCqdACCHgKkdrsPzMl1FwNVSslWh4sYDBpzoCdH+U91c0r16JR03SAw4zgbxq6o8TUtSVl9ItkyUk2SqDkC3u8798LJMS9ks05xH10N5OVUqAkBw0WP28wvlDJOJhfeFNxL1S88Y4Dh0yW3xg0F5Bm3ncjGhoFypAcB62ztfbhoZ0xTcMQ/qDUXRChiw/eUdxt7jlD98ZK3YeMWAbQXmelPQgu1MTxRqjwBYIn6s01k8fGQVA6IewrrdBYcOCY0EGgATKDjicNrzUgAAAABJRU5ErkJggg==');
}
#nextbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABCFBMVEUAAAC+ojXKsDi0mC/awzndxjvXwTTgzUjRuTTUvDjj1VbUvDrHrjHEqjLXxEu6ny/Sv0vWwTXhzkXUvjXq3lzl1lDRujPQujLbxj7RujTcyEfMtTPXwT7byUjRuDnJsTLSukDEqzHHqzm5oC/JsD+1mjDbxDfVwDS0ly+7nDO1mDDYwjW4mjLizULEqTzBpTnAozjUvTG3mTHFqz7fyTzKsDnUvjTSvDDq3Vjl1Evj0UbHrkDdxjvCpzq8njTIsEHgyz7awza/oTbQuTTs4V3k1lPn2VDMt0bQuUXLtUXKskPVvz7VvTvJsTO7oDDXxUzYwkDYwTzDpjrFqjjErDPDqzK/ozLCqTEl328YAAAAJnRSTlMAFVgI7ez7+sWuq6uMY1ctFfXs7Ovr4uLU1LGxr62ennZ2PT0eHggzQnUAAAEdSURBVDjL7ZFncsIwFITtQEJ6771KNrIt4QoOdmwTAoSQXu5/kzwZJE1mcgT215u3366kkTaV1OK6HA+v1RohMd1vr4oxrp1X/gG6TVESD+39SwHkAmj2X7o74xKbfbz5p3o550QCvUGv1jrROVAUaYCqK3xNFDB4vLvtx5szmpalqWmmHTS/BgAWwAP4nuO92se6b5qmZbnf4dxyBSuA+w5lQbuKSr9eNz7xbiiBFvgJZQUHwAfbML7wXqMhAc95p4w++Qt623Jd8J87cESoAMhD/yxcEvF6d4T5JVVDnNCEx2FEEP8Jt8pnRpEAbBb4PM4BaCdngP4FhtmSPh7zET64mqwjeUQG8YnIxoX8LPVMiAsd3WhSmGhTSf0Cx6gshxH98P4AAAAASUVORK5CYII=');
}
#volpbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABp1BMVEUAAADTv03byVXSvkzax1PYxEvbyVLWw07Svkrj0Ufr31vt4WPr317q3V7m2lvj1Vjm2mHdzE3cy1DRu0PbylHXxEzYxlHWw0/u5Gbs4V7r31nu5Gft4mPq3Vnq31/n2lfm2Fjn21zl11fo3WDk1lbj1VXl2FrdzErh0VPg0VPYxEXfz1Lcykzf0FTayEzWwUfcy0/ezlbfz1nUwEvPuUXXxVLGqjvNt0Xv52rs4V3s313k0kjs4V/o2lTm1lDp21fq3Vvu5Gnn2FPr3l3k003s4mfq317q3mHs4mbk1FHbx0Hp3mHo21/cx0Lfz0zdy0jo22Hfz07h0VDj1Vfezk7h01fk2F/YxEfj1Fvh0Vbj1F3g0FjQuD7h1FzZxk7g0lvdzVfez1nTv0nNt0XGrTzaylbYyFTYx1PXxVHt42XayVXv5Wjs4mbu42Ps4WHs4Fzez1np3Fjn2VXn22Dcy1fi0lDgz03w52ru5Wjq3mLk1l3o21rdzlbk1VTayFTo2VDWxFDk1U/dyknv5WXu42Dg0Vvs4Frq3lfk1lfg0Vbp21TUwU3gzUTlFyGcAAAAZXRSTlMAASgEEVk8JhX+9O7k1LaWjo1kTElFGQ78/Pzv5+XX0sm7uLe0sKWjmJCPiYV9cmppT0AtHRQUCPr69vby7+/t6+rq6OXf39zYzMrJwry4tLGxqpqaj4iGhXdsbGZeXllVNDQkGQe+VJQAAAGqSURBVDjLzdJlc9tAEIDh15Jsx2zHThxsqGkDDadJmZmZuZVkmSkOYxl+dCVZmlEyU3/s5Pm2s7d7t3fHvuN656URbygXEBrkj15drmSj/JN4Kx9423lexNbEbs9ylSjRxfd27Lko4TTdtpKdYnrpNZaHhWYcmrqW0xkBKfME0wyJQr9zwIFstXhMxNV2z4yfB5n3d9ineJnTtMxXuXgN6LqJIVwQGCwlqAuspBRFlouXkxA6ALTyeLWZ0XXrEJK2oaZlOV3VBqAvCJEIkz/GGF84gknQ9HJZUdSi1sqhU3DiIC3lIdwLh62Bs3q5nk+l8gki7XCuF6H8gJbaHavDkp5X9fzaF72DH/xGh0e4a1YHabGqGAuUfBj6umF4iEl9//Gdp9R1Voz6rY0rSegJma8Q255gZGeCuheZz1pubUs1JuzuxXB/c4a7vrjjJsP5lHpcxNUxaMbuS675k74552cIrv4ueJG+j2KaJe67jZOn/WdpCk/pDZaRP6/YZezb+jCxXx/s+NONuT0/tr901n36gohNZI9kT7m2HaOB2eubZ7w0FP/I//cX2VZVBFBJqXUAAAAASUVORK5CYII=');
}
#volmbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABd1BMVEUAAAC4njLo11PYxDrm00/hzlDaxEnIrUDHrUG9ojnk0Uvn1lHk0U3SvTPWwTfp2lnj0E3gzUniz0/dyEXj0VHgzU/bxkbaxUjfzVLey1HHsDTaxlHFrTq7ojLTu0i9ozXUvUyxlyyulSzNtEXGrECzmTDTvjLeykLq3Vzp2lnaxT7QujHm01HRuzPm1FPdyELYxEDNuC/WwTvLtS/l1Vfjz1Dm1ljaxkTJszDaxUbKtDLWwULVwELfzFLKszjey1LOuD7AqS/Zw0zKtDy7oyzHsDu+pjK5oC7Wv0zayFTXwk7XxFHTvU3TvU2pjyu9ojq6nze1mzO0mTLKr0LApDy2nDXUvzSxljHp2Vbhz0jgy0PMs0HaxTy+ozu8oDi4nTbQujLTvTGymDDr3Vvo2FnfzE7gzEbcyUDSvDbVwTXi0VXaxEzFrD/EqD/IsD7Cpj7OuD2+pTm6oDm+pDe7ozbMtzW5oTTKtDPIsTO+pTPCqjLFrjGuky/WrPCGAAAAT3RSTlMAJ/7+/bOWGQ4E/vby7u3s5OLX1Mm5tqWQjo5bS0A9NyUlFRQSEf377+/u7uvn5ubf3NjV09HMycK7uLaxl46IiIV7bGxeWVVPTTQoHgUEcf+/bgAAAS1JREFUOMvNzkV3wkAYheGLS4sVKS4F6u7ubgQCQQtJ8Lr7jy90l55Mlj082/fOdwad5yAkmUMznEEGsr4p9p11k/v5ImvYNxp1INni3txYLwRI3df/2fDCV9gjfWDshVfIEKlvEgbLTPxVoQMGVkXiLsc0mx+J52kAEwsig5Gv73Q6EX+a1AJWKwCNsEcZPs0nUqWH+gqwZAHUagjImNbzVIkq3tY06O0GulQQCDR+eyyWzHmh1gOjtj8XFPEU9Ri7SOb14heiBYoqtvp11gHYzYBzDULD9+1+R1u0wFwPgDCEdnK5WjZ/Q7fbuA3iHFk6r9QBchVhEDZXaXkQkcwGCPzKK+Uh/BkPSLblVRdc5WMQ2TMmz5DpDETa2cplxQkJp/PlwRNIOgri//0AbVY1/4adyuMAAAAASUVORK5CYII=');
}
#playlistbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABTVBMVEUAAADr4GLo3GTSvUrn2mLVwlDh0lLq32Xm2l/f0Ffi013o3Gbs4Wrg0VvXxlDf0Frz7Hncx0Dz63jfzUjm2Vjo3F3x6HPq4GTfzkrbyUXk2Fnx6XXu5W7y63fo3WLk11rw6HPVvTvr4Wnr4Gnf0VTv5nLUvUDZyEzs4m3v5XHo3GbMsjri1Fzl2WLUwEnHrDjaylPdzlfQukbXx1DGqjnWxE/r3mjYxlPPukjy6nTx6HHn2mPm2GHj1F3ez1nayFPfzUj07Xrw527u5W3u5Gns4mbg0Frdzljl1lPRvUnJsELGrT/s4mvq3mHk1l/h0lzm2VjczFfh0lLk1VDWxE/i0k7Tv03i0Uzgz0rNt0TKs0PdyULcxj/Eqj3Dpzvz63fr4Gfq3mfo3GPn22Dm2Vbby1XYyFHfy0Xbx0Tv5W3Tv0nZxEPTvT7Ruj7Irjt5kAYfAAAAOXRSTlMA+40mCQPLurZ0V01CPjYW/Pz6+Pf27+7r5uPi3t3Z0cnGw62roqGVhHt3dmtkXVNNREQ6MiwiHhGFwXcaAAABNUlEQVQ4y83SR3OCUBQFYHuNMb333nujWlCBBJQmgiHGrqn/f5mXZCZA5rr3bjjM+ebCm3me4Z2g/yw6oEomjn2RFa8oSUC5v702gzN1gmJTut4GQIZpEBTNdrqapvMcBMgiVaDlFJquBgOSJIimKE6vbnEqAJ4xfCnsOzq/RZkrgyDwl9UKADDMzmUQ4A5gQCBr50oaALgDGBDIvtg53YMA4wCPAGByv0//yYW/B4HcD7gOqUa63/8HAnHfQSyXR+lySuHvH55qlqsfWcSEeqOJQHBBMasIfFqufgwnSwW2g8CoxJvfC97XnWAZL1IlWi54EWjzaEHtwzp19DcZAl0EVm5F0CdCymvVfBs/dP3hhIAW0C1vAr3c7c5Nzu9cuc+whwkkkZ+NeQZOfHMjHE16hnS+AIiQOxEJiBv0AAAAAElFTkSuQmCC');
}
#eqbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAwFBMVEUAAAD27X/QvErn2WH27oH0633v43Hj01vcyk7w5XDj02HbyVf28IPx53Xu4m7s4Gni0ljgz1TayUvq3Wfo2mPy53Tt4G7s3Wrt4Gn27oDx5nP48of274Li0lT38YT17H306nru4mv59Irz6Hbr32bq3GTl1ljfz07v5G3p2mHo2l7gzl3m2Fvgz1LOuEzXxEDeylrczEvLtEjbykfZx0TVwj7SvznQuzXKtS7j02HcyVHSvVDZx07dzEzNuDTMtzDLJSoKAAAAGHRSTlMA4Uvh0tLS0tJLS0vh4eHh4eHh0tJLS0sGkbICAAAA4klEQVQ4y83Sx9KCMBSG4SN2/XtNCCGEKgjYe7v/uzJRR8YZOePSd5l5FpkvgSet+/PdQUE1Dt5Q4A/7Jty0PCzms8F0EmU8TOMzcCi1CrDXYDKKeBgmARANhAYlyf7KA6x3Il9R0Gk0/u8cG62WAVhf2/UHCqJxHkJJc7WBBikEPumZniOoZdk2uwI10giycZ5AQKQGtABFPN/EgPWZ8SoKjGazC4/1V6+3UVBxnAoKKJE23KTemadJ7BNpmp5QgNjAmOtewU5/lOQy0gkwYK4CJVmyx/BLCvGCgnat9gvP1BGHfhnUEswA0wAAAABJRU5ErkJggg==');
}
#settingsbutton {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAB8lBMVEUAAACDbR+QdyKgkjzEqirCrDWReCCyp0WJciCJcyKYhzChkzqTgS3Vw0G6oSe6oSjRw0q1nCm8oy3TyFO4nyrIuEKxlyfHu0qiiSKegyGijCyRdyKmlziomjqklTexqEmvpkmKdiXFrCzJry7n3mLf0lLXxUPHrS7cz0/KrzDZy0rPuDfBpyrn32jSwEDKsjTEqi3BqCzIsDTp4264nynPv0Pj3GfWyU/c01yzmybh2mSulSS+pi/Zz1rBrDazmSiqkCXFt0Pa1GOliiOtkynNxFTZ0mOpkCrBtUmqkivIv1OpkyybgSK+s0rJwlqplzKUeyGQdx++tU6ypUHCu1WWfSOnmDjCvFexpkSahCqNdSGHcB+XgimonECAax7OtDDLsC7Hrivt42js4mXq3l3h0Uy8oC/38Xv07XPv5Wvt5GPs4mHn21jez1fm2FLXxVDUwUneyULLtEHbxT7JrzzFqDS/oDTUuTPDpjH59ILz63Hp3GLi1Vzf0Frh0lbby1DUwk/ezUfSvUPQu0PNszvBpTrZwDjVvDfKsDa7nTPVujLRtjHPtDG2mS+xlS7Jry3Eqiz27nfx6W/k12Dq4F7bylXYx07j1E3Qu0rhz0fMtkTJsUHcxz/Vvj/Otj/Eqj7NsTTRtjPHqjO+oDLApDC+pCyMAG9RAAAAX3RSTlMADUYD/NtgQy4hFxQK+fTt49/e1tTT0bizqGVOSEE8Jg8G/vz6+vr49/f29vX09PTz8vHv6efm5uXl4eDf2NXRysbCu7i1s6Keko+Li31zcXFwal9dWU9NS0s+OjcbEJmukO4AAAFySURBVDjLYhiCIJZdlguXnLyXrUpWdkpOXiqvnTcnhnSIVUZVUnXt1PyGGc3Nc9vahUJRpMON06uSJtfU5ubWTysomt9aVhrfzc8El2Z2q0zPrE5OTs5OURUwVSssbl9Q2pvWnygJU+BXOTEpc1KmsEcwN0+YjCKXlLtgfEJa39JENpgKp/SMDAv2CHEBjbzpM+do27gwSZskTEiUQNhhphskLzwlpa6+YNbskpKOhfFinAF81kiOVFBwTc6qyW/IL2ia11La2VkRryTByIjsDfak7Nw6YBDosbLql3f1LOmbwBKNGg6+WSk5orLMXFKRPMxMYgn9iYHoIQWYuLmMnChvYXFbl7o9B5OlJGZQczumNjaVtJaVVcQnOscxYFGglVpU1NKxqCKtN4GPEVtsyTUWFhuJiBjGJ7BwYI9Pf9YYBkYehihBNpzJwVOzvFvHB096ESpfnBbvgEcBo0FPPL8iviTHoczCiT9RskkzDEcAAG+FX5nDaQtoAAAAAElFTkSuQmCC');
}
.infowrap {
display: flex;
width: 400px;
justify-content: space-around;
font-size: 14px;
margin: 16px 0;
}
#volrange, .slider {
overflow: hidden;
width: 432px;
margin-top: 34px;
background: linear-gradient(to right, #bfa73e 0%, #bfa73e 0%, #272727 0%, #272727 100%);
border: solid 2px #e3d25f;
border-radius: 13px;
height: 25px!important;
outline: none;
transition: background 450ms ease-in;
-webkit-appearance: none;
-moz-appearance: none;
box-sizing: border-box;
}
#volrange::-webkit-slider-thumb, .slider::-webkit-slider-thumb {
width: 10px;
-webkit-appearance: none;
height: 10px;
cursor: ew-resize;
background-color: transparent;
border: 0;
}
#volrange::-moz-range-thumb, .slider::-moz-range-thumb {
width: 10px;
-moz-appearance: none;
height: 10px;
cursor: ew-resize;
background-color: transparent;
border: 0;
}
input[type=range]::-moz-range-track {
background-color: transparent;
}
.slider {
width: 400px;
margin-top: 4px;
}
#playlist {
width: 400px;
scroll-behavior: smooth;
overflow: auto;
margin: 0 0 0 0;
padding: 0;
list-style-type: none;
border: solid 1px #e3d25f;
flex: 1 1 auto;
overflow-y: auto;
height: 0px;
box-sizing: border-box;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAABOAQMAAAAw4lVwAAAABlBMVEUnJycAAADxyujSAAAADklEQVQI12OgLjhATQgAdZgdQbNqrBUAAAAASUVORK5CYII=');
scrollbar-color: #e3d25f #000;
scrollbar-width: thin;
}
#playlist::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: #000;
}
#playlist::-webkit-scrollbar-thumb {
background: #e3d25f;
}
#playlist li {
text-transform: uppercase;
font-size: 20px;
padding: 8px 16px;
color: #bfa73e;
cursor: pointer;
position: relative;
background: #000;
}
#playlist li span {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
right: 0;
top: 0;
bottom: 0;
padding: 0 10px;
background: #000;
width: 44px;
box-sizing: border-box;
text-align: right;
font-size: 14px;
vertical-align: middle;
}
#playlist li:nth-child(odd), #playlist li:nth-child(odd) span {
background: #272727;
}
#playlist li:hover, #playlist li:hover span {
color: #fff;
background: #323232;
}
#playlist li.active, #playlist li.active span {
background: #bfa73e;
color: #000;
}
#copy {
padding-top: 14px;
font-size: 14px;
}
@-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@media screen and (max-width: 480px) {
.content { padding: 20px; }
#playlist { width: 100%; }
#playlist li { font-size: 16px; }
#volrange { width: 100%; margin-top: 24px;}
.playerbyttonwrap { width: 100%; margin-top: 8px; }
#navbar { width: 100%; padding: 20px 20px 0 20px; }
#meta { margin-bottom: 8px; }
.infowrap {width: 100%; padding: 0 10px;}
.logo { width: 100px; height: 65px; background-size: cover; }
#copy { font-size: 10px; padding-top: 10px; }
}
@media screen and (max-width: 480px) {
.playerbytton, #playbutton {
width: 42px;
height: 42px;
background-size: 75%;
}
}

Binary file not shown.

View File

@@ -11,8 +11,9 @@
DspCore dsp; DspCore dsp;
Display display; Display display;
#ifndef DUMMYDISPLAY
void ticks() { void ticks() {
display.clockRequest = true; display.putRequest({CLOCK,0});
} }
#ifndef STARTTIME #ifndef STARTTIME
@@ -58,6 +59,10 @@ void ticks() {
#define DO_SCROLL (tWidth > (display.screenwidth - (dsp.fillSpaces?((texttop==0)?CLOCK_SPACE:VOL_SPACE):0))) #define DO_SCROLL (tWidth > (display.screenwidth - (dsp.fillSpaces?((texttop==0)?CLOCK_SPACE:VOL_SPACE):0)))
#endif #endif
#ifndef CORE_STACK_SIZE
#define CORE_STACK_SIZE 1024*3
#endif
byte currentScrollId = 0; /* one scroll on one time */ byte currentScrollId = 0; /* one scroll on one time */
void Scroll::init(byte ScrollId, const char *sep, byte tsize, byte top, uint16_t dlay, uint16_t fgcolor, uint16_t bgcolor) { void Scroll::init(byte ScrollId, const char *sep, byte tsize, byte top, uint16_t dlay, uint16_t fgcolor, uint16_t bgcolor) {
@@ -78,10 +83,6 @@ void Scroll::setText(const char *txt) {
memset(text, 0, BUFLEN / 2); memset(text, 0, BUFLEN / 2);
strlcpy(text, txt, BUFLEN / 2 - 1); strlcpy(text, txt, BUFLEN / 2 - 1);
getbounds(textwidth, textheight, sepwidth); getbounds(textwidth, textheight, sepwidth);
if (doscroll) {
memset(text2, 0, BUFLEN + 10);
sprintf(text2, "%s%s%s", text, separator, text);
}
if (!locked) { if (!locked) {
clearscrolls(); clearscrolls();
reset(); reset();
@@ -103,7 +104,7 @@ void Scroll::reset() {
clear(); clear();
setTextParams(); setTextParams();
dsp.set_Cursor(TFT_FRAMEWDT, texttop); dsp.set_Cursor(TFT_FRAMEWDT, texttop);
dsp.printText(doscroll ? text2 : text); dsp.printText(text);
drawFrame(); drawFrame();
if (currentScrollId == id) currentScrollId = 0; if (currentScrollId == id) currentScrollId = 0;
} }
@@ -133,7 +134,6 @@ void Scroll::loop() {
scroll(); scroll();
sticks(); sticks();
} }
yield();
} }
boolean Scroll::checkdelay(int m, unsigned long &tstamp) { boolean Scroll::checkdelay(int m, unsigned long &tstamp) {
@@ -154,10 +154,9 @@ void Scroll::sticks() {
if (!doscroll || locked || textsize == 0) return; if (!doscroll || locked || textsize == 0) return;
setTextParams(); setTextParams();
dsp.set_Cursor(x, texttop); dsp.set_Cursor(x, texttop);
dsp.printText(text2); dsp.printText(text);
dsp.printText(separator);
//dsp.printText(separator); dsp.printText(text);
//dsp.printText(text);
if (x == TFT_FRAMEWDT) drawFrame(); if (x == TFT_FRAMEWDT) drawFrame();
} }
@@ -191,6 +190,33 @@ void Scroll::getbounds(uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
doscroll = DO_SCROLL; doscroll = DO_SCROLL;
} }
TaskHandle_t TaskCore0;
QueueHandle_t displayQueue;
void Display::createCore0Task(){
xTaskCreatePinnedToCore(
loopCore0, /* Task function. */
"TaskCore0", /* name of task. */
CORE_STACK_SIZE, /* Stack size of task */
NULL, /* parameter of the task */
4, /* no one flies higher than the Toruk */
&TaskCore0, /* Task handle to keep track of created task */
!xPortGetCoreID()); /* pin task to core 0 */
//delay(500);
}
void loopCore0( void * pvParameters ){
delay(500);
while(!display.busy){
if(displayQueue==NULL) break;
display.loop();
vTaskDelay(10);
}
vTaskDelete( NULL );
TaskCore0=NULL;
}
void Display::init() { void Display::init() {
dsp.initD(screenwidth, screenheight); dsp.initD(screenwidth, screenheight);
dsp.drawLogo(); dsp.drawLogo();
@@ -213,24 +239,43 @@ void Display::apScreen() {
dsp.apScreen(); dsp.apScreen();
} }
void Display::start() { void Display::stop() {
busy = true;
swichMode(PLAYER);
timer.detach();
resetQueue();
vQueueDelete(displayQueue);
displayQueue=NULL;
delay(100);
bootLogo();
bootString("reloading", 1);
busy = false;
}
void Display::start(bool reboot) {
busy = false;
displayQueue = xQueueCreate( 5, sizeof( requestParams_t ) );
createCore0Task();
clear(); clear();
if (network.status != CONNECTED) { if (network.status != CONNECTED) {
apScreen(); apScreen();
return; return;
} }
mode = PLAYER; mode = PLAYER;
config.setTitle("[READY]"); if(!reboot){
//title("[READY]"); config.setTitle("[READY]");
loop(); //loop();
}
ip(); ip();
volume(); volume();
station(); station();
rssi(); rssi();
time(); time(reboot);
if(reboot) title();
timer.attach_ms(1000, ticks); timer.attach_ms(1000, ticks);
if (dsp_on_start) dsp_on_start(&dsp); if (dsp_on_start) dsp_on_start(&dsp);
// Экстреминатус секвестирован /*дважды*/ /*трижды*/ четырежды // Экстреминатус секвестирован /*дважды*/ /*трижды*/ /*четырежды*/ пятирежды
} }
void Display::clear() { void Display::clear() {
@@ -253,7 +298,7 @@ void Display::swichMode(displayMode_e newmode) {
meta.reset(); meta.reset();
title1.reset(); title1.reset();
if (TITLE_SIZE2 != 0) title2.reset(); if (TITLE_SIZE2 != 0) title2.reset();
player.loop(); //player.loop();
plCurrent.lock(); plCurrent.lock();
time(true); time(true);
#ifdef CLOCK_SPACE // if set space for clock in 1602 displays #ifdef CLOCK_SPACE // if set space for clock in 1602 displays
@@ -314,26 +359,14 @@ void Display::drawVolume() {
} }
} }
TaskHandle_t drawPlaylistTaskHandle = NULL; void Display::resetQueue(){
bool taskDone = true; xQueueReset(displayQueue);
void getPlaylist( void * pvParameters ) {
char buf[PLMITEMLENGHT];
display.plCurrent.lockRequest = true;
dsp.drawPlaylist(display.currentPlItem, buf);
display.plCurrent.setText(dsp.utf8Rus(buf, true));
taskDone = true;
vTaskDelete( NULL );
} }
void Display::drawPlaylist() { void Display::drawPlaylist() {
while (!taskDone) player.loop(); char buf[PLMITEMLENGHT];
taskDone = false; dsp.drawPlaylist(currentPlItem, buf);
xTaskCreatePinnedToCore(getPlaylist, "getPlaylist0", 4096, NULL, 1, &drawPlaylistTaskHandle, 0); plCurrent.setText(dsp.utf8Rus(buf, true));
/*
char buf[PLMITEMLENGHT];
dsp.drawPlaylist(currentPlItem, buf);
plCurrent.setText(dsp.utf8Rus(buf, true));
*/
} }
void Display::drawNextStationNum(uint16_t num) { void Display::drawNextStationNum(uint16_t num) {
@@ -345,7 +378,55 @@ void Display::drawNextStationNum(uint16_t num) {
dsp.drawNextStationNum(num); dsp.drawNextStationNum(num);
} }
void Display::putRequest(requestParams_t request){
if(displayQueue==NULL) return;
xQueueSend(displayQueue, &request, portMAX_DELAY);
}
void Display::loop() { void Display::loop() {
if(displayQueue==NULL) return;
requestParams_t request;
if(xQueueReceive(displayQueue, &request, 20)){
switch (request.type){
case NEWMODE: {
swichMode((displayMode_e)request.payload);
break;
}
case CLOCK: {
clockRequest = true;
break;
}
case NEWTITLE: {
title();
break;
}
case RETURNTITLE: {
returnTile();
break;
}
case NEWSTATION: {
station();
break;
}
case NEXTSTATION: {
drawNextStationNum((displayMode_e)request.payload);
break;
}
case DRAWPLAYLIST: {
int p = request.payload ? currentPlItem + 1 : currentPlItem - 1;
if (p < 1) p = config.store.countStation;
if (p > config.store.countStation) p = 1;
currentPlItem = p;
drawPlaylist();
break;
}
case DRAWVOL: {
volume();
break;
}
}
}
switch (mode) { switch (mode) {
case PLAYER: { case PLAYER: {
drawPlayer(); drawPlayer();
@@ -365,8 +446,7 @@ void Display::loop() {
} }
} }
dsp.loop(); dsp.loop();
if (dsp_on_loop) dsp_on_loop(); if (dsp_on_loop) dsp_on_loop(&dsp);
yield();
} }
void Display::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) { void Display::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
@@ -374,6 +454,7 @@ void Display::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
} }
void Display::bootString(const char* text, byte y) { void Display::bootString(const char* text, byte y) {
dsp.set_TextSize(1);
dsp.centerText(text, y == 1 ? BOOTSTR_TOP1 : BOOTSTR_TOP2, TFT_LOGO, TFT_BG); dsp.centerText(text, y == 1 ? BOOTSTR_TOP1 : BOOTSTR_TOP2, TFT_LOGO, TFT_BG);
dsp.loop(true); dsp.loop(true);
} }
@@ -392,7 +473,7 @@ void Display::station() {
#ifdef DEBUG_TITLES #ifdef DEBUG_TITLES
meta.setText(dsp.utf8Rus("Utenim adminim veniam FM", true)); meta.setText(dsp.utf8Rus("Utenim adminim veniam FM", true));
#endif #endif
dsp.loop(true); //dsp.loop(true);
//netserver.requestOnChange(STATION, 0); //netserver.requestOnChange(STATION, 0);
} }
@@ -402,7 +483,7 @@ void Display::returnTile() {
meta.setText(dsp.utf8Rus("Utenim adminim veniam FM", true)); meta.setText(dsp.utf8Rus("Utenim adminim veniam FM", true));
#endif #endif
meta.reset(); meta.reset();
dsp.loop(true); //dsp.loop(true);
} }
void Display::title() { void Display::title() {
@@ -429,7 +510,7 @@ void Display::title() {
title1.setText(dsp.utf8Rus(ttl, true)); title1.setText(dsp.utf8Rus(ttl, true));
if (TITLE_SIZE2 != 0) title2.setText(dsp.utf8Rus(sng, true)); if (TITLE_SIZE2 != 0) title2.setText(dsp.utf8Rus(sng, true));
dsp.loop(true); //dsp.loop(true);
} }
//netserver.requestOnChange(TITLE, 0); //netserver.requestOnChange(TITLE, 0);
} }
@@ -488,22 +569,9 @@ void Display::time(bool redraw) {
if (dsp_after_clock) dsp_after_clock(&dsp, dt); if (dsp_after_clock) dsp_after_clock(&dsp, dt);
} }
TaskHandle_t drawVolumeTaskHandle = NULL; void Display::volume() {
bool taskVDone = true; dsp.drawVolumeBar(mode == VOL);
void drawVolumeTask( void * pvParameters ) { //netserver.requestOnChange(VOLUME, 0);
delay(50); /* but it's too fast 0__o */
dsp.drawVolumeBar(true);
taskVDone = true;
vTaskDelete( NULL );
} }
void Display::volume() { #endif // DUMMYDISPLAY
if (mode == VOL) {
while (!taskVDone) player.loop();
taskVDone = false;
xTaskCreatePinnedToCore(drawVolumeTask, "drawVolumeTask0", 2048, NULL, 1, &drawVolumeTaskHandle, 0);
} else {
dsp.drawVolumeBar(false);
}
netserver.requestOnChange(VOLUME, 0);
}

View File

@@ -37,6 +37,16 @@
enum displayMode_e { PLAYER, VOL, STATIONS, NUMBERS, LOST }; enum displayMode_e { PLAYER, VOL, STATIONS, NUMBERS, LOST };
enum displayRequestType_e { NEWMODE, CLOCK, NEWTITLE, RETURNTITLE, NEWSTATION, NEXTSTATION, DRAWPLAYLIST, DRAWVOL };
struct requestParams_t
{
displayRequestType_e type;
int payload;
};
#ifndef DUMMYDISPLAY
void loopCore0( void * pvParameters );
class Scroll { class Scroll {
public: public:
Scroll() { }; Scroll() { };
@@ -50,7 +60,6 @@ class Scroll {
private: private:
byte textsize, texttop, id; byte textsize, texttop, id;
char text[BUFLEN/2]; char text[BUFLEN/2];
char text2[BUFLEN+10];
char separator[4]; char separator[4];
uint16_t fg, bg; uint16_t fg, bg;
uint16_t delayStartScroll; uint16_t delayStartScroll;
@@ -67,37 +76,51 @@ class Scroll {
void setTextParams(); void setTextParams();
void drawFrame(); void drawFrame();
}; };
#endif
class Display { class Display {
public: public:
bool clockRequest;
uint16_t screenwidth, screenheight; uint16_t screenwidth, screenheight;
displayMode_e mode; displayMode_e mode;
uint16_t currentPlItem; uint16_t currentPlItem;
uint16_t numOfNextStation; uint16_t numOfNextStation;
#ifndef DUMMYDISPLAY
Scroll plCurrent; Scroll plCurrent;
#endif
bool busy;
public: public:
Display() {}; Display() {};
#ifndef DUMMYDISPLAY
void init(); void init();
void clear();
void loop(); void loop();
void start(); void start(bool reboot=false);
void station(); void stop();
void title(); void resetQueue();
void volume();
void centerText(const char* text, byte y, uint16_t fg, uint16_t bg); void centerText(const char* text, byte y, uint16_t fg, uint16_t bg);
void rightText(const char* text, byte y, uint16_t fg, uint16_t bg); void rightText(const char* text, byte y, uint16_t fg, uint16_t bg);
void bootString(const char* text, byte y); void bootString(const char* text, byte y);
void bootLogo(); void bootLogo();
void returnTile(); void putRequest(requestParams_t request);
void swichMode(displayMode_e newmode); #else
void drawPlaylist(); void init(){};
void drawNextStationNum(uint16_t num); void loop(){};
void start(bool reboot=false){};
void stop(){};
void resetQueue(){};
void centerText(const char* text, byte y, uint16_t fg, uint16_t bg){};
void rightText(const char* text, byte y, uint16_t fg, uint16_t bg){};
void bootString(const char* text, byte y){};
void bootLogo(){};
void putRequest(requestParams_t request){};
#endif
#ifndef DUMMYDISPLAY
private: private:
Ticker timer; Ticker timer;
Scroll meta, title1, title2; Scroll meta, title1, title2;
bool clockRequest;
bool dt; // dots bool dt; // dots
unsigned long volDelay; unsigned long volDelay;
void clear();
void heap(); void heap();
void rssi(); void rssi();
void ip(); void ip();
@@ -106,6 +129,15 @@ class Display {
void drawPlayer(); void drawPlayer();
void drawVolume(); void drawVolume();
void checkConnection(); void checkConnection();
void swichMode(displayMode_e newmode);
void drawPlaylist();
void volume();
void title();
void station();
void drawNextStationNum(uint16_t num);
void returnTile();
void createCore0Task();
#endif
}; };
extern Display display; extern Display display;
@@ -113,7 +145,7 @@ extern Display display;
extern __attribute__((weak)) bool dsp_before_clock(DspCore *dsp, bool dots); extern __attribute__((weak)) bool dsp_before_clock(DspCore *dsp, bool dots);
extern __attribute__((weak)) void dsp_after_clock(DspCore *dsp, bool dots); extern __attribute__((weak)) void dsp_after_clock(DspCore *dsp, bool dots);
extern __attribute__((weak)) void dsp_on_init(); extern __attribute__((weak)) void dsp_on_init();
extern __attribute__((weak)) void dsp_on_loop(); extern __attribute__((weak)) void dsp_on_loop(DspCore *dsp);
extern __attribute__((weak)) void dsp_on_start(DspCore *dsp); extern __attribute__((weak)) void dsp_on_start(DspCore *dsp);
extern __attribute__((weak)) void dsp_on_newmode(displayMode_e newmode); extern __attribute__((weak)) void dsp_on_newmode(displayMode_e newmode);

View File

@@ -9,6 +9,10 @@
#include "network.h" #include "network.h"
#include "mqtt.h" #include "mqtt.h"
#ifndef MIN_MALLOC
#define MIN_MALLOC 24112
#endif
NetServer netserver; NetServer netserver;
AsyncWebServer webserver(80); AsyncWebServer webserver(80);
@@ -27,9 +31,21 @@ bool NetServer::begin() {
webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
ssidCount = 0; ssidCount = 0;
int mcb = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int mci = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
log_i("[yoradio] webserver.on / - MALLOC_CAP_INTERNAL=%d, MALLOC_CAP_8BIT=%d", mci, mcb);
netserver.resumePlay = mcb < MIN_MALLOC;
if (netserver.resumePlay) {
player.toggle();
while (player.isRunning()) {
delay(10);
}
}
request->send(SPIFFS, "/www/index.html", String(), false, processor); request->send(SPIFFS, "/www/index.html", String(), false, processor);
}); });
webserver.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=31536000"); webserver.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=31536000");
webserver.on("/", HTTP_POST, [](AsyncWebServerRequest * request) { webserver.on("/", HTTP_POST, [](AsyncWebServerRequest * request) {
handleHTTPPost(request); handleHTTPPost(request);
}); });
@@ -71,10 +87,9 @@ void NetServer::loop() {
} }
importRequest = false; importRequest = false;
} }
if(rssi<255){ if (rssi < 255) {
requestOnChange(NRSSI, 0); requestOnChange(NRSSI, 0);
} }
yield();
} }
void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len) { void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len) {
@@ -97,28 +112,17 @@ void NetServer::setRSSI(int val) {
} }
void NetServer::getPlaylist(uint8_t clientId) { void NetServer::getPlaylist(uint8_t clientId) {
String dataString = ""; char buf[160] = {0};
File file = SPIFFS.open(PLAYLIST_PATH, "r"); sprintf(buf, "{\"file\": \"http://%s%s\"}", WiFi.localIP().toString().c_str(), PLAYLIST_PATH);
if (!file || file.isDirectory()) { if (clientId == 0) {
return; websocket.textAll(buf);
} else {
websocket.text(clientId, buf);
} }
char sName[BUFLEN], sUrl[BUFLEN], pOvol[30]; if (resumePlay) {
int sOvol; resumePlay = false;
while (file.available()) { player.toggle();
String line = file.readStringUntil('\n');
if (config.parseCSV(line.c_str(), sName, sUrl, sOvol)) {
sprintf(pOvol, "%d", sOvol);
dataString += "{\"name\":\"" + String(sName) + "\",\"url\":\"" + String(sUrl) + "\",\"ovol\":" + String(pOvol) + "},";
}
} }
if (dataString.length() > 0) {
if (clientId == 0) {
websocket.textAll("{\"file\": [" + dataString.substring(0, dataString.length() - 1) + "]}");
} else {
websocket.text(clientId, "{\"file\": [" + dataString.substring(0, dataString.length() - 1) + "]}");
}
}
file.close();
} }
bool NetServer::savePlaylist(const char* post) { bool NetServer::savePlaylist(const char* post) {
@@ -222,7 +226,7 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) {
} }
case NRSSI: { case NRSSI: {
sprintf (buf, "{\"rssi\": %d}", rssi); sprintf (buf, "{\"rssi\": %d}", rssi);
rssi=255; rssi = 255;
break; break;
} }
case BITRATE: { case BITRATE: {
@@ -293,6 +297,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
switch (type) { switch (type) {
case WS_EVT_CONNECT: case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
netserver.requestOnChange(STATION, client->id()); netserver.requestOnChange(STATION, client->id());
netserver.requestOnChange(TITLE, client->id()); netserver.requestOnChange(TITLE, client->id());
netserver.requestOnChange(VOLUME, client->id()); netserver.requestOnChange(VOLUME, client->id());
@@ -301,6 +306,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
netserver.requestOnChange(BITRATE, client->id()); netserver.requestOnChange(BITRATE, client->id());
netserver.requestOnChange(MODE, client->id()); netserver.requestOnChange(MODE, client->id());
netserver.playlistrequest = client->id(); netserver.playlistrequest = client->id();
break; break;
case WS_EVT_DISCONNECT: case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id()); Serial.printf("WebSocket client #%u disconnected\n", client->id());

View File

@@ -11,6 +11,7 @@ class NetServer {
public: public:
uint8_t playlistrequest; // ClientId want the playlist uint8_t playlistrequest; // ClientId want the playlist
bool importRequest; bool importRequest;
bool resumePlay;
public: public:
NetServer() {}; NetServer() {};
bool begin(); bool begin();
@@ -22,6 +23,7 @@ class NetServer {
private: private:
requestType_e request; requestType_e request;
int rssi; int rssi;
void getPlaylist(uint8_t clientId); void getPlaylist(uint8_t clientId);
bool importPlaylist(); bool importPlaylist();
}; };

View File

@@ -1,7 +1,7 @@
#ifndef options_h #ifndef options_h
#define options_h #define options_h
#define VERSION "0.6.121" #define VERSION "0.6.200"
/******************************************************* /*******************************************************
DO NOT EDIT THIS FILE. DO NOT EDIT THIS FILE.
@@ -209,6 +209,7 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti
INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html
See this note If INITR_BLACKTAB have a noisy line on one side of the screen https://github.com/e2002/yoradio#note-if-initr_blacktab-dsp-have-a-noisy-line-on-one-side-of-the-screen-then-in-adafruit_st7735cpp See this note If INITR_BLACKTAB have a noisy line on one side of the screen https://github.com/e2002/yoradio#note-if-initr_blacktab-dsp-have-a-noisy-line-on-one-side-of-the-screen-then-in-adafruit_st7735cpp
INITR_144GREENTAB // 1.44' https://aliexpress.ru/item/1005002822797745.html INITR_144GREENTAB // 1.44' https://aliexpress.ru/item/1005002822797745.html
INITR_MINI160x80 // 0.96' 160x80 ST7735S https://????
INITR_GREENTAB INITR_GREENTAB
INITR_REDTAB INITR_REDTAB
*/ */

View File

@@ -59,10 +59,10 @@ void Player::loop() {
if (isRunning()) { if (isRunning()) {
//digitalWrite(LED_BUILTIN, LOW); //digitalWrite(LED_BUILTIN, LOW);
setOutputPins(false); setOutputPins(false);
//display.title("[stopped]");
config.setTitle(display.mode==LOST?"":"[stopped]"); config.setTitle(display.mode==LOST?"":"[stopped]");
netserver.requestOnChange(TITLE, 0); netserver.requestOnChange(TITLE, 0);
stopSong(); //stopSong();
setDefaults();
stopInfo(); stopInfo();
} }
} }
@@ -78,7 +78,8 @@ void Player::loop() {
telnet.printf("##CLI.VOL#: %d\n", config.store.volume); telnet.printf("##CLI.VOL#: %d\n", config.store.volume);
Audio::setVolume(volToI2S(request.volume)); Audio::setVolume(volToI2S(request.volume));
zeroRequest(); zeroRequest();
display.volume(); display.putRequest({DRAWVOL, 0});
netserver.requestOnChange(VOLUME, 0);
} }
} }
@@ -94,17 +95,17 @@ void Player::setOutputPins(bool isPlaying) {
} }
void Player::play(uint16_t stationId) { void Player::play(uint16_t stationId) {
stopSong(); //stopSong();
setDefaults();
setOutputPins(false); setOutputPins(false);
config.setTitle("[connecting]"); config.setTitle("[connecting]");
netserver.requestOnChange(TITLE, 0); netserver.requestOnChange(TITLE, 0);
//telnet.printf("##CLI.META#: %s\n", config.station.title); //telnet.printf("##CLI.META#: %s\n", config.station.title);
config.loadStation(stationId); config.loadStation(stationId);
setVol(config.store.volume, true); setVol(config.store.volume, true);
display.station(); display.putRequest({NEWSTATION, 0});
netserver.requestOnChange(STATION, 0); netserver.requestOnChange(STATION, 0);
telnet.printf("##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name); telnet.printf("##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name);
display.loop();
if (connecttohost(config.station.url)) { if (connecttohost(config.station.url)) {
mode = PLAYING; mode = PLAYING;
config.setSmartStart(1); config.setSmartStart(1);
@@ -113,8 +114,7 @@ void Player::play(uint16_t stationId) {
requestToStart = true; requestToStart = true;
}else{ }else{
Serial.println("some unknown bug..."); Serial.println("some unknown bug...");
} };
display.loop();
} }
void Player::prev() { void Player::prev() {

View File

@@ -21,7 +21,6 @@
* BSD license, all text here must be included in any redistribution. * BSD license, all text here must be included in any redistribution.
* *
*/ */
#include "../../options.h" #include "../../options.h"
#if DSP_MODEL==DSP_GC9106 #if DSP_MODEL==DSP_GC9106

View File

@@ -3614,7 +3614,7 @@ void Audio::showstreamtitle(const char* ml) {
} }
free(sTit); free(sTit);
} }
sTit_remember = 0;
idx1 = indexOf(ml, "StreamUrl=", 0); idx1 = indexOf(ml, "StreamUrl=", 0);
idx2 = indexOf(ml, ";", idx1); idx2 = indexOf(ml, ";", idx1);
if(idx1 >= 0 && idx2 > idx1){ // StreamURL found if(idx1 >= 0 && idx2 > idx1){ // StreamURL found
@@ -4246,7 +4246,7 @@ void Audio::setBalance(int8_t bal){ // bal -16...16
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void Audio::setVolume(uint8_t vol) { // vol 22 steps, 0...21 void Audio::setVolume(uint8_t vol) { // vol 22 steps, 0...21
if(vol > 255) vol = 255; if(vol > 255) vol = 254;
//volume = map(eeprom_config.volume, 0, 21, 0, 255); //volume = map(eeprom_config.volume, 0, 21, 0, 255);
//m_vol = map(vol, 0, 254, 0, 64); //m_vol = map(vol, 0, 254, 0, 64);
m_vol = vol; m_vol = vol;

View File

@@ -185,6 +185,7 @@ public:
uint32_t getAudioFileDuration(); uint32_t getAudioFileDuration();
uint32_t getAudioCurrentTime(); uint32_t getAudioCurrentTime();
uint32_t getTotalPlayingTime(); uint32_t getTotalPlayingTime();
void setDefaults();
esp_err_t i2s_mclk_pin_select(const uint8_t pin); esp_err_t i2s_mclk_pin_select(const uint8_t pin);
uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
@@ -197,7 +198,7 @@ private:
void UTF8toASCII(char* str); void UTF8toASCII(char* str);
bool latinToUTF8(char* buff, size_t bufflen); bool latinToUTF8(char* buff, size_t bufflen);
void httpPrint(const char* url); void httpPrint(const char* url);
void setDefaults(); // free buffers and set defaults //void setDefaults(); // free buffers and set defaults
void initInBuff(); void initInBuff();
void processLocalFile(); void processLocalFile();
void processWebStream(); void processWebStream();

View File

@@ -536,7 +536,7 @@ void Audio::showstreamtitle(const char* ml) {
} }
free(sTit); free(sTit);
} }
sTit_remember = 0;
idx1 = indexOf(ml, "StreamUrl=", 0); idx1 = indexOf(ml, "StreamUrl=", 0);
idx2 = indexOf(ml, ";", idx1); idx2 = indexOf(ml, ";", idx1);
if(idx1 >= 0 && idx2 > idx1){ // StreamURL found if(idx1 >= 0 && idx2 > idx1){ // StreamURL found

View File

@@ -237,7 +237,7 @@ protected:
bool readMetadata(uint8_t b, bool first = false); bool readMetadata(uint8_t b, bool first = false);
void UTF8toASCII(char* str); void UTF8toASCII(char* str);
void unicode2utf8(char* buff, uint32_t len); void unicode2utf8(char* buff, uint32_t len);
void setDefaults(); //void setDefaults();
void loadUserCode(); void loadUserCode();
@@ -271,7 +271,7 @@ public:
bool isRunning() {/*Serial.printf("m_f_running=%d\n", m_f_running); */return m_f_running;} bool isRunning() {/*Serial.printf("m_f_running=%d\n", m_f_running); */return m_f_running;}
void setBalance(int8_t bal = 0); void setBalance(int8_t bal = 0);
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass); void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
void setDefaults();
// implement several function with respect to the index of string // implement several function with respect to the index of string
bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;} bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;}
bool endsWith (const char* base, const char* str) { bool endsWith (const char* base, const char* str) {

View File

@@ -9,7 +9,7 @@
#include "../../network.h" #include "../../network.h"
#ifndef DEF_SPI_FREQ #ifndef DEF_SPI_FREQ
#define DEF_SPI_FREQ 16000000UL /* set it to 0 for system default */ #define DEF_SPI_FREQ 8000000UL /* set it to 0 for system default */
#endif #endif
DspCore::DspCore(): Adafruit_GC9106Ex(TFT_CS, TFT_DC, TFT_RST) { DspCore::DspCore(): Adafruit_GC9106Ex(TFT_CS, TFT_DC, TFT_RST) {
@@ -113,7 +113,10 @@ void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
cp437(true); cp437(true);
invertDisplay(!TFT_INVERT); invertDisplay(!TFT_INVERT);
fillScreen(TFT_BG); fillScreen(TFT_BG);
setRotation(TFT_ROTATE); byte tftRotate = TFT_ROTATE;
if(tftRotate>1) tftRotate=3;
if(tftRotate==0) tftRotate=1;
setRotation(tftRotate);
setTextWrap(false); setTextWrap(false);
screenwidth = width(); screenwidth = width();
screenheight = height(); screenheight = height();

View File

@@ -16,7 +16,7 @@
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 3 #define SCROLLDELTA 3
#define SCROLLTIME 65 #define SCROLLTIME 30
#endif #endif
#define TFT_FULLTIME 1 #define TFT_FULLTIME 1

View File

@@ -14,8 +14,8 @@
#define TITLE_SIZE2 2 #define TITLE_SIZE2 2
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 4 #define SCROLLDELTA 3
#define SCROLLTIME 40 #define SCROLLTIME 30
#endif #endif
#define PLMITEMS 9 #define PLMITEMS 9

View File

@@ -14,8 +14,8 @@
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
//#define SCROLLDELTA 8 //#define SCROLLDELTA 8
//#define SCROLLTIME 332 //#define SCROLLTIME 332
#define SCROLLDELTA 4 #define SCROLLDELTA 5
#define SCROLLTIME 250 #define SCROLLTIME 200
#endif #endif
#define META_SIZE 1 #define META_SIZE 1

View File

@@ -20,8 +20,8 @@
#endif #endif
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 3 #define SCROLLDELTA 2
#define SCROLLTIME 60 #define SCROLLTIME 35
#endif #endif
#if DSP_MODEL==DSP_SH1106 #if DSP_MODEL==DSP_SH1106

View File

@@ -18,8 +18,8 @@
#define TFT_FULLTIME 1 #define TFT_FULLTIME 1
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 3 #define SCROLLDELTA 2
#define SCROLLTIME 83 #define SCROLLTIME 35
#endif #endif
class DspCore: public Adafruit_SSD1305 { class DspCore: public Adafruit_SSD1305 {

View File

@@ -337,7 +337,7 @@ void DspCore::printText(const char* txt) {
} }
void DspCore::loop(bool force) { void DspCore::loop(bool force) {
if (checkdelay(83, loopdelay) || force) { if (checkdelay(SCROLLTIME, loopdelay) || force) {
#if DSP_MODEL==DSP_SSD1306x32 #if DSP_MODEL==DSP_SSD1306x32
if(fillSpaces) printClock(insideClc); if(fillSpaces) printClock(insideClc);
#endif #endif

View File

@@ -11,7 +11,7 @@
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 2 #define SCROLLDELTA 2
#define SCROLLTIME 40 #define SCROLLTIME 35
#endif #endif
#if DSP_MODEL==DSP_SSD1306 #if DSP_MODEL==DSP_SSD1306

View File

@@ -3,7 +3,7 @@
#include "displaySSD1327.h" #include "displaySSD1327.h"
#include <Wire.h> #include <Wire.h>
#include "fonts/bootlogo.h" #include "fonts/bootlogobw.h"
#include "../../player.h" #include "../../player.h"
#include "../../config.h" #include "../../config.h"
#include "../../network.h" #include "../../network.h"
@@ -133,7 +133,7 @@ void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
} }
void DspCore::drawLogo() { void DspCore::drawLogo() {
drawRGBBitmap((swidth - 99) / 2, 18, bootlogo2, 99, 64); drawGrayscaleBitmap((swidth - 99) / 2, 18, bootlogobw, 99, 64);
} }
#define CLR_ITEM1 0xA #define CLR_ITEM1 0xA
@@ -159,7 +159,7 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
print(utf8Rus(plMenu[i], true)); print(utf8Rus(plMenu[i], true));
} }
} }
display(); //display();
} }
void DspCore::clearDsp() { void DspCore::clearDsp() {
@@ -197,7 +197,7 @@ void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
setCursor((swidth - w) / 2, y); setCursor((swidth - w) / 2, y);
fillRect(0, y, swidth, h, bg); fillRect(0, y, swidth, h, bg);
print(txt); print(txt);
display(); //display();
} }
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) { void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
@@ -212,7 +212,23 @@ void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
} }
void DspCore::displayHeapForDebug() { void DspCore::displayHeapForDebug() {
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT * 2 - 2;
setTextSize(1);
setTextColor(DARK_GRAY, TFT_BG);
setCursor(TFT_FRAMEWDT, vTop);
fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, TFT_BG);
print(ESP.getFreeHeap());
print(" / ");
print(ESP.getMaxAllocHeap());
#if VS1053_CS==255
// audio buffer;
fillRect(0, sheight - 2, swidth, 2, TFT_BG);
int astored = player.inBufferFilled();
int afree = player.inBufferFree();
int aprcnt = 100 * astored / (astored + afree);
byte sbw = map(aprcnt, 0, 100 , 0, swidth);
fillRect(0, sheight - 2, sbw, 2, DARK_GRAY);
#endif
} }
void DspCore::setClockBounds(){ void DspCore::setClockBounds(){
@@ -226,7 +242,7 @@ void DspCore::setClockBounds(){
} }
void DspCore::printClock(const char* timestr) { void DspCore::printClock(const char* timestr) {
uint16_t ncwidth, ncheight; /* uint16_t ncwidth, ncheight;
setFont(&DS_DIGI28pt7b); setFont(&DS_DIGI28pt7b);
setTextSize(1); setTextSize(1);
getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot); getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot);
@@ -240,11 +256,60 @@ void DspCore::printClock(const char* timestr) {
setCursor((swidth - ncwidth) / 2 - 4, clockY+28+6); setCursor((swidth - ncwidth) / 2 - 4, clockY+28+6);
print(timestr); print(timestr);
setFont(); setFont();
//display();*/
}
byte DspCore::getPw(uint16_t ncwidth){
byte pw = 6;
if(ncwidth<35) pw = 7;
if(ncwidth<20) pw = 8;
return pw;
}
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
char timeBuf[50] = { 0 };
char tmpBuf[4] = { 0 };
uint16_t ncwidth, ncheight;
strftime(timeBuf, sizeof(timeBuf), "%H %M", &timeinfo);
setTextSize(1);
setFont(&DS_DIGI28pt7b);
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot);
setCursor((swidth - wot) / 2 - 4, clockY+28+6);
setTextColor(TFT_BG);
print(oldTimeBuf);
dot = (swidth - wot) / 2 - 4;
/* dots */
strlcpy(tmpBuf, oldTimeBuf, 3);
getTextBounds(tmpBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
dot = dot + ncwidth + getPw(ncwidth);
setCursor(dot, clockY+28+6);
print(":");
/* dots */
strlcpy(oldTimeBuf, timeBuf, 20);
setTextSize(1);
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
setTextColor(TFT_LOGO);
setCursor((swidth - ncwidth) / 2 - 4, clockY+28+6);
dot = (swidth - ncwidth) / 2 - 4;
setTextSize(1);
print(timeBuf);
/* dots */
strftime(timeBuf, sizeof(timeBuf), "%H", &timeinfo);
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
dot = dot + ncwidth + getPw(ncwidth);
/* dots */
}
setCursor(dot, clockY+28+6);
setTextColor(dots?TFT_BG:TFT_LOGO);
print(":");
setFont();
display(); display();
} }
void DspCore::drawVolumeBar(bool withNumber) { void DspCore::drawVolumeBar(bool withNumber) {
if (withNumber) delay(150); /* buuuut iiiiit's toooooo faaaast 0000__oooo !!111 ommm____nomm____nomm */ //if (withNumber) delay(150); /* buuuut iiiiit's toooooo faaaast 0000__oooo !!111 ommm____nomm____nomm */
int16_t vTop = sheight - TFT_FRAMEWDT * 2; int16_t vTop = sheight - TFT_FRAMEWDT * 2;
int16_t vWidth = swidth - TFT_FRAMEWDT - 4; int16_t vWidth = swidth - TFT_FRAMEWDT - 4;
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2); uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
@@ -267,7 +332,7 @@ void DspCore::drawVolumeBar(bool withNumber) {
print(volstr); print(volstr);
setFont(); setFont();
} }
display(); //display();
} }
void DspCore::drawNextStationNum(uint16_t num) { void DspCore::drawNextStationNum(uint16_t num) {
@@ -283,7 +348,7 @@ void DspCore::drawNextStationNum(uint16_t num) {
setCursor((swidth - wv) / 2, 48 + hv); setCursor((swidth - wv) / 2, 48 + hv);
print(numstr); print(numstr);
setFont(); setFont();
display(); //display();
} }
void DspCore::frameTitle(const char* str) { void DspCore::frameTitle(const char* str) {
@@ -320,12 +385,12 @@ void DspCore::set_Cursor(int16_t x, int16_t y) {
void DspCore::printText(const char* txt) { void DspCore::printText(const char* txt) {
print(txt); print(txt);
display(); //display();
} }
void DspCore::loop(bool force) { void DspCore::loop(bool force) {
if (checkdelay(LOOP_DELAY, loopdelay) || force) { if (checkdelay(LOOP_DELAY, loopdelay) || force) {
//display(); display();
} }
yield(); yield();
} }

View File

@@ -30,11 +30,16 @@
#endif #endif
*/ */
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 4 /*#define SCROLLDELTA 5
#define SCROLLTIME 83 #define SCROLLTIME 83
#define LOOP_DELAY 60 #define LOOP_DELAY 100*/
#define SCROLLDELTA 2
#define SCROLLTIME 30
#define LOOP_DELAY 33
#endif #endif
#define TFT_FULLTIME 1
class DspCore: public Adafruit_SSD1327 { class DspCore: public Adafruit_SSD1327 {
public: public:
bool fillSpaces; bool fillSpaces;
@@ -52,6 +57,7 @@ class DspCore: public Adafruit_SSD1327 {
void set_Cursor(int16_t x, int16_t y); void set_Cursor(int16_t x, int16_t y);
void printText(const char* txt); void printText(const char* txt);
void printClock(const char* timestr); void printClock(const char* timestr);
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
void displayHeapForDebug(); void displayHeapForDebug();
void drawVolumeBar(bool withNumber); void drawVolumeBar(bool withNumber);
void drawNextStationNum(uint16_t num); void drawNextStationNum(uint16_t num);
@@ -70,9 +76,10 @@ class DspCore: public Adafruit_SSD1327 {
uint16_t cwidth, cheight; uint16_t cwidth, cheight;
unsigned long loopdelay; unsigned long loopdelay;
char oldTimeBuf[20]; char oldTimeBuf[20];
uint16_t wot, hot; uint16_t wot, hot, dot;
boolean checkdelay(int m, unsigned long &tstamp); boolean checkdelay(int m, unsigned long &tstamp);
void setClockBounds(); void setClockBounds();
byte getPw(uint16_t ncwidth);
}; };
extern DspCore dsp; extern DspCore dsp;
@@ -86,9 +93,12 @@ extern DspCore dsp;
/* /*
* TFT COLORS * TFT COLORS
*/ */
#define DARK_GRAY 0x01
#define SILVER 0x07 #define SILVER 0x07
#define TFT_BG 0x00 #define TFT_BG 0x00
#define TFT_FG 0x08 #define TFT_FG 0x08
#define TFT_LOGO 0x3f #define TFT_LOGO 0x3f
#define ORANGE 0x02
#define PINK 0x02
#endif #endif

View File

@@ -25,8 +25,8 @@
#define TITLE_FG2 SILVER #define TITLE_FG2 SILVER
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 3 #define SCROLLDELTA 2
#define SCROLLTIME 65 #define SCROLLTIME 30
#endif #endif
#define TFT_FULLTIME 1 #define TFT_FULLTIME 1

View File

@@ -14,8 +14,8 @@
#define TITLE_SIZE2 2 #define TITLE_SIZE2 2
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME) #if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
#define SCROLLDELTA 5 #define SCROLLDELTA 3
#define SCROLLTIME 50 #define SCROLLTIME 30
#endif #endif
#define PLMITEMS 9 #define PLMITEMS 9

View File

@@ -0,0 +1,163 @@
/*******************************************************************************
* generated by lcd-image-converter rev.030b30d from 2019-03-17 01:38:34 +0500
* image
* filename: unsaved
* name: bl40
*
* preset name: Grayscale 8
* data block size: 8 bit(s), uint8_t
* RLE compression enabled: no
* conversion type: Grayscale, not_used not_used
* split to rows: yes
* bits per pixel: 8
*
* preprocess:
* main scan direction: top_to_bottom
* line scan direction: forward
* inverse: no
*******************************************************************************/
/*
typedef struct {
const uint8_t *data;
uint16_t width;
uint16_t height;
uint8_t dataSize;
} tImage;
*/
#include <stdint.h>
static const uint8_t bootlogobw[6336] PROGMEM = {
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▓▒∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙▒▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙▒▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙█▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙∙∙░█▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▓▓▓▓░∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙░███▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░░░∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒░░∙∙∙▒▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒∙∙∙∙∙∙∙∙∙░∙∙▓▒∙∙∙∙░▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░░∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙▒▒░░░░▒▒░∙∙∙∙∙∙∙∙∙∙▒∙∙∙░▓▒▒▓▓▓▒▒▒▒▒▒▒▒▒▓▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒░∙░▒∙∙∙
// ∙∙∙∙∙∙∙∙∙∙▒░∙∙∙∙∙░░░▒∙∙∙∙∙∙∙∙∙▓∙∙∙∙∙▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▓░∙∙∙▓∙∙∙
// ∙∙∙∙∙∙∙∙░▒∙∙∙∙∙∙▒∙∙∙▓∙∙∙∙∙∙∙∙▓░∙∙∙░█░░▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░∙∙∙∙∙▒▓░∙∙∙∙▓∙∙∙
// ∙∙∙∙∙∙∙▒∙∙∙∙∙∙▒∙∙∙∙∙▓░∙∙∙∙∙∙▓▒∙∙∙▒▓▓░░▒▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓█∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙∙∙▒▓░∙∙∙∙∙▓∙∙∙
// ∙∙∙∙∙∙▓∙∙∙∙∙∙▒∙∙∙∙∙∙▒▒∙∙∙∙∙▒▓∙∙∙█▓▓▓░░▒▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙░░∙∙∙∙▒▓▒∙∙∙∙▒▓▒∙∙∙∙∙▒░∙∙░
// ∙∙∙∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙▒▒∙∙∙∙∙▓░∙∙▓▓▓▓▓░░▒▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙∙░▓▓∙∙∙∙░▓▓∙∙∙∙∙∙▓∙∙▒∙
// ∙∙∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙∙▓▒∙∙∙∙▓▓∙∙▒█▓▓▓▓░░▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓∙∙∙∙∙∙∙∙▓▓░∙∙∙∙▓▓░∙∙∙∙▓▓▒∙∙∙∙∙░░∙░∙∙
// ∙∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙∙∙▓░∙∙∙▒▓░∙░█▓▓▓▓▒░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓░▒▒∙∙∙∙▒▓▓∙∙∙∙▒▓▒∙∙∙∙▓▓▓∙∙∙∙∙∙▒∙▒∙∙∙
// ∙∙∙∙∙∙∙∙∙░∙∙∙∙∙∙∙∙∙░▓∙∙∙∙▓▓∙∙████▓▓░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒░░▒▒░▓∙∙∙∙░▒▓∙∙∙∙∙▓▓∙∙∙∙▒░▓▓∙∙∙∙∙▒▓░∙∙∙∙
// ∙∙▒∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙▒▓▒∙▓█████▒░▒▓▓▓▓▓▓█▒░∙░▒█▓▓▓▓▒▒▒░▒▒▒▒░░░∙∙∙▒░▓▓∙∙∙∙▓▓▒∙∙∙▒∙▒▓░∙∙∙∙░∙∙∙∙∙∙∙
// ∙░∙∙∙∙∙▓∙∙∙∙∙∙∙∙∙∙∙▓▒∙∙░▓▓∙∙█████▓░▒█▓▓▓▓█░∙∙∙∙∙∙∙∙▓▓▓▒░░▒▒▒▒▒░░▓∙∙∙∙▓▓∙∙∙∙▒▓▓∙∙∙∙∙∙▒▓∙∙∙∙∙░∙∙∙∙∙∙∙
// ∙▒∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙▓▓▒∙▓█████░▒████▓█∙∙∙∙∙░▒∙∙∙∙▓▒░░▓▓▒▒▒░░▒▓░∙░▒▓▒∙∙∙░▓▓░∙∙∙░∙∙░▓∙∙∙░░∙∙∙∙∙∙∙∙
// ░∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙▓▒∙∙░▓▓∙∙████▓░▒██████∙∙∙∙∙▒▓∙∙∙∙∙░░░▓▓▓▓▓░░░▒▒▓▒∙▓▓∙∙∙∙▒▓▓∙∙∙▒∙∙∙∙▓░∙▒░∙∙∙∙∙∙∙∙∙
// ░∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙▓▓▒∙░███▒░███████▓▒░░░░▓▒∙∙∙∙∙▓▒▒▓▓▓▓▒░░▒▒▒▓∙▒▓░∙∙∙▒∙▓▒∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙▓░∙∙░▓▓∙∙▒▒▒▓████████░░∙∙∙░▓▓∙∙∙∙∙▓▓░▓▓▓▓▓░░░▓▓▒▒∙▓▓∙∙∙▒∙∙▓∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙▓▓▒∙∙██████████▓░▒∙∙∙∙▒▓▒∙∙∙∙▓▓▓∙▓▓▓▓▒░░▒▓▓▒▓∙▓░∙∙▒∙∙∙▓▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙░∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙░▓▓∙∙∙█████████▓░▒▒∙∙∙░▓▓∙∙∙∙▒▓▓░∙▒▓▓▓▒░░▓▓▒▓▓░▓∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙░∙∙∙∙∙∙∙∙∙░▓∙∙∙∙▓▓▒∙∙░████████▓░░█▒░░░▒▒▒░░░░▒▒▒░░▒▓▓▒░░▒▓▒▓▓▓▒▒▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙░∙∙∙∙∙∙∙∙∙░▓░∙∙∙░▓▓∙∙∙░████████░░▓████▓░░████▓▓░░▓▓▓▓▒▓░░▓▒▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙░∙∙∙∙∙∙∙∙░▓∙∙∙∙∙▒▓▒∙∙∙▒▓██████░░▒█████░░▓███▒█▓░▓███▒▓▒░▓▒▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙░∙∙∙∙∙∙▒▒∙∙∙∙∙░▓▓∙∙∙∙▒▓▓▓███▒░░▓████▒░░███▒██▓░▓██▒▓▓░▒▒▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙▒∙∙∙∙░▒░∙∙∙∙∙∙▓▓░∙∙∙∙▒▓▓▓▓██░░▒████▓░░▓██▓████░▒▒▒▓█▓░▒▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙░░▒▒░∙∙∙∙∙∙∙░▓▒∙∙∙∙∙▒▓▓▓▓▓▓░░▓████▓▒░██▓▓█████▓▓███░░▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙∙∙∙▒▓▓▓▓▓▓░░▓███▒█▒░█▓▓█████████▓▒░▓███▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙∙∙∙∙▒▓▓▓▓▓▓░░█▓█▒██▓░░██████████▓▓▒░██████▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓░∙∙∙∙∙∙∙░▓▓▓▓▓▓▒░▓▓▒▓██████████████▒██░▓█████████▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒∙∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▒▒▒▓▓░∙∙∙∙∙∙∙∙∙∙∙∙▒∙∙▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙∙∙∙∙▒∙∙∙▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙░▓∙∙∙∙∙∙∙∙∙∙∙▓▒▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙∙∙∙▒∙∙∙▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▓▓▓▓▓▓▓▓▓░∙∙∙∙∙∙∙∙▓∙∙∙∙▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙▓▓▒∙∙∙∙∙∙∙░▒∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▓▓▓▓▓▓▓█∙∙∙∙∙∙∙▓∙∙∙∙▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ░▓▓▓∙∙∙∙∙∙▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▒▒▒▓▓▓▓▓▓▓∙∙∙∙∙▒∙∙∙∙∙▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ▒▓▓░∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▒▒▒▒▒▓▓▓▓▓▓░∙∙░▒∙∙∙∙▓∙∙∙∙∙∙∙∙∙▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙▓▓▒∙∙░▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓█░▓∙∙∙∙░∙∙∙∙∙∙∙▒███▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙▒▒▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▒▒███▒▒▓███████████∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▓▓▓▒▓▓▓▓▓▓▓██████∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒░▓▒▒▓▓▓▓▓▓▓▓▓█████∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓███░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▓▓▓▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x68, 0xb0, 0xcb, 0xc9, 0xc4, 0x83, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x70, 0xa7, 0xa7, 0xa4, 0x8f, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xcb, 0xc4, 0xc4, 0xc4, 0xc3, 0xc2, 0xc0, 0xca, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xb4, 0xa6, 0xa3, 0xa1, 0x9e, 0x9b, 0x9a, 0xa2, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc4, 0xbb, 0xbe, 0xc0, 0xc2, 0xc4, 0xc4, 0xc2, 0xc2, 0xc4, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xb6, 0xad, 0xab, 0xa8, 0xa7, 0xa3, 0xa0, 0x9e, 0x9b, 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xb5, 0xb7, 0xb9, 0xbb, 0xbe, 0xc0, 0xc2, 0xc4, 0xc5, 0xc3, 0xcd, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xc4, 0xb5, 0xb3, 0xb0, 0xae, 0xaa, 0xa8, 0xa6, 0xa3, 0xa1, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xbf, 0xb1, 0xb2, 0xb4, 0xb7, 0xba, 0xbc, 0xbe, 0xc0, 0xc3, 0xc4, 0xc5, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0xb9, 0xb6, 0xb5, 0xb2, 0xaf, 0xad, 0xaa, 0xa8, 0xa5, 0xa2, 0xac, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xb4, 0xac, 0xaf, 0xb1, 0xb3, 0xb5, 0xb8, 0xba, 0xbc, 0xbe, 0xc1, 0xc3, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0xbb, 0xbb, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xaf, 0xac, 0xaa, 0xa8, 0xac, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xad, 0xa7, 0xaa, 0xac, 0xaf, 0xb2, 0xb3, 0xb5, 0xb8, 0xba, 0xbc, 0xbe, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xbe, 0xbd, 0xbc, 0xbb, 0xb9, 0xb8, 0xb6, 0xb4, 0xb1, 0xaf, 0xac, 0xae, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xae, 0xa3, 0xa5, 0xa8, 0xaa, 0xad, 0xaf, 0xb2, 0xb3, 0xb6, 0xb8, 0xb9, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xc0, 0xc0, 0xbe, 0xbd, 0xbc, 0xbb, 0xb9, 0xb8, 0xb6, 0xb4, 0xb1, 0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb6, 0x9e, 0xa1, 0xa3, 0xa6, 0xa8, 0xaa, 0xad, 0xb0, 0xb2, 0xb3, 0xbb, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xcb, 0xc2, 0xc1, 0xbf, 0xbe, 0xbe, 0xbc, 0xba, 0xb9, 0xb8, 0xb6, 0xc4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x9c, 0x9c, 0x9e, 0xa1, 0xa3, 0xa6, 0xa8, 0xab, 0xad, 0xb0, 0xca, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd2, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbe, 0xbd, 0xbc, 0xba, 0xbd, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa6, 0x9a, 0x99, 0x9c, 0x9f, 0xa1, 0xa4, 0xa6, 0xa8, 0xbd, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0xd1, 0xc4, 0xc4, 0xc3, 0xc2, 0xc0, 0xc0, 0xbe, 0xc0, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xa3, 0x9a, 0x9a, 0x9c, 0xa1, 0xa9, 0xb9, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xcb, 0xc9, 0xc6, 0xc4, 0xc2, 0xc4, 0xcb, 0xb2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x90, 0xb4, 0xb6, 0xb9, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xd1, 0xd5, 0xd6, 0xb6, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x19, 0x26, 0x36, 0x3b, 0x38, 0x2a, 0x2b, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x41, 0x94, 0x95, 0x64, 0x36, 0x1e, 0x15, 0x2c, 0x76, 0xad, 0xad, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x85, 0x31, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x61, 0x00, 0x2e, 0xb2, 0x97, 0x00, 0x00, 0x00, 0x0b, 0x5d, 0xb2, 0xb6, 0xab, 0xa6, 0xa4, 0xaa, 0xb2, 0xbe, 0xbf, 0xb1, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x72, 0x7d, 0x5e, 0x4e, 0x49, 0x55, 0x86, 0x8f, 0x41, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x95, 0x00, 0x00, 0x00, 0x3e, 0xb5, 0x81, 0x80, 0xb1, 0xab, 0x9d, 0x95, 0x8f, 0x8e, 0x8d, 0x8c, 0x8d, 0x90, 0x93, 0x97, 0x9f, 0xa8, 0xbb, 0xaf, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x8e, 0x60, 0x1a, 0x4e, 0x86, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x63, 0x16, 0x00, 0x00, 0x00, 0x02, 0x5e, 0x52, 0x5e, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xae, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x73, 0x47, 0x98, 0x96, 0x96, 0x96, 0x94, 0x94, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8e, 0x92, 0x95, 0x97, 0x99, 0x9d, 0xb3, 0xc2, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb0, 0x33, 0x00, 0x00, 0x0f, 0xad, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x78, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xb0, 0x39, 0x00, 0x00, 0x00, 0x42, 0xd1, 0x59, 0x4c, 0x78, 0x9d, 0x9a, 0x98, 0x97, 0x95, 0x95, 0x93, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8f, 0x92, 0x95, 0x98, 0x9b, 0x9b, 0xba, 0x9f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x30, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb4, 0x37, 0x00, 0x00, 0x00, 0x15, 0xac, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x8b, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6f, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x7d, 0x00, 0x00, 0x01, 0x92, 0xc7, 0xac, 0x5f, 0x4c, 0x67, 0xa3, 0x9e, 0x9b, 0x99, 0x98, 0x98, 0x96, 0x95, 0x93, 0x91, 0x90, 0x8f, 0x8d, 0x8d, 0x8f, 0x92, 0x95, 0x99, 0x9c, 0xa0, 0xce, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb4, 0xb3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xb4, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x9c, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x9c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xb4, 0x13, 0x00, 0x00, 0xce, 0xc2, 0xb5, 0xb5, 0x51, 0x4c, 0x67, 0xa9, 0xa2, 0xa0, 0x9d, 0x9b, 0x99, 0x99, 0x97, 0x96, 0x95, 0x93, 0x92, 0x90, 0x8f, 0x8d, 0x8e, 0x90, 0x93, 0x96, 0x99, 0x9b, 0xc8, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x00, 0x00, 0x00, 0x00, 0x95, 0xb3, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x83, 0xb3, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x47, 0x00, 0x00, 0x56,
0x00, 0x00, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x22, 0xb3, 0x5e, 0x00, 0x00, 0xc3, 0xc7, 0xbd, 0xbb, 0xb5, 0x48, 0x4c, 0x7c, 0xad, 0xa8, 0xa5, 0xa2, 0x9f, 0x9d, 0x9b, 0x99, 0x99, 0x97, 0x95, 0x95, 0x93, 0x92, 0x90, 0x8e, 0x8d, 0x8e, 0x91, 0x93, 0x96, 0x9a, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xb1, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb4, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x53, 0xb3, 0xb4, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x74, 0x0b,
0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x85, 0x00, 0x00, 0x00, 0x07, 0xb0, 0xb3, 0x0a, 0x00, 0x8d, 0xd1, 0xc5, 0xc2, 0xbf, 0xa9, 0x4a, 0x4b, 0xa0, 0xb1, 0xae, 0xaa, 0xa8, 0xa5, 0xa1, 0x9f, 0x9c, 0x9b, 0x99, 0x98, 0x96, 0x95, 0x94, 0x93, 0x91, 0x8f, 0x8e, 0x8d, 0x8e, 0x91, 0x94, 0x99, 0xbd, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x14, 0xab, 0xb3, 0x42, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xb4, 0x4c, 0x00, 0x00, 0x00, 0x2f, 0xb3, 0xb3, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x52, 0x00, 0x62, 0x18, 0x00,
0x00, 0x00, 0x00, 0x73, 0x16, 0x00, 0x00, 0x00, 0x00, 0x25, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb4, 0x5b, 0x00, 0x00, 0x00, 0x6a, 0xb3, 0x61, 0x00, 0x53, 0xdf, 0xcb, 0xc9, 0xc6, 0xc6, 0x85, 0x4c, 0x51, 0xba, 0xb7, 0xb4, 0xb1, 0xac, 0xaa, 0xa7, 0xa4, 0xa1, 0x9f, 0x9c, 0x9a, 0x98, 0x98, 0x96, 0x95, 0x94, 0x92, 0x91, 0x8f, 0x8f, 0x8e, 0x90, 0x91, 0xa7, 0x5c, 0x97, 0x7a, 0x00, 0x00, 0x00, 0x07, 0x7f, 0xb2, 0xad, 0x01, 0x00, 0x00, 0x00, 0x79, 0xb4, 0x95, 0x00, 0x00, 0x00, 0x14, 0xa2, 0xb3, 0xb2, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x16, 0x6a, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x19, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xb4, 0x21, 0x00, 0x00, 0x28, 0xb4, 0xad, 0x02, 0x00, 0xe0, 0xd0, 0xd0, 0xcd, 0xcb, 0xc8, 0x46, 0x4c, 0xaf, 0xbf, 0xbd, 0xba, 0xb6, 0xb3, 0xb1, 0xaf, 0xad, 0xab, 0xa7, 0xa4, 0xa0, 0x9c, 0x9a, 0x99, 0x97, 0x96, 0x95, 0x93, 0x8f, 0x72, 0x5a, 0x63, 0x8e, 0x8b, 0x41, 0xac, 0x00, 0x00, 0x00, 0x00, 0x60, 0x6e, 0xb3, 0x23, 0x00, 0x00, 0x00, 0x14, 0xb2, 0xb3, 0x25, 0x00, 0x00, 0x00, 0x73, 0x48, 0xb3, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xa6, 0x46, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xa8, 0x00, 0x00, 0x00, 0x96, 0xb3, 0x71, 0x00, 0xb0, 0xdd, 0xd6, 0xd4, 0xd2, 0xd0, 0x83, 0x4a, 0x73, 0xc6, 0xc3, 0xc1, 0xbf, 0xbc, 0xca, 0xdb, 0x88, 0x64, 0x21, 0x52, 0x69, 0xce, 0xbe, 0x9d, 0x9c, 0x9a, 0x98, 0x98, 0x72, 0x52, 0x8d, 0x92, 0x83, 0x81, 0x57, 0x4b, 0x3a, 0x00, 0x00, 0x00, 0x69, 0x41, 0xb4, 0xa4, 0x00, 0x00, 0x00, 0x03, 0xb2, 0xb3, 0x6f, 0x00, 0x00, 0x00, 0x7f, 0x04, 0x6e, 0xb3, 0x55, 0x00, 0x00, 0x00, 0x00, 0x35, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x99, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x7d, 0x00, 0x00, 0x53, 0xb4, 0xae, 0x00, 0x00, 0xeb, 0xdc, 0xda, 0xd8, 0xd6, 0xb9, 0x49, 0x69, 0xce, 0xca, 0xc8, 0xc5, 0xc5, 0xdf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0xc7, 0xa5, 0x9e, 0x96, 0x55, 0x5c, 0x97, 0x96, 0x95, 0x86, 0x7f, 0x4c, 0x4a, 0xb3, 0x00, 0x00, 0x2e, 0x28, 0xaf, 0xb1, 0x0d, 0x00, 0x00, 0x00, 0x6a, 0xb3, 0xb3, 0x0e, 0x00, 0x00, 0x2c, 0x1d, 0x00, 0x6e, 0xb3, 0x0e, 0x00, 0x00, 0x00, 0x28, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x83, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xb3, 0x1a, 0x00, 0x00, 0xa9, 0xb3, 0x72, 0x00, 0xaf, 0xe5, 0xe1, 0xdf, 0xdc, 0xd3, 0x4e, 0x74, 0xd4, 0xd0, 0xcf, 0xcc, 0xca, 0xd3, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x35, 0x73, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x93, 0x4e, 0x5b, 0x9e, 0x9a, 0x98, 0x98, 0x74, 0x58, 0x4c, 0x77, 0xa5, 0x33, 0x05, 0x52, 0x73, 0xb4, 0x7e, 0x00, 0x00, 0x00, 0x35, 0xb4, 0xb3, 0x58, 0x00, 0x00, 0x10, 0x56, 0x00, 0x00, 0x53, 0xb2, 0x00, 0x00, 0x00, 0x4b, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4b, 0x04, 0x00, 0x00, 0x00, 0x1b, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 0x59, 0xb3, 0xb2, 0x09, 0x08, 0xed, 0xe3, 0xe4, 0xe5, 0xc7, 0x47, 0x8e, 0xde, 0xd7, 0xd5, 0xd3, 0xd0, 0xe2, 0x1c, 0x25, 0x31, 0x01, 0x00, 0x96, 0xb4, 0x17, 0x00, 0x00, 0x00, 0x00, 0x33, 0x54, 0x53, 0xa5, 0xa0, 0x9d, 0x9b, 0x9a, 0x4b, 0x4c, 0x4d, 0x93, 0x98, 0x99, 0x8a, 0x09, 0xb1, 0xb1, 0x01, 0x00, 0x00, 0x0d, 0x76, 0xb4, 0xb2, 0x06, 0x00, 0x05, 0x73, 0x00, 0x00, 0x00, 0x1b, 0xb1, 0x4f, 0x2f, 0x77, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5d, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xb3, 0x1d, 0x00, 0x06, 0xb1, 0xb3, 0x6a, 0x00, 0x40, 0xde, 0xde, 0xd8, 0x95, 0x5e, 0xdd, 0xe1, 0xde, 0xdc, 0xd9, 0xd7, 0xd8, 0xa7, 0x92, 0x38, 0x43, 0x37, 0x45, 0xb4, 0x92, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xb3, 0x7e, 0x98, 0xa8, 0xa5, 0xa2, 0x9f, 0x7c, 0x4b, 0x4c, 0x82, 0x97, 0x94, 0xa8, 0x0b, 0x7d, 0xb4, 0x5e, 0x00, 0x00, 0x00, 0x83, 0x19, 0xb3, 0x71, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1b, 0x00, 0x00, 0x00, 0x2b, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xb3, 0x58, 0x00, 0x00, 0x46, 0xb3, 0xb4, 0x16, 0x00, 0x90, 0x92, 0x84, 0xa8, 0xdf, 0xe3, 0xe4, 0xe4, 0xe2, 0xe0, 0xde, 0xdc, 0x5f, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x9b, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xb3, 0xb3, 0x58, 0xca, 0xac, 0xaa, 0xa7, 0xa9, 0x4f, 0x4c, 0x4e, 0x99, 0x99, 0x8f, 0x85, 0x00, 0xa9, 0xae, 0x00, 0x00, 0x00, 0x97, 0x0f, 0x1c, 0xb3, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xab, 0xac, 0x01, 0x00, 0x04, 0xb2, 0xb3, 0x6d, 0x00, 0x00, 0xea, 0xdd, 0xde, 0xdf, 0xdf, 0xe0, 0xe1, 0xe3, 0xe4, 0xe5, 0xc9, 0x51, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x95, 0xb4, 0x6d, 0x00, 0x00, 0x00, 0x02, 0xae, 0xb3, 0xb3, 0x02, 0xa5, 0xb2, 0xb0, 0xad, 0x70, 0x55, 0x4a, 0x8a, 0x9f, 0xa1, 0x71, 0xa6, 0x22, 0xaf, 0x4d, 0x00, 0x00, 0x77, 0x19, 0x00, 0x00, 0x9e, 0x87, 0x70, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0xb0, 0x0a, 0x00, 0x00, 0x3e, 0xb3, 0xb4, 0x11, 0x00, 0x1f, 0xe5, 0xd9, 0xda, 0xdc, 0xdd, 0xdf, 0xdf, 0xe1, 0xe4, 0xbb, 0x49, 0x83, 0x6d, 0x00, 0x00, 0x00, 0x4f, 0xb4, 0xae, 0x00, 0x00, 0x00, 0x00, 0x79, 0xb4, 0xb3, 0x5a, 0x00, 0x72, 0xba, 0xb7, 0xa5, 0x7a, 0x48, 0x57, 0xa9, 0xa7, 0x73, 0x9e, 0xa2, 0x5e, 0xb1, 0x23, 0x00, 0x6c, 0x27, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x19, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xb3, 0x2e, 0x00, 0x00, 0x00, 0xa5, 0xb3, 0x80, 0x00, 0x00, 0x3a, 0xde, 0xd8, 0xd9, 0xd9, 0xdb, 0xdc, 0xdd, 0xdf, 0xbc, 0x46, 0x56, 0xe6, 0x74, 0x51, 0x51, 0x50, 0x8d, 0x8e, 0x7f, 0x4e, 0x4f, 0x4f, 0x52, 0x73, 0x90, 0x90, 0x4e, 0x4c, 0x91, 0xc1, 0xbc, 0x6e, 0x64, 0x48, 0x92, 0xad, 0x7c, 0x9f, 0xa3, 0xa5, 0x6b, 0x95, 0x77, 0x77, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xb3, 0x37, 0x00, 0x00, 0x00, 0x42, 0xb4, 0xb0, 0x02, 0x00, 0x00, 0x47, 0xd3, 0xd4, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xd0, 0x4a, 0x49, 0xc5, 0xe1, 0xe2, 0xe3, 0xe4, 0xc1, 0x4c, 0x4c, 0xdf, 0xd9, 0xd7, 0xcd, 0xae, 0xaa, 0x48, 0x5e, 0xca, 0xc6, 0xc3, 0xc4, 0x73, 0xba, 0x4a, 0x61, 0xbb, 0x8e, 0xa8, 0xab, 0xa9, 0xa9, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xb2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x98, 0xb3, 0x72, 0x00, 0x00, 0x00, 0x68, 0xca, 0xce, 0xd1, 0xd5, 0xd7, 0xd8, 0xdb, 0x59, 0x4c, 0x6e, 0xde, 0xdf, 0xe0, 0xe1, 0xdf, 0x48, 0x4c, 0xb3, 0xe1, 0xde, 0xda, 0x81, 0xda, 0xac, 0x46, 0x9b, 0xce, 0xcc, 0xcd, 0x89, 0xc4, 0x6a, 0x48, 0xa1, 0x89, 0xb4, 0xb5, 0xb2, 0xaf, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x94, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xb3, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x8b, 0xc4, 0xc9, 0xcb, 0xce, 0xd2, 0xd5, 0x6d, 0x4b, 0x44, 0xc7, 0xdb, 0xdc, 0xde, 0xe3, 0x94, 0x4c, 0x47, 0xe1, 0xe4, 0xe5, 0x7a, 0xdc, 0xdc, 0xc1, 0x42, 0xbe, 0xd3, 0xd8, 0x7c, 0xc0, 0xc7, 0x4f, 0x6e, 0x7d, 0xb9, 0xbe, 0xbb, 0xb8, 0xb4, 0xb2, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x72, 0x1e, 0x00, 0x00, 0x00, 0x5b, 0x95, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xb4, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x8e, 0xbe, 0xc2, 0xc5, 0xc9, 0xcc, 0xcc, 0x50, 0x4c, 0x6d, 0xde, 0xd9, 0xda, 0xdb, 0xb4, 0x5e, 0x4b, 0xa8, 0xe3, 0xe8, 0xa5, 0xdb, 0xe1, 0xdf, 0xe2, 0x61, 0x71, 0x98, 0x81, 0xc5, 0xd1, 0x9c, 0x4b, 0x7f, 0xc3, 0xc4, 0xc2, 0xbf, 0xbd, 0xbb, 0xb8, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x63, 0x67, 0x7b, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xb3, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xb8, 0xbc, 0xbf, 0xc3, 0xc6, 0xc7, 0x50, 0x4a, 0xa3, 0xd5, 0xd7, 0xd9, 0xcf, 0x9a, 0x87, 0x50, 0xdb, 0xe3, 0xb1, 0xbf, 0xe2, 0xe4, 0xe4, 0xe2, 0xdd, 0xb0, 0xc2, 0xde, 0xd8, 0xce, 0x4c, 0x4b, 0xcb, 0xcb, 0xc9, 0xc6, 0xc4, 0xc1, 0xbf, 0xbd, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xb3, 0xb1, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xb1, 0xb6, 0xba, 0xbc, 0xc0, 0xc0, 0x4f, 0x45, 0xc2, 0xd0, 0xd4, 0xd5, 0x87, 0xe2, 0x94, 0x57, 0xdc, 0xac, 0xb9, 0xdf, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe1, 0xe0, 0xde, 0xc8, 0x70, 0x4b, 0xa1, 0xd3, 0xcf, 0xcd, 0xcb, 0xc9, 0xc6, 0xc4, 0xc2, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xb3, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xab, 0xb0, 0xb3, 0xb7, 0xba, 0xbc, 0x50, 0x48, 0xce, 0xca, 0xcc, 0x70, 0xd4, 0xd7, 0xc9, 0x51, 0x5c, 0xd2, 0xdb, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe3, 0xe5, 0xe3, 0xb1, 0xba, 0x77, 0x50, 0xd4, 0xd6, 0xd4, 0xd1, 0xcf, 0xcd, 0xca, 0xc9, 0xc8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xb3, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0xa6, 0xaa, 0xac, 0xb0, 0xb4, 0xb8, 0x6a, 0x45, 0xc6, 0xb8, 0x78, 0xc8, 0xd6, 0xd9, 0xdc, 0xde, 0xe1, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe9, 0x91, 0xd6, 0xd7, 0x3f, 0xac, 0xe3, 0xe2, 0xdf, 0xde, 0xdb, 0xda, 0xd8, 0xd6, 0xd5, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xa8, 0xa2, 0xa6, 0xa9, 0xad, 0xb0, 0xb2, 0x72, 0x72, 0x93, 0xc4, 0xca, 0x4d, 0x25, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x24, 0x95, 0x1e, 0x25, 0x75, 0x91, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x24, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xad, 0x9c, 0xa0, 0xa3, 0xa7, 0xaa, 0xae, 0xb4, 0xb9, 0xb9, 0xbc, 0xbe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x74, 0x00, 0x00, 0x00, 0xb0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xb5, 0x95, 0x99, 0x9c, 0xa0, 0xa3, 0xa7, 0xab, 0xae, 0xb2, 0xb4, 0xb8, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x84, 0x00, 0x00, 0x00, 0x71, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x8e, 0x92, 0x96, 0x9a, 0x9d, 0xa1, 0xa4, 0xa8, 0xab, 0xae, 0xb2, 0xc5, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0xb1, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1a, 0xb1, 0xb2, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x8a, 0x8b, 0x8f, 0x92, 0x96, 0x9a, 0x9d, 0xa1, 0xa4, 0xa8, 0xac, 0xae, 0xd0, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x00, 0x00, 0x8c, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0xb3, 0xb3, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x9c, 0x85, 0x88, 0x8c, 0x8f, 0x92, 0x97, 0x9b, 0x9e, 0xa2, 0xa5, 0xa9, 0xae, 0xca, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x90, 0x20, 0x00, 0x00, 0x00, 0x14, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6a, 0xb3, 0xb3, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xac, 0x81, 0x83, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x97, 0x9a, 0x9e, 0xa2, 0xa5, 0xaa, 0xcb, 0x57, 0x00, 0x00, 0x4d, 0x73, 0x00, 0x00, 0x00, 0x01, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x67, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2e, 0xb2, 0xb3, 0x8b, 0x15, 0x1b, 0x34, 0x7a, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x88, 0x7d, 0x81, 0x84, 0x86, 0x89, 0x8d, 0x90, 0x93, 0x98, 0x9b, 0x9f, 0xa3, 0xa4, 0xba, 0xcd, 0x51, 0xa1, 0x05, 0x00, 0x00, 0x00, 0x56, 0x32, 0x00, 0x00, 0x00, 0x12, 0x17, 0x2c, 0x80, 0xd8, 0xe9, 0xe2, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x19, 0x82, 0x97, 0x88, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x77, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x89, 0x8d, 0x91, 0x94, 0x98, 0x9b, 0x9f, 0xa3, 0xa6, 0x7f, 0x6b, 0xd5, 0xd6, 0xd0, 0x89, 0x98, 0xb0, 0xd6, 0xe1, 0xe4, 0xe4, 0xdf, 0xdb, 0xd7, 0xd7, 0xd9, 0xda, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x89, 0x75, 0x79, 0x7b, 0x7e, 0x82, 0x85, 0x88, 0x89, 0x8d, 0x91, 0x94, 0x99, 0x9c, 0xa1, 0x6a, 0x72, 0xaa, 0xaf, 0xa4, 0x7d, 0xbb, 0xbd, 0xbf, 0xc2, 0xc6, 0xc8, 0xcb, 0xce, 0xd2, 0xd5, 0xd7, 0xd8, 0xe9, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x77, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, 0x88, 0x8a, 0x8e, 0x92, 0x95, 0x9a, 0x6c, 0x64, 0xa8, 0x7d, 0x83, 0xb0, 0xb2, 0xb6, 0xb9, 0xbc, 0xbf, 0xc2, 0xc6, 0xc9, 0xcc, 0xcf, 0xd3, 0xd5, 0xe2, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x6f, 0x70, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x8f, 0x68, 0x6c, 0x93, 0xa6, 0xa8, 0xac, 0xaf, 0xb2, 0xb6, 0xb9, 0xbc, 0xc0, 0xc2, 0xc6, 0xca, 0xcc, 0xd0, 0xd9, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x8c, 0x6d, 0x6e, 0x71, 0x74, 0x76, 0x7a, 0x7d, 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8f, 0x93, 0x97, 0x9a, 0x9e, 0xa1, 0xa5, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xb9, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xcc, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x89, 0x6c, 0x6b, 0x6e, 0x71, 0x75, 0x77, 0x7a, 0x7d, 0x80, 0x83, 0x85, 0x89, 0x8b, 0x90, 0x93, 0x96, 0x9b, 0x9e, 0xa2, 0xa6, 0xa9, 0xac, 0xb0, 0xb4, 0xb7, 0xba, 0xbd, 0xc0, 0xc4, 0xc6, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x78, 0x77, 0x68, 0x6c, 0x6e, 0x72, 0x75, 0x77, 0x7b, 0x7d, 0x80, 0x83, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x97, 0x9b, 0x9e, 0xa2, 0xa6, 0xa9, 0xad, 0xb0, 0xb4, 0xb7, 0xba, 0xbd, 0xc1, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x82, 0x6f, 0x68, 0x6c, 0x6f, 0x73, 0x75, 0x78, 0x7a, 0x7e, 0x80, 0x84, 0x86, 0x8a, 0x8c, 0x90, 0x94, 0x98, 0x9c, 0x9f, 0xa3, 0xa6, 0xaa, 0xad, 0xb1, 0xb5, 0xb7, 0xba, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x7d, 0x73, 0x69, 0x6b, 0x70, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x91, 0x94, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa9, 0xb1, 0xbd, 0xc4, 0x85, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x70, 0x7a, 0x72, 0x71, 0x71, 0x73, 0x75, 0x78, 0x7c, 0x7e, 0x81, 0x84, 0x86, 0x89, 0x8d, 0x93, 0x99, 0x9e, 0xa6, 0xae, 0xa5, 0x8c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x50, 0x7f, 0x85, 0x88, 0x87, 0x86, 0x89, 0x8d, 0x90, 0x97, 0x9e, 0x9d, 0x9b, 0x78, 0x4d, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

View File

@@ -136,7 +136,6 @@ void Telnet::on_connect(const char* str, byte clientId) {
} }
void Telnet::info() { void Telnet::info() {
byte volume;
telnet.printf("##CLI.INFO#\n"); telnet.printf("##CLI.INFO#\n");
char timeStringBuff[50]; char timeStringBuff[50];
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &network.timeinfo); strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &network.timeinfo);
@@ -201,7 +200,7 @@ void Telnet::on_input(const char* str, byte clientId) {
printf(clientId, "##CLI.AUDIOINFO#: %d\n> ", config.store.audioinfo > 0); printf(clientId, "##CLI.AUDIOINFO#: %d\n> ", config.store.audioinfo > 0);
return; return;
} }
byte ainfo; int ainfo;
if (sscanf(str, "audioinfo(%d)", &ainfo) == 1 || sscanf(str, "cli.audioinfo(\"%d\")", &ainfo) == 1 || sscanf(str, "audioinfo %d", &ainfo) == 1) { if (sscanf(str, "audioinfo(%d)", &ainfo) == 1 || sscanf(str, "cli.audioinfo(\"%d\")", &ainfo) == 1 || sscanf(str, "audioinfo %d", &ainfo) == 1) {
config.store.audioinfo = ainfo > 0; config.store.audioinfo = ainfo > 0;
printf(clientId, "new audioinfo value is: %d\n> ", config.store.audioinfo); printf(clientId, "new audioinfo value is: %d\n> ", config.store.audioinfo);
@@ -212,9 +211,9 @@ void Telnet::on_input(const char* str, byte clientId) {
printf(clientId, "##CLI.SMARTSTART#: %d\n> ", config.store.smartstart); printf(clientId, "##CLI.SMARTSTART#: %d\n> ", config.store.smartstart);
return; return;
} }
byte sstart; int sstart;
if (sscanf(str, "smartstart(%d)", &sstart) == 1 || sscanf(str, "cli.smartstart(\"%d\")", &sstart) == 1 || sscanf(str, "smartstart %d", &sstart) == 1) { if (sscanf(str, "smartstart(%d)", &sstart) == 1 || sscanf(str, "cli.smartstart(\"%d\")", &sstart) == 1 || sscanf(str, "smartstart %d", &sstart) == 1) {
config.store.smartstart = sstart; config.store.smartstart = (byte)sstart;
printf(clientId, "new smartstart value is: %d\n> ", config.store.audioinfo); printf(clientId, "new smartstart value is: %d\n> ", config.store.audioinfo);
config.save(); config.save();
return; return;
@@ -260,24 +259,25 @@ void Telnet::on_input(const char* str, byte clientId) {
printf(clientId, "> "); printf(clientId, "> ");
return; return;
} }
uint16_t sb; int sb;
if (sscanf(str, "play(%d)", &sb) == 1 || sscanf(str, "cli.play(\"%d\")", &sb) == 1 || sscanf(str, "play %d", &sb) == 1 ) { if (sscanf(str, "play(%d)", &sb) == 1 || sscanf(str, "cli.play(\"%d\")", &sb) == 1 || sscanf(str, "play %d", &sb) == 1 ) {
if (sb < 1) sb = 1; if (sb < 1) sb = 1;
if (sb >= config.store.countStation) sb = config.store.countStation; if (sb >= config.store.countStation) sb = config.store.countStation;
player.play(sb); player.play((uint16_t)sb);
return; return;
} }
if (strcmp(str, "sys.tzo") == 0 || strcmp(str, "tzo") == 0) { if (strcmp(str, "sys.tzo") == 0 || strcmp(str, "tzo") == 0) {
printf(clientId, "##SYS.TZO#: %d:%d\n> ", config.store.tzHour, config.store.tzMin); printf(clientId, "##SYS.TZO#: %d:%d\n> ", config.store.tzHour, config.store.tzMin);
return; return;
} }
int16_t tzh, tzm; //int16_t tzh, tzm;
int tzh, tzm;
if (sscanf(str, "tzo(%d:%d)", &tzh, &tzm) == 2 || sscanf(str, "sys.tzo(\"%d:%d\")", &tzh, &tzm) == 2 || sscanf(str, "tzo %d:%d", &tzh, &tzm) == 2) { if (sscanf(str, "tzo(%d:%d)", &tzh, &tzm) == 2 || sscanf(str, "sys.tzo(\"%d:%d\")", &tzh, &tzm) == 2 || sscanf(str, "tzo %d:%d", &tzh, &tzm) == 2) {
if (tzh < -12) tzh = -12; if (tzh < -12) tzh = -12;
if (tzh > 14) tzh = 14; if (tzh > 14) tzh = 14;
if (tzm < 0) tzm = 0; if (tzm < 0) tzm = 0;
if (tzm > 59) tzm = 59; if (tzm > 59) tzm = 59;
config.setTimezone(tzh, tzm); config.setTimezone((int8_t)tzh, (int8_t)tzm);
if(tzh<0){ if(tzh<0){
printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin); printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin);
}else{ }else{
@@ -289,7 +289,7 @@ void Telnet::on_input(const char* str, byte clientId) {
if (sscanf(str, "tzo(%d)", &tzh) == 1 || sscanf(str, "sys.tzo(\"%d\")", &tzh) == 1 || sscanf(str, "tzo %d", &tzh) == 1) { if (sscanf(str, "tzo(%d)", &tzh) == 1 || sscanf(str, "sys.tzo(\"%d\")", &tzh) == 1 || sscanf(str, "tzo %d", &tzh) == 1) {
if (tzh < -12) tzh = -12; if (tzh < -12) tzh = -12;
if (tzh > 14) tzh = 14; if (tzh > 14) tzh = 14;
config.setTimezone(tzh, 0); config.setTimezone((int8_t)tzh, 0);
if(tzh<0){ if(tzh<0){
printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin); printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin);
}else{ }else{

View File

@@ -1,6 +1,9 @@
#include "Arduino.h" #include "Arduino.h"
#include "options.h" #include "options.h"
#if DSP_MODEL==DSP_DUMMY
#define DUMMYDISPLAY
#endif
#include "config.h" #include "config.h"
#include "telnet.h" #include "telnet.h"
#include "player.h" #include "player.h"
@@ -42,6 +45,6 @@ void loop() {
player.loop(); player.loop();
loopControls(); loopControls();
} }
display.loop(); // display.loop();
netserver.loop(); netserver.loop();
} }