Regex para contraseña debe contener al menos ocho caracteres, al menos un número y letras mayúsculas y minúsculas y caracteres especiales

445

Quiero una expresión regular para verificar eso:

Una contraseña contiene al menos ocho caracteres, incluyendo al menos un número e incluye tanto las letras minúsculas y mayúsculas y caracteres especiales, por ejemplo #, ?, !.

No puede ser su contraseña anterior o contener su nombre de usuario "password", o"websitename"

Y aquí está mi expresión de validación que es para ocho caracteres, incluyendo una letra mayúscula, una letra minúscula y un número o carácter especial.

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

¿Cómo puedo escribirlo para una contraseña que debe tener ocho caracteres, incluyendo una letra mayúscula, un carácter especial y caracteres alfanuméricos ?

Swapnil Tatkondawar
fuente

Respuestas:

1181

Mínimo ocho caracteres, al menos una letra y un número:

"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$"

Mínimo ocho caracteres, al menos una letra, un número y un carácter especial:

"^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$"

Mínimo ocho caracteres, al menos una letra mayúscula, una letra minúscula y un número:

"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$"

Mínimo ocho caracteres, al menos una letra mayúscula, una letra minúscula, un número y un carácter especial:

"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"

Mínimo ocho y máximo 10 caracteres, al menos una letra mayúscula, una letra minúscula, un número y un carácter especial:

"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,10}$"
Srinivas
fuente
46
"^ (? =. * [A-Za-z]) (? =. * \ D) [A-Za-z \ d] {8,} $" no permite símbolos como uno de los 8 caracteres
Wee
Encontré lo siguiente permitido para todos los caracteres (especiales y signos de puntuación), sin que sean obligatorios: "^ (? =. * [Az]) (? =. * [AZ]) (? =. * \ D) [a- zA-Z \ d \ w \ W] {8,} $ "
Gavin
413

Puede usar esta expresión regular con múltiples aserciones anticipadas (condiciones) :

^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$

Esta expresión regular hará cumplir estas reglas:

  • Al menos una letra mayúscula en inglés ,(?=.*?[A-Z])
  • Al menos una letra minúscula en inglés, (?=.*?[a-z])
  • Al menos un dígito, (?=.*?[0-9])
  • Al menos un personaje especial, (?=.*?[#?!@$%^&*-])
  • Mínimo ocho de longitud .{8,}(con los anclajes)
anubhava
fuente
71

Las expresiones regulares no tienen un operador AND, por lo que es bastante difícil escribir una expresión regular que coincida con contraseñas válidas, cuando la validez se define por algo Y algo más Y algo más ...

Pero, las expresiones regulares tienen un operador OR, así que solo aplique el teorema de DeMorgan y escriba una expresión regular que coincida con contraseñas no válidas:

Cualquier cosa con menos de ocho caracteres O cualquier cosa sin números O cualquier cosa sin mayúsculas O cualquier cosa sin minúsculas O cualquier cosa sin caracteres especiales.

Entonces:

^(.{0,7}|[^0-9]*|[^A-Z]*|[^a-z]*|[a-zA-Z0-9]*)$

Si algo coincide con eso, entonces es una contraseña no válida.

Matt Timmermans
fuente
3
De acuerdo, temía que fueras uno de esos informáticos que a veces tenemos y que no nos damos cuenta de que hay una diferencia entre expresiones regulares y expresiones regulares . ;) Es cierto que muchas tareas de expresiones regulares son mucho más simples si puedes negar el resultado del partido después, pero eso no siempre es posible. Sin embargo, esa es una hermosa expresión regular. ¡No es simple, es elegante!
Alan Moore
1
¿Por qué no he pensado antes? Gran respuesta (cuando es posible negar el resultado)
TeChn4K
2
este está permitiendo espacios, ¿cómo verificar que una contraseña no contenga espacio con su expresión regular? probé esto /^(\s|.{0,7}|[^0-9font>*|[^AZfont>*|[^azfont>*|[^$#@%font>*|\s)$/ .test ('aAa # a1a aa'); pero no funciona
Gaurav
1
@Gaurav, agregue | [^ \ s] * \ s. *
Matt Timmermans
1
Quiéralo. Sin embargo, para que funcione, tuve que eliminar la última cláusula |[a-zA-Z0-9]*.
i--
35

Solo una pequeña mejora para la respuesta de @anubhava: dado que los caracteres especiales están limitados a los del teclado, use esto para cualquier carácter especial:

^(?=.*?[A-Z])(?=(.*[a-z]){1,})(?=(.*[\d]){1,})(?=(.*[\W]){1,})(?!.*\s).{8,}$

Esta expresión regular hará cumplir estas reglas:

  • Al menos una letra mayúscula en inglés
  • Al menos una letra minúscula en inglés
  • Al menos un dígito
  • Al menos un personaje especial
  • Mínimo ocho de longitud
Edwin Beltrán
fuente
1
En el sabor de JavaScript, \Wsolo coincide con los caracteres ASCII. Entonces no ha cambiado eso, y ahora tiene que filtrar los caracteres de espacios en blanco. Además, todos los paréntesis y {1,}cuantificadores que agregó son puro ruido, y eliminar los ?operadores no codiciosos ( ) no tenía sentido. No hay mejora aquí.
Alan Moore
Y cómo evitar la cadena vacía. La expresión regular de cadena vacía debe devolver verdadero. He usado las siguientes expresiones regulares (? =. * [0-9]) (? =. * [Az]) (? =. * [AZ]) (? =. * [@ # $% ^ & + =]) (? = \\ S + $). {8,15}
Codificador
2
falla por _ personaje especial
Akhilesh
22

Tuve algunas dificultades para seguir la respuesta más popular para mis circunstancias. Por ejemplo, mi validación estaba fallando con caracteres como ;o [. No estaba interesado en incluir en una lista blanca mis caracteres especiales, por lo que en su lugar aproveché [^\w\s]como prueba, simplemente poner, coincide con los caracteres que no son palabras (incluidos los numéricos) y los que no son espacios en blanco. Para resumir, esto es lo que funcionó para mí ...

  • al menos 8personajes
  • al menos 1carácter numérico
  • al menos 1 letra minúscula
  • al menos 1 letra mayúscula
  • al menos 1un personaje especial

/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$/

JSFiddle Link : demostración simple que cubre varios casos

scniro
fuente
2
Buena esa. pero he encontrado un problema en el que su expresión regular no aceptará _ (guión bajo) como un carácter especial :(.
user3217843
Bien, pero pequeños errores. También acepta Space, que no es una contraseña válida si usamos space.
Dinesh.net
Realmente me gusta esta respuesta, excepto que no puede aceptar guiones bajos. Todo lo que hice fue reemplazar (?=.*?[^\w\s])con (?=.*?([^\w\s]|[_]))añadir soporte para guiones y funciona muy bien ahora. También @ Dinish.net, el sistema que uso recorta el espacio en blanco de la cadena de contraseña cuando lo obtenemos, por lo que usar el método vanilla JS String.prototype.trim () funcionaría bien si desea usar esta respuesta.
Devin Carpenter
15

Una versión más "genérica" ​​(?), Que no permite letras inglesas como caracteres especiales .

^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*\d)(?=\S*[^\w\s])\S{8,}$

var pwdList = [
    '@@V4-\3Z`zTzM{>k',
    '12qw!"QW12',
    '123qweASD!"#',
    '1qA!"#$%&',
    'Günther32',
    '123456789',
    'qweASD123',
    'qweqQWEQWEqw',
    '12qwAS!'
  ],
  re = /^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*\d)(?=\S*[^\w\s])\S{8,}$/;
  
  pwdList.forEach(function (pw) {
    document.write('<span style="color:'+ (re.test(pw) ? 'green':'red') + '">' + pw + '</span><br/>');
  });

SamWhan
fuente
13

Importa el archivo JavaScript jquery.validate.min.js.

Puedes usar este método:

$.validator.addMethod("pwcheck", function (value) {
    return /[\@\#\$\%\^\&\*\(\)\_\+\!]/.test(value) && /[a-z]/.test(value) && /[0-9]/.test(value) && /[A-Z]/.test(value)
});
  1. Al menos una letra mayúscula en inglés
  2. Al menos una letra minúscula en inglés
  3. Al menos un dígito
  4. Al menos un personaje especial
Vikram
fuente
10

Prueba este:

  1. Mínimo seis caracteres
  2. Al menos un carácter en mayúscula
  3. Al menos un carácter en minúscula
  4. Al menos un personaje especial

Expresión:

"/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&.])[A-Za-z\d$@$!%*?&.]{6, 20}/"

Caracteres especiales opcionales:

  1. Al menos un personaje especial
  2. Al menos un número
  3. Los caracteres especiales son opcionales
  4. Mínimo seis caracteres y máximo 16 caracteres.

Expresión:

"/^(?=.*\d)(?=.*[a-zA-Z]).{6,20}$/"

Si no se requieren las condiciones mínimas y máximas, elimine .{6, 16}

  • 6 es el límite mínimo de caracteres
  • 20 es el límite máximo de caracteres
  • ? = significa expresión de coincidencia
ojus kulkarni
fuente
2
@Madhu He actualizado mi respuesta para su condición para caracteres especiales opcionales
ojus kulkarni
7

No responde directamente a la pregunta, pero ¿realmente tiene que ser una expresión regular?

Solía ​​hacer mucho Perl, y me acostumbré a resolver problemas con expresiones regulares. Sin embargo, cuando se vuelven más complicados con todos los look-aheads y otras peculiaridades, debes escribir docenas de pruebas unitarias para matar a todos esos pequeños errores.

Además, una expresión regular suele ser varias veces más lenta que una solución imperativa o funcional.

Por ejemplo, la siguiente función Scala (no muy FP) resuelve la pregunta original aproximadamente tres veces más rápido que la expresión regular de la respuesta más popular. Lo que hace también es tan claro que no necesita una prueba unitaria:

def validatePassword(password: String): Boolean = {
  if (password.length < 8)
    return false

  var lower = false
  var upper = false
  var numbers = false
  var special = false

  password.foreach { c =>
    if (c.isDigit)       numbers = true
    else if (c.isLower)  lower = true
    else if (c.isUpper)  upper = true
    else                 special = true
  }

  lower && upper && numbers && special
}
Heikki Salokanto
fuente
7

Le respondería a Peter Mortensen, pero no tengo suficiente reputación.

Sus expresiones son perfectas para cada uno de los requisitos mínimos especificados. El problema con sus expresiones que no requieren caracteres especiales es que tampoco PERMITEN caracteres especiales, por lo que también imponen requisitos máximos, lo que no creo que el OP solicitó. Normalmente desea permitir que sus usuarios hagan que su contraseña sea tan segura como quieran; ¿Por qué restringir contraseñas seguras?

Entonces, su expresión "mínimo ocho caracteres, al menos una letra y un número":

^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$

logra el requisito mínimo, pero los caracteres restantes solo pueden ser letras y números. Para permitir (pero no requerir) caracteres especiales, debe usar algo como:

^(?=.*[A-Za-z])(?=.*\d).{8,}$ para permitir cualquier personaje

o

^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d$@$!%*#?&]{8,}$ para permitir caracteres especiales específicos

Del mismo modo, "mínimo ocho caracteres, al menos una letra mayúscula, una letra minúscula y un número:"

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$

cumple con ese requisito mínimo, pero solo permite letras y números. Utilizar:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$ para permitir cualquier personaje

o

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d$@$!%*?&]{8,} para permitir caracteres especiales específicos.

Deathwombat
fuente
Gracias por la explicación.
Hải Nguyễn
Esto debe marcarse como la respuesta correcta. La respuesta principal es incorrecta.
Jake
6
Use the following Regex to satisfy the below conditions:

Conditions: 1] Min 1 uppercase letter.
            2] Min 1 lowercase letter.
            3] Min 1 special character.
            4] Min 1 number.
            5] Min 8 characters.
            6] Max 30 characters.

Regex: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,30}$/    
SHASHANK HONRAO
fuente
2
¿De qué manera tu respuesta es mejor que las otras respuestas escritas hace años?
JSantos
@ JoshYates1980, ¿podría mencionar el "Carácter especial" por el cual la expresión regular no funcionó? Permítanme verificar con eso y actualizarlo en consecuencia. Pero hasta donde sé, funciona con todos según la condición de mandato de 1 personaje especial. Esperando su respuesta ...
SHASHANK HONRAO
1
@SHASHANKHONRAO Actualicé la expresión a: ^ (? =. * [Az]) (? =. * [AZ]) (? =. * \ D) (? =. * [$ @ $!% *? & + ~ |{}:;<>/])[A-Za-z\d$@$!%*?&+~| {}:; <> /] {8,15} que incluirá los siguientes caracteres no alfanuméricos: (@ $!% *? & + ~ `| {}
:;
6

¿Qué hay de considerar la siguiente solución regex:

^(?=.*[\w])(?=.*[\W])[\w\W]{8,}$

Lo que valida lo siguiente:

  1. Al menos una minúscula
  2. Al menos una mayúscula
  3. Al menos un dígito
  4. Al menos un personaje especial
  5. Al menos debe tener 8 caracteres de longitud.

Compruébelo trabajando en el siguiente enlace https://regex101.com/r/qPmC06/4/

Emerson Joel Rojas Soliz
fuente
Su expresión regular sugerida y la que está debajo del enlace regex101 varía. ¿No debería ser ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W\_])[A-Za-z\d\W\_]{8,}$?
CraZ
1
@ Craz He editado la expresión regular, gracias por su sugerencia.
Emerson Joel Rojas Soliz
3

Según su necesidad, este patrón debería funcionar bien. Prueba esto,

^(?=(.*\d){1})(.*\S)(?=.*[a-zA-Z\S])[0-9a-zA-Z\S]{8,}

Simplemente cree una variable de cadena, asigne el patrón y cree un método booleano que devuelva verdadero si el patrón es correcto, de lo contrario, falso.

Muestra:

String pattern = "^(?=(.*\d){1})(.*\S)(?=.*[a-zA-Z\S])[0-9a-zA-Z\S]{8,}";
String password_string = "Type the password here"

private boolean isValidPassword(String password_string) {
    return password_string.matches(Constants.passwordPattern);
}
Arun Sivanandan
fuente
3

He encontrado muchos problemas aquí, así que hice el mío.

Aquí está en todo su esplendor, con pruebas:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*([^a-zA-Z\d\s])).{9,}$

https://regex101.com/r/DCRR65/4/tests

Cosas a tener en cuenta:

  1. no usa \wporque eso incluye _, lo que estoy probando.
  2. He tenido muchos problemas para hacer coincidir símbolos, sin hacer coincidir el final de la línea.
  3. No especifica símbolos específicamente, esto también se debe a que las diferentes configuraciones regionales pueden tener diferentes símbolos en sus teclados que pueden querer usar.
Stefano
fuente
Este pase de expresiones regulares incluso cuando los espacios en blanco están dentro de la contraseña, no funcionó para mí
Arthur Melo
2

@ClasG ya ha sugerido :

^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*\d)(?=\S*[^\w\s])\S{8,}$

pero no acepta _ (guión bajo) como un carácter especial (por ejemplo, Aa12345_).

Una mejorada es:

^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*\d)(?=\S*([^\w\s]|[_]))\S{8,}$
SONewbiee
fuente
2

Manifestación:

function password_check() {
  pass = document.getElementById("password").value;
  console.log(pass);
  regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
  if (regex.exec(pass) == null) {
    alert('invalid password!')
  }
  else {
    console.log("valid");
  }
}
<input type="text" id="password" value="Sample@1">
<input type="button" id="submit" onclick="password_check()" value="submit">

Mohideen bin Mohammed
fuente
2

Prueba de este en 2020:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$

Verifícate

const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
const str = `some12*Nuts`;
let m;

if ((m = regex.exec(str)) !== null) {
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

Mihir Kumar
fuente
¿Cómo es esto mejor que la respuesta aceptada?
Toto
@Toto no hay una respuesta aceptada en este hilo, al menos no veo ninguna, hay respuestas con muchos votos pero no veo una respuesta aceptada. Además, encontré este y lo leí en regex101 para validarlo, así que lo compartí con un fragmento de código para verificar la validez también.
Mihir Kumar
1

Use la siguiente expresión regular para satisfacer las siguientes condiciones:

Conditions: 1] Min 1 special character.
            2] Min 1 number.
            3] Min 8 characters or More

Expresión regular: ^(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,}$

Puede probar en línea: https://regex101.com

Samrat Saha
fuente
1

Solo podemos hacer esto usando HTML5.

Use el siguiente código en el atributo de patrón,

pattern="(?=^.{8,}$)((?=.*\d)(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

Funcionará perfectamente.

Vidya
fuente
1

Puede usar el siguiente patrón de expresión regular para verificar la contraseña si coincide o no con sus expectativas.

((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*()]).{8,20})
Harshal_Kalavadiya
fuente
1

Utilizar este,

((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%?=*&]).{8,20})

Validará para al menos una minúscula, una mayúscula, un número y los caracteres especiales de (!, @, #, $,%,?, =, *, &).

La longitud mínima es 8 y la longitud máxima es 20

Anand Raja
fuente
¿Cómo es esto diferente de la respuesta aceptada?
Toto
0

En Java / Android, para probar una contraseña con al menos un número, una letra, un carácter especial en el siguiente patrón:

"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$@$!%*#?&])[A-Za-z\\d$@$!%*#?&]{8,}$"
Dadaji
fuente
0

Prueba esto:

^.*(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])[a-zA-Z0-9@#$%^&+=]*$

Esta expresión regular me funciona perfectamente.

function myFunction() {
    var str = "c1TTTTaTTT@";
    var patt = new RegExp("^.*(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])[a-zA-Z0-9@#$%^&+=]*$");
    var res = patt.test(str);
    console.log("Is regular matches:", res);
}
Kiwi Rupela
fuente
0

Patrón para que coincida con al menos 1 carácter en mayúscula, 1 dígito y cualquier carácter especial y la longitud entre 8 y 63.

"^ (? =. [az]) (? =. [AZ]) (? =. * \ d) [a-zA-Z \ d \ W] {8,63} $"

Este patrón se usó para la programación JAVA.

Anup Seth
fuente
0

Espero que lo siguiente funcione. Intenté esto en la política personalizada de Azure.

^ (? =. [az]) (? =. [AZ]) (? =. \ d) (? =. [@ # $% ^ & * -_ + = [] {} | \: ',? / ~&quot;();!])([A-Za-z\d@#$%^&amp;*\-_+=[\]{}|\\:',?/~ "() ;!] |. (?! @)) {6,16} $

Venkatesh
fuente
0

De hecho, acabo de copiar la primera respuesta aquí y la convertí en una expresión regular más conveniente para UX que necesita una superior, una inferior y al menos 8 caracteres, pero acepta todo "en el medio".

Este es un ejemplo de expresión regular que requiere

  1. al menos 8 caracteres de longitud
  2. al menos una letra minúscula
  3. al menos una letra mayuscula

IMPORTANTE : Esta expresión regular también excepto todos los demás caracteres, por ejemplo, números, caracteres especiales como $, # ,! etc. , siempre que las reglas 1. a 3. coincidan con la cadena de entrada

^(?=.*[a-z])(?=.*[A-Z]).{8,}$

Cuidado con el "." casi al final de la expresión regular. Esto coincidirá con casi cualquier personaje (y afaik cualquier personaje legible)

Frithjof Schaefer
fuente
0

Si desea utilizar expresiones regulares para verificar un mínimo de ocho caracteres, al menos una letra mayúscula, al menos una letra minúscula, al menos un número del 0 al 9 y al menos un carácter especial de:! @ # $% ^ & * _? Y también le da al usuario un poco más de información sobre lo que falta en la contraseña, puede usar el siguiente código:

let password = "@Aa3a4d$";

//  Check every single condition separately
let lowercase = password.match((/[a-z]+/g));
let uppercase = password.match((/[A-Z]+/g));
let digits = password.match((/[\d]+/g));
let special = password.match((/[!@#$%^&*_]+/g));
let lenght = password.match((/[A-Za-z\d!@#$%^&*_]{8,}/g));

//  Array to store information about any mismatches in the string
let errors = [];

if (password === '' ) {
    errors.push('Password is required');
}
if (lowercase === null) {
    errors.push('Password must include at least one lowercase letter');
}
if (uppercase === null) {
    errors.push('Password must include at least one uppercase letter');
}
if (digits === null) {
    errors.push('Password must include at least one digit from 0 to 9');
}
if (special  === null) {
    errors.push('Password must include at least one special character');
}
if (lenght === null) {
    errors.push('Password must include at least 8 characters');
}
if (errors.length > 0) {
    console.log(errors);
    return;
} else {
    // Process your password
}
Towerss
fuente
-1

Una solución que encontré en una de las respuestas anteriores como:

* Mínimo 8 caracteres al menos 1 alfabeto en mayúsculas, 1 alfabeto en minúsculas, 1 número y 1 carácter especial:

"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}"*

... no funcionó para mí, pero la siguiente es una versión simplificada y funciona muy bien (agregue cualquier carácter especial que desee, agregué # aquí) y agregue la regla de número como lo hace con las letras como:

"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&]){8,}"
Carette
fuente
1
Esto es cuantificar una anticipación positiva.
ctwheels