Commit 797c16cc authored by Dmitry.Shahtanov's avatar Dmitry.Shahtanov Committed by Alexander.Trofimov

работа с временем переведена на UTC, пространство имен для функций.

git-svn-id: svn://192.168.3.15/activex/AVS/Sources/TeamlabOffice/trunk/OfficeWeb@55785 954022d7-b5bf-4e40-9824-e11837661b57
parent 60a874e7
...@@ -2621,7 +2621,7 @@ ...@@ -2621,7 +2621,7 @@
var nSize = A.length; var nSize = A.length;
if ( A.length < 1 || nSize == 0 ) if ( A.length < 1 || nSize == 0 )
return new CError( cErrorType.not_available ).toString(); return new cError( cErrorType.not_available ).toString();
else { else {
if ( nSize == 1 ) if ( nSize == 1 )
return toFixed( A[0] ); return toFixed( A[0] );
...@@ -4142,7 +4142,7 @@ ...@@ -4142,7 +4142,7 @@
oParser = new parserFormula( "PRICE(DATE(2008,2,15),DATE(2017,11,15),0.0575,0.065,100,2,0)", "A2", ws ); oParser = new parserFormula( "PRICE(DATE(2008,2,15),DATE(2017,11,15),0.0575,0.065,100,2,0)", "A2", ws );
ok( oParser.parse() ); ok( oParser.parse() );
strictEqual( oParser.calculate().getValue(), _getprice( new Date( 2008, 1, 15 ), new Date( 2017, 10, 15 ), 0.0575, 0.065, 100, 2, 0 ) ); strictEqual( oParser.calculate().getValue(), _getprice( new Date( Date.UTC(2008, 1, 15 )), new Date( Date.UTC(2017, 10, 15 )), 0.0575, 0.065, 100, 2, 0 ) );
} ) } )
...@@ -4184,7 +4184,7 @@ ...@@ -4184,7 +4184,7 @@
oParser = new parserFormula( "YIELD(DATE(2008,2,15),DATE(2016,11,15),0.0575,95.04287,100,2,0)", "A2", ws ); oParser = new parserFormula( "YIELD(DATE(2008,2,15),DATE(2016,11,15),0.0575,95.04287,100,2,0)", "A2", ws );
ok( oParser.parse() ); ok( oParser.parse() );
strictEqual( oParser.calculate().getValue(), _getYield( new Date(2008,1,15), new Date(2016,10,15),0.0575,95.04287,100,2,0 ) ); strictEqual( oParser.calculate().getValue(), _getYield( new Date(Date.UTC(2008,1,15)), new Date(Date.UTC(2016,10,15)),0.0575,95.04287,100,2,0 ) );
} ) } )
...@@ -4229,7 +4229,7 @@ ...@@ -4229,7 +4229,7 @@
oParser = new parserFormula( "ODDLPRICE(DATE(2008,11,11),DATE(2021,3,1),DATE(2008,10,15),0.0785,0.0625,100,2,1)", "A2", ws ); oParser = new parserFormula( "ODDLPRICE(DATE(2008,11,11),DATE(2021,3,1),DATE(2008,10,15),0.0785,0.0625,100,2,1)", "A2", ws );
ok( oParser.parse() ); ok( oParser.parse() );
strictEqual( oParser.calculate().getValue(), oddlprice( new Date(2008,10,11), new Date(2021,2,1), new Date(2008,9,15), 0.0785, 0.0625, 100, 2, 1 ) ); strictEqual( oParser.calculate().getValue(), oddlprice( new Date(Date.UTC(2008,10,11)), new Date(Date.UTC(2021,2,1)), new Date(Date.UTC(2008,9,15)), 0.0785, 0.0625, 100, 2, 1 ) );
} ) } )
...@@ -4259,7 +4259,7 @@ ...@@ -4259,7 +4259,7 @@
oParser = new parserFormula( "DURATION(DATE(2008,1,1),DATE(2016,1,1),0.08,0.09,2,1)", "A2", ws ); oParser = new parserFormula( "DURATION(DATE(2008,1,1),DATE(2016,1,1),0.08,0.09,2,1)", "A2", ws );
ok( oParser.parse() ); ok( oParser.parse() );
strictEqual( oParser.calculate().getValue(), _duration( new Date(2008,0,1), new Date(2016,0,1), 0.08, 0.09, 2, 1 ) ); strictEqual( oParser.calculate().getValue(), _duration( new Date(Date.UTC(2008,0,1)), new Date(Date.UTC(2016,0,1)), 0.08, 0.09, 2, 1 ) );
} ) } )
...@@ -4273,7 +4273,7 @@ ...@@ -4273,7 +4273,7 @@
oParser = new parserFormula( "MDURATION(DATE(2008,1,1),DATE(2016,1,1),0.08,0.09,2,1)", "A2", ws ); oParser = new parserFormula( "MDURATION(DATE(2008,1,1),DATE(2016,1,1),0.08,0.09,2,1)", "A2", ws );
ok( oParser.parse() ); ok( oParser.parse() );
strictEqual( oParser.calculate().getValue(), mduration( new Date(2008,0,1), new Date(2016,0,1), 0.08, 0.09, 2, 1 ) ); strictEqual( oParser.calculate().getValue(), mduration( new Date(Date.UTC(2008,0,1)), new Date(Date.UTC(2016,0,1)), 0.08, 0.09, 2, 1 ) );
} ) } )
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:15 * Time: 15:15
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Cube = { FormulaObjects.cFormulaFunction.Cube = {
'groupName':"Cube", 'groupName':"Cube",
'CUBEKPIMEMBER':cCUBEKPIMEMBER, 'CUBEKPIMEMBER':cCUBEKPIMEMBER,
'CUBEMEMBER':cCUBEMEMBER, 'CUBEMEMBER':cCUBEMEMBER,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:16 * Time: 15:16
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Database = { FormulaObjects.cFormulaFunction.Database = {
'groupName':"Database", 'groupName':"Database",
'DAVERAGE':cDAVERAGE, 'DAVERAGE':cDAVERAGE,
'DCOUNT':cDCOUNT, 'DCOUNT':cDCOUNT,
......
...@@ -351,7 +351,7 @@ function BesselY( fNum, nOrder ) { ...@@ -351,7 +351,7 @@ function BesselY( fNum, nOrder ) {
* Time: 12:25 * Time: 12:25
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Engineering = { FormulaObjects.cFormulaFunction.Engineering = {
'groupName':"Engineering", 'groupName':"Engineering",
'BESSELI':cBESSELI, 'BESSELI':cBESSELI,
'BESSELJ':cBESSELJ, 'BESSELJ':cBESSELJ,
......
...@@ -165,7 +165,7 @@ function RateIteration( nper, payment, pv, fv, payType, guess ) { ...@@ -165,7 +165,7 @@ function RateIteration( nper, payment, pv, fv, payType, guess ) {
function lcl_GetCouppcd( settl, matur, freq ) { function lcl_GetCouppcd( settl, matur, freq ) {
var n = new Date( matur ); var n = new Date( matur );
n.setFullYear( settl.getFullYear() ); n.setUTCFullYear( settl.getUTCFullYear() );
if ( n < settl ) { if ( n < settl ) {
n.addYears( 1 ); n.addYears( 1 );
} }
...@@ -176,7 +176,7 @@ function lcl_GetCouppcd( settl, matur, freq ) { ...@@ -176,7 +176,7 @@ function lcl_GetCouppcd( settl, matur, freq ) {
} }
function lcl_GetCoupncd( settl, matur, freq ) { function lcl_GetCoupncd( settl, matur, freq ) {
matur.setFullYear( settl.getFullYear() ); matur.setUTCFullYear( settl.getUTCFullYear() );
if ( matur > settl ) { if ( matur > settl ) {
matur.addYears( -1 ); matur.addYears( -1 );
} }
...@@ -199,7 +199,7 @@ function getcoupdays( settl, matur, frequency, basis ) { ...@@ -199,7 +199,7 @@ function getcoupdays( settl, matur, frequency, basis ) {
function getcoupnum( settl, matur, frequency ) { function getcoupnum( settl, matur, frequency ) {
var n = lcl_GetCouppcd( settl, matur, frequency ), var n = lcl_GetCouppcd( settl, matur, frequency ),
months = (matur.getFullYear() - n.getFullYear()) * 12 + matur.getMonth() - n.getMonth(); months = (matur.getUTCFullYear() - n.getUTCFullYear()) * 12 + matur.getUTCMonth() - n.getUTCMonth();
return Math.ceil( months * frequency / 12 ); return Math.ceil( months * frequency / 12 );
} }
...@@ -289,9 +289,9 @@ function getyieldmat( settle, mat, issue, rate, price, base ) { ...@@ -289,9 +289,9 @@ function getyieldmat( settle, mat, issue, rate, price, base ) {
function getduration( settlement, maturity, coupon, yld, frequency, basis ) { function getduration( settlement, maturity, coupon, yld, frequency, basis ) {
var dbc = getcoupdaybs( new Date( settlement ).truncate(), new Date( maturity ).truncate(), frequency, basis ), var dbc = getcoupdaybs( new Date( settlement ), new Date( maturity ), frequency, basis ),
coupD = getcoupdays( new Date( settlement ).truncate(), new Date( maturity ).truncate(), frequency, basis ), coupD = getcoupdays( new Date( settlement ), new Date( maturity ), frequency, basis ),
numCoup = getcoupnum( new Date( settlement ).truncate(), new Date( maturity ).truncate(), frequency ); numCoup = getcoupnum( new Date( settlement ), new Date( maturity ), frequency );
var duration = 0, p = 0; var duration = 0, p = 0;
...@@ -326,7 +326,7 @@ function getduration( settlement, maturity, coupon, yld, frequency, basis ) { ...@@ -326,7 +326,7 @@ function getduration( settlement, maturity, coupon, yld, frequency, basis ) {
* Time: 15:19 * Time: 15:19
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Financial = { FormulaObjects.cFormulaFunction.Financial = {
'groupName':"Financial", 'groupName':"Financial",
'ACCRINT':cACCRINT, 'ACCRINT':cACCRINT,
'ACCRINTM':cACCRINTM, 'ACCRINTM':cACCRINTM,
...@@ -3278,7 +3278,7 @@ cODDFPRICE.prototype.Calculate = function ( arg ) { ...@@ -3278,7 +3278,7 @@ cODDFPRICE.prototype.Calculate = function ( arg ) {
var newDate = new Date( orgDate ); var newDate = new Date( orgDate );
newDate.addMonths( numMonths ); newDate.addMonths( numMonths );
if ( returnLastDay ) if ( returnLastDay )
return new Date( newDate.getFullYear(), newDate.getMonth(), newDate.getDaysInMonth() ); return new Date( newDate.getUTCFullYear(), newDate.getUTCMonth(), newDate.getDaysInMonth() );
else else
return newDate; return newDate;
} }
...@@ -3302,8 +3302,8 @@ cODDFPRICE.prototype.Calculate = function ( arg ) { ...@@ -3302,8 +3302,8 @@ cODDFPRICE.prototype.Calculate = function ( arg ) {
} }
function coupNumber( mat, settl, numMonths, isWholeNumber ) { function coupNumber( mat, settl, numMonths, isWholeNumber ) {
var my = mat.getFullYear(), mm = mat.getMonth() + 1, md = mat.getDate(), var my = mat.getUTCFullYear(), mm = mat.getUTCMonth() + 1, md = mat.getDate(),
sy = settl.getFullYear(), sm = settl.getMonth() + 1, sd = settl.getDate(), sy = settl.getUTCFullYear(), sm = settl.getUTCMonth() + 1, sd = settl.getDate(),
endOfMonthTemp = lastDayOfMonth( my, mm, md ), endOfMonthTemp = lastDayOfMonth( my, mm, md ),
endOfMonth = (!endOfMonthTemp && mm != 2 && md > 28 && md < new Date( my, mm ).getDaysInMonth()) ? lastDayOfMonth( sy, sm, sd ) : endOfMonthTemp, endOfMonth = (!endOfMonthTemp && mm != 2 && md > 28 && md < new Date( my, mm ).getDaysInMonth()) ? lastDayOfMonth( sy, sm, sd ) : endOfMonthTemp,
startDate = changeMonth( settl, 0, endOfMonth ), startDate = changeMonth( settl, 0, endOfMonth ),
...@@ -4684,8 +4684,8 @@ cTBILLEQ.prototype.Calculate = function ( arg ) { ...@@ -4684,8 +4684,8 @@ cTBILLEQ.prototype.Calculate = function ( arg ) {
var d1 = Date.prototype.getDateFromExcel( settlement.getValue() ); var d1 = Date.prototype.getDateFromExcel( settlement.getValue() );
var d2 = Date.prototype.getDateFromExcel( nMat ); var d2 = Date.prototype.getDateFromExcel( nMat );
var date1 = d1.getDate(), month1 = d1.getMonth(), year1 = d1.getFullYear(), var date1 = d1.getUTCDate(), month1 = d1.getUTCMonth(), year1 = d1.getUTCFullYear(),
date2 = d2.getDate(), month2 = d2.getMonth(), year2 = d2.getFullYear(); date2 = d2.getUTCDate(), month2 = d2.getUTCMonth(), year2 = d2.getUTCFullYear();
var nDiff = GetDiffDate360( date1, month1, year1, d1.isLeapYear(), date2, month2, year2, true ); var nDiff = GetDiffDate360( date1, month1, year1, d1.isLeapYear(), date2, month2, year2, true );
...@@ -4838,8 +4838,8 @@ cTBILLYIELD.prototype.Calculate = function ( arg ) { ...@@ -4838,8 +4838,8 @@ cTBILLYIELD.prototype.Calculate = function ( arg ) {
var d1 = Date.prototype.getDateFromExcel( settlement.getValue() ); var d1 = Date.prototype.getDateFromExcel( settlement.getValue() );
var d2 = Date.prototype.getDateFromExcel( maturity.getValue() ); var d2 = Date.prototype.getDateFromExcel( maturity.getValue() );
var date1 = d1.getDate(), month1 = d1.getMonth(), year1 = d1.getFullYear(), var date1 = d1.getUTCDate(), month1 = d1.getUTCMonth(), year1 = d1.getUTCFullYear(),
date2 = d2.getDate(), month2 = d2.getMonth(), year2 = d2.getFullYear(); date2 = d2.getUTCDate(), month2 = d2.getUTCMonth(), year2 = d2.getUTCFullYear();
var nDiff = GetDiffDate360( date1, month1, year1, d1.isLeapYear(), date2, month2, year2, true ); var nDiff = GetDiffDate360( date1, month1, year1, d1.isLeapYear(), date2, month2, year2, true );
nDiff++; nDiff++;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:21 * Time: 15:21
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Information = { FormulaObjects.cFormulaFunction.Information = {
'groupName':"Information", 'groupName':"Information",
'ERROR.TYPE':cERROR_TYPE, 'ERROR.TYPE':cERROR_TYPE,
'ISBLANK':cISBLANK, 'ISBLANK':cISBLANK,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:22 * Time: 15:22
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Logical = { FormulaObjects.cFormulaFunction.Logical = {
'groupName':"Logical", 'groupName':"Logical",
'AND':cAND, 'AND':cAND,
'FALSE':cFALSE, 'FALSE':cFALSE,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:21 * Time: 15:21
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.LookupAndReference = { FormulaObjects.cFormulaFunction.LookupAndReference = {
'groupName':"LookupAndReference", 'groupName':"LookupAndReference",
'ADDRESS':cADDRESS, 'ADDRESS':cADDRESS,
'AREAS':cAREAS, 'AREAS':cAREAS,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:20 * Time: 15:20
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Mathematic = { FormulaObjects.cFormulaFunction.Mathematic = {
'groupName':"Mathematic", 'groupName':"Mathematic",
'ABS':cABS, 'ABS':cABS,
'ACOS':cACOS, 'ACOS':cACOS,
...@@ -2857,42 +2857,39 @@ function cROMAN() { ...@@ -2857,42 +2857,39 @@ function cROMAN() {
} }
cROMAN.prototype = Object.create( cBaseFunction.prototype ) cROMAN.prototype = Object.create( cBaseFunction.prototype )
cROMAN.prototype.Calculate = function ( arg ) { cROMAN.prototype.Calculate = function ( arg ) {
function roman( fVal, fMode ) { function roman( num, mode ) {
if ( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) ) { if ( (mode >= 0) && (mode < 5) && (num >= 0) && (num < 4000) ) {
var pChars = [ 'M', 'D', 'C', 'L', 'X', 'V', 'I' ]; var chars = [ 'M', 'D', 'C', 'L', 'X', 'V', 'I' ],
var pValues = [ 1000, 500, 100, 50, 10, 5, 1 ]; values = [ 1000, 500, 100, 50, 10, 5, 1 ],
var nMaxIndex = pValues.length - 1; maxIndex = values.length - 1,
aRoman = "",
var aRoman = ""; index, digit, index2, steps;
var nVal = fVal; for ( var i = 0; i <= maxIndex / 2; i++ ) {
var nMode = fMode; index = 2 * i;
digit = parseInt( num / values[ index ] );
for ( var i = 0; i <= nMaxIndex / 2; i++ ) {
var nIndex = 2 * i; if ( (digit % 5) == 4 ) {
var nDigit = parseInt( nVal / pValues[ nIndex ] ); index2 = (digit == 4) ? index - 1 : index - 2;
steps = 0;
if ( (nDigit % 5) == 4 ) { while ( (steps < mode) && (index < maxIndex) ) {
var nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2; steps++;
var nSteps = 0; if ( values[ index2 ] - values[ index + 1 ] <= num )
while ( (nSteps < nMode) && (nIndex < nMaxIndex) ) { index++;
nSteps++;
if ( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
nIndex++;
else else
nSteps = nMode; steps = mode;
} }
aRoman += pChars[ nIndex ]; aRoman += chars[ index ];
aRoman += pChars[ nIndex2 ]; aRoman += chars[ index2 ];
nVal = ( nVal + pValues[ nIndex ] ); num = ( num + values[ index ] );
nVal = ( nVal - pValues[ nIndex2 ] ); num = ( num - values[ index2 ] );
} }
else { else {
if ( nDigit > 4 ) if ( digit > 4 )
aRoman += pChars[ nIndex - 1 ]; aRoman += chars[ index - 1 ];
for ( var j = nDigit % 5; j > 0; j-- ) { for ( var j = digit % 5; j > 0; j-- ) {
aRoman += pChars[ nIndex ]; aRoman += chars[ index ];
} }
nVal %= pValues[ nIndex ]; num %= values[ index ];
} }
} }
return new cString( aRoman ); return new cString( aRoman );
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:18 * Time: 15:18
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.Statistical = { FormulaObjects.cFormulaFunction.Statistical = {
'groupName':"Statistical", 'groupName':"Statistical",
'AVEDEV':cAVEDEV, 'AVEDEV':cAVEDEV,
'AVERAGE':cAVERAGE, 'AVERAGE':cAVERAGE,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Time: 15:17 * Time: 15:17
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
cFormulaFunction.TextAndData = { FormulaObjects.cFormulaFunction.TextAndData = {
'groupName':"TextAndData", 'groupName':"TextAndData",
'ASC':cASC, 'ASC':cASC,
'BAHTTEXT':cBAHTTEXT, 'BAHTTEXT':cBAHTTEXT,
...@@ -609,7 +609,7 @@ cFIND.prototype.getInfo = function () { ...@@ -609,7 +609,7 @@ cFIND.prototype.getInfo = function () {
} }
function cFINDB() { function cFINDB() {
var r = new cFormulaFunction.TextAndData["FIND"]() var r = new FormulaObjects.cFormulaFunction.TextAndData["FIND"]()
r.setName( "FINDB" ); r.setName( "FINDB" );
return r; return r;
} }
...@@ -869,7 +869,7 @@ cLEFT.prototype.getInfo = function () { ...@@ -869,7 +869,7 @@ cLEFT.prototype.getInfo = function () {
} }
function cLEFTB() { function cLEFTB() {
var r = new cFormulaFunction.TextAndData["LEFT"]() var r = new FormulaObjects.cFormulaFunction.TextAndData["LEFT"]()
r.setName( "LEFTB" ); r.setName( "LEFTB" );
return r; return r;
} }
...@@ -918,7 +918,7 @@ cLEN.prototype.getInfo = function () { ...@@ -918,7 +918,7 @@ cLEN.prototype.getInfo = function () {
} }
function cLENB() { function cLENB() {
var r = new cFormulaFunction.TextAndData["LEN"](); var r = new FormulaObjects.cFormulaFunction.TextAndData["LEN"]();
r.setName( "LENB" ); r.setName( "LENB" );
return r; return r;
} }
...@@ -1033,7 +1033,7 @@ cMID.prototype.getInfo = function () { ...@@ -1033,7 +1033,7 @@ cMID.prototype.getInfo = function () {
} }
function cMIDB() { function cMIDB() {
var r = new cFormulaFunction.TextAndData["MID"](); var r = new FormulaObjects.cFormulaFunction.TextAndData["MID"]();
r.setName( "MIDB" ); r.setName( "MIDB" );
return r; return r;
} }
...@@ -1210,7 +1210,7 @@ cREPLACE.prototype.getInfo = function () { ...@@ -1210,7 +1210,7 @@ cREPLACE.prototype.getInfo = function () {
} }
function cREPLACEB() { function cREPLACEB() {
var r = new cFormulaFunction.TextAndData["REPLACE"](); var r = new FormulaObjects.cFormulaFunction.TextAndData["REPLACE"]();
r.setName( "REPLACEB" ); r.setName( "REPLACEB" );
return r; return r;
} }
...@@ -1344,7 +1344,7 @@ cRIGHT.prototype.getInfo = function () { ...@@ -1344,7 +1344,7 @@ cRIGHT.prototype.getInfo = function () {
} }
function cRIGHTB() { function cRIGHTB() {
var r = new cFormulaFunction.TextAndData["RIGHT"]() var r = new FormulaObjects.cFormulaFunction.TextAndData["RIGHT"]()
r.setName( "RIGHTB" ); r.setName( "RIGHTB" );
return r; return r;
} }
...@@ -1450,7 +1450,7 @@ cSEARCH.prototype.getInfo = function () { ...@@ -1450,7 +1450,7 @@ cSEARCH.prototype.getInfo = function () {
} }
function cSEARCHB() { function cSEARCHB() {
var r = new cFormulaFunction.TextAndData["SEARCH"](); var r = new FormulaObjects.cFormulaFunction.TextAndData["SEARCH"]();
r.setName( "SEARCHB" ); r.setName( "SEARCHB" );
return r; return r;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment