/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
Dia-Semver
Copyright (C) 2018-2022 Anonymous
There are several releases over multiple years,
they are listed as ranges, such as: "2018-2022".
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/
pub mod parse_errors;
mod parser;
mod tests;
use {
alloc::string::{String, ToString},
core::{
cmp::Ordering,
ffi::CStr,
fmt::{self, Display, Formatter},
hash::{Hash, Hasher},
str::FromStr,
},
crate::{Error, PreRelease, Result},
self::parser::Parser,
};
#[cfg(feature="std")]
use std::ffi::OsStr;
/// # Max string length of a version number
const MAX_STR_LEN_OF_A_VERSION_NUMBER: usize = 20;
/// # Starter for pre-release
const PRE_RELEASE_STARTER: char = '-';
/// # Starter for build metadata
const BUILD_METADATA_STARTER: char = '+';
/// # Max input string length allowed to be parsed
#[cfg(target_pointer_width = "8")]
const MAX_INPUT_STR_LEN: usize = 255;
/// # Max input string length allowed to be parsed
#[cfg(not(target_pointer_width = "8"))]
const MAX_INPUT_STR_LEN: usize = 2048;
/// # Semver.
///
/// ## Concepts
///
/// ### Strict parser
///
/// - Does not allow leading/trailing white spaces.
/// - All 3 version numbers are required: major, minor, patch.
///
/// ### Tolerant parser
///
/// - Ignores leading/trailing white spaces.
/// - Minor and patch version numbers are optional.
///
/// This mode is added by the crate author, it's not described in official specification.
///
/// ### Usage
///
/// This struct does not expose internal fields, where the user can make new instance directly. Instead, it provides helper functions:
///
/// - [`new()`][fn:new] makes new instance from raw input version numbers.
/// - [`parse()`][fn:parse] and `parse_*()` use strict parser, while `from_*()` are more tolerant.
///
/// For protection against flood attack, max length of the string (to be parsed) is one of:
///
/// - `255` bytes (on 8-bit machines)
/// - `2048` bytes (on larger machines)
///
/// Since Rust encourages the use of [immutable variables][book:ch03-01], a semver instance should _not_ be changed. Indeed, there are no
/// mutable functions. However there are useful functions to help you make new semver from an existing one: [`new_major()`][fn:new_major],
/// [`new_minor()`][fn:new_minor], [`new_patch()`][fn:new_patch]...
///
/// Others might also come in handy: [`is_stable()`][fn:is_stable], [`is_early()`][fn:is_early]...
///
/// [book:ch03-01]: https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html
/// [fn:new]: #method.new
/// [fn:parse]: #method.parse
/// [fn:is_stable]: #method.is_stable
/// [fn:is_early]: #method.is_early
/// [fn:parse_pre_release]: #method.parse_pre_release
/// [fn:new_major]: #method.new_major
/// [fn:new_minor]: #method.new_minor
/// [fn:new_patch]: #method.new_patch
#[derive(Debug, Default, Clone, Eq)]
pub struct Semver {
/// # Major
major: u64,
/// # Minor
minor: u64,
/// # Patch
patch: u64,
/// # Pre-release
pre_release: Option<String>,
/// # Build metadata
build_metadata: Option<String>,
}
impl Semver {
/// # Makes new semver from raw input version numbers
///
/// This function does not support pre-release and build metadata -- which are required to be parsed. For convenience, it returns a direct
/// instance, not a `Result<Semver>`. If you need pre-release and/or build metadata, you can use [`parse()`][fn:parse].
///
/// If you only have a single major version number, there's a simpler call:
///
/// ```
/// use dia_semver::Semver;
///
/// assert_eq!(Semver::new(2, 0, 0), Semver::from(2_u8));
/// ```
///
/// [fn:parse]: #method.parse
pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
Semver {
major, minor, patch,
pre_release: None, build_metadata: None,
}
}
/// # Parses input string to make a new semver
///
/// - Minor and patch version numbers are **required**.
/// - Leading/trailing white spaces are **not** allowed.
///
/// For convenience, you can use implementation of [`FromStr`][trait:FromStr] trait. It uses _tolerant_ parser, where:
///
/// - Minor and patch version numbers are optional.
/// - Leading/trailing white spaces are ignored.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(Semver::parse("1.2.3")?.to_string(), "1.2.3");
/// assert_eq!(
/// Semver::from_str("\t 1-a.b.c \r\n")?.to_string(),
/// "1.0.0-a.b.c",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
///
/// [trait:FromStr]: https://doc.rust-lang.org/core/str/trait.FromStr.html
pub fn parse<S>(s: S) -> Result<Self> where S: AsRef<str> {
Parser::parse(s.as_ref(), true)
}
/// # Parses an [`&OsStr`][struct:OsStr]
///
/// _See [`Parser`][struct:Parser] for details_.
///
/// [struct:Parser]: struct.Parser.html
/// [struct:OsStr]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
#[cfg(feature="std")]
fn parse_os_str_with_options<S>(s: S, strict: bool) -> Result<Self> where S: AsRef<OsStr> {
match s.as_ref().to_str() {
Some(s) => Parser::parse(s.as_ref(), strict),
None => Err(err!(parse_errors::INVALID_TOKEN)),
}
}
/// # Parses an [`&OsStr`][struct:OsStr]
///
/// This function uses strict parser.
///
/// [struct:OsStr]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
#[cfg(feature="std")]
pub fn parse_os_str<S>(s: S) -> Result<Self> where S: AsRef<OsStr> {
Self::parse_os_str_with_options(s, true)
}
/// # Parses an [`&OsStr`][struct:OsStr]
///
/// This function uses tolerant parser.
///
/// [struct:OsStr]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
#[cfg(feature="std")]
pub fn from_os_str<S>(s: S) -> Result<Self> where S: AsRef<OsStr> {
Self::parse_os_str_with_options(s, false)
}
/// # Parses a [`&CStr`][struct:CStr]
///
/// _See [`Parser`][struct:Parser] for details_.
///
/// [struct:Parser]: struct.Parser.html
/// [struct:CStr]: https://doc.rust-lang.org/core/ffi/struct.CStr.html
fn parse_c_str_with_options<S>(s: S, strict: bool) -> Result<Self> where S: AsRef<CStr> {
match s.as_ref().to_str() {
Ok(s) => Parser::parse(s.as_ref(), strict),
_ => Err(err!(parse_errors::INVALID_TOKEN)),
}
}
/// # Parses a [`&CStr`][struct:CStr]
///
/// This function uses strict parser.
///
/// [struct:CStr]: https://doc.rust-lang.org/core/ffi/struct.CStr.html
pub fn parse_c_str<S>(s: S) -> Result<Self> where S: AsRef<CStr> {
Self::parse_c_str_with_options(s, true)
}
/// # Parses a [`&CStr`][struct:CStr]
///
/// This function uses tolerant parser.
///
/// [struct:CStr]: https://doc.rust-lang.org/core/ffi/struct.CStr.html
pub fn from_c_str<S>(s: S) -> Result<Self> where S: AsRef<CStr> {
Self::parse_c_str_with_options(s, false)
}
/// # Major
pub fn major(&self) -> u64 {
self.major
}
/// # Minor
pub fn minor(&self) -> u64 {
self.minor
}
/// # Patch
pub fn patch(&self) -> u64 {
self.patch
}
/// # Pre-release
///
/// This does **not** contain the leading character `-`. However calling `to_string()` will always have that character displayed.
pub fn pre_release(&self) -> Option<&str> {
self.pre_release.as_ref().map(|pr| pr.as_str())
}
/// # Build metadata
///
/// This does **not** contain the leading character `+`. However calling `to_string()` will always have that character displayed.
pub fn build_metadata(&self) -> Option<&str> {
self.build_metadata.as_ref().map(|bm| bm.as_str())
}
/// # Checks to see if the semver is stable
///
/// A semver is stable if:
///
/// - It's not a pre-release.
/// - Its major version is larger than zero.
pub fn is_stable(&self) -> bool {
self.major > 0 && self.pre_release.is_none()
}
/// # Checks to see if the semver is in early development state, in which major version is zero
pub fn is_early(&self) -> bool {
self.major == 0
}
/// # Parses pre-release to see if it starts with some common phrases
///
/// Notes:
///
/// - Case is ignored.
/// - If it returns `None`, it means the semver doesn't have a pre-release.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::{Semver, PreRelease};
///
/// match Semver::from_str("1.2.3-hola")?.parse_pre_release() {
/// Some(PreRelease::Alpha) => println!("Alpha"),
/// Some(PreRelease::Beta) => println!("Beta"),
/// Some(PreRelease::RC) => println!("RC"),
/// Some(PreRelease::Other) => println!("Other"),
/// None => println!("Not available"),
/// };
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn parse_pre_release(&self) -> Option<PreRelease> {
self.pre_release.as_ref().map(|pre_release| PreRelease::parse(pre_release))
}
/// # Checks to see if this semver is compatible with one other
///
/// Two semvers are compatible with each other if one of these conditions is true:
///
/// - They have same major version, which must be larger than `0`.
/// - If both major versions are `0`, they must have _exactly_ these same components: major, minor, patch, pre-release.
///
/// # Examples
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert!(Semver::new(1, 0, 1).compatible_with(&Semver::new(1, 2, 3)));
/// assert!(Semver::new(1, 0, 1).compatible_with(&Semver::new(1, 99, 9)));
/// assert!(Semver::new(1, 0, 1).compatible_with(&Semver::new(2, 0, 0)) == false);
/// assert!(Semver::new(0, 0, 1).compatible_with(&Semver::new(0, 2, 0)) == false);
/// assert!(Semver::new(0, 0, 1).compatible_with(&Semver::from_str("0.0.1-abc")?) == false);
/// assert!(Semver::new(0, 0, 1).compatible_with(&Semver::from_str("0.0.1+abc")?));
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn compatible_with(&self, other: &Self) -> bool {
if self.major != other.major { return false; }
if self.major > 0 { return true; }
if self.minor != other.minor || self.patch != other.patch { return false; }
match (self.pre_release.as_ref(), other.pre_release.as_ref()) {
(Some(self_pre_release), Some(other_pre_release)) => self_pre_release == other_pre_release,
(None, None) => true,
_ => false,
}
}
/// # Makes new semver with major version incremented by `1`
///
/// ## Notes
///
/// - Pre-release and build metadata will be *dropped*.
/// - `checked_add()` will be used. So if overflow happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-abc+xyz")?.new_major().unwrap().to_string(),
/// "2.0.0",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_major(&self) -> Option<Self> {
match self.major.checked_add(1) {
Some(new_major) => Some(Self::new(new_major, 0, 0)),
None => None,
}
}
/// # Makes new semver with major version incremented by `1`
///
/// ## Notes
///
/// - Pre-release and build metadata will be *kept*.
/// - `checked_add()` will be used. So if overflow happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-abc+xyz")?
/// .new_major_with_last_details().unwrap().to_string(),
/// "2.0.0-abc+xyz",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_major_with_last_details(&self) -> Option<Self> {
self.new_major().map(|mut result| {
result.pre_release = self.pre_release.clone();
result.build_metadata = self.build_metadata.clone();
result
})
}
/// # Makes new semver with minor version incremented by `1`
///
/// ## Notes
///
/// - Pre-release and build metadata will be *dropped*.
/// - `checked_add()` will be used. So if overflow happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-abc+xyz")?.new_minor().unwrap().to_string(),
/// "1.3.0",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_minor(&self) -> Option<Self> {
match self.minor.checked_add(1) {
Some(new_minor) => Some(Self::new(self.major, new_minor, 0)),
None => None,
}
}
/// # Makes new semver with minor version incremented by `1`
///
/// ## Notes
///
/// - Pre-release and build metadata will be *kept*.
/// - `checked_add()` will be used. So if overflow happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-abc+xyz")?
/// .new_minor_with_last_details().unwrap().to_string(),
/// "1.3.0-abc+xyz",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_minor_with_last_details(&self) -> Option<Self> {
self.new_minor().map(|mut result| {
result.pre_release = self.pre_release.clone();
result.build_metadata = self.build_metadata.clone();
result
})
}
/// # Makes new semver with patch version incremented by `1`
///
/// ## Notes
///
/// - Pre-release and build metadata will be *dropped*.
/// - `checked_add()` will be used. So if overflow happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-abc+xyz")?.new_patch().unwrap().to_string(),
/// "1.2.4",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_patch(&self) -> Option<Self> {
match self.patch.checked_add(1) {
Some(new_patch) => Some(Self::new(self.major, self.minor, new_patch)),
None => None,
}
}
/// # Makes new semver with patch version incremented by `1`
///
/// ## Notes
///
/// - Pre-release and build metadata will be *kept*.
/// - `checked_add()` will be used. So if overflow happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-abc+xyz")?
/// .new_patch_with_last_details().unwrap().to_string(),
/// "1.2.4-abc+xyz",
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_patch_with_last_details(&self) -> Option<Self> {
self.new_patch().map(|mut result| {
result.pre_release = self.pre_release.clone();
result.build_metadata = self.build_metadata.clone();
result
})
}
/// # Makes new semver with same version numbers, but new pre-release and/or same build metadata
///
/// `pre_release` should _not_ include leading character `-`; it will be added automatically.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-alpha.1+abc")?
/// .new_pre_release("alpha.2", false)?
/// .to_string(),
/// "1.2.3-alpha.2"
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_pre_release<S>(&self, pre_release: S, keep_build_metadata: bool) -> Result<Self> where S: AsRef<str> {
let pre_release = pre_release.as_ref();
// Pre-release
let mut s = alloc::format!(
"{major}.{minor}.{patch}{pre_release_starter}{pre_release}",
major=self.major, minor=self.minor, patch=self.patch, pre_release_starter=self::PRE_RELEASE_STARTER, pre_release=pre_release,
);
// Build metadata
if keep_build_metadata {
if let Some(build_metadata) = self.build_metadata.as_ref() {
s.push(self::BUILD_METADATA_STARTER);
s.push_str(build_metadata);
}
}
Self::parse(s)
}
/// # Drops pre-release
///
/// ## Examples
///
/// ```
/// use {
/// core::str::FromStr,
/// dia_semver::Semver,
/// };
///
/// assert_eq!(
/// Semver::from_str("1.2.3-alpha")?.drop_pre_release(),
/// Semver::new(1, 2, 3),
/// );
/// assert_eq!(
/// Semver::from_str("1.2.3-some+rigel")?.drop_pre_release().to_string(),
/// Semver::from_str("1.2.3+rigel")?.to_string(),
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn drop_pre_release(&self) -> Self {
Self {
major: self.major,
minor: self.minor,
patch: self.patch,
build_metadata: self.build_metadata.clone(),
pre_release: None,
}
}
/// # Makes new semver with same version numbers, but new build metadata and/or same pre-release
///
/// `build_metadata` should _not_ include leading character `+`; it will be added automatically.
///
/// # Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// assert_eq!(
/// Semver::from_str("1.2.3-alpha.1+abc")?
/// .new_build_metadata("xyz", false)?
/// .to_string(),
/// "1.2.3+xyz"
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn new_build_metadata<S>(&self, build_metadata: S, keep_pre_release: bool) -> Result<Self> where S: AsRef<str> {
let build_metadata = build_metadata.as_ref();
let mut s = alloc::format!("{major}.{minor}.{patch}", major=self.major, minor=self.minor, patch=self.patch);
// Pre-release
if keep_pre_release {
if let Some(pre_release) = self.pre_release.as_ref() {
s.push(self::PRE_RELEASE_STARTER);
s.push_str(pre_release);
}
}
// Build metadata
s.push(self::BUILD_METADATA_STARTER);
s.push_str(build_metadata);
Self::parse(s)
}
/// # Drops build metadata
///
/// ## Examples
///
/// ```
/// use {
/// core::str::FromStr,
/// dia_semver::Semver,
/// };
///
/// assert_eq!(
/// Semver::from_str("1.2.3+bsd")?.drop_build_metadata().to_string(),
/// Semver::new(1, 2, 3).to_string(),
/// );
/// assert_eq!(
/// Semver::from_str("1.2.3-beta+artix")?.drop_build_metadata().to_string(),
/// Semver::from_str("1.2.3-beta")?.to_string(),
/// );
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn drop_build_metadata(&self) -> Self {
Self {
major: self.major,
minor: self.minor,
patch: self.patch,
build_metadata: None,
pre_release: self.pre_release.clone(),
}
}
/// # Makes this version in short format
///
/// Short format means the last version number(s) will be left out, if they're zeros.
///
/// ## Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::Semver;
///
/// for (sample, expected) in &[
/// ("1.0.0-alpha+bsd", "1-alpha+bsd"),
/// ("1.1.0", "1.1"),
/// ("2.0.1-beta", "2.0.1-beta"),
/// ] {
/// assert_eq!(Semver::from_str(sample)?.to_short_format(), *expected);
/// }
///
/// # dia_semver::Result::Ok(())
/// ```
pub fn to_short_format(&self) -> String {
let mut result = match self.patch {
0 => match self.minor {
0 => self.major.to_string(),
_ => alloc::format!("{}.{}", self.major, self.minor),
},
_ => return self.to_string(),
};
if let Some(pre_release) = self.pre_release.as_ref() {
result.push(self::PRE_RELEASE_STARTER);
result.push_str(pre_release);
}
if let Some(build_metadata) = self.build_metadata.as_ref() {
result.push(self::BUILD_METADATA_STARTER);
result.push_str(build_metadata);
}
result
}
}
impl PartialEq for Semver {
fn eq(&self, other: &Self) -> bool {
self.cmp(&other) == Ordering::Equal
}
}
impl Ord for Semver {
fn cmp(&self, other: &Self) -> Ordering {
// Major, minor, patch
match self.major.cmp(&other.major) {
Ordering::Equal => match self.minor.cmp(&other.minor) {
Ordering::Equal => match self.patch.cmp(&other.patch) {
Ordering::Equal => (),
x => return x,
},
x => return x,
},
x => return x,
};
// Comparing pre-releases: see section 11
match (self.pre_release.as_ref(), other.pre_release.as_ref()) {
(None, None) => return Ordering::Equal,
(None, Some(_)) => return Ordering::Greater,
(Some(_), None) => return Ordering::Less,
(Some(self_pre_release), Some(other_pre_release)) => {
let mut self_pre_release = self_pre_release.split('.');
let mut other_pre_release = other_pre_release.split('.');
loop {
match (self_pre_release.next(), other_pre_release.next()) {
(None, None) => return Ordering::Equal,
(None, Some(_)) => return Ordering::Less,
(Some(_), None) => return Ordering::Greater,
(Some(self_field), Some(other_field)) => {
let self_field_is_number = self_field.chars().any(|c| c < '0' || c > '9') == false;
let other_field_is_number = other_field.chars().any(|c| c < '0' || c > '9') == false;
match (self_field_is_number, other_field_is_number) {
// Specification just says "numeric identifiers". So they might be large, we don't parse them into integers.
// The fields only contain ASCII numbers, so it's ok to use `len()`
(true, true) => match self_field.len().cmp(&other_field.len()) {
Ordering::Equal => match self_field.cmp(&other_field) {
Ordering::Equal => (),
x => return x,
},
x => return x,
},
(true, false) => return Ordering::Less,
(false, true) => return Ordering::Greater,
(false, false) => match self_field.cmp(&other_field) {
Ordering::Equal => (),
x => return x,
},
};
},
};
}
},
};
}
}
impl PartialOrd for Semver {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for Semver {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.major.hash(state);
self.minor.hash(state);
self.patch.hash(state);
if let Some(pre_release) = self.pre_release.as_ref() {
pre_release.hash(state);
}
}
}
impl FromStr for Semver {
type Err = Error;
/// # Parses input string via _tolerant_ parser to make a new semver
///
/// - Minor and patch version numbers are optional.
/// - Leading/trailing white spaces are ignored.
///
/// For strict parser, see [`parse()`][fn:parse].
///
/// [fn:parse]: #method.parse
fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
Parser::parse(s, false)
}
}
impl Display for Semver {
fn fmt(&self, f: &mut Formatter) -> core::result::Result<(), fmt::Error> {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
if let Some(pre_release) = self.pre_release.as_ref() {
write!(f, "{}{}", self::PRE_RELEASE_STARTER, pre_release)?;
}
if let Some(build_metadata) = self.build_metadata.as_ref() {
write!(f, "{}{}", self::BUILD_METADATA_STARTER, build_metadata)?;
}
Ok(())
}
}
impl<T> From<T> for Semver where T: Into<u64> {
fn from(value: T) -> Self {
Self::new(value.into(), u64::min_value(), u64::min_value())
}
}
#[test]
fn test_semver_internal_stuff() {
use alloc::string::ToString;
assert_eq!(Semver::new(0, 0, 0).major.wrapping_sub(1).to_string().len(), MAX_STR_LEN_OF_A_VERSION_NUMBER);
}