Skip to content

Instantly share code, notes, and snippets.

@pmiossec
Last active October 6, 2015 08:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmiossec/2966762 to your computer and use it in GitHub Desktop.
Save pmiossec/2966762 to your computer and use it in GitHub Desktop.
Check IBAN Validity
using System;
using System.Globalization;
using System.Text.RegularExpressions;
namespace Tools.Service
{
/// <summary>
/// Fonctionalité pour tester le format de la saisie
/// </summary>
public static class Tools
{
/// <summary>
/// Enum permettant de définir quel est le type de control sur la clé d'un compte RIB
/// </summary>
public enum TypeCheckCleRib
{
/// <summary>
/// Controle systématique
/// </summary>
Always,
/// <summary>
/// Aucun controle
/// </summary>
Never,
/// <summary>
/// Controle d'intégrité si la clé est présente
/// </summary>
OnlyWhenNotNull
}
/// <summary>
/// Verifie le format de saisie d'une date
/// </summary>
/// <param name="date">chaine contenant la date à verifier</param>
/// <returns>bool : true si la date est valide
/// </returns>
public static bool IsDateValid(string date)
{
DateTime dt = new DateTime();
return IsDateValid(date, out dt);
}
/// <summary>
/// Verifie le format de saisie d'une date
/// </summary>
/// <param name="date">chaine contenant la date à verifier</param>
/// <param name="castedDate">OUT chaine convertie en date si celle-ci est valide, DateTime.MinValue si celle-ci est invalide</param>
/// <returns>bool : true si la date est valide
/// </returns>
public static bool IsDateValid(string date, out DateTime castedDate)
{
try
{
castedDate = DateTime.MinValue;
Regex r = new Regex(@"([a-zA-Z ]{0,9}?)(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/(19|20)\d\d");
Match m = r.Match(date);
if (!m.Success)
return false;
castedDate = DateTime.Parse(date);
return true;
}
catch (Exception)
{
castedDate = DateTime.MinValue;
return false;
}
}
/// <summary>
/// Vérifie la validité (synthaxique) du code RIB
/// </summary>
/// <param name="codeBank">le code banque</param>
/// <param name="codeGuichet">le code guichet</param>
/// <param name="numeroCompte">le numero de compte</param>
/// <param name="cleRib">la clé RIB</param>
/// <returns>
/// true, si le rib est valide
/// false sinon
/// </returns>
public static bool IsRibValid(string codeBank, string codeGuichet, string numeroCompte, string cleRib)
{
return IsRibValid(codeBank, codeGuichet, numeroCompte, cleRib, TypeCheckCleRib.Always);
}
/// <summary>
/// Vérifie la validité du code RIB grâce à la clé
/// </summary>
/// <param name="codeBank">le code banque</param>
/// <param name="codeGuichet">le code guichet</param>
/// <param name="numeroCompte">le numero de compte</param>
/// <param name="cleRib">la clé RIB</param>
/// <param name="verifyKey">vérification ou non de la validité de la clé</param>
/// <returns>
/// true, si le rib est valide
/// false sinon
/// </returns>
public static bool IsRibValid(string codeBank, string codeGuichet, string numeroCompte, string cleRib, TypeCheckCleRib verifyKey)
{
string tabcompte = "";
if (codeBank.Length != 5)
return false;
if (codeGuichet.Length != 5)
return false;
int len = numeroCompte.Length;
if (len != 11)
return false;
if (TypeCheckCleRib.Never == verifyKey || (TypeCheckCleRib.OnlyWhenNotNull == verifyKey && 0 == cleRib.Length))
return true;
if (cleRib.Length != 2)
return false;
char[] cNumCompte = numeroCompte.ToUpper().ToCharArray();
for (int i = 0; i < len; i++)
{
char car = cNumCompte[i];
int tmp = 0;
try
{
//C'est un chiffre, on conserve la valeur
tmp = Convert.ToInt32("" + car);
}
catch (FormatException)
{
//C'est une lettre, on la convertit suivant un algorithme
int c = car - 64;
int b = (c < 10) ? c : ((c < 19) ? c - 9 : c - 17);
tmp = b;
}
finally
{
tabcompte += "" + tmp;
}
}
string strTmp = codeBank + codeGuichet + tabcompte + cleRib;
if (strTmp.Length < 21)
return false;
try
{
if (Decimal.Parse(strTmp) % 97 == 0)
return true;
return false;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Verifie le format d'un numero de compte
/// 5 chiffres, 5 chiffres, 11 lettres et chiffres, 2 chiffre
/// </summary>
/// <param name="champ1">champ1 sur 5 chiffres</param>
/// <param name="champ2">champ2 sur 5 chiffres</param>
/// <param name="champ3">champ3 sur 11 chiffres</param>
/// <param name="champ4">champ4 sur 2 chiffres</param>
/// <param name="msgErreur">Message d'erreur lors de la détection d'un format de compte invalide</param>
/// <returns>
/// true, si le compte est au bon format
/// false, sinon
/// </returns>
public static bool IsFormatCompte(string champ1, string champ2, string champ3, string champ4, out string msgErreur)
{
return IsFormatCompte(champ1, champ2, champ3, champ4, true, out msgErreur);
}
/// <summary>
/// Verifie le format d'un numero de compte
/// 5 chiffres, 5 chiffres, 11 lettres et chiffres, 2 chiffre
/// </summary>
/// <param name="champ1">champ1 sur 5 chiffres</param>
/// <param name="champ2">champ2 sur 5 chiffres</param>
/// <param name="champ3">champ3 sur 11 chiffres</param>
/// <param name="champ4">champ4 sur 2 chiffres</param>
/// <param name="verifyCle">verification obligatoire de la clé ou non</param>
/// <param name="msgErreur">Message d'erreur lors de la détection d'un format de compte invalide</param>
/// <returns>
/// true, si le compte est au bon format
/// false, sinon
/// </returns>
public static bool IsFormatCompte(string champ1, string champ2, string champ3, string champ4, bool verifyCle, out string msgErreur)
{
bool formatValide = true;
msgErreur = "";
Regex r = new Regex(@"\b([0-9]{5})\b");
Match m = r.Match(champ1);
if (!m.Success)
{
msgErreur += "- Le code banque doit être de 5 caractères numériques\n";
formatValide = false;
}
r = new Regex(@"\b([0-9]{5})\b");
m = r.Match(champ2);
if (!m.Success)
{
msgErreur += "- Le code guichet doit être de 5 caractères numériques\n";
formatValide = false;
}
r = new Regex(@"\b([0-9A-Za-z]{11})\b");
m = r.Match(champ3);
if (!m.Success)
{
msgErreur += "- Le numéro de compte doit être de 11 caractères alpha-numériques\n";
formatValide = false;
}
if (verifyCle)
{
r = new Regex(@"\b([0-9]{2})\b");
m = r.Match(champ4);
if (!m.Success)
{
msgErreur += "- La clé doit être de 2 caractères numériques\n";
formatValide = false;
}
}
return formatValide;
}
/// <summary>
/// Retourne une valeur indiquant si un Code ISIN est valide
/// </summary>
/// <param name="isinCode">chaine représentant le code ISIN</param>
/// <returns>
/// true, si le code ISIN est valide
/// false, sinon
/// </returns>
public static bool IsValidIsinCode(string isinCode)
{
try
{
// Un code ISIN a une longueur de 12 caractères.
if (string.IsNullOrEmpty(isinCode) || isinCode.Length != 12)
return false;
// Les deux premiers caractères doivent être un code ISO de pays.
if (!CheckCodePaysISO3166(isinCode.Substring(0, 2)))
return false;
// Le chiffre le plus à droite est la clé de contrôle
Char charCheckDigit = isinCode[isinCode.Length - 1];
if (!Char.IsDigit(charCheckDigit))
return false;
int checkDigit = int.Parse(charCheckDigit.ToString());
string code = string.Empty;
// On travaille avec la chaîne sans le chiffre le plus à droite qui est le chiffre de contrôle, d'où i < isinCode.Length - 1
for (int i = 0; i < isinCode.Length - 1; i++)
{
char c = isinCode[i];
if (Char.IsDigit(c))
code += c;
else
{
// Les lettres sont converties en valeurs numériques :
// A -> 10
// B -> 11
// ..
// Z -> 35
int value = (char.ToUpper(c)) - 'A' + 10;
code += value.ToString();
}
}
// on fait la somme des chiffres obtenus. Les chiffres d'indices pairs (commençant de 0 à partir de la droite) sont multipliés par deux avant d'être ajouté à la somme.
int sum = 0;
// on utilise parity pour savoir si on est sur un chiffre d'indice pair ou non.
int parity = (code.Length - 1) % 2;
for (int i = code.Length - 1; i >= 0; i--)
{
if (!Char.IsDigit(code[i]))
return false;
int digit = int.Parse(code[i].ToString());
if (i % 2 == parity)
{
int n = digit * 2;
sum += (n / 10) + (n % 10);
}
else
{
sum += digit;
}
}
return ((10 - (sum % 10)) % 10) == checkDigit;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Vérifie si le code pays passé en argument correspond bien à la norme ISO 3166-1
/// </summary>
/// <param name="code">Code pays (2 CAR)</param>
/// <returns>bool : true si OK</returns>
public static bool CheckCodePaysISO3166(string code)
{
if (code.Length != 2)
return false;
code = code.ToUpper();
//Codes pays ISO 3166-1 (ensemble des codes disponibles : http://fr.wikipedia.org/wiki/ISO_3166-1)
string[] CodesPays = {
"AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ",
"BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BK", "BL", "BM", "BN", "BO", "BP", "BQ", "BR", "BS", "BT", "BU", "BV", "BW", "BX", "BY", "BZ",
"CA", "CB", "CC", "CD", "CE", "CF", "CG", "CH", "CI", "CJ", "CK", "CL", "CM", "CN", "CO", "CP", "CQ", "CR", "CS", "CT", "CU", "CV", "CW", "CX", "CY", "CZ",
"DA", "DB", "DC", "DD", "DE", "DF", "DG", "DH", "DI", "DJ", "DK", "DL", "DM", "DN", "DO", "DP", "DQ", "DR", "DS", "DT", "DU", "DV", "DW", "DX", "DY", "DZ",
"EA", "EB", "EC", "ED", "EE", "EF", "EG", "EH", "EI", "EJ", "EK", "EL", "EM", "EN", "EO", "EP", "EQ", "ER", "ES", "ET", "EU", "EV", "EW", "EX", "EY", "EZ",
"FA", "FB", "FC", "FD", "FE", "FF", "FG", "FH", "FI", "FJ", "FK", "FL", "FM", "FN", "FO", "FP", "FQ", "FR", "FS", "FT", "FU", "FV", "FW", "FX", "FY", "FZ",
"GA", "GB", "GC", "GD", "GE", "GF", "GG", "GH", "GI", "GJ", "GK", "GL", "GM", "GN", "GO", "GP", "GQ", "GR", "GS", "GT", "GU", "GV", "GW", "GX", "GY", "GZ",
"HA", "HB", "HC", "HD", "HE", "HF", "HG", "HH", "HI", "HJ", "HK", "HL", "HM", "HN", "HO", "HP", "HQ", "HR", "HS", "HT", "HU", "HV", "HW", "HX", "HY", "HZ",
"IA", "IB", "IC", "ID", "IE", "IF", "IG", "IH", "II", "IJ", "IK", "IL", "IM", "IN", "IO", "IP", "IQ", "IR", "IS", "IT", "IU", "IV", "IW", "IX", "IY", "IZ",
"JA", "JB", "JC", "JD", "JE", "JF", "JG", "JH", "JI", "JJ", "JK", "JL", "JM", "JN", "JO", "JP", "JQ", "JR", "JS", "JT", "JU", "JV", "JW", "JX", "JY", "JZ",
"KA", "KB", "KC", "KD", "KE", "KF", "KG", "KH", "KI", "KJ", "KK", "KL", "KM", "KN", "KO", "KP", "KQ", "KR", "KS", "KT", "KU", "KV", "KW", "KX", "KY", "KZ",
"LA", "LB", "LC", "LD", "LE", "LF", "LG", "LH", "LI", "LJ", "LK", "LL", "LM", "LN", "LO", "LP", "LQ", "LR", "LS", "LT", "LU", "LV", "LW", "LX", "LY", "LZ",
"MA", "MB", "MC", "MD", "ME", "MF", "MG", "MH", "MI", "MJ", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ",
"NA", "NB", "NC", "ND", "NE", "NF", "NG", "NH", "NI", "NJ", "NK", "NL", "NM", "NN", "NO", "NP", "NQ", "NR", "NS", "NT", "NU", "NV", "NW", "NX", "NY", "NZ",
"OA", "OB", "OC", "OD", "OE", "OF", "OG", "OH", "OI", "OJ", "OK", "OL", "OM", "ON", "OO", "OP", "OQ", "OR", "OS", "OT", "OU", "OV", "OW", "OX", "OY", "OZ",
"PA", "PB", "PC", "PD", "PE", "PF", "PG", "PH", "PI", "PJ", "PK", "PL", "PM", "PN", "PO", "PP", "PQ", "PR", "PS", "PT", "PU", "PV", "PW", "PX", "PY", "PZ",
"QA", "QB", "QC", "QD", "QE", "QF", "QG", "QH", "QI", "QJ", "QK", "QL", "QM", "QN", "QO", "QP", "QQ", "QR", "QS", "QT", "QU", "QV", "QW", "QX", "QY", "QZ",
"RA", "RB", "RC", "RD", "RE", "RF", "RG", "RH", "RI", "RJ", "RK", "RL", "RM", "RN", "RO", "RP", "RQ", "RR", "RS", "RT", "RU", "RV", "RW", "RX", "RY", "RZ",
"SA", "SB", "SC", "SD", "SE", "SF", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SP", "SQ", "SR", "SS", "ST", "SU", "SV", "SW", "SX", "SY", "SZ",
"TA", "TB", "TC", "TD", "TE", "TF", "TG", "TH", "TI", "TJ", "TK", "TL", "TM", "TN", "TO", "TP", "TQ", "TR", "TS", "TT", "TU", "TV", "TW", "TX", "TY", "TZ",
"UA", "UB", "UC", "UD", "UE", "UF", "UG", "UH", "UI", "UJ", "UK", "UL", "UM", "UN", "UO", "UP", "UQ", "UR", "US", "UT", "UU", "UV", "UW", "UX", "UY", "UZ",
"VA", "VB", "VC", "VD", "VE", "VF", "VG", "VH", "VI", "VJ", "VK", "VL", "VM", "VN", "VO", "VP", "VQ", "VR", "VS", "VT", "VU", "VV", "VW", "VX", "VY", "VZ",
"WA", "WB", "WC", "WD", "WE", "WF", "WG", "WH", "WI", "WJ", "WK", "WL", "WM", "WN", "WO", "WP", "WQ", "WR", "WS", "WT", "WU", "WV", "WW", "WX", "WY", "WZ",
"XA", "XB", "XC", "XD", "XE", "XF", "XG", "XH", "XI", "XJ", "XK", "XL", "XM", "XN", "XO", "XP", "XQ", "XR", "XS", "XT", "XU", "XV", "XW", "XX", "XY", "XZ",
"YA", "YB", "YC", "YD", "YE", "YF", "YG", "YH", "YI", "YJ", "YK", "YL", "YM", "YN", "YO", "YP", "YQ", "YR", "YS", "YT", "YU", "YV", "YW", "YX", "YY", "YZ",
"ZA", "ZB", "ZC", "ZD", "ZE", "ZF", "ZG", "ZH", "ZI", "ZJ", "ZK", "ZL", "ZM", "ZN", "ZO", "ZP", "ZQ", "ZR", "ZS", "ZT", "ZU", "ZV", "ZW", "ZX", "ZY", "ZZ"
};
if (Array.IndexOf(CodesPays, code) < 0)
return false;
return true;
}
/// <summary>
/// Fonctionalité pour tester le format IBAN
/// </summary>
public static class IBAN
{
/// <summary>
/// Vérifie la validité du code IBAN
/// </summary>
/// <param name="codePays">Code Pays (2 CAR)</param>
/// <param name="cleControle">Clé contrôle (00 à 96)</param>
/// <param name="codeBban">Code BBAN (max 30 CAR)</param>
/// <returns>true, si l'IBAN est valide
/// false, sinon</returns>
public static bool IsIbanValid(string codePays, int cleControle, string codeBban)
{
#region Contrôles primitifs
if (codePays.Length != 2)
return false;
if (!CheckCodePaysISO3166(codePays))
return false;
if (cleControle < 0 || cleControle > 96)
return false;
if (codeBban.Length > 30)
return false;
#endregion Contrôles primitifs
string fullIBAN = codeBban.ToUpper();
fullIBAN += codePays.ToUpper();
fullIBAN += cleControle.ToString("00");
if (fullIBAN.Length > 34 || fullIBAN.Length < 5)
return false;
string modulus = ReplaceLetters(fullIBAN);
if (CustomModulo(modulus, 97) != 1)
return false;
return true;
}
private static int CustomModulo(string modulus, int divider)
{
int restInt;
string rest = "";
int start = 0;
int end = 0;
while (end <= modulus.Length - 1)
{
int current = int.Parse(rest + modulus.Substring(start, end - start + 1));
if (current >= divider)
{
int interInt = current / divider;
restInt = current - interInt * divider;
rest = restInt.ToString();
start = end + 1;
end = start;
}
else
end = end + 1;
}
if (start <= modulus.Length)
rest = rest + modulus.Substring(start);
return int.Parse(rest);
}
private static string ReplaceLetters(string sIBAN)
{
for (int x = 65; x < 90; x++)
{
int replacewith = x - 64 + 9;
string replace = ((char)x).ToString();
sIBAN = sIBAN.Replace(replace, replacewith.ToString());
}
return sIBAN;
}
}
/// <summary>
/// Détermine si la chaîne fournie est un numéro SIREN ou SIRET valide.
/// </summary>
/// <param name="numeroSirenSiret">La chaîne correspondant au numéro à contrôler.</param>
/// <returns>True, si la chaîne est un numéro SIRET valide; False, sinon.</returns>
public static bool IsValidNumeroSirenOrSiret(string numeroSirenSiret)
{
if (IsValidNumeroSiren(numeroSirenSiret))
return true;
return IsValidNumeroSiret(numeroSirenSiret);
}
/// <summary>
/// Détermine si la chaîne fournie est un numéro SIREN valide.
/// </summary>
/// <param name="numeroSiren">La chaîne à contrôler.</param>
/// <returns>True, si la chaîne est un numéro SIREN valide; False, sinon.</returns>
public static bool IsValidNumeroSiren(string numeroSiren)
{
if (string.IsNullOrEmpty(numeroSiren) || (numeroSiren.Length != 9))
return false;
return VerificationCodeSirenSiret(numeroSiren);
}
/// <summary>
/// Détermine si la chaîne fournie est un numéro SIRET valide.
/// </summary>
/// <param name="numeroSiret">La chaîne à contrôler.</param>
/// <returns>True, si la chaîne est un numéro SIRET valide; False, sinon.</returns>
public static bool IsValidNumeroSiret(string numeroSiret)
{
// Le numéro SIRET a 14 chiffres. Le contrôle se fait selon l'algorithme de Luhn.
// On part de la droite et le rang commence à 1.
// On multiplie les chiffres de rang impair par 1, ceux de rang pair par 2 ; et on fait la somme.
// Attention, si après multiplication par 2 d'un des chiffres (de rang pair) du numéro on obtient un nombre supérieur à 10 il faut ajouter à la somme non pas le nombre trouvé mais le chiffre des dizaines puis celui des unités du nombre.
// Par exemple, si un multiplication par 2 donne "12", il faudra ajouter les chiffres 1 puis 2 et non le nombre 12.
// Le numéro SIRET est correcte si la somme obtenue est un multiple de 10.
// Exemple :
// pour vérifier : 7 3 2 8 2 9 3 2 0 0 0 0 7 4
// rang impair x 1 : 3 8 9 2 0 0 4
// rang pair x 2 : 14 4 4 6 0 0 14
// -----------------------------------
// 1+4+3+4+8+4+9+6+2+0+0+0+0+1+4+4=50
// 50 est un multiple de 10 donc le numéro est exact.
// Sources :
// http://www.dsi.cnrs.fr/conduite-projet/phasedeveloppement/technique/etude-detaillee/modele-de-donnees/regles-SIREN-SIRET.pdf
// http://xml.insee.fr/schema/siret.html#controles
// http://fr.wikipedia.org/wiki/SIRET
// http://fr.wikipedia.org/wiki/Luhn
if (string.IsNullOrEmpty(numeroSiret) || (numeroSiret.Length != 14))
return false;
return VerificationCodeSirenSiret(numeroSiret);
}
private static bool VerificationCodeSirenSiret(string code)
{
int sum = 0;
// La variable parity servira à déterminer quel indice correspond à un rang pair.
// Les indices commencent par 0, les rangs par 1.
// Si la longueur est paire, c'est les indices pairs qui correspondent au rang pairs. Sinon, c'est les indices impairs.
int parity = code.Length % 2;
for (int i = code.Length - 1; i >= 0; i--)
{
if (!Char.IsDigit(code[i]))
return false;
int digit = Int32.Parse(code[i].ToString());
// si l'indice a la même parité que la longueur de la chaîne alors on est sur un chiffre de rang pair
if ((i % 2) == parity)
{
// rang pair
int n = digit * 2;
sum += (n / 10) + (n % 10);
}
else
{
// rang impair
sum += digit;
}
}
return ((sum % 10) == 0);
}
/// <summary>
/// Verification qu'une chaine de carcatère correspond à un nombre décimal dont les chiffres avant et après la virgule sont spécifiés
/// </summary>
/// <param name="champ">chaine de caractères à verifier</param>
/// <param name="nbChiffreAvant">nombre de chiffre avant la virgule</param>
/// <param name="nbChiffreApres">nombre de chiffre après la virgule</param>
/// <returns>true, si le nombre décimal est valide
/// false, sinon</returns>
public static bool VerifyDecimal(string champ, int nbChiffreAvant, int nbChiffreApres)
{
Regex r = new Regex("(([0-9]{1," + nbChiffreAvant + "},[0-9]{0," + nbChiffreApres + "})|[0-9]{1," + nbChiffreAvant + "})");
Match m = r.Match(champ);
return (m.Success & m.Length == champ.Length);
}
/// <summary>
/// Verification qu'une chaine de caractère correspond à un nombre entier dont les chiffres est spécifié
/// </summary>
/// <param name="champ">chaine de caractères à verifier</param>
/// <param name="nbChiffre">nombre de chiffre maximum constituant le nombre entier</param>
/// <returns>true, si le nombre entier est valide
/// false, sinon</returns>
public static bool VerifyInteger(string champ, int nbChiffre)
{
return VerifyDecimal(champ, nbChiffre, 0);
}
/// <summary>
/// Verification qu'une chaine de caractère correspond à une heure
/// </summary>
/// <param name="champ">chaine de caractères à verifier</param>
public static bool VerifyHour(string champ)
{
DateTime dateTime;
// C'est bien "H:mm" avec un seul H, pour que ça accepte à la fois 09:00 et 9:00
return DateTime.TryParseExact(champ, "H:mm", null, DateTimeStyles.NoCurrentDateDefault, out dateTime);
}
/// <summary>
/// Verification qu'une chaine de caractère correspond à un numéro de téléphone
/// </summary>
/// <param name="champ">chaine de caractères à verifier</param>
public static bool VerifyPhoneNumber(string champ)
{
//Numero français et International
Regex r = new Regex(@"((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}");
Match m = r.Match(champ);
if (m.Success & m.Length == champ.Length)
return true;
//Numero français avec ou sans séparateur
r = new Regex(@"0[1-68]([- ]?[0-9]{2}){4}");
m = r.Match(champ);
return (m.Success & m.Length == champ.Length);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment