//
//  AfficheurPreferences.m
//  Afficheur
//
//  Created by kichi on 08/04/05.
//  Copyright 2008 Katsuhiko Ichinose. All rights reserved.
//

#import "AfficheurPreferences.h"
#import "AfficheurController.h"
#import "AfficheurTimeline.h"
#import "AfficheurGrowl.h"
#import "HotKeyedApplication.h"
#import "Service.h"
#import "ServiceJaiku.h"
#import "ServiceTwitter.h"
#import "ServiceTumblr.h"
#import "ServiceFriendFeed.h"
#import "ServiceFaceBook.h"
#import "KeyEquivView.h"
#import "KeyEquivField.h"
#import "DraggedArrayController.h"
#import "TextFieldCell.h"
#import "i18n.h"
#import "OAuth.h"
#import "NSStringOgreKit.h"
#import <OgreKit/OgreKit.h>

#import <WebKit/WebKit.h>

@implementation AfficheurPreferences

// NIB file
static NSString* NibFile			= @"Preferences";

// UserDefault Keys
static NSString*	PostTwitter				= @"Post.Twitter";
static NSString*	PostJaiku				= @"Post.Jaiku";
static NSString*	PostTumblr				= @"Post.Tumblr";
static NSString*	PostWassr				= @"Post.Wassr";
//static NSString*	PostNowa				= @"Post.nowa";
static NSString*	PostIdentica			= @"Post.identica";
//static NSString*	PostJisko				= @"Post.Jisko";
//static NSString*	PostChuitter			= @"Post.chuitter";
static NSString*	PostFriendFeed			= @"Post.FriendFeed";
static NSString*	PostFaceBook			= @"Post.FaceBook";

static NSString*	TimelineVisibleToolbar	= @"Timeline.VisibleToolbar";

static NSString*	GeneralDockIcon				= @"General.DockIcon";
static NSString*	GeneralStatusMenuIcon		= @"General.StatusMenuIcon";
static NSString*	GeneralMenuIcon				= @"General.MenuIcon";
static NSString*	GeneralStartAtLogin			= @"General.StartAtLogin";
static NSString*	GeneralUseGrowl				= @"General.UseGrowl";
static NSString*	GeneralEncodeTinyURL		= @"General.EncodeTinyURL";
static NSString*	GeneralGrabURL				= @"General.GrabURL";
static NSString*	GeneralTextURL				= @"General.TextGrabURL";
static NSString*	GeneralGrabURLwithClipboard	= @"General.GrabURLwithClipboard";
static NSString*	GeneralGrabITunes			= @"General.GrabITunes";
static NSString*	GeneralTextITunes			= @"General.TextGrabITunes";
static NSString*	GeneralRetrieveWhenReply	= @"General.RetrieveWhenReply";
static NSString*	GeneralInlineImage			= @"General.InlineImage";
static NSString*	GeneralExtractTinyURL		= @"General.ExtractTinyURL";
static NSString*	GeneralDeleteAfterReply		= @"General.DeleteAfterReply";
static NSString*	GeneralKeepSelectedItem		= @"General.KeepSelectedItem";
static NSString*	GeneralKeepCursorPosition	= @"General.KeepCursorPosition";
static NSString*	GeneralNotKeepTimeline		= @"General.NotKeepTimeline";
static NSString*	GeneralStackTimeline		= @"General.StackTimeline";
static NSString*	GeneralHideAfterPost		= @"General.HideAfterPost";
static NSString*	GeneralConvertEmoji			= @"General.ConvertEmoji";
static NSString*	GeneralGrowlOldOrder		= @"General.GrowlOldOrder";
static NSString*	GeneralClearAfterPost		= @"General.ClearAfterPost";
static NSString*	GeneralUseEmoji				= @"General.UseEmoji";
static NSString*	GeneralIndicateSource		= @"General.IndicateSource";
static NSString*	GeneralGrowlDate			= @"General.GrowlDate";
static NSString*	GeneralLimitOfTimeline		= @"General.LimitOfTimeline";
static NSString*	GeneralHideStartup			= @"General.HideStartup";
static NSString*	GeneralAdjustPanel			= @"General.AdjustPanel";

static NSString*	GeneralHotKey				= @"General.HotKey";
static NSString*	GeneralHotKeyTimeline		= @"General.HotKeyTimeline";
static NSString*	GeneralPostTo				= @"General.PostTo";
static NSString*	GeneralPostToALT			= @"General.PostToALT";
static NSString*	GeneralReplyKeyMask			= @"General.ReplyKeyMask";
static NSString*	GeneralFavoriteKeyMask		= @"General.FavoriteKeyMask";
static NSString*	GeneralPermalinkKeyMask		= @"General.PermalinkKeyMask";
static NSString*	GeneralURLKeyMask			= @"General.URLKeyMask";
static NSString*	GeneralRetweetKeyMask		= @"General.RetweetKeyMask";
static NSString*	GeneralDirectMessageKeyMask	= @"General.DirectMessageKeyMask";

NSString*	InitGeneralTextURL			= @"Now browsing: %title% %url%";
NSString*	InitGeneralTextITunes		= @"Now playing: %title% -- %artist% [%album%]";

static NSString*	AccountTwitterUser					= @"Account.Twitter.User";
static NSString*	AccountTwitterPassOld				= @"Account.Twitter.Pass";
static NSString*	AccountTwitterPass					= @"Account.Twitter.Pass_new";
static NSString*	AccountTwitterUseStream				= @"Account.Twitter.UseStream";
static NSString*	AccountTwitterExecMenu				= @"Account.Twitter.ExecMenu";
static NSString*	AccountTwitterIntervalTimeline		= @"Account.Twitter.IntervalTimeline";
static NSString*	AccountTwitterIntervalReplies		= @"Account.Twitter.IntervalReplies";
static NSString*	AccountTwitterIntervalDM			= @"Account.Twitter.IntervalDM";
static NSString*	AccountTwitterRetrieveMax			= @"Account.Twitter.RetrieveMax";
static NSString*	AccountTwitterRetrieveMania			= @"Account.Twitter.RetrieveMania";
static NSString*	AccountTwitterRetrieveTweets		= @"Account.Twitter.RetrieveTweets";
static NSString*	AccountTwitterRetrieveTweetsMin		= @"Account.Twitter.RetrieveTweetsMin";
static NSString*	AccountTwitterRetrieveTweetsInc		= @"Account.Twitter.RetrieveTweetsInc";
static NSString*	AccountTwitterRetrieveTweetsDec		= @"Account.Twitter.RetrieveTweetsDec";
static NSString*	AccountTwitterRetrieveTweetsUp		= @"Account.Twitter.RetrieveTweetsUp";
static NSString*	AccountTwitterRetrieveTweetsDown	= @"Account.Twitter.RetrieveTweetsDown";
static NSString*	AccountTwitterRetrieveTweetsKeep	= @"Account.Twitter.RetrieveTweetsKeep";
static NSString*	AccountTwitterTweetsMania			= @"Account.Twitter.TweetsMania";
static NSString*	AccountTwitterTweetsManiaMin		= @"Account.Twitter.TweetsManiaMin";
static NSString*	AccountTwitterTweetsManiaInc		= @"Account.Twitter.TweetsManiaInc";
static NSString*	AccountTwitterTweetsManiaDec		= @"Account.Twitter.TweetsManiaDec";
static NSString*	AccountTwitterTweetsManiaUp			= @"Account.Twitter.TweetsManiaUp";
static NSString*	AccountTwitterTweetsManiaDown		= @"Account.Twitter.TweetsManiaDown";
static NSString*	AccountTwitterTweetsManiaKeep		= @"Account.Twitter.TweetsManiaKeep";
static NSString*	AccountTwitterRetrieveXMPP			= @"Account.Twitter.RetrieveXMPP";
static NSString*	AccountTwitterOAuthKeyOld			= @"Account.Twitter.OAuth.access_key";
static NSString*	AccountTwitterOAuthSecretOld		= @"Account.Twitter.OAuth.access_secret";
static NSString*	AccountTwitterOAuthKey				= @"Account.Twitter.OAuth.access_key_new";
static NSString*	AccountTwitterOAuthSecret			= @"Account.Twitter.OAuth.access_secret_new";
static NSString*	AccountJaikuUser					= @"Account.Jaiku.User";
static NSString*	AccountJaikuExecMenu				= @"Account.Jaiku.ExecMenu";
static NSString*	AccountJaikuLocation				= @"Account.Jaiku.Location";
static NSString*	AccountJaikuIntervalTimeline		= @"Account.Jaiku.IntervalTimeline";
static NSString*	AccountJaikuUseXMPP					= @"Account.Jaiku.XMPP.Use";
static NSString*	AccountJaikuJidXMPP					= @"Account.Jaiku.XMPP.Jid";
static NSString*	AccountJaikuPassXMPP				= @"Account.Jaiku.XMPP.Pass";
static NSString*	AccountJaikuServerXMPP				= @"Account.Jaiku.XMPP.Server";
static NSString*	AccountJaikuPortXMPP				= @"Account.Jaiku.XMPP.Port";
static NSString*	AccountJaikuRetrieveXMPP			= @"Account.Jaiku.XMPP.Retrieve";
static NSString*	AccountJaikuOfflineXMPP				= @"Account.Jaiku.XMPP.Offline";
static NSString*	AccountJaikuPostXMPP				= @"Account.Jaiku.XMPP.PostBy";
static NSString*	AccountJaikuOAuthKeyOld				= @"Account.Jaiku.OAuth.access_key";
static NSString*	AccountJaikuOAuthSecretOld			= @"Account.Jaiku.OAuth.access_secret";
static NSString*	AccountJaikuOAuthKey				= @"Account.Jaiku.OAuth.access_key_new";
static NSString*	AccountJaikuOAuthSecret				= @"Account.Jaiku.OAuth.access_secret_new";
static NSString*	AccountTumblrUser					= @"Account.Tumblr.User";
static NSString*	AccountTumblrPass					= @"Account.Tumblr.Pass";
static NSString*	AccountTumblrExecMenu				= @"Account.Tumblr.ExecMenu";
static NSString*	AccountTumblrIntervalTimeline		= @"Account.Tumblr.IntervalTimeline";
static NSString*	AccountTumblrOAuthKey				= @"Account.Tumblr.OAuth.access_key";
static NSString*	AccountTumblrOAuthSecret			= @"Account.Tumblr.OAuth.access_secret";
static NSString*	AccountWassrUser					= @"Account.Wassr.User";
static NSString*	AccountWassrPass					= @"Account.Wassr.Pass";
static NSString*	AccountWassrExecMenu				= @"Account.Wassr.ExecMenu";
static NSString*	AccountWassrIntervalTimeline		= @"Account.Wassr.IntervalTimeline";
static NSString*	AccountWassrIntervalReplies			= @"Account.Wassr.IntervalReplies";
static NSString*	AccountWassrIntervalChannel			= @"Account.Wassr.IntervalChannel";
static NSString*	AccountWassrUseXMPP					= @"Account.Wassr.XMPP.Use";
static NSString*	AccountWassrJidXMPP					= @"Account.Wassr.XMPP.Jid";
static NSString*	AccountWassrPassXMPP				= @"Account.Wassr.XMPP.Pass";
static NSString*	AccountWassrServerXMPP				= @"Account.Wassr.XMPP.Server";
static NSString*	AccountWassrPortXMPP				= @"Account.Wassr.XMPP.Port";
static NSString*	AccountWassrRetrieveXMPP			= @"Account.Wassr.XMPP.Retrieve";
static NSString*	AccountWassrOfflineXMPP				= @"Account.Wassr.XMPP.Offline";
static NSString*	AccountWassrPostXMPP				= @"Account.Wassr.XMPP.PostBy";
//static NSString*	AccountNowaUser						= @"Account.nowa.User";
//static NSString*	AccountNowaPass						= @"Account.nowa.Pass";
//static NSString*	AccountNowaExecMenu					= @"Account.nowa.ExecMenu";
//static NSString*	AccountNowaIntervalTimeline			= @"Account.nowa.IntervalTimeline";
static NSString*	AccountIdenticaUser					= @"Account.identica.User";
static NSString*	AccountIdenticaPass					= @"Account.identica.Pass";
static NSString*	AccountIdenticaExecMenu				= @"Account.identica.ExecMenu";
static NSString*	AccountIdenticaIntervalTimeline		= @"Account.identica.IntervalTimeline";
static NSString*	AccountIdenticaIntervalReplies		= @"Account.identica.IntervalReplies";
static NSString*	AccountIdenticaIntervalDM			= @"Account.identica.IntervalDM";
static NSString*	AccountIdenticaUseXMPP				= @"Account.identica.XMPP.Use";
static NSString*	AccountIdenticaJidXMPP				= @"Account.identica.XMPP.Jid";
static NSString*	AccountIdenticaPassXMPP				= @"Account.identica.XMPP.Pass";
static NSString*	AccountIdenticaServerXMPP			= @"Account.identica.XMPP.Server";
static NSString*	AccountIdenticaPortXMPP				= @"Account.identica.XMPP.Port";
static NSString*	AccountIdenticaRetrieveXMPP			= @"Account.identica.XMPP.Retrieve";
static NSString*	AccountIdenticaOfflineXMPP			= @"Account.identica.XMPP.Offline";
static NSString*	AccountIdenticaPostXMPP				= @"Account.identica.XMPP.PostBy";
//static NSString*	AccountJiskoUser					= @"Account.Jisko.User";
//static NSString*	AccountJiskoPass					= @"Account.Jisko.Pass";
//static NSString*	AccountJiskoExecMenu				= @"Account.Jisko.ExecMenu";
//static NSString*	AccountJiskoIntervalTimeline		= @"Account.Jisko.IntervalTimeline";
//static NSString*	AccountJiskoIntervalReplies			= @"Account.Jisko.IntervalReplies";
//static NSString*	AccountJiskoIntervalDM				= @"Account.Jisko.IntervalDM";
//static NSString*	AccountJiskoUseXMPP					= @"Account.Jisko.XMPP.Use";
//static NSString*	AccountJiskoJidXMPP					= @"Account.Jisko.XMPP.Jid";
//static NSString*	AccountJiskoPassXMPP				= @"Account.Jisko.XMPP.Pass";
//static NSString*	AccountJiskoServerXMPP				= @"Account.Jisko.XMPP.Server";
//static NSString*	AccountJiskoPortXMPP				= @"Account.Jisko.XMPP.Port";
//static NSString*	AccountJiskoRetrieveXMPP			= @"Account.Jisko.XMPP.Retrieve";
//static NSString*	AccountJiskoOfflineXMPP				= @"Account.Jisko.XMPP.Offline";
//static NSString*	AccountJiskoPostXMPP				= @"Account.Jisko.XMPP.PostBy";
//static NSString*	AccountChuitterUser					= @"Account.chuitter.User";
//static NSString*	AccountChuitterPass					= @"Account.chuitter.Pass";
//static NSString*	AccountChuitterExecMenu				= @"Account.chuitter.ExecMenu";
//static NSString*	AccountChuitterIntervalTimeline		= @"Account.chuitter.IntervalTimeline";
//static NSString*	AccountChuitterIntervalReplies		= @"Account.chuitter.IntervalReplies";
//static NSString*	AccountChuitterIntervalDM			= @"Account.chuitter.IntervalDM";
//static NSString*	AccountChuitterUseXMPP				= @"Account.chuitter.XMPP.Use";
//static NSString*	AccountChuitterJidXMPP				= @"Account.chuitter.XMPP.Jid";
//static NSString*	AccountChuitterPassXMPP				= @"Account.chuitter.XMPP.Pass";
//static NSString*	AccountChuitterServerXMPP			= @"Account.chuitter.XMPP.Server";
//static NSString*	AccountChuitterPortXMPP				= @"Account.chuitter.XMPP.Port";
//static NSString*	AccountChuitterRetrieveXMPP			= @"Account.chuitter.XMPP.Retrieve";
//static NSString*	AccountChuitterOfflineXMPP			= @"Account.chuitter.XMPP.Offline";
//static NSString*	AccountChuitterPostXMPP				= @"Account.chuitter.XMPP.PostBy";
static NSString*	AccountFriendFeedUser				= @"Account.FriendFeed.User";
static NSString*	AccountFriendFeedPass				= @"Account.FriendFeed.Pass";
static NSString*	AccountFriendFeedExecMenu			= @"Account.FriendFeed.ExecMenu";
static NSString*	AccountFriendFeedLocation			= @"Account.FriendFeed.Location";
static NSString*	AccountFriendFeedIntervalTimeline	= @"Account.FriendFeed.IntervalTimeline";
static NSString*	AccountFriendFeedUseXMPP			= @"Account.FriendFeed.XMPP.Use";
static NSString*	AccountFriendFeedJidXMPP			= @"Account.FriendFeed.XMPP.Jid";
static NSString*	AccountFriendFeedPassXMPP			= @"Account.FriendFeed.XMPP.Pass";
static NSString*	AccountFriendFeedServerXMPP			= @"Account.FriendFeed.XMPP.Server";
static NSString*	AccountFriendFeedPortXMPP			= @"Account.FriendFeed.XMPP.Port";
static NSString*	AccountFriendFeedRetrieveXMPP		= @"Account.FriendFeed.XMPP.Retrieve";
static NSString*	AccountFriendFeedOfflineXMPP		= @"Account.FriendFeed.XMPP.Offline";
static NSString*	AccountFriendFeedPostXMPP			= @"Account.FriendFeed.XMPP.PostBy";
static NSString*	AccountFriendFeedOAuthKeyOld		= @"Account.FriendFeed.OAuth.access_key";
static NSString*	AccountFriendFeedOAuthSecretOld		= @"Account.FriendFeed.OAuth.access_secret";
static NSString*	AccountFriendFeedOAuthKey			= @"Account.FriendFeed.OAuth.access_key_new";
static NSString*	AccountFriendFeedOAuthSecret		= @"Account.FriendFeed.OAuth.access_secret_new";
static NSString*	AccountFaceBookId					= @"Account.FaceBook.Id";
static NSString*	AccountFaceBookUser					= @"Account.FaceBook.User";
static NSString*	AccountFaceBookExecMenu				= @"Account.FaceBook.ExecMenu";
static NSString*	AccountFaceBookLocation				= @"Account.FaceBook.Location";
static NSString*	AccountFaceBookIntervalTimeline		= @"Account.FaceBook.IntervalTimeline";
static NSString*	AccountFaceBookUseXMPP				= @"Account.FaceBook.XMPP.Use";
static NSString*	AccountFaceBookJidXMPP				= @"Account.FaceBook.XMPP.Jid";
static NSString*	AccountFaceBookPassXMPP				= @"Account.FaceBook.XMPP.Pass";
static NSString*	AccountFaceBookServerXMPP			= @"Account.FaceBook.XMPP.Server";
static NSString*	AccountFaceBookPortXMPP				= @"Account.FaceBook.XMPP.Port";
static NSString*	AccountFaceBookRetrieveXMPP			= @"Account.FaceBook.XMPP.Retrieve";
static NSString*	AccountFaceBookOfflineXMPP			= @"Account.FaceBook.XMPP.Offline";
static NSString*	AccountFaceBookPostXMPP				= @"Account.FaceBook.XMPP.PostBy";
static NSString*	AccountFaceBookOAuthToken			= @"Account.FaceBook.OAuth.access_token";
static NSString*	AccountBitLyUser					= @"Account.bitly.User";
static NSString*	AccountBitLyAPIKey					= @"Account.bitly.APIKey";
static NSString*	AccountBitLyService					= @"Account.bitly.Service";

static NSString*	AppearanceFontUser					= @"Appearance.Font.User";
static NSString*	AppearanceFontText					= @"Appearance.Font.Text";
static NSString*	AppearanceFontComment				= @"Appearance.Font.Comment";
static NSString*	AppearanceFontDate					= @"Appearance.Font.Date";
static NSString*	AppearanceNormalColorUser			= @"Appearance.Normal.Color.User";
static NSString*	AppearanceNormalColorText			= @"Appearance.Normal.Color.Text";
static NSString*	AppearanceNormalColorComment		= @"Appearance.Normal.Color.Comment";
static NSString*	AppearanceNormalColorDate			= @"Appearance.Normal.Color.Date";
static NSString*	AppearanceNormalColorBackgraound	= @"Appearance.Normal.Color.Background";
static NSString*	AppearanceReplyColorUser			= @"Appearance.Reply.Color.User";
static NSString*	AppearanceReplyColorText			= @"Appearance.Reply.Color.Text";
static NSString*	AppearanceReplyColorComment			= @"Appearance.Reply.Color.Comment";
static NSString*	AppearanceReplyColorDate			= @"Appearance.Reply.Color.Date";
static NSString*	AppearanceReplyColorBackgraound		= @"Appearance.Reply.Color.Background";
static NSString*	AppearanceChannelColorUser			= @"Appearance.Channel.Color.User";
static NSString*	AppearanceChannelColorText			= @"Appearance.Channel.Color.Text";
static NSString*	AppearanceChannelColorComment		= @"Appearance.Channel.Color.Comment";
static NSString*	AppearanceChannelColorDate			= @"Appearance.Channel.Color.Date";
static NSString*	AppearanceChannelColorBackgraound	= @"Appearance.Channel.Color.Background";
static NSString*	AppearanceMessageColorUser			= @"Appearance.Message.Color.User";
static NSString*	AppearanceMessageColorText			= @"Appearance.Message.Color.Text";
static NSString*	AppearanceMessageColorComment		= @"Appearance.Message.Color.Comment";
static NSString*	AppearanceMessageColorDate			= @"Appearance.Message.Color.Date";
static NSString*	AppearanceMessageColorBackgraound	= @"Appearance.Message.Color.Background";
static NSString*	AppearanceKeywordColorUser			= @"Appearance.Keyword.Color.User";
static NSString*	AppearanceKeywordColorText			= @"Appearance.Keyword.Color.Text";
static NSString*	AppearanceKeywordColorComment		= @"Appearance.Keyword.Color.Comment";
static NSString*	AppearanceKeywordColorDate			= @"Appearance.Keyword.Color.Date";
static NSString*	AppearanceKeywordColorBackgraound	= @"Appearance.Keyword.Color.Background";

static NSString*	Keywords							= @"Keywords";
static NSString*	IgnoreKeywords						= @"Keywords.Ignore";
static NSString*	ArrayKeywords						= @"Keywords.Array";
static NSString*	Keyword								= @"keyword";
static NSString*	KeywordEnable						= @"enable";
static NSString*	Rule								= @"rule";
static NSString*	RuleArray							= @"rule.array";
static NSString*	NoGrowl								= @"no_growl";
static NSString*	NoTimeline							= @"no_timeline";
static NSString*	Complete							= @"Complete";
static NSString*	CompleteIgnore						= @"Complete.Ignore";

static NSString*	Suggestion							= @"suggestion";
static NSString*	Ignore								= @"suggestion";

static NSString*	ToolTipGeneralStartAtLogin			= @"ToolTip.General.StartAtLogin";

NSString*	AppearanceFont						= @"font";
NSString*	AppearanceColor						= @"color";
NSString*	AppearanceNormal					= @"normal";
NSString*	AppearanceReply						= @"reply";
NSString*	AppearanceChannel					= @"channel";
NSString*	AppearanceMessage					= @"message";
NSString*	AppearanceKeyword					= @"keyword";
NSString*	AppearanceUser						= @"name";
NSString*	AppearanceText						= @"text";
NSString*	AppearanceComment					= @"comment";
NSString*	AppearanceDate						= @"date";
NSString*	AppearanceBackground				= @"background";

NSString*	FrameMain							= @"NSWindow Frame Main";
NSString*	FrameTimeline						= @"NSWindow Frame Timeline";

// ToolBar Identifiers
static NSString*	IdToolBar = @"PrefsToolBar";
static NSString*	IdGeneral = @"PrefsGeneral";
static NSString*	IdHotKeys = @"PrefsHotKeys";
static NSString*	IdAccount = @"PrefsAccount";
static NSString*	IdKeyword = @"PrefsKeyword";
static NSString*	IdSuggestion = @"PrefsSuggestion";
static NSString*	IdAppearance = @"PrefsAppearance";

// DIALOG
enum {
	DIALOG_OK = 0,
	DIALOG_CANCEL
};

// 
static NSString*	KeySelector		= @"selector";
static NSString*	KeyTarget		= @"target";

// UtilityWindowMask for TimelineWindow
BOOL HUDTimelineWindow = NO;

- (void)loadNib
{
	[NSBundle loadNibNamed:NibFile owner:self];
}

- (NSArray *)arrayFromGrabText:(NSString *)text
{
	NSMutableArray *array = [NSMutableArray arrayWithArray:
							 [text componentsSeparatedByString:@" "]];
	int i = 0;
	while (i < [array count])
	{
		NSString *obj = [array objectAtIndex:i];
		if ([obj rangeOfString:@"%"].length == 0)
		{
			if ((i + 1) < [array count])
			{
				NSString *obj1 = [array objectAtIndex:i + 1];
				if ([obj1 rangeOfString:@"%"].length == 0)
				{
					[array replaceObjectAtIndex:i
									 withObject:[obj stringByAppendingFormat:
												 @" %@", obj1]];
					[array removeObjectAtIndex:i + 1];
					continue;
				}
			}
		}
		else if ([obj rangeOfString:@"%%"].length)
		{
			[array removeObjectAtIndex:i];
			NSEnumerator *e = [[obj componentsSeparatedByString:@"%"] objectEnumerator];
			int j = 0;
			id o;
			while ((o = [e nextObject]))
			{
				if (![o isEqualToString:@""])
				{
					[array insertObject:[NSString stringWithFormat:@"%%%@%%", o] atIndex:i+j];
					j++;
				}
			}
			continue;
		}
		i++;
	}
	return array;
}

- (void)convertPopupValue:(NSString *)key
				withTable:(NSDictionary *)table
{
	id value = [[NSUserDefaults standardUserDefaults] valueForKey:key];
	if ([value isKindOfClass:[NSString class]])
	{
		value = [table valueForKey:value];
		if (!value)
		{
			value = [NSNumber numberWithInt:0];
		}
		[[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
	}
}

- (id)init
{
	//LOG(@"[%@ init]", [self className]);
	//LOG(@"[%@ init] Font\n'%@'", [self className], [[NSFont systemFontOfSize:[NSFont smallSystemFontSize]] displayName]);
	self = [super init];
	if (self)
	{
		_timeline = nil;
		_controller = nil;
		_arrayBrowser = [[NSArray alloc] initWithObjects:@"%title%", @"%url%", nil];
		_arrayITunes = [[NSArray alloc] initWithObjects:@"%title%", @"%artist%", @"%album%",
						@"%playlist%", @"%count%", @"%rating%", nil];
		_target = nil;
		_accounts = nil;
		_appearances = nil;
		_localAppearances = nil;
		_appearanceButtons = nil;
		_currentAppearance = nil;
		_appearanceColorButtons = nil;
		_openColorPanel = NO;
		_openFirst = YES;
		_currentItem = @"";
		_panelToolBar = nil;
		_enabledURL = nil;
		_keyEquivViewPost = [[KeyEquivView alloc] init];
		_keyEquivViewTimeline = [[KeyEquivView alloc] init];
		_intervalTable = [[NSDictionary alloc] initWithObjectsAndKeys:
						  [NSNumber numberWithInt:0], @"Never",
						  [NSNumber numberWithInt:1], @"60 seconds",
						  [NSNumber numberWithInt:2], @"90 seconds",
						  [NSNumber numberWithInt:3], @"2 minutes",
						  [NSNumber numberWithInt:4], @"3 minutes",
						  [NSNumber numberWithInt:5], @"5 minutes",
						  [NSNumber numberWithInt:6], @"10 minutes",
						  [NSNumber numberWithInt:7], @"15 minutes",
						  [NSNumber numberWithInt:8], @"30 minutes",
						  [NSNumber numberWithInt:9], @"60 minutes",
						  nil];
		_intervalIndexes = [[NSDictionary alloc] initWithObjectsAndKeys:
						  [NSNumber numberWithInt:0], NEVER_INTERVAL,
						  [NSNumber numberWithInt:1], SEC60,
						  [NSNumber numberWithInt:2], SEC90,
						  [NSNumber numberWithInt:3], MIN2,
						  [NSNumber numberWithInt:4], MIN3,
						  [NSNumber numberWithInt:5], MIN5,
						  [NSNumber numberWithInt:6], MIN10,
						  [NSNumber numberWithInt:7], MIN15,
						  [NSNumber numberWithInt:8], MIN30,
						  [NSNumber numberWithInt:9], MIN60,
						  nil];
		_intervals = [[NSArray alloc] initWithObjects:
					  [NSNumber numberWithInt:0],
					  [NSNumber numberWithInt:60],
					  [NSNumber numberWithInt:90],
					  [NSNumber numberWithInt:120],
					  [NSNumber numberWithInt:180],
					  [NSNumber numberWithInt:300],
					  [NSNumber numberWithInt:600],
					  [NSNumber numberWithInt:900],
					  [NSNumber numberWithInt:1800],
					  [NSNumber numberWithInt:3600],
					  nil];
		_retrieveTable = [[NSDictionary alloc] initWithObjectsAndKeys:
						  [NSNumber numberWithInt:0], @"Never",
						  [NSNumber numberWithInt:1], @"5 statuses",
						  [NSNumber numberWithInt:2], @"10 statuses",
						  [NSNumber numberWithInt:3], @"15 statuses",
						  [NSNumber numberWithInt:4], @"16 statuses",
						  [NSNumber numberWithInt:5], @"17 statuses",
						  [NSNumber numberWithInt:6], @"18 statuses",
						  [NSNumber numberWithInt:7], @"19 statuses",
						  [NSNumber numberWithInt:8], @"20 statuses",
						  nil];
		_retrieves = [[NSArray alloc] initWithObjects:
					  [NSNumber numberWithInt:0],
					  [NSNumber numberWithInt:5],
					  [NSNumber numberWithInt:10],
					  [NSNumber numberWithInt:15],
					  [NSNumber numberWithInt:16],
					  [NSNumber numberWithInt:17],
					  [NSNumber numberWithInt:18],
					  [NSNumber numberWithInt:19],
					  [NSNumber numberWithInt:20],
					  nil];
		_timelineLimits = [[NSArray alloc] initWithObjects:
						   [NSNumber numberWithInt:0],
						   [NSNumber numberWithInt:500],
						   [NSNumber numberWithInt:1000],
						   [NSNumber numberWithInt:2000],
						   [NSNumber numberWithInt:3000],
						   [NSNumber numberWithInt:5000],
						   nil];
		//^⎇⇧⌘
		_keyMask = [[NSDictionary alloc] initWithObjectsAndKeys:
					[NSNumber numberWithInt:
					 NSCommandKeyMask],
					@"⌘Click",
					[NSNumber numberWithInt:
					 NSShiftKeyMask],
					@"⇧Click",
					[NSNumber numberWithInt:
					 NSShiftKeyMask|NSCommandKeyMask],
					@"⇧⌘Click",
					[NSNumber numberWithInt:
					 NSAlternateKeyMask],
					@"⎇Click",
					[NSNumber numberWithInt:
					 NSAlternateKeyMask|NSCommandKeyMask],
					@"⎇⌘Click",
					[NSNumber numberWithInt:
					 NSAlternateKeyMask|NSShiftKeyMask],
					@"⎇⇧Click",
					[NSNumber numberWithInt:
					 NSAlternateKeyMask|NSShiftKeyMask|NSCommandKeyMask],
					@"⎇⇧⌘Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask],
					@"^Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSCommandKeyMask],
					@"^⌘Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSShiftKeyMask],
					@"^⇧Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSShiftKeyMask|NSCommandKeyMask],
					@"^⇧⌘Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSAlternateKeyMask],
					@"^⎇Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask],
					@"^⎇⌘Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSAlternateKeyMask|NSShiftKeyMask],
					@"^⎇⇧Click",
					[NSNumber numberWithInt:
					 NSControlKeyMask|NSAlternateKeyMask|NSShiftKeyMask|NSCommandKeyMask],
					@"^⎇⇧⌘Click",
					[NSNumber numberWithInt:
					 0],
					@"None",
					nil];
		// Rate limit
		_rateLimit = 0x7fffffff;
		// NSUserDefaults
		NSData *defaultFont = [NSArchiver archivedDataWithRootObject:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
		NSData *defaultColor = [NSArchiver archivedDataWithRootObject:[NSColor textColor]];
		NSData *defaultBackground = [NSArchiver archivedDataWithRootObject:[NSColor textBackgroundColor]];
		NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
								  @"Mac起動時にAfficheurを起動します。",		ToolTipGeneralStartAtLogin,
								  [NSNumber numberWithBool:NO],		TimelineVisibleToolbar,
								  [NSNumber numberWithBool:NO],		GeneralDockIcon,
								  [NSNumber numberWithBool:YES],	GeneralStatusMenuIcon,
								  [NSNumber numberWithInt:0],		GeneralMenuIcon,
								  [NSNumber numberWithBool:NO],		GeneralStartAtLogin,
								  [NSNumber numberWithBool:YES],	GeneralEncodeTinyURL,
								  [NSNumber numberWithBool:YES],	GeneralUseGrowl,
								  [NSNumber numberWithBool:YES],	GeneralGrabURL,
								  [NSNumber numberWithBool:NO],		GeneralGrabURLwithClipboard,
								  [NSArray arrayWithObjects:
								   @"Now browsing:",
								   @"%title%",
								   @"%url%",
								   nil],							GeneralTextURL,
								  [NSNumber numberWithBool:YES],	GeneralGrabITunes,
								  [NSArray arrayWithObjects:
								   @"Now playing:",
								   @"%title%",
								   @"--",
								   @"%artist%",
								   @"[%album%]",
								   nil],							GeneralTextITunes,
								  [NSNumber numberWithBool:NO],		GeneralRetrieveWhenReply,
								  [NSNumber numberWithBool:NO],		GeneralInlineImage,
								  [NSNumber numberWithBool:NO],		GeneralExtractTinyURL,
								  [NSNumber numberWithBool:NO],		GeneralDeleteAfterReply,
								  [NSNumber numberWithBool:NO],		GeneralKeepSelectedItem,
								  [NSNumber numberWithBool:NO],		GeneralKeepCursorPosition,
								  [NSNumber numberWithBool:NO],		GeneralNotKeepTimeline,
								  [NSNumber numberWithBool:NO],		GeneralStackTimeline,
								  [NSNumber numberWithBool:NO],		GeneralHideAfterPost,
								  [NSNumber numberWithBool:NO],		GeneralGrowlOldOrder,
								  [NSNumber numberWithBool:YES],	GeneralUseEmoji,
								  [NSNumber numberWithBool:NO],		GeneralIndicateSource,
								  [NSNumber numberWithBool:NO],		GeneralGrowlDate,
								  [NSNumber numberWithInt:-1],		GeneralHotKey,
								  [NSNumber numberWithInt:-1],		GeneralHotKeyTimeline,
								  [NSNumber numberWithInt:0],		GeneralPostTo,
								  [NSNumber numberWithInt:0],		GeneralPostToALT,
								  @"⇧Click",						GeneralReplyKeyMask,
								  @"⎇⇧Click",						GeneralFavoriteKeyMask,
								  @"⎇Click",						GeneralPermalinkKeyMask,
								  @"^Click",						GeneralURLKeyMask,
								  @"None",							GeneralRetweetKeyMask,
								  @"None",							GeneralDirectMessageKeyMask,
								  [NSNumber numberWithBool:YES],	GeneralKeepSelectedItem,
								  [NSNumber numberWithBool:NO],		GeneralHideAfterPost,
								  [NSNumber numberWithBool:NO],		GeneralConvertEmoji,
								  [NSNumber numberWithInt:0],		GeneralLimitOfTimeline,
								  [NSNumber numberWithBool:NO],		GeneralHideStartup,
								  [NSNumber numberWithBool:YES],	GeneralAdjustPanel,
								  [NSNumber numberWithBool:NO],		AccountTwitterUseStream,
								  [NSNumber numberWithInt:0],		AccountTwitterIntervalTimeline,
								  [NSNumber numberWithInt:0],		AccountTwitterIntervalReplies,
								  [NSNumber numberWithInt:0],		AccountTwitterIntervalDM,
								  [NSNumber numberWithInt:200],		AccountTwitterRetrieveMax,
								  [NSNumber numberWithInt:60],		AccountTwitterRetrieveMania,
								  [NSNumber numberWithInt:20],		AccountTwitterRetrieveTweets,
								  [NSNumber numberWithInt:20],		AccountTwitterRetrieveTweetsMin,
								  [NSNumber numberWithInt:10],		AccountTwitterRetrieveTweetsInc,
								  [NSNumber numberWithInt:5],		AccountTwitterRetrieveTweetsDec,
								  [NSNumber numberWithInt:5],		AccountTwitterRetrieveTweetsUp,
								  [NSNumber numberWithInt:10],		AccountTwitterRetrieveTweetsDown,
								  [NSNumber numberWithInt:2],		AccountTwitterRetrieveTweetsKeep,
								  [NSNumber numberWithInt:50],		AccountTwitterTweetsMania,
								  [NSNumber numberWithInt:20],		AccountTwitterTweetsManiaMin,
								  [NSNumber numberWithInt:20],		AccountTwitterTweetsManiaInc,
								  [NSNumber numberWithInt:5],		AccountTwitterTweetsManiaDec,
								  [NSNumber numberWithInt:10],		AccountTwitterTweetsManiaUp,
								  [NSNumber numberWithInt:20],		AccountTwitterTweetsManiaDown,
								  [NSNumber numberWithInt:3],		AccountTwitterTweetsManiaKeep,
								  [NSNumber numberWithInt:0],		AccountTwitterRetrieveXMPP,
								  [NSNumber numberWithInt:0],		AccountJaikuIntervalTimeline,
								  [NSNumber numberWithBool:NO],		AccountJaikuUseXMPP,
								  [NSNumber numberWithInt:0],		AccountJaikuRetrieveXMPP,
								  [NSNumber numberWithBool:NO],		AccountJaikuOfflineXMPP,
								  [NSNumber numberWithBool:NO],		AccountJaikuPostXMPP,
								  [NSNumber numberWithInt:0],		AccountTumblrIntervalTimeline,
//								  @"Never",							AccountNowaIntervalTimeline,
								  [NSNumber numberWithInt:0],		AccountWassrIntervalTimeline,
								  [NSNumber numberWithInt:0],		AccountWassrIntervalReplies,
								  [NSNumber numberWithInt:0],		AccountWassrIntervalChannel,
								  [NSNumber numberWithBool:NO],		AccountWassrUseXMPP,
								  [NSNumber numberWithInt:0],		AccountWassrRetrieveXMPP,
								  [NSNumber numberWithBool:NO],		AccountWassrOfflineXMPP,
								  [NSNumber numberWithBool:NO],		AccountJaikuPostXMPP,
								  [NSNumber numberWithInt:0],		AccountIdenticaIntervalTimeline,
								  [NSNumber numberWithInt:0],		AccountIdenticaIntervalReplies,
								  [NSNumber numberWithInt:0],		AccountIdenticaIntervalDM,
								  [NSNumber numberWithBool:NO],		AccountIdenticaUseXMPP,
								  [NSNumber numberWithInt:0],		AccountIdenticaRetrieveXMPP,
								  [NSNumber numberWithBool:NO],		AccountIdenticaOfflineXMPP,
								  [NSNumber numberWithBool:NO],		AccountIdenticaPostXMPP,
//								  [NSNumber numberWithInt:0],		AccountJiskoIntervalTimeline,
//								  [NSNumber numberWithInt:0],		AccountJiskoIntervalReplies,
//								  [NSNumber numberWithInt:0],		AccountJiskoIntervalDM,
//								  [NSNumber numberWithBool:NO],		AccountJiskoUseXMPP,
//								  [NSNumber numberWithInt:0],		AccountJiskoRetrieveXMPP,
//								  [NSNumber numberWithBool:NO],		AccountJiskoOfflineXMPP,
//								  [NSNumber numberWithInt:0],		AccountChuitterIntervalTimeline,
//								  [NSNumber numberWithInt:0],		AccountChuitterIntervalReplies,
//								  [NSNumber numberWithInt:0],		AccountChuitterIntervalDM,
//								  [NSNumber numberWithBool:NO],		AccountChuitterUseXMPP,
//								  [NSNumber numberWithInt:0],		AccountChuitterRetrieveXMPP,
//								  [NSNumber numberWithBool:NO],		AccountChuitterOfflineXMPP,
//								  [NSNumber numberWithBool:NO],		AccountChuitterPostXMPP,
								  [NSNumber numberWithInt:0],		AccountFriendFeedIntervalTimeline,
//								  [NSNumber numberWithBool:NO],		AccountFriendFeedUseXMPP,
//								  [NSNumber numberWithInt:0],		AccountFriendFeedRetrieveXMPP,
//								  [NSNumber numberWithBool:NO],		AccountFriendFeedOfflineXMPP,
//								  [NSNumber numberWithBool:NO],		AccountFriendFeedPostXMPP,
								  [NSNumber numberWithInt:0],		AccountFaceBookIntervalTimeline,
								  [NSNumber numberWithBool:NO],		AccountFaceBookUseXMPP,
								  [NSNumber numberWithInt:0],		AccountFaceBookRetrieveXMPP,
//								  [NSNumber numberWithBool:NO],		AccountFaceBookOfflineXMPP,
								  [NSNumber numberWithBool:NO],		AccountFaceBookPostXMPP,
								  [NSNumber numberWithInt:0],		AccountBitLyService,
								  defaultFont,						AppearanceFontUser,
								  defaultFont,						AppearanceFontText,
								  defaultFont,						AppearanceFontComment,
								  defaultFont,						AppearanceFontDate,
								  defaultColor,						AppearanceNormalColorUser,
								  defaultColor,						AppearanceNormalColorText,
								  defaultColor,						AppearanceNormalColorComment,
								  defaultColor,						AppearanceNormalColorDate,
								  defaultBackground,				AppearanceNormalColorBackgraound,
								  defaultColor,						AppearanceReplyColorUser,
								  defaultColor,						AppearanceReplyColorText,
								  defaultColor,						AppearanceReplyColorComment,
								  defaultColor,						AppearanceReplyColorDate,
								  defaultBackground,				AppearanceReplyColorBackgraound,
								  defaultColor,						AppearanceChannelColorUser,
								  defaultColor,						AppearanceChannelColorText,
								  defaultColor,						AppearanceChannelColorComment,
								  defaultColor,						AppearanceChannelColorDate,
								  defaultBackground,				AppearanceChannelColorBackgraound,
								  defaultColor,						AppearanceMessageColorUser,
								  defaultColor,						AppearanceMessageColorText,
								  defaultColor,						AppearanceMessageColorComment,
								  defaultColor,						AppearanceMessageColorDate,
								  defaultBackground,				AppearanceMessageColorBackgraound,
								  defaultColor,						AppearanceKeywordColorUser,
								  defaultColor,						AppearanceKeywordColorText,
								  defaultColor,						AppearanceKeywordColorComment,
								  defaultColor,						AppearanceKeywordColorDate,
								  defaultBackground,				AppearanceKeywordColorBackgraound,
								  nil];
		[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
		id  url = [[NSUserDefaults standardUserDefaults] valueForKey:GeneralTextURL];
		if ([url isKindOfClass:[NSString class]])
		{
			NSArray *array = [self arrayFromGrabText:url];
			[[NSUserDefaults standardUserDefaults] setValue:array forKey:GeneralTextURL];
		}
		id  iTunes = [[NSUserDefaults standardUserDefaults] valueForKey:GeneralTextITunes];
		if ([iTunes isKindOfClass:[NSString class]])
		{
			NSArray *array = [self arrayFromGrabText:iTunes];
			[[NSUserDefaults standardUserDefaults] setValue:array forKey:GeneralTextITunes];
		}
		id clearAfterPost = [[NSUserDefaults standardUserDefaults] objectForKey:GeneralClearAfterPost];
		//LOG(@"[%@ init]\n%@ = %@", [self className], GeneralClearAfterPost, clearAfterPost);
		if (!clearAfterPost)
		{
			int clear = ClearAfterPostNever;
			if ([self generalDeleteAfterReply])
			{
				clear = ClearAfterPostReply;
			}
			//LOG(@"[%@ init]\n%@ = %d", [self className], GeneralClearAfterPost, clear);
			[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:clear]
													 forKey:GeneralClearAfterPost];
		}
		[self convertPopupValue:AccountTwitterIntervalTimeline withTable:_intervalTable];
		[self convertPopupValue:AccountTwitterIntervalReplies withTable:_intervalTable];
		[self convertPopupValue:AccountTwitterIntervalDM withTable:_intervalTable];
		[self convertPopupValue:AccountTwitterRetrieveXMPP withTable:_retrieveTable];
		[self convertPopupValue:AccountJaikuIntervalTimeline withTable:_intervalTable];
		[self convertPopupValue:AccountJaikuRetrieveXMPP withTable:_retrieveTable];
		[self convertPopupValue:AccountWassrIntervalTimeline withTable:_intervalTable];
		[self convertPopupValue:AccountWassrIntervalReplies withTable:_intervalTable];
		[self convertPopupValue:AccountWassrIntervalChannel withTable:_intervalTable];
		[self convertPopupValue:AccountWassrRetrieveXMPP withTable:_retrieveTable];
		[self convertPopupValue:AccountIdenticaIntervalTimeline withTable:_intervalTable];
		[self convertPopupValue:AccountIdenticaIntervalReplies withTable:_intervalTable];
		[self convertPopupValue:AccountIdenticaIntervalDM withTable:_intervalTable];
		[self convertPopupValue:AccountIdenticaRetrieveXMPP withTable:_retrieveTable];
		//[self convertPopupValue:AccountJiskoIntervalTimeline withTable:_intervalTable];
		//[self convertPopupValue:AccountJiskoIntervalReplies withTable:_intervalTable];
		//[self convertPopupValue:AccountJiskoIntervalDM withTable:_intervalTable];
		//[self convertPopupValue:AccountJiskoRetrieveXMPP withTable:_retrieveTable];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountTwitterPassOld];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountTwitterOAuthKeyOld];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountTwitterOAuthSecretOld];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountJaikuOAuthKeyOld];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountJaikuOAuthSecretOld];
		//[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountFriendFeedPass];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountFriendFeedOAuthKeyOld];
		[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountFriendFeedOAuthSecretOld];
		//LOG(@"[%@ init] URL\n%@\n'%@'", [self className], [url className], url);
		//LOG(@"[%@ init] iTunes\n%@\n'%@'", [self className], [iTunes className], iTunes);
		//LOG(@"[%@ init] URL\n%@", [self className], [[NSUserDefaults standardUserDefaults] valueForKey:GeneralTextURL]);
		//LOG(@"[%@ init] iTunes\n%@", [self className], [[NSUserDefaults standardUserDefaults] valueForKey:GeneralTextITunes]);
		_useEmoji = [[NSUserDefaults standardUserDefaults] boolForKey:GeneralUseEmoji];
		[self loadNib];
	}
	return self;
}

- (void)dealloc
{
	[_arrayBrowser release];
	[_arrayITunes release];
	[_keyEquivViewPost release];
	[_keyEquivViewTimeline release];
	if (_accounts)
	{
		[_accounts release];
	}
	if (_appearances)
	{
		[_appearances release];
	}
	if (_appearanceButtons)
	{
		[_appearanceButtons release];
	}
	if (_appearanceColorButtons)
	{
		[_appearanceColorButtons release];
	}
	if (_panelToolBar)
	{
		[_panelToolBar release];
	}
	[_intervals release];
	[_retrieves release];
	if (_enabledURL)
	{
		[_enabledURL release];
	}
	[super dealloc];
}

- (void)setTimeline:(AfficheurTimeline *)timeline
{
	_timeline = timeline;
}

- (void)setController:(AfficheurController *)controller
{
	_controller = controller;
}

- (NSString *)frameMain
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:FrameMain];
}

- (NSString *)frameTimeline
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:FrameTimeline];
}

#pragma mark Post

- (BOOL)postTwitter
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostTwitter];
}

- (BOOL)postJaiku
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostJaiku];
}

- (BOOL)postTumblr
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostTumblr];
}

- (BOOL)postWassr
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostWassr];
}

//- (BOOL)postNowa
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:PostNowa];
//}

- (BOOL)postIdentica
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostIdentica];
}

//- (BOOL)postJisko
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:PostJisko];
//}

//- (BOOL)postChuitter
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:PostChuitter];
//}

- (BOOL)postFriendFeed
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostFriendFeed];
}

- (BOOL)postFaceBook
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:PostFaceBook];
}

#pragma mark Timeline

- (BOOL)timelineVisibleToolbar
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:TimelineVisibleToolbar];
}

- (void)timelineSetVisibleToolbar:(BOOL)visible
{
	[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:visible]
											 forKey:TimelineVisibleToolbar];
}

#pragma mark General

- (BOOL)generalDockIcon
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralDockIcon];
}

- (BOOL)generalStatusMenuIcon
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralStatusMenuIcon];
}

- (int)generalMenuIcon
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralMenuIcon];
}

- (BOOL)generalStartAtLogin
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralStartAtLogin];
}

- (BOOL)generalUseGrowl
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralUseGrowl];
}

- (BOOL)generalEncodeTinyURL
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralEncodeTinyURL];
}

- (BOOL)generalGrabURL
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralGrabURL];
}

- (BOOL)generalGrabURLwithClipboard
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralGrabURLwithClipboard];
}

- (NSString *)generalTextURL
{
	NSString *text = @"";
	NSArray *array = [[NSUserDefaults standardUserDefaults] valueForKey:GeneralTextURL];
	NSEnumerator *enumerator = [array objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		if ([text isEqualToString:@""])
		{
			text = [NSString stringWithString:obj];
		}
		else
		{
			text = [NSString stringWithFormat:@"%@ %@", text, obj];
		}
	}
	return text;
}

- (BOOL)generalGrabITunes
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralGrabITunes];
}

- (NSString *)generalTextITunes
{
	NSString *text = @"";
	NSArray *array = [[NSUserDefaults standardUserDefaults] valueForKey:GeneralTextITunes];
	NSEnumerator *enumerator = [array objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		if ([text isEqualToString:@""])
		{
			text = [NSString stringWithString:obj];
		}
		else
		{
			text = [NSString stringWithFormat:@"%@ %@", text, obj];
		}
	}
	return text;
}

- (BOOL)generalRetrieveWhenReply
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralRetrieveWhenReply];
}

- (BOOL)generalInlineImage
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralInlineImage];
}

- (BOOL)generalExtractTinyURL
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralExtractTinyURL];
}

- (BOOL)generalDeleteAfterReply
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralDeleteAfterReply];
}

- (int)generalClearAfterPost
{
	return [[NSUserDefaults standardUserDefaults] integerForKey:GeneralClearAfterPost];
}

- (BOOL)generalKeepSelectedItem
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralKeepSelectedItem];
}

- (BOOL)generalKeepCursorPosition
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralKeepCursorPosition];
}

- (void)setGeneralKeepCursorPosition:(BOOL)value
{
	[[NSUserDefaults standardUserDefaults] setBool:value forKey:GeneralKeepCursorPosition];
}

- (BOOL)generalNotKeepTimeline
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralNotKeepTimeline];
}

- (BOOL)generalStackTimeline
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralStackTimeline];
}

- (BOOL)generalHideAfterPost
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralHideAfterPost];
}

- (BOOL)generalConvertEmoji
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralConvertEmoji];
}

- (BOOL)generalGrowlOldOrder
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralGrowlOldOrder];
}

- (BOOL)generalUseEmoji
{
	return _useEmoji;
}

- (BOOL)generalIndicateSource
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralIndicateSource];
}

- (BOOL)generalGrowlDate
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralGrowlDate];
}

- (UInt32)generalLimitOfTimeline
{
	UInt32 limit = [[NSUserDefaults standardUserDefaults] integerForKey:GeneralLimitOfTimeline];
	if (limit >= [_timelineLimits count])
	{
		limit = 0;
	}
	NSNumber *num = [_timelineLimits objectAtIndex:limit];
	return [num intValue];
}

- (BOOL)generalHideStartup
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralHideStartup];
}

- (BOOL)generalAdjustPanel
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:GeneralAdjustPanel];
}

- (UInt32)generalHotKey
{
	return [[NSUserDefaults standardUserDefaults] integerForKey:GeneralHotKey];
}

- (UInt32)generalHotKeyTimeline
{
	return [[NSUserDefaults standardUserDefaults] integerForKey:GeneralHotKeyTimeline];
}

- (int)generalPostTo
{
	NSNumber *postTo = [[NSUserDefaults standardUserDefaults] valueForKey:GeneralPostTo];
	if (postTo)
	{
		return [postTo intValue];
	}
	return 0;
}

- (int)generalPostToALT
{
	NSNumber *postToALT = [[NSUserDefaults standardUserDefaults] valueForKey:GeneralPostToALT];
	if (postToALT)
	{
		return [postToALT intValue];
	}
	return 0;
}

- (UInt32)generalReplyKeyMask
{
	NSString *key = [[NSUserDefaults standardUserDefaults] stringForKey:GeneralReplyKeyMask];
	if (key)
	{
		//LOG(@"[%@ generalReplyKeyMask] %@", [self className], key);
		return [[_keyMask valueForKey:key] intValue];
	}
	return 0;
}

- (UInt32)generalFavoriteKeyMask
{
	NSString *key = [[NSUserDefaults standardUserDefaults] stringForKey:GeneralFavoriteKeyMask];
	if (key)
	{
		//LOG(@"[%@ generalFavoriteKeyMask] %@", [self className], key);
		return [[_keyMask valueForKey:key] intValue];
	}
	return 0;
}

- (UInt32)generalPermalinkKeyMask
{
	NSString *key = [[NSUserDefaults standardUserDefaults] stringForKey:GeneralPermalinkKeyMask];
	if (key)
	{
		//LOG(@"[%@ generalPermalinkKeyMask] %@", [self className], key);
		return [[_keyMask valueForKey:key] intValue];
	}
	return 0;
}

- (UInt32)generalURLKeyMask
{
	NSString *key = [[NSUserDefaults standardUserDefaults] stringForKey:GeneralURLKeyMask];
	if (key)
	{
		//LOG(@"[%@ generalURLKeyMask] %@", [self className], key);
		return [[_keyMask valueForKey:key] intValue];
	}
	return 0;
}

- (UInt32)generalRetweetKeyMask
{
	NSString *key = [[NSUserDefaults standardUserDefaults] stringForKey:GeneralRetweetKeyMask];
	if (key)
	{
		//LOG(@"[%@ generalRetweetKeyMask] %@", [self className], key);
		return [[_keyMask valueForKey:key] intValue];
	}
	return 0;
}

- (UInt32)generalDirectMessageKeyMask
{
	NSString *key = [[NSUserDefaults standardUserDefaults] stringForKey:GeneralDirectMessageKeyMask];
	if (key)
	{
		//LOG(@"[%@ generalDirectMessageKeyMask] %@", [self className], key);
		return [[_keyMask valueForKey:key] intValue];
	}
	return 0;
}

#pragma mark Accounts


- (NSTimeInterval)accountInterval:(NSString *)key
{
	int intervals = [[[NSUserDefaults standardUserDefaults]
					  stringForKey:key] intValue];
	if (intervals < [_intervals count])
	{
		return [[_intervals objectAtIndex:intervals] doubleValue];
	}
	return 0;
}

- (NSString *)accountTwitterUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTwitterUser];
}

- (NSString *)accountTwitterPass
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTwitterPass];
}

- (BOOL)accountTwitterUseStream
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountTwitterUseStream];
}

- (BOOL)accountTwitterExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountTwitterExecMenu];
}

- (NSTimeInterval)accountTwitterIntervalTimeline
{
	return [self accountInterval:AccountTwitterIntervalTimeline];
}

- (NSTimeInterval)accountTwitterIntervalReplies
{
	return [self accountInterval:AccountTwitterIntervalReplies];
}

- (NSTimeInterval)accountTwitterIntervalDM
{
	return [self accountInterval:AccountTwitterIntervalDM];
}

- (int)accountTwitterRetrieveTweets
{
	return [[[NSUserDefaults standardUserDefaults]
			 stringForKey:AccountTwitterRetrieveTweets]
			intValue];
}

- (NSString *)accountTwitterOAuthKey
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTwitterOAuthKey];
}

- (NSString *)accountTwitterOAuthSecret
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTwitterOAuthSecret];
}

- (int)accountTwitterTweetsMania
{
	return [[[NSUserDefaults standardUserDefaults]
			 stringForKey:AccountTwitterTweetsMania]
			intValue];
}

- (BOOL)isTweetsMania
{
	int intarval = [self accountTwitterIntervalTimeline];
	int mania = [[[NSUserDefaults standardUserDefaults]
				  stringForKey:AccountTwitterRetrieveMania] intValue];
	return ((intarval > 0) && (intarval <= mania));
}

- (int)tweetsAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweets;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsMania;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (int)tweetsMaxAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveMax;
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (int)tweetsMinAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweetsMin;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaMin;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (void)setTweetsMinAccountTwitterRetrieveTweets:(int)tweets
{
	NSString *key = AccountTwitterRetrieveTweetsMin;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaMin;
	}
	[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:tweets] forKey:key];
}

- (int)tweetsIncAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweetsInc;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaInc;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (int)tweetsDecAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweetsDec;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaDec;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (int)tweetsUpAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweetsUp;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaUp;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (int)tweetsDownAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweetsDown;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaDown;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (int)tweetsKeepAccountTwitterRetrieveTweets
{
	NSString *key = AccountTwitterRetrieveTweetsKeep;
	if ([self isTweetsMania])
	{
		key = AccountTwitterTweetsManiaKeep;
	}
	return [[[NSUserDefaults standardUserDefaults] stringForKey:key] intValue];
}

- (NSString *)accountJaikuUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuUser];
}

- (NSString *)accountJaikuLocation
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuLocation];
}

- (BOOL)accountJaikuExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJaikuExecMenu];
}

- (NSTimeInterval)accountJaikuIntervalTimeline
{
	return [self accountInterval:AccountJaikuIntervalTimeline];
}

- (BOOL)accountJaikuUseXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJaikuUseXMPP];
}

- (NSString *)accountJaikuJidXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuJidXMPP];
}

- (NSString *)accountJaikuPassXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuPassXMPP];
}

- (NSString *)accountJaikuServerXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuServerXMPP];
}

- (int)accountJaikuPortXMPP
{
	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuPortXMPP]
			intValue];
}

- (int)accountJaikuRetrieveXMPP
{
	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
										stringForKey:AccountJaikuRetrieveXMPP]
									   intValue]] intValue];
}

- (BOOL)accountJaikuOfflineXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJaikuOfflineXMPP];
}

- (BOOL)accountJaikuPostXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJaikuPostXMPP];
}

- (NSString *)accountJaikuOAuthKey
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuOAuthKey];
}

- (NSString *)accountJaikuOAuthSecret
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJaikuOAuthSecret];
}

- (NSString *)accountTumblrUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTumblrUser];
}

- (NSString *)accountTumblrPass
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTumblrPass];
}

- (BOOL)accountTumblrExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountTumblrExecMenu];
}

- (NSTimeInterval)accountTumblrIntervalTimeline
{
	return [self accountInterval:AccountTumblrIntervalTimeline];
}

- (NSString *)accountTumblrOAuthKey
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTumblrOAuthKey];
}

- (NSString *)accountTumblrOAuthSecret
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountTumblrOAuthSecret];
}

- (NSString *)accountWassrUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountWassrUser];
}

- (NSString *)accountWassrPass
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountWassrPass];
}

- (BOOL)accountWassrExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountWassrExecMenu];
}

- (NSTimeInterval)accountWassrIntervalTimeline
{
	return [self accountInterval:AccountWassrIntervalTimeline];
}

- (NSTimeInterval)accountWassrIntervalReplies
{
	return [self accountInterval:AccountWassrIntervalReplies];
}

- (NSTimeInterval)accountWassrIntervalChannel
{
	return [self accountInterval:AccountWassrIntervalChannel];
}

- (BOOL)accountWassrUseXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountWassrUseXMPP];
}

- (NSString *)accountWassrJidXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountWassrJidXMPP];
}

- (NSString *)accountWassrPassXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountWassrPassXMPP];
}

- (NSString *)accountWassrServerXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountWassrServerXMPP];
}

- (int)accountWassrPortXMPP
{
	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountWassrPortXMPP]
			intValue];
}

- (int)accountWassrRetrieveXMPP
{
	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
										stringForKey:AccountWassrRetrieveXMPP]
									   intValue]] intValue];
}

- (BOOL)accountWassrOfflineXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountWassrOfflineXMPP];
}

- (BOOL)accountWassrPostXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountWassrPostXMPP];
}

//- (NSString *)accountNowaUser
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountNowaUser];
//}

//- (NSString *)accountNowaPass
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountNowaPass];
//}

//- (BOOL)accountNowaExecMenu
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountNowaExecMenu];
//}

//- (NSTimeInterval)accountNowaIntervalTimeline
//{
//	return [[_intervals valueForKey:[[NSUserDefaults standardUserDefaults]
//									 stringForKey:AccountNowaIntervalTimeline]]
//			doubleValue];
//}

- (NSString *)accountIdenticaUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountIdenticaUser];
}

- (NSString *)accountIdenticaPass
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountIdenticaPass];
}

- (BOOL)accountIdenticaExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountIdenticaExecMenu];
}

- (NSTimeInterval)accountIdenticaIntervalTimeline
{
	return [self accountInterval:AccountIdenticaIntervalTimeline];
}

- (NSTimeInterval)accountIdenticaIntervalReplies
{
	return [self accountInterval:AccountIdenticaIntervalReplies];
}

- (NSTimeInterval)accountIdenticaIntervalDM
{
	return [self accountInterval:AccountIdenticaIntervalDM];
}

- (BOOL)accountIdenticaUseXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountIdenticaUseXMPP];
}

- (NSString *)accountIdenticaJidXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountIdenticaJidXMPP];
}

- (NSString *)accountIdenticaPassXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountIdenticaPassXMPP];
}

- (NSString *)accountIdenticaServerXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountIdenticaServerXMPP];
}

- (int)accountIdenticaPortXMPP
{
	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountIdenticaPortXMPP]
			intValue];
}

- (int)accountIdenticaRetrieveXMPP
{
	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
										stringForKey:AccountIdenticaRetrieveXMPP]
									   intValue]] intValue];
}

- (BOOL)accountIdenticaOfflineXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountIdenticaOfflineXMPP];
}

- (BOOL)accountIdenticaPostXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountIdenticaPostXMPP];
}

//- (NSString *)accountJiskoUser
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJiskoUser];
//}

//- (NSString *)accountJiskoPass
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJiskoPass];
//}

//- (BOOL)accountJiskoExecMenu
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJiskoExecMenu];
//}

//- (NSTimeInterval)accountJiskoIntervalTimeline
//{
//	return [self accountInterval:AccountJiskoIntervalTimeline];
//}

//- (NSTimeInterval)accountJiskoIntervalReplies
//{
//	return [self accountInterval:AccountJiskoIntervalReplies];
//}

//- (NSTimeInterval)accountJiskoIntervalDM
//{
//	return [self accountInterval:AccountJiskoIntervalDM];
//}

//- (BOOL)accountJiskoUseXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJiskoUseXMPP];
//}

//- (NSString *)accountJiskoJidXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJiskoJidXMPP];
//}

//- (NSString *)accountJiskoPassXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJiskoPassXMPP];
//}

//- (NSString *)accountJiskoServerXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountJiskoServerXMPP];
//}

//- (int)accountJiskoPortXMPP
//{
//	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountJiskoPortXMPP]
//			intValue];
//}

//- (int)accountJiskoRetrieveXMPP
//{
//	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
//										stringForKey:AccountJiskoRetrieveXMPP]
//									   intValue]] intValue];
//}

//- (BOOL)accountJiskoOfflineXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJiskoOfflineXMPP];
//}

//- (BOOL)accountJiskoPostXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountJiskoPostXMPP];
//}

//- (NSString *)accountChuitterUser
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountChuitterUser];
//}

//- (NSString *)accountChuitterPass
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountChuitterPass];
//}

//- (BOOL)accountChuitterExecMenu
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountChuitterExecMenu];
//}

//- (NSTimeInterval)accountChuitterIntervalTimeline
//{
//	return [self accountInterval:AccountChuitterIntervalTimeline];
//}

//- (NSTimeInterval)accountChuitterIntervalReplies
//{
//	return [self accountInterval:AccountChuitterIntervalReplies];
//}

//- (NSTimeInterval)accountChuitterIntervalDM
//{
//	return [self accountInterval:AccountChuitterIntervalDM];
//}

//- (BOOL)accountChuitterUseXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountChuitterUseXMPP];
//}

//- (NSString *)accountChuitterJidXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountChuitterJidXMPP];
//}

//- (NSString *)accountChuitterPassXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountChuitterPassXMPP];
//}

//- (NSString *)accountChuitterServerXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountChuitterServerXMPP];
//}

//- (int)accountChuitterPortXMPP
//{
//	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountChuitterPortXMPP]
//			intValue];
//}

//- (int)accountChuitterRetrieveXMPP
//{
//	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
//										stringForKey:AccountChuitterRetrieveXMPP]
//									   intValue]] intValue];
//}

//- (BOOL)accountChuitterOfflineXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountChuitterOfflineXMPP];
//}

//- (BOOL)accountChuitterPostXMPP
//{
//	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountChuitterPostXMPP];
//}

- (NSString *)accountFriendFeedUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedUser];
}

- (NSString *)accountFriendFeedPass
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedPass];
}

- (NSString *)accountFriendFeedLocation
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedLocation];
}

- (BOOL)accountFriendFeedExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFriendFeedExecMenu];
}

- (NSTimeInterval)accountFriendFeedIntervalTimeline
{
	return [self accountInterval:AccountFriendFeedIntervalTimeline];
}

- (BOOL)accountFriendFeedUseXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFriendFeedUseXMPP];
}

- (NSString *)accountFriendFeedJidXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedJidXMPP];
}

- (NSString *)accountFriendFeedPassXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedPassXMPP];
}

- (NSString *)accountFriendFeedServerXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedServerXMPP];
}

- (int)accountFriendFeedPortXMPP
{
	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedPortXMPP]
			intValue];
}

- (int)accountFriendFeedRetrieveXMPP
{
	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
										stringForKey:AccountFriendFeedRetrieveXMPP]
									   intValue]] intValue];
}

- (BOOL)accountFriendFeedOfflineXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFriendFeedOfflineXMPP];
}

- (BOOL)accountFriendFeedPostXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFriendFeedPostXMPP];
}

- (NSString *)accountFriendFeedOAuthKey
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedOAuthKey];
}

- (NSString *)accountFriendFeedOAuthSecret
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFriendFeedOAuthSecret];
}

- (NSString *)accountFaceBookId
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookId];
}

- (NSString *)accountFaceBookUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookUser];
}

- (NSString *)accountFaceBookLocation
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookLocation];
}

- (BOOL)accountFaceBookExecMenu
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFaceBookExecMenu];
}

- (NSTimeInterval)accountFaceBookIntervalTimeline
{
	return [self accountInterval:AccountFaceBookIntervalTimeline];
}

- (BOOL)accountFaceBookUseXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFaceBookUseXMPP];
}

- (NSString *)accountFaceBookJidXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookJidXMPP];
}

- (NSString *)accountFaceBookPassXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookPassXMPP];
}

- (NSString *)accountFaceBookServerXMPP
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookServerXMPP];
}

- (int)accountFaceBookPortXMPP
{
	return [[[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookPortXMPP]
			intValue];
}

- (int)accountFaceBookRetrieveXMPP
{
	return [[_retrieves objectAtIndex:[[[NSUserDefaults standardUserDefaults]
										stringForKey:AccountFaceBookRetrieveXMPP]
									   intValue]] intValue];
}

- (BOOL)accountFaceBookOfflineXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFaceBookOfflineXMPP];
}

- (BOOL)accountFaceBookPostXMPP
{
	return [[NSUserDefaults standardUserDefaults] boolForKey:AccountFaceBookPostXMPP];
}

- (NSString *)accountFaceBookOAuthToken
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountFaceBookOAuthToken];
}

- (NSString *)accountBitLyUser
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountBitLyUser];
}

- (NSString *)accountBitLyAPIKey
{
	return [[NSUserDefaults standardUserDefaults] stringForKey:AccountBitLyAPIKey];
}

- (int)accountBitLyService
{
	return [[NSUserDefaults standardUserDefaults] integerForKey:AccountBitLyService];
}

#pragma mark Keywords

- (NSArray *)keywords
{
	return [_arrayKeywords content];
}

- (NSArray *)ignoreKeywords
{
	return [_arrayIgnoreKeywords content];
}

#pragma mark Suggestions

- (NSArray *)complete
{
	NSMutableArray *complete = [NSMutableArray array];
	NSEnumerator *enumerator =  [[_arraySuggestions content] objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		[complete addObject:[obj valueForKey:Suggestion]];
	}
	[complete sortUsingSelector:@selector(caseInsensitiveCompare:)];
	return [NSArray arrayWithArray:complete];
}

- (NSArray *)ignore
{
	NSMutableArray *ignore = [NSMutableArray array];
	NSEnumerator *enumerator =  [[_arrayIgnores content] objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		[ignore addObject:[obj valueForKey:Ignore]];
	}
	[ignore sortUsingSelector:@selector(caseInsensitiveCompare:)];
	return [NSArray arrayWithArray:ignore];
}

- (void)sortSuggestions
{
	NSMutableArray *content = [NSMutableArray array];
	while ([[_arraySuggestions content] count] > 0)
	{
		[content addObject:[[[_arraySuggestions content] objectAtIndex:0]
							valueForKey:Suggestion]];
		[_arraySuggestions removeObjectAtArrangedObjectIndex:0];
	}
	if ([content count] > 0)
	{
		[content sortUsingSelector:@selector(caseInsensitiveCompare:)];
		NSEnumerator *enumerator = [content objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			[[_arraySuggestions content] addObject:
			 [NSMutableDictionary dictionaryWithObjectsAndKeys:obj, Suggestion, nil]];
		}
		[_arraySuggestions rearrangeObjects];
	}
	//LOG(@"[%@ sortSuggestions]\n%@", [self className], [_arraySuggestions content]);
}

- (void)loadSuggestions
{
	while ([[_arraySuggestions content] count] > 0)
	{
		[_arraySuggestions removeObjectAtArrangedObjectIndex:0];
	}
	NSArray *suggestions = [[NSUserDefaults standardUserDefaults] arrayForKey:Complete];
	if (suggestions)
	{
		NSEnumerator *enumerator = [suggestions objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			if ([obj isKindOfClass:[NSString class]])
			{
				obj = [NSMutableDictionary dictionaryWithObjectsAndKeys:obj, Suggestion, nil];
			}
			[[_arraySuggestions content] addObject:obj];
		}
		[_arraySuggestions rearrangeObjects];
		//LOG(@"[%@ loadSuggestions]\n%@", [self className], [_arraySuggestions content]);
	}
	[self sortSuggestions];
}

- (void)sortIgnores
{
	NSMutableArray *content = [NSMutableArray array];
	while ([[_arrayIgnores content] count] > 0)
	{
		[content addObject:[[[_arrayIgnores content] objectAtIndex:0]
							valueForKey:Ignore]];
		[_arrayIgnores removeObjectAtArrangedObjectIndex:0];
	}
	if ([content count] > 0)
	{
		[content sortUsingSelector:@selector(caseInsensitiveCompare:)];
		NSEnumerator *enumerator = [content objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			[[_arrayIgnores content] addObject:
			 [NSMutableDictionary dictionaryWithObjectsAndKeys:obj, Ignore, nil]];
		}
		[_arrayIgnores rearrangeObjects];
	}
	//LOG(@"[%@ sortIgnore]\n%@", [self className], [_arrayIgnore content]);
}

- (void)loadIgnores
{
	while ([[_arrayIgnores content] count] > 0)
	{
		[_arrayIgnores removeObjectAtArrangedObjectIndex:0];
	}
	NSArray *ignores = [[NSUserDefaults standardUserDefaults] arrayForKey:CompleteIgnore];
	if (ignores)
	{
		NSEnumerator *enumerator = [ignores objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			if ([obj isKindOfClass:[NSString class]])
			{
				obj = [NSMutableDictionary dictionaryWithObjectsAndKeys:obj, Ignore, nil];
			}
			[[_arrayIgnores content] addObject:obj];
		}
		[_arrayIgnores rearrangeObjects];
		//LOG(@"[%@ loadIgnores]\n%@", [self className], [_arrayIgnores content]);
	}
	[self sortIgnores];
}

- (BOOL)addComplete:(NSString *)complete
{
	NSArray *array = [self complete];
	NSEnumerator *enumerator = [array objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		if ([complete compare:obj options:NSCaseInsensitiveSearch] == NSOrderedSame)
		{
			return NO;
		}
	}
	array = [self ignore];
	enumerator = [array objectEnumerator];
	while ((obj = [enumerator nextObject]))
	{
		if ([complete compare:obj options:NSCaseInsensitiveSearch] == NSOrderedSame)
		{
			LOG(@"[%@ addComplete]\nIgnore: %@", [self className], complete);
			return NO;
		}
	}
	//LOG(@"[%@ addComplete]\n%@", [self className], complete);
	[[_arraySuggestions content]
	 addObject:[NSDictionary dictionaryWithObjectsAndKeys:complete, Suggestion, nil]];
	[self sortSuggestions];
	//[[NSUserDefaults standardUserDefaults] setObject:array forKey:Complete];
	return YES;
}

#pragma mark Appearances

- (NSDictionary *)appearances
{
	NSDictionary *appearances = nil;
	@synchronized(self)
	{
		appearances = _appearances;
	}
	return appearances;
}

#pragma mark Rate limit of Twitter

- (int)timesInterval:(id)popup
{
	//LOG(@"[%@ timesInterval]\n%@", [self className], [popup titleOfSelectedItem]);
	id interval = [_intervals objectAtIndex:[popup indexOfSelectedItem]];
	if (interval)
	{
		int sec = [interval intValue];
		if (sec)
		{
			return 3600 / sec;
		}
	}
	return 0;
}

- (int)timesIntervals
{
	int times = 0;
	times += [self timesInterval:_popupIntervalTimeline];
	times += [self timesInterval:_popupIntervalReplies];
	times += [self timesInterval:_popupIntervalDM];
	return times;
}

- (int)timesAnotherInterval:(id)popup
{
	int times = 0;
	if (popup != _popupIntervalTimeline)
	{
		times += [self timesInterval:_popupIntervalTimeline];
	}
	if (popup != _popupIntervalReplies)
	{
		times += [self timesInterval:_popupIntervalReplies];
	}
	if (popup != _popupIntervalDM)
	{
		times += [self timesInterval:_popupIntervalDM];
	}
	return times;
}

- (BOOL)adjustPopupButton:(id)popup
			withRateLimit:(int)rateLimit
{
	BOOL needAddjust = NO;
	//LOG(@"[%@ adjustPopupButton]\n%@", [self className], [popup titleOfSelectedItem]);
	int times = [self timesAnotherInterval:popup];
	int limit = rateLimit - times;
	//LOG(@"[%@ adjustPopupButton]\n%d / %d", [self className], times, limit);
	NSString *selected = [popup titleOfSelectedItem];
	NSEnumerator *enumerator = [[popup itemArray] objectEnumerator];
	id item;
	while ((item = [enumerator nextObject]))
	{
		//LOG(@"[%@ adjustPopupButton] %@", [self className], item);
		int sec = [[_intervals objectAtIndex:
					[[_intervalIndexes valueForKey:[item title]]
					 intValue]] intValue];
		if ((sec == 0) || ((3600 / sec) <= limit))
		{
			//LOG(@"[%@ adjustPopupButton] YES", [self className]);
			if (![item isEnabled])
			{
				[item setEnabled:YES];
			}
		}
		else
		{
			LOG(@"[%@ adjustPopupButton] %@", [self className], [item title]);
			if ([item isEnabled])
			{
				[item setEnabled:NO];
			}
			if ([[item title] isEqualToString:selected])
			{
				LOG(@"[%@ adjustPopupButton] !!!", [self className]);
				needAddjust = YES;
			}
		}
	}
	return needAddjust;
}

- (BOOL)adjustRateLimit:(id)object
		  withRateLimit:(int)rateLimit
{
	BOOL needAddjust = NO;
	//LOG(@"[%@ adjustRateLimit]", [self className]);
	if (object != _popupIntervalTimeline)
	{
		if ([self adjustPopupButton:_popupIntervalTimeline withRateLimit:rateLimit])
		{
			needAddjust = YES;
		}
	}
	if (object != _popupIntervalReplies)
	{
		if ([self adjustPopupButton:_popupIntervalReplies withRateLimit:rateLimit])
		{
			needAddjust = YES;
		}
	}
	if (object != _popupIntervalDM)
	{
		if ([self adjustPopupButton:_popupIntervalDM withRateLimit:rateLimit])
		{
			needAddjust = YES;
		}
	}
	return needAddjust;
}

- (void)setLabelRequests:(NSString *)string
{
	[_labelRequests setStringValue:string];
}

- (void)updateLabelRequests:(int)requests
			  withRateLimit:(int)rateLimit
{
	NSString *string = [NSString stringWithFormat:RATE_LIMIT, requests, rateLimit];
	[self performSelectorOnMainThread:@selector(setLabelRequests:)
						   withObject:string
						waitUntilDone:YES];
}

- (void)warningRateLimit:(NSString *)message
{
	[_controller alert:message
			 withTitle:WARNING
			  selector:nil
				target:nil];
}

- (void)updatetRateLimitOfTwitter
{
	int limit = [_controller rateLimitOfTwitter];
	LOG(@"[%@ updatetRateLimitOfTwitter] %d", [self className], limit);
	if (limit > 0)
	{
		_rateLimit = limit;
	}
}

- (int)rateLimitOfTwitter
{
	return _rateLimit;
}

- (void)updatetRateLimit
{
	[self updatetRateLimitOfTwitter];
	int limit = [self rateLimitOfTwitter];
	int times = [self timesIntervals];
	LOG(@"[%@ updatetRateLimit] %d / %d", [self className], times, limit);
	[self updateLabelRequests:times
				withRateLimit:limit];
}

- (void)performRateLimitHelper:(id)object
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performRateLimitHelper]", [self className]);
	@try
	{
		[self updatetRateLimit];
		int limit = [self rateLimitOfTwitter];
		int times = [self timesIntervals];
		if ([self adjustRateLimit:object
					withRateLimit:limit])
		{
			NSString *message = [NSString stringWithFormat:WARNING_RATE_LIMIT, times, limit];
			LOG(@"[%@ performRateLimitHelper] !!!", [self className]);
			[self performSelectorOnMainThread:@selector(warningRateLimit:)
								   withObject:message
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performRateLimitHelper] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	@finally
	{
		[object release];
	}
	//LOG(@"[%@ performRateLimitHelper] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)rateLimitHelper:(id)sender
{
	id object = sender;
	if (object)
	{
		[object retain];
	}
	[NSThread detachNewThreadSelector:@selector(performRateLimitHelper:)
							 toTarget:self
						   withObject:object];
}

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
		 withPopupButton:(NSPopUpButton *)popup
			   rateLimit:(int)rateLimit
{
	//LOG(@"[%@ validateMenuItem]", [self className]);
	int times = [self timesAnotherInterval:popup];
	int limit = rateLimit - times;
	//LOG(@"[%@ validateMenuItem]\n%d / %d", [self className], times, limit);
	int sec = [[_intervals objectAtIndex:
				[[_intervalIndexes valueForKey:[menuItem title]]
				 intValue]] intValue];
	if ((sec == 0) || ((3600 / sec) <= limit))
	{
		//LOG(@"[%@ adjustPopupButton] YES", [self className]);
		return YES;
	}
	return NO;
}

#pragma mark WebView

- (void)webSheetDidEnd:(NSWindow*)sheet
			returnCode:(int)returnCode
		   contextInfo:(void*)contextInfo
{
	LOG(@"[%@ webSheetDidEnd]", [self className]);
	@try
	{
		[sheet orderOut:self];
		if (returnCode == DIALOG_OK)
		{
			if (contextInfo && [(id)contextInfo isKindOfClass:[NSDictionary class]])
			{
				SEL	selector = NSSelectorFromString([(id)contextInfo valueForKey:KeySelector]);
				id	target = [(id)contextInfo valueForKey:KeyTarget];
				if (selector && target)
				{
					if ([target respondsToSelector:selector])
					{
						[NSThread detachNewThreadSelector:selector
												 toTarget:target
											   withObject:nil];
					}
				}
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ webSheetDidEnd] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	@finally
	{
		if (contextInfo)
		{
			[(id)contextInfo release];
		}
	}
}

- (void)beginWebSheet:(NSString *)path
		   enabledURL:(NSString *)enabledURL
			 selector:(SEL)selector
			   target:(id)target
				 text:(NSString *)text
{
	LOG(@"[%@ beginWebSheet]\n%@", [self className], path);
	@try
	{
		if (_enabledURL)
		{
			[_enabledURL release];
		}
		[_textPleaseAuthorize setStringValue:text];
		_enabledURL = [enabledURL copy];
		[_webOK setEnabled:NO];
		[[NSApplication sharedApplication] beginSheet:_panelWeb
									   modalForWindow:_panel
										modalDelegate:self
									   didEndSelector:@selector(webSheetDidEnd:returnCode:contextInfo:)
										  contextInfo:[[NSDictionary dictionaryWithObjectsAndKeys:
														NSStringFromSelector(selector), KeySelector,
														target, KeyTarget,
														nil] retain]];
		[_panelWeb makeFirstResponder:_webView];
		[_webView stopLoading:self];
		[_webView setFrameLoadDelegate:self];
		WebFrame *frame = [_webView mainFrame];
		if (frame)
		{
			NSURL *URL = [NSURL URLWithString:path];
			NSURLRequest *req = [NSURLRequest requestWithURL:URL
												 cachePolicy:NSURLCacheStorageNotAllowed
											 timeoutInterval:10];
			LOG(@"[%@ beginWebSheet] req\n%@", [self className], req);
			[frame loadRequest:req];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ beginWebSheet] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

#pragma mark OAuth

- (void)adjustAuthorizeButton:(id)button
			  withAccessToken:(NSString *)token
					   secret:(NSString *)secret
{
	if (token && ![token isEqualToString:@""] && secret && ![secret isEqualToString:@""])
	{
		[button setTitle:REMOVE];
	}
	else
	{
		[button setTitle:AUTHORIZE];
	}
}

- (void)confirmSheetDidEnd:(NSWindow*)sheet
				returnCode:(int)returnCode
			   contextInfo:(void*)contextInfo
{
	LOG(@"[%@ confirmSheetDidEnd]", [self className]);
	@try
	{
		[sheet orderOut:self];
		if (contextInfo && [(id)contextInfo isKindOfClass:[NSDictionary class]])
		{
			SEL	selector = NSSelectorFromString([(id)contextInfo valueForKey:KeySelector]);
			id	target = [(id)contextInfo valueForKey:KeyTarget];
			if (selector && target)
			{
				if ([target respondsToSelector:selector])
				{
					[NSThread detachNewThreadSelector:selector
											 toTarget:target
										   withObject:[NSNumber numberWithInt:returnCode]];
				}
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ confirmSheetDidEnd] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	@finally
	{
		if (contextInfo)
		{
			[(id)contextInfo release];
		}
	}
}

- (void)beginConfirmSheetWithText:(NSString *)text
						 selector:(SEL)selector
						   target:(id)target
{
	LOG(@"[%@ beginConfirmSheetWithText]", [self className]);
	@try
	{
		[[NSApplication sharedApplication] beginSheet:_panelConfirm
									   modalForWindow:_panel
										modalDelegate:self
									   didEndSelector:@selector(confirmSheetDidEnd:returnCode:contextInfo:)
										  contextInfo:[[NSDictionary dictionaryWithObjectsAndKeys:
														NSStringFromSelector(selector), KeySelector,
														target, KeyTarget,
														nil] retain]];
		[_textConfirm setStringValue:text];
		[_panelConfirm makeKeyAndOrderFront:self];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ beginConfirmSheetWithText] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

#pragma mark OAuth of Jaiku

- (void)adjustJaikuAuthorizeButton
{
#if 0
	[_btnJaikuAuthorize setTitle:AUTHORIZE];
#else
	[self adjustAuthorizeButton:_btnJaikuAuthorize
				withAccessToken:[self accountJaikuOAuthKey]
						 secret:[self accountJaikuOAuthSecret]];
#endif
}

- (void)setJaikuAccessToken
{
	LOG(@"[%@ setJaikuAccessToken]", [self className]);
	ServiceJaiku *jaiku = (ServiceJaiku *)[_controller service:Jaiku];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setValue:[jaiku accessToken]
				forKey:AccountJaikuOAuthKey];
	[defaults setValue:[jaiku accessTokenSecret]
				forKey:AccountJaikuOAuthSecret];
	[_textJaikuToken setStringValue:[jaiku accessToken]];
	[self adjustJaikuAuthorizeButton];
}

- (void)removeJaikuAccessToken:(NSNumber *)returnCode
{
	LOG(@"[%@ removeJaikuAccessToken]", [self className]);
	@try
	{
		if ([returnCode intValue] == DIALOG_OK)
		{
			NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
			[defaults removeObjectForKey:AccountJaikuOAuthKey];
			[defaults removeObjectForKey:AccountJaikuOAuthSecret];
			[_textJaikuToken setStringValue:@""];
			[self adjustJaikuAuthorizeButton];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ removeJaikuAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)performJaikuAccessToken
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performJaikuAccessToken]", [self className]);
	@try
	{
		ServiceJaiku *jaiku = (ServiceJaiku *)[_controller service:Jaiku];
		if ([jaiku access_token])
		{
			LOG(@"[%@ performJaikuAccessToken]\n%@\n%@", [self className], [jaiku accessToken], [jaiku accessTokenSecret]);
			[self performSelectorOnMainThread:@selector(setJaikuAccessToken)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performJaikuAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performJaikuAccessToken] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)performJaikuBeginWebSheet:(NSString *)path
{
	[self beginWebSheet:path
			 enabledURL:@"http://www.jaiku.com/api/authorize"
			   selector:@selector(performJaikuAccessToken)
				 target:self
				   text:PLEASE_JAIKU_AUTHORIZE];
}

- (void)performJaikuBeginConfirm:(id)object
{
	[self beginConfirmSheetWithText:REMOVE_TOKEN
						   selector:@selector(removeJaikuAccessToken:)
							 target:self];
}

- (void)performJaikuAuthorize
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performJaikuAuthorize]", [self className]);
	@try
	{
		if ([[_btnJaikuAuthorize title] isEqualToString:AUTHORIZE])
		{
			ServiceJaiku *jaiku = (ServiceJaiku *)[_controller service:Jaiku];
			NSString *path = [jaiku authorize];
			if (path)
			{
				LOG(@"[%@ performJaikuAuthorize]\n%@", [self className], path);
				[self performSelectorOnMainThread:@selector(performJaikuBeginWebSheet:)
									   withObject:path
									waitUntilDone:YES];
			}
		}
		else
		{
			[self performSelectorOnMainThread:@selector(performJaikuBeginConfirm:)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performJaikuAuthorize] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performJaikuAuthorize] done", [self className]);
	[pool release];
	[NSThread exit];
}

#pragma mark OAuth of Twitter

- (void)adjustTwitterAuthorizeButton
{
	[self adjustAuthorizeButton:_btnTwitterAuthorize
				withAccessToken:[self accountTwitterOAuthKey]
						 secret:[self accountTwitterOAuthSecret]];
}

- (void)setTwitterAccessToken
{
	LOG(@"[%@ setTwitterAccessToken]", [self className]);
	ServiceTwitter *twitter = (ServiceTwitter *)[_controller service:Twitter];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setValue:[twitter accessToken]
				forKey:AccountTwitterOAuthKey];
	[defaults setValue:[twitter accessTokenSecret]
				forKey:AccountTwitterOAuthSecret];
	[_textTwitterToken setStringValue:[twitter accessToken]];
	[self adjustTwitterAuthorizeButton];
}

- (void)removeTwitterAccessToken:(NSNumber *)returnCode
{
	LOG(@"[%@ removeTwitterAccessToken]", [self className]);
	@try
	{
		if ([returnCode intValue] == DIALOG_OK)
		{
			NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
			[defaults removeObjectForKey:AccountTwitterOAuthKey];
			[defaults removeObjectForKey:AccountTwitterOAuthSecret];
			[_textTwitterToken setStringValue:@""];
			[self adjustTwitterAuthorizeButton];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ removeTwitterAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)performTwitterAccessToken
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performTwitterAccessToken]", [self className]);
	@try
	{
		NSData *data = [[[_webView mainFrame] dataSource] data];
		NSString *html = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
	//	NSString *pin = [html replaceWithExpression:@"^.*<div id\\=\"oauth_pin\">\\s+(\\S+).*$"
	//										replace:@"\\1"
	//										options:OgreMultilineOption];
		NSString *pin = [html replaceWithExpression:@"^.*<kbd aria\\-labelledby\\=\"code-desc\"><code>(.*?)<\\/code>.*$"
											replace:@"\\1"
											options:OgreMultilineOption];
		LOG(@"[%@ performTwitterAccessToken]\n%@", [self className], html);
		LOG(@"[%@ performTwitterAccessToken]\n'%@'", [self className], pin);
		if ([pin lengthOfRegularExpression:@"^\\S+$"] == [pin length])
		{
			ServiceTwitter *twitter = (ServiceTwitter *)[_controller service:Twitter];
			if ([twitter access_token:pin])
			{
				LOG(@"[%@ performTwitterAccessToken]\n%@\n%@", [self className], [twitter accessToken], [twitter accessTokenSecret]);
				[self performSelectorOnMainThread:@selector(setTwitterAccessToken)
									   withObject:nil
									waitUntilDone:YES];
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performTwitterAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performTwitterTwitterToken] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)performTwitterBeginWebSheet:(NSString *)path
{
	LOG(@"[%@ performTwitterBeginWebSheet]\n%@", [self className], path);
	[self beginWebSheet:path
			 enabledURL:@"https://twitter.com/oauth/authorize"
			   selector:@selector(performTwitterAccessToken)
				 target:self
				   text:PLEASE_TWITTER_AUTHORIZE];
}

- (void)performTwitterBeginConfirm:(id)object
{
	[self beginConfirmSheetWithText:REMOVE_TOKEN
						   selector:@selector(removeTwitterAccessToken:)
							 target:self];
}

- (void)performTwitterAuthorize
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	LOG(@"[%@ performTwitterAuthorize]", [self className]);
	@try
	{
		if ([[_btnTwitterAuthorize title] isEqualToString:AUTHORIZE])
		{
			ServiceTwitter *twitter = (ServiceTwitter *)[_controller service:Twitter];
			NSString *path = [twitter authorize];
			if (path)
			{
				LOG(@"[%@ performTwitterAuthorize]\n%@", [self className], path);
				[self performSelectorOnMainThread:@selector(performTwitterBeginWebSheet:)
									   withObject:path
									waitUntilDone:YES];
			}
		}
		else
		{
			[self performSelectorOnMainThread:@selector(performTwitterBeginConfirm:)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performTwitterAuthorize] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performTwitterAuthorize] done", [self className]);
	[pool release];
	[NSThread exit];
}

#pragma mark OAuth of Tumblr

- (void)adjustTumblrAuthorizeButton
{
	[self adjustAuthorizeButton:_btnTumblrAuthorize
				withAccessToken:[self accountTumblrOAuthKey]
						 secret:[self accountTumblrOAuthSecret]];
}

- (void)setTumblrAccessToken
{
	LOG(@"[%@ setTumblrAccessToken]", [self className]);
	ServiceTumblr *tumblr = (ServiceTumblr *)[_controller service:Tumblr];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setValue:[tumblr accessToken]
				forKey:AccountTumblrOAuthKey];
	[defaults setValue:[tumblr accessTokenSecret]
				forKey:AccountTumblrOAuthSecret];
	[_textTumblrToken setStringValue:[tumblr accessToken]];
	[self adjustTumblrAuthorizeButton];
}

- (void)removeTumblrAccessToken:(NSNumber *)returnCode
{
	LOG(@"[%@ removeTumblrAccessToken]", [self className]);
	@try
	{
		if ([returnCode intValue] == DIALOG_OK)
		{
			NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
			[defaults removeObjectForKey:AccountTumblrOAuthKey];
			[defaults removeObjectForKey:AccountTumblrOAuthSecret];
			[_textTumblrToken setStringValue:@""];
			[self adjustTumblrAuthorizeButton];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ removeTumblrAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)performTumblrAccessToken
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performTumblrAccessToken]", [self className]);
	@try
	{
		NSData *data = [[[_webView mainFrame] dataSource] data];
		NSString *html = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
		//	NSString *pin = [html replaceWithExpression:@"^.*<div id\\=\"oauth_pin\">\\s+(\\S+).*$"
		//										replace:@"\\1"
		//										options:OgreMultilineOption];
		NSString *pin = [html replaceWithExpression:@"^.*<kbd aria\\-labelledby\\=\"code-desc\"><code>(.*?)<\\/code>.*$"
											replace:@"\\1"
											options:OgreMultilineOption];
		LOG(@"[%@ performTumblrAccessToken]\n%@", [self className], html);
		LOG(@"[%@ performTumblrAccessToken]\n'%@'", [self className], pin);
		if ([pin lengthOfRegularExpression:@"^\\S+$"] == [pin length])
		{
			ServiceTumblr *tumblr = (ServiceTumblr *)[_controller service:Tumblr];
			if ([tumblr access_token:pin])
			{
				LOG(@"[%@ performTumblrAccessToken]\n%@\n%@", [self className], [tumblr accessToken], [tumblr accessTokenSecret]);
				[self performSelectorOnMainThread:@selector(setTumblrAccessToken)
									   withObject:nil
									waitUntilDone:YES];
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performTumblrAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performTumblrTumblrToken] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)performTumblrBeginWebSheet:(NSString *)path
{
	LOG(@"[%@ performTumblrBeginWebSheet]\n%@", [self className], path);
	[self beginWebSheet:path
			 enabledURL:@"http://www.tumblr.com/oauth/authorize"
			   selector:@selector(performTumblrAccessToken)
				 target:self
				   text:PLEASE_TUMBLR_AUTHORIZE];
}

- (void)performTumblrBeginConfirm:(id)object
{
	[self beginConfirmSheetWithText:REMOVE_TOKEN
						   selector:@selector(removeTumblrAccessToken:)
							 target:self];
}

- (void)performTumblrAuthorize
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	LOG(@"[%@ performTumblrAuthorize]", [self className]);
	@try
	{
		if ([[_btnTumblrAuthorize title] isEqualToString:AUTHORIZE])
		{
			ServiceTumblr *tumblr = (ServiceTumblr *)[_controller service:Tumblr];
			NSString *path = [tumblr authorize];
			if (path)
			{
				LOG(@"[%@ performTumblrAuthorize]\n%@", [self className], path);
				[self performSelectorOnMainThread:@selector(performTumblrBeginWebSheet:)
									   withObject:path
									waitUntilDone:YES];
			}
		}
		else
		{
			[self performSelectorOnMainThread:@selector(performTumblrBeginConfirm:)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performTumblrAuthorize] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performTwitterAuthorize] done", [self className]);
	[pool release];
	[NSThread exit];
}

#pragma mark OAuth of FriendFeed

- (void)adjustFriendFeedAuthorizeButton
{
#if 0
	[_btnFriendFeedAuthorize setTitle:AUTHORIZE];
#else
	[self adjustAuthorizeButton:_btnFriendFeedAuthorize
				withAccessToken:[self accountFriendFeedOAuthKey]
						 secret:[self accountFriendFeedOAuthSecret]];
#endif
}

- (void)setFriendFeedAccessToken
{
	LOG(@"[%@ setFriendFeedAccessToken]", [self className]);
	ServiceFriendFeed *friendFeed = (ServiceFriendFeed *)[_controller service:FriendFeed];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setValue:[friendFeed accessToken]
				forKey:AccountFriendFeedOAuthKey];
	[defaults setValue:[friendFeed accessTokenSecret]
				forKey:AccountFriendFeedOAuthSecret];
	[_textFriendFeedToken setStringValue:[friendFeed accessToken]];
	[self adjustFriendFeedAuthorizeButton];
}

- (void)removeFriendFeedAccessToken:(NSNumber *)returnCode
{
	LOG2(@"[%@ removeFriendFeedAccessToken]", [self className]);
	@try
	{
		if ([returnCode intValue] == DIALOG_OK)
		{
			NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
			[defaults removeObjectForKey:AccountFriendFeedOAuthKey];
			[defaults removeObjectForKey:AccountFriendFeedOAuthSecret];
			[_textFriendFeedToken setStringValue:@""];
			[self adjustFriendFeedAuthorizeButton];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ removeFriendFeedAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG2(@"[%@ removeFriendFeedAccessToken] done", [self className]);
}

- (void)performFriendFeedAccessToken
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performFriendFeedAccessToken]", [self className]);
	@try
	{
		ServiceFriendFeed *friendFeed = (ServiceFriendFeed *)[_controller service:FriendFeed];
		if ([friendFeed access_token])
		{
			LOG(@"[%@ performFriendFeedAccessToken]\n%@\n%@", [self className], [friendFeed accessToken], [friendFeed accessTokenSecret]);
			[self performSelectorOnMainThread:@selector(setFriendFeedAccessToken)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performFriendFeedAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performFriendFeedAccessToken] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)performFriendFeedBeginWebSheet:(NSString *)path
{
	[self beginWebSheet:path
			 enabledURL:@"https://friendfeed.com/account/oauth/authorize"
			   selector:@selector(performFriendFeedAccessToken)
				 target:self
				   text:PLEASE_FRIENDFEED_AUTHORIZE];
}

- (void)performFriendFeedBeginConfirmSheet:(id)object
{
	[self beginConfirmSheetWithText:REMOVE_TOKEN
						   selector:@selector(removeFriendFeedAccessToken:)
							 target:self];
}

- (void)performFriendFeedAuthorize
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performFriendFeedAuthorize]", [self className]);
	@try
	{
		if ([[_btnFriendFeedAuthorize title] isEqualToString:AUTHORIZE])
		{
			ServiceFriendFeed *friendFeed = (ServiceFriendFeed *)[_controller service:FriendFeed];
			NSString *path = [friendFeed authorize];
			if (path)
			{
#if 1
				[self setFriendFeedAccessToken];
#else
				LOG(@"[%@ performFriendFeedAuthorize]\n%@", [self className], path);
				[self performSelectorOnMainThread:@selector(performFriendFeedBeginWebSheet:)
									   withObject:path
									waitUntilDone:YES];
#endif
			}
		}
		else
		{
			LOG2(@"[%@ performFriendFeedAuthorize] beginConfirmSheetWithText", [self className]);
			[self performSelectorOnMainThread:@selector(performFriendFeedBeginConfirmSheet:)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performFriendFeedAuthorize] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG2(@"[%@ performFriendFeedAuthorize] done", [self className]);
	[pool release];
	[NSThread exit];
}

#pragma mark OAuth of FaceBook

- (void)adjustFaceBookAuthorizeButton
{
	[self adjustAuthorizeButton:_btnFaceBookAuthorize
				withAccessToken:[self accountFaceBookOAuthToken]
						 secret:[self accountFaceBookOAuthToken]];
}

- (void)setFaceBookAccessToken
{
	LOG(@"[%@ setFaceBookAccessToken]", [self className]);
	ServiceFaceBook *faceBook = (ServiceFaceBook *)[_controller service:FaceBook];
	[_textFaceBookUser setStringValue:[faceBook userName]];
	[_textFaceBookToken setStringValue:[faceBook accessToken]];
	[self adjustFaceBookAuthorizeButton];
}

- (void)removeFaceBookAccessToken:(NSNumber *)returnCode
{
	LOG2(@"[%@ removeFaceBookAccessToken]", [self className]);
	@try
	{
		if ([returnCode intValue] == DIALOG_OK)
		{
			NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
			[defaults removeObjectForKey:AccountFaceBookOAuthToken];
			[_textFaceBookUser setStringValue:@""];
			[_textFaceBookToken setStringValue:@""];
			[self adjustFaceBookAuthorizeButton];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ removeFaceBookAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG2(@"[%@ removeFaceBookAccessToken] done", [self className]);
}

- (void)performFaceBookAccessToken
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//LOG(@"[%@ performFaceBookAccessToken]", [self className]);
	@try
	{
		NSString *url = [[[[[_webView mainFrame] dataSource] request] URL] absoluteString];
		ServiceFaceBook *faceBook = (ServiceFaceBook *)[_controller service:FaceBook];
		if ([faceBook access_token:url])
		{
			LOG(@"[%@ performFaceBookAccessToken]\n%@", [self className], [faceBook accessToken]);
			NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
			[defaults setValue:[faceBook accessToken]
						forKey:AccountFaceBookOAuthToken];
			if ([faceBook me])
			{
				[defaults setValue:[faceBook userId]
							forKey:AccountFaceBookId];
				[defaults setValue:[faceBook userName]
							forKey:AccountFaceBookUser];
				[self performSelectorOnMainThread:@selector(setFaceBookAccessToken)
									   withObject:nil
									waitUntilDone:YES];
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performFaceBookAccessToken] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performFaceBookAccessToken] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)performFaceBookBeginWebSheet:(NSString *)path
{
	[self beginWebSheet:path
			 enabledURL:@"(:?http|https)://www.facebook.com/connect/login_success.html"
			   selector:@selector(performFaceBookAccessToken)
				 target:self
				   text:PLEASE_FACEBOOK_AUTHORIZE];
}

- (void)performFaceBookBeginConfirmSheet:(id)object
{
	[self beginConfirmSheetWithText:REMOVE_TOKEN
						   selector:@selector(removeFaceBookAccessToken:)
							 target:self];
}

- (void)performFaceBookAuthorize
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	LOG2(@"[%@ performFaceBookAuthorize]", [self className]);
	@try
	{
		if ([[_btnFaceBookAuthorize title] isEqualToString:AUTHORIZE])
		{
			ServiceFaceBook *faceBook = (ServiceFaceBook *)[_controller service:FaceBook];
			NSString *path = [faceBook authorize];
			if (path)
			{
				LOG2(@"[%@ performFaceBookAuthorize]\n%@", [self className], path);
				[self performSelectorOnMainThread:@selector(performFaceBookBeginWebSheet:)
									   withObject:path
									waitUntilDone:YES];
			}
		}
		else
		{
			LOG2(@"[%@ performFaceBookAuthorize] beginConfirmSheetWithText", [self className]);
			[self performSelectorOnMainThread:@selector(performFaceBookBeginConfirmSheet:)
								   withObject:nil
								waitUntilDone:YES];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performFaceBookAuthorize] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG2(@"[%@ performFaceBookAuthorize] done", [self className]);
	[pool release];
	[NSThread exit];
}

#pragma mark Appearances utils

- (id)unarchive:(NSString *)key
{
	return [NSUnarchiver unarchiveObjectWithData:
			[[NSUserDefaults standardUserDefaults] dataForKey:key]];
}

- (NSString *)keyFromAppearanceButton:(id)object
{
	NSString *key = nil;
	if (object && ![object isKindOfClass:[NSNull class]])
	{
		NSArray *keys = [_appearanceButtons allKeysForObject:object];
		if (keys && [keys count] > 0)
		{
			key = [keys objectAtIndex:0];
		}
	}
	return key;
}

- (NSFont *)fontFromAppearanceButton:(id)object
{
	NSFont *font = nil;
	NSString *key = [self keyFromAppearanceButton:object];
	if (key)
	{
		font = [self unarchive:key];
	}
	return font;
}

- (void)setAppearanceFontButton:(id)object
{
	NSFont *font = [self fontFromAppearanceButton:object];
	if (font)
	{
		NSString *title = [NSString stringWithFormat:@"%@ %.0f", [font displayName], [font pointSize]];
		[object setTitle:title];
		[object setFont:font];
	}
}

- (NSString *)keyFromAppearanceColorButton:(id)object
{
	NSString *key = nil;
	if (object && ![object isKindOfClass:[NSNull class]])
	{
		NSArray *keys = [_appearanceColorButtons allKeysForObject:object];
		if (keys && [keys count] > 0)
		{
			key = [keys objectAtIndex:0];
		}
	}
	return key;
}

- (NSColor *)colorFromAppearanceColorButton:(id)object
{
	NSColor *color = nil;
	NSString *key = [self keyFromAppearanceColorButton:object];
	if (key)
	{
		color = [self unarchive:key];
	}
	return color;
}

- (void)setAppearanceColorButton:(id)object
{
	//LOG(@"[%@ setAppearanceColorButton]", [self className]);
	NSColor *color = [self colorFromAppearanceColorButton:object];
	if (color)
	{
		[object setColor:color];
	}
}

- (void)doAppearanceFont:(id)object
{
	NSFont *font = [self fontFromAppearanceButton:object];
	if (font)
	{
		_currentAppearance = object;
		[[NSFontManager sharedFontManager] orderFrontFontPanel:self];
		[[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
	}
}

- (NSDictionary *)buildAppearances
{
	NSDictionary *appearances = nil;
	@synchronized(self)
	{
		appearances = [[NSDictionary alloc] initWithObjectsAndKeys:
					   [NSDictionary dictionaryWithObjectsAndKeys:
						[self unarchive:AppearanceFontUser], AppearanceUser,
						[self unarchive:AppearanceFontText], AppearanceText,
						[self unarchive:AppearanceFontComment], AppearanceComment,
						[self unarchive:AppearanceFontDate], AppearanceDate,
						nil], AppearanceFont,
					   [NSDictionary dictionaryWithObjectsAndKeys:
						[NSDictionary dictionaryWithObjectsAndKeys:
						 [self unarchive:AppearanceNormalColorUser], AppearanceUser,
						 [self unarchive:AppearanceNormalColorText], AppearanceText,
						 [self unarchive:AppearanceNormalColorComment], AppearanceComment,
						 [self unarchive:AppearanceNormalColorDate], AppearanceDate,
						 [self unarchive:AppearanceNormalColorBackgraound], AppearanceBackground,
						 nil], AppearanceNormal,
						[NSDictionary dictionaryWithObjectsAndKeys:
						 [self unarchive:AppearanceChannelColorUser], AppearanceUser,
						 [self unarchive:AppearanceChannelColorText], AppearanceText,
						 [self unarchive:AppearanceChannelColorComment], AppearanceComment,
						 [self unarchive:AppearanceChannelColorDate], AppearanceDate,
						 [self unarchive:AppearanceChannelColorBackgraound], AppearanceBackground,
						 nil], AppearanceChannel,
						[NSDictionary dictionaryWithObjectsAndKeys:
						 [self unarchive:AppearanceReplyColorUser], AppearanceUser,
						 [self unarchive:AppearanceReplyColorText], AppearanceText,
						 [self unarchive:AppearanceReplyColorComment], AppearanceComment,
						 [self unarchive:AppearanceReplyColorDate], AppearanceDate,
						 [self unarchive:AppearanceReplyColorBackgraound], AppearanceBackground,
						 nil], AppearanceReply,
						[NSDictionary dictionaryWithObjectsAndKeys:
						 [self unarchive:AppearanceMessageColorUser], AppearanceUser,
						 [self unarchive:AppearanceMessageColorText], AppearanceText,
						 [self unarchive:AppearanceMessageColorComment], AppearanceComment,
						 [self unarchive:AppearanceMessageColorDate], AppearanceDate,
						 [self unarchive:AppearanceMessageColorBackgraound], AppearanceBackground,
						 nil], AppearanceMessage,
						[NSDictionary dictionaryWithObjectsAndKeys:
						 [self unarchive:AppearanceKeywordColorUser], AppearanceUser,
						 [self unarchive:AppearanceKeywordColorText], AppearanceText,
						 [self unarchive:AppearanceKeywordColorComment], AppearanceComment,
						 [self unarchive:AppearanceKeywordColorDate], AppearanceDate,
						 [self unarchive:AppearanceKeywordColorBackgraound], AppearanceBackground,
						 nil], AppearanceKeyword,
						nil], AppearanceColor,
					   nil];
	}
	return appearances;
}

- (void)makeLocalAppearances
{
	@synchronized(self)
	{
		if (_localAppearances)
		{
			[_localAppearances release];
		}
		_localAppearances = [self buildAppearances];
	}
	//LOG(@"[%@ makeLocalAppearances]\n%@", [self className], _localAppearances);
}

- (void)makeAppearances
{
	[self makeLocalAppearances];
	@synchronized(self)
	{
		if (_appearances)
		{
			[_appearances release];
		}
		_appearances = [self buildAppearances];
	}
	//LOG(@"[%@ makeAppearances]\n%@", [self className], _appearances);
}

- (void)setDateWidth
{
	@try
	{
		NSDictionary *appearances = _localAppearances;
		NSDictionary *fonts = [appearances valueForKey:AppearanceFont];
		NSFont *font = [fonts valueForKey:AppearanceDate];
		NSMutableParagraphStyle *paragraph = [[[NSMutableParagraphStyle alloc] init] autorelease];
		//[paragraph  setAlignment:NSJustifiedTextAlignment];
		[paragraph  setAlignment:NSCenterTextAlignment];
		TextFieldCell *cell = [[TextFieldCell alloc] init];
		[cell setAttributedStringValue:
		 [[[NSAttributedString alloc]
		   initWithString:@"88/88\n88:88"
		   attributes:[NSDictionary dictionaryWithObjectsAndKeys:
					   font, NSFontAttributeName,
					   paragraph, NSParagraphStyleAttributeName,
					   nil]] autorelease]];
		float width = [cell cellSizeForBounds:NSMakeRect(0, 0, 2000, 2000)].width;
		float mod = modff(width, &width);
		//LOG(@"[%@ setDateWidth]\nwidth = %f\nmod = %f\n%@", [self className], width, mod, font);
		if (mod > 0)
		{
			width += 1.0;
		}
		float diff = width - [_columnDate width];
		if (diff > 0)
		{
			[_columnText setWidth:[_columnText width] - diff];
		}
		[_columnDate setWidth:width];
		if (diff < 0)
		{
			[_columnText setWidth:[_columnText width] - diff];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ setDateWidth] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)performReloadData
{
	[_tableTimeline reloadData];
}

- (void)performReformat
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	LOG(@"[%@ reformat]", [self className]);
	@try
	{
		NSMutableArray *format = [[NSMutableArray array] retain];
		@try
		{
			@synchronized(_arrayTimeline)
			{
				[self makeLocalAppearances];
				int count = [_arrayTimeline count];
				//LOG(@"[%@ reformat]\n%@", [self className], _localAppearances);
				int i = 0;
				while (i < count)
				{
					NSMutableDictionary *obj = [NSMutableDictionary dictionaryWithDictionary:
												[_arrayTimeline objectAtIndex:0]];
					[_timeline formatText:obj
							  withService:[_controller service:[obj valueForKey:KeyService]]
							  appearances:_localAppearances];
					[obj setValue:[NSNumber numberWithInt:-1] forKey:KeyWidth];
					[format addObject:obj];
					[_arrayTimeline removeObjectAtIndex:0];
					LOG(@"[%@ reformat] %d: %p\n%@", [self className], i, obj, [obj valueForKey:KeyText]);
					i++;
				}
				//[_tableTimeline noteNumberOfRowsChanged];
				[self setDateWidth];
				//[_tableTimeline reloadData];
				i = 0;
				while (i < count)
				{
					id obj = [NSDictionary dictionaryWithDictionary:[format objectAtIndex:0]];
					//LOG(@"[%@ reformat] %d: %p\n%@", [self className], i, obj, [obj valueForKey:KeyTextDisplay]);
					[_arrayTimeline addObject:obj];
					[format removeObjectAtIndex:0];
					i++;
				}
				//[_tableTimeline noteNumberOfRowsChanged];
			}
			[self performSelectorOnMainThread:@selector(performReloadData)
								   withObject:nil
								waitUntilDone:YES];
		}
		@catch (NSException *exception)
		{
			EXPLOG(@"[%@ reformat] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
		}
		@finally
		{
			[format release];
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ reformat] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	[pool release];
	[NSThread exit];
}

- (void)reformat
{
	[NSThread detachNewThreadSelector:@selector(performReformat)
							 toTarget:self
						   withObject:nil];
}

- (void)initAppearances
{
	// Appearances
	while ([_arrayTimeline count] > 0)
	{
		[_arrayTimeline removeObjectAtIndex:0];
	}
	NSArray *timeline = [NSArray arrayWithObjects:
						 [NSDictionary dictionaryWithObjectsAndKeys:
						  @"1", KeyId,
						  @"Color", KeyUser,
						  @"", KeyName,
						  @"", KeyChannel,
						  @"Normal：通常のテキスト", KeyTextEx,
						  @"(on Comment: コメント)", KeyComment,
						  @"Notify", KeyNotifyTitle,
						  @"", KeyTextNotify,
						  @"", KeyTextDisplay,
						  @"", KeyTextDisplaySelected,
						  @"01/20\n03:05", KeyDate,
						  @"", KeyDateDisplay,
						  @"", KeyDateDisplaySelected,
						  @"<a href=\"http://afficheur.sourceforge.jp\">Afficheur</a>", KeySource,
						  KindTimeline, KeyKind,
						  GrowlAfficheurTwitterNotify, KeyNotify,
						  Twitter, KeyService,
						  [NSNumber numberWithInt:-1], KeyWidth,
						  [NSNumber numberWithInt:-1], KeyHeight,
						  nil],
						 [NSDictionary dictionaryWithObjectsAndKeys:
						  @"2", KeyId,
						  @"Channel", KeyUser,
						  @"", KeyName,
						  @"", KeyChannel,
						  @"CH：チャンネルのテキスト", KeyTextEx,
						  @"(on Comment: コメント)", KeyComment,
						  @"Notify", KeyNotifyTitle,
						  @"", KeyTextNotify,
						  @"", KeyTextDisplay,
						  @"", KeyTextDisplaySelected,
						  @"01/20\n03:05", KeyDate,
						  @"", KeyDateDisplay,
						  @"", KeyDateDisplaySelected,
						  @"<a href=\"http://afficheur.sourceforge.jp\">Afficheur</a>", KeySource,
						  KindTimeline, KeyKind,
						  GrowlAfficheurIdenticaGroupNotify, KeyNotify,
						  Identica, KeyService,
						  [NSNumber numberWithInt:-1], KeyWidth,
						  [NSNumber numberWithInt:-1], KeyHeight,
						  nil],
						 [NSDictionary dictionaryWithObjectsAndKeys:
						  @"3", KeyId,
						  @"Reply", KeyUser,
						  @"", KeyName,
						  @"", KeyChannel,
						  @"Reply：リプライのテキスト", KeyTextEx,
						  @"(on Comment: コメント)", KeyComment,
						  @"Notify", KeyNotifyTitle,
						  @"", KeyTextNotify,
						  @"", KeyTextDisplay,
						  @"", KeyTextDisplaySelected,
						  @"01/20\n03:05", KeyDate,
						  @"", KeyDateDisplay,
						  @"", KeyDateDisplaySelected,
						  @"<a href=\"http://afficheur.sourceforge.jp\">Afficheur</a>", KeySource,
						  KindReply, KeyKind,
						  GrowlAfficheurTwitterNotify, KeyNotify,
						  Twitter, KeyService,
						  [NSNumber numberWithInt:-1], KeyWidth,
						  [NSNumber numberWithInt:-1], KeyHeight,
						  nil],
						 [NSDictionary dictionaryWithObjectsAndKeys:
						  @"4", KeyId,
						  @"Direct Message", KeyUser,
						  @"", KeyName,
						  @"", KeyChannel,
						  @"DM：ダイレクトメッセージのテキスト", KeyTextEx,
						  @"(on Comment: コメント)", KeyComment,
						  @"Notify", KeyNotifyTitle,
						  @"", KeyTextNotify,
						  @"", KeyTextDisplay,
						  @"", KeyTextDisplaySelected,
						  @"01/20\n03:05", KeyDate,
						  @"", KeyDateDisplay,
						  @"", KeyDateDisplaySelected,
						  @"<a href=\"http://afficheur.sourceforge.jp\">Afficheur</a>", KeySource,
						  KindDM, KeyKind,
						  GrowlAfficheurTwitterNotify, KeyNotify,
						  Twitter, KeyService,
						  [NSNumber numberWithInt:-1], KeyWidth,
						  [NSNumber numberWithInt:-1], KeyHeight,
						  nil],
						 [NSDictionary dictionaryWithObjectsAndKeys:
						  @"5", KeyId,
						  @"Keyword", KeyUser,
						  @"", KeyName,
						  @"", KeyChannel,
						  @"Keyword：キーワードのテキスト", KeyTextEx,
						  @"(on Comment: コメント)", KeyComment,
						  @"Notify", KeyNotifyTitle,
						  @"", KeyTextNotify,
						  @"", KeyTextDisplay,
						  @"", KeyTextDisplaySelected,
						  @"01/20\n03:05", KeyDate,
						  @"", KeyDateDisplay,
						  @"", KeyDateDisplaySelected,
						  @"<a href=\"http://afficheur.sourceforge.jp\">Afficheur</a>", KeySource,
						  KindTimeline, KeyKind,
						  GrowlAfficheurKeywordsNotify, KeyNotify,
						  Twitter, KeyService,
						  [NSNumber numberWithInt:-1], KeyWidth,
						  [NSNumber numberWithInt:-1], KeyHeight,
						  nil],
						 nil];
	NSEnumerator *enumerator = [timeline objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		//LOG(@"[%@ initAppearances]\n%@", [self className], [obj valueForKey:KeyText]);
		[_arrayTimeline addObject:obj];
	}
	[self reformat];
}

#pragma mark Preferences Dialog

- (BOOL)removeFile:(NSString *)file
{
	NSFileManager *fm = [NSFileManager defaultManager];
	if ([fm fileExistsAtPath:file] && [fm isDeletableFileAtPath:file])
	{
		BOOL result = [fm removeFileAtPath:file handler:nil];
		if (!result)
		{
			LOG(@"[%@ removeFile] '%@' ERROR", [self className], file);
		}
		return result;
	}
	return YES;
}

- (BOOL)moveFile:(NSString *)srcFile toPath:(NSString *)dstFile
{
	NSFileManager *fm = [NSFileManager defaultManager];
	BOOL result = [fm movePath:srcFile toPath:dstFile handler:nil];
	if (!result)
	{
		LOG(@"[%@ moveFile] '%@' toPath:'%@' ERROR", [self className], srcFile, dstFile);
	}
	return result;
}

- (BOOL)touch:(NSString *)path
{
	NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/touch" arguments:[NSArray arrayWithObject:path]];
	if (!task)
	{
		LOG(@"[%@ touch] ERROR", [self className]);
	}
	else
	{
		[task waitUntilExit];
		int status = [task terminationStatus];
		if (status)
		{
			LOG(@"[%@ touch] ERROR %d", [self className], status);
			return NO;
		}
		return YES;
	}
	return NO;
}

- (BOOL)saveInfoPlist
{
	NSString *app = [[NSBundle mainBundle] bundlePath];
	NSString *contents = [NSString stringWithFormat:@"%@/Contents", app];
	NSString *plistName = @"Info.plist";
	NSString *tmpName = @"Info.plist~";
	NSString *bakName = @"Info.plist.bak";
	NSString *LSUIElement = @"LSUIElement";
	NSString *plistFile = [NSString stringWithFormat:@"%@/%@", contents, plistName];
	NSString *tmpFile = [NSString stringWithFormat:@"%@/%@", contents, tmpName];
	NSString *bakFile = [NSString stringWithFormat:@"%@/%@", contents, bakName];
	NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFile];
	if (!plist)
	{
		return NO;
	}
	int elm;
	if (![[NSScanner scannerWithString:[plist valueForKey:LSUIElement]] scanInt:&elm])
	{
		return NO;
	}
	BOOL dockIcon = ![self generalDockIcon];
	if (dockIcon == (elm != 0))
	{
		return YES;
	}
	[plist setValue:[NSString stringWithFormat:@"%d", dockIcon] forKey:LSUIElement];
	if (![plist writeToFile:tmpFile atomically:YES])
	{
		return NO;
	}
	if (![self removeFile:bakFile])
	{
		return NO;
	}
	if (![self moveFile:plistFile toPath:bakFile])
	{
		return NO;
	}
	if (![self moveFile:tmpFile toPath:plistFile])
	{
		[self removeFile:plistFile];
		[self moveFile:bakFile toPath:plistFile];
		return NO;
	}
	if (![self removeFile:bakFile])
	{
		return NO;
	}
	if (![self touch:app])
	{
		return NO;
	}
	return YES;
}

- (void)saveStartAtLogin
{
	NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
	NSString *Loginwindow = @"loginwindow";
	NSString *AutoLaunchedApplicationDictionary = @"AutoLaunchedApplicationDictionary";
	NSString *Path = @"Path";
	NSString *Hide = @"Hide";
	NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
	
	//loginwindowドメインのdictionaryを取得してコピー
	NSMutableDictionary *prefs = [[[defs persistentDomainForName:Loginwindow] mutableCopy] autorelease];

	if (!prefs)
	{
		LOG(@"[%@ saveStartAtLogin] ERROR !prefs", [self className]);
	}
	else
	{
		//起動項目の配列を取得してコピー
		NSMutableArray *items = [[[prefs objectForKey:AutoLaunchedApplicationDictionary] mutableCopy] autorelease];
		BOOL needSynchronize = NO;
		if (!items)
		{
			if ([self generalStartAtLogin])
			{
				items = [NSArray arrayWithObject:
						 [NSDictionary dictionaryWithObjectsAndKeys:
						  bundlePath, Path,
						  [NSNumber numberWithBool:NO], Hide,
						  nil]];
				needSynchronize = YES;
			}
		}
		else
		{
			unsigned n = [items count];
			id		item;
			int		i = 0;
			for (i = 0 ; i < n ; i++)
			{
				item = [items objectAtIndex:i];
				if ([item isKindOfClass:[NSDictionary class]])
				{
					if ([[item valueForKey:Path] isEqualToString:bundlePath])
					{
						break;
					}
				}
			}
			if ([self generalStartAtLogin])
			{
				if (i >= n)
				{
					[items addObject:[NSDictionary dictionaryWithObjectsAndKeys:
									  bundlePath, Path,
									  [NSNumber numberWithBool:NO], Hide,
									  nil]];
					needSynchronize = YES;
				}
			}
			else if (i < n)
			{
				[items removeObjectAtIndex:i];
				needSynchronize = YES;
			}
		}
		if (needSynchronize)
		{
			[prefs setObject:items forKey:AutoLaunchedApplicationDictionary];
			[defs setPersistentDomain:prefs forName:Loginwindow];
			[defs synchronize];
		}
	}
}

- (BOOL)synchronize
{
	return [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)sheetDidEnd:(NSWindow*)sheet
		 returnCode:(int)returnCode
		contextInfo:(void*)contextInfo
{
	NSEnumerator *enumerator = [[_appearanceColorButtons allValues] objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		if ([obj isActive])
		{
			[obj deactivate];
		}
	}
	NSFontPanel *fontPanel = [[NSFontManager sharedFontManager] fontPanel:NO];
	if (fontPanel)
	{
		[fontPanel orderOut:self];
	}
	if (_openColorPanel)
	{
		NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];
		if (colorPanel)
		{
			[colorPanel orderOut:self];
		}
	}
	_currentAppearance = nil;
    [sheet orderOut:self];
	[_keyEquivViewPost setEnableKeyDown:NO];
	[_keyEquivViewTimeline setEnableKeyDown:NO];
	//[[NSUserDefaults standardUserDefaults] removeObjectForKey:AccountFriendFeedPass];
    if(returnCode == DIALOG_CANCEL) {
    }
    else if(returnCode == DIALOG_OK) {
		[self sortSuggestions];
		[self sortIgnores];
		[[NSUserDefaults standardUserDefaults] setInteger:[_keyEquivViewPost keyCode]
												   forKey:GeneralHotKey];
		[[NSUserDefaults standardUserDefaults] setInteger:[_keyEquivViewTimeline keyCode]
												   forKey:GeneralHotKeyTimeline];
		//[[NSUserDefaults standardUserDefaults] setObject:[_arrayKeywords content] forKey:Keywords];
		//[[NSUserDefaults standardUserDefaults] setObject:[_arrayIgnoreKeywords content] forKey:IgnoreKeywords];
		[[NSUserDefaults standardUserDefaults] setObject:[_arrayKeywords content] forKey:ArrayKeywords];
		[[NSUserDefaults standardUserDefaults] setObject:[_arraySuggestions content] forKey:Complete];
		[[NSUserDefaults standardUserDefaults] setObject:[_arrayIgnores content] forKey:CompleteIgnore];
		[self synchronize];
		[self makeAppearances];
    }
	if (contextInfo && [(id)contextInfo isKindOfClass:[NSDictionary class]])
	{
		SEL	selector = NSSelectorFromString([(id)contextInfo valueForKey:KeySelector]);
		id	target = [(id)contextInfo valueForKey:KeyTarget];
		if (selector && target)
		{
			if ([target respondsToSelector:selector])
			{
				[target performSelector:selector];
			}
		}
	}
	if (contextInfo)
	{
		[(id)contextInfo release];
	}
}

- (void)doDialogWithWindow:(NSWindow *)window
				  selector:(SEL)selector
					target:(id)target
{
	_target = target;
	_openColorPanel = NO;
	[window makeKeyAndOrderFront:self];
	[[NSApplication sharedApplication] beginSheet:_panel
								   modalForWindow:window
									modalDelegate:self
								   didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
									  contextInfo:[[NSDictionary dictionaryWithObjectsAndKeys:
													NSStringFromSelector(selector), KeySelector,
													target, KeyTarget,
													nil] retain]];
	if (_openFirst)
	{
		_openFirst = NO;
		if (_panelToolBar)
		{
			[_panelToolBar release];
		}
		_panelToolBar = [[NSToolbar alloc] initWithIdentifier:IdToolBar];
		[_panelToolBar setDelegate:self];
		[_panel setToolbar:_panelToolBar];
	}
}

#pragma mark NSApplication interface

- (void)applicationDidFinishLaunching
{
	// HotKey
	[_textFieldPost setIsLeopard:[_controller isLeopard]];
	[_textFieldTimeline setIsLeopard:[_controller isLeopard]];
	
	// Appearances
	[self initAppearances];

	// Jaiku
	[self adjustJaikuAuthorizeButton];
	
	// Twitter
	[self adjustTwitterAuthorizeButton];
	[self rateLimitHelper:nil];
	
	// FriendFeed
	[self adjustFriendFeedAuthorizeButton];
	
	// facebook
	[self adjustFaceBookAuthorizeButton];
	
	LOG(@"[%@ applicationDidFinishLaunching]", [self className]);
}

- (void)applicationWillTerminate
{
	[self saveInfoPlist];
	[self saveStartAtLogin];
}

#pragma mark NSObject Delegates

- (void)awakeFromNib
{
	//LOG(@"[%@ awakeFromNib]", [self className]);
	//LOG(@"[%@ awakeFromNib]\n%@", [self className], [_arrayTimeline className]);
	// Accounts
	if (!_accounts)
	{
		_accounts = [[NSArray alloc] initWithObjects:
					 _viewTwitter,
					 _viewJaiku,
					 _viewTumblr,
//					 _viewNowa,
					 _viewWassr,
					 _viewIdentica,
//					 _viewJisko,
//					 _viewChuitter,
					 _viewFriendFeed,
					 _viewFaceBook,
					 _viewBitLy,
					 nil];
	}
	while ([[_arrayAccount content] count] > 0)
	{
		[_arrayAccount removeObjectAtIndex:0];
	}
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"bit.ly", @"service", nil]
		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"facebook", @"service", nil]
		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"FriendFeed", @"service", nil]
		  atArrangedObjectIndex:0];
//	[_arrayAccount insertObject:
//	 [NSDictionary dictionaryWithObjectsAndKeys:@"chuitter", @"service", nil]
//		  atArrangedObjectIndex:0];
//	[_arrayAccount insertObject:
//	 [NSDictionary dictionaryWithObjectsAndKeys:@"Jisko", @"service", nil]
//		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"Identi.ca", @"service", nil]
		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"Wassr", @"service", nil]
		  atArrangedObjectIndex:0];
//	[_arrayAccount insertObject:
//	 [NSDictionary dictionaryWithObjectsAndKeys:@"nowa", @"service", nil]
//		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"Tumblr", @"service", nil]
		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"Jaiku", @"service", nil]
		  atArrangedObjectIndex:0];
	[_arrayAccount insertObject:
	 [NSDictionary dictionaryWithObjectsAndKeys:@"Twitter", @"service", nil]
		  atArrangedObjectIndex:0];
	[self tableView:_tableAccount shouldSelectRow:0];
	// Appearances
	NSArray *columns = [_tableTimeline tableColumns];
	_columnText = [columns objectAtIndex:0];
	_columnDate = [columns objectAtIndex:1];
	if (!_appearanceButtons)
	{
		_appearanceButtons = [[NSDictionary alloc] initWithObjectsAndKeys:
							  _btnAppearanceUser,		AppearanceFontUser,
							  _btnAppearanceText,		AppearanceFontText,
							  _btnAppearanceComment,	AppearanceFontComment,
							  _btnAppearanceDate,		AppearanceFontDate,
							  nil];
	}
	NSEnumerator *enumerator = [[_appearanceButtons allValues] objectEnumerator];
	id button;
	while ((button = [enumerator nextObject]))
	{
		[self setAppearanceFontButton:button];
	}
	_appearanceColorButtons = [[NSDictionary alloc] initWithObjectsAndKeys:
							   _btnAppearanceColorUser,			AppearanceNormalColorUser,
							   _btnAppearanceColorText,			AppearanceNormalColorText,
							   _btnAppearanceColorComment,		AppearanceNormalColorComment,
							   _btnAppearanceColorDate,			AppearanceNormalColorDate,
							   _btnAppearanceColorBackground,	AppearanceNormalColorBackgraound,
							   _btnAppearanceReplyUser,			AppearanceReplyColorUser,
							   _btnAppearanceReplyText,			AppearanceReplyColorText,
							   _btnAppearanceReplyComment,		AppearanceReplyColorComment,
							   _btnAppearanceReplyDate,			AppearanceReplyColorDate,
							   _btnAppearanceReplyBackground,	AppearanceReplyColorBackgraound,
							   _btnAppearanceChannelUser,		AppearanceChannelColorUser,
							   _btnAppearanceChannelText,		AppearanceChannelColorText,
							   _btnAppearanceChannelComment,	AppearanceChannelColorComment,
							   _btnAppearanceChannelDate,		AppearanceChannelColorDate,
							   _btnAppearanceChannelBackground,	AppearanceChannelColorBackgraound,
							   _btnAppearanceMessageUser,		AppearanceMessageColorUser,
							   _btnAppearanceMessageText,		AppearanceMessageColorText,
							   _btnAppearanceMessageComment,	AppearanceMessageColorComment,
							   _btnAppearanceMessageDate,		AppearanceMessageColorDate,
							   _btnAppearanceMessageBackground,	AppearanceMessageColorBackgraound,
							   _btnAppearanceKeywordUser,		AppearanceKeywordColorUser,
							   _btnAppearanceKeywordText,		AppearanceKeywordColorText,
							   _btnAppearanceKeywordComment,	AppearanceKeywordColorComment,
							   _btnAppearanceKeywordDate,		AppearanceKeywordColorDate,
							   _btnAppearanceKeywordBackground,	AppearanceKeywordColorBackgraound,
							   nil];
	enumerator = [[_appearanceColorButtons allValues] objectEnumerator];
	while ((button = [enumerator nextObject]))
	{
		[self setAppearanceColorButton:button];
	}
	[self makeAppearances];
	
	// General
	NSMutableParagraphStyle *style = [[[NSMutableParagraphStyle alloc] init] autorelease];
	[style setAlignment:NSRightTextAlignment];
//	NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys:
//						  [_label font], NSFontAttributeName,
//						  [style copy], NSParagraphStyleAttributeName,
//						  @"http://api.jaiku.com/", NSLinkAttributeName,
//						  nil];
//	NSAttributedString* str = [[[NSAttributedString alloc]
//								initWithString:API_KEY attributes:attr] autorelease];
//	[_jaikuAPI setSelectable:YES];
//	[_jaikuAPI setEditable:YES];
//	[_jaikuAPI setString:@""];
//	[_jaikuAPI insertText:str];
//	[_jaikuAPI setEditable:NO];
	
//	attr = [NSDictionary dictionaryWithObjectsAndKeys:
//			[_label font], NSFontAttributeName,
//			[style copy], NSParagraphStyleAttributeName,
//			@"http://my.nowa.jp/config/account/api_auth", NSLinkAttributeName,
//			nil];
//	str = [[[NSAttributedString alloc] initWithString:@"API Password" attributes:attr] autorelease];
//	[_nowaAPI setSelectable:YES];
//	[_nowaAPI setEditable:YES];
//	[_nowaAPI setString:@""];
//	[_nowaAPI insertText:str];
//	[_nowaAPI setEditable:NO];
	
//	NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys:
//						  [_label font], NSFontAttributeName,
//					//	  [style copy], NSParagraphStyleAttributeName,
//						  style, NSParagraphStyleAttributeName,
//						  @"http://jisko.net/settings/config", NSLinkAttributeName,
//						  nil];
//	NSAttributedString* str = [[[NSAttributedString alloc]
//								initWithString:API_KEY attributes:attr] autorelease];
//	[_jiskoAPI setSelectable:YES];
//	[_jiskoAPI setEditable:YES];
//	[_jiskoAPI setString:@""];
//	[_jiskoAPI insertText:str];
//	[_jiskoAPI setEditable:NO];
	
	_openFirst = YES;
	_currentItem = @"";
	[_keyEquivViewPost setTextField:_textFieldPost];
	[_keyEquivViewPost setKeyCode:[self generalHotKey]];
	[_keyEquivViewTimeline setTextField:_textFieldTimeline];
	[_keyEquivViewTimeline setKeyCode:[self generalHotKeyTimeline]];
	
	// Keywords
	//while ([[_arrayKeywords content] count] > 0)
	//{
	//	[_arrayKeywords removeObjectAtArrangedObjectIndex:0];
	//}
	NSArray *keywords = [[NSUserDefaults standardUserDefaults] arrayForKey:Keywords];
	//if (keywords)
	//{
	//	NSEnumerator *enumerator = [keywords objectEnumerator];
	//	id obj;
	//	while ((obj = [enumerator nextObject]))
	//	{
	//		[[_arrayKeywords content] addObject:obj];
	//	}
	//}
	//[_arrayKeywords rearrangeObjects];
	
	// IgnoreKeywords
	while ([[_arrayIgnoreKeywords content] count] > 0)
	{
		[_arrayIgnoreKeywords removeObjectAtArrangedObjectIndex:0];
	}
	NSArray *ignoreKeywords = [[NSUserDefaults standardUserDefaults] arrayForKey:IgnoreKeywords];
	if (ignoreKeywords)
	{
		NSEnumerator *enumerator = [ignoreKeywords objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			[[_arrayIgnoreKeywords content] addObject:obj];
		}
	}
	[_arrayIgnoreKeywords rearrangeObjects];
	
	while ([[_arrayKeywords content] count] > 0)
	{
		[_arrayKeywords removeObjectAtArrangedObjectIndex:0];
	}
	NSArray *arrayKeywords = [[NSUserDefaults standardUserDefaults] arrayForKey:ArrayKeywords];
	if (arrayKeywords)
	{
		NSEnumerator *enumerator = [arrayKeywords objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			[[_arrayKeywords content] addObject:obj];
		}
	}
	else if (keywords)
	{
		NSEnumerator *enumerator = [keywords objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:
										[obj objectForKey:Keyword], Keyword, nil];
			[dic setValue:[NSNumber numberWithBool:YES] forKey:KeywordEnable];
			[dic setValue:[NSNumber numberWithInt:1] forKey:Rule];
			[dic setValue:[NSNumber numberWithInt:0] forKey:NoGrowl];
			[dic setValue:[NSNumber numberWithInt:0] forKey:NoTimeline];
			NSMutableArray *array = [NSMutableArray arrayWithObject:
									 [NSDictionary dictionaryWithObjectsAndKeys:
									  [obj objectForKey:Keyword], Keyword,
									  [NSNumber numberWithInt:0], Rule,
									  nil]];
			if (ignoreKeywords)
			{
				NSEnumerator *enumerator = [ignoreKeywords objectEnumerator];
				id ignore;
				while ((ignore = [enumerator nextObject]))
				{
					[array addObject:[NSDictionary dictionaryWithObjectsAndKeys:
									  [ignore objectForKey:Keyword], Keyword,
									  [NSNumber numberWithInt:1], Rule,
									  nil]];
				}
			}
			[dic setValue:array forKey:RuleArray];
			LOG(@"[%@ awakeFromNib]\n%@", [self className], dic);
			[[_arrayKeywords content] addObject:dic];
		}
	}
	[_arrayKeywords rearrangeObjects];
	
	// Suggestions
	[self loadSuggestions];
	[self loadIgnores];
	[_arraySuggestions setTableView:_tableSuggestions];
	[_tableSuggestions registerForDraggedTypes:[NSArray arrayWithObjects:
												NSStringPboardType,
												nil]];
	[_tableSuggestions setDraggingSourceOperationMask:NSDragOperationMove forLocal:YES];
	[_arrayIgnores setTableView:_tableIgnores];
	[_tableIgnores registerForDraggedTypes:[NSArray arrayWithObjects:
											NSStringPboardType,
											nil]];
	[_tableIgnores setDraggingSourceOperationMask:NSDragOperationMove forLocal:YES];
	[_tableKeyword setDoubleAction:@selector(onKeywordDoubleClicked:)];
}

- (void)changeFont:(id)sender
{
	//LOG(@"[%@ changeFont]\n%@", [self className], sender);
	if (_currentAppearance)
	{
		NSFont *font = [self fontFromAppearanceButton:_currentAppearance];
		NSString *key = [self keyFromAppearanceButton:_currentAppearance];
		if (font)
		{
			LOG(@"[%@ changeFont] key\n%@", [self className], key);
			LOG(@"[%@ changeFont] font\n%@", [self className], font);
			NSFont *newFont = [sender convertFont:font];
			if (![newFont isEqualTo:font])
			{
				[[NSUserDefaults standardUserDefaults]
				 setObject:[NSArchiver archivedDataWithRootObject:newFont]
				 forKey:key];
				LOG(@"[%@ changeFont] font\n%@", [self className], [self unarchive:key]);
				[self setAppearanceFontButton:_currentAppearance];
				[self reformat];
			}
		}
	}
}

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
	//LOG(@"[%@ validateMenuItem] %p", [self className], menuItem);
	int rateLimit = [self rateLimitOfTwitter];
	if ([menuItem menu] ==  [_popupIntervalTimeline menu])
	{
		//LOG(@"[%@ validateMenuItem] Timeline", [self className]);
		return [self validateMenuItem:menuItem
					  withPopupButton:_popupIntervalTimeline
							rateLimit:rateLimit];
	}
	else if ([menuItem menu] ==  [_popupIntervalReplies menu])
	{
		//LOG(@"[%@ validateMenuItem] Replies", [self className]);
		return [self validateMenuItem:menuItem
					  withPopupButton:_popupIntervalReplies
							rateLimit:rateLimit];
	}
	else if ([menuItem menu] == [_popupIntervalDM menu])
	{
		//LOG(@"[%@ validateMenuItem] DM", [self className]);
		return [self validateMenuItem:menuItem
					  withPopupButton:_popupIntervalDM
							rateLimit:rateLimit];
	}
	return YES;
}

#pragma mark NSToolbar methods

- (NSString *)label:(NSString *)key
{
	return [[NSDictionary dictionaryWithObjectsAndKeys:
			 GENERAL,			IdGeneral,
			 HOTKEY,			IdHotKeys,
			 ACCOUNT,			IdAccount,
			 KEYWORDS,			IdKeyword,
			 SUGGESTION,		IdSuggestion,
			 APPEARANCES,		IdAppearance,
			 nil]
			valueForKey:key];
}

- (NSString *)imageName:(NSString *)key
{
	return [[NSDictionary dictionaryWithObjectsAndKeys:
			 @"PreferencesGeneral",	IdGeneral,
			 @"Advanced",			IdHotKeys,
			 @"UserAccounts",		IdAccount,
			 @"Keywords",			IdKeyword,
			 @"Suggestions",		IdSuggestion,
			 @"Appearances",		IdAppearance,
			 nil]
			valueForKey:key];
}

- (void)onSelectTab:(NSToolbarItem *)sender
{
	NSString* itemId = [sender itemIdentifier];
	[_panel setTitle:[self label:itemId]];
	[_panelToolBar setSelectedItemIdentifier:itemId];
	id view = nil;
	if ([itemId isEqual:IdGeneral])
	{
		view = _viewGeneral;
	}
	else if ([itemId isEqual:IdHotKeys])
	{
		view = _viewHotKeys;
	}
	else if ([itemId isEqual:IdAccount])
	{
		view = _viewAccount;
	}
	else if ([itemId isEqual:IdKeyword])
	{
		view = _viewKeyword;
	}
	else if ([itemId isEqual:IdSuggestion])
	{
		view = _viewSuggestion;
	}
	else if ([itemId isEqual:IdAppearance])
	{
		view = _viewAppearance;
	}
	if (view && (![_currentItem isEqual:itemId]))
	{
		_currentItem = itemId;
		NSRect	bounds = [view bounds];
		NSRect	aFrame = [_panel frameRectForContentRect:bounds];
		int		x = [_panel frame].origin.x + ([_panel frame].size.width - aFrame.size.width) / 2;
		int		y = [_panel frame].origin.y + ([_panel frame].size.height - aFrame.size.height);
		NSRect	rect = NSMakeRect(x, y, aFrame.size.width, aFrame.size.height);
		NSTimeInterval interval = [_panel animationResizeTime:rect];
		[_panel autorecalculatesKeyViewLoop];//recalculateKeyViewLoop];
		[_panel setContentView:_viewNil];
		[_panel setFrame:rect display:YES animate:YES];
		[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(setView:) userInfo:view repeats:false];
	}
}

- (void)setView:(NSTimer *)theTimer
{
	if (theTimer && theTimer.userInfo)
	{
		[_panel setContentView:theTimer.userInfo];
		[_panel recalculateKeyViewLoop];
		[_panel selectKeyViewFollowingView:theTimer.userInfo];
	}
}

#pragma mark NSToolbar Delegates

- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
{
	return [NSArray arrayWithObjects:
			IdGeneral,
			IdHotKeys,
			IdAccount,
			IdKeyword,
			IdSuggestion,
			IdAppearance,
			nil];
}

- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
	return [self toolbarDefaultItemIdentifiers:toolbar];
}

- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
	return [self toolbarDefaultItemIdentifiers:toolbar];
}

- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
	 itemForItemIdentifier:(NSString *)itemIdentifier
 willBeInsertedIntoToolbar:(BOOL)flag
{
	NSString* label = [self label:itemIdentifier];
	if (!label)
	{
		return nil;
	}
	NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
	[item setTarget:self];
	[item setAction:@selector(onSelectTab:)];
	[item setLabel:label];
	[item setImage:[NSImage imageNamed:[self imageName:itemIdentifier]]];
	if ([itemIdentifier isEqual:IdGeneral])
	{
		[self onSelectTab:item];
	}
	return item;
}

#pragma mark NSWindow Delegates

- (id)windowWillReturnFieldEditor:(NSWindow *)sender
						 toObject:(id)anObject
{
	if ([anObject isKindOfClass:[KeyEquivField class]])
	{
		//LOG(@"[%@ windowWillReturnFieldEditor]\n%@", [self className], sender);
		//LOG(@"[%@ windowWillReturnFieldEditor]\n%@", [self className], anObject);
		//LOG(@"[%@ windowWillReturnFieldEditor]\n%p", [self className], _textFieldPost);
		//LOG(@"[%@ windowWillReturnFieldEditor]\n%p", [self className], _textFieldTimeline);
		if ([anObject isEqual:_textFieldPost])
		{
			return _keyEquivViewPost;
		}
		else if ([anObject isEqual:_textFieldTimeline])
		{
			return _keyEquivViewTimeline;
		}
	}
	return nil;
}

#pragma mark NSTableView Delegates

- (BOOL)tableView:(NSTableView *)aTableView
  shouldSelectRow:(int)rowIndex
{
	//LOG(@"[%@ shouldSelectRow] %d", [self className], rowIndex);
	if ([aTableView isEqual:_tableAccount])
	{
		//LOG(@"[%@ shouldSelectRow] Account", [self className]);
		if (rowIndex < [_accounts count])
		{
			[_boxAccount setContentView:[_accounts objectAtIndex:rowIndex]];
			[_panel recalculateKeyViewLoop];
			return YES;
		}
		return NO;
	}
	return YES;
}

- (float)tableView:(NSTableView *)tableView
	   heightOfRow:(int)row
{
	if (![tableView isEqualTo:_tableTimeline])
	{
		return [tableView rowHeight];
	}
	float height = 42;
	@synchronized(_arrayTimeline)
	{
		if (row < [_arrayTimeline count])
		{
			NSDictionary *item = [_arrayTimeline objectAtIndex:row];
			@try
			{
				float width = [_columnText width];
				float itemWidth = [[item valueForKey:KeyWidth] floatValue];
				if ((itemWidth < 0) || (itemWidth != width))
				{
					NSMutableDictionary *obj = [NSMutableDictionary dictionaryWithDictionary:item];
					NSCell *cell = [_columnText dataCell];
					[cell setAttributedStringValue:[item valueForKey:KeyTextDisplay]];
					height = [cell cellSizeForBounds:NSMakeRect(0, 0, width, 2000)].height;
					[obj setValue:[NSNumber numberWithFloat:width] forKey:KeyWidth];
					[obj setValue:[NSNumber numberWithFloat:height] forKey:KeyHeight];
					[_arrayTimeline replaceObjectAtIndex:row withObject:obj];
				}
				else
				{
					height = [[item valueForKey:KeyHeight] floatValue];
				}
				float min = 40;
				if (height < min)
				{
					height = min;
				}
				if (index < 0)
				{
					LOG(@"[%@ heightOfRow]!!!\n%@", [self className], item);
				}
			}
			@catch (NSException *exception)
			{
				EXPLOG(@"[%@ heightOfRow] EXCEPTION\n%@: %@\n%@", [self className], [exception name], [exception reason], [item valueForKey:KeyService]);
			}
		}
	}
	return height + 2;
}

- (void)tableView:(NSTableView *)aTableView
  willDisplayCell:(id)aCell
   forTableColumn:(NSTableColumn *)aTableColumn
			  row:(int)rowIndex
{
	if (![aTableView isEqualTo:_tableTimeline])
	{
		return;
	}
	@synchronized(_arrayTimeline)
	{
		if (rowIndex < [_arrayTimeline count])
		{
			NSDictionary *item = [_arrayTimeline objectAtIndex:rowIndex];
			@try
			{
				int selected = [aTableView selectedRow];
				if (item)
				{
					NSDictionary *colors = [_localAppearances valueForKey:AppearanceColor];
					NSDictionary *color = [_timeline appearanceColor:item withColors:colors];
					if ((selected < 0) || (selected != rowIndex))
					{
						[aCell setDrawsBackground:YES];
						[aCell setBackgroundColor:[color valueForKey:AppearanceBackground]];
					}
					else
					{
						[aCell setDrawsBackground:NO];
					}
				}
			}
			@catch (NSException *exception)
			{
				EXPLOG(@"[%@ willDisplayCell] EXCEPTION\n%@: %@\n%@", [self className], [exception name], [exception reason], [item valueForKey:KeyService]);
			}
		}
	}
}

#pragma mark NSTableDataSource Protocols

- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
	//LOG(@"[%@ numberOfRowsInTableView]", [self className]);
	if ([aTableView isEqualTo:_tableTimeline])
	{
		if ([_arrayTimeline respondsToSelector:@selector(count)])
		{
			return [_arrayTimeline count];
		}
	}
	return 0;
}

- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
			row:(int)rowIndex
{
	//LOG(@"[%@ objectValueForTableColumn]", [self className]);
	id obj = @"";
	@synchronized(_arrayTimeline)
	{
		if (rowIndex < [_arrayTimeline count])
		{
			NSDictionary *item = [_arrayTimeline objectAtIndex:rowIndex];
			@try
			{
				int selected = [aTableView selectedRow];
				if (item)
				{
					if ((selected < 0) || (selected != rowIndex))
					{
						if ([aTableColumn isEqual:_columnText])
						{
							obj = [item valueForKey:KeyTextDisplay];
						}
						else if ([aTableColumn isEqual:_columnDate])
						{
							obj = [item valueForKey:KeyDateDisplay];
						}
					}
					else
					{
						if ([aTableColumn isEqual:_columnText])
						{
							obj = [item valueForKey:KeyTextDisplaySelected];
						}
						else if ([aTableColumn isEqual:_columnDate])
						{
							obj = [item valueForKey:KeyDateDisplaySelected];
						}
					}
				}
			}
			@catch (NSException *exception)
			{
				EXPLOG(@"[%@ objectValueForTableColumn] EXCEPTION\n%@: %@\n%@", [self className], [exception name], [exception reason], [item valueForKey:KeyService]);
			}
		}
	}
	return obj;
}

#pragma mark NSTokenField Delegates

- (NSTokenStyle)tokenField:(NSTokenField *)tokenField
 styleForRepresentedObject:(id)representedObject
{
	NSArray *array = nil;
	if ([tokenField isEqual:_tokenBrowser])
	{
		array = _arrayBrowser;
	}
	else if ([tokenField isEqual:_tokenITunes])
	{
		array = _arrayITunes;
	}
	if (array)
	{
		NSEnumerator *enumerator = [array objectEnumerator];
		id obj;
		while ((obj = [enumerator nextObject]))
		{
			if ([representedObject rangeOfString:obj].length > 0)
			{
				return NSRoundedTokenStyle;
			}
		}
		return NSPlainTextTokenStyle;
	}
	return NSRoundedTokenStyle;
}

#pragma mark ColorWell Delegates

- (void)changeColorWell:(id)sender
{
	LOG(@"[%@ changeColorWell]\n%@", [self className], sender);
	NSEnumerator *enumerator = [[_appearanceColorButtons allValues] objectEnumerator];
	id obj;
	while ((obj = [enumerator nextObject]))
	{
		if ([obj isActive] || [obj isEqualTo:sender])
		{
			NSColor *color = [self colorFromAppearanceColorButton:obj];
			NSString *key = [self keyFromAppearanceColorButton:obj];
			LOG(@"[%@ changeColorWell]\nkey: %@\ncolor: %@", [self className], key, color);
			if (key)
			{
				NSColor *newColor = [sender color];
				if (![newColor isEqualTo:color])
				{
					[[NSUserDefaults standardUserDefaults]
					 setObject:[NSArchiver archivedDataWithRootObject:newColor]
					 forKey:key];
					LOG(@"[%@ changeColorWell]\nnew color: %@\n%@", [self className], newColor, [self unarchive:key]);
					[self reformat];
				}
			}
			break;
		}
	}
}

#pragma mark WebFrameLoadDelegate Delegates

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
	LOG2(@"[%@ didFinishLoadForFrame]\n%@", [self className], [[frame dataSource] request]);
	NSString *url = [[[[frame dataSource] request] URL] absoluteString];
	NSArray *array = [url componentsSeparatedByString:@"#"];
	if ([array count] > 0)
	{
		url = [array objectAtIndex:0];
	}
	LOG2(@"[%@ didFinishLoadForFrame]\n%@", [self className], url);
	if ([url lengthOfRegularExpression:_enabledURL] > 0)
	{
		[_webOK setEnabled:YES];
	}
}

#pragma mark IBActions

- (IBAction)onOK:(id)sender
{
    [[NSApplication sharedApplication] endSheet:_panel returnCode:DIALOG_OK];
}

- (IBAction)onCancel:(id)sender
{
    [[NSApplication sharedApplication] endSheet:_panel returnCode:DIALOG_CANCEL];
}

- (IBAction)onClearPost:(id)sender
{
	[_keyEquivViewPost setKeyCode:-1];
}

- (IBAction)onClearTimeline:(id)sender
{
	[_keyEquivViewTimeline setKeyCode:-1];
}

- (IBAction)onMenuIcon:(id)sender
{
	if (_target && [_target respondsToSelector:@selector(setMenuIcon:)])
	{
		[_target performSelector:@selector(setMenuIcon:)
					  withObject:[NSNumber numberWithInt:0]];
	}
}

- (IBAction)onMenuIconAlternate:(id)sender
{
	if (_target && [_target respondsToSelector:@selector(setMenuIcon:)])
	{
		[_target performSelector:@selector(setMenuIcon:)
					  withObject:[NSNumber numberWithInt:1]];
	}
}

- (IBAction)onAppearanceFont:(id)sender
{
	LOG(@"[%@ onAppearanceFont]\n%@", [self className], sender);
	[self doAppearanceFont:sender];
}

- (IBAction)onAppearanceColor:(id)sender
{
	LOG(@"[%@ onAppearanceColor]\n%@", [self className], sender);
	_openColorPanel = YES;
}

- (IBAction)onPopupInterval:(id)sender
{
	LOG(@"[%@ onPopupInterval]\n%@", [self className], sender);
	[self updateLabelRequests:[self timesIntervals]
				withRateLimit:[self rateLimitOfTwitter]];
	[self adjustRateLimit:sender
			withRateLimit:[self rateLimitOfTwitter]];
}

- (IBAction)onJaikuAuthorize:(id)sender
{
	[NSThread detachNewThreadSelector:@selector(performJaikuAuthorize)
							 toTarget:self
						   withObject:nil];
}

- (IBAction)onTwitterAuthorize:(id)sender
{
	[NSThread detachNewThreadSelector:@selector(performTwitterAuthorize)
							 toTarget:self
						   withObject:nil];
}

- (IBAction)onTumblrAuthorize:(id)sender
{
//	[NSThread detachNewThreadSelector:@selector(performTumblrAuthorize)
//							 toTarget:self
//						   withObject:nil];
}

- (IBAction)onFriendFeedAuthorize:(id)sender
{
	[NSThread detachNewThreadSelector:@selector(performFriendFeedAuthorize)
							 toTarget:self
						   withObject:nil];
}

- (IBAction)onFaceBookAuthorize:(id)sender
{
	[NSThread detachNewThreadSelector:@selector(performFaceBookAuthorize)
							 toTarget:self
						   withObject:nil];
}

- (IBAction)onWebOK:(id)sender
{
	LOG(@"[%@ onWebOK]\n%@", [self className], sender);
    [[NSApplication sharedApplication] endSheet:_panelWeb returnCode:DIALOG_OK];
}

- (IBAction)onWebCancel:(id)sender
{
	LOG(@"[%@ onWebCancel]\n%@", [self className], sender);
    [[NSApplication sharedApplication] endSheet:_panelWeb returnCode:DIALOG_CANCEL];
}

- (IBAction)onConfirmOK:(id)sender
{
	LOG(@"[%@ onConfirmOK]\n%@", [self className], sender);
    [[NSApplication sharedApplication] endSheet:_panelConfirm returnCode:DIALOG_OK];
}

- (IBAction)onConfirmCancel:(id)sender
{
	LOG(@"[%@ onConfirmCancel]\n%@", [self className], sender);
    [[NSApplication sharedApplication] endSheet:_panelConfirm returnCode:DIALOG_CANCEL];
}

- (void)keywordSheetDidEnd:(NSWindow*)sheet
				returnCode:(int)returnCode
			   contextInfo:(void*)contextInfo
{
	LOG(@"[%@ keywordSheetDidEnd] %d", [self className], returnCode);
	@try
	{
		[sheet orderOut:self];
		if (returnCode == DIALOG_OK)
		{
			NSMutableArray *rules = [NSMutableArray arrayWithObjects:nil];
			NSEnumerator *enumerator = [[_arrayRule arrangedObjects] objectEnumerator];
			id rule;
			while ((rule = [enumerator nextObject]))
			{
				[rules addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
								  [rule objectForKey:Keyword], Keyword,
								  [rule objectForKey:Rule], Rule,
								  nil]];
			}
			NSMutableDictionary *keyword = [NSMutableDictionary dictionaryWithObjectsAndKeys:
											[_dicRule objectForKey:Keyword], Keyword,
											[_dicRule objectForKey:Rule], Rule,
											rules, RuleArray,
											[_dicRule objectForKey:NoGrowl], NoGrowl,
											[_dicRule objectForKey:NoTimeline], NoTimeline,
											nil];
			int select = [_tableKeyword selectedRow];
			if (contextInfo)
			{
				id info = (id)contextInfo;
				if ([info isKindOfClass:[self class]])
				{
					[keyword setValue:[NSNumber numberWithBool:YES]
							   forKey:KeywordEnable];
					[_arrayKeywords addObject:keyword];
					[_arrayKeywords rearrangeObjects];
					[_tableKeyword deselectRow:[[_arrayKeywords arrangedObjects] count] - 1];
				}
				else if ((select >= 0) && (select < [[_arrayKeywords arrangedObjects] count]))
				{
					id obj = [[_arrayKeywords arrangedObjects] objectAtIndex:select];
					[keyword setValue:[obj valueForKey:KeywordEnable]
							   forKey:KeywordEnable];
					[_arrayKeywords removeObjectAtArrangedObjectIndex:select];
					[_arrayKeywords insertObject:keyword atArrangedObjectIndex:select];
					[_arrayKeywords rearrangeObjects];
				}
			}
			else if ((select >= 0) && (select < [[_arrayKeywords arrangedObjects] count]))
			{
				[_arrayKeywords removeObjectAtArrangedObjectIndex:select];
				[_arrayKeywords insertObject:keyword atArrangedObjectIndex:select];
				[_arrayKeywords rearrangeObjects];
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ keywordSheetDidEnd] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (IBAction)onKeywordAdd:(id)sender
{
	[self onKeywordDoubleClicked:self];
}

- (IBAction)onKeywordDoubleClicked:(id)sender
{
	LOG(@"[%@ onKeywordDoubleClicked]\n%@", [self className], sender);
	int select = [_tableKeyword selectedRow];
	if ([sender isKindOfClass:[self class]])
	{
		while ([[_arrayRule content] count] > 0)
		{
			[_arrayRule removeObjectAtArrangedObjectIndex:0];
		}
		[_arrayRule rearrangeObjects];
		[_dicRule setValue:@"" forKey:Keyword];
		[_dicRule setValue:[NSNumber numberWithInt:0] forKey:Rule];
		[_dicRule setValue:[NSNumber numberWithBool:NO] forKey:NoGrowl];
		[_dicRule setValue:[NSNumber numberWithBool:NO] forKey:NoTimeline];
		[[NSApplication sharedApplication] beginSheet:_panelKeyword
									   modalForWindow:_panel
										modalDelegate:self
									   didEndSelector:@selector(keywordSheetDidEnd:returnCode:contextInfo:)
										  contextInfo:sender];
	}
	else if ((select >= 0) && (select < [[_arrayKeywords arrangedObjects] count]))
	{
		id obj = [[_arrayKeywords arrangedObjects] objectAtIndex:select];
		while ([[_arrayRule content] count] > 0)
		{
			[_arrayRule removeObjectAtArrangedObjectIndex:0];
		}
		NSArray *rules = [obj objectForKey:RuleArray];
		NSEnumerator *enumerator = [rules objectEnumerator];
		id rule;
		while ((rule = [enumerator nextObject]))
		{
			[_arrayRule addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
								   [rule objectForKey:Keyword], Keyword,
								   [rule objectForKey:Rule], Rule,
								   nil]];
		}
		[_arrayRule rearrangeObjects];
		[_tableRule deselectRow:-1];
		[_dicRule setValue:[obj objectForKey:Keyword] forKey:Keyword];
		[_dicRule setValue:[obj objectForKey:Rule] forKey:Rule];
		[_dicRule setValue:[obj objectForKey:NoGrowl] forKey:NoGrowl];
		[_dicRule setValue:[obj objectForKey:NoTimeline] forKey:NoTimeline];
		[[NSApplication sharedApplication] beginSheet:_panelKeyword
									   modalForWindow:_panel
										modalDelegate:self
									   didEndSelector:@selector(keywordSheetDidEnd:returnCode:contextInfo:)
										  contextInfo:sender];
	}
}

- (IBAction)onKeywordOK:(id)sender
{
	LOG(@"[%@ onKeywordOK]\n%@", [self className], sender);
    [[NSApplication sharedApplication] endSheet:_panelKeyword returnCode:DIALOG_OK];
}

- (IBAction)onKeywordCancel:(id)sender
{
	LOG(@"[%@ onKeywordCancel]\n%@", [self className], sender);
    [[NSApplication sharedApplication] endSheet:_panelKeyword returnCode:DIALOG_CANCEL];
}

@end
