parent
5446b30185
commit
9abcfabc5f
976 changed files with 10011 additions and 5277 deletions
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:c8eab0ec610fccd29115e8451f1088ed71db5ce7575956d08fd76baf62172e28 |
||||
size 2565 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:14e21ae221670a6b9178371274d1b30428f6d136195e8320943e8988764d9bd4 |
||||
size 152571 |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:6e6f3a8037283b87271a7bb0c95a9ae1a8ff5a86dea7e2b25d49911179b6e05e |
||||
oid sha256:309b46b7c38f10da52b18b0340eb3c57b633558a9a27c3ca4116474969ebb456 |
||||
size 84675 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:61fc21ef8cec4ca15be05b1b5fdb9c4d95f3a78be891a36d84bd2dd89441e28e |
||||
size 2596571 |
||||
oid sha256:2b53c6b8927e634d09ece8c780cf8f3d4201a6ea1c8327396a46b663da0e94a6 |
||||
size 2604116 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:6976978d140b928a499f26a6e8d879a752034a762154dde2d9bde55ef59a9c29 |
||||
size 18310604 |
||||
oid sha256:3eaf6c7d0666f721967fdf5441ea254568cbe898ee71f31e55e41c0cdd6cc41b |
||||
size 18310731 |
||||
|
@ -0,0 +1,88 @@ |
||||
CC = clang
|
||||
CXX = clang++
|
||||
|
||||
PHONELIBS = ../../phonelibs
|
||||
|
||||
WARN_FLAGS = -Werror=implicit-function-declaration \
|
||||
-Werror=incompatible-pointer-types \
|
||||
-Werror=int-conversion \
|
||||
-Werror=return-type \
|
||||
-Werror=format-extra-args
|
||||
|
||||
CFLAGS = -std=gnu11 -g -fPIC -O2 $(WARN_FLAGS)
|
||||
CXXFLAGS = -std=c++11 -g -fPIC -O2 $(WARN_FLAGS)
|
||||
|
||||
CURL_FLAGS = -I$(PHONELIBS)/curl/include
|
||||
CURL_LIBS = $(PHONELIBS)/curl/lib/libcurl.a \
|
||||
$(PHONELIBS)/zlib/lib/libz.a
|
||||
|
||||
BORINGSSL_FLAGS = -I$(PHONELIBS)/boringssl/include
|
||||
BORINGSSL_LIBS = $(PHONELIBS)/boringssl/lib/libssl_static.a \
|
||||
$(PHONELIBS)/boringssl/lib/libcrypto_static.a \
|
||||
|
||||
NANOVG_FLAGS = -I$(PHONELIBS)/nanovg
|
||||
|
||||
JSON11_FLAGS = -I$(PHONELIBS)/json11
|
||||
|
||||
OPENGL_LIBS = -lGLESv3
|
||||
|
||||
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
|
||||
|
||||
.PHONY: all |
||||
all: updater |
||||
|
||||
OBJS = courbd.ttf.o \
|
||||
../../selfdrive/common/touch.o \
|
||||
../../selfdrive/common/framebuffer.o \
|
||||
$(PHONELIBS)/json11/json11.o \
|
||||
$(PHONELIBS)/nanovg/nanovg.o
|
||||
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
updater: updater.o $(OBJS) |
||||
@echo "[ LINK ] $@"
|
||||
$(CXX) $(CPPFLAGS) -fPIC -o 'updater' $^ \
|
||||
$(FRAMEBUFFER_LIBS) \
|
||||
$(CURL_LIBS) \
|
||||
$(BORINGSSL_LIBS) \
|
||||
-L/system/vendor/lib64 \
|
||||
$(OPENGL_LIBS) \
|
||||
-lcutils -lm -llog
|
||||
strip updater
|
||||
|
||||
courbd.ttf.o: ../../selfdrive/assets/courbd.ttf |
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
%.o: %.c |
||||
mkdir -p $(@D)
|
||||
@echo "[ CC ] $@"
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) \
|
||||
-I../.. \
|
||||
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||
-I$(PHONELIBS)/android_system_core/include \
|
||||
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||
$(NANOVG_FLAGS) \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
%.o: %.cc |
||||
mkdir -p $(@D)
|
||||
@echo "[ CXX ] $@"
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) \
|
||||
-I../../selfdrive \
|
||||
-I../../ \
|
||||
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||
-I$(PHONELIBS)/android_system_core/include \
|
||||
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||
$(NANOVG_FLAGS) \
|
||||
$(JSON11_FLAGS) \
|
||||
$(CURL_FLAGS) \
|
||||
$(BORINGSSL_FLAGS) \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
|
||||
.PHONY: clean |
||||
clean: |
||||
rm -f $(OBJS) $(DEPS)
|
||||
|
||||
-include $(DEPS) |
@ -0,0 +1,7 @@ |
||||
{ |
||||
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-c992abb59cbaf6588f51055db52db619061107851773fc8480acb8bb5d77a28f.zip", |
||||
"ota_hash": "c992abb59cbaf6588f51055db52db619061107851773fc8480acb8bb5d77a28f", |
||||
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-af099a84cfd7b91266090779238ac358278948dcde2dcfa0fbca6e8397366f0a.img", |
||||
"recovery_len": 15136044, |
||||
"recovery_hash": "af099a84cfd7b91266090779238ac358278948dcde2dcfa0fbca6e8397366f0a" |
||||
} |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:206205b51ce5bfd3c387cb961302879b72d1e1ea3e81bb8b59dbbb7109197142 |
||||
size 2501608 |
||||
oid sha256:743ba86c3b4d643272c11eba28e2b0a8824c542caa613a94ff6a2f01c37e54a7 |
||||
size 2501656 |
||||
|
@ -0,0 +1,675 @@ |
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
#include <cstring> |
||||
#include <cassert> |
||||
|
||||
#include <unistd.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/statvfs.h> |
||||
|
||||
#include <string> |
||||
#include <sstream> |
||||
#include <fstream> |
||||
#include <mutex> |
||||
#include <thread> |
||||
|
||||
#include <curl/curl.h> |
||||
#include <openssl/sha.h> |
||||
|
||||
#include <GLES3/gl3.h> |
||||
#include <EGL/egl.h> |
||||
#include <EGL/eglext.h> |
||||
|
||||
#include "nanovg.h" |
||||
#define NANOVG_GLES3_IMPLEMENTATION |
||||
#include "nanovg_gl.h" |
||||
#include "nanovg_gl_utils.h" |
||||
|
||||
#include "json11.hpp" |
||||
|
||||
#include "common/framebuffer.h" |
||||
#include "common/touch.h" |
||||
#include "common/utilpp.h" |
||||
|
||||
#define USER_AGENT "NEOSUpdater-0.2" |
||||
|
||||
#define MANIFEST_URL_EON_STAGING "https://github.com/commaai/eon-neos/raw/master/update.staging.json"
|
||||
#define MANIFEST_URL_EON_LOCAL "http://192.168.5.1:8000/neosupdate/update.local.json"
|
||||
#define MANIFEST_URL_EON "https://github.com/commaai/eon-neos/raw/master/update.json"
|
||||
const char *manifest_url = MANIFEST_URL_EON; |
||||
|
||||
#define RECOVERY_DEV "/dev/block/bootdevice/by-name/recovery" |
||||
#define RECOVERY_COMMAND "/cache/recovery/command" |
||||
|
||||
#define UPDATE_DIR "/data/neoupdate" |
||||
|
||||
extern const uint8_t bin_courbd[] asm("_binary_courbd_ttf_start"); |
||||
extern const uint8_t bin_courbd_end[] asm("_binary_courbd_ttf_end"); |
||||
|
||||
namespace { |
||||
|
||||
std::string sha256_file(std::string fn, size_t limit=0) { |
||||
SHA256_CTX ctx; |
||||
SHA256_Init(&ctx); |
||||
|
||||
FILE *file = fopen(fn.c_str(), "rb"); |
||||
if (!file) return ""; |
||||
|
||||
const size_t buf_size = 8192; |
||||
std::unique_ptr<char[]> buffer( new char[ buf_size ] ); |
||||
|
||||
bool read_limit = (limit != 0); |
||||
while (true) { |
||||
size_t read_size = buf_size; |
||||
if (read_limit) read_size = std::min(read_size, limit); |
||||
size_t bytes_read = fread(buffer.get(), 1, read_size, file); |
||||
if (!bytes_read) break; |
||||
|
||||
SHA256_Update(&ctx, buffer.get(), bytes_read); |
||||
|
||||
if (read_limit) { |
||||
limit -= bytes_read; |
||||
if (limit == 0) break; |
||||
} |
||||
} |
||||
|
||||
uint8_t hash[SHA256_DIGEST_LENGTH]; |
||||
SHA256_Final(hash, &ctx); |
||||
|
||||
fclose(file); |
||||
|
||||
return util::tohex(hash, sizeof(hash)); |
||||
} |
||||
|
||||
size_t download_string_write(void *ptr, size_t size, size_t nmeb, void *up) { |
||||
size_t sz = size * nmeb; |
||||
((std::string*)up)->append((char*)ptr, sz); |
||||
return sz; |
||||
} |
||||
|
||||
std::string download_string(CURL *curl, std::string url) { |
||||
std::string os; |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); |
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); |
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); |
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); |
||||
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 0); |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_string_write); |
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &os); |
||||
CURLcode res = curl_easy_perform(curl); |
||||
if (res != CURLE_OK) { |
||||
return ""; |
||||
} |
||||
|
||||
return os; |
||||
} |
||||
|
||||
size_t download_file_write(void *ptr, size_t size, size_t nmeb, void *up) { |
||||
return fwrite(ptr, size, nmeb, (FILE*)up); |
||||
} |
||||
|
||||
bool check_battery() { |
||||
std::string bat_cap_s = util::read_file("/sys/class/power_supply/battery/capacity"); |
||||
int bat_cap = atoi(bat_cap_s.c_str()); |
||||
std::string current_now_s = util::read_file("/sys/class/power_supply/battery/current_now"); |
||||
int current_now = atoi(current_now_s.c_str()); |
||||
return bat_cap > 35 || (current_now < 0 && bat_cap > 10); |
||||
} |
||||
|
||||
bool check_space() { |
||||
struct statvfs stat; |
||||
if (statvfs("/data/", &stat) != 0) { |
||||
return false; |
||||
} |
||||
size_t space = stat.f_bsize * stat.f_bavail; |
||||
return space > 2000000000ULL; // 2GB
|
||||
} |
||||
|
||||
static void start_settings_activity(const char* name) { |
||||
char launch_cmd[1024]; |
||||
snprintf(launch_cmd, sizeof(launch_cmd), |
||||
"am start -W --ez :settings:show_fragment_as_subsetting true -n 'com.android.settings/.%s'", name); |
||||
system(launch_cmd); |
||||
} |
||||
|
||||
struct Updater { |
||||
bool do_exit = false; |
||||
|
||||
TouchState touch; |
||||
|
||||
int fb_w, fb_h; |
||||
EGLDisplay display; |
||||
EGLSurface surface; |
||||
|
||||
FramebufferState *fb = NULL; |
||||
NVGcontext *vg = NULL; |
||||
int font; |
||||
|
||||
std::thread update_thread_handle; |
||||
|
||||
std::mutex lock; |
||||
|
||||
// i hate state machines give me coroutines already
|
||||
enum UpdateState { |
||||
CONFIRMATION, |
||||
RUNNING, |
||||
ERROR, |
||||
}; |
||||
UpdateState state; |
||||
|
||||
std::string progress_text; |
||||
float progress_frac; |
||||
|
||||
std::string error_text; |
||||
|
||||
// button
|
||||
int b_x, b_w, b_y, b_h; |
||||
int balt_x; |
||||
|
||||
CURL *curl = NULL; |
||||
|
||||
Updater() { |
||||
touch_init(&touch); |
||||
|
||||
fb = framebuffer_init("updater", 0x00001000, false, |
||||
&display, &surface, &fb_w, &fb_h); |
||||
assert(fb); |
||||
|
||||
vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); |
||||
assert(vg); |
||||
font = nvgCreateFontMem(vg, "courbd", (unsigned char*)bin_courbd, (bin_courbd_end - bin_courbd), 0); |
||||
assert(font >= 0); |
||||
|
||||
b_w = 600; |
||||
balt_x = 200; |
||||
b_x = fb_w-b_w-200; |
||||
b_y = 700; |
||||
b_h = 250; |
||||
|
||||
state = CONFIRMATION; |
||||
|
||||
} |
||||
|
||||
int download_file_xferinfo(curl_off_t dltotal, curl_off_t dlno, |
||||
curl_off_t ultotal, curl_off_t ulnow) { |
||||
{ |
||||
std::lock_guard<std::mutex> guard(lock); |
||||
if (dltotal != 0) { |
||||
progress_frac = (float) dlno / dltotal; |
||||
} |
||||
} |
||||
// printf("info: %ld %ld %f\n", dltotal, dlno, progress_frac);
|
||||
return 0; |
||||
} |
||||
|
||||
bool download_file(std::string url, std::string out_fn) { |
||||
FILE *of = fopen(out_fn.c_str(), "ab"); |
||||
assert(of); |
||||
|
||||
CURLcode res; |
||||
long last_resume_from = 0; |
||||
|
||||
fseek(of, 0, SEEK_END); |
||||
|
||||
int tries = 4; |
||||
|
||||
bool ret = false; |
||||
|
||||
while (true) { |
||||
long resume_from = ftell(of); |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); |
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); |
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); |
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); |
||||
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, resume_from); |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_file_write); |
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, of); |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this); |
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &Updater::download_file_xferinfo); |
||||
|
||||
CURLcode res = curl_easy_perform(curl); |
||||
|
||||
long response_code = 0; |
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); |
||||
|
||||
// double content_length = 0.0;
|
||||
// curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length);
|
||||
|
||||
printf("download %s res %d, code %ld, resume from %ld\n", url.c_str(), res, response_code, resume_from); |
||||
if (res == CURLE_OK) { |
||||
ret = true; |
||||
break; |
||||
} else if (res == CURLE_HTTP_RETURNED_ERROR && response_code == 416) { |
||||
// failed because the file is already complete?
|
||||
ret = true; |
||||
break; |
||||
} else if (resume_from == last_resume_from) { |
||||
// failed and dind't make make forward progress. only retry a couple times
|
||||
tries--; |
||||
if (tries <= 0) { |
||||
break; |
||||
} |
||||
} |
||||
last_resume_from = resume_from; |
||||
} |
||||
// printf("res %d\n", res);
|
||||
|
||||
// printf("- %ld %f\n", response_code, content_length);
|
||||
|
||||
fclose(of); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
void set_progress(std::string text) { |
||||
std::lock_guard<std::mutex> guard(lock); |
||||
progress_text = text; |
||||
} |
||||
|
||||
void set_error(std::string text) { |
||||
std::lock_guard<std::mutex> guard(lock); |
||||
error_text = text; |
||||
state = ERROR; |
||||
} |
||||
|
||||
std::string stage_download(std::string url, std::string hash, std::string name) { |
||||
std::string out_fn = UPDATE_DIR "/" + util::base_name(url); |
||||
|
||||
set_progress("downloading " + name + "..."); |
||||
bool r = download_file(url, out_fn); |
||||
if (!r) { |
||||
set_error("failed to download " + name); |
||||
return ""; |
||||
} |
||||
|
||||
set_progress("verifying " + name + "..."); |
||||
std::string fn_hash = sha256_file(out_fn); |
||||
printf("got %s hash: %s\n", name.c_str(), hash.c_str()); |
||||
if (fn_hash != hash) { |
||||
set_error(name + " was corrupt"); |
||||
unlink(out_fn.c_str()); |
||||
return ""; |
||||
} |
||||
|
||||
return out_fn; |
||||
} |
||||
|
||||
void run_stages() { |
||||
curl = curl_easy_init(); |
||||
assert(curl); |
||||
|
||||
if (!check_battery()) { |
||||
set_error("Please plug power in to your EON and wait for charge"); |
||||
return; |
||||
} |
||||
|
||||
if (!check_space()) { |
||||
set_error("2GB of free space required to update"); |
||||
return; |
||||
} |
||||
|
||||
mkdir(UPDATE_DIR, 0777); |
||||
|
||||
const int EON = (access("/EON", F_OK) != -1); |
||||
|
||||
set_progress("finding latest version..."); |
||||
std::string manifest_s; |
||||
if (EON) { |
||||
manifest_s = download_string(curl, manifest_url); |
||||
} else { |
||||
// don't update NEO
|
||||
exit(0); |
||||
} |
||||
|
||||
printf("manifest: %s\n", manifest_s.c_str()); |
||||
|
||||
std::string err; |
||||
auto manifest = json11::Json::parse(manifest_s, err); |
||||
if (manifest.is_null() || !err.empty()) { |
||||
set_error("failed to load update manifest"); |
||||
return; |
||||
} |
||||
|
||||
std::string ota_url = manifest["ota_url"].string_value(); |
||||
std::string ota_hash = manifest["ota_hash"].string_value(); |
||||
|
||||
std::string recovery_url = manifest["recovery_url"].string_value(); |
||||
std::string recovery_hash = manifest["recovery_hash"].string_value(); |
||||
int recovery_len = manifest["recovery_len"].int_value(); |
||||
|
||||
// std::string installer_url = manifest["installer_url"].string_value();
|
||||
// std::string installer_hash = manifest["installer_hash"].string_value();
|
||||
|
||||
if (ota_url.empty() || ota_hash.empty()) { |
||||
set_error("invalid update manifest"); |
||||
return; |
||||
} |
||||
|
||||
// std::string installer_fn = stage_download(installer_url, installer_hash, "installer");
|
||||
// if (installer_fn.empty()) {
|
||||
// //error'd
|
||||
// return;
|
||||
// }
|
||||
|
||||
std::string recovery_fn; |
||||
if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) { |
||||
set_progress("skipping recovery flash..."); |
||||
} else { |
||||
// only download the recovery if it differs from what's flashed
|
||||
set_progress("checking recovery..."); |
||||
std::string existing_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len); |
||||
printf("existing recovery hash: %s\n", existing_recovery_hash.c_str()); |
||||
|
||||
if (existing_recovery_hash != recovery_hash) { |
||||
recovery_fn = stage_download(recovery_url, recovery_hash, "recovery"); |
||||
if (recovery_fn.empty()) { |
||||
// error'd
|
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
std::string ota_fn = stage_download(ota_url, ota_hash, "update"); |
||||
if (ota_fn.empty()) { |
||||
//error'd
|
||||
return; |
||||
} |
||||
|
||||
if (!check_battery()) { |
||||
set_error("must have at least 35% battery to update"); |
||||
return; |
||||
} |
||||
|
||||
if (!recovery_fn.empty()) { |
||||
// flash recovery
|
||||
set_progress("flashing recovery..."); |
||||
|
||||
FILE *flash_file = fopen(recovery_fn.c_str(), "rb"); |
||||
if (!flash_file) { |
||||
set_error("failed to flash recovery"); |
||||
return; |
||||
} |
||||
|
||||
FILE *recovery_dev = fopen(RECOVERY_DEV, "w+b"); |
||||
if (!recovery_dev) { |
||||
fclose(flash_file); |
||||
set_error("failed to flash recovery"); |
||||
return; |
||||
} |
||||
|
||||
const size_t buf_size = 4096; |
||||
std::unique_ptr<char[]> buffer( new char[ buf_size ] ); |
||||
|
||||
while (true) { |
||||
size_t bytes_read = fread(buffer.get(), 1, buf_size, flash_file); |
||||
if (!bytes_read) break; |
||||
|
||||
size_t bytes_written = fwrite(buffer.get(), 1, bytes_read, recovery_dev); |
||||
if (bytes_read != bytes_written) { |
||||
fclose(recovery_dev); |
||||
fclose(flash_file); |
||||
set_error("failed to flash recovery: write failed"); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
fclose(recovery_dev); |
||||
fclose(flash_file); |
||||
|
||||
set_progress("verifying flash..."); |
||||
std::string new_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len); |
||||
printf("new recovery hash: %s\n", new_recovery_hash.c_str()); |
||||
|
||||
if (new_recovery_hash != recovery_hash) { |
||||
set_error("recovery flash corrupted"); |
||||
return; |
||||
} |
||||
|
||||
} |
||||
|
||||
// write arguments to recovery
|
||||
FILE *cmd_file = fopen(RECOVERY_COMMAND, "wb"); |
||||
if (!cmd_file) { |
||||
set_error("failed to reboot into recovery"); |
||||
return; |
||||
} |
||||
fprintf(cmd_file, "--update_package=%s\n", ota_fn.c_str()); |
||||
fclose(cmd_file); |
||||
|
||||
set_progress("rebooting"); |
||||
|
||||
// remove the continue.sh so we come back into the setup.
|
||||
// maybe we should go directly into the installer, but what if we don't come back with internet? :/
|
||||
//unlink("/data/data/com.termux/files/continue.sh");
|
||||
|
||||
// TODO: this should be generic between android versions
|
||||
// IPowerManager.reboot(confirm=false, reason="recovery", wait=true)
|
||||
system("service call power 16 i32 0 s16 recovery i32 1"); |
||||
while(1) pause(); |
||||
|
||||
// execl("/system/bin/reboot", "recovery");
|
||||
// set_error("failed to reboot into recovery");
|
||||
} |
||||
|
||||
void draw_ack_screen(const char *message, const char *button, const char *altbutton) { |
||||
nvgFontSize(vg, 96.0f); |
||||
nvgFillColor(vg, nvgRGBA(255,255,255,255)); |
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); |
||||
nvgTextBox(vg, 50, 100, fb_w-100, message, NULL); |
||||
|
||||
// draw button
|
||||
if (button) { |
||||
nvgBeginPath(vg); |
||||
nvgFillColor(vg, nvgRGBA(0, 0, 0, 255)); |
||||
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); |
||||
nvgFill(vg); |
||||
|
||||
nvgFillColor(vg, nvgRGBA(255, 255, 255, 255)); |
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); |
||||
nvgText(vg, b_x+b_w/2, b_y+b_h/2, button, NULL); |
||||
|
||||
nvgBeginPath(vg); |
||||
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 255)); |
||||
nvgStrokeWidth(vg, 5); |
||||
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); |
||||
nvgStroke(vg); |
||||
} |
||||
|
||||
// draw button
|
||||
if (altbutton) { |
||||
nvgBeginPath(vg); |
||||
nvgFillColor(vg, nvgRGBA(0, 0, 0, 255)); |
||||
nvgRoundedRect(vg, balt_x, b_y, b_w, b_h, 20); |
||||
nvgFill(vg); |
||||
|
||||
nvgFillColor(vg, nvgRGBA(255, 255, 255, 255)); |
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); |
||||
nvgText(vg, balt_x+b_w/2, b_y+b_h/2, altbutton, NULL); |
||||
|
||||
nvgBeginPath(vg); |
||||
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 255)); |
||||
nvgStrokeWidth(vg, 5); |
||||
nvgRoundedRect(vg, balt_x, b_y, b_w, b_h, 20); |
||||
nvgStroke(vg); |
||||
} |
||||
} |
||||
|
||||
void draw_progress_screen() { |
||||
// draw progress message
|
||||
nvgFontSize(vg, 64.0f); |
||||
nvgFillColor(vg, nvgRGBA(255,255,255,255)); |
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); |
||||
nvgTextBox(vg, 0, 700, fb_w, progress_text.c_str(), NULL); |
||||
|
||||
// draw progress bar
|
||||
{ |
||||
int progress_width = 800; |
||||
int progress_x = fb_w/2-progress_width/2; |
||||
int progress_y = 768; |
||||
int progress_height = 15; |
||||
|
||||
int powerprompt_y = 512; |
||||
nvgText(vg, fb_w/2, powerprompt_y, "Ensure EON is connected to power", NULL); |
||||
|
||||
NVGpaint paint = nvgBoxGradient( |
||||
vg, progress_x + 1, progress_y + 1, |
||||
progress_width - 2, progress_height, 3, 4, nvgRGB(0, 32, 0), nvgRGB(0, 92, 0)); |
||||
nvgBeginPath(vg); |
||||
nvgRoundedRect(vg, progress_x, progress_y, progress_width, progress_height, 3); |
||||
nvgFillPaint(vg, paint); |
||||
nvgFill(vg); |
||||
|
||||
float value = std::min(std::max(0.0f, progress_frac), 1.0f); |
||||
int bar_pos = ((progress_width - 2) * value); |
||||
|
||||
paint = nvgBoxGradient( |
||||
vg, progress_x, progress_y, |
||||
bar_pos+1.5f, progress_height-1, 3, 4, |
||||
nvgRGB(220, 100, 0), nvgRGB(128, 100, 0)); |
||||
|
||||
nvgBeginPath(vg); |
||||
nvgRoundedRect( |
||||
vg, progress_x+1, progress_y+1, |
||||
bar_pos, progress_height-2, 3); |
||||
nvgFillPaint(vg, paint); |
||||
nvgFill(vg); |
||||
} |
||||
} |
||||
|
||||
void ui_draw() { |
||||
std::lock_guard<std::mutex> guard(lock); |
||||
|
||||
nvgBeginFrame(vg, fb_w, fb_h, 1.0f); |
||||
|
||||
switch (state) { |
||||
case CONFIRMATION: |
||||
draw_ack_screen("An upgrade to NEOS is required.\n\n" |
||||
"Your device will now be reset and upgraded. You may want to connect to wifi as download is around 1 GB\nData on device shouldn't be lost.", |
||||
"continue", |
||||
"wifi"); |
||||
break; |
||||
case RUNNING: |
||||
draw_progress_screen(); |
||||
break; |
||||
case ERROR: |
||||
draw_ack_screen(("ERROR: " + error_text + "\n\nYou will need to retry").c_str(), NULL, "exit"); |
||||
break; |
||||
} |
||||
|
||||
nvgEndFrame(vg); |
||||
} |
||||
|
||||
void ui_update() { |
||||
std::lock_guard<std::mutex> guard(lock); |
||||
|
||||
switch (state) { |
||||
case ERROR: |
||||
case CONFIRMATION: { |
||||
int touch_x = -1, touch_y = -1; |
||||
int res = touch_poll(&touch, &touch_x, &touch_y, 0); |
||||
if (res == 1 && !is_settings_active()) { |
||||
if (touch_x >= b_x && touch_x < b_x+b_w && touch_y >= b_y && touch_y < b_y+b_h) { |
||||
if (state == CONFIRMATION) { |
||||
state = RUNNING; |
||||
update_thread_handle = std::thread(&Updater::run_stages, this); |
||||
} |
||||
} |
||||
if (touch_x >= balt_x && touch_x < balt_x+b_w && touch_y >= b_y && touch_y < b_y+b_h) { |
||||
if (state == CONFIRMATION) { |
||||
start_settings_activity("Settings$WifiSettingsActivity"); |
||||
} else if (state == ERROR) { |
||||
do_exit = 1; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
void go() { |
||||
while (!do_exit) { |
||||
ui_update(); |
||||
|
||||
glClearColor(0.19, 0.09, 0.2, 1.0); |
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
||||
|
||||
glEnable(GL_BLEND); |
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||
|
||||
ui_draw(); |
||||
|
||||
glDisable(GL_BLEND); |
||||
|
||||
eglSwapBuffers(display, surface); |
||||
assert(glGetError() == GL_NO_ERROR); |
||||
|
||||
// no simple way to do 30fps vsync with surfaceflinger...
|
||||
usleep(30000); |
||||
} |
||||
|
||||
if (update_thread_handle.joinable()) { |
||||
update_thread_handle.join(); |
||||
} |
||||
|
||||
system("service call power 16 i32 0 i32 0 i32 1"); |
||||
} |
||||
|
||||
bool is_settings_active() { |
||||
FILE *fp; |
||||
char sys_output[4096]; |
||||
|
||||
fp = popen("/bin/dumpsys window windows", "r"); |
||||
if (fp == NULL) { |
||||
return false; |
||||
} |
||||
|
||||
bool active = false; |
||||
while (fgets(sys_output, sizeof(sys_output), fp) != NULL) { |
||||
if (strstr(sys_output, "mCurrentFocus=null") != NULL) { |
||||
break; |
||||
} |
||||
|
||||
if (strstr(sys_output, "mCurrentFocus=Window") != NULL) { |
||||
active = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
pclose(fp); |
||||
|
||||
return active; |
||||
} |
||||
|
||||
}; |
||||
|
||||
} |
||||
int main(int argc, char *argv[]) { |
||||
if (argc > 1) { |
||||
if (strcmp(argv[1], "local") == 0) { |
||||
manifest_url = MANIFEST_URL_EON_LOCAL; |
||||
} else if (strcmp(argv[1], "staging") == 0) { |
||||
manifest_url = MANIFEST_URL_EON_STAGING; |
||||
} else { |
||||
manifest_url = argv[1]; |
||||
} |
||||
} |
||||
printf("updating from %s\n", manifest_url); |
||||
Updater updater; |
||||
updater.go(); |
||||
|
||||
return 0; |
||||
} |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:d1805ad557a93999b787ab1fd66f4bcef7d25226b123bd4f49774340f2e7476c |
||||
size 6354536 |
||||
oid sha256:46b4433f49e6d54ced1049e03aed650f6cb6de6d243ae64167945150935d7cd8 |
||||
size 12039472 |
||||
|
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:e9f15383e6c4c5b38d23ebddc61e1ea470e3bfe1162bc5541731110c44c5e930 |
||||
size 218 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4f5dfc20e99151c75d84292c20078403e74a57845b67b7a7a6a4b914bc7489d7 |
||||
size 6310 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1cc3d193d044c640dc508a71edade54dfbc8eda63ecd8357a56140040b9c7edb |
||||
size 1297 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:115e60c96995ddb54fb0e512f6daf22d4202f837b184516387db5d23d26a5646 |
||||
size 3321 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6224c4f8ab7b39d8adeb75546a6525079ffedfeea5237cbd36e867f3cee04803 |
||||
size 24230 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:522965edc66e550247798a34aea163332039153f24634d89258d291dc273e3c0 |
||||
size 50206 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:670bbc519eb78fc02e3d219bb22852094a822c93059cb0d8b84bfb589bef69d2 |
||||
size 28013 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ac6faedcf48e9e7b4d5d3d954902e89ba4cb10547bf3b95e6d0b18d449622380 |
||||
size 9362 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fc9d7e479c930899802a616233eb19cf35c348f1983e58e0b19009314f70e300 |
||||
size 3827 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:04f85d119fc222abd65aef1f57f8e03a94134c272b95ed781e8f3791c64d973a |
||||
size 11780 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ee90636296c75189310323ce3bf1b4a2f893b04c46c0e4f6f103b9a013a60033 |
||||
size 4316 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:170b6129e63451b96442573ecc95758388176d8793d5a979b00bf5346856716e |
||||
size 1312 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fd3e7a17778fa696a0fce301b5d50ed840d555b804f6d1b5b8f03d7fbb39283b |
||||
size 1645 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7cc1c4048bdea60287aa1d882bc7d6f6022650f9046e25aff467460e824682eb |
||||
size 1360 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1adbf47e36c389ce0b35d7e71d5dc554b395c773354f492fb05014f596a62fbb |
||||
size 13375 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2a5447e1652b16d9980d3b2c49f0c768ae72f3fbca63e53327db1f6792c017c9 |
||||
size 4478 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:101ddabd30d19118826fed11932cc31f93ca66f431577f9da332276ebe2b836c |
||||
size 1863 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2f1458af50d003e0ecdce63c3898ff3d4ea8dd377d8c578bf3585224f09e0a19 |
||||
size 9558 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c2a41eb4ce0779c2b1a8688963d941e42d865bb329f00b9b0afd1a47ce13f457 |
||||
size 3487 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d4f7436534cc53b22144089c1b4f1a2e2f0e46a73f7e34baac65f99f0c65b36e |
||||
size 1443 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3ef80851c4f0dabc111ca30f20fab1ad6986f3f0d0e647c0ff215cf0875b95d3 |
||||
size 1847 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:78aff1f5e3fcdd820a67090f0db2dc8354c3cce3bace7da137739e7c0698b3d0 |
||||
size 4135 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:84a970cfdf33f86843304d0f49b9bde40cfd36b538c6e92cf8fccbb8101eba39 |
||||
size 3670 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:757ac756acdb326d3b40dc1e01e56c38b4466cb188b0e2db34ea54407e28f14b |
||||
size 1909 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ca3771c1f65b2e9e95be641185f3948d06b41e274cfd84faa2237d926000a7d8 |
||||
size 4198 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:21d16d34c5fd57030ad898f7b4c658f56a0cb16ddc187acbb514abaed91d3524 |
||||
size 1946 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ec7353283565bfabfec563ffe770d538816c7f014f71268467f25535f83ce4b9 |
||||
size 1461 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dfd9355ceea4af60c603125897f8f1286488c415685a94849282eaf55f88a4cf |
||||
size 1587 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cccdfcc2f97ae9f4555108f88d0afccb05ce60dc77ca5ce77ef9bed336439079 |
||||
size 2967 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:673dcc1b4783a037c0bd740dd6eb197abfedb4b60652b9f197eb42d2bbbb111d |
||||
size 2652 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c3588b911e0996b8c3d1302159543078a7f47f284a643757baaa064b33ef54f7 |
||||
size 5719 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f1df1400d1802efa1493b12011c42a0463a78992fdcede39465a5a5c607d5f12 |
||||
size 5346 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:03399faeadd032a6ee04243da9598731155120ce5e0ba561176eeb5a23448a64 |
||||
size 2760 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2bb01005609d90b2764e74a286439d8ce18384ed49c5da5a32514a98199d3268 |
||||
size 5794 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6b7097beb61dd5f61c97ed00811ce3fdc8f54eb924966cb8df1c90587157ed29 |
||||
size 1989 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f6b79dd4de99b1641eed90ecdfc1bebe22b8eced1952f76d0817715ddeca1be2 |
||||
size 1761 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b8ebc04536bf5b9a3b8476fc69b16af88b4f7e270cc25dd5593775d8fd168e4a |
||||
size 3058 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:91e920eb91a889b7ebe4f75cf93d85974f15f56830bd74446274c297e45ebb1b |
||||
size 1478 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f2fa384a16c2dab3f5da239a403d475d1f66929c49546a68fef185f514b88f84 |
||||
size 1779 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:20ff33d9c67fc9f1dda1185a0c22233ba76fe802d9cd0baa1dc4d605866c2de5 |
||||
size 2969 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:67a6a070382d161ad4986058dcee5796d6872c1fbbc1e4ebf9405a2bb149a00b |
||||
size 2121 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a56179f0413127e1f482b52ed33484cd5614d0e4c3f5b73339e63855e5f33a5c |
||||
size 16085 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0d2b02316d73c9c8162200def733398df09c65d0cd095f36b41cb85b65e99aa0 |
||||
size 2537 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:855e3f340536dc4f8adcc36d9008462581b03b1896424ab1e280d06d48eef8b2 |
||||
size 2089 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cb9b5d3a8de374d4d321483dbad9f87d82aed3e5bae94b4ea95f0469f921b5aa |
||||
size 4161 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:265061758f26c7f49c73d3bd5b378a19dd6a85c2670184c425329db726f40f62 |
||||
size 5538 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f64238396d565007970e2dae18e6512f78c76ef7f25afb7bfecca2781410cff1 |
||||
size 850 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1dd4dd8ea31194aec5eb308448a84f68e00686c2e388ffdaa0b3d59ecbeb7605 |
||||
size 2925 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6da33fd21ca28b94f486cc7c3d8f0963aefd5e281681dad2c59e27b0649dfda7 |
||||
size 4146 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a7a2bce5e0fd0dbabf73d310d5b3396befca8a40fb3860c36fe99f5cbcebe552 |
||||
size 3771 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e188a71436fdb40a19171bee104f0faf35fc73d7b170420ec468c1053ffafe2b |
||||
size 3770 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bae5d175a8754ab82f351203496381c9f988ffa9f1549dfd47254280cbc572c1 |
||||
size 8057 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bbcdb1e69a5d74aa1c549fa191853a03536d9408fef9023a98ed5436b498c912 |
||||
size 11790 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2fd6327d02df20b3560bcbbfc0f1c9cab5bd506b2bc26a78f2bd3abcebdcf9e8 |
||||
size 1144 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:78dd17ec37b92b113c1e30c226458ebec4006c75ec71d3324e659f0b6334c756 |
||||
size 10433 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:245631b236d2ca272f3d565eefe70af92be7a2cbd7ef73b2cf6d276b9bad1090 |
||||
size 5494 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:339188da63c72c067a7b88bce21452d20d42f62bf9e0a9f23013b64e51121ad9 |
||||
size 11552 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:78197bb11633009e50538af6822158be2d00231c3e25f340f8914756833ae006 |
||||
size 4683 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0b17767bfe0b7796f422fb9132a23e7bddf1ed29111562ecb49cdf0f42d52b8a |
||||
size 3979 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:65f7cd6b57b6afa4afb020769c45ce7c34ecb28aa24e2a32db422ec049501ae7 |
||||
size 22456 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a5f5ad65254a75518430630e0efb42437717c1b5d5c779d8979a95d4bcfd43b2 |
||||
size 1404 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7e2756965873ef04d7a5e9c74d129f987c7bda68cc6c2bcf1621ec7f607d8655 |
||||
size 892 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f27a7d810fab79a182925bcbad91845e8b0fcd23e34450187de2120b1b651b20 |
||||
size 4207 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0c041de77a8d30abba6fdc0cfd6a1d3e12e0542d2d36db0ad50fbffde103a9a9 |
||||
size 2260 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:190e6fd0d3aa51febe4425f207c9ccb3f3d477df30de4ecd47cf15d72b07cc2a |
||||
size 1797 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7cc59712c78a22786ea7ea8151b49fa0882f4db09f79e5551f87780933378cbd |
||||
size 12943 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:64566e05d8794a536fb6a7a86bd5125c76b54f5ce4c1c95fa1cfe810f3a4f4f8 |
||||
size 24769 |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d1df0d4b3379b6daebd902add7e38a8f53b90c3b7c25b1d8855fd44a043fe650 |
||||
size 4488 |
||||
oid sha256:f34c4a8a04b6b04c012bf730d7e17ec379af9c1a1b06f3bf5d093ed3a182b18d |
||||
size 2071 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5eae57aaf0445cb13dd971a5e050835d3dfe0d8a73818d9d700850845012f3f0 |
||||
size 1947 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b6f1016bc60c8b046c4010d09b674d5b65812bc58abe1345de2e5bbbae8ccb3a |
||||
size 1873 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4bf890c484480988656a5ad46d265d1d6c82832a521a2168a199f6ff5a77bfb7 |
||||
size 6461 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d64ef9a3ce9b4cf20a1c68ccf2fda5d8afeaa00c87b51fbfe424cea50ed4f3ce |
||||
size 2916 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fef9e2cf234338f057d1ca7fd572c288dbb55039c64e5430bbc4519818806d6d |
||||
size 3579 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1e7abdb7046401e50d7a00bdf3e0af74c8cb6e29eec684559beb203f2dc2cb55 |
||||
size 3079 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4e6e156d6f99b5b5fe1ea69241d466eafda734c20d76b506b976028695486d09 |
||||
size 2528 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e126e8f6dc76e9f5ac8ceeb24f1c1add7d77b5d53e9b7281d37593d8e7bae956 |
||||
size 7596 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e3762e8cb68493ea8951bfe72510de46735e750e0acacb5e1abff719508c4634 |
||||
size 13515 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c32afc8cbfaa4cb365712a7a5dfe32ab25c9f7c9fb9aa604ba0008375ac6af42 |
||||
size 9287 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5e8d9b67e029a12641f472d341eb2f7e59ced566e7a0ed163158679eb09dfcb3 |
||||
size 3360 |
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7675d7d60165054bb459a20959e179a66cb4338db61d5da468c022be23e992ef |
||||
size 1356 |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue