Deprecate array methods that take function names as parameters.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
//! Module containing all deprecated API that will be removed in the next major version.
|
||||
|
||||
use crate::func::RegisterNativeFunction;
|
||||
use crate::plugin::*;
|
||||
use crate::types::dynamic::Variant;
|
||||
use crate::{
|
||||
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, NativeCallContext,
|
||||
@@ -631,3 +632,593 @@ impl Module {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[export_module]
|
||||
pub mod deprecated_array_functions {
|
||||
use crate::packages::array_basic::array_functions::*;
|
||||
use crate::{Array, INT};
|
||||
|
||||
/// Iterate through all the elements in the array, applying a function named by `mapper` to each
|
||||
/// element in turn, and return the results as a new array.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.map(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `mapper` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn square(x) { x * x }
|
||||
///
|
||||
/// fn multiply(x, i) { x * i }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.map("square");
|
||||
///
|
||||
/// print(y); // prints "[1, 4, 9, 16, 25]"
|
||||
///
|
||||
/// let y = x.map("multiply");
|
||||
///
|
||||
/// print(y); // prints "[0, 2, 6, 12, 20]"
|
||||
/// ```
|
||||
#[rhai_fn(name = "map", return_raw)]
|
||||
pub fn map_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: Array,
|
||||
mapper: &str,
|
||||
) -> RhaiResultOf<Array> {
|
||||
map(ctx, array, FnPtr::new(mapper)?)
|
||||
}
|
||||
/// Iterate through all the elements in the array, applying a function named by `filter` to each
|
||||
/// element in turn, and return a copy of all elements (in order) that return `true` as a new array.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.filter(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn screen(x, i) { x * i >= 10 }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.filter("is_odd");
|
||||
///
|
||||
/// print(y); // prints "[1, 3, 5]"
|
||||
///
|
||||
/// let y = x.filter("screen");
|
||||
///
|
||||
/// print(y); // prints "[12, 20]"
|
||||
/// ```
|
||||
#[rhai_fn(name = "filter", return_raw)]
|
||||
pub fn filter_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: Array,
|
||||
filter_func: &str,
|
||||
) -> RhaiResultOf<Array> {
|
||||
filter(ctx, array, FnPtr::new(filter_func)?)
|
||||
}
|
||||
/// Iterate through all the elements in the array, applying a function named by `filter` to each
|
||||
/// element in turn, and return the index of the first element that returns `true`.
|
||||
/// If no element returns `true`, `-1` is returned.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.index_of(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn is_special(x) { x > 3 }
|
||||
///
|
||||
/// fn is_dumb(x) { x > 8 }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5];
|
||||
///
|
||||
/// print(x.index_of("is_special")); // prints 3
|
||||
///
|
||||
/// print(x.index_of("is_dumb")); // prints -1
|
||||
/// ```
|
||||
#[rhai_fn(name = "index_of", return_raw, pure)]
|
||||
pub fn index_of_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
filter: &str,
|
||||
) -> RhaiResultOf<INT> {
|
||||
index_of_filter(ctx, array, FnPtr::new(filter)?)
|
||||
}
|
||||
/// Iterate through all the elements in the array, starting from a particular `start` position,
|
||||
/// applying a function named by `filter` to each element in turn, and return the index of the
|
||||
/// first element that returns `true`. If no element returns `true`, `-1` is returned.
|
||||
///
|
||||
/// * If `start` < 0, position counts from the end of the array (`-1` is the last element).
|
||||
/// * If `start` < -length of array, position counts from the beginning of the array.
|
||||
/// * If `start` ≥ length of array, `-1` is returned.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.index_of(Fn("fn_name"), start)` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn plural(x) { x > 1 }
|
||||
///
|
||||
/// fn singular(x) { x < 2 }
|
||||
///
|
||||
/// fn screen(x, i) { x * i > 20 }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5];
|
||||
///
|
||||
/// print(x.index_of("plural", 3)); // prints 5: 2 > 1
|
||||
///
|
||||
/// print(x.index_of("singular", 9)); // prints -1: nothing < 2 past index 9
|
||||
///
|
||||
/// print(x.index_of("plural", 15)); // prints -1: nothing found past end of array
|
||||
///
|
||||
/// print(x.index_of("plural", -5)); // prints 9: -5 = start from index 8
|
||||
///
|
||||
/// print(x.index_of("plural", -99)); // prints 1: -99 = start from beginning
|
||||
///
|
||||
/// print(x.index_of("screen", 8)); // prints 10: 3 * 10 > 20
|
||||
/// ```
|
||||
#[rhai_fn(name = "index_of", return_raw, pure)]
|
||||
pub fn index_of_by_fn_name_starting_from(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
filter: &str,
|
||||
start: INT,
|
||||
) -> RhaiResultOf<INT> {
|
||||
index_of_filter_starting_from(ctx, array, FnPtr::new(filter)?, start)
|
||||
}
|
||||
/// Return `true` if any element in the array that returns `true` when applied a function named
|
||||
/// by `filter`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.some(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn large(x) { x > 3 }
|
||||
///
|
||||
/// fn huge(x) { x > 10 }
|
||||
///
|
||||
/// fn screen(x, i) { i > x }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5];
|
||||
///
|
||||
/// print(x.some("large")); // prints true
|
||||
///
|
||||
/// print(x.some("huge")); // prints false
|
||||
///
|
||||
/// print(x.some("screen")); // prints true
|
||||
/// ```
|
||||
#[rhai_fn(name = "some", return_raw, pure)]
|
||||
pub fn some_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
filter: &str,
|
||||
) -> RhaiResultOf<bool> {
|
||||
some(ctx, array, FnPtr::new(filter)?)
|
||||
}
|
||||
/// Return `true` if all elements in the array return `true` when applied a function named by `filter`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.all(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// let x = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5];
|
||||
///
|
||||
/// print(x.all(|v| v > 3)); // prints false
|
||||
///
|
||||
/// print(x.all(|v| v > 1)); // prints true
|
||||
///
|
||||
/// print(x.all(|v, i| i > v)); // prints false
|
||||
/// ```
|
||||
#[rhai_fn(name = "all", return_raw, pure)]
|
||||
pub fn all_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
filter: &str,
|
||||
) -> RhaiResultOf<bool> {
|
||||
all(ctx, array, FnPtr::new(filter)?)
|
||||
}
|
||||
/// Remove duplicated _consecutive_ elements from the array that return `true` when applied a
|
||||
/// function named by `comparer`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.dedup(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// No element is removed if the correct `comparer` function does not exist.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// * `element1`: copy of the current array element to compare
|
||||
/// * `element2`: copy of the next array element to compare
|
||||
///
|
||||
/// ## Return Value
|
||||
///
|
||||
/// `true` if `element1 == element2`, otherwise `false`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn declining(a, b) { a >= b }
|
||||
///
|
||||
/// let x = [1, 2, 2, 2, 3, 1, 2, 3, 4, 3, 3, 2, 1];
|
||||
///
|
||||
/// x.dedup("declining");
|
||||
///
|
||||
/// print(x); // prints "[1, 2, 3, 4]"
|
||||
/// ```
|
||||
#[rhai_fn(name = "dedup", return_raw)]
|
||||
pub fn dedup_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
comparer: &str,
|
||||
) -> RhaiResultOf<()> {
|
||||
Ok(dedup_by_comparer(ctx, array, FnPtr::new(comparer)?))
|
||||
}
|
||||
/// Reduce an array by iterating through all elements while applying a function named by `reducer`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.reduce(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `reducer` must exist taking these parameters:
|
||||
///
|
||||
/// * `result`: accumulated result, initially `()`
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn process(r, x) {
|
||||
/// x + (r ?? 0)
|
||||
/// }
|
||||
/// fn process_extra(r, x, i) {
|
||||
/// x + i + (r ?? 0)
|
||||
/// }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.reduce("process");
|
||||
///
|
||||
/// print(y); // prints 15
|
||||
///
|
||||
/// let y = x.reduce("process_extra");
|
||||
///
|
||||
/// print(y); // prints 25
|
||||
/// ```
|
||||
#[rhai_fn(name = "reduce", return_raw, pure)]
|
||||
pub fn reduce_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
reducer: &str,
|
||||
) -> RhaiResult {
|
||||
reduce(ctx, array, FnPtr::new(reducer)?)
|
||||
}
|
||||
/// Reduce an array by iterating through all elements while applying a function named by `reducer`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.reduce(Fn("fn_name"), initial)` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `reducer` must exist taking these parameters:
|
||||
///
|
||||
/// * `result`: accumulated result, starting with the value of `initial`
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn process(r, x) { x + r }
|
||||
///
|
||||
/// fn process_extra(r, x, i) { x + i + r }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.reduce("process", 5);
|
||||
///
|
||||
/// print(y); // prints 20
|
||||
///
|
||||
/// let y = x.reduce("process_extra", 5);
|
||||
///
|
||||
/// print(y); // prints 30
|
||||
/// ```
|
||||
#[rhai_fn(name = "reduce", return_raw, pure)]
|
||||
pub fn reduce_by_fn_name_with_initial(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
reducer: &str,
|
||||
initial: Dynamic,
|
||||
) -> RhaiResult {
|
||||
reduce_with_initial(ctx, array, FnPtr::new(reducer)?, initial)
|
||||
}
|
||||
/// Reduce an array by iterating through all elements, in _reverse_ order,
|
||||
/// while applying a function named by `reducer`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.reduce_rev(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `reducer` must exist taking these parameters:
|
||||
///
|
||||
/// * `result`: accumulated result, initially `()`
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn process(r, x) {
|
||||
/// x + (r ?? 0)
|
||||
/// }
|
||||
/// fn process_extra(r, x, i) {
|
||||
/// x + i + (r ?? 0)
|
||||
/// }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.reduce_rev("process");
|
||||
///
|
||||
/// print(y); // prints 15
|
||||
///
|
||||
/// let y = x.reduce_rev("process_extra");
|
||||
///
|
||||
/// print(y); // prints 25
|
||||
/// ```
|
||||
#[rhai_fn(name = "reduce_rev", return_raw, pure)]
|
||||
pub fn reduce_rev_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
reducer: &str,
|
||||
) -> RhaiResult {
|
||||
reduce_rev(ctx, array, FnPtr::new(reducer)?)
|
||||
}
|
||||
/// Reduce an array by iterating through all elements, in _reverse_ order,
|
||||
/// while applying a function named by `reducer`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.reduce_rev(Fn("fn_name"), initial)` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `reducer` must exist taking these parameters:
|
||||
///
|
||||
/// * `result`: accumulated result, starting with the value of `initial`
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn process(r, x) { x + r }
|
||||
///
|
||||
/// fn process_extra(r, x, i) { x + i + r }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.reduce_rev("process", 5);
|
||||
///
|
||||
/// print(y); // prints 20
|
||||
///
|
||||
/// let y = x.reduce_rev("process_extra", 5);
|
||||
///
|
||||
/// print(y); // prints 30
|
||||
/// ```
|
||||
#[rhai_fn(name = "reduce_rev", return_raw, pure)]
|
||||
pub fn reduce_rev_by_fn_name_with_initial(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
reducer: &str,
|
||||
initial: Dynamic,
|
||||
) -> RhaiResult {
|
||||
reduce_rev_with_initial(ctx, array, FnPtr::new(reducer)?, initial)
|
||||
}
|
||||
/// Sort the array based on applying a function named by `comparer`.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.sort(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `comparer` must exist taking these parameters:
|
||||
///
|
||||
/// * `element1`: copy of the current array element to compare
|
||||
/// * `element2`: copy of the next array element to compare
|
||||
///
|
||||
/// ## Return Value
|
||||
///
|
||||
/// * Any integer > 0 if `element1 > element2`
|
||||
/// * Zero if `element1 == element2`
|
||||
/// * Any integer < 0 if `element1 < element2`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn reverse(a, b) {
|
||||
/// if a > b {
|
||||
/// -1
|
||||
/// } else if a < b {
|
||||
/// 1
|
||||
/// } else {
|
||||
/// 0
|
||||
/// }
|
||||
/// }
|
||||
/// let x = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10];
|
||||
///
|
||||
/// x.sort("reverse");
|
||||
///
|
||||
/// print(x); // prints "[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]"
|
||||
/// ```
|
||||
#[rhai_fn(name = "sort", return_raw)]
|
||||
pub fn sort_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
comparer: &str,
|
||||
) -> RhaiResultOf<()> {
|
||||
sort(ctx, array, FnPtr::new(comparer)?)
|
||||
}
|
||||
/// Remove all elements in the array that returns `true` when applied a function named by `filter`
|
||||
/// and return them as a new array.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.drain(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn small(x) { x < 3 }
|
||||
///
|
||||
/// fn screen(x, i) { x + i > 5 }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.drain("small");
|
||||
///
|
||||
/// print(x); // prints "[3, 4, 5]"
|
||||
///
|
||||
/// print(y); // prints "[1, 2]"
|
||||
///
|
||||
/// let z = x.drain("screen");
|
||||
///
|
||||
/// print(x); // prints "[3, 4]"
|
||||
///
|
||||
/// print(z); // prints "[5]"
|
||||
/// ```
|
||||
#[rhai_fn(name = "drain", return_raw)]
|
||||
pub fn drain_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
filter: &str,
|
||||
) -> RhaiResultOf<Array> {
|
||||
drain(ctx, array, FnPtr::new(filter)?)
|
||||
}
|
||||
/// Remove all elements in the array that do not return `true` when applied a function named by
|
||||
/// `filter` and return them as a new array.
|
||||
///
|
||||
/// # Deprecated API
|
||||
///
|
||||
/// This method is deprecated and will be removed from the next major version.
|
||||
/// Use `array.retain(Fn("fn_name"))` instead.
|
||||
///
|
||||
/// # Function Parameters
|
||||
///
|
||||
/// A function with the same name as the value of `filter` must exist taking these parameters:
|
||||
///
|
||||
/// * `element`: copy of array element
|
||||
/// * `index` _(optional)_: current index in the array
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// fn large(x) { x >= 3 }
|
||||
///
|
||||
/// fn screen(x, i) { x + i <= 5 }
|
||||
///
|
||||
/// let x = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let y = x.retain("large");
|
||||
///
|
||||
/// print(x); // prints "[3, 4, 5]"
|
||||
///
|
||||
/// print(y); // prints "[1, 2]"
|
||||
///
|
||||
/// let z = x.retain("screen");
|
||||
///
|
||||
/// print(x); // prints "[3, 4]"
|
||||
///
|
||||
/// print(z); // prints "[5]"
|
||||
/// ```
|
||||
#[rhai_fn(name = "retain", return_raw)]
|
||||
pub fn retain_by_fn_name(
|
||||
ctx: NativeCallContext,
|
||||
array: &mut Array,
|
||||
filter: &str,
|
||||
) -> RhaiResultOf<Array> {
|
||||
retain(ctx, array, FnPtr::new(filter)?)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user