From 9bb1c1531b6fe1f774d70c5df7786e210ac1a0a0 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Fri, 16 Oct 2015 12:25:02 +0900 Subject: [PATCH] evlog - update tool to look and work better --- build.sh | 2 +- evlog.c | 1350 ++++++++++++++++++++++++-------------- evlog.edc | 64 +- img/box_glow.png | Bin 470 -> 0 bytes img/box_outline.png | Bin 115 -> 0 bytes img/diagonal_stripes.png | Bin 0 -> 1076 bytes img/runner_vert.png | Bin 99 -> 0 bytes 7 files changed, 882 insertions(+), 534 deletions(-) delete mode 100644 img/box_glow.png delete mode 100644 img/box_outline.png create mode 100644 img/diagonal_stripes.png delete mode 100644 img/runner_vert.png diff --git a/build.sh b/build.sh index f144398..34c1c2e 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,5 @@ #!/bin/sh -gcc evlog.c -o evlog `pkg-config --cflags --libs elementary` +gcc evlog.c -o evlog `pkg-config --cflags --libs elementary` -g edje_cc evlog.edc -id ./img ### minimal docs! diff --git a/evlog.c b/evlog.c index 509edb4..4bc5244 100644 --- a/evlog.c +++ b/evlog.c @@ -5,255 +5,248 @@ edje_cc evlog.edc -id ./img #include -#define RES 1000000.0 +#define RES 100000.0 Evas_Object *win; Evas_Object *zoom_slider; typedef struct _Evlog Evlog; -typedef struct _Evlog_Block Evlog_Block; -typedef struct _Evlog_Stack Evlog_Stack; -typedef struct _Evlog_Stack_Item Evlog_Stack_Item; +typedef struct _Evlog_Thread Evlog_Thread; +typedef struct _Evlog_Event Evlog_Event; struct _Evlog { FILE *file; - double start_t; - double end_t; - Evlog_Block *blocks; - unsigned int blocks_num; + double first_timestamp; + double last_timestamp; + int state_num; + int thread_num; + Evlog_Event *states; + Evlog_Thread *threads; }; -struct _Evlog_Stack_Item +struct _Evlog_Event { - long offset; - void *ptr; - Eina_Evlog_Item item; + const char *event; +// const char *detail; + double timestamp; + double latency; }; -struct _Evlog_Stack +struct _Evlog_Thread { - unsigned long long thread; - unsigned int items_num; - unsigned int items_alloc; - Evlog_Stack_Item *items; + unsigned long long id; + int event_num; + Evlog_Event *events; }; -struct _Evlog_Block +typedef struct { - unsigned int overflow; - unsigned int num; - unsigned int end_stacks_num; - long start; - long end; - Evlog_Stack *end_stacks; - double start_t; - double end_t; -}; + Evlog *evlog; + Evas_Object *win; + Evas_Object *scroller; + Evas_Object *table; + struct { + Evas_Object *state; + Evas_Object **thread; + Evas_Object *over; + } grid; + Eina_List *objs; + struct { + Ecore_Job *job; + Ecore_Thread *thread; + double t0, t1, tmin; + Eina_Bool redo : 1; + Eina_List *remobjs; + } update; +} Inf; -static long -_evlog_item_fetch(Evlog *evlog, Eina_Evlog_Item *item) +typedef struct { - long pos; + void *src; + char *event; + Evas_Object *obj; + double t0, t1; + int n; + int slot; + Eina_Bool nuke : 1; +} Event; - pos = ftell(evlog->file); - if (fread(item, sizeof(Eina_Evlog_Item), 1, evlog->file) != 1) return -1; - if (item->event_offset != sizeof(Eina_Evlog_Item)) return -1; - if (item->event_offset >= item->event_next) return -1; - if (item->detail_offset >= item->event_next) return -1; - if (fseek(evlog->file, -sizeof(Eina_Evlog_Item), SEEK_CUR) != 0) return -1; - return pos; -} +#define ROUND_AMOUNT 1024 +#define ROUND(x) ((x + (ROUND_AMOUNT - 1)) / ROUND_AMOUNT) * ROUND_AMOUNT; -static char * -_evlog_item_event_fetch(Evlog *evlog, long pos, Eina_Evlog_Item *item) +static void _fill_begin(Inf *inf); + + + + + + + + + + + + + + + + +static void +evlog_state_event_register(Evlog *evlog, Evlog_Event *ev) { - long ppos = ftell(evlog->file); - char *str = malloc(item->event_next); - if (!str) return NULL; - fseek(evlog->file, pos + item->event_offset, SEEK_SET); - if (fread(str, item->event_next, 1, evlog->file) != 1) + int n0, n; + + n0 = evlog->state_num; + evlog->state_num++; + n = evlog->state_num; + n0 = ROUND(n0); + n = ROUND(n); + if (n != n0) { - free(str); - str = NULL; + Evlog_Event *tmp; + + tmp = realloc(evlog->states, n * sizeof(Evlog_Event)); + if (!tmp) + { + eina_stringshare_del(ev->event); + return; + } + evlog->states = tmp; } - fseek(evlog->file, ppos, SEEK_SET); - return str; + evlog->states[evlog->state_num - 1] = *ev; } static void -_evlog_stack_push(Evlog_Stack *stack, long pos, Eina_Evlog_Item *item) +evlog_thread_event_register(Evlog_Thread *th, Evlog_Event *ev) { - stack->items_num++; - if (!stack->items) - { - stack->items_alloc = 16; - stack->items = malloc(sizeof(Evlog_Stack_Item) * - stack->items_alloc); - if (!stack->items) return; - } - else if (stack->items_num > stack->items_alloc) - { - Evlog_Stack_Item *items; + int n0, n; - stack->items_alloc += 16; - items = realloc(stack->items, sizeof(Evlog_Stack_Item) * - stack->items_alloc); - if (!items) return; - stack->items = items; + n0 = th->event_num; + th->event_num++; + n = th->event_num; + n0 = ROUND(n0); + n = ROUND(n); + if (n != n0) + { + Evlog_Event *tmp; + + tmp = realloc(th->events, n * sizeof(Evlog_Event)); + if (!tmp) + { + eina_stringshare_del(ev->event); + return; + } + th->events = tmp; } - stack->items[stack->items_num - 1].offset = pos; - stack->items[stack->items_num - 1].item = *item; + th->events[th->event_num - 1] = *ev; } static void -_evlog_stack_pop(Evlog_Stack *stack) +evlog_event_register(Evlog *evlog, unsigned long long thread, Evlog_Event *ev) { - stack->items_num--; - if (stack->items_num == 0) - { - free(stack->items); - stack->items_alloc = 0; - stack->items = NULL; - } -} - -static void -_evlog_stack_dup(Evlog_Stack *stack, Evlog_Stack *dst) -{ - *dst = *stack; - dst->items = malloc(sizeof(Evlog_Stack_Item) * stack->items_num); - if (!dst->items) return; - memcpy(dst->items, stack->items, sizeof(Evlog_Stack_Item) * stack->items_num); - dst->items_alloc = dst->items_num; -} - -static Evlog_Stack * -_evlog_stack_get(Evlog_Stack **stacks, int *stacks_num, unsigned long long thread) -{ - Evlog_Stack *stack = NULL; int i; - for (i = 0; i < *stacks_num; i++) + if ((ev->event[0] == '<') || (ev->event[0] == '>')) { - if ((*stacks)[i].thread == thread) - { - stack = &((*stacks)[i]); - break; - } + evlog_state_event_register(evlog, ev); } - if (!(*stacks)) + else { - (*stacks_num)++; - stack = realloc(*stacks, sizeof(Evlog_Stack) * (*stacks_num)); - if (stack) + for (i = 0; i < evlog->thread_num; i++) { - *stacks = stack; - stack = &((*stacks)[(*stacks_num) - 1]); - memset(stack, 0, sizeof(Evlog_Stack)); - stack->thread = thread; + if (evlog->threads[i].id == thread) break; } + if (i >= evlog->thread_num) + { + Evlog_Thread *tmp; + + evlog->thread_num++; + tmp = realloc(evlog->threads, + evlog->thread_num * sizeof(Evlog_Thread)); + if (!tmp) + { + eina_stringshare_del(ev->event); + return; + } + evlog->threads = tmp; + evlog->threads[i].id = thread; + evlog->threads[i].event_num = 0; + evlog->threads[i].events = NULL; + } + evlog_thread_event_register(&(evlog->threads[i]), ev); } - return stack; } -static void -_evlog_block_list(Evlog *evlog) +static void * +evlog_event_read(Evlog *evlog, void *ptr, void *end) +{ + unsigned char *data = ptr; + unsigned char *dataend = end; + const char *eventstr = NULL, *detailstr = NULL; + Eina_Evlog_Item item; + + if ((dataend - data) < sizeof(Eina_Evlog_Item)) return NULL; + + memcpy(&item, data, sizeof(Eina_Evlog_Item)); + + if (item.event_offset >= sizeof(Eina_Evlog_Item)) + eventstr = data + item.event_offset; + if (item.detail_offset >= sizeof(Eina_Evlog_Item)) + detailstr = data + item.detail_offset; + if (eventstr) + { + Evlog_Event ev; + ev.event = eina_stringshare_add(eventstr); + ev.timestamp = (item.srctim == 0.0) ? item.tim : item.srctim; + ev.latency = (item.srctim != 0.0) ? item.tim - item.srctim : 0.0; + if (evlog->first_timestamp == 0.0) + evlog->first_timestamp = ev.timestamp; + if (ev.timestamp > evlog->last_timestamp) + evlog->last_timestamp = ev.timestamp; + evlog_event_register(evlog, item.thread, &ev); + } + + data += item.event_next; + if (data >= dataend) return NULL; + return data; +} + +static Eina_Bool +evlog_block_read(Evlog *evlog) { unsigned int header[3]; - Eina_Binbuf *buf; - unsigned int num = 0, blocksize, evnum; - long pos; - Evlog_Block block = { 0 }; - Eina_Evlog_Item item = { 0 }; - int stacks_num = 0, i; - Evlog_Stack *stacks = NULL; + Eina_Bool bigendian = EINA_FALSE; - buf = eina_binbuf_new(); - rewind(evlog->file); - for (;;) + if (fread(header, 12, 1, evlog->file) != 1) return EINA_FALSE; + if (header[0] == 0x0ffee211) bigendian = EINA_FALSE; + else if (header[0] == 0x11e2fe0f) bigendian = EINA_TRUE; + else return EINA_FALSE; + if (!bigendian) { - block.start_t = 0.0; - block.num = 0; - if (fread(header, 12, 1, evlog->file) != 1) break; - if (header[0] == 0xffee211) + unsigned int blocksize = header[1]; + unsigned int overflow = header[2]; + void *buf = malloc(blocksize); + if (buf) { - blocksize = header[1]; - block.overflow = header[2]; - block.start = ftell(evlog->file); - if (fseek(evlog->file, blocksize, SEEK_CUR) != 0) break; - block.end = ftell(evlog->file); - if (fseek(evlog->file, block.start, SEEK_SET) != 0) break; - } - else break; - while ((pos = _evlog_item_fetch(evlog, &item)) >= 0) - { - char *event = _evlog_item_event_fetch(evlog, pos, &item); - if (event) + void *ptr, *end; + + if (fread(buf, blocksize, 1, evlog->file) != 1) { - if (block.start_t == 0.0) block.start_t = item.tim; - block.end_t = item.tim; - if (event[0] == '+') - { - Evlog_Stack *stack; - - stack = _evlog_stack_get(&stacks, &stacks_num, item.thread); - if (stack) _evlog_stack_push(stack, pos, &item); - } - else if (event[0] == '-') - { - Evlog_Stack *stack = NULL; - - stack = _evlog_stack_get(&stacks, &stacks_num, item.thread); - if ((stack) && (stack->items_num > 0)) - { - char *event_top = _evlog_item_event_fetch - (evlog, stack->items[stack->items_num - 1].offset, - &(stack->items[stack->items_num - 1].item)); - if ((event_top) && - (!strcmp(event + 1, event_top + 1))) - _evlog_stack_pop(stack); - free(event_top); - } - } - free(event); - block.num++; + free(buf); + return EINA_FALSE; } - fseek(evlog->file, item.event_next, SEEK_CUR); + ptr = buf; + end = ptr + blocksize; + while ((ptr = evlog_event_read(evlog, ptr, end))); + free(buf); } - block.end_stacks = stacks; - block.end_stacks_num = stacks_num; - stacks = NULL; - stacks_num = 0; - printf("BLOCK %i, %i events, o=%i %1.7f (%1.7f)\n", - num, block.num, block.overflow, - block.start_t, block.end_t - block.start_t); - eina_binbuf_append_length(buf, (unsigned char *)(&block), sizeof(Evlog_Block)); - fseek(evlog->file, block.end, SEEK_SET); - num++; } - printf("have %i blocks\n", num); - rewind(evlog->file); - evlog->blocks = (Evlog_Block *)eina_binbuf_string_steal(buf); - evlog->blocks_num = num; - eina_binbuf_free(buf); -} - -static int -evlog_block_find(Evlog *evlog, double t) -{ - int i; - - t += evlog->start_t; - for (i = 0; i < evlog->blocks_num; i++) + else { - if ((t < evlog->blocks[i].start_t) && (i > 0)) - return i -1; - else if ((i == (evlog->blocks_num - 1)) && - (t <= evlog->blocks[i].end_t)) - return i; + // XXX: handle bigendian } - return -1; + return EINA_TRUE; } static Evlog * @@ -267,18 +260,14 @@ evlog_new(const char *file) free(evlog); return EINA_FALSE; } - _evlog_block_list(evlog); - if (evlog->blocks_num > 0) - { - evlog->start_t = evlog->blocks[0].start_t; - evlog->end_t = evlog->blocks[evlog->blocks_num - 1].end_t; - } + while (evlog_block_read(evlog)); return evlog; } static void evlog_free(Evlog *evlog) { + // XXX free other stuff fclose(evlog->file); free(evlog); } @@ -289,368 +278,724 @@ evlog_free(Evlog *evlog) -typedef struct _Evlog_View Evlog_View; -typedef struct _Evlog_View_Block Evlog_View_Block; -typedef struct _Evlog_View_Item Evlog_View_Item; -struct _Evlog_View_Item + + + + +static Eina_Bool +_can_see(double t0, double t1, double tmin, double t0in, double t1in) { - double start_t; - double end_t; - unsigned long long thread; - int level; - Evas_Object *obj; - char *event; -}; - -struct _Evlog_View_Block -{ - int src_block; - Eina_List *items; -}; - -struct _Evlog_View -{ - Evas_Object *scroller, *zoom, *table, *rect, *grid; - Evlog *evlog; - double pzoom; - int blocks_start; - int blocks_end; - Eina_List *blocks; -}; - -static void -evlog_view_zoom_update(Evas_Object *sc) -{ - Evlog_View *view = evas_object_data_get(sc, "view"); - double zoom = elm_slider_value_get(view->zoom); - double tlen; - - tlen = view->evlog->end_t - view->evlog->start_t; - evas_object_size_hint_min_set(view->rect, - tlen * zoom * 100.0, - 400); + if (t1in >= 0.0) + { + if ((t0in <= t1) && + (t1in >= t0) && + ((t1in - t0in) >= tmin)) + return EINA_TRUE; + } + else + { + if ((t0in <= t1) && + (t0in >= t0)) + return EINA_TRUE; + } + return EINA_FALSE; } -static void -evlog_blocks_clear(Evas_Object *sc) +static Evas_Object * +_create_log_states(Evas_Object *win, Evlog *evlog, Evas_Object *zoom) { - Evlog_View *view = evas_object_data_get(sc, "view"); - Evlog_View_Item *vi; - Evlog_View_Block *b; + Evas_Object *o, *oo; + double len = evlog->last_timestamp - evlog->first_timestamp; int i; + int h = 0; + Eina_List *events = NULL, *l; + Event *ev; + Evlog_Event *e; + double t; - EINA_LIST_FREE(view->blocks, b) + o = elm_grid_add(win); + for (i = 0; i < evlog->state_num; i++) { - EINA_LIST_FREE(b->items, vi) + e = &(evlog->states[i]); + t = e->timestamp - evlog->first_timestamp; + if (e->event[0] == '>') { - if (vi->obj) evas_object_del(vi->obj); - free(vi->event); - free(vi); - } - free(b); - } -} - -static void -evlog_view_block_fill(Evas_Object *sc, Evlog_View_Block *b) -{ - Evlog_View *view = evas_object_data_get(sc, "view"); - Evlog_View_Item *vi; - Evlog_Block *bl; - Evlog_Stack *stacks = NULL; - int i, j, stacks_num = 0; - int items_num = 0; - long pos; - Eina_Evlog_Item item = { 0 }; - - if (b->src_block > 0) - { - bl = &(view->evlog->blocks[b->src_block - 1]); - for (i = 0; i < bl->end_stacks_num; i++) - { - Evlog_Stack *stack; - - stack = _evlog_stack_get(&stacks, &stacks_num, bl->end_stacks[i].thread); - if (stack) + ev = calloc(1, sizeof(Event)); + if (ev) { - _evlog_stack_dup(&(bl->end_stacks[i]), stack); - for (j = 0; j < stack->items_num; j++) - { - vi = calloc(1, sizeof(Evlog_View_Item)); - vi->start_t = stack->items[j].item.tim - view->evlog->start_t; - vi->end_t = 0.0; - vi->thread = stack->thread; - vi->level = j; - vi->obj = NULL; - vi->event = _evlog_item_event_fetch(view->evlog, stack->items[j].offset, &(stack->items[j].item)); - b->items = eina_list_append(b->items, vi); - stack->items[j].ptr = vi; - } + ev->src = e; + ev->event = strdup(e->event + 1); + ev->t0 = t; + events = eina_list_append(events, ev); + ev->n = eina_list_count(events) - 1; + if ((ev->n + 1) > h) h = ev->n + 1; } } - } - bl = &(view->evlog->blocks[b->src_block]); - fseek(view->evlog->file, bl->start, SEEK_SET); - while ((pos = _evlog_item_fetch(view->evlog, &item)) >= 0) - { - char *event = _evlog_item_event_fetch(view->evlog, pos, &item); - if (event) + else if (e->event[0] == '<') { - printf("EV %s\n", event); - if (event[0] == '!') + EINA_LIST_FOREACH(events, l, ev) { - vi = calloc(1, sizeof(Evlog_View_Item)); - vi->start_t = item.tim - view->evlog->start_t; - vi->end_t = -1.0; - vi->thread =item.thread; - vi->level = -1; - vi->obj = NULL; - vi->event = _evlog_item_event_fetch(view->evlog, pos, &item); - b->items = eina_list_append(b->items, vi); - } - else if (event[0] == '+') - { - Evlog_Stack *stack; - - stack = _evlog_stack_get(&stacks, &stacks_num, item.thread); - if (stack) + if (!strcmp(ev->event, e->event + 1)) { - _evlog_stack_push(stack, pos, &item); - j = stack->items_num - 1; - printf(" %i\n", j); - vi = calloc(1, sizeof(Evlog_View_Item)); - vi->start_t = item.tim - view->evlog->start_t; - vi->end_t = 0.0; - vi->thread = item.thread; - vi->level = j; - vi->obj = NULL; - vi->event = _evlog_item_event_fetch(view->evlog, pos, &(stack->items[j].item)); - b->items = eina_list_append(b->items, vi); - stack->items[j].ptr = vi; - } - } - else if (event[0] == '-') - { - Evlog_Stack *stack = NULL; - - stack = _evlog_stack_get(&stacks, &stacks_num, item.thread); - if ((stack) && (stack->items_num > 0)) - { - char *event_top = _evlog_item_event_fetch - (view->evlog, - stack->items[stack->items_num - 1].offset, - &(stack->items[stack->items_num - 1].item)); - if ((event_top) && - (!strcmp(event + 1, event_top + 1))) - { - j = stack->items_num - 1; - vi = stack->items[j].ptr; - if (vi) - { - vi->end_t = item.tim - view->evlog->start_t; - } - _evlog_stack_pop(stack); - } - free(event_top); - } - } - free(event); - } - fseek(view->evlog->file, item.event_next, SEEK_CUR); - } -} - -static void -evlog_view_update(Evas_Object *sc) -{ - Evlog_View *view = evas_object_data_get(sc, "view"); - double zoom = elm_slider_value_get(view->zoom); - Evas_Coord x, y, w, h, ww, hh, xx; - double tlen, t0, t1; - int b0, b1, i; - Evlog_View_Block *b; - Evlog_View_Item *vi; - Eina_List *l, *ln; - - evas_output_viewport_get(evas_object_evas_get(sc), NULL, NULL, &ww, &hh); - evas_object_geometry_get(view->rect, &x, &y, &w, &h); - if (w == 0) return; - - tlen = view->evlog->end_t - view->evlog->start_t; - - if (x <= 0) t0 = (double)(-x * tlen) / (double)w; - else t0 = 0.0; - - xx = x + w; - if (xx < ww) t1 = tlen; - else t1 = (double)((ww - x) * tlen) / (double)w; - if (t0 < 0.0) t0 = 0.0; - if (t1 > tlen) t1 = tlen; - - b0 = evlog_block_find(view->evlog, t0); - b1 = evlog_block_find(view->evlog, t1); - printf("can see from %1.7f to %1.7f [%i %i]\n", t0, t1, b0, b1); - if (view->pzoom != zoom) - { - evlog_blocks_clear(sc); - view->blocks_start = 0; - view->blocks_end = 0; - } - if ((view->blocks_start != b0) || (view->blocks_end != (b1 + 1))) - { - Eina_List *blocks = NULL; - Eina_Bool ok; - - for (i = b0; i <= b1; i++) - { - ok = EINA_FALSE; - EINA_LIST_FOREACH_SAFE(view->blocks, l, ln, b) - { - if (b->src_block == i) - { - blocks = eina_list_append(blocks, b); - view->blocks = eina_list_remove_list(view->blocks, l); - ok = EINA_TRUE; + ev->t1 = t; + free(ev->event); + free(ev); + events = eina_list_remove_list(events, l); break; } } - if (!ok) + } + } + t = evlog->last_timestamp - evlog->first_timestamp; + EINA_LIST_FREE(events, ev) + { + ev->t1 = t; + free(ev->event); + free(ev); + } + + if (h < 1) h = 1; + elm_grid_size_set(o, len * RES, h); + double res = elm_slider_value_get(zoom); + res = res * res; + evas_object_size_hint_min_set(o, len * res, h * 20); + + oo = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(oo, 24, 24, 24, 255); + elm_grid_pack(o, oo, 0, 0, len * RES, h); + evas_object_show(oo); + return o; +} + +static void +_add_log_state(Inf *inf, Event *ev) +{ + Eina_List *l; + Event *ev2; + + EINA_LIST_FOREACH(inf->objs, l, ev2) + { + if (ev2->src == ev->src) + { + free(ev->event); + free(ev); + return; + } + } + inf->objs = eina_list_append(inf->objs, ev); +} + +static void +_fill_log_states(Inf *inf, Evlog *evlog, double t0, double t1, double tmin) +{ + int i; + Eina_List *events = NULL, *l; + Event *ev; + Evlog_Event *e; + double t; + + for (i = 0; i < evlog->state_num; i++) + { + e = &(evlog->states[i]); + t = e->timestamp - evlog->first_timestamp; + if (e->event[0] == '>') + { + ev = calloc(1, sizeof(Event)); + if (ev) { - b = calloc(1, sizeof(Evlog_View_Block)); - blocks = eina_list_append(blocks, b); - b->src_block = i; - evlog_view_block_fill(sc, b); + ev->src = e; + ev->event = strdup(e->event + 1); + ev->t0 = t; + events = eina_list_append(events, ev); + ev->n = eina_list_count(events) - 1; + ev->slot = 0; } } - evlog_blocks_clear(sc); - view->blocks = blocks; - view->blocks_start = b0; - view->blocks_end = b1 + 1; - } - EINA_LIST_FOREACH(view->blocks, l, b) - { - EINA_LIST_FOREACH(b->items, ln, vi) + else if (e->event[0] == '<') { - if (!vi->obj) + EINA_LIST_FOREACH(events, l, ev) { - double vt0, vt1; - - vt0 = vi->start_t; - vt1 = vi->end_t; -// if (vt1 == 0.0) vt1 = t1; -/* - if (vt1 > 0.0) - else if (vt1 < 0.0) - */ - if ((vt0 < t1) && - ((vt1 < 0.0) || (vt1 >= t0)) - ) + if (!strcmp(ev->event, e->event + 1)) { - if ((vt1 > 0.0) && - ((((vt1 - vt0) * w) / tlen) >= 4)) + ev->t1 = t; + if (_can_see(t0, t1, tmin, ev->t0, ev->t1)) + _add_log_state(inf, ev); + else { - vi->obj = edje_object_add(evas_object_evas_get(sc)); - edje_object_file_set(vi->obj, "./evlog.edj", "range"); - edje_object_part_text_set(vi->obj, "text", vi->event + 1); - elm_grid_pack(view->grid, vi->obj, - vt0 * RES, - 400 - ((vi->level + 1) * 14), - (vt1 - vt0) * RES, - 14); - evas_object_show(vi->obj); - } - else if (vt1 < 0.0) - { - vi->obj = edje_object_add(evas_object_evas_get(sc)); - if (!strcmp(vi->event, "!FRAME")) - edje_object_file_set(vi->obj, "./evlog.edj", "frame"); - else - edje_object_file_set(vi->obj, "./evlog.edj", "event"); - edje_object_part_text_set(vi->obj, "text", vi->event + 1); - elm_grid_pack(view->grid, vi->obj, - (vt0 * RES), - 0, - 1, - 400); - evas_object_show(vi->obj); - evas_object_lower(vi->obj); + free(ev->event); + free(ev); } + events = eina_list_remove_list(events, l); + break; } } } } - view->pzoom = zoom; + t = evlog->last_timestamp - evlog->first_timestamp; + EINA_LIST_FREE(events, ev) + { + ev->t1 = t; + if (_can_see(t0, t1, tmin, ev->t0, ev->t1)) + _add_log_state(inf, ev); + else + { + free(ev->event); + free(ev); + } + } +} + + + + + + + + + +static Evas_Object * +_create_log_thread(Evas_Object *win, Evlog *evlog, Evlog_Thread *th, int slot, Evas_Object *zoom) +{ + Evas_Object *o, *oo; + double len = evlog->last_timestamp - evlog->first_timestamp; + int i, c; + int h = 0; + Eina_List *stack = NULL, *l; + Event *ev; + Evlog_Event *e; + double t; + + o = elm_grid_add(win); + for (i = 0; i < th->event_num; i++) + { + e = &(th->events[i]); + t = e->timestamp - evlog->first_timestamp; + if (e->event[0] == '+') + { + ev = calloc(1, sizeof(Event)); + if (ev) + { + ev->src = e; + stack = eina_list_append(stack, ev); + ev->event = strdup(e->event + 1); + ev->t0 = t; + ev->n = eina_list_count(stack) - 1; + if ((ev->n + 1) > h) h = ev->n + 1; + } + } + else if (e->event[0] == '-') + { + l = eina_list_last(stack); + if (l) + { + ev = l->data; + ev->t1 = t; + free(ev->event); + free(ev); + stack = eina_list_remove_list(stack, l); + } + } + else if (e->event[0] == '!') + { + } + else if (e->event[0] == '*') + { + } + } + t = evlog->last_timestamp - evlog->first_timestamp; + EINA_LIST_FREE(stack, ev) + { + ev->t1 = t; + free(ev->event); + free(ev); + } + if (h < 1) h = 1; + elm_grid_size_set(o, len * RES, h); + evas_object_size_hint_min_set(o, 1, h * 20); + + oo = evas_object_rectangle_add(evas_object_evas_get(win)); + c = 32 + ((slot % 2) * 16); + evas_object_color_set(oo, c, c, c, 255); + elm_grid_pack(o, oo, 0, 0, len * RES, h); + evas_object_show(oo); + return o; +} + +static void +_add_log_event(Inf *inf, Event *ev) +{ + Eina_List *l; + Event *ev2; + + EINA_LIST_FOREACH(inf->objs, l, ev2) + { + if (ev2->src == ev->src) + { + free(ev->event); + free(ev); + return; + } + } + inf->objs = eina_list_append(inf->objs, ev); +} + +static void +_fill_log_thread(Inf *inf, Evlog *evlog, Evlog_Thread *th, int slot, double t0, double t1, double tmin) +{ + Eina_List *stack = NULL, *l; + Event *ev; + int i; + int h = 0; + Evlog_Event *e; + double t; + + for (i = 0; i < th->event_num; i++) + { + e = &(th->events[i]); + t = e->timestamp - evlog->first_timestamp; + if (e->event[0] == '+') + { + ev = calloc(1, sizeof(Event)); + if (ev) + { + ev->src = e; + stack = eina_list_append(stack, ev); + ev->event = strdup(e->event + 1); + ev->t0 = t; + ev->n = eina_list_count(stack) - 1; + ev->slot = slot; + if ((ev->n + 1) > h) h = ev->n + 1; + } + } + else if (e->event[0] == '-') + { + l = eina_list_last(stack); + if (l) + { + ev = l->data; + ev->t1 = t; + if (_can_see(t0, t1, tmin, ev->t0, ev->t1)) + _add_log_event(inf, ev); + else + { + free(ev->event); + free(ev); + } + stack = eina_list_remove_list(stack, l); + } + } + else if (e->event[0] == '!') + { + ev = calloc(1, sizeof(Event)); + if (ev) + { + ev->src = e; + ev->event = strdup(e->event + 1); + ev->t0 = t; + ev->t1 = -1.0; + ev->n = 0; + ev->slot = -1; + if (_can_see(t0, t1, tmin, ev->t0, ev->t1)) + _add_log_event(inf, ev); + else + { + free(ev->event); + free(ev); + } + } + } + else if (e->event[0] == '*') + { + } + } + t = evlog->last_timestamp - evlog->first_timestamp; + EINA_LIST_FREE(stack, ev) + { + ev->t1 = t; + if (_can_see(t0, t1, tmin, ev->t0, ev->t1)) + _add_log_event(inf, ev); + else + { + free(ev->event); + free(ev); + } + } +} + +static void +_fill_event_clean(Inf *inf, double t0, double t1, double tmin) +{ + Eina_List *l; + Event *ev; + + EINA_LIST_FOREACH(inf->objs, l, ev) + { + if (_can_see(t0, t1, tmin, ev->t0, ev->t1)) + { + if (ev->nuke) + { + inf->update.remobjs = eina_list_remove(inf->update.remobjs, ev); + ev->nuke = 0; + } + } + else + { + if (!ev->nuke) + { + inf->update.remobjs = eina_list_append(inf->update.remobjs, ev); + ev->nuke = 1; + } + } + } +} + +static void +_fill_log_table(Evas_Object *win, Evas_Object *tb, Evlog *evlog, Evas_Object *zoom) +{ + Inf *inf = evas_object_data_get(zoom, "inf"); + Evas_Object *o; + char buf[256]; + int i, y = 0; + + o = elm_label_add(win); + elm_object_text_set(o, "STATES"); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5); + elm_table_pack(tb, o, 0, y, 1, 1); + evas_object_show(o); + + o = _create_log_states(win, evlog, zoom); + inf->grid.state = o; + evas_object_size_hint_weight_set(o, 0.0, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5); + elm_table_pack(tb, o, 2, y++, 1, 1); + evas_object_show(o); + + inf->grid.thread = calloc(1, evlog->thread_num * sizeof(Evas_Object *)); + + for (i = 0; i < evlog->thread_num; i++) + { + snprintf(buf, sizeof(buf), "%i", i + 1); + + o = elm_label_add(win); + elm_object_text_set(o, buf); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5); + elm_table_pack(tb, o, 0, y, 1, 1); + evas_object_show(o); + + o = _create_log_thread(win, evlog, &(evlog->threads[i]), i ,zoom); + inf->grid.thread[i] = o; + evas_object_size_hint_weight_set(o, 0.0, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5); + elm_table_pack(tb, o, 2, y++, 1, 1); + evas_object_show(o); + } + + o = elm_separator_add(win); + evas_object_size_hint_weight_set(o, 0.0, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, 0.5, EVAS_HINT_FILL); + elm_table_pack(tb, o, 1, 0, 1, y); + evas_object_show(o); + + o = elm_grid_add(win); + inf->grid.over = o; + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_grid_size_set(o, (evlog->last_timestamp - evlog->first_timestamp) * RES, 1); + elm_table_pack(tb, o, 2, 0, 1, y); + evas_object_show(o); +} + + + + + + +static void +_cb_fill_blocking(void *data, Ecore_Thread *thread) +{ + Inf *inf = data; + int i; + + _fill_event_clean(inf, + inf->update.t0 - inf->evlog->first_timestamp, + inf->update.t1 - inf->evlog->first_timestamp, + inf->update.tmin); + + _fill_log_states(inf, inf->evlog, + inf->update.t0 - inf->evlog->first_timestamp, + inf->update.t1 - inf->evlog->first_timestamp, + inf->update.tmin); + + for (i = 0; i < inf->evlog->thread_num; i++) + { + _fill_log_thread(inf, inf->evlog, &(inf->evlog->threads[i]), i + 1, + inf->update.t0 - inf->evlog->first_timestamp, + inf->update.t1 - inf->evlog->first_timestamp, + inf->update.tmin); + } +} + + + + + + + + + +static Evas_Object * +_add_log_state_object(Evas_Object *win, Evas_Object *grid, Event *ev) +{ + Evas_Object *o, *oe; + int col[4] = {255, 255, 255, 255}, i; + char *s; + + o = elm_layout_add(win); + oe = elm_layout_edje_get(o); + elm_layout_file_set(o, "./evlog.edj", "state"); + i = 0; + for (s = ev->event; *s; s++) + { + col[i % 3] ^= *s; + i++; + } + edje_object_color_class_set(oe, "state", + col[0] / 2, col[1] / 2, col[2] / 2, col[3], + 255, 255, 255, 255, + 255, 255, 255, 255); + edje_object_part_text_set(oe, "text", ev->event); + elm_grid_pack(grid, o, ev->t0 * RES, ev->n, (ev->t1 - ev->t0) * RES, 1); + elm_object_tooltip_text_set(o, ev->event); + evas_object_show(o); + return o; +} + +static Evas_Object * +_add_log_event_object(Evas_Object *win, Evas_Object *grid, Event *ev) +{ + Evas_Object *o, *oe; + int col[4] = {255, 255, 255, 255}, i; + char *s; + + o = elm_layout_add(win); + oe = elm_layout_edje_get(o); + elm_layout_file_set(o, "./evlog.edj", "range"); + i = 0; + for (s = ev->event; *s; s++) + { + col[i % 3] ^= *s; + i++; + } + edje_object_color_class_set(oe, "range", + col[0] / 2, col[1] / 2, col[2] / 2, col[3], + 255, 255, 255, 255, + 255, 255, 255, 255); + edje_object_part_text_set(oe, "text", ev->event); + elm_grid_pack(grid, o, ev->t0 * RES, ev->n, (ev->t1 - ev->t0) * RES, 1); + elm_object_tooltip_text_set(o, ev->event); + evas_object_show(o); + return o; +} + +static Evas_Object * +_add_log_frame_object(Evas_Object *win, Evas_Object *grid, Event *ev) +{ + Evas_Object *o, *oe; + + o = elm_layout_add(win); + oe = elm_layout_edje_get(o); + elm_layout_file_set(o, "./evlog.edj", "frame"); + elm_grid_pack(grid, o, ev->t0 * RES, ev->n, (ev->t1 - ev->t0) * RES, 1); + elm_object_tooltip_text_set(o, ev->event); + evas_object_show(o); + return o; +} + +static void +_cb_fill_end(void *data, Ecore_Thread *thread) +{ + Inf *inf = data; + Event *ev; + Evas_Object *o; + Eina_List *l; + + inf->update.thread = NULL; + EINA_LIST_FOREACH(inf->objs, l, ev) + { + if ((!ev->obj) && (!ev->nuke)) + { + if (ev->slot == 0) // state + { + o = _add_log_state_object(inf->win, + inf->grid.state, + ev); + ev->obj = o; + } + else if (ev->slot > 0) // thread + { + o = _add_log_event_object(inf->win, + inf->grid.thread[ev->slot - 1], + ev); + ev->obj = o; + } + else if (ev->slot == -1) // frames + { + if (!strcmp(ev->event, "FRAME")) + { + o = _add_log_frame_object(inf->win, + inf->grid.over, + ev); + ev->obj = o; + } + } + } + } + EINA_LIST_FREE(inf->update.remobjs, ev) + { + inf->objs = eina_list_remove(inf->objs, ev); + if (ev->obj) evas_object_del(ev->obj); + free(ev->event); + free(ev); + } + if (inf->update.redo) + { + inf->update.redo = EINA_FALSE; + _fill_begin(inf); + } +} + + + + + + + + + + +static void +_cb_fill_cancel(void *data, Ecore_Thread *thread) +{ + Inf *inf = data; + inf->update.thread = NULL; +} + +static void +_fill_begin(Inf *inf) +{ + Evas_Coord x, w, wx, ww; + double t, t0, t1; + Evas_Coord gw; + + if (inf->update.thread) + { + inf->update.redo = EINA_TRUE; + return; + } + elm_grid_size_get(inf->grid.state, &gw, NULL); + evas_object_geometry_get(inf->grid.state, &x, NULL, &w, NULL); + evas_output_viewport_get(evas_object_evas_get(inf->grid.state), + &wx, NULL, &ww, NULL); + if (ww < 1) ww = 1; + if (w < 1) w = 1; + if (w < ww) w = ww; + if (gw < 1) gw = 1; + + t0 = inf->evlog->first_timestamp; + t1 = inf->evlog->last_timestamp; + + inf->update.tmin = (1.0 * (double)gw) / ((double)w * RES); + + wx -= 100; + ww += 200; + + t = ((t1 - t0) * (double)ww) / ((double)w); + t0 = ((wx - x) * (t1 - t0)) / ((double)w); + if (t0 < 0.0) t0 = 0.0; + inf->update.t0 = t0 + inf->evlog->first_timestamp; + inf->update.t1 = inf->update.t0 + t; + inf->update.thread = ecore_thread_run(_cb_fill_blocking, + _cb_fill_end, + _cb_fill_cancel, + inf); +} + +static void +_cb_fill_job(void *data) +{ + Inf *inf = evas_object_data_get(data, "inf"); + inf->update.job = NULL; + _fill_begin(inf); +} + +static void +_fill_update(Evas_Object *zoom) +{ + Inf *inf = evas_object_data_get(zoom, "inf"); + if (inf->update.job) ecore_job_del(inf->update.job); + inf->update.job = ecore_job_add(_cb_fill_job, zoom); } static void _cb_zoom(void *data, Evas_Object *obj, void *info) { - evlog_view_zoom_update(data); + Inf *inf = evas_object_data_get(data, "inf"); + Evas_Coord w = 0, h = 1; + evas_object_size_hint_min_get(inf->grid.state, &w, &h); + if (w < 1) w = 1; + double len = inf->evlog->last_timestamp - inf->evlog->first_timestamp; + double res = elm_slider_value_get(obj); + Evas_Coord sx, sy, sw, sh; + elm_scroller_region_get(inf->scroller, &sx, &sy, &sw, &sh); + res = res * res; + evas_object_size_hint_min_set(inf->grid.state, len * res, h); + double snx = ((double)(sx + (sw / 2)) * (len * res)) / (double)w; + double snw = ((double)(sw) * (len * res)) / (double)w; + elm_scroller_region_show(inf->scroller, snx - (snw / 2), sy, snw, sh); } static void _cb_move(void *data, Evas *e, Evas_Object *obj, void *info) { - evlog_view_update(data); + _fill_update(data); } static void _cb_resize(void *data, Evas *e, Evas_Object *obj, void *info) { - evlog_view_update(data); + _fill_update(data); } static void _cb_sc_resize(void *data, Evas *e, Evas_Object *obj, void *info) { - evlog_view_update(data); + _fill_update(data); } static Evas_Object * evlog_view_add(Evas_Object *win, Evlog *evlog, Evas_Object *zoom) { + Inf *inf = evas_object_data_get(zoom, "inf"); Evas_Object *o; - Evas_Object *sc, *tb, *gr, *rc; - Evlog_View *view; + Evas_Object *sc, *tb; sc = o = elm_scroller_add(win); - - view = calloc(1, sizeof(Evlog_View)); - evas_object_data_set(sc, "view", view); - view->scroller = sc; - view->zoom = zoom; - view->evlog = evlog; - - evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_sc_resize, sc); + inf->scroller = o; + evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_sc_resize, zoom); tb = o = elm_table_add(win); - view->table = o; - evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE, _cb_move, sc); - evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_resize, sc); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE, _cb_move, zoom); + evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_resize, zoom); - rc = o = evas_object_rectangle_add(evas_object_evas_get(win)); - view->rect = o; - evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_color_set(o, 48, 48, 48, 255); - elm_table_pack(tb, o, 0, 0, 1, 1); - evas_object_show(o); - - gr = o = elm_grid_add(win); - view->grid = o; - elm_grid_size_set(o, (evlog->end_t - evlog->start_t) * RES, 400); - evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_table_pack(tb, o, 0, 0, 1, 1); - evas_object_show(o); + _fill_log_table(win, tb, evlog, zoom); elm_object_content_set(sc, tb); evas_object_show(tb); - evas_object_smart_callback_add(zoom, "changed", _cb_zoom, sc); - evlog_view_zoom_update(sc); - evlog_view_update(sc); + evas_object_smart_callback_add(zoom, "changed", _cb_zoom, zoom); return sc; } @@ -660,15 +1005,21 @@ elm_main(int argc, char **argv) Evlog *evl; Evas_Object *o; Evas_Object *box; + Inf *inf; if (argc < 2) return -1; evl = evlog_new(argv[1]); if (!evl) return -1; + inf = calloc(1, sizeof(Inf)); + inf->evlog = evl; + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("evlog", "Event Log"); + inf->win = win; elm_win_autodel_set(win, EINA_TRUE); + evas_object_data_set(win, "inf", inf); box = o = elm_box_add(win); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); @@ -677,9 +1028,10 @@ elm_main(int argc, char **argv) evas_object_show(o); zoom_slider = o = elm_slider_add(win); - elm_slider_min_max_set(o, 1.0, 10000.0); + evas_object_data_set(o, "inf", inf); + elm_slider_min_max_set(o, 1.0, 500.0); elm_slider_step_set(o, 0.1); - elm_slider_value_set(o, 500.0); + elm_slider_value_set(o, 20.0); elm_object_text_set(o, "Zoom"); elm_slider_unit_format_set(o, "%1.1f"); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0); @@ -693,7 +1045,7 @@ elm_main(int argc, char **argv) elm_box_pack_end(box, o); evas_object_show(o); - evas_object_resize(win, 480, 480); + evas_object_resize(win, 620, 400); evas_object_show(win); elm_run(); diff --git a/evlog.edc b/evlog.edc index edaef04..f480ee4 100644 --- a/evlog.edc +++ b/evlog.edc @@ -1,66 +1,56 @@ +#define TILED_PATTERN(_WIDTH, _HEIGHT) \ + fill { size { relative: 0.0 0.0; offset: _WIDTH _HEIGHT; } } + collections { images.image: "box_glow.png" COMP; images.image: "box_outline.png" COMP; group { name: "range"; parts { - part { name: "bg"; + part { name: "bg"; type: RECT; description { state: "default" 0.0; - rel1.offset: -9 -9; - rel2.offset: 8 8; - image.normal: "box_glow.png"; - image.border: 12 12 12 12; + rel1.offset: 1 1; + rel2.offset: -2 -2; + color_class: "range"; } } part { name: "text"; type: TEXT; - effect: SHADOW BOTTOM; scale: 1; - description { state: "default" 0.0; - color: 255 255 255 255; - color3: 0 0 0 128; - text { font: "Sans"; size: 10; - min: 0 1; - align: 0.0 1.0; - text_class: "fileman_icon"; - } - } - } - part { name: "over"; description { state: "default" 0.0; rel1.to: "bg"; rel2.to: "bg"; - image.normal: "box_outline.png"; - image.border: 12 12 12 12; + color: 255 255 255 255; + text { font: "Sans"; size: 10; + min: 0 1; + align: 0.0 1.0; + } } } } } - images.image: "runner_vert.png" COMP; + images.image: "diagonal_stripes.png" COMP; - group { name: "event"; + group { name: "state"; parts { part { name: "bg"; description { state: "default" 0.0; - image.normal: "runner_vert.png"; - image.border: 1 1 2 2; - fill.smooth: 0; - min: 3 6; - max: 3 9999; + rel1.offset: 1 1; + rel2.offset: -2 -2; + color_class: "state"; + TILED_PATTERN(240, 240) + image.normal: "diagonal_stripes.png"; } } part { name: "text"; type: TEXT; - effect: SHADOW BOTTOM; scale: 1; description { state: "default" 0.0; - rel1.offset: 4 0; - rel2.offset: 4 -1; - color: 21 21 21 255; - color3: 255 255 255 25; - align: 0.0 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + color: 255 255 255 255; text { font: "Sans"; size: 10; - min: 1 1; - align: 0.0 0.0; + min: 0 1; + align: 0.0 1.0; } } } @@ -71,6 +61,12 @@ collections { group { name: "frame"; parts { + part { name: "base"; type: RECT; + description { state: "default" 0.0; + color: 51 153 255 128; + min: 1 1; + } + } part { name: "bg"; description { state: "default" 0.0; image.normal: "handle_pick_up_right.png"; diff --git a/img/box_glow.png b/img/box_glow.png deleted file mode 100644 index 785eb6d93d765d4c9539950811d3808a25a5dfea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 470 zcmV;{0V)28P)Ydk>pc_E-dmu{Kys}M7S*-UG|aU?3e(&XPy~W$4VY_z zcxeNE*p#Y}93>eEZTXZdb z05-r1copDYejosi5hd6_Kr`UE=j?s}K7cPZA`qD@s1&)z(*FpopM zU1+(zkwC+eTx;M3coQjfl)$Y4m!_sJCtYs6?0|OxRpwcmk-HWtT~0d8B29&_)0AD# zU1b({nq9S;EH1YkiW4lQZ)9@|E)>NvZO@2ou5YoEs1nL#Nm3J=@8um-ZKIXYx45v5 z5in6!W2g5--s!BD&p?8*4rDQM!h%KR*7nEkh=MZ6jr1>i)Mq2PwKmi?&_PUbCEnH7 zRJZbt2FUJ5d{oLuy{^_K_8Z&E$VSG9lz+W-In M07*qoM6N<$fd4{_Vo0m>}(S0=2)4!DEvZilu6db6|Pg5#j>XHElv>W31DFOv{Ha)b3LCB&=dww LS3j3^P6QL70(Y)*K0-AbW|YuPgg~E`Dx({f_U?Di|1;4|=*dhE&{odvhc2VFLjc$H{-c z>nty0Uw%|WSZ()HAB`f>AIW)O}&fzm2XhZhwtxpY|oH1%{W! zS*~&LUL_K=bi$?3P_E3^ZQD3>R|a_muM)X5MXNPLb4f|)RHs{2Pd6}ugr_=rg@>a3y%PWc literal 0 HcmV?d00001 diff --git a/img/runner_vert.png b/img/runner_vert.png deleted file mode 100644 index 1db8e6cc88027c7af59f8bac8f6fa7a2d2832c07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y>!3H9qs_+0QEl(H65RU7m#~1P*Fc4rcTpbj# xwC~Gr|58O(MML8niT#dOe_PyPUOg)-SLHa@ebvbiUjlV8c)I$ztaD0e0swpx9UA}u