2022 Day 17 part 1 Complete
This commit is contained in:
1
2022/day17/input
Normal file
1
2022/day17/input
Normal file
File diff suppressed because one or more lines are too long
294
2022/day17/main.go
Normal file
294
2022/day17/main.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
const (
|
||||
dirU = iota
|
||||
dirR
|
||||
dirD
|
||||
dirL
|
||||
|
||||
rocks = 5
|
||||
|
||||
debug = false
|
||||
)
|
||||
|
||||
var (
|
||||
emptyRow = []byte{'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'}
|
||||
bottomRow = []byte{'+', '-', '-', '-', '-', '-', '-', '-', '+'}
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToString()
|
||||
//fmt.Println("# Part 1")
|
||||
//simulate(inp, 2022)
|
||||
fmt.Println("# Part 2")
|
||||
simulate(inp, 1000000000000)
|
||||
}
|
||||
|
||||
func stateAndSleep(m *h.GrowUpCoordByteMap) {
|
||||
if !debug {
|
||||
return
|
||||
}
|
||||
fmt.Print(h.CLEAR_SCREEN)
|
||||
//fmt.Println()
|
||||
fmt.Println(m)
|
||||
time.Sleep(time.Second / 10)
|
||||
}
|
||||
|
||||
var cache map[string][]int
|
||||
|
||||
func simulate(jets string, numRocks int) {
|
||||
cache = make(map[string][]int)
|
||||
m := h.NewGrowUpCoordByteMap()
|
||||
m.PutBytes([][]byte{
|
||||
bottomRow, emptyRow, emptyRow, emptyRow, emptyRow,
|
||||
emptyRow, emptyRow, emptyRow,
|
||||
}, h.Coordinate{X: 0, Y: 0})
|
||||
m.StringEmptyIsSpace = true
|
||||
|
||||
jetIdx := 0
|
||||
rockType := 0
|
||||
var state string
|
||||
var height int
|
||||
var turboHeight int
|
||||
var cacheDisabled bool
|
||||
for rockNum := 1; rockNum <= numRocks; rockNum++ {
|
||||
fmt.Println(h.CLEAR_SCREEN)
|
||||
fmt.Println("Simulating:", rockNum, "/", numRocks)
|
||||
h.PrintProgress(rockNum, numRocks)
|
||||
fmt.Println("\nHeight:", height)
|
||||
if !cacheDisabled {
|
||||
state, height = GetState(rockType, jetIdx, m)
|
||||
if v, ok := cache[state]; !cacheDisabled && ok {
|
||||
// Ok, we've got a duplicate. Go full turbo.
|
||||
//addHeight := height
|
||||
mult := numRocks / rockNum
|
||||
newRockNum := rockNum * mult
|
||||
turboHeight = height * mult
|
||||
/*
|
||||
for rockNum+v[1] <= numRocks {
|
||||
rockNum = rockNum + v[1]
|
||||
height = height + addHeight
|
||||
fmt.Println(h.CLEAR_SCREEN)
|
||||
fmt.Println("Simulating:", rockNum, "/", numRocks)
|
||||
h.PrintProgress(rockNum, numRocks)
|
||||
fmt.Println("\nHeight:", height)
|
||||
}
|
||||
*/
|
||||
fmt.Println(h.CLEAR_SCREEN)
|
||||
fmt.Println("Simulating:", rockNum, "/", numRocks)
|
||||
h.PrintProgress(rockNum, numRocks)
|
||||
fmt.Println("\nHeight:", height)
|
||||
fmt.Println("State", state, "\nV:", v, "\nMult:", mult, "\nRockNum:", rockNum, "\nNewRockNum:", newRockNum, "\nTurboHeight:", turboHeight)
|
||||
cacheDisabled = true
|
||||
os.Exit(0)
|
||||
} else {
|
||||
cache[state] = []int{rockNum, height}
|
||||
}
|
||||
} else {
|
||||
fmt.Println("\nHeight:", turboHeight+GetHeight(m))
|
||||
}
|
||||
AddFallingRock(rockType, m)
|
||||
stateAndSleep(m)
|
||||
doJet := true
|
||||
for {
|
||||
if !doJet && AtRest(m) {
|
||||
break
|
||||
}
|
||||
shiftDir := dirD
|
||||
if doJet {
|
||||
switch jets[jetIdx] {
|
||||
case '>':
|
||||
shiftDir = dirR
|
||||
case '<':
|
||||
shiftDir = dirL
|
||||
}
|
||||
jetIdx = (jetIdx + 1) % len(jets)
|
||||
}
|
||||
ShiftRock(shiftDir, m)
|
||||
stateAndSleep(m)
|
||||
doJet = !doJet
|
||||
}
|
||||
// The falling rock has stopped
|
||||
StopRock(m)
|
||||
stateAndSleep(m)
|
||||
rockType = (rockType + 1) % rocks
|
||||
}
|
||||
fmt.Println("After", numRocks, "the tower is", GetHeight(m), "blocks tall")
|
||||
}
|
||||
|
||||
func GetState(r, j int, m *h.GrowUpCoordByteMap) (string, int) {
|
||||
ret := fmt.Sprintf("%d;%d;", r, j)
|
||||
for x := 1; x < 7; x++ {
|
||||
for y := m.TLY; y > 1; y-- {
|
||||
if m.Get(h.Coordinate{X: x, Y: y}) == '#' {
|
||||
ret = fmt.Sprintf("%s-%d", ret, m.TLY-y)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret, GetHeight(m)
|
||||
}
|
||||
|
||||
func GetHeight(m *h.GrowUpCoordByteMap) int {
|
||||
return h.GetHighestY(m.FindAll('#')...)
|
||||
}
|
||||
|
||||
func FindTopAtRestY(m *h.GrowUpCoordByteMap) int {
|
||||
rockSpots := m.FindAll('#')
|
||||
if len(rockSpots) != 0 {
|
||||
return h.GetHighestY(rockSpots...)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func StopRock(m *h.GrowUpCoordByteMap) {
|
||||
rockSpots := m.FindAll('@')
|
||||
for i := range rockSpots {
|
||||
m.Put(rockSpots[i], '#')
|
||||
}
|
||||
}
|
||||
func ShiftRock(dir int, m *h.GrowUpCoordByteMap) {
|
||||
if !CanShift(dir, m) {
|
||||
return
|
||||
}
|
||||
|
||||
rockSpots := m.FindAll('@')
|
||||
for i := range rockSpots {
|
||||
m.Put(rockSpots[i], ' ')
|
||||
}
|
||||
for i := range rockSpots {
|
||||
switch dir {
|
||||
case dirU:
|
||||
m.Put(GetUp(rockSpots[i]), '@')
|
||||
case dirR:
|
||||
m.Put(GetRight(rockSpots[i]), '@')
|
||||
case dirD:
|
||||
m.Put(GetDown(rockSpots[i]), '@')
|
||||
case dirL:
|
||||
m.Put(GetLeft(rockSpots[i]), '@')
|
||||
}
|
||||
}
|
||||
}
|
||||
func CanShift(dir int, m *h.GrowUpCoordByteMap) bool {
|
||||
rockSpots := m.FindAll('@')
|
||||
switch dir {
|
||||
case dirU: // Shouldn't need to, though.
|
||||
return true
|
||||
case dirR:
|
||||
for i := range rockSpots {
|
||||
tst := m.Get(GetRight(rockSpots[i]))
|
||||
if tst != '@' && tst != ' ' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case dirD:
|
||||
for i := range rockSpots {
|
||||
tst := m.Get(GetDown(rockSpots[i]))
|
||||
if tst != '@' && tst != ' ' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case dirL:
|
||||
for i := range rockSpots {
|
||||
tst := m.Get(GetLeft(rockSpots[i]))
|
||||
if tst != '@' && tst != ' ' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func AddFallingRock(tp int, m *h.GrowUpCoordByteMap) {
|
||||
rock := GetRockBytes(tp)
|
||||
pos := h.Coordinate{X: 3, Y: FindTopAtRestY(m) + 4}
|
||||
for pos.Y+3 > m.TLY {
|
||||
m.PutBytes([][]byte{emptyRow}, h.Coordinate{X: 0, Y: m.TLY + 1})
|
||||
}
|
||||
m.PutBytes(rock, pos)
|
||||
}
|
||||
func AtRest(m *h.GrowUpCoordByteMap) bool {
|
||||
rockSpots := m.FindAll('@')
|
||||
if len(rockSpots) == 0 {
|
||||
return true
|
||||
}
|
||||
for i := range rockSpots {
|
||||
pos := GetDown(rockSpots[i])
|
||||
wrk := m.Get(pos)
|
||||
if pos.Y == m.BRY {
|
||||
return true
|
||||
}
|
||||
if wrk != ' ' && wrk != '@' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetRockBytes(tp int) [][]byte {
|
||||
switch tp {
|
||||
case 0:
|
||||
return [][]byte{{'@', '@', '@', '@'}}
|
||||
case 1:
|
||||
return [][]byte{
|
||||
{' ', '@', ' '},
|
||||
{'@', '@', '@'},
|
||||
{' ', '@', ' '},
|
||||
}
|
||||
case 2:
|
||||
return [][]byte{
|
||||
{'@', '@', '@'},
|
||||
{' ', ' ', '@'},
|
||||
{' ', ' ', '@'},
|
||||
}
|
||||
case 3:
|
||||
return [][]byte{
|
||||
{'@'},
|
||||
{'@'},
|
||||
{'@'},
|
||||
{'@'},
|
||||
}
|
||||
case 4:
|
||||
return [][]byte{
|
||||
{'@', '@'},
|
||||
{'@', '@'},
|
||||
}
|
||||
}
|
||||
return [][]byte{}
|
||||
}
|
||||
|
||||
func GetLeft(c h.Coordinate) h.Coordinate {
|
||||
return h.Coordinate{X: c.X - 1, Y: c.Y}
|
||||
}
|
||||
func GetRight(c h.Coordinate) h.Coordinate {
|
||||
return h.Coordinate{X: c.X + 1, Y: c.Y}
|
||||
}
|
||||
func GetUp(c h.Coordinate) h.Coordinate {
|
||||
return h.Coordinate{X: c.X, Y: c.Y + 1}
|
||||
}
|
||||
func GetDown(c h.Coordinate) h.Coordinate {
|
||||
return h.Coordinate{X: c.X, Y: c.Y - 1}
|
||||
}
|
||||
func DirToString(shiftDir int) string {
|
||||
switch shiftDir {
|
||||
case dirU:
|
||||
return "^"
|
||||
case dirR:
|
||||
return ">"
|
||||
case dirD:
|
||||
return "v"
|
||||
case dirL:
|
||||
return "<"
|
||||
}
|
||||
return " "
|
||||
}
|
404
2022/day17/problem
Normal file
404
2022/day17/problem
Normal file
@@ -0,0 +1,404 @@
|
||||
Advent of Code
|
||||
|
||||
• [About]
|
||||
• [Events]
|
||||
• [Shop]
|
||||
• [Settings]
|
||||
• [Log Out]
|
||||
|
||||
br0xen (AoC++) 32*
|
||||
|
||||
sub y{2022}
|
||||
|
||||
• [Calendar]
|
||||
• [AoC++]
|
||||
• [Sponsors]
|
||||
• [Leaderboard]
|
||||
• [Stats]
|
||||
|
||||
Our sponsors help make Advent of Code possible:
|
||||
Smarty - Join our private leaderboard and solve our puzzles for BIG PRIZES!!! ----------------- Address Validation
|
||||
and Autocomplete, and more!
|
||||
|
||||
--- Day 17: Pyroclastic Flow ---
|
||||
|
||||
Your handheld device has located an alternative exit from the cave for you and the elephants. The ground is
|
||||
rumbling almost continuously now, but the strange valves bought you some time. It's definitely getting warmer in
|
||||
here, though.
|
||||
|
||||
The tunnels eventually open into a very tall, narrow chamber. Large, oddly-shaped rocks are falling into the
|
||||
chamber from above, presumably due to all the rumbling. If you can't work out where the rocks will fall next, you
|
||||
might be crushed!
|
||||
|
||||
The five types of rocks have the following peculiar shapes, where # is rock and . is empty space:
|
||||
|
||||
####
|
||||
|
||||
.#.
|
||||
###
|
||||
.#.
|
||||
|
||||
..#
|
||||
..#
|
||||
###
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
##
|
||||
##
|
||||
|
||||
The rocks fall in the order shown above: first the - shape, then the + shape, and so on. Once the end of the list
|
||||
is reached, the same order repeats: the - shape falls first, sixth, 11th, 16th, etc.
|
||||
|
||||
The rocks don't spin, but they do get pushed around by jets of hot gas coming out of the walls themselves. A quick
|
||||
scan reveals the effect the jets of hot gas will have on the rocks as they fall (your puzzle input).
|
||||
|
||||
For example, suppose this was the jet pattern in your cave:
|
||||
|
||||
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
||||
|
||||
In jet patterns, < means a push to the left, while > means a push to the right. The pattern above means that the
|
||||
jets will push a falling rock right, then right, then right, then left, then left, then right, and so on. If the
|
||||
end of the list is reached, it repeats.
|
||||
|
||||
The tall, vertical chamber is exactly seven units wide. Each rock appears so that its left edge is two units away
|
||||
from the left wall and its bottom edge is three units above the highest rock in the room (or the floor, if there
|
||||
isn't one).
|
||||
|
||||
After a rock appears, it alternates between being pushed by a jet of hot gas one unit (in the direction indicated
|
||||
by the next symbol in the jet pattern) and then falling one unit down. If any movement would cause any part of the
|
||||
rock to move into the walls, floor, or a stopped rock, the movement instead does not occur. If a downward movement
|
||||
would have caused a falling rock to move into the floor or an already-fallen rock, the falling rock stops where it
|
||||
is (having landed on something) and a new rock immediately begins falling.
|
||||
|
||||
Drawing falling rocks with @ and stopped rocks with #, the jet pattern in the example above manifests as follows:
|
||||
|
||||
The first rock begins falling:
|
||||
|..@@@@.|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock right:
|
||||
|...@@@@|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit:
|
||||
|...@@@@|
|
||||
|.......|
|
||||
|.......|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock right, but nothing happens:
|
||||
|...@@@@|
|
||||
|.......|
|
||||
|.......|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit:
|
||||
|...@@@@|
|
||||
|.......|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock right, but nothing happens:
|
||||
|...@@@@|
|
||||
|.......|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit:
|
||||
|...@@@@|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock left:
|
||||
|..@@@@.|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit, causing it to come to rest:
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
A new rock begins falling:
|
||||
|...@...|
|
||||
|..@@@..|
|
||||
|...@...|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock left:
|
||||
|..@....|
|
||||
|.@@@...|
|
||||
|..@....|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit:
|
||||
|..@....|
|
||||
|.@@@...|
|
||||
|..@....|
|
||||
|.......|
|
||||
|.......|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock right:
|
||||
|...@...|
|
||||
|..@@@..|
|
||||
|...@...|
|
||||
|.......|
|
||||
|.......|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit:
|
||||
|...@...|
|
||||
|..@@@..|
|
||||
|...@...|
|
||||
|.......|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock left:
|
||||
|..@....|
|
||||
|.@@@...|
|
||||
|..@....|
|
||||
|.......|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit:
|
||||
|..@....|
|
||||
|.@@@...|
|
||||
|..@....|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Jet of gas pushes rock right:
|
||||
|...@...|
|
||||
|..@@@..|
|
||||
|...@...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
Rock falls 1 unit, causing it to come to rest:
|
||||
|...#...|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
A new rock begins falling:
|
||||
|....@..|
|
||||
|....@..|
|
||||
|..@@@..|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|...#...|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
The moment each of the next few rocks begins falling, you would see this:
|
||||
|
||||
|..@....|
|
||||
|..@....|
|
||||
|..@....|
|
||||
|..@....|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|..#....|
|
||||
|..#....|
|
||||
|####...|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|..@@...|
|
||||
|..@@...|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|..@@@@.|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|...@...|
|
||||
|..@@@..|
|
||||
|...@...|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|.####..|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|....@..|
|
||||
|....@..|
|
||||
|..@@@..|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|..#....|
|
||||
|.###...|
|
||||
|..#....|
|
||||
|.####..|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|..@....|
|
||||
|..@....|
|
||||
|..@....|
|
||||
|..@....|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|.....#.|
|
||||
|.....#.|
|
||||
|..####.|
|
||||
|.###...|
|
||||
|..#....|
|
||||
|.####..|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|..@@...|
|
||||
|..@@...|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|....#..|
|
||||
|....#..|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|..####.|
|
||||
|.###...|
|
||||
|..#....|
|
||||
|.####..|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
|..@@@@.|
|
||||
|.......|
|
||||
|.......|
|
||||
|.......|
|
||||
|....#..|
|
||||
|....#..|
|
||||
|....##.|
|
||||
|##..##.|
|
||||
|######.|
|
||||
|.###...|
|
||||
|..#....|
|
||||
|.####..|
|
||||
|....##.|
|
||||
|....##.|
|
||||
|....#..|
|
||||
|..#.#..|
|
||||
|..#.#..|
|
||||
|#####..|
|
||||
|..###..|
|
||||
|...#...|
|
||||
|..####.|
|
||||
+-------+
|
||||
|
||||
To prove to the elephants your simulation is accurate, they want to know how tall the tower will get after 2022
|
||||
rocks have stopped (but before the 2023rd rock begins falling). In this example, the tower of rocks will be 3068
|
||||
units tall.
|
||||
|
||||
How many units tall will the tower of rocks be after 2022 rocks have stopped falling?
|
||||
|
||||
To begin, get your puzzle input.
|
||||
|
||||
Answer: _____________________ [ [Submit] ]
|
||||
|
||||
You can also [Shareon Twitter Mastodon] this puzzle.
|
||||
|
||||
References
|
||||
|
||||
Visible links
|
||||
. https://adventofcode.com/
|
||||
. https://adventofcode.com/2022/about
|
||||
. https://adventofcode.com/2022/events
|
||||
. https://teespring.com/stores/advent-of-code
|
||||
. https://adventofcode.com/2022/settings
|
||||
. https://adventofcode.com/2022/auth/logout
|
||||
. Advent of Code Supporter
|
||||
https://adventofcode.com/2022/support
|
||||
. https://adventofcode.com/2022
|
||||
. https://adventofcode.com/2022
|
||||
. https://adventofcode.com/2022/support
|
||||
. https://adventofcode.com/2022/sponsors
|
||||
. https://adventofcode.com/2022/leaderboard
|
||||
. https://adventofcode.com/2022/stats
|
||||
. https://adventofcode.com/2022/sponsors
|
||||
. https://www.smarty.com/advent-of-code
|
||||
. https://adventofcode.com/2022/day/17/input
|
||||
. https://twitter.com/intent/tweet?text=%22Pyroclastic+Flow%22+%2D+Day+17+%2D+Advent+of+Code+2022&url=https%3A%2F%2Fadventofcode%2Ecom%2F2022%2Fday%2F17&related=ericwastl&hashtags=AdventOfCode
|
||||
. javascript:void(0);
|
1
2022/day17/testinput
Normal file
1
2022/day17/testinput
Normal file
@@ -0,0 +1 @@
|
||||
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
Reference in New Issue
Block a user