Twitter Nostalgia

December 1st, 2006. Something important in my life began rather inauspiciously:

My first tweet.

Little did I realize that these tweets would become a log of important events in my life. And now thanks to Twitter’s new search capabilities, I can remember that past. Please indulge me as I sift through these moments and get nostalgic…

It turns out I was the sixth person to mention “iPhone” on Twitter. My colleague Corey beat me by a few hours and the guy who started Twitter was first. There must have been something in the water at the Iconfactory water that day. I wish all my predictions on Twitter were so prescient!

(Thanks to Dan Frommer for doing the legwork on this one.)

Interestingly, the very next tweet in my timeline was the start of the world’s first Twitter client:

These two tweets, separated by only a few hours, are an amazing summary of what was about to happen.

But first, another important event transpired: I started writing publicly. Twitter was clearly an inspiration here: I loved those 140 characters, but found that I needed another venue to expand upon my thoughts:

Note the date on that last tweet: the day before the original iPhone went on sale. My first post stated that I didn’t know where there I was going with the blog. A few days later, I had a pretty good idea:

I had just bought an iPhone.

And remember that “video iPhone nano gaming system”? Here I am being the first person to display a Twitter timeline on it:

Worlds were colliding: Twitter, iPhone, and a place to talk about both.

Twitter was always an outlet for my strange sense of humor. Depending on your point-of-view, April Fool’s in 2008 was either the best or worst day ever:

It’s now commonly known as the CHOCK LOCK, but it took almost five months for someone to christen it:

And amazingly, just six minutes later:

Both Seth and Michael were spurred on by Dan Wood, so I guess we can blame him!

The iPhone SDK was released in February 2008 and a lot of that early hacking I did on the iPhone was finally turning into a real product. It’s likely that this affection with capital letters was triggered by a shitload of coding.

But all that hard work paid off:

I tweeted that just after being handed an Apple Design Award. Those colliding worlds were good to me.

I’m a firm believer of looking forward in your work, but there’s also value in remembering how you got to where you are today.

And speaking of today, guess when the bulk of this post was written?

Some things never change.

A day with WATCH

As every Apple developer knows by now, WATCH is becoming a reality. If you do nothing else right now, watch the video at that link: it’s a great overview of WatchKit that will only take a half hour of your time.

David Smith put it best: there’s a lot more here than most of us expected. I spent yesterday exploring the APIs and have some thoughts and links to share below.

Software Design

The local and remote nature of WKInterfaceObject feels a lot like the days of a dumb terminal talking to a mainframe. Except this time, the terminal ain’t dumb, and the mainframe fits in your pocket.

But still, there’s RPC going on here, and a lot of the design patterns and limitations are due to that fact. Our IBOulets and IBActions are traveling around in thin air: let’s take a look at what that means.

No customization

WKInterfaceObject inherits from NSObject, but don’t let that fool you. There’s absolutely no customization here: you can’t subclass WKInterfaceWhatever.

If you don’t believe me, try to set a Custom Class for one of the objects in Interface Builder. While this is a limitation, it’s also a good thing for a new platform: it forces consistency in the user interface. None of us have even held an WATCH before, so constraints will help us to not shoot ourselves in the foot.

One thing that some of us are wondering: why aren’t these classes that can’t be instantiated just protocols? Time will tell, I’m sure.

No properties

In a similar vein, these WKInterfaceObject classes aren’t like other UI objects we’re used to dealing with. There are no @properties, only setters. Why?

Querying a property would mean a round-trip over Bluetooth to get a control’s current state. It’s more efficient for your iPhone app to keep track of things instead of consuming power with a radio.

Object marshaling

When you set a property using an object, you may be fooled into thinking that object goes over the wire.

Look at UIFont in an attributed string, for example. If you try to instantiate one of the San Francisco fonts that you find in the SDK, you’ll be surprised that it returns nil. Remember, you’re creating this instance on an iPhone (where the font doesn’t exist) to use on a watch (where it does exist.)

I’m guessing that things like font instances are marshaled over to the device. At this point, it’s important to remember that an object you create may not be the one used in the user interface.

Images

Images are a large part of what makes a great looking app these days. We’ve gotten pretty good at it. Understanding how they work in WatchKit is essential.

It’s best to make your images static resources in the bundle that gets delivered to the watch. It’s expensive to transfer these large assets over Bluetooth. The best experience for the user is to pay that price at the time the watch app is installed.

To get an idea of the extent of this philosophy, download the Lister sample code and look in the Watch App assets for the Glance UI. You’ll find 360 images: one for each degree of the circle’s movement. Your designer is going to love making these images. j/k LOL

Still, there are cases where you’ll need to send images to the watch dynamically. Think about avatars for a social networking service: no amount of memory can hold all the images you’d need for Twitter.

This confused me at first, so I asked someone who’d know. The solution is to use WKInterfaceDevice to add images by name. These can then be used in WKInterfaceImage using the -setImageNamed: method. The image cache can hold up to 20 MB and is persistent across launches. Think of it as a way to dynamically extend the contents of the bundle you delivered during the install process.

Another approach is to create the image on the iPhone and transfer it directly to WKInterfaceImage using the -setImage: method. This is reasonably fast in the simulator, but I’ll bet money there’s a significant lag on the actual device.

WKInterfaceGroup

My first impression of the user interfaces you could design in Interface Builder wasn’t entirely positive. I could create designs that were functional, but I couldn’t personalize the layout. That all changed when I figured out how WKInterfaceGroup worked.

The light went on when I saw that a WKInterfaceButton had a content setting for “Text” and “Group”. When you specify “Group”, you get a container where you can place other items. It was only a matter of time until I ended up with this:

WKInterfaceGroup

The pretty part is the list of objects on the left, not my abuse on the right!

The topmost “Button” uses the group content mode, so it’s layout is defined with a container. That container includes three more items: another blue button with an “A”, a WKInterfaceTimer that counts down, and an image with the “check-all.png” graphic. The Group container uses a red background with another transparent image (the teal arc.)

The interesting thing here is that while you only get one IBAction for the button, you can set up multiple IBOutlets for the items in the container. As a test, I hooked up the button’s action to change the background color of the group, reset the timer, and swap one of the images.

In Interface Builder, the Size and Position settings in WKInterfaceObject’s Attribute inspector let you define where the items in the container are placed and how much space they should use. Since you don’t know if you’re going to be running on a 38mm or 42mm device, think in fractions. The example above uses 0.25 for the button and the timer, and 0.5 for the image.

Power Consumption

Bluetooth Low Energy must be really low power: the design of WKInterfaceObject means it’s going to be on a lot. Every interaction with the watch has the potential to move actions and data between your pocket and wrist using the radio.

But more importantly, this API design gives Apple a simple way to put a cap on power consumption. We saw this approach in the early days of the iPhone and that worked out pretty well, didn’t it?

One final thought about the API design: your code never runs on the watch.

Physical Design

In addition to new APIs, more information about the physical characteristics of the watch have been made available. We now know that the 42mm model has a 312×390 pixel display and that its 38mm counterpart uses 272×340 pixels.

Screen resolution

In addition to its size, the placement of the display on the face of the watch has been documented in the layout section of the Human Interface Guidelines. That has led some of us to estimate the screen resolution.

My calculations put the resolution somewhere above 300 ppi:

Soulver

Since we’re not dealing with engineering drawings here, it’s impossible to be precise. For one thing, we don’t know where Apple is measuring 38 and 42 millimeters. Traditionally, it’s measured from the center of the lugs, but since the WATCH uses a different mechanism, it could be the size of the sapphire crystal.

John Gruber, who has a stellar record at this guessing game, thinks the display will be 326 ppi, just like on the iPhone 6.

But you’ve got bigger problems than pixel perfect design now anyway…

Screen size

The display layout drawings give us enough information to create a reasonable physical facsimile of the watch.

It’s small. Very small.

Much smaller than you think if you’ve been looking at it in the simulator.

You’ll want to download this PDF created by Thibaut Sailly and print it out at 100%. My first thoughts were that my finger covered more than half the screen and that I could fit eight of these displays on my iPhone 6!

After this “physical contact” with the WATCH, some of the controls that we see in the simulator feel ridiculously small. There’s no way you’re going to tap the back arrow in the nav controller with your finger: I’m guessing that control is there solely for developers who are using mice and trackpads to develop their apps.

Mockups

Once you have the PDF to give you an idea of the physical size, you can then start to see how your design works at that scale. Thibaut has already made the world’s ugliest watch and it’s doing important information design work. Here it is showing a simulated scroll view and exploring glance interactions.

You can even take these mockups a step further and strap a phone to your wrist. While it may look and feel a bit strange, there are definitely some interesting insights being discovered in that Dribbble post. The Mirror tool in xScope could be very handy for this kind of work: design in Photoshop, view on your wrist and learn.

These physical interactions with your designs are incredibly important at this point. Wondering why the scroll indicator only appears in the upper-right corner while you scroll your view? I was until I realized that’s where the digital crown is physically located.

Orientation

One thing that none of us are going to miss in WatchKit: you don’t have to worry about device orientation changes.

As my friend, and party pooper, John Siracusa points out, this is probably just a temporary situation. As a fashion accessory, WATCH could easily become a pendant watch.

Where to go from here

So there you have it: a day spent with another revolutionary set of APIs. If you’re just starting out, the links to the HIG and sample code above are great places to start learning.

If design interests you as much as code, you’ll also want to download the Apple Watch Design Resources (the link is at the bottom of that page.) You’ll find all the fonts and Photoshop documents you need to start pushing pixels. But as you saw above, make every effort to put those pixels into physical perspective.

As Apple has stated, this is only the initial phase of the API rollout: fully native apps will be possible later this year. Even though this is a first step, it’s a really good one.

All that’s left to do now is start making awesome apps.

FLASH_LIGHT

Behind The App: Flare 2

Here’s what I’ve been pouring my heart and soul into since the day WWDC 2014 ended: Flare 2.

We started working on this project well before WWDC. A significant redesign that put content first had been completed. A lot of code had been written and the app was working well.

But…

WWDC was a cornucopia for developers. There were suddenly so many new things we could do on both iOS and OS X. It was overwhelming and exciting at the same time.

And…

Three things stood out for us: the new look for Yosemite, iOS 8 extensions, and CloudKit. We had always wanted to do something with Flare that needed these things. It really felt like we won the Apple developer lottery.

We could now create great photographic effects on our Macs and apply them to the photos taken with the camera that’s in our pocket. Perfect. Simple.

But even with a simple and perfect goal, execution is never easy. I think there’s always a lot to learn by looking back at the struggles you encounter during product development, so here are some things Anthony, Talos, Travis, Wolfgang, Sean and I encountered during our journey.

Yosemite’s User Interface

The Flattening

As I noted above, we’re acutely aware of the direction that OS X and iOS user interfaces are heading. We’ve been striving to put content first for a couple of years now. This effort started with Twitterrific 5.

Note the date of the post in that last link: December 2012 was six months prior to iOS 7 and “flat user interfaces” being announced at WWDC 2013. While everyone else was making interfaces like the one on the left, we created the one on the right:

Twitterrific

Click on the image to see a bigger version

We saw the same opportunity to simplify Flare. It was possible to create an app that put the customer’s content frontmost while retaining advanced controls to adjust the photo when needed.

This is where we were at on May 28th of this year. Anthony’s mockup was already very flat and content-centric:

Twitterrific

Of course, after WWDC we realize we could do even more to simplify the user interface. Here’s how the final product turned out:

Twitterrific

(If you’re at all interested in interface design, I suggest downloading a copy of Flare just to try it out. There are a lot of animations and other effects that can’t be expressed in static screenshots.)

As a company, designing and implementing a user interface for Yosemite is a very important exercise. We have clients who want us to help move their apps in a similar direction, and the only way to become an expert with this stuff is by making it.

Here are a few observations from the “Yosemitification” of Flare. (And yes, we used “Yosemitify” frequently in our internal discussions!)

Tint & Themes

The influence of iOS 8 goes beyond the flatness of the design. We wanted to use control tint color to give the user feedback on the state of the application. The tint color also gave us a visual anchor between the two platforms were Flare runs: the purple tint links the user interfaces on iOS and OS X.

Unfortunately, OS X only supports the notion of two tints: blue or graphite. In the end, we wrote our own control cell classes that used a custom tint color. I’m hoping to have the time to open source this code some day: many products besides ours are embracing multiple platforms and these controls will be very helpful to other developers.

Another subtle touch in the Flare user interface: it supports both the light and dark themes in Yosemite. The theme support in Yosemite allows you to change the entire control hierarchy’s appearance at any time. We use this capability as another way to put the customer’s content first: sometimes their photos look best on a black background, other times a white background.

Vibrancy

There was a very common theme throughout Flare’s development. We would add vibrancy to the interface, and then a couple of weeks later, we’d remove it.

Personally, I think it’s a lovely and subtle effect. But it’s just too easy to use it in a way that interferes with usability. Text and other lightly stroked information (such as icons) can disappear on the subtly colored gradients that you have little control over.

The last vibrant holdout in Flare was the header at the top of the list of effects. In fact, we removed it the day before the app was submitted for review! The thumbnail images looked really cool sliding up underneath a transparent header, but since we don’t have control of the content generated by the thumbnails, it was much too easy to have colors that rendered the icons and text unreadable.

(In the screenshot above, you will notice a slight color shift between the header and the thumbnail content that’s not in the final product: the screenshot was created before we removed the visual effects view.)

Vibrancy does still have a place in our app. It works great in the “guided tour” for displaying help over the content and controls of the interface. This guided tour is also a piece of UI that we’re all very proud of: we wish we could sit down with every customer and say “Hey, look at this!”, but this tour is a really great alternative.

iOS 8 Extensions

Tools

Let’s just say things were a little rough development-wise at the beginning. Extensions are an awesome addition to both OS X and iOS, but as with anything new, they were also fragile. At one point, the only debugging tool was my old friend printf(). Not having Instruments available to track down memory leaks makes you appreciate the awesome power of that tool.

As new versions of Xcode came out during the iOS 8 beta, the situation improved steadily. This is why they call it the “bleeding edge.” I just want to know why I always forget this when starting out with something new and shiny :-)

I’ll have some more to say about these tools in the very near future: I’m working on a field guide for iOS extension development.

Memory

As someone who developed an app on the original iPhone using iOS 2.0, I didn’t think there would ever again be so many problems with managing memory. I was wrong.

Creating the Photos Extensions in Flare Effects was a huge challenge. First off, the most recent cameras have very high resolution. For example, the native size on my iPhone 6 is 2448 x 3264 pixels. That’s over 20 MB of source data you need to deal with.

These big images are being handled in an XPC process that runs at the same time as the Photos or Camera processes. You’re not the only one who’s dealing with a lot of pixels.

Compounding this is the fact that you usually need several of these big images around for compositing and other effects. Luckily, a lot of the magic in Flare (and iOS 8 in general) is done with Core Image, so a lot of the heavy memory requirements can be offloaded to the GPU via OpenGL ES. But even then, you have to be very careful: a post on Stack Overflow about managing textures across thread boundaries, literally saved our ass. I owe Max a beer.

Wolfgang did some amazing work to get our very complex filters running smoothly on iOS. Despite the APIs for Core Image being nearly identical between OS X and iOS, the data and parameters you feed the filters have very different requirements. Textures, scaling factors, extents and many other things had to be adjusted for the new platform!

The situation with memory was a constant struggle. In fact, it was even an issue after we had the app approved and ready for sale. We discovered a crashing bug that only happened on the iPhone 6 Plus because it needed a @3x preview image that weighed in at over 20 MB! Rejecting a binary and resubmitting for review the day before an Apple Event is not for the faint of heart.

CloudKit

As developers we often complained about the opaqueness of iCloud. Things would happen and you’d have no idea what was going on behind the scenes.

With CloudKit, that all changed. We’re now responsible for every little thing. Every response, every error, every piece of data. That’s a good thing, but the age-old fact remains: syncing is hard.

Luckily, my colleague Sean likes hard problems and built a syncing system that “just works”. Even then, we’re a little afraid we haven’t covered all the bases: just before submitting the app for review, we discovered an issue where expired tokens weren’t being handled correctly (because we’d switched from the development servers to the production servers.) To be honest here, our fingers are still crossed as we deploy this to millions of potential customers.

Still, the flexibility and breadth of this new API makes it all worthwhile. It makes it possible for us to get cool and free photo effects to folks on iOS even if they don’t use our Mac product. Doing something like that prior to iOS 8 and CloudKit would have been cost prohibitive from an infrastructure point-of-view.

Conclusion

So there you have it, a roundup of all the fun stuff that went into making Flare 2. We hope you enjoy it!

Device Log Douche

The new Devices window in Xcode 6 has been a constant source of grief for the past few months. Getting device logs was an exercise in frustration which usually resulted in me admitting defeat (and without my logs.)

Over the weekend, I found a 2.21 GB answer:

iOS_Device_Logs

I’ve been developing iOS apps since the beginning of time. I had over 7,000 crash logs in my ~/Library/Developer/Xcode/iOS Device Logs folder! Every time I opened the new Devices window Xcode would tell me it processing some very old crash logs: at one point I saw one from 2008 go by! All this useless work prevented me from getting to the most recent reports.

It appears that newer versions of Xcode store the crash reports in a Core Data SQLite database. Both the raw and symbolicated reports are kept in the iOS Device Logs folder:

$ sqlite3 "iOS Device Logs 6.0.1.db"
sqlite> select count(*) from zrawlogtext;
1840
sqlite> select count(*) from zlogtext;
1840

I first tried removing all the old .crash files. Xcode still insisted on processing, so it must be working on stuff already captured in the SQLite database. When I removed the most recent database, I was greeted with an Xcode hang after clicking on the “View Device Logs” button.

A spindump showed that Xcode’s DTDKCrashLogDatabase class was doing a -performBlockAndWait: on the main thread. I’m guessing that Xcode was trying to copy over databases from previous versions as some kind of migration process.

In the end, I removed everything in the iOS Device Logs folder and can now use the Devices window as it was intended.

Note for Apple folks: A Radar with the spindump is here: rdar://18489861.

In-App Browsers Considered Harmful

How many apps on your iPhone or iPad have a built-in browser?

Would it surprise you to know that every one of those apps could eavesdrop on your typing? Even when it’s in a secure login screen with a password field?

Here is a proof-of-concept (ZIP file) that shows how an app can do this. For those of you who don’t have Xcode installed, here’s a video that shows what’s going on:

A few things to note about what you’re seeing:

  • The information at the top of the screen is generated by the app, not the web page. This information could easily be uploaded to remote server.
  • This is not phishing: the site shown is the actual Twitter website. This technique can be applied to any site that has a input form. All the attacker needs to know can easily be obtained by viewing the public facing HTML on the site.
  • The app is stealing your username and password by watching what you type on the site. There’s nothing the site owner can do about this, since the web view has control over JavaScript that runs in the browser.
  • The site content is also modified: the text on the button label is normally “Sign in” and has been changed to “SUCK IT UP”. It seemed appropriate.
  • This technique works in iOS 7 and 8 (and probably earlier versions, but I didn’t have an easy way to test them.)

OMFG APPLE IS HACKING ME

No, this is not a WebKit bug.

The Shadow DOM does a great job of protecting static user content on a web page. It’s not possible to use JavaScript to view the contents of an input field on iOS since the current value attribute is actually being held in a platform-native control. The value of that control is uploaded when the user submits a <form>.

I don’t know for sure, but I suspect that the keyCode attribute of the KeyboardEvent in the JavaScript event handler is provided for backward compatibility. This API has been deprecated but there are still plenty of web pages out there that use it to handle keyboard input.

In fact, both the techniques shown in the sample app can be used for good as well as evil. Changing the content of a web page is a good thing when it’s done to make a page more readable or accessible. Handling keyboard events can also guide a user through a complex form or make viewing a slide show easier.

These are not inherently bad web technologies. The problem is that an iOS app has as much access to these technologies as the developer of the web page.

OAuth To The Rescue. Or Not.

Websites have been dealing with username and password attacks for as long as there have been <input> fields on their pages. One of the primary goals of OAuth was to keep a user’s login information away from an external website or app.

OAuth does this by exchanging cryptographically signed tokens between the site where the user has an account and the app or web service that wants to access that account. A key factor in making this secure is that the exchange of these secure tokens is done through a trusted channel: the user’s web browser. Twitter has required third-party developers to use OAuth since 2010.

As early as 2008, the developers of OAuth recommended the following:

We’re trying to ensure that users are only exposed to the safest way to disclose their location using OAuth. To do this, it’s critical that a fundamental principal of browser-based authentication is followed; that the contexts of the third party application and the web service authentication remain separate. To allow users to grant trust to an application, they must perform the OAuth action within their web browser, not within the applications themselves. Otherwise, there is no way to verify the identity and authenticity of any page which asks for their username and password. Users must not ever enter their username and password into a third party application when a browser-based authentication API like OAuth is available.

There is always a tradeoff between usability and security. Doing the OAuth token exchange with an in-app browser makes it easier for a user to login, but they’ll have no idea if their personal information was captured. That is why Twitterrific did its token exchange in Safari, even though it’s a more complex user interaction and a more difficult technical implementation. As a user, I know that there’s no way for my login to be compromised when the transaction involves Safari.

Unfortunately, Apple’s current App Review policy does not agree with this recommendation or with Twittterrific’s previous implementation. This is why our update for iOS 8 was delayed—it was the first time since the launch of the App Store that we haven’t had a new version on release day.

(Apple folks can learn more about this situation by reviewing Radar #18419943)

Recommendations for Apple

Apple has taken a strong and welcome stance on privacy. They’ve recently been implicated in some high profile attacks so they definitely have skin in this game. Hell, they even want to protect us from the US government watching what we do online!

There’s no denying that the behavior demonstrated above could be very harmful in the wrong hands. It’s also Apple’s job as the gatekeeper for iOS to keep malicious apps out of the App Store. But how?

I don’t think it’s feasible to catch misbehaving apps at review time. There are a huge number of apps that need to be reviewed every day, especially when new versions of iOS are released. Many of these apps use in-app browsers which would require extra time and effort to vet. Longer review times benefit no one: developers, Apple and our customers need timely updates.

It’s also very easy to an app to hide any nefarious activity. JavaScript has an eval() function that makes it easy for code to be obfuscated and very difficult to be checked at review time. Look at this page and see if you can guess how the uppercase text was created. Then view the HTML source and see how wrong you were.

Additionally, an app that wants to collect your information can easily implement a remote switch that disables the functionality while the app is in review. App reviewers won’t stand a chance.

Changing how WebKit and UIWebView behave isn’t practical either. To prevent this keylogging technique, Apple would need to release a new version of iOS for each version that included Safari and WebKit. Do you really think they’re going to do a point release of iOS 3?

And this brings me back to protecting users with OAuth. It’s designed to avoid these problems and works well to maintain privacy. Granted, it goes against section 10.6 of the App Store Review Guidelines, but in my opinion, this is a case where user security trumps usability. Apple should change their policy for apps that use OAuth.

Recommendations for Users

Another goal of this essay is to increase user awareness of the potential dangers of using an in-app browser. You should never enter any private information while you’re using an app that’s not Safari.

An in-app browser is a great tool for quickly viewing web content, especially for things like links in Twitterrific’s timeline. But if you should always open a link in Safari if you have any concern that your information might be collected. Safari is the only app on iOS that comes with Apple’s guarantee of security.

(For the record, we never collect any private information in any of the Iconfactory apps. And we never will.)

Xcode vs. Gatekeeper

Have you noticed how launching a new beta version of Xcode seems to take forever the first time you do it?

There’s a reason for that and its name is Gatekeeper. When you double-click on that shiny new icon, you’re asking your Mac to compute a checksum on tens of thousands of files using over 5 GB of space. That’s going to take awhile.

If you trust the source of the file, there’s no harm in removing the flag that causes Gatekeeper to perform this check:

$ cd /Applications
$ xattr -d com.apple.quarantine Xcode6-Beta7.app

Now, when you launch that new version it will open up immediately and won’t annoy you with the dialog asking if it’s OK. How many collective developer hours will this little trick save?

For more info on xattr, check this out.

Updated September 9th, 2014: As Greg Parker points out “trusting the source” means that you’re absolutely sure that both the DNS and network between you and Apple hasn’t been compromised. My personal opinion is that if those things happen, I have a much bigger problem than an Xcode download (e.g. someone can watch all my transactions with iTunes.) Your mileage may vary.

The Terminal

I’ve been using the Unix command line since 1983 and like most software developers, the Terminal app is a permanent fixture in my Dock. Over the years I’ve learned a lot of things that make working in this environment more productive, but even old dogs like me are constantly learning new tricks.

As much as I love them, these long “trick lists” on Stack Overflow have a problem: they’re poorly organized with little narrative describing why you’d want to use a technique. This long homage to the command line is my attempt to remedy that situation.

Note: I originally learned the shell using the newfangled csh (which was a huge improvement over the original sh.) When I first started using Mac OS X, I tweaked it to use tcsh because that’s what I knew and loved. Over time, I gave up using these tweaks and started using the default shell: bash. The following examples assume that you’re doing the same.

Editing Keys

My most recent discovery, and the one that made me realize a post like this would be helpful to a lot of fellow developers, was the revelation that an option-click in the Terminal window emulates arrow keys.

Say you’re entering the following in the command line:

$ echo "this is a test"

Oops! You left out “awesome” and now find yourself tapping the left arrow a bunch of times before entering the missing word. The pain increases linearly with the length of the command line you screwed up. If your Mac keyboard is anything like mine, the arrow keys are shiny from constant wear and tear.

Luckily, you can give those keys a bit of a rest with this simple trick: try Option-clicking on the first letter in “test”. The cursor is just where you want it and you haven’t touched the arrow keys!

To get a better idea about how this works, try this:

$ cat -v

Now, press the arrow keys. The terminal emulator sends an escape (^[) followed by an open bracket and then A for up, B for down, C for right, and D for left. Now hold down the Option key and click with the mouse: the Terminal app just emits arrow keys to move the cursor block between the source and destination locations. This means it also works in tools like vi or even the Xcode debugging panel: a huge time saver just got even better!

(Use Control-C to get out of this echo mode and back to your shell prompt.)

While we're on the Option key, you can also hold it down while using the left and right arrows to move the command line cursor by a full word instead of a character. Which is exactly what you need when your editing a path with a missing directory name.

The command line also responds to control keys. The ones I use the most are Control-A and Control-E to move to the beginning and end of the line. Control-U and Control-K are also useful to delete text from the cursor to the beginning and end of the line buffer. I've heard that these are standard emacs key bindings, but can't confirm this since I'm a vi LOVER NOT A LOSER

Note that the Control and Option keys also work in standard Cocoa controls. In a Finder window, you can use Command-Shift-G to change the folder path and then use same muscle memory that you've acquired in the shell.

For those really long commands, you'll probably want to get into a more comfortable editing environment. Just use Control-X followed by Control-E to open the command buffer in your EDITOR. (More about setting up the EDITOR in just a bit.)

Another great key to know about is Tab. Try entering this:

$ ls /Vol

Press Tab once and it completes "/Vol" to "/Volumes". Press Tab twice and you'll see a list of all mounted volumes. Welcome to the Lazy Typist Club™.

Shell Setup

As I mentioned earlier, I no longer configure which shell I use on a new OS X install. I do however, change the bash configuration on every Mac I touch.

Every time a new Terminal window is opened a shell process is created with your current login. As the shell is initialized, the .profile file in your home folder is used to initialize the interactive shell. Basically, you can think of .profile as a bunch of typing you don't have to do each time a new Terminal window is created.

(The name .profile dates back to the original sh. See "man bash" for a ton of more info and options.)

Here's my .profile. I like to keep it fairly simple:

alias ll="ls -lahL"
alias con="tail -40 -f /var/log/system.log"

bind '"\e[A":history-search-backward'
bind '"\e[B":history-search-forward'

export EDITOR="vi"
export CLICOLOR=1
export XCODE="`xcode-select --print-path`"
export PATH="/Users/CHOCK/bin:$XCODE/Tools:$PATH\
:/opt/local/bin:/opt/local/sbin"

Let's take a look at each group of settings.

Aliases

Aliases let you define command shortcuts. Since I'm old and forgetful, there aren't many. I used to have a lot of aliases, but found myself constantly using the alias command to list them out and find the right one. Which, of course, defeats the entire purpose of a shortcut.

The alias ll lets me list files in a format that is more readable, especially with the large files. I like using con instead of firing up the Console app (which is total overkill for most situations.) It should be pretty obvious how to create your own aliases. A lot of the command tricks you'll learn below will be good candidates if you use them often enough.

Search Setup

By default, the shell allows you to use Control-R to search previous commands. After typing the control sequence, your command history is searched for each letter that you type. Cool idea, but in my opinion, it's a terrible user experience. The reason is that my history is filled with entries that are very similar. If you have both "ssh CHOCKMASTER@domain1“ and "ssh CHOCKMASTER@domain2“, there's just too much typing to get the right match.

The next two lines in my .profile solve this problem: the bind command tells the shell to do a history search when the up and down arrow keys are used. When the shell is in this mode, you can just type "ssh" and then use the arrows to select the command you want to run again. This fits my needs much better and feels more consistent with the shell's default ability to move through the history with the up and down arrow keys if you haven't entered any text into the edit buffer.

Environment Variables

Finally, there are the environment variables. Again, i've whittled it down to the bare essentials. The EDITOR variable is used by Control-X, Control-E in the shell and lots of other tools. You can change it to emacs, but then I'd laugh at you.

The CLICOLOR variable is used by the ls command to show files and folders with color coding. You can change the colors using the LSCOLORS environment variable, but the configuration string is just too damn arcane for me, so I skip it and go with the defaults. See the man page for ls to learn more about the color coding and the options.

Finally, there's the PATH environment variable. The items, separated by a colon, are directories in the file system that contain the commands I use. By default, these paths are "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin".

I have a bunch of command line tools and scripts that I've accumulated over the years and they are all in the bin directory of my user folder. I also use MacPorts, so the /opt binaries get added to the end of my path.

Note: I've added a backslash to the end of the first line that contains the PATH definition. This is the "line continuation character" and can be used to break up lines that are too long for your editor, terminal or the narrow column of this web page :-)

If you use Xcode, you might find it handy to put the /Tools folder in your PATH. If you want command line access to the same versions of gcc, git, svn and other tools that Xcode uses, you can substitute /Tools with /usr/bin. Since I prefer to use MacPorts to get specific versions of the tools I use, I generally don't need access to Xcode's binaries. If I do, it's easy enough to do this:

$ $XCODE/usr/bin/gcc --version

Note that since the .profile is only read when the shell starts, the XCODE environment variable won't be correct if you run xcode-select after the shell is started. This is usually only a problem if you're juggling multiple versions of Xcode and can easily be solved by closing the Terminal window and opening another.

Shell Scripts

As I said before, I populate my ~/bin directory with a bunch of useful tools that I've developed over the years.

Two of my favorites scripts in that repository are psc and opensim.

psc

The first script is an oldie but a goodie (note the shebangtcsh!). I named it psc:

#!/bin/tcsh
set cmd = 'ps axo pid,ppid,user,command'
if ("$1" == "") then
  $cmd
else
  $cmd | grep "$1" | grep -v "grep $1" | grep -v "bin/psc"
endif

It's a wrapper for ps that shows all of the process' command and can target it for a specific app. For example:

$ psc Xcode
15401   150 CHOCK  … Xcode -psn_0_26982842
15476 15401 CHOCK  … XcodeDeviceMonitor --bonjour _15401

Now you'll see all of the processes that have "Xcode" in the command. The process ids are also shown, so you can kill them, of course.

I also find that seeing the parent process id, which is shown in the second column, is important in these days where everything seems to be a child of launchd. It's also helpful for finding things like XPC processes and other items that get executed from an app's bundle.

opensim

If you're an iOS developer, the opensim script is very helpful for finding your app's sandbox folder in the Simulator. Here's the script:

#!/bin/sh 

if [ -z "$1" ]; then
  echo “usage: $0  [ Preferences |  ]”
else
  base=~/Library/Application\ Support/iPhone\ Simulator/
  apps=Applications
  app=`ls -1td “$base/”*”/$apps/”*”/$1.app” | head -1`
  if [ -n "$app" ]; then
    dir=`dirname “$app”`
    if [ "$2" = "Preferences" ]; then
      open “$dir/Library/Preferences”
    else
      open “$dir/Documents/$2″
    fi
  fi
fi

And here's how to use it.

Version Control

Most of the other stuff in my ~/bin directory are utilities that help with my own workflow (managing servers, testing, backups, etc.)

One of the reasons I prefer to keep these kinds of tools in separate files (as opposed to aliases) is that they're easier to manage from a version control repository. When I set up a new machine, I just go to the User's home folder and checkout my bin directory. Fin.

Another reason that I use files instead of aliases is that they're easier to search. For example, if I'm looking for a script that I wrote three years ago and I know it uses ssh, I just do this to jog my memory:

$ grep -li "ssh" ~/bin/*
/Users/CHOCK/bin/connect
/Users/CHOCK/bin/rsync_host
…

Shell Tricks

Once you get your shell setup, it's time to learn some of its most useful tricks.

History

The shell remembers everything you type. With a few simple characters, you can avoid retyping. The first two are !! which repeats the last command entered. I'm ashamed to admit that I do this every time I edit my /etc/hosts file:

$ vi /etc/hosts

"Oh crap, it's read only."

:q
$ sudo !!

If you just want to reuse the last item in the command, which is typically a file name, then you can use !$:

$ cat TODO.txt
$ rm !$

Merlin has Inbox Zero. I HAVE TODO LIST ZERO

The history command will give you a list of the last 500 things you've typed:

$ history

That's a lot of stuff, huh?

If you want to execute one of those commands again, just use an exclamation point followed by the sequence number. For example:

$ !100

Because the history list is so long, there are a couple of strategies for dealing with its size. The first is to do a simple search:

$ history | grep “BLOW”

Alternatively, you can use use less to search the list interactively:

$ history | less

There are a few other ways to reuse your shell history: do a search for "Event Designators" in the bash manual page.

Command Substitution

Another powerful feature of the shell is command substitution. When you place back ticks around a command, the results are used in the current command. For example:

$ xcode-select --print-path
/Applications/Xcode.app/Contents/Developer

$ cd `xcode-select --print-path`

$ pwd
/Applications/Xcode.app/Contents/Developer

Not only does this save typing, but it makes sure that you're in the right place if you have multiple versions of Xcode installed. Bring on the beta releases!

Note: This is essentially how I setup the $XCODE environment variable in my .profile earlier.

Command substitution isn't limited to just paths, either. Try this:

$ `which svn` --version

Desktop Integration

As software developers, we live in two worlds: the command line and the desktop. Not surprisingly, Apple has provided several tools that helps you unite these two worlds. The following are some of my favorites.

open

The first tool is called open. Both the name and a manual page that says "opens files and directories" belie its true power.

For example, say you want to open the shell's current directory in a Finder folder. It's this easy:

$ open .

If you want to reveal the enclosing folder for a directory or file, then just add the -R parameter:

$ open -R .

The default is to open a file item in the Finder, but you can also specify and application using the -a parameter. Here are a few examples:

$ open -a Terminal /Users/CHOCK/DOT_PRON

$ open -a Preview Default.png 

$ open -a TextEdit README.txt

$ open PUMPERNICKLE.dmg

Since this is a Unix tool, you can open the standard input in an application using the -f parameter:

$ cal | open -a TextEdit -f

The open command assumes that text will be used for standard input, so if you want to use it with other file types, you'll need to use a temporary file. For example:

$ temp="/tmp/CHOCKIFY.HTML"; \
    curl -s http://iconfactory.com/ | \
    tr "[a-z]" "[A-Z]" > $temp; \
    open -a Safari $temp

And since URLs are just another kind of file in OS X, you can use open to download them:

$ open http://files.iconfactory.net/downloads/miscellaneous/xScope_Presskit.zip
$ open http://CHOCKLOCK.COM/NOSY/CHOCKERSIZE.GIF

Or open your favorite network share points:

$ open afp://datacenter.nsa.gov/CHOCK/UNDIES

You can also include a "username:password@" before the host name, but I recommend that you just let the Finder prompt you for the login information. Remember that your shell history contains the last 500 things you've typed, so protect yourself from some smart-ass like me that sits down in front of your Terminal and does this:

$ history | grep -e "ssh" -e "afp"

Drag & Drop

As you can see, there are many different ways to go from the command line to the desktop. Conversely, going from the desktop to the command line is remarkably simple: you can drag any file or folder from a Finder window into the Terminal window and you get it's path.

Boom.

Clipboard

As developers, we live and die by our clipboard. Code and data moves between different contexts all day long thanks to Cocoa's NSPasteboard. It should not be surprising that pbcopy and pbpaste are simple and powerful integration points at the command line.

Want to see the contents of your clipboard or put it in a file? Here you go:

$ echo `pbpaste`

$ pbpaste > /tmp/ELMERS.TXT

Going the other direction, you can copy the current month's calendar to the clipboard and then paste it into another app:

$ cal | pbcopy

Simple!

defaults

Most apps have preferences that are managed by NSUserDefaults. You can easily view or modify these settings from the command line using the defaults command.

Let's start by looking at all the preferences for Xcode:

$ defaults read com.apple.dt.Xcode

Looks more like a database than preferences, right? Every setting is shown with its key and associated value.

If you're interested in a single key, you can use it to limit the output. Say you want to get the information of every iOS device you've used in the Xcode Device Manager:

$ defaults read com.apple.dt.Xcode DVTSavediPhoneDevices

You can also specify a new value after the key. Set the one true tab width using:

$ defaults write com.apple.dt.Xcode DVTTextIndentTabWidth 4

Sometimes settings are used to persist data across launches. There are often cases where you want to get rid of things without wiping out the entire database. Here's an example of removing the recent text completions in Xcode:

$ defaults delete com.apple.dt.Xcode \
    DVTTextCompletionRecentCompletions

Note that using the defaults command is much safer than editing a .plist file in ~/Library/Preferences by hand. Beginning in Mavericks, there is a cfprefsd daemon that manages and caches updates to these files. If you use a text editor to modify the file directly, both you and your app will get confused when the changes don't propagate through the cache managed by the daemon.

say

You know your Mac has pretty great speech synthesis built-in. But did you know is available from the command line as well? Say hello to:

$ say hello

Do you ever find yourself with a process that takes a really long time to run? Something like realigning the cores on Marco's new Mac Pro:

$ ./realign_core_processing_units ; say "cores realigned"

When the script finishes running after a few hours, you'll hear "cores realigned". Even if you’re not looking at the Terminal window, you’ll immediately know why everything feels so much snappier.

Now imagine the fun you can have when you ssh into a designer’s Mac with an open Skype microphone nearby:

$ say “I’m getting a tingling sensation in my hard drive.”

Hugs and kisses, Louie.

screencapture

Speaking of designers, one of the best ways to communicate with them is through pictures. The screencapture tool let's you do some things you can't do using the Command-Shift-3 and Command-Shift-4 keys in the Finder.

If you need to take a screenshot of the entire screen and want to put it in a new email message, just do this:

$ screencapture -C -M /tmp/image.png

Sometimes you need to get things setup before taking the screenshot (opening menus, for example.) So just tell screencapture to wait ten seconds:

$ screencapture -T 10 -P /tmp/image.png

The -P option tells the tool to open the captured image in the Preview app, too. That's often helpful to make sure you got everything you wanted in the shot.

If you're going to paste the image into an image editor, use the -c option to put the shot on the clipboard:

$ screencapture -c

If you're interested in getting just a portion of the screen, use the -s to select a portion using the mouse. You can also specify different output formats with -t option:

$ screencapture -s -t pdf /tmp/image.pdf

As you've seen, this tool has a lot of options, so I usually refresh my memory with the built-in help:

$ screencapture -h

mdls and mdfind

Spotlight search on the Desktop has become an essential tool for developers. We find code, documentation, messages and all kinds of information that's related to our projects using Command-space and a simple text field. Would it surprise you to know that you can do more complex searches of the same dataset using the command line?

To give you and idea of how much searchable data is available for Spotlight, use the following command on one of your Mac's hard drives:

$ sudo du -sh /Volumes/ELEVEN/.Spotlight-V100
1.6G	/Volumes/ELEVEN/.Spotlight-V100

The Spotlight index on my MacBook Air's 256 GB drive is a whopping 1.6 GB.

So how do we dig around in this huge database? The first step is to get an idea of what the key/value pairs in the index look like. The mdls tool is the way to do this:

$ mdls ~/Documents

Try this command on a few document files as well (folders and files have different metadata.) The keys usually start with "kMD”. For example, an item’s name in the filesystem is stored with the kMDItemFSName key. The values are everything after the equal sign.

Now that you've got an idea of what keys and values can be used, let's do some searching!

At its simplest, mdfind is a command line version of the Spotlight search in the upper-right corner of your menubar:

$ mdfind -interpret "BOOGIE WOOGIE"

FYI THATS AN INTERPRETED DANCE DUH

This facility starts to get more powerful when you start using keys and values in the query. For example, this is a simple query that lists all items, both files and folders, that have a custom icon:

$ mdfind "kMDItemFSHasCustomIcon == 1"

(Remember this command when we start digging around in resource forks below.)

These queries can be combined with || or && to form more expressive searches. Here's how you'd find all Photoshop files that have a layer named "Layer 1":

$ mdfind "kMDItemLayerNames == 'Layer 1' \
    && kMDItemContentType == 'com.adobe.photoshop-image'"

I found out that PSD files have a kMDItemLayerNames key by using mdls on a sample file. This is generally faster than Reading The Fine Manual.

The search through the metadata can also be limited to items that are in a specific folder. For example, here's how you'd find all the items in a Project folder that have been localized in Japanese:

$ mdfind "kMDItemLanguages == 'Japanese'" \
    -onlyin ~/Projects

Another great feature of mdfind is that you can pipe it's output to xargs to run other shell commands on the results. For example, the following command will find all apps that are PowerPC-only and send them to xargs (note the usage of -0 in both commands to delimit the listed items.) In turn, xargs will use du to show how much space each app uses and a grand total at the end:

$ mdfind "kMDItemExecutableArchitectures == 'ppc' \
    && kMDItemExecutableArchitectures != i386 \
    && kMDItemExecutableArchitectures != x86_64" -0 \
    | xargs -0 du -sh -c

If you're like me and have been migrating your Applications folder for years, there are a surprisingly large number of items that are wasting space. Doing the actual work of removing these items is left an exercise for the reader.

(Hint: rm is a shell command just like du. Be careful and backup first.)

Application Integration

It's incredibly handy to control your desktop apps using the shell. Since AppleScript has always been the best way to control apps, it makes sense that there would be a command line tool. The osascript tool is one the Swiss Army would love.

Want to change the volume of your speakers with a shell script? Go for it:

$ osascript -e 'set volume output muted true'
$ sudo osascript -e 'set volume 10'

You can also tell the Finder to do common chores:

$ osascript -e 'tell application "Finder" to empty trash'

It's the end of a long work day and you have a script that needs to run for a few hours. It would be really nice to sleep your Mac after that job is finished, wouldn't it?

$ ./realign_core_processing_units; \
    osascript -e 'tell application "Finder" to sleep'

It's kind of a shame that Marco won't be there to see how snappy the realigned cores are, but hey, whatever.

AppleScript from your shell can also relieve frustration:

$ osascript -e 'tell application "Messages" to quit'

Note that this is a more friendly way to do it than killall Messages since the "quit" Apple Event gives the app a chance to shutdown gracefully. Not that Messages would really notice.

If you want to switch from the Terminal to another application, use this:

$ osascript -e 'tell app "Safari" to activate'

You can also use AppleScript to get information about apps:

$ osascript -e 'id of app "Xcode"'
com.apple.dt.Xcode

$ defaults read `osascript -e 'id of app "Xcode"'`

Or get the properties of any file or folder:

$ osascript -s s -e 'tell application "Finder" ¬
    to get properties of item POSIX file ¬
    "/tmp/HOTT.png"' > /tmp/HOTTNESS.txt

$ cat /tmp/HOTTNESS.txt 
{class:document file, name:"HOTT.png", index:2, displayed name:"HOTT.png", name extension:"png", extension hidden:false, container:folder "tmp" of item "private" of startup disk of application "Finder", disk:startup disk of application "Finder", position:{-1, -1}, desktop position:missing value, bounds:{-33, -33, 31, 31}, kind:"Portable Network Graphics image", label index:0, locked:false, description:missing value, comment:"", size:49547, physical size:53248, creation date:date "Saturday, July 5, 2014 12:01:52 PM", modification date:date "Saturday, July 5, 2014 12:01:52 PM", icon:missing value, URL:"file://localhost/private/tmp/HOTT.png", owner:"CHOCK", group:"root", owner privileges:read write, group privileges:read only, everyones privileges:read only, file type:missing value, creator type:missing value, stationery:false, product version:"", version:""}

Note the use of ¬ as AppleScript's line continuation character. You can get this character into your editor by using Option-L on your keyboard.

File Tools

We're developers. We love files. In more ways than ls, cat, and rm can ever know.

Let's meet some new friends...

file

How often have you opened a Get Info window in the Finder just to know the dimensions of an image or other basic information about a file in a project? The Finder is fine, but you're already at the command line, so just use file instead:

$ file Default.png
Default.png: PNG image data, 640 x 1136, 8-bit/color RGB, non-interlaced

Getting the file information from the command line is often faster if you're dealing with a lot of different resources. For example, when your designer gives you a bunch of PNG files and you need to set sizes for them in code, here's how you get all the non-2x dimensions:

$ cd Images
$ file *[^2][^x].png

Much quicker! And file can tell you things that the Finder can't. Like the architectures supported in a binary:

$ cd /Applications/iTunes.app/Contents/MacOS
$ file iTunes
iTunes: Mach-O universal binary with 2 architectures
iTunes (for architecture i386): Mach-O executable i386
iTunes (for architecture x86_64): Mach-O 64-bit executable x86_64

This is particularly helpful when you're getting link errors for a .dylib library that's in your project: file will probably tell you that an architecture you need is missing.

You can throw pretty much anything at file:

$ file Notes.rtf 
Notes.rtf: Rich Text Format data, version 1, ANSI

$ file Wallpaper.psd 
Wallpaper.psd: Adobe Photoshop Image, 744 x 1392, RGB, 3x 8-bit channels

$ file Rubylith.qtz 
Rubylith.qtz: Apple binary property list

$ file Colors.pdf 
Colors.pdf: PDF document, version 1.1

$ file xScope.entitlements 
xScope.entitlements: XML  document text

Note that it doesn't know that .entitlements is an XML plist. But we've still got less to figure that out.

It's amazing how many different types of files can be examined using this simple command. To get an idea:

$ ls /usr/share/file/magic

$ less /usr/share/file/magic/apple

If you ever run across a Newton package or some Applesoft BASIC, file has you covered.

Quick Look

As its name implies, Quick Look is an extremely fast way to check the contents of a project asset. Want to make sure your iOS app's launch images are correct without leaving the command line?

$ qlmanage -p Default*.png

The arrow keys let you scroll through the images and a tap on the space bar gets you back at a command prompt. This is a much quicker and easier way than viewing the images with Preview or an open command—your hands never need to leave the keyboard!

To make this even easier, I have a short shell script named ql:

#!/bin/sh
qlmanage -p "$@" 

I use it every day to check one or more files:

$ ql single.png multiple/*.{png,jpg}

Extended Attributes

While Spotlight’s index is an external source of metadata about files, the OS X file systems also support extended attributes. Like Spotlight’s metadata, these can be thought of as key/value pairs that are attached to any regular file or directory.

To view these attributes, you use the xattr utility:

$ xattr ~/Downloads/tweets.zip 
com.apple.metadata:kMDItemDownloadedDate
com.apple.metadata:kMDItemWhereFroms
com.apple.quarantine

Another way to get the same information is to use the -l@ option with ls.

The tweets.zip file that was downloaded has three extended attributes. But what’s in these attributes?

The simple answer is that you don’t know: the use of reverse domain names is the first hint that the data is application-specific. Apple clearly uses these attributes for their own internal needs. Additionally, any application can attach its own information to a file using this mechanism.

In practice though, you can usually figure out what’s being stored there using the -p and -lp options. For example, after you look at the contents of the attribute, it’s a pretty safe bet that com.apple.quarantine is used to mark files that have just been downloaded:

$ xattr -p com.apple.quarantine ~/Downloads/tweets.zip 
0001;50d603ed;Safari;8DDC53C8-E2E2-4F1F-88DD-8F940F4CF93E|com.apple.Safari

In fact, if you want to skip the warnings from the Finder about the dangers of opening files, you can remove the quarantine attribute:

$ xattr -d com.apple.quarantine ~/Downloads/tweets.zip 

Since any data can be attached to the named attribute, sometimes you’ll see a bunch of hex values instead of text:

$ xattr -p com.apple.metadata:kMDItemDownloadedDate \
    ~/Downloads/tweets.zip 
62 70 6C 69 73 74 30 30 A1 01 33 41 B6 86 3B 6D
B2 87 5D 08 0A 00 00 00 00 00 00 01 01 00 00 00
00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 13

If that happens, just use the -lp option instead:

$ xattr -lp com.apple.metadata:kMDItemDownloadedDate \
    ~/Downloads/tweets.zip 
com.apple.metadata:kMDItemDownloadedDate:
00000000  62 70 6C 69 … B6 86 3B 6D  |bplist00..3A..;m|
00000010  B2 87 5D 08 … 01 00 00 00  |..].............|
00000020  00 00 00 00 … 00 00 00 00  |................|
00000030  00 00 00 00 …              |.....|
00000035

That “bplist” looks like a hint to the contents of the data. More about that in just a bit.

Extended attributes are pervasive: you’ll find that they’re working quietly behind the scenes to enable a lot of functionality we take for granted. For example, have you ever wondered why Xcode build folders never get backed up by Time Machine? Here’s your answer:

$ cd ~/Projects/CHOCKINATOR/build
$ xattr .
com.apple.XcodeGenerated
com.apple.metadata:com_apple_backup_excludeItem

Resource Forks

If you’re a long-time Mac developer, you’ll remember the days of resource forks. They were kind of like the extended attributes shown above, but the attribute names were limited to four characters and the data being stored was only accessible on a Mac.

Some things never die: Mac files can still have a resource fork. These days, they’re mostly used to store custom icons that have been attached to a file or folder.

To access the resource fork of a file, just append “..namedfork/rsrc” to the path. For example:

$ ls -oh FERRET
-rw-r--r--@ 1 CHOCK     0B Apr 19  2010 FERRET
$ ls -oh FERRET/..namedfork/rsrc
-rw-r--r--  1 CHOCK   155K Apr 19  2010 FERRET/..namedfork/rsrc

The file has zero bytes of data, but the resource fork uses 155 KB. Let’s throw it at file and see what happens:

$ file FERRET/..namedfork/rsrc
FERRET/..namedfork/rsrc: MS Windows icon resource

Close. It’s actually a Mac ICNS resource. I'm pretty sure this is the first and only time I've seen file get it wrong.

If you’ve ever noticed a zero length file named “Icon?” in a folder that has a custom icon, it’s the same thing:

$ file Icon^M/..namedfork/rsrc
/..namedfork/rsrc: MS Windows icon resource

Note: to get the ^M in the name, type Control-V followed by Control-M. You can do this to get any control character into the shell’s edit buffer.

Internally, the resource forks are stored as extended attributes using com.apple.ResourceFork. If you try to access it with xattr you’ll get an “operation not permitted” error.

Finder Info

Another extended attribute that can contain useful information is com.apple.FinderInfo. This chunk of data contains, well, information for the Finder:

$ xattr HOTT.png
com.apple.FinderInfo
$ xattr -p com.apple.FinderInfo HOTT.png
00 00 00 00 43 48 4F 4B 00 50 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Unless you're me, you don't recognize the extreme importance of 0x43, 0x48, 0x4F, and 0x4B. Luckily, there are some helpful tools in your Xcode Developer Tools folder. The first is GetFileInfo:

$ GetFileInfo HOTT.png 
file: "/private/tmp/HOTT.png"
type: "\0\0\0\0"
creator: "CHOK"
attributes: avbstclinMEdz
created: 01/21/2014 10:31:53
modified: 01/21/2014 10:31:53

The man page for GetFileInfo explains the attributes. The creator, and source of those four hex bytes mentioned above, needs no explanation.

To change the file info, you'd use SetFile. That being said, it's probably easier to do it in the Finder's Get Info panel:

$ osascript -e 'tell application "Finder" to ¬
    open information window ¬
    of item POSIX file "/tmp/HOTT.png"'

Fun Fact: These tools have been around since the days of MPW. If you don't know what MPW means, consider yourself lucky. In fact, pretty much everything in $XCODE/Tools is a trip back in time. Do this if you remember them as the "good ol' days":

$ man Rez

Examining Binaries

A lot of the files we deal with are executable. Even if symbols have been stripped from the app, you can still infer a lot of information by looking at the null terminated strings present in the data:

$ cd /Applications/TextEdit.app/Contents/MacOS
$ strings TextEdit

Better yet, take it a step further and look at the information the Objective-C runtime uses in the Mach-O binary:

$ class-dump TextEdit

I think it's safe to say that the iOS Jailbreak community would not formed as quickly as it did without this tool. It's that important for figuring out what another developer did in their Objective-C code.

If you don't have class-dump installed on your development machine, fix that right now. And while you're there, don't be a tightwad: put some money in Steve Nygard's tip jar. He's been supporting and maintaining this free tool for years.

Test and Debug

So far we've pretty much treated the shell as a static environment. But we all know there are lots of gears and levers moving behind the scenes. The shell is a great place to watch that activity.

top

When I'm in a shell and want to see the overall activity on a system, this is the first tool that I turn to:

$ top -d -u -s 10

The -d option shows deltas for network and paging activity (which is much more useful than total counts.) I typically run this command when some process is running amok: -u sorts the list by CPU usage. Using -s 10 updates the output every 10 seconds, minimizing the sampling affecting in the results. A longer sampling period also helps keep the listed processes from jumping around too much.

On the desktop, I always run the first Cocoa app I ever wrote: iPulse presents this information (and more!) in an interface that's easy to read at a glance.

lsof

Have you ever tried to eject a disk and had the Finder tell you it can't because there are still files still open? You've probably seen lsof used as a way to tell you what those files are:

$ lsof +d /Volumes/KILO

But as with most great Unix tools, lsof is not a one-trick pony.

For example, you can use lsof to see all the files an app has open. Let's look at everything the Finder has open using the -c option:

$ lsof -c Finder

Yeah, that's a lot of files. So use grep to narrow down the search:

$ lsof -c Finder | grep PrivateFrameworks

Hmmm… the large ArtFile.bin file in CoreUI.framework sure looks interesting.

And remember that Unix sockets are just another kind of file. So in addition to checking what normal files a process has open:

$ lsof -c Dropbox | grep "/Users/CHOCK"

You can also check what kind of network connections it has open and the state of those connections:

$ lsof -c Dropbox | grep "TCP"
$ lsof -c Dropbox | grep "LISTEN"

Taking the network theme a bit further, the -i parameter lets you see which processes have open connections on specific ports:

$ lsof -i :80
$ lsof -i :22

Want to see all the processes that are listening on a socket? Here you go:

$ lsof -i | grep LISTEN

Or ones that have established connections:

$ lsof -i | grep ESTABLISHED

Remember that sockets are often used for interprocess communication, so just because there's a connection, it doesn't mean that packets are leaving your Mac.

In general, lsof is a great tool for investigate processes that are unknown, poorly documented, or you're just curious about:

$ psc securityd
   18     1 root           /usr/sbin/securityd -i
$ sudo lsof -p 18 | grep "/Applications"

You probably didn't realize it at first, but you just got a list of all applications that are using the Keychain. Note that sudo is required because the securityd process runs with elevated privileges.

As you can see, there are a lot of options and parameters, so make sure to take a look at the lsof man page.

DTrace

If you're developing for Mac or iOS, you already know how damn useful Instruments is for tracking application behavior. DTrace is the framework that makes all that possible. Well, take a look at all the stuff in the shell that "uses DTrace":

$ man -k dtrace

Whoa. That's a lot of stuff. A shorter and more useful list can be had by just showing the "snoop" tools:

$ man -k snoop

As you saw above, lsof gives you a snapshot of the current state of processes and the files they have open. The "snoop" tools, on the other hand, show you the system as it changes state. For example, let's use opensnoop to watch the system logging process as it opens files:

$ sudo opensnoop -p `cat /var/run/syslog.pid`

Every command that uses DTrace requires elevated permissions to retrieve the buffered data from the kernel. Get used to typing sudo.

Now, in another Terminal window, send something to the system log:

$ sudo syslog -s "CHOCK ME BABY"

The window running open snoop should show something like this:

  UID    PID COMM          FD PATH                 
    0     23 syslogd       15 /var/log/system.log  

Have you ever wondered how crackers find the super secret file you use to store serial numbers? Use the -n to specify a process by name:

$ sudo opensnoop -n Uncrackable.app

There you go. Good luck trying to outsmart the kernel with your "uncrackable" protection scheme.

If you're interested in seeing which processes open a specific file, use -f to specify a path:

$ cd ~/Library/Keychains
$ sudo opensnoop -f CHOCK.keychain

You can also track file or disk activity with rwsnoop and iosnoop:

$ sudo rwsnoop -n Safari
$ sudo iosnoop -n Safari

As you saw with that long list of DTrace shell commands, there's a lot more you can do with this facility. In fact, you can actually write code that gets compiled and run. Here's a one-liner that shows when processes are spawned and exec'ed:

$ sudo dtrace -n 'proc:::exec-success { \
    printf("%d %s", timestamp, curpsinfo->pr_psargs); \
    }'

In fact, those "snoop" tools you just ran are just script wrappers around code written in the D language:

$ less `which opensnoop`

For more information and tips about using DTrace on Mac OS X, check out the DTrace site.

fs_usage

Another tool to watch what's going on in the filesystem is fs_usage. This tool reports any activity for calls to like fopen(), fwrite(), getattrlist(), fsync(), etc.

For example, if you want to watch the Finder manipulate files:

$ sudo fs_usage Finder

When using this tool, remember that a "file system" doesn't necessarily mean a disk is involved. The -f option lets you filter out network related events:

$ sudo fs_usage -f network Safari

tccutil

If there was an award for the crappiest OS X man page, I'd have to award it to tccutil:

$ man tccutil

Only one service is listed in the man page: "AddressBook". There are others, and now that you know how to poke around in binary files, you can find them:

$ strings /System/Library/PrivateFrameworks/TCC.framework/TCC \
    | grep kTCCService 
kTCCServiceAll
kTCCServiceAddressBook
kTCCServiceCalendar
kTCCServiceReminders
kTCCServiceTwitter
kTCCServiceFacebook
kTCCServiceSinaWeibo
kTCCServiceLiverpool
kTCCServiceUbiquity
kTCCServiceTencentWeibo
kTCCServiceLinkedIn
kTCCServiceAccessibility
kTCCServiceLocation

If you're testing an app that requests for a user's calendar information, you can reset the authorization by removing the "kTCCService" prefix from the list above:

$ sudo tccutil reset Calendar

Be careful when you're using this tool: you're resetting all apps in each service category, not just your own. I do not recommend running this command on a machine where you have apps already registered in System Preferences > Security & Privacy > Privacy. Use a test machine or a clean VM image before you start blasting away at security settings.

It's also worth noting that Accessibility is a special case. There is a SQLite database that contains the bundle ids for the applications that have been granted access. And you can modify that database:

$ sudo sqlite3 \
    /Library/Application\ Support/com.apple.TCC/TCC.db
sqlite> .schema access
sqlite> select * from access;
sqlite> delete from access where client like '%Xcode';

Note that these commands have no effect on whether you see the authorization prompts the first time a user accesses the service from your app. After a new app been presented with the alert dialog, an entry is added to the com.apple.universalaccessAuthWarning defaults:

$ defaults read com.apple.universalaccessAuthWarning

You can hunt for specific paths and bundle IDs, or just use the nuclear option:

$ defaults delete com.apple.universalaccessAuthWarning

After clearing the warnings, you'll need to restart your Mac and run the app again. Again, this is much more palatable if you're working in a test environment on a dedicated machine or VM.

When your working with the above commands, remember that as far as security is concerned, you'll be getting a bundle ID for Xcode when running under the debugger. In many cases, you want to get rid of settings for com.apple.dt.Xcode as well as ones for your own app.

The Internet

True story: the Internet existed on the command line before the Tim Berners-Lee ever thought about making a browser in the early '90's. First there was Telnet in 1969, then FTP in 1971, followed by Finger in 1977, and so on.

I think it's pretty safe to say the command line will never die, but the best part is that your Terminal continues to be a tool that works great in our networked world.

curl

Every time I upload a new version of our software, I check it using curl:

$ curl --head http://iconfactory.com/assets/software/xscope/xScope-4.0.zip

This lets me see that a "200 OK" response is returned and that the number of bytes match my local copy.

Another great use for curl is to watch all data that gets transferred over a HTTP connection. And I mean ALL the data:

$ curl -v http://CHOCKLOCK.COM

The title of curl's man page is "transfer a URL." That all encompassing description should be your first hint that the tool does a lot. And I mean a lot—it supports the DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP protocols.

If you use URLs in your work, do yourself a favor and check out the man page.

tcpdump

Did you know that you can write code that runs in the OS X kernel and looks at every network packet at the data link layer? And that you can do it from the command line?

The tcpdump command is a user interface for Berkeley Packet Filters. This powerful tool can show you anything that's happening on your network.

A simple example is to watch what's happening when you access a web resource. Say you want to see all the HTTP data that passes on the network when you load Gruber's latest post in your browser:

$ sudo tcpdump -s 0 -A \
    port 80 and host daringfireball.net 

The -s parameter sets the amount of data you see in each packet: when it's set to zero, you get everything. The -A parameter specifies that the data should be displayed in ASCII. You need to use sudo with tcpdump because you're accessing the /dev/bpf* devices which have root-only permissions.

In conjunction with Internet Sharing, tcpdump can be a very powerful tool for iOS developers. After setting up Internet Sharing in your Mac's System Preferences, you can then watch traffic that passes between the Ethernet and Wi-Fi interfaces of that shared connection. If your iPhone is connected over Wi-Fi to your Mac using the IP address 192.168.2.2, the following command will show all the requests it sends to Daring Fireball:

$ sudo tcpdump -s 0 -A port 80 \
    and src 192.168.2.2 \
    and dst daringfireball.net 

If you were interested in packets going the other way, just swap the src and dst. Hopefully, you'll see how this is useful when debugging network traffic between your iOS device and a REST service.

The syntax used to write the packet filter code is defined in the pcap-filter manual page ("pcap" is short for packet capture.) The filtering options in the expression include detecting different network protocols and examining the length and contents of the packets themselves.

Web

Have you ever had a folder full of files that you've wanted to access through a web browser? You could setup Apache to do this by editing the httpd.conf file, or just enter the following command in the folder you want to access:

$ python -m SimpleHTTPServer 8000

Now, when you open http://localhost:8000 in browser, you'll be able to traverse the directory structure. Note that the server runs until you use Control-C to get back to the shell prompt.

This can be a great tool when testing your code: the directory can contain static JSON files that include data for your app. Just update the endpoints in your code to use the localhost and you're set.

DNS

Caches are designed to store information that's used repeatedly. But when that data gets stale, you need a way to flush the cache. As developers, we're often faced with DNS or other changes that affect our network stack.

When you find some piece of software misbehaving on the network, it's often caused by the Directory Service cache being out-of-date. Luckily, there's a simple command to flush the cache and get things back in working order:

$ dscacheutil -flushcache

If you're having problems resolving IP addresses from domain names, you can restart the DNS server with:

$ sudo killall -HUP mDNSResponder

A similar command causes statistics and other diagnostic information to be logged to /var/log/system.log:

$ sudo killall -INFO mDNSResponder

Be prepared to sift through a lot of information!

Services

Every Unix system has a simple tab-delimited database of service names and ports. The file is located in /etc/services. If you're wondering what's listening on port 69, do this:

$ grep "\s69/" /etc/services
tftp             69/udp     # Trivial File Transfer
tftp             69/tcp     # Trivial File Transfer

You'll also see that the TFTP service can use both TCP and UDP protocols.

Another handy search is if your looking for the standard ports for a protocol. Say you want to know which ports can be used for IMAP:

$ grep imap /etc/services
imap      143/udp  # Internet Message Access Protocol
imap      143/tcp  # Internet Message Access Protocol
imap3     220/udp  # Interactive Mail Access Protocol v3
imap3     220/tcp  # Interactive Mail Access Protocol v3
imap4-ssl 585/udp  # IMAP4+SSL (use 993 instead)
imap4-ssl 585/tcp  # IMAP4+SSL (use 993 instead)
imaps     993/udp  # imap4 protocol over TLS/SSL
imaps     993/tcp  # imap4 protocol over TLS/SSL

IP address

Need to know the WAN IP address you've been assigned outside your internal LAN?

$ curl -s ifconfig.me

Loading the site in your browser shows a lot of other options. Be aware that information about the HTTP connection and HTML content aren't available from the command line unless you explicitly set them as options for curl.

Conversions

Data is never in the format you need it, is it? The shell's notion of standard input and output has always made it great for doing data conversion. Here are some tools that you may not know about...

Format

Want to convert text between .txt, .html, .rtf, .rtfd, .doc, .docx, .wordml, .odt and .webarchive formats? Look here:

$ man textutil

It's pretty hard to read a binary property list, so convert it to XML or JSON. Or vice versa:

$ man plutil

Your designer gives you individual PNG files for your app icon, but your project needs an .icns file. Or vice versa:

$ man iconutil

Pretend like you're in The Matrix:

$ hexdump -C Default.png

Or convert between hex and binary formats:

$ man xxd

Compression

How many ways do we need to compress data? In the world of the command line, I'm pretty sure the answer to that question is a number that approaches infinity. Regardless, here are a few of the most common formats and the tools used to view and extract the data from the command line.

If you have a ZIP file and you want to quickly view its contents, use the unzip command with the -l option:

$ unzip -l RUBBERUNDIES.ZIP

Without the option, the ZIP file will be extracted to the current directory:

$ unzip RUBBERUNDIES.ZIP

Similarly, a GZIP compressed TAR archive can be listed with:

$ tar tvfz feather.tgz

And extracted with:

$ tar xvfz feather.tgz

Fun fact: the name tar is short for "tape archive". That gives you an idea of how long this piece of code, and resulting archives, have been around. I think it's pretty cool that an archive you created in the 1970's can still be used forty years later. How much code being written today will be able to say that?

Log files are often compressed with either GZIP or BZIP. A quick way to uncompress these files and view their contents is to use the "cat" variants and pipe the output to less:

$ gzcat les_paul.log.gz | less

$ bzcat /var/log/system.log.0.bz2 | less

Disk Utilities

If you're looking for a disk utility, look no further than diskutil. This is essentially the command line version of the Disk Utility in your Applications > Utilities folder.

The first command I use is list:

$ diskutil list
/dev/disk0
 #:                  TYPE              SIZE     IDENTIFIER
 0: GUID_partition_scheme             *251.0 GB disk0
 1:                   EFI              209.7 MB disk0s1
 2:             Apple_HFS KITTYS       250.1 GB disk0s2
 3:            Apple_Boot Recovery HD  650.0 MB disk0s3

This gives you the layout of all attached disks. The identifier column is typically used as a parameter for the other commands. For example, if you want to see all the information about your Apple_HFS partition, you'd use the identifier for that partition:

$ diskutil info disk0s2

A similar command gets information about the disk itself. In this case, we're also using grep to quickly get the SMART status for the drive:

$ diskutil info disk0 | grep "SMART"
   SMART Status:             Verified

Some of the commands can use volume names instead of identifiers. For example, to eject a volume, you can use:

$ diskutil eject /Volumes/NOODLE

Be careful with diskutil since it also provides commands like secureErase and partitionDisk—they can quickly and permanently destroy your data. Expert users also use this command to setup and manage software RAID sets.

Another simple disk utility is the df (the short form for "disk free".) To show how much free space you have on your boot volume, use:

$ df -h /

Unicode

Did you know you can use Unicode in shell commands? Yep:

$ echo $'\xf0\x9f\x8d\x94'
🍔

$ date +$'\xe2\x98\x95 %A'
🍔 Tuesday

The sequence of hex values is the UTF-8 representation of code point U+1F354. It's a shame that there is no such sequence for a taco.

If that example doesn't show up correctly in your browser, it's because you're using one that has lousy support for emoji characters *cough* Chrome *cough*. Go ahead and paste the text into the Terminal: it has a much better taste for grilled meat on a soft bun.

A Practical Example

Remember that "bplist" we encountered in the extended attributes for our download? What did those hex values represent? We now have the tools to figure that out!

First start by getting the metadata into a temporary file:

$ cd ~/Downloads
$ xattr -p com.apple.metadata:kMDItemDownloadedDate tweets.zip > /tmp/tweets.xd

$ cat /tmp/tweets.xd 
62 70 6C 69 73 74 30 30 A1 01 33 41 B6 86 3B 6D
B2 87 5D 08 0A 00 00 00 00 00 00 01 01 00 00 00
00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 13

Now, let's convert the hex dump into binary data:

$ xxd -r -p -g 1 -c 16 /tmp/tweets.xd - > /tmp/tweets.plist

And then convert the binary data to XML text:

$ plutil -convert xml1 /tmp/tweets.plist -o -
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
	<date>2012-12-22T19:03:09Z</date>
</array>
</plist>

Note that the date is in UTC (GMT), so let's figure out the local time:

$ date -ujf "%Y-%m-%d %H:%M:%S" "2012-12-22 19:03:09" +%s
1356202989

$ date -r 1356202989
Sat Dec 22 11:03:09 PST 2012

Or we could have just gotten that info directly from the same APIs that the Finder uses :-)

$ GetFileInfo tweets.zip
file: "/Users/CHOCK/Downloads/tweets.zip"
type: "\0\0\0\0"
creator: "\0\0\0\0"
attributes: avbstclinmedz
created: 12/22/2012 11:03:09
modified: 12/22/2012 11:03:09

Mastering the shell is not so much a matter of learning individual commands, but rather learning how the tools can be used together to solve a problem.

Of course, the hard part is knowing which commands you have at your disposal. Now that you've made it to the end of this huge post, hopefully you'll have a few new things in your mental tool chest.

Footnote

This post came to life last February during a five hour layover caused by a cancelled flight. Finishing touches were made on my trip home from WWDC 2014. The fact that I was writing about the terminal while sitting in the terminal was not lost on me.

Writing 9,000+ words on a technical topic takes a long time. These "Siracusian" efforts are all about the details: there is an amazing amount of research involved, even for things you already know well!

In spite of the effort involved, I love writing long-form pieces like this one. The problem is that I also love paying my bills. As a result, what could have been written in a few days takes months to pull together.

This is where you come in: you can help pay for more of my writing by purchasing one of the many products my company offers. Download a free trial of xScope 4, sign up for a free AppViz account, or ask us to do some design work for your project. Besides getting a great product or service, you're also giving me the ability to write about topics that are valuable to you and your fellow developers.

If you have already supported the Iconfactory in one way or another, thank you! You can still help out: take a moment to tell your friends and followers about us on Twitter or Facebook. Word of mouth is our favorite form of marketing and it's up to you to make it happen!

A documentary

For the past few months, I’ve been helping a couple of talented filmmakers with a new project. I’ve been making introductions, reminding busy people to find some time for an interview, and that kind of thing. Today, the result was made public and it’s better than I ever imagined.

I think this project that looks at our past is important for two reasons: our present and future.

It’s no secret that the art and business of software development has changed radically since that day in January 2007. Listening to my colleagues talk about what that moment meant to them is incredibly helpful for putting today’s situation in perspective. You don’t give a shit how big the next iPhone’s screen is going to be when your peers are talking about how these devices have changed their lives.

By funding this project, you’re also giving your future self a rare gift. I was a young developer when the Mac was announced in 1984, and let me assure you that many of the details of that time have been lost over the course of thirty years. You’re going to look back at this time in your career fondly and wish you remembered more about it.

Something like what Andy Hertzfeld has done at Folklore.org has been a godsend to those of us who were around in the early days of the Mac. But I don’t think that approach would work now: the Internet made the iPhone a world-wide phenomenon, not a project limited to the Texaco Towers. (Did you know that the first person to make money from selling apps was a developer in New Zealand?)

This is your chance to create a record of something that has changed so many lives. Please take a moment to look at what Jake and Jed have done and join me in contributing to this Kickstarter.

Un-fucking-believable

An anonymous individual is spreading accusations that I’m a patent troll. Hard to believe, huh?

It makes me furious that I have to respond to these claims without knowing my accuser, but here goes:

Yes, we have a patent. Yes, we got a license fee for it. No, it wasn’t unreasonable.

We originally got the patent as protection against a large company, like Adobe, using our innovation. Patents are like trademarks, you have to protect them after you get them (by collecting licensing fees, even if it’s a small one.) The arrangement with Ricci Adams was amicable from the first email to the last.

From a monetary point-of-view, all I’m going to tell you is that the fee we collected from Ricci Adams was less than the amount of time and money spent getting the legal documents in place. We didn’t profit from it, nor did it “stifle competition.” (Pixel Winch is a great product, you should check out the beta. And no, I’m not making any money by saying that.)

We also acquired this patent before our encounter with Lodsys. Our view of patents has obviously changed since then. I can’t go into any specific details there, thanks to the lawyers.

And you want to know the real kicker? After talking about this stuff with my friend Marco Arment, we’re no longer sure that software patents have the same “use it or lose it” conditions as with a trademark. Of course, for a lawyer who’s collecting fees, mentioning this is not in their best interest.

Any further comment on this situation will have to wait until the coward who’s making these claims comes forward.

P.S. Marco, I could use that beer now.

Confidence

We witnessed something amazing yesterday: a WWDC keynote that will be remembered for a long time. And not for the reason you might expect.

As developers, it’s easy to focus on the fantastic software that was announced: a UI refresh that’s getting a thumbs up from designers and developers alike, great new user-facing features in iOS and OS X, and literally thousands of new APIs that let developers do new and amazing things with their apps. We even got a new programming language!

**BLINK**

But that all pales in comparison to the undercurrent for all these changes: Apple has a newfound confidence in itself. It’s at the top of its game, and it knows it.

This is personified by the man who ran the show: Craig Federighi. It was only four years ago that we first saw him on stage at an Apple event. His shaking hand is still painful to watch, especially if you’ve felt that same fear while giving a presentation on stage. Yesterday, we saw a different man, one that owned the stage and the products being presented.

With this confidence, we’re starting to see some important cultural change in the company.

  • Legal agreements that lets developers talk about technologies without breaking confidentiality.
  • Opening up proprietary technologies like iCloud: providing more transparent access, without hiding things through opaque APIs.
  • Improvements to the App Store that give developers better ways to manage and sell their products.

This confidence manifests itself in many ways. When was the last time you heard an Apple executive tout the best product line he’s seen in 25 years?

In short, with confidence comes a new kind of openness. As developers, we’ve always struggled with a company that doesn’t want to give anything away. Yesterday, that started to change.