Skip to content

Instantly share code, notes, and snippets.

@xiispace
Last active January 31, 2018 03:40
Show Gist options
  • Save xiispace/34d79f41f844a59d8645cb5ec7a8ef98 to your computer and use it in GitHub Desktop.
Save xiispace/34d79f41f844a59d8645cb5ec7a8ef98 to your computer and use it in GitHub Desktop.
js 常用功能函数
//**************已使用*********************
$(document).ready(function() {
//页面权限控制
$.ajaxSetup({
contentType:"application/x-www-form-urlencoded;charset=utf-8",
//跨域处理
// xhrFields: {
// withCredentials: true
// },
// crossDomain: true,
complete:function(XMLHttpRequest, textStatus){
var sessionStatus = XMLHttpRequest.getResponseHeader("sessionStatus"); //通过XMLHttpRequest取得响应头
if(sessionStatus == "timeout") {
//如果超时就处理 ,指定要跳转的页面
window.location.href = getRootPath() + "/passport/login";
}
}
});
});
//设置登录后跳转页面
function setUrlSession(ctx) {
if(!ctx) { //ctx为空
ctx = getRootPath();
}
$.post(ctx + "/passport/setUrlSession", {'reqUrl':window.location.href}, function() {
window.location.href= ctx + "/passport/login";
});
}
//加载图片
function imgLoad(img, callback) {
var timer = setInterval(function() {
if (img.complete) {
callback(img);
clearInterval(timer);
}
}, 50);
}
//jquery提交表单
function fwSubmit(formId, url) {
$("#" + formId).attr("action", url);
$("#" + formId).submit();
}
//提示框
function showMsg(msg) {
layer.open({
type:1,
title:false,
closeBtn:false,
content:'<div style="text-align:center;line-height:100px;font-size:24px;background-color:#333;color:#fff">' + msg + '</div>',
area:['600px','100px'],
time:1000
});
}
//登录框
function openLogin() {
openLogin(null, null);
}
//登录框,reqTarget、p可为空
function openLogin(reqTarget, reqParam) {
var urlparam = "";
if(reqTarget) {
urlparam = "?reqTarget=" + reqTarget;
if(reqParam) {
urlparam = urlparam + "&reqParam=" + reqParam;
}
} else {
if(reqParam) {
urlparam = "?reqParam=" + reqParam;
}
}
layer.open({
type: 2,
title: '登录',
shadeClose: true,
area: ['420px', '380px'],
skin: 'layui-layer-rim', //加上边框
content: [getRootPath() + "/passport/popLogin" + urlparam, "no"]
});
}
//获取项目根目录
function getRootPath() {
//获取当前网址,如: http://localhost:8080/ems/Pages/Basic/Person.jsp
var curWwwPath = window.document.location.href;
//获取主机地址之后的目录,如: /ems/Pages/Basic/Person.jsp
var pathName = window.document.location.pathname;
var pos = curWwwPath.indexOf(pathName);
//获取主机地址,如: http://localhost:8080
//var localhostPath = curWwwPath.substring(0, pos);
var a = curWwwPath.split("/",3)
var localhostPath = a[0] + "//" + a[2];
//获取带"/"的项目名,如:/ems
var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
if(projectName == "/gpyh-site") { //暂时解决没有项目名问题
return (localhostPath + projectName);
} else {
return localhostPath;
}
}
/**
* 删除两端空格
*/
String.prototype.trim = function(){
return this.replace(/(^\s*)|(\s*$)/g, "");
}
String.prototype.startWith = function(str){
var reg = new RegExp("^"+str);
return reg.test(this);
}
String.prototype.endWith = function(str){
var reg = new RegExp(str+"$");
return reg.test(this);
}
//解决tofixed计算精度问题
Number.prototype.toFixed=function (d) {
var s=this+"";
if(!d)d=0;
if(s.indexOf(".")==-1)s+=".";
s+=new Array(d+1).join("0");
if(new RegExp("^(-|\\+)?(\\d+(\\.\\d{0,"+(d+1)+"})?)\\d*$").test(s)){
var s="0"+RegExp.$2,pm=RegExp.$1,a=RegExp.$3.length,b=true;
if(a==d+2){
a=s.match(/\d/g);
if(parseInt(a[a.length-1])>4){
for(var i=a.length-2;i>=0;i--){
a[i]=parseInt(a[i])+1;
if(a[i]==10){
a[i]=0;
b=i!=1;
}else break;
}
}
s=a.join("").replace(new RegExp("(\\d+)(\\d{"+d+"})\\d$"),"$1.$2");
}if(b)s=s.substr(1);
return (pm+s).replace(/\.$/,"");
}return this+"";
};
//允许输入小数位的数字
function clearNoFloat(curObj){
curObj.value = curObj.value.replace(/[^\d.]/g,""); //清除“数字”和“.”以外的字符
curObj.value = curObj.value.replace(/^\./g,""); //验证第一个字符是数字而不是.
curObj.value = curObj.value.replace(/\.{2,}/g,"."); //只保留第一个. 清除多余的.
curObj.value = curObj.value.replace(".","$#$").replace(/\./g,"").replace("$#$",".");
}
//允许正整数
function clearNoInt(curObj){
curObj.value = curObj.value.replace(/[^\d]/g,""); //清除“数字”和“.”以外的字符
}
/**
* 检查字符串是否为空
*/
function checkIsEmpty(str) {
if (null != str && undefined != str && "" != str) {
return false;
}
return true;
}
/**
* 检查字符串是否为空
*/
function checkIsBlank(str) {
if(str != null && undefined != str && typeof(str) == "string"){
str = str.trim();
}
if (null != str && undefined != str && "" != str) {
return false;
}
return true;
}
/**
* 检查用户名是否满足要求,只能是英文或英文数字
*/
function checkLoginName(loginName){
return /^[A-Za-z0-9]*$/.test(loginName) && !/(^\d*$)|(^\S+\s+\S+$)/.test(loginName);
}
/**
* 验证密码,必须是字母和数字结合
*/
function checkPasswordValidate(password){
return /^(?!^\d+$)(?!^[a-zA-Z]+$)[0-9a-zA-Z]{6,20}$/.test(password);
}
/**
* 检查输入的邮箱格式是否正确
*
* @param str
* 字符串
* @returns true 或 false; true表示格式正确
*/
function checkEmail(str) {
if (str.match(/[A-Za-z0-9_-]+[@](\S*)(net|com|cn|org|cc|tv|[0-9]{1,3})(\S*)/g) == null) {
return false;
} else {
return true;
}
}
/**
* 检查输入的手机号码格式是否正确
*
* @param str
* 字符串
* @returns true 或 false; true表示格式正确
*/
function checkMobilePhone(str) {
if (str.match("^1([0-9][0-9])\\d{8}$") == null) {
return false;
} else {
return true;
}
}
/**
* 检查输入的邮政编码是否正确
* @param str
* @returns {Boolean}
*/
function checkPostcode(str){
if (str.match(/^[1-9][0-9]{5}$/) == null) {
return false;
} else {
return true;
}
}
/**
* 检查输入的固定电话号码是否正确
*
* @param str
* 字符串
* @returns true 或 false; true表示格式正确
*/
function checkTelephone(str) {
var filter=/^(([0\+]\d{2,3}-)?(0\d{2,3})-)?(\d{7,8})(-(\d{1,}))?$/;
return filter.test(str);
}
//上传图片
function change(imgId, fileId) {
var pic = document.getElementById(imgId);
var file = document.getElementById(fileId);
var ext=file.value.substring(file.value.lastIndexOf(".")+1).toLowerCase();
// gif在IE浏览器暂时无法显示
if(ext != 'png' && ext != 'jpg' && ext != 'jpeg'){
file.value = "";
showMsg("图片格式必须是png、jpg或jpeg");
return;
}
var isIE = navigator.userAgent.match(/MSIE/) != null;
var isIE6 = navigator.userAgent.match(/MSIE 6.0/) != null;
if(isIE) {
file.select();
file.blur();
var reallocalpath = document.selection.createRange().text;
// IE6浏览器设置img的src为本地路径可以直接显示图片
if (isIE6) {
pic.src = reallocalpath;
}else {
// 非IE6版本的IE由于安全问题直接设置img的src无法显示本地图片,但是可以通过滤镜来实现
pic.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src=\"" + reallocalpath + "\")";
// 设置img的src为base64编码的透明图片 取消显示浏览器默认图片
pic.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
}
}else {
html5Reader(file, imgId);
}
}
//上传图片,显示图片
function html5Reader(file,imgId){
var file = file.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e){
var pic = document.getElementById(imgId);
pic.src=this.result;
}
}
//**************已使用*********************
/**验证是否为正整数
* @param str
* @returns
*/
function checkNumber(str){
return /^[1-9]\d*$/.test(str);
}
/**
* 检查输入的一串字符是否全部是数字
*
* @param str
* 字符串
* @returns true 或 false; true表示为数字
*/
function checkNum(str) {
if (checkHasFull(str)) {
return false;
}
return str.match(/\D/) == null;
}
/**
* 检查输入的一串字符是否全部是数字或者英文
*
* @param str
* 字符串
* @returns true 或 false; true表示为数字或者英文
*/
function checkEnNum(str) {
for ( var i = 0; i < str.length; i++) {
var strTmp = str.charAt(i);
if (!(/[A-Za-z0-9]/.test(strTmp))) {
return false;
}
}
return true;
}
/**
* 检查输入的一串字符是否全部是数字或者英文
*
* @param str
* 字符串
* @returns true 或 false; true表示为数字或者英文
*/
function checkUperCapsNum(str) {
for ( var i = 0; i < str.length; i++) {
var strTmp = str.charAt(i);
if (!(/[A-Z0-9]/.test(strTmp))) {
return false;
}
}
return true;
}
/**
* 检查输入的一串字符是否全部是数字或者英文或半角-或者空格
*
* @param str
* 字符串
* @returns true 或 false; true表示为数字或者英文
*/
function checkEnNumDashOrSpace(str) {
for ( var i = 0; i < str.length; i++) {
var strTmp = str.charAt(i);
if (strTmp == ' ') {
continue;
} else {
if (!(/[A-Za-z0-9-]/.test(strTmp))) {
return false;
}
}
}
return true;
}
/**
* 检查输入的一串字符是否全部是英文
*
* @param str
* 字符串
* @returns true 或 false; true表示为数字或者英文
*/
function checkEnDashOrSpace(str) {
for ( var i = 0; i < str.length; i++) {
var strTmp = str.charAt(i);
if (!(/[A-Za-z]/.test(strTmp))) {
return false;
}
}
return true;
}
/**
* 检查输入的一串字符是否为小数
*
* @param str
* 字符串
* @returns true 或 false; true表示为小数
*/
function checkDecimal(str) {
if (str.match(/^-?\d+(\.\d+)?$/g) == null) {
return false;
} else {
return true;
}
}
/**
* 检查输入的一串字符是否为整型数据
*
* @param str
* 字符串
* @returns true 或 false; true表示为小数
*/
function checkInteger(str) {
if (str.match(/^[-+]?\d*$/) == null) {
return false;
} else {
return true;
}
}
/**
* 检查输入的一串字符是否是字符
*
* @param str
* 字符串
* @returns true 或 false; true表示为全部为字符 不包含汉字
*/
function checkStr(str) {
if (/[^\x00-\xff]/g.test(str)) {
return false;
} else {
return true;
}
}
/**
* 检查输入的一串字符是否包含汉字
*
* @param str
* 字符串
* @returns true 或 false; true表示包含汉字
*/
function checkChinese(str) {
if (escape(str).indexOf("%u") != -1) {
return true;
} else {
return false;
}
}
/**
* 检查输入的身份证号是否正确
*
* @param str
* 字符串
* @returns true 或 false; true表示格式正确
*/
function checkCard(str) {
// 15位数身份证正则表达式
var arg1 = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
// 18位数身份证正则表达式
var arg2 = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[A-Z])$/;
if (str.match(arg1) == null && str.match(arg2) == null) {
return false;
} else {
return true;
}
}
/**
* 检查输入的字符是否具有特殊字符
*
* @param str
* 字符串
* @returns true 或 false; true表示包含特殊字符 主要用于注册信息的时候验证
*/
function checkQuote(str) {
var items = new Array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "{", "}", "[", "]", "(", ")");
items.push(":", ";", "'", "|", "\\", "<", ">", "?", "/", "<<", ">>", "||", "//");
items.push("select", "delete", "update", "insert", "create", "drop", "alter", "trancate");
str = str.toLowerCase();
for ( var i = 0; i < items.length; i++) {
if (str.indexOf(items[i]) >= 0) {
return true;
}
}
return false;
}
/**
* 判断是否包含全角
*
* @param str
*/
function checkHasFull(str) {
for ( var i = 0; i < str.length; i++) {
strCode = str.charCodeAt(i);
if ((strCode > 65248) || (strCode == 12288)) {
return true;
break;
}
}
return false;
}
/**
* 判断BigDecimal
*
* @param str
*/
function checkDecimalSize(str, pattern) {
if(BIGDECIMAL_PATTERN_FIVE_TWO != pattern && BIGDECIMAL_PATTERN_SEVEN_TWO != pattern) {
return false;
}
if (!checkDecimal(str)) {
return false;
}
var intPart = str.split(".")[0];
var decimalPart = str.split(".")[1];
var intPartSize = 0;
var decimalPartSize = 0;
if(BIGDECIMAL_PATTERN_FIVE_TWO == pattern) {
intPartSize = 5;
decimalPartSize = 2;
} else if (BIGDECIMAL_PATTERN_SEVEN_TWO != pattern) {
intPartSize = 7;
decimalPartSize = 2;
}
if (intPart.length > intPartSize || decimalPart.length > decimalPartSize) {
return false;
} else {
return true;
}
}
/**
* 验证日期格式
*
* @param strValue
* @returns {Boolean}
*/
function validateDate(strValue) {
var objRegExp = /^\d{4}(\/)\d{1,2}\1\d{1,2}$/;
if (!objRegExp.test(strValue)) {
return false;
} else {
var arrayDate = strValue.split(RegExp.$1);
var intDay = parseInt(arrayDate[2], 10);
var intYear = parseInt(arrayDate[0], 10);
var intMonth = parseInt(arrayDate[1], 10);
var day = arrayDate[2].split("");
if (day == null || day.length < 2) {
return false;
}
if (intMonth > 12 || intMonth < 1) {
return false;
}
var arrayLookup = {
'01' : 31,
'03' : 31,
'04' : 30,
'05' : 31,
'06' : 30,
'07' : 31,
'08' : 31,
'09' : 30,
'10' : 31,
'11' : 30,
'12' : 31
};
if (arrayLookup[arrayDate[1]] != null) {
if (intDay <= arrayLookup[arrayDate[1]] && intDay != 0)
return true;
}
if (intMonth - 2 == 0) {
var booLeapYear = (intYear % 4 == 0 && (intYear % 100 != 0 || intYear % 400 == 0));
if (((booLeapYear && intDay <= 29) || (!booLeapYear && intDay <= 28)) && intDay != 0)
return true;
}
}
return false;
}
/**
* 比较2个日期大小
*
* @param str1
* @param str2
* @param expression
* @returns {Boolean}
*/
function validateCompare(str1, str2, expression) {
switch (expression) {
case '>':
case 'gt':
return str1 > str2;
case '>=':
return str1 >= str2;
case '==':
case 'eq':
return str1 == str2;
case '<=':
return str1 <= str2;
case '<':
case 'lt':
return str1 < str2;
default:
return true;
}
return true;
}
/**
* 验证开始时间结束时间
*
* @param objId
* 当前焦点时区时的控件ID
* @param startDate
* 开始时间ID
* @param endDate
* 结束时间ID
* @param DateName
* 验证的名字
* @param errorArea
* 错误显示区域ID
* @returns {Boolean}
*/
function validateDateInput(objId, startDate, endDate, DateName, errorArea) {
sDate = startDate;
eDate = endDate;
thisDate = objId;
dName = DateName;
eArea = errorArea;
var flag;
var res = true;
$("#" + errorArea).html("");
$("#" + startDate).removeClass("lightRed");
$("#" + endDate).removeClass("lightRed");
// 验证第一个控件
if ($("#" + startDate).val() != "") {
flag = validateDate($("#" + startDate).val());
if (flag == false) {
$("#" + errorArea).html(DateName + ERR_COMMON_JS_014);
$("#" + startDate).addClass("lightRed");
res = false;
}
}
// 验证第二个控件
if ($("#" + endDate).val() != "") {
flag = validateDate($("#" + endDate).val());
if (flag == false) {
$("#" + errorArea).html(DateName + ERR_COMMON_JS_015);
$("#" + endDate).addClass("lightRed");
res = false;
}
}
// 优先验证焦点离开的控件
if (objId != null && objId != "" && $("#" + objId) != null) {
flag = validateDate($("#" + objId).val());
if ($("#" + objId).val() != "" && flag == false) {
$("#" + objId).addClass("lightRed");
if (objId == startDate) {
$("#" + errorArea).html(DateName + ERR_COMMON_JS_014);
} else {
$("#" + errorArea).html(DateName + ERR_COMMON_JS_015);
}
res = false;
}
}
if(res != false){
// 验证大小关系
if ($("#" + startDate).val() != "" && $("#" + endDate).val() != "") {
flag = validateCompare($("#" + startDate).val(), $("#" + endDate).val(), "<=");
if (flag == false) {
$("#" + startDate).addClass("lightRed");
$("#" + endDate).addClass("lightRed");
$("#" + errorArea).html(DateName + ERR_COMMON_JS_016);
res = false;
} else {
res = true;
}
}
}
return res;
}
/**
* 验证开始时间结束时间
*
* @param startDate
* 开始时间ID
* @param endDate
* 结束时间ID
* @param DateName
* 验证的名字
* @returns {message}
*/
function validateDateInput2(startDate, endDate, DateName) {
sDate = startDate;
eDate = endDate;
dName = DateName;
var message = "";
var flag;
var res = true;
$("#" + startDate).removeClass("lightRed");
$("#" + endDate).removeClass("lightRed");
// 验证第一个控件
if ($("#" + startDate).val() != "") {
flag = validateDate($("#" + startDate).val());
if (flag == false) {
message = DateName + ERR_COMMON_JS_014;
$("#" + startDate).addClass("lightRed");
res = false;
}
}
// 验证第二个控件
if ($("#" + endDate).val() != "") {
flag = validateDate($("#" + endDate).val());
if (flag == false) {
if(!res){
message += "<br/>";
}
message += DateName + ERR_COMMON_JS_015;
$("#" + endDate).addClass("lightRed");
res = false;
}
}
if(res != false){
// 验证大小关系
if ($("#" + startDate).val() != "" && $("#" + endDate).val() != "") {
flag = validateCompare($("#" + startDate).val(), $("#" + endDate).val(), "<=");
if (flag == false) {
$("#" + startDate).addClass("lightRed");
$("#" + endDate).addClass("lightRed");
message = (DateName + ERR_COMMON_JS_016);
res = false;
} else {
res = true;
}
}
}
return message;
}
/**
* 验证是否为网址
* @param str_url
* @returns {Boolean}
*/
function checkURL(str_url){
var strRegex = "^((https|http|ftp|rtsp|mms)?://)"
+ "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" //ftp的user@
+ "(([0-9]{1,3}\.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184
+ "|" // 允许IP和DOMAIN(域名)
+ "([0-9a-z_!~*'()-]+\.)*" // 域名- www.
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\." // 二级域名
+ "[a-z]{2,6})" // first level domain- .com or .museum
+ "(:[0-9]{1,4})?" // 端口- :80
+ "((/?)|" // a slash isn't required if there is no file name
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
var re=new RegExp(strRegex);
//re.test()
if (re.test(str_url)){
return (true);
}else{
return (false);
}
}
/**
* 如果值为undefined返回''
* @param obj
* @returns
*/
function ifUndefined(obj){
if(obj==null || obj=='null' || obj=='NULL'){
obj= '';
}
return typeof(obj)=="undefined"?'':obj;
}
/* 上传图片时,还未提交也显示
*/
function changeImg(imgId,fileId) {
var pic = document.getElementById(imgId),
file = document.getElementById(fileId);
var ext=file.value.substring(file.value.lastIndexOf(".")+1).toLowerCase();
// gif在IE浏览器暂时无法显示
if(ext!='png'&&ext!='jpg'&&ext!='jpeg'){
layerMsg("<h3>图片的格式必须为png、jpg或jpeg!</h3>");
return;
}
var isIE = navigator.userAgent.match(/MSIE/)!= null,
isIE6 = navigator.userAgent.match(/MSIE 6.0/)!= null;
if(isIE) {
file.select();
file.blur();
var reallocalpath = document.selection.createRange().text;
// IE6浏览器设置img的src为本地路径可以直接显示图片
if (isIE6) {
pic.src = reallocalpath;
}else {
// 非IE6版本的IE由于安全问题直接设置img的src无法显示本地图片,但是可以通过滤镜来实现
pic.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src=\"" + reallocalpath + "\")";
// 设置img的src为base64编码的透明图片 取消显示浏览器默认图片
pic.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
}
}else {
html5Reader(file,imgId);
}
}
/**
* 上传图片时,还未提交也显示
*/
function html5Reader(file,imgId){
var file = file.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e){
var pic = document.getElementById(imgId);
pic.src=this.result;
}
}
/**
* 检验密码的安全性
*/
function check_password(thisval, obj){
var characters = 0;
var capitalletters = 0;
var loweletters = 0;
var number = 0;
var upperCase= new RegExp('[A-Z]');
var lowerCase= new RegExp('[a-z]');
var numbers = new RegExp('[0-9]');
var specialchars = new RegExp('([!,%,&,@,#,$,^,*,?,_,~])');
if (thisval.length > 6) { characters = 1; } else { characters = 0; };
if (thisval.match(upperCase)) { capitalletters = 1} else { capitalletters = 0; };
if (thisval.match(lowerCase)) { loweletters = 1} else { loweletters = 0; };
if (thisval.match(numbers)) { number = 1} else { number = 0; };
var total = characters + capitalletters + loweletters + number;
if(total == 0){
$(obj).html("未设置密码");
}else if (total <= 1) {
$(obj).html('非常弱');
} else if (total == 2){
$(obj).html(' 一般');
} else if(total == 3){
$(obj).html('中等');
} else {
$(obj).html('很安全');
}
}
//获取url中的参数
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]); return null; //返回参数值
}
//设置cookie(当前页面有效)
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + "; " + expires;
}
//获取cookie(当前页面有效)
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1);
if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
}
return "";
}
//清除cookie(当前页面有效)
function clearCookie(name) {
setCookie(name, "", -1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment