Determining The Size Of A Resource Fork

21st April 2018 | Programming

With the release of macOS 10.13.4, Apple is now actively warning its users that any 32-bit software may not be fully compatible with future versions of the Macintosh operating system. This does not come as too much of a surprise since we recently underwent this forced transition from 32 to 64-bit software in iOS. 64-bit Intel processors, starting with the Core 2 Duo, have been available in Macs for well over a decade, but it is only now that Apple is "encouraging" that all modern software should be run as 64-bit. Fortunately, a casual perusal of what software is 64-bit shows that most software has already made the transition. Only older software and deprecated frameworks have not been updated. This includes even Apple's own QuickTime framework, which has been replaced by the newer AVFoundation framework.

From Apple's 64-Bit Transition Guide:

Beginning in OS X v10.5, most OS X APIs are available to 64-bit applications. Going forward, Apple plans to make new APIs 64-bit-compatible unless otherwise noted. However, not all existing 32-bit APIs are supported in 64-bit applications. ... In certain technology areas (Carbon particularly), a few APIs have been deprecated for 32-bit use beginning in OS X v10.5. Most of these APIs are not available in 64-bit applications.

Back in 2007, Apple notified developers that it would not be updating the Carbon framework to 64-bit. Considering that a few bits of Permanent Eraser still rely upon Carbon, I was concerned that Permanent Eraser would break in the future due to Carbon. The good news is that "Carbon" acts as more of an umbrella term, and some of its various functionality fall under other frameworks (such as Core Foundation or Core Services) which have been updated to 64-bit. However, in my research, I did come upon some older methods I've used have been deprecated over the years, so it was still a useful exercise to look for more modern alternatives.

I created a small example program which details several methods to determine if a select file contains a resource fork (or not), and if so, determine the size of the fork. Early methods depended on methods such as FSGetCatalogInfo, which was deprecated several years ago in OS X 10.8 Mountain Lion. Even if some of these deprecated methods still work on a 64-bit system, it is a good idea to update them with more modern methods to protect against the case that these methods might break in the future since they are no longer being maintained.

This coding example examines four different methods: getxattr, NSFileManager, getattrlist, and FSGetCatalogInfo


Edenwaith 4.0

25th March 2018 | Website

Today marks the unveiling of the fourth major iteration of the Edenwaith website. This is an important milestone for the Edenwaith website as it adopts a responsive design for both desktop and mobile web browsers and finally strips away the last remnants of ancient table-based layout. Some of the oldest pages of the previous iteration dated as far back as 2005. The website was far, far past due for a refresh.

The website has slowly evolved since the last major version by eschewing older design methods and adopting newer technologies such as HTML5 and CSS3. Revamping the entire website was a good opportunity to rethink the design, layout, and content, which included stripping some ancient content such as the tutorials and product pages for retired apps.

When I first began doing web design, it was not uncommon to see a footnote on a site recommending that the site looked best on a screen with a minimum resolution of 640x480 or 800x600. One of the biggest shifts in web development over the past nine years has been the rise of mobile web browsers on phones and tablets. A web designer can no longer assume that their content will be viewed on a large desktop monitor, but instead, will likely be viewed on a smaller display limited to several inches along the diagonal.

Adopting a responsive web design was the top priority for Edenwaith 4.0. But with all of the changes which have occurred with the rise of mobile devices, where does one start to learn how to adopt these new methodologies? It initially seems like designing for multiple screen sizes can be daunting and complicated, but it pretty much all boils down to one bit of useful CSS: @media screen and (max-width: 450px)

By being able to dynamically detect the size of the screen's viewport, it allows the page to resize and reposition its content, much in a similar manner to how Adaptive UI handles the interface for iOS. With some careful design, a site can look and work well with all sizes of screens. In learning responsive web design, I read through Ethan Marcotte's book Responsive Web Design and Interneting Is Hard's article on Responsive Design, topped with some neat CSS animation tricks from the W3Schools website.


EdenList 2.0 for iOS

17th March 2018 | EdenList

After a year of development, EdenList 2.0 for iOS has been released, featuring the following:

With this release, EdenList for iOS has become Edenwaith's second product to reach its second major version. Work initially began on version 1.2.4, but the archaic code dating back to 2009 was finally succumbing to all of the changes which have occurred with iOS development since EdenList was first started. Instead of continuing to fight with trying to coax the code to play nicely with the latest version of Xcode, I made the decision to scrap the code and start from scratch. Gone is Objective-C, manually managed memory, and XIB files to be replaced by Swift 4, ARC, Auto Layout, and Storyboards. The previous version of EdenList still supported iOS 6, which would not have worked well with Xcode 9, much less properly supporting Safe Areas to handle layout and display for the new iPhone X. With this rewrite, it allowed me to discard any legacy code and methods and adhere to more modern practices. EdenList for iOS now requires iOS 10. As of this writing, Apple reports that 65% of active devices are using iOS 11, another 28% are using iOS 10, which leaves a slim 7% of devices using an earlier version of iOS.

In addition to a new version of EdenList, its product page also sports a new look with the first major steps towards the retooling of the Edenwaith website. Once the entire Edenwaith website has been converted to the new style (which is responsive for different screen sizes), this will mark off two of the major tasks mentioned last year.

The Mobile Plateau Revisited

11th March 2018 | Apple

It has been nearly three years since I originally wrote about the Mobile Plateau, so enough time has passed that it is worth to take another glance at the technological world and see if things have continued at a flat rate of progress or if there have been any noticeable advancements.

Android Phones

In 2017, the company I was working for offered its employees either an Android phone or an iPhone 7. I already had an iPhone 6, so I was more interested in what Android phones were available. After browsing through Best Buy's offerings, I became somewhat dismayed how the majority of phones were essentially bland imitators of each other. Only the Huawei Mate 9 and the Google Pixel phones really stood out. If one liked the look and feel of the iPhone, but wanted it packaged around Android, then the Pixel was a wonderful offering.

Unfortunately, I later learned that the only Android phone we were actually offered was the Samsung Galaxy 8. Knowing how many unique problems Android developers tend to face with Samsung devices, I was not too interested. Sadly, for those developers, the Samsung Galaxy is the most popular line of Android phones today, so it is not a market they can ignore.


I waited three years between the iPhone 4S and the iPhone 6, and the upgrade was well worth it. It's been another three years, but the set of improvements from the iPhone 6 to the iPhone 8 are not groundbreaking, and if not for the introduction of the iPhone X, I would have easily been tempted to have waited another year. The iPhone 6 continues to be a great and reliable phone. When compared to iPhone 8, the only areas which I feel are truly lacking are the 3D Touch and second generation Touch ID, two features which were introduced in the iPhone 6S. The addition of inductive charging is a very welcome feature, especially with the removal of the 3.5mm headphone jack, so if one wants to listen to music and charge their phone at the same time, using a Qi charging pad is a useful option.

Listed below are the major features and changes for the last three generations of the iPhone.

On the hardware front, Apple and its competitors continue to refine and improve, but the hardware improvements from the iPhone 6 to the 8 are not as monumental as it was from the iPhone 4S to the 6. While the hardware has stagnated somewhat, it does provide a more stable field for software to build against. Perhaps one of the most exciting new developments in software is the introduction of augmented reality frameworks such as ARKit and ARCore. Any Apple device with an A9 chip or later can run ARKit applications, which means that millions of devices are capable of running augmented reality apps. ARCore is a very new framework for Android, but the number of devices which are compatible is quite limited, something which will hopefully be rectified in the near future.

The iPhone 8 was a decent improvement over the iPhone 7, and certainly more so than the 7 was over the 6S, but besides the addition of inductive charging, the 8 does not offer too much more than the iPhone 6S already possesses. Mostly more of the same. It's not broke, it has proven to be a great success for Apple, so why bother fixing what obviously still works?

Except this is technology, which sits still for no one. If all we did was make small iterations on the original model, we would still be working with punch cards and vacuum tubes. Which brings us to the elephant which has barely been mentioned in this article...

iPhone X

The iPhone has undergone several cosmetic changes since the original version. The materials have changed, the dimensions have been altered, but the basic appearance of the iPhone has essentially remained the same.

Enter the iPhone X — the iPhone for the next decade. The iPhone X boasts the following features:

On the inside, the iPhone X contains many of the same improvements as the iPhone 8 Plus. However, it's the outside where the real changes are apparent. Gone are the forehead and chin bezels, supplanted with a screen which covers nearly the entire front of the device. Also gone is the (no longer) ever-present Home button. Face ID replaces Touch ID, and swipe gestures replace other functionality which had been piled on top of the Home button.

My initial impression of these changes were not exactly warmly met. I like Touch ID. That glaring notch at the top of the iPhone X looks stupid. What was Apple thinking?! I was not alone in my knee-jerk reactions. I heavily considered getting an iPhone 8, which would be released before the iPhone X, plus it would have all the comfort and familiarity of my old phone.

If I did not develop iOS apps for a living, then I probably would have waited another year or gone with the iPhone 8. But the iPhone X introduced many changes, especially with its form factor and how developers would need to work with it, so this became one of the biggest selling points to get an iPhone X. This isn't about having the latest tech, but to be able to perform my job.

After working with the iPhone X for several weeks, these are my initial impressions:

Apple has made it clear that the iPhone X is the new direction they are taking with the iPhone for the foreseeable future. Had the iPhone X not been released alongside the iPhone 8, the technorati would have not bothered to suppress their collective yawn after another year of less than stellar changes. However, the iPhone X gave the press much to ponder and discuss. Already, other phone manufacturers are producing their own clone devices, mimicking Apple, which includes the obtrusive notch at the top of the phone. The notch sticks out like the proverbial sore thumb, but perhaps there will be a day that there will be a phone with a full display — no bevels, no notch — all screen.

Apple TV + Streaming Services

In my original piece, I lamented the lack of an update to the Apple TV, but this wish was soon granted several months later with the introduction of the 4th generation Apple TV and the new software platform of tvOS. My wish was for a platform that would replace traditional cable TV where the consumer can be more selective about what channels they want without having to pay increasing fees for the other 990 channels they don't want or need.

Apple TV takes a step in the right direction, but it is not alone in this space. In addition to other dedicated hardware options such as the Roku or Chromecast, there are other software offerings on pretty much any other device which can support Netflix, Hulu, YouTube, Twitch, PS Vue, or any of many other streaming content services.

Choice is good, but having too many choices can also be detrimental and overwhelming. There are so many streaming options, but none of them may have everything one might want. Netflix has older movies and TV shows, and Hulu has more recent episodes. If you want to watch a sports game, then you might need to subscribe to another service. If you add them all up, you might still end up with the same problem as having a cable provider — paying too much money for too much content.

I feel that this is a marginal improvement over cable, but it is not without its problems, especially regarding the fragmentation of content. It shall be interesting to see how things shake out in the next several years.


Three years ago, the Apple Watch had just been released, so it was certainly too early to get a proper gauge on how well the Apple Watch and competing wearables were going to perform. Three years later, the Apple Watch and its associated software of watchOS continue their yearly iterations while still trying to answer the question of What can we do with this thing?. The Apple Watch has leaned more in the direction of a fitness role, which is where its strongest competitors reside, such as the FitBit. The Apple Watch has not quite become the smash hit that the iPod or iPhone became, but it is not an unmitigated failure by any means, either. As the hardware and software continue to improve, the Apple Watch may eventually turn from an interesting gadget to a truly useful appliance that can stand on its own without needing to be tethered to a phone.

But what about the Android Wear Smartwatches? After the Apple Watch was announced, competitors quickly rushed to the scene, but none of them have gained a proper foothold in the wearables market, and many have stumbled and fallen away. Even the early smartwatch company Pebble became another technology casuality as it shut down in December 2016 and its intellectual properties were purchased by FitBit.


Time continues to march ever onwards, and so will the progress of technology, albeit not always at a rapid pace. The introduction of new hardware and software platforms provide for new sandboxes which to play in. The iPhone/iOS SDK has now been available for the past decade, and it has provided a fertile ground for new software development, the likes we also saw with the rise of microcomputers (PCs) and the Internet. The pace for new mobile software has not been abated, and a new disruptive platform has yet to truly rise up. watchOS and tvOS are new entrants into the Apple ecosystem, but neither one has a comparable user base that the iPhone has. Being that these are relatively new operating systems, there is much potential for them to grow during the next several years, but I see these as supplementary technologies when compared to the iPhone or even the Mac.

There are always new ideas cropping up, whether it is IoT or the latest "smart" gadget (smart speakers such as Amazon Echo, Google Home, or Apple's HomePod are the current fad in 2018). It's the products which prove to be truly useful and remain after the initial trend has come and gone which determine what becomes notable and what is relegated to a footnote. Let's check back in another three years to see how it all plays out.

On Controlling Massive View Controllers

6th March 2018 | Programming

When one is writing a computer program, one should write compact, logical, and modular components and veer away from source files which burgeon into unwieldy monoliths. In the iOS world, there are some who are turning away from the traditional Model-View-Controller (MVC) design pattern and are experimenting with other architectural patterns in the effort to correct the so-called "Massive View Controller" problem, where the ViewController class has become an unorganized heap of assorted bits. In a future post, I will discuss these alternative architectures in more depth, but for this post, I will detail several real world cases I've seen and how to fix them without having to resort to rearchitecting your entire app so the ViewController is not so massive.

There is no single "right way" for designing an application, but there certainly are some grave missteps which can be easily avoided so your code is better organized, cleaner, and easier to read, maintain and use.


The Category in Objective-C (otherwise known as Extensions in Swift) is an amazing feature which allows the programmer to extend the capabilities of an existing class, without having to create a subclass. Want to create a custom method for a color or font? Done. Want to extend the functionality of the string class? No problem. Not every programming language has this feature, but once you learn how to implement Categories, they are immensely useful.

In an old project I inherited, I came across a source file that was a little over a thousand lines of code.  However, nearly a quarter of that was taken up by just one lengthy method.  In this particular case, it was a method used to return a specific color, depending on the character passed in.  In this example, several options could be used to reduce the code bloat.  Instead of setting values for three different variables (assigning values for the red, green, and blue values), the UIColor can be created and returned for each case, which will cut down two-thirds of the code.

Next, since this is returning a UIColor, this entire method is better placed within a category class, which will also provide the benefit of code reusability so that any other parts of the app can make use of the same functionality.

The new UIColor category class (both header and implementation files) resulted in 225 lines of code after I slimmed down the original method by removing unnecessary braces in a giant switch statement.  Another pass could like reduce this even further, but for an initial pass, that was a nice improvement for half an hour's worth of work.

After further inspection of this project, I discovered that this same lengthy method was copied and used in six different areas of the app.  This is an obvious opportunity for code reuse.  By consolidating all of these instances of the same method into the category, I was able to strip out 1,500 lines of code from the other classes.

Remember — Don't Repeat Yourself. If you can consolidate your code into a centralized location, do so. This reduces problems of having to modify all instances of duplicate code with the added bonus of reducing the amount of code.

Designing UI: Interface Builder vs. Programmatically

Years ago I wrote an FTP client in Java. Constructing the interface was an arduous task of making a small edit, compiling, running, and then repeating the whole process over again. Fine tuning the look and feel of the application was not a quick process.

Enter Interface Builder and Project Builder (the precursor to Xcode). It was immediately apparent that Interface Builder was a godsend of a tool. I could rapidly prototype new UI designs with the drag and drop interface. No more endless edit-build-run cycles! Improvements in programming languages and their associated tools are often incremental, but Interface Builder was one of those rare massive jumps in programming productivity.

I love the visual aspect and designing beautiful interfaces, whether it is for the web, desktop, or mobile software. One of the things I love about macOS (née Mac OS X) is the beautiful interface laid on top of a UNIX core. It's a world of both beauty and brawn. So it is not a surprise that I enjoy creating interfaces using Interface Builder.

I was once knocked out of consideration for a programming job because I preferred to design my UI in Interface Builder instead of doing everything in code. Perhaps that company felt it was easier to review UI changes if they were in code or to avoid the horrendous storyboard conflicts which easily arrise when more than one person works on the same project. I get that, but I'm not so certain that this is ultimately a worthy tradeoff.

The same program mentioned earlier had been originally designed without any storyboards or XIBs. This means that all of the UI is set up in code, which takes up a sizable portion of each ViewController to configure the UI elements. When separating the view and the controller, it is perhaps best to design the UI in the tool which was intended for it.

If you are purposefully designing all of your UI programmatically inside your view controllers, there is a special place in hell for masochists like you. If designing UI programmatically is your thing and you can do it quickly and effectively, then knock yourself out.  Just keep in mind that other programmers may have to maintain your code someday. Designing UI in code is like the adage I heard when I was first learning C: Just because you can, doesn't mean you should.

This is not to say that there isn't a time and place for designing certain UI elements in code.  Interface Builder is easy and powerful, but it is not all inclusive with everything which can be done.  If you want to perform more complex UI operations, such as a wavy border or rotating a view to a specific angle, that will require the aid of code.

However, designing all of your UI elements in code takes both space and time to generate. In the effort to reduce unnecessary code bloat, use storyboards and XIBs as much as possible, and reserve the more complex effects to code. To extend the capabilities even further in Interface Builder, make use of IBInspectable and IBDesignable to add custom controls for your UI elements, such as buttons and views.

In Ryan Poolos' 360iDev presentation Life Beyond Storyboards: Building Your UI In Code, he shows how it is possible to design an iOS app without the aid of storyboards, but he does not propose an effective reason why someone would want to do this fulltime. He talks about the How, but not the Why. This echoes a line from the novel 1984: I understand HOW: I do not understand WHY.

Auto Layout certainly has its benefits, especially when dealing with variable size devices, but what it makes up in flexibility it sacrifices in brevity compared to the old method of using CGRects to size and place views. What might have been a single line of code can easily quadruple (or more) in size by implementing Auto Layout constraints. Whether or not if you like Auto Layout, it's the direction Apple has been taking for years, and it will only continue as the variety of device sizes continues to expand. Fortunately, most of the complexity of setting up the interface is easily handled by Interface Builder.

While I espouse the use of storyboards, they can also be abused in a similar manner where too much is dumped into one file, resulting in their own "massive" problem. I've worked on some projects where every view was thrown into a single storyboard, which could quickly bring Xcode to its knees when trying to open the file or make any type of modifications. Much as with code, storyboards need to be divided into logical sections so no one storyboard is trying to do too much. Storyboards can be finicky and are a nightmare to resolve when doing merge conflicts, so it is best if storyboards are kept small enough that no more than one developer needs to actively work on any one storyboard at a time.


None of these approaches need to be all of nothing. Use the best tool for the job. Reuse code so you aren't unnecessarily repeating yourself. Just keep in mind that the best code is no code at all. The less code there is, the less there is to maintain, and the less chance there is for bugs. By maintaining good organization and programming practices, you should be able to keep the size of your ViewControllers to a manageable size.


Permanent Eraser 2.7.3

21st January 2018 | Permanent Eraser

Permanent Eraser 2.7.3 is now available from this website and the Mac App Store (MAS). The MAS version's release was delayed for a few days as Apple's review process was not available for a week during the holidays. The following are the changes in this version:

Since version 2.7.2 was released last November, Permanent Eraser was also updated so it could be approved for the Mac App Store. The previous version in MAS was 2.5.3, which encountered a severe issue when working with macOS Sierra and later. This issue had been fixed years earlier in version 2.6.0, but since the MAS version of Permanent Eraser had not been updated since then, that version was essentially broken and useless on newer versions of macOS.

While working on the MAS update for Permanent Eraser, I encountered a couple of additional areas which needed to be updated. Since the major planned feature for version 2.8.0 will not be accepted for the Mac App Store, 2.7.3 was created to get in these minor updates for both the website and MAS versions. Permanent Eraser 2.8.0 is planned for release later in 2018.

Edenwaith 2018

1st January 2018 | Edenwaith

Many of the plans for Edenwaith in 2018 are a continuation of what was started in 2017. EdenList 2.0, a complete rewrite of this app, is still in the works. Permanent Eraser 2.7.3 was released a few weeks ago (the Mac App Store version is still waiting for approval from Apple), and Permanent Eraser 2.8.0 is also in the works. Eventually the entire Edenwaith website will be redesigned with a new appearance, better support for mobile devices, and a reorganization of the content. Some old material will finally be archived or removed, and other pages will be simplified (mostly for historical purposes for retired projects).

Working With ARKit

22nd December 2017 | Programming

Augmented Reality (AR) has been around for a number of years, but it has only been in the past year that AR has finally been making some inroads into the mainstream, starting with the mobile game Pokémon GO.

Now Apple is opening up the capabilities of AR to developers and millions of AR-ready iOS devices with the introduction of the new ARKit framework. Developers have quickly embraced the new capabilities provided by ARKit by developing useful utilities to games enhanced by the AR experience.

There are numerous articles currently available about how to initially set up an ARKit project, so this post will focus more on specific topics when developing with ARKit and SceneKit.

This article makes use of a sample AR demo project which detects a plane, loads in a 3D model of a dragon, places the model on the plane, and then animates the dragon when it has been tapped.

Plane Detection

One of the key aspects to AR is for the device to be able to inspect its environment so it can learn how to interact with its surroundings, especially when trying to place virtual objects on a flat surface. Since ARKit does not come with a Hervé Villechaize module, your AR app will need to implement the ARSCNViewDelegate to help find "da plane".

Plane detection is initially disabled, so it needs to be set, otherwise the device will not look for available surfaces. To enable plane detection, ensure that the ARWorldTrackingConfiguration object's planeDetection property has been set to .horizontal.

// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
configuration.isLightEstimationEnabled = true

// Run the view's session

ARKit currently only supports the detection of horizontal planes, but there is the potential of vertical plane detection in a future version of iOS.

Plane detection is far from a precise science at this point, and it usually takes at least several seconds to detect a suitable plane. You might need to move your iOS device around so it gains knowledge of its environment so it can better estimate the distance to surrounding objects.

To aid in detecting a plane, set the sceneView.debugOptions = [ ARSCNDebugOptions.showFeaturePoints ] to provide the yellow dots, which indicates that the camera is trying to detect reference points in the environment. Objects which are shiny or lack any proper definition make it difficult for the device to obtain a decent reference point and to be able to distinguish unique points in the environment. Areas with poor lighting conditions can also compound these problems. If you are not seeing many yellow feature points, slowly move around the area and point the device's camera at different objects to help determine which surfaces can be identified.

Once a plane is detected, the ARSCNViewDelegate method renderer(_:didAdd:for:) is called. In this example, we check if the argument anchor is an ARPlaneAnchor, and if so, we then save this as our planeAnchor, which will be used as the base where to place the 3D model.

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
    if self.planeAnchor == nil {
        self.planeAnchor = planeAnchor
        self.loadDragonScene(with: planeAnchor)

3D Models in SceneKit

ARKit integrates well with SpriteKit and SceneKit, Apple's respective 2D and 3D frameworks, which have been available for macOS and iOS for a number of years. Due to these years of development, Apple already has mature platforms which can be quickly hooked into an AR project to add 2D or 3D virtual elements.

There's a wide variety of 3D model formats available, but for this project, we are working with COLLADA (.dae) files. COLLADA is an open 3D format which many 3D modeling apps support. It was originally intended as an interchange format between competing 3D standards, but it has gained the support of a number of software tools, game engines and applications. COLLADA is also well supported in the Apple ecosystem, including the macOS Finder, Preview, and Xcode.

If your model has image textures which are referenced in the model file, then copy the .dae file and its associated image assets into the art.scnassets folder. One of the advantages of COLLADA being an open XML format is that the model file can be opened and edited with a standard text editor, which can be particularly useful if the image paths were improperly referenced (absolute path versus a relative path).

let dragonScene = SCNScene(named: "art.scnassets/Dragon_Baked_Actions_fbx_6.dae")!
let position = anchor.transform

// Iterate through all of the nodes and add them to the dragonNode object
for childNode in dragonScene.rootNode.childNodes {

// Scale and position the node
let scale:Float = 0.01
self.dragonNode.scale = SCNVector3(x: scale, y: scale, z: scale)
self.dragonNode.position = SCNVector3(x: position.columns.3.x, y: position.columns.3.y, z: position.columns.3.z)

// Add the dragonNode to the scene
self.dragonNode.isPaused = true // Initially pause any animations

Clearing Out Old Scenes

Loading in 3D models and the associated textures can be extremely memory intensive, so it is essential that any unused resources are properly released.

When removing a child node from a scene, it is not good enough to just call the node's removeFromParentNode() method. Any material objects from the node's geometry also need to be set to nil before removing the node from it's parent.

func clearScene() {

    sceneView.scene.rootNode.enumerateChildNodes { (node, stop) in
        // Free up memory when removing the node by removing any textures
        node.geometry?.firstMaterial?.normal.contents = nil
        node.geometry?.firstMaterial?.diffuse.contents = nil

Hit Detection

Being able to add objects to a scene is a key element for creating an augmented experience, but it does not provide much usefulness if one cannot interact with the environment. For this demonstration, tapping on the dragon will toggle its animation.

Upon tapping the screen, the sceneView will perform a hit test by extending a ray from where the screen was touched and will return an array of all of the objects which intersected the ray. The first object in the array is selected, which represents the object closest to the camera.

Since a 3D object might be comprised of multiple smaller nodes, the selected node might be a child node of a larger object. To check if the dragon model was tapped, the selected node's parent node is compared against the dragon node. If so, this will then call a method to toggle the model's animation.

func registerTapRecognizer() {
    let tapGestureRecognizer =  UITapGestureRecognizer (target:self ,action : #selector (screenTapped))

@objc func screenTapped(tapRecognizer: UITapGestureRecognizer) {
    let tappedLocation = tapRecognizer.location(in: self.sceneView)
    let hitResults = self.sceneView.hitTest(tappedLocation, options: [:])
    if hitResults.count > 0 {
        guard let firstHitResult = hitResults.first else {
        if self.dragonNode == firstHitResult.node.parent {


Not all 3D models are static entities and some include animation effects. There are a variety of ways to start and stop animations, whether it is for a particular object or for the entire scene.

To toggle all animations for the scene requires just a single line of code:

self.sceneView.scene.isPaused = !self.sceneView.scene.isPaused

Toggling the animations for just a single node has similar functionality:

self.dragonNode.isPaused = !self.dragonNode.isPaused

These are simple methods to toggle the overall animation, but if you need more fine-grained control of the animations, then you will need to iterate through your SCNNode and modify each of the embedded animations.


ARKit is just getting started, so there is still plenty of low-hanging fruit available to pick to improve the AR experience. Some of the current limitations are areas which can be improved upon with succeeding iterations of future hardware and software, but some issues will likely remain to be complex problems with no perfect solutions.


Augmented Reality is in its nascent stages of development, which will provide many new and interesting ways for us to be able to use our mobile devices to interact with the world, whether it is for information, utility, or fun.

As the possibilities of what can be achieved with AR are explored further, more and more developers will delve into this new realm and see what they can create. Documentation and blog posts are invaluable in helping to reduce the initial learning curve and avoid some of the more troublesome hurtles that others have previously encountered, as this post aimed to accomplish by providing some tips on how to implement several common tasks when working with ARKit.

January 2018 Update

February 2018 Update

With the announcement of the upcoming ARKit 1.5 framework (currently available in the beta version of iOS 11.3) will be able to map to vertical surfaces, fixing one of the shortcomings in the original release of the framework.

Permanent Eraser 2.7.2 for Mac App Store

10th December 2017 | Permanent Eraser

For the first time in five years, Permanent Eraser has been updated on the Mac App Store. The major reason that Permanent Eraser has not been updated for the Mac App Store (MAS) for years is due to a rejection which occurred back with version 2.6.0, where the app was not allowed to add the Erase plug-in, which copies an Automator service to ~/Library/Services/. Since this is one of my favorite features of Permanent Eraser, I did not bother trying to update Permanent Eraser for MAS. The odd thing about this rejection, is that the version available on the store (version 2.5.3) had the same functionality which was the reason version 2.6.0 was rejected. Quite odd.

When macOS Sierra came out in 2016, this broke the MAS version of Permanent Eraser, since it relies upon the srm utility, which was no longer provided with Sierra. Permanent Eraser 2.6.0 and later contains its own custom version of srm, which fixes this problem. Since Permanent Eraser 2.5.3 was effectively rendered useless on the more modern versions of macOS, I decided to try and update it again for MAS, even if that required making a couple of sacrifices by limiting some of the functionality. A limited version of Permanent Eraser is better than a completely non-functional version. The other option would have been removing Permanent Eraser from MAS.

The first order of business was to determine what functionality needed to be removed to make Permanent Eraser compliant for the Mac App Store. Fortunately, there wasn't too much which needed to be excluded, primarily the plug-ins and the software update mechanism. Since MAS already offers its own capability to update the software, that was a non-issue. I'm hoping in a future incarnation of Permanent Eraser that I'll be able to directly integrate the plug-in service into the app, thus avoiding the issue of needing to manually installing the plug-in.

Once I had removed the necessary pieces from the app, that was only the beginning. Since the MAS version of Permanent Eraser hadn't been built for several years, it did not even initially compile, which required some tweaking of the project to get that to work again. Since this app is still built using Xcode 3 (so it can build as a Universal Binary for PowerPC and Intel), I needed to use the Application Loader app. However, one cannot just upload the app by itself. The app needs to be packaged first using the productbuild command line tool. In addition to the plethora of other Apple certificates I've generated for Mac and iOS apps, I also needed to generate a Mac Developer Installer certificate to properly sign and build the package. To package the app, I used the following command:

productbuild --component "Permanent" /Applications --sign "3rd Party Mac Developer Installer: Developer Name (12AB34567C)" \
--product "Permanent" "Permanent Eraser.pkg"

I was now able to upload the app, but quickly received an e-mail reporting a problem with the app:

Missing required icon - The application bundle does not contain an icon in ICNS format, containing both a 512x512 and a 512x512@2x image. For further assistance, see the Apple Human Interface Guidelines at

Since the current version of Permanent Eraser still supports Leopard, I normally do not include the 1024x1024 app icon, which causes problems in Leopard. But since all apps on MAS require Snow Leopard or later, this is not an issue. After doing some research, it appears that the best tools to generate the older .icns file is to use Icon Composer 2.2 (included with Xcode 4.3.3) or the command-line utility iconutil. If Icon Composer 2.2 is used, it must be used under Lion to generate the icon properly with the 1024x1024 image. I initially tried running Icon Composer 2.2 under Snow Leopard, but the generated icon did not include the 1024x1024 image. Running the app under Lion saved it properly.

Another alternative is to create an icon set folder with the required images and then convert it into an icon file. Add the following images to a new folder with the .iconset extension:

Next, run the following command from the Terminal:

iconutil -c icns -o appicon.icns appicon.iconset

With the proper icon in place, I tried uploading again. The next round of errors was due to an "invalid signature". I found this odd since I had already signed the app, yet MAS was reporting an issue. After digging around further, it appeared that I had used the incorrect certificate to sign the MAS version of the app. Yet another grey hair due to code signing issues. I initially used the certificate which started with "Mac Developer:", which is similar to what I had originally used years ago. The correct certificate is the one which starts with ""3rd Party Mac Developer Application:".

After climbing over these obstacles, Permanent Eraser was finally approved and is now up-to-date on the Mac App Store. Despite some of these unexpected issues, it did result in a learning process where I discovered a couple new things during the journey.


Permanent Eraser 2.7.2

29th November 2017 | Permanent Eraser

Ydych chi'n siarad Cymraeg? Permanent Eraser does! Ar ben hynny mae'r app ar gael yn Gymraeg rwan! (The app is also available in Welsh now!)

Permanent Eraser 2.7.2, released on 17 November 2017, features a new Welsh localization and an updated Traditional Chinese localization. Many thanks to Applingua and Fangzhou for their incredible translation work.

This version finally introduces a feature I've been wanting to add for a long time — the ability to erase free space. This is currently available as the new Automator Action Erase Free Space, which joins the two previous Automator actions, which have also been updated in Permanent Eraser 2.7.2.

The ability to erase free space from Disk Utility has been removed in more recent versions of macOS, so if you have a hard drive which you want to wipe the free space, using the Erase Free Space Automator action is a solution.

This is just the first step in erasing free space. I'm hoping to be able to be able to integrate it directly into Permanent Eraser in a future version.

The full version history of what's new in Permanent Eraser 2.7.2:

Determining If A User Used An Earlier Version Of An iOS App

22nd November 2017 | Programming

The popular writing app Ulysses recently moved to a subscription payment model and they extensively explained their reasoning for the transition. Switching to a subscription model is rarely a popular move, which tends to incite the masses to pull out their torches and pitchforks.

Max Seelemann, development lead for Ulysses, does an excellent job in outlining the reasons for moving over to subscription in an attempt to assuage those people who bothered to read the article before they start angrily gnashing their teeth. One thing a company does not want to do when changing their pricing model (whether it be going from paid to subscription or paid to freemium) is to anger the current customers with this change.

Ideally, those early customers should be rewarded, and they should be enticed to remain loyal customers. Punishing them with a subscription fee on top of what they had previously paid for will not win many adoring fans. If you are changing your pricing model for your app, you should check if this was a customer before the change.

So how do you determine if someone had used an earlier version of an iOS app? We'll take a look at several different approaches below.

Check the build number in the receipt

Every app downloaded from the iOS or Mac App Store has a receipt, which contains a variety of information such as the bundle identifier, any in-app purchases, the subscription expiration date, the original app version, and more. The item we are interested in is the original app version. For iOS, this is the build number (CFBundleVersion), which is not the version number of the app (e.g. 2.1.3). On macOS, the receipt returns the CFBundleShortVersionString, instead, which is the version number of the app. If the build number for each release of your iOS app is unique, this is a valid solution to determine when a user first purchased the app. However, if the build numbers are not unique (such as the build numbers are reset back to 1 after each new release), then this can become quite problematic. On macOS, the receipt will contain the app's version number (e.g. 2.1.3), which is far more straightforward in determining which version of the app was initially purchased.

As long as build number scheme has been consistent and continues to increase and each version is unique, then this is a reliable method to compare the check if the user had an early version of the app before the pricing switch.

Check by the earliest date in any IAP

If your app offers in-app purchases (IAP), iterate through them and search for the oldest item. However, if your app does not offer IAP, this is not a viable option.

On-line accounts

If available in the app, if there is a login process and proper records stored on a server, when the user logs in to the app, the server could return information on when the user first registered. This would be dependent upon if the login process had recorded such information and could return it, as well. There is also the consideration of how an account was first created, whether it was through the iOS app, a website, or via some other method (another app, in-store sign up, etc.). This option is geared more towards a larger company which may have a larger resources and can afford to have multiple channels. This may not apply to all apps.

Roll your own method

These first three approaches can work if the app is reinstalled or downloaded onto another device. If the user has been using the app on the same device for awhile, the next several approaches can be used.

The app can save previous versions of the app to the device (either to the user defaults or a database), which can be checked against the current version of the app. Unfortunately, this will not work so well if the user has deleted the app (which deletes the user data, as well) and then reinstalls the app. Same applies if the app was installed on a new device, and the old local data may not exist or get transferred.

One method to be able to check if the app had been installed on that particular device at one time is to save some data in the Keychain, instead of the user defaults, which will persist even if the original app has been deleted.

Check creation date of the app's documentation folder

A clever approach to determine when the app was installed on the particular device is to check the creation date for the app's documents folder. The same problems arises, though, if the app has been newly installed or was deleted and then reinstalled on the device. Otherwise, this is a fairly reliable method to determine when the app was installed, but it should be used as the final check to determine how long the user has been using this app.


NSError *error = nil;
NSURL *documentsFolderURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSDate *installDate = [[[NSFileManager defaultManager] attributesOfItemAtPath:documentsFolderURL.path error:&error] objectForKey:NSFileCreationDate];

if (error != nil) {
	NSLog(@"Error retrieving install date: %@", [error localizedDescription]);

Swift 3:

let documentsFolderURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
let installDate = (try! FileManager.default.attributesOfItem(atPath: documentsFolderURL.path)[FileAttributeKey.creationDate])


33 RPM's Future

23rd September 2017 | 33 RPM

During Apple's Platform State of the Union keynote, Apple revealed that macOS High Sierra would be the "last macOS release to support 32-bit apps without compromises." Considering that Apple has been warning us for a good year or more that 32-bit apps were going to be dropped in iOS, this does not come as too much of a surprise. I've had a few people inquire about a 64-bit version of 33 RPM being created. Even though 33 RPM has not been updated in nearly five years, this seemed like a simple enough request. Another Edenwaith app, Permanent Eraser, is an older app which is built for both 32 and 64 bit support, so I was hoping that all I would need to do is adjust a couple of settings and recompile 33 RPM.

Or so I hoped.

Returning to an old project was a good opportunity to perform some clean up and rethink some things with this app. I did not want to spend too much time on what was intended to be a minor update, otherwise I might tumble deep down the rabbit hole of endless features. A couple of ideas did seem plausible such as establishing a new code repository, code signing the app, fixing a few bugs which have crept up in newer versions of macOS, add TouchBar support, and compile the app with 64-bit support.

Considering that 33 RPM began its development in earnest in 2005, it was originally developed with a much earlier version of Xcode. The app was last updated in 2012, which still used Xcode 3 so it could be compiled as a Universal Binary for both PowerPC and Intel processors. Since most of the new ideas for the next version would be mostly keyed for more modern systems, I looked into compiling the app using Xcode 9 on macOS Sierra. Despite a 6 version difference between the original project and the current version of Xcode, it didn't act up too much upon trying to get the project to compile (in comparison to an old Project Builder project which would require finding an old version of Xcode to migrate it to the newer Xcode project format). Once I tried to compile the code, I first encountered the following error:

"QTKit/QTKit.h" file not found

Well.....huh. That's odd. 33 RPM is highly dependent upon QuickTime for a majority of its functionality, so why wouldn't the QTKit framework be found? The QTKit documentation page answers that question:

QuickTime Kit was deprecated in OS X v10.9. Use the AVFoundation framework instead.

Not only had QTKit been deprecated, but the framework was removed from Xcode 8. Fortunately, there is a workaround by extracting the MacOSX10.11.sdk from Xcode 7 and placing it in Xcode 8 or 9's Contents/Developer/Platforms/MacOSX.platform/Developer/SDKS/ folder.

After getting the MacOSX10.11.sdk put in place, it resolved the issue where the QTKit framework was not found, but it resulted in a barrage of 68 new errors, where many of the common QuickTime types (Movie, QTPropertyValueType, kQTMetaDataItemPropertyID_Key, etc.) could not be identified. When I went back to Xcode 3 and tried to compile the app with 64-bit support, it resulted in the same type of errors, so this seemed to indicate an issue with the 64-bit support. If I reverted the project back to 32-bit, it compiled without any issues.

Even with the older SDK in place, an app relying on QuickTime was not going to compile with 64-bit support. Apple has a Transitioning QTKit Code to AV Foundation guide, which recommends using the nm (display name list - symbol table) command line utility to get a list of the QuickTime APIs used within an app.

$ nm -m /Applications/33\\ RPM | egrep "QuickTime|QTKit"
         (undefined [lazy bound]) external .objc_class_name_QTMovie (from QTKit)
         (undefined [lazy bound]) external .objc_class_name_QTMovieView (from QTKit)
         (undefined [lazy bound]) external _AttachMovieToCurrentThread (from QuickTime)
         (undefined [lazy bound]) external _DetachMovieFromCurrentThread (from QuickTime)
         (undefined [lazy bound]) external _DisposeMovie (from QuickTime)
         (undefined [lazy bound]) external _EnterMoviesOnThread (from QuickTime)
         (undefined [lazy bound]) external _ExitMoviesOnThread (from QuickTime)
         (undefined [lazy bound]) external _GetMediaSampleDescription (from QuickTime)
         (undefined [lazy bound]) external _GetMovieIndTrackType (from QuickTime)
         (undefined [lazy bound]) external _GetMovieTimeBase (from QuickTime)
         (undefined [lazy bound]) external _GetMovieTimeScale (from QuickTime)
         (undefined [lazy bound]) external _GetMovieTrackCount (from QuickTime)
         (undefined [lazy bound]) external _GetTrackDuration (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionBegin (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionEnd (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionFillBuffer (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionSetProperty (from QuickTime)
         (undefined [lazy bound]) external _MovieExportDoUserDialog (from QuickTime)
         (undefined [lazy bound]) external _MovieExportGetSettingsAsAtomContainer (from QuickTime)
         (undefined [lazy bound]) external _NewMovieFromHandle (from QuickTime)
         (undefined [lazy bound]) external _PutMovieIntoHandle (from QuickTime)
         (undefined [lazy bound]) external _QTCopyMovieMetaData (from QuickTime)
         (undefined [lazy bound]) external _QTGetComponentProperty (from QuickTime)
         (undefined [lazy bound]) external _QTGetComponentPropertyInfo (from QuickTime)
         (undefined [lazy bound]) external _QTGetMovieProperty (from QuickTime)
         (undefined [lazy bound]) external _QTGetMoviePropertyInfo (from QuickTime)
         (undefined [lazy bound]) external _QTGetTimeInterval (from QTKit)
         (undefined [lazy bound]) external _QTMakeTime (from QTKit)
         (undefined [lazy bound]) external _QTMakeTimeRange (from QTKit)
         (undefined) external _QTMediaTypeMPEG (from QTKit)
         (undefined) external _QTMediaTypeVideo (from QTKit)
         (undefined [lazy bound]) external _QTMetaDataGetItemCountWithKey (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataGetItemProperty (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataGetItemPropertyInfo (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataGetNextItem (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataRelease (from QuickTime)
         (undefined) external _QTMovieDataSizeAttribute (from QTKit)
         (undefined) external _QTMovieDidEndNotification (from QTKit)
         (undefined) external _QTMovieDisplayNameAttribute (from QTKit)
         (undefined) external _QTMovieEditableAttribute (from QTKit)
         (undefined) external _QTMovieExport (from QTKit)
         (undefined) external _QTMovieExportManufacturer (from QTKit)
         (undefined) external _QTMovieExportSettings (from QTKit)
         (undefined) external _QTMovieExportType (from QTKit)
         (undefined) external _QTMovieFileNameAttribute (from QTKit)
         (undefined) external _QTMovieLoadStateAttribute (from QTKit)
         (undefined) external _QTMovieLoopsAttribute (from QTKit)
         (undefined) external _QTMovieOpenAsyncOKAttribute (from QTKit)
         (undefined) external _QTMoviePlaysSelectionOnlyAttribute (from QTKit)
         (undefined) external _QTMovieRateAttribute (from QTKit)
         (undefined) external _QTMovieTimeScaleAttribute (from QTKit)
         (undefined) external _QTMovieURLAttribute (from QTKit)
         (undefined) external _QTMovieVolumeAttribute (from QTKit)
         (undefined [lazy bound]) external _QTSetComponentProperty (from QuickTime)
         (undefined [lazy bound]) external _QTSetMovieProperty (from QuickTime)
         (undefined [lazy bound]) external _QTSoundDescriptionGetProperty (from QuickTime)
         (undefined [lazy bound]) external _SCRequestImageSettings (from QuickTime)
         (undefined [lazy bound]) external .objc_class_name_QTMovie (from QTKit)
         (undefined [lazy bound]) external .objc_class_name_QTMovieView (from QTKit)
         (undefined [lazy bound]) external _AttachMovieToCurrentThread (from QuickTime)
         (undefined [lazy bound]) external _DetachMovieFromCurrentThread (from QuickTime)
         (undefined [lazy bound]) external _DisposeMovie (from QuickTime)
         (undefined [lazy bound]) external _EnterMoviesOnThread (from QuickTime)
         (undefined [lazy bound]) external _ExitMoviesOnThread (from QuickTime)
         (undefined [lazy bound]) external _GetMediaSampleDescription (from QuickTime)
         (undefined [lazy bound]) external _GetMovieIndTrackType (from QuickTime)
         (undefined [lazy bound]) external _GetMovieTimeBase (from QuickTime)
         (undefined [lazy bound]) external _GetMovieTimeScale (from QuickTime)
         (undefined [lazy bound]) external _GetMovieTrackCount (from QuickTime)
         (undefined [lazy bound]) external _GetTrackDuration (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionBegin (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionEnd (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionFillBuffer (from QuickTime)
         (undefined [lazy bound]) external _MovieAudioExtractionSetProperty (from QuickTime)
         (undefined [lazy bound]) external _MovieExportDoUserDialog (from QuickTime)
         (undefined [lazy bound]) external _MovieExportGetSettingsAsAtomContainer (from QuickTime)
         (undefined [lazy bound]) external _NewMovieFromHandle (from QuickTime)
         (undefined [lazy bound]) external _PutMovieIntoHandle (from QuickTime)
         (undefined [lazy bound]) external _QTCopyMovieMetaData (from QuickTime)
         (undefined [lazy bound]) external _QTGetComponentProperty (from QuickTime)
         (undefined [lazy bound]) external _QTGetComponentPropertyInfo (from QuickTime)
         (undefined [lazy bound]) external _QTGetMovieProperty (from QuickTime)
         (undefined [lazy bound]) external _QTGetMoviePropertyInfo (from QuickTime)
         (undefined [lazy bound]) external _QTGetTimeInterval (from QTKit)
         (undefined [lazy bound]) external _QTMakeTime (from QTKit)
         (undefined [lazy bound]) external _QTMakeTimeRange (from QTKit)
         (undefined) external _QTMediaTypeMPEG (from QTKit)
         (undefined) external _QTMediaTypeVideo (from QTKit)
         (undefined [lazy bound]) external _QTMetaDataGetItemCountWithKey (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataGetItemProperty (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataGetItemPropertyInfo (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataGetNextItem (from QuickTime)
         (undefined [lazy bound]) external _QTMetaDataRelease (from QuickTime)
         (undefined) external _QTMovieDataSizeAttribute (from QTKit)
         (undefined) external _QTMovieDidEndNotification (from QTKit)
         (undefined) external _QTMovieDisplayNameAttribute (from QTKit)
         (undefined) external _QTMovieEditableAttribute (from QTKit)
         (undefined) external _QTMovieExport (from QTKit)
         (undefined) external _QTMovieExportManufacturer (from QTKit)
         (undefined) external _QTMovieExportSettings (from QTKit)
         (undefined) external _QTMovieExportType (from QTKit)
         (undefined) external _QTMovieFileNameAttribute (from QTKit)
         (undefined) external _QTMovieLoadStateAttribute (from QTKit)
         (undefined) external _QTMovieLoopsAttribute (from QTKit)
         (undefined) external _QTMovieOpenAsyncOKAttribute (from QTKit)
         (undefined) external _QTMoviePlaysSelectionOnlyAttribute (from QTKit)
         (undefined) external _QTMovieRateAttribute (from QTKit)
         (undefined) external _QTMovieTimeScaleAttribute (from QTKit)
         (undefined) external _QTMovieURLAttribute (from QTKit)
         (undefined) external _QTMovieVolumeAttribute (from QTKit)
         (undefined [lazy bound]) external _QTSetComponentProperty (from QuickTime)
         (undefined [lazy bound]) external _QTSetMovieProperty (from QuickTime)
         (undefined [lazy bound]) external _QTSoundDescriptionGetProperty (from QuickTime)
         (undefined [lazy bound]) external _SCRequestImageSettings (from QuickTime)

With these problems in mind, where does this leave 33 RPM? With the deprecation of QuickTime and its lack of proper 64-bit support, this makes it impossible for 33 RPM to be a 64-bit app in its current state. The most obvious path is to transition the app from using QTKit to AV Foundation. If I do take this approach, it would also open up the possibility of also porting this app to iOS, which is something I've considered over the years, especially considering how abysmal, unfriendly, and ugly the stock iOS Music app has become over the past few years. This approach would likely take a fair amount of time, effectively rewriting the entire current app. Fortunately, we have at least another year before Apple really starts enforcing their new 64-bit only dictum. Apple also said, "In the next major release after High Sierra, we're going to aggressively start warning users if apps are not compatible for 64-bit.", so 32-bit apps may or may not work properly in 2018 and beyond, or we might see the coaxing messages we have seen on iOS for the past year or two which has warned users that older 32-bit iOS apps will not be supported in the future.

Had QuickTime not been deprecated and eschewed proper 64-bit support, I would have gladly made an update to 33 RPM so it would run on a future macOS without any additional compromises. However, it will likely take a good amount of time and effort to update 33 RPM to use the more modern AV Foundation framework. I will continue to look into this and determine how difficult it will actually be to update this app for more modern Apple platforms. But for now, continue to enjoy using 33 RPM and thanks to all who have supported and used 33 RPM over the past nine years.


Installing an APK Onto an Android Device

31st August 2017 | Programming

Several years ago I was doing some Android development. One of the things I appreciated the most about Android was the relative simplicity of being able to install apps to a device, unlike iOS which requires jumping through numerous hoops (although it is getting better with Xcode 9).

As a refresher for myself (and good documentation in the case I need to repeat these steps sometime in the future), here are the steps to take to install an APK app bundle onto an Android device.

  1. Install the platform tools (such as adb). Download the platform tools from Google's website.
  2. Unzip the downloaded file.
  3. On the Mac, copy any wanted utilities to the /usr/local/bin folder (create the folder if necessary). For this purpose, adb needs to be copied over.
  4. On an Android device, make sure the Developer mode is enabled. If not, go to Settings > About Phone/Tablet, then tap on the Build Number seven times to enable the Developer mode (otherwise, adb won't be able to see the device).
  5. Ensure that USB Debugging is also enabled in the Developer Options
  6. Verify that the device is visible with the command: adb devices
  7. To install the apk file onto the device: adb install -r path/to/apk_file
  8. If there are multiple devices or emulators connected, the APK can be installed to a specific device: adb -s FA3C3S903152 install -r path/to/apk_file
  9. If needed, uninstall the app with the command: adb uninstall com.example.appname

Note: If the app you try and load an app which requires a higher API version than what is on the phone, you'll see an error like the following:

$ adb install -r example.apk 
example.apk: 1 file pushed. 3.1 MB/s (8255173 bytes in 2.560s)
	pkg: /data/local/tmp/example.apk


Quest For Glory V and Mac OS 9: Rite of Passage

10th August 2017 | Programming

Each year I play through at least one of the five Quest For Glory computer games, and this year it was time for Quest For Glory V. Whereas the first four games in the series can be played under DOSBox, QFG5 was released in 1998, which put it in the era of Windows 9X and the "Classic" era of Mac OS. Due to the hardware and software changes made in the past 19 years, QFG5 cannot be played natively on modern Macs. I've finally setup Sheepshaver on my main Mac, however I haven't experimented with it much, but it might be worth testing further in the future to determine if it can be a reliable replacement for aging hardware. Instead of using an emulator, I pulled out my Gigabit PowerMac G4, which can run every version of Mac OS from 9.0.4 through 10.4.11. This amazing machine was my main workhorse for seven years before I moved over to a new iMac. Sadly, time is starting to catch up with the G4, and I encountered a bevy of crashes, related both to dying hardware and the unreliability of a 90s-era operating system.

Using a computing system of yesteryear invokes sweet nostalgia, but that quickly wears off when one is rudely reminded of the shortcomings which have long been remedied with modern systems. Mac OS 9 lacked protected memory and preemptive multitasking, so one errant program could take down the entire system. Between the game freezing, the computer locking up, an entire boot volume gone AWOL and other hardware issues, completing QFG5 became much more difficult than normal by trying to fix and maintain the PowerMac.

After the first of several frustrating crashes, the main Macintosh HD volume refused to mount. After performing a scan with Disk Utility, it reported the following error:

invalid key length 4, 1579

The issue refused to be repaired by Disk Utility. Fortunately, I had a copy of DiskWarrior 3 on a Mac OS X partition, and it was able to rebuild the Macintosh HD. For good measure, I blessed the Mac OS 9 system folder so it was bootable. Running the following command from the Mac OS X Terminal will bless the specified Mac OS 9 system folder so it will be bootable:

sudo bless -folder9 "/Volumes/Macintosh HD/System Folder" --bootBlockFile "/usr/share/misc/bootblockdata"

Note: The -folder9 option has been removed from more modern versions of the bless utility, since Mac OS 9 has not been available on Macs since 2003.

This appeared to resolve the issues for a short while, until the computer crashed again, but this time, trying to fix the unmountable partition wasn't working. After digging further into old tricks on restoring Mac OS 9, I finally came across why the system was not booting properly any longer. When DiskWarrior tried rebuilding the Macintosh HD the second time, not all of the files were found. Another approach to bless the drive was to remove the System and Finder files from the System Folder, and then replace them. If everything goes well, the System Folder will get badged with a little Mac or Finder icon. What I encountered was that Finder file was missing! That would explain a lot why the system was not booting if a very critical part to the OS was missing.

The solution to fix this issue was to carefully reinstall Mac OS 9, and hopefully not have to wipe everything first. Since the Mac OS installer detected that a newer version of the OS already existed, it refused to install. By removing the existing System Folder, this helped convince the installer to begin installing. I started by installing Mac OS 9.1, which came along with my copy of Mac OS X 10.0. I then used the 9.2.1 upgrade disc that came with Mac OS X Jaguar for the next step. Trying to find the 9.2.2 installer proved to be a little more difficult and required a little digging across the internet to find a working version (albeit, on a very sluggish FTP server). A copy of the Mac OS 9.2.2 upgrade installer is available here.

Fortunately, even after telling the Mac OS installer to perform a clean install, it left most of the original files intact, so I did not have to reinstall much except for the driver for the ATI Radeon 9000 video card.

Things looked good again! Well, for a few minutes, at least. I started getting odd glitches and errors again, such as when I tried to launch QFG5, the OS claimed it could not find the DrawSprocketLib, but when I tried again, the game launched fine. Then the game started to get extremely sluggish, and eventually froze. When I restarted the computer, the Macintosh HD could not be found as a bootable drive again. (sigh)

The number of errors I was encountering indicated something far past software-related issues, so I started performing more extensive hardware tests using DiskWarrior, Data Rescue II, and the Apple Hardware Test disc that came with the computer. The issues I kept experiencing seemed to indicate some bad sectors on the hard drive, but any of the tools did not report the disk being faulty. The extended Apple hardware test did reveal that one of the sticks of RAM was bad (error: mem_/2/4), which is a likely culprit to random errors, lock ups, and crashes. I removed the bad stick of RAM (and fortunately the RAM sticks didn't need to be paired on this particular Mac), which was somewhat sad, since that was 512MB of RAM on a system which had 1.5GB of RAM, a very impressive amount for a machine of that age. Still, 1GB of RAM is more than enough for Mac OS 9. I'm hoping that the bad RAM is the source of all of the issues and that the hard drive isn't also dying, since trying to find a small hard drive would become increasingly difficult during this time where most storage has moved over to SSD. I might need to look into other options in the future to equip the G4 with an SSD.

I ended up completing QFG5 by playing in Classic mode from one of my Mac OS X partitions, which was passable, but not as smooth as playing natively in Mac OS 9. I finished it this way since the Mac OS 9 drive was available in the Classic system preference pane so I could make use of the System Folder to launch the Classic mode, but I still wasn't able to boot back into Mac OS 9. Disk Utility was once again reporting an invalid key length and the disk could not be repaired. Time for DiskWarrior, again. I tried DiskWarrior once more, but when it tried to rebuild the disk, it kept locking up at a certain spot (sigh again). Classic mode it would be, before digging into this problem once again.

Next up I made use of the command line utility fsck_hfs to attempt to verify and repair the hard drive.

[Ixia:~] % sudo fsck_hfs -r -d /dev/disk0s10
** /dev/rdisk0s10
** Checking HFS Plus volume.
** Checking Extents Overflow file.
** Checking Catalog file.
** Rebuilding Catalog B-tree.
hfs_UNswap_BTNode: invalid node height (1)
hfs_swap_HFSPlusBTInternalNode: catalog key #9 invalid length (8220)
   Invalid key length
(4, 1335)
hfs_swap_HFSPlusBTInternalNode: catalog key #32 invalid length (12338)
   Invalid key length
(4, 1614)
** Rechecking volume.
** Checking HFS Plus volume.
** Checking Extents Overflow file.
** Checking Catalog file.
   Missing thread record (id = 805355401)
   Invalid extent entry
(4, 1504)
   Incorrect block count for file Finder Preferences
   (It should be 0 instead of 12288)
   Invalid extent entry
(4, 1504)
   Incorrect block count for file Finder Preferences
   (It should be 1 instead of 8193)
   Invalid extent entry
(4, 1504)
   Incorrect block count for file FonၴAnnexFiぬe
   (It should be 0 instead of 1)
   Invalid extent entry
(4, 1504)
   Incorrect size for file FonၴAnnexFiぬe
   (It should be 0 instead of 536870912)
   Invalid extent entry
(4, 1504)
   Incorrect block count for file Game Sばrockets〠Update ⁐refs
   (It should be 12289 instead of 8193)
   Invalid extent entry
(4, 1504)
   Incorrect block count for file Game Sばrockets〠Update ⁐refs
   (It should be 8193 instead of 12289)
   Invalid extent entry
(4, 1504)
   Invalid extent entry
(4, 1581)
   Invalid extent entry
(4, 1581)
   Incorrect block count for file Standard Additions
   (It should be 12299 instead of 11)
   Incorrect size for file 4/C Ctd. TRUMATCH/RIၔ/Profil⁥80
   (It should be 909312 instead of 52776559040052)
   Incorrect number of thread records
(4, 260)
        CheckCatalogBTree: dirCount = 6565, dirThread = 6583
   Incorrect number of thread records
(4, 260)
        CheckCatalogBTree: fileCount = 34766, fileThread = 34718
** Checking Catalog hierarchy.
   Missing thread record (id = 805355401)
   Invalid directory item count
   (It should be 7 instead of 45)
   Missing thread record (id = 805359315)
   Invalid directory item count
   (It should be 0 instead of 3)
   Invalid volume directory count
   (It should be 6355 instead of 6564)
   Invalid volume file count
   (It should be 32838 instead of 34766)
** Checking Extended Attributes file.
   Incorrect number of Extended Attributes
(8, 1)
        extentType=0x0, startBlock=0x277437, blockCount=0x1, attrName=(null)
   Overlapped extent allocation (file 805355895)
        extentType=0x0, startBlock=0x277439, blockCount=0x6, attrName=(null)
   Overlapped extent allocation (file 805355897)
        extentType=0xff, startBlock=0x277441, blockCount=0x1, attrName=(null)
   Overlapped extent allocation (file 805355898)   
        extentType=0x0, startBlock=0x277442, blockCount=0x1, attrName=(null)
    ... (several thousand more lines like this)
   Overlapped extent allocation (file 805362187)
** Checking volume bitmap.
   Volume Bit Map needs minor repair
** Checking volume information.
   Invalid volume free block count
   (It should be 2729961 instead of 2797618)
        invalid VHB nextCatalogID 
   Volume Header needs minor repair
(2, 0)
   Verify Status: VIStat = 0xa800, ABTStat = 0x0040 EBTStat = 0x0000
                  CBTStat = 0x0800 CatStat = 0x4230
** Repairing volume.
   Cannot create links to all corrupt files
** The volume Macintosh HD could not be repaired.
        volume type is embedded HFS+ 
        primary MDB is at block 2 0x02 
        alternate MDB is at block 41680894 0x27bfffe 
        primary VHB is at block 3226 0xc9a 
        alternate VHB is at block 41680662 0x27bff16 
        sector size = 512 0x200 
        VolumeObject flags = 0x1F 
        total sectors for volume = 41680896 0x27c0000 
        total sectors for embedded volume = 41677440 0x27bf280 
[Ixia:~] % 

I tried to force rebuild the catalog with the command sudo fsck_hfs -y -r -d /dev/disk0s10, but it was the same error as what Disk Utility displayed that the disk could not be repaired. That was enough fun and hair pulling for that night.

The next day...the computer booted up fine into Mac OS 9! Well, go figure. That's computers. Sometimes it does pay to step away from the problem and come back later. Perhaps the hardware is still having issues and giving it a rest fixed the problem for now (shrug). Either way, it probably is time to either resolve any additional hardware issues or finally retire this trusty workhorse of a Mac.

Working and playing with Mac OS 9 for a couple of weeks was an interesting experience. Some tools such as Transmit 1.7, BBEdit Lite 6.1.2 and Classilla proved to be quite useful, but other tools needed to be dug up or experimented with. I also tried out USBOverdrive 1.4, but it did not seem to work with the Razer DeathAdder mouse, and the mouse cursor locked up, so I had to restart the computer and hold down Shift to disable the Extensions and then permanently disable USBOverdrive. In addition to the software previously mentioned, I even downloaded ResEdit for fun.

Special thanks to those sites like Macintosh Repository and Mac OS 9 Lives for providing resources to keep the "classic" Mac OS alive, which proved useful in searching for old software.


Calculating Free Space on macOS

12th May 2017 | Programming

As a set of interesting programming exercises, I've written up a number of examples to calculate the amount of free space on a given disk running on macOS. The first two examples are command line solutions, while the other examples take more programatic approaches.

Update (26 November 2017)

Due to some new approaches I came across from this StackOverflow post, two additional methods have been added by using diskutil and the private macOS framework DiskManagement.


To easily display the amount of available disk space and how much is free, use the built in utility df which returns the statistics about the amount of free disk space on a specified filesystem. This is a great little utility to use from the terminal or within a script. To get the details on the root drive, run the command df -kP / which will return data formatted like the following:

	Filesystem 1024-blocks      Used  Available Capacity  Mounted on
	/dev/disk2  2018614912 698624560 1319734352    35%    /

If you want just the amount of free disk space (calculated in kilobytes), use one of these two options which calls df and then parses out the pertinent data.

	df -kP / | tail -1 | awk '{print $4}'
	df -kP / | awk '/[0-9]%/{print $(NF-2)}'


diskutil is a veritable utility for disk related information and maintenance tasks, which serves as the command line version of the Disk Utility app. To retrieve the amount of free space (sometimes referred to as "available space"), run the command. diskutil info / | grep "Available Space". Due to changes in the output from diskutil over the years, on older version of Mac OS X, use the command diskutil info / | grep "Free Space".

$ diskutil info / | grep "Available Space"
   Volume Available Space:   94.0 GB (93988098048 Bytes) (exactly 183570504 512-Byte-Units) (37.6%)

DiskManagement Framework

Ivan Genchev discovered an interesting approach to determine the available free space by using the private macOS framework DiskManagement, which is used by diskutil (and I assume, Disk Utility, as well). Since this framework is not public, you'll need to generate a header file by using Steve Nygard's excellent utility class-dump, which allows you to examine the Objective-C runtime information stored in a Mach-O file. This is the same approach I used in another project to write a Finder plug-in, which required generating a Finder.h header file to be able to access the private Finder methods.

Download class-dump and copy the executable onto your system, such as in your /usr/local/bin directory.

Next, generate the header file with the command:

$ class-dump /System/Library/PrivateFrameworks/DiskManagement.framework/Versions/Current/DiskManagement > DiskManagement.h

This will create the necessary header file to link to the program. This is a fairly large file (the one for macOS High Sierra is 840 lines in length), and contains a number of interesting private methods. The method we are interested in is (id)volumeFreeSpaceForDisk:(struct __DADisk *)arg1 error:(int *)arg2.

Once we have the DiskManagement.h file, we can integrate it into our program. The following code is modified from Ivan Genchev's code in the StackOverflow post.

/*	dmfreespace.m
 *	Description: Get the available free space on the root drive using the method 
 *	volumeFreeSpaceForDisk from the private framework DiskManagement
 *	Original reference:
 *	To compile: clang -g dmfreespace.m -F/System/Library/PrivateFrameworks/ -framework Foundation 
 *	-framework DiskArbitration -framework DiskManagement -o dmfreespace

#import <Foundation/Foundation.h>
#import "DiskManagement.h"
#import <DiskArbitration/DADisk.h>
// For statfs
#include <sys/param.h>
#include <sys/mount.h>

int main(int argc, char *argv[])
    int                 err = 0;
    const char *        bsdName;
    DASessionRef        session;
    DADiskRef           disk;
    CFDictionaryRef     descDict;
    NSString *.         rootPath = @"/";
    session  = NULL;
    disk     = NULL;
    descDict = NULL;
    // Get the BSD name for the given path
    struct statfs devStats;
    statfs([rootPath UTF8String], &devStats);
    bsdName = devStats.f_mntfromname;
    NSLog(@"bsdName: %s", bsdName);
    if (err == 0) {session = DASessionCreate(NULL); if (session == NULL) {err = EINVAL;}}
    if (err == 0) {disk = DADiskCreateFromBSDName(NULL, session, bsdName); if (disk == NULL) {err = EINVAL;}}
    if (err == 0) {descDict = DADiskCopyDescription(disk); if (descDict == NULL) {err = EINVAL;}}

    DMManager *dmMan = [DMManager sharedManager];
    NSLog(@"blockSizeForDisk: %@", [dmMan blockSizeForDisk:disk error:nil]);
    NSLog(@"totalSizeForDisk: %@", [dmMan totalSizeForDisk:disk error:nil]);
    NSLog(@"volumeTotalSizeForDisk: %@", [dmMan volumeTotalSizeForDisk:disk error:nil]);
    NSLog(@"volumeFreeSpaceForDisk: %@", [dmMan volumeFreeSpaceForDisk:disk error:nil]);
    return 0;

Run the app and you should get output like the following:

 $ ./dmfreespace
2017-11-26 12:35:44.945 dmfreespace[17103:2781845] bsdName: /dev/disk1s1
2017-11-26 12:35:44.969 dmfreespace[17103:2781845] blockSizeForDisk: 4096
2017-11-26 12:35:44.970 dmfreespace[17103:2781845] totalSizeForDisk: 250035572736
2017-11-26 12:35:44.971 dmfreespace[17103:2781845] volumeTotalSizeForDisk: 250035572736
2017-11-26 12:35:44.971 dmfreespace[17103:2781845] volumeFreeSpaceForDisk: 93637120000

A GitHub Gist with dmfreespace.m and DiskManagement.h is available here.


The following program freesize.m takes five different approaches to calculate the free space on a drive. The first two examples use Cocoa's Foundation framework. The first example uses NSFileManager and asks for the NSFileSystemFreeSize attribute. Simple and straight forward.

The second example uses NSURL with some more modern approaches. This example gets a URL's resources and requests the value for the key NSURLVolumeAvailableCapacityKey. This code also makes use of NSByteCountFormatter, which was introduced with OS X 10.8 Mountain Lion. This method is a little more useful than the original way, since this can display the total available free space, which tends to be slightly smaller than all of the free space, not all which is available to the user, since some space might be reserved for the system.


getattrlist is a method I had read about in the books Advanced Mac OS X Programming and Mac OS X Internals before, but the available examples for this tool are quite sparse and seem to be rarely used. I spent several days trying to get this example to work, but the data never seemed to line up properly with the other results I was obtaining via other methods. getattrlist behaves in a curious and obfuscated way, by returning some blob of data, but one needs to carefully construct a custom structure in which to line up against the data blob. The data I was getting often would come out like the following:

	Volume size: 16229794380578291739
	Free space:  15103894473735667713
	Avail size:  1

This was obviously incorrect, which makes me suspect that the vol_attr structure was not lining up properly with the returned data, and I might even need to add some sort of padding inside the structure. There are far more easier methods to obtain the free space size than by using getattrlist.

statfs + statvfs

The final two examples are similar UNIX system calls to get file system information and statistics. These methods statfs and statvfs are nearly identical in how a structure is passed into a system call and then the necessary information is parsed out. The one major difference I found between these two system calls was that the f_bsize returned different values. The statfs structure returns a value of 4096 for f_bsize, whereas statvfs returns a value of 1048576, a value 256 times larger than the other one. To properly calculate the available free space using the statvfs call, I needed to use f_frsize instead. Multiply f_frsize by f_bavail and that will result in the total number of available bytes. To calculate that number in kilobytes, divide that product by 1024.

freesize.m Gist

Purgeable Space

In more current versions of macOS, if you pull up the Get Info window on a selected disk, the amount of available space might be different from the values which was calculated in the examples above. However, there is a second value which details how much space is purgeable. If you subtract the purgeable space from the available space, you should get a value very similar to the one calculated above. This purgeable space seems to come from snapshots taken by Time Machine or APFS, which are occasionally cleaned up (or purged).

Get Info Window


Edenwaith 2017

25th March 2017 | Edenwaith

2017 will be a year of renewal, which will focus on rebuilding the website and certain products.


The last major set of website improvements date back to 2009, well before responsive design was a standard to address the browsing capabilities for smart phones and tablets, in addition to their desktop counterparts. I've been researching a number of new methods for the fourth major redesign of the Edenwaith website. I've been heavily favoring some form of static site generation to display the various projects hosted here, plus allow for a decent blogging solution. This is still in the early stages and will require some experimentation to determine what will work best for this site's needs.

Until the day that Edenwaith 4.0 is live, I have introduced a couple of new design elements to the current site to try out a couple of new ideas.

EdenList for iOS 2.0

EdenList for iOS began as my first project for the iPhone back in 2009. In the past eight years, a lot has changed in the realm of iOS development. I have incrementally improved this app on a yearly basis, but its development has finally reached a point where the original foundation is too unstable and archaic to be viable in this rapidly mutating environment. Gone will be the Objective-C, XIBs, and manually managed memory, which will be replaced by Swift, Storyboards, and ARC (amongst many of the various other refinements).

Permanent Eraser

There are still a handful of features I'd like to complete during the 2.x lifespan of Permanent Eraser. Version 2.7.1 was released last December and plans are in the works for PE 2.7.2 and 2.8. After that, things are very much up in the air, but there are some interesting paths which Permanent Eraser might travel in the future.

Organization + Clean Up Tips for iOS Developers

29th January 2017 | Programming

The following are a collection of useful tips and tricks I've developed over the past year to help keep things neat and tidy in my development environment.

Free up space taken by Xcode

The problem: Xcode is a huge space hog, not only in the size of the app, but with all of the detritus which is left about from old archives, simulators, and derived data. This often results in my work computer displaying low space warnings.

Clean up old local git branches

The problem: Without regular maintenance, your local git repository will become a cluttered mess of old branches. Before cleaning your local git branches, your repository might look like this:

$ git branch --merged
* develop

Using a git/grep/xargs concoction, you can quickly clean this up. Delete all local merged branches, except for the branches named master or develop.

git branch --merged | grep -v '\*\|master\|develop' | xargs -n 1 git branch -d

This will result in local branches being deleted, with output similar to this:

Deleted branch Bugfix/FOOBAR-1000 (was ab382ed).
Deleted branch Bugfix/FOOBAR-1007 (was 493b17b).
Deleted branch Bugfix/FOOBAR-1015 (was e7e1f6a).
Deleted branch Bugfix/FOOBAR-1026 (was 19b6d62).
Deleted branch Bugfix/FOOBAR-1057 (was 8f06d42).
Deleted branch Bugfix/FOOBAR-1058 (was e285fde).
Deleted branch Bugfix/FOOBAR-1060 (was 96318b5).
Deleted branch Bugfix/FOOBAR-1061 (was a84bcac).
Deleted branch Bugfix/FOOBAR-1062 (was 2b7310c).
Deleted branch Bugfix/FOOBAR-1099 (was 8260dd0).
Deleted branch Bugfix/FOOBAR-1106 (was cf401f2).
Deleted branch Bugfix/FOOBAR-1132 (was 4af883c).
Deleted branch Bugfix/FOOBAR-1139 (was 3f89c9b).
Deleted branch Bugfix/FOOBAR-1141 (was 13763d0).
Deleted branch Bugfix/FOOBAR-1151 (was 6ca43c4).
Deleted branch Bugfix/FOOBAR-1155 (was b020c21).
Deleted branch Bugfix/FOOBAR-1157 (was 903dee7).
Deleted branch Bugfix/FOOBAR-1168 (was abb20b6).

Perform one more check to ensure that your local repository has been cleaned up:

$ git branch --merged
* develop

synx — Organize an Xcode project's file system

The problem: The file system structure of your project does not match up to the project's Xcode structure. If not properly handled early on in a project's life cycle, the organization between the project and it's matching file system will quickly become out of sync and result in a massive dump of unorganized files.

The idea to write a script seemed like a good weekend project, but fortunately this problem has already been solved. Enter synx, a command-line tool that reorganizes your Xcode project folder to match your Xcode groups.

To install: sudo gem install synx

To run: synx /path/to/project.xcodeproj

...and viola!á! No more unorganized file system structure.

Taking a simulator screenshot from the command line

The problem: As of Xcode 8, trying to take a screenshot of the iOS simulator using the keyboard shortcut ⌘-S will result in the simulator crashing. This issue occurs only with OS X El Capitan and Xcode 8, but not with macOS Sierra and Xcode 8.

From the command line, run: xcrun simctl io booted screenshot

I created a small shell script named (short for Take Simulator Screenshot) which switches to the Desktop, takes the screenshot of the running simulator, saves the picture to the Desktop, then switches back to the original directory. I then created an alias so I only need to type tss from the Terminal to take a screenshot.

To make this even easier, create an Automator Workflow service to run the shell script and then attach a keyboard shortcut to it. This method circumvents event needing to go to the command line to call the script. Press ⇧-⌘-5 and a screenshot is taken of the simulator.


Creating a Single Logical Volume Using USB Drives and Core Storage

10th September 2016 | Programming

I recently came across TarDisk, an interesting combination of hardware and software wizardry which uses the often unused SDXC slot on a Mac laptop to increase the total storage space. Considering that I am constantly running out of drive space on my work computer, this struck me as a very useful thing to assuage the perpetual freespace problem, but I was even more intrigued by the associated Pear software which combines the laptop's and the TarDisk's space into one logical unit, much like the Fusion drive in modern iMacs which take advantage of the speed of an SSD and the cheapness and spaciousness of HHD. I have not found any specifics on how Pear manages to merge the SD card with the computer's SSD, but I would not be surprised if it is making use of OS X's Core Storage technology to combine multiple disks into a single logical volume.

This got me wondering if it would be possible to do something similar by combining two connected USB disks into a single drive by using Core Storage. Indeed, this is possible. To do so involves running two commands from the command line using the diskutil utility.

diskutil coreStorage create LOGICAL_VOL_GROUP_NAME DRIVE_1 DRIVE_2
diskutil coreStorage createVolume lvgUUID type name size

LOGICAL_VOL_GROUP_NAME is the name you wish to assign to the new volume. DRIVE_1 and DRIVE_2 are the paths to the drives. Use the command diskutil list to get the path name of the drives (e.g. /dev/disk2). lvgUUID is returned after creating the new group. The output should be similar to the following:

diskutil coreStorage create FusedUSB /dev/disk4 /dev/disk5
Started CoreStorage operation
Unmounting disk4
Repartitioning disk4
Unmounting disk
Creating the partition map
Rediscovering disk4
Adding disk4s1 to Logical Volume Group
Unmounting disk5
Repartitioning disk5
Unmounting disk
Creating the partition map
Rediscovering disk5
Adding disk5s1 to Logical Volume Group
Creating Core Storage Logical Volume Group
Switching disk4s1 to Core Storage
Switching disk5s1 to Core Storage
Waiting for Logical Volume Group to appear
Discovered new Logical Volume Group "BF21D233-99CC-8AD9-853D-4339E765UI09"
Core Storage LVG UUID: BF21D233-99CC-8AD9-853D-4339E765UI09


diskutil coreStorage create FusedUSB /dev/disk4 /dev/disk5
diskutil coreStorage createVolume BF21D233-99CC-8AD9-853D-4339E765UI09 jhfs+ FusedUSB 100%

To revert these changes, run the command diskutil coreStorage delete lvgUUID. Keep in mind that creating and deleting Core Storage volumes is a destructive process and will delete any content that is already existing on the drives.


Newcomer's Guide to WWDC (2016 Addendum)

9th July 2016 | Apple

This year I was finally fortunate enough to attend WWDC, and following the advice of many others, I am including my own thoughts, tips and tricks about attending WWDC for the first time.

Finding a Hotel

Lodging in a large city is not cheap, and San Francisco (already renown for being one of the most expensive places to live in the U.S.) was no different. Trying to find anything even semi-affordable in downtown S.F. is a difficult task, and even more so to find something in a nicer area. Read up on reviews of the various hotels first, and stay out of the Tenderloin district. I will repeat that: Stay out of the Tenderloin district.

The Keynote

Historically, one wanted to line up for the Keynote as early as possible so one could get a seat in the main conference room where the Keynote was being held, otherwise you would be relegated to an overflow room. This year the Keynote was moved to the Bill Graham Civic Center, which was able to seat all 5000 attendees, journalists and special guests. It was packed, but this probably worked a lot better than trying to herd everyone into Moscone West for the Keynote.

I arrived at the Bill Graham Civic Center around 5:55. Just 10 minutes later, a decent sized line showed up behind me. Two lines were formed, one for the ground level and one for the upper level. I ended up on the upper level, but the giant screens helped show what was going on and the acoustics weren’t too bad.


Others have reported that in the past meals were a catered affair. With 5000 people to feed, though, it works best to have the pre-packaged meals so people can just quickly pick up a meal from a table and then find a place to sit and eat. Breakfast generally consisted of pastries, muffins, donuts and bagels with juice and coffee. Lunch often came in three varieties such as chicken, beef or vegetarian (sandwiches, salads, and some form of desert). Snacks and beverages were also available between meals. There was enough food, and sometimes there was enough left over from my lunch that it made for a good dinner. If you want a coffee, there are plenty of Starbucks around, including two just a block away from Moscone West. Interestingly enough, I never came across a single McDonalds during my stay in San Francisco, so no iced coffees from there.


San Francisco's weather is reminiscent of being in the mountains. It tends to be cool in the mornings and evenings, but will warm up during the middle of the day. During the week of the conference, temperatures ranged from 13°C to 18°C (I'll leave it as an exercise to the reader to convert those temperatures to Fahrenheit). I was glad I was given an extra jacket when I checked in, since I needed it on Monday morning while waiting in line for the Keynote.

Sight Seeing

Most of my time was spent attending the conference, but I did manage to reserve a couple of hours to check out some of the more interesting and pleasant parts of downtown San Francisco.


Attending WWDC was a magnificent experience. I’m not certain if I’ll be able to ever attend again, so it was wonderful to have the chance to attend this conference. Having all of the WWDC sessions available on-line is a great resource, but it just isn’t quite the same as being there in person where you have an entire week dedicated to watching these sessions and (trying to) absorb as much new knowledge as possible. In the past, I might watch a handful of sessions on the internet, but by being at the conference it allowed me to see a lot more of the sessions, including some I may not have bothered watching. Some of the sessions were great, some were surprisingly more interesting than expected, and a few were incredibly deep and complex. The information is invaluable, but the networking is what truly makes WWDC a fun experience. Meet other developers from all over the world (and there is plenty of chance to meet new people when you stand in various lines throughout the day) or perhaps even bump into a semi-famous face or two.

Automating Periodic Scripts With Launchd

22nd May 2016 | Programming

The Goal

Create a recurring maintenance task that will move all screenshots from the Mac's Desktop into a designated folder each day.

The Options

I looked at a number of different options to automate this maintenance task. I needed something non-obtrusive, straightforward and flexible.

The Code

In this example, I created a plist list file named local.cleanupdesktop.plist and placed it into the directory ~/Library/LaunchAgents. This particular plist configuration displays just a small portion of what is possible. In this example, it runs the script each day at 9:30. For a more comprehensive list of what options are available, check the comprehensive resources at

The script is a small bash script which searches for any screenshots which are on the Desktop and places them into the Screenshots folder. This particular script will take screenshots from the keyboard shortcut or from screenshots taken from the iOS Simulator.

Another Example

The next example is even simpler which has everything contained within the plist file. This launch agent will display an alert every weekday at 5 p.m. (17:00) as a handy reminder. The code passes in program arguments, which effectively invokes an Applescript command: osascript -e 'display notification "Update your tickets" with title "Reminder" sound name "Sosumi"'.

Installing the Launch Agent

To get these new launch agents to run, either log out and then log back in to your account, or the launch agent can be manually loaded from the command line using the launchctl utility:

launchctl load -w ~/Library/LaunchAgent/local.cleanupdesktop.plist

Likewise, if you want to unload the launch agent, use the command:

launchctl unload -w ~/Library/LaunchAgent/local.cleanupdesktop.plist


AppleScript: Counting Open Safari Tabs

19th May 2016 | Programming

On a typical day, I might have a dozen Safari windows open, each replete with its own set of tabs. With each tab sandboxed in its own process, this can result in a bevy of running tasks on the system. As an interesting (and useful) exercise, I wanted to write a small script which would quickly tell me how many open tabs I had in Safari.

The most obvious solution for my needs to be able to interact with Mac applications, yet retain the flexibility of a programming language is AppleScript. AppleScript is just another one of a multitude of languages I've dabbled with over the years, going as far back as the System 7 days. I pick up AppleScript every now and again when the appropriate need arises, but I find myself needing to relearn its capabilities. AppleScript has high readability with its English-like syntax, but it makes for some esoteric writing at times, to ensure that the proper syntax is being used.

The goal is straightforward: Grab every Safari window, total up the number of tabs, and return the result. In this particular example, I had the script print out the result so I could run it from the command line using the osascript command.

The Code

Running the script

osascript CountOpenSafariTabs.scpt There are 112 Safari tabs open.

To further simplify things, I added the following alias to my .bash_profile file, so I only need to type counttabs in the Terminal to get the desired answer:

alias counttabs='osascript ~/Projects/scripts/CountOpenSafariTabs.scpt'


Edenwaith 2016 : Preview + Review

15th May 2016 | Edenwaith

A couple of quick items about the year so far and a brief look ahead.

EdenList 1.2.3

EdenList for iOS was updated in April with several UI and UX improvements. In accordance to recent trends, the App Store approval time for this app had improved over past experiences to just three days. In the past, review times were generally between seven to ten days.

EdenGraph Retired

After ten years of inactivity, the decision has been made to officially retire EdenGraph. The source code for this project is available on GitHub.

The Mysterious Case of the Expired Certificate

Another talk about the fun and joys of dealing (translation: struggling and fighting) with Xcode, code signing and provisioning profiles. The summary of the talk was about the Apple Worldwide Developer Relations Certification Authority certificate expiring on 14 February 2016, which resulted in a number of bizarre behaviors. Delete the old certificate from your Keychain and update to the latest certificate. We'll be all set until 7 February 2023, when the current certificate expires.

Tip : Disabling Auto-launching For Android Phones on a Mac

Whenever I would plug in the HTC One (M7) into a Mac, a couple of apps might try and start up. This became quite annoying, so here are a couple of tips to disable Android File Transfer and Photos from launching when the HTC One is connected.

2016 : On and On...

The plans for the remainder of this year are fairly slim, but will mainly focus on an update to Permanent Eraser and rebuilding the Edenwaith website.

Permanent Eraser 2.7.0

26th December 2015 | Permanent Eraser

As mentioned earlier this year, the newly released Permanent Eraser 2.7 will (likely) be the final major hurrah for the 2.x line. New features, fixes and improvements in this release include:

The biggest new feature is a new contextual menu plug-in for pre-Snow Leopard versions of Mac OS X. The plug-in has been tested on both Tiger and Leopard (it may work on even earlier versions of Mac OS X, but this has not been verified). Even though Permanent Eraser 2.7 does not run on Tiger, the plug-in can be downloaded and installed into your account's ~/Library/Contextual Menu Items/ folder. If the folder Contextual Menu Items does not exist, create the folder first, then copy the file EraseCMI.plugin into the folder. Then restart your Finder by either restarting your computer or typing the following command into the Terminal: killall Finder

This new plug-in was more of an interesting exercise to create the type of plug-in from that would have been written ten years ago, during the days when Finder was still based off of Carbon instead of Cocoa. The result is a faster and more integrated solution for older versions of Mac OS X, rather than using the slower Automator workflow.

The latest version of OS X (10.11 El Capitan) finally removed the Secure Empty Trash and Erase Free Space features from Finder and Disk Utility, respectively. As detailed in the security note CVE-2015-5901:


Available for: Mac OS X v10.6.8 and later

Impact: The “Secure Empty Trash” feature may not securely delete files placed in the Trash
Description: An issue existed in guaranteeing secure deletion of Trash files on some systems, such as those with flash storage. This issue was addressed by removing the “Secure Empty Trash” option.

CVE-2015-5901 : Apple

Due to the way that Solid State Drives rewrite data to the disk using wear leveling techniques, it is not possible to repeatedly write over data like it is with mechanical hard drives. In 2015, the only Apple computers which even come with the older hard drives (whether stand alone or as part of a Fusion Drive) are the iMac, the Mac mini, and a 3 year old version of the 13" Mac Book Pro. Even the Mac Pro has eschewed the older technology in favor of the faster speeds of SSD. Since a majority of Apple's computers which are sold these days are laptops, there is less and less need for secure file shredders. If you are using an SSD, the recommended way to protect your data is to encrypt the drive by turning on FileVault.

Does this mean that this is the end of Permanent Eraser? Not necessarily. Various ideas and prototypes for the next version of this app have been floating around for several years, but with the shift in storage technology, Permanent Eraser may also need to shift to address new needs — otherwise, the app will slowly become obsolete as it would cater to a continually declining niche market.

Mobile Plateau

2nd July 2015 | Apple

When the iPhone 5s came out, I wanted to love it, to be enamored by its advancements. I really did, but despite my desire to yearn for it, the longing and admiration just wasn't there. The iPhone 5s is a fine phone, but the level of improvements over the iPhone 4S just were not enough to convince me to immediately upgrade. There were some niceties such as the addition of LTE and Touch ID, but those still weren't enough. Much of the low hanging fruit had already been plucked, and the yearly advancements in mobile technologies were tapering off.

Eager to find something fresh, my gaze extend outside of the Apple ecosphere. Many Android phones are slabs of poorly designed plastic, lacking the level of precision and quality which I was accustomed to with Apple products. One product which did catch my eye was the 2013 edition of the HTC One (M7).

I've used two versions of the M7, a silver Google Play edition and a metallic blue Verizon version. Externally, the phones are nearly identical except for the coloring and the addition of a carrier logo on the Verizon phone. The phone is a good size (quite a bit larger than the iPhone 4S), and feels very solid. However, one thing I missed about iOS was having a Home button to wake up the phone. Otherwise, the build quality is excellent.

The Google Play edition resolved one of Android's biggest hurdles by being able to upgrade to the latest version of KitKat (Android 4.4), whereas the Verizon version was restricted to version 4.2.2, with no word that Verizon has any plans on updating the software on the phone. The only work around to get future versions of Android looks like to root the device and upgrade it manually. This may not be the worst idea, since the Verizon M7 comes cluttered with a bunch of their carrier-branded crapware (which can't be manually uninstalled, either), so wiping the device and upgrading might be a worthwhile endeavor. I used these phones as testing devices (no SIM cards), which need to be put into Airplane Mode to get them to work properly with Wi-Fi. On the software front, getting the Google Play version of a device is certainly the way to go. No corporate branding, no unwanted crapware, and an easy upgrade path.

In September 2014, Apple announced the yearly update to the iPhone line: the iPhone 6 and iPhone 6 Plus. The iPhone 6 was Apple phone I was hoping for that would impress me again and make upgrading worthwhile. After using my trusty workhorse of an iPhone 4S for three years, trading up to the iPhone 6 came with numerous perks.

The iPhone 6 line builds upon its predecessors, so some of these features had already been around for a year or few, but the larger screen size and expanded storage space were great additions. The 3.5" screen on the first several iterations of the iPhone looked astounding in comparison to the bevy of phones it supplanted, but it began to look diminutive in comparison to some of the newer Android phones, such as the HTC One's gorgeous 4.7" screen.

The iPhone 6 is an amazing device, one which I hope to be using well into 2017. The two year cycle of replacing phones might become more a thing of the past as the hardware and software improves to a point where these devices' lifespans can reach out to 3+ years (barring the usual accidents). Personal computers in the 1980s had a life expectancy of around three years before they became too antiquated to run the latest software. The computers built in the 21st century have reached a point where they can easily reach 5, 7, or more years of use. The youngest of the three Macs I use regularly at home is 8 and the oldest is now a dozen years in age.

Google's and Apple's developer conferences, Google I/O and WWDC respectively, are used as the platforms to announce their latest advancements and things to look forward to in the coming year. Normally these conferences bring about some interesting changes, especially in the realm of mobile technologies, but 2015 was quite the bust for both conferences. Aside from the Google Photos service, Google I/O elicited not much more than a yawn from me. I was hoping that WWDC would hold more promise.

The potential was there, but it was not met. Aside from the now yearly upgrades to OS X and iOS, there was the introduction of Apple Music, which was only marginally more interesting to me than Google Photos. For the past three years I've been hoping for an upgrade to the Apple TV that would be amazing enough that it would finally convince the rest of my family to cut the TV cable. No announcement yet, but there is always hope that something like this is in the works.

The iPhone in 2007 heralded the beginning of the current generation of smart phones, turning a device with twelve buttons into an amazing computer that fits into your pocket. The biggest shortcomings have been addressed and now Google and Apple are grasping to find interesting and important problems to tackle in the mobile space. We have reached a plateau in this space, where the annual leaps in technology are no longer being met. This is a lull in the storm for the time being, but things will eventually be churned up again, bringing about the next set of technological advancements, whether that is in mobile or another area altogether.

Permanent Eraser + Yosemite

29th April 2015 | Permanent Eraser

Each new version of OS X brings changes, which often prompts software makers to update their own products to ensure that things work properly on the new system. Sometimes the changes are minor and other times they are quite severe. This article will focus on two areas, Gestalt and code signing, which required some additional work to get Permanent Eraser 2.6.3 to work properly with Apple's desktop OS of 2014 — Yosemite.

Gestalt + Yosemite

There have been numerous ways to determine the operating system version on OS X, but it hasn't been until recently that Apple provided a sanctioned way in Objective-C (and Swift) with the inclusion of NSProcessInfo's operatingSystemVersion method. This is a welcome, albeit highly belated, addition to the Cocoa framework.

Before the inclusion of the operatingSystemVersion method, programmers used a variety of methods to determine the operating system's version, including a mainstay which harkens back to the pre-Cocoa days — the Gestalt Manager. Up until Yosemite (aka OS X 10.10), the following code snippet worked pretty well.

SInt32	osVersion;
Gestalt(gestaltSystemVersion, (SInt32 *) &osVersion);	// Set OS Version

if (osVersion >= 0x00001060) { // Snow Leopard (10.6) or later

Unfortunately, with a system version like 10.10.0, we have run out of space using this old format, which results in warnings such as the following to appear:

WARNING: The Gestalt selector gestaltSystemVersion is returning 10.9.0 instead of 10.10.0. Use NSProcessInfo's operatingSystemVersion property to get correct system version number.

The problem which is encountered is when either the minor or patch numbers exceed the number 9, so the version of Mac OS X 10.4.11 would be returned as 10.4.9 or 10.10.3 would be returned as 10.9.3. Years ago, some Adobe installers encountered an error when trying to install on Mac OS X 10.4.10 or 10.4.11, thinking that it was an earlier version of Tiger (Adobe InDesign 4.0.5 does no longer start up). The problem now results in the returned OS version has run out of space to properly represent the system version for Yosemite.

The work around for this problem was to make use of a back port which will use the latest methods, but will fallback to another method for earlier versions of OS X. The replacement for the Gestalt call I used was Jake Petroules' CocoaBackports, which checks if methods like operatingSystemVersion and isOperatingSystemAtLeastVersion are available. If not, swizzle the methods and use the custom methods. The updated code now looks like this:

if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 6, 0}] == YES)	{

Code Signing + Yosemite

A year ago I detailed the process I took to code sign Permanent Eraser to work with Gatekeeper on Mountain Lion and Mavericks. However, when developing Permanent Eraser 2.6.3, I encountered the following error when trying to launch the app on Yosemite.

So what happened?! This was working before! Let's do a quick codesign verification to see what is happening. If your app has been signed with an older version of codesign, you will see the following message if you verify the package with current versions of OS X:

codesign --verify --verbose=4 resource envelope is obsolete (version 1 signature)

If everything is good, then it might look more like this:

codesign --verify --verbose=4 valid on disk satisfies its Designated Requirement

Or for the more succinct version:

codesign --verify -v valid on disk satisfies its Designated Requirement

If the app hasn't been signed at all, then you will see a response like this:

codesign --verify --verbose=4 code object is not signed at all
In architecture: ppc

The short answer is that Gatekeeper has changed in the past year. For apps to be approved by Gatekeeper, they now need to be signed in OS X 10.9.5 or later, which contains the latest signature. Due to changes like these, there's little wonder why I have sprouted at least three grey hairs due to dealing with code signing and provisioning profiles.

Apple Says: Important: For your apps to run on updated versions of OS X they must be signed on OS X version 10.9 or later and thus have a version 2 signature. They also must not contain any custom resource rules. You must sign using OS X 10.9 or later. You cannot just take the codesign utility and move it to an older version of OS X. Mac applications signed with version 2 signatures will still work on older versions of OS X.

Gatekeeper changes in OS X 10.9.5 and later

What to sign

How to sign

Start by trying to sign the main application bundle. If any enclosed subcomponents need to be signed, you will be notified.

codesign --force --sign "Developer ID Application: John Doe" replacing existing signature code object is not signed at all
In subcomponent: /Users/jdoe/Desktop/

In this example, the Automator action named Foo still needs to be signed.

codesign --force --sign "Developer ID Application: John Doe"

In the UNIX world, no news is good news. If you sign this bundle and nothing else comes back after the process is complete, assume everything is good. This works fine for signing Automator actions. If you are trying to sign a workflow, the process requires a little extra work. If you try and sign the top level of the workflow package, you will receive the following error:

codesign --force --sign "Developer ID Application: John Doe" code object is not signed at all
In subcomponent: /Users/jdoe/Desktop/

The correct way to sign a workflow is to first sign the XML file document.wflow, then sign the enclosing workflow file.

codesign --force --sign "Developer ID Application: John Doe"
codesign --force --sign "Developer ID Application: John Doe"

Problem Signing an Old Automator Workflow

Here is an error which occurs when trying to codesign the old Automator workflow plug-in which is intended for Leopard systems.

codesign --force -v --sign "Developer ID Application: John Doe" bundle format unrecognized, invalid, or unsuitable

To work around this issue, an Info.plist file needs to be included into the workflow bundle's Contents folder. An example Info.plist file is below. Replace the CFBundleName's value with the name of the workflow.

Example Info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">


Once the application and all of its subcomponents have been properly code signed, verify using codesign and spctl to ensure that everything is good.

codesign --verify -v valid on disk satisfies its Designated Requirement

spctl -a -t exec -vv accepted
source=Developer ID
origin=Developer ID Application: John Doe


When I was initially packaging Permanent Eraser 2.6.3 as a DMG, I used FileStorm 1.9.5. Unfortunately, this did not package the application correctly, so the app could not be verified properly by Gatekeeper. To work around this problem, I used FileStorm 2.0.2. Zipping the application from the Finder also works.


Permanent Eraser 2.6.3

7th April 2015 | Permanent Eraser

Permanent Eraser 2.6.3 is now available, albeit a couple months later than originally intended, mostly due to resolving issues related to the OS X Yosemite (further technical details on this will be posted later). However, the extra time was well spent resolving various issues (both large and small) and further UI refinements were made (such as Retina-level images).

The tentative plan at this point is to work on Permanent Eraser 2.7, which is intended to be one final hurrah for the long-standing 2.x line. Initial work for Permanent Eraser 3 has begun, which will most likely drop support for older versions of OS X, which will include PowerPC compatibility. This is the current roadmap for Permanent Eraser, but it is certainly possible that all, some or none of these plans will come to fruition.

Fashion Is The Design Of Our Products

13th November 2014 | Apple

When Apple Computer was founded, Steve Wozniak was the brains of the company, but Steve Jobs was the heart and soul of the organization. When Jobs left in 1985, an important piece of the company was lost until his return in early 1997. Watch the MacWorld 1997 video to see the distinct difference in presentation style between Jobs and former Apple CEO Gil Amelio. Just several days after Apple acquired Next Computers, Jobs already had a plan to get Apple back on track, while Amelio fumbled through his presentation.

MacWorld SF 1997

Watch the presentations Jobs made in the late 90s, and one will see a man who has clear cut goals. Quite often, Jobs' visions of the future were often over reaching (some ideas would never manage to land), but it's interesting to see how many of these ideas did manage to see the light of day.

Pundits have been crying for years that an Apple without Steve Jobs is doomed to fail. Time will ultimately rule the final verdict of these claims, but three years after the passing of the Apple co-founder, the company is still healthy and immensely profitable. However, Apple is currently riding an enormous wave of inertia from the products which were released while Jobs was at the helm. Eventually, this momentum will begin to falter, and the future of the company will depend upon new innovations.

In early September 2014, a fervor was buzzing throughout the tech circles, similar to that of December 2006, with all eyes turned toward Apple. Breaths were carefully held, only to be released in the zealous joy of another miracle product being born from the depths of Cupertino. A product that will carry Apple forward, that will prove that Apple can stand without Jobs.

Loud whispers predicted that Apple would be releasing a new brand of wearable, something which would formally herald the era of new computing devices. Many attempts have already been made at popularizing this concept, but no one single item has broken out from niche markets and entered the mainstream.

Enter the  Watch.

This new device isn't just of interest to the technorati, but it has also garnered the attention of those in higher fashion and design. It is the embodiment of both form and function. As the press has tried to glean every available detail from the announced (but unreleased) Apple Watch, it has introduced a broader audience to horology, the digital crown, and Milanese Loops.

Comments from Apple CEO Tim Cook and Senior Vice President of Design Jony Ive have indicated that the Apple Watch is the first new post-Jobs product from the company. This is perhaps true, that Jobs did not have direct input on the Apple Watch, but that does not necessarily mean that his vision and spirit did not have some influence over the design and construction of this product.

Let's play the Devil's Advocate and assume that the ethereal presence of Jobs rose from the grave and played a subtle part in the creation of this new device.

Step back sixteen years to WWDC '98 where Jobs presented to a crowd of the Apple faithful, and he espoused the ideas of simplicity, technology, design, and fashion. The original iMac had just been announced the prior week, the first indicator of a new Apple. Gone was the myriad of confusing beige boxes, to be replaced by a simple matrix of four focused products, with the candy-colored Bondi Blue iMac being the keystone of this new strategy.

"As we get more towards consumer products, fashion gets important," Steve Jobs mentioned at the 1998 Worldwide Developers Conference. "For us, fashion is the design of our products. And we think this is really important to consumers." While he was initially describing computers, he also gave an alternative example.

Of a watch.

The Casio G-Shock — the hottest selling watch of 1998. Because of design.

Ten years earlier in 1988, the average American owned only one watch. Jobs continued, "Ten years later today, because of design, the average American owns seven watches."

WWDC 1998

To summarize: Design is very powerful.

Jobs has long recognized this, and it has been a common theme that Apple is at the crossroads of technology and the liberal arts. The marriage of tasteful design and fashion sense with technology. The wedding of Form and Function in the style of Apple.

Perhaps this is merely a coincidence that Jobs had mentioned a watch back in 1998, and Jobs had no hand in the creation of the Apple Watch, but it does provide for plenty of fodder for conspiracy theories. Regardless of where the line is drawn that divides fact and fiction, what we do know is that while Steve Jobs the man is gone, the ideals he presented persist.

JSON Utilities

19th October 2014 | Programming

When working with RESTful services and JSON, there are several utilities which will make it easier to work with this format.

JSON Quick Look Plug-in

Since a blob of JSON data is just text, it can be saved into a simple, flat file. Amazingly enough, though, OS X does not have a native Quick Look plug-in to quickly preview files which end with the json extension. Fortunately, third-party extensions are available, such as the quick look JSON plug-in from sagtau.com2. Installing the Quick Look plug-in can be performed in three quick steps.

  1. Download QuickLookJSON.qlgenerator
  2. Copy the file to the directory /Library/QuickLook/
  3. Restart the Quick Look Server with the Terminal command: qlmanage -r

Text Filter Plug-Ins

BareBones Software makes two great text editors for the Mac, BBEdit and its little sister, TextWrangler. Both can also be extended with text filters which can be written in a variety of scripting languages like Perl, Python, or even a shell script. Text Filters are located in the following directories:

TextWrangler: ~/Library/Application Support/TextWrangler/Text Filters/
BBEdit: ~/Library/Application Support/BBEdit/Text Filters/

Formatting JSON

After receiving an unorganized blob of JSON data from a web service, it would be nice to neatly format the information to make it easier to read for human consumption. An entry at Interactive Logic's1 site details how to create a Python scripts to take an unmanageable blob of JSON data and format it into a neater blob of JSON data.

Compacting JSON

Perhaps you don't like your JSON to be all nice and orderly and prefer a compressed mass of bits. No problem, there is a script for that, as well.

After a little research 3 through Python's documentation, I found that I could easily modify the Format file to strip out the unwanted white space from the formatted JSON.



  1. How to Format JSON in TextWrangler
  2. quick look JSON
  3. JSON encoder and decoder Python documentation
  4. Compact JSON Gist
  5. Format JSON Gist

Swift Factorial

6th July 2014 | Programming

With the introduction of Swift at WWDC 2014, I was eager to begin experimenting with this new language. My initial impression of Swift was that it was like learning a new language which is vaguely foreign, yet inherits enough niceities/commonalities from other languages, (such as C, Scala, Ada, and of course, Objective-C) that it doesn't feel overly strange.

Following up on a recommendation, I decided to design a small Mac application with Swift that would calculate factorials, including non-integer numbers. The result is Swift Factorial. The source code is available on GitHub. The Mac app can be downloaded here.

As simple and straightforward of an exercise this was, it proved useful in resolving an issue in calculating factorials for floating-point numbers on Intel Macs. EdenMath and EdenGraph currently use the following logic to calculate the factorial for floating-point numbers:

lg = lgamma(currentValue+1.0); currentValue = signgam*exp(lg); /* signgam is a predefined variable */

This worked fine originally when EdenMath 1.1.1 and EdenGraph 1.2.0 were introduced in 2004 and Macs were powered by PowerPC processors. However, something doesn't seem to work quite right initially on Intel chips (perhaps the signgam isn't set yet), and the first run of a factorial returns 0. The new solution simplifies the calculation of non-integer factorials down to one line:

newValue = exp(lgamma(originalValue + 1))

This code fix will be incorporated into future versions of EdenMath and EdenGraph.

Permanent Eraser 2.6.2 and Gatekeeper

4th January 2014 | Permanent Eraser

Permanent Eraser 2.6.2 came out at the end of December 2013, fixing some issues related to Gatekeeper and the latest version of OS X — Mavericks. 2013 almost became the first year since the inception of Permanent Eraser that the app was not updated at least once. Since 2003, Permanent Eraser has received at least one or two yearly updates, sometimes even more, depending upon the development schedule. Looking forward to 2014, work on Permanent Eraser 2.7 will begin.

What's new in Permanent Eraser 2.6.2

One of the biggest fixes in Permanent Eraser 2.6.2 was to properly code sign the app so it would be identified by Gatekeeper as an app by a trusted source. The article Code Signing and Mavericks by Craig Hockenberry helped reveal some trouble areas to resolve. Even though Permanent Eraser 2.6.1 had been code signed, it was not validating properly with Gatekeeper. If I verified the code signature of the app, I saw the following results:

codesign --verify --verbose=4 Permanent\ Eraser\
Permanent Eraser valid on disk
Permanent Eraser satisfies its Designated Requirement

Looks good so far. For the interest of it, I then tried verifying an earlier version of Permanent Eraser which had not been code signed.

codesign --verify --verbose=4 Permanent\ Eraser\
Permanent Eraser code object is not signed at all

Once again, this is returning the expected results. However, if I used the new spctl utility to verify Permanent Eraser in OS X 10.8+, I encountered a problem.

spctl --verbose=4 --assess --type execute Permanent\ Eraser\
Permanent Eraser rejected

spctl, which manages the system policy security, is a command line utility which first appeared in Mac OS X 10.7.3, but the security system known as Gatekeeper came to prominence with OS X 10.8 "Mountain Lion".

The solution was not to use the Mac Developer signing idenity to sign the app (which is used for signing an app for the Mac App Store), but to use the Developer ID Application one, instead. Now when I perform the appropriate checks in OS X Mavericks, everything is looking good.

codesign --verify --verbose=4 Permanent\
Permanent valid on disk
Permanent satisfies its Designated Requirement

spctl --verbose=4 --assess --type execute Permanent\
../Permanent accepted
source=Developer ID

Oddly enough, after signing this way in Snow Leopard, trying to verify the app returned this result:

codesign --verify --verbose=4 Permanent\
Permanent valid on disk
Permanent does not satisfy its designated Requirement

However, since the other checks appear to be in proper working order on post-Snow Leopard systems, this looks to be the proper route to properly code sign the app and let it verify properly with Gatekeeper.


git-branch-delete : Deleting local and remote git branches in one fell swoop

25th December 2013 | Tutorial

At my work, I build up a large collection of branches in my git repository over time. Eventually the large number of branches gets overwhelming and requires some maintenance to make the project more manageable (AKA less cluttered). Cleaning up the local and remote branches tends to follow this two step process:

  1. Delete local branch: git branch -d name_of_branch
  2. Delete remote branch: git push origin :name_of_branch

After doing some research, I did not find any quick and dirty way to delete both the local and remote branches with one simple command in git on a Mac. However, I did eventually discover a Ruby script named git-branch-delete that someone1 had written which does nicely perform this task.

Installation for OS X

  1. Download the file git-branch-delete
  2. Extract the file git-branch-delete from the compressed tarball
  3. Copy the file git-branch-delete to /usr/local/bin
  4. Set the proper permissions: chmod 755 /usr/local/bin/git-branch-delete


Once this has been set up, open up a new Terminal session and delete old git branches from the command line using the following command: git branch-delete <branch-name>


Edenwaith git-branch-delete Gist :


1) Original source :

Compiling Git for PowerPC Macs

3rd August 2013 | Tutorial

This year I've begun using the version control system Git for managing source control. I've been putting up some of my older projects on GitHub, which were built as Universal Binaries on Xcode 3 (or earlier). Since I've been working on a long-due update for EdenGraph, I began looking around for a Git client for older PowerPC Macs. The results were disappointing, but this may not be too surprising since Git is a relatively new tool and PowerPC Macs were fazed out in 2006.

However, I did come across a blog post on how to compile Git from source for a PPC Leopard machine, but the instructions, while close, didn't work entirely in my tests. When trying to build the source code, it resulted in the following error:

	$:git-master admin$ make prefix=/usr/local
	GIT_VERSION = 1.8.4-rc0
		* new build flags
		CC credential-store.o
	In file included from cache.h:8,
					 from credential-store.c:1:
	gettext.h:17:22: error: libintl.h: No such file or directory
	In file included from cache.h:8,
					 from credential-store.c:1:
	gettext.h: In function ‘_’:
	gettext.h:54: warning: implicit declaration of function ‘gettext’
	gettext.h:54: warning: incompatible implicit declaration of built-in function ‘gettext’
	gettext.h: In function ‘Q_’:
	gettext.h:62: warning: implicit declaration of function ‘ngettext’
	gettext.h:62: warning: return makes pointer from integer without a cast
	make: *** [credential-store.o] Error 1

I found that I needed to create a configuration file first, configure the project, and then build it. These instructions installed git 1.8.2 on a PowerBook G4 running Mac OS X 10.5.8.

  1. Download the latest Git source from
  2. Create configuration file: make configure
  3. ./configure --disable-nls
  4. make prefix=/usr/local
  5. sudo make prefix=/usr/local install

Once Git has been installed, go to the project folder (via the Terminal) and create an empty Git repository with the git init command and then download a project with the command git clone git://path/to/MyProject.git. If you are looking for a GUI-based Git client for PPC Macs, check out GitX.

EdenMath 1.2

31st May 2013 | EdenMath

After a nine year long hiatus, EdenMath has been polished and updated, ready to run on the latest versions of OS X.

New Features


EdenMath was the first Cocoa-based application I wrote for the Mac. Cracking open the time capsule shows how EdenMath has evolved over the years, from an embarrassingly bad and inconsistent user interface in the first version of the application, to the more refined later versions.

The interface for EdenMath 1.1 was a dramatic improvement over its predecessors', but it still had its flaws. Developing for EdenMath 1.2 allowed for the opportunity to rethink the entire interface. The following screenshots are a couple of experimental interfaces which were designed during the process of constructing EdenMath 1.2.

Source Code

The source code has always been available, but the source is now even more accessible at its own Github repository.

The Future

The original plan was to update EdenMath with several key features and then lovingly retire the program. However, time was running short and not every feature made it into this version. I am tentatively planning a 1.3 version of EdenMath for the future, which might include the following features:

2013 : Turning The Corner

1st January 2013 | Edenwaith

2012 was intended as a year for cleaning out the old to make way for the new. Some good progress was made, but not everything has been completed yet, which will continue throughout this year, in addition to updating the active projects.

Here is 2012 at a glance:

The progress is half-way complete in retiring the older programs. In 2013, GUI Tar, EdenGraph, and EdenMath will each receive at least one more update before being retired. This will leave 33 RPM, Permanent Eraser, and EdenList as the remaining Edenwaith projects.

Aside from the plans for application retirement, preparations are being made for the development of Permanent Eraser 2.7 and EdenList 1.2 for iOS.

33 RPM 1.1.8

9th December 2012 | 33 RPM

Today, the long due update to 33 RPM, version 1.1.8, was released.

Features and updates:

The most important change to 33 RPM in this release is that 33 RPM is now free of cost. Since the development of this project has dropped off precipitously in the past two years, it did not make sense to continue charging for a product which was not being continually updated. If you recently purchased 33 RPM and have not already received a refund, please contact us.

33 RPM 1.1.8 has also been tested and verified for the past two releases of OS X — Lion and Mountain Lion, both which have been quickly released since 33 RPM 1.1.7 was released in September 2010. One nasty, but occasional, bug that was squashed was trying to adjust the time slider would not work in Lion or Mountain Lion. A number of other smaller cosmetic and functional issues have also been made.

Psychomancer 1.0.7

2nd September 2012 | Psychomancer

Yesterday, Psychomancer 1.0.7 was released, which coincided with the ten year anniversary of the release of the Linux version of the previous version -- 1.06. As mentioned earlier this year, a number of older projects are being cleaned up and retired. Psychomancer was one of the earliest Edenwaith products, but it has been largely ignored for the past decade as newer Mac and iOS projects took precedence. However, before retiring Psychomancer in its current incarnation, a little love needed to be shown with one more update. Over the course of the past two months, Psychomancer was updated with 150 new features, improvements, and bug fixes. This represents the largest set of changes to the game since the original incarnation of the game in August 1999.

Before sending off Psychomancer, let's reflect on how things have changed since the last significant update. In 2002, Psychomancer was still being developed under Digital UNIX, the same platform where it was born in 1999. 2002 and 2003 extended the range of supported platforms to Mac OS 8, 9, X, Linux (x86), and Windows 9x - XP. Strangely enough, Windows XP is one which is still relevant in its same incarnation as it was years ago, whereas (Mac) OS X has undergone quite a few transitions since then, the most noteworthy change being the switch from PowerPC to Intel processors.

The first early versions of Psychomancer 1.0.7 had been organized under Project Builder on Macs running Mac OS X 10.1 and 10.2. Since I no longer have any computers running those versions of the Mac OS (however, my trusty PowerMac G4 is still running which supports Mac OS 9, Mac OS X 10.3 and 10.4), I had to convert the old Project Builder file using Xcode 2 before upgrading the project to Xcode 3. One primary goal for this update was to create a Universal Binary for both PowerPC and Intel-based Macs. Unfortunately, Xcode 4 dropped this feature, so Xcode 3 was necessary to be able to generate a Universal Binary. This project was built on a 2003 PowerBook G4, running Mac OS X 10.5.8 and Xcode 3.1.4.

Going through this game with a fresh perspective (since it had been so long since the last update), I found numerous areas for improvement from better descriptions, adding new features, and fixing bugs.

Improvements to each of the classes:

After playing Diablo 3, I took inspiration in adding more random events to increase the playability of the game by randomizing the potions found in the Treasury and adding additional random puzzle locks.

Upon going through the list of old and new bugs, I kept encountering odd issues with the inventory. Sometimes too many health potions would be added. Sometimes an item wouldn't be added. Other times, random items would just disappear from the inventory. I finally sat down and reworked the inventory system, based off of a linked list. This was an interesting (and somewhat fun) exercise to go back to code written thirteen years ago and figure out what wasn't working properly. All things considered, most of the code in this project was quite clean and organized. However, there were a couple of odd issues with adding and removing items from the linked list, which were finally fixed.

The largest bug I quickly encountered was that drinking potions didn't do anything. What the...?! I was quite surprised that issue hadn't been caught and fixed a long time ago. Fortunately, a quick fix, but an issue that should have never stayed around as long as it had.

And so, now, we bid Psychomancer a fond adieu. While this journey has come to an end, it does not mean that a new one cannot begin. One never knows. Perhaps someday Psychomancer will be converted to work on Z-machine interpreters. Perhaps it will be given a long-promised overhaul and be gain graphics and sound. Considering the popularity of mobile development in 2012, it would not be unthinkable to one day see Psychomancer on a phone or tablet. Or perhaps Psychomancer will end up in some other form entirely. Time will tell...

Permanent Eraser 2.6.0

28th May 2012 | Permanent Eraser

On 19 May 2012, Permanent Eraser 2.6.0 was released. The two most important new features are Solid State Drive (SSD) detection and the new DoE overwrite pattern. If a file is detected to reside on an SSD, the file will only be overwritten once, instead of multiple times, due to wear leveling techniques used by SSDs. The next feature is the addition of the 3-pass DoE pattern to erase files.

In order to keep up with the latest versions of Mac OS X, older versions of the OS are occasionally dropped. Permanent Eraser 2.6 was originally intended to still support Mac OS X 10.4 "Tiger", but the addition of the new DoE overwriting pattern required a custom build of the srm utility, which unexpectedly failed to run on Tiger. However, we'll look further into this issue to determine if support for Tiger can be returned in a future version. For those who are still using Tiger, Permanent Eraser 2.5.3 is still available for download.

Likely due to the pending deadline which requires all new application submissions to begin using entitlements at the beginning of June, it took nearly two weeks for Permanent Eraser 2.6.0 to be reviewed for the Mac App Store, which is at least double the length I've encountered with an app (for either iOS or Mac) to be reviewed. And in the continuing spirit of inconsistent app reviews, PE 2.6 was rejected since the plug-in is installed in the user's ~/Library/Services/ folder, which is also how Permanent Eraser 2.5.3 handled the plug-in, yet that version had been approved. The work around to this problem is to either remove the plug-in or re-architect the application and build the Service directly into the program. This latter point is already planned for a future release of Permanent Eraser, however it will likely not happen until Permanent Eraser 2.7 or later.

Permanent Eraser 2.5.3

13th January 2012 | Permanent Eraser

Today Edenwaith released Permanent Eraser 2.5.3, an important update for the latest version of Mac OS X — Lion. This update focused mostly on fixing incompatibilities with Lion. Since these improvements focused on Lion, a separate version of Permanent Eraser 2.5.3 was not made for the aging Mac OS X 10.3 Panther, since there would have been no added benefit.

What's new in Permanent Eraser 2.5.3:

2012: It's The End Of The World As We Know It (And I Feel Fine)*

1st January 2012 | Edenwaith

"I've always felt that death is the greatest invention of life. I'm sure that life evolved without death at first and found that without death, life didn't work very well because it didn't make room for the young. It didn't know how the world was fifty years ago. It didn't know how the world was twenty years ago. It saw it as it is today, without any preconceptions, and dreamed how it could be based on that. We're not satisfied based on the accomplishment of the last thirty years. We're dissatisfied because the current state didn't live up to their ideals. Without death there would be very little progress."

Steve Jobs

The preceding quote came from an interview with Steve Jobs in 1995. Ten years later, Steve Jobs would echo the idea of death in the speech he gave at the 2005 Stanford commencement.

The premise of Edenwaith was to develop useful software, often to fill in a gap in the application ecosystem. The radical shift from Mac OS 9 to Mac OS X provided the opportunity for a new breed of application developers to create for this new platform. Apple discarded the previous 17 years of Mac OS development in favor of a UNIX-based OS which would provide the Mac OS foundation for the next 15 to 20 years.

During the early years, the software selection was slim, as established developers scrambled to update their own offerings for Mac OS X. It was during this time that two of Edenwaith's earliest products (EdenMath and EdenGraph) were developed. The calculator provided with the operating system was very simple, and the venerable Graphing Calculator, once a staple third party application on Macs, would not make the transition to Mac OS X for several years. Apple has done an excellent job in not allowing Mac OS to atrophy like it had in the 1990s. Each iteration of the operating system has built upon its predecessor, which filled in many of the gaps and cracks which were visible in the earliest versions of Mac OS X.

Over the past decade at Edenwaith, some ideas have flourished while others have languished. As Mac OS X improved over the years, the need for several of Edenwaith's products came to an end. Rather than let them shrivel on the vine until nothing remains but a dried-out husk, I have decided to retire a number of applications to disrupt the illusion of any life that might be left in these old projects. Some projects will likely not be updated any further, but a couple of projects will see a final update before being put to rest.

2012 will be a time for rebirth, by cleaning out the old to make way for the new. Several years ago the decision was made to focus on a select few applications instead of dividing time and effort amongst a plethora of projects. Our time is finite, so we must decide what do wish to wisely spend our time on, instead of wasting it.

* Apologies to R.E.M.

EdenList 1.1 for iOS

15th December 2011 | EdenList

Today, EdenList 1.1 for iOS was approved and made available on Apple's App Store. The biggest addition to this version is native support for the iPad. Other new features include:

This app's release was delayed by a few days, due to an app rejection since screenshots for the iPad had not been uploaded through the iTunes Connect website. Note: Make sure to scroll down to be able to see the contents of the entire screen. Apple has gotten a little too happy-go-lucky with the disappearing scrollbars motif in iOS and Lion, such that they have extended the UI paradigm to the iTunes Connect website, as well. A little frustrating, but everything was set right and the app is now available.

Another notable change is that EdenList for iOS now requires iOS 4.2 or later. Fortunately, the churn rate for phones tends to be every two years, so I would assume that a majority of the active iOS devices today can run iOS 4.2 or later. Some recent posts have confirmed this thought that a large majority of iOS users are keeping up with recent trends, as long as they have supported hardware. Despite the iPhone 3GS now being over two years old, I'm glad to see that it can still run the most current version of iOS (version 5.0.1 as of this writing) and this model of iPhone is still being sold as the low-end option.

Permanent Eraser 2.5.2

11th July 2011 | Permanent Eraser

Today, Permanent Eraser 2.5.2 was released, with a focus on updating the localizations for the new Preferences window introduced in Permanent Eraser 2.5.

Uli Jon Roth Website

7th June 2011 | Website

Ten years since the release of the last major version, the Uli Jon Roth website has been updated to its fifth incarnation. While not directly related to Edenwaith's software products, this site has been hosted under the Edenwaith domain for several years.

The updated Uli Jon Roth website is the culmination of the past seven years of work to redesign the site for the 21st century. The previous version was designed in June 2001, supporting the web browsers of the day, such as Netscape 4 and IE 5. The Web has evolved over the past decade, and while the old site lived well past its years, the time has finally come to usher in a new version.

This site redesign cleaned out a lot of cobwebs, and uncovered a few hidden treasures along the way. Here's what is new:

Google Chrome

22nd April 2011 | Google Chrome

The first web browser I used was Netscape 3, then soon picked up Netscape 4. During the height of the 90s Browser Wars, I kept a far distance from the other browser, signified by a blue E. When Mac OS X was first released, the choice of native web browsers was fairly limited. While I impatiently waited for Netscape to port their browser to Mac OS X, I searched for alternatives and ended up settling with OmniWeb 4.

This was the beginning of a long relationship with a very functional and flexible browser. I even purchased two licenses for the product, I liked it that much, which is unusual for a product landscape that contains many capable and free browsers. Sadly, the Omnigroup's attention for OmniWeb has waned over the past several years (so they can spend their time on products which actually make money to keep the business alive). I still use OmniWeb as my Power Browser, but as the Web progresses, and new and existing browsers continue evolving, OmniWeb hasn't been able to keep up with the times. I have been experimenting with other web browsers. Safari 5 finally added support for some extensions, but even the extensions seem somewhat limited. Safari is a great browser, which I've used as my Quick Browser when I just want to get in and out, but I miss the flexibility and power that OmniWeb has offered. I then tried Firefox, which is my favorite browser when using Windows. Due to its cross-platform nature, there are a few things which don't feel "quite right". It's a good browser, and the flexibility is good. However, when I upgraded to Firefox 4, I was finding that the browser locked up once a day (an issue I was not seeing with Firefox 3.6). This was getting very annoying, so I took another look at Google Chrome.

I had looked at earlier versions of Google Chrome in the past, but its stripped down, minimalistic appearance initially turned me off. I liked having lots of flexibility and power in my browser. The unified address-search bar seemed to be a step back : that's how OmniWeb 4 used to handle things before OmniWeb 5 added the search bar. However, after using Chrome for the past week, I am greatly impressed. There are many little things which make the browsing experience feel "just right".



EdenList 1.0.1 for iOS

5th March 2011 | EdenList

The first update to EdenList for iOS has been released and is available for download to your iPhone, iPod touch, or iPad.

EdenList 1.0.1 for iOS now can share EdenList files between the Mac and your iOS device (iOS 3.2 or higher required) via the iTunes File Sharing pane.

Future versions of EdenList for iOS will incorporate a native iPad layout and more advanced features for managing your lists.

10 Year Anniversary

13th February 2011 | Edenwaith

Today marks the 10th anniversary of the founding of

The Past...

Edenwaith started with two small products, a Javascript FTP site and the text-based RPG/Adventure game Psychomancer.

2002 saw the introduction of Edenwaith's first set of Cocoa-based Macintosh applications: EdenMath and Untar. The next several years saw a flourishing of additional Macintosh applications, ranging across utilities for file archiving, security, mathematics, entertainment, and audio.

While the first decade of the 21st century proved to be a revitalizing time for Apple Inc., its largest successes came not in the form of its core strengths of computers and operating systems, but from new lines of popular mobile devices. Whereas the Web and Internet created an explosion of new interest in the technical world, the same is now occuring with a new breed of mobile devices, namely cell/mobile phones and light-weight tablet computers. Even though Macintosh sales are better than they ever have been (more than 4 million Macs were sold in Q1 2011), these numbers pale in comparison to the number of iOS devices which are now in the market. Apple can claim an installed Mac OS X base in the tens of millions, whereas the iOS base (iPhone, iPod touch, and iPad) is well over 100 million and accelerating at a much higher rate than Macintosh sales. Since iOS is an extension from Mac OS X, it has been a natural progression for many Macintosh developers to transition to iOS. While Edenwaith has mainly focused on developing utilities for Mac OS X, our first foray into iOS development came to fruition last year — EdenList for iPhone. This is just the first step for Edenwaith into iOS development. EdenList will continue to evolve and new products will come to the iOS platform in the next several years.

Looking ahead...

Ten years ago at this time, Mac OS X was still in beta, the original iPod had not even been announced, and mobile phones were more a novelty than a commodity. It can be difficult to even see five minutes into the future, much less five or ten years down the line of a quicksilver industry. Who would have thought in 2001 that Apple would have surpassed Microsoft's market value in the coming decade?

If anything has been learned from the past ten years when trying to make predicitions is not to make predicitions. They are almost always wrong. Yet, for the sake of amusement, let's make some far reaching statements and guesses about Edenwaith's future.

For the foreseeable future, Edenwaith will continue to work on its active Mac OS X products for as long as they are useful and needed. Several of Edenwaith's earliest products (EdenMath, EdenGraph) were designed to fill in the gaps found in a young Mac OS X. However, as Mac OS X matured, some of the usefulness our products was lost as Apple improved upon their OS and associated utilities. The future is murky to determine, but if anything is certain, change is inevitable. Already the wind of change is blowing directly into developers' faces as mobile developers are in high demand, indicating where current trends are leading.

Edenwaith has made its first baby steps into the mobile arena, and we will further entrentch into this space in the coming years with several new products. Hopefully we will turn back in the direction which started Edenwaith: games. There are a number of other ideas brewing, so we'll need to evaluate how feasible these ideas might be before dedicating time and effort into new projects.

Just as the Web did not kill the Desktop, neither will mobile devices eliminate the need for personal computers and web pages. Edenwaith's Mac OS X products are not going away any time soon, but our direction will likely lead down many new paths in the coming decade. Just as Edenwaith has gone through numerous changes in the past ten years, we expect just as many changes in the next ten. It is not unfair to consider that Edenwaith might wear a completely different mask in 2021. Perhaps some of our current products will be still around. Perhaps there will be an entirely new set of products. Perhaps there will be no products at all. Time will tell...

Check for 64-bit

29th January 2011 | Tutorial

If you have a Macintosh application and you need to check if the OS is running in either 32 or 64 bit mode, here is a code snippet to make that determination.

/* File: check64bit.c
 * Description: Check if the running version of Mac OS X is 64-bit
 * To Compile: gcc -Wall -o check64bit check64bit.c
 * To run: ./check64bit
 #include <stdio.h>
 #include <string.h>
 #include <sys/utsname.h>
 int main(int argc, char *argv[])
 	int ret = 0;
 	struct utsname uname_info;
 	ret = uname(&uname_info);
 	if (ret == 0)
		printf("Uname Info\n");
		printf("Sysname  : %s\n", uname_info.sysname);
		printf("Nodename : %s\n", uname_info.nodename);
		printf("Release  : %s\n", uname_info.release);
		printf("Version  : %s\n", uname_info.version);
		printf("Machine  : %s\n", uname_info.machine);
		if (strcmp(uname_info.machine, "x86_64") == 0)
			printf("You are running in 64-bit mode!\n");
			printf("You are running in 32-bit mode.\n");
 	return 0;


Edenwaith Gist :

GUI Tar 1.2.4

27th January 2011 | GUI Tar

2011 has started off well with two software updates in January. GUI Tar has been updated to address a couple of issues.

At this time, this is the only planned release for GUI Tar this year. GUI Tar is a freeware application which has seen infrequent updates in the past several years, and there are no current plans to heavily continue development on GUI Tar in the foreseeable future. If your archiving needs exceed what Mac OS X or GUI Tar can provide, it is recommended that you look for a more appropriate solution (such as StuffIt, BetterZip, or one of the many other archiving utilities available).

Permanent Eraser 2.5.1

11th January 2011 | Permanent Eraser

A number of people reported having difficulty accessing the new Preferences in Permanent Eraser 2.5.0. Considering that the Preferences was one of the cornerstones for the 2.5 release, this problem needed to be fixed so trying to open the Preferences was not so much of a delicate timing issue. Permanent Eraser 2.5.1 has fixed this problem, so the Preferences window can be opened, even when the initial warning message appears.