Skip to content

Commit

Permalink
wip introduce proxy realtime presence class
Browse files Browse the repository at this point in the history
no functionality here
  • Loading branch information
lawrence-forooghian committed Feb 13, 2025
1 parent fa17140 commit 7cf48a3
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 5 deletions.
24 changes: 24 additions & 0 deletions Ably.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,15 @@
21E5D8932D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E5D8922D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m */; };
21E5D8942D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E5D8922D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m */; };
21E5D8952D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E5D8922D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m */; };
21E5D8972D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E5D8962D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m */; };
21E5D8982D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E5D8962D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m */; };
21E5D8992D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E5D8962D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m */; };
21E5D89B2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E5D89A2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h */; settings = {ATTRIBUTES = (Public, ); }; };
21E5D89C2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E5D89A2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h */; settings = {ATTRIBUTES = (Public, ); }; };
21E5D89D2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E5D89A2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h */; settings = {ATTRIBUTES = (Public, ); }; };
21E5D89F2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E5D89E2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
21E5D8A02D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E5D89E2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
21E5D8A12D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E5D89E2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
21FD9F272A015BE400216482 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD9F262A015BE400216482 /* Test.swift */; };
21FD9F282A015BE400216482 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD9F262A015BE400216482 /* Test.swift */; };
21FD9F292A015BE400216482 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD9F262A015BE400216482 /* Test.swift */; };
Expand Down Expand Up @@ -1362,6 +1371,9 @@
21E5D88A2D5E65F600526C4C /* ARTWrapperSDKProxyPushChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ARTWrapperSDKProxyPushChannel.h; path = include/Ably/ARTWrapperSDKProxyPushChannel.h; sourceTree = "<group>"; };
21E5D88E2D5E663500526C4C /* ARTWrapperSDKProxyPushChannel+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "ARTWrapperSDKProxyPushChannel+Private.h"; path = "PrivateHeaders/Ably/ARTWrapperSDKProxyPushChannel+Private.h"; sourceTree = "<group>"; };
21E5D8922D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTWrapperSDKProxyPushChannel.m; sourceTree = "<group>"; };
21E5D8962D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTWrapperSDKProxyRealtimePresence.m; sourceTree = "<group>"; };
21E5D89A2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ARTWrapperSDKProxyRealtimePresence.h; path = include/Ably/ARTWrapperSDKProxyRealtimePresence.h; sourceTree = "<group>"; };
21E5D89E2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "ARTWrapperSDKProxyRealtimePresence+Private.h"; path = "PrivateHeaders/Ably/ARTWrapperSDKProxyRealtimePresence+Private.h"; sourceTree = "<group>"; };
21FD9F262A015BE400216482 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = "<group>"; };
560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARTDefaultTests.swift; sourceTree = "<group>"; };
56190953238C3D3200A862A6 /* CryptoTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1742,6 +1754,9 @@
21E5D88A2D5E65F600526C4C /* ARTWrapperSDKProxyPushChannel.h */,
21E5D88E2D5E663500526C4C /* ARTWrapperSDKProxyPushChannel+Private.h */,
21E5D8922D5E665C00526C4C /* ARTWrapperSDKProxyPushChannel.m */,
21E5D89A2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h */,
21E5D89E2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h */,
21E5D8962D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m */,
);
name = "Wrapper SDK Proxy";
sourceTree = "<group>";
Expand Down Expand Up @@ -2417,6 +2432,7 @@
21E5D8722D5D321700526C4C /* ARTWrapperSDKProxyPushChannelSubscriptions+Private.h in Headers */,
21E5D8732D5D321700526C4C /* ARTWrapperSDKProxyPushDeviceRegistrations+Private.h in Headers */,
96BF615E1A35C1C8004CF2B3 /* ARTTypes.h in Headers */,
21E5D89D2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h in Headers */,
EB503C881C7E4A090053AF00 /* ARTClientOptions+Private.h in Headers */,
EB2D84F71CD75CCE00F23CDA /* ARTReachability.h in Headers */,
D73B655523EF2B2900D459A6 /* ARTDeltaCodec.h in Headers */,
Expand All @@ -2428,6 +2444,7 @@
213AEA272D35A7FC0067FD5F /* ARTWrapperSDKProxyRealtime.h in Headers */,
96BF61641A35CDE1004CF2B3 /* ARTBaseMessage.h in Headers */,
D746AE221BBB60EE003ECEF8 /* ARTChannel.h in Headers */,
21E5D89F2D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h in Headers */,
D7D5A69A1CA3D9040071BD6D /* ARTAuthOptions+Private.h in Headers */,
21E5D85D2D5D273900526C4C /* ARTWrapperSDKProxyPushAdmin.h in Headers */,
2114D4312D4BCAE20032839A /* ARTRealtime+WrapperSDKProxy.h in Headers */,
Expand Down Expand Up @@ -2671,6 +2688,7 @@
21AC0CCC2D4AA0F50030BD23 /* ARTWrapperSDKProxyRealtimeChannel+Private.h in Headers */,
21AC0CCD2D4AA0F50030BD23 /* ARTWrapperSDKProxyRealtimeChannels+Private.h in Headers */,
D710D51D21949C42008F54AD /* ARTDeviceStorage.h in Headers */,
21E5D89B2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h in Headers */,
D710D60D21949DDB008F54AD /* ARTDataQuery.h in Headers */,
D710D58221949D28008F54AD /* ARTTokenParams.h in Headers */,
D710D51921949C42008F54AD /* ARTDeviceDetails.h in Headers */,
Expand Down Expand Up @@ -2724,6 +2742,7 @@
21E5D8602D5D275700526C4C /* ARTWrapperSDKProxyPushAdmin+Private.h in Headers */,
D710D58321949D28008F54AD /* ARTTokenDetails.h in Headers */,
D710D54C21949C66008F54AD /* ARTPush+Private.h in Headers */,
21E5D8A02D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h in Headers */,
D710D68A21949EDA008F54AD /* ARTNSDate+ARTUtil.h in Headers */,
D710D4D721949BF9008F54AD /* ARTConnectionDetails.h in Headers */,
D710D4DB21949BF9008F54AD /* ARTRealtimeChannels.h in Headers */,
Expand Down Expand Up @@ -2862,6 +2881,7 @@
21AC0CCA2D4AA0F50030BD23 /* ARTWrapperSDKProxyRealtimeChannel+Private.h in Headers */,
21AC0CCB2D4AA0F50030BD23 /* ARTWrapperSDKProxyRealtimeChannels+Private.h in Headers */,
D710D52F21949C44008F54AD /* ARTDeviceStorage.h in Headers */,
21E5D89C2D5E862900526C4C /* ARTWrapperSDKProxyRealtimePresence.h in Headers */,
D710D61721949DDC008F54AD /* ARTDataQuery.h in Headers */,
D710D5A821949D2A008F54AD /* ARTTokenParams.h in Headers */,
D710D52B21949C44008F54AD /* ARTDeviceDetails.h in Headers */,
Expand Down Expand Up @@ -2915,6 +2935,7 @@
21E5D8612D5D275700526C4C /* ARTWrapperSDKProxyPushAdmin+Private.h in Headers */,
D710D5A921949D2A008F54AD /* ARTTokenDetails.h in Headers */,
D710D55221949C67008F54AD /* ARTPush+Private.h in Headers */,
21E5D8A12D5E864400526C4C /* ARTWrapperSDKProxyRealtimePresence+Private.h in Headers */,
D710D68C21949EDB008F54AD /* ARTNSDate+ARTUtil.h in Headers */,
D710D4E721949BFB008F54AD /* ARTConnectionDetails.h in Headers */,
D710D4EB21949BFB008F54AD /* ARTRealtimeChannels.h in Headers */,
Expand Down Expand Up @@ -3412,6 +3433,7 @@
D71966E51E5DF360000974DD /* ARTPushActivationStateMachine.m in Sources */,
EB9121401CA0AD8200BA0A40 /* ARTMsgPackEncoder.m in Sources */,
96BF61651A35CDE1004CF2B3 /* ARTBaseMessage.m in Sources */,
21E5D8992D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m in Sources */,
D7F1D3781BF4DE72001A4B5E /* ARTRealtimePresence.m in Sources */,
D7DF738B1EA645300013CD36 /* ARTLocalDeviceStorage.m in Sources */,
D7B621911E4A6E0200684474 /* ARTPush.m in Sources */,
Expand Down Expand Up @@ -3665,6 +3687,7 @@
D710D49B21949ACA008F54AD /* ARTRestChannels.m in Sources */,
D710D62E21949E03008F54AD /* ARTURLSessionServerTrust.m in Sources */,
D710D66B21949E78008F54AD /* ARTJsonEncoder.m in Sources */,
21E5D8982D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m in Sources */,
D710D5D521949D78008F54AD /* ARTClientOptions.m in Sources */,
D710D5D621949D78008F54AD /* ARTChannel.m in Sources */,
D70C36C7233E6831002FD6E3 /* ARTFormEncode.m in Sources */,
Expand Down Expand Up @@ -3798,6 +3821,7 @@
D710D63E21949E04008F54AD /* ARTURLSessionServerTrust.m in Sources */,
D710D65121949E77008F54AD /* ARTJsonEncoder.m in Sources */,
D710D5FB21949D79008F54AD /* ARTClientOptions.m in Sources */,
21E5D8972D5E861E00526C4C /* ARTWrapperSDKProxyRealtimePresence.m in Sources */,
D710D5FC21949D79008F54AD /* ARTChannel.m in Sources */,
D70C36C8233E6831002FD6E3 /* ARTFormEncode.m in Sources */,
D710D5F721949D79008F54AD /* ARTAuthDetails.m in Sources */,
Expand Down
7 changes: 3 additions & 4 deletions Source/ARTWrapperSDKProxyRealtimeChannel.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import "ARTRealtimeChannel+Private.h"
#import "ARTWrapperSDKProxyOptions.h"
#import "ARTWrapperSDKProxyPushChannel+Private.h"
#import "ARTWrapperSDKProxyRealtimePresence+Private.h"

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -24,6 +25,8 @@ - (instancetype)initWithChannel:(ARTRealtimeChannel *)channel proxyOptions:(ARTW
_push = [[ARTWrapperSDKProxyPushChannel alloc] initWithPushChannel:channel.push
proxyOptions:proxyOptions];
#endif
_presence = [[ARTWrapperSDKProxyRealtimePresence alloc] initWithRealtimePresence:channel.presence
proxyOptions:proxyOptions];
}

return self;
Expand All @@ -41,10 +44,6 @@ - (ARTRealtimeChannelOptions *)getOptions {
return self.underlyingChannel.options;
}

- (id<ARTRealtimePresenceProtocol>)presence {
return self.underlyingChannel.presence;
}

- (ARTChannelProperties *)properties {
return self.underlyingChannel.properties;
}
Expand Down
121 changes: 121 additions & 0 deletions Source/ARTWrapperSDKProxyRealtimePresence.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#import "ARTWrapperSDKProxyRealtimePresence+Private.h"

NS_ASSUME_NONNULL_BEGIN

@interface ARTWrapperSDKProxyRealtimePresence ()

@property (nonatomic, readonly) ARTRealtimePresence *underlyingRealtimePresence;
@property (nonatomic, readonly) ARTWrapperSDKProxyOptions *proxyOptions;

@end

NS_ASSUME_NONNULL_END

@implementation ARTWrapperSDKProxyRealtimePresence

- (instancetype)initWithRealtimePresence:(ARTRealtimePresence *)push proxyOptions:(ARTWrapperSDKProxyOptions *)proxyOptions {
if (self = [super init]) {
_underlyingRealtimePresence = push;
_proxyOptions = proxyOptions;
}

return self;
}

- (BOOL)syncComplete {
return self.underlyingRealtimePresence.syncComplete;
}

- (void)enter:(id _Nullable)data {
[self.underlyingRealtimePresence enter:data];
}

- (void)enter:(id _Nullable)data callback:(nullable ARTCallback)callback {
[self.underlyingRealtimePresence enter:data callback:callback];
}

- (void)enterClient:(nonnull NSString *)clientId data:(id _Nullable)data {
[self.underlyingRealtimePresence enterClient:clientId data:data];
}

- (void)enterClient:(nonnull NSString *)clientId data:(id _Nullable)data callback:(nullable ARTCallback)callback {
[self.underlyingRealtimePresence enterClient:clientId data:data callback:callback];
}

- (void)get:(nonnull ARTPresenceMessagesCallback)callback {
[self.underlyingRealtimePresence get:callback];
}

- (void)get:(nonnull ARTRealtimePresenceQuery *)query callback:(nonnull ARTPresenceMessagesCallback)callback {
[self.underlyingRealtimePresence get:query callback:callback];
}

- (void)history:(nonnull ARTPaginatedPresenceCallback)callback {
[self.underlyingRealtimePresence history:callback];
}

- (BOOL)history:(ARTRealtimeHistoryQuery * _Nullable)query callback:(nonnull ARTPaginatedPresenceCallback)callback error:(NSError * _Nullable __autoreleasing * _Nullable)errorPtr {
return [self.underlyingRealtimePresence history:query callback:callback error:errorPtr];
}

- (void)leave:(id _Nullable)data {
[self.underlyingRealtimePresence leave:data];
}

- (void)leave:(id _Nullable)data callback:(nullable ARTCallback)callback {
[self.underlyingRealtimePresence leave:data callback:callback];
}

- (void)leaveClient:(nonnull NSString *)clientId data:(id _Nullable)data {
[self.underlyingRealtimePresence leaveClient:clientId data:data];
}

- (void)leaveClient:(nonnull NSString *)clientId data:(id _Nullable)data callback:(nullable ARTCallback)callback {
[self.underlyingRealtimePresence leaveClient:clientId data:data callback:callback];
}

- (ARTEventListener * _Nullable)subscribe:(nonnull ARTPresenceMessageCallback)callback {
return [self.underlyingRealtimePresence subscribe:callback];
}

- (ARTEventListener * _Nullable)subscribe:(ARTPresenceAction)action callback:(nonnull ARTPresenceMessageCallback)callback {
return [self.underlyingRealtimePresence subscribe:action callback:callback];
}

- (ARTEventListener * _Nullable)subscribe:(ARTPresenceAction)action onAttach:(nullable ARTCallback)onAttach callback:(nonnull ARTPresenceMessageCallback)callback {
return [self.underlyingRealtimePresence subscribe:action onAttach:onAttach callback:callback];
}

- (ARTEventListener * _Nullable)subscribeWithAttachCallback:(nullable ARTCallback)onAttach callback:(nonnull ARTPresenceMessageCallback)callback {
return [self.underlyingRealtimePresence subscribeWithAttachCallback:onAttach callback:callback];
}

- (void)unsubscribe {
[self.underlyingRealtimePresence unsubscribe];
}

- (void)unsubscribe:(nonnull ARTEventListener *)listener {
[self.underlyingRealtimePresence unsubscribe:listener];
}

- (void)unsubscribe:(ARTPresenceAction)action listener:(nonnull ARTEventListener *)listener {
[self.underlyingRealtimePresence unsubscribe:action listener:listener];
}

- (void)update:(id _Nullable)data {
[self.underlyingRealtimePresence update:data];
}

- (void)update:(id _Nullable)data callback:(nullable ARTCallback)callback {
[self.underlyingRealtimePresence update:data callback:callback];
}

- (void)updateClient:(nonnull NSString *)clientId data:(id _Nullable)data {
[self.underlyingRealtimePresence updateClient:clientId data:data];
}

- (void)updateClient:(nonnull NSString *)clientId data:(id _Nullable)data callback:(nullable ARTCallback)callback {
[self.underlyingRealtimePresence updateClient:clientId data:data callback:callback];
}

@end
1 change: 1 addition & 0 deletions Source/Ably.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,6 @@ framework module Ably {
header "ARTWrapperSDKProxyPushDeviceRegistrations+Private.h"
header "ARTWrapperSDKProxyPushChannelSubscriptions+Private.h"
header "ARTWrapperSDKProxyPushChannel+Private.h"
header "ARTWrapperSDKProxyRealtimePresence+Private.h"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import <Ably/ARTWrapperSDKProxyRealtimePresence.h>

@class ARTWrapperSDKProxyOptions;

NS_ASSUME_NONNULL_BEGIN

@interface ARTWrapperSDKProxyRealtimePresence ()

- (instancetype)initWithRealtimePresence:(ARTRealtimePresence *)realtimePresence
proxyOptions:(ARTWrapperSDKProxyOptions *)proxyOptions NS_DESIGNATED_INITIALIZER;

@end

NS_ASSUME_NONNULL_END
1 change: 1 addition & 0 deletions Source/include/Ably.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,6 @@ framework module Ably {
header "Ably/ARTWrapperSDKProxyPushDeviceRegistrations+Private.h"
header "Ably/ARTWrapperSDKProxyPushChannelSubscriptions+Private.h"
header "Ably/ARTWrapperSDKProxyPushChannel+Private.h"
header "Ably/ARTWrapperSDKProxyRealtimePresence+Private.h"
}
}
3 changes: 2 additions & 1 deletion Source/include/Ably/ARTWrapperSDKProxyRealtimeChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

@class ARTWrapperSDKProxyRealtimeChannel;
@class ARTWrapperSDKProxyPushChannel;
@class ARTWrapperSDKProxyRealtimePresence;

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -16,7 +17,7 @@ NS_SWIFT_SENDABLE

- (instancetype)init NS_UNAVAILABLE;

@property (readonly) ARTRealtimePresence *presence;
@property (readonly) ARTWrapperSDKProxyRealtimePresence *presence;

#if TARGET_OS_IPHONE
@property (readonly) ARTWrapperSDKProxyPushChannel *push;
Expand Down
18 changes: 18 additions & 0 deletions Source/include/Ably/ARTWrapperSDKProxyRealtimePresence.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
#import <Ably/ARTRealtimePresence.h>

NS_ASSUME_NONNULL_BEGIN

/**
* An object which wraps an instance of `ARTRealtimePresence` and provides a similar API. It allows Ably-authored wrapper SDKs to send analytics information so that Ably can track the usage of the wrapper SDK.
*
* - Important: This class should only be used by Ably-authored SDKs.
*/
NS_SWIFT_SENDABLE
@interface ARTWrapperSDKProxyRealtimePresence : NSObject <ARTRealtimePresenceProtocol>

- (instancetype)init NS_UNAVAILABLE;

@end

NS_ASSUME_NONNULL_END
1 change: 1 addition & 0 deletions Source/include/Ably/AblyInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
#import <Ably/ARTWrapperSDKProxyPushDeviceRegistrations.h>
#import <Ably/ARTWrapperSDKProxyPushChannelSubscriptions.h>
#import <Ably/ARTWrapperSDKProxyPushChannel.h>
#import <Ably/ARTWrapperSDKProxyRealtimePresence.h>

0 comments on commit 7cf48a3

Please sign in to comment.