diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index b4a21c2e4f..beaa6059a2 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1408,6 +1408,7 @@ "objc2-io-surface_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"optional\":true,\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFDictionary\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"NSDictionary\",\"NSObject\",\"NSString\",\"alloc\"],\"name\":\"objc2-foundation\",\"optional\":true,\"req\":\"^0.3.2\"}],\"features\":{\"IOSurface\":[],\"IOSurfaceAPI\":[],\"IOSurfaceBase\":[],\"IOSurfaceRef\":[\"bitflags\"],\"IOSurfaceTypes\":[\"bitflags\"],\"ObjC\":[\"objc2\"],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"default\":[\"std\",\"IOSurface\",\"IOSurfaceAPI\",\"IOSurfaceBase\",\"IOSurfaceRef\",\"IOSurfaceTypes\",\"bitflags\",\"libc\",\"objc2\",\"objc2-core-foundation\",\"objc2-foundation\"],\"libc\":[\"dep:libc\"],\"objc2\":[\"dep:objc2\",\"objc2-core-foundation?/objc2\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-foundation\":[\"dep:objc2-foundation\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-local-authentication_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"SecBase\",\"SecKey\",\"objc2\"],\"name\":\"objc2-security\",\"optional\":true,\"req\":\"^0.3.2\"}],\"features\":{\"LABase\":[],\"LABiometryType\":[],\"LACompanionType\":[],\"LAContext\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"LADomainState\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSValue\"],\"LAEnvironment\":[],\"LAEnvironmentMechanism\":[\"objc2-foundation/NSString\"],\"LAEnvironmentMechanismBiometry\":[\"objc2-foundation/NSData\"],\"LAEnvironmentMechanismCompanion\":[\"objc2-foundation/NSData\"],\"LAEnvironmentMechanismUserPassword\":[],\"LAEnvironmentState\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"LAError\":[\"objc2-foundation/NSString\"],\"LAPersistedRight\":[],\"LAPrivateKey\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\"],\"LAPublicDefines\":[],\"LAPublicKey\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSError\"],\"LARequirement\":[],\"LARight\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"LARightStore\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"LASecret\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSError\"],\"alloc\":[],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"LABase\",\"LABiometryType\",\"LACompanionType\",\"LAContext\",\"LADomainState\",\"LAEnvironment\",\"LAEnvironmentMechanism\",\"LAEnvironmentMechanismBiometry\",\"LAEnvironmentMechanismCompanion\",\"LAEnvironmentMechanismUserPassword\",\"LAEnvironmentState\",\"LAError\",\"LAPersistedRight\",\"LAPrivateKey\",\"LAPublicDefines\",\"LAPublicKey\",\"LARequirement\",\"LARight\",\"LARightStore\",\"LASecret\",\"block2\",\"objc2-security\"],\"objc2-security\":[\"dep:objc2-security\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-quartz-core_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFCGTypes\",\"CFDate\",\"objc2\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGColor\",\"CGColorSpace\",\"CGContext\",\"CGPath\",\"objc2\"],\"name\":\"objc2-core-graphics\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CVBase\",\"objc2\"],\"name\":\"objc2-core-video\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"MTLAllocation\",\"MTLDevice\",\"MTLDrawable\",\"MTLPixelFormat\",\"MTLResidencySet\",\"MTLResource\",\"MTLTexture\"],\"name\":\"objc2-metal\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGLTypes\"],\"name\":\"objc2-open-gl\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(target_os = \\\"macos\\\")\"}],\"features\":{\"CAAnimation\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"CABase\":[],\"CAConstraintLayoutManager\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CADisplayLink\":[\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSRunLoop\",\"objc2-foundation/NSString\"],\"CAEAGLLayer\":[],\"CAEDRMetadata\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\"],\"CAEmitterCell\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAEmitterLayer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAFrameRateRange\":[],\"CAGradientLayer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"CALayer\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNull\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAMediaTiming\":[\"objc2-foundation/NSString\"],\"CAMediaTimingFunction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAMetalDisplayLink\":[\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSRunLoop\",\"objc2-foundation/NSString\"],\"CAMetalLayer\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\"],\"CAOpenGLLayer\":[\"objc2-foundation/NSObject\"],\"CARemoteLayerClient\":[],\"CARemoteLayerServer\":[],\"CARenderer\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"CAReplicatorLayer\":[\"objc2-foundation/NSObject\"],\"CAScrollLayer\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAShapeLayer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"CATextLayer\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CATiledLayer\":[\"objc2-foundation/NSObject\"],\"CATransaction\":[\"objc2-foundation/NSString\"],\"CATransform3D\":[\"objc2-foundation/NSValue\"],\"CATransformLayer\":[\"objc2-foundation/NSObject\"],\"CAValueFunction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CoreAnimation\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"CAAnimation\",\"CABase\",\"CAConstraintLayoutManager\",\"CADisplayLink\",\"CAEAGLLayer\",\"CAEDRMetadata\",\"CAEmitterCell\",\"CAEmitterLayer\",\"CAFrameRateRange\",\"CAGradientLayer\",\"CALayer\",\"CAMediaTiming\",\"CAMediaTimingFunction\",\"CAMetalDisplayLink\",\"CAMetalLayer\",\"CAOpenGLLayer\",\"CARemoteLayerClient\",\"CARemoteLayerServer\",\"CARenderer\",\"CAReplicatorLayer\",\"CAScrollLayer\",\"CAShapeLayer\",\"CATextLayer\",\"CATiledLayer\",\"CATransaction\",\"CATransform3D\",\"CATransformLayer\",\"CAValueFunction\",\"CoreAnimation\",\"bitflags\",\"block2\",\"libc\",\"objc2-core-foundation\",\"objc2-core-graphics\",\"objc2-core-video\",\"objc2-metal\"],\"gnustep-1-7\":[],\"gnustep-1-8\":[],\"gnustep-1-9\":[],\"gnustep-2-0\":[],\"gnustep-2-1\":[],\"libc\":[\"dep:libc\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-core-graphics\":[\"dep:objc2-core-graphics\"],\"objc2-core-video\":[\"dep:objc2-core-video\"],\"objc2-metal\":[\"dep:objc2-metal\"],\"objc2-open-gl\":[\"dep:objc2-open-gl\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", + "objc2-security_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"optional\":true,\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"name\":\"objc2-core-foundation\",\"req\":\"^0.3.2\"}],\"features\":{\"AuthSession\":[\"bitflags\"],\"Authorization\":[\"bitflags\"],\"AuthorizationDB\":[\"objc2-core-foundation/CFBundle\",\"objc2-core-foundation/CFDictionary\"],\"AuthorizationPlugin\":[\"bitflags\",\"objc2-core-foundation/CFArray\"],\"AuthorizationTags\":[],\"CMSDecoder\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDate\"],\"CMSEncoder\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDate\"],\"CSCommon\":[\"bitflags\"],\"CipherSuite\":[],\"CodeSigning\":[],\"SecACL\":[\"bitflags\",\"objc2-core-foundation/CFArray\"],\"SecAccess\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFError\"],\"SecAccessControl\":[\"bitflags\",\"objc2-core-foundation/CFError\"],\"SecAsn1Coder\":[],\"SecAsn1Templates\":[],\"SecAsn1Types\":[],\"SecBase\":[],\"SecCertificate\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDate\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\"],\"SecCertificateOIDs\":[],\"SecCode\":[\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\",\"objc2-core-foundation/CFURL\"],\"SecCodeHost\":[\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFURL\"],\"SecCustomTransform\":[\"objc2-core-foundation/CFError\"],\"SecDecodeTransform\":[\"objc2-core-foundation/CFError\"],\"SecDigestTransform\":[\"objc2-core-foundation/CFError\"],\"SecEncodeTransform\":[\"objc2-core-foundation/CFError\"],\"SecEncryptTransform\":[\"objc2-core-foundation/CFError\"],\"SecIdentity\":[\"objc2-core-foundation/CFArray\"],\"SecIdentitySearch\":[],\"SecImportExport\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDictionary\"],\"SecItem\":[\"objc2-core-foundation/CFDictionary\"],\"SecKey\":[\"bitflags\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\"],\"SecKeychain\":[\"bitflags\",\"objc2-core-foundation/CFArray\"],\"SecKeychainItem\":[\"objc2-core-foundation/CFData\"],\"SecKeychainSearch\":[],\"SecPolicy\":[\"objc2-core-foundation/CFDictionary\"],\"SecPolicySearch\":[],\"SecProtocolMetadata\":[],\"SecProtocolObject\":[],\"SecProtocolOptions\":[],\"SecProtocolTypes\":[\"objc2-core-foundation/CFArray\"],\"SecRandom\":[],\"SecReadTransform\":[],\"SecRequirement\":[\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFError\"],\"SecSharedCredential\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFError\"],\"SecSignVerifyTransform\":[\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFError\"],\"SecStaticCode\":[\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\",\"objc2-core-foundation/CFURL\"],\"SecTask\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\"],\"SecTransform\":[\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\"],\"SecTransformReadTransform\":[\"objc2-core-foundation/CFStream\"],\"SecTrust\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDate\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\"],\"SecTrustSettings\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDate\"],\"SecTrustedApplication\":[\"objc2-core-foundation/CFData\"],\"SecureDownload\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDate\",\"objc2-core-foundation/CFURL\"],\"SecureTransport\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFData\"],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"certextensions\":[],\"cssm\":[],\"cssmaci\":[],\"cssmapi\":[],\"cssmapple\":[],\"cssmcli\":[],\"cssmconfig\":[],\"cssmcspi\":[],\"cssmdli\":[],\"cssmerr\":[],\"cssmkrapi\":[],\"cssmkrspi\":[],\"cssmspi\":[],\"cssmtpi\":[],\"cssmtype\":[],\"default\":[\"std\",\"AuthSession\",\"Authorization\",\"AuthorizationDB\",\"AuthorizationPlugin\",\"AuthorizationTags\",\"CMSDecoder\",\"CMSEncoder\",\"CSCommon\",\"CipherSuite\",\"CodeSigning\",\"SecACL\",\"SecAccess\",\"SecAccessControl\",\"SecAsn1Coder\",\"SecAsn1Templates\",\"SecAsn1Types\",\"SecBase\",\"SecCertificate\",\"SecCertificateOIDs\",\"SecCode\",\"SecCodeHost\",\"SecCustomTransform\",\"SecDecodeTransform\",\"SecDigestTransform\",\"SecEncodeTransform\",\"SecEncryptTransform\",\"SecIdentity\",\"SecIdentitySearch\",\"SecImportExport\",\"SecItem\",\"SecKey\",\"SecKeychain\",\"SecKeychainItem\",\"SecKeychainSearch\",\"SecPolicy\",\"SecPolicySearch\",\"SecProtocolMetadata\",\"SecProtocolObject\",\"SecProtocolOptions\",\"SecProtocolTypes\",\"SecRandom\",\"SecReadTransform\",\"SecRequirement\",\"SecSharedCredential\",\"SecSignVerifyTransform\",\"SecStaticCode\",\"SecTask\",\"SecTransform\",\"SecTransformReadTransform\",\"SecTrust\",\"SecTrustSettings\",\"SecTrustedApplication\",\"SecureDownload\",\"SecureTransport\",\"bitflags\",\"block2\",\"certextensions\",\"cssm\",\"cssmaci\",\"cssmapi\",\"cssmapple\",\"cssmcli\",\"cssmconfig\",\"cssmcspi\",\"cssmdli\",\"cssmerr\",\"cssmkrapi\",\"cssmkrspi\",\"cssmspi\",\"cssmtpi\",\"cssmtype\",\"eisl\",\"emmspi\",\"emmtype\",\"libc\",\"mds\",\"mds_schema\",\"objc2\",\"oids\",\"oidsalg\",\"oidsattr\",\"oidsbase\",\"oidscert\",\"oidscrl\",\"x509defs\"],\"eisl\":[],\"emmspi\":[],\"emmtype\":[],\"libc\":[\"dep:libc\"],\"mds\":[],\"mds_schema\":[],\"objc2\":[\"dep:objc2\",\"objc2-core-foundation/objc2\"],\"oids\":[],\"oidsalg\":[],\"oidsattr\":[],\"oidsbase\":[],\"oidscert\":[],\"oidscrl\":[],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[],\"x509defs\":[]}}", "objc2-ui-kit_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CKContainer\",\"CKRecord\",\"CKShare\",\"CKShareMetadata\"],\"name\":\"objc2-cloud-kit\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"NSManagedObjectContext\",\"NSManagedObjectModel\"],\"name\":\"objc2-core-data\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CFCGTypes\",\"CFDate\",\"objc2\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGColor\",\"CGContext\",\"CGFont\",\"CGImage\",\"CGPath\",\"objc2\"],\"name\":\"objc2-core-graphics\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CIColor\",\"CIImage\"],\"name\":\"objc2-core-image\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(not(target_os = \\\"watchos\\\"))\"},{\"default_features\":false,\"features\":[\"CLRegion\"],\"name\":\"objc2-core-location\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CTFont\",\"CTFontDescriptor\",\"objc2\"],\"name\":\"objc2-core-text\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CADisplayLink\",\"CAFrameRateRange\",\"CALayer\",\"CAMediaTiming\",\"CATransform3D\",\"objc2-core-foundation\"],\"name\":\"objc2-quartz-core\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(not(target_os = \\\"watchos\\\"))\"},{\"default_features\":false,\"features\":[\"NSSymbolEffect\"],\"name\":\"objc2-symbols\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"UTType\"],\"name\":\"objc2-uniform-type-identifiers\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"UNNotificationResponse\"],\"name\":\"objc2-user-notifications\",\"optional\":true,\"req\":\"^0.3.2\"}],\"features\":{\"DocumentManager\":[],\"NSAdaptiveImageGlyph\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSAttributedString\":[\"bitflags\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSFileWrapper\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"NSDataAsset\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSDiffableDataSourceSectionSnapshot\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSFileProviderExtension\":[],\"NSIndexPath_UIKitAdditions\":[\"objc2-foundation/NSIndexPath\"],\"NSItemProvider_UIKitAdditions\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"NSLayoutAnchor\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSLayoutConstraint\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"NSLayoutManager\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSParagraphStyle\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCharacterSet\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSShadow\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"NSStringDrawing\":[\"bitflags\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"NSText\":[],\"NSTextAttachment\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSFileWrapper\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSTextContainer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"NSTextContentManager\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSError\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSTextElement\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\"],\"NSTextLayoutFragment\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOperation\"],\"NSTextLayoutManager\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOperation\",\"objc2-foundation/NSString\"],\"NSTextLineFragment\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSTextList\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSTextListElement\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"NSTextRange\":[\"objc2-foundation/NSObjCRuntime\"],\"NSTextSelection\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSTextSelectionNavigation\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"NSTextStorage\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSTextViewportLayoutController\":[],\"NSToolbar_UIKitAdditions\":[],\"NSTouchBar_UIKitAdditions\":[],\"NSUserActivity_NSItemProvider\":[],\"PrintKitUI\":[],\"ShareSheet\":[],\"UIAccelerometer\":[\"objc2-foundation/NSDate\"],\"UIAccessibility\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIAccessibilityAdditions\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityConstants\":[\"bitflags\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIAccessibilityContainer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSRange\"],\"UIAccessibilityContentSizeCategoryImageAdjusting\":[],\"UIAccessibilityCustomAction\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityCustomRotor\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityElement\":[\"objc2-foundation/NSString\"],\"UIAccessibilityIdentification\":[\"objc2-foundation/NSString\"],\"UIAccessibilityLocationDescriptor\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityZoom\":[],\"UIAction\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIActionSheet\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIActivity\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UIActivityCollaborationModeRestriction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIActivityIndicatorView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIActivityItemProvider\":[\"objc2-foundation/NSOperation\",\"objc2-foundation/NSString\"],\"UIActivityItemsConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"UIActivityItemsConfigurationReading\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"UIActivityItemsConfigurationReading_ShareSheet\":[\"objc2-foundation/NSString\"],\"UIActivityViewController\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAlert\":[],\"UIAlertController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAlertView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAppearance\":[\"objc2-foundation/NSArray\"],\"UIApplication\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSUserActivity\"],\"UIApplicationShortcutItem\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAttachmentBehavior\":[\"objc2-foundation/NSArray\"],\"UIBackgroundConfiguration\":[\"objc2-foundation/NSObject\"],\"UIBackgroundExtensionView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIBandSelectionInteraction\":[],\"UIBarAppearance\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIBarButtonItem\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIBarButtonItemAppearance\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBarButtonItemBadge\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBarButtonItemGroup\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBarCommon\":[],\"UIBarItem\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBehavioralStyle\":[],\"UIBezierPath\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIBlurEffect\":[\"objc2-foundation/NSObject\"],\"UIButton\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIButtonConfiguration\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICalendarSelection\":[],\"UICalendarSelectionMultiDate\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCalendar\"],\"UICalendarSelectionSingleDate\":[\"objc2-foundation/NSCalendar\"],\"UICalendarSelectionWeekOfYear\":[\"objc2-foundation/NSCalendar\"],\"UICalendarView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDateInterval\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSTimeZone\"],\"UICalendarViewDecoration\":[],\"UICanvasFeedbackGenerator\":[],\"UICellAccessory\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICellConfigurationState\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UICloudSharingController\":[\"bitflags\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionLayoutList\":[\"bitflags\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\"],\"UICollectionView\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSIndexSet\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UICollectionViewCell\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewCompositionalLayout\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewFlowLayout\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\"],\"UICollectionViewItemRegistration\":[\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSString\"],\"UICollectionViewLayout\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewListCell\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UICollectionViewTransitionLayout\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewUpdateItem\":[\"objc2-foundation/NSIndexPath\"],\"UICollisionBehavior\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIColor\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIColorPickerViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIColorWell\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICommand\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIConfigurationColorTransformer\":[],\"UIConfigurationState\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIContentConfiguration\":[\"objc2-foundation/NSObject\"],\"UIContentSizeCategory\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSString\"],\"UIContentSizeCategoryAdjusting\":[],\"UIContentUnavailableButtonProperties\":[\"objc2-foundation/NSObject\"],\"UIContentUnavailableConfiguration\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIContentUnavailableConfigurationState\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIContentUnavailableImageProperties\":[\"objc2-foundation/NSObject\"],\"UIContentUnavailableTextProperties\":[\"objc2-foundation/NSObject\"],\"UIContentUnavailableView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIContextMenuConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\"],\"UIContextMenuInteraction\":[\"objc2-foundation/NSObject\"],\"UIContextMenuSystem\":[],\"UIContextualAction\":[\"objc2-foundation/NSString\"],\"UIControl\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIConversationContext\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSPersonNameComponents\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIConversationEntry\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UICornerConfiguration\":[\"objc2-foundation/NSObject\"],\"UICornerRadius\":[\"objc2-foundation/NSObject\"],\"UIDataDetectors\":[\"bitflags\"],\"UIDataSourceTranslating\":[\"objc2-foundation/NSIndexPath\"],\"UIDatePicker\":[\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSTimeZone\"],\"UIDeferredMenuElement\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIDevice\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUUID\"],\"UIDiffableDataSource\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOrderedCollectionDifference\",\"objc2-foundation/NSString\"],\"UIDocument\":[\"bitflags\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSFilePresenter\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSUndoManager\",\"objc2-foundation/NSUserActivity\"],\"UIDocumentBrowserAction\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentBrowserViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentInteractionController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentMenuViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentPickerExtensionViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentPickerViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentProperties\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSURL\"],\"UIDocumentViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIDocumentViewControllerLaunchOptions\":[\"objc2-foundation/NSString\"],\"UIDragInteraction\":[\"objc2-foundation/NSArray\"],\"UIDragItem\":[\"objc2-foundation/NSItemProvider\"],\"UIDragPreview\":[\"objc2-foundation/NSObject\"],\"UIDragPreviewParameters\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSValue\"],\"UIDragSession\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UIDropInteraction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\"],\"UIDynamicAnimator\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSString\"],\"UIDynamicBehavior\":[\"objc2-foundation/NSArray\"],\"UIDynamicItemBehavior\":[\"objc2-foundation/NSArray\"],\"UIEditMenuInteraction\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIEvent\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSSet\"],\"UIEventAttribution\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIEventAttributionView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIFeedbackGenerator\":[],\"UIFieldBehavior\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\"],\"UIFindInteraction\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UIFindSession\":[\"objc2-foundation/NSString\"],\"UIFocus\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIFocusAnimationCoordinator\":[\"objc2-foundation/NSDate\"],\"UIFocusDebugger\":[],\"UIFocusDefines\":[],\"UIFocusEffect\":[\"objc2-foundation/NSObject\"],\"UIFocusGuide\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIFocusMovementHint\":[\"objc2-foundation/NSObject\"],\"UIFocusSystem\":[],\"UIFocusSystem_UIKitAdditions\":[\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIFocusUpdateContext_UIKitAdditions\":[],\"UIFont\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIFontDescriptor\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIFontMetrics\":[\"objc2-foundation/NSString\"],\"UIFontPickerViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIFontPickerViewControllerConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSPredicate\",\"objc2-foundation/NSString\"],\"UIFoundation\":[],\"UIGeometry\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UIGestureRecognizer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UIGestureRecognizerSubclass\":[\"objc2-foundation/NSSet\"],\"UIGlassEffect\":[\"objc2-foundation/NSObject\"],\"UIGraphics\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIGraphicsImageRenderer\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\"],\"UIGraphicsPDFRenderer\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIGraphicsRenderer\":[\"objc2-foundation/NSObject\"],\"UIGraphicsRendererSubclass\":[\"objc2-foundation/NSError\"],\"UIGravityBehavior\":[\"objc2-foundation/NSArray\"],\"UIGuidedAccess\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"UIGuidedAccessRestrictions\":[],\"UIHoverEffect\":[\"objc2-foundation/NSObject\"],\"UIHoverEffectLayer\":[\"objc2-foundation/NSObject\"],\"UIHoverGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIHoverStyle\":[\"objc2-foundation/NSObject\"],\"UIImage\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIImageAsset\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIImageConfiguration\":[\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\"],\"UIImagePickerController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UIImageReader\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSURL\"],\"UIImageSymbolConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIImageView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIImpactFeedbackGenerator\":[],\"UIIndirectScribbleInteraction\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIInputSuggestion\":[],\"UIInputView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIInputViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUUID\"],\"UIInteraction\":[\"objc2-foundation/NSArray\"],\"UIInterface\":[],\"UIKey\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIKeyCommand\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIKeyConstants\":[],\"UIKeyboardLayoutGuide\":[\"objc2-foundation/NSObject\"],\"UIKitCore\":[],\"UIKitDefines\":[],\"UILabel\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UILargeContentViewer\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UILayoutGuide\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UILetterformAwareAdjusting\":[],\"UILexicon\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIListContentConfiguration\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIListContentImageProperties\":[\"objc2-foundation/NSObject\"],\"UIListContentTextProperties\":[\"objc2-foundation/NSObject\"],\"UIListSeparatorConfiguration\":[\"objc2-foundation/NSObject\"],\"UILocalNotification\":[\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSTimeZone\"],\"UILocalizedIndexedCollation\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UILongPressGestureRecognizer\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\"],\"UIMailConversationContext\":[\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIMailConversationEntry\":[\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIMainMenuSystem\":[\"objc2-foundation/NSObject\"],\"UIManagedDocument\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSFilePresenter\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIMenu\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIMenuBuilder\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UIMenuController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIMenuDisplayPreferences\":[\"objc2-foundation/NSObject\"],\"UIMenuElement\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIMenuLeaf\":[\"objc2-foundation/NSString\"],\"UIMenuSystem\":[],\"UIMessageConversationContext\":[],\"UIMessageConversationEntry\":[],\"UIMotionEffect\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationBar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationBarAppearance\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationItem\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"UINib\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"UINibDeclarations\":[],\"UINibLoading\":[\"objc2-foundation/NSString\"],\"UINotificationFeedbackGenerator\":[],\"UIOpenURLContext\":[\"objc2-foundation/NSURL\"],\"UIOrientation\":[\"bitflags\"],\"UIPageControl\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIPageControlProgress\":[\"objc2-foundation/NSDate\"],\"UIPageViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPanGestureRecognizer\":[\"bitflags\",\"objc2-foundation/NSCoder\"],\"UIPasteConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPasteConfigurationSupporting\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\"],\"UIPasteControl\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIPasteboard\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSIndexSet\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPencilInteraction\":[\"objc2-foundation/NSDate\"],\"UIPickerView\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPinchGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIPointerAccessory\":[\"objc2-foundation/NSObject\"],\"UIPointerInteraction\":[],\"UIPointerLockState\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIPointerRegion\":[\"objc2-foundation/NSObject\"],\"UIPointerStyle\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIPopoverBackgroundView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIPopoverController\":[\"objc2-foundation/NSArray\"],\"UIPopoverPresentationController\":[\"objc2-foundation/NSArray\"],\"UIPopoverPresentationControllerSourceItem\":[],\"UIPopoverSupport\":[\"bitflags\"],\"UIPresentationController\":[],\"UIPress\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\"],\"UIPressesEvent\":[\"objc2-foundation/NSSet\"],\"UIPreviewInteraction\":[],\"UIPreviewParameters\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSValue\"],\"UIPrintError\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"UIPrintFormatter\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPrintInfo\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPrintInteractionController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPrintPageRenderer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSRange\"],\"UIPrintPaper\":[\"objc2-foundation/NSArray\"],\"UIPrintServiceExtension\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPrinter\":[\"bitflags\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPrinterPickerController\":[\"objc2-foundation/NSError\"],\"UIProgressView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\"],\"UIPushBehavior\":[\"objc2-foundation/NSArray\"],\"UIReferenceLibraryViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIRefreshControl\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIRegion\":[\"objc2-foundation/NSObject\"],\"UIResponder\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUndoManager\",\"objc2-foundation/NSUserActivity\"],\"UIResponder_UIActivityItemsConfiguration\":[],\"UIRotationGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIScene\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSUserActivity\"],\"UISceneActivationConditions\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSPredicate\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\"],\"UISceneConfiguration\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISceneDefinitions\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"UISceneDestructionCondition\":[\"objc2-foundation/NSObject\"],\"UISceneEnhancedStateRestoration\":[],\"UISceneOptions\":[\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\"],\"UISceneSession\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\",\"UISceneConfiguration\"],\"UISceneSessionActivationRequest\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\"],\"UISceneSizeRestrictions\":[],\"UISceneSystemProtectionManager\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UISceneWindowingBehaviors\":[],\"UISceneWindowingControlStyle\":[],\"UIScene_AVAudioSession\":[],\"UIScreen\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIScreenEdgePanGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIScreenMode\":[],\"UIScreenshotService\":[\"objc2-foundation/NSData\"],\"UIScribbleInteraction\":[],\"UIScrollEdgeElementContainerInteraction\":[],\"UIScrollView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\"],\"UISearchBar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UISearchContainerViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISearchController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISearchDisplayController\":[\"objc2-foundation/NSString\"],\"UISearchSuggestion\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UISearchTab\":[\"objc2-foundation/NSString\"],\"UISearchTextField\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISegmentedControl\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISelectionFeedbackGenerator\":[],\"UIShadowProperties\":[\"objc2-foundation/NSObject\"],\"UIShape\":[\"objc2-foundation/NSObject\"],\"UISheetPresentationController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UISlider\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UISliderTrackConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISmartReplySuggestion\":[\"objc2-foundation/NSString\"],\"UISnapBehavior\":[],\"UISplitViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISplitViewControllerLayoutEnvironment\":[],\"UISpringLoadedInteraction\":[],\"UISpringLoadedInteractionSupporting\":[],\"UIStackView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIStandardTextCursorView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIStateRestoration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSString\"],\"UIStatusBarManager\":[],\"UIStepper\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIStoryboard\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSString\"],\"UIStoryboardPopoverSegue\":[\"objc2-foundation/NSString\"],\"UIStoryboardSegue\":[\"objc2-foundation/NSString\"],\"UIStringDrawing\":[\"objc2-foundation/NSString\"],\"UISwipeActionsConfiguration\":[\"objc2-foundation/NSArray\"],\"UISwipeGestureRecognizer\":[\"bitflags\",\"objc2-foundation/NSCoder\"],\"UISwitch\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISymbolContentTransition\":[\"objc2-foundation/NSObject\"],\"UISymbolEffectCompletion\":[],\"UITab\":[\"objc2-foundation/NSString\"],\"UITabAccessory\":[],\"UITabBar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UITabBarAppearance\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITabBarController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UITabBarControllerSidebar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\"],\"UITabBarItem\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITabGroup\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UITabSidebarItem\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UITableView\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSIndexSet\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UITableViewCell\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITableViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITableViewHeaderFooterView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITapGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UITargetedDragPreview\":[\"objc2-foundation/NSObject\"],\"UITargetedPreview\":[\"objc2-foundation/NSObject\"],\"UITextChecker\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"UITextCursorDropPositionAnimator\":[],\"UITextCursorView\":[],\"UITextDragPreviewRenderer\":[\"objc2-foundation/NSRange\"],\"UITextDragURLPreviews\":[\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UITextDragging\":[\"bitflags\",\"objc2-foundation/NSArray\"],\"UITextDropProposal\":[\"objc2-foundation/NSObject\"],\"UITextDropping\":[\"objc2-foundation/NSProgress\"],\"UITextField\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UITextFormattingCoordinator\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"UITextFormattingViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextFormattingViewControllerChangeValue\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UITextFormattingViewControllerComponent\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextFormattingViewControllerConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UITextFormattingViewControllerFormattingDescriptor\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UITextFormattingViewControllerFormattingStyle\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextInput\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"UITextInputContext\":[],\"UITextInputTraits\":[\"bitflags\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextInteraction\":[\"objc2-foundation/NSArray\"],\"UITextItem\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UITextItemInteraction\":[],\"UITextLoupeSession\":[],\"UITextPasteConfigurationSupporting\":[],\"UITextPasteDelegate\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"UITextSearching\":[\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOrderedSet\",\"objc2-foundation/NSString\"],\"UITextSelectionDisplayInteraction\":[\"objc2-foundation/NSArray\"],\"UITextSelectionHandleView\":[],\"UITextSelectionHighlightView\":[\"objc2-foundation/NSArray\"],\"UITextView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSValue\"],\"UITimingCurveProvider\":[\"objc2-foundation/NSObject\"],\"UITimingParameters\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIToolTipInteraction\":[\"objc2-foundation/NSString\"],\"UIToolbar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIToolbarAppearance\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UITouch\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSValue\"],\"UITrackingLayoutGuide\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UITrait\":[\"objc2-foundation/NSString\"],\"UITraitCollection\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITraitListEnvironment\":[],\"UIUpdateActionPhase\":[],\"UIUpdateInfo\":[\"objc2-foundation/NSDate\"],\"UIUpdateLink\":[],\"UIUserActivity\":[\"objc2-foundation/NSUserActivity\"],\"UIUserNotificationSettings\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIVibrancyEffect\":[\"objc2-foundation/NSObject\"],\"UIVideoEditorController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIView\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIViewAnimating\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIViewConfigurationState\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSExtensionContext\",\"objc2-foundation/NSExtensionRequestHandling\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIViewControllerTransition\":[],\"UIViewControllerTransitionCoordinator\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSString\"],\"UIViewControllerTransitioning\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIViewLayoutRegion\":[],\"UIViewPropertyAnimator\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIVisualEffect\":[\"objc2-foundation/NSObject\"],\"UIVisualEffectView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIWebView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSURLRequest\"],\"UIWindow\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIWindowScene\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\",\"UISceneSizeRestrictions\"],\"UIWindowSceneActivationAction\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIWindowSceneActivationConfiguration\":[\"objc2-foundation/NSUserActivity\"],\"UIWindowSceneActivationInteraction\":[\"objc2-foundation/NSError\"],\"UIWindowSceneActivationRequestOptions\":[],\"UIWindowSceneDragInteraction\":[],\"UIWindowSceneGeometry\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneGeometryPreferences\":[],\"UIWindowSceneGeometryPreferencesIOS\":[],\"UIWindowSceneGeometryPreferencesMac\":[],\"UIWindowSceneGeometryPreferencesVision\":[],\"UIWindowScenePlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneProminentPlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowScenePushPlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneReplacePlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneStandardPlacement\":[\"objc2-foundation/NSObject\"],\"UIWritingToolsCoordinator\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUUID\",\"objc2-foundation/NSValue\"],\"UIWritingToolsCoordinatorAnimationParameters\":[],\"UIWritingToolsCoordinatorContext\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSUUID\"],\"UIZoomTransitionOptions\":[\"objc2-foundation/NSObject\"],\"UNNotificationResponse_UIKitAdditions\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"DocumentManager\",\"NSAdaptiveImageGlyph\",\"NSAttributedString\",\"NSDataAsset\",\"NSDiffableDataSourceSectionSnapshot\",\"NSFileProviderExtension\",\"NSIndexPath_UIKitAdditions\",\"NSItemProvider_UIKitAdditions\",\"NSLayoutAnchor\",\"NSLayoutConstraint\",\"NSLayoutManager\",\"NSParagraphStyle\",\"NSShadow\",\"NSStringDrawing\",\"NSText\",\"NSTextAttachment\",\"NSTextContainer\",\"NSTextContentManager\",\"NSTextElement\",\"NSTextLayoutFragment\",\"NSTextLayoutManager\",\"NSTextLineFragment\",\"NSTextList\",\"NSTextListElement\",\"NSTextRange\",\"NSTextSelection\",\"NSTextSelectionNavigation\",\"NSTextStorage\",\"NSTextViewportLayoutController\",\"NSToolbar_UIKitAdditions\",\"NSTouchBar_UIKitAdditions\",\"NSUserActivity_NSItemProvider\",\"PrintKitUI\",\"ShareSheet\",\"UIAccelerometer\",\"UIAccessibility\",\"UIAccessibilityAdditions\",\"UIAccessibilityConstants\",\"UIAccessibilityContainer\",\"UIAccessibilityContentSizeCategoryImageAdjusting\",\"UIAccessibilityCustomAction\",\"UIAccessibilityCustomRotor\",\"UIAccessibilityElement\",\"UIAccessibilityIdentification\",\"UIAccessibilityLocationDescriptor\",\"UIAccessibilityZoom\",\"UIAction\",\"UIActionSheet\",\"UIActivity\",\"UIActivityCollaborationModeRestriction\",\"UIActivityIndicatorView\",\"UIActivityItemProvider\",\"UIActivityItemsConfiguration\",\"UIActivityItemsConfigurationReading\",\"UIActivityItemsConfigurationReading_ShareSheet\",\"UIActivityViewController\",\"UIAlert\",\"UIAlertController\",\"UIAlertView\",\"UIAppearance\",\"UIApplication\",\"UIApplicationShortcutItem\",\"UIAttachmentBehavior\",\"UIBackgroundConfiguration\",\"UIBackgroundExtensionView\",\"UIBandSelectionInteraction\",\"UIBarAppearance\",\"UIBarButtonItem\",\"UIBarButtonItemAppearance\",\"UIBarButtonItemBadge\",\"UIBarButtonItemGroup\",\"UIBarCommon\",\"UIBarItem\",\"UIBehavioralStyle\",\"UIBezierPath\",\"UIBlurEffect\",\"UIButton\",\"UIButtonConfiguration\",\"UICalendarSelection\",\"UICalendarSelectionMultiDate\",\"UICalendarSelectionSingleDate\",\"UICalendarSelectionWeekOfYear\",\"UICalendarView\",\"UICalendarViewDecoration\",\"UICanvasFeedbackGenerator\",\"UICellAccessory\",\"UICellConfigurationState\",\"UICloudSharingController\",\"UICollectionLayoutList\",\"UICollectionView\",\"UICollectionViewCell\",\"UICollectionViewCompositionalLayout\",\"UICollectionViewController\",\"UICollectionViewFlowLayout\",\"UICollectionViewItemRegistration\",\"UICollectionViewLayout\",\"UICollectionViewListCell\",\"UICollectionViewTransitionLayout\",\"UICollectionViewUpdateItem\",\"UICollisionBehavior\",\"UIColor\",\"UIColorPickerViewController\",\"UIColorWell\",\"UICommand\",\"UIConfigurationColorTransformer\",\"UIConfigurationState\",\"UIContentConfiguration\",\"UIContentSizeCategory\",\"UIContentSizeCategoryAdjusting\",\"UIContentUnavailableButtonProperties\",\"UIContentUnavailableConfiguration\",\"UIContentUnavailableConfigurationState\",\"UIContentUnavailableImageProperties\",\"UIContentUnavailableTextProperties\",\"UIContentUnavailableView\",\"UIContextMenuConfiguration\",\"UIContextMenuInteraction\",\"UIContextMenuSystem\",\"UIContextualAction\",\"UIControl\",\"UIConversationContext\",\"UIConversationEntry\",\"UICornerConfiguration\",\"UICornerRadius\",\"UIDataDetectors\",\"UIDataSourceTranslating\",\"UIDatePicker\",\"UIDeferredMenuElement\",\"UIDevice\",\"UIDiffableDataSource\",\"UIDocument\",\"UIDocumentBrowserAction\",\"UIDocumentBrowserViewController\",\"UIDocumentInteractionController\",\"UIDocumentMenuViewController\",\"UIDocumentPickerExtensionViewController\",\"UIDocumentPickerViewController\",\"UIDocumentProperties\",\"UIDocumentViewController\",\"UIDocumentViewControllerLaunchOptions\",\"UIDragInteraction\",\"UIDragItem\",\"UIDragPreview\",\"UIDragPreviewParameters\",\"UIDragSession\",\"UIDropInteraction\",\"UIDynamicAnimator\",\"UIDynamicBehavior\",\"UIDynamicItemBehavior\",\"UIEditMenuInteraction\",\"UIEvent\",\"UIEventAttribution\",\"UIEventAttributionView\",\"UIFeedbackGenerator\",\"UIFieldBehavior\",\"UIFindInteraction\",\"UIFindSession\",\"UIFocus\",\"UIFocusAnimationCoordinator\",\"UIFocusDebugger\",\"UIFocusDefines\",\"UIFocusEffect\",\"UIFocusGuide\",\"UIFocusMovementHint\",\"UIFocusSystem\",\"UIFocusSystem_UIKitAdditions\",\"UIFocusUpdateContext_UIKitAdditions\",\"UIFont\",\"UIFontDescriptor\",\"UIFontMetrics\",\"UIFontPickerViewController\",\"UIFontPickerViewControllerConfiguration\",\"UIFoundation\",\"UIGeometry\",\"UIGestureRecognizer\",\"UIGestureRecognizerSubclass\",\"UIGlassEffect\",\"UIGraphics\",\"UIGraphicsImageRenderer\",\"UIGraphicsPDFRenderer\",\"UIGraphicsRenderer\",\"UIGraphicsRendererSubclass\",\"UIGravityBehavior\",\"UIGuidedAccess\",\"UIGuidedAccessRestrictions\",\"UIHoverEffect\",\"UIHoverEffectLayer\",\"UIHoverGestureRecognizer\",\"UIHoverStyle\",\"UIImage\",\"UIImageAsset\",\"UIImageConfiguration\",\"UIImagePickerController\",\"UIImageReader\",\"UIImageSymbolConfiguration\",\"UIImageView\",\"UIImpactFeedbackGenerator\",\"UIIndirectScribbleInteraction\",\"UIInputSuggestion\",\"UIInputView\",\"UIInputViewController\",\"UIInteraction\",\"UIInterface\",\"UIKey\",\"UIKeyCommand\",\"UIKeyConstants\",\"UIKeyboardLayoutGuide\",\"UIKitCore\",\"UIKitDefines\",\"UILabel\",\"UILargeContentViewer\",\"UILayoutGuide\",\"UILetterformAwareAdjusting\",\"UILexicon\",\"UIListContentConfiguration\",\"UIListContentImageProperties\",\"UIListContentTextProperties\",\"UIListSeparatorConfiguration\",\"UILocalNotification\",\"UILocalizedIndexedCollation\",\"UILongPressGestureRecognizer\",\"UIMailConversationContext\",\"UIMailConversationEntry\",\"UIMainMenuSystem\",\"UIManagedDocument\",\"UIMenu\",\"UIMenuBuilder\",\"UIMenuController\",\"UIMenuDisplayPreferences\",\"UIMenuElement\",\"UIMenuLeaf\",\"UIMenuSystem\",\"UIMessageConversationContext\",\"UIMessageConversationEntry\",\"UIMotionEffect\",\"UINavigationBar\",\"UINavigationBarAppearance\",\"UINavigationController\",\"UINavigationItem\",\"UINib\",\"UINibDeclarations\",\"UINibLoading\",\"UINotificationFeedbackGenerator\",\"UIOpenURLContext\",\"UIOrientation\",\"UIPageControl\",\"UIPageControlProgress\",\"UIPageViewController\",\"UIPanGestureRecognizer\",\"UIPasteConfiguration\",\"UIPasteConfigurationSupporting\",\"UIPasteControl\",\"UIPasteboard\",\"UIPencilInteraction\",\"UIPickerView\",\"UIPinchGestureRecognizer\",\"UIPointerAccessory\",\"UIPointerInteraction\",\"UIPointerLockState\",\"UIPointerRegion\",\"UIPointerStyle\",\"UIPopoverBackgroundView\",\"UIPopoverController\",\"UIPopoverPresentationController\",\"UIPopoverPresentationControllerSourceItem\",\"UIPopoverSupport\",\"UIPresentationController\",\"UIPress\",\"UIPressesEvent\",\"UIPreviewInteraction\",\"UIPreviewParameters\",\"UIPrintError\",\"UIPrintFormatter\",\"UIPrintInfo\",\"UIPrintInteractionController\",\"UIPrintPageRenderer\",\"UIPrintPaper\",\"UIPrintServiceExtension\",\"UIPrinter\",\"UIPrinterPickerController\",\"UIProgressView\",\"UIPushBehavior\",\"UIReferenceLibraryViewController\",\"UIRefreshControl\",\"UIRegion\",\"UIResponder\",\"UIResponder_UIActivityItemsConfiguration\",\"UIRotationGestureRecognizer\",\"UIScene\",\"UISceneActivationConditions\",\"UISceneConfiguration\",\"UISceneDefinitions\",\"UISceneDestructionCondition\",\"UISceneEnhancedStateRestoration\",\"UISceneOptions\",\"UISceneSession\",\"UISceneSessionActivationRequest\",\"UISceneSizeRestrictions\",\"UISceneSystemProtectionManager\",\"UISceneWindowingBehaviors\",\"UISceneWindowingControlStyle\",\"UIScene_AVAudioSession\",\"UIScreen\",\"UIScreenEdgePanGestureRecognizer\",\"UIScreenMode\",\"UIScreenshotService\",\"UIScribbleInteraction\",\"UIScrollEdgeElementContainerInteraction\",\"UIScrollView\",\"UISearchBar\",\"UISearchContainerViewController\",\"UISearchController\",\"UISearchDisplayController\",\"UISearchSuggestion\",\"UISearchTab\",\"UISearchTextField\",\"UISegmentedControl\",\"UISelectionFeedbackGenerator\",\"UIShadowProperties\",\"UIShape\",\"UISheetPresentationController\",\"UISlider\",\"UISliderTrackConfiguration\",\"UISmartReplySuggestion\",\"UISnapBehavior\",\"UISplitViewController\",\"UISplitViewControllerLayoutEnvironment\",\"UISpringLoadedInteraction\",\"UISpringLoadedInteractionSupporting\",\"UIStackView\",\"UIStandardTextCursorView\",\"UIStateRestoration\",\"UIStatusBarManager\",\"UIStepper\",\"UIStoryboard\",\"UIStoryboardPopoverSegue\",\"UIStoryboardSegue\",\"UIStringDrawing\",\"UISwipeActionsConfiguration\",\"UISwipeGestureRecognizer\",\"UISwitch\",\"UISymbolContentTransition\",\"UISymbolEffectCompletion\",\"UITab\",\"UITabAccessory\",\"UITabBar\",\"UITabBarAppearance\",\"UITabBarController\",\"UITabBarControllerSidebar\",\"UITabBarItem\",\"UITabGroup\",\"UITabSidebarItem\",\"UITableView\",\"UITableViewCell\",\"UITableViewController\",\"UITableViewHeaderFooterView\",\"UITapGestureRecognizer\",\"UITargetedDragPreview\",\"UITargetedPreview\",\"UITextChecker\",\"UITextCursorDropPositionAnimator\",\"UITextCursorView\",\"UITextDragPreviewRenderer\",\"UITextDragURLPreviews\",\"UITextDragging\",\"UITextDropProposal\",\"UITextDropping\",\"UITextField\",\"UITextFormattingCoordinator\",\"UITextFormattingViewController\",\"UITextFormattingViewControllerChangeValue\",\"UITextFormattingViewControllerComponent\",\"UITextFormattingViewControllerConfiguration\",\"UITextFormattingViewControllerFormattingDescriptor\",\"UITextFormattingViewControllerFormattingStyle\",\"UITextInput\",\"UITextInputContext\",\"UITextInputTraits\",\"UITextInteraction\",\"UITextItem\",\"UITextItemInteraction\",\"UITextLoupeSession\",\"UITextPasteConfigurationSupporting\",\"UITextPasteDelegate\",\"UITextSearching\",\"UITextSelectionDisplayInteraction\",\"UITextSelectionHandleView\",\"UITextSelectionHighlightView\",\"UITextView\",\"UITimingCurveProvider\",\"UITimingParameters\",\"UIToolTipInteraction\",\"UIToolbar\",\"UIToolbarAppearance\",\"UITouch\",\"UITrackingLayoutGuide\",\"UITrait\",\"UITraitCollection\",\"UITraitListEnvironment\",\"UIUpdateActionPhase\",\"UIUpdateInfo\",\"UIUpdateLink\",\"UIUserActivity\",\"UIUserNotificationSettings\",\"UIVibrancyEffect\",\"UIVideoEditorController\",\"UIView\",\"UIViewAnimating\",\"UIViewConfigurationState\",\"UIViewController\",\"UIViewControllerTransition\",\"UIViewControllerTransitionCoordinator\",\"UIViewControllerTransitioning\",\"UIViewLayoutRegion\",\"UIViewPropertyAnimator\",\"UIVisualEffect\",\"UIVisualEffectView\",\"UIWebView\",\"UIWindow\",\"UIWindowScene\",\"UIWindowSceneActivationAction\",\"UIWindowSceneActivationConfiguration\",\"UIWindowSceneActivationInteraction\",\"UIWindowSceneActivationRequestOptions\",\"UIWindowSceneDragInteraction\",\"UIWindowSceneGeometry\",\"UIWindowSceneGeometryPreferences\",\"UIWindowSceneGeometryPreferencesIOS\",\"UIWindowSceneGeometryPreferencesMac\",\"UIWindowSceneGeometryPreferencesVision\",\"UIWindowScenePlacement\",\"UIWindowSceneProminentPlacement\",\"UIWindowScenePushPlacement\",\"UIWindowSceneReplacePlacement\",\"UIWindowSceneStandardPlacement\",\"UIWritingToolsCoordinator\",\"UIWritingToolsCoordinatorAnimationParameters\",\"UIWritingToolsCoordinatorContext\",\"UIZoomTransitionOptions\",\"UNNotificationResponse_UIKitAdditions\",\"bitflags\",\"block2\",\"objc2-cloud-kit\",\"objc2-core-data\",\"objc2-core-foundation\",\"objc2-core-graphics\",\"objc2-core-image\",\"objc2-core-location\",\"objc2-core-text\",\"objc2-quartz-core\",\"objc2-user-notifications\"],\"objc2-cloud-kit\":[\"dep:objc2-cloud-kit\"],\"objc2-core-data\":[\"dep:objc2-core-data\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-core-graphics\":[\"dep:objc2-core-graphics\"],\"objc2-core-image\":[\"dep:objc2-core-image\"],\"objc2-core-location\":[\"dep:objc2-core-location\"],\"objc2-core-text\":[\"dep:objc2-core-text\"],\"objc2-quartz-core\":[\"dep:objc2-quartz-core\"],\"objc2-symbols\":[\"dep:objc2-symbols\"],\"objc2-uniform-type-identifiers\":[\"dep:objc2-uniform-type-identifiers\"],\"objc2-user-notifications\":[\"dep:objc2-user-notifications\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-user-notifications_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CLRegion\"],\"name\":\"objc2-core-location\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"}],\"features\":{\"NSString_UserNotifications\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UNError\":[\"objc2-foundation/NSString\"],\"UNNotification\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UNNotificationAction\":[\"bitflags\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationActionIcon\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationAttachment\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UNNotificationAttributedMessageContext\":[],\"UNNotificationCategory\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationContent\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UNNotificationRequest\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationResponse\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationServiceExtension\":[],\"UNNotificationSettings\":[\"objc2-foundation/NSObject\"],\"UNNotificationSound\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationTrigger\":[\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UNUserNotificationCenter\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"NSString_UserNotifications\",\"UNError\",\"UNNotification\",\"UNNotificationAction\",\"UNNotificationActionIcon\",\"UNNotificationAttachment\",\"UNNotificationAttributedMessageContext\",\"UNNotificationCategory\",\"UNNotificationContent\",\"UNNotificationRequest\",\"UNNotificationResponse\",\"UNNotificationServiceExtension\",\"UNNotificationSettings\",\"UNNotificationSound\",\"UNNotificationTrigger\",\"UNUserNotificationCenter\",\"bitflags\",\"block2\",\"objc2-core-location\"],\"objc2-core-location\":[\"dep:objc2-core-location\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2_0.6.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"backtrace\",\"req\":\"^0.3.74\"},{\"kind\":\"dev\",\"name\":\"core-foundation\",\"req\":\"^0.10.0\",\"target\":\"cfg(target_vendor = \\\"apple\\\")\"},{\"kind\":\"dev\",\"name\":\"iai\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.158\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"objc2-encode\",\"req\":\"^4.1.0\"},{\"default_features\":false,\"name\":\"objc2-exception-helper\",\"optional\":true,\"req\":\"^0.1.1\"},{\"name\":\"objc2-proc-macros\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"alloc\":[\"objc2-encode/alloc\"],\"catch-all\":[\"exception\"],\"default\":[\"std\"],\"disable-encoding-assertions\":[],\"exception\":[\"dep:objc2-exception-helper\"],\"gnustep-1-7\":[\"unstable-static-class\",\"objc2-exception-helper?/gnustep-1-7\"],\"gnustep-1-8\":[\"gnustep-1-7\",\"objc2-exception-helper?/gnustep-1-8\"],\"gnustep-1-9\":[\"gnustep-1-8\",\"objc2-exception-helper?/gnustep-1-9\"],\"gnustep-2-0\":[\"gnustep-1-9\",\"objc2-exception-helper?/gnustep-2-0\"],\"gnustep-2-1\":[\"gnustep-2-0\",\"objc2-exception-helper?/gnustep-2-1\"],\"objc2-proc-macros\":[],\"relax-sign-encoding\":[],\"relax-void-encoding\":[],\"std\":[\"alloc\",\"objc2-encode/std\"],\"unstable-apple-new\":[],\"unstable-arbitrary-self-types\":[],\"unstable-autoreleasesafe\":[],\"unstable-coerce-pointee\":[],\"unstable-compiler-rt\":[\"gnustep-1-7\"],\"unstable-gnustep-strict-apple-compat\":[\"gnustep-1-7\"],\"unstable-objfw\":[],\"unstable-requires-macos\":[],\"unstable-static-class\":[\"dep:objc2-proc-macros\"],\"unstable-static-class-inlined\":[\"unstable-static-class\"],\"unstable-static-sel\":[\"dep:objc2-proc-macros\"],\"unstable-static-sel-inlined\":[\"unstable-static-sel\"],\"unstable-winobjc\":[\"gnustep-1-8\"],\"verify\":[]}}", diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index d2d52d2268..9b4f7e5a07 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -4935,6 +4935,7 @@ name = "codex-user-verification" version = "0.0.0" dependencies = [ "base64 0.22.1", + "block2", "core-foundation 0.10.1", "dirs", "objc2", @@ -10961,8 +10962,10 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48e0b8b339e0d9d2ed4416b7f93f9d4daadff7d4dd797f89867cde11aeac607" dependencies = [ + "block2", "objc2", "objc2-foundation", + "objc2-security", ] [[package]] @@ -10977,6 +10980,17 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" diff --git a/codex-rs/user-verification/Cargo.toml b/codex-rs/user-verification/Cargo.toml index fe4d5298f0..50aa510964 100644 --- a/codex-rs/user-verification/Cargo.toml +++ b/codex-rs/user-verification/Cargo.toml @@ -15,11 +15,12 @@ thiserror = { workspace = true } tracing = { workspace = true } [target.'cfg(target_os = "macos")'.dependencies] +block2 = "0.6.2" core-foundation = "0.10" dirs = { workspace = true } objc2 = "0.6.3" objc2-foundation = { version = "0.3.2", default-features = false, features = ["std", "NSString"] } -objc2-local-authentication = { version = "0.3.2", default-features = false, features = ["std", "LAContext", "LABiometryType"] } +objc2-local-authentication = { version = "0.3.2", default-features = false, features = ["std", "LAContext", "LABiometryType", "block2", "objc2-security"] } security-framework = { version = "3.5", features = ["OSX_10_15"] } security-framework-sys = "2.15" diff --git a/codex-rs/user-verification/README.md b/codex-rs/user-verification/README.md new file mode 100644 index 0000000000..53150c9c25 --- /dev/null +++ b/codex-rs/user-verification/README.md @@ -0,0 +1,59 @@ +# Native hardware test + +`tests/hardware.rs` exercises the macOS provider with a real persisted Secure +Enclave key: create and reload it, verify a signature, cancel an authentication +request, and sign a new challenge with the same key. It is ignored by default. + +Run on a physical Touch ID Mac with fingerprints enrolled and the lid open. Use +an existing **isolated development app** with a valid provisioning profile and +Keychain Sharing entitlements, plus its Apple Development signing identity. +The test does not use a Wallet account or submit a purchase. Run only one copy at +a time; it reserves the `codex-user-verification-hardware-test` key namespace and +removes that namespace's key before and after the test. + +From the repository root, set `TEMPLATE_APP` to that signed development `.app` +and `SIGNING_IDENTITY` to its signing identity, then run in Bash. Signing the +runner is insufficient: the test executable itself needs the profile and +entitlements. + +```bash +set -euo pipefail +: "${TEMPLATE_APP:?Set the path to the isolated signed development app}" +: "${SIGNING_IDENTITY:?Set its Apple Development identity}" +run_dir=$(mktemp -d) +app="$run_dir/HardwareTest.app" +(cd codex-rs && cargo build --locked -p codex-user-verification --test hardware \ + --message-format=json) > "$run_dir/build.jsonl" +binary=$(jq -r 'select(.reason == "compiler-artifact" and .target.name == "hardware" and .executable != null) | .executable' "$run_dir/build.jsonl") +mkdir -p "$app/Contents/MacOS" +cp "$binary" "$app/Contents/MacOS/hardware" +cp "$TEMPLATE_APP/Contents/Info.plist" "$app/Contents/Info.plist" +cp "$TEMPLATE_APP/Contents/embedded.provisionprofile" "$app/Contents/embedded.provisionprofile" +/usr/libexec/PlistBuddy -c 'Set :CFBundleExecutable hardware' "$app/Contents/Info.plist" +codesign -d --xml --entitlements - "$TEMPLATE_APP" > "$run_dir/entitlements.plist" +codesign --force --options runtime --entitlements "$run_dir/entitlements.plist" \ + --sign "$SIGNING_IDENTITY" "$app" +codesign --verify --strict "$app" +echo "Test bundle: $app" +"$app/Contents/MacOS/hardware" --ignored --exact \ + persisted_key_signing_cancellation_and_retry --nocapture --test-threads=1 +``` + +Use Touch ID for the first prompt, then remove your finger. Leave the +**cancellation** prompt untouched and observe that it appears and closes on its +own. Authenticate the **retry signing** prompt once. Passing assertions verify +both signatures, the cancellation result, and key removal; confirming visible +prompt dismissal is the operator's part of the test. An early interruption fails +the test rather than counting as cancellation. + +If cancellation has not returned ten seconds after it is issued, the watchdog +exits with a failure instead of hanging. After a forced exit, stop any remaining +test process and remove the reserved key with the same signed bundle: + +```bash +CODEX_HARDWARE_TEST_CLEANUP=1 "$app/Contents/MacOS/hardware" --ignored --exact \ + persisted_key_signing_cancellation_and_retry --nocapture --test-threads=1 +``` + +This test covers the native provider. It does not exercise app-server routing, +UI state, closed-lid recovery, or hosted Wallet completion. diff --git a/codex-rs/user-verification/src/native_operation.rs b/codex-rs/user-verification/src/native_operation.rs index 234d25499d..558d8c3cd3 100644 --- a/codex-rs/user-verification/src/native_operation.rs +++ b/codex-rs/user-verification/src/native_operation.rs @@ -1,4 +1,4 @@ -//! Keeps the authentication context on its owner thread while a native operation blocks. +//! Drains asynchronous authentication before releasing its context and lifecycle lock. use crate::UserVerificationError; use crate::UserVerificationFailureReason; @@ -6,46 +6,35 @@ use crate::UserVerificationRequestGuard; use std::sync::mpsc; use std::time::Duration; -pub(crate) fn run_with_cancellation( +pub(crate) fn wait_with_cancellation( guard: &UserVerificationRequestGuard, - operation: impl FnOnce() -> Result + Send, + completion: mpsc::Receiver>, cancel: impl FnOnce(), ) -> Result { - guard.check()?; - let (done_tx, done_rx) = mpsc::sync_channel(1); - std::thread::scope(|scope| { - let worker = std::thread::Builder::new() - .name("user-verification-sign".to_string()) - .spawn_scoped(scope, move || { - let _ = done_tx.send(guard.check().and_then(|()| operation())); - }) - .map_err(|error| { - tracing::warn!(%error, "could not start user-verification signer"); - worker_error() - })?; - let result = loop { - match done_rx.recv_timeout(Duration::from_millis(/*millis*/ 50)) { - Ok(result) => break Some(result), - Err(mpsc::RecvTimeoutError::Timeout) => { - if !guard.is_active() { - cancel(); - break None; - } + let result = loop { + match completion.recv_timeout(Duration::from_millis(/*millis*/ 50)) { + Ok(result) => break result, + Err(mpsc::RecvTimeoutError::Timeout) => { + if !guard.is_active() { + cancel(); + // Invalidation is asynchronous. Keep the lifecycle lock until the + // authentication callback completes, then reject any late success. + break completion + .recv() + .unwrap_or_else(|_| Err(completion_error())); } - Err(mpsc::RecvTimeoutError::Disconnected) => break Some(Err(worker_error())), } - }; - // Join before returning so no signer outlives the context or its lifecycle lock. - worker.join().map_err(|_| worker_error())?; - guard.check()?; - result.unwrap_or_else(|| Err(worker_error())) - }) + Err(mpsc::RecvTimeoutError::Disconnected) => break Err(completion_error()), + } + }; + guard.check()?; + result } -fn worker_error() -> UserVerificationError { +fn completion_error() -> UserVerificationError { UserVerificationError::Failed { reason: UserVerificationFailureReason::ProviderError, - message: "the user-verification signer could not complete".to_string(), + message: "the user-verification authorization could not complete".to_string(), } } diff --git a/codex-rs/user-verification/src/native_operation_tests.rs b/codex-rs/user-verification/src/native_operation_tests.rs index 95b30ab250..84081ebf16 100644 --- a/codex-rs/user-verification/src/native_operation_tests.rs +++ b/codex-rs/user-verification/src/native_operation_tests.rs @@ -1,4 +1,4 @@ -//! Exercises prompt teardown and late-result rejection without requiring biometric hardware. +//! Exercises cancellation completion and late-result rejection without biometric hardware. use super::*; use crate::UserVerificationCancellationReason; @@ -7,34 +7,26 @@ use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; #[test] -fn cancellation_tears_down_the_prompt_on_the_context_owner_thread() { +fn cancellation_waits_for_completion_on_the_context_owner_thread() { let guard = UserVerificationRequestGuard::default(); let queued = guard.clone(); - let (started_tx, started_rx) = mpsc::channel(); - let (dismissed_tx, dismissed_rx) = mpsc::channel(); - let (exited_tx, exited_rx) = mpsc::channel(); + let (done_tx, done_rx) = mpsc::sync_channel(0); + let (cancelled_tx, cancelled_rx) = mpsc::channel(); let owner = std::thread::spawn(move || { let owner_thread = std::thread::current().id(); - run_with_cancellation( - &queued, - move || { - started_tx.send(()).expect("authentication started"); - dismissed_rx - .recv_timeout(Duration::from_secs(/*secs*/ 5)) - .expect("prompt dismissed before the deadline"); - exited_tx.send(()).expect("signer exited"); - Ok("late signature") - }, - || { - assert_eq!(std::thread::current().id(), owner_thread); - dismissed_tx.send(()).expect("dismiss authentication"); - }, - ) + wait_with_cancellation(&queued, done_rx, || { + assert_eq!(std::thread::current().id(), owner_thread); + cancelled_tx.send(()).expect("dismiss authentication"); + }) }); - started_rx - .recv_timeout(Duration::from_secs(/*secs*/ 5)) - .expect("signer is waiting for authentication"); guard.cancel(); + cancelled_rx + .recv_timeout(Duration::from_secs(/*secs*/ 5)) + .expect("authentication invalidated"); + assert!(!owner.is_finished()); + done_tx + .send(Ok("late authorization")) + .expect("complete authentication"); assert_eq!( owner.join().expect("owner returned"), Err(UserVerificationError::Cancelled { @@ -42,42 +34,37 @@ fn cancellation_tears_down_the_prompt_on_the_context_owner_thread() { message: "the verification operation is no longer active".to_string(), }) ); - exited_rx.try_recv().expect("signer exited before return"); } #[test] fn completed_operation_does_not_cancel_its_context() { let cancelled = AtomicBool::new(/*v*/ false); + let (done_tx, done_rx) = mpsc::channel(); + done_tx + .send(Ok("authorization")) + .expect("complete authentication"); assert_eq!( - run_with_cancellation( - &UserVerificationRequestGuard::default(), - || Ok("signature"), - || cancelled.store(/*val*/ true, Ordering::Release), - ), - Ok("signature") + wait_with_cancellation(&UserVerificationRequestGuard::default(), done_rx, || { + cancelled.store(/*val*/ true, Ordering::Release) + },), + Ok("authorization") ); assert!(!cancelled.load(Ordering::Acquire)); } #[test] -fn already_cancelled_operation_never_starts_a_signer() { +fn cancellation_rejects_already_completed_authorization() { let guard = UserVerificationRequestGuard::default(); + let (done_tx, done_rx) = mpsc::channel(); + done_tx.send(Ok(())).expect("complete authentication"); guard.cancel(); - let started = AtomicBool::new(/*v*/ false); - let result = run_with_cancellation( - &guard, - || { - started.store(/*val*/ true, Ordering::Release); - Ok(()) - }, - || panic!("no context needs cancellation"), - ); assert_eq!( - result, + wait_with_cancellation(&guard, done_rx, || panic!( + "authentication already completed" + )), Err(UserVerificationError::Cancelled { reason: UserVerificationCancellationReason::Interrupted, message: "the verification operation is no longer active".to_string(), }) ); - assert!(!started.load(Ordering::Acquire)); } diff --git a/codex-rs/user-verification/src/platform_macos/key_protection.rs b/codex-rs/user-verification/src/platform_macos/key_protection.rs index a5b9003f25..456aa3e061 100644 --- a/codex-rs/user-verification/src/platform_macos/key_protection.rs +++ b/codex-rs/user-verification/src/platform_macos/key_protection.rs @@ -9,6 +9,7 @@ use core_foundation::dictionary::CFDictionary; use core_foundation::number::CFNumber; use security_framework::access_control::ProtectionMode; use security_framework::access_control::SecAccessControl; +use security_framework::key::SecKey; use security_framework_sys::access_control::kSecAccessControlBiometryAny; use security_framework_sys::access_control::kSecAccessControlPrivateKeyUsage; use security_framework_sys::item::kSecAttrKeyClass; @@ -27,7 +28,11 @@ pub(super) fn access_control() -> Result Result<(), UserVerificationError> { +pub(super) fn validate(key: &SecKey) -> Result<(), UserVerificationError> { + validate_attributes(&key.attributes()) +} + +fn validate_attributes(attributes: &CFDictionary) -> Result<(), UserVerificationError> { let size = CFNumber::from(/*value*/ 256); // Do not compare opaque SecAccessControl objects: macOS can change their persisted // representation. Biometric signing is enforced by the policy set at key creation. diff --git a/codex-rs/user-verification/src/platform_macos/key_protection_tests.rs b/codex-rs/user-verification/src/platform_macos/key_protection_tests.rs index dc44bf2f8c..c579908fc9 100644 --- a/codex-rs/user-verification/src/platform_macos/key_protection_tests.rs +++ b/codex-rs/user-verification/src/platform_macos/key_protection_tests.rs @@ -32,7 +32,10 @@ fn protected_attributes() -> CFMutableDictionary { #[test] fn reuse_requires_secure_enclave_key_attributes() { let attributes = protected_attributes(); - assert_eq!(validate(&attributes.to_immutable().to_untyped()), Ok(())); + assert_eq!( + validate_attributes(&attributes.to_immutable().to_untyped()), + Ok(()) + ); let alternatives = unsafe { [ (kSecAttrTokenID, CFString::new("software").as_CFType()), @@ -48,7 +51,7 @@ fn reuse_requires_secure_enclave_key_attributes() { let mut attributes = protected_attributes(); attributes.set(unsafe { CFString::wrap_under_get_rule(attribute) }, value); assert_eq!( - validate(&attributes.to_immutable().to_untyped()), + validate_attributes(&attributes.to_immutable().to_untyped()), Err(UserVerificationError::Unavailable { reason: UserVerificationUnavailableReason::ProviderUnavailable, message: "the local credential has incompatible key protection; delete it before enrolling again" diff --git a/codex-rs/user-verification/src/platform_macos/provider.rs b/codex-rs/user-verification/src/platform_macos/provider.rs index 9c532b275f..a1df3604e1 100644 --- a/codex-rs/user-verification/src/platform_macos/provider.rs +++ b/codex-rs/user-verification/src/platform_macos/provider.rs @@ -15,16 +15,21 @@ use crate::UserVerificationRequestGuard; use crate::UserVerificationStatus; use crate::UserVerificationUnavailableReason; use crate::lifecycle_lock::LifecycleLock; -use crate::native_operation::run_with_cancellation; +use crate::native_operation::wait_with_cancellation; use base64::Engine as _; use base64::engine::general_purpose::URL_SAFE_NO_PAD; +use block2::RcBlock; use core_foundation::base::CFType; use core_foundation::base::TCFType as _; use objc2::rc::Retained; +use objc2::runtime::Bool; +use objc2_foundation::NSError; use objc2_foundation::NSString; +use objc2_local_authentication::LAAccessControlOperation; use objc2_local_authentication::LABiometryType; use objc2_local_authentication::LAContext; use objc2_local_authentication::LAPolicy; +use security_framework::access_control::SecAccessControl; use security_framework::base::Error as SecurityError; use security_framework::item::ItemClass; use security_framework::item::ItemSearchOptions; @@ -39,6 +44,9 @@ use security_framework::key::KeyType; use security_framework::key::SecKey; use security_framework::key::Token; use security_framework_sys::base::errSecItemNotFound; +use security_framework_sys::item::kSecAttrAccessControl; +use security_framework_sys::item::kSecValueRef; +use std::sync::mpsc; pub(crate) struct NativeProvider { pub(crate) namespace: UserVerificationKeyNamespace, @@ -168,13 +176,85 @@ impl UserVerificationProvider for NativeProvider { } else { format!("{}\n\n{}", request.title, request.description) }; - // The keychain query retains this context and uses its text for the signing prompt. unsafe { context.setLocalizedFallbackTitle(Some(&NSString::from_str(""))); context.setLocalizedReason(&NSString::from_str(&reason)); } check_biometrics(&context)?; guard.check()?; + // SecKeyCopyAttributes does not guarantee the stored item's access-control attribute. + let attributes = match key_query(&self.namespace.label, &noninteractive_context()) + .load_refs(true) + .load_attributes(true) + .search() + { + Ok(results) => results.into_iter().find_map(|result| match result { + SearchResult::Dict(attributes) => Some(attributes), + _ => None, + }), + Err(error) if error.code() == errSecItemNotFound => { + return Err(UserVerificationError::Unavailable { + reason: UserVerificationUnavailableReason::CredentialMissing, + message: "no user-verification credential has been created".to_string(), + }); + } + Err(error) => return Err(keychain_error(error)), + } + .ok_or_else(|| UserVerificationError::Failed { + reason: UserVerificationFailureReason::ProviderError, + message: "the user-verification key has no attributes".to_string(), + })?; + let key = attributes + .find(unsafe { kSecValueRef.cast() }) + .and_then(|value| unsafe { CFType::wrap_under_get_rule(*value) }.downcast::()) + .ok_or_else(|| UserVerificationError::Failed { + reason: UserVerificationFailureReason::ProviderError, + message: "the user-verification item has no key reference".to_string(), + })?; + key_protection::validate(&key)?; + let access = attributes + .find(unsafe { kSecAttrAccessControl.cast() }) + .and_then(|value| { + unsafe { CFType::wrap_under_get_rule(*value) }.downcast::() + }) + .ok_or_else(|| UserVerificationError::Failed { + reason: UserVerificationFailureReason::ProviderError, + message: "the user-verification key has no access control".to_string(), + })?; + let (done_tx, done_rx) = mpsc::sync_channel(1); + let reply = RcBlock::new(move |success: Bool, error: *mut NSError| { + let result = if success.as_bool() { + Ok(()) + } else if let Some(error) = unsafe { error.as_ref() } { + Err(error::classify( + &error.domain().to_string(), + error.code() as i64, + )) + } else { + Err(UserVerificationError::Failed { + reason: UserVerificationFailureReason::ProviderError, + message: "biometric authorization did not complete".to_string(), + }) + }; + let _ = done_tx.send(result); + }); + guard.check()?; + // Keychain signing reconstructs its own context. Evaluate the key's policy here + // so cancellation invalidates the context that actually owns the prompt. + unsafe { + context.evaluateAccessControl_operation_localizedReason_reply( + &*access.as_concrete_TypeRef().cast(), + LAAccessControlOperation::UseKeySign, + &NSString::from_str(&reason), + &reply, + ); + } + wait_with_cancellation(guard, done_rx, || unsafe { context.invalidate() })?; + // Fetch a new key reference with the authorized, noninteractive context. Signing + // must fail instead of opening another prompt if that authorization is unusable. + unsafe { + context.setInteractionNotAllowed(/*interaction_not_allowed*/ true) + }; let key = find_key(&self.namespace.label, &context, KeyUse::Protected)?.ok_or_else(|| { UserVerificationError::Unavailable { @@ -184,21 +264,12 @@ impl UserVerificationProvider for NativeProvider { })?; let credential = key_info(&key)?; guard.check()?; - let signature = run_with_cancellation( - guard, - || { - key.create_signature( - Algorithm::ECDSASignatureMessageX962SHA256, - &request.challenge, - ) - .map_err(|error| error::classify(&error.domain().to_string(), error.code() as i64)) - }, - || { - // LAContext remains on this thread. Invalidation cancels its pending - // keychain authentication, allowing the signer and lifecycle lock to exit. - unsafe { context.invalidate() }; - }, - ); + let signature = key + .create_signature( + Algorithm::ECDSASignatureMessageX962SHA256, + &request.challenge, + ) + .map_err(|error| error::classify(&error.domain().to_string(), error.code() as i64)); guard.check()?; Ok(UserVerificationProof { credential_id: credential.credential_id, @@ -217,7 +288,7 @@ fn noninteractive_context() -> Retained { } fn check_biometrics(context: &LAContext) -> Result<(), UserVerificationError> { - // canEvaluatePolicy only checks availability; the protected key triggers authentication. + // canEvaluatePolicy only checks availability; evaluating the key's policy authenticates. unsafe { context.canEvaluatePolicy_error(LAPolicy::DeviceOwnerAuthenticationWithBiometrics) } .map_err(|error| error::classify(&error.domain().to_string(), error.code() as i64)) } @@ -232,6 +303,25 @@ fn find_key( context: &LAContext, key_use: KeyUse, ) -> Result, UserVerificationError> { + match key_query(label, context).load_refs(true).search() { + Ok(results) => { + let key = results.into_iter().find_map(|result| match result { + SearchResult::Ref(Reference::Key(key)) => Some(key), + _ => None, + }); + if let Some(key) = &key + && matches!(key_use, KeyUse::Protected) + { + key_protection::validate(key)?; + } + Ok(key) + } + Err(error) if error.code() == errSecItemNotFound => Ok(None), + Err(error) => Err(keychain_error(error)), + } +} + +fn key_query(label: &str, context: &LAContext) -> ItemSearchOptions { // Security accepts an LAContext object as kSecUseAuthenticationContext. Wrapping under // the get rule retains it, and ItemSearchOptions owns that retain for the query lifetime. let authentication = unsafe { CFType::wrap_under_get_rule(std::ptr::from_ref(context).cast()) }; @@ -241,24 +331,8 @@ fn find_key( .key_class(KeyClass::private()) .label(label) .local_authentication_context(Some(authentication)) - .load_refs(true) .limit(Limit::Max(1)); - match options.search() { - Ok(results) => { - let key = results.into_iter().find_map(|result| match result { - SearchResult::Ref(Reference::Key(key)) => Some(key), - _ => None, - }); - if let Some(key) = &key - && matches!(key_use, KeyUse::Protected) - { - key_protection::validate(&key.attributes())?; - } - Ok(key) - } - Err(error) if error.code() == errSecItemNotFound => Ok(None), - Err(error) => Err(keychain_error(error)), - } + options } fn create_key(label: &str) -> Result { @@ -273,7 +347,7 @@ fn create_key(label: &str) -> Result { .set_access_control(access); let key = SecKey::new(&options) .map_err(|error| error::classify(&error.domain().to_string(), error.code() as i64))?; - key_protection::validate(&key.attributes())?; + key_protection::validate(&key)?; Ok(key) } diff --git a/codex-rs/user-verification/tests/hardware.rs b/codex-rs/user-verification/tests/hardware.rs new file mode 100644 index 0000000000..9039ba5f68 --- /dev/null +++ b/codex-rs/user-verification/tests/hardware.rs @@ -0,0 +1,134 @@ +//! Opt-in checks of the persisted Secure Enclave signing and cancellation path. +#![cfg(target_os = "macos")] + +use base64::Engine as _; +use base64::engine::general_purpose::URL_SAFE_NO_PAD; +use codex_user_verification::UserVerificationCancellationReason; +use codex_user_verification::UserVerificationError; +use codex_user_verification::UserVerificationKeyNamespace; +use codex_user_verification::UserVerificationProvider; +use codex_user_verification::UserVerificationRequest; +use codex_user_verification::UserVerificationRequestGuard; +use codex_user_verification::platform_provider; +use p256::ecdsa::Signature; +use p256::ecdsa::VerifyingKey; +use p256::ecdsa::signature::Verifier as _; +use p256::pkcs8::DecodePublicKey as _; +use pretty_assertions::assert_eq; +use std::sync::Arc; +use std::sync::mpsc; +use std::time::Duration; + +const TEST_IDENTITY: &str = "codex-user-verification-hardware-test"; + +struct TestKey(Arc); + +impl Drop for TestKey { + fn drop(&mut self) { + let deleted = self.0.delete(&UserVerificationRequestGuard::default()); + if !std::thread::panicking() { + assert!(deleted.is_ok(), "delete the test credential: {deleted:?}"); + } + } +} + +#[test] +#[ignore = "requires a signed test app, a physical Touch ID Mac, and user interaction; see README.md"] +fn persisted_key_signing_cancellation_and_retry() { + let provider = platform_provider(UserVerificationKeyNamespace::new(TEST_IDENTITY)); + // This namespace is reserved for this test, including cleanup after a killed run. + provider + .delete(&UserVerificationRequestGuard::default()) + .expect("clear any previous test credential"); + if std::env::var_os("CODEX_HARDWARE_TEST_CLEANUP").is_some() { + return; + } + let cleanup = TestKey(Arc::clone(&provider)); + let created = provider + .ensure_key(&UserVerificationRequestGuard::default()) + .expect("create a persisted Secure Enclave key"); + assert!(created.created); + let reloaded = platform_provider(UserVerificationKeyNamespace::new(TEST_IDENTITY)) + .ensure_key(&UserVerificationRequestGuard::default()) + .expect("reload the persisted key"); + assert!(!reloaded.created); + assert_eq!(reloaded.credential, created.credential); + let public_key = VerifyingKey::from_public_key_der( + &URL_SAFE_NO_PAD + .decode(&created.credential.public_key) + .unwrap(), + ) + .unwrap(); + let sign = |request: &UserVerificationRequest| { + let proof = provider + .verify(request, &UserVerificationRequestGuard::default()) + .expect("sign with the persisted key"); + assert_eq!(proof.credential_id, created.credential.credential_id); + let signature = + Signature::from_der(&URL_SAFE_NO_PAD.decode(proof.signature).unwrap()).unwrap(); + public_key.verify(&request.challenge, &signature).unwrap(); + }; + let mut request = UserVerificationRequest { + challenge: b"Local hardware test. No purchase.".to_vec(), + title: "Hardware test: authenticate".into(), + description: "Use Touch ID once, then remove your finger.".into(), + }; + eprintln!("Use Touch ID for the first signature."); + sign(&request); + + request.title = "Hardware test: cancellation".into(); + request.description = + "Leave Touch ID untouched; this prompt should close automatically.".into(); + eprintln!("Leave the next prompt untouched; cancellation follows in three seconds."); + let guard = UserVerificationRequestGuard::default(); + let cancellation = guard.clone(); + let (finished, completion) = mpsc::channel(); + let timer = std::thread::spawn(move || { + if completion.recv_timeout(Duration::from_secs(/* secs */ 3)) + == Err(mpsc::RecvTimeoutError::Timeout) + { + cancellation.cancel(); + if completion.recv_timeout(Duration::from_secs(/* secs */ 10)) + == Err(mpsc::RecvTimeoutError::Timeout) + { + eprintln!( + "Cancellation did not finish. Run with CODEX_HARDWARE_TEST_CLEANUP=1 to remove the test key." + ); + std::process::exit(/* code */ 1); + } + true + } else { + false + } + }); + let result = provider.verify(&request, &guard); + finished.send(()).unwrap(); + assert!( + timer.join().unwrap(), + "verification finished before cancellation" + ); + assert!( + matches!( + result, + Err(UserVerificationError::Cancelled { + reason: UserVerificationCancellationReason::Interrupted, + .. + }) + ), + "unexpected cancellation result: {result:?}" + ); + + request.challenge = b"Retry signing after cancellation.".to_vec(); + request.title = "Hardware test: retry signing".into(); + request.description = "Use Touch ID to sign again with the same stored key.".into(); + eprintln!("Use Touch ID for the retry."); + sign(&request); + drop(cleanup); + assert!( + provider + .status(&UserVerificationRequestGuard::default()) + .unwrap() + .credential + .is_none() + ); +}