mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-29 19:37:14 +00:00
Translate all code to English (#1836)
* Review the EN heading format. * Fix pythontutor headings. * Fix pythontutor headings. * bug fixes * Fix headings in **/summary.md * Revisit the CN-to-EN translation for Python code using Claude-4.5 * Revisit the CN-to-EN translation for Java code using Claude-4.5 * Revisit the CN-to-EN translation for Cpp code using Claude-4.5. * Fix the dictionary. * Fix cpp code translation for the multipart strings. * Translate Go code to English. * Update workflows to test EN code. * Add EN translation for C. * Add EN translation for CSharp. * Add EN translation for Swift. * Trigger the CI check. * Revert. * Update en/hash_map.md * Add the EN version of Dart code. * Add the EN version of Kotlin code. * Add missing code files. * Add the EN version of JavaScript code. * Add the EN version of TypeScript code. * Fix the workflows. * Add the EN version of Ruby code. * Add the EN version of Rust code. * Update the CI check for the English version code. * Update Python CI check. * Fix cmakelists for en/C code. * Fix Ruby comments
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* File: n_queens.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.n_queens
|
||||
|
||||
/* Backtracking algorithm: N queens */
|
||||
fun backtrack(
|
||||
row: Int,
|
||||
n: Int,
|
||||
state: MutableList<MutableList<String>>,
|
||||
res: MutableList<MutableList<MutableList<String>>?>,
|
||||
cols: BooleanArray,
|
||||
diags1: BooleanArray,
|
||||
diags2: BooleanArray
|
||||
) {
|
||||
// When all rows are placed, record the solution
|
||||
if (row == n) {
|
||||
val copyState = mutableListOf<MutableList<String>>()
|
||||
for (sRow in state) {
|
||||
copyState.add(sRow.toMutableList())
|
||||
}
|
||||
res.add(copyState)
|
||||
return
|
||||
}
|
||||
// Traverse all columns
|
||||
for (col in 0..<n) {
|
||||
// Calculate the main diagonal and anti-diagonal corresponding to this cell
|
||||
val diag1 = row - col + n - 1
|
||||
val diag2 = row + col
|
||||
// Pruning: do not allow queens to exist in the column, main diagonal, and anti-diagonal of this cell
|
||||
if (!cols[col] && !diags1[diag1] && !diags2[diag2]) {
|
||||
// Attempt: place the queen in this cell
|
||||
state[row][col] = "Q"
|
||||
diags2[diag2] = true
|
||||
diags1[diag1] = diags2[diag2]
|
||||
cols[col] = diags1[diag1]
|
||||
// Place the next row
|
||||
backtrack(row + 1, n, state, res, cols, diags1, diags2)
|
||||
// Backtrack: restore this cell to an empty cell
|
||||
state[row][col] = "#"
|
||||
diags2[diag2] = false
|
||||
diags1[diag1] = diags2[diag2]
|
||||
cols[col] = diags1[diag1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve N queens */
|
||||
fun nQueens(n: Int): MutableList<MutableList<MutableList<String>>?> {
|
||||
// Initialize an n*n chessboard, where 'Q' represents a queen and '#' represents an empty cell
|
||||
val state = mutableListOf<MutableList<String>>()
|
||||
for (i in 0..<n) {
|
||||
val row = mutableListOf<String>()
|
||||
for (j in 0..<n) {
|
||||
row.add("#")
|
||||
}
|
||||
state.add(row)
|
||||
}
|
||||
val cols = BooleanArray(n) // Record whether there is a queen in the column
|
||||
val diags1 = BooleanArray(2 * n - 1) // Record whether there is a queen on the main diagonal
|
||||
val diags2 = BooleanArray(2 * n - 1) // Record whether there is a queen on the anti-diagonal
|
||||
val res = mutableListOf<MutableList<MutableList<String>>?>()
|
||||
|
||||
backtrack(0, n, state, res, cols, diags1, diags2)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val n = 4
|
||||
val res = nQueens(n)
|
||||
|
||||
println("Input board size is $n")
|
||||
println("Total queen placement solutions: ${res.size}")
|
||||
for (state in res) {
|
||||
println("--------------------")
|
||||
for (row in state!!) {
|
||||
println(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* File: permutations_i.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.permutations_i
|
||||
|
||||
/* Backtracking algorithm: Permutations I */
|
||||
fun backtrack(
|
||||
state: MutableList<Int>,
|
||||
choices: IntArray,
|
||||
selected: BooleanArray,
|
||||
res: MutableList<MutableList<Int>?>
|
||||
) {
|
||||
// When the state length equals the number of elements, record the solution
|
||||
if (state.size == choices.size) {
|
||||
res.add(state.toMutableList())
|
||||
return
|
||||
}
|
||||
// Traverse all choices
|
||||
for (i in choices.indices) {
|
||||
val choice = choices[i]
|
||||
// Pruning: do not allow repeated selection of elements
|
||||
if (!selected[i]) {
|
||||
// Attempt: make choice, update state
|
||||
selected[i] = true
|
||||
state.add(choice)
|
||||
// Proceed to the next round of selection
|
||||
backtrack(state, choices, selected, res)
|
||||
// Backtrack: undo choice, restore to previous state
|
||||
selected[i] = false
|
||||
state.removeAt(state.size - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Permutations I */
|
||||
fun permutationsI(nums: IntArray): MutableList<MutableList<Int>?> {
|
||||
val res = mutableListOf<MutableList<Int>?>()
|
||||
backtrack(mutableListOf(), nums, BooleanArray(nums.size), res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val nums = intArrayOf(1, 2, 3)
|
||||
|
||||
val res = permutationsI(nums)
|
||||
|
||||
println("Input array nums = ${nums.contentToString()}")
|
||||
println("All permutations res = $res")
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* File: permutations_ii.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.permutations_ii
|
||||
|
||||
/* Backtracking algorithm: Permutations II */
|
||||
fun backtrack(
|
||||
state: MutableList<Int>,
|
||||
choices: IntArray,
|
||||
selected: BooleanArray,
|
||||
res: MutableList<MutableList<Int>?>
|
||||
) {
|
||||
// When the state length equals the number of elements, record the solution
|
||||
if (state.size == choices.size) {
|
||||
res.add(state.toMutableList())
|
||||
return
|
||||
}
|
||||
// Traverse all choices
|
||||
val duplicated = HashSet<Int>()
|
||||
for (i in choices.indices) {
|
||||
val choice = choices[i]
|
||||
// Pruning: do not allow repeated selection of elements and do not allow repeated selection of equal elements
|
||||
if (!selected[i] && !duplicated.contains(choice)) {
|
||||
// Attempt: make choice, update state
|
||||
duplicated.add(choice) // Record the selected element value
|
||||
selected[i] = true
|
||||
state.add(choice)
|
||||
// Proceed to the next round of selection
|
||||
backtrack(state, choices, selected, res)
|
||||
// Backtrack: undo choice, restore to previous state
|
||||
selected[i] = false
|
||||
state.removeAt(state.size - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Permutations II */
|
||||
fun permutationsII(nums: IntArray): MutableList<MutableList<Int>?> {
|
||||
val res = mutableListOf<MutableList<Int>?>()
|
||||
backtrack(mutableListOf(), nums, BooleanArray(nums.size), res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val nums = intArrayOf(1, 2, 2)
|
||||
val res = permutationsII(nums)
|
||||
|
||||
println("Input array nums = ${nums.contentToString()}")
|
||||
println("All permutations res = $res")
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* File: preorder_traversal_i_compact.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.preorder_traversal_i_compact
|
||||
|
||||
import utils.TreeNode
|
||||
import utils.printTree
|
||||
|
||||
var res: MutableList<TreeNode>? = null
|
||||
|
||||
/* Preorder traversal: Example 1 */
|
||||
fun preOrder(root: TreeNode?) {
|
||||
if (root == null) {
|
||||
return
|
||||
}
|
||||
if (root._val == 7) {
|
||||
// Record solution
|
||||
res!!.add(root)
|
||||
}
|
||||
preOrder(root.left)
|
||||
preOrder(root.right)
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7))
|
||||
println("\nInitialize binary tree")
|
||||
printTree(root)
|
||||
|
||||
// Preorder traversal
|
||||
res = mutableListOf()
|
||||
preOrder(root)
|
||||
|
||||
println("\nOutput all nodes with value 7")
|
||||
val vals = mutableListOf<Int>()
|
||||
for (node in res!!) {
|
||||
vals.add(node._val)
|
||||
}
|
||||
println(vals)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* File: preorder_traversal_ii_compact.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.preorder_traversal_ii_compact
|
||||
|
||||
import utils.TreeNode
|
||||
import utils.printTree
|
||||
|
||||
var path: MutableList<TreeNode>? = null
|
||||
var res: MutableList<MutableList<TreeNode>>? = null
|
||||
|
||||
/* Preorder traversal: Example 2 */
|
||||
fun preOrder(root: TreeNode?) {
|
||||
if (root == null) {
|
||||
return
|
||||
}
|
||||
// Attempt
|
||||
path!!.add(root)
|
||||
if (root._val == 7) {
|
||||
// Record solution
|
||||
res!!.add(path!!.toMutableList())
|
||||
}
|
||||
preOrder(root.left)
|
||||
preOrder(root.right)
|
||||
// Backtrack
|
||||
path!!.removeAt(path!!.size - 1)
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7))
|
||||
println("\nInitialize binary tree")
|
||||
printTree(root)
|
||||
|
||||
// Preorder traversal
|
||||
path = mutableListOf()
|
||||
res = mutableListOf()
|
||||
preOrder(root)
|
||||
|
||||
println("\nOutput all paths from root node to node 7")
|
||||
for (path in res!!) {
|
||||
val _vals = mutableListOf<Int>()
|
||||
for (node in path) {
|
||||
_vals.add(node._val)
|
||||
}
|
||||
println(_vals)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* File: preorder_traversal_iii_compact.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.preorder_traversal_iii_compact
|
||||
|
||||
import utils.TreeNode
|
||||
import utils.printTree
|
||||
|
||||
var path: MutableList<TreeNode>? = null
|
||||
var res: MutableList<MutableList<TreeNode>>? = null
|
||||
|
||||
/* Preorder traversal: Example 3 */
|
||||
fun preOrder(root: TreeNode?) {
|
||||
// Pruning
|
||||
if (root == null || root._val == 3) {
|
||||
return
|
||||
}
|
||||
// Attempt
|
||||
path!!.add(root)
|
||||
if (root._val == 7) {
|
||||
// Record solution
|
||||
res!!.add(path!!.toMutableList())
|
||||
}
|
||||
preOrder(root.left)
|
||||
preOrder(root.right)
|
||||
// Backtrack
|
||||
path!!.removeAt(path!!.size - 1)
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7))
|
||||
println("\nInitialize binary tree")
|
||||
printTree(root)
|
||||
|
||||
// Preorder traversal
|
||||
path = mutableListOf()
|
||||
res = mutableListOf()
|
||||
preOrder(root)
|
||||
|
||||
println("\nOutput all paths from root node to node 7, paths do not include nodes with value 3")
|
||||
for (path in res!!) {
|
||||
val _vals = mutableListOf<Int>()
|
||||
for (node in path) {
|
||||
_vals.add(node._val)
|
||||
}
|
||||
println(_vals)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* File: preorder_traversal_iii_template.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.preorder_traversal_iii_template
|
||||
|
||||
import utils.TreeNode
|
||||
import utils.printTree
|
||||
|
||||
/* Check if the current state is a solution */
|
||||
fun isSolution(state: MutableList<TreeNode?>): Boolean {
|
||||
return state.isNotEmpty() && state[state.size - 1]?._val == 7
|
||||
}
|
||||
|
||||
/* Record solution */
|
||||
fun recordSolution(state: MutableList<TreeNode?>?, res: MutableList<MutableList<TreeNode?>?>) {
|
||||
res.add(state!!.toMutableList())
|
||||
}
|
||||
|
||||
/* Check if the choice is valid under the current state */
|
||||
fun isValid(state: MutableList<TreeNode?>?, choice: TreeNode?): Boolean {
|
||||
return choice != null && choice._val != 3
|
||||
}
|
||||
|
||||
/* Update state */
|
||||
fun makeChoice(state: MutableList<TreeNode?>, choice: TreeNode?) {
|
||||
state.add(choice)
|
||||
}
|
||||
|
||||
/* Restore state */
|
||||
fun undoChoice(state: MutableList<TreeNode?>, choice: TreeNode?) {
|
||||
state.removeLast()
|
||||
}
|
||||
|
||||
/* Backtracking algorithm: Example 3 */
|
||||
fun backtrack(
|
||||
state: MutableList<TreeNode?>,
|
||||
choices: MutableList<TreeNode?>,
|
||||
res: MutableList<MutableList<TreeNode?>?>
|
||||
) {
|
||||
// Check if it is a solution
|
||||
if (isSolution(state)) {
|
||||
// Record solution
|
||||
recordSolution(state, res)
|
||||
}
|
||||
// Traverse all choices
|
||||
for (choice in choices) {
|
||||
// Pruning: check if the choice is valid
|
||||
if (isValid(state, choice)) {
|
||||
// Attempt: make choice, update state
|
||||
makeChoice(state, choice)
|
||||
// Proceed to the next round of selection
|
||||
backtrack(state, mutableListOf(choice!!.left, choice.right), res)
|
||||
// Backtrack: undo choice, restore to previous state
|
||||
undoChoice(state, choice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7))
|
||||
println("\nInitialize binary tree")
|
||||
printTree(root)
|
||||
|
||||
// Backtracking algorithm
|
||||
val res = mutableListOf<MutableList<TreeNode?>?>()
|
||||
backtrack(mutableListOf(), mutableListOf(root), res)
|
||||
|
||||
println("\nOutput all paths from root node to node 7, requiring paths do not include nodes with value 3")
|
||||
for (path in res) {
|
||||
val vals = mutableListOf<Int>()
|
||||
for (node in path!!) {
|
||||
if (node != null) {
|
||||
vals.add(node._val)
|
||||
}
|
||||
}
|
||||
println(vals)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* File: subset_sum_i.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.subset_sum_i
|
||||
|
||||
/* Backtracking algorithm: Subset sum I */
|
||||
fun backtrack(
|
||||
state: MutableList<Int>,
|
||||
target: Int,
|
||||
choices: IntArray,
|
||||
start: Int,
|
||||
res: MutableList<MutableList<Int>?>
|
||||
) {
|
||||
// When the subset sum equals target, record the solution
|
||||
if (target == 0) {
|
||||
res.add(state.toMutableList())
|
||||
return
|
||||
}
|
||||
// Traverse all choices
|
||||
// Pruning 2: start traversing from start to avoid generating duplicate subsets
|
||||
for (i in start..<choices.size) {
|
||||
// Pruning 1: if the subset sum exceeds target, end the loop directly
|
||||
// This is because the array is sorted, and later elements are larger, so the subset sum will definitely exceed target
|
||||
if (target - choices[i] < 0) {
|
||||
break
|
||||
}
|
||||
// Attempt: make choice, update target, start
|
||||
state.add(choices[i])
|
||||
// Proceed to the next round of selection
|
||||
backtrack(state, target - choices[i], choices, i, res)
|
||||
// Backtrack: undo choice, restore to previous state
|
||||
state.removeAt(state.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve subset sum I */
|
||||
fun subsetSumI(nums: IntArray, target: Int): MutableList<MutableList<Int>?> {
|
||||
val state = mutableListOf<Int>() // State (subset)
|
||||
nums.sort() // Sort nums
|
||||
val start = 0 // Start point for traversal
|
||||
val res = mutableListOf<MutableList<Int>?>() // Result list (subset list)
|
||||
backtrack(state, target, nums, start, res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val nums = intArrayOf(3, 4, 5)
|
||||
val target = 9
|
||||
|
||||
val res = subsetSumI(nums, target)
|
||||
|
||||
println("Input array nums = ${nums.contentToString()}, target = $target")
|
||||
println("All subsets with sum equal to $target res = $res")
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* File: subset_sum_i_native.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.subset_sum_i_naive
|
||||
|
||||
/* Backtracking algorithm: Subset sum I */
|
||||
fun backtrack(
|
||||
state: MutableList<Int>,
|
||||
target: Int,
|
||||
total: Int,
|
||||
choices: IntArray,
|
||||
res: MutableList<MutableList<Int>?>
|
||||
) {
|
||||
// When the subset sum equals target, record the solution
|
||||
if (total == target) {
|
||||
res.add(state.toMutableList())
|
||||
return
|
||||
}
|
||||
// Traverse all choices
|
||||
for (i in choices.indices) {
|
||||
// Pruning: if the subset sum exceeds target, skip this choice
|
||||
if (total + choices[i] > target) {
|
||||
continue
|
||||
}
|
||||
// Attempt: make choice, update element sum total
|
||||
state.add(choices[i])
|
||||
// Proceed to the next round of selection
|
||||
backtrack(state, target, total + choices[i], choices, res)
|
||||
// Backtrack: undo choice, restore to previous state
|
||||
state.removeAt(state.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve subset sum I (including duplicate subsets) */
|
||||
fun subsetSumINaive(nums: IntArray, target: Int): MutableList<MutableList<Int>?> {
|
||||
val state = mutableListOf<Int>() // State (subset)
|
||||
val total = 0 // Subset sum
|
||||
val res = mutableListOf<MutableList<Int>?>() // Result list (subset list)
|
||||
backtrack(state, target, total, nums, res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val nums = intArrayOf(3, 4, 5)
|
||||
val target = 9
|
||||
val res = subsetSumINaive(nums, target)
|
||||
|
||||
println("Input array nums = ${nums.contentToString()}, target = $target")
|
||||
println("All subsets with sum equal to $target res = $res")
|
||||
println("Please note that this method outputs results containing duplicate sets")
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* File: subset_sum_ii.kt
|
||||
* Created Time: 2024-01-25
|
||||
* Author: curtishd (1023632660@qq.com)
|
||||
*/
|
||||
|
||||
package chapter_backtracking.subset_sum_ii
|
||||
|
||||
/* Backtracking algorithm: Subset sum II */
|
||||
fun backtrack(
|
||||
state: MutableList<Int>,
|
||||
target: Int,
|
||||
choices: IntArray,
|
||||
start: Int,
|
||||
res: MutableList<MutableList<Int>?>
|
||||
) {
|
||||
// When the subset sum equals target, record the solution
|
||||
if (target == 0) {
|
||||
res.add(state.toMutableList())
|
||||
return
|
||||
}
|
||||
// Traverse all choices
|
||||
// Pruning 2: start traversing from start to avoid generating duplicate subsets
|
||||
// Pruning 3: start traversing from start to avoid repeatedly selecting the same element
|
||||
for (i in start..<choices.size) {
|
||||
// Pruning 1: if the subset sum exceeds target, end the loop directly
|
||||
// This is because the array is sorted, and later elements are larger, so the subset sum will definitely exceed target
|
||||
if (target - choices[i] < 0) {
|
||||
break
|
||||
}
|
||||
// Pruning 4: if this element equals the left element, it means this search branch is duplicate, skip it directly
|
||||
if (i > start && choices[i] == choices[i - 1]) {
|
||||
continue
|
||||
}
|
||||
// Attempt: make choice, update target, start
|
||||
state.add(choices[i])
|
||||
// Proceed to the next round of selection
|
||||
backtrack(state, target - choices[i], choices, i + 1, res)
|
||||
// Backtrack: undo choice, restore to previous state
|
||||
state.removeAt(state.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve subset sum II */
|
||||
fun subsetSumII(nums: IntArray, target: Int): MutableList<MutableList<Int>?> {
|
||||
val state = mutableListOf<Int>() // State (subset)
|
||||
nums.sort() // Sort nums
|
||||
val start = 0 // Start point for traversal
|
||||
val res = mutableListOf<MutableList<Int>?>() // Result list (subset list)
|
||||
backtrack(state, target, nums, start, res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fun main() {
|
||||
val nums = intArrayOf(4, 4, 5)
|
||||
val target = 9
|
||||
val res = subsetSumII(nums, target)
|
||||
|
||||
println("Input array nums = ${nums.contentToString()}, target = $target")
|
||||
println("All subsets with sum equal to $target res = $res")
|
||||
}
|
||||
Reference in New Issue
Block a user