diff --git a/app/Makefile b/app/Makefile index 0628f18d..5b27b162 100644 --- a/app/Makefile +++ b/app/Makefile @@ -323,7 +323,7 @@ ${ZSV_UTIL_A}: ${BUILD_DIR}/objs/utils/util.a @mkdir -p `dirname $@` cp -p $< $@ -UTIL_A_OBJ:=writer file dirs-no-jq os ${UTIL_A_OBJ_WIN} +UTIL_A_OBJ:=index writer file dirs-no-jq os ${UTIL_A_OBJ_WIN} UTIL_A_OBJ:=$(addprefix ${BUILD_DIR}/objs/utils/,$(addsuffix .o,${UTIL_A_OBJ})) ${BUILD_DIR}/objs/utils/util.a: ${UTIL_A_OBJ} diff --git a/app/cli.c b/app/cli.c index 5a8eeb35..40fb1b75 100644 --- a/app/cli.c +++ b/app/cli.c @@ -748,7 +748,11 @@ static struct zsv_ext *zsv_ext_new(const char *dl_name, const char *id, char ver } } if (!h) +#if defined(WIN32) || defined(_WIN32) fprintf(stderr, "Library %s not found\n", dl_name); +#else + fprintf(stderr, "Library %s failed to load: %s\n", dl_name, dlerror()); +#endif // run zsv_ext_init to add to our extension list, even if it's invalid tmp.ok = !zsv_ext_init(h, dl_name, &tmp); diff --git a/app/ext_example/Makefile b/app/ext_example/Makefile index c8cd1a67..b024cbf3 100644 --- a/app/ext_example/Makefile +++ b/app/ext_example/Makefile @@ -61,7 +61,7 @@ else CFLAGS += -g endif -THIS_LIB_BASE=$(shell cd ../.. && pwd) +export THIS_LIB_BASE=$(shell cd ../.. && pwd) CCBN=$(shell basename ${CC}) BUILD_DIR=${THIS_LIB_BASE}/build/${BUILD_SUBDIR}/${CCBN} TARGET=${BUILD_DIR}/bin/zsvextmy.${SO} @@ -77,7 +77,9 @@ TEST_PASS=printf "${COLOR_BLUE}$@: ${COLOR_GREEN}Passed${COLOR_NONE}\n" TEST_FAIL=(printf "${COLOR_BLUE}$@: ${COLOR_RED}Failed!${COLOR_NONE}\n" && exit 1) TEST_INIT=printf "${COLOR_PINK}$@: ${COLOR_NONE}\n" -UTILS1= +EXPECT=../../scripts/test-expect.sh +export EXPECTED_PATH=test/expected + CFLAGS_SHARED=-shared ifneq ($(findstring emcc,$(CC)),) # emcc CFLAGS_SHARED=-s SIDE_MODULE=1 -s LINKABLE=1 @@ -86,9 +88,6 @@ else INSTALLED_EXTENSION= endif -UTILS1+=writer -UTILS=$(addprefix ${BUILD_DIR}/objs/utils/,$(addsuffix .o,${UTILS1})) - CFLAGS+= -I${THIS_LIB_BASE}/include -I${PREFIX}/include all: ${TARGET} ${TARGET_SHEET} @@ -145,7 +144,10 @@ test-3: test-%: ${CLI} ${TARGET} ../test/worldcitiespop_mil.csv: make -C ../test worldcitiespop_mil.csv -TMP_DIR=/tmp +export TMP_DIR=/tmp +DATE_TIME:=$(shell date +%F-%H-%M-%S) +export TIMINGS_CSV:=${TMP_DIR}/timings-${DATE_TIME}.csv +export CMP=cmp TMUX_TERM=xterm-256color test-sheet-extension-1: ${CLI} ${TARGET} ../test/worldcitiespop_mil.csv @${TEST_INIT} @@ -154,15 +156,10 @@ test-sheet-extension-1: ${CLI} ${TARGET} ../test/worldcitiespop_mil.csv @${RUN_CLI} unregister my 2>/dev/null 1>/dev/null || [ 1==1 ] @${RUN_CLI} register my 2>&1 | grep -v [.]so || [ 1==1 ] @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf - @(ZSV_CONFIG_DIR=/tmp tmux -v new-session -x 80 -y 5 -d -s $@ && \ - sleep 0.5 && \ - tmux send-keys -t $@ "${CLI} sheet ../test/worldcitiespop_mil.csv" ENTER && \ - sleep 0.5 && \ + @(ZSV_CONFIG_DIR=/tmp tmux -v new-session -x 80 -y 5 -d -s $@ $< sheet ../test/worldcitiespop_mil.csv && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "t" "hello" Enter && \ - tmux capture-pane -t $@ -p > ${TMP_DIR}/$@.out && \ - tmux kill-session -t $@ && \ - cmp ${TMP_DIR}/$@.out test/expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && \ - if [ -f ${TMP_DIR}/$@.out ]; then cat ${TMP_DIR}/$@.out; fi && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-sheet-extension-2: ${CLI} ${TARGET} @${TEST_INIT} @@ -171,18 +168,12 @@ test-sheet-extension-2: ${CLI} ${TARGET} @${RUN_CLI} unregister my 2>/dev/null 1>/dev/null || [ 1==1 ] @${RUN_CLI} register my 2>&1 | grep -v [.]so || [ 1==1 ] @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf - @(ZSV_CONFIG_DIR=/tmp tmux -v new-session -x 120 -y 5 -d -s $@ && \ - sleep 0.5 && \ - tmux send-keys -t $@ "${CLI} sheet -d 3 ../../data/test/mixed-line-endings.csv" ENTER && \ - sleep 0.5 && \ + @(ZSV_CONFIG_DIR=/tmp tmux -v new-session -x 120 -y 5 -d -s $@ $< sheet -d 3 ../../data/test/mixed-line-endings.csv && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ T Enter && \ - sleep 0.5 && \ + ${EXPECT} $@ transformed && \ tmux send-keys -t $@ G && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p > ${TMP_DIR}/$@.out && \ - tmux kill-session -t $@ && \ - cmp ${TMP_DIR}/$@.out test/expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && \ - if [ -f ${TMP_DIR}/$@.out ]; then cat ${TMP_DIR}/$@.out; fi && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-4: test-%: ${CLI} ${TARGET} @${TEST_INIT} @@ -213,13 +204,21 @@ clean: ${BUILD_DIR}/objs/%.o : ${THIS_LIB_BASE}/src/%.c ${PARSER_DEPS} ${MAKE} -C ${THIS_LIB_BASE}/src CONFIGFILE=${CONFIGFILEPATH} DEBUG=${DEBUG} WIN=${WIN} $@ +LIBZSV=${PREFIX}/lib/libzsv.a +${LIBZSV}: + ${MAKE} -C ${THIS_LIB_BASE}/src CONFIGFILE=${CONFIGFILEPATH} DEBUG=${DEBUG} WIN=${WIN} install + +LIBZSVUTIL=${PREFIX}/lib/libzsvutil.a +${LIBZSVUTIL}: + ${MAKE} -C ${THIS_LIB_BASE}/app CONFIGFILE=${CONFIGFILEPATH} DEBUG=${DEBUG} WIN=${WIN} install-util-lib YAJL_SRC_DIR=${THIS_MAKEFILE_DIR}/../external/yajl YAJL_INCLUDE=-I${YAJL_SRC_DIR}/build/yajl-2.1.1/include YAJL_HELPER_INCLUDE=-I${THIS_MAKEFILE_DIR}/../external/yajl_helper -${TARGET_SHEET}: LIBS="../external/sqlite3/sqlite3.c" -lzsv -lzsvutil -L${PREFIX}/lib -ljq -lutf8proc -${TARGET} ${TARGET_SHEET}: ${BUILD_DIR}/bin/zsvext%.${SO} : %_extension.c ${UTILS} +${TARGET_SHEET}: LIBS="../external/sqlite3/sqlite3.c" -lzsvutil -lzsv -L${PREFIX}/lib -ljq -lutf8proc +${TARGET}: LIBS=-lzsvutil -lzsv -L${PREFIX}/lib +${TARGET} ${TARGET_SHEET}: ${BUILD_DIR}/bin/zsvext%.${SO} : %_extension.c ${LIBZSV} ${LIBZSVUTIL} @mkdir -p `dirname "$@"` - ${CC} ${CFLAGS} ${CFLAGS_SHARED} $< ${UTILS} -o $@ ${LIBS} ${YAJL_INCLUDE} ${YAJL_HELPER_INCLUDE} + ${CC} ${CFLAGS} ${CFLAGS_SHARED} $< -o $@ ${LIBS} ${YAJL_INCLUDE} ${YAJL_HELPER_INCLUDE} .PHONY: all test test-% clean install diff --git a/app/ext_example/test/expected/test-sheet-extension-1-indexed.out b/app/ext_example/test/expected/test-sheet-extension-1-indexed.out new file mode 100644 index 00000000..7c4ad173 --- /dev/null +++ b/app/ext_example/test/expected/test-sheet-extension-1-indexed.out @@ -0,0 +1,5 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +? for help 1 diff --git a/app/ext_example/test/expected/test-sheet-extension-2-indexed.out b/app/ext_example/test/expected/test-sheet-extension-2-indexed.out new file mode 100644 index 00000000..7eb68921 --- /dev/null +++ b/app/ext_example/test/expected/test-sheet-extension-2-indexed.out @@ -0,0 +1,5 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +1 A1 B1 C1 +2 A2 B2 C2 +3 A3 B3 C3 +? for help 1 diff --git a/app/ext_example/test/expected/test-sheet-extension-2-transformed.out b/app/ext_example/test/expected/test-sheet-extension-2-transformed.out new file mode 100644 index 00000000..34ae790b --- /dev/null +++ b/app/ext_example/test/expected/test-sheet-extension-2-transformed.out @@ -0,0 +1,5 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 Column count +1 A1 B1 C1 6 +2 A2 B2 C2 9 +3 A3 B3 C3 12 +? for help 1 diff --git a/app/sheet.c b/app/sheet.c index e4fae039..0a0c6972 100644 --- a/app/sheet.c +++ b/app/sheet.c @@ -343,7 +343,7 @@ static zsvsheet_status zsvsheet_find(struct zsvsheet_sheet_context *state, bool struct zsvsheet_opts zsvsheet_opts = {0}; int prompt_footer_row = (int)(di->dimensions->rows - di->dimensions->footer_span); - if (!current_ui_buffer->filename) + if (!zsvsheet_buffer_data_filename(current_ui_buffer)) goto out; if (!next) { @@ -381,14 +381,14 @@ static zsvsheet_status zsvsheet_open_file_handler(struct zsvsheet_proc_context * UNUSED(ctx); if (ctx->num_params > 0) { - filename = ctx->params[0].u.string; + filename = strdup(ctx->params[0].u.string); } else { if (!ctx->invocation.interactive) return zsvsheet_status_error; get_subcommand("File to open", prompt_buffer, sizeof(prompt_buffer), prompt_footer_row); if (*prompt_buffer == '\0') goto no_input; - filename = prompt_buffer; + filename = strdup(prompt_buffer); } if ((err = zsvsheet_ui_buffer_open_file(filename, NULL, state->custom_prop_handler, di->ui_buffers.base, @@ -637,6 +637,19 @@ void zsvsheet_register_builtin_procedures(void) { } } +static void zsvsheet_check_buffer_worker_updates(struct zsvsheet_ui_buffer *ub, + struct zsvsheet_display_dimensions *display_dims, + struct zsvsheet_sheet_context *handler_state) { + pthread_mutex_lock(&ub->mutex); + if (ub->status) + zsvsheet_priv_set_status(display_dims, 1, ub->status); + if (ub->index_ready && ub->dimensions.row_count != ub->index->row_count + 1) { + ub->dimensions.row_count = ub->index->row_count + 1; + handler_state->display_info.update_buffer = true; + } + pthread_mutex_unlock(&ub->mutex); +} + int ZSV_MAIN_FUNC(ZSV_COMMAND)(int argc, const char *argv[], struct zsv_opts *optsp, struct zsv_prop_handler *custom_prop_handler) { if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { @@ -695,7 +708,6 @@ int ZSV_MAIN_FUNC(ZSV_COMMAND)(int argc, const char *argv[], struct zsv_opts *op cbreak(); set_escdelay(30); struct zsvsheet_display_dimensions display_dims = get_display_dimensions(1, 1); - display_buffer_subtable(current_ui_buffer, header_span, &display_dims); zsvsheet_register_builtin_procedures(); @@ -717,6 +729,9 @@ int ZSV_MAIN_FUNC(ZSV_COMMAND)(int argc, const char *argv[], struct zsv_opts *op zsvsheet_status status; + zsvsheet_check_buffer_worker_updates(current_ui_buffer, &display_dims, &handler_state); + display_buffer_subtable(current_ui_buffer, header_span, &display_dims); + halfdelay(2); // now ncurses getch() will fire every 2-tenths of a second so we can check for status update // while (true) { @@ -734,18 +749,7 @@ int ZSV_MAIN_FUNC(ZSV_COMMAND)(int argc, const char *argv[], struct zsv_opts *op } struct zsvsheet_ui_buffer *ub = current_ui_buffer; - pthread_mutex_lock(&ub->mutex); - if (ub->status) - zsvsheet_priv_set_status(&display_dims, 1, ub->status); - if (ub->write_progressed) { - handler_state.display_info.update_buffer = true; - ub->write_progressed = 0; - } - if (ub->index_ready && ub->dimensions.row_count != ub->index->row_count + 1) { - ub->dimensions.row_count = ub->index->row_count + 1; - handler_state.display_info.update_buffer = true; - } - pthread_mutex_unlock(&ub->mutex); + zsvsheet_check_buffer_worker_updates(ub, &display_dims, &handler_state); if (handler_state.display_info.update_buffer && zsvsheet_buffer_data_filename(ub)) { struct zsvsheet_opts zsvsheet_opts = {0}; diff --git a/app/sheet/index.c b/app/sheet/index.c index 6f1822a5..a411888b 100644 --- a/app/sheet/index.c +++ b/app/sheet/index.c @@ -12,8 +12,9 @@ static void build_memory_index_row_handler(void *ctx) { struct zsvsheet_indexer *ixr = ctx; struct zsv_index *ix = ixr->ix; zsv_parser parser = ixr->parser; + uint64_t line_end = zsv_cum_scanned_length(parser); - if (zsv_index_add_row(ix, parser) != zsv_index_status_ok) + if (zsv_index_add_row(ix, line_end) != zsv_index_status_ok) zsv_abort(parser); } @@ -42,23 +43,33 @@ enum zsv_index_status build_memory_index(struct zsvsheet_index_opts *optsp) { if (!ixr.ix) goto out; + optsp->uib->index = ixr.ix; + char cancelled = 0; + size_t committed_bytes = 0; while (!cancelled && (zst = zsv_parse_more(ixr.parser)) == zsv_status_ok) { + if (zsv_cum_scanned_length(ixr.parser) - committed_bytes < 32 * 1024 * 1024) + continue; + committed_bytes = zsv_cum_scanned_length(ixr.parser); + pthread_mutex_lock(&optsp->uib->mutex); if (optsp->uib->worker_cancelled) { cancelled = 1; zst = zsv_status_cancelled; } + zsv_index_commit_rows(ixr.ix); + optsp->uib->index_ready = 1; pthread_mutex_unlock(&optsp->uib->mutex); } zsv_finish(ixr.parser); + pthread_mutex_lock(&optsp->uib->mutex); + zsv_index_commit_rows(ixr.ix); + optsp->uib->index_ready = 1; + pthread_mutex_unlock(&optsp->uib->mutex); - if (zst == zsv_status_no_more_input || zst == zsv_status_cancelled) { + if (zst == zsv_status_no_more_input || zst == zsv_status_cancelled) ret = zsv_index_status_ok; - optsp->uib->index = ixr.ix; - } else - zsv_index_delete(ixr.ix); out: if (ixr.parser) diff --git a/app/sheet/index.h b/app/sheet/index.h index 647a1f77..25104281 100644 --- a/app/sheet/index.h +++ b/app/sheet/index.h @@ -17,6 +17,7 @@ struct zsvsheet_index_opts { struct zsvsheet_ui_buffer *uib; int *errp; struct zsv_prop_handler *custom_prop_handler; + char *old_ui_status; }; enum zsv_index_status build_memory_index(struct zsvsheet_index_opts *optsp); diff --git a/app/sheet/read-data.c b/app/sheet/read-data.c index 77f34b71..7ca36a81 100644 --- a/app/sheet/read-data.c +++ b/app/sheet/read-data.c @@ -29,14 +29,15 @@ static char *zsvsheet_found_in_row(zsv_parser parser, size_t col_count, const ch static void *get_data_index(void *d); static void get_data_index_async(struct zsvsheet_ui_buffer *uibuffp, const char *filename, struct zsv_opts *optsp, - struct zsv_prop_handler *custom_prop_handler, pthread_mutex_t *mutexp) { + struct zsv_prop_handler *custom_prop_handler, char *old_ui_status) { struct zsvsheet_index_opts *ixopts = calloc(1, sizeof(*ixopts)); - ixopts->mutexp = mutexp; + ixopts->mutexp = &uibuffp->mutex; ixopts->filename = filename; ixopts->zsv_opts = *optsp; ixopts->custom_prop_handler = custom_prop_handler; ixopts->uib = uibuffp; ixopts->uib->ixopts = ixopts; + ixopts->old_ui_status = old_ui_status; if (uibuffp->worker_active) zsvsheet_ui_buffer_join_worker(uibuffp); @@ -204,16 +205,20 @@ static int read_data(struct zsvsheet_ui_buffer **uibufferp, // a new zsvsheet_ return 0; pthread_mutex_lock(&uibuff->mutex); - char need_index = !uibuff->index_started && (!uibuff->write_in_progress || uibuff->write_done); + char need_index = !uibuff->index_started && !uibuff->write_in_progress; + char *old_ui_status = uibuff->status; pthread_mutex_unlock(&uibuff->mutex); if (need_index) { + if (asprintf(&uibuff->status, "%s(building index) ", old_ui_status ? old_ui_status : "") == -1) + return -1; + uibuff->buff_used_rows = rows_read; uibuff->dimensions.row_count = rows_read; uibuff->index_started = 1; if (original_row_num > 1 && rows_read > 0) { opts.stream = NULL; - get_data_index_async(uibuff, filename, &opts, custom_prop_handler, &uibuff->mutex); + get_data_index_async(uibuff, filename, &opts, custom_prop_handler, old_ui_status); } } else if (rows_read > uibuff->buff_used_rows) { uibuff->buff_used_rows = rows_read; @@ -229,22 +234,7 @@ static void *get_data_index(void *gdi) { pthread_mutex_t *mutexp = d->mutexp; int *errp = d->errp; struct zsvsheet_ui_buffer *uib = d->uib; - - pthread_mutex_lock(&uib->mutex); - char *old_ui_status = uib->status; - pthread_mutex_unlock(&uib->mutex); - - char *ui_status; - /* I think there was a race between this print and a "? for help" which causes - * ci to fail. Once read-file is called the main thread displays its contents - * and this thread indexes the file. There is no synchronisation between the - * two so the status we end up with is random. - */ - // asprintf(&ui_status, "%s(building index) ", old_ui_status ? old_ui_status : ""); - - pthread_mutex_lock(&uib->mutex); - uib->status = ui_status; - pthread_mutex_unlock(&uib->mutex); + char *ui_status = uib->status; enum zsv_index_status ix_status = build_memory_index(d); @@ -258,8 +248,7 @@ static void *get_data_index(void *gdi) { } pthread_mutex_lock(mutexp); - uib->index_ready = 1; - uib->status = old_ui_status; + uib->status = d->old_ui_status; uib->ixopts = NULL; pthread_mutex_unlock(mutexp); diff --git a/app/sheet/transformation.c b/app/sheet/transformation.c index 779ee353..0b654ccd 100644 --- a/app/sheet/transformation.c +++ b/app/sheet/transformation.c @@ -5,6 +5,7 @@ #include "transformation.h" #include "pthread.h" #include "zsv/utils/file.h" +#include "zsv/utils/index.h" #include "zsv/utils/prop.h" struct zsvsheet_transformation { @@ -14,7 +15,7 @@ struct zsvsheet_transformation { FILE *output_stream; unsigned char *output_buffer; int output_fileno; - size_t output_count; + char writer_wrote; struct zsvsheet_transformation_opts opts; void *user_context; @@ -27,7 +28,7 @@ static size_t transformation_write(const void *restrict ptr, size_t size, size_t struct zsvsheet_transformation *trn = stream; const size_t count = fwrite(ptr, size, nitems, trn->output_stream); - trn->output_count += count; + trn->writer_wrote = count > 0; return count > 0 ? count : 0; } @@ -60,6 +61,7 @@ enum zsv_status zsvsheet_transformation_new(struct zsvsheet_transformation_opts struct zsv_csv_writer_options writer_opts = { .with_bom = 0, + .index = opts.index, .write = transformation_write, .stream = trn, .table_init = NULL, @@ -132,14 +134,17 @@ static void *zsvsheet_run_buffer_transformation(void *arg) { zsv_parser parser = trn->parser; pthread_mutex_t *mutex = &uib->mutex; enum zsv_status zst; + char *default_status = trn->default_status; - size_t c = trn->output_count; char cancelled = 0; while (!cancelled && (zst = zsv_parse_more(parser)) == zsv_status_ok) { pthread_mutex_lock(mutex); cancelled = uib->worker_cancelled; - if (trn->output_count != c) - uib->write_progressed = 1; + if (trn->writer_wrote) { + trn->writer_wrote = 0; + zsv_index_commit_rows(uib->index); + uib->index_ready = 1; + } pthread_mutex_unlock(mutex); } @@ -149,19 +154,22 @@ static void *zsvsheet_run_buffer_transformation(void *arg) { if (trn->on_done) trn->on_done(trn); + if (trn->user_context) + free(trn->user_context); + + zsvsheet_transformation_delete(trn); + pthread_mutex_lock(mutex); char *buff_status_old = uib->status; - uib->write_progressed = 1; uib->write_done = 1; - if (buff_status_old == trn->default_status) + zsv_index_commit_rows(uib->index); + uib->index_ready = 1; + if (buff_status_old == default_status) uib->status = NULL; pthread_mutex_unlock(mutex); - if (buff_status_old == trn->default_status) + if (buff_status_old == default_status) free(buff_status_old); - if (trn->user_context) - free(trn->user_context); - zsvsheet_transformation_delete(trn); return NULL; } @@ -172,6 +180,7 @@ enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, const char *filename = zsvsheet_buffer_data_filename(buff); enum zsvsheet_status stat = zsvsheet_status_error; struct zsvsheet_buffer_info_internal info = zsvsheet_buffer_info_internal(buff); + struct zsv_index *index = NULL; // TODO: Starting a second transformation before the first ends works, but if the second is faster // than the first then it can end prematurely and read a partially written row. @@ -179,12 +188,16 @@ enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, if (info.write_in_progress && !info.write_done) return zsvsheet_status_busy; + if (!(index = zsv_index_new())) + return zsvsheet_status_memory; + // TODO: custom_prop_handler is not passed to extensions? struct zsvsheet_transformation_opts trn_opts = { .custom_prop_handler = NULL, .input_filename = filename, .on_done = opts.on_done, .ui_buffer = NULL, + .index = index, }; zsvsheet_transformation trn = NULL; struct zsv_opts zopts = zsvsheet_buffer_get_zsv_opts(buff); @@ -192,35 +205,37 @@ enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, zopts.ctx = opts.user_context; zopts.row_handler = (void (*)(void *))opts.row_handler; zopts.stream = fopen(filename, "rb"); + zopts.buffsize = 2 * 1024 * 1024; if (!zopts.stream) - goto out; + goto error; trn_opts.zsv_opts = zopts; enum zsv_status zst = zsvsheet_transformation_new(trn_opts, &trn); if (zst != zsv_status_ok) - return stat; + goto error; // Transform part of the file to initially populate the UI buffer // TODO: If the transformation is a reduction that doesn't output for some time this will caus a pause zsv_parser parser = zsvsheet_transformation_parser(trn); while ((zst = zsv_parse_more(parser)) == zsv_status_ok) { - if (trn->output_count > 0) + if (trn->writer_wrote) break; } + trn->writer_wrote = 0; switch (zst) { case zsv_status_no_more_input: case zsv_status_cancelled: if (zsv_finish(parser) != zsv_status_ok) - goto out; + goto error; zsv_writer_flush(trn->writer); break; case zsv_status_ok: break; default: - goto out; + goto error; } struct zsvsheet_ui_buffer_opts uibopts = {0}; @@ -230,15 +245,22 @@ enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, stat = zsvsheet_open_file_opts(ctx, &uibopts); if (stat != zsvsheet_status_ok) - goto out; + goto error; struct zsvsheet_ui_buffer *nbuff = zsvsheet_buffer_current(ctx); trn->ui_buffer = nbuff; - nbuff->write_progressed = 1; + zsv_index_commit_rows(index); + nbuff->index_started = 1; + nbuff->index = index; if (zst != zsv_status_ok) { nbuff->write_done = 1; - goto out; + nbuff->index_ready = 1; + if (trn->on_done) + opts.on_done(trn); + zsvsheet_transformation_delete(trn); + zsv_index_commit_rows(index); + return stat; } asprintf(&trn->default_status, "(working) Press ESC to cancel "); @@ -247,7 +269,9 @@ enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, zsvsheet_ui_buffer_create_worker(nbuff, zsvsheet_run_buffer_transformation, trn); return stat; -out: +error: + zsv_index_delete(index); + if (trn && trn->on_done) opts.on_done(trn); if (trn) diff --git a/app/sheet/transformation.h b/app/sheet/transformation.h index 87ea7226..f5af1a8f 100644 --- a/app/sheet/transformation.h +++ b/app/sheet/transformation.h @@ -15,6 +15,7 @@ struct zsvsheet_transformation_opts { const char *input_filename; void (*on_done)(zsvsheet_transformation trn); struct zsvsheet_ui_buffer *ui_buffer; + struct zsv_index *index; }; enum zsv_status zsvsheet_transformation_new(struct zsvsheet_transformation_opts, zsvsheet_transformation *); diff --git a/app/sheet/ui_buffer.c b/app/sheet/ui_buffer.c index 7cc2faff..ebf30d1f 100644 --- a/app/sheet/ui_buffer.c +++ b/app/sheet/ui_buffer.c @@ -44,11 +44,10 @@ struct zsvsheet_ui_buffer { unsigned char has_row_num : 1; unsigned char mutex_inited : 1; unsigned char write_in_progress : 1; - unsigned char write_progressed : 1; unsigned char write_done : 1; unsigned char worker_active : 1; unsigned char worker_cancelled : 1; - unsigned char _ : 6; + unsigned char _ : 7; }; void zsvsheet_ui_buffer_create_worker(struct zsvsheet_ui_buffer *ub, void *(*start_func)(void *), void *arg) { diff --git a/app/test/Makefile b/app/test/Makefile index 70287b40..195503a2 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -39,10 +39,10 @@ else EXE=.exe endif -THIS_LIB_BASE=$(shell cd ../.. && pwd) +export THIS_LIB_BASE=$(shell cd ../.. && pwd) CCBN=$(shell basename ${CC}) BUILD_DIR=${THIS_LIB_BASE}/build/${BUILD_SUBDIR}/${CCBN} -TMP_DIR=${THIS_LIB_BASE}/tmp +export TMP_DIR=${THIS_LIB_BASE}/tmp TEST_DATA_DIR=${THIS_LIB_BASE}/data SOURCES=echo count count-pull select select-pull sql 2json serialize flatten pretty desc stack 2db 2tsv jq compare overwrite @@ -77,17 +77,25 @@ ifneq ($(LEAKS),) REDIRECT=>${TMP_DIR}/leaks.txt; grep leak ${TMP_DIR}/leaks.txt | grep bytes \# # stop processing at this step REDIRECT1=>${TMP_DIR}/leaks.txt; grep leak ${TMP_DIR}/leaks.txt | grep bytes ) \# # stop processing at this step REDIRECT2=>${TMP_DIR}/leaks.txt; grep leak ${TMP_DIR}/leaks.txt | grep bytes ) \# # stop processing at this step - CMP=\# # don't run this step + export CMP=\# # don't run this step else PREFIX= REDIRECT=> REDIRECT1=> REDIRECT2=-o - CMP=cmp + export CMP=cmp endif +BIG_FILE ?= none +EXPECT_TIMEOUT ?= 5 +EXPECT=../../scripts/test-expect.sh +export EXPECTED_PATH=expected + MAKE_BIN=$(notdir ${MAKE}) +DATE_TIME:=$(shell date +%F-%H-%M-%S) +export TIMINGS_CSV:=${TMP_DIR}/timings-${DATE_TIME}.csv + help: @echo "To run all tests: ${MAKE_BIN} test [LEAKS=1]" @echo "To run individual test: ${MAKE_BIN} test-xxx" @@ -106,6 +114,10 @@ test: ${TESTS} test-paste: @echo "TO DO: test paste" +${TIMINGS_CSV}: + @mkdir -p ${TMP_DIR} + @echo -n "Test, Stage, Time" > ${TIMINGS_CSV} + .SECONDARY: worldcitiespop_mil.csv .PHONY: help test test-% test-stack clean @@ -618,150 +630,121 @@ test-sheet-1: ${BUILD_DIR}/bin/zsv_sheet${EXE} tmux -v send-keys -t $@ "q" "exit" && \ ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (for x in `ls tmux-*.log` ; do echo "Log $$x:" && cat $$x ; done && ${TEST_FAIL})) -test-sheet-2: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-2: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @(tmux new-session -x 80 -y 5 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "C-d" && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || ${TEST_FAIL}) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-3: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-3: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @(tmux new-session -x 80 -y 5 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "f" "sarmaj" Enter && \ - sleep 2 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || ${TEST_FAIL}) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-4: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-4: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @(tmux new-session -x 80 -y 5 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "C-d" "C-d" "C-u" && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || ${TEST_FAIL}) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-5: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-5: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 160 -y 5 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || ${TEST_FAIL}) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-6: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-6: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 50 -d -s $@ "${PREFIX} $< -d 3 ${TEST_DATA_DIR}/test/mixed-line-endings.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "G" "C-u" "C-u" "C-u" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-7: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-7: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 5 -d -s $@ "${PREFIX} $< -d 3 ${TEST_DATA_DIR}/test/mixed-line-endings.csv" && \ - sleep 1 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "G" "g" "g" "C-u" "/" "1234" "Enter" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-8: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-8: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 160 -y 5 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "f" "e" "Enter" && \ - sleep 1 && \ + ${EXPECT} $@ filtered && \ tmux send-keys -t $@ "G" "C-u" "k" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-9: ${BUILD_DIR}/bin/zsv_sheet${EXE} +test-sheet-9: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 6 -d -s $@ "${PREFIX} $< -d 3 ${TEST_DATA_DIR}/test/mixed-line-endings.csv" && \ - sleep 1 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "G" && \ tmux send-keys -t $@ -N 4096 "k" && \ - sleep 2 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-10: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.tsv +test-sheet-10: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.tsv ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 6 -d -s $@ "${PREFIX} $< -t worldcitiespop_mil.tsv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "f" "e" "Enter" && \ - sleep 1 && \ + ${EXPECT} $@ filtered && \ tmux send-keys -t $@ "G" && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-11: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv +test-sheet-11: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 50 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 1 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ -N 11 "C-d" && \ - sleep 1 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-12: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv +test-sheet-12: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 6 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ indexed && \ tmux send-keys -t $@ "f" "el" "Enter" && \ - sleep 0.5 && \ + ${EXPECT} $@ filtered-el && \ tmux send-keys -t $@ "f" "al" "Enter" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) - -test-sheet-13: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv - set -x - ${TEST_INIT} - echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) + +test-sheet-13: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv ${TIMINGS_CSV} + @${TEST_INIT} + @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 25 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ tmux send-keys -t $@ "?" "/" "f" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) -test-sheet-14: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv +test-sheet-14: ${BUILD_DIR}/bin/zsv_sheet${EXE} worldcitiespop_mil.csv ${TIMINGS_CSV} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 25 -d -s $@ "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ tmux send-keys -t $@ "?" && \ - sleep 0.5 && \ + ${EXPECT} $@ help && \ tmux send-keys -t $@ "Escape" && \ - sleep 1 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) + +test-sheet-15: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} + @${TEST_INIT} + @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf + @(tmux new-session -x 80 -y 6 -d -s $@ "${PREFIX} $< -d 3 ${TEST_DATA_DIR}/test/crlf-line-ending.csv" && \ + ${EXPECT} $@ indexed && \ + tmux send-keys -t $@ "G" && \ + ${EXPECT} $@ bottom && \ + tmux send-keys -t $@ -N 4096 "k" && \ + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-sheet-subcommand:\ test-sheet-subcommand-open-file-prompt test-sheet-subcommand-open-file-argument\ @@ -771,50 +754,37 @@ test-sheet-subcommand-open-file-prompt: ${BUILD_DIR}/bin/zsv_sheet${EXE} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 25 -d -s "$@" "${PREFIX} $<" && \ - sleep 0.5 && \ + ${EXPECT} $@ blank && \ tmux send-keys -t $@ ":open" "Enter" && \ - sleep 0.5 && \ + ${EXPECT} $@ open && \ tmux send-keys -t $@ "worldcitiespop_mil.csv" "Enter" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-sheet-subcommand-open-file-argument: ${BUILD_DIR}/bin/zsv_sheet${EXE} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 25 -d -s "$@" "${PREFIX} $<" && \ - sleep 0.5 && \ + ${EXPECT} $@ blank && \ tmux send-keys -t $@ ":open worldcitiespop_mil.csv" "Enter" && \ - sleep 0.5 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) - + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-sheet-subcommand-filter-file-prompt: ${BUILD_DIR}/bin/zsv_sheet${EXE} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 25 -d -s "$@" "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ blank && \ tmux send-keys -t $@ ":filter" "Enter" && \ - sleep 0.5 && \ + ${EXPECT} $@ filter && \ tmux send-keys -t $@ "ireland" "Enter" && \ - sleep 1.0 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-sheet-subcommand-filter-file-argument: ${BUILD_DIR}/bin/zsv_sheet${EXE} @${TEST_INIT} @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf @(tmux new-session -x 80 -y 25 -d -s "$@" "${PREFIX} $< worldcitiespop_mil.csv" && \ - sleep 0.5 && \ + ${EXPECT} $@ blank && \ tmux send-keys -t $@ ":filter \"ireland\"" "Enter" && \ - sleep 1.0 && \ - tmux capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out && \ - tmux send-keys -t $@ "q" && \ - ${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL})) + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) test-sheet-prop-cmd-opt: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${BUILD_DIR}/bin/zsv_prop${EXE} @echo "TO DO: test-sheet-prop-cmd-opt" @@ -831,3 +801,15 @@ test-sheet-prop-cmd-opt: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${BUILD_DIR}/bin/zsv_p # @tmux -v capture-pane -t $@ -p ${REDIRECT1} ${TMP_DIR}/$@.out # @tmux send-keys -t $@ "q" # @${CMP} ${TMP_DIR}/$@.out expected/$@.out && ${TEST_PASS} || (echo 'Incorrect output:' && cat ${TMP_DIR}/$@.out && ${TEST_FAIL}) + +benchmark-sheet-index: ${BUILD_DIR}/bin/zsv_sheet${EXE} ${TIMINGS_CSV} + @${TEST_INIT} + @if [ "${BIG_FILE}" = "none" ]; then \ + echo "Need to set BIG_FILE to a CSV file; ideally 10GB+"; \ + fi + @echo 'set-option default-terminal "${TMUX_TERM}"' > ~/.tmux.conf + @(tmux new-session -x 80 -y 50 -d -s "$@" "${PREFIX} $< ${BIG_FILE}" && \ + ${EXPECT} $@ indexed && \ + tmux send-keys -t $@ "G" && \ + ${EXPECT} $@ && ${TEST_PASS} || ${TEST_FAIL}) + diff --git a/app/test/expected/test-sheet-10-filtered.out b/app/test/expected/test-sheet-10-filtered.out new file mode 100644 index 00000000..4beb11a5 --- /dev/null +++ b/app/test/expected/test-sheet-10-filtered.out @@ -0,0 +1,6 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +4 id selingon Selingon 17 -8.8374 116.4914 +5 ir berimvand Berimvand 13 34.2953 47.1096 +8 ad andorra-v Andorra-V 07 42.5 1.5166667 +(493039 filtered rows) 1 diff --git a/app/test/expected/test-sheet-10-indexed.out b/app/test/expected/test-sheet-10-indexed.out new file mode 100644 index 00000000..80a6d987 --- /dev/null +++ b/app/test/expected/test-sheet-10-indexed.out @@ -0,0 +1,6 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +4 id selingon Selingon 17 -8.8374 116.4914 +? for help 1 diff --git a/app/test/expected/test-sheet-11-indexed.out b/app/test/expected/test-sheet-11-indexed.out new file mode 100644 index 00000000..e1829d4a --- /dev/null +++ b/app/test/expected/test-sheet-11-indexed.out @@ -0,0 +1,50 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +4 id selingon Selingon 17 -8.8374 116.4914 +5 ir berimvand Berimvand 13 34.2953 47.1096 +6 pl chomiaza Chomiaza 73 52.7508 17.841793 +7 mg itona Itona 02 -23.86666 47.216666 +8 ad andorra-v Andorra-V 07 42.5 1.5166667 +9 mx la tortug La Tortug 25 25.75 -108.3333 +10 us asaph Asaph PA 41.770833 -77.40527 +11 ad andorre-v Andorre-V 07 42.5 1.5166667 +12 ru dolmatova Dolmatova 71 57.436791 63.279522 +13 ro escu Escu 13 47.133333 23.533333 +14 us la presa La Presa CA 35119 32.708055 -116.9963 +15 pk makam khu Makam Khu 04 33.650863 72.551536 +16 ad aubinya Aubinyà 06 42.45 1.5 +17 mm kiosong Kiosöng 11 22.583333 97.05 +18 tr donencay Dönençay 28 40.266667 38.583333 +19 it roncaglia Roncaglia 05 45.05 9.8 +20 ml kourmouss Kourmouss 04 14.75 -5.033333 +21 id lamogo Lamogo 38 -4.3945 119.9028 +22 ad casas vil Casas Vil 03 42.533333 1.5666667 +23 ru otdeleniy Otdeleniy 86 51.726473 39.714345 +24 ad certes Certés 06 42.466666 1.5 +25 us mound Mound LA 32.339166 -91.02388 +26 ad el pui El Pui 04 42.55 1.5166667 +27 ad els bons Els Bons 03 42.533333 1.5833333 +28 ru roshina Roshina 46 54.641096 43.547234 +29 ad els plans Els Plans 02 42.583333 1.6333333 +30 ru zelenaya Zelënaya 55 52.616667 54.35 +31 mx tejalpa Tejalpa 21 18.35 -98.36666 +32 ad el vilar El Vilar 02 42.566666 1.6 +33 td narweyt Narweyt 02 15.133333 21.95 +34 id babakanme Babakanme 30 -7.5209 108.0738 +35 mx rancho sa Rancho Sa 10 25.4 -105.1166 +36 ad ercz Ercz 04 42.566666 1.5 +37 ad erez Erez 04 42.566666 1.5 +38 id cigaleuh Cigaleuh 30 -6.415833 107.61027 +39 jp ushitaki Ushitaki 03 41.283333 140.8 +40 ml nkalamedo Nkalaméd 07 12.136944 -7.744722 +41 la ban huai Ban Huai 13 17.875556 101.21944 +42 ad fontaneda Fontaneda 06 42.45 1.4666667 +43 kr chinbol Chinbol 13 37.7376 127.2266 +44 ad juverri Juverri 06 42.433333 1.5 +45 ua arginchik Arginchik 11 45.237894 34.648083 +46 il ezuz Ezuz 01 30.792445 34.472671 +47 ad l'aldosa L'Aldosa 02 42.583333 1.6333333 +48 kh phumi tra Phumi Tra 06 10.866666 104.68333 +? for help 1 diff --git a/app/test/expected/test-sheet-12-filtered-el.out b/app/test/expected/test-sheet-12-filtered-el.out new file mode 100644 index 00000000..8ec2a7dc --- /dev/null +++ b/app/test/expected/test-sheet-12-filtered-el.out @@ -0,0 +1,6 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +4 id selingon Selingon 17 -8.8374 116.4914 +23 ru otdeleniy Otdeleniy 86 51.726473 39.714345 +26 ad el pui El Pui 04 42.55 1.5166667 +27 ad els bons Els Bons 03 42.533333 1.5833333 +(59456 filtered rows) 4 diff --git a/app/test/expected/test-sheet-12-indexed.out b/app/test/expected/test-sheet-12-indexed.out new file mode 100644 index 00000000..80a6d987 --- /dev/null +++ b/app/test/expected/test-sheet-12-indexed.out @@ -0,0 +1,6 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +4 id selingon Selingon 17 -8.8374 116.4914 +? for help 1 diff --git a/app/test/expected/test-sheet-14-help.out b/app/test/expected/test-sheet-14-help.out new file mode 100644 index 00000000..56fc3c48 --- /dev/null +++ b/app/test/expected/test-sheet-14-help.out @@ -0,0 +1,25 @@ +Key(s) Action Description +q quit Exit the application + escape Leave the current view or +^ first Jump to the first column +$ last Jump to the last column + first Jump to the first column + last Jump to the last column +k up Move up one row +j down Move down one row +h left Move left one column +l right Move right one column + up Move up one row + down Move down one row + left Move left one column + right Move right one column +d pagedown Move down one page +u pageup Move up one page + pagedown Move down one page + pageup Move up one page +g g top Jump to the first row +G bottom Jump to the last row +/ find Set a search term and jum +n next Jump to the next search r +e open Open a another CSV file + to exit help Key(s) diff --git a/app/test/expected/test-sheet-15-bottom.out b/app/test/expected/test-sheet-15-bottom.out new file mode 100644 index 00000000..d9824d9d --- /dev/null +++ b/app/test/expected/test-sheet-15-bottom.out @@ -0,0 +1,6 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +4093 A4093 B4093 C4093 +4094 A4094 B4094 C4094 +4095 A4095 B4095 C4095 +4096 A4096 B4096 C4096 +? for help 4096 diff --git a/app/test/expected/test-sheet-15-indexed.out b/app/test/expected/test-sheet-15-indexed.out new file mode 100644 index 00000000..fbae507e --- /dev/null +++ b/app/test/expected/test-sheet-15-indexed.out @@ -0,0 +1,6 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +1 A1 B1 C1 +2 A2 B2 C2 +3 A3 B3 C3 +4 A4 B4 C4 +? for help 1 diff --git a/app/test/expected/test-sheet-15.out b/app/test/expected/test-sheet-15.out new file mode 100644 index 00000000..3de62ade --- /dev/null +++ b/app/test/expected/test-sheet-15.out @@ -0,0 +1,6 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +1 A1 B1 C1 +2 A2 B2 C2 +3 A3 B3 C3 +4 A4 B4 C4 +? for help Row # diff --git a/app/test/expected/test-sheet-2-indexed.out b/app/test/expected/test-sheet-2-indexed.out new file mode 100644 index 00000000..7c4ad173 --- /dev/null +++ b/app/test/expected/test-sheet-2-indexed.out @@ -0,0 +1,5 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +? for help 1 diff --git a/app/test/expected/test-sheet-3-indexed.out b/app/test/expected/test-sheet-3-indexed.out new file mode 100644 index 00000000..7c4ad173 --- /dev/null +++ b/app/test/expected/test-sheet-3-indexed.out @@ -0,0 +1,5 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +? for help 1 diff --git a/app/test/expected/test-sheet-4-indexed.out b/app/test/expected/test-sheet-4-indexed.out new file mode 100644 index 00000000..7c4ad173 --- /dev/null +++ b/app/test/expected/test-sheet-4-indexed.out @@ -0,0 +1,5 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +? for help 1 diff --git a/app/test/expected/test-sheet-6-indexed.out b/app/test/expected/test-sheet-6-indexed.out new file mode 100644 index 00000000..a89c4b65 --- /dev/null +++ b/app/test/expected/test-sheet-6-indexed.out @@ -0,0 +1,50 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +1 A1 B1 C1 +2 A2 B2 C2 +3 A3 B3 C3 +4 A4 B4 C4 +5 A5 B5 C5 +6 A6 B6 C6 +7 A7 B7 C7 +8 A8 B8 C8 +9 A9 B9 C9 +10 A10 B10 C10 +11 A11 B11 C11 +12 A12 B12 C12 +13 A13 B13 C13 +14 A14 B14 C14 +15 A15 B15 C15 +16 A16 B16 C16 +17 A17 B17 C17 +18 A18 B18 C18 +19 A19 B19 C19 +20 A20 B20 C20 +21 A21 B21 C21 +22 A22 B22 C22 +23 A23 B23 C23 +24 A24 B24 C24 +25 A25 B25 C25 +26 A26 B26 C26 +27 A27 B27 C27 +28 A28 B28 C28 +29 A29 B29 C29 +30 A30 B30 C30 +31 A31 B31 C31 +32 A32 B32 C32 +33 A33 B33 C33 +34 A34 B34 C34 +35 A35 B35 C35 +36 A36 B36 C36 +37 A37 B37 C37 +38 A38 B38 C38 +39 A39 B39 C39 +40 A40 B40 C40 +41 A41 B41 C41 +42 A42 B42 C42 +43 A43 B43 C43 +44 A44 B44 C44 +45 A45 B45 C45 +46 A46 B46 C46 +47 A47 B47 C47 +48 A48 B48 C48 +? for help 1 diff --git a/app/test/expected/test-sheet-7-indexed.out b/app/test/expected/test-sheet-7-indexed.out new file mode 100644 index 00000000..6a018f15 --- /dev/null +++ b/app/test/expected/test-sheet-7-indexed.out @@ -0,0 +1,5 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +1 A1 B1 C1 +2 A2 B2 C2 +3 A3 B3 C3 +? for help 1 diff --git a/app/test/expected/test-sheet-8-filtered.out b/app/test/expected/test-sheet-8-filtered.out new file mode 100644 index 00000000..b00c58ab --- /dev/null +++ b/app/test/expected/test-sheet-8-filtered.out @@ -0,0 +1,5 @@ +Row # Country City AccentCity Region Population Latitude Longitude +1 ir sarmaj-e hoseynkhan Sarmaj-e Hoseynkhan 13 34.3578 47.5207 +4 id selingon Selingon 17 -8.8374 116.4914 +5 ir berimvand Berimvand 13 34.2953 47.1096 +(493039 filtered rows) 1 diff --git a/app/test/expected/test-sheet-8-indexed.out b/app/test/expected/test-sheet-8-indexed.out new file mode 100644 index 00000000..8c4e66a4 --- /dev/null +++ b/app/test/expected/test-sheet-8-indexed.out @@ -0,0 +1,5 @@ +Row # Country City AccentCity Region Population Latitude Longitude +1 ir sarmaj-e hoseynkhan Sarmaj-e Hoseynkhan 13 34.3578 47.5207 +2 ad aixirivali Aixirivali 06 42.4666667 1.5 +3 mm mokho-atwinywa Mokho-atwinywa 09 18.0333333 96.75 +? for help 1 diff --git a/app/test/expected/test-sheet-9-indexed.out b/app/test/expected/test-sheet-9-indexed.out new file mode 100644 index 00000000..fbae507e --- /dev/null +++ b/app/test/expected/test-sheet-9-indexed.out @@ -0,0 +1,6 @@ +Row # HA1 HA2 HA3 HB1 HB2 HB3 HC1 HC2 HC3 +1 A1 B1 C1 +2 A2 B2 C2 +3 A3 B3 C3 +4 A4 B4 C4 +? for help 1 diff --git a/app/test/expected/test-sheet-subcommand-filter-file-argument-blank.out b/app/test/expected/test-sheet-subcommand-filter-file-argument-blank.out new file mode 100644 index 00000000..610fb180 --- /dev/null +++ b/app/test/expected/test-sheet-subcommand-filter-file-argument-blank.out @@ -0,0 +1,25 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +4 id selingon Selingon 17 -8.8374 116.4914 +5 ir berimvand Berimvand 13 34.2953 47.1096 +6 pl chomiaza Chomiaza 73 52.7508 17.841793 +7 mg itona Itona 02 -23.86666 47.216666 +8 ad andorra-v Andorra-V 07 42.5 1.5166667 +9 mx la tortug La Tortug 25 25.75 -108.3333 +10 us asaph Asaph PA 41.770833 -77.40527 +11 ad andorre-v Andorre-V 07 42.5 1.5166667 +12 ru dolmatova Dolmatova 71 57.436791 63.279522 +13 ro escu Escu 13 47.133333 23.533333 +14 us la presa La Presa CA 35119 32.708055 -116.9963 +15 pk makam khu Makam Khu 04 33.650863 72.551536 +16 ad aubinya Aubinyà 06 42.45 1.5 +17 mm kiosong Kiosöng 11 22.583333 97.05 +18 tr donencay Dönençay 28 40.266667 38.583333 +19 it roncaglia Roncaglia 05 45.05 9.8 +20 ml kourmouss Kourmouss 04 14.75 -5.033333 +21 id lamogo Lamogo 38 -4.3945 119.9028 +22 ad casas vil Casas Vil 03 42.533333 1.5666667 +23 ru otdeleniy Otdeleniy 86 51.726473 39.714345 +? for help 1 diff --git a/app/test/expected/test-sheet-subcommand-filter-file-prompt-blank.out b/app/test/expected/test-sheet-subcommand-filter-file-prompt-blank.out new file mode 100644 index 00000000..610fb180 --- /dev/null +++ b/app/test/expected/test-sheet-subcommand-filter-file-prompt-blank.out @@ -0,0 +1,25 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +4 id selingon Selingon 17 -8.8374 116.4914 +5 ir berimvand Berimvand 13 34.2953 47.1096 +6 pl chomiaza Chomiaza 73 52.7508 17.841793 +7 mg itona Itona 02 -23.86666 47.216666 +8 ad andorra-v Andorra-V 07 42.5 1.5166667 +9 mx la tortug La Tortug 25 25.75 -108.3333 +10 us asaph Asaph PA 41.770833 -77.40527 +11 ad andorre-v Andorre-V 07 42.5 1.5166667 +12 ru dolmatova Dolmatova 71 57.436791 63.279522 +13 ro escu Escu 13 47.133333 23.533333 +14 us la presa La Presa CA 35119 32.708055 -116.9963 +15 pk makam khu Makam Khu 04 33.650863 72.551536 +16 ad aubinya Aubinyà 06 42.45 1.5 +17 mm kiosong Kiosöng 11 22.583333 97.05 +18 tr donencay Dönençay 28 40.266667 38.583333 +19 it roncaglia Roncaglia 05 45.05 9.8 +20 ml kourmouss Kourmouss 04 14.75 -5.033333 +21 id lamogo Lamogo 38 -4.3945 119.9028 +22 ad casas vil Casas Vil 03 42.533333 1.5666667 +23 ru otdeleniy Otdeleniy 86 51.726473 39.714345 +? for help 1 diff --git a/app/test/expected/test-sheet-subcommand-filter-file-prompt-filter.out b/app/test/expected/test-sheet-subcommand-filter-file-prompt-filter.out new file mode 100644 index 00000000..53e1b8d7 --- /dev/null +++ b/app/test/expected/test-sheet-subcommand-filter-file-prompt-filter.out @@ -0,0 +1,25 @@ +Row # Country City AccentCit Region Populatio Latitude Longitude +1 ir sarmaj-e Sarmaj-e 13 34.3578 47.5207 +2 ad aixirival Aixirival 06 42.466666 1.5 +3 mm mokho-atw Mokho-atw 09 18.033333 96.75 +4 id selingon Selingon 17 -8.8374 116.4914 +5 ir berimvand Berimvand 13 34.2953 47.1096 +6 pl chomiaza Chomiaza 73 52.7508 17.841793 +7 mg itona Itona 02 -23.86666 47.216666 +8 ad andorra-v Andorra-V 07 42.5 1.5166667 +9 mx la tortug La Tortug 25 25.75 -108.3333 +10 us asaph Asaph PA 41.770833 -77.40527 +11 ad andorre-v Andorre-V 07 42.5 1.5166667 +12 ru dolmatova Dolmatova 71 57.436791 63.279522 +13 ro escu Escu 13 47.133333 23.533333 +14 us la presa La Presa CA 35119 32.708055 -116.9963 +15 pk makam khu Makam Khu 04 33.650863 72.551536 +16 ad aubinya Aubinyà 06 42.45 1.5 +17 mm kiosong Kiosöng 11 22.583333 97.05 +18 tr donencay Dönençay 28 40.266667 38.583333 +19 it roncaglia Roncaglia 05 45.05 9.8 +20 ml kourmouss Kourmouss 04 14.75 -5.033333 +21 id lamogo Lamogo 38 -4.3945 119.9028 +22 ad casas vil Casas Vil 03 42.533333 1.5666667 +23 ru otdeleniy Otdeleniy 86 51.726473 39.714345 +Filter: diff --git a/app/test/expected/test-sheet-subcommand-open-file-argument-blank.out b/app/test/expected/test-sheet-subcommand-open-file-argument-blank.out new file mode 100644 index 00000000..db7e396c --- /dev/null +++ b/app/test/expected/test-sheet-subcommand-open-file-argument-blank.out @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +? for help diff --git a/app/test/expected/test-sheet-subcommand-open-file-prompt-blank.out b/app/test/expected/test-sheet-subcommand-open-file-prompt-blank.out new file mode 100644 index 00000000..db7e396c --- /dev/null +++ b/app/test/expected/test-sheet-subcommand-open-file-prompt-blank.out @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +? for help diff --git a/app/test/expected/test-sheet-subcommand-open-file-prompt-open.out b/app/test/expected/test-sheet-subcommand-open-file-prompt-open.out new file mode 100644 index 00000000..3ffe7e9a --- /dev/null +++ b/app/test/expected/test-sheet-subcommand-open-file-prompt-open.out @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +File to open: diff --git a/app/utils/index.c b/app/utils/index.c index 5cd56635..c5d397ca 100644 --- a/app/utils/index.c +++ b/app/utils/index.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -8,51 +7,62 @@ #include struct zsv_index *zsv_index_new(void) { - struct zsv_index *ix = malloc(sizeof(*ix)); + struct zsv_index *ix = calloc(1, sizeof(*ix)); if (!ix) return ix; - memset(ix, 0, sizeof(*ix)); - - const size_t init_cap = 256; - ix->array = malloc(sizeof(*ix->array) + init_cap * sizeof(ix->array->u64s[0])); - ix->array->capacity = init_cap; - ix->array->len = 0; + const size_t init_cap = 512; + ix->first = calloc(1, sizeof(*ix->first) + init_cap * sizeof(ix->first->u64s[0])); + ix->first->capacity = init_cap; return ix; } void zsv_index_delete(struct zsv_index *ix) { if (ix) { - free(ix->array); + struct zsv_index_array *arr = ix->first; + + while (arr) { + struct zsv_index_array *a = arr; + arr = arr->next; + free(a); + } + free(ix); } } -enum zsv_index_status zsv_index_add_row(struct zsv_index *ix, zsv_parser parser) { - struct zsv_index_array *arr = ix->array; +enum zsv_index_status zsv_index_add_row(struct zsv_index *ix, uint64_t line_end) { + struct zsv_index_array *arr = ix->first; size_t len = arr->len, cap = arr->capacity; - uint64_t line_end = zsv_cum_scanned_length(parser); if (!ix->header_line_end) { ix->header_line_end = line_end; return zsv_index_status_ok; } - ix->row_count++; + ix->row_count_local++; - if ((ix->row_count & (ZSV_INDEX_ROW_N - 1)) != 0) + if ((ix->row_count_local & (ZSV_INDEX_ROW_N - 1)) != 0) return zsv_index_status_ok; - if (len >= cap) { - cap *= 2; - arr = realloc(arr, sizeof(*arr) + cap * sizeof(arr->u64s[0])); - if (!arr) - return zsv_index_status_memory; - - arr->capacity = cap; - ix->array = arr; + while (len >= cap) { + assert(len == cap); + + if (!arr->next) { + len = 0; + cap *= 2; + arr->next = calloc(1, sizeof(*arr) + cap * sizeof(arr->u64s[0])); + arr = arr->next; + if (!arr) + return zsv_index_status_memory; + arr->capacity = cap; + } else { + arr = arr->next; + len = arr->len; + cap = arr->capacity; + } } arr->u64s[len] = line_end; @@ -61,22 +71,38 @@ enum zsv_index_status zsv_index_add_row(struct zsv_index *ix, zsv_parser parser) return zsv_index_status_ok; } +void zsv_index_commit_rows(struct zsv_index *ix) { + ix->row_count = ix->row_count_local; +} + enum zsv_index_status zsv_index_row_end_offset(const struct zsv_index *ix, uint64_t row, uint64_t *offset_out, uint64_t *remaining_rows_out) { + assert(ix->row_count <= ix->row_count_local); + if (row > ix->row_count) return zsv_index_status_error; if (row < ZSV_INDEX_ROW_N) { *offset_out = ix->header_line_end; *remaining_rows_out = row; - } else { - const size_t i = (row >> ZSV_INDEX_ROW_SHIFT) - 1; - assert(i < ix->array->len); - *offset_out = (long)ix->array->u64s[i]; - *remaining_rows_out = row & (ZSV_INDEX_ROW_N - 1); + return zsv_index_status_ok; } + const size_t i = (row >> ZSV_INDEX_ROW_SHIFT) - 1; + struct zsv_index_array *arr = ix->first; + size_t lens = 0; + + while (i >= lens + arr->len) { + assert(arr->next); + + lens += arr->len; + arr = arr->next; + } + + *offset_out = (long)arr->u64s[i - lens]; + *remaining_rows_out = row & (ZSV_INDEX_ROW_N - 1); + return zsv_index_status_ok; } @@ -118,12 +144,10 @@ static enum zsv_index_status seek_and_check_newline(long *offset, struct zsv_opt if (new_line[0] == '\n') { *offset += 1; } else if (new_line[0] == '\r') { - if (new_line[1] == '\n') { - *offset += 1; - return zsv_index_status_ok; - } - *offset += 1; + + if (new_line[1] == '\n') + *offset += 1; } else { return zsv_index_status_error; } diff --git a/app/utils/writer.c b/app/utils/writer.c index 39be2c30..80b912e5 100644 --- a/app/utils/writer.c +++ b/app/utils/writer.c @@ -6,6 +6,7 @@ * https://opensource.org/licenses/MIT */ +#include "zsv/utils/index.h" #include #include #include @@ -108,6 +109,7 @@ struct zsv_output_buff { size_t (*write)(const void *restrict, size_t size, size_t nitems, void *restrict stream); void *stream; size_t used; + uint64_t written; unsigned char close_on_delete : 1; unsigned char _ : 7; }; @@ -122,6 +124,7 @@ struct zsv_writer_data { void *table_init_ctx; const char *cell_prepend; + struct zsv_index *index; unsigned char with_bom : 1; unsigned char started : 1; @@ -132,6 +135,7 @@ struct zsv_writer_data { static inline void zsv_output_buff_flush(struct zsv_output_buff *b) { b->write(b->buff, b->used, 1, b->stream); + b->written += b->used; b->used = 0; } @@ -141,6 +145,7 @@ static inline void zsv_output_buff_write(struct zsv_output_buff *b, const unsign zsv_output_buff_flush(b); if (n > ZSV_OUTPUT_BUFF_SIZE) { // n too big, so write directly b->write(s, n, 1, b->stream); + b->written += n; return; } } @@ -199,6 +204,7 @@ zsv_csv_writer zsv_writer_new(struct zsv_csv_writer_options *opts) { w->with_bom = opts->with_bom; w->table_init = opts->table_init; w->table_init_ctx = opts->table_init_ctx; + w->index = opts->index; } } return w; @@ -223,17 +229,21 @@ enum zsv_writer_status zsv_writer_delete(zsv_csv_writer w) { if (!w) return zsv_writer_status_missing_handle; + if (w->started) + zsv_output_buff_write(&w->out, (const unsigned char *)"\n", 1); + if (w->out.stream && w->out.write && w->out.buff) zsv_output_buff_flush(&w->out); - if (w->started) - w->out.write("\n", 1, 1, w->out.stream); + if (w->started && w->index) + zsv_index_add_row(w->index, w->out.written); if (w->out.buff) free(w->out.buff); if (w->out.close_on_delete && w->out.stream) fclose(w->out.stream); + free(w); return zsv_writer_status_ok; } @@ -266,9 +276,11 @@ enum zsv_writer_status zsv_writer_cell(zsv_csv_writer w, char new_row, const uns if (w->with_bom) zsv_output_buff_write(&w->out, (const unsigned char *)"\xef\xbb\xbf", 3); w->started = 1; - } else if (new_row) + } else if (new_row) { + if (w->index) + zsv_index_add_row(w->index, (uint64_t)(w->out.used + w->out.written)); zsv_output_buff_write(&w->out, (const unsigned char *)"\n", 1); - else + } else zsv_output_buff_write(&w->out, (const unsigned char *)",", 1); if (VERY_UNLIKELY(w->cell_prepend && *w->cell_prepend)) { diff --git a/data/test/crlf-line-ending.csv b/data/test/crlf-line-ending.csv new file mode 100644 index 00000000..5f5d1888 --- /dev/null +++ b/data/test/crlf-line-ending.csv @@ -0,0 +1,2747 @@ +HA1, HB1, HC1 +HA2, HB2, HC2 +HA3, HB3, HC3 +A1, B1, C1 +A2, B2, C2 +A3, B3, C3 +A4, B4, C4 +A5, B5, C5 A6, B6, C6 +A7, B7, C7 +A8, B8, C8 +A9, B9, C9 A10, B10, C10 +A11, B11, C11 +A12, B12, C12 +A13, B13, C13 +A14, B14, C14 +A15, B15, C15 A16, B16, C16 +A17, B17, C17 +A18, B18, C18 +A19, B19, C19 A20, B20, C20 A21, B21, C21 +A22, B22, C22 +A23, B23, C23 +A24, B24, C24 +A25, B25, C25 +A26, B26, C26 +A27, B27, C27 +A28, B28, C28 +A29, B29, C29 +A30, B30, C30 +A31, B31, C31 +A32, B32, C32 +A33, B33, C33 +A34, B34, C34 A35, B35, C35 +A36, B36, C36 +A37, B37, C37 +A38, B38, C38 +A39, B39, C39 +A40, B40, C40 +A41, B41, C41 +A42, B42, C42 A43, B43, C43 +A44, B44, C44 +A45, B45, C45 A46, B46, C46 +A47, B47, C47 +A48, B48, C48 +A49, B49, C49 +A50, B50, C50 +A51, B51, C51 +A52, B52, C52 +A53, B53, C53 A54, B54, C54 A55, B55, C55 A56, B56, C56 A57, B57, C57 A58, B58, C58 A59, B59, C59 A60, B60, C60 +A61, B61, C61 +A62, B62, C62 +A63, B63, C63 A64, B64, C64 +A65, B65, C65 +A66, B66, C66 +A67, B67, C67 +A68, B68, C68 +A69, B69, C69 A70, B70, C70 +A71, B71, C71 A72, B72, C72 +A73, B73, C73 A74, B74, C74 A75, B75, C75 +A76, B76, C76 +A77, B77, C77 +A78, B78, C78 A79, B79, C79 +A80, B80, C80 A81, B81, C81 +A82, B82, C82 +A83, B83, C83 A84, B84, C84 +A85, B85, C85 +A86, B86, C86 +A87, B87, C87 +A88, B88, C88 A89, B89, C89 +A90, B90, C90 +A91, B91, C91 A92, B92, C92 +A93, B93, C93 +A94, B94, C94 +A95, B95, C95 A96, B96, C96 +A97, B97, C97 +A98, B98, C98 A99, B99, C99 +A100, B100, C100 +A101, B101, C101 +A102, B102, C102 +A103, B103, C103 +A104, B104, C104 +A105, B105, C105 A106, B106, C106 +A107, B107, C107 +A108, B108, C108 +A109, B109, C109 A110, B110, C110 A111, B111, C111 +A112, B112, C112 +A113, B113, C113 +A114, B114, C114 A115, B115, C115 A116, B116, C116 +A117, B117, C117 +A118, B118, C118 A119, B119, C119 A120, B120, C120 +A121, B121, C121 +A122, B122, C122 +A123, B123, C123 A124, B124, C124 +A125, B125, C125 A126, B126, C126 A127, B127, C127 +A128, B128, C128 +A129, B129, C129 A130, B130, C130 +A131, B131, C131 +A132, B132, C132 A133, B133, C133 +A134, B134, C134 +A135, B135, C135 +A136, B136, C136 +A137, B137, C137 +A138, B138, C138 A139, B139, C139 +A140, B140, C140 +A141, B141, C141 +A142, B142, C142 A143, B143, C143 A144, B144, C144 +A145, B145, C145 A146, B146, C146 +A147, B147, C147 +A148, B148, C148 A149, B149, C149 A150, B150, C150 +A151, B151, C151 +A152, B152, C152 A153, B153, C153 +A154, B154, C154 A155, B155, C155 +A156, B156, C156 A157, B157, C157 +A158, B158, C158 A159, B159, C159 A160, B160, C160 +A161, B161, C161 +A162, B162, C162 +A163, B163, C163 +A164, B164, C164 +A165, B165, C165 A166, B166, C166 +A167, B167, C167 +A168, B168, C168 +A169, B169, C169 A170, B170, C170 +A171, B171, C171 +A172, B172, C172 A173, B173, C173 +A174, B174, C174 +A175, B175, C175 A176, B176, C176 +A177, B177, C177 +A178, B178, C178 A179, B179, C179 +A180, B180, C180 A181, B181, C181 +A182, B182, C182 +A183, B183, C183 A184, B184, C184 +A185, B185, C185 +A186, B186, C186 +A187, B187, C187 +A188, B188, C188 +A189, B189, C189 +A190, B190, C190 +A191, B191, C191 +A192, B192, C192 +A193, B193, C193 A194, B194, C194 +A195, B195, C195 +A196, B196, C196 +A197, B197, C197 +A198, B198, C198 +A199, B199, C199 +A200, B200, C200 +A201, B201, C201 A202, B202, C202 A203, B203, C203 +A204, B204, C204 +A205, B205, C205 +A206, B206, C206 +A207, B207, C207 +A208, B208, C208 A209, B209, C209 +A210, B210, C210 +A211, B211, C211 A212, B212, C212 A213, B213, C213 A214, B214, C214 +A215, B215, C215 +A216, B216, C216 A217, B217, C217 +A218, B218, C218 +A219, B219, C219 +A220, B220, C220 A221, B221, C221 +A222, B222, C222 +A223, B223, C223 A224, B224, C224 +A225, B225, C225 +A226, B226, C226 +A227, B227, C227 +A228, B228, C228 +A229, B229, C229 +A230, B230, C230 A231, B231, C231 A232, B232, C232 +A233, B233, C233 +A234, B234, C234 A235, B235, C235 A236, B236, C236 +A237, B237, C237 +A238, B238, C238 +A239, B239, C239 A240, B240, C240 +A241, B241, C241 +A242, B242, C242 +A243, B243, C243 A244, B244, C244 +A245, B245, C245 +A246, B246, C246 A247, B247, C247 A248, B248, C248 A249, B249, C249 A250, B250, C250 +A251, B251, C251 +A252, B252, C252 +A253, B253, C253 +A254, B254, C254 A255, B255, C255 +A256, B256, C256 +A257, B257, C257 +A258, B258, C258 +A259, B259, C259 +A260, B260, C260 +A261, B261, C261 +A262, B262, C262 +A263, B263, C263 +A264, B264, C264 +A265, B265, C265 +A266, B266, C266 +A267, B267, C267 +A268, B268, C268 A269, B269, C269 +A270, B270, C270 +A271, B271, C271 A272, B272, C272 A273, B273, C273 +A274, B274, C274 +A275, B275, C275 +A276, B276, C276 +A277, B277, C277 A278, B278, C278 A279, B279, C279 A280, B280, C280 A281, B281, C281 +A282, B282, C282 +A283, B283, C283 A284, B284, C284 +A285, B285, C285 A286, B286, C286 +A287, B287, C287 +A288, B288, C288 +A289, B289, C289 +A290, B290, C290 A291, B291, C291 +A292, B292, C292 +A293, B293, C293 +A294, B294, C294 +A295, B295, C295 +A296, B296, C296 +A297, B297, C297 A298, B298, C298 +A299, B299, C299 A300, B300, C300 +A301, B301, C301 +A302, B302, C302 +A303, B303, C303 +A304, B304, C304 +A305, B305, C305 A306, B306, C306 +A307, B307, C307 +A308, B308, C308 +A309, B309, C309 A310, B310, C310 +A311, B311, C311 A312, B312, C312 A313, B313, C313 A314, B314, C314 +A315, B315, C315 +A316, B316, C316 +A317, B317, C317 A318, B318, C318 A319, B319, C319 +A320, B320, C320 +A321, B321, C321 A322, B322, C322 +A323, B323, C323 +A324, B324, C324 +A325, B325, C325 +A326, B326, C326 A327, B327, C327 +A328, B328, C328 +A329, B329, C329 A330, B330, C330 +A331, B331, C331 +A332, B332, C332 +A333, B333, C333 +A334, B334, C334 +A335, B335, C335 A336, B336, C336 A337, B337, C337 +A338, B338, C338 A339, B339, C339 A340, B340, C340 +A341, B341, C341 +A342, B342, C342 A343, B343, C343 +A344, B344, C344 +A345, B345, C345 +A346, B346, C346 +A347, B347, C347 A348, B348, C348 A349, B349, C349 +A350, B350, C350 A351, B351, C351 +A352, B352, C352 +A353, B353, C353 +A354, B354, C354 +A355, B355, C355 A356, B356, C356 A357, B357, C357 A358, B358, C358 +A359, B359, C359 +A360, B360, C360 +A361, B361, C361 +A362, B362, C362 A363, B363, C363 +A364, B364, C364 +A365, B365, C365 +A366, B366, C366 +A367, B367, C367 A368, B368, C368 +A369, B369, C369 +A370, B370, C370 +A371, B371, C371 +A372, B372, C372 +A373, B373, C373 +A374, B374, C374 +A375, B375, C375 +A376, B376, C376 A377, B377, C377 +A378, B378, C378 +A379, B379, C379 +A380, B380, C380 A381, B381, C381 A382, B382, C382 +A383, B383, C383 A384, B384, C384 +A385, B385, C385 +A386, B386, C386 +A387, B387, C387 +A388, B388, C388 +A389, B389, C389 A390, B390, C390 +A391, B391, C391 A392, B392, C392 +A393, B393, C393 +A394, B394, C394 +A395, B395, C395 A396, B396, C396 +A397, B397, C397 +A398, B398, C398 A399, B399, C399 +A400, B400, C400 +A401, B401, C401 +A402, B402, C402 +A403, B403, C403 A404, B404, C404 +A405, B405, C405 A406, B406, C406 A407, B407, C407 +A408, B408, C408 +A409, B409, C409 A410, B410, C410 +A411, B411, C411 +A412, B412, C412 +A413, B413, C413 +A414, B414, C414 +A415, B415, C415 +A416, B416, C416 +A417, B417, C417 +A418, B418, C418 +A419, B419, C419 +A420, B420, C420 +A421, B421, C421 A422, B422, C422 +A423, B423, C423 A424, B424, C424 +A425, B425, C425 +A426, B426, C426 A427, B427, C427 A428, B428, C428 A429, B429, C429 +A430, B430, C430 +A431, B431, C431 +A432, B432, C432 +A433, B433, C433 +A434, B434, C434 +A435, B435, C435 +A436, B436, C436 +A437, B437, C437 +A438, B438, C438 +A439, B439, C439 A440, B440, C440 +A441, B441, C441 A442, B442, C442 +A443, B443, C443 +A444, B444, C444 A445, B445, C445 +A446, B446, C446 +A447, B447, C447 A448, B448, C448 A449, B449, C449 +A450, B450, C450 A451, B451, C451 A452, B452, C452 +A453, B453, C453 +A454, B454, C454 +A455, B455, C455 +A456, B456, C456 +A457, B457, C457 +A458, B458, C458 A459, B459, C459 +A460, B460, C460 +A461, B461, C461 A462, B462, C462 A463, B463, C463 +A464, B464, C464 +A465, B465, C465 +A466, B466, C466 +A467, B467, C467 +A468, B468, C468 +A469, B469, C469 +A470, B470, C470 A471, B471, C471 +A472, B472, C472 +A473, B473, C473 +A474, B474, C474 +A475, B475, C475 A476, B476, C476 +A477, B477, C477 +A478, B478, C478 +A479, B479, C479 A480, B480, C480 +A481, B481, C481 +A482, B482, C482 +A483, B483, C483 +A484, B484, C484 +A485, B485, C485 A486, B486, C486 A487, B487, C487 A488, B488, C488 +A489, B489, C489 +A490, B490, C490 +A491, B491, C491 +A492, B492, C492 +A493, B493, C493 +A494, B494, C494 +A495, B495, C495 +A496, B496, C496 +A497, B497, C497 +A498, B498, C498 +A499, B499, C499 +A500, B500, C500 +A501, B501, C501 +A502, B502, C502 +A503, B503, C503 +A504, B504, C504 +A505, B505, C505 +A506, B506, C506 +A507, B507, C507 A508, B508, C508 +A509, B509, C509 +A510, B510, C510 A511, B511, C511 +A512, B512, C512 +A513, B513, C513 A514, B514, C514 +A515, B515, C515 +A516, B516, C516 +A517, B517, C517 A518, B518, C518 +A519, B519, C519 +A520, B520, C520 A521, B521, C521 A522, B522, C522 +A523, B523, C523 +A524, B524, C524 A525, B525, C525 +A526, B526, C526 A527, B527, C527 +A528, B528, C528 A529, B529, C529 +A530, B530, C530 A531, B531, C531 A532, B532, C532 A533, B533, C533 +A534, B534, C534 +A535, B535, C535 A536, B536, C536 +A537, B537, C537 +A538, B538, C538 +A539, B539, C539 +A540, B540, C540 +A541, B541, C541 A542, B542, C542 +A543, B543, C543 A544, B544, C544 +A545, B545, C545 A546, B546, C546 A547, B547, C547 +A548, B548, C548 A549, B549, C549 +A550, B550, C550 +A551, B551, C551 +A552, B552, C552 +A553, B553, C553 A554, B554, C554 A555, B555, C555 A556, B556, C556 +A557, B557, C557 +A558, B558, C558 A559, B559, C559 +A560, B560, C560 +A561, B561, C561 +A562, B562, C562 A563, B563, C563 A564, B564, C564 +A565, B565, C565 +A566, B566, C566 +A567, B567, C567 +A568, B568, C568 +A569, B569, C569 A570, B570, C570 +A571, B571, C571 +A572, B572, C572 +A573, B573, C573 +A574, B574, C574 +A575, B575, C575 A576, B576, C576 +A577, B577, C577 +A578, B578, C578 +A579, B579, C579 +A580, B580, C580 +A581, B581, C581 +A582, B582, C582 +A583, B583, C583 +A584, B584, C584 +A585, B585, C585 +A586, B586, C586 +A587, B587, C587 +A588, B588, C588 +A589, B589, C589 +A590, B590, C590 +A591, B591, C591 +A592, B592, C592 +A593, B593, C593 +A594, B594, C594 +A595, B595, C595 +A596, B596, C596 +A597, B597, C597 +A598, B598, C598 A599, B599, C599 +A600, B600, C600 +A601, B601, C601 A602, B602, C602 +A603, B603, C603 A604, B604, C604 A605, B605, C605 +A606, B606, C606 +A607, B607, C607 A608, B608, C608 +A609, B609, C609 +A610, B610, C610 A611, B611, C611 A612, B612, C612 +A613, B613, C613 +A614, B614, C614 +A615, B615, C615 +A616, B616, C616 +A617, B617, C617 +A618, B618, C618 +A619, B619, C619 +A620, B620, C620 A621, B621, C621 +A622, B622, C622 +A623, B623, C623 A624, B624, C624 A625, B625, C625 +A626, B626, C626 +A627, B627, C627 +A628, B628, C628 +A629, B629, C629 +A630, B630, C630 +A631, B631, C631 A632, B632, C632 A633, B633, C633 +A634, B634, C634 +A635, B635, C635 A636, B636, C636 +A637, B637, C637 A638, B638, C638 A639, B639, C639 +A640, B640, C640 A641, B641, C641 +A642, B642, C642 A643, B643, C643 A644, B644, C644 +A645, B645, C645 +A646, B646, C646 +A647, B647, C647 +A648, B648, C648 +A649, B649, C649 +A650, B650, C650 A651, B651, C651 A652, B652, C652 A653, B653, C653 +A654, B654, C654 +A655, B655, C655 +A656, B656, C656 A657, B657, C657 A658, B658, C658 +A659, B659, C659 A660, B660, C660 +A661, B661, C661 +A662, B662, C662 +A663, B663, C663 +A664, B664, C664 +A665, B665, C665 +A666, B666, C666 +A667, B667, C667 +A668, B668, C668 A669, B669, C669 A670, B670, C670 A671, B671, C671 +A672, B672, C672 A673, B673, C673 A674, B674, C674 +A675, B675, C675 A676, B676, C676 +A677, B677, C677 +A678, B678, C678 A679, B679, C679 +A680, B680, C680 +A681, B681, C681 +A682, B682, C682 A683, B683, C683 A684, B684, C684 +A685, B685, C685 +A686, B686, C686 +A687, B687, C687 +A688, B688, C688 A689, B689, C689 A690, B690, C690 A691, B691, C691 +A692, B692, C692 A693, B693, C693 +A694, B694, C694 +A695, B695, C695 +A696, B696, C696 +A697, B697, C697 +A698, B698, C698 +A699, B699, C699 A700, B700, C700 +A701, B701, C701 +A702, B702, C702 +A703, B703, C703 +A704, B704, C704 +A705, B705, C705 +A706, B706, C706 +A707, B707, C707 +A708, B708, C708 +A709, B709, C709 +A710, B710, C710 +A711, B711, C711 A712, B712, C712 +A713, B713, C713 A714, B714, C714 +A715, B715, C715 A716, B716, C716 A717, B717, C717 +A718, B718, C718 A719, B719, C719 +A720, B720, C720 +A721, B721, C721 +A722, B722, C722 +A723, B723, C723 A724, B724, C724 +A725, B725, C725 +A726, B726, C726 +A727, B727, C727 +A728, B728, C728 +A729, B729, C729 +A730, B730, C730 +A731, B731, C731 A732, B732, C732 +A733, B733, C733 +A734, B734, C734 +A735, B735, C735 +A736, B736, C736 +A737, B737, C737 +A738, B738, C738 +A739, B739, C739 +A740, B740, C740 +A741, B741, C741 +A742, B742, C742 +A743, B743, C743 A744, B744, C744 +A745, B745, C745 +A746, B746, C746 +A747, B747, C747 A748, B748, C748 +A749, B749, C749 +A750, B750, C750 +A751, B751, C751 A752, B752, C752 A753, B753, C753 +A754, B754, C754 A755, B755, C755 +A756, B756, C756 +A757, B757, C757 +A758, B758, C758 A759, B759, C759 +A760, B760, C760 A761, B761, C761 A762, B762, C762 A763, B763, C763 A764, B764, C764 +A765, B765, C765 A766, B766, C766 +A767, B767, C767 +A768, B768, C768 +A769, B769, C769 +A770, B770, C770 +A771, B771, C771 +A772, B772, C772 +A773, B773, C773 A774, B774, C774 +A775, B775, C775 A776, B776, C776 +A777, B777, C777 +A778, B778, C778 A779, B779, C779 +A780, B780, C780 +A781, B781, C781 +A782, B782, C782 +A783, B783, C783 A784, B784, C784 +A785, B785, C785 +A786, B786, C786 A787, B787, C787 +A788, B788, C788 A789, B789, C789 +A790, B790, C790 A791, B791, C791 A792, B792, C792 +A793, B793, C793 +A794, B794, C794 A795, B795, C795 +A796, B796, C796 +A797, B797, C797 +A798, B798, C798 A799, B799, C799 +A800, B800, C800 +A801, B801, C801 A802, B802, C802 +A803, B803, C803 +A804, B804, C804 +A805, B805, C805 +A806, B806, C806 +A807, B807, C807 +A808, B808, C808 A809, B809, C809 +A810, B810, C810 A811, B811, C811 +A812, B812, C812 A813, B813, C813 A814, B814, C814 +A815, B815, C815 A816, B816, C816 +A817, B817, C817 +A818, B818, C818 +A819, B819, C819 +A820, B820, C820 +A821, B821, C821 +A822, B822, C822 +A823, B823, C823 +A824, B824, C824 A825, B825, C825 +A826, B826, C826 +A827, B827, C827 +A828, B828, C828 +A829, B829, C829 +A830, B830, C830 +A831, B831, C831 +A832, B832, C832 +A833, B833, C833 +A834, B834, C834 +A835, B835, C835 +A836, B836, C836 +A837, B837, C837 +A838, B838, C838 A839, B839, C839 +A840, B840, C840 +A841, B841, C841 +A842, B842, C842 +A843, B843, C843 +A844, B844, C844 +A845, B845, C845 +A846, B846, C846 +A847, B847, C847 +A848, B848, C848 +A849, B849, C849 +A850, B850, C850 A851, B851, C851 +A852, B852, C852 A853, B853, C853 A854, B854, C854 +A855, B855, C855 A856, B856, C856 A857, B857, C857 A858, B858, C858 A859, B859, C859 A860, B860, C860 +A861, B861, C861 +A862, B862, C862 +A863, B863, C863 A864, B864, C864 +A865, B865, C865 +A866, B866, C866 +A867, B867, C867 A868, B868, C868 +A869, B869, C869 A870, B870, C870 A871, B871, C871 +A872, B872, C872 A873, B873, C873 A874, B874, C874 +A875, B875, C875 +A876, B876, C876 A877, B877, C877 A878, B878, C878 +A879, B879, C879 +A880, B880, C880 +A881, B881, C881 A882, B882, C882 A883, B883, C883 A884, B884, C884 A885, B885, C885 A886, B886, C886 +A887, B887, C887 +A888, B888, C888 +A889, B889, C889 +A890, B890, C890 +A891, B891, C891 A892, B892, C892 +A893, B893, C893 +A894, B894, C894 +A895, B895, C895 +A896, B896, C896 +A897, B897, C897 +A898, B898, C898 +A899, B899, C899 A900, B900, C900 A901, B901, C901 A902, B902, C902 A903, B903, C903 +A904, B904, C904 A905, B905, C905 +A906, B906, C906 +A907, B907, C907 +A908, B908, C908 +A909, B909, C909 +A910, B910, C910 +A911, B911, C911 A912, B912, C912 A913, B913, C913 +A914, B914, C914 +A915, B915, C915 +A916, B916, C916 A917, B917, C917 A918, B918, C918 +A919, B919, C919 +A920, B920, C920 A921, B921, C921 +A922, B922, C922 +A923, B923, C923 +A924, B924, C924 A925, B925, C925 +A926, B926, C926 +A927, B927, C927 +A928, B928, C928 +A929, B929, C929 A930, B930, C930 +A931, B931, C931 A932, B932, C932 A933, B933, C933 A934, B934, C934 +A935, B935, C935 +A936, B936, C936 +A937, B937, C937 +A938, B938, C938 +A939, B939, C939 +A940, B940, C940 A941, B941, C941 +A942, B942, C942 +A943, B943, C943 +A944, B944, C944 A945, B945, C945 A946, B946, C946 A947, B947, C947 A948, B948, C948 +A949, B949, C949 +A950, B950, C950 A951, B951, C951 +A952, B952, C952 +A953, B953, C953 A954, B954, C954 +A955, B955, C955 +A956, B956, C956 A957, B957, C957 +A958, B958, C958 +A959, B959, C959 A960, B960, C960 A961, B961, C961 +A962, B962, C962 +A963, B963, C963 A964, B964, C964 +A965, B965, C965 +A966, B966, C966 +A967, B967, C967 A968, B968, C968 +A969, B969, C969 A970, B970, C970 A971, B971, C971 +A972, B972, C972 +A973, B973, C973 A974, B974, C974 +A975, B975, C975 +A976, B976, C976 +A977, B977, C977 +A978, B978, C978 +A979, B979, C979 +A980, B980, C980 A981, B981, C981 +A982, B982, C982 +A983, B983, C983 +A984, B984, C984 +A985, B985, C985 A986, B986, C986 +A987, B987, C987 +A988, B988, C988 A989, B989, C989 A990, B990, C990 A991, B991, C991 A992, B992, C992 +A993, B993, C993 A994, B994, C994 A995, B995, C995 A996, B996, C996 A997, B997, C997 A998, B998, C998 A999, B999, C999 +A1000, B1000, C1000 +A1001, B1001, C1001 +A1002, B1002, C1002 +A1003, B1003, C1003 +A1004, B1004, C1004 A1005, B1005, C1005 +A1006, B1006, C1006 A1007, B1007, C1007 A1008, B1008, C1008 +A1009, B1009, C1009 +A1010, B1010, C1010 +A1011, B1011, C1011 +A1012, B1012, C1012 A1013, B1013, C1013 +A1014, B1014, C1014 +A1015, B1015, C1015 +A1016, B1016, C1016 +A1017, B1017, C1017 +A1018, B1018, C1018 +A1019, B1019, C1019 A1020, B1020, C1020 +A1021, B1021, C1021 +A1022, B1022, C1022 +A1023, B1023, C1023 A1024, B1024, C1024 +A1025, B1025, C1025 A1026, B1026, C1026 +A1027, B1027, C1027 +A1028, B1028, C1028 +A1029, B1029, C1029 A1030, B1030, C1030 A1031, B1031, C1031 +A1032, B1032, C1032 A1033, B1033, C1033 +A1034, B1034, C1034 A1035, B1035, C1035 A1036, B1036, C1036 +A1037, B1037, C1037 A1038, B1038, C1038 +A1039, B1039, C1039 A1040, B1040, C1040 A1041, B1041, C1041 A1042, B1042, C1042 +A1043, B1043, C1043 +A1044, B1044, C1044 A1045, B1045, C1045 +A1046, B1046, C1046 A1047, B1047, C1047 +A1048, B1048, C1048 +A1049, B1049, C1049 +A1050, B1050, C1050 +A1051, B1051, C1051 +A1052, B1052, C1052 +A1053, B1053, C1053 A1054, B1054, C1054 +A1055, B1055, C1055 A1056, B1056, C1056 +A1057, B1057, C1057 +A1058, B1058, C1058 A1059, B1059, C1059 +A1060, B1060, C1060 +A1061, B1061, C1061 A1062, B1062, C1062 +A1063, B1063, C1063 +A1064, B1064, C1064 +A1065, B1065, C1065 +A1066, B1066, C1066 A1067, B1067, C1067 +A1068, B1068, C1068 +A1069, B1069, C1069 +A1070, B1070, C1070 +A1071, B1071, C1071 A1072, B1072, C1072 +A1073, B1073, C1073 +A1074, B1074, C1074 +A1075, B1075, C1075 +A1076, B1076, C1076 +A1077, B1077, C1077 +A1078, B1078, C1078 A1079, B1079, C1079 +A1080, B1080, C1080 +A1081, B1081, C1081 +A1082, B1082, C1082 +A1083, B1083, C1083 +A1084, B1084, C1084 +A1085, B1085, C1085 +A1086, B1086, C1086 +A1087, B1087, C1087 +A1088, B1088, C1088 +A1089, B1089, C1089 +A1090, B1090, C1090 +A1091, B1091, C1091 +A1092, B1092, C1092 +A1093, B1093, C1093 +A1094, B1094, C1094 +A1095, B1095, C1095 +A1096, B1096, C1096 +A1097, B1097, C1097 +A1098, B1098, C1098 +A1099, B1099, C1099 +A1100, B1100, C1100 +A1101, B1101, C1101 +A1102, B1102, C1102 A1103, B1103, C1103 +A1104, B1104, C1104 A1105, B1105, C1105 A1106, B1106, C1106 +A1107, B1107, C1107 +A1108, B1108, C1108 +A1109, B1109, C1109 A1110, B1110, C1110 A1111, B1111, C1111 A1112, B1112, C1112 +A1113, B1113, C1113 A1114, B1114, C1114 +A1115, B1115, C1115 A1116, B1116, C1116 +A1117, B1117, C1117 +A1118, B1118, C1118 A1119, B1119, C1119 A1120, B1120, C1120 A1121, B1121, C1121 A1122, B1122, C1122 A1123, B1123, C1123 +A1124, B1124, C1124 +A1125, B1125, C1125 +A1126, B1126, C1126 +A1127, B1127, C1127 A1128, B1128, C1128 +A1129, B1129, C1129 +A1130, B1130, C1130 A1131, B1131, C1131 +A1132, B1132, C1132 +A1133, B1133, C1133 +A1134, B1134, C1134 +A1135, B1135, C1135 +A1136, B1136, C1136 A1137, B1137, C1137 +A1138, B1138, C1138 +A1139, B1139, C1139 A1140, B1140, C1140 A1141, B1141, C1141 +A1142, B1142, C1142 +A1143, B1143, C1143 +A1144, B1144, C1144 A1145, B1145, C1145 +A1146, B1146, C1146 A1147, B1147, C1147 A1148, B1148, C1148 +A1149, B1149, C1149 +A1150, B1150, C1150 +A1151, B1151, C1151 +A1152, B1152, C1152 +A1153, B1153, C1153 A1154, B1154, C1154 +A1155, B1155, C1155 +A1156, B1156, C1156 A1157, B1157, C1157 +A1158, B1158, C1158 +A1159, B1159, C1159 +A1160, B1160, C1160 A1161, B1161, C1161 +A1162, B1162, C1162 +A1163, B1163, C1163 +A1164, B1164, C1164 +A1165, B1165, C1165 A1166, B1166, C1166 +A1167, B1167, C1167 +A1168, B1168, C1168 +A1169, B1169, C1169 +A1170, B1170, C1170 A1171, B1171, C1171 +A1172, B1172, C1172 +A1173, B1173, C1173 +A1174, B1174, C1174 A1175, B1175, C1175 A1176, B1176, C1176 A1177, B1177, C1177 +A1178, B1178, C1178 +A1179, B1179, C1179 +A1180, B1180, C1180 +A1181, B1181, C1181 +A1182, B1182, C1182 +A1183, B1183, C1183 A1184, B1184, C1184 +A1185, B1185, C1185 A1186, B1186, C1186 +A1187, B1187, C1187 A1188, B1188, C1188 A1189, B1189, C1189 +A1190, B1190, C1190 +A1191, B1191, C1191 +A1192, B1192, C1192 +A1193, B1193, C1193 A1194, B1194, C1194 A1195, B1195, C1195 +A1196, B1196, C1196 +A1197, B1197, C1197 +A1198, B1198, C1198 +A1199, B1199, C1199 +A1200, B1200, C1200 A1201, B1201, C1201 A1202, B1202, C1202 +A1203, B1203, C1203 +A1204, B1204, C1204 A1205, B1205, C1205 A1206, B1206, C1206 +A1207, B1207, C1207 +A1208, B1208, C1208 +A1209, B1209, C1209 +A1210, B1210, C1210 +A1211, B1211, C1211 A1212, B1212, C1212 +A1213, B1213, C1213 A1214, B1214, C1214 +A1215, B1215, C1215 +A1216, B1216, C1216 +A1217, B1217, C1217 A1218, B1218, C1218 +A1219, B1219, C1219 A1220, B1220, C1220 +A1221, B1221, C1221 A1222, B1222, C1222 +A1223, B1223, C1223 +A1224, B1224, C1224 +A1225, B1225, C1225 A1226, B1226, C1226 A1227, B1227, C1227 +A1228, B1228, C1228 A1229, B1229, C1229 +A1230, B1230, C1230 +A1231, B1231, C1231 +A1232, B1232, C1232 +A1233, B1233, C1233 +A1234, B1234, C1234 +A1235, B1235, C1235 A1236, B1236, C1236 +A1237, B1237, C1237 +A1238, B1238, C1238 A1239, B1239, C1239 A1240, B1240, C1240 A1241, B1241, C1241 +A1242, B1242, C1242 +A1243, B1243, C1243 +A1244, B1244, C1244 +A1245, B1245, C1245 +A1246, B1246, C1246 +A1247, B1247, C1247 A1248, B1248, C1248 +A1249, B1249, C1249 +A1250, B1250, C1250 A1251, B1251, C1251 +A1252, B1252, C1252 +A1253, B1253, C1253 +A1254, B1254, C1254 A1255, B1255, C1255 +A1256, B1256, C1256 +A1257, B1257, C1257 +A1258, B1258, C1258 +A1259, B1259, C1259 +A1260, B1260, C1260 +A1261, B1261, C1261 +A1262, B1262, C1262 +A1263, B1263, C1263 +A1264, B1264, C1264 A1265, B1265, C1265 A1266, B1266, C1266 +A1267, B1267, C1267 +A1268, B1268, C1268 +A1269, B1269, C1269 A1270, B1270, C1270 +A1271, B1271, C1271 A1272, B1272, C1272 A1273, B1273, C1273 A1274, B1274, C1274 +A1275, B1275, C1275 +A1276, B1276, C1276 A1277, B1277, C1277 +A1278, B1278, C1278 A1279, B1279, C1279 A1280, B1280, C1280 +A1281, B1281, C1281 +A1282, B1282, C1282 +A1283, B1283, C1283 A1284, B1284, C1284 +A1285, B1285, C1285 A1286, B1286, C1286 +A1287, B1287, C1287 A1288, B1288, C1288 A1289, B1289, C1289 +A1290, B1290, C1290 +A1291, B1291, C1291 A1292, B1292, C1292 +A1293, B1293, C1293 +A1294, B1294, C1294 +A1295, B1295, C1295 +A1296, B1296, C1296 A1297, B1297, C1297 +A1298, B1298, C1298 +A1299, B1299, C1299 +A1300, B1300, C1300 +A1301, B1301, C1301 +A1302, B1302, C1302 +A1303, B1303, C1303 +A1304, B1304, C1304 +A1305, B1305, C1305 +A1306, B1306, C1306 +A1307, B1307, C1307 +A1308, B1308, C1308 +A1309, B1309, C1309 A1310, B1310, C1310 A1311, B1311, C1311 +A1312, B1312, C1312 +A1313, B1313, C1313 +A1314, B1314, C1314 A1315, B1315, C1315 +A1316, B1316, C1316 A1317, B1317, C1317 +A1318, B1318, C1318 A1319, B1319, C1319 A1320, B1320, C1320 A1321, B1321, C1321 +A1322, B1322, C1322 A1323, B1323, C1323 A1324, B1324, C1324 +A1325, B1325, C1325 A1326, B1326, C1326 +A1327, B1327, C1327 +A1328, B1328, C1328 A1329, B1329, C1329 +A1330, B1330, C1330 A1331, B1331, C1331 A1332, B1332, C1332 A1333, B1333, C1333 A1334, B1334, C1334 +A1335, B1335, C1335 A1336, B1336, C1336 +A1337, B1337, C1337 +A1338, B1338, C1338 +A1339, B1339, C1339 +A1340, B1340, C1340 +A1341, B1341, C1341 +A1342, B1342, C1342 +A1343, B1343, C1343 +A1344, B1344, C1344 +A1345, B1345, C1345 +A1346, B1346, C1346 +A1347, B1347, C1347 +A1348, B1348, C1348 A1349, B1349, C1349 A1350, B1350, C1350 A1351, B1351, C1351 +A1352, B1352, C1352 A1353, B1353, C1353 +A1354, B1354, C1354 A1355, B1355, C1355 A1356, B1356, C1356 A1357, B1357, C1357 +A1358, B1358, C1358 +A1359, B1359, C1359 A1360, B1360, C1360 +A1361, B1361, C1361 +A1362, B1362, C1362 A1363, B1363, C1363 +A1364, B1364, C1364 +A1365, B1365, C1365 +A1366, B1366, C1366 +A1367, B1367, C1367 +A1368, B1368, C1368 +A1369, B1369, C1369 +A1370, B1370, C1370 A1371, B1371, C1371 +A1372, B1372, C1372 +A1373, B1373, C1373 A1374, B1374, C1374 +A1375, B1375, C1375 +A1376, B1376, C1376 +A1377, B1377, C1377 A1378, B1378, C1378 A1379, B1379, C1379 +A1380, B1380, C1380 +A1381, B1381, C1381 +A1382, B1382, C1382 +A1383, B1383, C1383 +A1384, B1384, C1384 A1385, B1385, C1385 +A1386, B1386, C1386 +A1387, B1387, C1387 +A1388, B1388, C1388 +A1389, B1389, C1389 A1390, B1390, C1390 +A1391, B1391, C1391 +A1392, B1392, C1392 +A1393, B1393, C1393 +A1394, B1394, C1394 +A1395, B1395, C1395 +A1396, B1396, C1396 +A1397, B1397, C1397 +A1398, B1398, C1398 +A1399, B1399, C1399 +A1400, B1400, C1400 +A1401, B1401, C1401 A1402, B1402, C1402 +A1403, B1403, C1403 +A1404, B1404, C1404 A1405, B1405, C1405 A1406, B1406, C1406 +A1407, B1407, C1407 +A1408, B1408, C1408 +A1409, B1409, C1409 A1410, B1410, C1410 +A1411, B1411, C1411 +A1412, B1412, C1412 +A1413, B1413, C1413 +A1414, B1414, C1414 +A1415, B1415, C1415 A1416, B1416, C1416 +A1417, B1417, C1417 A1418, B1418, C1418 +A1419, B1419, C1419 +A1420, B1420, C1420 A1421, B1421, C1421 +A1422, B1422, C1422 A1423, B1423, C1423 +A1424, B1424, C1424 +A1425, B1425, C1425 +A1426, B1426, C1426 A1427, B1427, C1427 A1428, B1428, C1428 +A1429, B1429, C1429 +A1430, B1430, C1430 +A1431, B1431, C1431 A1432, B1432, C1432 A1433, B1433, C1433 +A1434, B1434, C1434 +A1435, B1435, C1435 +A1436, B1436, C1436 +A1437, B1437, C1437 +A1438, B1438, C1438 A1439, B1439, C1439 +A1440, B1440, C1440 +A1441, B1441, C1441 A1442, B1442, C1442 +A1443, B1443, C1443 +A1444, B1444, C1444 +A1445, B1445, C1445 A1446, B1446, C1446 +A1447, B1447, C1447 A1448, B1448, C1448 +A1449, B1449, C1449 A1450, B1450, C1450 A1451, B1451, C1451 +A1452, B1452, C1452 A1453, B1453, C1453 +A1454, B1454, C1454 +A1455, B1455, C1455 A1456, B1456, C1456 +A1457, B1457, C1457 +A1458, B1458, C1458 A1459, B1459, C1459 A1460, B1460, C1460 +A1461, B1461, C1461 A1462, B1462, C1462 +A1463, B1463, C1463 A1464, B1464, C1464 +A1465, B1465, C1465 +A1466, B1466, C1466 +A1467, B1467, C1467 +A1468, B1468, C1468 +A1469, B1469, C1469 +A1470, B1470, C1470 A1471, B1471, C1471 +A1472, B1472, C1472 A1473, B1473, C1473 +A1474, B1474, C1474 A1475, B1475, C1475 +A1476, B1476, C1476 +A1477, B1477, C1477 +A1478, B1478, C1478 +A1479, B1479, C1479 +A1480, B1480, C1480 A1481, B1481, C1481 +A1482, B1482, C1482 A1483, B1483, C1483 +A1484, B1484, C1484 +A1485, B1485, C1485 +A1486, B1486, C1486 A1487, B1487, C1487 A1488, B1488, C1488 +A1489, B1489, C1489 +A1490, B1490, C1490 +A1491, B1491, C1491 A1492, B1492, C1492 A1493, B1493, C1493 +A1494, B1494, C1494 +A1495, B1495, C1495 +A1496, B1496, C1496 +A1497, B1497, C1497 A1498, B1498, C1498 A1499, B1499, C1499 +A1500, B1500, C1500 +A1501, B1501, C1501 +A1502, B1502, C1502 A1503, B1503, C1503 A1504, B1504, C1504 A1505, B1505, C1505 A1506, B1506, C1506 +A1507, B1507, C1507 +A1508, B1508, C1508 +A1509, B1509, C1509 A1510, B1510, C1510 +A1511, B1511, C1511 +A1512, B1512, C1512 +A1513, B1513, C1513 A1514, B1514, C1514 A1515, B1515, C1515 +A1516, B1516, C1516 A1517, B1517, C1517 +A1518, B1518, C1518 +A1519, B1519, C1519 +A1520, B1520, C1520 +A1521, B1521, C1521 +A1522, B1522, C1522 A1523, B1523, C1523 +A1524, B1524, C1524 A1525, B1525, C1525 A1526, B1526, C1526 +A1527, B1527, C1527 +A1528, B1528, C1528 +A1529, B1529, C1529 +A1530, B1530, C1530 +A1531, B1531, C1531 +A1532, B1532, C1532 +A1533, B1533, C1533 +A1534, B1534, C1534 +A1535, B1535, C1535 +A1536, B1536, C1536 A1537, B1537, C1537 +A1538, B1538, C1538 +A1539, B1539, C1539 +A1540, B1540, C1540 +A1541, B1541, C1541 +A1542, B1542, C1542 A1543, B1543, C1543 A1544, B1544, C1544 A1545, B1545, C1545 +A1546, B1546, C1546 +A1547, B1547, C1547 +A1548, B1548, C1548 +A1549, B1549, C1549 +A1550, B1550, C1550 +A1551, B1551, C1551 +A1552, B1552, C1552 +A1553, B1553, C1553 +A1554, B1554, C1554 +A1555, B1555, C1555 +A1556, B1556, C1556 +A1557, B1557, C1557 A1558, B1558, C1558 A1559, B1559, C1559 +A1560, B1560, C1560 A1561, B1561, C1561 A1562, B1562, C1562 +A1563, B1563, C1563 A1564, B1564, C1564 +A1565, B1565, C1565 +A1566, B1566, C1566 A1567, B1567, C1567 A1568, B1568, C1568 +A1569, B1569, C1569 +A1570, B1570, C1570 A1571, B1571, C1571 A1572, B1572, C1572 A1573, B1573, C1573 A1574, B1574, C1574 A1575, B1575, C1575 A1576, B1576, C1576 A1577, B1577, C1577 +A1578, B1578, C1578 +A1579, B1579, C1579 A1580, B1580, C1580 A1581, B1581, C1581 A1582, B1582, C1582 A1583, B1583, C1583 +A1584, B1584, C1584 +A1585, B1585, C1585 +A1586, B1586, C1586 +A1587, B1587, C1587 A1588, B1588, C1588 A1589, B1589, C1589 +A1590, B1590, C1590 +A1591, B1591, C1591 A1592, B1592, C1592 +A1593, B1593, C1593 +A1594, B1594, C1594 +A1595, B1595, C1595 +A1596, B1596, C1596 A1597, B1597, C1597 A1598, B1598, C1598 +A1599, B1599, C1599 A1600, B1600, C1600 +A1601, B1601, C1601 A1602, B1602, C1602 +A1603, B1603, C1603 A1604, B1604, C1604 A1605, B1605, C1605 +A1606, B1606, C1606 +A1607, B1607, C1607 +A1608, B1608, C1608 +A1609, B1609, C1609 +A1610, B1610, C1610 A1611, B1611, C1611 +A1612, B1612, C1612 A1613, B1613, C1613 +A1614, B1614, C1614 +A1615, B1615, C1615 A1616, B1616, C1616 +A1617, B1617, C1617 A1618, B1618, C1618 +A1619, B1619, C1619 A1620, B1620, C1620 +A1621, B1621, C1621 +A1622, B1622, C1622 A1623, B1623, C1623 +A1624, B1624, C1624 +A1625, B1625, C1625 A1626, B1626, C1626 A1627, B1627, C1627 +A1628, B1628, C1628 +A1629, B1629, C1629 +A1630, B1630, C1630 A1631, B1631, C1631 +A1632, B1632, C1632 +A1633, B1633, C1633 +A1634, B1634, C1634 +A1635, B1635, C1635 +A1636, B1636, C1636 A1637, B1637, C1637 +A1638, B1638, C1638 +A1639, B1639, C1639 +A1640, B1640, C1640 A1641, B1641, C1641 +A1642, B1642, C1642 +A1643, B1643, C1643 A1644, B1644, C1644 +A1645, B1645, C1645 +A1646, B1646, C1646 +A1647, B1647, C1647 A1648, B1648, C1648 +A1649, B1649, C1649 +A1650, B1650, C1650 A1651, B1651, C1651 +A1652, B1652, C1652 +A1653, B1653, C1653 +A1654, B1654, C1654 A1655, B1655, C1655 +A1656, B1656, C1656 A1657, B1657, C1657 A1658, B1658, C1658 A1659, B1659, C1659 +A1660, B1660, C1660 A1661, B1661, C1661 A1662, B1662, C1662 +A1663, B1663, C1663 +A1664, B1664, C1664 A1665, B1665, C1665 +A1666, B1666, C1666 A1667, B1667, C1667 +A1668, B1668, C1668 +A1669, B1669, C1669 +A1670, B1670, C1670 +A1671, B1671, C1671 +A1672, B1672, C1672 +A1673, B1673, C1673 +A1674, B1674, C1674 +A1675, B1675, C1675 +A1676, B1676, C1676 +A1677, B1677, C1677 +A1678, B1678, C1678 +A1679, B1679, C1679 +A1680, B1680, C1680 +A1681, B1681, C1681 +A1682, B1682, C1682 A1683, B1683, C1683 A1684, B1684, C1684 A1685, B1685, C1685 +A1686, B1686, C1686 +A1687, B1687, C1687 +A1688, B1688, C1688 +A1689, B1689, C1689 +A1690, B1690, C1690 +A1691, B1691, C1691 +A1692, B1692, C1692 +A1693, B1693, C1693 A1694, B1694, C1694 +A1695, B1695, C1695 +A1696, B1696, C1696 A1697, B1697, C1697 +A1698, B1698, C1698 +A1699, B1699, C1699 A1700, B1700, C1700 +A1701, B1701, C1701 +A1702, B1702, C1702 +A1703, B1703, C1703 +A1704, B1704, C1704 +A1705, B1705, C1705 +A1706, B1706, C1706 +A1707, B1707, C1707 +A1708, B1708, C1708 +A1709, B1709, C1709 +A1710, B1710, C1710 +A1711, B1711, C1711 +A1712, B1712, C1712 +A1713, B1713, C1713 +A1714, B1714, C1714 A1715, B1715, C1715 +A1716, B1716, C1716 +A1717, B1717, C1717 +A1718, B1718, C1718 A1719, B1719, C1719 +A1720, B1720, C1720 A1721, B1721, C1721 A1722, B1722, C1722 +A1723, B1723, C1723 +A1724, B1724, C1724 +A1725, B1725, C1725 +A1726, B1726, C1726 +A1727, B1727, C1727 A1728, B1728, C1728 +A1729, B1729, C1729 +A1730, B1730, C1730 A1731, B1731, C1731 A1732, B1732, C1732 +A1733, B1733, C1733 +A1734, B1734, C1734 +A1735, B1735, C1735 A1736, B1736, C1736 +A1737, B1737, C1737 A1738, B1738, C1738 A1739, B1739, C1739 +A1740, B1740, C1740 +A1741, B1741, C1741 A1742, B1742, C1742 +A1743, B1743, C1743 A1744, B1744, C1744 +A1745, B1745, C1745 +A1746, B1746, C1746 A1747, B1747, C1747 +A1748, B1748, C1748 A1749, B1749, C1749 +A1750, B1750, C1750 +A1751, B1751, C1751 +A1752, B1752, C1752 A1753, B1753, C1753 +A1754, B1754, C1754 +A1755, B1755, C1755 +A1756, B1756, C1756 +A1757, B1757, C1757 A1758, B1758, C1758 +A1759, B1759, C1759 A1760, B1760, C1760 A1761, B1761, C1761 +A1762, B1762, C1762 +A1763, B1763, C1763 +A1764, B1764, C1764 +A1765, B1765, C1765 +A1766, B1766, C1766 A1767, B1767, C1767 A1768, B1768, C1768 +A1769, B1769, C1769 +A1770, B1770, C1770 +A1771, B1771, C1771 +A1772, B1772, C1772 +A1773, B1773, C1773 A1774, B1774, C1774 A1775, B1775, C1775 A1776, B1776, C1776 A1777, B1777, C1777 +A1778, B1778, C1778 +A1779, B1779, C1779 +A1780, B1780, C1780 +A1781, B1781, C1781 +A1782, B1782, C1782 +A1783, B1783, C1783 A1784, B1784, C1784 +A1785, B1785, C1785 +A1786, B1786, C1786 +A1787, B1787, C1787 A1788, B1788, C1788 +A1789, B1789, C1789 A1790, B1790, C1790 +A1791, B1791, C1791 +A1792, B1792, C1792 A1793, B1793, C1793 +A1794, B1794, C1794 +A1795, B1795, C1795 +A1796, B1796, C1796 +A1797, B1797, C1797 A1798, B1798, C1798 +A1799, B1799, C1799 +A1800, B1800, C1800 A1801, B1801, C1801 A1802, B1802, C1802 A1803, B1803, C1803 A1804, B1804, C1804 A1805, B1805, C1805 A1806, B1806, C1806 A1807, B1807, C1807 +A1808, B1808, C1808 A1809, B1809, C1809 +A1810, B1810, C1810 +A1811, B1811, C1811 A1812, B1812, C1812 +A1813, B1813, C1813 +A1814, B1814, C1814 +A1815, B1815, C1815 A1816, B1816, C1816 +A1817, B1817, C1817 +A1818, B1818, C1818 +A1819, B1819, C1819 +A1820, B1820, C1820 +A1821, B1821, C1821 A1822, B1822, C1822 +A1823, B1823, C1823 +A1824, B1824, C1824 A1825, B1825, C1825 A1826, B1826, C1826 +A1827, B1827, C1827 +A1828, B1828, C1828 A1829, B1829, C1829 A1830, B1830, C1830 A1831, B1831, C1831 +A1832, B1832, C1832 +A1833, B1833, C1833 +A1834, B1834, C1834 +A1835, B1835, C1835 A1836, B1836, C1836 A1837, B1837, C1837 +A1838, B1838, C1838 +A1839, B1839, C1839 A1840, B1840, C1840 A1841, B1841, C1841 +A1842, B1842, C1842 A1843, B1843, C1843 +A1844, B1844, C1844 A1845, B1845, C1845 +A1846, B1846, C1846 +A1847, B1847, C1847 A1848, B1848, C1848 A1849, B1849, C1849 +A1850, B1850, C1850 +A1851, B1851, C1851 +A1852, B1852, C1852 +A1853, B1853, C1853 +A1854, B1854, C1854 A1855, B1855, C1855 +A1856, B1856, C1856 +A1857, B1857, C1857 +A1858, B1858, C1858 +A1859, B1859, C1859 +A1860, B1860, C1860 +A1861, B1861, C1861 +A1862, B1862, C1862 +A1863, B1863, C1863 A1864, B1864, C1864 +A1865, B1865, C1865 +A1866, B1866, C1866 +A1867, B1867, C1867 +A1868, B1868, C1868 +A1869, B1869, C1869 +A1870, B1870, C1870 +A1871, B1871, C1871 A1872, B1872, C1872 +A1873, B1873, C1873 +A1874, B1874, C1874 +A1875, B1875, C1875 +A1876, B1876, C1876 A1877, B1877, C1877 A1878, B1878, C1878 +A1879, B1879, C1879 +A1880, B1880, C1880 +A1881, B1881, C1881 A1882, B1882, C1882 +A1883, B1883, C1883 +A1884, B1884, C1884 +A1885, B1885, C1885 +A1886, B1886, C1886 +A1887, B1887, C1887 +A1888, B1888, C1888 A1889, B1889, C1889 +A1890, B1890, C1890 A1891, B1891, C1891 A1892, B1892, C1892 +A1893, B1893, C1893 +A1894, B1894, C1894 +A1895, B1895, C1895 +A1896, B1896, C1896 +A1897, B1897, C1897 +A1898, B1898, C1898 A1899, B1899, C1899 +A1900, B1900, C1900 +A1901, B1901, C1901 A1902, B1902, C1902 A1903, B1903, C1903 +A1904, B1904, C1904 +A1905, B1905, C1905 +A1906, B1906, C1906 +A1907, B1907, C1907 A1908, B1908, C1908 +A1909, B1909, C1909 +A1910, B1910, C1910 +A1911, B1911, C1911 +A1912, B1912, C1912 +A1913, B1913, C1913 +A1914, B1914, C1914 +A1915, B1915, C1915 A1916, B1916, C1916 A1917, B1917, C1917 A1918, B1918, C1918 +A1919, B1919, C1919 +A1920, B1920, C1920 +A1921, B1921, C1921 A1922, B1922, C1922 +A1923, B1923, C1923 A1924, B1924, C1924 +A1925, B1925, C1925 +A1926, B1926, C1926 A1927, B1927, C1927 A1928, B1928, C1928 +A1929, B1929, C1929 A1930, B1930, C1930 +A1931, B1931, C1931 +A1932, B1932, C1932 +A1933, B1933, C1933 A1934, B1934, C1934 +A1935, B1935, C1935 +A1936, B1936, C1936 +A1937, B1937, C1937 +A1938, B1938, C1938 A1939, B1939, C1939 +A1940, B1940, C1940 +A1941, B1941, C1941 A1942, B1942, C1942 +A1943, B1943, C1943 A1944, B1944, C1944 +A1945, B1945, C1945 +A1946, B1946, C1946 +A1947, B1947, C1947 +A1948, B1948, C1948 +A1949, B1949, C1949 +A1950, B1950, C1950 +A1951, B1951, C1951 +A1952, B1952, C1952 +A1953, B1953, C1953 +A1954, B1954, C1954 A1955, B1955, C1955 +A1956, B1956, C1956 +A1957, B1957, C1957 A1958, B1958, C1958 +A1959, B1959, C1959 +A1960, B1960, C1960 +A1961, B1961, C1961 A1962, B1962, C1962 A1963, B1963, C1963 +A1964, B1964, C1964 +A1965, B1965, C1965 +A1966, B1966, C1966 +A1967, B1967, C1967 A1968, B1968, C1968 +A1969, B1969, C1969 +A1970, B1970, C1970 A1971, B1971, C1971 +A1972, B1972, C1972 +A1973, B1973, C1973 A1974, B1974, C1974 +A1975, B1975, C1975 +A1976, B1976, C1976 +A1977, B1977, C1977 +A1978, B1978, C1978 +A1979, B1979, C1979 +A1980, B1980, C1980 +A1981, B1981, C1981 A1982, B1982, C1982 A1983, B1983, C1983 A1984, B1984, C1984 +A1985, B1985, C1985 +A1986, B1986, C1986 A1987, B1987, C1987 A1988, B1988, C1988 +A1989, B1989, C1989 +A1990, B1990, C1990 +A1991, B1991, C1991 A1992, B1992, C1992 A1993, B1993, C1993 +A1994, B1994, C1994 +A1995, B1995, C1995 A1996, B1996, C1996 +A1997, B1997, C1997 +A1998, B1998, C1998 +A1999, B1999, C1999 A2000, B2000, C2000 A2001, B2001, C2001 +A2002, B2002, C2002 +A2003, B2003, C2003 A2004, B2004, C2004 A2005, B2005, C2005 +A2006, B2006, C2006 +A2007, B2007, C2007 +A2008, B2008, C2008 A2009, B2009, C2009 A2010, B2010, C2010 +A2011, B2011, C2011 A2012, B2012, C2012 +A2013, B2013, C2013 A2014, B2014, C2014 +A2015, B2015, C2015 A2016, B2016, C2016 +A2017, B2017, C2017 +A2018, B2018, C2018 +A2019, B2019, C2019 A2020, B2020, C2020 +A2021, B2021, C2021 +A2022, B2022, C2022 +A2023, B2023, C2023 +A2024, B2024, C2024 +A2025, B2025, C2025 +A2026, B2026, C2026 A2027, B2027, C2027 A2028, B2028, C2028 +A2029, B2029, C2029 A2030, B2030, C2030 A2031, B2031, C2031 A2032, B2032, C2032 A2033, B2033, C2033 +A2034, B2034, C2034 A2035, B2035, C2035 +A2036, B2036, C2036 +A2037, B2037, C2037 A2038, B2038, C2038 +A2039, B2039, C2039 A2040, B2040, C2040 A2041, B2041, C2041 +A2042, B2042, C2042 A2043, B2043, C2043 +A2044, B2044, C2044 +A2045, B2045, C2045 +A2046, B2046, C2046 +A2047, B2047, C2047 +A2048, B2048, C2048 +A2049, B2049, C2049 A2050, B2050, C2050 A2051, B2051, C2051 A2052, B2052, C2052 A2053, B2053, C2053 +A2054, B2054, C2054 +A2055, B2055, C2055 +A2056, B2056, C2056 +A2057, B2057, C2057 +A2058, B2058, C2058 +A2059, B2059, C2059 +A2060, B2060, C2060 A2061, B2061, C2061 +A2062, B2062, C2062 A2063, B2063, C2063 +A2064, B2064, C2064 A2065, B2065, C2065 A2066, B2066, C2066 A2067, B2067, C2067 +A2068, B2068, C2068 +A2069, B2069, C2069 +A2070, B2070, C2070 A2071, B2071, C2071 +A2072, B2072, C2072 A2073, B2073, C2073 +A2074, B2074, C2074 +A2075, B2075, C2075 +A2076, B2076, C2076 +A2077, B2077, C2077 +A2078, B2078, C2078 +A2079, B2079, C2079 A2080, B2080, C2080 +A2081, B2081, C2081 A2082, B2082, C2082 +A2083, B2083, C2083 A2084, B2084, C2084 A2085, B2085, C2085 A2086, B2086, C2086 +A2087, B2087, C2087 +A2088, B2088, C2088 +A2089, B2089, C2089 A2090, B2090, C2090 +A2091, B2091, C2091 +A2092, B2092, C2092 +A2093, B2093, C2093 +A2094, B2094, C2094 +A2095, B2095, C2095 +A2096, B2096, C2096 +A2097, B2097, C2097 A2098, B2098, C2098 A2099, B2099, C2099 +A2100, B2100, C2100 +A2101, B2101, C2101 +A2102, B2102, C2102 +A2103, B2103, C2103 A2104, B2104, C2104 A2105, B2105, C2105 +A2106, B2106, C2106 A2107, B2107, C2107 +A2108, B2108, C2108 +A2109, B2109, C2109 +A2110, B2110, C2110 A2111, B2111, C2111 +A2112, B2112, C2112 +A2113, B2113, C2113 +A2114, B2114, C2114 +A2115, B2115, C2115 A2116, B2116, C2116 A2117, B2117, C2117 +A2118, B2118, C2118 +A2119, B2119, C2119 A2120, B2120, C2120 +A2121, B2121, C2121 +A2122, B2122, C2122 A2123, B2123, C2123 A2124, B2124, C2124 A2125, B2125, C2125 +A2126, B2126, C2126 A2127, B2127, C2127 A2128, B2128, C2128 A2129, B2129, C2129 A2130, B2130, C2130 +A2131, B2131, C2131 A2132, B2132, C2132 +A2133, B2133, C2133 +A2134, B2134, C2134 +A2135, B2135, C2135 +A2136, B2136, C2136 +A2137, B2137, C2137 A2138, B2138, C2138 +A2139, B2139, C2139 +A2140, B2140, C2140 +A2141, B2141, C2141 +A2142, B2142, C2142 A2143, B2143, C2143 +A2144, B2144, C2144 A2145, B2145, C2145 +A2146, B2146, C2146 +A2147, B2147, C2147 +A2148, B2148, C2148 +A2149, B2149, C2149 +A2150, B2150, C2150 A2151, B2151, C2151 +A2152, B2152, C2152 +A2153, B2153, C2153 +A2154, B2154, C2154 +A2155, B2155, C2155 +A2156, B2156, C2156 +A2157, B2157, C2157 +A2158, B2158, C2158 +A2159, B2159, C2159 +A2160, B2160, C2160 A2161, B2161, C2161 A2162, B2162, C2162 +A2163, B2163, C2163 +A2164, B2164, C2164 +A2165, B2165, C2165 +A2166, B2166, C2166 +A2167, B2167, C2167 +A2168, B2168, C2168 +A2169, B2169, C2169 A2170, B2170, C2170 +A2171, B2171, C2171 +A2172, B2172, C2172 +A2173, B2173, C2173 +A2174, B2174, C2174 A2175, B2175, C2175 A2176, B2176, C2176 A2177, B2177, C2177 +A2178, B2178, C2178 +A2179, B2179, C2179 A2180, B2180, C2180 +A2181, B2181, C2181 +A2182, B2182, C2182 A2183, B2183, C2183 +A2184, B2184, C2184 +A2185, B2185, C2185 +A2186, B2186, C2186 +A2187, B2187, C2187 +A2188, B2188, C2188 +A2189, B2189, C2189 +A2190, B2190, C2190 +A2191, B2191, C2191 A2192, B2192, C2192 +A2193, B2193, C2193 +A2194, B2194, C2194 +A2195, B2195, C2195 +A2196, B2196, C2196 +A2197, B2197, C2197 +A2198, B2198, C2198 +A2199, B2199, C2199 A2200, B2200, C2200 +A2201, B2201, C2201 +A2202, B2202, C2202 +A2203, B2203, C2203 +A2204, B2204, C2204 +A2205, B2205, C2205 A2206, B2206, C2206 +A2207, B2207, C2207 A2208, B2208, C2208 A2209, B2209, C2209 +A2210, B2210, C2210 +A2211, B2211, C2211 +A2212, B2212, C2212 +A2213, B2213, C2213 +A2214, B2214, C2214 A2215, B2215, C2215 +A2216, B2216, C2216 +A2217, B2217, C2217 +A2218, B2218, C2218 A2219, B2219, C2219 +A2220, B2220, C2220 +A2221, B2221, C2221 +A2222, B2222, C2222 A2223, B2223, C2223 +A2224, B2224, C2224 A2225, B2225, C2225 +A2226, B2226, C2226 +A2227, B2227, C2227 A2228, B2228, C2228 +A2229, B2229, C2229 +A2230, B2230, C2230 +A2231, B2231, C2231 +A2232, B2232, C2232 A2233, B2233, C2233 +A2234, B2234, C2234 A2235, B2235, C2235 +A2236, B2236, C2236 +A2237, B2237, C2237 A2238, B2238, C2238 +A2239, B2239, C2239 +A2240, B2240, C2240 +A2241, B2241, C2241 +A2242, B2242, C2242 A2243, B2243, C2243 +A2244, B2244, C2244 +A2245, B2245, C2245 +A2246, B2246, C2246 +A2247, B2247, C2247 +A2248, B2248, C2248 A2249, B2249, C2249 +A2250, B2250, C2250 +A2251, B2251, C2251 +A2252, B2252, C2252 +A2253, B2253, C2253 +A2254, B2254, C2254 +A2255, B2255, C2255 +A2256, B2256, C2256 +A2257, B2257, C2257 +A2258, B2258, C2258 +A2259, B2259, C2259 +A2260, B2260, C2260 +A2261, B2261, C2261 A2262, B2262, C2262 A2263, B2263, C2263 +A2264, B2264, C2264 +A2265, B2265, C2265 A2266, B2266, C2266 A2267, B2267, C2267 +A2268, B2268, C2268 +A2269, B2269, C2269 +A2270, B2270, C2270 A2271, B2271, C2271 A2272, B2272, C2272 +A2273, B2273, C2273 +A2274, B2274, C2274 A2275, B2275, C2275 +A2276, B2276, C2276 +A2277, B2277, C2277 +A2278, B2278, C2278 +A2279, B2279, C2279 A2280, B2280, C2280 +A2281, B2281, C2281 +A2282, B2282, C2282 +A2283, B2283, C2283 +A2284, B2284, C2284 +A2285, B2285, C2285 +A2286, B2286, C2286 +A2287, B2287, C2287 +A2288, B2288, C2288 A2289, B2289, C2289 A2290, B2290, C2290 A2291, B2291, C2291 +A2292, B2292, C2292 +A2293, B2293, C2293 +A2294, B2294, C2294 +A2295, B2295, C2295 +A2296, B2296, C2296 A2297, B2297, C2297 +A2298, B2298, C2298 +A2299, B2299, C2299 +A2300, B2300, C2300 +A2301, B2301, C2301 +A2302, B2302, C2302 +A2303, B2303, C2303 +A2304, B2304, C2304 A2305, B2305, C2305 +A2306, B2306, C2306 +A2307, B2307, C2307 A2308, B2308, C2308 +A2309, B2309, C2309 +A2310, B2310, C2310 A2311, B2311, C2311 +A2312, B2312, C2312 A2313, B2313, C2313 A2314, B2314, C2314 +A2315, B2315, C2315 +A2316, B2316, C2316 +A2317, B2317, C2317 +A2318, B2318, C2318 +A2319, B2319, C2319 +A2320, B2320, C2320 +A2321, B2321, C2321 +A2322, B2322, C2322 A2323, B2323, C2323 +A2324, B2324, C2324 +A2325, B2325, C2325 +A2326, B2326, C2326 A2327, B2327, C2327 A2328, B2328, C2328 A2329, B2329, C2329 A2330, B2330, C2330 +A2331, B2331, C2331 +A2332, B2332, C2332 A2333, B2333, C2333 +A2334, B2334, C2334 +A2335, B2335, C2335 +A2336, B2336, C2336 A2337, B2337, C2337 +A2338, B2338, C2338 +A2339, B2339, C2339 A2340, B2340, C2340 A2341, B2341, C2341 A2342, B2342, C2342 +A2343, B2343, C2343 A2344, B2344, C2344 +A2345, B2345, C2345 +A2346, B2346, C2346 +A2347, B2347, C2347 A2348, B2348, C2348 +A2349, B2349, C2349 A2350, B2350, C2350 +A2351, B2351, C2351 +A2352, B2352, C2352 +A2353, B2353, C2353 A2354, B2354, C2354 A2355, B2355, C2355 +A2356, B2356, C2356 +A2357, B2357, C2357 A2358, B2358, C2358 +A2359, B2359, C2359 +A2360, B2360, C2360 +A2361, B2361, C2361 +A2362, B2362, C2362 +A2363, B2363, C2363 A2364, B2364, C2364 +A2365, B2365, C2365 +A2366, B2366, C2366 A2367, B2367, C2367 A2368, B2368, C2368 +A2369, B2369, C2369 A2370, B2370, C2370 A2371, B2371, C2371 A2372, B2372, C2372 +A2373, B2373, C2373 A2374, B2374, C2374 A2375, B2375, C2375 A2376, B2376, C2376 A2377, B2377, C2377 A2378, B2378, C2378 A2379, B2379, C2379 A2380, B2380, C2380 +A2381, B2381, C2381 A2382, B2382, C2382 A2383, B2383, C2383 +A2384, B2384, C2384 +A2385, B2385, C2385 +A2386, B2386, C2386 +A2387, B2387, C2387 +A2388, B2388, C2388 A2389, B2389, C2389 +A2390, B2390, C2390 +A2391, B2391, C2391 +A2392, B2392, C2392 +A2393, B2393, C2393 A2394, B2394, C2394 +A2395, B2395, C2395 +A2396, B2396, C2396 +A2397, B2397, C2397 +A2398, B2398, C2398 +A2399, B2399, C2399 +A2400, B2400, C2400 +A2401, B2401, C2401 +A2402, B2402, C2402 +A2403, B2403, C2403 A2404, B2404, C2404 +A2405, B2405, C2405 +A2406, B2406, C2406 A2407, B2407, C2407 A2408, B2408, C2408 +A2409, B2409, C2409 +A2410, B2410, C2410 +A2411, B2411, C2411 +A2412, B2412, C2412 A2413, B2413, C2413 +A2414, B2414, C2414 +A2415, B2415, C2415 A2416, B2416, C2416 A2417, B2417, C2417 +A2418, B2418, C2418 A2419, B2419, C2419 A2420, B2420, C2420 +A2421, B2421, C2421 A2422, B2422, C2422 A2423, B2423, C2423 +A2424, B2424, C2424 +A2425, B2425, C2425 +A2426, B2426, C2426 +A2427, B2427, C2427 +A2428, B2428, C2428 +A2429, B2429, C2429 +A2430, B2430, C2430 +A2431, B2431, C2431 A2432, B2432, C2432 A2433, B2433, C2433 +A2434, B2434, C2434 +A2435, B2435, C2435 +A2436, B2436, C2436 A2437, B2437, C2437 +A2438, B2438, C2438 +A2439, B2439, C2439 +A2440, B2440, C2440 A2441, B2441, C2441 +A2442, B2442, C2442 A2443, B2443, C2443 +A2444, B2444, C2444 A2445, B2445, C2445 A2446, B2446, C2446 +A2447, B2447, C2447 +A2448, B2448, C2448 +A2449, B2449, C2449 +A2450, B2450, C2450 +A2451, B2451, C2451 A2452, B2452, C2452 +A2453, B2453, C2453 A2454, B2454, C2454 +A2455, B2455, C2455 +A2456, B2456, C2456 +A2457, B2457, C2457 +A2458, B2458, C2458 +A2459, B2459, C2459 +A2460, B2460, C2460 +A2461, B2461, C2461 A2462, B2462, C2462 +A2463, B2463, C2463 A2464, B2464, C2464 +A2465, B2465, C2465 +A2466, B2466, C2466 +A2467, B2467, C2467 +A2468, B2468, C2468 +A2469, B2469, C2469 +A2470, B2470, C2470 A2471, B2471, C2471 +A2472, B2472, C2472 +A2473, B2473, C2473 +A2474, B2474, C2474 +A2475, B2475, C2475 A2476, B2476, C2476 +A2477, B2477, C2477 +A2478, B2478, C2478 A2479, B2479, C2479 +A2480, B2480, C2480 +A2481, B2481, C2481 +A2482, B2482, C2482 A2483, B2483, C2483 +A2484, B2484, C2484 +A2485, B2485, C2485 +A2486, B2486, C2486 +A2487, B2487, C2487 +A2488, B2488, C2488 +A2489, B2489, C2489 A2490, B2490, C2490 +A2491, B2491, C2491 +A2492, B2492, C2492 +A2493, B2493, C2493 +A2494, B2494, C2494 +A2495, B2495, C2495 +A2496, B2496, C2496 A2497, B2497, C2497 +A2498, B2498, C2498 +A2499, B2499, C2499 A2500, B2500, C2500 +A2501, B2501, C2501 +A2502, B2502, C2502 +A2503, B2503, C2503 A2504, B2504, C2504 A2505, B2505, C2505 +A2506, B2506, C2506 +A2507, B2507, C2507 +A2508, B2508, C2508 +A2509, B2509, C2509 +A2510, B2510, C2510 A2511, B2511, C2511 +A2512, B2512, C2512 +A2513, B2513, C2513 A2514, B2514, C2514 +A2515, B2515, C2515 +A2516, B2516, C2516 A2517, B2517, C2517 +A2518, B2518, C2518 +A2519, B2519, C2519 +A2520, B2520, C2520 A2521, B2521, C2521 +A2522, B2522, C2522 +A2523, B2523, C2523 +A2524, B2524, C2524 +A2525, B2525, C2525 +A2526, B2526, C2526 +A2527, B2527, C2527 +A2528, B2528, C2528 A2529, B2529, C2529 +A2530, B2530, C2530 +A2531, B2531, C2531 A2532, B2532, C2532 +A2533, B2533, C2533 +A2534, B2534, C2534 A2535, B2535, C2535 A2536, B2536, C2536 +A2537, B2537, C2537 +A2538, B2538, C2538 +A2539, B2539, C2539 A2540, B2540, C2540 +A2541, B2541, C2541 A2542, B2542, C2542 A2543, B2543, C2543 +A2544, B2544, C2544 A2545, B2545, C2545 A2546, B2546, C2546 A2547, B2547, C2547 A2548, B2548, C2548 A2549, B2549, C2549 +A2550, B2550, C2550 +A2551, B2551, C2551 A2552, B2552, C2552 +A2553, B2553, C2553 +A2554, B2554, C2554 +A2555, B2555, C2555 A2556, B2556, C2556 A2557, B2557, C2557 A2558, B2558, C2558 A2559, B2559, C2559 A2560, B2560, C2560 +A2561, B2561, C2561 +A2562, B2562, C2562 +A2563, B2563, C2563 A2564, B2564, C2564 A2565, B2565, C2565 +A2566, B2566, C2566 A2567, B2567, C2567 +A2568, B2568, C2568 +A2569, B2569, C2569 A2570, B2570, C2570 A2571, B2571, C2571 A2572, B2572, C2572 +A2573, B2573, C2573 +A2574, B2574, C2574 A2575, B2575, C2575 A2576, B2576, C2576 +A2577, B2577, C2577 A2578, B2578, C2578 +A2579, B2579, C2579 A2580, B2580, C2580 A2581, B2581, C2581 +A2582, B2582, C2582 A2583, B2583, C2583 +A2584, B2584, C2584 A2585, B2585, C2585 +A2586, B2586, C2586 A2587, B2587, C2587 A2588, B2588, C2588 +A2589, B2589, C2589 +A2590, B2590, C2590 A2591, B2591, C2591 +A2592, B2592, C2592 +A2593, B2593, C2593 +A2594, B2594, C2594 +A2595, B2595, C2595 +A2596, B2596, C2596 +A2597, B2597, C2597 A2598, B2598, C2598 +A2599, B2599, C2599 +A2600, B2600, C2600 A2601, B2601, C2601 +A2602, B2602, C2602 A2603, B2603, C2603 +A2604, B2604, C2604 +A2605, B2605, C2605 +A2606, B2606, C2606 +A2607, B2607, C2607 A2608, B2608, C2608 A2609, B2609, C2609 A2610, B2610, C2610 +A2611, B2611, C2611 A2612, B2612, C2612 A2613, B2613, C2613 A2614, B2614, C2614 +A2615, B2615, C2615 +A2616, B2616, C2616 A2617, B2617, C2617 A2618, B2618, C2618 A2619, B2619, C2619 +A2620, B2620, C2620 A2621, B2621, C2621 +A2622, B2622, C2622 A2623, B2623, C2623 +A2624, B2624, C2624 +A2625, B2625, C2625 +A2626, B2626, C2626 +A2627, B2627, C2627 +A2628, B2628, C2628 +A2629, B2629, C2629 +A2630, B2630, C2630 A2631, B2631, C2631 +A2632, B2632, C2632 +A2633, B2633, C2633 A2634, B2634, C2634 +A2635, B2635, C2635 +A2636, B2636, C2636 A2637, B2637, C2637 A2638, B2638, C2638 A2639, B2639, C2639 +A2640, B2640, C2640 +A2641, B2641, C2641 A2642, B2642, C2642 A2643, B2643, C2643 A2644, B2644, C2644 +A2645, B2645, C2645 A2646, B2646, C2646 +A2647, B2647, C2647 +A2648, B2648, C2648 A2649, B2649, C2649 A2650, B2650, C2650 A2651, B2651, C2651 A2652, B2652, C2652 +A2653, B2653, C2653 +A2654, B2654, C2654 +A2655, B2655, C2655 +A2656, B2656, C2656 +A2657, B2657, C2657 +A2658, B2658, C2658 A2659, B2659, C2659 +A2660, B2660, C2660 +A2661, B2661, C2661 A2662, B2662, C2662 A2663, B2663, C2663 +A2664, B2664, C2664 A2665, B2665, C2665 +A2666, B2666, C2666 +A2667, B2667, C2667 A2668, B2668, C2668 +A2669, B2669, C2669 +A2670, B2670, C2670 +A2671, B2671, C2671 +A2672, B2672, C2672 +A2673, B2673, C2673 A2674, B2674, C2674 +A2675, B2675, C2675 A2676, B2676, C2676 +A2677, B2677, C2677 A2678, B2678, C2678 +A2679, B2679, C2679 A2680, B2680, C2680 +A2681, B2681, C2681 +A2682, B2682, C2682 +A2683, B2683, C2683 A2684, B2684, C2684 +A2685, B2685, C2685 A2686, B2686, C2686 +A2687, B2687, C2687 +A2688, B2688, C2688 +A2689, B2689, C2689 +A2690, B2690, C2690 +A2691, B2691, C2691 A2692, B2692, C2692 +A2693, B2693, C2693 A2694, B2694, C2694 A2695, B2695, C2695 A2696, B2696, C2696 +A2697, B2697, C2697 A2698, B2698, C2698 A2699, B2699, C2699 A2700, B2700, C2700 +A2701, B2701, C2701 A2702, B2702, C2702 +A2703, B2703, C2703 A2704, B2704, C2704 A2705, B2705, C2705 A2706, B2706, C2706 +A2707, B2707, C2707 +A2708, B2708, C2708 +A2709, B2709, C2709 +A2710, B2710, C2710 A2711, B2711, C2711 A2712, B2712, C2712 A2713, B2713, C2713 A2714, B2714, C2714 +A2715, B2715, C2715 +A2716, B2716, C2716 +A2717, B2717, C2717 +A2718, B2718, C2718 A2719, B2719, C2719 +A2720, B2720, C2720 +A2721, B2721, C2721 A2722, B2722, C2722 A2723, B2723, C2723 +A2724, B2724, C2724 +A2725, B2725, C2725 A2726, B2726, C2726 +A2727, B2727, C2727 +A2728, B2728, C2728 +A2729, B2729, C2729 A2730, B2730, C2730 +A2731, B2731, C2731 A2732, B2732, C2732 A2733, B2733, C2733 A2734, B2734, C2734 +A2735, B2735, C2735 +A2736, B2736, C2736 +A2737, B2737, C2737 +A2738, B2738, C2738 +A2739, B2739, C2739 +A2740, B2740, C2740 A2741, B2741, C2741 A2742, B2742, C2742 +A2743, B2743, C2743 A2744, B2744, C2744 A2745, B2745, C2745 +A2746, B2746, C2746 A2747, B2747, C2747 +A2748, B2748, C2748 A2749, B2749, C2749 +A2750, B2750, C2750 A2751, B2751, C2751 A2752, B2752, C2752 +A2753, B2753, C2753 +A2754, B2754, C2754 A2755, B2755, C2755 A2756, B2756, C2756 +A2757, B2757, C2757 +A2758, B2758, C2758 +A2759, B2759, C2759 +A2760, B2760, C2760 +A2761, B2761, C2761 +A2762, B2762, C2762 A2763, B2763, C2763 +A2764, B2764, C2764 A2765, B2765, C2765 A2766, B2766, C2766 +A2767, B2767, C2767 +A2768, B2768, C2768 A2769, B2769, C2769 +A2770, B2770, C2770 A2771, B2771, C2771 +A2772, B2772, C2772 A2773, B2773, C2773 +A2774, B2774, C2774 +A2775, B2775, C2775 +A2776, B2776, C2776 +A2777, B2777, C2777 A2778, B2778, C2778 +A2779, B2779, C2779 +A2780, B2780, C2780 +A2781, B2781, C2781 +A2782, B2782, C2782 +A2783, B2783, C2783 A2784, B2784, C2784 +A2785, B2785, C2785 +A2786, B2786, C2786 A2787, B2787, C2787 A2788, B2788, C2788 A2789, B2789, C2789 A2790, B2790, C2790 +A2791, B2791, C2791 +A2792, B2792, C2792 A2793, B2793, C2793 +A2794, B2794, C2794 +A2795, B2795, C2795 A2796, B2796, C2796 +A2797, B2797, C2797 +A2798, B2798, C2798 A2799, B2799, C2799 A2800, B2800, C2800 +A2801, B2801, C2801 +A2802, B2802, C2802 +A2803, B2803, C2803 A2804, B2804, C2804 A2805, B2805, C2805 +A2806, B2806, C2806 +A2807, B2807, C2807 +A2808, B2808, C2808 A2809, B2809, C2809 A2810, B2810, C2810 +A2811, B2811, C2811 A2812, B2812, C2812 +A2813, B2813, C2813 +A2814, B2814, C2814 +A2815, B2815, C2815 +A2816, B2816, C2816 A2817, B2817, C2817 +A2818, B2818, C2818 A2819, B2819, C2819 +A2820, B2820, C2820 A2821, B2821, C2821 A2822, B2822, C2822 +A2823, B2823, C2823 A2824, B2824, C2824 +A2825, B2825, C2825 A2826, B2826, C2826 +A2827, B2827, C2827 +A2828, B2828, C2828 +A2829, B2829, C2829 +A2830, B2830, C2830 +A2831, B2831, C2831 +A2832, B2832, C2832 +A2833, B2833, C2833 +A2834, B2834, C2834 +A2835, B2835, C2835 +A2836, B2836, C2836 +A2837, B2837, C2837 +A2838, B2838, C2838 +A2839, B2839, C2839 +A2840, B2840, C2840 +A2841, B2841, C2841 A2842, B2842, C2842 +A2843, B2843, C2843 +A2844, B2844, C2844 A2845, B2845, C2845 +A2846, B2846, C2846 +A2847, B2847, C2847 +A2848, B2848, C2848 +A2849, B2849, C2849 +A2850, B2850, C2850 +A2851, B2851, C2851 +A2852, B2852, C2852 +A2853, B2853, C2853 A2854, B2854, C2854 +A2855, B2855, C2855 +A2856, B2856, C2856 +A2857, B2857, C2857 +A2858, B2858, C2858 A2859, B2859, C2859 A2860, B2860, C2860 +A2861, B2861, C2861 +A2862, B2862, C2862 +A2863, B2863, C2863 +A2864, B2864, C2864 A2865, B2865, C2865 +A2866, B2866, C2866 +A2867, B2867, C2867 A2868, B2868, C2868 A2869, B2869, C2869 A2870, B2870, C2870 +A2871, B2871, C2871 A2872, B2872, C2872 +A2873, B2873, C2873 +A2874, B2874, C2874 +A2875, B2875, C2875 A2876, B2876, C2876 +A2877, B2877, C2877 A2878, B2878, C2878 +A2879, B2879, C2879 A2880, B2880, C2880 +A2881, B2881, C2881 A2882, B2882, C2882 A2883, B2883, C2883 A2884, B2884, C2884 +A2885, B2885, C2885 +A2886, B2886, C2886 +A2887, B2887, C2887 +A2888, B2888, C2888 +A2889, B2889, C2889 +A2890, B2890, C2890 +A2891, B2891, C2891 +A2892, B2892, C2892 +A2893, B2893, C2893 +A2894, B2894, C2894 +A2895, B2895, C2895 A2896, B2896, C2896 +A2897, B2897, C2897 +A2898, B2898, C2898 +A2899, B2899, C2899 +A2900, B2900, C2900 +A2901, B2901, C2901 A2902, B2902, C2902 +A2903, B2903, C2903 +A2904, B2904, C2904 A2905, B2905, C2905 +A2906, B2906, C2906 A2907, B2907, C2907 +A2908, B2908, C2908 A2909, B2909, C2909 +A2910, B2910, C2910 +A2911, B2911, C2911 A2912, B2912, C2912 +A2913, B2913, C2913 +A2914, B2914, C2914 A2915, B2915, C2915 +A2916, B2916, C2916 A2917, B2917, C2917 A2918, B2918, C2918 +A2919, B2919, C2919 +A2920, B2920, C2920 +A2921, B2921, C2921 A2922, B2922, C2922 A2923, B2923, C2923 +A2924, B2924, C2924 A2925, B2925, C2925 A2926, B2926, C2926 +A2927, B2927, C2927 A2928, B2928, C2928 A2929, B2929, C2929 A2930, B2930, C2930 A2931, B2931, C2931 +A2932, B2932, C2932 +A2933, B2933, C2933 +A2934, B2934, C2934 +A2935, B2935, C2935 +A2936, B2936, C2936 A2937, B2937, C2937 +A2938, B2938, C2938 +A2939, B2939, C2939 +A2940, B2940, C2940 +A2941, B2941, C2941 A2942, B2942, C2942 +A2943, B2943, C2943 +A2944, B2944, C2944 A2945, B2945, C2945 A2946, B2946, C2946 +A2947, B2947, C2947 +A2948, B2948, C2948 +A2949, B2949, C2949 +A2950, B2950, C2950 +A2951, B2951, C2951 +A2952, B2952, C2952 +A2953, B2953, C2953 +A2954, B2954, C2954 +A2955, B2955, C2955 A2956, B2956, C2956 +A2957, B2957, C2957 +A2958, B2958, C2958 +A2959, B2959, C2959 A2960, B2960, C2960 A2961, B2961, C2961 +A2962, B2962, C2962 +A2963, B2963, C2963 +A2964, B2964, C2964 A2965, B2965, C2965 A2966, B2966, C2966 +A2967, B2967, C2967 A2968, B2968, C2968 +A2969, B2969, C2969 +A2970, B2970, C2970 +A2971, B2971, C2971 A2972, B2972, C2972 A2973, B2973, C2973 +A2974, B2974, C2974 +A2975, B2975, C2975 +A2976, B2976, C2976 A2977, B2977, C2977 +A2978, B2978, C2978 +A2979, B2979, C2979 +A2980, B2980, C2980 +A2981, B2981, C2981 +A2982, B2982, C2982 A2983, B2983, C2983 +A2984, B2984, C2984 A2985, B2985, C2985 +A2986, B2986, C2986 +A2987, B2987, C2987 +A2988, B2988, C2988 +A2989, B2989, C2989 A2990, B2990, C2990 +A2991, B2991, C2991 +A2992, B2992, C2992 +A2993, B2993, C2993 +A2994, B2994, C2994 +A2995, B2995, C2995 +A2996, B2996, C2996 +A2997, B2997, C2997 A2998, B2998, C2998 A2999, B2999, C2999 +A3000, B3000, C3000 A3001, B3001, C3001 A3002, B3002, C3002 A3003, B3003, C3003 A3004, B3004, C3004 A3005, B3005, C3005 A3006, B3006, C3006 A3007, B3007, C3007 A3008, B3008, C3008 A3009, B3009, C3009 +A3010, B3010, C3010 +A3011, B3011, C3011 +A3012, B3012, C3012 A3013, B3013, C3013 A3014, B3014, C3014 A3015, B3015, C3015 +A3016, B3016, C3016 A3017, B3017, C3017 +A3018, B3018, C3018 +A3019, B3019, C3019 A3020, B3020, C3020 +A3021, B3021, C3021 A3022, B3022, C3022 +A3023, B3023, C3023 +A3024, B3024, C3024 A3025, B3025, C3025 +A3026, B3026, C3026 +A3027, B3027, C3027 A3028, B3028, C3028 A3029, B3029, C3029 +A3030, B3030, C3030 A3031, B3031, C3031 +A3032, B3032, C3032 A3033, B3033, C3033 A3034, B3034, C3034 +A3035, B3035, C3035 +A3036, B3036, C3036 +A3037, B3037, C3037 A3038, B3038, C3038 +A3039, B3039, C3039 A3040, B3040, C3040 +A3041, B3041, C3041 +A3042, B3042, C3042 +A3043, B3043, C3043 A3044, B3044, C3044 +A3045, B3045, C3045 +A3046, B3046, C3046 +A3047, B3047, C3047 +A3048, B3048, C3048 +A3049, B3049, C3049 +A3050, B3050, C3050 +A3051, B3051, C3051 +A3052, B3052, C3052 +A3053, B3053, C3053 A3054, B3054, C3054 A3055, B3055, C3055 A3056, B3056, C3056 +A3057, B3057, C3057 +A3058, B3058, C3058 +A3059, B3059, C3059 +A3060, B3060, C3060 A3061, B3061, C3061 +A3062, B3062, C3062 A3063, B3063, C3063 +A3064, B3064, C3064 +A3065, B3065, C3065 A3066, B3066, C3066 A3067, B3067, C3067 +A3068, B3068, C3068 +A3069, B3069, C3069 A3070, B3070, C3070 +A3071, B3071, C3071 +A3072, B3072, C3072 +A3073, B3073, C3073 +A3074, B3074, C3074 A3075, B3075, C3075 A3076, B3076, C3076 +A3077, B3077, C3077 +A3078, B3078, C3078 +A3079, B3079, C3079 +A3080, B3080, C3080 +A3081, B3081, C3081 +A3082, B3082, C3082 A3083, B3083, C3083 +A3084, B3084, C3084 +A3085, B3085, C3085 A3086, B3086, C3086 +A3087, B3087, C3087 +A3088, B3088, C3088 A3089, B3089, C3089 A3090, B3090, C3090 +A3091, B3091, C3091 A3092, B3092, C3092 A3093, B3093, C3093 +A3094, B3094, C3094 +A3095, B3095, C3095 +A3096, B3096, C3096 +A3097, B3097, C3097 A3098, B3098, C3098 +A3099, B3099, C3099 A3100, B3100, C3100 +A3101, B3101, C3101 +A3102, B3102, C3102 A3103, B3103, C3103 +A3104, B3104, C3104 +A3105, B3105, C3105 +A3106, B3106, C3106 A3107, B3107, C3107 +A3108, B3108, C3108 +A3109, B3109, C3109 +A3110, B3110, C3110 A3111, B3111, C3111 +A3112, B3112, C3112 +A3113, B3113, C3113 +A3114, B3114, C3114 A3115, B3115, C3115 +A3116, B3116, C3116 A3117, B3117, C3117 A3118, B3118, C3118 +A3119, B3119, C3119 +A3120, B3120, C3120 +A3121, B3121, C3121 A3122, B3122, C3122 +A3123, B3123, C3123 +A3124, B3124, C3124 +A3125, B3125, C3125 +A3126, B3126, C3126 +A3127, B3127, C3127 +A3128, B3128, C3128 +A3129, B3129, C3129 +A3130, B3130, C3130 +A3131, B3131, C3131 +A3132, B3132, C3132 +A3133, B3133, C3133 A3134, B3134, C3134 A3135, B3135, C3135 +A3136, B3136, C3136 A3137, B3137, C3137 A3138, B3138, C3138 +A3139, B3139, C3139 +A3140, B3140, C3140 +A3141, B3141, C3141 +A3142, B3142, C3142 +A3143, B3143, C3143 A3144, B3144, C3144 A3145, B3145, C3145 A3146, B3146, C3146 +A3147, B3147, C3147 A3148, B3148, C3148 +A3149, B3149, C3149 +A3150, B3150, C3150 +A3151, B3151, C3151 +A3152, B3152, C3152 +A3153, B3153, C3153 A3154, B3154, C3154 A3155, B3155, C3155 +A3156, B3156, C3156 A3157, B3157, C3157 +A3158, B3158, C3158 A3159, B3159, C3159 A3160, B3160, C3160 +A3161, B3161, C3161 +A3162, B3162, C3162 +A3163, B3163, C3163 A3164, B3164, C3164 +A3165, B3165, C3165 A3166, B3166, C3166 A3167, B3167, C3167 A3168, B3168, C3168 +A3169, B3169, C3169 +A3170, B3170, C3170 A3171, B3171, C3171 +A3172, B3172, C3172 +A3173, B3173, C3173 +A3174, B3174, C3174 A3175, B3175, C3175 +A3176, B3176, C3176 +A3177, B3177, C3177 A3178, B3178, C3178 A3179, B3179, C3179 A3180, B3180, C3180 +A3181, B3181, C3181 +A3182, B3182, C3182 +A3183, B3183, C3183 +A3184, B3184, C3184 +A3185, B3185, C3185 A3186, B3186, C3186 +A3187, B3187, C3187 +A3188, B3188, C3188 +A3189, B3189, C3189 +A3190, B3190, C3190 A3191, B3191, C3191 +A3192, B3192, C3192 A3193, B3193, C3193 +A3194, B3194, C3194 +A3195, B3195, C3195 +A3196, B3196, C3196 +A3197, B3197, C3197 A3198, B3198, C3198 A3199, B3199, C3199 +A3200, B3200, C3200 +A3201, B3201, C3201 +A3202, B3202, C3202 +A3203, B3203, C3203 A3204, B3204, C3204 A3205, B3205, C3205 +A3206, B3206, C3206 A3207, B3207, C3207 A3208, B3208, C3208 +A3209, B3209, C3209 A3210, B3210, C3210 +A3211, B3211, C3211 +A3212, B3212, C3212 A3213, B3213, C3213 +A3214, B3214, C3214 A3215, B3215, C3215 +A3216, B3216, C3216 +A3217, B3217, C3217 +A3218, B3218, C3218 +A3219, B3219, C3219 +A3220, B3220, C3220 A3221, B3221, C3221 +A3222, B3222, C3222 A3223, B3223, C3223 A3224, B3224, C3224 +A3225, B3225, C3225 +A3226, B3226, C3226 +A3227, B3227, C3227 +A3228, B3228, C3228 A3229, B3229, C3229 +A3230, B3230, C3230 +A3231, B3231, C3231 +A3232, B3232, C3232 +A3233, B3233, C3233 +A3234, B3234, C3234 A3235, B3235, C3235 +A3236, B3236, C3236 +A3237, B3237, C3237 +A3238, B3238, C3238 +A3239, B3239, C3239 +A3240, B3240, C3240 A3241, B3241, C3241 +A3242, B3242, C3242 +A3243, B3243, C3243 +A3244, B3244, C3244 A3245, B3245, C3245 A3246, B3246, C3246 A3247, B3247, C3247 +A3248, B3248, C3248 +A3249, B3249, C3249 +A3250, B3250, C3250 A3251, B3251, C3251 +A3252, B3252, C3252 +A3253, B3253, C3253 +A3254, B3254, C3254 A3255, B3255, C3255 A3256, B3256, C3256 A3257, B3257, C3257 +A3258, B3258, C3258 +A3259, B3259, C3259 A3260, B3260, C3260 +A3261, B3261, C3261 +A3262, B3262, C3262 A3263, B3263, C3263 +A3264, B3264, C3264 A3265, B3265, C3265 +A3266, B3266, C3266 A3267, B3267, C3267 +A3268, B3268, C3268 +A3269, B3269, C3269 +A3270, B3270, C3270 A3271, B3271, C3271 +A3272, B3272, C3272 A3273, B3273, C3273 +A3274, B3274, C3274 A3275, B3275, C3275 A3276, B3276, C3276 +A3277, B3277, C3277 A3278, B3278, C3278 A3279, B3279, C3279 A3280, B3280, C3280 +A3281, B3281, C3281 +A3282, B3282, C3282 +A3283, B3283, C3283 A3284, B3284, C3284 +A3285, B3285, C3285 +A3286, B3286, C3286 +A3287, B3287, C3287 A3288, B3288, C3288 +A3289, B3289, C3289 +A3290, B3290, C3290 +A3291, B3291, C3291 +A3292, B3292, C3292 +A3293, B3293, C3293 +A3294, B3294, C3294 +A3295, B3295, C3295 +A3296, B3296, C3296 A3297, B3297, C3297 +A3298, B3298, C3298 +A3299, B3299, C3299 A3300, B3300, C3300 +A3301, B3301, C3301 +A3302, B3302, C3302 +A3303, B3303, C3303 +A3304, B3304, C3304 A3305, B3305, C3305 +A3306, B3306, C3306 +A3307, B3307, C3307 +A3308, B3308, C3308 +A3309, B3309, C3309 +A3310, B3310, C3310 +A3311, B3311, C3311 A3312, B3312, C3312 A3313, B3313, C3313 +A3314, B3314, C3314 +A3315, B3315, C3315 +A3316, B3316, C3316 +A3317, B3317, C3317 +A3318, B3318, C3318 +A3319, B3319, C3319 +A3320, B3320, C3320 +A3321, B3321, C3321 +A3322, B3322, C3322 +A3323, B3323, C3323 A3324, B3324, C3324 A3325, B3325, C3325 +A3326, B3326, C3326 +A3327, B3327, C3327 +A3328, B3328, C3328 +A3329, B3329, C3329 +A3330, B3330, C3330 A3331, B3331, C3331 +A3332, B3332, C3332 +A3333, B3333, C3333 +A3334, B3334, C3334 +A3335, B3335, C3335 +A3336, B3336, C3336 +A3337, B3337, C3337 +A3338, B3338, C3338 +A3339, B3339, C3339 +A3340, B3340, C3340 +A3341, B3341, C3341 A3342, B3342, C3342 +A3343, B3343, C3343 A3344, B3344, C3344 A3345, B3345, C3345 +A3346, B3346, C3346 +A3347, B3347, C3347 +A3348, B3348, C3348 A3349, B3349, C3349 +A3350, B3350, C3350 A3351, B3351, C3351 +A3352, B3352, C3352 +A3353, B3353, C3353 A3354, B3354, C3354 +A3355, B3355, C3355 +A3356, B3356, C3356 +A3357, B3357, C3357 +A3358, B3358, C3358 A3359, B3359, C3359 +A3360, B3360, C3360 A3361, B3361, C3361 +A3362, B3362, C3362 +A3363, B3363, C3363 +A3364, B3364, C3364 +A3365, B3365, C3365 +A3366, B3366, C3366 +A3367, B3367, C3367 +A3368, B3368, C3368 +A3369, B3369, C3369 +A3370, B3370, C3370 +A3371, B3371, C3371 A3372, B3372, C3372 +A3373, B3373, C3373 +A3374, B3374, C3374 +A3375, B3375, C3375 +A3376, B3376, C3376 +A3377, B3377, C3377 +A3378, B3378, C3378 +A3379, B3379, C3379 +A3380, B3380, C3380 +A3381, B3381, C3381 A3382, B3382, C3382 A3383, B3383, C3383 +A3384, B3384, C3384 A3385, B3385, C3385 +A3386, B3386, C3386 A3387, B3387, C3387 A3388, B3388, C3388 +A3389, B3389, C3389 +A3390, B3390, C3390 +A3391, B3391, C3391 A3392, B3392, C3392 +A3393, B3393, C3393 A3394, B3394, C3394 A3395, B3395, C3395 +A3396, B3396, C3396 +A3397, B3397, C3397 A3398, B3398, C3398 +A3399, B3399, C3399 +A3400, B3400, C3400 +A3401, B3401, C3401 +A3402, B3402, C3402 +A3403, B3403, C3403 +A3404, B3404, C3404 +A3405, B3405, C3405 +A3406, B3406, C3406 +A3407, B3407, C3407 +A3408, B3408, C3408 +A3409, B3409, C3409 +A3410, B3410, C3410 +A3411, B3411, C3411 A3412, B3412, C3412 +A3413, B3413, C3413 A3414, B3414, C3414 +A3415, B3415, C3415 +A3416, B3416, C3416 A3417, B3417, C3417 +A3418, B3418, C3418 A3419, B3419, C3419 +A3420, B3420, C3420 +A3421, B3421, C3421 +A3422, B3422, C3422 A3423, B3423, C3423 A3424, B3424, C3424 +A3425, B3425, C3425 A3426, B3426, C3426 A3427, B3427, C3427 +A3428, B3428, C3428 +A3429, B3429, C3429 +A3430, B3430, C3430 +A3431, B3431, C3431 +A3432, B3432, C3432 +A3433, B3433, C3433 +A3434, B3434, C3434 A3435, B3435, C3435 A3436, B3436, C3436 +A3437, B3437, C3437 +A3438, B3438, C3438 +A3439, B3439, C3439 +A3440, B3440, C3440 +A3441, B3441, C3441 +A3442, B3442, C3442 +A3443, B3443, C3443 +A3444, B3444, C3444 +A3445, B3445, C3445 +A3446, B3446, C3446 +A3447, B3447, C3447 A3448, B3448, C3448 A3449, B3449, C3449 A3450, B3450, C3450 +A3451, B3451, C3451 +A3452, B3452, C3452 +A3453, B3453, C3453 +A3454, B3454, C3454 +A3455, B3455, C3455 A3456, B3456, C3456 +A3457, B3457, C3457 +A3458, B3458, C3458 +A3459, B3459, C3459 +A3460, B3460, C3460 A3461, B3461, C3461 +A3462, B3462, C3462 +A3463, B3463, C3463 +A3464, B3464, C3464 +A3465, B3465, C3465 +A3466, B3466, C3466 +A3467, B3467, C3467 +A3468, B3468, C3468 A3469, B3469, C3469 A3470, B3470, C3470 +A3471, B3471, C3471 +A3472, B3472, C3472 +A3473, B3473, C3473 A3474, B3474, C3474 +A3475, B3475, C3475 +A3476, B3476, C3476 A3477, B3477, C3477 +A3478, B3478, C3478 A3479, B3479, C3479 +A3480, B3480, C3480 +A3481, B3481, C3481 A3482, B3482, C3482 +A3483, B3483, C3483 +A3484, B3484, C3484 +A3485, B3485, C3485 +A3486, B3486, C3486 A3487, B3487, C3487 +A3488, B3488, C3488 +A3489, B3489, C3489 +A3490, B3490, C3490 +A3491, B3491, C3491 A3492, B3492, C3492 +A3493, B3493, C3493 +A3494, B3494, C3494 +A3495, B3495, C3495 +A3496, B3496, C3496 A3497, B3497, C3497 A3498, B3498, C3498 +A3499, B3499, C3499 +A3500, B3500, C3500 +A3501, B3501, C3501 A3502, B3502, C3502 A3503, B3503, C3503 +A3504, B3504, C3504 +A3505, B3505, C3505 +A3506, B3506, C3506 +A3507, B3507, C3507 +A3508, B3508, C3508 +A3509, B3509, C3509 +A3510, B3510, C3510 +A3511, B3511, C3511 +A3512, B3512, C3512 A3513, B3513, C3513 A3514, B3514, C3514 A3515, B3515, C3515 +A3516, B3516, C3516 +A3517, B3517, C3517 A3518, B3518, C3518 A3519, B3519, C3519 A3520, B3520, C3520 +A3521, B3521, C3521 +A3522, B3522, C3522 A3523, B3523, C3523 A3524, B3524, C3524 +A3525, B3525, C3525 +A3526, B3526, C3526 +A3527, B3527, C3527 +A3528, B3528, C3528 A3529, B3529, C3529 A3530, B3530, C3530 A3531, B3531, C3531 +A3532, B3532, C3532 +A3533, B3533, C3533 A3534, B3534, C3534 +A3535, B3535, C3535 +A3536, B3536, C3536 +A3537, B3537, C3537 +A3538, B3538, C3538 +A3539, B3539, C3539 +A3540, B3540, C3540 +A3541, B3541, C3541 +A3542, B3542, C3542 A3543, B3543, C3543 +A3544, B3544, C3544 +A3545, B3545, C3545 +A3546, B3546, C3546 +A3547, B3547, C3547 +A3548, B3548, C3548 A3549, B3549, C3549 A3550, B3550, C3550 A3551, B3551, C3551 +A3552, B3552, C3552 A3553, B3553, C3553 A3554, B3554, C3554 A3555, B3555, C3555 +A3556, B3556, C3556 +A3557, B3557, C3557 +A3558, B3558, C3558 A3559, B3559, C3559 A3560, B3560, C3560 A3561, B3561, C3561 +A3562, B3562, C3562 +A3563, B3563, C3563 +A3564, B3564, C3564 A3565, B3565, C3565 A3566, B3566, C3566 +A3567, B3567, C3567 +A3568, B3568, C3568 +A3569, B3569, C3569 A3570, B3570, C3570 +A3571, B3571, C3571 A3572, B3572, C3572 A3573, B3573, C3573 +A3574, B3574, C3574 A3575, B3575, C3575 +A3576, B3576, C3576 +A3577, B3577, C3577 +A3578, B3578, C3578 A3579, B3579, C3579 A3580, B3580, C3580 +A3581, B3581, C3581 +A3582, B3582, C3582 +A3583, B3583, C3583 +A3584, B3584, C3584 +A3585, B3585, C3585 +A3586, B3586, C3586 +A3587, B3587, C3587 +A3588, B3588, C3588 +A3589, B3589, C3589 +A3590, B3590, C3590 +A3591, B3591, C3591 +A3592, B3592, C3592 +A3593, B3593, C3593 A3594, B3594, C3594 A3595, B3595, C3595 A3596, B3596, C3596 A3597, B3597, C3597 +A3598, B3598, C3598 A3599, B3599, C3599 +A3600, B3600, C3600 A3601, B3601, C3601 A3602, B3602, C3602 +A3603, B3603, C3603 A3604, B3604, C3604 +A3605, B3605, C3605 +A3606, B3606, C3606 +A3607, B3607, C3607 A3608, B3608, C3608 A3609, B3609, C3609 +A3610, B3610, C3610 +A3611, B3611, C3611 +A3612, B3612, C3612 +A3613, B3613, C3613 +A3614, B3614, C3614 +A3615, B3615, C3615 +A3616, B3616, C3616 +A3617, B3617, C3617 +A3618, B3618, C3618 +A3619, B3619, C3619 A3620, B3620, C3620 A3621, B3621, C3621 +A3622, B3622, C3622 A3623, B3623, C3623 +A3624, B3624, C3624 +A3625, B3625, C3625 A3626, B3626, C3626 +A3627, B3627, C3627 A3628, B3628, C3628 A3629, B3629, C3629 A3630, B3630, C3630 +A3631, B3631, C3631 A3632, B3632, C3632 +A3633, B3633, C3633 +A3634, B3634, C3634 +A3635, B3635, C3635 A3636, B3636, C3636 A3637, B3637, C3637 A3638, B3638, C3638 A3639, B3639, C3639 +A3640, B3640, C3640 +A3641, B3641, C3641 +A3642, B3642, C3642 +A3643, B3643, C3643 +A3644, B3644, C3644 A3645, B3645, C3645 +A3646, B3646, C3646 A3647, B3647, C3647 +A3648, B3648, C3648 A3649, B3649, C3649 +A3650, B3650, C3650 +A3651, B3651, C3651 +A3652, B3652, C3652 +A3653, B3653, C3653 +A3654, B3654, C3654 +A3655, B3655, C3655 +A3656, B3656, C3656 +A3657, B3657, C3657 A3658, B3658, C3658 A3659, B3659, C3659 +A3660, B3660, C3660 +A3661, B3661, C3661 +A3662, B3662, C3662 A3663, B3663, C3663 +A3664, B3664, C3664 A3665, B3665, C3665 +A3666, B3666, C3666 +A3667, B3667, C3667 +A3668, B3668, C3668 +A3669, B3669, C3669 A3670, B3670, C3670 +A3671, B3671, C3671 +A3672, B3672, C3672 +A3673, B3673, C3673 A3674, B3674, C3674 +A3675, B3675, C3675 +A3676, B3676, C3676 A3677, B3677, C3677 +A3678, B3678, C3678 +A3679, B3679, C3679 A3680, B3680, C3680 +A3681, B3681, C3681 +A3682, B3682, C3682 A3683, B3683, C3683 A3684, B3684, C3684 +A3685, B3685, C3685 +A3686, B3686, C3686 A3687, B3687, C3687 A3688, B3688, C3688 +A3689, B3689, C3689 +A3690, B3690, C3690 A3691, B3691, C3691 A3692, B3692, C3692 A3693, B3693, C3693 A3694, B3694, C3694 +A3695, B3695, C3695 +A3696, B3696, C3696 A3697, B3697, C3697 +A3698, B3698, C3698 A3699, B3699, C3699 +A3700, B3700, C3700 +A3701, B3701, C3701 +A3702, B3702, C3702 +A3703, B3703, C3703 +A3704, B3704, C3704 +A3705, B3705, C3705 +A3706, B3706, C3706 A3707, B3707, C3707 +A3708, B3708, C3708 +A3709, B3709, C3709 +A3710, B3710, C3710 A3711, B3711, C3711 +A3712, B3712, C3712 +A3713, B3713, C3713 +A3714, B3714, C3714 +A3715, B3715, C3715 +A3716, B3716, C3716 +A3717, B3717, C3717 A3718, B3718, C3718 A3719, B3719, C3719 A3720, B3720, C3720 A3721, B3721, C3721 +A3722, B3722, C3722 +A3723, B3723, C3723 +A3724, B3724, C3724 +A3725, B3725, C3725 A3726, B3726, C3726 A3727, B3727, C3727 +A3728, B3728, C3728 +A3729, B3729, C3729 +A3730, B3730, C3730 A3731, B3731, C3731 A3732, B3732, C3732 +A3733, B3733, C3733 A3734, B3734, C3734 +A3735, B3735, C3735 A3736, B3736, C3736 A3737, B3737, C3737 A3738, B3738, C3738 A3739, B3739, C3739 A3740, B3740, C3740 +A3741, B3741, C3741 +A3742, B3742, C3742 +A3743, B3743, C3743 +A3744, B3744, C3744 +A3745, B3745, C3745 +A3746, B3746, C3746 A3747, B3747, C3747 +A3748, B3748, C3748 +A3749, B3749, C3749 A3750, B3750, C3750 +A3751, B3751, C3751 +A3752, B3752, C3752 A3753, B3753, C3753 +A3754, B3754, C3754 +A3755, B3755, C3755 +A3756, B3756, C3756 +A3757, B3757, C3757 +A3758, B3758, C3758 +A3759, B3759, C3759 +A3760, B3760, C3760 A3761, B3761, C3761 A3762, B3762, C3762 +A3763, B3763, C3763 A3764, B3764, C3764 +A3765, B3765, C3765 +A3766, B3766, C3766 +A3767, B3767, C3767 A3768, B3768, C3768 +A3769, B3769, C3769 A3770, B3770, C3770 +A3771, B3771, C3771 +A3772, B3772, C3772 A3773, B3773, C3773 +A3774, B3774, C3774 +A3775, B3775, C3775 +A3776, B3776, C3776 +A3777, B3777, C3777 +A3778, B3778, C3778 A3779, B3779, C3779 +A3780, B3780, C3780 A3781, B3781, C3781 +A3782, B3782, C3782 +A3783, B3783, C3783 +A3784, B3784, C3784 A3785, B3785, C3785 +A3786, B3786, C3786 A3787, B3787, C3787 A3788, B3788, C3788 A3789, B3789, C3789 A3790, B3790, C3790 +A3791, B3791, C3791 A3792, B3792, C3792 +A3793, B3793, C3793 +A3794, B3794, C3794 A3795, B3795, C3795 +A3796, B3796, C3796 +A3797, B3797, C3797 +A3798, B3798, C3798 +A3799, B3799, C3799 A3800, B3800, C3800 A3801, B3801, C3801 A3802, B3802, C3802 A3803, B3803, C3803 +A3804, B3804, C3804 +A3805, B3805, C3805 +A3806, B3806, C3806 +A3807, B3807, C3807 A3808, B3808, C3808 A3809, B3809, C3809 +A3810, B3810, C3810 A3811, B3811, C3811 A3812, B3812, C3812 +A3813, B3813, C3813 A3814, B3814, C3814 +A3815, B3815, C3815 A3816, B3816, C3816 A3817, B3817, C3817 +A3818, B3818, C3818 +A3819, B3819, C3819 A3820, B3820, C3820 A3821, B3821, C3821 +A3822, B3822, C3822 +A3823, B3823, C3823 +A3824, B3824, C3824 +A3825, B3825, C3825 +A3826, B3826, C3826 +A3827, B3827, C3827 +A3828, B3828, C3828 A3829, B3829, C3829 +A3830, B3830, C3830 +A3831, B3831, C3831 +A3832, B3832, C3832 +A3833, B3833, C3833 +A3834, B3834, C3834 A3835, B3835, C3835 A3836, B3836, C3836 A3837, B3837, C3837 +A3838, B3838, C3838 +A3839, B3839, C3839 +A3840, B3840, C3840 A3841, B3841, C3841 +A3842, B3842, C3842 +A3843, B3843, C3843 +A3844, B3844, C3844 +A3845, B3845, C3845 +A3846, B3846, C3846 A3847, B3847, C3847 A3848, B3848, C3848 +A3849, B3849, C3849 +A3850, B3850, C3850 +A3851, B3851, C3851 +A3852, B3852, C3852 +A3853, B3853, C3853 +A3854, B3854, C3854 +A3855, B3855, C3855 +A3856, B3856, C3856 +A3857, B3857, C3857 +A3858, B3858, C3858 +A3859, B3859, C3859 +A3860, B3860, C3860 +A3861, B3861, C3861 +A3862, B3862, C3862 A3863, B3863, C3863 A3864, B3864, C3864 A3865, B3865, C3865 A3866, B3866, C3866 +A3867, B3867, C3867 +A3868, B3868, C3868 A3869, B3869, C3869 +A3870, B3870, C3870 +A3871, B3871, C3871 A3872, B3872, C3872 +A3873, B3873, C3873 +A3874, B3874, C3874 A3875, B3875, C3875 +A3876, B3876, C3876 A3877, B3877, C3877 +A3878, B3878, C3878 +A3879, B3879, C3879 +A3880, B3880, C3880 +A3881, B3881, C3881 +A3882, B3882, C3882 +A3883, B3883, C3883 +A3884, B3884, C3884 A3885, B3885, C3885 A3886, B3886, C3886 A3887, B3887, C3887 +A3888, B3888, C3888 +A3889, B3889, C3889 +A3890, B3890, C3890 A3891, B3891, C3891 +A3892, B3892, C3892 +A3893, B3893, C3893 +A3894, B3894, C3894 +A3895, B3895, C3895 A3896, B3896, C3896 +A3897, B3897, C3897 +A3898, B3898, C3898 +A3899, B3899, C3899 +A3900, B3900, C3900 A3901, B3901, C3901 +A3902, B3902, C3902 +A3903, B3903, C3903 A3904, B3904, C3904 +A3905, B3905, C3905 A3906, B3906, C3906 +A3907, B3907, C3907 +A3908, B3908, C3908 +A3909, B3909, C3909 +A3910, B3910, C3910 +A3911, B3911, C3911 A3912, B3912, C3912 +A3913, B3913, C3913 +A3914, B3914, C3914 +A3915, B3915, C3915 +A3916, B3916, C3916 +A3917, B3917, C3917 +A3918, B3918, C3918 +A3919, B3919, C3919 A3920, B3920, C3920 +A3921, B3921, C3921 +A3922, B3922, C3922 +A3923, B3923, C3923 +A3924, B3924, C3924 +A3925, B3925, C3925 +A3926, B3926, C3926 A3927, B3927, C3927 +A3928, B3928, C3928 A3929, B3929, C3929 A3930, B3930, C3930 A3931, B3931, C3931 +A3932, B3932, C3932 A3933, B3933, C3933 +A3934, B3934, C3934 +A3935, B3935, C3935 +A3936, B3936, C3936 +A3937, B3937, C3937 A3938, B3938, C3938 A3939, B3939, C3939 +A3940, B3940, C3940 +A3941, B3941, C3941 A3942, B3942, C3942 +A3943, B3943, C3943 A3944, B3944, C3944 +A3945, B3945, C3945 +A3946, B3946, C3946 +A3947, B3947, C3947 +A3948, B3948, C3948 +A3949, B3949, C3949 +A3950, B3950, C3950 A3951, B3951, C3951 +A3952, B3952, C3952 +A3953, B3953, C3953 A3954, B3954, C3954 +A3955, B3955, C3955 +A3956, B3956, C3956 +A3957, B3957, C3957 A3958, B3958, C3958 A3959, B3959, C3959 A3960, B3960, C3960 +A3961, B3961, C3961 +A3962, B3962, C3962 +A3963, B3963, C3963 A3964, B3964, C3964 +A3965, B3965, C3965 A3966, B3966, C3966 A3967, B3967, C3967 +A3968, B3968, C3968 A3969, B3969, C3969 A3970, B3970, C3970 +A3971, B3971, C3971 +A3972, B3972, C3972 +A3973, B3973, C3973 +A3974, B3974, C3974 +A3975, B3975, C3975 A3976, B3976, C3976 A3977, B3977, C3977 +A3978, B3978, C3978 +A3979, B3979, C3979 +A3980, B3980, C3980 +A3981, B3981, C3981 +A3982, B3982, C3982 +A3983, B3983, C3983 A3984, B3984, C3984 A3985, B3985, C3985 +A3986, B3986, C3986 +A3987, B3987, C3987 A3988, B3988, C3988 +A3989, B3989, C3989 +A3990, B3990, C3990 A3991, B3991, C3991 A3992, B3992, C3992 +A3993, B3993, C3993 A3994, B3994, C3994 +A3995, B3995, C3995 +A3996, B3996, C3996 +A3997, B3997, C3997 A3998, B3998, C3998 A3999, B3999, C3999 +A4000, B4000, C4000 A4001, B4001, C4001 +A4002, B4002, C4002 A4003, B4003, C4003 +A4004, B4004, C4004 +A4005, B4005, C4005 +A4006, B4006, C4006 +A4007, B4007, C4007 +A4008, B4008, C4008 +A4009, B4009, C4009 +A4010, B4010, C4010 A4011, B4011, C4011 +A4012, B4012, C4012 +A4013, B4013, C4013 A4014, B4014, C4014 +A4015, B4015, C4015 +A4016, B4016, C4016 A4017, B4017, C4017 A4018, B4018, C4018 +A4019, B4019, C4019 +A4020, B4020, C4020 +A4021, B4021, C4021 A4022, B4022, C4022 +A4023, B4023, C4023 A4024, B4024, C4024 A4025, B4025, C4025 A4026, B4026, C4026 +A4027, B4027, C4027 +A4028, B4028, C4028 +A4029, B4029, C4029 A4030, B4030, C4030 A4031, B4031, C4031 +A4032, B4032, C4032 +A4033, B4033, C4033 A4034, B4034, C4034 +A4035, B4035, C4035 A4036, B4036, C4036 A4037, B4037, C4037 +A4038, B4038, C4038 A4039, B4039, C4039 +A4040, B4040, C4040 +A4041, B4041, C4041 A4042, B4042, C4042 +A4043, B4043, C4043 A4044, B4044, C4044 +A4045, B4045, C4045 +A4046, B4046, C4046 +A4047, B4047, C4047 +A4048, B4048, C4048 +A4049, B4049, C4049 A4050, B4050, C4050 +A4051, B4051, C4051 +A4052, B4052, C4052 A4053, B4053, C4053 A4054, B4054, C4054 A4055, B4055, C4055 +A4056, B4056, C4056 +A4057, B4057, C4057 A4058, B4058, C4058 A4059, B4059, C4059 A4060, B4060, C4060 A4061, B4061, C4061 A4062, B4062, C4062 +A4063, B4063, C4063 +A4064, B4064, C4064 +A4065, B4065, C4065 +A4066, B4066, C4066 A4067, B4067, C4067 A4068, B4068, C4068 +A4069, B4069, C4069 +A4070, B4070, C4070 +A4071, B4071, C4071 A4072, B4072, C4072 +A4073, B4073, C4073 +A4074, B4074, C4074 +A4075, B4075, C4075 A4076, B4076, C4076 +A4077, B4077, C4077 +A4078, B4078, C4078 A4079, B4079, C4079 +A4080, B4080, C4080 +A4081, B4081, C4081 A4082, B4082, C4082 +A4083, B4083, C4083 +A4084, B4084, C4084 +A4085, B4085, C4085 +A4086, B4086, C4086 +A4087, B4087, C4087 A4088, B4088, C4088 +A4089, B4089, C4089 +A4090, B4090, C4090 +A4091, B4091, C4091 +A4092, B4092, C4092 +A4093, B4093, C4093 +A4094, B4094, C4094 +A4095, B4095, C4095 +A4096, B4096, C4096 diff --git a/include/zsv/utils/index.h b/include/zsv/utils/index.h index b9466a7d..9735fc40 100644 --- a/include/zsv/utils/index.h +++ b/include/zsv/utils/index.h @@ -2,8 +2,7 @@ #define ZSV_UTILS_INDEX_H #include -#include -#include +#include #include "zsv/common.h" @@ -24,20 +23,25 @@ enum zsv_index_status { struct zsv_index_array { size_t capacity; size_t len; + struct zsv_index_array *next; uint64_t u64s[]; }; struct zsv_index { uint64_t header_line_end; + // Reading and writing should be protected with a lock uint64_t row_count; + // Should only be updated by the thread building the index + uint64_t row_count_local; // array containing the offsets of every ZSV_INDEX_ROW_N line end - struct zsv_index_array *array; + struct zsv_index_array *first; }; struct zsv_index *zsv_index_new(void); void zsv_index_delete(struct zsv_index *ix); -enum zsv_index_status zsv_index_add_row(struct zsv_index *ix, zsv_parser parser); +enum zsv_index_status zsv_index_add_row(struct zsv_index *ix, uint64_t line_end); +void zsv_index_commit_rows(struct zsv_index *ix); enum zsv_index_status zsv_index_row_end_offset(const struct zsv_index *ix, uint64_t row, uint64_t *offset_out, uint64_t *remaining_rows_out); enum zsv_index_status zsv_index_seek_row(const struct zsv_index *ix, struct zsv_opts *opts, uint64_t row); diff --git a/include/zsv/utils/writer.h b/include/zsv/utils/writer.h index e9a0a9d0..7727522e 100644 --- a/include/zsv/utils/writer.h +++ b/include/zsv/utils/writer.h @@ -26,6 +26,7 @@ struct zsv_csv_writer_options { void (*table_init)(void *); void *table_init_ctx; const char *output_path; // if provided, will be created by zsv_writer_new() and closed by zsv_writer_delete() + struct zsv_index *index; }; void zsv_writer_set_default_opts(struct zsv_csv_writer_options opts); diff --git a/scripts/test-expect.sh b/scripts/test-expect.sh new file mode 100755 index 00000000..92aad22f --- /dev/null +++ b/scripts/test-expect.sh @@ -0,0 +1,49 @@ +#!/bin/sh -eu + +script_dir=$(dirname "$0") + +export TARGET="$1" +if [ -z "${2:-}" ]; then + export STAGE="" +else + export STAGE=-"$2" +fi +export CAPTURE="${TMP_DIR}/$TARGET$STAGE".out +EXPECTED="$EXPECTED_PATH/$TARGET$STAGE".out +export EXPECTED +matched=false + +t=${EXPECT_TIMEOUT:-5} + +cleanup() { + if $matched; then + if [ -z "$STAGE" ]; then + tmux send-keys -t "$TARGET" "q" + fi + exit 0 + fi + + tmux send-keys -t "$TARGET" "q" + echo 'Incorrect output:' + cat "$CAPTURE" + ${CMP} -s "$CAPTURE" "$EXPECTED" + exit 1 +} + +trap cleanup INT TERM QUIT + +printf "\n%s, %s" "$TARGET" "${2:-}" >> "${TIMINGS_CSV}" + +set +e +match_time=$(time -p timeout -k $(( t + 1 )) $t "${script_dir}"/test-retry-capture-cmp.sh 2>&1) +status=$? +set -e + +if [ $status -eq 0 ]; then + matched=true + match_time=$(echo "$match_time" | head -n 1 | cut -f 2 -d ' ') + echo "$TARGET$STAGE took $match_time" + printf ", %s" "$match_time" >> "${TIMINGS_CSV}" +fi + +cleanup diff --git a/scripts/test-retry-capture-cmp.sh b/scripts/test-retry-capture-cmp.sh new file mode 100755 index 00000000..3fc46073 --- /dev/null +++ b/scripts/test-retry-capture-cmp.sh @@ -0,0 +1,12 @@ +#!/bin/sh -eu + +while true; do + tmux capture-pane -t "$TARGET" -p > "$CAPTURE" + + if ${CMP} -s "$CAPTURE" "$EXPECTED"; then + exit 0 + fi + + sleep 0.025 +done +