static void setuptables(void) { unsigned int i; int *c = pt; memory_clear(pml4t, 0x1000); memory_clear(pml4t, 0x1000); memory_clear(pdt, 0x1000); memory_clear(pt, 0x200000); pml4t[0] = (unsigned int)pdpt | 3; pdpt[0] = (unsigned int)pdt | 3; pdt[0] = (unsigned int)pt | 3; for (i = 0; i < 512; i++) { *c = (i * 0x1000) | 3; c++; *c = 0; c++; } }
void dino_http_start(dino_http_site_t *dino_site) { if (NULL == dino_site) { fprintf(stderr, "[ERROR] The site is not defined..\n\r"); return; } struct sockaddr_in sockaddr_client; socklen_t sockaddr_client_length = sizeof(sockaddr_client); memory_clear(&sockaddr_client, sockaddr_client_length); memory_cache_alloc(1024 * 16); g_server_socket = startup_connection(dino_site); if (-1 != g_server_socket) { fprintf(stdout, "[INFO] Dino has taking the stage on port %d\n\r", dino_site->port); while (g_dino_keep_running) { int client_socket = accept(g_server_socket, (struct sockaddr *) &sockaddr_client, &sockaddr_client_length); dino_process_request(dino_site, client_socket); } close(g_server_socket); } memory_cache_free(); }
void init_request(dino_handle_t *dhandle) { memory_clear(dhandle, sizeof(dino_handle_t)); dhandle->http.handle_type = dino_handle_http; dhandle->http.request.params_map = dino_strmap_new(32); dhandle->http.response.params_map = dino_strmap_new(32); }
void memory_cache_alloc(size_t n) { if (NULL == g_mem_cache) { g_mem_cache = malloc(sizeof(memory_cache_t)); memory_clear(g_mem_cache, sizeof(memory_cache_t)); g_mem_cache->buffer = malloc(n); g_mem_cache->size = n; g_mem_cache->freed = n; } }
void DINO_EXPORT params_enumerate(DHANDLE dhandle, dino_enum_func callback, const void *obj) { dino_http_request_t *request = cast_dhandle_request(dhandle); if (NULL != request) { dino_callback_param_t callback_data; memory_clear(&callback_data, sizeof(dino_callback_param_t)); callback_data.callback = callback; callback_data.dhandle = dhandle; callback_data.obj = obj; dino_strmap_enum(request->params_map, param_enum, &callback_data); } }
size_t read_data(int socket, char *data, size_t size) { memory_clear(data, size); size_t i = 0; char c = '\0'; while (i < size) { ssize_t n = recv(socket, &c, 1, 0); if (n > 0) { data[i] = c; ++i; } } return i; }
void *memory_alloc(size_t n) { void *p = NULL; // See if it will fit in the cache: // if (NULL != g_mem_cache && n < g_mem_cache->freed) { p = g_mem_cache->buffer + (g_mem_cache->size - g_mem_cache->freed); g_mem_cache->freed -= n; } else { // If not allocate from memory. // p = malloc(n); } return memory_clear(p, n); }
int main() { setbuf(stdout, NULL); int T, tc, i, j; scanf("%d", &T); for (tc = 1; tc <= T; tc++) { // inputs: scanf("%s %d", qKey, &wNum); // solve: 1. create total min/max int min = 0, max = 0; for (i = 0; qKey[i]; i++) { int x = qKey[i] - '0'; min += a[x - 2][0]; max += a[x - 2][1]; } //printf("%d %d\n", min, max); // solve: 2. check boundary int valid_w_cnt = 0; for (i = 0; i < wNum; i++) { scanf("%s", dWord); //printf("%s\n", dWord); int sum = 0; for (j = 0; dWord[j]; sum += dWord[j], j++); //printf("%d\n", sum); if (min <= sum && sum <= max) valid_w_cnt++; } // outouts: printf("#%d %d\n", tc, valid_w_cnt); // clear buffer memory_clear(); } return 0; }
dino_http_method parse_method_url(dino_http_data_t *http) { // Should not happen: // if (NULL == http) { return http_invalid; } // Read in the data: // STRING_BUFFER_PTR string_buffer_ptr = NULL; if (0 == read_line(http->socket, &string_buffer_ptr)) { string_buffer_delete(string_buffer_ptr, true); return http_invalid; } // Obtain the method // char method[32]; memory_clear(method, sizeof(method)); int offset = 0; const char *line = string_buffer_c_string(string_buffer_ptr); for (int i = 0; !isspace(line[i]) && (i < sizeof(method)); i++) { method[i] = line[i]; offset++; } http->request.method = map_string_to_http_method(method); if (http_invalid == http->request.method) { string_buffer_delete(string_buffer_ptr, true); return http_invalid; } // Fetch the URL // const char *query = line + offset; STRING_BUFFER_PTR buffer_url = string_buffer_new(); // Skip over the ' 's and the tabs // while (*query != '\0' && (*query == ' ' || *query == '\t')) { ++query; } while (*query != '\0' && *query != '?' && *query != ' ' && *query != '\t') { string_buffer_append_char(buffer_url, *query); query++; } http->request.url = buffer_url; if (*query == '?') { // Move off of '?' // query++; offset = 0; STRING_BUFFER_PTR buffer_params = string_buffer_new(); while (!isspace(*query) && *query != 0) { string_buffer_append_char(buffer_params, *query); offset++; query++; } // Parse the URL parameters // char *break_token = NULL; for (char *param = strtok_r(string_buffer_c_string(buffer_params), "&", &break_token); param; param = strtok_r(NULL, "&", &break_token)) { char *break_token_2 = NULL; char *key = strtok_r(param, "=", &break_token_2); char *value = strtok_r(NULL, "=", &break_token_2); dino_strmap_add(http->request.params_map, key, value); } string_buffer_delete(buffer_params, true); } string_buffer_delete(string_buffer_ptr, true); return http->request.method; }
int read_elf(char *filename, struct _memory *memory, uint8_t *cpu_type, struct _symbols *symbols) { FILE *in; uint8_t e_ident[16]; int e_shoff; int e_shentsize; int e_shnum; int e_shstrndx; int n; int start, end; struct _elf32_shdr elf32_shdr; long strtab_offset = 0; get_int16_t get_int16; get_int32_t get_int32; memory_clear(memory); //memset(dirty, 0, memory->size); start = -1; end = -1; in = fopen(filename, "rb"); if (in == 0) { return -1; } memset(e_ident, 0, 16); n = fread(e_ident, 1, 16, in); if (e_ident[0] != 0x7f || e_ident[1] != 'E' || e_ident[2] != 'L' || e_ident[3] != 'F') { //printf("Not an ELF file.\n"); fclose(in); return -2; } #define EI_CLASS 4 // 1=32 bit, 2=64 bit #define EI_DATA 5 // 1=little endian, 2=big endian #define EI_OSABI 7 // 0=SysV, 255=Embedded if (e_ident[EI_CLASS] != 1) // let's let other stuff in || e_ident[7]!=0xff) { printf("ELF Error: e_ident shows incorrect type\n"); fclose(in); return -1; } // EI_DATA if (e_ident[EI_DATA] == 1) { memory->endian = ENDIAN_LITTLE; get_int16 = get_int16_le; get_int32 = get_int32_le; } else if (e_ident[EI_DATA] == 2) { memory->endian = ENDIAN_BIG; get_int16 = get_int16_be; get_int32 = get_int32_be; } else { printf("ELF Error: EI_DATA incorrect data encoding\n"); fclose(in); return -1; } get_int16(in); n = get_int16(in); switch(n) { case 8: case 10: *cpu_type = CPU_TYPE_MIPS; break; case 40: *cpu_type = CPU_TYPE_ARM; break; case 83: *cpu_type = CPU_TYPE_AVR8; break; case 105: *cpu_type = CPU_TYPE_MSP430; break; case 118: *cpu_type = CPU_TYPE_DSPIC; break; default: printf("ELF Error: e_machine unknown\n"); fclose(in); return -1; } fseek(in, 32, SEEK_SET); e_shoff = get_int32(in); fseek(in, 46, SEEK_SET); e_shentsize = get_int16(in); e_shnum = get_int16(in); e_shstrndx = get_int16(in); //printf("e_shoff=%d\n", e_shoff); //printf("e_shentsize=%d\n", e_shentsize); //printf("e_shnum=%d\n", e_shnum); //printf("e_shstrndx=%d\n", e_shstrndx); fseek(in, e_shoff + (e_shstrndx * e_shentsize) + 16, SEEK_SET); int stroffset = get_int32(in); char name[32]; // Need to find .strtab so we can fill in symbol names for (n = 0; n < e_shnum; n++) { fseek(in, e_shoff + (n * e_shentsize), SEEK_SET); read_shdr(in, &elf32_shdr, get_int32); if (elf32_shdr.sh_type == SHT_STRTAB) { read_name(in, name, 32, stroffset + elf32_shdr.sh_name); if (strcmp(name, ".strtab") == 0) { strtab_offset = elf32_shdr.sh_offset; break; } } } for (n = 0; n < e_shnum; n++) { // FIXME - a little inefficient eh? fseek(in, e_shoff + (n * e_shentsize), SEEK_SET); read_shdr(in, &elf32_shdr, get_int32); read_name(in, name, 32, stroffset + elf32_shdr.sh_name); //printf("name=%s\n", name); //int is_text = strncmp(name, ".text", 5) == 0 ? 1 : 0; int is_text = (elf32_shdr.sh_flags & SHF_EXECINSTR) != 0 ? 1 : 0; if (is_text || strncmp(name, ".data", 5) == 0 || strcmp(name, ".vectors") == 0) { if (is_text) { if (start == -1) { start = elf32_shdr.sh_addr; } else if (start > elf32_shdr.sh_addr) { start = elf32_shdr.sh_addr; } if (end == -1) { end = elf32_shdr.sh_addr + elf32_shdr.sh_size - 1; } else if (end < elf32_shdr.sh_addr + elf32_shdr.sh_size) { end = elf32_shdr.sh_addr+elf32_shdr.sh_size - 1; } } long marker = ftell(in); fseek(in, elf32_shdr.sh_offset, SEEK_SET); int n; for (n = 0; n < elf32_shdr.sh_size; n++) { if (elf32_shdr.sh_addr + n >= memory->size) break; memory_write_m(memory, elf32_shdr.sh_addr + n, getc(in)); } fseek(in, marker, SEEK_SET); printf("Loaded %d %s bytes from 0x%04x\n", n, name, elf32_shdr.sh_addr); } else if (elf32_shdr.sh_type == SHT_SYMTAB && symbols != NULL) { long marker = ftell(in); fseek(in, elf32_shdr.sh_offset, SEEK_SET); for (n = 0; n < elf32_shdr.sh_size; n += 16) { char name[128]; struct _elf32_sym elf32_sym; elf32_sym.st_name = get_int32(in); elf32_sym.st_value = get_int32(in); elf32_sym.st_size = get_int32(in); elf32_sym.st_info = getc(in); elf32_sym.st_other = getc(in); elf32_sym.st_shndx = get_int16(in); read_name(in, name, 128, strtab_offset + elf32_sym.st_name); printf("symbol %12s 0x%04x\n", name, elf32_sym.st_value); if (elf32_sym.st_info != STT_NOTYPE && elf32_sym.st_info != STT_SECTION && elf32_sym.st_info != STT_FILE) { symbols_append(symbols, name, elf32_sym.st_value); } } fseek(in, marker, SEEK_SET); } } memory->low_address = start; memory->high_address = end; fclose(in); return start; }
void main(void) { ////////////////////// TMUNUM_INFO xx; TMUNUM_INFO yy; /////////////////////////// unsigned char index; static unsigned char num_byte = 0; char y =0; EA = 0; Soft_WDT_Disnable(); mcu_f340_init(); delay_ms(10); var_init(); fmu_cmd_init(); uart1_init(); #ifdef ID_ONE_WIRE one_wire_init( ONE_WIRE_STANDARD_SPEED); #endif delay_ms(10); tmu_address_init(); EA = 1; WatchDog_Init(); index = 0; countnum = 0; port_num = 0; while(1) { xx.c[0] = 2; xx.c[1] = 2; xx.c[2] = 2; xx.c[3] = 2; xx.c[4] = 2; xx.c[5] = 2; write_tmunum_info(&xx); read_tmunum_info(&yy); } while(1) { char x[10]={1,2,3,4,5,6,7,8,9,10}; char temp[10]; int i; unsigned char code * data ptrCode; x[0] = y++; WatchDog(); earseCodeFlash(TMU_NUM_INFO_ADDR); WatchDog(); writeInnerFlash(TMU_NUM_INFO_ADDR, 10, x); ptrCode = (char code *)TMU_NUM_INFO_ADDR; for(i = 0;i<10;i++) { temp[i] = 0; } for (i = 0; i <10; i++) { temp[i] = *ptrCode++; } WatchDog(); } while(1) { WatchDog(); uart_process(); if(flag30ms) { /*sssssssssssssssss*/ flag30ms = 0; if(num_byte == 0) { num_byte = 1; read_id(0,0,(unsigned char*)localid_buf); WatchDog(); } else { num_byte = 0; read_id(0,1,(unsigned char*)localid_buf); WatchDog(); refresh_current_id(); memory_clear((unsigned char*)localid_buf,sizeof(localid_buf)); read_id_96(); } } if( flag60ms ) { flag60ms = 0; index ++; uart1_timeout(); port_state_process(); slot_aging_time(); if(index >= 20) { index = 0; fmu_cmd_update_file_timer_count(); } } } }
template<int N, int N_obj> template<typename F> void GA<N, N_obj>::run_multiobjective (F &f, Individual _lower_boundary, Individual _upper_boundary, Individual *initial_population, int initial_population_size) { if(N_obj < 2) { std::cout << "GA::run: attempt to call multi-objective solver with " << N_obj << " objective(s)\n"; wait_and_exit(); } if(first_run) { first_run = false; } else { memory_clear(); memory_allocate(); } lower_boundary = _lower_boundary; upper_boundary = _upper_boundary; int n_crossover_children = round(options.crossover_fraction * options.population_size), n_mutation_children = options.population_size - n_crossover_children, n_parents = n_mutation_children + 2 * n_crossover_children; // form the initial population and score it int mobj_pop_size = 2 * options.population_size; seed_population(initial_population, initial_population_size); for(int i = 0; i < mobj_pop_size; i++) score[i] = f(population[i]); generation = 0; index_comparator<> comp; for(int gen = 0; gen < options.max_generations; gen++) { // separate Pareto fronts ================================================================= // unranked individuals have zero rank // mark all individual as unranked for(int i = 0; i < mobj_pop_size; i++) rank[i] = 0; // set current front rank total_front_ranks = 0; bool found_unranked = true; while(found_unranked) { total_front_ranks++; found_unranked = false; // find unranked indivuduals for(int i = 0; i < mobj_pop_size; i++) { if(rank[i] == 0) { found_unranked = true; // test rank them with the current front rank rank[i] = total_front_ranks; // check all other individuals of the current front for(int j = 0; j < mobj_pop_size; j++) { if(rank[j] == total_front_ranks && j != i) { // if candidate individual is dominated by some individual of the current front, delete the candidate if(pareto_dominates(j, i)) { rank[i] = 0; break; } else { // if candidate individual dominates some individual of the current front, delete the latter if(pareto_dominates(i, j)) rank[j] = 0; } } } } } } // while unranked individuals are found total_front_ranks--; // calculate the distances for each front ================================================= double infinity = std::numeric_limits<double>::max(); // infinite distance flag for(int r = 1; r <= total_front_ranks; r++) { // get the size and indexes of the current front front_size[r] = 0; for(int i = 0; i < mobj_pop_size; i++) { if(rank[i] == r) { // set the distances of individuals on the front to zero distance[i] = 0.; // store the indexes of the individuals of the current front index[front_size[r]] = i; front_size[r]++; } } // accumulate distance for all objectives for(int obj = 0; obj < N_obj; obj++) { // get score array for current objective for(int i = 0; i < front_size[r]; i++) { score_for_objective[index[i]] = score[index[i]][obj]; } // sort indexes according to increasing score_for_objective_order comp.set_objective(score_for_objective); std::sort(index, index + front_size[r], comp); // distance is infinite for individuals at Pareto front ends distance[index[0]] = infinity; distance[index[front_size[r] - 1]] = infinity; double score_range_for_objective = fabs(score[index[0]][obj] - score[index[front_size[r] - 1]][obj]); // this can be zero, test it ================================== if(score_range_for_objective == 0. || score_range_for_objective == -1. * 0.) score_range_for_objective = 1. + std::max(fabs(score[index[0]][obj]), fabs(score[index[front_size[r] - 1]][obj])); for(int i = 1; i < front_size[r] - 1; i++) { if(distance[index[i]] != infinity) distance[index[i]] += fabs(score[index[i + 1]][obj] - score[index[i - 1]][obj]) / score_range_for_objective; } } // for objectives ... } // for ranks ... // fill the archive ======================================================================= int archive_size = 0; for(int r = 1; r <= total_front_ranks; r++) { if(front_size[r] > options.population_size - archive_size) { // archive has no room for all the front individuals, pick only the most distant int n_selected = options.population_size - archive_size; // get the indexes of the individuals in the current front int current_front_size = 0; for(int i = 0; i < mobj_pop_size; i++) { if(rank[i] == r) { index[current_front_size] = i; current_front_size++; } } // set distance array as score for(int i = 0; i < front_size[r]; i++) { score_for_objective[index[i]] = distance[index[i]]; } // sort indexes according to increasing distance comp.set_objective(score_for_objective); std::sort(index, index + front_size[r], comp); // pick the most distant 'n_selected' individuals for(int i = 0; i < n_selected; i++) { archive[archive_size] = index[front_size[r] - 1 - i]; archive_size++; } // parents selection done, exit the loop break; } else { // we can transfer the whole front to parents for(int i = 0; i < mobj_pop_size; i++) { if(rank[i] == r) { archive[archive_size] = i; archive_size++; } } } } // for ranks ... for(int i = 0; i < options.population_size; i++) { archive_individuals[i] = population[archive[i]]; archive_score[i] = score[archive[i]]; } // calculate monitoring data ============================================================== // calculate average distances for non-dominated Pareto front average_distance[generation] = 0.; average_distance_deviation[generation] = 0.; int n_finite = 0; for(int i = 0; i < mobj_pop_size; i++) { if(rank[i] == 1 && distance[i] != infinity) { average_distance[generation] += distance[i]; index[n_finite] = i; n_finite++; } } if(n_finite != 0) { average_distance[generation] /= n_finite; for(int i = 0; i < n_finite; i++) { average_distance_deviation[generation] += pow(average_distance[generation] - distance[index[i]], 2); } average_distance_deviation[generation] = sqrt(average_distance_deviation[generation] / n_finite); } // extreme Pareto solutions for(int obj = 0; obj < N_obj; obj++) { int i_min_elem = 0; for(int i = 1; i < mobj_pop_size; i++) { if(score[i][obj] < score[i_min_elem][obj]) i_min_elem = i; } extreme_Pareto_solution[generation][obj] = score[i_min_elem]; } double extreme_Pareto_distance = 0.; if(generation > 0) { for(int i = 0; i < N_obj; i++) extreme_Pareto_distance += scalar_norm(extreme_Pareto_solution[generation][i] - extreme_Pareto_solution[generation - 1][i]); } if(extreme_Pareto_distance > 0 || average_distance_deviation[generation] > 0) spread[generation] = (extreme_Pareto_distance + average_distance_deviation[generation]) / (extreme_Pareto_distance + N_obj * average_distance[generation]); else spread[generation] = extreme_Pareto_distance; // output monitoring data if(options.verbose) { std::cout << generation << "\tspread = " << spread[generation] << "\taverage distance = " << average_distance[generation] << "\tPareto front size = " << front_size[1] << "\n"; } // check termination criteria ============================================================= bool terminate = false; int window = options.stall_generations_limit + 1; if(generation > window) { double mean_spread = 0.; for(int i = 0; i < window; i++) mean_spread += spread[generation - i]; mean_spread /= window; double spread_weight = 0.5; double spread_change = 0.; for(int i = 1; i < window; i++) { spread_change += pow(spread_weight, i) * fabs(spread[generation - i + 1] - spread[generation - i]) / (1 + spread[generation - i]); } spread_change /= window; if(spread_change < options.spread_change_tolerance && mean_spread >= spread[generation]) { std::cout << "spread change = " << spread_change << " is less than termination tolerance\n"; terminate = true; } } // output the data ======================================================================== if(generation == options.max_generations - 1 || generation == 0 || generation % options.output_generations_step == 0 || terminate == true) { std::string filename_objective = options.output_directory + "objective" + boost::lexical_cast<std::string>(generation) + ".txt"; output(filename_objective, true); std::string filename_parameter = options.output_directory + "parameter" + boost::lexical_cast<std::string>(generation) + ".txt"; output(filename_parameter, false); } if(generation == options.max_generations - 1 || terminate == true) { std::string filename_objective = options.output_directory + "objective_final" + ".txt"; output(filename_objective, true); std::string filename_parameter = options.output_directory + "parameter_final" + ".txt"; output(filename_parameter, false); } // no need to breed in the last generation if(generation == options.max_generations - 1 || terminate == true) break; // breed the new generation using archive ================================================= // get parents' indexes selection_tournament_multiobjective(n_parents); std::random_shuffle(parents, parents + n_parents); // perform genetic operators to get the children ma_step_changed = false; // lower the flag for adaptive mutation int i_parent = 0; for(int i = 0; i < n_mutation_children; ++i, ++i_parent) (this->*options.mutation) (population[parents[i_parent]], children[i]); //if(options.verbose) //{ // std::cout << "\tma_step_size = " << ma_step_size << "\n"; //} for(int i = n_mutation_children; i < options.population_size; ++i, i_parent+=2) (this->*options.crossover) (population[parents[i_parent]], population[parents[i_parent + 1]], children[i]); // merge children and archive into the new population for(int i = 0; i < options.population_size; i++) { population[i] = children[i]; score[i] = f(population[i]); population[i + options.population_size] = archive_individuals[i]; score[i + options.population_size] = archive_score[i]; } generation++; } // main GA loop }
template<int N, int N_obj> template<typename F> void GA<N, N_obj>::run (F &f, Individual _lower_boundary, Individual _upper_boundary, Individual *initial_population, int initial_population_size) { if(N_obj != 1) { std::cout << "GA::run: attempt to call single-objective solver with " << N_obj << " objectives\n"; wait_and_exit(); } if(!first_run) { memory_clear(); memory_allocate(); } first_run = false; lower_boundary = _lower_boundary; upper_boundary = _upper_boundary; seed_population(initial_population, initial_population_size); int n_crossover_children = floor(0.5 + options.crossover_fraction * (options.population_size - options.n_elite)), n_mutation_children = options.population_size - options.n_elite - n_crossover_children, n_parents = n_mutation_children + 2 * n_crossover_children; generation = 0; last_improvement_generation = 0; index_comparator<Objective> comp; for(int gen = 0; gen < options.max_generations; gen++) { // score the population for(int i = 0; i < options.population_size; i++) score[i] = f(population[i]); // sort score index array according to score values in ascending order for(int i = 0; i < options.population_size; i++) score_index[i] = i; comp.set_objective(score); std::sort(score_index, score_index + options.population_size, comp); best_score[generation] = score[score_index[0]]; best_individual[generation] = population[score_index[0]]; if(options.verbose) { std::cout << generation << "\t" << best_score[generation] << "\t" << population[score_index[0]] << "\n"; } if(generation == options.max_generations - 1) break; if(generation > 0) { if(best_score[generation] < best_score[generation - 1]) last_improvement_generation = generation; } // break if no improvement for last 'options.stall_generations_limit' generations if(generation - last_improvement_generation > options.stall_generations_limit || generation == options.max_generations) break; (this->*options.scaling)(); // normalize fitness so that total fitness sum is 1. double cumulative_fitness = 0.; for(int i = 0; i < options.population_size; i++) cumulative_fitness += fitness[i]; for(int i = 0; i < options.population_size; i++) fitness[i] /= cumulative_fitness; // get parents' indexes (this->*options.selection)(n_parents); // parents are indexes in the current generation std::random_shuffle(parents, parents + n_parents); // transfer elite children for(int i = 0; i < options.n_elite; i++) children[i] = population[score_index[i]]; // perform genetic operators to get the rest of the children ma_step_changed = false; int i_parent = 0; for(int i = options.n_elite; i < options.n_elite + n_mutation_children; ++i, ++i_parent) (this->*options.mutation) (population[parents[i_parent]], children[i]); for(int i = options.n_elite + n_mutation_children; i < options.population_size; ++i, i_parent+=2) (this->*options.crossover) (population[parents[i_parent]], population[parents[i_parent + 1]], children[i]); for(int i = 0; i < options.population_size; ++i) population[i] = children[i]; generation++; } // main GA loop std::string filename_objective = options.output_directory + "single_objective" + ".txt"; output(filename_objective); }