function stringify(evt) {
    var which = evt.which || evt.keyCode;
    var keyVal = KEY_VALUES[which];
    var key;
    var modifiers = [];

    if (evt.ctrlKey) modifiers.push('Ctrl');
    if (evt.originalEvent && evt.originalEvent.metaKey) modifiers.push('Meta');
    if (evt.altKey) modifiers.push('Alt');
    if (evt.shiftKey) modifiers.push('Shift');

    key = keyVal || String.fromCharCode(which);

    if (!modifiers.length && !keyVal) return key;

    modifiers.push(key);
    return modifiers.join('-');
  }
**********************************************
Textarea Manager

An abstraction layer wrapping the textarea in
an object with methods to manipulate and listen
to events on, that hides all the nasty cross-
browser incompatibilities behind a uniform API.

Design goal: This is a *HARD* internal
abstraction barrier. Cross-browser
inconsistencies are not allowed to leak through
and be dealt with by event handlers. All future
cross-browser issues that arise must be dealt
with here, and if necessary, the API updated.

Organization:
- key values map and stringify()
- manageTextarea()
   + defer() and flush()
   + event handler logic
   + attach event handlers and export methods
**********************************************