From ebe8b84f78b9e90c9cf4a3c055669f9037544b4a Mon Sep 17 00:00:00 2001 From: Etienne Rey-bethbeder Date: Wed, 3 May 2023 17:48:36 +0200 Subject: [PATCH] Raycasting done ! Problem of FOV --- Makefile | 4 +- cube3D.h | 6 +-- game/.game.h.swp | Bin 12288 -> 0 bytes game/dda.c | 129 ++++++++++++++++++++++++++++----------------- game/game.c | 9 ++-- game/game.h | 45 +++++++++++++--- game/init.c | 23 ++++---- game/manage.c | 2 +- game/manage_keys.c | 49 +++++++++++++---- game/raycasting.c | 17 +++--- main.c | 29 +++++----- map/parsing.o | Bin 0 -> 2944 bytes 12 files changed, 203 insertions(+), 110 deletions(-) delete mode 100644 game/.game.h.swp create mode 100644 map/parsing.o diff --git a/Makefile b/Makefile index b5e4285..7003cd9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ SRCS_GAME := main.c game/game.c game/init.c game/manage.c \ -game/manage_keys.c game/raycasting.c -SRCS_MAP := parsing.c parsing_header.c parsing_header2.c parsing_meta.c parsing_body.c +game/manage_keys.c game/raycasting.c game/dda.c +SRCS_MAP := #parsing.c parsing_header.c parsing_header2.c parsing_meta.c parsing_body.c SRCS_MAP := $(addprefix map/, $(SRCS_MAP)) SRCS := ${SRCS_MAP} \ diff --git a/cube3D.h b/cube3D.h index f55884f..5a0ac4c 100644 --- a/cube3D.h +++ b/cube3D.h @@ -6,7 +6,7 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/26 12:34:04 by erey-bet #+# #+# */ -/* Updated: 2023/04/27 14:41:37 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 14:51:05 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ @@ -37,7 +37,7 @@ typedef struct s_map } t_map; /*INIT*/ -t_map *map_parsing(char *path); -int start_game(t_map *map); +t_map *map_parsing(t_map *map, char *path); +int start_game(t_map map); #endif diff --git a/game/.game.h.swp b/game/.game.h.swp deleted file mode 100644 index f392d08dbad1b092fd5ba75fbb13f4731ce7e95b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O>7%Q9K|ObC<~-TAOS)ghHM3`1H1Oxt>R6oFlk6EaFE)xRY77k&W^pSuGg#m zh+|cNkU*S}3Kyhu;R*-1a^S!P5TfUtkl+AqbWcSKB zp$9J>SV<0)4oC;21JVKMfOJ4QARUknNC)mb2jXCkyoqJsl`p-Mmvet9^H3Jj0qKBr zKsq2DkPb)(qyy3c>40=VIv^d84%~qbFq@F;M+o`p9xNWe{}=!Ne}0UR*T6jZ@+cu! z!DHaNc|vx;Q(*UgLf!#yg9LD3gO@-PEP>x z`5Ekjo8Wu!75E6;0PlfU!7Jcp@F;i$+zoz%Z@&WJ-;csWnWO{K0qKBrKsq2D_}?8+ zxo^8YLR>#qLN?xFQSAEt6R{<(8q$i$Pc9R^LeICZth6p{wl~&jMbG*Vn9us$y2{7V ziGjBxDwfS+X2ld$QG1&17kY8^%7s*7d+6Fqrt!DKMITxTSjYz1GCHk|*4pZHyz9F$ zRy$w;tst8)XRo z-WrP$-p(?)M&fb6ZQi3%941>ajZ*gr5fj=rLw{kfVux&G!S6kB6tgfcT0Gb1mc!k? zGii!kn-`BAciJ5Dz!K|Al_L>hC5k;vx*k^o9tPHkd7fpvkrh^r`b;?6={3?f*#8H6YA*Mp`Vt_NxZIc>R zqpnv^>D4-|8D_&U>owXP)8cybWNKAaQAeI8+>6ei6oM-uFAFww<20?EGL5ELZ_E^= z>Y`9Aid>E!Y|D!f%Rdl8Z6Y@ne12?Bw}lrSZoB?-4Fg*_Tk1WjrXq`Gp;Xc=wmj*2 zyA`1}Rm3`T^+Hhm1=pP0RZIJsi)Pk8uVh6b_^+gj&Zb#Nq9zg^{3pRexLjs}hjvhK H=ydWY8nXfj diff --git a/game/dda.c b/game/dda.c index 5e0d9bb..f67c10c 100644 --- a/game/dda.c +++ b/game/dda.c @@ -6,48 +6,53 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/05/02 15:49:00 by erey-bet #+# #+# */ -/* Updated: 2023/05/02 16:58:31 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 17:37:31 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ #include "game.h" +double ft_abs(double nb) +{ + if (nb < 0) + return (-nb); + return (nb); +} + void init_dda(t_game *game, t_dda *dda) { - t_ray *ray + t_ray *ray; + t_ply *ply; - ray = game->ray; - dda->map_x = (int)game->ply->pos_x; - dda->map_y = (int)game->ply->pos_y; + ray = &game->ray; + ply = &game->ply; + dda->map_x = (int)ply->pos_x; + dda->map_y = (int)ply->pos_y; if (ray->dir_x == 0) dda->delta_dist_x = 1e30; else - dda->delta_dist_x = abs(1 / ray->dir_x); + dda->delta_dist_x = ft_abs(1 / ray->dir_x); if (ray->dir_y == 0) dda->delta_dist_y = 1e30; else - dda->delta_dist_y = abs(1 / ray->dir_y); - dda->hit = 0; + dda->delta_dist_y = ft_abs(1 / ray->dir_y); + dda->step_x = 1; + dda->step_y = 1; if (ray->dir_x < 0) { dda->step_x = -1; - dda->side_dist_x = (game->ply->pos_x - dda->map_x) * dda->delta_dist_x; + dda->side_dist_x = (ply->pos_x - dda->map_x) * dda->delta_dist_x; } else - { - dda->step_x = 1; - dda->side_dist_x = (dda->map_x + 1.0 - game->ply->pos_y) * dda->delta_dist_x; - } + dda->side_dist_x = (dda->map_x + 1.0 - ply->pos_x) * dda->delta_dist_x; if (ray->dir_y < 0) { dda->step_y = -1; - dda->side_dist_y = (game->ply->pos_y - dda->map_y) * dda->delta_dist_y; + dda->side_dist_y = (ply->pos_y - dda->map_y) * dda->delta_dist_y; } else - { - dda->step_y = 1; - dda->side_dist_y = (dda->map_y + 1.0 - game->ply->pos_y) * dda->delta_dist_y; - } + dda->side_dist_y = (dda->map_y + 1.0 - ply->pos_y) * dda->delta_dist_y; + dda->hit = 0; } void loop_dda(t_game *game, t_dda *dda) @@ -66,56 +71,82 @@ void loop_dda(t_game *game, t_dda *dda) dda->map_y += dda->step_y; dda->side = 1; } - if (game->map->map[dda->map_x][dda->map_y] > 0) + if (dda->map_x >= 0 && dda->map_y >= 0 && + game->map.map[dda->map_y][dda->map_x] == '1') dda->hit = 1; } } -void ray_dda(t_game *game, t_dda *dda) +void ray_dda(t_dda *dda) { if(dda->side == 0) - dda->perp_wall_dist = (dda->side_dist_x - dda->delta_dist_x); + dda->perp_wall_dist = dda->side_dist_x - dda->delta_dist_x; else - dda->perp_wall_dist = (dda->side_dist_y - dda->delta_dist_y); + dda->perp_wall_dist = dda->side_dist_y - dda->delta_dist_y; + if (dda->perp_wall_dist == 0) + dda->perp_wall_dist = 1e30; dda->line_height = (int)(HEIGHT / dda->perp_wall_dist); - dda->draw_start = -dda->line_height / 2 + HEIGHT / 2; + dda->draw_start = -(dda->line_height) / 2 + HEIGHT / 2; if(dda->draw_start < 0) dda->draw_start = 0; dda->draw_end = dda->line_height / 2 + HEIGHT / 2; - if(draw_end >= HEIGHT) - draw_end = HEIGHT - 1; + if(dda->draw_end >= HEIGHT) + dda->draw_end = HEIGHT - 1; } -int create_trgb(int t, int r, int g, int b) +unsigned int get_rgba(int r, int g, int b, int a) { - return (t << 24 | r << 16 | g << 8 | b); + return (a << 24 | r << 16 | g << 8 | b); } -#include -#include - -void draw_dda(t_game *game, t_dda *dda) +void draw_line(t_game *game, t_dda *dda, unsigned int color, int x) { - int color; + int y; + unsigned int white; - srand(time(NULL)); - int r = rand() % 4; - if (r == 0) - color = create_trgv(255, 150, 10, 200); - else if (r == 1) - color = create_trgv(255, 10, 150, 200); - else if (r == 2) - color = create_trgv(255, 200, 150, 10); - else if (r == 3) - color = create_trgv(255, 10, 200, 150); - - mlx_put_pixel(game->mlx->window, abs(x), y, + white = 0xFFFFFFFF; + y = 0; + while (y < HEIGHT) + { + if (y < dda->draw_start) + { + mlx_put_pixel(game->window, x, y, white); + } + else if (y >= dda->draw_start && y <= dda->draw_end) + { + mlx_put_pixel(game->window, x, y, color); + } + else if (y > dda->draw_end) + { + mlx_put_pixel(game->window, x, y, white); + } + y ++; + } } -void dda(t_game *game, t_dda *dda) + +void draw_dda(t_game *game, t_dda *dda, int x) { - init_dda(game, dda); - loop_dda(game, dda); - ray_dda(game, dda); - draw_dda(game, dda); + unsigned int color; + + if (dda->step_x == -1 && dda->side == 0) // EAST + color = get_rgba(255, 0, 0, 255); + else if (dda->step_x == 1 && dda->side == 0) // WEST + color = get_rgba(0, 255, 0, 255); + else if (dda->step_y == 1 && dda->side == 1) // NORTH + color = get_rgba(0, 0, 255, 255); + else // SOUTH + color = get_rgba(100, 100, 100, 255); + + draw_line(game, dda, color, x); +} + +void dda(t_game *game, int x) +{ + t_dda dda; + + init_dda(game, &dda); + loop_dda(game, &dda); + ray_dda(&dda); + draw_dda(game, &dda, x); } diff --git a/game/game.c b/game/game.c index 927cfd8..f61cfc5 100644 --- a/game/game.c +++ b/game/game.c @@ -6,13 +6,13 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/26 12:59:53 by erey-bet #+# #+# */ -/* Updated: 2023/05/03 12:47:12 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 14:50:16 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ #include "game.h" -int start_game(t_map *map) +int start_game(t_map map) { t_game game; @@ -22,15 +22,16 @@ int start_game(t_map *map) game.window = mlx_new_image(game.mlx, WIDTH, HEIGHT); if (!game.window) { - mlx_close_window(game.mlx); + mlx_terminate(game.mlx); return(1); } if (mlx_image_to_window(game.mlx, game.window, 0, 0) == -1) { - mlx_close_window(game.mlx); + mlx_terminate(game.mlx); return(1); } + raycasting(&game); mlx_key_hook(game.mlx, manage, &game); mlx_loop(game.mlx); mlx_terminate(game.mlx); diff --git a/game/game.h b/game/game.h index 813103f..5c7f3a7 100644 --- a/game/game.h +++ b/game/game.h @@ -6,7 +6,7 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/26 15:29:34 by erey-bet #+# #+# */ -/* Updated: 2023/05/03 12:42:31 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 16:51:50 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,9 +15,38 @@ # include "../cube3D.h" # include +# include + +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +# include +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ +/* FAUT REMOVE */ + # define WIDTH 1920 # define HEIGHT 1080 +# define MOVESPEED 0.1 +# define ROTATIONSPEED 10 typedef struct s_player { @@ -57,21 +86,23 @@ typedef struct s_game { mlx_t *mlx; mlx_image_t *window; - t_ply *ply; - t_map *map; - t_ray *ray; + t_ply ply; + t_map map; + t_ray ray; } t_game; /* INIT */ -void init(t_map *map, t_game *game); +void init(t_map map, t_game *game); /* MANAGE */ void manage(mlx_key_data_t keydata, void *param); /* KEYS */ -int manage_keys(mlx_key_data_t keydata, t_game *game); +int manage_keys(mlx_key_data_t keydata, t_game *game); /* RAYCASTING */ -int raycasting(t_game *game); +int raycasting(t_game *game); +/* DDA ALGO */ +void dda(t_game *game, int x); #endif diff --git a/game/init.c b/game/init.c index 403166a..2fb8e70 100644 --- a/game/init.c +++ b/game/init.c @@ -6,16 +6,20 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/27 14:50:22 by erey-bet #+# #+# */ -/* Updated: 2023/05/03 12:44:19 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 17:47:38 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ #include "game.h" -void init_ply(t_map *map, t_ply *ply) +void init_ply(t_map map, t_ply *ply) { - ply->pos_x = map->ply_x; - ply->pos_y = map->ply_y; + ply->pos_x = map.ply_x; + ply->pos_y = map.ply_y; + ply->dir_x = -1; + ply->dir_y = 0; + ply->pla_x = 0; + ply->pla_y = 0.90; } void init_ray(t_ray *ray) @@ -24,17 +28,12 @@ void init_ray(t_ray *ray) ray->dir_y = 0; } -void init(t_map *map, t_game *game) +void init(t_map map, t_game *game) { - t_ply ply; - t_ray ray; - game->mlx = mlx_init(WIDTH, HEIGHT, "jan lili", true); if (!game->mlx) return ; game->map = map; - init_ply(map, &ply); - game->ply = &ply; - init_ray(&ray); - game->ray = &ray; + init_ply(map, &game->ply); + init_ray(&game->ray); } diff --git a/game/manage.c b/game/manage.c index 8779232..21c4bed 100644 --- a/game/manage.c +++ b/game/manage.c @@ -6,7 +6,7 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/27 12:52:14 by erey-bet #+# #+# */ -/* Updated: 2023/04/27 14:31:50 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 14:53:14 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/game/manage_keys.c b/game/manage_keys.c index acde5d5..168b1a0 100644 --- a/game/manage_keys.c +++ b/game/manage_keys.c @@ -6,22 +6,53 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/27 14:14:51 by erey-bet #+# #+# */ -/* Updated: 2023/05/03 12:44:41 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 16:16:34 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ #include "game.h" -int movement(t_ply *ply, int key) +void rotate(t_ply *ply, bool right) { + double old_dir_x; + double old_plane_x; + double speed; + + old_dir_x = ply->dir_x; + old_plane_x = ply->pla_x; + speed = ROTATIONSPEED * (M_1_PI / 180.0); + if (right) + speed = -speed; + ply->dir_x = ply->dir_x * cos(speed) - ply->dir_y * sin(speed); + ply->dir_y = old_dir_x * sin(speed) + ply->dir_y * cos(speed); + ply->pla_x = ply->pla_x * cos(speed) - ply->pla_y * sin(speed); + ply->pla_y = old_plane_x * sin(speed) + ply->pla_y * cos(speed); +} + +void movement(t_game *game, t_ply *ply, double x, double y) +{ + if(game->map.map[(int)(ply->pos_x + ply->dir_x * MOVESPEED)][(int)ply->pos_y] == '0') + ply->pos_x += x; + if(game->map.map[(int)ply->pos_x][(int)(ply->pos_y + ply->dir_y * MOVESPEED)] == '0') + ply->pos_y += y; + printf("ply->pos_x: %f, ply->pos_y: %f\n", ply->pos_x, ply->pos_y); + printf("x: %f, y: %f\n", x, y); +} + + +int manage_movement(t_game *game, int key) +{ + t_ply *ply; + + ply = &game->ply; if (key == MLX_KEY_W) - ply->pos_y -= 0.1; + movement(game, ply, ply->dir_x * MOVESPEED, ply->dir_y * MOVESPEED); else if (key == MLX_KEY_S) - ply->pos_y += 0.1; + movement(game, ply, -(ply->dir_x * MOVESPEED), -(ply->dir_y * MOVESPEED)); else if (key == MLX_KEY_D) - ply->pos_x += 0.1; + rotate(ply, true); else if (key == MLX_KEY_A) - ply->pos_x -= 0.1; + rotate(ply, false); return (1); } @@ -36,11 +67,7 @@ int manage_keys(mlx_key_data_t keys, t_game *game) || keys.key == MLX_KEY_S || keys.key == MLX_KEY_D || keys.key == MLX_KEY_A) - is_moving = movement(game->ply, keys.key); - /*else if (key.key == MLX_KEY_RIGHT) - game->ply->direc += 0.1; - else if (key.key == MLX_KEY_LEFT) - game->ply->direc -= 0.1;*/ + is_moving = manage_movement(game, keys.key); if (is_moving) return (1); return (0); diff --git a/game/raycasting.c b/game/raycasting.c index 46c80c9..d762391 100644 --- a/game/raycasting.c +++ b/game/raycasting.c @@ -6,7 +6,7 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/27 14:30:29 by erey-bet #+# #+# */ -/* Updated: 2023/05/03 12:45:15 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 17:44:24 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,16 +17,19 @@ int ray(t_game *game) t_ply *p; t_ray *ray; double camera; - int i; + int x; - i = 0; - p = game->ply; - ray = game->ray; - while (i <= WIDTH) + x = 0; + p = &game->ply; + + ray = &game->ray; + while (x <= WIDTH) { - camera = 2 * i / (double)WIDTH - 1; //x-coordinate in camera space + camera = 2 * x / ((double)(WIDTH - 1)); ray->dir_x = p->dir_x + p->pla_x * camera; ray->dir_y = p->dir_y + p->pla_y * camera; + dda(game, x); + x++; } return(0); } diff --git a/main.c b/main.c index 9b3a504..fcfe81a 100644 --- a/main.c +++ b/main.c @@ -6,7 +6,7 @@ /* By: erey-bet +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/26 12:44:55 by erey-bet #+# #+# */ -/* Updated: 2023/04/27 14:43:10 by erey-bet ### ########.fr */ +/* Updated: 2023/05/03 17:33:16 by erey-bet ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,30 +14,31 @@ int main(int argc, char **argv) { - t_map *map; + t_map map; if (argc != 2) { printf("No argument"); return (1); } - /*map = map_parsing(argv[1]); + /*map = map_parsing(&map, argv[1]); if (!map) { return (2); }*/ (void)argv; - map = malloc(sizeof(t_map)); - map->map = malloc(sizeof(char *) * 5); - map->map[0] = "11111"; - map->map[1] = "10001"; - map->map[2] = "10S01"; - map->map[3] = "10101"; - map->map[4] = "11111"; - map->size_x = 5; - map->size_y = 5; - map->ply_x = 3; - map->ply_y = 3; + map.map = malloc(sizeof(char *) * 10); + map.map[0] = "111111"; + map.map[1] = "100101"; + map.map[2] = "101001"; + map.map[3] = "100001"; + map.map[4] = "10N001"; + map.map[5] = "101001"; + map.map[6] = "111111"; + map.size_x = 5; + map.size_y = 5; + map.ply_x = 2; + map.ply_y = 4; if (start_game(map)) { return (3); diff --git a/map/parsing.o b/map/parsing.o new file mode 100644 index 0000000000000000000000000000000000000000..12587f05155d5781510e7a4e8ac9642ac951cb4d GIT binary patch literal 2944 zcmb_eO>7%g5T4!jt{rc@NfRh7MaYPsBGjziB#5Y$Qb(=9p%tJ&5Cx&t+S%Av?On6G zPLqm~NP$WbmlSd0P$5o;azME{f`@G|t+#NilSt1_2n#fMU## z6PQ7mz6;^3uA`|-5~U8`fvFE5&X7yjXVEn7iAIG#u&e|&95Y&_;m8)dQ%J}PX9-D9 z5|R`f`-FVC)j_|YQsv9F2&v=)Z5g}db7Z2(BeY^rl9NNEKf)#tL1ceTb~+W=Kaj28 z+p~xBJv%egvyB31*DzT79J@3&&?NmnRKwq5mjK! zTg|RGeo*(^?9oXxZ{{ba+L80<3zLYZ&HJHgw{k5TW8A7)ftJ(*KER$@g)NCK>%_>;d+`_`#S?lrnr;FATXCEtC z7F4{3=UZhjgocMzMP1zu86SEr2wL`e*IH$I4FZb>4Wqtghq&(l>37jW+(aFUbYTIc z)luota5A-xN8vW)sFBcy!<;dCNj{m;)-eF#61D`G*h`Z1r;#B=CkUHFML}=DkV3|+ zb?)Jij8T!?tftcMshW00O>3u7Kcy;KRZV}U%G$%Kq@9-2I4BPm^)?a-_-#+*2`kW@ zqtC6dquxhG@v+As=2YOu>#&9X(O3*OA4OvTjF`my`Ww<2pUojlL3uyEB zfbr*q_~;fQ=L`I&3||mZvN#chcI8~(i)1z$D^1H@TEeHT+Lzj>yAC6qnziiPO$Rd@4X+Zr z*CtLF+GQ|E;`f0M`X#$CeBU@PJ`nVt5y$Trk1H^P-%HMmcbUG^@q5SP zwi$VV5fn%J7k$rAbDriFYeEWMqz>h3M|FEKb_zWrN5MHpM*lmy**C`0i#(|QHyOFh z#-aM@y%6ia6FCaWV~fjSc38iOlW6l=xu$n#Q2yU6pX!SX&*S<8I=LN>J2L1{42WIt za4j}ncZfX8pXo9kga3X`)4MZh{a$AWitjV6AH5MgpYtwqgX*ub`D^Hpix^u+=b-uD z9WXzAE5!MqK~6cd=b_rb)|KllpU+42lW^QY0B@int{wTVv-&?IfI@jRq&WXSbix%d literal 0 HcmV?d00001