mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-04 20:03:40 +00:00
curve: Expand lints (#530)
Adds a lints section to the top of lib.rs with the following:
#![warn(
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
`warn` is used instead of `deny` to prevent the lints from firing during
local development, however we already configure `-D warnings` in CI so
if any lint fails on checked-in code, it will cause a CI failure.
This commit also fixes or explicitly allows any current violations of
these lints. The main ones were:
- `clippy::unwrap_used`: replaces usages of `unwrap` with `expect`
- `rust_2018_idioms`: no implicit lifetimes, which were present on
usages of `core::fmt::Formatter`
This commit is contained in:
parent
8e0cef5b72
commit
c058cd9057
18 changed files with 54 additions and 48 deletions
|
|
@ -527,7 +527,7 @@ impl<'a> Neg for &'a AffineNielsPoint {
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
impl Debug for ProjectivePoint {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}",
|
||||
|
|
@ -537,7 +537,7 @@ impl Debug for ProjectivePoint {
|
|||
}
|
||||
|
||||
impl Debug for CompletedPoint {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}",
|
||||
|
|
@ -547,7 +547,7 @@ impl Debug for CompletedPoint {
|
|||
}
|
||||
|
||||
impl Debug for AffineNielsPoint {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}",
|
||||
|
|
@ -557,7 +557,7 @@ impl Debug for AffineNielsPoint {
|
|||
}
|
||||
|
||||
impl Debug for ProjectiveNielsPoint {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}",
|
||||
&self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ use fiat_crypto::curve25519_32::*;
|
|||
pub struct FieldElement2625(pub(crate) [u32; 10]);
|
||||
|
||||
impl Debug for FieldElement2625 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "FieldElement2625({:?})", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ use fiat_crypto::curve25519_64::*;
|
|||
pub struct FieldElement51(pub(crate) [u64; 5]);
|
||||
|
||||
impl Debug for FieldElement51 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "FieldElement51({:?})", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,8 +154,7 @@ impl VartimeMultiscalarMul for Pippenger {
|
|||
});
|
||||
|
||||
// Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`.
|
||||
// `unwrap()` always succeeds because we know we have more than zero digits.
|
||||
let hi_column = columns.next().unwrap();
|
||||
let hi_column = columns.next().expect("should have more than zero digits");
|
||||
|
||||
Some(columns.fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ use zeroize::Zeroize;
|
|||
pub struct FieldElement2625(pub(crate) [u32; 10]);
|
||||
|
||||
impl Debug for FieldElement2625 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "FieldElement2625({:?})", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use crate::constants;
|
|||
pub struct Scalar29(pub [u32; 9]);
|
||||
|
||||
impl Debug for Scalar29 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "Scalar29: {:?}", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ use zeroize::Zeroize;
|
|||
pub struct FieldElement51(pub(crate) [u64; 5]);
|
||||
|
||||
impl Debug for FieldElement51 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "FieldElement51({:?})", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::constants;
|
|||
pub struct Scalar52(pub [u64; 5]);
|
||||
|
||||
impl Debug for Scalar52 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "Scalar52: {:?}", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ impl ConditionallySelectable for CachedPoint {
|
|||
}
|
||||
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a> Neg for &'a CachedPoint {
|
||||
impl Neg for &CachedPoint {
|
||||
type Output = CachedPoint;
|
||||
/// Lazily negate the point.
|
||||
///
|
||||
|
|
@ -255,11 +255,11 @@ impl<'a> Neg for &'a CachedPoint {
|
|||
}
|
||||
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
|
||||
impl Add<&CachedPoint> for &ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Add an `ExtendedPoint` and a `CachedPoint`.
|
||||
fn add(self, other: &'b CachedPoint) -> ExtendedPoint {
|
||||
fn add(self, other: &CachedPoint) -> ExtendedPoint {
|
||||
// The coefficients of an `ExtendedPoint` are reduced after
|
||||
// every operation. If the `CachedPoint` was negated, its
|
||||
// coefficients grow by one bit. So on input, `self` is
|
||||
|
|
@ -293,7 +293,7 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
|
|||
}
|
||||
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
|
||||
impl Sub<&CachedPoint> for &ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Implement subtraction by negating the point and adding.
|
||||
|
|
@ -301,14 +301,14 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
|
|||
/// Empirically, this seems about the same cost as a custom
|
||||
/// subtraction impl (maybe because the benefit is cancelled by
|
||||
/// increased code size?)
|
||||
fn sub(self, other: &'b CachedPoint) -> ExtendedPoint {
|
||||
fn sub(self, other: &CachedPoint) -> ExtendedPoint {
|
||||
self + &(-other)
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
|
||||
fn from(point: &'a edwards::EdwardsPoint) -> Self {
|
||||
impl From<&edwards::EdwardsPoint> for LookupTable<CachedPoint> {
|
||||
fn from(point: &edwards::EdwardsPoint) -> Self {
|
||||
let P = ExtendedPoint::from(*point);
|
||||
let mut points = [CachedPoint::from(P); 8];
|
||||
for i in 0..7 {
|
||||
|
|
@ -319,8 +319,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
|
|||
}
|
||||
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
|
||||
fn from(point: &'a edwards::EdwardsPoint) -> Self {
|
||||
impl From<&edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
|
||||
fn from(point: &edwards::EdwardsPoint) -> Self {
|
||||
let A = ExtendedPoint::from(*point);
|
||||
let mut Ai = [CachedPoint::from(A); 8];
|
||||
let A2 = A.double();
|
||||
|
|
@ -334,8 +334,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
|
|||
|
||||
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> {
|
||||
fn from(point: &'a edwards::EdwardsPoint) -> Self {
|
||||
impl From<&edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> {
|
||||
fn from(point: &edwards::EdwardsPoint) -> Self {
|
||||
let A = ExtendedPoint::from(*point);
|
||||
let mut Ai = [CachedPoint::from(A); 64];
|
||||
let A2 = A.double();
|
||||
|
|
|
|||
|
|
@ -760,7 +760,7 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 {
|
|||
}
|
||||
|
||||
#[unsafe_target_feature("avx2")]
|
||||
impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 {
|
||||
impl Mul<&FieldElement2625x4> for &FieldElement2625x4 {
|
||||
type Output = FieldElement2625x4;
|
||||
/// Multiply `self` by `rhs`.
|
||||
///
|
||||
|
|
@ -776,7 +776,7 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 {
|
|||
///
|
||||
#[rustfmt::skip] // keep alignment of z* calculations
|
||||
#[inline]
|
||||
fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 {
|
||||
fn mul(self, rhs: &FieldElement2625x4) -> FieldElement2625x4 {
|
||||
#[inline(always)]
|
||||
fn m(x: u32x8, y: u32x8) -> u64x4 {
|
||||
x.mul32(y)
|
||||
|
|
|
|||
|
|
@ -123,8 +123,7 @@ pub mod spec {
|
|||
});
|
||||
|
||||
// Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`.
|
||||
// `unwrap()` always succeeds because we know we have more than zero digits.
|
||||
let hi_column = columns.next().unwrap();
|
||||
let hi_column = columns.next().expect("should have more than zero digits");
|
||||
|
||||
Some(
|
||||
columns
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ impl ConstantTimeEq for CompressedEdwardsY {
|
|||
}
|
||||
|
||||
impl Debug for CompressedEdwardsY {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "CompressedEdwardsY: {:?}", self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
|
@ -301,7 +301,7 @@ impl<'de> Deserialize<'de> for EdwardsPoint {
|
|||
impl<'de> Visitor<'de> for EdwardsPointVisitor {
|
||||
type Value = EdwardsPoint;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
formatter.write_str("a valid point in Edwards y + sign format")
|
||||
}
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY {
|
|||
impl<'de> Visitor<'de> for CompressedEdwardsYVisitor {
|
||||
type Value = CompressedEdwardsY;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
formatter.write_str("32 bytes of data")
|
||||
}
|
||||
|
||||
|
|
@ -1052,7 +1052,7 @@ macro_rules! impl_basepoint_table {
|
|||
}
|
||||
|
||||
impl Debug for $name {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "{:?}([\n", stringify!($name))?;
|
||||
for i in 0..32 {
|
||||
write!(f, "\t{:?},\n", &self.0[i])?;
|
||||
|
|
@ -1263,7 +1263,7 @@ impl EdwardsPoint {
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
impl Debug for EdwardsPoint {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
//! Field operations defined in terms of other field operations, such as
|
||||
//! field inversion or square roots, are defined here.
|
||||
|
||||
#![allow(unused_qualifications)]
|
||||
|
||||
use core::cmp::{Eq, PartialEq};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
|
|
|||
|
|
@ -17,15 +17,24 @@
|
|||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))]
|
||||
#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))]
|
||||
#![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))]
|
||||
//------------------------------------------------------------------------
|
||||
// Documentation:
|
||||
//------------------------------------------------------------------------
|
||||
#![deny(missing_docs)]
|
||||
#![doc(
|
||||
html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png"
|
||||
)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
//------------------------------------------------------------------------
|
||||
// Linting:
|
||||
//------------------------------------------------------------------------
|
||||
#![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))]
|
||||
#![warn(
|
||||
clippy::unwrap_used,
|
||||
missing_docs,
|
||||
rust_2018_idioms,
|
||||
unused_lifetimes,
|
||||
unused_qualifications
|
||||
)]
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// External dependencies:
|
||||
|
|
@ -44,9 +53,6 @@ extern crate std;
|
|||
#[cfg(feature = "digest")]
|
||||
pub use digest;
|
||||
|
||||
#[cfg(feature = "group")]
|
||||
extern crate group;
|
||||
|
||||
// Internal macros. Must come first!
|
||||
#[macro_use]
|
||||
pub(crate) mod macros;
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ impl<'de> Deserialize<'de> for RistrettoPoint {
|
|||
impl<'de> Visitor<'de> for RistrettoPointVisitor {
|
||||
type Value = RistrettoPoint;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
formatter.write_str("a valid point in Ristretto format")
|
||||
}
|
||||
|
||||
|
|
@ -443,7 +443,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto {
|
|||
impl<'de> Visitor<'de> for CompressedRistrettoVisitor {
|
||||
type Value = CompressedRistretto;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
formatter.write_str("32 bytes of data")
|
||||
}
|
||||
|
||||
|
|
@ -1155,13 +1155,13 @@ impl ConditionallySelectable for RistrettoPoint {
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
impl Debug for CompressedRistretto {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "CompressedRistretto: {:?}", self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for RistrettoPoint {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
let coset = self.coset4();
|
||||
write!(
|
||||
f,
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ impl Scalar {
|
|||
}
|
||||
|
||||
impl Debug for Scalar {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "Scalar{{\n\tbytes: {:?},\n}}", &self.bytes)
|
||||
}
|
||||
}
|
||||
|
|
@ -430,7 +430,7 @@ impl<'de> Deserialize<'de> for Scalar {
|
|||
impl<'de> Visitor<'de> for ScalarVisitor {
|
||||
type Value = Scalar;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
formatter.write_str(
|
||||
"a sequence of 32 bytes whose little-endian interpretation is less than the \
|
||||
basepoint order ℓ",
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ pub trait VartimeMultiscalarMul {
|
|||
scalars,
|
||||
points.into_iter().map(|P| Some(P.borrow().clone())),
|
||||
)
|
||||
.unwrap()
|
||||
.expect("should return some point")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +365,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized {
|
|||
dynamic_scalars,
|
||||
dynamic_points.into_iter().map(|P| Some(P.borrow().clone())),
|
||||
)
|
||||
.unwrap()
|
||||
.expect("should return some point")
|
||||
}
|
||||
|
||||
/// Given `static_scalars`, an iterator of public scalars
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ macro_rules! impl_lookup_table {
|
|||
}
|
||||
|
||||
impl<T: Debug> Debug for $name<T> {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "{:?}(", stringify!($name))?;
|
||||
|
||||
for x in self.0.iter() {
|
||||
|
|
@ -193,7 +193,7 @@ impl<T: Copy> NafLookupTable5<T> {
|
|||
}
|
||||
|
||||
impl<T: Debug> Debug for NafLookupTable5<T> {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "NafLookupTable5({:?})", self.0)
|
||||
}
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ impl<T: Copy> NafLookupTable8<T> {
|
|||
|
||||
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
|
||||
impl<T: Debug> Debug for NafLookupTable8<T> {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
writeln!(f, "NafLookupTable8([")?;
|
||||
for i in 0..64 {
|
||||
writeln!(f, "\t{:?},", &self.0[i])?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue