Compare commits
	
		
			4 Commits
		
	
	
		
			11b29a4d57
			...
			de535303d4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| de535303d4 | |||
| 50b6d045e7 | |||
| d2defae8a2 | |||
| cd8900d936 | 
| @@ -12,3 +12,6 @@ itertools = "0.13.0" | ||||
| rayon = "1.10.0" | ||||
| regex = "1.11.1" | ||||
| thread_local = "1.1.8" | ||||
|  | ||||
| [profile.release] | ||||
| lto = true | ||||
							
								
								
									
										12
									
								
								src/day10.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/day10.rs
									
									
									
									
									
								
							| @@ -29,12 +29,12 @@ impl TrailMap { | ||||
|             .collect_vec() | ||||
|     } | ||||
|     fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 { | ||||
|         if visited.get(pos.0, pos.1) == Some(true) { | ||||
|         if visited.get(pos) == Some(true) { | ||||
|             return 0; | ||||
|         } else { | ||||
|             visited.set(pos.0, pos.1, true); | ||||
|             visited.set(pos, true); | ||||
|         } | ||||
|         let our_val = self.map.get(pos.0, pos.1).unwrap(); | ||||
|         let our_val = self.map.get(pos).unwrap(); | ||||
|         if our_val == needle { | ||||
|             return 1; | ||||
|         } | ||||
| @@ -42,7 +42,7 @@ impl TrailMap { | ||||
|         [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down | ||||
|             .iter() | ||||
|             .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position | ||||
|             .map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position | ||||
|             .map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position | ||||
|             .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 | ||||
|             .map(|(pos, _)| pos) // discard the value | ||||
|             .map(|pos| self.count_reachable_from(&pos, needle, visited)) | ||||
| @@ -50,14 +50,14 @@ impl TrailMap { | ||||
|     } | ||||
|  | ||||
|     fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 { | ||||
|         let our_val = self.map.get(pos.0, pos.1).unwrap(); | ||||
|         let our_val = self.map.get(pos).unwrap(); | ||||
|         if our_val == needle { | ||||
|             return 1; | ||||
|         } | ||||
|         [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down | ||||
|             .iter() | ||||
|             .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position | ||||
|             .map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position | ||||
|             .map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position | ||||
|             .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 | ||||
|             .map(|(pos, _)| pos) // discard the value | ||||
|             .map(|mov| self.count_paths_to(&mov, needle)) | ||||
|   | ||||
							
								
								
									
										21
									
								
								src/day11.rs
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/day11.rs
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use aoc_runner_derive::aoc; | ||||
| use itertools::Itertools; | ||||
| use std::collections::HashMap; | ||||
| use std::iter::repeat; | ||||
| @@ -26,7 +26,6 @@ impl From<&str> for Stones { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[aoc_generator(day11)] | ||||
| fn parse(input: &str) -> Stones { | ||||
|     Stones::from(input) | ||||
| } | ||||
| @@ -47,8 +46,8 @@ impl Stone { | ||||
| } | ||||
|  | ||||
| fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntType { | ||||
|     if cache[blink].contains_key(&stone) { | ||||
|         return cache[blink][&stone].clone(); | ||||
|     if cache[blink].contains_key(stone) { | ||||
|         return cache[blink][stone]; | ||||
|     } | ||||
|     let stones = stone.blink_once(); | ||||
|     let result = if blink == 0 { | ||||
| @@ -63,10 +62,10 @@ fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntT | ||||
|         } | ||||
|     }; | ||||
|     cache[blink].insert(stone.clone(), result); | ||||
|     cache[blink][&stone].clone() | ||||
|     cache[blink][stone] | ||||
| } | ||||
|  | ||||
| fn blink_stones(stones: &Stones, blinks: usize) -> IntType { | ||||
| fn blink_stones(stones: Stones, blinks: usize) -> IntType { | ||||
|     let mut cache = Vec::from_iter(repeat(CacheType::new()).take(blinks)); | ||||
|     stones | ||||
|         .0 | ||||
| @@ -76,12 +75,14 @@ fn blink_stones(stones: &Stones, blinks: usize) -> IntType { | ||||
| } | ||||
|  | ||||
| #[aoc(day11, part1)] | ||||
| fn part1(stones: &Stones) -> IntType { | ||||
| pub fn part1(input: &str) -> IntType { | ||||
|     let stones = parse(input); | ||||
|     blink_stones(stones, 25) | ||||
| } | ||||
|  | ||||
| #[aoc(day11, part2)] | ||||
| fn part2(stones: &Stones) -> IntType { | ||||
| pub fn part2(input: &str) -> IntType { | ||||
|     let stones = parse(input); | ||||
|     blink_stones(stones, 75) | ||||
| } | ||||
|  | ||||
| @@ -92,11 +93,11 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!(part1(&parse(EXAMPLE)), 55312); | ||||
|         assert_eq!(part1(EXAMPLE), 55312); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn part2_example() { | ||||
|         assert_eq!(part2(&parse(EXAMPLE)), 65601038650482); | ||||
|         assert_eq!(part2(EXAMPLE), 65601038650482); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										61
									
								
								src/day6.rs
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								src/day6.rs
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use bitflags::bitflags; | ||||
| use rayon::iter::ParallelIterator; | ||||
| use rayon::slice::ParallelSlice; | ||||
| use std::fmt; | ||||
| use std::io::{BufRead, Lines}; | ||||
| use std::ops::BitAnd; | ||||
| @@ -14,10 +16,10 @@ pub fn get_input(input: &[u8]) -> Map { | ||||
| #[repr(u8)] | ||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] | ||||
| enum FacingDirection { | ||||
|     Up = b'^', | ||||
|     Down = b'v', | ||||
|     Left = b'<', | ||||
|     Right = b'>', | ||||
|     Up = 1, | ||||
|     Down = 2, | ||||
|     Left = 4, | ||||
|     Right = 8, | ||||
| } | ||||
|  | ||||
| impl FacingDirection { | ||||
| @@ -45,6 +47,7 @@ enum StepOutcome { | ||||
|     Continue, | ||||
| } | ||||
|  | ||||
| #[derive(Eq, PartialEq)] | ||||
| enum RunOutcome { | ||||
|     LeftMap, | ||||
|     LoopFound, | ||||
| @@ -98,7 +101,7 @@ impl<T: BufRead> From<Lines<T>> for Map { | ||||
|         let grid = Grid::from(input); | ||||
|         let mut visited_from: Grid<DirectionSet> = Grid::new(grid.width() as i64); | ||||
|         visited_from.data.resize(grid.data.len(), DirectionSet::empty()); | ||||
|         let guard_pos = grid.find(b'^').expect("Guard not found"); | ||||
|         let guard_pos = grid.find(&b'^').expect("Guard not found"); | ||||
|         let guard_facing = FacingDirection::Up; | ||||
|         Self { | ||||
|             grid, | ||||
| @@ -112,31 +115,24 @@ impl<T: BufRead> From<Lines<T>> for Map { | ||||
|  | ||||
| impl Map { | ||||
|     fn look(&self, dir: &FacingDirection) -> Option<u8> { | ||||
|         match dir { | ||||
|             FacingDirection::Up => self.grid.get(self.guard_pos.0, self.guard_pos.1 - 1), | ||||
|             FacingDirection::Down => self.grid.get(self.guard_pos.0, self.guard_pos.1 + 1), | ||||
|             FacingDirection::Left => self.grid.get(self.guard_pos.0 - 1, self.guard_pos.1), | ||||
|             FacingDirection::Right => self.grid.get(self.guard_pos.0 + 1, self.guard_pos.1), | ||||
|         } | ||||
|         self.grid.get(&dir.pos_ofs(self.guard_pos)) | ||||
|     } | ||||
|     /// Move one step in the facing direction, return if we are still inside the bounds | ||||
|     fn step_guard<const RECORD_PATH: bool>(&mut self) -> StepOutcome { | ||||
|         let new_pos = self.guard_facing.pos_ofs(self.guard_pos); | ||||
|         if self | ||||
|             .visited_from | ||||
|             .get(new_pos.0, new_pos.1) | ||||
|             .get(&new_pos) | ||||
|             .is_some_and(|dirs| dirs.contains(self.guard_facing.into())) | ||||
|         { | ||||
|             return StepOutcome::LoopFound; | ||||
|         } | ||||
|         if self.grid.set(new_pos.0, new_pos.1, b'X') { | ||||
|             StepOutcome::LoopFound | ||||
|         } else if self.grid.set(&new_pos, b'X').is_some() { | ||||
|             if RECORD_PATH { | ||||
|                 self.path.push((new_pos, self.guard_facing)); | ||||
|             } | ||||
|             self.visited_from.set( | ||||
|                 new_pos.0, | ||||
|                 new_pos.1, | ||||
|                 self.visited_from.get(new_pos.0, new_pos.1).unwrap() | self.guard_facing.into(), | ||||
|                 &new_pos, | ||||
|                 self.visited_from.get(&new_pos).unwrap() | self.guard_facing.into(), | ||||
|             ); | ||||
|             self.guard_pos = new_pos; | ||||
|             StepOutcome::Continue | ||||
| @@ -168,7 +164,7 @@ pub fn part1(map: &Map) -> u64 { | ||||
|     let mut map = map.clone(); | ||||
|     map.run_guard::<false>(); | ||||
|  | ||||
|     (map.grid.count(b'X') + map.grid.count(b'-') + map.grid.count(b'|') + map.grid.count(b'^')) as u64 | ||||
|     map.grid.count(&b'X') as u64 + 1 // 'X' path positions + 1 starting position | ||||
| } | ||||
|  | ||||
| // PROBLEM 2 solution | ||||
| @@ -178,28 +174,19 @@ pub fn part2(input_map: &Map) -> u64 { | ||||
|     let mut path_map = input_map.clone(); | ||||
|     path_map.run_guard::<true>(); | ||||
|  | ||||
|     let mut tested_position: grid::Grid<bool> = grid::Grid::new(path_map.grid.width() as i64); | ||||
|     tested_position.data.resize(path_map.grid.data.len(), false); | ||||
|  | ||||
|     let mut loop_count = 0u64; | ||||
|     let mut last_posdir = (input_map.guard_pos, input_map.guard_facing); | ||||
|  | ||||
|     for ((x, y), dir) in path_map.path.iter() { | ||||
|         if !tested_position.get(*x, *y).unwrap() { | ||||
|             tested_position.set(*x, *y, true); | ||||
|     path_map | ||||
|         .path | ||||
|         .par_windows(2) | ||||
|         .filter(|prev_cur| { | ||||
|             let last_posdir = prev_cur[0]; | ||||
|             let mut test_map = input_map.clone(); | ||||
|             test_map.grid.set(*x, *y, b'#'); | ||||
|             test_map.grid.set(&prev_cur[1].0, b'#').unwrap(); | ||||
|             test_map.guard_pos = last_posdir.0; | ||||
|             test_map.guard_facing = last_posdir.1; | ||||
|  | ||||
|             if let RunOutcome::LoopFound = test_map.run_guard::<false>() { | ||||
|                 loop_count += 1 | ||||
|             } | ||||
|             last_posdir = ((*x, *y), *dir); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     loop_count | ||||
|             test_map.run_guard::<false>() == RunOutcome::LoopFound | ||||
|         }) | ||||
|         .count() as u64 | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|   | ||||
| @@ -43,7 +43,7 @@ impl AntennaMap { | ||||
|                 let offset = (a.0 - b.0, a.1 - b.1); | ||||
|                 for i in (start..).map_while(|i| if Some(i - start) != reps { Some(i as i64) } else { None }) { | ||||
|                     let node_pos = (a.0 + i * offset.0, a.1 + i * offset.1); | ||||
|                     if !antinodes.set(node_pos.0, node_pos.1, true) { | ||||
|                     if antinodes.set(&node_pos, true).is_none() { | ||||
|                         // left the grid | ||||
|                         break; | ||||
|                     } | ||||
| @@ -58,14 +58,14 @@ impl AntennaMap { | ||||
| #[aoc(day8, part1)] | ||||
| pub fn part1(map: &AntennaMap) -> u64 { | ||||
|     let antinodes = map.find_antinodes(1, Some(1)); | ||||
|     antinodes.count(true) as u64 | ||||
|     antinodes.count(&true) as u64 | ||||
| } | ||||
|  | ||||
| // PROBLEM 2 solution | ||||
| #[aoc(day8, part2)] | ||||
| pub fn part2(map: &AntennaMap) -> u64 { | ||||
|     let antinodes = map.find_antinodes(0, None); | ||||
|     antinodes.count(true) as u64 | ||||
|     antinodes.count(&true) as u64 | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|   | ||||
							
								
								
									
										22
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,15 +1,15 @@ | ||||
| mod day11; | ||||
| use aoc_runner_derive::aoc_lib; | ||||
|  | ||||
| mod day1; | ||||
| mod day2; | ||||
| mod day3; | ||||
| mod day4; | ||||
| mod day5; | ||||
| mod day6; | ||||
| mod day7; | ||||
| mod day8; | ||||
| mod day9; | ||||
| mod day10; | ||||
| pub mod day1; | ||||
| pub mod day2; | ||||
| pub mod day3; | ||||
| pub mod day4; | ||||
| pub mod day5; | ||||
| pub mod day6; | ||||
| pub mod day7; | ||||
| pub mod day8; | ||||
| pub mod day9; | ||||
| pub mod day10; | ||||
| pub mod day11; | ||||
|  | ||||
| aoc_lib! { year = 2024 } | ||||
|   | ||||
| @@ -4,6 +4,42 @@ use std::{ | ||||
|     iter::repeat, | ||||
| }; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Coord2d { | ||||
|     pub x: i64, | ||||
|     pub y: i64, | ||||
| } | ||||
|  | ||||
| pub trait AsCoord2d { | ||||
|     fn to_coord(self) -> Coord2d; | ||||
|     fn x(&self) -> i64; | ||||
|     fn y(&self) -> i64; | ||||
| } | ||||
|  | ||||
| impl AsCoord2d for Coord2d { | ||||
|     fn to_coord(self) -> Coord2d { | ||||
|         self | ||||
|     } | ||||
|     fn x(&self) -> i64 { | ||||
|         self.x | ||||
|     } | ||||
|     fn y(&self) -> i64 { | ||||
|         self.y | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl AsCoord2d for (i64, i64) { | ||||
|     fn to_coord(self) -> Coord2d { | ||||
|         Coord2d { x: self.0, y: self.1 } | ||||
|     } | ||||
|     fn x(&self) -> i64 { | ||||
|         self.0 | ||||
|     } | ||||
|     fn y(&self) -> i64 { | ||||
|         self.1 | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Grid<T> { | ||||
|     pub data: Vec<T>, | ||||
| @@ -29,8 +65,8 @@ impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> { | ||||
|     pub fn height(&self) -> usize { | ||||
|         return self.data.len() / self.width(); | ||||
|     } | ||||
|     fn pos(&self, x: i64, y: i64) -> i64 { | ||||
|         y * self.width + x | ||||
|     fn pos<C: AsCoord2d>(&self, c: &C) -> i64 { | ||||
|         c.y() * self.width + c.x() | ||||
|     } | ||||
|     pub fn coord(&self, pos: i64) -> Option<(i64, i64)> { | ||||
|         if pos < 0 || pos >= self.data.len() as i64 { | ||||
| @@ -39,57 +75,58 @@ impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> { | ||||
|             Some((pos % self.width, pos / self.width)) | ||||
|         } | ||||
|     } | ||||
|     fn valid_pos(&self, x: i64, y: i64) -> Option<usize> { | ||||
|         if x < 0 || x >= self.width { | ||||
|     fn valid_pos<C: AsCoord2d>(&self, c: &C) -> Option<usize> { | ||||
|         if c.x() < 0 || c.x() >= self.width { | ||||
|             return None; | ||||
|         } | ||||
|         if y < 0 || y >= self.data.len() as i64 / self.width { | ||||
|         if c.y() < 0 || c.y() >= self.data.len() as i64 / self.width { | ||||
|             return None; | ||||
|         } | ||||
|         let pos = self.pos(x, y); | ||||
|         let pos = self.pos(c); | ||||
|         if pos < 0 || pos as usize >= self.data.len() { | ||||
|             return None; | ||||
|         } | ||||
|         self.pos(x, y).try_into().ok() | ||||
|         self.pos(c).try_into().ok() | ||||
|     } | ||||
|     pub fn get(&self, x: i64, y: i64) -> Option<T> { | ||||
|         match self.valid_pos(x, y) { | ||||
|     pub fn get<C: AsCoord2d>(&self, c: &C) -> Option<T> { | ||||
|         match self.valid_pos(c) { | ||||
|             Some(pos) => Some(self.data[pos]), | ||||
|             None => None, | ||||
|         } | ||||
|     } | ||||
|     pub fn set(&mut self, x: i64, y: i64, val: T) -> bool { | ||||
|         match self.valid_pos(x, y) { | ||||
|     pub fn set<C: AsCoord2d>(&mut self, c: &C, val: T) -> Option<T> { | ||||
|         match self.valid_pos(c) { | ||||
|             Some(pos) => { | ||||
|                 let res = Some(self.data[pos]); | ||||
|                 self.data[pos] = val; | ||||
|                 true | ||||
|                 res | ||||
|             } | ||||
|             None => false, | ||||
|             None => None, | ||||
|         } | ||||
|     } | ||||
|     pub fn row(&self, y: i64) -> Option<&[T]> { | ||||
|         if y < self.height() as i64 { | ||||
|             Some(&self.data[self.pos(0, y) as usize..self.pos(self.width, y) as usize]) | ||||
|             Some(&self.data[self.pos(&(0, y)) as usize..self.pos(&(self.width, y)) as usize]) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn find(&self, haystack: T) -> Option<(i64, i64)> { | ||||
|     pub fn find(&self, haystack: &T) -> Option<(i64, i64)> { | ||||
|         self.coord( | ||||
|             self.data | ||||
|                 .iter() | ||||
|                 .enumerate() | ||||
|                 .find_map(|(pos, val)| if *val == haystack { Some(pos as i64) } else { None }) | ||||
|                 .find_map(|(pos, val)| if val == haystack { Some(pos as i64) } else { None }) | ||||
|                 .unwrap_or(-1), | ||||
|         ) | ||||
|     } | ||||
|     pub fn count(&self, haystack: T) -> usize { | ||||
|         self.data.iter().filter(|item| **item == haystack).count() | ||||
|     pub fn count(&self, haystack: &T) -> usize { | ||||
|         self.data.iter().filter(|item| *item == haystack).count() | ||||
|     } | ||||
|  | ||||
|     pub fn forward_slice(&self, x: i64, y: i64, len: i64) -> Option<&[T]> { | ||||
|         let pos = (self.valid_pos(x, y), self.valid_pos(x + len - 1, y)); | ||||
|     pub fn forward_slice<C: AsCoord2d>(&self, start: &C, len: i64) -> Option<&[T]> { | ||||
|         let pos = (self.valid_pos(start), self.valid_pos(&(start.x() + len - 1, start.y()))); | ||||
|         match pos { | ||||
|             (Some(pos1), Some(pos2)) => Some(&self.data[pos1..pos2 + 1]), | ||||
|             _ => None, | ||||
| @@ -151,7 +188,7 @@ impl Display for Grid<u8> { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||
|         for y in 0..self.height() { | ||||
|             for x in 0..self.width() { | ||||
|                 f.write_fmt(format_args!("{}",self.get(x as i64, y as i64).unwrap() as char))?; | ||||
|                 f.write_fmt(format_args!("{}", self.get(&(x as i64, y as i64)).unwrap() as char))?; | ||||
|             } | ||||
|             f.write_char('\n')?; | ||||
|         } | ||||
| @@ -181,21 +218,21 @@ FBCG"; | ||||
|     #[test] | ||||
|     fn indexing() { | ||||
|         let grid = unchecked_load(); | ||||
|         assert_eq!(grid.get(0, 0), Some(b'A')); | ||||
|         assert_eq!(grid.get(3, 3), Some(b'G')); | ||||
|         assert_eq!(grid.get(-1, 0), None); | ||||
|         assert_eq!(grid.get(0, -1), None); | ||||
|         assert_eq!(grid.get(5, 0), None); | ||||
|         assert_eq!(grid.get(0, 5), None); | ||||
|         assert_eq!(grid.get(&(0, 0)), Some(b'A')); | ||||
|         assert_eq!(grid.get(&(3, 3)), Some(b'G')); | ||||
|         assert_eq!(grid.get(&(-1, 0)), None); | ||||
|         assert_eq!(grid.get(&(0, -1)), None); | ||||
|         assert_eq!(grid.get(&(5, 0)), None); | ||||
|         assert_eq!(grid.get(&(0, 5)), None); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn forward_slice() { | ||||
|         let grid = unchecked_load(); | ||||
|         assert_eq!(grid.forward_slice(0, 0, 2), Some(b"AB".as_slice())); | ||||
|         assert_eq!(grid.forward_slice(2, 0, 2), Some(b"CD".as_slice())); | ||||
|         assert_eq!(grid.forward_slice(2, 0, 3), None); | ||||
|         assert_eq!(grid.forward_slice(0, 2, 4), Some(b"IJKL".as_slice())); | ||||
|         assert_eq!(grid.forward_slice(&(0, 0), 2), Some(b"AB".as_slice())); | ||||
|         assert_eq!(grid.forward_slice(&(2, 0), 2), Some(b"CD".as_slice())); | ||||
|         assert_eq!(grid.forward_slice(&(2, 0), 3), None); | ||||
|         assert_eq!(grid.forward_slice(&(0, 2), 4), Some(b"IJKL".as_slice())); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user