Borkware Miniblog

February 10, 2013

App localization – lessons learned

Filed under: Uncategorized — Mark Dalrymple @ 8:20 pm

App localization – lessons learned

My friend, and fellow Pittsburgh CocoaHead, Adam Ratana has posted about some lessons learned when localizing his Sun Surveyor app for iOS and Android.

April 13, 2012

Stuff Going On At The Ranch

Filed under: Big Nerd Ranch, meta, programming, Visix, work, writing — Mark Dalrymple @ 8:48 pm

In case folks are dying to read more of my technical writing, I’ve been writing a lot of material over at the Big Nerd Ranch Weblog, including some gems like:

Well, OK, that’s everything, even the not-so-gemmy. For the forseeable future my geek writing will be over there, and I’ll reserve this weblog for cute Vikki pictures:

IMG 0005 IMG 0057 IMG 0090 IMG 0175 IMG 0191 IMG 0219 IMG 0427

March 2, 2012

Keith on Monochrome Icons

Filed under: off-topic, whining — Mark Dalrymple @ 11:22 am

Keith Blount, the brain behind Scrivener (one of my favorite pieces of software), talks about The Mac Monochrome Trend – A Plea For Keeping Things Colourful:

When Apple decided to drain the icons in these programs of their colour, I learned something about the way my brain works that I hadn’t hitherto ever had to think about: my brain is an awful lot faster at processing colours than it is at processing shapes.

I’m the same way. I use a mix of 10.6 and 10.7 machines. When I go back to 10.6, I’m reminded how quickly I recognize the sidebar icons in the Finder, and on 10.7, it’s all a gray mass.

January 24, 2012

Interview from Salt Lake City

Filed under: Big Nerd Ranch, cocoaheads, Questions From Friends — Mark Dalrymple @ 2:52 pm

Earlier this month I went down to Salt Lake City to do an on-site class for a company there.  Rod Schmidt, the organizer of the SLC CocoaHeads chapter, was kind enough to delay their meeting by a week so I could join them.

One of the members, Patrick Cassell, runs an Apple news and commentary blog at iTechCrossroads.  He did a brief interview, and posted it online.

I wasn’t quite expecting a verbatim interview, so like I guess like that’s how I actually speak and stuff.  But there were some interesting questions.

Here’s part 1, and part 2.

November 3, 2011

Outlet Collections

Filed under: Cycling Fusion, iPhone, programming, work — Mark Dalrymple @ 12:29 pm

A quick post to explain my tweet.

Screen shot 2011 11 03 at 11 41 55 AM

TL;DR: I can batch show and hide UIViews really easily now. Easier than setting up a bunch of outlets, fiddling with tags, making dummy views, or groveling through the view hierarchy.

I bet it’s Cocoa 101 nowadays, but they were new to me, pretty much seeing the reference when dragging a connection to header files (which I never do) and promptly forgetting about them. I might have seen reference to them in a WWDC sessions or something. But finally now I had a real use. Yay! For a lot of this stuff I need to actually use it for Something Real before it sticks in my brain. I can learn stuff by doing, but I’m lousy at memorization. Just look at my history grades during high school. On second thought, please don’t.

RideBuddy™ is one of the new apps coming from Cycling Fusion. Amongst a ton of other stuff, RideBuddy lets you track workout time in various heart zones – ranges of heart rates that have different benefits and consequences to the body. We like the Sally Edwards Heart Zones® system, which is a five-zone system based on certain physiological markers. I won’t get into specifics here, you can join the Cycling Fusion Winter Training in January and get the full details.

Five zones are kind of a lot for a beginner or just a casual rider to wrap their mind around, so Sally created Zoning™, a friendlier three-zone system and a color-coded heart rate monitor. It’s only three zones, but it’s based on the same physiological markers as the five-zone system. You can get a lot of health and training benefit by using the three zone system, and can graduate to the five-zone system when you feel up to it.

My stuff needs to support both. So, I have a number of screens like this one:

Two zone models

Something that’ll support three zones or five zones. Internally I can support from one to five zones. The code that adjusts the layouts based on the zone system in-use hides everything zone-related, then populates and enables stuff zone-by-zone until it runs out of zones. In the above screenie I have four objects per zone: two static labels and two text fields. zone zone zone.

To simplify that work, I have five IBOutletCollection(UIView)s — one for each zone. I walk through all of them to Hide All The Things, then walk the zones enabling a particular collection and populating items until I run out of zones. If I don’t hit a collection, it stays hidden.

Understandably, this is so much nicer than setting up an IBOutlet for each label and text field and making the connections. Or setting a tag on the items. Or groveling through the view hierarchy showing and hiding things. Or having a dummy UIView just to be a container. Just add the outlet collection and make connections in IB.

Markus Möller on Twitter “uses them for animating / moving groups of views. Better than putting them all in a container view. Less hierarchy.” which is another excellent use.


October 7, 2011

CocoaConf Raleigh NC December 2-3

Filed under: cocoaheads, conferences — Mark Dalrymple @ 5:44 pm


I had a great time when I spoke at CocoaConf this last August in Columbus, OH. It was in my back yard and was a no-brainer to go to. I had a huge amount of fun, learned a lot from the other speakers, and had a fun panel discussion. Plus Dave Klein’s family is a lot of fun. Be sure to hang out with Solomon if he’s there.

I’m not sure what my gesture over there is from. Maybe from the virtual sock puppet portion of “Performance Tuning.”

CocoaConf will be in Raleigh NC, December 2th and 3th. You can browse the full schedule to see if stuff is interesting to you. There’s a registration page if you want to go. I can’t make it because I’ll be playing a concert that weekend, otherwise I’d probably head down.  (December is always nuts for me.)

There’s a $50 discount for CocoaHeads folk. The coupon code is a secret to the non-COCOAHEAD individuals out there, but smart folks should be able to figure it out.

October 6, 2011


Filed under: Uncategorized — Mark Dalrymple @ 11:36 am

I got the news on an iphone last night riding to rehearsal.  Today I’m on an iPad and two MacBookPros for doing my daily work.  Some of my most joyous times in my youth were spent in front of an Apple ][, then an Apple //e.

I’ve been to a bunch of SteveNotes.  The RDF was real.  I always recommended WWDC (and MacWorld) newtimers  to do at least one SteveNote.  Now we can just reminisce.

The thing that’s really impressed me about Post-NeXT Apple is the quality of people attracted to, and kept by, the company.  I have friends inside of the The Fruit, all of whom are amazingly awesome.  Curtis. Zach. Evan. Ben. Bill. Clark. Chris. Dave. John.  And any others I’ve forgotten.  It’s a true testament to the leadership that such talent has been assembled.

I never met the man.  I did pass within 30 feet of him on the Google campus a couple of years before.  I was helping move 200 pounds of homebrew for a tech talk, and saw someone sitting under a tree chatting with someone else.  I asked my companion “is that…”  “yes it is”  “whoa”.  And we went on our merry way.

I’m gonna head over to and read some stories now.

October 4, 2011

Speaking in Little Rock, AR October 11

Filed under: Random — Mark Dalrymple @ 9:02 pm

Just a quick note for anyone who hasn’t heard yet – I’ll be speaking at Apple Rock on Tuesday, October 11. Location is Pulaski Academy’s Murphy Theater. The topic is mobile development compared to the desktop. If you’re in central Arkansas, please stop by and say hi.

August 16, 2011

My First App: Class Builder

Filed under: cycling, iPhone, programming, work — Mark Dalrymple @ 2:02 pm

Class builder beauty

My first App got accepted into the AppStore yesterday – Cycling Fusion’s Class Builder™. Woot! Amazingly enough, it went through the approval process without a peep. There’s screen shots and tutorial videos (some still in the making – didn’t expect AppStore approval so quickly) at the link. And it’s at the AppStore.

Class Builder is a tool for Indoor Cycling (a.k.a. “Spinning®”) instructors to lead better classes. Rather than juggling an ipod, sheets of paper or 3×5 cards, and a stopwatch; instructors can plug their Device into the club sound system, run the class, and have cues pop up at the proper time during the class. They can also configure pre-class and post-class music for ambience before and afterwards. If the club has a projector, the instructor can plug their Device into the projector and show everyone the ride profile, along with additional information like current cadence / power / HeartZone®. A slideshow of photos can be shown during the pre-class time to help set the mood.

Despite “Class” in the name, this has nothing to do with programming.

Folks have asked me what I’ve been up to in the year-and-change since I left Google to work with Cycling Fusion. This is it, and the usual billion other things that go on when you work at a startup (along with the major update to AMOSXP)

The code is pretty much all mine, end-to-end. 13,000 non-comment / non-whitespace / non-brace LoC, 84 classes, 32 html files, and 677 .pngs. Not huge, but respectable. It was my first time really to work on something small enough that could be coded by a single programmer – usually I work on behind-the-scenes stuff that nobody else wants to touch. App design was by me and Gene Nacey, the fearless leader of Cycling Fusion. Graphic design by Emanuel Rufino and me. Luckily I now have the Photoshop skills to convert between an inspired artist and the user interface, to tone things down or amp them up as needed to fit the demands of the UI.

Class Builder is a part of the overall Cycling Fusion strategy for bringing the worlds of Indoor and Outdoor cycling together. We’re revolutionizing Indoor Cycling as we now know it through curriculum and certification, targeted training programs, web-based tools, mobile device apps, licensable music and an online video training library. Our big coming-out party is in the fall. If you’re into that kind of stuff, come on down to the ICI Pro Conference in October and check us out.

August 15, 2011

The New Phone Books Are Here! The New Phone Books Are Here!

Filed under: amosxp, Big Nerd Ranch, writing — Mark Dalrymple @ 11:56 am

Vikki bookIt’s been a while in the making, but Advanced Mac OS X Programming 3 / The Big Nerd Ranch Guide has finally started trickling out to folks.  I got my Author Copies today.  WOOOO!  You can see Vikki posing with the new edition.  Everything on the internet is improved by adding a cat.

This book is a massive overhaul of the second edition.  I dropped a number of chapters (I’m pretty sure folks know about version control systems these days), and a number were added (DTrace and GCD anyone?), with pretty much everything edited and improved (bye-bye Shark :-(  Hello Instruments :-) ), covering stuff through 10.6 / iOS 4.  Students taking my class at the ranch get to be guinea pigs a sneak peek of the Lion-related material.  It had already been over five years since the second edition, so we decided to go ahead and ship it, and then do a thorough job on the Lion / iOS5 / iCloud stuff in a later edition.  Hopefully not so much later this time.

Speaking of Editing, Susan and Chris Loper from Intelligent English edited the book and maintained the DocBook-based pipeline of tools.  The second edition did not have an editor, and it shows.  Chris wrangled the tools, and thanks to Susan’s work I’m quite proud of the third edition, the quality of the writing, and the quality of the index (another second edition sore spot).

These things make great Labor Day gifts.  Be sure to order several for the children.  I’ll have a couple with me at CocoaHeads/Pittsburgh this week to give away.

Edit2: Gaige Paulsen pointed out that it’s already available in the iBooks / Kindle stores.  You can snarf the free sample and check out the table of contents.

Edit1: Folks have asked what’s new (skimming down the ToC – I’ve been living inside this thing, and teaching out of it for five years now…)

  • ObjC 2.0 stuff, properties, etc
  • Blocks
  • 64-Bit computing
  • getopt_long
  • lib/otool
  • Garbage Collection
  • Debugging techniques
  • DTrace
  • Overhaul of Performance Tuning
  • Instruments
  • NSFileManager got a complete overhaul
  • IPv6, overhaul of the code
  • CFHost
  • FSEvents
  • Operations
  • GCD

June 25, 2011

Speaking at CocoaConf

Filed under: conferences, Random — Mark Dalrymple @ 6:36 pm

Wanted to let folks know I’m speaking at CocoaConf, Columbus OH, August 12-13. There’s a pretty nice lineup of speakers and sessions. Mine about debugging and performance tuning.  Sexy and exciting topics to be sure.

For folks in/near the DC area, iOSDevCampDC is happening that same weekend. I wish I could be split in two, because they’ve got some good speakers as well.

June 14, 2011

Scrivener for long-form technical writing

Filed under: amosxp, meta, Random, writing — Mark Dalrymple @ 6:00 pm


Every now and then I come across a software tool that Gets It. A tool that does everything right. A tool that is a joy to use. VoodooPad is one. MarsEdit is another. Scrivener is the latest to enter the pantheon of My Favorite Apps.  The last three big chunks of new stuff for AMOSXP(3), (GCD, using Instruments, and a re-write and major updating of NSFileManager) were organized and written in Scrivener, and then later converted to DocBook for inclusion in the book. In all, about 18,000 words worth of work.

Scrivener is a non-linear text editing environment. Rather than having, say, a chapter of a book in one single Word or Pages document, you can have each section or sub-section of that chapter in an entity. You can organize these entities in an outline, and Scrivener will automatically flow the text as if it were a larger document. Each entity can be as long or as short as it needs to be.

For example, this is the “binder”, the outline view, for the new GCD chapter:

Dispatch binder

It has all of the sections of the chapter. If I’m wanting to edit the text for Dispatch Groups, I can select it in the Binder and focus in only on that text. If I wanted to make sure that the text flows into and out of that section, I can multi-select Time, Dispatch Groups, and Semaphores, and see those three sections of text in one editing panel, with subtle separators between the sections. If I decide that I really should talk about queues before terminology, I can just drag the entity and rearrange things. This feature alone, to me, is worth the low price of admission ($45).  Doing major surgery like that in a single document is fraught with peril.  With Scrivener, it’s drag and drop.  Don’t like it?  Undo it.

In addition to seeing the text, and a standard wordprocesor-style outline view (which I don’t use), there’s a cool corkboard mode. I originally thought it was silly and gratuitous, but I eventually found it to be a nice (and fun) way to play with the organization of the document. The corkboard mode also shows metadata, such as a high-level description of the section, its draft status, and other things:


You can see that most of the chapters are First Draft, meaning that I’ve gurgitated out the text, did an editing pass, and it’s ready to make the one-way trip to DocBookland for markup, professional editing, and indexing. A couple are “In Progress”, meaning they’re being worked on but not ready to see the light of day. I can tell at a glance what shape the chapter is in. You can rearrange the document here too. Clicking and dragging the note cards is reflected in the outline view, and hence in your overall body of text.

One of the cool things is the text contents of the note cards. The title of the card matches the title in the Binder view. Simple enough. But you can also have a description, independent from the actual contents of the section. Scrivener gives you a lot of opportunity for out-of-band data. With traditional word processing environments, pretty much everything that’s in the document is part of the flow of text, except maybe things like reviewer’s comments. Scrivener has lots of opportunities for attaching meaningful metadata to sections: add tags, arbitrary keywords, arbitrary long notes and descriptions. Fiction writers can tag scenes with characters, themes, locations, smells, etc. Later on they can do searches to see all the scenes a particular character is in, or what sections concentrate on badger foreshadowing.  I didn’t use much metadata stuff, mainly the note card descriptions and the status.

In addition to the “Draft” area, which has all the text of your document in the little entity files, you can have any number of non-publishing hierarchies of stuff. I do most of my research in VoodooPad – it’s where all the raw information goes as I read technical docs, research on the web, and write test apps. Then I bring it over piecemeal into Scrivener as I suss out how things should be organized, and figure out what needs to be included and what can be left on the floor. Here’s the research part for Instruments:


Each of the texty-looking icons is the equivalent of a text file. You can have whatever text you want there, formatted how you want, embedded images, etc. Kind of like Keynote, these text docs aren’t the leaves of the tree. They’re also the internal nodes. The “Different Kinds of Instruments” text doc actually has three child documents too, each with their own text. I can select “Different Kinds of Templates”, and see its text, along with the children’s text in-line (if I want). There are also images, in this case screenshots, that are part of the “document” hierarchy. As I was writing the chapter, I’d be migrating important information from Voodoo Pad, arranging and rearranging entities so the order of presentation made sense. I wrote a fair amount of the chapter’s prose here. As I took screen shots, I added them as child nodes to the text they would appear in. This way they’d carried along as I rearranged chapters. It’s a very powerful, yet easy to use system.

One odd thing about Scrivener is that it is actually fun to write in. No other text editor feels as responsive as Scriv’s. It’s hard to describe, but typing just feels better than in other apps. The obligatory full-screen mode is nice when you have to concentrate to Get Things Done.  Also, I am a huge fan of the “typewriter” mode. This centers the line being edited in the window. I can have a tall window so I can get lots of context, but when I’m actually typing and editing, the text is in the sweet-spot of my eyeglasses.

Indie developers would should take a good look at Scrivener’s website.  I spent a long time reading the materials, and looking at the demo movies.  They’re all very targeted.  “Here is a cool feature, here’s how it fits in with the rest of the product and here is how you would use it.”  After awhile, I got a very good sense of the how the product worked, and what particular features would make my life easier.  I had zero problems getting Real Work done immediately after download.

So, if you’re into any kind of long-form writing, whether it be novels for NaNoWriMo or technical books, or even the occasional complicated blog post, I recommend you check out Scrivener. It does so much Right that it is a joy to use.

May 6, 2011

Blast from the past: gprof

Filed under: history, programming, Random, Visix — Mark Dalrymple @ 1:56 pm

Dino rific

I stumbled across this little tutorial I wrote back in the mists of time, probably around 1996 or 1997.  And it was based on a tutorial I wrote at Visix, probably in 1993 during one of our Optimization Parties.  It describes how to read the output of gprof, a profiling tool available on most unix systems.  It’s even still there on Mac OS X.  So you kids with your fancy Shark and Instruments, here’s what some of your elders used.

gprof is not a GNU tool, even though it has the leading “g”.  That “g” probably stands for “call Graph” profiler. You’ll need to check your system’s documentation (e.g. man gprof) for exact instructions on getting gprof to work, but usually it just involves compiling and linking with -pg, running your program, and doing gprof gmon.out > oopack.

Here’s a 300K sample of output from gprof on the Dec Alpha if you want to take a look at it. This particular report is from a run of AOLServer 2.2.1 which involved fetching index.html 53,623 times.  The links that follow go to anchors in that 300K sample.  What was I wanting to profile?  I wanted a gut check to make sure that life in the server was sane, and if there were any obvious bottlenecks that maybe I could address if I had the time.  The test was to fetch index.html over and over again. In this case, around 53,000 times

There’s 4 parts to gprof output:

  • Built-in documentation: Short form of everything here, and more.
  • Call-graph: Each function, who called it, whom it called, and how many times said calling happened.
  • Flat profile How many times each function got called, the total times involved, sorted by time consumed.
  • Index: Cross-reference of function names and gprof identification numbers numbers.

I go to the flat profile section when I first start looking at gprof output. The big time consumers are usually pretty obvious. You’ll notice that each function has a [number] after it. You can search on that number throughout the file to see who called that function and what functions that function calls. Emacs incremental search is really nice for bouncing around the file like this.

Here you can see that DString is a big time gobbler:

  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 17.7       3.72     3.72 13786208     0.00     0.00  Ns_DStringNAppend [8]
  6.1       5.00     1.28   107276     0.01     0.03  MakePath [10]
  2.9       5.60     0.60  1555972     0.00     0.00  Ns_DStringFree [35]
  2.7       6.18     0.58  1555965     0.00     0.00  Ns_DStringInit [36]
  2.3       6.67     0.49  1507858     0.00     0.00  ns_realloc [40]

Out of 21.05 seconds of total clock time, Ns_DStringNAppend consumed about 4 seconds, or about 18% of the time in and of itself. It was called 13 million times.

MakePath consumed one and a half seconds itself, and its children consumed three and a half seconds. At least one individual call to this consumed 0.01, and at least one individual call took a total of 0.03 seconds in MakePath and its children.

Handy tip – the function numbers in brackets are approximately sorted by time consumption, so a function with a [low number] will generally be more interesting than one with a [high number].

Now that you know that Ns_DStringNAppend is called a bunch of times, this could be a useful target for optimization, I’d look at its entry in the call graph section.

Before doing that, just for illustration, take a look at AllocateCa [33] since it has all of the interesting pieces of the call graph in a more compact size:

                0.04        0.18   53622/160866      Ns_CacheNewEntry [62]
                0.04        0.18   53622/160866      Ns_CacheDoStat [58]
                0.04        0.18   53622/160866      Ns_CacheLockURL [64]
[33]     3.0    0.11        0.53  160866         AllocateCa [33]
                0.16        0.17  160866/321890      Ns_DStringVarAppend [30]
                0.06        0.00  160866/1555972     Ns_DStringFree [35]
                0.06        0.00  160866/1555965     Ns_DStringInit [36]
                0.04        0.00  160866/1341534     Ns_LockMutex [43]
                0.03        0.00  160866/1341534     Ns_UnlockMutex [53]

The entries above AllocateCa [33] are the functions that call AllocateCa. The entries below that are the functions that AllocateCa calls. There are two numbers separated by a slash: the first number is the number of calls that the function has made, while the second number is the total number of invocations of that function.

In other words, for 160866/321890 Ns_DStringVarAppend [30], AllocateCa called Ns_DStringVarAppend 160866 times. Across all of AOLServer, Ns_DStringVarAppend was called 321890 times.

Similarly, for 53622/160866 Ns_CacheNewEntry [62], means that Ns_CacheNewEntry called AllocateCa 53622 times, and AllocateCa was called 160866 times total.

So, just by looking at this snippet, you know that the three Ns_Cache functions each call AllocateCa about once per serving of index.html, and that AllocateCa makes a single call to Ns_DStringVarAppend, Ns_DStringFree, etc… each time. What’s also interesting to note is that someone is calling Ns_DStringFree more than Ns_DStringInit. This may be (or may not) be a bug in AOLServer. You can go see Ns_DStringInit and Ns_DStringFree yourself and track down who the culprit is.

The floating “3.0” on the left is the percent of total time that the function consumed. The two columns of numbers are the amount of time (in seconds) that the function consumed itself (AllocateCa took 0.11 seconds of time total to run its own code) and the amount of time in the function’s children (0.53 seconds were spent in its children)

Getting back to real analysis of DStringNAppend, you can see that MakePath made 50% of the Ns_DStringNAppend calls. Since you know that there were 53623 fetches of index.html, that means that for each page, MakePath was called twice, and for each call to MakePath, Ns_DStringNAppend was called 64 times.

If one call to MakePath could be elided (since it’s getting called twice), or if fewer than 64 Ns_DStringNAppends could be done per call, we could see a performance boost.

Just browsing the gprof output can be an illuminating exercise. If you have a gut feeling that a particular function is a hot spot (say, Ns_LockMutex [43]), you can see the call graph for that function, see if it’s consuming lots of time, or if it’s being called a whole bunch.  Here it was called 1,341,534 times, or about 25 times per page serve. Maybe that’s high.  Maybe that’s right.  Sometimes a suspected culprit isn’t there, or you find a surprising time waster.

Because this sample gprof output was done on a Dec Alpha system, there was some suckage involved, such as no explicit time recorded for system calls. So we don’t know if, for example, select() blocked for a long time on each call.


April 19, 2011

Learning iPhone Programming

Filed under: Big Nerd Ranch, cocoaheads, programming, Questions From Friends — Mark Dalrymple @ 1:20 pm

D31 2840 1

This last weekend I taught an Objective-C and iOS bootcamp to a group of students and faculty at WVU down in Morgantown WV. They have a cool “AppLaunch” project going on, to inspire students to write real applications on iDevices and encourage an entrepreneurial spirit (sorry, link is broken now), and they invited me down to kick off the technical portion.  Slides are available at my Free Talks for CocoaHeads page

A common question I got beforehand was “what’s the best way to get up to speed on this stuff?” That’s kind of like asking “what’s the best kind of pizza”. It all depends on where you’re coming from, where you want to go, and how fast.

If money is no object, take a Big Nerd Ranch class. In addition to teaching there, I have taken a number of Ranch classes from a bunch of different instructors, and they are all top-notch. The Ranch has a way of doing things that ends up with a really high quality product, enjoyable to both instructor and student. This will cost you a couple thousand dollars and take a week of your life, but you will be well on your way to iPhone programming studliness. Check out AnneKate Halsall’s Taming the Wild Dogcow tumblog for impressions and ah-has during the course of a class.

There are a number of video courses available. Stanford CS 193P iPhone Application Development is online. There is another set of materials from the Rose-Hulmn Institute of Technology for their CSSE490: iOS SDK Programming class.  Also, check the comments here, with some links to videos courtesy of Richard Smiley.

The next level down is books. I love books. I learned to program from books and magazines. Old folks may remember back in the day when computer magazines had pages of BASIC program listings. Keying those in and debugging the inevitable typos is how I learned to program. There are two books I really like for iOS programming: the Apress Beginning iPhone 6 Development: Exploring the iOS SDK by Dave Mark, Jack Nutting, Jeff LaMarche; and the Big Nerd Ranch iPhone Programming, the Big Nerd Ranch Guide by Aaron Hillegass and Joe Conway. I recommend people read both of them. If one book glosses over a topic the other covers in depth. Disclaimer: I’ve been the technical reviewer for the Apress Beginning iPhone books since the first edition.

What order to read them? If you’re strapped for time, read the Ranch one first. It’s short and to the point. Dedicate a weekend or a couple of evenings and type in everything. Then start working through the Apress book at your leisure.

If you’ve got more time, or you’re working over a longer period of time with other people, such as the Pittsburgh CocoaHeads Learn iPhone project, use the Apress book. It’s longer and wordier (764 vs 380 pages), but goes into topics in more detail. Some of the code is repetitious so you might not want to type in everything.

You’ll want some introductory books if you’ve never programmed before. The Aaron Hillegass Objective-C Programming: The Big Nerd Ranch Guide is very good. I’m partial to the Apress Learn C on the Mac by Dave Mark, followed by Learn Objective-C on the Mac the latter written by me and my hero Scott Knaster. This pair was designed to take you from “loops are cool!” up through Categories, Properties, and Predicates. If you already know C you can go straight into Learn Objective-C. If you already know how to program in something else and just want a quick brush-up on what’s peculiar to C, I’ve broken out the first two chapters of the first edition of Core Mac OS X Programming into a C RefresherLearn Objective-C has an appendix on what weirdnesses to expect if you’re coming from other languages like VB or Java. I know I get frustrated when I have to wade through “loops are cool!” when picking up a new language, so it’s nice having different places you can catch the train.

Finally, take a look around your community. You may have an active CocoaHeads or an NSCoderNight chapter, or perhaps an iPhone programming MeetUp. If there’s not one now, start one! There’s nothing like having living breathing people to ask questions of, and to generally hang around with. You might discover one-off classes like what I did at WVU, or longer-term learning projects like what we’re doing at our local CocoaHeads.

April 6, 2011

The NeXT Chapter

Filed under: history, off-topic — Mark Dalrymple @ 11:24 am

Dans panel

I guess folks liked my little WWDC guide. I got more traffic from than than everything else around here gets, combined. Poring through my referrer logs I found one tumble about it from @alanQuatermain who said:

“I have a suspicion that someone at NeXT went around with a huge bucketful of awesome one day, because everyone I’ve met with a NeXT association seems to have a fair amount of it these days.”

I can’t argue with that. Over the years, everyone I’ve met with NeXT affiliations has been incredibly smart, and usually very kind and gracious as well. The funny thing is, NeXT wanted nothing to do with me at the time.

I remember when the NeXT cube first hit the mainstream press. BYTE Magazine had a cover story with the cube along with a pretty in-depth article about the tech inside. The 68040 processor, the DSP, scads of memory, the advanced OS and the toolkit. There was even a centerfold. I was in love. I wanted one of those machines. Who cares if the optical drive was slow.  It was mag-NEATO! 256 megs of space! Who cares if the machine was $10,000? Somehow I managed to secure funding for it. Now all I needed was someone who would exchange a pile of money for a black cube of 2-bit graphic goodness.

The first NeXT machines were only sold to educational institutions. At the time, around 1989-90, I was still in college,  fairly small liberal arts college in central Arkansas you’ve probably never heard of. Hendrix College was too small to qualify for any kind of educational co-op with NeXT. UCA, the larger school across town, was large enough though. A friend of mine was the trombone professor over there even had a visit from a NeXT sales representative. I got an invite, and was blown away. I really wanted that machine. Unfortunately, I was told point-blank that there would be no way I could get a machine for myself through regular channels.

Plan B. I’m a programmer. They had a developer program. I got an application and sent it in. I didn’t have a huge number of qualifications (Unix? Is that like VMS?), but I have programmed Macs since they first came out. I even had a couple of application ideas in mind, including a MacDraw-like diagramming app, and a medical database system similar to one I built in high school.

About a month later I got my rejection letter. I think I still have it in my archives somewhere. I purchased the developer documentation anyway so I could live vicariously. Boy did Objective-C look weird. And Display Postscript.

And so there ended my dreams of being a NeXT programmer. I spent the money on a Mac IIci with an ungodly amount of memory (maybe 8 megs?) to continue my Mac programming. A little while later at my first job I discovered we had some NeXT cubes. They were in the corners being used for print servers. But dutifully I got a login, worked through the programing tutorials, had some fun, learned a lot, and then went back to my day job of Unix and C because there was No Future in the NeXT technology.

Needless to say I was pretty happy when NeXT bought Apple for -429 million dollars. I now had all my favorite worlds in one place: Mac, Unix, and now NeXTstuff.

April 3, 2011

My first professional bug

Filed under: history, programming, Random, Visix — Mark Dalrymple @ 8:23 pm

Clearning with rooking grass

Mike Ash’s recent Friday Q&A about signals mentioned SIGWINCH, the hearing of which always sends me down memory lane.  My first professional bug was centered around SIGWINCH.  By “professional bug”, I mean a bug that someone paid me actual money to fix during a period of employment.

I went to work for a company called Visix straight out of college in the early 90’s, which at the time sold a product called Looking Glass, a file browser much like the Macintosh Finder but for Unix.  Eventually Looking Glass would become the Caldera Linux desktop.  Looking Glass supported the major graphical windowing systems of the time: X11, Intergraph’s Environ V, and Sun’s SunView.  The image at the top of this posting is the only screen shot I could find of the version of Looking Glass I worked on running on SunView.  Notice the awesome desktop widgets at the top.  That was typical SunView style, so Looking Glass was pure awesome eye candy in comparison.

I was hired for the tech support team, and our duties were phone support (typically debugging network configurations and X server font paths) and porting Looking Glass to other platforms.  Being the Lo Mein on the totem pole I got given the old platform nobody wanted to touch any more: SunView.

SunOS 4.1.X had just come out, and Looking Glass would hang randomly.  It worked fine on 4.0.3.  My job was to find and fix this hang.  This was my first introduction to a lot of things: C, unix systems, windowing systems, navigating large code bases, conditional compilation, debuggers, vendor documentation that wasn’t from Apple, working in a company, and so on.  Luckily the SunView version didn’t sell terribly well any more because everyone was moving to X11, but there were a couple of customers bitten by this problem.

So what is SunView?  SunView is a windowing system: different programs run displaying graphical output into a window.  Nowadays that’s commonplace, but back when SunView came out it was pretty cool.  SunView was one of the earlier windowing systems,so it had a bunch of peculiarities: the biggest was that each window on the screen was represented by an honest-to-god kernel device.  /dev/wnd5 is a window, as would be /dev/wnd12.  There were a finite number of these window devices, so once the system ran out of windows you couldn’t open any more.

There was a definite assumption of “one window to one process” in SunView.  Your window was your only playground.  Looking Glass was different because it could open multiple windows.  Because of the finite number of windows available system-wide, we had to create the alert that said “You can’t open any more windows because you’re out of windows” at launch time, thereby consuming a precious window resource, and hide it offscreen.  It was the only way we could reliably tell users why they couldn’t open any more windows.  Glad I wasn’t the one that had to make this work in the first place.  I was just fixing Legacy Code.

The other peculiarity is that you never got window events.  Even in the 1.0 version of the Macintosh toolbox you could easily figure out if the user dragged the window, or resized it, or changed its stacking order.  In SunView you just got a signal. SIGWINCH, for WINdow CHange, and hence the memory-lane trigger.  The user moved a window?  SIGWINCH.  The user resized it?  SIGWINCH.  The user changed the z-order?  SIGWINCH.

With just one window that’s not too bad.  Just query your only window for its current size.  For us, though, we had to cache every window’s location, size, and stacking order.  Upon receipt of a SIGWINCH we would walk all of our windows and compare the new values to the cached version.  If something interesting changed we would need to do the work of laying out the window’s contents.

So, back to my bug.  It took me a solid month to fix.  All this time I thought I was a failure and was worried I’d get fired.  That would be embarrassing. It took so long to fix because it was part time work in amongst my other responsibilities, and also because it was difficult to reproduce.  Spastic clicking and dragging could make it lock up, but not reliably.  Using the debugger was pointless – a 4 meg Sun 3/50 swapped for two hours as dbx tried to load Looking Glass.  I ended up using a lot of caveman debugging.

Event queues

The application event architecture we used is shown right up there.  Each window had an event queue (remember that one window to one process assumption) that held all of the mouse and keyboard events.  Upon receipt of new events (I forget if we got a signal for that, or if some file descriptor became readable), we would walk our windows: read each event, handle it, then move on to the next window.

I was getting some printouts, though, showing an window receiving mouse-downs and mouse-drags, but no mouse-up.  Occasionally I would see a mouse-up, with no mouse-downs.  Ah-ha!  The mouse-up was being delivered to the wrong window’s event queue, probably due to some race condition down in the system that didn’t notice the current window changed during the drag. The fix was easy once I found it : just merge the events from all the windows first, and then process them.  Happiness and light.

It was then I learned how expensive malloc is.  I malloc’d and free’d event structures, but performance was dog-slow, especially during mouse drags.  Caching the structures made life fast again.

Memories like these make me so happy with the cool tech we get to play with these days.

March 31, 2011

My Time Machine Exclusion List

Filed under: off-topic, Questions From Friends, Random — Mark Dalrymple @ 12:18 pm

A friend recently asked me about my opinions on the Time Capsule. I had the first generation device. It was OK, but slow, and eventually died the death of the power supply.

I have the latest gen now, 2TB, and love it. With 10.6 over a fast network, I don’t notice the hourly backups. One thing I did notice as time went on that the backups were getting kind of big. I want my individual machine backups to be under 1TB so I could archive them to some terrorbyte external drives I already have. I’d exceed that if I backed up too much junk too often.

My main goal for backups is to restore my $HOME data in the event of a machine failure. I don’t plan on restoring the OS or Applications from the backup. I’ll just use whatever OS is on the replacement machine or install my own, and I’ll install applications as I need them.

Backup Loupe is a great application for looking at your backups and seeing what’s being piggy. A file that’s only 50 megs is not a big deal, but it becomes a bigger deal if it gets touched regularly and gets backed up every hour. Using Backup Loupe, and general foresight, I have built this exclusion list over the last year or so. Unfortunately the list is not in any sane order. I’m not sure what order it’s listed, since it’s not chronological.

Time machine exclusions

Some are pretty obvious:

~/.Trash – no need to backup trash.

/Library/Application Support, /Library/Caches and ~/Library/Caches, those will be re-created by applications. ~/Library/Application Support I do back up since it might have useful goodies.  [edit: Mark Aufflick suggests preserving /Library/Application Support/Adobe.  Personally I just use Lightroom and Photoshop CS5.  Lightroom is pretty well behaved, and I’ll just reinstall Photoshop.  But if you had the full Suite, that’d probably be a huge pain].

/Applications, I’ll just redownload and reinstall them.

/Users/bork is a test user I only use for development. No need to back that up.

The various parts peculiar to individual app or companies are there because they’re either big, can be regenerated, or an app touches a file often. Camino is one of them. I don’t use it very often, but every time I do I have to back up 50 megs. So its application support directory is on the chopping block. Similarly, Chrome gets updated every week, and is pretty big.

/Developer and /Xcode4 are there because I’d fill up the Time Capsule just from Xcode updates. I can always download the latest one if I’m setting up a new machine.

~/junk is a directory I use to throw junk into (hence the name). NoBackup is a similar directory at the top level. I have one in Movies too as a place to store one-off iMovie projects. Once I create the final movie the project can go bye-bye, and I usually don’t feel the need to back it up in the interim. I can get the original footage from the camera again. If it’s something larger or more important, I’ll leave it in ~/Movies, which does get backed up.

~/Downloads is another place for stuff I don’t want to delete right now, but won’t cry if it suddenly went away. If I want to keep it, I’ll put it somewhere that’s backed up.

Lightroom generates previews of photographs so that the UI is more responsive. Those can be regenerated later, so they don’t ned to be backed up.

All system files, including /Library/Printers,and /usr are things that would come with a fresh OS instal. Things in /usr/local I can re-install as needed. Same with /opt.

My music lives on another machine, so I don’t need to back up ~/Music

I check with Backup Loupe every now and then to make sure there’s not a new suprise that’s getting backed up.

Addendum: courtesy of brad@cynicalpeak, there’s other trash directories, /.Trashes, /Volumes/*/.Trashes if you have multiple disks.  Also /var/folders is yet another cache location.

March 28, 2011

Borkware’s First-Timer’s Guide to WWDC

Filed under: off-topic — Mark Dalrymple @ 12:23 pm

Atm machienSo, you’ve just purchased your first WWDC ticket. Congratulations! Many folks have have published their “First-timer’s guide to WWDC”, so being a veteran of 6 or 7 of them, both in the modern age and during the Dark Times, I figured I’d hop on the bandwagon.

1) The ticket is expensive, so you’re probably short on cash now. Don’t worry about booking a hotel. The weather in San Francisco is really nice. It hardly ever rains. And if it does, there are many store fronts and office building entrances you can use for shelter. It’s also pleasantly warm 24/7.

2) Go to as many sessions, labs, BOF sessions, and parties you can at the Moscone center. It’s a virtual firehose of firehoses of information and activity. You won’t have time to bathe, so don’t even bother.

3) Get into the keynote line early. Most hardcore attendees start lining up Sunday afternoon. You’ll be guaranteed of a good spot if you get there late Saturday night. There’s really only 700 spaces in the keynote room, even though the videos make it look deceptively large (*cough* CGI *cough*). Due to health concerns, Steve’s Reality Distortion Field doesn’t extend past 10 or 15 rows these days. :-( May he rest in peace.

4) Don’t worry about food. In fact, you don’t have to really bring any money, credit cards, or Automatic ATM Machine cards. I can never remember my PIN Number anyway. Apple always lays out a huge spread of food from dusk to dawn and back to dusk again. Make sure to hang around friday evening for Prime Rib and Champagne night, in celebration of the end of a good conference.

5) A secret: you don’t have to wait until the end of a session for Q&A. There are microphones around the room. If the one you are at happens to be turned off, no problem. Bring your own bullhorn.

6) When asking questions in sessions, be sure to state your name, where you work, which platform you work on, which version of Xcode you prefer, and your opinion on the App store and C++ vs Objective-C. Be sure to complement the speaker on their sartorial choices. The sound systems are run rather hot, so please don’t speak too loudly into the microphone. Of course, if you brought a bullhorn, you can tailor its output to the conditions of the room.

7) Follow proper Labs etiquette. The labs where you can chat with Apple engineers are an invaluable resource. It is a scarce, shared resource, so treat it like you would computationaly: pretend to be a mutex. You walk into the lab you want and shout “I AM ATTEMPTING TO OBTAIN A LOCK ON THE MEDIA PLAYER FRAMEWORK ENGINEERS”. If an engineer is free, you’ll hear “LOCK SUCCEDED” from the back, and you can go to the engineer who just shouted and ask your questions. If no one responds wait until you time out, and try again. Expert tip: “spinlock”.

8) We’re all friends at WWDC. If a session looks to be standing room only, feel free to find an available lap.

9) The Thursday night beer bash is actually just a giant mosh pit.

10) Don’t forget that recording devices are forbidden. So please leave your voice recorder, iPhone, video camera, DSLR, pens and paper at home. The TSA has been contracted to provide session information security.

Have a great time! WWDC is an awesome experience.

January 20, 2011

Learning iPhone in Pittsburgh

Filed under: cocoaheads, iPhone, programming — Mark Dalrymple @ 7:35 pm

iPhone made out of cup cakesThe Pittsburgh CocoaHeads (where it all started) are going to be working through the new edition of the Dave Mark / Jeff Lamarche / Jack Nutting iPhone book as a group (ebook available today! woo!). Our regular monthly meetings will have a kick-off presentation on what to expect the next month. We figure a chapter a week is a good pace for folks with busy lifestyles.

A couple of us are making ourselves available for “office hours” if folks have questions / get stuck. Huge gumption traps for beginners are compiler errors and basic memory management, things that programmers with more experience can just glance at and know exactly what’s wrong. We’re hoping this solves the “stall-out half-way through” problem many people have picking up new technology as a hobby.

I had the pleasure of being the Tech Reviewer for this updated edition of Beginning iPhone4 Development. There’s a lot of good cool new stuff in there. During the course of discussions with Apress about acquiring the book in time for our launch, they’ve made a CocoaHeads discount code good for 25% off Mac/Phone ebook titles until the end of March : APRESSCOCOAHEADS2011, when you get it from the Apress store. There’s also a discount for folks who already have the iPhone3 version of the book, but I don’t know if they stack.

More info is available at, especially if you’re in the Pittsburgh area. Come join us! Folks outside of Pittsburgh are welcome to do the same thing. Feel free to use the monthly kick-off slides, which I’ll be putting up at as we progress into the year.

November 4, 2010

Links from my MacTech talk

Filed under: Random — Mark Dalrymple @ 1:54 am

For the folks who had the stamina to sit through my talk about Debugging at today’s MacTech conference sessions, here are some links I mentioned

And for the folks who missed it, I believe MacTech will be selling DVDs.

October 29, 2010

Benzado: How to Learn to Program in 2010

Filed under: programming, Random — Mark Dalrymple @ 10:39 pm

My bud Ben Ragheb wrote a blurb on learning to program in 2010.  I too started with the 8-bit personal computers of the 80s and typed in games from books and magazines, so I’m usually at a loss when someone asks me how to learn to program.  Usually I point them at the browser and mumble “Javascript”, then run away when they’re not looking.


September 19, 2010

Stay out of Apple’s Namespace

Filed under: Uncategorized — Mark Dalrymple @ 5:00 pm

I’ve been noticing a disturbing trend lately.

A friend asked me recently, “Would naming your own Objective class prefix with NS be an issue with Apple or that is just not good in general?”.

An industry luminary retweeted an otherwise useful macro:

#define CFAutorelease(cf) ((__typeof(cf))[NSMakeCollectable(cf) autorelease])

And recently I saw a blog post where they make their own CLLocationCoordinate2DMake, and then go through contortions to fix things when Apple introduced their own version in a later SDK.

Don’t do this! Stay out of Apple’s Namespace.

There are two big reasons to do this:

  1. Apple changes things. Often. If you add a function, macro, class, or struct in their namespace, you may break. People who use your code may break. People who cut and paste your tweets may break.
  2. It’s confusing for the person reading your code 3 years from now. Or your new hire. Or someone who uses part of your open source library. Or you include it into a posting on a mailing list or stack overflow. “CFAutorelease, I didn’t know that existed.” “uh, sorry, it really doesn’t.”

In general, you should stay out of the namespaces of any code you’re using, such as making your own GTM-named classes if you’re using the Google Toolbox For Mac. That could break you the next time Google revs that library.

CF, NS, CLLocation, etc. Those aren’t your playground.
That’s Apple’s turf. Which kind of makes me sad, since I’m doing stuff for Cycling Fusion now, and using the obvious prefix would be a disaster.

Pick your own prefix and use that. BWCFAutorelease, BWCLLocationCoordinate2DMake. This shows that yes, this is not part of Apple’s API, but also clearly shows the intent of the symbol. Without you being broken by Apple in the future.

September 10, 2010

QFF: Where’s it live?

Filed under: programming, Questions From Friends — Mark Dalrymple @ 8:52 pm

Friend asked on AIM:

I’m curious about how static variables work. Presumably they aren’t stored in the stack, right? So how come you don’t have to store it as a pointer?

They’re just global variables, but with limited visibility. So their actual storage is off with all the other global variables, but nobody outside of that function can actually see it. like having a spy in their midst.

Where is that? I guess my confusion is that it seemed like the sort of thing you’d have to allocate memory for.

Have an illustration:

so the arrows show where stuff lives / ends up. arg and the local vars are on the stack.
The four bytes for the ‘blah‘ pointer is on the stack. The return from malloc is in the heap, and the static local is off hanging out with the globals.

I thought char * blah and static char blah were basically the same thing

char * blah has a short life span. Kind of like a firefly.

static char *blah has a long life span. Kind of like a roach that’ll never leave the kitchen. attacks with Raid™ notwithstanding.
Definitely a kill -9 situation then.

So with char * blah if you forget to free the memory before the function exits you can’t get to it again, right? Because the pointer to it is gone

if you do char *blah = malloc (23); and then exit the function before free() ing, then yes, it’s gone. It’s occupying space, but there’s no map to find it

So that’s a leak


September 6, 2010

Block Retain Cycles

Filed under: amosxp, programming — Mark Dalrymple @ 10:37 pm

So I’ve seen in a couple of places where you can get retain cycles with Objective-C blocks, and then have to do some contortions to get a __block-storage-class self pointer that won’t be auto-retained.

But I couldn’t find a simple example to demonstrate the problem, and I want to verify the problem before it gets cast into dead trees or implanted into student’s minds.

So here is minimal example. First is a typedef for a block pointer, and a simple object that holds on to the block:

// Just a simple block pointer that asks for nothing and gives nothing.
typedef void (^BlockHead)(void);

// The leaky object.
@interface Leakzor : NSObject {
    NSString *string;
    BlockHead blockhead;

// Print |string|.
- (void) funk;

@end // Leakzor

This will leak the object and the block due to the retain cycle:

- (id) init {
    if ((self = [super init])) {
        string = @"snork";

        // |string| is the same as self->string, so |self| is retained.
        blockhead = Block_copy(^{
                NSLog (@"string is %@", string);
    return self;
} // init

If you compile blockcycle with -DRETAIN_CYCLE=1 you won’t see the dealloc NSLog. Why?

blockhead has caused self to be retained. self won’t be released until blockhead is cleaned up in -dealloc. But -dealloc won’t get called because self is still retained by the block. This is a classic retain cycle.

So how to fix it? With these hoops:

        // |blockSelf| is __block scope, so won't be auto-retained
        __block Leakzor *blockSelf = self;
        blockhead = Block_copy(^{
                NSLog (@"string is %@", blockSelf->string);

So now I access string by using the self pointer, but in the shape of a __block-storage-class local variable. This doesn’t have the retain behavior that ordinary variable capture has.

Does this mean that I’m going to be peppering every block that refers to self, directly or indirectly, with this stuff? Nope. But it’s something to keep in mind, especially if you’re making a copy of a block and then dealing with its cleanup in -dealloc (vs some kind of good-bye kiss method).

July 22, 2010

QFF: Kitchen MVC, part 1

Filed under: programming, Questions From Friends — Mark Dalrymple @ 2:08 pm

I got a question a couple of weeks ago under the subject “Cross File Method Calling” from a friend who was struggling with Model/View/Controller. Like a lot of stuff, it’s easy to look at a concept like MVC, grasp the contents, and then have your brain go into vapor lock when faced with empty source files. This F# major scale only has six sharps in it. It looks pretty easy on paper. Then you try to play it on the bassoon. Oh my.

We had a nice chat that turned into more “how to reduce dependencies” rather than full-blown “here is MVC in all of its glory”. Specifics have been changed to protect the cool project he’s working on.

I have this: KitchenCombatViewController.m – I create 4 new UIViews: OvenView, FrigeView, PantryView, and BlenderView. These know how to draw themselves, I can layer them and hide/unhide them as needed. Works well.

Now in the touches routine in BlenderView, I want to call a method in another file, like setNeedsDisplay in PantryView. I can make an instance variable that points to it, but I don’t know how to initialize it to point to the PantryView.

Let’s take a step back. Here’s what I saw with the first sentence:


The next statement, having BlenderView talk to PantryView, would look like this


Which would work OK now. But as software evolves, you’ll find other places to do the same trick. “FrigeView will need to tell the OvenView this. And then the BlenderView will also need to tell the FrigeView that.” And before you know it, you’ve got a pretty complex web of interactions:


It might not happen immediately. It might not happen until the next version or two as you add features, but as you add more dependencies between objects, it becomes easier to add even more dependencies. Wonder what happens if you add another view into the mix later? You’ll probably end up with another N connections. And if you’re not careful with memory management, you’ll get retain cycles.

What you want to do is to reduce the number of individual points of contact between the moving pieces. The KitchenCombatViewController already knows about the four views. It creates, layers, shows and hides them after all. So it would be a good place for that logic:


Notice that the relationship between the controller and the views has become two-way. The views need to know about the controller so they can tell the controller “hey something Interesting happened to me. Other folks may or may not want to know about it”. But notice that there are much fewer direct interconnections between objects. If you need to have FrigeView’s touch handlers tweak the OvenView, it’s a line or two of code in the Combat controller rather than setting up a direct dependency relationship between the two.

Also, if you add a new view type, say a SinkView that needs to be updated as combat progresses, you don’t have to touch any of the other views. This last point is huge. You can extend the capabilities of your system without having to touch a lot of other places in the code. That’s fewer changes that could introduce bugs. Less chance of forgetting some detail, like “oh yeah, touches in the FrigeView really needs to tweak the SinkView too”.

That makes sense, but I’m not seeing how I do that “tell the combat controller” that something interesting happened?

That’s in part 2, attack of the code.

Older Posts »

Create a free website or blog at