RSS

FastCGI a Lesson in priorities.

by loudmouthman

Posting in June for work done in May I am the bane of this sites hopes to keep all the projects in tune with their month, sorry about that. Meanwhile what I had hoped to be playing with , namely near realtime ajax and site interactivity took a back seat as a seperate learning experience came up.

Catalyst is a Perl MVC Framework and has been used for numerous web projects and applications all of which are now starting to feel a little bit legacy thanks to Rails and Node.js. However support in terms of system administration is still required as a result I had the opportunity of taking on the hosting and uptime for a previous Catalyst application and this meant  my rather straight forward appreciation of Apache Mysql and PHP  would have to be discarded.

I learnt that Apache can use sockets to pass queries from the server to the application instance and pass the results back in turn. To explain how this feels unusual to the average webmaster you need to understand that for part of the configuration in Apache you are specifying fictional files and extensions in order to ensure the fast_cgi module works correctly but before we go there lets look at how the Catalyst application starts.

In the application folder there are a number of scripts which can run the application with its own test server or against a socket.  Adding the startup script to /etc/rc.local ensures that the application is restarted and listening on the socket when the server is rebooted.

/home/useraccount/catapp/script/catapp_fastcgi.pl –listen /tmp/catapp.socket -n 6 -p /tmp/forumevents.pid -d

Here the catapp_fastcgi perl script configured the application to listen on the file /tmp/catapp.socket with a maximum of 6 new processes and to report its processid to /tmp/forumevents.pid and then to run in the background as a deamon.

That will get the Application started now you can configured Apache; you will need the fastcgi modules loaded and enabled in apache

../mods-enabled/fastcgi.load -> ../mods-available/fastcgi.load
../mods-enabled/fastcgi.conf -> ../mods-available/fastcgi.conf

The fastcgi.conf is configured as

<IfModule mod_fastcgi.c>
AddHandler fastcgi-script .fcgi
#FastCgiWrapper /usr/lib/apache2/suexec
FastCgiIpcDir /var/lib/apache2/fastcgi
</IfModule>

In ./sites-enables/fastcgi_catapp

<VirtualHost *:80>
ServerName testcatapp.testserver.co.uk
FastCgiExternalServer /tmp/catapp.fcgi -socket /tmp/catapp.socket
Alias / /tmp/catapp.fcgi/
</VirtualHost>

What caught me out when looking at the Documentation was the entry for FastCgiExternalServer there are a number of similar commands that look like FastCgiExternalServer and I was using them incorrectly. As you can see there is a mention to catapp.fcgi which is file that will not exist , its  fictitous , so you need to get past it  and accept that it is needed and you are expecting it to be there since it is used in the Alias command to point the server to the application.

 

That was it. A fastcgi implementation of Catalyst running under Apache and its very very FAST indeed. A Practical lesson learnt and a new technology under my belt. It fits neatly into the path for 12412.org I have set myself since this puts socket.io on my horizon and leads nicely back to my original plan for May; I learnt a little if indirectly a web technology and I gained some understanding of Catalyst on the road.

 

 

 

No Comments »

An Introduction to CSS3 Animations

by mrqwest

There are some really nice effects which can be achieved using keyframe animations through CSS3, and generally speaking, once you understand the premise behind it, it’s relatively easy to get these animations working.

A keyframe animation is made up of the keyframe, a series of instructions which tell the browser what to render and when in the animation flow and some CSS declerations within your .css file.

Let’s look at an example which fades content in on page load.

@keyframes fadeIn {
0% {opacity: 0;}
100% {opacity:1;}
}

If you are only using two keyframes, you could also set the @keyframes animation as:

@keyframes fadeIn {
from {opacity: 0;}
to {opacity: 1;}
}

I generally stick with percentages as I find it easier.

All keyframe animations start with @keyframes followed by the name of your animation. This could be anything, but ideally should describe what your animation will do. In this instance, it’s called fadeIn.

Open up your keyframe animation with a set of curly braces. Within these braces, you declare your animation keyframes. In the example above, it’s a really simple effort. 0% = the start, 100% = the end. You could have 100 different keyframes in there starting from 0% through to 100% but in this instance, it’s not required.

On our starting keyframe, we’ve set the opacity to 0 which makes it transparent. Our ending frame (100%) has the opacity set to 1 which makes it opaque. So when the animation runs, it takes the element, makes it transparent and then increases the opacity of the element until it reaches the end frame, which in our case is @opacity: 1;@.

Once we’ve written our keyframe animation, the next step is to hook that animation up to our element. CSS3 gives us several different declarations which help us manipulate the animations.

As an example, let’s say we want the whole page to fade in once it’s loaded, a nifty little effect you may have seen previously. To do this, we’ll apply our keyframe animation to the body tag of our page.

body {
animation-name: fadeIn;
animation-duration: 1s;
}

These are the two basic declarations needed for what we’re doing. The first name is pretty self explanatory. You’re calling the keyframe animation you’ve just written, so this will be ‘fadeIn’.

The second declaration is ‘animation-duration’, which tells the browser how long to take between 0% & 100%. This example shows ’1s’ which is equal to 1 second, but could be anything. Speed it up to .5s for a quicker animation, or slow it down to 4s for a slower animation.

That’s all you need for a basic animation.

As mentioned though, there are several other declarations you could add into your CSS to enhance the effect.

animation-timing-function

The animation-timing-function alters the curve of the animation. There are several options that can be applied here but the default is ‘ease’ which is pretty nice anyway.

Other options include: linear, ease, ease-in, ease-out, ease-in-out & cubic-bezier(x,x,x,x) (which you can specify your own curve).

animation-delay

As the declaration suggests, this denotes when the animation will start. It accepts a time-related value in either seconds (s) or milliseconds (ms).

animation-iteration-count

This declaration denotes how many times the animation will take place. The default is _1_ so the animation will only take place once, setting a value of 10 would mean the animation looped 10 times and then stop. You could also specify ‘infinite’ as a value which means the animation would, as suggested, run infinitiely.

animation-direction

Instead of running the animation from 0% to 100%, declaring animation-direction: alternate; would run the animation from 100% to 0%.

animation-play-state

Two options are available for this decleration, ‘running’ which is the default and ‘paused’ which as suggests, pauses the animation.

animation-fill-mode

This is a hard one to describe. Generally, css animations will start and stop at the beginning & end of the keyframe animation. @animation-fill-mode@ lets the animations bleed out from these restrictions and allows the animation to continue to an extent after the keyframes have finished by retaining the values set for the 100% keyframe. The selector will accept the following values: none (default), forwards, backwards, both.

Support

Support is generally quite good for CSS animations. Firefox, Chrome, Safari & Mobile Safari all support animations as does Android 4. IE9 and below doesn’t support but are you surprised by that? IE10 will support them though. Opera, Opera Mini & Opera Mobile also lack support however Opera 12 will support.

But you can still use CSS prefixs to use animations now. Here’s our fadeIn animation using prefixes:

/* webkit browsers */
@-webkit-keyframes fadeIn {
0% {opacity: 0;}
100% {opacity:1;}
}

/* Firefox */
@-moz-keyframes fadeIn {
0% {opacity: 0;}
100% {opacity:1;}
}

/* IE */
@-ms-keyframes fadeIn {
0% {opacity: 0;}
100% {opacity:1;}
}

/* Opera browsers */
@-o-keyframes fadeIn {
0% {opacity: 0;}
100% {opacity:1;}
}

/* For when it’s a standard */
@keyframes fadeIn {
0% {opacity: 0;}
100% {opacity:1;}
}

body {
/* add in the animation name */
-webkit-animation-name: fadeIn;
-moz-animation-name: fadeIn;
-ms-animation-name: fadeIn;
-o-animation-name: fadeIn;
animation-name: fadeIn;

/* We only want the animation to run for 1 second */
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
-ms-animation-duration: 1s;
-o-animation-duration: 1s;
animation-duration: 1s;
}

Elsewhere

For some other cracking resources, check out Animate.css by Dan Eden, where he has kindly created a whole bunch of excellent animations and put it all on github for you to drop into your websites.

Mozilla Developer Network is also a valuable resource.

Also keep an eye on Can I Use.com which shows you the current level of browser support for animations.

No Comments »

Ketchup

by Stephen Fulljames

So once again I’ve become the guy who invented the site but never posts updates to it. Sorry about that.

A combination of complex work projects and the odd family drama hasn’t left a lot of time for web learnin’, although I achieved more with Node during March and April than I had a chance to write about. Mainly creating a new site using Node and the Express framework – What the Framework – intended as a bluffer’s guide to all those fancy new technologies the cool kids are talking about. And recreating the previously PHP-driven fulljames.net as another Node site – kind of because I could. I still hope to write up the basics of how these sites work but until then you could do worse than check out Jack Franklin’s excellent tutorial on getting started with Node and Express.

Then at the end of April Paul and I flew to Poland for the excellent Front Trends conference, which did a lot to get my motivation going again. Most of the talks across the two days were excellent, but the highlights for me in terms of picking up new things to get into were Lea Verou on CSS animations and Jina Bolton on SASS, and for general inspiration and provocation Alex Russell, Bartosz Szopka, Chris Coyier, John Schultz and Rachel Andrew.

And this week in Brighton saw the second Points mini conference, which in comparison may have “only” comprised of four talks and a raffle of top quality web-related prizes, but was an equally inspirational and thought provoking evening in the company of friends and new acquaintances (some of whom have also posted here!).

So with a couple of weeks of May still to go I’m going to carry on with my exploration of Node, particularly as I’m now getting to the point where I need to do stuff with data, and there are various options for storing it including MongoDB, Redis and even good old MySQL. I’m also going to continue a talk outline I started putting together on the train home from Points, perhaps I’ll find an opportunity to try it out on a few people as the year goes on…

No Comments »

Keeping busy

by mrqwest

Wow, it’s been a while. Last post I made on here was back in March where I’d said I had been reading up on jQuery.  Well, funnily enough, I still am (it’s a big subject) but I’m proud of what I’ve learnt.  I’m still reading Sitepoints ‘jQuery: Novice to Ninja’ (it’s hard finding time to read with a newborn) but I’ve picked up a lot in the past few months and now pretty confident with the basics of jQuery (even if I do forget the (document).ready declaration a lot of the time).  The last client project I handed over had a .js file with around 150 lines of jQuery I had written!  That’s pretty epic from where I’m standing and that’s the whole idea behind the 12412project!

So what’s next?  jQuery is faaar from finished but I figured I’ll pick up more of that throughout the year. I’ve had a real flurry of client projects take hold the last couple of months and I’m pretty booked up for the foreseeable few months too, so that should help get the jQuery knowledge cemented.

CSS Animations are next on my list, and I’ve played with those once or twice on recent projects. I’ve got a domain name with my name on it (literally!) which I want to make into a cool introduction page with portfolio and contacts. A kinda flashy way of saying ‘Hi, I can do awesome stuff – hire me why dontcha’!   I’ve got some ideas in my head which I want to flesh out first and I’ll post my brief introduction to CSS animations in a week or so!

Stay tuned :)

No Comments »

Say it in Style : Cufon or Google Fonts ?

by loudmouthman

So Its May and I am writing about my April explortion so I guess posting late is my thing then.

Getting the Fonts a client wants to see into a webpage has been fraught with technical issues which tend towards the obscure from a clients point of view. From their perspective the graphics designer has created a document that they can see on a screen with no problem so why cant a web page do just that  ? When these conversations raise their head these are the moments which lead a developer to beat their head against the brick wall of customer obstinacy as they attempt to explain why text embeded in graphics becomes problematic in terms of  search, in terms of design and in terms of portability.

Google web fonts has been a good start in answering the how and the why as to the design issue but it has lacked a certain portability in terms of choices available to the designer. Cufon appears to fill the gap in the ‘pick your font and show it’ market but my experiences in the last few weeks demonstrate that the market for purchasing and implementing cufonts is tenuous and unsatisfactorily delivered.

Both technologies require javascript implementations in their preload and this can lead to limitations in site interactivity and functionality from a users perspective  as well as the usual hassle of playing browser support limitations with delivery.   They are well supported with plugins for WordPress and plenty of sample code abounds on the net to demonstrate the how to implement requirements.

Finally the End User License requirements of managing Fonts ( an aspect the copyright industry rarely seems to chase after as efficaciously as say Music or Video ) has been a constant source of delay and investigation and at the end of an hours deliberation over font texture and styles the lack of clarity on permission is a straw that breaks a back of a decision.

For now I am sticking with Google Fonts until such time as CuFon marketplace is mature enough to ensure simple delivery of Font content for a developer and webdesigner.

As for May; Well I want to take a detour back to Jquery and get a deeper appreciation of creating Ajax calls with live feedback such as the type required in status updates and scrolling completion status bars.

 

Thanks for reading.

 

2 Comments »

A Mad March For PhoneGap

by loudmouthman

If I were to be graded for March then I would get a partial fail for this month. Whilst I did goto PhoneGap and download and install the extensions for both iPhone and Android development I failed to actually follow the tutorials and create some form of Hello World application for any platform; which on the whole is not a very impressive affair.

The lesson to be learnt here is that “Failure Is An Option” and that whilst March may not have been the most productive month for my 12412 Experiences it did not leave me utterly devoid of experience or understanding. Not only did I re-aqaint myself with The Eclipse  development environment on Ubuntu and Windows but I refreshed my Macboook Pro Xcode installation and updated the machines OS  to Lion. All good procrastination activities to be done when trying to complete any module and all good pointers towards the fact that I have an abundance of kit to code on and I could be trying harder.

I had hoped to gain some understanding of developing using Phonegap instead  what I learned was that March was a little too busy and that I dont feel harsh on myself for not completing a task.

I hope this post can encourage all of you taking part in 12412 to keep up the focus month to month and to  have fun and feel guilt free about some goals.

 

No Comments »

Running Node sites on Webfaction

by Stephen Fulljames

I chose Node.js as my March project because, for someone working mainly in Javascript development, the thought of being able to use the same technology and ways of working on both client and server is pretty exciting. I’ve used it a little bit already, on prototyping projects for clients, but I wanted to step back and start from the fundamentals to really understand how to do it properly. A big part of this was taking myself to Remy Sharp’s Node workshop in Brighton, which was a brilliant introduction to the concepts behind the language and an opportunity to spend a couple of days immersed in asynchronous thinking and the wonders of new real-time tools such as websockets which Node is perfect for.

I’m not going to cover setting up Node on a local system for development, because for Mac and Windows users there’s now a simple package installer for the latest versions. And if you’re on Linux you’ll already be used to whistling your own TCP/IP packets down an ethernet cable so it should be a snap. Just head to the Node.js downloads to get going.

However I also wanted to make sure that it would be possible to run Node sites on my hosting service of choice – Webfaction. There are a number of other more immediately compatible services out there, such as Heroku and Linode, but as Webfaction allows you free access to install software and there are a few guides out there on the web I thought I would give it a go. At best it would let me keep all my sites in once place and avoid paying out for something else, at worst… at least I tried!

Onwards!

The first guide I tried made it sound pretty straightforward. And indeed it is. Open a SSH connection to your hosting account, download the package. Build it. Job done.

The catch, in my case, was that my hosting account was on an older server at Webfaction which doesn’t support…. actually I had no idea why it didn’t do what it needed to, but this is a known problem and they offer free migration to a new server if you need it. So I spent a week moving over and reconfiguring old sites and a few WordPress installations (including this one, did you notice?) and then set back to getting Node up and running.

Once this was done, the actual Node install process ran without any further glitches. Broadly speaking I followed the answer in this error report, although its worth mentioning that more recent versions of Node have NPM (the module manager) built so there’s no need to do the extra step listed in the first guide. And of course you are getting the current version of Node – which at the time of writing was 0.6.12.

Forwards!

With a working Node installation it was time to test some code out. The specifics of this I’ll cover in another post, but there is a further step to get to a running application on Webfaction hosting. Within the service’s control panel you manage your URLs, create applications and then associate them together into websites. By default, applications are chosen from a list of pre-installed frameworks – Rails, WordPress, etc – but with a manually installed language like Node things are a little more complicated.

One of the options is ‘custom application – listening on port’, which assigns a port number that it will forward traffic from. So if you create one of these, assign it to a URL and then start a Node instance running on that port – website!

As a test of all this I decided to recreate my very simple personal homepage – fulljames.net – as a Node application, and I’ll blog more about doing that soon.

No Comments »

Joining the 12412 project (a little late)

by Niall McMahon

So I’ve decided to join in on the 12412 project. I’m a little late, but to be fair, I only found out about it a few weeks ago.

I’ve been involved in the web development industry since 2004 when I had 2 weeks work experience at a local firm. That lead to a summer job, which lead to a part time job, that eventually led to me working full time as a web developer nearly 2 years ago. I like to think I am pretty up to date with the current web technologies — I’ve been using HTML5 and CSS3 on all my projects for the last few months, I use jQuery on most projects, and I have been using PHP (with MySQL where appropriate) since I became familiar with it a few years ago. I don’t claim to be a graphic designer, but I would say I have keen eye for design and love creating beautiful hand crafted websites.

However, I am always interested in furthering my knowledge of web technologies, so when I discovered the 12412 project, I was keen to get on board. I am currently having a bit of trouble even thinking of 12 things to learn over the year, but I have a few in mind to get me started, and I can add more to the list as the year goes on. I have already learnt something new this year, which I am going to cheat and include as one of the twelve so I can catch up. Here’s what I have so far:

  • HTML5 geolocation API (I’ve learnt this already — Clive Walker has very nicely linked to my article in his own about geolocation)
  • HTML5 canvas
  • LESS dynamic stylesheet language
  • WordPress
  • iPhone application development

OK, so the last one isn’t strictly a web technology. I’ve experimented with iPhone web app development over the last couple of months, but having an understanding of native app development is something I think will be useful.

If anyone has any suggestions of things to learn, I would be happy to hear them.

4 Comments »

How we update our WordPress theme

by Stephen Fulljames

With three of us working on the core WordPress theme which makes up the 12412 site, we wanted to be sure we could all easily make updates to it – but without conflicting with each other and in a way that made the theme open and available for anyone to look at.

The second part of this requirement was simple: we work with the theme in a Git repository, and are using Github both as the “origin” repo and a place to host and give access to the theme files for anyone who is interested in seeing them. The theme itself is based upon Paul’s Slim Starkers, which is itself a further cut-down fork of Elliot Jay Stocks’ Starkers and provides a nice, clean starting point for your own layouts. Between us we have varying experience of Git as a source control system, so working in this way is also helping to build up the skills of the whole team.

The first part, allowing us all to push theme updates to the 12412 site, required a little more thought.

One great feature of Github is its facility for post-commit hooks, which allows you to trigger a HTTP post to an external service whenever you push to the repository. Typically this is used a signal to the service that you want it to fetch the new commit from the repo and do something with it – in our case it would simply be to deploy the files. There are a couple of documented ways of doing this tailored to WordPress, requiring Git to be installed on your web server, and ultimately we’ve evaluated this method as being one to try in the future.

Back in the now, we still needed a simple but effective way to get our updates live. Of course you could manually copy files up after making a change in your local repo, but there is a risk of conflict here and over-writing other work if you’re not careful about pushing and fetching code from the origin. Perhaps there was something out there a bit neater.

If you’re familiar with WordPress’s theming system, you’ll know that they can be versioned through meta data in the style.css file. This is what triggers updates in your site’s admin panel when new versions of publicly hosted themes are released but it doesn’t work if the theme is hosted on Github. However a bit of searching turned up the Theme Updater plugin, which promises to do exactly that.

Now in our style.css file there is a new piece of metadata, Github Theme URI, which should be set to the location of the Github repo.

The Version of the theme is then incremented for each version we want to update with, using SemVer principles, and that commit in the repo is tagged with the same version number.

Finally, in the admin interface, the plugin polls for updates from Github in exactly the same way as a regular theme and – when a new tagged commit is seen – prompts for the update to be applied.

In this way we get to hook into WordPress’s own theme updater which means all the niceties such as switching to maintenance mode are taken care of.

So far it seems to work brilliantly. We may later on look at a post-commit hook to automate our updates, but for the time being the plugin is doing exactly what we need it to.

There is a slight caveat in that it only works with public Github repos, but I’m sure it wouldn’t be impossible to put some authentication in the plugin to access private ones – should you need it.

No Comments »

User Feedback & Simplifying the NSPopover

by Michael Robinson

Preamble

For my March 12412 project, I wanted to investigate ways to improve how one may provide user feedback in Objective C, from both the user’s and my (the programmer’s) perspective.

PANmedia Contact FormFirst, let me tell you one thing I dearly love about creating web forms: it’s so easy to provide salient user feedback where appropriate, and to connect that feedback to the related input. In fact it’s so easy that there really is no excuse to not do this. None. Even the most basic implementation will help increase conversion rates. Better feedback will increase rates further. Fundamentally, if a website doesn’t bother to tell a user what they’re doing wrong, they don’t bother trying to do it right!

A great example of one way feedback can be provided is on the PANmedia site’s contact form – PANMedia. If the user’s flailing attempts at entering their email address fail, the form will let them know. A user who knows what to do is one that might actually do it. This user feedback increases the likelihood that PAN will receive enquiries, which is one of the goals of that page.


None of us is without flaws

My secret love, Cocoa doesn’t make providing this feedback as easy for me. The paradigm is different: users on a website are accustomed to colours changing, forms morphing, elements popping in below input fields. Users of a desktop application, not so much. On top of that, websites are free to impose whatever colour scheme they like, while desktop applications have these imposed upon them.

In Cocoa, compared to an HTML form:

  • UI element positions are less flexible
  • The colour scheme is dictated by the OS. Therefore most applications will conform. It follows that changing text input background colours or related styling is generally a horrible idea
  • The GUI isn’t a DOM, there is no CSS & we don’t have jQuery, so popping labels in & out isn’t really feasible
  • The user is accustomed to all applications behaving in a certain way, and is alienated when something too wild happens, no matter how wonderful the feed back may be

Having covered what we can’t do, how do we politely let the user know that their sausage fingers have done it again, and “joe@gmailcom” isn’t a valid email address? Until now the programmer has had variations of the following options:

  • Use a modal alert (aka a popup)
  • Use an alert attached to the window (aka a modal sheet)
  • Write your own “ideal” solution
  • Do something broken, like change the input’s background colour

None of these are really ideal – the basic modal breaks the user out of the input view’s context, the sheet modal (although cool), doesn’t give targeted feedback, and finally, the “ideal” solution, well… I’ve never had time to write one, and if I did, I doubt it would be applicable to all situations (or as good as what you’re about to see).


He comes bearing gifts

Happily, and with great fanfare, along with OS X 10.7 Apple introduced the NSPopover, a way to display information related to specific items to the user. For me, this is the perfect solution – the popover allows one to display a message right next to the input in question. The popover will be consistent across applications, even those I don’t control (yes those exist). The popover is customizeable and may be filled with anything, anything I desire. Another popover? Don’t be silly.

My only issue after learning to use it was the amount of code / XIB work required.

If all I want to do is show a short snippet of text next to an input field, I dont really want to add 3-4 items to my XIB. If I didn’t do this, and opted instead for a completely programatic popover, I was looking at 10-12 lines of code. Neither was really good enough for me. In programming, the less one has to write, the less painful the code will be to debug in 3 months when all memory of it has vanished, and the code has transformed from the pinnacle of human achievement to something that appears to have been hacked together by a monkey on PCP.

One line of code would be perfect.


Enter the dragon

In the form of the Objective C category, one of my favourite features of the language. Categories allow the programmer to add methods to a class without being required to subclass it. I could, for example, add a category to NSPopover that allows me to initialise, configure and show a popover in one line. And so added, it was.

I christened the category “NSPopover+Message”, and it was good. It has reduced the complexity of creating and showing a text-filled popover from 10-12 lines of code or 3+ XIB items + a line of code to one line. Objective C, come here, let me kiss you.

Or, seeing as we’re not alone, let’s just let them see how good you look:

[NSPopover showRelativeToRect:[theInput frame]
                       ofView:[theInput superview]
                preferredEdge:NSMaxXEdge  // Show the popover on the right edge
                       string:@"Once upon a time, in a land far, far away, there was a little cake. It didn't last long."
                     maxWidth:250.0];
Popover Popping

Conclusion

The NSPopover was something I’ve wanted to investigate for awhile, but until recently couldn’t think of a reason that wasn’t absolutely contrived. After using it in the recommended way: adding the NSPopoverController, NSPopover, an NSView & NSLabel to the XIB then showing it in my controller, I felt this was too much work. Doing the above in code was less work, but still not idea. Ultimately, I created a category of NSPopover that does this all for me. All one has to do is provide a view, a position, a string and a willingness to experiment. Cocoa, that pretty little thing, will do the rest.

Special treats for those who made it all this way

I’ve taken the liberty of making an example application showing this popover in action. It’s available on GitHub here: 12412 NSPopover+Message Example.

For an excellent introduction to the NSPopover, see Using the New NSPopover.

1 Comment »