Regex pattern to validate -1,0,1,...9 - javascript

In my angular project, I'm validating a text box should accept only -1,0,1,2,...9 using Angular Directives and Regex
The following code is accepting both positive and negative values. But I want to restrict that allow only -1 for negative value.
app.directive("onlyNumber", function() {
return {
restrict: "A",
scope: {
max: '=',
},
priority: 10,
link: function(scope, element, attr) {
var oldVal = Number(element.val());
element.bind('input', function(e) {
var position = this.selectionStart - 1;
//remove all but number and .
var fixed = this.value.replace(/(?!^-)[^0-9.]/g, '');
if (fixed.charAt(0) === '.') //can't start with .
fixed = fixed.slice(1);
var pos = fixed.indexOf(".") + 1;
if (pos >= 0) //avoid more than one .
fixed = fixed.substr(0, pos) + fixed.slice(pos).replace('.', '');
if(maxLimits[e.currentTarget.name] != undefined ){
if(maxLimits[e.currentTarget.name]['decimal'] == "YES"){
if(fixed.indexOf('.') != -1){
if(fixed.length > (fixed.indexOf('.')+3))
fixed = fixed.substring(0, fixed.length-1);
}
} else{
fixed = fixed.replace(/[^0-9]/g, '');
}
if (this.value !== fixed) {
this.value = fixed;
this.selectionStart = position;
this.selectionEnd = position;
} else{
if(this.value > Number(maxLimits[e.currentTarget.name]['maxVal'])){
element.val(oldVal);
} else{
oldVal = Number(element.val());
}
}
} else{
if(e.currentTarget.attributes.getNamedItem('decimal').value == "YES"){
if(fixed.indexOf('.') != -1){
if(fixed.length > (fixed.indexOf('.')+3))
fixed = fixed.substring(0, fixed.length-1);
}
} else{
fixed = fixed.replace(/[^0-9]/g, '');
}
if (this.value !== fixed) {
this.value = fixed;
this.selectionStart = position;
this.selectionEnd = position;
} else{
if(this.value > Number(e.currentTarget.max)){
element.val(oldVal);
} else{
oldVal = Number(element.val());
}
}
}
});
}
};
});
Regex:
this.value.replace(/(?!^-)[^0-9.]/g, '');
Can anyone tell me the proper regex that should allow only -1 and positive values?
Thanks in advance.

How about the following regex?
^(-1|[0-9])$
See it live on regex101
If you want to allow any positive number, you can use the following regex:
^(-1|[0-9]+)$

I am not sure if this qualifies the answer.
function check(val) {
if (('' + val).split('.').length > 2) {
return "Invalid Number";
}
try {
val = parseFloat(val);
if (-2 >= val) {
return 'Invalid'; // this can be used for message or removing the input text value
}
return val; // you shouldn't return anything if valid as it will make the user input box flickery with cursor moving around.
} catch (e) {
return "Invalid Number";
}
}
console.log(check(-1.2));
console.log(check(-2.000000001));
console.log(check(1.32143241239));
console.log(check(987654321));
console.log(check('1.32143.241.239'));

Related

To allow the user to insert date in dd/mm/yyyy format in text-box

Friends ,I have a text box for date to be inserted by the user but i want it to allow user to insert only "dd" ,"mm" and "yyyy" values ,slashes(/)should be already present and as soon as the user inserts "dd" values the pointer should move directly behind the slash for "mm" value and on pressing backspace it should delete the "mm" or "dd "values not the slashes(/).
Here is what i have tried but it does not give me the desired result-
function dateCheck(){
var d_value=$("#pdate").val();
if(d_value.length =="2" || d_value.length =="5")
{
$('#pdate').val($('#pdate').val()+"/");
}
}
html code-
Date:<input type="text" name="p_date" id="pdate" onkeydown="dateCheck()" placeholder="DD/MM/YYYY" required />
There's probably plugins out there, but nobody's been too forthcoming with any. Here's something I've knocked up during my lunch break :).
It's not perfect, and could be improved with some tweaking. For example, highlighting multiple characters for deletion is a bit screwy, but hopefully it's not a bad starter for 10. Credit to this post for getting/setting the caret position. Also, it does allow invalid dates right now - 12/34/5678. It wouldn't be too difficult to sort that out. I might stick something on Git and finish it off when I get home.
I've hard-coded it for dd/mm/yyyy format, but, again, with improvments, it could use the user locale.
$.fn.textboxDatePicker = function() {
var _getCaret = function(el) {
if (el.selectionStart) {
return el.selectionStart;
} else if (document.selection) {
el.focus();
var r = document.selection.createRange();
if (r == null) {
return 0;
}
var re = el.createTextRange(), rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
return rc.text.length;
}
return 0;
};
var _setCaretPosition = function(elem, caretPos) {
if (caretPos == 2 || caretPos == 5) {
caretPos++;
}
if (elem != null) {
if (elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
} else {
if (elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else elem.focus();
}
}
};
$(this).val('dd/mm/yyyy');
$(this).on("keydown", function(e) {
var keyCode = e.which || e.charCode || e.keyCode;
var key = String.fromCharCode(keyCode);
// arrows, home, end
if ([35, 36].indexOf(keyCode) > -1) {
return true;
}
if (keyCode == 37) {
var newCaretPos = _getCaret(this) - 1;
if ([2, 5].indexOf(newCaretPos) > -1) {
_setCaretPosition(this, newCaretPos - 1);
return false;
}
return true;
}
if (keyCode == 39) {
var newCaretPos = _getCaret(this) + 1;
if ([2, 5].indexOf(newCaretPos) > -1) {
_setCaretPosition(this, newCaretPos + 1);
return false;
}
return true;
}
// backspace
if (keyCode == 8) {
var text = this.value;
var caret = _getCaret(this);
if (caret == 3 || caret == 6) {
caret = caret - 2;
} else {
caret--;
}
if (caret < 0) {
return false;
}
var output = text.substring(0, caret);
key = 'd';
if (caret > 2) {
key = 'm'
};
if (caret > 4) {
key = 'y'
};
this.value = output + key + text.substring(caret + 1);
_setCaretPosition(this, caret);
return false;
}
if (/[0-9]/.test(key)) {
var text = this.value;
var caret = _getCaret(this);
if (caret > 9) {
return false;
}
var output = text.substring(0, caret);
this.value = output + key + text.substring(caret + 1);
_setCaretPosition(this, caret + 1);
}
return false;
});
};
$('.date').textboxDatePicker();
UPDATE
Might be overthinking this. Could you just use 3 separate boxes and style them to look like one, with a little JS to sort out focusing between them?
https://jsfiddle.net/w9by2350/3/
MUCH cleaner!
Try it
function datecheck(){
value=$(#input_id).val();
if(value.match(/^\d\d?\/\d\d?\/\d\d\d\d$/){
return true;
}else{
alert("not valid format")
}
}

Convert first letter to uppercase on input box

JS Bin demo
This regex transform each lower case word to upper case. I have a full name input field. I do want the user to see that each word's first letter he/she pressed is converted to uppercase in the input field.
I have no idea how to properly replace the selected characters in the current input field.
$('input').on('keypress', function(event) {
var $this = $(this),
val = $this.val(),
regex = /\b[a-z]/g;
val = val.toLowerCase().replace(regex, function(letter) {
return letter.toUpperCase();
});
// I want this value to be in the input field.
console.log(val);
});
Given i.e: const str = "hello world" to become Hello world
const firstUpper = str.substr(0, 1).toUpperCase() + str.substr(1);
or:
const firstUpper = str.charAt(0).toUpperCase() + str.substr(1);
or:
const firstUpper = str[0] + str.substr(1);
input {
text-transform: capitalize;
}
http://jsfiddle.net/yuMZq/1/
Using text-transform would be better.
You can convert the first letter to Uppercase and still avoid the annoying problem of the cursor jumping to the beginning of the line, by checking the caret position and resetting the caret position. I do this on a form by defining a few functions, one for all Uppercase, one for Proper Case, one for only Initial Uppercase... Then two functions for the Caret Position, one that gets and one that sets:
function ProperCase(el) {
pos = getInputSelection(el);
s = $(el).val();
s = s.toLowerCase().replace(/^(.)|\s(.)|'(.)/g,
function($1) { return $1.toUpperCase(); });
$(el).val(s);
setCaretPosition(el,pos.start);
}
function UpperCase(el) {
pos = getInputSelection(el);
s = $(el).val();
s = s.toUpperCase();
$(el).val(s);
setCaretPosition(el,pos.start);
}
function initialCap(el) {
pos = getInputSelection(el);
s = $(el).val();
s = s.substr(0, 1).toUpperCase() + s.substr(1);
$(el).val(s);
setCaretPosition(el,pos.start);
}
/* GETS CARET POSITION */
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == 'number' && typeof el.selectionEnd == 'number') {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
/* SETS CARET POSITION */
function setCaretPosition(el, caretPos) {
el.value = el.value;
// ^ this is used to not only get "focus", but
// to make sure we don't have it everything -selected-
// (it causes an issue in chrome, and having it doesn't hurt any other browser)
if (el !== null) {
if (el.createTextRange) {
var range = el.createTextRange();
range.move('character', caretPos);
range.select();
return true;
}
else {
// (el.selectionStart === 0 added for Firefox bug)
if (el.selectionStart || el.selectionStart === 0) {
el.focus();
el.setSelectionRange(caretPos, caretPos);
return true;
}
else { // fail city, fortunately this never happens (as far as I've tested) :)
el.focus();
return false;
}
}
}
}
Then on document ready I apply a keyup event listener to the fields I want to be checked, but I only listen for keys that can actually modify the content of the field (I skip "Shift" key for example...), and if user hits "Esc" I restore the original value of the field...
$('.updatablefield', $('#myform')).keyup(function(e) {
myfield=this.id;
myfieldname=this.name;
el = document.getElementById(myfield);
// or the jquery way:
// el = $(this)[0];
if (e.keyCode == 27) { // if esc character is pressed
$('#'+myfield).val(original_field_values[myfield]); // I stored the original value of the fields in an array...
// if you only need to do the initial letter uppercase, you can apply it here directly like this:
initialCap(el);
} // end if (e.keyCode == 27)
// if any other character is pressed that will modify the field (letters, numbers, symbols, space, backspace, del...)
else if (e.keyCode == 8||e.keycode == 32||e.keyCode > 45 && e.keyCode < 91||e.keyCode > 95 && e.keyCode < 112||e.keyCode > 185 && e.keyCode < 223||e.keyCode == 226) {
// if you only need to do the initial letter uppercase, you can apply it here directly like this:
initialCap(el);
} // end else = if any other character is pressed //
}); // end $(document).keyup(function(e)
You can see a working fiddle of this example here: http://jsfiddle.net/ZSDXA/
Simply put:
$this.val(val);
$(document).ready(function() {
$('input').on('keypress', function(event) {
var $this = $(this),
val = $this.val();
val = val.toLowerCase().replace(/\b[a-z]/g, function(letter) {
return letter.toUpperCase();
});
console.log(val);
$this.val(val);
});
});
As #roXon has shown though, this can be simplified:
$(document).ready(function() {
//alert('ready');
$('input').on('keypress', function(event) {
var $this = $(this),
val = $this.val();
val = val.substr(0, 1).toUpperCase() + val.substr(1).toLowerCase();
$this.val(val);
});
});
An alternative, and better solution in my opinion, would be to only style the element as being capitalized, and then do your logic server side.
This removes the overhead of any javascript, and ensures the logic is handled server side (which it should be anyway!)
$('input').on('keyup', function(event) {
$(this).val(function(i, v){
return v.replace(/[a-zA-Z]/, function(c){
return c.toUpperCase();
})
})
});
http://jsfiddle.net/AbxVx/
This will do for every textfield call function on keyup
where id is id of your textfield and value is value you type in textfield
function capitalizeFirstLetter(value,id)
{
if(value.length>0){
var str= value.replace(value.substr(0,1),value.substr(0,1).toUpperCase());
document.getElementById(id).value=str;
}
}
only use this This work for first name in capital char
style="text-transform:capitalize;
Like
<asp:TextBox ID="txtName" style="text-transform:capitalize;" runat="server" placeholder="Your Name" required=""></asp:TextBox>
$('.form-capitalize').keyup(function(event) {
var $this = $(this),
val = $this.val(),
regex = /\b[a-z]/g;
val = val.toLowerCase().replace(regex, function(letter) {
return letter.toUpperCase();
});
this.value = val;
// I want this value to be in the input field.
console.log(val);
});

Where in the code to validate a phone number, in JavaScript orRazor?

This is my first webpage in which I prompt the user for a phone number to add to a Do Not Call List database. Everything is working so far but I need to add the following, which I can do following the advice in this answer
stripping the input from all characters except digits
validating that the resulting string is 10 digits long
Then, when telling the user that the number was added to the list, I want to present it in the (999) 999-9999 format.
Where should I add all that code? Iside the #{ } block? In JavaScript? Razor?
Check phone number
function IsNumber(s) {
var i, currentCharacter;
for (i = 0; i < s.length; i++) {
// Check that current character is number.
currentCharacter = s.charAt(i);
if (((currentCharacter < "0") || (currentCharacter > "9"))) {
return false;
}
}
// All characters are numbers.
return true;
}
function TestInternationalPhone(strPhone) {
var bracket = 3,
openBracket,
phoneNumberOnly,
phoneNumberDelimiters = "()- ",
validWorldPhoneChars = phoneNumberDelimiters + "+",
minDigitsInIPhoneNumber = 10;
strPhone = SOS.StringHelper.Trim(strPhone);
if (strPhone.length === 0) {
return false;
}
if (strPhone.indexOf("+") > 1) {
return false;
}
if (strPhone.indexOf("-") != -1) {
bracket = bracket + 1;
}
if (strPhone.indexOf("(") != -1 && strPhone.indexOf("(") > bracket) {
return false;
}
openBracket = strPhone.indexOf("(");
if (strPhone.indexOf("(") != -1 && strPhone.charAt(openBracket + 2) != ")") {
return false;
}
if (strPhone.indexOf("(") == -1 && strPhone.indexOf(")") != -1) {
return false;
}
phoneNumberOnly = SOS.StringHelper.StripCharsInBag(strPhone, validWorldPhoneChars);
return (IsNumber(phoneNumberOnly) && phoneNumberOnly.length >= minDigitsInIPhoneNumber);
}

Accept input only number with 2 decimal Javascript

I want to make user control to get number like this:
125.00
125
125.27
125.20
1231545.25
2566.66
I have tried with mask textbox but its length can be anything.
I have used textbox with Javascript that accepts a number
like this:
click here
If a Javascript plugin is available for this let me know,
or any code to accept value in price format.
Restrict user to insert only number and two decimal spaces while entering.
If number is not well formatted then cut and format number after text change.
Like if 125.2 then 125.20 or if 125 then 125.00 or 135156. then 135156
I have search on internet but no plugin or script was found for this.
I have a plugin like numeric.js but it doesn't restrict decimal spaces.
Post if any Javascript available.
I don't want to do validation to check for entered values; I want to accept values with restriction.
Please help me.
You can use Ajax Control Toolkit MaskedEdit control:
MaskedEdit is an ASP.NET AJAX extender that attaches to a TextBox control to restrict the kind of text that can be entered. MaskedEdit applies a "mask" to the input that permits only certain types of characters/text to be entered. The supported data formats are: Number, Date, Time, and DateTime. MaskedEdit uses the culture settings specified in the CultureName property. If none is specified the culture setting will be the same as the page: English (United States).
Sample Code:
<ajaxToolkit:MaskedEditExtender
TargetControlID="TextBox2"
Mask="9,999,999.99"
MessageValidatorTip="true"
OnFocusCssClass="MaskedEditFocus"
OnInvalidCssClass="MaskedEditError"
MaskType="Number"
InputDirection="RightToLeft"
AcceptNegative="Left"
DisplayMoney="Left"
ErrorTooltipEnabled="True"/>
See Working Demo
I also having same problem.This code has solved my problem.This solution is exactly what u want.It's not only foramt yous decimal number but also will eliminate blank spaces. Try this.As in my condition i was allowing user to enter '+' or '-' so i check for this validation also.
<script type="text/javascript">
function checkforvalidation() {
var txtvalue = document.getElementById('<%=txtspherical.ClientID %>').value;
var leftstr = "";
var rightstr = "";
var tempstr = "";
var operator = "";
txtvalue = txtvalue.replace(/\s/g, '');
document.getElementById('<%=txtspherical.ClientID %>').value = txtvalue;
if (txtvalue.indexOf(".") != -1) {
leftstr = txtvalue.split(".")[0];
rightstr = txtvalue.split(".")[1];
if (leftstr.indexOf("-") == 0 || leftstr.indexOf("+") == 0) {
operator = leftstr.substr(0, 1);
tempstr = leftstr.substr(1, leftstr.length - 1);
leftstr = ltrim(tempstr, '0');
if (leftstr.length == 0) {
leftstr = '0';
}
if (rightstr.indexOf("-") == -1 || rightstr.indexOf("+") == -1) {
rightstr = ltrim(rightstr, '0');
rightstr = chkdecimalpoints(rightstr);
if (operator != null || operator != "") {
txtvalue = operator + leftstr + "." + rightstr;
}
else {
txtvalue = leftstr + "." + rightstr;
}
document.getElementById('<%=txtspherical.ClientID %>').value = txtvalue;
}
else {
document.getElementById('<%=txtspherical.ClientID %>').value = "";
}
}
else {
tempstr = leftstr.substr(0, leftstr.length);
leftstr = ltrim(tempstr, '0');
if (leftstr.length == 0) {
leftstr = '0';
}
if (rightstr.indexOf("-") == -1 || rightstr.indexOf("+") == -1) {
rightstr = rtrim(rightstr, '0');
rightstr = chkdecimalpoints(rightstr);
txtvalue = leftstr + "." + rightstr;
document.getElementById('<%=txtspherical.ClientID %>').value = txtvalue;
}
}
}
else if (txtvalue.indexOf("-") == -1 || txtvalue.indexOf("+") == -1) {
txtvalue = ltrim(txtvalue, '0');
if (txtvalue.length == 0) {
txtvalue = '0';
}
if (operator != null || operator != "") {
txtvalue = operator + txtvalue + ".00";
}
// txtvalue = leftstr + "." + rightstr;
document.getElementById('<%=txtspherical.ClientID %>').value = txtvalue;
}
else if (txtvalue.indexOf("-") == 0 || txtvalue.indexOf("+") == 0) {
operator = txtvalue.substr(0, 1);
tempstr = txtvalue.substr(1, leftstr.length - 1);
txtvalue = alltrim(tempstr, '0');
if (operator != null || operator != "") {
txtvalue = operator + txtvalue + ".00";
document.getElementById('<%=txtspherical.ClientID %>').value = txtvalue;
}
}
}
function chkdecimalpoints(rightstr) {
if (rightstr.length == 0) {
rightstr = '00';
return rightstr;
}
else if (rightstr.length == 1) {
rightstr = rightstr + '0';
return rightstr;
}
else if (rightstr.length > 2) {
var tempvar = rightstr.substr(2, 1);
if (tempvar >= 5) {
tempvar = parseInt(rightstr.substr(1, 1)) + 1;
tempvar = rightstr.substr(0, 1) + tempvar.toString();
if (tempvar.length > 2) {
tempvar = tempvar.substr(0, 2);
}
return tempvar;
}
else {
tempvar = rightstr.substr(0, 2);
return tempvar;
}
}
else {
return rightstr;
}
}
function ltrim(str, chars) {
chars = chars || "\\s";
return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}
function rtrim(str, chars) {
chars = chars || "\\s";
return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}
function alltrim(str, chars) {
chars = chars || "\\s";
return str.replace(new RegExp("^[" + chars + "]+$", "g"), "");
}
</script>
HTML Source:
<asp:TextBox ID="txtspherical" runat="server" OnBlur="javascript:checkforvalidation();">
</asp:TextBox>
function validNumber(input){
input=input.replace(/\s+/g," ").replace(/^\s+|\s+$/g,"");
if( input.match(/\d+\.*\d*/i) ){
input=input.match(/(\d+\.*\d*)/i)[1].replace(/\.$/i, "");
if(!input.match(/\./i)) input+=".00";
if(input.match(/\.(\d+)/i)[1].length<2) input+="0";
return input;
}else{
return "0.00";
}
}

phone number validation with added input

I recently filled out a form and when I got to the phone number textBox I noticed some really cool things going on. As I entered my number, general phone symbols were getting added automatically. Example:
I start entering my area code '555'
and my input was changed to 1 (555)
to test what just happened I backspaced on the ) and it quickly added it back in.
So my question is, how do I get this input to happen?
I use a javascript library called automask - you dont see the mask but it wont let you type anything outside the mask
for instance if your mask is ###-###-#### then any other characters are ignored (ie not 0-9) and the dashes are put in automatically.
I can post the library if you would like to take a look at
example of implementation
<input type=text name=ssn onkeypress="return autoMask(this,event, '###-##-####');">
// email kireol at yahoo.com
// autoMask - an adaption of anyMask
//
// this will force #'s, not allowing alphas where the #'s are, and auto add -'s
function autoMask(field, event, sMask) {
//var sMask = "**?##?####";
var KeyTyped = String.fromCharCode(getKeyCode(event));
var targ = getTarget(event);
keyCount = targ.value.length;
if (getKeyCode(event) < 32)
{
return true;
}
if(keyCount == sMask.length && getKeyCode(event) > 32)
{
return false;
}
if ((sMask.charAt(keyCount+1) != '#') && (sMask.charAt(keyCount+1) != 'A' ) && (sMask.charAt(keyCount+1) != '~' ))
{
field.value = field.value + KeyTyped + sMask.charAt(keyCount+1);
return false;
}
if (sMask.charAt(keyCount) == '*')
return true;
if (sMask.charAt(keyCount) == KeyTyped)
{
return true;
}
if ((sMask.charAt(keyCount) == '~') && isNumeric_plusdash(KeyTyped))
return true;
if ((sMask.charAt(keyCount) == '#') && isNumeric(KeyTyped))
return true;
if ((sMask.charAt(keyCount) == 'A') && isAlpha(KeyTyped))
return true;
if ((sMask.charAt(keyCount+1) == '?') )
{
field.value = field.value + KeyTyped + sMask.charAt(keyCount+1);
return true;
}
return false;
}
function getTarget(e) {
// IE5
if (e.srcElement) {
return e.srcElement;
}
if (e.target) {
return e.target;
}
}
function getKeyCode(e) {
//IE5
if (e.srcElement) {
return e.keyCode
}
// NC5
if (e.target) {
return e.which
}
}
function isNumeric(c)
{
var sNumbers = "01234567890";
if (sNumbers.indexOf(c) == -1)
return false;
else
return true;
}
function isNumeric_plusdash(c)
{
var sNumbers = "01234567890-";
if (sNumbers.indexOf(c) == -1)
return false;
else
return true;
}
function isAlpha(c)
{
var lCode = c.charCodeAt(0);
if (lCode >= 65 && lCode <= 122 )
{
return true;
}
else
return false;
}
function isPunct(c)
{
var lCode = c.charCodeAt(0);
if (lCode >= 32 && lCode <= 47 )
{
return true;
}
else
return false;
}
If this was an aspx page, they were probably using the AJAX Control Toolkit MaskedEdit Extender. There is also the Masked Input plugin for jQuery.

Categories