Skip to content

Commit

Permalink
RUM-5248 feat: setup ContextReceiver which can observe to single prop…
Browse files Browse the repository at this point in the history
…erty in context message
  • Loading branch information
ganeshnj committed Jul 15, 2024
1 parent 216873d commit cd9c78d
Show file tree
Hide file tree
Showing 16 changed files with 346 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- [FEATURE] Enable DatadogCore, DatadogLogs and DatadogTrace to compile on watchOS platform. See [#1918][] (Thanks [@jfiser-paylocity][]) [#1946][]
- [IMPROVEMENT] Ability to clear feature data storage using `clearAllData` API. See [#1940][]
- [IMPROVEMENT] Send memory warning as RUM error.

# 2.14.1 / 09-07-2024

Expand Down
30 changes: 30 additions & 0 deletions Datadog/Datadog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
3C41693C29FBF4D50042B9D2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; };
3C43A3882C188974000BFB21 /* WatchdogTerminationMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */; };
3C43A3892C188975000BFB21 /* WatchdogTerminationMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */; };
3C5CD8C22C3EBA1700B12303 /* MemoryWarningPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C12C3EBA1700B12303 /* MemoryWarningPublisher.swift */; };
3C5CD8C32C3EBA1700B12303 /* MemoryWarningPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C12C3EBA1700B12303 /* MemoryWarningPublisher.swift */; };
3C5CD8C72C3EC61F00B12303 /* MemoryWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */; };
3C5CD8C82C3EC62000B12303 /* MemoryWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */; };
3C5CD8CD2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */; };
3C5CD8CE2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */; };
3C5D63692B55512B00FEB4BA /* OTelTraceState+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */; };
3C5D636A2B55512B00FEB4BA /* OTelTraceState+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */; };
3C5D636C2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D636B2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift */; };
Expand Down Expand Up @@ -103,6 +109,10 @@
3CCECDB32BC68A0A0013C125 /* SpanIDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCECDB12BC68A0A0013C125 /* SpanIDTests.swift */; };
3CDA3F7E2BCD866D005D2C13 /* DatadogSDKTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 3CDA3F7D2BCD866D005D2C13 /* DatadogSDKTesting */; };
3CDA3F802BCD8687005D2C13 /* DatadogSDKTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 3CDA3F7F2BCD8687005D2C13 /* DatadogSDKTesting */; };
3CDD60DE2C45574500371331 /* ContextReceptionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDD60DD2C45574500371331 /* ContextReceptionManager.swift */; };
3CDD60DF2C45574500371331 /* ContextReceptionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDD60DD2C45574500371331 /* ContextReceptionManager.swift */; };
3CDD60E12C4557BE00371331 /* ContextReceiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDD60E02C4557BE00371331 /* ContextReceiver.swift */; };
3CDD60E22C4557BE00371331 /* ContextReceiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDD60E02C4557BE00371331 /* ContextReceiver.swift */; };
3CE11A1129F7BE0900202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; };
3CE11A1229F7BE0900202522 /* DatadogWebViewTracking.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3CEC57732C16FD0B0042B5F2 /* WatchdogTerminationMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CEC57702C16FD000042B5F2 /* WatchdogTerminationMocks.swift */; };
Expand Down Expand Up @@ -2107,6 +2117,9 @@
3C33E4062BEE35A7003B2988 /* RUMContextMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMContextMocks.swift; sourceTree = "<group>"; };
3C3EF2AF2C1AEBAB009E9E57 /* LaunchReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchReport.swift; sourceTree = "<group>"; };
3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchdogTerminationMonitorTests.swift; sourceTree = "<group>"; };
3C5CD8C12C3EBA1700B12303 /* MemoryWarningPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarningPublisher.swift; sourceTree = "<group>"; };
3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarning.swift; sourceTree = "<group>"; };
3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarningReporter.swift; sourceTree = "<group>"; };
3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceState+Datadog.swift"; sourceTree = "<group>"; };
3C5D636B2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceState+DatadogTests.swift"; sourceTree = "<group>"; };
3C6C7FE02B459AAA006F5CBC /* OTelSpan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTelSpan.swift; sourceTree = "<group>"; };
Expand All @@ -2132,6 +2145,8 @@
3CCCA5C62ABAF5230029D7BD /* DDURLSessionInstrumentationConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDURLSessionInstrumentationConfigurationTests.swift; sourceTree = "<group>"; };
3CCECDAE2BC688120013C125 /* SpanIDGeneratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanIDGeneratorTests.swift; sourceTree = "<group>"; };
3CCECDB12BC68A0A0013C125 /* SpanIDTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanIDTests.swift; sourceTree = "<group>"; };
3CDD60DD2C45574500371331 /* ContextReceptionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextReceptionManager.swift; sourceTree = "<group>"; };
3CDD60E02C4557BE00371331 /* ContextReceiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextReceiver.swift; sourceTree = "<group>"; };
3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DatadogWebViewTrackingTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
3CEC57702C16FD000042B5F2 /* WatchdogTerminationMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchdogTerminationMocks.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4811,6 +4826,7 @@
616CCE11250A181C009FED46 /* Instrumentation */ = {
isa = PBXGroup;
children = (
3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */,
616CCE12250A1868009FED46 /* RUMCommandSubscriber.swift */,
616CCE15250A467E009FED46 /* RUMInstrumentation.swift */,
61F3CDA1251118DD00C816E5 /* Views */,
Expand Down Expand Up @@ -5827,6 +5843,7 @@
D23039BE298D5235001A1FA3 /* LaunchTime.swift */,
D2F8235229915E12003C7E99 /* DatadogSite.swift */,
6174D6122BFDF16C00EC7469 /* BundleType.swift */,
3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */,
);
path = Context;
sourceTree = "<group>";
Expand All @@ -5837,6 +5854,8 @@
D2216EBF2A94DE2800ADAEC8 /* FeatureBaggage.swift */,
D23039C1298D5235001A1FA3 /* FeatureMessageReceiver.swift */,
D23039C2298D5235001A1FA3 /* FeatureMessage.swift */,
3CDD60DD2C45574500371331 /* ContextReceptionManager.swift */,
3CDD60E02C4557BE00371331 /* ContextReceiver.swift */,
);
path = MessageBus;
sourceTree = "<group>";
Expand Down Expand Up @@ -6439,6 +6458,7 @@
D2553828288F0B2300727FAD /* LowPowerModePublisher.swift */,
D29294DF291D5ECD00F8EFF9 /* ApplicationVersionPublisher.swift */,
D2FB1253292E0E92005B13F8 /* TrackingConsentPublisher.swift */,
3C5CD8C12C3EBA1700B12303 /* MemoryWarningPublisher.swift */,
);
path = Context;
sourceTree = "<group>";
Expand Down Expand Up @@ -8036,6 +8056,7 @@
D2C7E3AE28FEBDA10023B2CC /* LaunchTimePublisher.swift in Sources */,
61133BD12423979B00786299 /* FilesOrchestrator.swift in Sources */,
D20605A3287464F40047275C /* ContextValuePublisher.swift in Sources */,
3C5CD8C22C3EBA1700B12303 /* MemoryWarningPublisher.swift in Sources */,
61DA8CAF28620C760074A606 /* Cryptography.swift in Sources */,
E1D5AEA724B4D45B007F194B /* Versioning.swift in Sources */,
61133BD82423979B00786299 /* URLSessionClient.swift in Sources */,
Expand Down Expand Up @@ -8579,6 +8600,7 @@
D23039F9298D5236001A1FA3 /* CoreLogger.swift in Sources */,
D2160CA229C0DE5700FAA9A5 /* NetworkInstrumentationFeature.swift in Sources */,
D2EBEE1F29BA160F00B15732 /* HTTPHeadersReader.swift in Sources */,
3C5CD8C72C3EC61F00B12303 /* MemoryWarning.swift in Sources */,
E2AA55E72C32C6D9002FEF28 /* ApplicationNotifications.swift in Sources */,
D263BCAF29DAFFEB00FA0E21 /* PerformancePresetOverride.swift in Sources */,
D23039E7298D5236001A1FA3 /* NetworkConnectionInfo.swift in Sources */,
Expand Down Expand Up @@ -8617,6 +8639,7 @@
D23039FA298D5236001A1FA3 /* Telemetry.swift in Sources */,
D23039FC298D5236001A1FA3 /* DataFormat.swift in Sources */,
D2160CED29C0E0E600FAA9A5 /* DatadogURLSessionHandler.swift in Sources */,
3CDD60DE2C45574500371331 /* ContextReceptionManager.swift in Sources */,
D2160C9E29C0DE5700FAA9A5 /* TracingHeaderType.swift in Sources */,
D23039F5298D5236001A1FA3 /* AnyEncodable.swift in Sources */,
D2303A00298D5236001A1FA3 /* DatadogExtended.swift in Sources */,
Expand All @@ -8635,6 +8658,7 @@
3C9B27252B9F174700569C07 /* SpanID.swift in Sources */,
D2216EC02A94DE2900ADAEC8 /* FeatureBaggage.swift in Sources */,
D23039F1298D5236001A1FA3 /* AnyDecodable.swift in Sources */,
3CDD60E12C4557BE00371331 /* ContextReceiver.swift in Sources */,
6167E6E22B81207200C3CA2D /* DDCrashReport.swift in Sources */,
D2160CC529C0DED100FAA9A5 /* URLSessionTaskInterception.swift in Sources */,
6167E6FD2B81EC0400C3CA2D /* BacktraceReporter.swift in Sources */,
Expand Down Expand Up @@ -8751,6 +8775,7 @@
D23F8E8229DDCD28001CFAE8 /* RUMSessionScope.swift in Sources */,
D23F8E8329DDCD28001CFAE8 /* RUMUser.swift in Sources */,
D23F8E8429DDCD28001CFAE8 /* UIKitRUMUserActionsPredicate.swift in Sources */,
3C5CD8CE2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */,
D23F8E8529DDCD28001CFAE8 /* SwiftUIExtensions.swift in Sources */,
3CFF4F952C09E63C006F191D /* WatchdogTerminationChecker.swift in Sources */,
D23F8E8629DDCD28001CFAE8 /* RUMDataModelsMapping.swift in Sources */,
Expand Down Expand Up @@ -9080,6 +9105,7 @@
D29A9F5C29DD85BB005C54A4 /* RUMSessionScope.swift in Sources */,
D29A9F6629DD85BB005C54A4 /* RUMUser.swift in Sources */,
D29A9F8229DD85BB005C54A4 /* UIKitRUMUserActionsPredicate.swift in Sources */,
3C5CD8CD2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */,
D29A9F8E29DD8665005C54A4 /* SwiftUIExtensions.swift in Sources */,
3CFF4F942C09E63C006F191D /* WatchdogTerminationChecker.swift in Sources */,
D29A9F7829DD85BB005C54A4 /* RUMDataModelsMapping.swift in Sources */,
Expand Down Expand Up @@ -9301,6 +9327,7 @@
D2CB6E9727C50EAE00A62B57 /* DataUploadStatus.swift in Sources */,
D255382A288F0B2400727FAD /* LowPowerModePublisher.swift in Sources */,
D2CB6E9927C50EAE00A62B57 /* DataUploadWorker.swift in Sources */,
3C5CD8C32C3EBA1700B12303 /* MemoryWarningPublisher.swift in Sources */,
D2CB6E9A27C50EAE00A62B57 /* KronosTimeStorage.swift in Sources */,
D2CB6E9B27C50EAE00A62B57 /* FilesOrchestrator.swift in Sources */,
D2553827288F0B1A00727FAD /* BatteryStatusPublisher.swift in Sources */,
Expand Down Expand Up @@ -9547,6 +9574,7 @@
D2DA2358298D57AA00C6C7E6 /* CoreLogger.swift in Sources */,
D2160CA329C0DE5700FAA9A5 /* NetworkInstrumentationFeature.swift in Sources */,
D2EBEE2D29BA161100B15732 /* HTTPHeadersReader.swift in Sources */,
3C5CD8C82C3EC62000B12303 /* MemoryWarning.swift in Sources */,
E2AA55E82C32C6D9002FEF28 /* ApplicationNotifications.swift in Sources */,
D263BCB029DAFFEB00FA0E21 /* PerformancePresetOverride.swift in Sources */,
D2DA2359298D57AA00C6C7E6 /* NetworkConnectionInfo.swift in Sources */,
Expand Down Expand Up @@ -9585,6 +9613,7 @@
D2DA2367298D57AA00C6C7E6 /* Telemetry.swift in Sources */,
D2DA2368298D57AA00C6C7E6 /* DataFormat.swift in Sources */,
D2160CEE29C0E0E600FAA9A5 /* DatadogURLSessionHandler.swift in Sources */,
3CDD60DF2C45574500371331 /* ContextReceptionManager.swift in Sources */,
D2160C9F29C0DE5700FAA9A5 /* TracingHeaderType.swift in Sources */,
D2DA2369298D57AA00C6C7E6 /* AnyEncodable.swift in Sources */,
D2DA236A298D57AA00C6C7E6 /* DatadogExtended.swift in Sources */,
Expand All @@ -9603,6 +9632,7 @@
3C9B27262B9F174700569C07 /* SpanID.swift in Sources */,
D2216EC12A94DE2900ADAEC8 /* FeatureBaggage.swift in Sources */,
D2DA2370298D57AA00C6C7E6 /* AnyDecodable.swift in Sources */,
3CDD60E22C4557BE00371331 /* ContextReceiver.swift in Sources */,
6167E6E32B81207200C3CA2D /* DDCrashReport.swift in Sources */,
D2160CC629C0DED100FAA9A5 /* URLSessionTaskInterception.swift in Sources */,
6167E6FE2B81EC0400C3CA2D /* BacktraceReporter.swift in Sources */,
Expand Down
51 changes: 51 additions & 0 deletions DatadogCore/Sources/Core/Context/MemoryWarningPublisher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/

import Foundation
import DatadogInternal
import UIKit

/// Tracks the memory warnings history and publishes it to the subscribers.
internal final class MemoryWarningPublisher: ContextValuePublisher {
private let queue: DispatchQueue
var initialValue: MemoryWarningsHistory
private var receiver: ContextValueReceiver<MemoryWarningsHistory>?
private let notificationCenter: NotificationCenter
private var history: MemoryWarningsHistory

private static let defaultQueue = DispatchQueue(
label: "com.datadoghq.memory-warning-publisher",
target: .global(qos: .utility)
)

init(
notificationCenter: NotificationCenter = .default,
queue: DispatchQueue = MemoryWarningPublisher.defaultQueue,
initialValue: MemoryWarningsHistory = .init()
) {
self.notificationCenter = notificationCenter
self.queue = queue
self.initialValue = initialValue
self.history = initialValue
}

func publish(to receiver: @escaping ContextValueReceiver<MemoryWarningsHistory>) {
queue.async { self.receiver = receiver }
notificationCenter.addObserver(self, selector: #selector(didReceiveMemoryWarning), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
}

@objc
func didReceiveMemoryWarning() {
queue.async {
self.history.append(warning: .init())
self.receiver?(self.history)
}
}

func cancel() {
notificationCenter.removeObserver(self)
}
}
21 changes: 19 additions & 2 deletions DatadogCore/Sources/Core/DatadogCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ internal final class DatadogCore {
/// The message-bus instance.
let bus = MessageBus()

let contextReceptionManager: ContextReceptionManager

/// Registry for Features.
@ReadWriteLock
private(set) var stores: [String: (storage: FeatureStorage, upload: FeatureUpload)] = [:]
Expand Down Expand Up @@ -93,7 +95,8 @@ internal final class DatadogCore {
applicationVersion: String,
maxBatchesPerUpload: Int,
backgroundTasksEnabled: Bool,
isRunFromExtension: Bool = false
isRunFromExtension: Bool = false,
contextReceptionManager: ContextReceptionManager = .init()
) {
self.directory = directory
self.dateProvider = dateProvider
Expand All @@ -106,6 +109,7 @@ internal final class DatadogCore {
self.isRunFromExtension = isRunFromExtension
self.applicationVersionPublisher = ApplicationVersionPublisher(version: applicationVersion)
self.consentPublisher = TrackingConsentPublisher(consent: initialConsent)
self.contextReceptionManager = contextReceptionManager
self.contextProvider.subscribe(\.userInfo, to: userInfoPublisher)
self.contextProvider.subscribe(\.version, to: applicationVersionPublisher)
self.contextProvider.subscribe(\.trackingConsent, to: consentPublisher)
Expand Down Expand Up @@ -181,7 +185,17 @@ internal final class DatadogCore {
private func add(messageReceiver: FeatureMessageReceiver, forKey key: String) {
bus.connect(messageReceiver, forKey: key)
contextProvider.read { context in
self.bus.queue.async { messageReceiver.receive(message: .context(context), from: self) }
self.bus.queue.async {
let message: FeatureMessage = .context(context)
switch messageReceiver {
case let contextReceiver as ContextReceiver:
if self.contextReceptionManager.canReceive(contextReceiver, message: message) {
contextReceiver.receive(message: message, from: self)
}
default:
messageReceiver.receive(message: message, from: self)
}
}
}
}

Expand Down Expand Up @@ -452,6 +466,9 @@ extension DatadogContextProvider {
self.subscribe(\.applicationStateHistory, to: applicationStatePublisher)
}
#endif

let memoryWarningPublisher = MemoryWarningPublisher()
self.subscribe(\.memoryWarningHistory, to: memoryWarningPublisher)
}
}

Expand Down
11 changes: 8 additions & 3 deletions DatadogCore/Sources/Core/MessageBus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ internal final class MessageBus {
}

/// Removes the given key and its associated receiver from the bus.
///
///
/// - Parameter key: The key to remove along with its associated receiver.
func removeReceiver(forKey key: String) {
queue.async { self.bus.removeValue(forKey: key) }
Expand All @@ -99,8 +99,13 @@ internal final class MessageBus {
return
}

let receivers = self.bus.values.filter {
$0.receive(message: message, from: core)
let receivers = self.bus.values.filter { receiver in
switch receiver {
case let contextReceiver as ContextReceiver:
return contextReceiver.receive(message: message, from: core)
default:
return receiver.receive(message: message, from: core)
}
}

if receivers.isEmpty {
Expand Down
Loading

0 comments on commit cd9c78d

Please sign in to comment.