Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…sights-JS/security/code-scanning (#1744)

And Dependabot potential security vulnerabilities in your dependencies.
  • Loading branch information
MSNev committed Jan 14, 2022
1 parent 543f20b commit 20d8707
Show file tree
Hide file tree
Showing 37 changed files with 2,384 additions and 2,899 deletions.
2 changes: 1 addition & 1 deletion AISKU/src/Init.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { Initialization as ApplicationInsights, Telemetry, Snippet } from "./Initialization";
import { Snippet } from "./Initialization";
import { ApplicationInsightsContainer } from "./ApplicationInsightsContainer";

export { Initialization as ApplicationInsights, Telemetry, Snippet } from "./Initialization";
Expand Down
2 changes: 2 additions & 0 deletions AISKU/src/Initialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
ITelemetryContext as Common_ITelemetryContext, parseConnectionString
} from "@microsoft/applicationinsights-common"

export { IUtil, ICorrelationIdHelper, IUrlHelper, IDateTimeUtils, IRequestHeaders };

"use strict";

let _internalSdkSrc: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export function PageViewEnvelopeCreator(logger: IDiagnosticLogger, telemetryItem
if (((telemetryItem.ext || {}).trace || {}).traceID) {
currentContextId = telemetryItem.ext.trace.traceID;
}
const id = bd.id || currentContextId
const id = bd.id || currentContextId;
const name = bd.name;
const url = bd.uri;
const properties = bd[strProperties] || {};
Expand Down
2 changes: 1 addition & 1 deletion channels/applicationinsights-channel-js/src/Offline.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EventHelper, getWindow, getDocument, getNavigator, isUndefined, isNullOrUndefined, attachEvent } from "@microsoft/applicationinsights-core-js";
import { getWindow, getDocument, getNavigator, isUndefined, isNullOrUndefined, attachEvent } from "@microsoft/applicationinsights-core-js";
import dynamicProto from "@microsoft/dynamicproto-js";

/**
Expand Down
2 changes: 1 addition & 1 deletion channels/applicationinsights-channel-js/src/SendBuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export class SessionStorageSendBuffer extends BaseSendBuffer implements ISendBuf
sentElements = _removePayloadsFromBuffer(payload, sentElements);

_setBuffer(SessionStorageSendBuffer.SENT_BUFFER_KEY, sentElements);
}
};

function _removePayloadsFromBuffer(payloads: string[], buffer: string[]): string[] {
const remaining: string[] = [];
Expand Down
2 changes: 1 addition & 1 deletion channels/applicationinsights-channel-js/src/Sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControlsAI {

_self.addHeader = (name: string, value: string) => {
_headers[name] = value;
}
};

_self.initialize = (config: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?:ITelemetryPluginChain): void => {
_base.initialize(config, core, extensions, pluginChain);
Expand Down
5,168 changes: 2,325 additions & 2,843 deletions common/config/rush/npm-shrinkwrap.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
BaseTelemetryPlugin, ITelemetryItem, IProcessTelemetryContext, ITelemetryPluginChain,
IDiagnosticLogger, LoggingSeverity, _InternalMessageId, ICustomProperties,
getWindow, getDocument, getHistory, getLocation, doPerf, objForEachKey,
isString, isFunction, isNullOrUndefined, arrForEach, generateW3CId, dumpObj, getExceptionName, isError, ICookieMgr, safeGetCookieMgr
isString, isFunction, isNullOrUndefined, arrForEach, generateW3CId, dumpObj, getExceptionName, ICookieMgr, safeGetCookieMgr
} from "@microsoft/applicationinsights-core-js";
import { PageViewManager, IAppInsightsInternal } from "./Telemetry/PageViewManager";
import { PageVisitTimeManager } from "./Telemetry/PageVisitTimeManager";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from "@microsoft/applicationinsights-common";
import {
IAppInsightsCore, IDiagnosticLogger, LoggingSeverity,
_InternalMessageId, getNavigator, getPerformance, isNotNullOrUndefined
_InternalMessageId, getNavigator, getPerformance
} from "@microsoft/applicationinsights-core-js";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class PageVisitTimeManager {
return null;
} catch (e) {
this._logger.warnToConsole("Stop page visit timer failed: " + dumpObj(e));
return null
return null;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class PageAction extends WebEvent {
this._traceLogger.throwInternal(
LoggingSeverity.WARNING,
_ExtendedInternalMessageId.InvalidContentBlob, "Missing attributes id or contentName in click event. Click event information will still be collected!"
)
);
}
}
pageActionEvent.name = elementContent.id || elementContent.contentName || strNotSpecified;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class DomContentHandler implements IContentHandler {
this._traceLogger.throwInternal(
LoggingSeverity.CRITICAL,
_ExtendedInternalMessageId.CannotParseAiBlobValue, "Can not parse " + biBlobValue
)
);
}
} else {
// traverse up the DOM to find the closest parent with data-* tag defined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function myFunc() {
'trackTrace',
'throwInternal',
'logInternalMessage'
]
];

var debugPlugin = Microsoft.ApplicationInsights.DebugPlugin;
var debugPluginInstance = new debugPlugin();
Expand All @@ -85,7 +85,7 @@ function myFunc() {
};

configObj.extensionConfig[debugPlugin.identifier] = {
//trackers: toTrack,
trackers: toTrack,
//logProcessTelemetry: true,
maxMessages: 50
};
Expand Down Expand Up @@ -114,7 +114,7 @@ function myFunc() {
var idx = appInsights.core._extensions.findIndex(function(v) { return v.identifier === 'ChannelControllerPlugin' });
appInsights.core._extensions[idx].getChannelControls()[0][0].triggerSend();
}
}
};

var container = document.createElement('div');
container.style.position = 'absolute';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ export class Dashboard {
textFilterInput.className = "text-filter-input";
textFilterInput.setAttribute("placeholder", "filter text");
textFilterInput.onchange = (evt: Event) => {
_self.setTextFilter(textFilterInput.value)
}
_self.setTextFilter(textFilterInput.value);
};

textFilterInput.onblur = (evt: Event) => {
_self.setTextFilter(textFilterInput.value)
}
_self.setTextFilter(textFilterInput.value);
};

textFilterInput.onkeyup = (evt: Event) => {
if (keyupTimer != null) {
Expand All @@ -203,10 +203,10 @@ export class Dashboard {
if (newValue !== _self.getTextFilter()) {
keyupTimer = setTimeout(() => {
keyupTimer = null;
_self.setTextFilter(textFilterInput.value)
_self.setTextFilter(textFilterInput.value);
}, 200);
}
}
};

controlDiv.appendChild(textFilterInput);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { ITelemetryPlugin, IConfiguration } from "@microsoft/applicationinsights-core-js";
import { IConfiguration } from "@microsoft/applicationinsights-core-js";

export interface IDebugPluginConfig extends IConfiguration{

Expand Down
8 changes: 5 additions & 3 deletions extensions/applicationinsights-dependencies-js/src/ajax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
import {
isNullOrUndefined, arrForEach, isString, strTrim, isFunction, LoggingSeverity, _InternalMessageId,
IAppInsightsCore, BaseTelemetryPlugin, ITelemetryPluginChain, IConfiguration, IPlugin, ITelemetryItem, IProcessTelemetryContext,
getLocation, getGlobal, strUndefined, strPrototype, IInstrumentCallDetails, InstrumentFunc, InstrumentProto, getPerformance,
IInstrumentHooksCallbacks, IInstrumentHook, objForEachKey, generateW3CId, getIEVersion, dumpObj,objKeys, ICustomProperties, isXhrSupported, attachEvent
getLocation, getGlobal, strPrototype, IInstrumentCallDetails, InstrumentFunc, InstrumentProto, getPerformance,
IInstrumentHooksCallbacks, IInstrumentHook, objForEachKey, generateW3CId, getIEVersion, dumpObj, ICustomProperties, isXhrSupported, attachEvent
} from "@microsoft/applicationinsights-core-js";
import { ajaxRecord, IAjaxRecordResponse } from "./ajaxRecord";
import { Traceparent } from "./TraceParent";
Expand Down Expand Up @@ -259,10 +259,12 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
let propExt: any, extIx = 0;
while (!propExt && extIx < extensions.length) {
if (extensions[extIx] && extensions[extIx].identifier === PropertiesPluginIdentifier) {
propExt = extensions[extIx]
propExt = extensions[extIx];
}

extIx++;
}

if (propExt) {
_context = propExt.context; // we could move IPropertiesPlugin to common as well
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function _populatePerfData(ajaxData:ajaxRecord, dependency:IDependencyTelemetry)
let strTransferSize = "transferSize";
let strEncodedBodySize = "encodedBodySize";
let strDecodedBodySize = "decodedBodySize";
let strServerTiming = "serverTiming"
let strServerTiming = "serverTiming";

if (resourceEntry) {
// redirect
Expand Down Expand Up @@ -157,9 +157,9 @@ function _populatePerfData(ajaxData:ajaxRecord, dependency:IDependencyTelemetry)
propsSet |= _setPerfValue(props, strServerTiming, server);
}

propsSet |= _setPerfValue(props, strTransferSize, resourceEntry[strTransferSize])
propsSet |= _setPerfValue(props, strEncodedBodySize, resourceEntry[strEncodedBodySize])
propsSet |= _setPerfValue(props, strDecodedBodySize, resourceEntry[strDecodedBodySize])
propsSet |= _setPerfValue(props, strTransferSize, resourceEntry[strTransferSize]);
propsSet |= _setPerfValue(props, strEncodedBodySize, resourceEntry[strEncodedBodySize]);
propsSet |= _setPerfValue(props, strDecodedBodySize, resourceEntry[strDecodedBodySize]);
} else {
if (ajaxData.perfMark) {
propsSet |= _setPerfValue(props, "missing", ajaxData.perfAttempts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import dynamicProto from "@microsoft/dynamicproto-js";
import { ISession, utlCanUseLocalStorage, utlGetLocalStorage, utlSetLocalStorage } from "@microsoft/applicationinsights-common";
import {
IDiagnosticLogger, _InternalMessageId, LoggingSeverity, DiagnosticLogger, IAppInsightsCore, ICookieMgr, safeGetCookieMgr, isFunction,
IDiagnosticLogger, _InternalMessageId, LoggingSeverity, IAppInsightsCore, ICookieMgr, safeGetCookieMgr, isFunction,
newId, dumpObj, getExceptionName, dateNow, safeGetLogger
} from "@microsoft/applicationinsights-core-js";

Expand Down Expand Up @@ -211,7 +211,7 @@ export class _SessionManager {

function _setCookie(session: ISession, nowMs: number) {
let acq = session.acquisitionDate;
session.renewalDate = nowMs
session.renewalDate = nowMs;

let config = _self.config;
let renewalPeriodMs = config.sessionRenewalMs();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import dynamicProto from "@microsoft/dynamicproto-js";
import { ITelemetryConfig } from "../Interfaces/ITelemetryConfig";
import { utlRemoveStorage, IUserContext, CtxTagKeys } from "@microsoft/applicationinsights-common";
import { utlRemoveStorage, IUserContext } from "@microsoft/applicationinsights-common";
import { _InternalMessageId, LoggingSeverity, IAppInsightsCore, ICookieMgr, safeGetCookieMgr, safeGetLogger, newId, toISOString } from "@microsoft/applicationinsights-core-js";


Expand Down
4 changes: 2 additions & 2 deletions extensions/applicationinsights-react-js/src/ReactPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import {
IConfig, IPageViewTelemetry, IMetricTelemetry, IAppInsights, IEventTelemetry, IExceptionTelemetry, ITraceTelemetry
} from "@microsoft/applicationinsights-common";
import {
IPlugin, IConfiguration, IAppInsightsCore, IDiagnosticLogger,
IPlugin, IConfiguration, IAppInsightsCore,
ITelemetryPlugin, BaseTelemetryPlugin, ITelemetryItem, IProcessTelemetryContext,
ITelemetryPluginChain, _InternalMessageId, LoggingSeverity, ICustomProperties, safeGetCookieMgr, ICookieMgr, arrForEach
} from "@microsoft/applicationinsights-core-js";
import { IReactExtensionConfig } from './Interfaces/IReactExtensionConfig';
import { History, Location, Action, Update } from "history";
import { History, Location, Update } from "history";

export default class ReactPlugin extends BaseTelemetryPlugin {
public priority = 185;
Expand Down
2 changes: 1 addition & 1 deletion gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ module.exports = function (grunt) {
// const perfTestVersions = ["2.0.0","2.0.1","2.1.0","2.2.0","2.2.1","2.2.2","2.3.0","2.3.1",
// "2.4.1","2.4.3","2.4.4","2.5.2","2.5.3","2.5.4","2.5.5","2.5.6","2.5.7","2.5.8","2.5.9","2.5.10","2.5.11",
// "2.6.0","2.6.1","2.6.2","2.6.3","2.6.4","2.6.5","2.7.0"];
const perfTestVersions=["2.7.1"]
const perfTestVersions=["2.7.1"];

try {
var theBuildConfig = deepMerge(buildConfig({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { IDiagnosticLogger, LoggingSeverity, _InternalMessageId, hasJSON, getJSON, objForEachKey, isObject, isString, strTrim } from "@microsoft/applicationinsights-core-js";
import { IDiagnosticLogger, LoggingSeverity, _InternalMessageId, hasJSON, getJSON, objForEachKey, isObject, strTrim } from "@microsoft/applicationinsights-core-js";

export const enum DataSanitizerValues {
/**
Expand Down
4 changes: 2 additions & 2 deletions shared/AppInsightsCommon/src/Telemetry/Exception.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ISerializable } from "../Interfaces/Telemetry/ISerializable";
import { dataSanitizeException, dataSanitizeMeasurements, dataSanitizeMessage, dataSanitizeProperties, dataSanitizeString } from "./Common/DataSanitizer";
import { FieldType } from "../Enums";
import { SeverityLevel } from "../Interfaces/Contracts/Generated/SeverityLevel";
import { IDiagnosticLogger, isNullOrUndefined, arrMap, isString, strTrim, isArray, isError, arrForEach, isObject, isFunction, getSetValue } from "@microsoft/applicationinsights-core-js";
import { IDiagnosticLogger, isNullOrUndefined, arrMap, isString, strTrim, isArray, isError, arrForEach, isObject, isFunction } from "@microsoft/applicationinsights-core-js";
import {
IExceptionInternal, IExceptionDetailsInternal, IExceptionStackFrameInternal, IAutoExceptionTelemetry, IStackDetails
} from "../Interfaces/IExceptionTelemetry";
Expand Down Expand Up @@ -391,7 +391,7 @@ export class Exception extends ExceptionData implements ISerializable {
}

public toInterface(): IExceptionInternal {
const { exceptions, properties, measurements, severityLevel, ver, problemGroup, id, isManual } = this;
const { exceptions, properties, measurements, severityLevel, problemGroup, id, isManual } = this;

const exceptionDetailsInterface = exceptions instanceof Array
&& arrMap(exceptions, (exception: _ExceptionDetails) => exception.toInterface())
Expand Down
4 changes: 2 additions & 2 deletions shared/AppInsightsCommon/src/Telemetry/PageViewPerformance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PageViewPerfData } from "../Interfaces/Contracts/Generated/PageViewPerf
import { FieldType } from "../Enums";
import { ISerializable } from "../Interfaces/Telemetry/ISerializable";
import { dataSanitizeMeasurements, dataSanitizeProperties, dataSanitizeString, dataSanitizeUrl } from "./Common/DataSanitizer";
import { IDiagnosticLogger, _InternalMessageId, LoggingSeverity } from "@microsoft/applicationinsights-core-js";
import { IDiagnosticLogger, _InternalMessageId } from "@microsoft/applicationinsights-core-js";
import { IPageViewPerformanceTelemetry } from "../Interfaces/IPageViewPerformanceTelemetry";
import { strNotSpecified } from "../Constants";

Expand Down Expand Up @@ -42,7 +42,7 @@ export class PageViewPerformance extends PageViewPerfData implements ISerializab

if (cs4BaseData) {
this.domProcessing = cs4BaseData.domProcessing;
this.duration = cs4BaseData.duration
this.duration = cs4BaseData.duration;
this.networkConnect = cs4BaseData.networkConnect;
this.perfTotal = cs4BaseData.perfTotal;
this.receivedResponse = cs4BaseData.receivedResponse;
Expand Down
3 changes: 1 addition & 2 deletions shared/AppInsightsCommon/src/Util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { StorageType } from "./Enums";
import {
_InternalMessageId, IDiagnosticLogger, IPlugin, getPerformance,
getExceptionName as coreGetExceptionName, dumpObj,
Expand Down Expand Up @@ -421,7 +420,7 @@ export function AjaxHelperParseDependencyPath(logger: IDiagnosticLogger, absolut
let target, name = commandName, data = commandName;

if (absoluteUrl && absoluteUrl.length > 0) {
const parsedUrl: HTMLAnchorElement = urlParseUrl(absoluteUrl)
const parsedUrl: HTMLAnchorElement = urlParseUrl(absoluteUrl);
target = parsedUrl.host;
if (!name) {
if (parsedUrl.pathname != null) {
Expand Down
2 changes: 1 addition & 1 deletion shared/AppInsightsCore/src/JavaScriptSDK/CookieMgr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export function createCookieMgr(rootConfig?: IConfiguration, logger?: IDiagnosti
if (_isMgrEnabled(cookieMgr)) {
let values: any = {};
let theValue = strTrim(value || strEmpty);
let idx = theValue.indexOf(";")
let idx = theValue.indexOf(";");
if (idx !== -1) {
theValue = strTrim(value.substring(0, idx));
values = _extractParts(value.substring(idx + 1));
Expand Down
2 changes: 1 addition & 1 deletion shared/AppInsightsCore/src/JavaScriptSDK/EnvUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ export function isFetchSupported(withKeepAlive?: boolean): boolean {

export function useXDomainRequest(): boolean | undefined {
if (_useXDomainRequest === null) {
_useXDomainRequest = (typeof XDomainRequest !== undefined);
_useXDomainRequest = (typeof XDomainRequest !== "undefined");
if (_useXDomainRequest && isXhrSupported()) {
_useXDomainRequest = _useXDomainRequest && !_hasProperty(getGlobalInst("XMLHttpRequest"), "withCredentials");
}
Expand Down
4 changes: 2 additions & 2 deletions shared/AppInsightsCore/src/JavaScriptSDK/PerfManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class PerfEvent implements IPerfEvent {
// If we couldn't define the property set during complete -- to minimize the perf impact until after the time
_self.payload = payloadDetails();
}
}
};
}
}

Expand Down Expand Up @@ -232,7 +232,7 @@ export function doPerf<T>(mgrSource: IPerfManagerProvider | IPerfManager, getSou
let perfMgr: IPerfManager = mgrSource as IPerfManager;
if (isFunction(perfMgr["getPerfMgr"])) {
// Looks like a perf manager provider object
perfMgr = perfMgr["getPerfMgr"]()
perfMgr = perfMgr["getPerfMgr"]();
}

if (perfMgr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem";
import { IPlugin, ITelemetryPlugin } from "../JavaScriptSDK.Interfaces/ITelemetryPlugin";
import { IProcessTelemetryContext } from "../JavaScriptSDK.Interfaces/IProcessTelemetryContext";
import { ITelemetryPluginChain } from "../JavaScriptSDK.Interfaces/ITelemetryPluginChain";
import { DiagnosticLogger, safeGetLogger } from "./DiagnosticLogger";
import { safeGetLogger } from "./DiagnosticLogger";
import { TelemetryPluginChain } from "./TelemetryPluginChain";
import { arrForEach, isFunction, isNullOrUndefined, isUndefined } from "./HelperFuncs";

Expand Down
2 changes: 1 addition & 1 deletion tools/chrome-debug-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"@types/node": "11.13.2",
"@types/react": "^16.9.11",
"@types/react-dom": "^16.9.4",
"ansi-regex": "4.1.0",
"ansi-regex": ">=5.0.1",
"autoprefixer": "9.4.5",
"grunt": "^1.4.1",
"rollup": "^2.32.0",
Expand Down
2 changes: 1 addition & 1 deletion tools/chrome-debug-extension/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export function formatLogElements(target: Object, tmLabel: string, key: string,
currentLine.className = "obj-key expandable closed"
}

let matched = true;
let matched: boolean;
// Always displayed opened if there is no filter
let childOpened = textFilter ? false : true;
const keys = getTargetKeys(target, excludeKeys, includeFunctions as boolean);
Expand Down
2 changes: 1 addition & 1 deletion tools/chrome-debug-extension/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ export class Session {
}
}

if (filterText && this._filterSettings.filterContent) {
if (this._filterSettings.filterContent) {
let excludeKeys: string[] = [];
let logEntry = singleDataEvent.logEntry = singleDataEvent.logEntry || new LogEntry(singleDataEvent.data, 0);
if (logEntry.isMatch(filterText, excludeKeys, true)) {
Expand Down
Loading

0 comments on commit 20d8707

Please sign in to comment.