Posts

Sort by:
Post not yet marked as solved
0 Replies
27 Views
Over the years I’ve helped a lot of folks investigate a lot of crashes. In some cases those crashes only make sense if you know a little about how Foundation and Core Foundation types are toll-free bridged. This post is my attempt to explain that. If you have questions or comments, please put them in a new thread. Tag it with Foundation and Debugging so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Devel oper Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Crashes on the Toll-Free Bridge Certain Core Foundation (CF) types are toll-free bridged to their Foundation equivalent. That allows you to pass the Foundation object to a CF routine and vice versa [1]. For example, NSData and CFData are toll-free bridged, allowing you to pass an NSData object to a CF routine like CFDataGetBytePtr. For more information on this topic, see Toll-Free Bridged Types within Core Foundation Design Concepts in the Documentation Archive. This is cool, but it does present some interesting challenges. One of these relates to subclassing. Many of the toll-free bridge Foundation types support subclassing and, if you create a instance of your subclass and pass it to CF, CF has to do the right thing. Continuing the NSData example above, it’s legal [2] to create your own subclass of NSData with a completely custom implementation. As long as you implement the -bytes method and the length property, all the other NSData methods will just work. Moreover, this class works with CFData routines as well. If you pass an instance of your subclass to CFDataGetBytePtr, CF detects that it’s an Objective-C object and calls your -bytes method. Exciting! So, how does this actually work? It relies on the fact that CF and Objective-C types share a common object header. That object header is an implementation detail, but the first word of the header is always an indication of the class [3]. CF uses this word to distinguish between CF and Objective-C objects. Note This basic technique is used by other Objective-C compatible types, including Swift objects and XPC objects. If, for example, you call CFRetain on Swift object, it detects that this is an Objective-C compatible object and calls objc_retain, which in turns detects that this is a Swift object and calls swift_retain. To see this in action, check out the Swift Foundation open source. Continuing our NSData example, the first line of CFDataGetBytePtr uses the CF_OBJC_FUNCDISPATCHV macro to check if this is an Objective-C object and, if so, call -bytes on it. Sadly, the open source trail goes cold here, because Objective-C integration is only supported on Apple platforms. However, some disassembly reveals the presence of an internal routine called CF_IS_OBJC. (lldb) disas -n CFDataGetBytePtr CoreFoundation`CFDataGetBytePtr: … <+0>: pacibsp … <+4>: stp x20, x19, [sp, #-0x20]! … <+8>: stp x29, x30, [sp, #0x10] … <+12>: add x29, sp, #0x10 … <+16>: mov x19, x0 … <+20>: mov w0, #0x14 … <+24>: mov x1, x19 … <+28>: bl 0x19cc60100 ; CF_IS_OBJC … WARNING Do not rely on the presence or behaviour of CF_IS_OBJC. This is an implementation detail. It has changed many times in the past and may well change in the future [4]. While this is an implementation detail, it’s useful to know about when debugging. If you pass something that’s not a valid object to CFDataGetBytePtr, you might see it crash in CF_IS_OBJC. For example, this code: void test(void) { struct { int i; } s = { 0 }; CFDataGetBytePtr( (const struct __CFData *) &s ); } crashes like this: Exception Type: EXC_BREAKPOINT (SIGTRAP) … Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 CoreFoundation … CF_IS_OBJC + 76 1 CoreFoundation … CFDataGetBytePtr + 32 2 xxot … test + 24 … … In this case CF_IS_OBJC has detected the problem and trapped, resulting in an EXC_BREAKPOINT crash. However, if you pass it a pointer that looks more like an object, this might crash trying to dereference a bad pointer, which will result in a EXC_BAD_ACCESS crash. The other common failure you see occurs when you pass it an Objective-C object of the wrong type. Consider code like this: void test(void) { id str = [NSString stringWithFormat:@"Hello Cruel World!-%d", (int) getpid()]; const void * ptr = CFDataGetBytePtr( (__bridge CFDataRef) str); … } When you run this code, it throws a language exception like this: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString bytes]: unrecognized selector sent to instance 0x6000028545a0' *** First throw call stack: ( 0 CoreFoundation … __exceptionPreprocess + 176 1 libobjc.A.dylib … objc_exception_throw + 60 2 CoreFoundation … -[NSObject(NSObject) __retain_OA] + 0 3 CoreFoundation … ___forwarding___ + 1580 4 CoreFoundation … _CF_forwarding_prep_0 + 96 5 xxot … test + 92 … ) CFDataGetBytePtr has detected this is an Objective-C object and called -bytes on it. However, this is actually an NSString [5] and NSString doesn’t implement the -bytes method. The end result is an unrecognized selector exception. [1] To be clear, when using CF objects in Objective-C you first cast the CF object to its Foundation equivalent and then call Objective-C methods on it. [2] While it’s legal to do this, it’s probably not very sensible. Subclassing Foundation types is something that might’ve made sense back in the day, but these days there are generally better ways to solve your problems. [3] Historically this word was called isa and was of type Class, that is, a pointer to the actual Objective-C class. These days things are much more complex (-: [4] Historically, CF_IS_OBJC was very simple: If the object’s isa word was 0, it was a CF object, otherwise it was an Objective-C object. That’s no longer the case. [5] The actual type is __NSCFString. That’s because NSString is a class cluster. For more about that, see Class Clusters within Cocoa Fundamentals Guide in the Documentation Archive.
Posted
by
Post not yet marked as solved
3 Replies
30 Views
I am a bit confused on whether certain Video Toolbox (VT) encoders support hardware acceleration or not. When I query the list of VT encoders (VTCopyVideoEncoderList(nil,&encoderList)) on an iPhone 14 Pro device, for avc1 (AVC / H.264) and hevc1 (HEVC / H.265) encoders, the kVTVideoEncoderList_IsHardwareAccelerated flag is not there, which -based on the documentation found on the VTVideoEncoderList.h- means that the encoders do not support hardware acceleration: optional. CFBoolean. If present and set to kCFBooleanTrue, indicates that the encoder is hardware accelerated. In fact, no encoders from this list return this flag as true and most of them do not include the flag at all on their dictionaries. On the other hand, when I create a compression session using the VTCompressionSessionCreate() and pass the kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder as true in the encoder specifications, after querying the kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder using the following code, I get a CFBoolean value of true for both H.264 and H.265 encoder. In fact, I get a true value (for both of the aforementioned encoders) even if I don't specify the kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder during the creation of the compression session (note here that this flag was introduced in iOS 17.4 ^1). So the question is: Are those encoders actually hardware accelerated on my device, and if so, why isn't that reflected on the VTCopyVideoEncoderList() call?
Posted
by
Post not yet marked as solved
0 Replies
2 Views
My project was working fine on xcode 14 for ios 16 simulators and real devices with all setup and pods, recently i updated system for xcode 15, and sicne then on build getting this error for simulator and real devices - Driver threw unknown argument: '-bvvutkjqcsvcmlfdhxkrjtgqdzeg/Build/Intermediates.noindex/' without emitting errors. i did everyting - clean ,deep clean, restart, update cocoapod, all pods update, deintegrate - install again, delete cache, delete derived data btw - this- bvvutkjqcsvcmlfdhxkrjtgqdzeg/Build/Intermediates.noindex/ is a file getting generated in derived data - and in log getting this also - error: Driver threw unknown argument: '-bvvutkjqcsvcmlfdhxkrjtgqdzeg/Build/Intermediates.noindex/' without emitting errors. (in target 'fabfinance' from project ' ') this is my pod file - # Uncomment the next line to define a global platform for your project # platform :ios, '13.0' target 'fabfinance' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! # Pods for fabfinance pod 'Alamofire' pod 'SwiftyJSON' pod 'PopupDialog' pod 'JMImageCache' #pod 'Firebase/Analytics' #pod 'Firebase/Messaging' #pod 'Firebase/Crashlytics' #pod 'Firebase/Core' #pod 'Firebase/Auth' pod 'SOTabBar' pod 'MaterialComponents' pod 'IQKeyboardManagerSwift' pod 'DropDown' pod 'DLRadioButton', '~> 1.4' pod 'ADCountryPicker', '~> 2.1.0' pod 'MDFInternationalization' pod 'SDWebImage' pod 'ProgressHUD' pod 'DatePickerDialog' pod 'PhoneNumberKit' pod 'Charts' target 'fabfinanceTests' do inherit! :search_paths # Pods for testing end target 'fabfinanceUITests' do # Pods for testing end end post_install do |installer| installer.generated_projects.each do |project| project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' end end end end
Posted
by
Post not yet marked as solved
1 Replies
2 Views
Hello everyone! I'm encountering an issue while trying to use the Sign in with Apple token revocation API. I've followed the steps outlined in the official documentation (https://developer.apple.com/documentation/sign_in_with_apple/revoke_tokens), but when I consume the API, I receive a 200 status code instead of the expected code. I've double-checked my implementation and can't find any obvious errors. Has anyone else experienced this issue before? I would greatly appreciate any suggestions or advice on how to resolve this issue. Thank you in advance for your help!
Posted
by
Post not yet marked as solved
0 Replies
4 Views
Dear Apple Community, I've been dealing with a frustrating situation for the past three months regarding my application to the Apple Development program. It's been a rollercoaster of emotions, and I'm reaching out for some assistance. TL;DR: I've received the "Complete your enrollment in the Apple Developer Program" email, but when I try to proceed with the payment, the system puts me back in the enrollment stage again. Despite numerous calls to the support center, I'm stuck in a loop and unable to move forward. Has anyone else encountered this issue? Long Version: Today, I received an email prompting me to complete my enrollment in the Apple Developer Program. However, upon attempting to do so through the Apple Developer App, I discovered that my previous enrollment had been somehow withdrawn, leaving me back at square one. Frustrated and confused, I turned to the Apple Developer Web for answers, only to find myself facing the same message. After taking a 5min break to gather my thoughts, I returned to the Apple Developer app, only to encounter another roadblock. Now, I'm being directed to enrol through the web page, despite being told previously that the process must be completed through the app. It's a super annoying and confusing situation, to say the least. I am from Australia and trying to navigate my business overseas; I've faced many different challenges. However, this experience with Apple has been particularly the most ridiculous one. I've seen many different problems over the years but this has no logic. If anyone has experienced a similar issue or has any insights to offer, I'd greatly appreciated. Thank you for your support.
Posted
by
Post not yet marked as solved
0 Replies
2 Views
There is at least one app in AppStore (Prisma: Photo Editor, Filters), that suggest 1 day of free trial, but if you accept it, your card will be charged next day for full price of year subscription, even if you already removed app from your device and canceled subscription during this free trial day. This looks like fraud. Developers refuse to take responsibility for this. Apple support chat confirms, that such situatioin is a kind of not ok, but they are not going to do anything about it at all. Is it a known issue of AppStore? Do you know other apps like this? Is there any chance for people that were forced to purchase such subscription to get a compensation? How to setup such trial and subscription settings for my app?
Posted
by
Post not yet marked as solved
0 Replies
50 Views
I have set up the app identifier in Apple developer with the document URL set up for iCloud and also updated the info.plist file and entitlements according to this. info.plist <dict> <key>iCloud.com.abc.MyApp</key> <dict> <key>NSUbiquitousContainerIsDocumentScopePublic</key> <true/> <key>NSUbiquitousContainerName</key> <string>MyApp</string> <key>NSUbiquitousContainerSupportedFolderLevels</key> <string>Any</string> </dict> </dict> <key>UIFileSharingEnabled</key> <true/> <key>LSSupportsOpeningDocumentsInPlace</key> <true/> <key>UIBackgroundModes</key> <array> <string>fetch</string> <string>remote-notification</string> </array> <key>NSUbiquitousContainersUsageDescription</key> <string>This app uses iCloud containers to store and sync documents.</string> Entitlement.plist <array> <string>iCloud.com.abc.MyApp</string> </array> <key>com.apple.developer.icloud-services</key> <array> <string>CloudDocuments</string> </array> <key>com.apple.developer.ubiquity-container-identifiers</key> <array> <string>iCloud.com.abc.MyApp</string> </array> // Then I am using iCloud for CRUD operation in the app // Code snippet { try { var iCloudDocumentsURL = NSFileManager.DefaultManager.GetUrlForUbiquityContainer(null); if (iCloudDocumentsURL != null) { var path = iCloudDocumentsURL.ToString().Replace("%C3%97", "x"); var filepath = path.Replace("file://", string.Empty).Replace("%20", " "); var destinationdirectoryPath = Path.combine(filePath,"MyAppDocuments"); if (Directory.Exists(destinationdirectoryPath)) { Directory.Delete(destinationdirectoryPath, recursive: true); } } }catch(Exception ex) { LogHandler.LogError(ex); } } But in Delete operation gives Exception -> System.IO.IOException: Access to the path '/Users/USERABC/Library/Mobile Documents/iCloudcomabc~MyApp/MyAppDocuments' is denied.
Posted
by
Post not yet marked as solved
0 Replies
48 Views
Below, I have a button designed to facilitate the purchase of a subscription, which depends on the availability of the subscription in App Store Connect. This button is visible when testing locally using a StoreKit Configuration File synced from App Store Connect, and I have linked my subscription to my app in the information section. Currently, my app is in a "waiting for review" status, and the subscription is marked as "developer action needed - rejected." However, this issue of the button not appearing persisted even when the subscription was previously in the "waiting for review" status, indicating that the problem may not be related to the subscription status. I'm encountering an issue where the 'request products' function returns no results in the TestFlight environment, even when using a sandbox Apple ID. This problem has led to repeated rejections of my app, as testers are unable to verify its functionality. What could be causing these issues? VStack { if storeVM.subscriptions.isEmpty { if storeVM.isLoading { ProgressView("Loading subscriptions...") .progressViewStyle(.circular) .scaleEffect(2.0) .padding() } else if let errorMessage = storeVM.errorMessage { Text("Error: \(errorMessage)") .foregroundColor(.red) .padding() } else { Text("No subscriptions available") .padding() } } else { ForEach(storeVM.subscriptions, id: \.id) { product in Button(action: { Task { await buy(product: product) } }) { HStack { Spacer() Text("Unlock 3-day free trial. \nThen $23.99 per year. Cancel anytime.") .font(.custom("Lora-VariableFont_wght", size: 20)) .foregroundColor(.white) .lineSpacing(5) Spacer() } } .padding() .background(Color.black.opacity(0.6)) .cornerRadius(10) .padding(.horizontal, 10) } } .onAppear { Task { await storeVM.requestProducts() } } func requestProducts() async { isLoading = true errorMessage = nil do { subscriptions = try await Product.products(for: productIds) isLoading = false } catch { print("Failed product request from App Store server: \(error)") isLoading = false errorMessage = "Failed to load products" } }
Posted
by
Post not yet marked as solved
0 Replies
40 Views
Hi, as I checked now multiple threats in the internet I cant find a solution to solve the Problems with the Apple Guidelines. Our Business Model is based on pay per user. As Apple rejected our App due to not compatible guidelines I cant figure out how to implement pay per user with InApp Purchase. Because I cannot find a solution to increate the subscriptions because you can only have 1 Subscription per Account. I cant increase the subscription amount nor adjust prices of the subscription when they invite a user for example. I really need help to figure out how to solve this type of issue. I appreciate any hints how I could solve this.
Posted
by
Post not yet marked as solved
1 Replies
52 Views
with the latest Xcode that runs with Mac OS 14.5 Developer Beta has messages with a time and date in them There are also some other fields of an indeterminate origin/type. "2024-05-06 15:37:32.383996-0500 RoomPlanExampleApp[24190:1708576] [CAMetalLayerDrawable texture] should not be called after already presenting this drawable. Get a nextDrawable instead." specifically I need to know how the string [24190:1708576] relates to a location in my application so I can act on the message. I certainly can't find the text in the "[CAMetalLayerDrawable texture]". field anywhere in the user documentation OR the Development documentation. In order for a diagnostic message to be Actionable and remedied by a user it must identify the module and source line of the initiating code and there must be accessible documentation for users to access to get an explanation of potential remedies.. This interface fails to supply enough information to diagnose the problem. The label in [CAMetalLayerDrawable texture] cannot even be found in a search of the package information attached to the Xcode Release paired with the IOS and Mac OS system releases.
Posted
by
Post not yet marked as solved
0 Replies
42 Views
I have an Apple app that uses SwiftData and icloud to sync the App's data across users' devices. Everything is working well. However, I am facing the following issue: SwiftData does not support public sharing of the object graph with other users via iCloud. How can I overcome this limitation without stopping using SwiftData? Thanks in advance!
Posted
by
Post not yet marked as solved
0 Replies
48 Views
My app is using iBeacons, and I am using func startMonitoring(for region: CLRegion). Then I am using func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) and func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) to run logic when user enters / exits certain Beacon CLBeaconRegion. Everything worked fine until recently, iOS 17 update I guess. Now after I call startMonitoring(for: region) the code works for couple hours, and then it seems my app is somehow suspended and no longer able to use CoreLocation, and my code does not work, entry and exit events to beacon regions are NOT detected. Funny enough I have some Beacon managment apps that can scan for nearby beacons, when I run one of those apps, I see on top of iPhone screen “hollow arrow” sign that marks CoreLocation being used, and then my app works for few minutes, and then again my app is suspended, and no entry/exit events into beacon regions are detected. I could figure out how to engage CoreLocation but that would rely on user intentionally opening my app, and the sole purpose of my app is to remind user when he is near one of his Beacons, so expecting user to remember to open my app defeats my apps purpose. I added Location Updates under Background Modes for my app , maybe my app has little bit more background time until it is suspended, but the problem still persists. So for any Beacon based app to work it should be able to monitor for nearby beacons, and run logic once beacons are detected. Any suggestions on how I could solve this? iOS 17 CLMonitor has BeaconIdentityCondition that can match UUID, major, minor but this is only to detect we are NEAR a Beacon (entry event), what about exit event? Should I monitor for a change in Condition from .satisfied to .unsatisfied and that transition is Exit event? My questions: Is there a way to use old code: startMonitoring(for: region) - how to fix my app so it DOES NOT get suspended, and so that this method can monitor for beacons in background with AlwaysAllow authorization? If not and I must switch to CLMonitor how do I capture Exit event - when user exits Beacon region in iOS 17 using CLMonitor? Thanks
Posted
by
Post not yet marked as solved
1 Replies
69 Views
Hey, I've been trying to fetch my Apple Music recently played songs for an app I'm working on, and I want to access the lastPlayedDate field. If I'm not mistaken, this field should exist for a Song according to Apple's documentation: https://developer.apple.com/documentation/musickit/song/lastplayeddate However, whenever I try to fetch this data, the lastPlayedDate field is always nil. All the other data I'm looking for, however, seems to fetch without issue. Here's the code I'm using: //Request as described in Apple MusicKit //https://developer.apple.com/documentation/musickit/musicrecentlyplayedrequestable var request = MusicRecentlyPlayedRequest<Song>() request.limit=30 do { let response = try await request.response() let songs = response.items.compactMap { song -> RecentlyPlayedSong? in let songName = song.title let songArtist = song.artistName let songAlbum = song.albumTitle let artwork: MusicArtworkType let preview_url = song.previewAssets?.first?.url?.absoluteString if let appleMusicArtwork = song.artwork { print("Found a song, \(song) with lastPlayedDate \(song.lastPlayedDate)") artwork = .AppleMusic(appleMusicArtwork) return RecentlyPlayedSong(name: songName, artist: songArtist, album: songAlbum, artwork: artwork, preview_url: preview_url, lastPlayedDate: song.lastPlayedDate ?? Date()) } I'm trying to map the response into a custom struct I made, but here's a sample of what's getting printed to the logs: Found a song, Song(id: "1676362342", title: "pwdr Blu (feat. Brother.)", artistName: "Kx5, deadmau5 & Kaskade") with lastPlayedDate nil Found a song, Song(id: "881289980", title: "Worlds Apart (feat. Kerli)", artistName: "Seven Lions") with lastPlayedDate nil Found a song, Song(id: "1501540431", title: "What’s Done Is Done", artistName: "Seven Lions & HALIENE") with lastPlayedDate nil Even though I just listened to these songs a a few minutes ago. Anyone ever run into this issue before? Any settings I need to look at changing to get this to show?
Posted
by
Post not yet marked as solved
1 Replies
52 Views
Im trying to use a RealityView with attachments and this error is being thowen. Am i using the RealityView wrong? I've seen other people use a RealityView with Attachments in visionOS... Please let this be a bug... RealityView { content, attachments in contentEntity = ModelEntity(mesh: .generatePlane(width: 0.3, height: 0.5)) content.add(contentEntity!) } attachments: { Text("Hello!") }.task { await loadImage() await runSession() await processImageTrackingUpdates() }
Posted
by
Post not yet marked as solved
0 Replies
47 Views
On versions iOS 14+, my app which is connected by bluetooth to another device will become slow to write information. This isn't a couple hundred ms or a second or two, but upwards of 10 minutes for it to be sent and then 400 ms to be processed by the device and send its response back. I've confirmed with PacketLogger and with system logs that what commands we are sending with .writeValue are taking over 10 minutes. This is the timestamp of when we are writing to the device This is the PacketLogger timestamp of when the phone actually wrote to our device This doesn't occur immediately, but is intermittent and once it does begin to occur, there's nothing to do to get out of it except for connecting once again to the device. Which, overtime, the issue begins to spring up again. So why is it taking 13 minutes for it to go through the phone and finally being sent?
Posted
by
Post not yet marked as solved
0 Replies
45 Views
Ever since I received the latest Beta update I have not been able to use CarPlay via a cord to my car (I've tried multiple cords with the same result). It has been working as expected since I bought the car a few years ago. I've tried multiple other Apple phones and they have no issue, so I know it's not my car's software. I have called apple support and they gave me instructions on how to uninstall the Beta software, which has also not been successful. I entered a ticket for this issue on April 22nd, but haven't heard anything back. Anyone have suggestions on how I can get my CarPlay to work? or how to uninstall successfully from the Beta ios?
Posted
by
Post not yet marked as solved
1 Replies
49 Views
I've recently installed x code 15.3, but when I try and open simulator I am unable to select a device. When I navigate through the top menu a few item are active. One of these (active menu item) is New Simulator: I've tried to add a new simulator. Enter a name, selected a device type, but the drop down menu for OIS Version is not populating. I am leaving paired apple watch off. When I click create nothing happens. Open Simulator is an option, but there does not list any device when the arrow is clicked. Any suggestion? Thanks, Ed.
Posted
by
Post not yet marked as solved
1 Replies
58 Views
Hello can I have some help on how to fix the code. Please can you tell me what to adjust to make the code work.(it was from a YouTube video and have compared it as close as possible and still doesn't work. 'No exact matches in call to initialiser' error at the work 'Group {' import SwiftUI struct ContentView: View { @State var text: Array&lt;String&gt; = [] @State var showsheet = false @State var textitemtemp = "" var body: some View { NavigationView { Group { if text.count &lt;= 1 { Text("no items") } else { List { ForEach((1...text.count-1, id: \.self), {i in Text(text[i]) .contextMenu { Button(action: { text.remove(at: i) }, label: { Label ("Delete", systemImage: "delete.left") }) } } ) } .navigationTitle("Idea Book") .toolbar { Button(action: { showsheet.toggle() textitemtemp = "" }, label: { Image(systemName: "plus") } ) } .onChange(of: text) { save() load() } .onAppear() { save() load() } } .refreshable { save() load() } .sheet(isPresented: $showsheet) { NavigationView { List { TextField("Item", text: $textitemtemp) } .navigationTitle("Add an Idea") .toolbar { Button("add") { text.append(textitemtemp) showsheet.toggle() } } } } func save() -&gt; Void { let temp = text.joined(separator: "/[split]/") let key = UserDefaults.standard key.set(temp, forKey: "text") } func load() -&gt; Void { let key = UserDefaults.standard let temp = key.string(forKey: "text") ?? "" let temparray = temp.components(separatedBy:"/[split]/") text = temparray } } #if DEBUG ContentView() #endif } } }
Posted
by

TestFlight Public Links

Get Started

Pinned Posts

Categories

See all