         The formatter to use before displaying content in the title label. This can be the `selectedTitle`, `deselectedTitle` or the `errorMessage`.
         The default implementation converts the text to uppercase.
     */
-    var titleFormatter:(String -> String) = { (text:String) -> String in
+    public var titleFormatter:(String -> String) = { (text:String) -> String in
         return text.uppercaseString
     }
     
     /**
         Identifies whether the text object should hide the text being entered.
     */
-    var secureTextEntry:Bool = false {
+    public var secureTextEntry:Bool = false {
         didSet {
             self.textField.secureTextEntry = secureTextEntry
             self.textField.fixCaretPosition()
         }
     }
     
-    /// The error message to display.
-    var errorMessage:String? {
+    /// A String value for the error message to display.
+    public var errorMessage:String? {
         didSet {
             self.updateControl(true)
         }
     }
+    
+    /// A Boolean value that determines whether the receiver discards `errorMessage` when the text input is changed.
+    public var discardsErrorMessageOnTextChange:Bool = true
     
     /// A Boolean value that determines whether the receiver is enabled.
     override public var enabled:Bool {

        }
    }
    
    /// A Boolean value that determines if the receiver is currently editing.
    var editing:Bool {
        get {
            return self.isFirstResponder() || self.tooltipVisible
        }
    }
    
    var hasErrorMessage:Bool {
        get {
            return self.errorMessage != nil
        }
    }
    
    var hasText:Bool {
        get {
            if let text = self.text {
                return text.characters.count > 0
            }
            return false
        }
    }
    
    private var _text:String?
    @IBInspectable var text:String? {
        set {
            self.setText(newValue, animated:false)
        }
        get {
            return _text
        }
    }
    
    /**
        The String to display when the input field is empty.
        The placeholder can also appear in the title label when both `selectedTitle` and `deselectedTitle` are `nil`.
     */
    @IBInspectable var placeholder:String? {
        didSet {
            self.placeholderLabel.text = placeholder
            self.updateTitleLabel()
        }
    }
    
    /// The String to display when the textfield is editing and the input is not empty.
    @IBInspectable var selectedTitle:String? {
        didSet {
            self.updateControl()
        }
    }

    /// The String to display when the textfield is not editing and the input is not empty.
    @IBInspectable var deselectedTitle:String? {
        didSet {
            self.updateControl()
        }
    }
    
    // TODO: get a better name for this, permanentlySelected?
    var tooltipVisible:Bool = false {
        didSet {
            self.updateControl(true)
        }
    }
    
    // TODO: get rid of this?
    var titleHeight:CGFloat = 20.0
    
    // MARK: - init
    
    public init(frame:CGRect, textField:UITextField?, lineView:UIView?) {
        super.init(frame: frame)
        
        self.lineView = lineView
        self.textField = textField
        self.createLineView()
        self.createTitleLabel()
        self.createPlaceholderLabel()
        self.createTextField()
    }
    
    override convenience init(frame: CGRect) {
        self.init(frame:frame, textField:nil, lineView:nil)
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.createLineView()
        self.createTitleLabel()
        self.createPlaceholderLabel()
        self.createTextField()
    }
    
    // MARK: create components
    
    private func createTitleLabel() {
        let titleLabel = UILabel()
        titleLabel.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        titleLabel.font = UIFont.systemFontOfSize(13)
        titleLabel.alpha = 0.0
        titleLabel.textColor = self.titleColor
        self.addSubview(titleLabel)
        self.titleLabel = titleLabel
    }
    
    private func createPlaceholderLabel() {
        let placeholderLabel = UILabel()
        placeholderLabel.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        placeholderLabel.font = UIFont.systemFontOfSize(18.0)
        placeholderLabel.textColor = self.placeholderColor
        placeholderLabel.alpha = 1.0
        self.addSubview(placeholderLabel)
        self.placeholderLabel = placeholderLabel
    }
    
    private func createTextField() {
        
        if self.textField == nil {
            let textField = UITextField()
            textField.font = UIFont.systemFontOfSize(18.0)
            self.textField = textField
        }
        textField.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        textField.delegate = self
        textField.addTarget(self, action: Selector("editingDidEndOnExit:"), forControlEvents: .EditingDidEndOnExit)
        textField.addTarget(self, action: Selector("textFieldChanged:"), forControlEvents: .EditingChanged)
        self.addSubview(textField)
    }
    
    private func createLineView() {
        
        if self.lineView == nil {
            let lineView = UIView()
            lineView.userInteractionEnabled = false
            self.lineView = lineView
        }
        lineView.autoresizingMask = [.FlexibleWidth, .FlexibleTopMargin]
        self.addSubview(lineView)
    }
    
    // MARK: input
    
    private func installDummyInputView() {
        self.textField.inputView = UIView(frame: CGRectZero)
    }
    
    // MARK: responder
    
    override public func becomeFirstResponder() -> Bool {
        self.textField.userInteractionEnabled = true
        let success = self.textField.becomeFirstResponder()
        if !success {
            self.textField.userInteractionEnabled = false
        }
        self.updateControl(true)
        return success
    }
    
    override public func resignFirstResponder() -> Bool {
        let success = self.textField.resignFirstResponder()
        if success {
            self.textField.userInteractionEnabled = false
        }
        self.updateControl(true)
        return success
    }
    
    override public func isFirstResponder() -> Bool {
        return self.textField.isFirstResponder() || self.textField.editing
    }
    
    // MARK: -

    private func resetErrorMessageIfPresent() {
        if self.hasErrorMessage {
            self.errorMessage = nil
        }
    }
    
    // MARK: -
    
    private func deselectedTitleOrPlaceholder() -> String? {
        if let title = self.deselectedTitle ?? self.placeholder {
            return self.titleFormatter(title)
        }
        return nil
    }
    
    private func selectedTitleOrPlaceholder() -> String? {
        if let title = self.selectedTitle ?? self.placeholder {
            return self.titleFormatter(title)
        }
        return nil
    }
    
    public func setText(text:String?, animated:Bool = false) {
        _text = text
        self.textField.text = text
        self.resetErrorMessageIfPresent()
        self.updateControl(animated)
    }
    
    public func setHighlighted(highlighted:Bool, animated:Bool = false) {
        if(super.highlighted != highlighted) {
            super.highlighted = highlighted
            

        }
    }
    
    /// A Boolean value that determines if the receiver is currently editing.
    public var editing:Bool {
        get {
            return self.isFirstResponder() || self.tooltipVisible
        }
    }
    
    /// A Boolean value that determines whether the receiver has an error message.
    public var hasErrorMessage:Bool {
        get {
            return self.errorMessage != nil
        }
    }
    
    /// A Boolean value that determines whether the receiver has text input.
    public var hasText:Bool {
        get {
            if let text = self.text {
                return text.characters.count > 0
            }
            return false
        }
    }
    
    /// A String value that is displayed in the input field.
    private var _text:String?
    @IBInspectable public var text:String? {
        set {
            self.setText(newValue, animated:false)
        }
        get {
            return _text
        }
    }
    
    public func setText(text:String?, animated:Bool = false) {
        _text = text
        self.textField.text = text
        self.resetErrorMessageIfPresent()
        self.updateControl(animated)
    }
    
    /**
        The String to display when the input field is empty.
        The placeholder can also appear in the title label when both `selectedTitle` and `deselectedTitle` are `nil`.
     */
    @IBInspectable public var placeholder:String? {
        didSet {
            self.placeholderLabel.text = placeholder
            self.updateTitleLabel()
        }
    }
    
    /// The String to display when the textfield is editing and the input is not empty.
    @IBInspectable public var selectedTitle:String? {
        didSet {
            self.updateControl()
        }
    }

    /// The String to display when the textfield is not editing and the input is not empty.
    @IBInspectable public var deselectedTitle:String? {
        didSet {
            self.updateControl()
        }
    }
    
    // TODO: get a better name for this, permanentlySelected?
    public var tooltipVisible:Bool = false {
        didSet {
            self.updateControl(true)
        }
    }
    
    // TODO: get rid of this?
    var titleHeight:CGFloat = 20.0
    
    // MARK: - init
    
    public init(frame:CGRect, textField:UITextField?, lineView:UIView?) {
        super.init(frame: frame)
        
        self.lineView = lineView
        self.textField = textField
        self.createLineView()
        self.createTitleLabel()
        self.createPlaceholderLabel()
        self.createTextField()
    }
    
    override convenience init(frame: CGRect) {
        self.init(frame:frame, textField:nil, lineView:nil)
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.createLineView()
        self.createTitleLabel()
        self.createPlaceholderLabel()
        self.createTextField()
    }
    
    // MARK: create components
    
    private func createTitleLabel() {
        let titleLabel = UILabel()
        titleLabel.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        titleLabel.font = UIFont.systemFontOfSize(13)
        titleLabel.alpha = 0.0
        titleLabel.textColor = self.titleColor
        self.addSubview(titleLabel)
        self.titleLabel = titleLabel
    }
    
    private func createPlaceholderLabel() {
        let placeholderLabel = UILabel()
        placeholderLabel.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        placeholderLabel.font = UIFont.systemFontOfSize(18.0)
        placeholderLabel.textColor = self.placeholderColor
        placeholderLabel.alpha = 1.0
        self.addSubview(placeholderLabel)
        self.placeholderLabel = placeholderLabel
    }
    
    private func createTextField() {
        
        if self.textField == nil {
            let textField = UITextField()
            textField.font = UIFont.systemFontOfSize(18.0)
            self.textField = textField
        }
        textField.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        textField.delegate = self
        textField.addTarget(self, action: Selector("editingDidEndOnExit:"), forControlEvents: .EditingDidEndOnExit)
        textField.addTarget(self, action: Selector("textFieldChanged:"), forControlEvents: .EditingChanged)
        self.addSubview(textField)
    }
    
    private func createLineView() {
        
        if self.lineView == nil {
            let lineView = UIView()
            lineView.userInteractionEnabled = false
            self.lineView = lineView
        }
        lineView.autoresizingMask = [.FlexibleWidth, .FlexibleTopMargin]
        self.addSubview(lineView)
    }
    
    // MARK: input
    
    private func installDummyInputView() {
        self.textField.inputView = UIView(frame: CGRectZero)
    }
    
    // MARK: responder
    
    override public func becomeFirstResponder() -> Bool {
        self.textField.userInteractionEnabled = true
        let success = self.textField.becomeFirstResponder()
        if !success {
            self.textField.userInteractionEnabled = false
        }
        self.updateControl(true)
        return success
    }
    
    override public func resignFirstResponder() -> Bool {
        let success = self.textField.resignFirstResponder()
        if success {
            self.textField.userInteractionEnabled = false
        }
        self.updateControl(true)
        return success
    }
    
    override public func isFirstResponder() -> Bool {
        return self.textField.isFirstResponder() || self.textField.editing
    }
    
    // MARK: -

    private func resetErrorMessageIfPresent() {
        if self.hasErrorMessage && discardsErrorMessageOnTextChange {
            self.errorMessage = nil
        }
    }
    
    private func deselectedTitleOrPlaceholder() -> String? {
        if let title = self.deselectedTitle ?? self.placeholder {
            return self.titleFormatter(title)
        }
        return nil
    }
    
    private func selectedTitleOrPlaceholder() -> String? {
        if let title = self.selectedTitle ?? self.placeholder {
            return self.titleFormatter(title)
        }
        return nil
    }
    
    // MARK: - View updates
    
    private func updateControl(animated:Bool = false) {
        
