
var URL_DEP = null;

function DEPChk( url ) {
	if( URL_DEP == null ) {
		var loc = ( window.location + "" ).replace( /http(s)?:\/\//i , '' );
		var m = null;
		if( m = loc.match( /^(.+)\.mixer\.pl/i ) ) {
			URL_DEP = m[1];
		} else {
			URL_DEP = false;
		}
	}
	if( URL_DEP ) {
		var i = url.indexOf( URL_DEP );
		if( i != 7 && i != 8 ) {
			url = url.replace( /^(https?:\/\/)/ , '$1' + URL_DEP + '.' );
		}
	}
	return url;
}


function UrlNick( nick ) {
	return "http://" + nick + ".mixer.pl/";
}

var URL_BASE                 = "http://mixer.pl/";
var URL_API                  = "http://mixer.pl/api/";
var URL_IMAGES               = "http://mixer.pl/img/dbw.1046/";
 

// auth
var URL_LOGIN                = DEPChk('http://mixer.pl/api/zaloguj/');
var URL_LOGOUT               = DEPChk('http://mixer.pl/api/wyloguj/');
var URL_CHANGEAUTOLOGIN      = DEPChk('http://mixer.pl/api/wylacz-auto-login/');
var URL_CREATE_USER          = DEPChk('http://mixer.pl/nowe-konto/');

// user
var URL_SUBSCRIBE            = DEPChk('http://mixer.pl/api/stworz-konto/');
var URL_USER_QUESTION        = DEPChk('http://mixer.pl/api/pobierz-pytanie/');
var URL_USER_ANSWERE         = DEPChk('http://mixer.pl/api/odpowiedz-na-pytanie/');
var URL_CHANGEPASS           = DEPChk('http://mixer.pl/api/zmiana-hasla/');
var URL_CHANGEEMAIL          = DEPChk('http://mixer.pl/api/zmiana-adresu-email/');
var URL_CHANGEQUESTION       = DEPChk('http://mixer.pl/api/zmiana-pytania-pomocniczego/');
var URL_CHANGELANG           = DEPChk('http://mixer.pl/api/zmiana-jezyka/');
var URL_USER_INVITE          = DEPChk('http://mixer.pl/api/email-zaproszenie/');
var URL_ACTIVATE_USER        = DEPChk('http://mixer.pl/potwierdzenie-rejestracji/');
var URL_DEACTIVATE_USER      = DEPChk('http://mixer.pl/odrzucanie-rejestracji/');

// profile
var URL_PROFILE_API          = DEPChk('http://mixer.pl/api/profil/');
var URL_PROFILE_SETTINGS     = DEPChk('http://mixer.pl/api/moje-profile/');
var URL_JS_PROFILE_WWW       = DEPChk('http://mixer.pl/js/strony-www/');
var URL_PROFILE_WWW          = DEPChk('http://mixer.pl/api/strony-www/');
var URL_PROFILE_DATA         = DEPChk('http://mixer.pl/js/edycja-profilu/');
var URL_PROFILE_SAVE         = DEPChk('http://mixer.pl/api/edycja-profilu/');
var URL_PROFILE_SHOW         = DEPChk('http://mixer.pl/profil/');
var URL_PROFILE_TEST         = DEPChk('http://mixer.pl/test-profilu/');
var URL_PROFILE_EDIT         = DEPChk('http://mixer.pl/edycja-profilu/');
var URL_PROFILE_VIEW         = DEPChk('http://mixer.pl/wyglad-profilu/');
var URL_JS_PROFILE_VIEW      = DEPChk('http://mixer.pl/js/wyglad-profilu/');
var PROFILE_ALIEN_MODE       = "alien-mode";

// guest book
var URL_GBOOK_API            = DEPChk('http://mixer.pl/api/ksiega-gosci/');
var URL_GBOOK_PAGE           = DEPChk('http://mixer.pl/strona-ksiegi-gosci/');

var URL_BLOG_API             = DEPChk('http://mixer.pl/api/blog/');
var URL_BLOG_DATA            = DEPChk('http://mixer.pl/js/blog-data/');

// contacts
var URL_ADD_CONTACT          = DEPChk('http://mixer.pl/api/dodaj-kontakt/');
var URL_EDIT_CONTACT         = DEPChk('http://mixer.pl/edycja-kontaktu/');
var URL_CONTACTS_SETTINGS    = DEPChk('http://mixer.pl/api/ustawienia-kontaktow/');
var URL_CONTACT_INFO_SAVE    = DEPChk('http://mixer.pl/api/edycja-kontaktu/');
var URL_CONTACTS_LIST        = DEPChk('http://mixer.pl/js/ustawienia-kontaktow/');
var URL_CONTACT_VIEW         = DEPChk('http://mixer.pl/kontakt/');
var URL_CONTACT_EDIT         = DEPChk('http://mixer.pl/edycja-kontaktu/');
var URL_CONTACTS_API         = DEPChk('http://mixer.pl/api/lista-kontaktow/');
var URL_CONTACTS_SEARCH      = DEPChk('http://mixer.pl/js/szukaj-znajomych/');
var URL_PROFILE_CONTACTS     = DEPChk('http://mixer.pl/przegladaj-kontakty/');

var URL_MSG_API              = DEPChk('http://mixer.pl/api/skrzynka-kontaktowa/');
var URL_MSG_JS               = DEPChk('http://mixer.pl/js/skrzynka-kontaktowa/');

var URL_MSG_TO               = DEPChk('http://mixer.pl/wiadomosc/napisz-do/');
var URL_MSG_REPLY            = DEPChk('http://mixer.pl/wiadomosc/odpowiedz/');
var URL_MSG_REPLYALL         = DEPChk('http://mixer.pl/wiadomosc/odpowiedz-wszystkim/');
var URL_MSG_FORWARD          = DEPChk('http://mixer.pl/wiadomosc/przekaz/');
var URL_MSG_DRAFT            = DEPChk('http://mixer.pl/wiadomosc/kontynuuj-pisanie/');
var URL_MSG_THREAD           = DEPChk('http://mixer.pl/watek-wiadomosci/');
var URL_MSG_HISTORY          = DEPChk('http://mixer.pl/historia-wiadomosci/');
var URL_MSG_BOX              = DEPChk('http://mixer.pl/skrzynka-kontaktowa/');

// files
var URL_FILES_API            = DEPChk('http://mixer.pl/api/pliki/');
var URL_FILES_JS             = DEPChk('http://mixer.pl/js/pliki/');
var URL_GET_FILE             = DEPChk('http://mixer.pl/plik/pobierz/');
var URL_SHOW_FILE            = DEPChk('http://mixer.pl/plik/pokaz/');
var URL_FILES_LIST           = DEPChk('http://mixer.pl/pliki/wszystkie/');
var URL_FILES_UPLOAD         = DEPChk('http://mixer.pl/upload-plikow/');
var URL_SHOW_IMAGE           = DEPChk('http://mixer.pl/pliki/obrazy/');
var URL_SHOW_AUDIO           = DEPChk('http://mixer.pl/pliki/audio/');
var URL_SHOW_VIDEO           = DEPChk('http://mixer.pl/pliki/video/');

// galleries
var URL_GALLERY              = DEPChk('http://mixer.pl/galerie/');

// search
var URL_SEARCH               = DEPChk('http://mixer.pl/wyszukiwarka/');

var URL_STORAGE              = new Array( );

URL_STORAGE.push( "http://i1.mixer.pl" );

URL_STORAGE.push( "http://i2.mixer.pl" );
var STORAGE_CNT              = 0;


var FICONS = {
	image : {
		original:0,
		icon:1,
		square:2,
		lsquare:3,
		thumb:4,
		small:5,
		medium:6,
		large:7
	},
	video:{
		original:0,
		icon:9,
		square:10,
		lsquare:11,
		mini_image:12,
		image:13,
		mini_movie:14,
		movie:15
	},
	audio:{
		original:0,
		audio:16
	},
	archive:{original:0},
	text:{original:0},
	unknown:{original:0}
};

function FileURL( dsmid , id , icon , type ) {
	if( URL_STORAGE.length == 0 ) {
		throw new Error("Brak serwerow skladowania plikow.");
	}
	if( isString( icon ) && isString( type ) && FICONS[type] && isNumber( FICONS[type][icon] ) ) {
		icon = FICONS[type][icon];
	} else {
		icon = '0';
	}
	if( STORAGE_CNT >= URL_STORAGE.length ) {
		STORAGE_CNT = 0;
	}
	var url = URL_STORAGE[STORAGE_CNT] + '/' + dsmid + '/0/' + icon + '/' + id + '/';
	++STORAGE_CNT;
	return url;
}




var USER_LOGIN_MIN_LENGTH = 3;
var USER_LOGIN_MAX_LENGTH = 32;
var USER_PASS_MIN_LENGTH  = 4;
var USER_ACTIVATION_MAIL  = true;






var lang_errors                      = new Array( );

lang_errors['bad_input']             = "Błąd danych...";

// main
lang_errors['unknown_command']       = "Błąd systemowy: niepoprawne zapytanie (nieznane polecenie)";
lang_errors['access']                = "Brak dostępu";

// auth
lang_errors['login_bad_pass']        = "Niepoprawne hasło lub nazwa użytkownika";
lang_errors['login_banned']          = "Konto jest zablokowane";
lang_errors['login_inactive']        = "Konto nie jest jeszcze aktywne. Aktywuj konto poprzez link wysłany na twój adres email.";
lang_errors['already_logged_in']     = "Niedozwolona próba ponownego zalogowania.";
lang_errors['user_not_logged']       = "Aby wykonać operację musisz się zalogować.";
lang_errors['access_denied']         = "Brak dostępu. Sprawdź czy jesteś zalogowany/a.";

// user
lang_errors['pass_length']           = "Niepoprawna długość hasła.";
lang_errors['pass_match']            = "Hasło niepoprawnie powtórzone";
lang_errors['login_length']          = "Niepoprawna długość nazwy użytkownika.";
lang_errors['login_incorrect']       = "Niepoprawna nazwa użytkownika.";
lang_errors['email_incorrect']       = "Niepoprawny adres email.";
lang_errors['user_exists']           = "Podana nazwa użytkownika jest już używana.";
lang_errors['user_not_exists']       = "Podany użytkownik nie istnieje.";
lang_errors['email_exists']          = "Podany adres e-mail został już zarejestrowany w bazie danych.";
lang_errors['bad_question']          = "Niepoprawne pytanie.";
lang_errors['bad_answere']           = "Niepoprawna odpowiedź.";
lang_errors['question_length']       = "Niepoprawna długość pytania.";
lang_errors['answer_length']         = "Niepoprawna długość odpowiedzi.";
lang_errors['answere_not_match']     = "Podana odpowiedź nie jest poprawna";
lang_errors['user_question_not_set'] = "Pytanie odzyskiwania hasła dla podanego użytkownika nie zostało ustawione. Odzyskanie hasła nie jest moźliwe.";
lang_errors['user_answere_not_set']  = "Odpowiedź na pytanie odzyskiwania hasła dla podanego użytkownika nie została ustawiona. Odzyskanie hasła nie jest moźliwe.";
lang_errors['question_error_new']    = "Konto nie zostało jeszcze aktywowane. Nie można odzyskać hasła. Aby korzystać z serwisu aktywuj konto wchodząc na adres podany w wiadomości e-mail wysłanej na adres podany podczas rejestracji.";
lang_errors['question_error_banned'] = "Konto zostało zablokowane przez administratora. Nie można odzyskać hasła.";
lang_errors['bad_language']          = "Niepoprawny język.";
lang_errors['userAddressIncorr']     = "Adres email nie zgadza się z adresem zaproszenia za pomocą którego chcesz się zarejestrować.";
lang_errors['userKeyIncorr']         = "Klucz z zaproszenia do serwisu z którym próbujesz się zarejestrować jest niepoprawny.";

// profile
lang_errors['bad_nickname']          = "Niepoprawna nazwa wyświetlana. Nazwa wyświetlana może mieć od 3 do 64 znaków.";
lang_errors['profile_www_url_length']= "Adres zbyt długi.";
lang_errors['profile_www_bad_url']   = "Niepoprawny adres.";
lang_errors['profile_www_name']      = "Zbyt długa nazwa.";
lang_errors['profile_www_desc']      = "Zbyt długi opis.";
lang_errors['bad_birthday']          = "Niepoprawna data urodzin. Data powinna być w formacie RRRR-MM-DD gdzie RRRR oznacza rok w postaci 4 cyfrowej, MM miesiąc przedstawiony 2 cyframi, a DD dzień miesiąca w postaci 2 cyfr";
lang_errors['im_name']               = "Niepoprawna nazwa komunikatora.";
lang_errors['im_uin']                = "Niepoprawny identyfikator.";
lang_errors['profile_rate']          = "Już oceniałeś/aś ten profil!";
lang_errors['profile_date_incorrect']= "Niepoprawna data początkowa.";
lang_errors['profile_access_denied'] = "Brak dostępu. Sprawdź czy jesteś zalogowany/a."
lang_errors['profile_file_inorrect'] = "Niepoprawny plik zdjęcia lub serwer zdjęć jest zajęty i nie może teraz przyjąć zdjęcia. Przyjmowane formaty zdjęć: jpg, png, gif."

// contacts
lang_errors['contact_not_exists']    = "Kontakt nie istnieje, nie znajduje się na Twojej liście kontaktów lub nie jest zaakceptowany.";
lang_errors['search_keywords']       = "Wpisz słowa do wyszukania. Słowa krótsze niż 3 znaki zostaną odrzucone.";
lang_errors['user_invited']          = "Osoba którą chcesz zaprosić znajduje się już na Twojej liście kontaktów lub zaproszeń.";
lang_errors['select_recipients']     = "Wybierz odbiorców wiadomości.";
lang_errors['message_content']       = "Brak tytułu i treści wiadomości."
lang_errors['message_not_exists']    = "";

// msgbox
lang_errors['folder_name']           = "Niepoprawna nazwa folderu.";

// files
lang_errors['photo_mimetype']           = "Niepoprawny format zdjęcia. Obsługiwane obrazy: *.jpg, *.gif, *.png";
lang_errors['filename_length']          = "Zbyt długa nazwa pliku. Nazwa pliku może mieć maksymalnie 255 znaków.";
lang_errors['filename_invalid']         = "Niepoprawna nazwa pliku.";
lang_errors['files_cpy_not_selected']   = "Zaznacz pliki do skopiowania.";
lang_errors['select_profiles']          = "Nie zaznaczono żadnego profilu.";
lang_errors['no_files_chosen_file']     = "Nie wybrano żadnych plików!";
lang_errors['no_files_chosen_gallery']  = "Nie wybrano żadnych zdjęć!";
lang_errors['upload_file']              = "Niektórych plików nie udało się przesłać na serwer. Prawdopodobnie były za duże. Spróbuj spakować pliki i wysłać ponownie.";
lang_errors['upload_gallery']           = "Niektórych zdjęć nie udało się umieścić w galerii. Były w złym formacie lub zbyt duże. Akceptowane formaty to: JPEG, GIF i PNG.";
lang_errors['no_folders_to_create']     = "Brak katalogów do utworzenia!";
lang_errors['create_dir_gallery']       = "Wystąpiły błędy podczas tworzenia niektórych galerii. Sprawdż czy podane nazwy są poprawne i czy jest zalogowany/a.";
lang_errors['create_dir_file']          = "Wystąpiły błędy podczas tworzenia niektórych katalogów. Sprawdż czy podane nazwy są poprawne i czy jest zalogowany/a.";
lang_errors['upload_limit_file']        = "Limit plików przesyłanych jednocześnie na serwer(15) został osiągnięty!";
lang_errors['upload_limit_gallery']     = "Limit zdjęć przesyłanych jednocześnie na serwer(15) został osiągnięty!";
lang_errors['upload_limit_dir_file']    = "Limit tworzonych jednocześnie folderów(15) został osiągnięty!";
lang_errors['upload_limit_dir_gallery'] = "Limit tworzonych jednocześnie galerii(15) został osiągnięty!";
lang_errors['no_files_selected_gallery']= "Zaznacz zdjęcia!";
lang_errors['no_files_selected_file']   = "Zaznacz pliki!";
lang_errors['files_wrong_name']         = "Niepoprawna nazwa. Nazwa musi być podana i nie może mieć więcej niż 128 znaków.";
lang_errors['files_wrong_artist']       = "Niepoprawne pole wykonawca. Pole może zawierać maksymalnie 128 znaków.";
lang_errors['files_wrong_album']        = "Niepoprawne pole album. Pole album może zawierać maksymalnie 128 znaków.";
lang_errors['files_wrong_title']        = "Niepoprawne pole tytuł. Pole tytuł może zawierać maksymalnie 128 znaków.";
lang_errors['files_choose_pic']         = "Wybierz zdjęcie.";

//blogs
lang_errors['blog_title_length']        = "Tytuł jest za długi: maksymalna długość to 128 znaków.";
lang_errors['blog_error']               = "BŁĄD";

//settings
lang_errors['profile_id_info']          = "ID Profilu moze składać się tylko z liter a-z (bez polskich znaków), cyfr 0-9, znaków `.` i `-`. Znaki `.` i `-` nie mogą znajdować się ani na początku ani na końcu.";
lang_errors['profile_id_info_length']   = "ID Profilu nie może być krótsze niż 3 znaki i dłuższe niż 25.";

//guestbook
lang_errors['guestbook_error']          = "Wystąpił błąd wewnętrzny serwisu. Przeładuj stronę aby kontynuować.";


var LANG = "pl";


var WEEK_DAYS = new Array(
					"Niedziela",
					"Poniedziałek",
					"Wtorek",
					"Środa",
					"Czwartek",
					"Piątek",
					"Sobota"
				);
var WEEK_DAYS_SHORT = new Array( 
	'Nd',
	'Pn',
	'Wt',
	'Śr',
	'Cz',
	'Pt',
	'So'
);
				
var MONTHS = new Array(
	'Styczeń',
	'Luty',
	'Marzec',
	'Kwiecień',
	'Maj',
	'Czerwiec',
	'Lipiec',
	'Sierpień',
	'Wrzesień',
	'Październik',
	'Listopad',
	'Grudzień'
);

var MONTHS_SHORT = new Array( 
	'Sty',
	'Lut',
	'Mar',
	'Kwi',
	'Maj',
	'Cze',
	'Lip',
	'Sie',
	'Wrz',
	'Paź',
	'Lis',
	'Gru'
);


// basic lang variables
var lang_yes              = "tak";
var lang_no               = "nie";
var lang_cancel           = "anuluj";
var lang_close            = "zamknij";
var lang_move             = "przenieś";
var lang_progress         = "przesyłanie danych...";
var lang_settingsSaved    = "Ustawienia zostały zapisane.";
var lang_saveSettingsP    = "Zapisywanie ustawień...";
var lang_desc             = "Opis";

// auth

lang_loginP               = "logowanie do systemu...";
lang_logoutP              = "wylogowywanie z systemu...";

// user

var lang_user_created          = "";
var lang_user_created_login    = "";
var lang_changeQuestion        = "Pytanie pomocnicze i odpowiedź zostały zmienione.";
var lang_changePassword        = "Hasło zostało zmienione.";
var lang_changeEmail           = "Adres email został zmieniony.";
var lang_changeLang            = "Język został zmieniony";

// profile - tabs

var lang_tabAll                = "Wszystkie";
var lang_tabBasic              = "Podstawowy";
var lang_tabAnonymus           = "Anonimowy";
var lang_tabErotic             = "Przygodowo-randkowy";

// profile


var lang_wwwListGetP           = "Pobieranie listy adresów.";
var lang_wwwAddURLP            = "Dodawanie adresu.";
var lang_profileWWWDeleteQ     = "Napewno chcesz usunąć ten adres?";
var lang_profileWWWDeleteP     = "Usuwanie adresu.";
var lang_imRemoveQ             = "Napewno usunąć ten komunikator?";
var lang_emailRemoveQ          = "Napewno usunąć ten adres email?";
var lang_profileRateP          = "Wysyłanie oceny...";


var lang_profileSaving         = "Zapisywanie...";
var lang_profileCommName       = "Podaj nazwę komunikatora.";
var lang_profileCommId         = "Podaj identyfikator.";
var lang_profileWriteMotto     = "Wpisz treść motta.";
var lang_profileEventBegin     = "Wyznacz początek zdarzenia.";
var lang_profileWriteDesc      = "Wpisz opis.";
var lang_profileFileSending    = "Przesyłanie pliku...";
var lang_profileIdask          = "Uwaga!! ID Profilu nie będzie można później zmienić!!! Czy napewno utworzyć profil?";
var lang_profileCreating       = "Tworzenie profilu...";
var lang_profileGGError        = "Błędny identyfikator gadu-gadu";
var lang_profileSkypeError     = "Błędny identyfikator skype";
var lang_profileTlenError      = "Niepoprawny identyfikator tlenu. Poprawny format to: nick@tlen.pl lub nick@o2.pl lub nick@go2.pl";
var lang_profileIdToShort      = "Podany identyfikator jest za krótki";
var lang_profilePostCodeIncorr = "Niepoprawny kod pocztowy";
var lang_profilePhoneIncorr    = "Niepoprawny numer telefonu stacjonarnego";               
var lang_profileMobileIncorr   = "Niepoprawny numer telefonu komórkowego"; 

// contacts

var lang_addContactP           = "Dodawanie kontaktu...";
var lang_getContactsListP      = "Pobieranie listy kontaktów...";
var lang_removeContactQ        = "Czy jesteś pewien/na że chcesz usunąć ten kontakt?";
var lang_removeContactP        = "Usuwanie kontaktu";
var lang_contactsSearchP       = "Pobieranie wyników wyszukiwania...";
var lang_inviteP               = "Zapraszanie użytkownika do listy znajomych...";
var lang_contactAdded          = "Użytkownik został dodany do listy twoich znajomych.";
var lang_contactInvited        = "Użytkownik został zaproszony do listy twoich znajomych.";
var lang_favouriteAsk          = "Czy napewno usunąć kontakt z listy ulubionych?";
var lang_favouriteInfo         = "Ten profil jest już dodany do Twoich ulubionych.";
var lang_favouriteAdd          = "Dodawanie do ulubionych.";
var lang_favouriteAddInfo      = "Profil został dodany do ulubionych";
var lang_favouriteBreak        = "Przerwa techniczna. Przepraszamy. Spróbuj za jakiś czas.";

var lang_contactBtnWrite       = "napisz do";
var lang_contactBtnGallery     = "galerie";
var lang_contactBtnAllFiles    = "wszystkie pliki";
var lang_contactBtnList        = "lista kontaktów";
var lang_contactBtnEdit        = "edytuj kontakt";
var lang_contactBtnTrash       = "kosz";

//invites
var lang_invitesEmail          = "Adres email znajomego:";
var lang_invitesEmailWrite     = "Wpisz poprawne adresy znajomych których chcesz zaprosić.";
var lang_invitesSending        = "Wysyłanie zaproszenia ";
var lang_invitesEmailsSent     = "Zaproszenia zostały wysłane na adresy: ";
var lang_invitesErrorSent      = "Nie można wysłać zaproszenia do ";
var lang_invitesReason         = "Powód: ";
var lang_invitesSent           = "Wysłano zaproszenia.";
var lang_invitesBreak          = "Przerwa techniczna. Przepraszamy. Spróbuj później.";

var lang_inviteWrite           = "Wpisz treść zaproszenia.";
var lang_inviteProfileChoose   = "Wybierz swój profil do którego zamierzasz zaprosić.";
var lang_inviteWasAdd          = "Użytkownik został dodany do Twojej listy znajomych.";
var lang_inviteWasSend         = "Zaproszenie zostało wysłane.";
var lang_inviteInfo            = "Zaproszenie zostało zapisane i zostanie wysłane po utworzeniu konta. Jeśli nie chcesz aby serwis pamiętał to zaproszenie wciśnij przycisk 'anuluj' - w przeciwnym wypadku bedzie ono zapamiętane aż do zamknięcia przeglądarki (lub rejestracji w serwisie - wtedy zostanie wysłane).";

var lang_inviteTxt             = "Treść zaproszenia:";
var lang_inviteTxtFrom         = "Od:";
var lang_inviteDate            = "Data:";
var lang_inviteReceive         = "Przyjmij/odrzuć:";
var lang_inviteEmpty           = "brak treści zaproszenia...";
var lang_inviteAccept          = "akceptuj";
var lang_inviteRefuse          = "odrzuć";

// msgbox

var lang_folderListGetP        = "Pobieranie listy folderów...";
var lang_folderCreateP         = "Tworzenie folderu...";
var lang_folderSaveP           = "Zapisywanie nazwy folderu...";
var lang_folderRemoveQ         = "Napewno usunąć folder?";
var lang_folderMsgRemoveQ      = "Usunąć wszystkie wiadomości znajdujące się w folderze?";
var lang_folderRemoveP         = "Usuwanie folderu...";
var lang_sendMessageP          = "Wysyłanie wiadomości...";
var lang_saveMessageP          = "Zapisywanie wiadomości...";
var lang_messageSent           = "Wiadomość została wysłana.";
var lang_messageSaved          = "Wiadomość została zapisana w folderze wiadomości tymczasowych.";
var lang_getMsgBodyP           = "Pobieranie treści wiadomości...";
var lang_removeSelectedMSGSQ   = "Czy napewno usunąć zaznaczone wiadomości?";
var lang_removeMSGQ            = "Czy napewno usunąć wiadomość?";
var lang_removeMSGSP           = "Usuwanie wiadomości...";
var lang_removeMSGP            = "Usuwanie wiadomości...";
var lang_undeleteMSGP          = "Przywracanie wiadomości...";
var lang_noMessageSelectedW    = "Nie zaznaczono żadnej wiadomości.";
var lang_getMSGSListP          = "Pobieranie listy wiadomości z serwera...";
var lang_moveMSGTo             = "Przenieś wiadomość do:";
var lang_moveMSGSTo            = "Przenieś wiadomości do:";
var lang_msgMovingP            = "Przenoszenie wiadomości...";
var lang_msgTo                 = "Do:";
var lang_anonTitle             = "Wpisz temat wiadomości.";
var lang_anonTextWrite         = "Wpisz treść wiadomości.";
var lang_anonSending           = "Wysyłanie wiadomości...";
var lang_msgBtnEdit            = "edytuj";
var lang_msgBtnAnswer          = "odpowiedz";
var lang_msgBtnAnswerAll       = "odpowiedz wszystkim";
var lang_msgBtnTransfer        = "przekaż";
var lang_msgBtnMove            = "przenieś";
var lang_msgBtnRestore         = "przywróć";
var lang_msgBtnDelete          = "usuń";
var lang_msgBtnAddRecipent     = "dodaj odbiorcę";
var lang_msgBtnDelRecipent     = "usuń odbiorcę";
var lang_msgBtnChangeName      = "zmień nazwę";


// files

var lang_copyingFilesP         = "Kopiowanie plików...";
var lang_copyingImagesP        = "Kopiowanie zdjęć...";
var lang_filesCopied           = "Pliki zostały skopiowane.";
var lang_imagesCopied          = "Zdjęcia zostały skopiowane.";
var lang_loadingFilesP         = "Pobieranie listy plików z serwera...";
var lang_fieldFile             = "Plik";
var lang_fieldImage            = "Zdjęcie";
var lang_fileStatusWait        = "oczekiwanie";
var lang_fileStatusOk          = "ok";
var lang_fileStatusError       = "błąd";
var lang_fileDeleting          = "Usuwanie zdjęcia...";
var lang_uploadImageTitle      = "Przesyłanie zdjęć (może potrwać kilka minut)!";
var lang_uploadFileTitle       = "Przesyłanie plików (może potrwać kilka minut)!";
var lang_uploadFoldersTitle    = "Tworzenie folderów";
var lang_uploadGalleryTitle    = "Tworzenie galerii";
var lang_uploadImageFinished   = "Przesyłanie zdjęć zakończone"
var lang_uploadFileFinished    = "Przesyłanie plików zakończone";
var lang_uploadFolderFinished  = "Tworzenie katalogów zakończone";
var lang_uploadGalleryFinished = "Tworzenie galerii zakończone";
var lang_dirNameFieldGallery   = "Nazwa galerii";
var lang_dirNameFieldFile      = "Nazwa katalogu";
var lang_imagesMovingP         = "Przenoszenie zdjęć...";
var lang_imagesMoved           = "Zdjęcia zostały przeniesione.";
var lang_filesMovingP          = "Przenoszenie plików...";
var lang_filesMoved            = "Pliki zostały przeniesione.";
var lang_accessSavingP         = "Zapisywanie praw...";
var lang_accessSaved           = "Prawa zostały zapisane.";
var lang_savingDescP           = "Zapisywanie...";
var lang_removeSelFilesQ       = "Czy napewno usunąć zaznaczone pliki?";
var lang_removeSelImgsQ        = "Czy napewno usunąć zaznaczone zdjęcia?";
var lang_removeDirContentQ     = "Czy usunąć całą zawartość folderu? Jeśli wybierzesz NIE pliki zawarte w folderze zostaną przeniesione do folderu głównego.";
var lang_removeGalContentQ     = "Czy usunąć całą zawartość galerii? Jeśli wybierzesz NIE zdjęcia zawarte w galerii zostaną przeniesione do katalogu głównego.";
var lang_removeGalQ            = "Czy napewno usunąć galerię?";
var lang_removeDirQ            = "Czy napewno usunąć folder?";
var lang_removingP             = "Usuwanie...";
var lang_removeImageQ          = "Czy napewno usunąć zdjęcie?";
var lang_removeFileQ           = "Czy napewno usunąć plik?";
var lang_convertedStatus       = "wszystko ok, plik niekonwertowalny";
var lang_convertedError        = "wystapily błedy podczas konwersji, plik nie będzie skonwertowany";
var lang_convertedWait         = "plik czeka na konwersję";
var lang_convertedPlay         = "plik odtwarzalny";
var lang_waitInfo              = "Pliki audio/wideo oczekują na konwersję aby można było je odtwarzać";
var lang_filesBtnEnter         = "wejdź";
var lang_filesBtnOut           = "wyjdź";
var lang_filesBtnShow          = "pokaż";                    
var lang_filesBtnDownload      = "pobierz";
var lang_filesBtnBtnCpyMv      = "kopiuj/przenieś";
var lang_filesBtnEditName      = "edytuj nazwę";
var lang_filesBtnEditAccess    = "edytuj prawa";
var lang_filesBtnDelete        = "usuń";


// blogs

var lang_blogDel               = "<span>Usuń</span>";
var lang_blogDownload          = "Pobieranie danych...";
var lang_blogTitle             = "Wpisz tytuł.";
var lang_blogCreate            = "Tworzenie nowego wpisu...";
var lang_blogSaving            = "Zapisywanie tytułu...";
var lang_blogDelAsk            = "Czy napewno chcesz usunąć wpis?";
var lang_blogDelReg            = "Usuwanie wpisu...";
var lang_blogPublish           = "Publikowanie wpisu...";
var lang_blogPublishAsk        = "Czy napewno opublikować wpis?";
var lang_blogAddingText        = "Dodawanie tekstu...";
var lang_blogSavingText        = "Zapisywanie tekstu...";
var lang_blogDelFileAsk        = "Czy napewno usunąć plik?";
var lang_blogMarkDelAsk        = "Czy napewno usunąć zaznaczone pliki?";
var lang_blogDeletingFiles     = "Usuwanie plików...";
var lang_blogAddingFiles       = "Wstawianie plików...";
var lang_blogMarkFiles         = "Zaznacz pliki do wstawienia.";
var lang_blogFileSent          = "Przesyłanie pliku zakończone.";
var lang_blogChooseFile        = "Wybierz plik do przesłania.";
var lang_blogFileSending       = "Przesyłanie pliku (może potrwać kilka minut)!";
var lang_blogMove              = "przesuń";
var lang_blogRegEdit           = "edytuj wpis";
var lang_blogRegDel            = "usuń wpis";
var lang_blogBtnEdit           = "edytuj";
var lang_blogBtnDel            = "usuń";
var lang_blogTextInfo          = "Wpisz tekst!";
var lang_blogTextVar1          = "wpis";
var lang_blogTextVar2          = "wpisy";
var lang_blogTextVar3          = "wpisów";

// guestbook
var lang_guestbookAddNew       = "Dodaj nowy wpis";
var lang_guestbookHideEditor   = "Ukryj edytor wpisu";
var lang_guestbookChooseProf   = "Wybierz swój profil.";
var lang_guestbookTextWrite    = "Wpisz treść wpisu.";
var lang_guestbookSending      = "Wysyłanie wpisu...";
var lang_guestbookRegAsk       = "Czy napewno usunąć wpis?";
var lang_guestbookRegDel       = "Usuwanie wpisu...";
var lang_guestbookDownloading  = "Pobieranie strony...";

// search
var lang_searchMinAge          = "Podaj dolna granice wieku.";
var lang_searchMaxAge   	   = "Podaj górną granice wieku.";
var lang_searchMax_Height	   = "Podaj maksymalny wzrost.";
var lang_searchSearching       = "Wyszukiwanie...";
var lang_searchCriterion	   = "Podaj kryteria wyszukiwania.";
var lang_searchDownloading	   = "Pobieranie strony...";
/*  Prototype JavaScript framework, version 1.5.1
 *  (c) 2005-2007 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.5.1',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      (document.createElement('div').__proto__ !==
       document.createElement('form').__proto__)
  },

  ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
  JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  toJSON: function(object) {
    var type = typeof object;
    switch(type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }
    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (object.ownerDocument === document) return;
    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (value !== undefined)
        results.push(property.toJSON() + ': ' + value);
    }
    return '{' + results.join(', ') + '}';
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({}, object);
  }
});

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $A(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [event || window.event].concat(args));
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    return this.toPaddedString(2, 16);
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  },

  toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  },

  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});

Date.prototype.toJSON = function() {
  return '"' + this.getFullYear() + '-' +
    (this.getMonth() + 1).toPaddedString(2) + '-' +
    this.getDate().toPaddedString(2) + 'T' +
    this.getHours().toPaddedString(2) + ':' +
    this.getMinutes().toPaddedString(2) + ':' +
    this.getSeconds().toPaddedString(2) + '"';
};

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback(this);
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var self = arguments.callee;
    self.text.data = this;
    return self.div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  },

  toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return {};

    return match[1].split(separator || '&').inject({}, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (hash[key].constructor != Array) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  },

  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  times: function(count) {
    var result = '';
    for (var i = 0; i < count; i++) result += this;
    return result;
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  },

  toJSON: function() {
    return this.inspect(true);
  },

  unfilterJSON: function(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  },

  evalJSON: function(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
        return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  },

  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },

  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },

  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },

  empty: function() {
    return this == '';
  },

  blank: function() {
    return /^\s*$/.test(this);
  }
});

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

String.prototype.parseQuery = String.prototype.toQueryParams;

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

with (String.prototype.escapeHTML) div.appendChild(text);

var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + String.interpret(object[match[3]]);
    });
  }
}

var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        iterator(value, index++);
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  },

  eachSlice: function(number, iterator) {
    var index = -number, slices = [], array = this.toArray();
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.map(iterator);
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = false;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push((iterator || Prototype.K)(value, index));
    });
    return results;
  },

  detect: function(iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inGroupsOf: function(number, fillWith) {
    fillWith = fillWith === undefined ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.map(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.map();
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  size: function() {
    return this.toArray().length;
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}

if (Prototype.Browser.WebKit) {
  $A = Array.from = function(iterable) {
    if (!iterable) return [];
    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
      iterable.toArray) {
      return iterable.toArray();
    } else {
      var results = [];
      for (var i = 0, length = iterable.length; i < length; i++)
        results.push(iterable[i]);
      return results;
    }
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0, length = this.length; i < length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  },

  clone: function() {
    return [].concat(this);
  },

  size: function() {
    return this.length;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  },

  toJSON: function() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (value !== undefined) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }
});

Array.prototype.toArray = Array.prototype.clone;

function $w(string) {
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if (Prototype.Browser.Opera){
  Array.prototype.concat = function() {
    var array = [];
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for (var i = 0, length = arguments.length; i < length; i++) {
      if (arguments[i].constructor == Array) {
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
          array.push(arguments[i][j]);
      } else {
        array.push(arguments[i]);
      }
    }
    return array;
  }
}
var Hash = function(object) {
  if (object instanceof Hash) this.merge(object);
  else Object.extend(this, object || {});
};

Object.extend(Hash, {
  toQueryString: function(obj) {
    var parts = [];
    parts.add = arguments.callee.addPair;

    this.prototype._each.call(obj, function(pair) {
      if (!pair.key) return;
      var value = pair.value;

      if (value && typeof value == 'object') {
        if (value.constructor == Array) value.each(function(value) {
          parts.add(pair.key, value);
        });
        return;
      }
      parts.add(pair.key, value);
    });

    return parts.join('&');
  },

  toJSON: function(object) {
    var results = [];
    this.prototype._each.call(object, function(pair) {
      var value = Object.toJSON(pair.value);
      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
    });
    return '{' + results.join(', ') + '}';
  }
});

Hash.toQueryString.addPair = function(key, value, prefix) {
  key = encodeURIComponent(key);
  if (value === undefined) this.push(key);
  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
}

Object.extend(Hash.prototype, Enumerable);
Object.extend(Hash.prototype, {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (value && value == Hash.prototype[key]) continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject(this, function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  remove: function() {
    var result;
    for(var i = 0, length = arguments.length; i < length; i++) {
      var value = this[arguments[i]];
      if (value !== undefined){
        if (result === undefined) result = value;
        else {
          if (result.constructor != Array) result = [result];
          result.push(value)
        }
      }
      delete this[arguments[i]];
    }
    return result;
  },

  toQueryString: function() {
    return Hash.toQueryString(this);
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  },

  toJSON: function() {
    return Hash.toJSON(this);
  }
});

function $H(object) {
  if (object instanceof Hash) return object;
  return new Hash(object);
};

// Safari iterates over shadowed properties
if (function() {
  var i = 0, Test = function(value) { this.key = value };
  Test.prototype.key = 'foo';
  for (var property in new Test('bar')) i++;
  return i > 1;
}()) Hash.prototype._each = function(iterator) {
  var cache = [];
  for (var key in this) {
    var value = this[key];
    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
    cache.push(key);
    var pair = [key, value];
    pair.key = key;
    pair.value = value;
    iterator(pair);
  }
};
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },
  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   ''
    }
    Object.extend(this.options, options || {});

    this.options.method = this.options.method.toLowerCase();
    if (typeof this.options.parameters == 'string')
      this.options.parameters = this.options.parameters.toQueryParams();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  _complete: false,

  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Hash.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      if (this.options.onCreate) this.options.onCreate(this.transport);
      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete))
      this.respondToReadyState(this.transport.readyState);
  },

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (typeof extras.push == 'function')
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    return !this.transport.status
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = this.getHeader('Content-type');
      if (contentType && contentType.strip().
        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
          this.evalResponse();
    }

    try {
      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + state, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalJSON: function() {
    try {
      var json = this.getHeader('X-JSON');
      return json ? json.evalJSON() : null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, param) {
      this.updateContent();
      onComplete(transport, param);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.container[this.success() ? 'success' : 'failure'];
    var response = this.transport.responseText;

    if (!this.options.evalScripts) response = response.stripScripts();

    if (receiver = $(receiver)) {
      if (this.options.insertion)
        new this.options.insertion(receiver, response);
      else
        receiver.update(response);
    }

    if (this.success()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(query.snapshotItem(i));
    return results;
  };

  document.getElementsByClassName = function(className, parentElement) {
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
    return document._getElementsByXPath(q, parentElement);
  }

} else document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  var elements = [], child;
  for (var i = 0, length = children.length; i < length; i++) {
    child = children[i];
    if (Element.hasClassName(child, className))
      elements.push(Element.extend(child));
  }
  return elements;
};

/*--------------------------------------------------------------------------*/

if (!window.Element) var Element = {};

Element.extend = function(element) {
  var F = Prototype.BrowserFeatures;
  if (!element || !element.tagName || element.nodeType == 3 ||
   element._extended || F.SpecificElementExtensions || element == window)
    return element;

  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
   T = Element.Methods.ByTag;

  // extend methods for all tags (Safari doesn't need this)
  if (!F.ElementExtensions) {
    Object.extend(methods, Element.Methods),
    Object.extend(methods, Element.Methods.Simulated);
  }

  // extend methods for specific tags
  if (T[tagName]) Object.extend(methods, T[tagName]);

  for (var property in methods) {
    var value = methods[property];
    if (typeof value == 'function' && !(property in element))
      element[property] = cache.findOrStore(value);
  }

  element._extended = Prototype.emptyFunction;
  return element;
};

Element.extend.cache = {
  findOrStore: function(value) {
  	return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($A(arguments)));
    }
  }
};

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, html) {
    html = typeof html == 'undefined' ? '' : html.toString();
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  replace: function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    if (element.outerHTML) {
      element.outerHTML = html.stripScripts();
    } else {
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
        range.createContextualFragment(html.stripScripts()), element);
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    return $A($(element).getElementsByTagName('*')).each(Element.extend);
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return expression ? Selector.findElement(ancestors, expression, index) :
      ancestors[index || 0];
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    var descendants = element.descendants();
    return expression ? Selector.findElement(descendants, expression, index) :
      descendants[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return expression ? Selector.findElement(previousSiblings, expression, index) :
      previousSiblings[index || 0];
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return expression ? Selector.findElement(nextSiblings, expression, index) :
      nextSiblings[index || 0];
  },

  getElementsBySelector: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  getElementsByClassName: function(element, className) {
    return document.getElementsByClassName(className, element);
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      if (!element.attributes) return null;
      var t = Element._attributeTranslations;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name])  name = t.names[name];
      var attribute = element.attributes[name];
      return attribute ? attribute.nodeValue : null;
    }
    return element.getAttribute(name);
  },

  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    if (elementClassName.length == 0) return false;
    if (elementClassName == className ||
        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      return true;
    return false;
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).add(className);
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).remove(className);
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
    return element;
  },

  observe: function() {
    Event.observe.apply(Event, arguments);
    return $A(arguments).first();
  },

  stopObserving: function() {
    Event.stopObserving.apply(Event, arguments);
    return $A(arguments).first();
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Position.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles, camelized) {
    element = $(element);
    var elementStyle = element.style;

    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property])
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
          (camelized ? property : property.camelize())] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return element;
    element._overflow = element.style.overflow || 'auto';
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  }
};

Object.extend(Element.Methods, {
  childOf: Element.Methods.descendantOf,
  childElements: Element.Methods.immediateDescendants
});

if (Prototype.Browser.Opera) {
  Element.Methods._getStyle = Element.Methods.getStyle;
  Element.Methods.getStyle = function(element, style) {
    switch(style) {
      case 'left':
      case 'top':
      case 'right':
      case 'bottom':
        if (Element._getStyle(element, 'position') == 'static') return null;
      default: return Element._getStyle(element, style);
    }
  };
}
else if (Prototype.Browser.IE) {
  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset'+style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  // IE is missing .innerHTML support for TABLE-related elements
  Element.Methods.update = function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    var tagName = element.tagName.toUpperCase();
    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
      var div = document.createElement('div');
      switch (tagName) {
        case 'THEAD':
        case 'TBODY':
          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
          depth = 2;
          break;
        case 'TR':
          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
          depth = 3;
          break;
        case 'TD':
          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
          depth = 4;
      }
      $A(element.childNodes).each(function(node) { element.removeChild(node) });
      depth.times(function() { div = div.firstChild });
      $A(div.childNodes).each(function(node) { element.appendChild(node) });
    } else {
      element.innerHTML = html.stripScripts();
    }
    setTimeout(function() { html.evalScripts() }, 10);
    return element;
  }
}
else if (Prototype.Browser.Gecko) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

Element._attributeTranslations = {
  names: {
    colspan:   "colSpan",
    rowspan:   "rowSpan",
    valign:    "vAlign",
    datetime:  "dateTime",
    accesskey: "accessKey",
    tabindex:  "tabIndex",
    enctype:   "encType",
    maxlength: "maxLength",
    readonly:  "readOnly",
    longdesc:  "longDesc"
  },
  values: {
    _getAttr: function(element, attribute) {
      return element.getAttribute(attribute, 2);
    },
    _flag: function(element, attribute) {
      return $(element).hasAttribute(attribute) ? attribute : null;
    },
    style: function(element) {
      return element.style.cssText.toLowerCase();
    },
    title: function(element) {
      var node = element.getAttributeNode('title');
      return node.specified ? node.nodeValue : null;
    }
  }
};

(function() {
  Object.extend(this, {
    href: this._getAttr,
    src:  this._getAttr,
    type: this._getAttr,
    disabled: this._flag,
    checked:  this._flag,
    readonly: this._flag,
    multiple: this._flag
  });
}).call(Element._attributeTranslations.values);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    var t = Element._attributeTranslations, node;
    attribute = t.names[attribute] || attribute;
    node = $(element).getAttributeNode(attribute);
    return node && node.specified;
  }
};

Element.Methods.ByTag = {};

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
 document.createElement('div').__proto__) {
  window.HTMLElement = {};
  window.HTMLElement.prototype = document.createElement('div').__proto__;
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || {});
  else {
    if (tagName.constructor == Array) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = {};
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    var cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = cache.findOrStore(value);
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = {};
    window[klass].prototype = document.createElement(tagName).__proto__;
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (typeof klass == "undefined") continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;
};

var Toggle = { display: Element.toggle };

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toUpperCase();
        if (['TBODY', 'TR'].include(tagName)) {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);
/* Portions of the Selector class are derived from Jack Slocumâ��s DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create();

Selector.prototype = {
  initialize: function(expression) {
    this.expression = expression.strip();
    this.compileMatcher();
  },

  compileMatcher: function() {
    // Selectors with namespaced attributes can't use the XPath version
    if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
      return this.compileXPathMatcher();

    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e]; return;
    }
    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
    	      new Template(c[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le,  m;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        if (m = e.match(ps[i])) {
          this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
            new Template(x[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    return this.matcher(root);
  },

  match: function(element) {
    return this.findElements(document).include(element);
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
};

Object.extend(Selector, {
  _cache: {},

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: "[@#{1}]",
    attr: function(m) {
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (typeof h === 'function') return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
      'checked':     "[@checked]",
      'disabled':    "[@disabled]",
      'enabled':     "[not(@disabled)]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, m, v;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i in p) {
            if (m = e.match(p[i])) {
              v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    className:    'n = h.className(n, r, "#{1}", c); c = false;',
    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    },
    pseudo:       function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: {
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    laterSibling: /^\s*~\s*/,
    child:        /^\s*>\s*/,
    adjacent:     /^\s*\+\s*/,
    descendant:   /^\s/,

    // selectors follow
    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    id:           /^#([\w\-\*]+)(\b|$)/,
    className:    /^\.([\w\-\*]+)(\b|$)/,
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
    attrPresence: /^\[([\w]+)\]/,
    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._counted = true;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._counted) {
          n._counted = true;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
	      if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      tagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() == tagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!nodes && root == document) return targetNode ? [targetNode] : [];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr) {
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._counted) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._counted) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled) results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv.startsWith(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
  },

  matchElements: function(elements, expression) {
    var matches = new Selector(expression).findElements(), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._counted) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    var exprs = expressions.join(','), expressions = [];
    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, getHash) {
    var data = elements.inject({}, function(result, element) {
      if (!element.disabled && element.name) {
        var key = element.name, value = $(element).getValue();
        if (value != null) {
         	if (key in result) {
            if (result[key].constructor != Array) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return getHash ? data : Hash.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, getHash) {
    return Form.serializeElements(Form.getElements(form), getHash);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    return $(form).getElements().find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || {});

    var params = options.parameters;
    options.parameters = form.serialize(true);

    if (params) {
      if (typeof params == 'string') params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(form.readAttribute('action'), options);
  }
}

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = {};
        pair[element.name] = value;
        return Hash.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
        !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) {}
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
}

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
      default:
        return Form.Element.Serializers.textarea(element);
    }
  },

  inputSelector: function(element) {
    return element.checked ? element.value : null;
  },

  textarea: function(element) {
    return element.value;
  },

  select: function(element) {
    return this[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
}

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
      ? this.lastValue != value : String(this.lastValue) != String(value));
    if (changed) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback.bind(this));
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,

  element: function(event) {
    return $(event.target || event.srcElement);
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0, length = Event.observers.length; i < length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
      (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  }
});

/* prevent memory leaks in IE */
if (Prototype.Browser.IE)
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if(element.tagName=='BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent == document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!window.opera || element.tagName=='BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.width  = width + 'px';
    element.style.height = height + 'px';
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (Prototype.Browser.WebKit) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}

Element.addMethods();// script.aculo.us builder.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Builder = {
  NODEMAP: {
    AREA: 'map',
    CAPTION: 'table',
    COL: 'table',
    COLGROUP: 'table',
    LEGEND: 'fieldset',
    OPTGROUP: 'select',
    OPTION: 'select',
    PARAM: 'object',
    TBODY: 'table',
    TD: 'table',
    TFOOT: 'table',
    TH: 'table',
    THEAD: 'table',
    TR: 'table'
  },
  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
  //       due to a Firefox bug
  node: function(elementName) {
    elementName = elementName.toUpperCase();
    
    // try innerHTML approach
    var parentTag = this.NODEMAP[elementName] || 'div';
    var parentElement = document.createElement(parentTag);
    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
    } catch(e) {}
    var element = parentElement.firstChild || null;
      
    // see if browser added wrapping tags
    if(element && (element.tagName.toUpperCase() != elementName))
      element = element.getElementsByTagName(elementName)[0];
    
    // fallback to createElement approach
    if(!element) element = document.createElement(elementName);
    
    // abort if nothing could be created
    if(!element) return;

    // attributes (or text)
    if(arguments[1])
      if(this._isStringOrNumber(arguments[1]) ||
        (arguments[1] instanceof Array) ||
        arguments[1].tagName) {
          this._children(element, arguments[1]);
        } else {
          var attrs = this._attributes(arguments[1]);
          if(attrs.length) {
            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
              parentElement.innerHTML = "<" +elementName + " " +
                attrs + "></" + elementName + ">";
            } catch(e) {}
            element = parentElement.firstChild || null;
            // workaround firefox 1.0.X bug
            if(!element) {
              element = document.createElement(elementName);
              for(attr in arguments[1]) 
                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
            }
            if(element.tagName.toUpperCase() != elementName)
              element = parentElement.getElementsByTagName(elementName)[0];
          }
        } 

    // text, or array of children
    if(arguments[2])
      this._children(element, arguments[2]);

     return element;
  },
  _text: function(text) {
     return document.createTextNode(text);
  },

  ATTR_MAP: {
    'className': 'class',
    'htmlFor': 'for'
  },

  _attributes: function(attributes) {
    var attrs = [];
    for(attribute in attributes)
      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
          '="' + attributes[attribute].toString().escapeHTML().gsub( /"/ , '&quot;' ) + '"' );
    return attrs.join(" ");
  },
  _children: function(element, children) {
    if(children.tagName) {
      element.appendChild(children);
      return;
    }
    if(typeof children=='object') { // array can hold nodes and text
      children.flatten().each( function(e) {
        if(typeof e=='object')
          element.appendChild(e)
        else
          if(Builder._isStringOrNumber(e))
            element.appendChild(Builder._text(e));
      });
    } else
      if(Builder._isStringOrNumber(children))
        element.appendChild(Builder._text(children));
  },
  _isStringOrNumber: function(param) {
    return(typeof param=='string' || typeof param=='number');
  },
  build: function(html) {
    var element = this.node('div');
    $(element).update(html.strip());
    return element.down();
  },
  dump: function(scope) { 
    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
  
    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
  
    tags.each( function(tag){ 
      scope[tag] = function() { 
        return Builder.node.apply(Builder, [tag].concat($A(arguments)));  
      } 
    });
  }
}
// script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/ 

// converts rgb() and #xxx to #xxxxxx format,  
// returns self (or first argument) if not convertable  
String.prototype.parseColor = function() {  
  var color = '#';
  if(this.slice(0,4) == 'rgb(') {  
    var cols = this.slice(4,this.length-1).split(',');  
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  } else {  
    if(this.slice(0,1) == '#') {  
      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
      if(this.length==7) color = this.toLowerCase();  
    }  
  }  
  return(color.length==7 ? color : (arguments[0] || this));  
}

/*--------------------------------------------------------------------------*/

Element.collectTextNodes = function(element) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  }).flatten().join('');
}

Element.collectTextNodesIgnoreClass = function(element, className) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
        Element.collectTextNodesIgnoreClass(node, className) : ''));
  }).flatten().join('');
}

Element.setContentZoom = function(element, percent) {
  element = $(element);  
  element.setStyle({fontSize: (percent/100) + 'em'});   
  if(Prototype.Browser.WebKit) window.scrollBy(0,0);
  return element;
}

Element.getInlineOpacity = function(element){
  return $(element).style.opacity || '';
}

Element.forceRerendering = function(element) {
  try {
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    element.removeChild(n);
  } catch(e) { }
};

/*--------------------------------------------------------------------------*/

Array.prototype.call = function() {
  var args = arguments;
  this.each(function(f){ f.apply(this, args) });
}

/*--------------------------------------------------------------------------*/

var Effect = {
  _elementDoesNotExistError: {
    name: 'ElementDoesNotExistError',
    message: 'The specified DOM element does not exist, but is required for this effect to operate'
  },
  tagifyText: function(element) {
    if(typeof Builder == 'undefined')
      throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
      
    var tagifyStyle = 'position:relative';
    if(Prototype.Browser.IE) tagifyStyle += ';zoom:1';
    
    element = $(element);
    $A(element.childNodes).each( function(child) {
      if(child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            Builder.node('span',{style: tagifyStyle},
              character == ' ' ? String.fromCharCode(160) : character), 
              child);
        });
        Element.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if(((typeof element == 'object') || 
        (typeof element == 'function')) && 
       (element.length))
      elements = element;
    else
      elements = $(element).childNodes;
      
    var options = Object.extend({
      speed: 0.1,
      delay: 0.0
    }, arguments[2] || {});
    var masterDelay = options.delay;

    $A(elements).each( function(element, index) {
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
    });
  },
  PAIRS: {
    'slide':  ['SlideDown','SlideUp'],
    'blind':  ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },
  toggle: function(element, effect) {
    element = $(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, arguments[2] || {});
    Effect[element.visible() ? 
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  }
};

var Effect2 = Effect; // deprecated

/* ------------- transitions ------------- */

Effect.Transitions = {
  linear: Prototype.K,
  sinoidal: function(pos) {
    return (-Math.cos(pos*Math.PI)/2) + 0.5;
  },
  reverse: function(pos) {
    return 1-pos;
  },
  flicker: function(pos) {
    var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
    return (pos > 1 ? 1 : pos);
  },
  wobble: function(pos) {
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  },
  pulse: function(pos, pulses) { 
    pulses = pulses || 5; 
    return (
      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
      );
  },
  none: function(pos) {
    return 0;
  },
  full: function(pos) {
    return 1;
  }
};

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
  initialize: function() {
    this.effects  = [];
    this.interval = null;    
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();
    
    var position = (typeof effect.options.queue == 'string') ? 
      effect.options.queue : effect.options.queue.position;
    
    switch(position) {
      case 'front':
        // move unstarted effects after this effect  
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }
    
    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);
    
    if(!this.interval)
      this.interval = setInterval(this.loop.bind(this), 15);
  },
  remove: function(effect) {
    this.effects = this.effects.reject(function(e) { return e==effect });
    if(this.effects.length == 0) {
      clearInterval(this.interval);
      this.interval = null;
    }
  },
  loop: function() {
    var timePos = new Date().getTime();
    for(var i=0, len=this.effects.length;i<len;i++) 
      this.effects[i] && this.effects[i].loop(timePos);
  }
});

Effect.Queues = {
  instances: $H(),
  get: function(queueName) {
    if(typeof queueName != 'string') return queueName;
    
    if(!this.instances[queueName])
      this.instances[queueName] = new Effect.ScopedQueue();
      
    return this.instances[queueName];
  }
}
Effect.Queue = Effect.Queues.get('global');

Effect.DefaultOptions = {
  transition: Effect.Transitions.sinoidal,
  duration:   1.0,   // seconds
  fps:        100,   // 100= assume 66fps max.
  sync:       false, // true for combining
  from:       0.0,
  to:         1.0,
  delay:      0.0,
  queue:      'parallel'
}

Effect.Base = function() {};
Effect.Base.prototype = {
  position: null,
  start: function(options) {
    function codeForEvent(options,eventName){
      return (
        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
      );
    }
    if(options.transition === false) options.transition = Effect.Transitions.linear;
    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn+(this.options.duration*1000);
    this.fromToDelta  = this.options.to-this.options.from;
    this.totalTime    = this.finishOn-this.startOn;
    this.totalFrames  = this.options.fps*this.options.duration;
    
    eval('this.render = function(pos){ '+
      'if(this.state=="idle"){this.state="running";'+
      codeForEvent(options,'beforeSetup')+
      (this.setup ? 'this.setup();':'')+ 
      codeForEvent(options,'afterSetup')+
      '};if(this.state=="running"){'+
      'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
      'this.position=pos;'+
      codeForEvent(options,'beforeUpdate')+
      (this.update ? 'this.update(pos);':'')+
      codeForEvent(options,'afterUpdate')+
      '}}');
    
    this.event('beforeStart');
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).add(this);
  },
  loop: function(timePos) {
    if(timePos >= this.startOn) {
      if(timePos >= this.finishOn) {
        this.render(1.0);
        this.cancel();
        this.event('beforeFinish');
        if(this.finish) this.finish(); 
        this.event('afterFinish');
        return;  
      }
      var pos   = (timePos - this.startOn) / this.totalTime,
          frame = Math.round(pos * this.totalFrames);
      if(frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  cancel: function() {
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).remove(this);
    this.state = 'finished';
  },
  event: function(eventName) {
    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
    if(this.options[eventName]) this.options[eventName](this);
  },
  inspect: function() {
    var data = $H();
    for(property in this)
      if(typeof this[property] != 'function') data[property] = this[property];
    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
  }
}

Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    this.effects.invoke('render', position);
  },
  finish: function(position) {
    this.effects.each( function(effect) {
      effect.render(1.0);
      effect.cancel();
      effect.event('beforeFinish');
      if(effect.finish) effect.finish(position);
      effect.event('afterFinish');
    });
  }
});

Effect.Event = Class.create();
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
  initialize: function() {
    var options = Object.extend({
      duration: 0
    }, arguments[0] || {});
    this.start(options);
  },
  update: Prototype.emptyFunction
});

Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    // make this work on IE on elements without 'layout'
    if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

Effect.Move = Class.create();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Bug in Opera: Opera returns the "real" position of a static element or
    // relative element that does not have top/left explicitly set.
    // ==> Always set top and left for position relative elements in your stylesheets 
    // (to 0 if you do not need them) 
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
    if(this.options.mode == 'absolute') {
      // absolute movement, so we need to calc deltaX and deltaY
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    this.element.setStyle({
      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
    });
  }
});

// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
  return new Effect.Move(element, 
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};

Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
  initialize: function(element, percent) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');
    
    this.originalStyle = {};
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
    if(this.options.scaleX) d.width = Math.round(width) + 'px';
    if(this.options.scaleY) d.height = Math.round(height) + 'px';
    if(this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if(this.elementPositioning == 'absolute') {
        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if(this.options.scaleY) d.top = -topd + 'px';
        if(this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

Effect.Highlight = Class.create();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = {};
    if (!this.options.keepBackgroundImage) {
      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
      this.element.setStyle({backgroundImage: 'none'});
    }
    if(!this.options.endcolor)
      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
    if(!this.options.restorecolor)
      this.options.restorecolor = this.element.getStyle('background-color');
    // init color calculations
    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  },
  update: function(position) {
    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
  },
  finish: function() {
    this.element.setStyle(Object.extend(this.oldStyle, {
      backgroundColor: this.options.restorecolor
    }));
  }
});

Effect.ScrollTo = Class.create();
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    this.start(arguments[1] || {});
  },
  setup: function() {
    Position.prepare();
    var offsets = Position.cumulativeOffset(this.element);
    if(this.options.offset) offsets[1] += this.options.offset;
    var max = window.innerHeight ? 
      window.height - window.innerHeight :
      document.body.scrollHeight - 
        (document.documentElement.clientHeight ? 
          document.documentElement.clientHeight : document.body.clientHeight);
    this.scrollStart = Position.deltaY;
    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
  },
  update: function(position) {
    Position.prepare();
    window.scrollTo(Position.deltaX, 
      this.scrollStart + (position*this.delta));
  }
});

/* ------------- combination effects ------------- */

Effect.Fade = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
  from: element.getOpacity() || 1.0,
  to:   0.0,
  afterFinishInternal: function(effect) { 
    if(effect.options.to!=0) return;
    effect.element.hide().setStyle({opacity: oldOpacity}); 
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

Effect.Appear = function(element) {
  element = $(element);
  var options = Object.extend({
  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
  to:   1.0,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from).show(); 
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

Effect.Puff = function(element) {
  element = $(element);
  var oldStyle = { 
    opacity: element.getInlineOpacity(), 
    position: element.getStyle('position'),
    top:  element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height
  };
  return new Effect.Parallel(
   [ new Effect.Scale(element, 200, 
      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
     Object.extend({ duration: 1.0, 
      beforeSetupInternal: function(effect) {
        Position.absolutize(effect.effects[0].element)
      },
      afterFinishInternal: function(effect) {
         effect.effects[0].element.hide().setStyle(oldStyle); }
     }, arguments[1] || {})
   );
}

Effect.BlindUp = function(element) {
  element = $(element);
  element.makeClipping();
  return new Effect.Scale(element, 0,
    Object.extend({ scaleContent: false, 
      scaleX: false, 
      restoreAfterFinish: true,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
      } 
    }, arguments[1] || {})
  );
}

Effect.BlindDown = function(element) {
  element = $(element);
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false,
    scaleFrom: 0,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.undoClipping();
    }
  }, arguments[1] || {}));
}

Effect.SwitchOff = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  return new Effect.Appear(element, Object.extend({
    duration: 0.4,
    from: 0,
    transition: Effect.Transitions.flicker,
    afterFinishInternal: function(effect) {
      new Effect.Scale(effect.element, 1, { 
        duration: 0.3, scaleFromCenter: true,
        scaleX: false, scaleContent: false, restoreAfterFinish: true,
        beforeSetup: function(effect) { 
          effect.element.makePositioned().makeClipping();
        },
        afterFinishInternal: function(effect) {
          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
        }
      })
    }
  }, arguments[1] || {}));
}

Effect.DropOut = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left'),
    opacity: element.getInlineOpacity() };
  return new Effect.Parallel(
    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
    Object.extend(
      { duration: 0.5,
        beforeSetup: function(effect) {
          effect.effects[0].element.makePositioned(); 
        },
        afterFinishInternal: function(effect) {
          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
        } 
      }, arguments[1] || {}));
}

Effect.Shake = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left') };
    return new Effect.Move(element, 
      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
        effect.element.undoPositioned().setStyle(oldStyle);
  }}) }}) }}) }}) }}) }});
}

Effect.SlideDown = function(element) {
  element = $(element).cleanWhitespace();
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false, 
    scaleFrom: window.opera ? 0 : 1,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if(window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
    },
    afterFinishInternal: function(effect) {
      effect.element.undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
    }, arguments[1] || {})
  );
}

Effect.SlideUp = function(element) {
  element = $(element).cleanWhitespace();
  var oldInnerBottom = element.down().getStyle('bottom');
  return new Effect.Scale(element, window.opera ? 0 : 1,
   Object.extend({ scaleContent: false, 
    scaleX: false, 
    scaleMode: 'box',
    scaleFrom: 100,
    restoreAfterFinish: true,
    beforeStartInternal: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if(window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().show();
    },  
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
    },
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
      effect.element.down().undoPositioned();
    }
   }, arguments[1] || {})
  );
}

// Bug in opera makes the TD containing this element expand for a instance after finish 
Effect.Squish = function(element) {
  return new Effect.Scale(element, window.opera ? 1 : 0, { 
    restoreAfterFinish: true,
    beforeSetup: function(effect) {
      effect.element.makeClipping(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping(); 
    }
  });
}

Effect.Grow = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.full
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();    
  var initialMoveX, initialMoveY;
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      initialMoveX = initialMoveY = moveX = moveY = 0; 
      break;
    case 'top-right':
      initialMoveX = dims.width;
      initialMoveY = moveY = 0;
      moveX = -dims.width;
      break;
    case 'bottom-left':
      initialMoveX = moveX = 0;
      initialMoveY = dims.height;
      moveY = -dims.height;
      break;
    case 'bottom-right':
      initialMoveX = dims.width;
      initialMoveY = dims.height;
      moveX = -dims.width;
      moveY = -dims.height;
      break;
    case 'center':
      initialMoveX = dims.width / 2;
      initialMoveY = dims.height / 2;
      moveX = -dims.width / 2;
      moveY = -dims.height / 2;
      break;
  }
  
  return new Effect.Move(element, {
    x: initialMoveX,
    y: initialMoveY,
    duration: 0.01, 
    beforeSetup: function(effect) {
      effect.element.hide().makeClipping().makePositioned();
    },
    afterFinishInternal: function(effect) {
      new Effect.Parallel(
        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
          new Effect.Scale(effect.element, 100, {
            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
        ], Object.extend({
             beforeSetup: function(effect) {
               effect.effects[0].element.setStyle({height: '0px'}).show(); 
             },
             afterFinishInternal: function(effect) {
               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
             }
           }, options)
      )
    }
  });
}

Effect.Shrink = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.none
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      moveX = moveY = 0;
      break;
    case 'top-right':
      moveX = dims.width;
      moveY = 0;
      break;
    case 'bottom-left':
      moveX = 0;
      moveY = dims.height;
      break;
    case 'bottom-right':
      moveX = dims.width;
      moveY = dims.height;
      break;
    case 'center':  
      moveX = dims.width / 2;
      moveY = dims.height / 2;
      break;
  }
  
  return new Effect.Parallel(
    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
    ], Object.extend({            
         beforeStartInternal: function(effect) {
           effect.effects[0].element.makePositioned().makeClipping(); 
         },
         afterFinishInternal: function(effect) {
           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
       }, options)
  );
}

Effect.Pulsate = function(element) {
  element = $(element);
  var options    = arguments[1] || {};
  var oldOpacity = element.getInlineOpacity();
  var transition = options.transition || Effect.Transitions.sinoidal;
  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
  reverser.bind(transition);
  return new Effect.Opacity(element, 
    Object.extend(Object.extend({  duration: 2.0, from: 0,
      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
    }, options), {transition: reverser}));
}

Effect.Fold = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height };
  element.makeClipping();
  return new Effect.Scale(element, 5, Object.extend({   
    scaleContent: false,
    scaleX: false,
    afterFinishInternal: function(effect) {
    new Effect.Scale(element, 1, { 
      scaleContent: false, 
      scaleY: false,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping().setStyle(oldStyle);
      } });
  }}, arguments[1] || {}));
};

Effect.Morph = Class.create();
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      style: {}
    }, arguments[1] || {});
    if (typeof options.style == 'string') {
      if(options.style.indexOf(':') == -1) {
        var cssText = '', selector = '.' + options.style;
        $A(document.styleSheets).reverse().each(function(styleSheet) {
          if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
          else if (styleSheet.rules) cssRules = styleSheet.rules;
          $A(cssRules).reverse().each(function(rule) {
            if (selector == rule.selectorText) {
              cssText = rule.style.cssText;
              throw $break;
            }
          });
          if (cssText) throw $break;
        });
        this.style = cssText.parseStyle();
        options.afterFinishInternal = function(effect){
          effect.element.addClassName(effect.options.style);
          effect.transforms.each(function(transform) {
            if(transform.style != 'opacity')
              effect.element.style[transform.style] = '';
          });
        }
      } else this.style = options.style.parseStyle();
    } else this.style = $H(options.style)
    this.start(options);
  },
  setup: function(){
    function parseColor(color){
      if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
      color = color.parseColor();
      return $R(0,2).map(function(i){
        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
      });
    }
    this.transforms = this.style.map(function(pair){
      var property = pair[0], value = pair[1], unit = null;

      if(value.parseColor('#zzzzzz') != '#zzzzzz') {
        value = value.parseColor();
        unit  = 'color';
      } else if(property == 'opacity') {
        value = parseFloat(value);
        if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
          this.element.setStyle({zoom: 1});
      } else if(Element.CSS_LENGTH.test(value)) {
          var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
          value = parseFloat(components[1]);
          unit = (components.length == 3) ? components[2] : null;
      }

      var originalValue = this.element.getStyle(property);
      return { 
        style: property.camelize(), 
        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
        targetValue: unit=='color' ? parseColor(value) : value,
        unit: unit
      };
    }.bind(this)).reject(function(transform){
      return (
        (transform.originalValue == transform.targetValue) ||
        (
          transform.unit != 'color' &&
          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
        )
      )
    });
  },
  update: function(position) {
    var style = {}, transform, i = this.transforms.length;
    while(i--)
      style[(transform = this.transforms[i]).style] = 
        transform.unit=='color' ? '#'+
          (Math.round(transform.originalValue[0]+
            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
          (Math.round(transform.originalValue[1]+
            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
          (Math.round(transform.originalValue[2]+
            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
        transform.originalValue + Math.round(
          ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
    this.element.setStyle(style, true);
  }
});

Effect.Transform = Class.create();
Object.extend(Effect.Transform.prototype, {
  initialize: function(tracks){
    this.tracks  = [];
    this.options = arguments[1] || {};
    this.addTracks(tracks);
  },
  addTracks: function(tracks){
    tracks.each(function(track){
      var data = $H(track).values().first();
      this.tracks.push($H({
        ids:     $H(track).keys().first(),
        effect:  Effect.Morph,
        options: { style: data }
      }));
    }.bind(this));
    return this;
  },
  play: function(){
    return new Effect.Parallel(
      this.tracks.map(function(track){
        var elements = [$(track.ids) || $$(track.ids)].flatten();
        return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
      }).flatten(),
      this.options
    );
  }
});

Element.CSS_PROPERTIES = $w(
  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  'fontSize fontWeight height left letterSpacing lineHeight ' +
  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  'right textIndent top width wordSpacing zIndex');
  
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;

String.prototype.parseStyle = function(){
  var element = document.createElement('div');
  element.innerHTML = '<div style="' + this + '"></div>';
  var style = element.childNodes[0].style, styleRules = $H();
  
  Element.CSS_PROPERTIES.each(function(property){
    if(style[property]) styleRules[property] = style[property]; 
  });
  if(Prototype.Browser.IE && this.indexOf('opacity') > -1) {
    styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
  }
  return styleRules;
};

Element.morph = function(element, style) {
  new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
  return element;
};

['getInlineOpacity','forceRerendering','setContentZoom',
 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
  function(f) { Element.Methods[f] = Element[f]; }
);

Element.Methods.visualEffect = function(element, effect, options) {
  s = effect.dasherize().camelize();
  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
  new Effect[effect_class](element, options);
  return $(element);
};

Element.addMethods();// script.aculo.us dragdrop.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(typeof Effect == 'undefined')
  throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
  drops: [],

  remove: function(element) {
    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  },

  add: function(element) {
    element = $(element);
    var options = Object.extend({
      greedy:     true,
      hoverclass: null,
      tree:       false
    }, arguments[1] || {});

    // cache containers
    if(options.containment) {
      options._containers = [];
      var containment = options.containment;
      if((typeof containment == 'object') && 
        (containment.constructor == Array)) {
        containment.each( function(c) { options._containers.push($(c)) });
      } else {
        options._containers.push($(containment));
      }
    }
    
    if(options.accept) options.accept = [options.accept].flatten();

    Element.makePositioned(element); // fix IE
    options.element = element;

    this.drops.push(options);
  },
  
  findDeepestChild: function(drops) {
    deepest = drops[0];
      
    for (i = 1; i < drops.length; ++i)
      if (Element.isParent(drops[i].element, deepest.element))
        deepest = drops[i];
    
    return deepest;
  },

  isContained: function(element, drop) {
    var containmentNode;
    if(drop.tree) {
      containmentNode = element.treeNode; 
    } else {
      containmentNode = element.parentNode;
    }
    return drop._containers.detect(function(c) { return containmentNode == c });
  },
  
  isAffected: function(point, element, drop) {
    return (
      (drop.element!=element) &&
      ((!drop._containers) ||
        this.isContained(element, drop)) &&
      ((!drop.accept) ||
        (Element.classNames(element).detect( 
          function(v) { return drop.accept.include(v) } ) )) &&
      Position.within(drop.element, point[0], point[1]) );
  },

  deactivate: function(drop) {
    if(drop.hoverclass)
      Element.removeClassName(drop.element, drop.hoverclass);
    this.last_active = null;
  },

  activate: function(drop) {
    if(drop.hoverclass)
      Element.addClassName(drop.element, drop.hoverclass);
    this.last_active = drop;
  },

  show: function(point, element) {
    if(!this.drops.length) return;
    var affected = [];
    
    if(this.last_active) this.deactivate(this.last_active);
    this.drops.each( function(drop) {
      if(Droppables.isAffected(point, element, drop))
        affected.push(drop);
    });
        
    if(affected.length>0) {
      drop = Droppables.findDeepestChild(affected);
      Position.within(drop.element, point[0], point[1]);
      if(drop.onHover)
        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
      
      Droppables.activate(drop);
    }
  },

  fire: function(event, element) {
    if(!this.last_active) return;
    Position.prepare();

    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
      if (this.last_active.onDrop) {
        this.last_active.onDrop(element, this.last_active.element, event); 
        return true; 
      }
  },

  reset: function() {
    if(this.last_active)
      this.deactivate(this.last_active);
  }
}

var Draggables = {
  drags: [],
  observers: [],
  
  register: function(draggable) {
    if(this.drags.length == 0) {
      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
      
      Event.observe(document, "mouseup", this.eventMouseUp);
      Event.observe(document, "mousemove", this.eventMouseMove);
      Event.observe(document, "keypress", this.eventKeypress);
    }
    this.drags.push(draggable);
  },
  
  unregister: function(draggable) {
    this.drags = this.drags.reject(function(d) { return d==draggable });
    if(this.drags.length == 0) {
      Event.stopObserving(document, "mouseup", this.eventMouseUp);
      Event.stopObserving(document, "mousemove", this.eventMouseMove);
      Event.stopObserving(document, "keypress", this.eventKeypress);
    }
  },
  
  activate: function(draggable) {
    if(draggable.options.delay) { 
      this._timeout = setTimeout(function() { 
        Draggables._timeout = null; 
        window.focus(); 
        Draggables.activeDraggable = draggable; 
      }.bind(this), draggable.options.delay); 
    } else {
      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
      this.activeDraggable = draggable;
    }
  },
  
  deactivate: function() {
    this.activeDraggable = null;
  },
  
  updateDrag: function(event) {
    if(!this.activeDraggable) return;
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    // Mozilla-based browsers fire successive mousemove events with
    // the same coordinates, prevent needless redrawing (moz bug?)
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    this._lastPointer = pointer;
    
    this.activeDraggable.updateDrag(event, pointer);
  },
  
  endDrag: function(event) {
    if(this._timeout) { 
      clearTimeout(this._timeout); 
      this._timeout = null; 
    }
    if(!this.activeDraggable) return;
    this._lastPointer = null;
    this.activeDraggable.endDrag(event);
    this.activeDraggable = null;
  },
  
  keyPress: function(event) {
    if(this.activeDraggable)
      this.activeDraggable.keyPress(event);
  },
  
  addObserver: function(observer) {
    this.observers.push(observer);
    this._cacheObserverCallbacks();
  },
  
  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    this.observers = this.observers.reject( function(o) { return o.element==element });
    this._cacheObserverCallbacks();
  },
  
  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    if(this[eventName+'Count'] > 0)
      this.observers.each( function(o) {
        if(o[eventName]) o[eventName](eventName, draggable, event);
      });
    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  },
  
  _cacheObserverCallbacks: function() {
    ['onStart','onEnd','onDrag'].each( function(eventName) {
      Draggables[eventName+'Count'] = Draggables.observers.select(
        function(o) { return o[eventName]; }
      ).length;
    });
  }
}

/*--------------------------------------------------------------------------*/

var Draggable = Class.create();
Draggable._dragging    = {};

Draggable.prototype = {
  initialize: function(element) {
    var defaults = {
      handle: false,
      reverteffect: function(element, top_offset, left_offset) {
        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
          queue: {scope:'_draggable', position:'end'}
        });
      },
      endeffect: function(element) {
        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
          queue: {scope:'_draggable', position:'end'},
          afterFinish: function(){ 
            Draggable._dragging[element] = false 
          }
        }); 
      },
      zindex: 1000,
      revert: false,
      quiet: false,
      scroll: false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
      delay: 0
    };
    
    if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
      Object.extend(defaults, {
        starteffect: function(element) {
          element._opacity = Element.getOpacity(element);
          Draggable._dragging[element] = true;
          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
        }
      });
    
    var options = Object.extend(defaults, arguments[1] || {});

    this.element = $(element);
    
    if(options.handle && (typeof options.handle == 'string'))
      this.handle = this.element.down('.'+options.handle, 0);
    
    if(!this.handle) this.handle = $(options.handle);
    if(!this.handle) this.handle = this.element;
    
    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
      options.scroll = $(options.scroll);
      this._isScrollChild = Element.childOf(this.element, options.scroll);
    }

    Element.makePositioned(this.element); // fix IE    

    this.delta    = this.currentDelta();
    this.options  = options;
    this.dragging = false;   

    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    Event.observe(this.handle, "mousedown", this.eventMouseDown);
    
    Draggables.register(this);
  },
  
  destroy: function() {
    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    Draggables.unregister(this);
  },
  
  currentDelta: function() {
    return([
      parseInt(Element.getStyle(this.element,'left') || '0'),
      parseInt(Element.getStyle(this.element,'top') || '0')]);
  },
  
  initDrag: function(event) {
    if(typeof Draggable._dragging[this.element] != 'undefined' &&
      Draggable._dragging[this.element]) return;
    if(Event.isLeftClick(event)) {    
      // abort on form elements, fixes a Firefox issue
      var src = Event.element(event);
      if((tag_name = src.tagName.toUpperCase()) && (
        tag_name=='INPUT' ||
        tag_name=='SELECT' ||
        tag_name=='OPTION' ||
        tag_name=='BUTTON' ||
        tag_name=='TEXTAREA')) return;
        
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      var pos     = Position.cumulativeOffset(this.element);
      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
      
      Draggables.activate(this);
      Event.stop(event);
    }
  },
  
  startDrag: function(event) {
    this.dragging = true;
    
    if(this.options.zindex) {
      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
      this.element.style.zIndex = this.options.zindex;
    }
    
    if(this.options.ghosting) {
      this._clone = this.element.cloneNode(true);
      Position.absolutize(this.element);
      this.element.parentNode.insertBefore(this._clone, this.element);
    }
    
    if(this.options.scroll) {
      if (this.options.scroll == window) {
        var where = this._getWindowScroll(this.options.scroll);
        this.originalScrollLeft = where.left;
        this.originalScrollTop = where.top;
      } else {
        this.originalScrollLeft = this.options.scroll.scrollLeft;
        this.originalScrollTop = this.options.scroll.scrollTop;
      }
    }
    
    Draggables.notify('onStart', this, event);
        
    if(this.options.starteffect) this.options.starteffect(this.element);
  },
  
  updateDrag: function(event, pointer) {
    if(!this.dragging) this.startDrag(event);
    
    if(!this.options.quiet){
      Position.prepare();
      Droppables.show(pointer, this.element);
    }
    
    Draggables.notify('onDrag', this, event);
    
    this.draw(pointer);
    if(this.options.change) this.options.change(this);
    
    if(this.options.scroll) {
      this.stopScrolling();
      
      var p;
      if (this.options.scroll == window) {
        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
      } else {
        p = Position.page(this.options.scroll);
        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
        p[1] += this.options.scroll.scrollTop + Position.deltaY;
        p.push(p[0]+this.options.scroll.offsetWidth);
        p.push(p[1]+this.options.scroll.offsetHeight);
      }
      var speed = [0,0];
      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
      this.startScrolling(speed);
    }
    
    // fix AppleWebKit rendering
    if(Prototype.Browser.WebKit) window.scrollBy(0,0);
    
    Event.stop(event);
  },
  
  finishDrag: function(event, success) {
    this.dragging = false;
    
    if(this.options.quiet){
      Position.prepare();
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      Droppables.show(pointer, this.element);
    }

    if(this.options.ghosting) {
      Position.relativize(this.element);
      Element.remove(this._clone);
      this._clone = null;
    }

    var dropped = false; 
    if(success) { 
      dropped = Droppables.fire(event, this.element); 
      if (!dropped) dropped = false; 
    }
    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
    Draggables.notify('onEnd', this, event);

    var revert = this.options.revert;
    if(revert && typeof revert == 'function') revert = revert(this.element);
    
    var d = this.currentDelta();
    if(revert && this.options.reverteffect) {
      if (dropped == 0 || revert != 'failure')
        this.options.reverteffect(this.element,
          d[1]-this.delta[1], d[0]-this.delta[0]);
    } else {
      this.delta = d;
    }

    if(this.options.zindex)
      this.element.style.zIndex = this.originalZ;

    if(this.options.endeffect) 
      this.options.endeffect(this.element);
      
    Draggables.deactivate(this);
    Droppables.reset();
  },
  
  keyPress: function(event) {
    if(event.keyCode!=Event.KEY_ESC) return;
    this.finishDrag(event, false);
    Event.stop(event);
  },
  
  endDrag: function(event) {
    if(!this.dragging) return;
    this.stopScrolling();
    this.finishDrag(event, true);
    Event.stop(event);
  },
  
  draw: function(point) {
    var pos = Position.cumulativeOffset(this.element);
    if(this.options.ghosting) {
      var r   = Position.realOffset(this.element);
      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    }
    
    var d = this.currentDelta();
    pos[0] -= d[0]; pos[1] -= d[1];
    
    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    }
    
    var p = [0,1].map(function(i){ 
      return (point[i]-pos[i]-this.offset[i]) 
    }.bind(this));
    
    if(this.options.snap) {
      if(typeof this.options.snap == 'function') {
        p = this.options.snap(p[0],p[1],this);
      } else {
      if(this.options.snap instanceof Array) {
        p = p.map( function(v, i) {
          return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
      } else {
        p = p.map( function(v) {
          return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
      }
    }}
    
    var style = this.element.style;
    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
      style.left = p[0] + "px";
    if((!this.options.constraint) || (this.options.constraint=='vertical'))
      style.top  = p[1] + "px";
    
    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
  },
  
  stopScrolling: function() {
    if(this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
      Draggables._lastScrollPointer = null;
    }
  },
  
  startScrolling: function(speed) {
    if(!(speed[0] || speed[1])) return;
    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
    this.lastScrolled = new Date();
    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
  },
  
  scroll: function() {
    var current = new Date();
    var delta = current - this.lastScrolled;
    this.lastScrolled = current;
    if(this.options.scroll == window) {
      with (this._getWindowScroll(this.options.scroll)) {
        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
          var d = delta / 1000;
          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
        }
      }
    } else {
      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    }
    
    Position.prepare();
    Droppables.show(Draggables._lastPointer, this.element);
    Draggables.notify('onDrag', this);
    if (this._isScrollChild) {
      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
      if (Draggables._lastScrollPointer[0] < 0)
        Draggables._lastScrollPointer[0] = 0;
      if (Draggables._lastScrollPointer[1] < 0)
        Draggables._lastScrollPointer[1] = 0;
      this.draw(Draggables._lastScrollPointer);
    }
    
    if(this.options.change) this.options.change(this);
  },
  
  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop) {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight
      }
    }
    return { top: T, left: L, width: W, height: H };
  }
}

/*--------------------------------------------------------------------------*/

var SortableObserver = Class.create();
SortableObserver.prototype = {
  initialize: function(element, observer) {
    this.element   = $(element);
    this.observer  = observer;
    this.lastValue = Sortable.serialize(this.element);
  },
  
  onStart: function() {
    this.lastValue = Sortable.serialize(this.element);
  },
  
  onEnd: function() {
    Sortable.unmark();
    if(this.lastValue != Sortable.serialize(this.element))
      this.observer(this.element)
  }
}

var Sortable = {
  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
  
  sortables: {},
  
  _findRootElement: function(element) {
    while (element.tagName.toUpperCase() != "BODY") {  
      if(element.id && Sortable.sortables[element.id]) return element;
      element = element.parentNode;
    }
  },

  options: function(element) {
    element = Sortable._findRootElement($(element));
    if(!element) return;
    return Sortable.sortables[element.id];
  },
  
  destroy: function(element){
    var s = Sortable.options(element);
    
    if(s) {
      Draggables.removeObserver(s.element);
      s.droppables.each(function(d){ Droppables.remove(d) });
      s.draggables.invoke('destroy');
      
      delete Sortable.sortables[s.element.id];
    }
  },

  create: function(element) {
    element = $(element);
    var options = Object.extend({ 
      element:     element,
      tag:         'li',       // assumes li children, override with tag: 'tagname'
      dropOnEmpty: false,
      tree:        false,
      treeTag:     'ul',
      overlap:     'vertical', // one of 'vertical', 'horizontal'
      constraint:  'vertical', // one of 'vertical', 'horizontal', false
      containment: element,    // also takes array of elements (or id's); or false
      handle:      false,      // or a CSS class
      only:        false,
      delay:       0,
      hoverclass:  null,
      ghosting:    false,
      quiet:       false, 
      scroll:      false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      format:      this.SERIALIZE_RULE,
      
      // these take arrays of elements or ids and can be 
      // used for better initialization performance
      elements:    false,
      handles:     false,
      
      onChange:    Prototype.emptyFunction,
      onUpdate:    Prototype.emptyFunction
    }, arguments[1] || {});

    // clear any old sortable with same element
    this.destroy(element);

    // build options for the draggables
    var options_for_draggable = {
      revert:      true,
      quiet:       options.quiet,
      scroll:      options.scroll,
      scrollSpeed: options.scrollSpeed,
      scrollSensitivity: options.scrollSensitivity,
      delay:       options.delay,
      ghosting:    options.ghosting,
      constraint:  options.constraint,
      handle:      options.handle };

    if(options.starteffect)
      options_for_draggable.starteffect = options.starteffect;

    if(options.reverteffect)
      options_for_draggable.reverteffect = options.reverteffect;
    else
      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
        element.style.top  = 0;
        element.style.left = 0;
      };

    if(options.endeffect)
      options_for_draggable.endeffect = options.endeffect;

    if(options.zindex)
      options_for_draggable.zindex = options.zindex;

    // build options for the droppables  
    var options_for_droppable = {
      overlap:     options.overlap,
      containment: options.containment,
      tree:        options.tree,
      hoverclass:  options.hoverclass,
      onHover:     Sortable.onHover
    }
    
    var options_for_tree = {
      onHover:      Sortable.onEmptyHover,
      overlap:      options.overlap,
      containment:  options.containment,
      hoverclass:   options.hoverclass
    }

    // fix for gecko engine
    Element.cleanWhitespace(element); 

    options.draggables = [];
    options.droppables = [];

    // drop on empty handling
    if(options.dropOnEmpty || options.tree) {
      Droppables.add(element, options_for_tree);
      options.droppables.push(element);
    }

    (options.elements || this.findElements(element, options) || []).each( function(e,i) {
      var handle = options.handles ? $(options.handles[i]) :
        (options.handle ? $(e).getElementsByClassName(options.handle)[0] : e); 
      options.draggables.push(
        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
      Droppables.add(e, options_for_droppable);
      if(options.tree) e.treeNode = element;
      options.droppables.push(e);      
    });
    
    if(options.tree) {
      (Sortable.findTreeElements(element, options) || []).each( function(e) {
        Droppables.add(e, options_for_tree);
        e.treeNode = element;
        options.droppables.push(e);
      });
    }

    // keep reference
    this.sortables[element.id] = options;

    // for onupdate
    Draggables.addObserver(new SortableObserver(element, options.onUpdate));

  },

  // return all suitable-for-sortable elements in a guaranteed order
  findElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.tag);
  },
  
  findTreeElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.treeTag);
  },

  onHover: function(element, dropon, overlap) {
    if(Element.isParent(dropon, element)) return;

    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
      return;
    } else if(overlap>0.5) {
      Sortable.mark(dropon, 'before');
      if(dropon.previousSibling != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, dropon);
        if(dropon.parentNode!=oldParentNode) 
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    } else {
      Sortable.mark(dropon, 'after');
      var nextElement = dropon.nextSibling || null;
      if(nextElement != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, nextElement);
        if(dropon.parentNode!=oldParentNode) 
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    }
  },
  
  onEmptyHover: function(element, dropon, overlap) {
    var oldParentNode = element.parentNode;
    var droponOptions = Sortable.options(dropon);
        
    if(!Element.isParent(dropon, element)) {
      var index;
      
      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
      var child = null;
            
      if(children) {
        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
        
        for (index = 0; index < children.length; index += 1) {
          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
            offset -= Element.offsetSize (children[index], droponOptions.overlap);
          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
            child = index + 1 < children.length ? children[index + 1] : null;
            break;
          } else {
            child = children[index];
            break;
          }
        }
      }
      
      dropon.insertBefore(element, child);
      
      Sortable.options(oldParentNode).onChange(element);
      droponOptions.onChange(element);
    }
  },

  unmark: function() {
    if(Sortable._marker) Sortable._marker.hide();
  },

  mark: function(dropon, position) {
    // mark on ghosting only
    var sortable = Sortable.options(dropon.parentNode);
    if(sortable && !sortable.ghosting) return; 

    if(!Sortable._marker) {
      Sortable._marker = 
        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
          hide().addClassName('dropmarker').setStyle({position:'absolute'});
      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
    }    
    var offsets = Position.cumulativeOffset(dropon);
    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
    
    if(position=='after')
      if(sortable.overlap == 'horizontal') 
        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
      else
        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
    
    Sortable._marker.show();
  },
  
  _tree: function(element, options, parent) {
    var children = Sortable.findElements(element, options) || [];
  
    for (var i = 0; i < children.length; ++i) {
      var match = children[i].id.match(options.format);

      if (!match) continue;
      
      var child = {
        id: encodeURIComponent(match ? match[1] : null),
        element: element,
        parent: parent,
        children: [],
        position: parent.children.length,
        container: $(children[i]).down(options.treeTag)
      }
      
      /* Get the element containing the children and recurse over it */
      if (child.container)
        this._tree(child.container, options, child)
      
      parent.children.push (child);
    }

    return parent; 
  },

  tree: function(element) {
    element = $(element);
    var sortableOptions = this.options(element);
    var options = Object.extend({
      tag: sortableOptions.tag,
      treeTag: sortableOptions.treeTag,
      only: sortableOptions.only,
      name: element.id,
      format: sortableOptions.format
    }, arguments[1] || {});
    
    var root = {
      id: null,
      parent: null,
      children: [],
      container: element,
      position: 0
    }
    
    return Sortable._tree(element, options, root);
  },

  /* Construct a [i] index for a particular node */
  _constructIndex: function(node) {
    var index = '';
    do {
      if (node.id) index = '[' + node.position + ']' + index;
    } while ((node = node.parent) != null);
    return index;
  },

  sequence: function(element) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[1] || {});
    
    return $(this.findElements(element, options) || []).map( function(item) {
      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
    });
  },

  setSequence: function(element, new_sequence) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[2] || {});
    
    var nodeMap = {};
    this.findElements(element, options).each( function(n) {
        if (n.id.match(options.format))
            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
        n.parentNode.removeChild(n);
    });
   
    new_sequence.each(function(ident) {
      var n = nodeMap[ident];
      if (n) {
        n[1].appendChild(n[0]);
        delete nodeMap[ident];
      }
    });
  },
  
  serialize: function(element) {
    element = $(element);
    var options = Object.extend(Sortable.options(element), arguments[1] || {});
    var name = encodeURIComponent(
      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
    
    if (options.tree) {
      return Sortable.tree(element, arguments[1]).children.map( function (item) {
        return [name + Sortable._constructIndex(item) + "[id]=" + 
                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
      }).flatten().join('&');
    } else {
      return Sortable.sequence(element, arguments[1]).map( function(item) {
        return name + "[]=" + encodeURIComponent(item);
      }).join('&');
    }
  }
}

// Returns true if child is contained within element
Element.isParent = function(child, element) {
  if (!child.parentNode || child == element) return false;
  if (child.parentNode == element) return true;
  return Element.isParent(child.parentNode, element);
}

Element.findChildren = function(element, only, recursive, tagName) {   
  if(!element.hasChildNodes()) return null;
  tagName = tagName.toUpperCase();
  if(only) only = [only].flatten();
  var elements = [];
  $A(element.childNodes).each( function(e) {
    if(e.tagName && e.tagName.toUpperCase()==tagName &&
      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
        elements.push(e);
    if(recursive) {
      var grandchildren = Element.findChildren(e, only, recursive, tagName);
      if(grandchildren) elements.push(grandchildren);
    }
  });

  return (elements.length>0 ? elements.flatten() : []);
}

Element.offsetSize = function (element, type) {
  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}
// script.aculo.us controls.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
//  Richard Livsey
//  Rahul Bhargava
//  Rob Wills
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// Autocompleter.Base handles all the autocompletion functionality 
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least, 
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method 
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most 
// useful when one of the tokens is \n (a newline), as it 
// allows smart autocompletion after linebreaks.

if(typeof Effect == 'undefined')
  throw("controls.js requires including script.aculo.us' effects.js library");

var Autocompleter = {}
Autocompleter.Base = function() {};
Autocompleter.Base.prototype = {
  baseInitialize: function(element, update, options) {
    element          = $(element)
    this.element     = element; 
    this.update      = $(update);  
    this.hasFocus    = false; 
    this.changed     = false; 
    this.active      = false; 
    this.index       = 0;     
    this.entryCount  = 0;

    if(this.setOptions)
      this.setOptions(options);
    else
      this.options = options || {};

    this.options.paramName    = this.options.paramName || this.element.name;
    this.options.tokens       = this.options.tokens || [];
    this.options.frequency    = this.options.frequency || 0.4;
    this.options.minChars     = this.options.minChars || 1;
    this.options.onShow       = this.options.onShow || 
      function(element, update){ 
        if(!update.style.position || update.style.position=='absolute') {
          update.style.position = 'absolute';
          Position.clone(element, update, {
            setHeight: false, 
            offsetTop: element.offsetHeight
          });
        }
        Effect.Appear(update,{duration:0.15});
      };
    this.options.onHide = this.options.onHide || 
      function(element, update){ new Effect.Fade(update,{duration:0.15}) };

    if(typeof(this.options.tokens) == 'string') 
      this.options.tokens = new Array(this.options.tokens);

    this.observer = null;
    
    this.element.setAttribute('autocomplete','off');

    Element.hide(this.update);

    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));

    // Turn autocomplete back on when the user leaves the page, so that the
    // field's value will be remembered on Mozilla-based browsers.
    Event.observe(window, 'beforeunload', function(){ 
      element.setAttribute('autocomplete', 'on'); 
    });
  },

  show: function() {
    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
    if(!this.iefix && 
      (Prototype.Browser.IE) &&
      (Element.getStyle(this.update, 'position')=='absolute')) {
      new Insertion.After(this.update, 
       '<iframe id="' + this.update.id + '_iefix" '+
       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
      this.iefix = $(this.update.id+'_iefix');
    }
    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
  },
  
  fixIEOverlapping: function() {
    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
    this.iefix.style.zIndex = 1;
    this.update.style.zIndex = 2;
    Element.show(this.iefix);
  },

  hide: function() {
    this.stopIndicator();
    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
    if(this.iefix) Element.hide(this.iefix);
  },

  startIndicator: function() {
    if(this.options.indicator) Element.show(this.options.indicator);
  },

  stopIndicator: function() {
    if(this.options.indicator) Element.hide(this.options.indicator);
  },

  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         Event.stop(event);
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_UP:
         this.markPrevious();
         this.render();
         if(Prototype.Browser.WebKit) Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.markNext();
         this.render();
         if(Prototype.Browser.WebKit) Event.stop(event);
         return;
      }
     else 
       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;

    this.changed = true;
    this.hasFocus = true;

    if(this.observer) clearTimeout(this.observer);
      this.observer = 
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
  },

  activate: function() {
    this.changed = false;
    this.hasFocus = true;
    this.getUpdatedChoices();
  },

  onHover: function(event) {
    var element = Event.findElement(event, 'LI');
    if(this.index != element.autocompleteIndex) 
    {
        this.index = element.autocompleteIndex;
        this.render();
    }
    Event.stop(event);
  },
  
  onClick: function(event) {
    var element = Event.findElement(event, 'LI');
    this.index = element.autocompleteIndex;
    this.selectEntry();
    this.hide();
  },
  
  onBlur: function(event) {
    // needed to make click events working
    setTimeout(this.hide.bind(this), 250);
    this.hasFocus = false;
    this.active = false;     
  }, 
  
  render: function() {
    if(this.entryCount > 0) {
      for (var i = 0; i < this.entryCount; i++)
        this.index==i ? 
          Element.addClassName(this.getEntry(i),"selected") : 
          Element.removeClassName(this.getEntry(i),"selected");
      if(this.hasFocus) { 
        this.show();
        this.active = true;
      }
    } else {
      this.active = false;
      this.hide();
    }
  },
  
  markPrevious: function() {
    if(this.index > 0) this.index--
      else this.index = this.entryCount-1;
    this.getEntry(this.index).scrollIntoView(true);
  },
  
  markNext: function() {
    if(this.index < this.entryCount-1) this.index++
      else this.index = 0;
    this.getEntry(this.index).scrollIntoView(false);
  },
  
  getEntry: function(index) {
    return this.update.firstChild.childNodes[index];
  },
  
  getCurrentEntry: function() {
    return this.getEntry(this.index);
  },
  
  selectEntry: function() {
    this.active = false;
    this.updateElement(this.getCurrentEntry());
  },

  updateElement: function(selectedElement) {
    if (this.options.updateElement) {
      this.options.updateElement(selectedElement);
      return;
    }
    var value = '';
    if (this.options.select) {
      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
    } else
      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
    
    var lastTokenPos = this.findLastToken();
    if (lastTokenPos != -1) {
      var newValue = this.element.value.substr(0, lastTokenPos + 1);
      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
      if (whitespace)
        newValue += whitespace[0];
      this.element.value = newValue + value;
    } else {
      this.element.value = value;
    }
    this.element.focus();
    
    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
  },

  updateChoices: function(choices) {
    if(!this.changed && this.hasFocus) {
      this.update.innerHTML = choices;
      Element.cleanWhitespace(this.update);
      Element.cleanWhitespace(this.update.down());

      if(this.update.firstChild && this.update.down().childNodes) {
        this.entryCount = 
          this.update.down().childNodes.length;
        for (var i = 0; i < this.entryCount; i++) {
          var entry = this.getEntry(i);
          entry.autocompleteIndex = i;
          this.addObservers(entry);
        }
      } else { 
        this.entryCount = 0;
      }

      this.stopIndicator();
      this.index = 0;
      
      if(this.entryCount==1 && this.options.autoSelect) {
        this.selectEntry();
        this.hide();
      } else {
        this.render();
      }
    }
  },

  addObservers: function(element) {
    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
  },

  onObserverEvent: function() {
    this.changed = false;   
    if(this.getToken().length>=this.options.minChars) {
      this.getUpdatedChoices();
    } else {
      this.active = false;
      this.hide();
    }
  },

  getToken: function() {
    var tokenPos = this.findLastToken();
    if (tokenPos != -1)
      var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
    else
      var ret = this.element.value;

    return /\n/.test(ret) ? '' : ret;
  },

  findLastToken: function() {
    var lastTokenPos = -1;

    for (var i=0; i<this.options.tokens.length; i++) {
      var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
      if (thisTokenPos > lastTokenPos)
        lastTokenPos = thisTokenPos;
    }
    return lastTokenPos;
  }
}

Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
  initialize: function(element, update, url, options) {
    this.baseInitialize(element, update, options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.url                   = url;
  },

  getUpdatedChoices: function() {
    this.startIndicator();
    
    var entry = encodeURIComponent(this.options.paramName) + '=' + 
      encodeURIComponent(this.getToken());

    this.options.parameters = this.options.callback ?
      this.options.callback(this.element, entry) : entry;

    if(this.options.defaultParams) 
      this.options.parameters += '&' + this.options.defaultParams;
    
    new Ajax.Request(this.url, this.options);
  },

  onComplete: function(request) {
    this.updateChoices(request.responseText);
  }

});

// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
//                    text only at the beginning of strings in the 
//                    autocomplete array. Defaults to true, which will
//                    match text at the beginning of any *word* in the
//                    strings in the autocomplete array. If you want to
//                    search anywhere in the string, additionally set
//                    the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
//                   a partial match (unlike minChars, which defines
//                   how many characters are required to do any match
//                   at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
//                 Defaults to true.
//
// It's possible to pass in a custom function as the 'selector' 
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.

Autocompleter.Local = Class.create();
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
  initialize: function(element, update, array, options) {
    this.baseInitialize(element, update, options);
    this.options.array = array;
  },

  getUpdatedChoices: function() {
    this.updateChoices(this.options.selector(this));
  },

  setOptions: function(options) {
    this.options = Object.extend({
      choices: 10,
      partialSearch: true,
      partialChars: 2,
      ignoreCase: true,
      fullSearch: false,
      selector: function(instance) {
        var ret       = []; // Beginning matches
        var partial   = []; // Inside matches
        var entry     = instance.getToken();
        var count     = 0;

        for (var i = 0; i < instance.options.array.length &&  
          ret.length < instance.options.choices ; i++) { 

          var elem = instance.options.array[i];
          var foundPos = instance.options.ignoreCase ? 
            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
            elem.indexOf(entry);

          while (foundPos != -1) {
            if (foundPos == 0 && elem.length != entry.length) { 
              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
                elem.substr(entry.length) + "</li>");
              break;
            } else if (entry.length >= instance.options.partialChars && 
              instance.options.partialSearch && foundPos != -1) {
              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
                  foundPos + entry.length) + "</li>");
                break;
              }
            }

            foundPos = instance.options.ignoreCase ? 
              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
              elem.indexOf(entry, foundPos + 1);

          }
        }
        if (partial.length)
          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
        return "<ul>" + ret.join('') + "</ul>";
      }
    }, options || {});
  }
});

// AJAX in-place editor
//
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor

// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
  setTimeout(function() {
    Field.activate(field);
  }, 1);
}

Ajax.InPlaceEditor = Class.create();
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
Ajax.InPlaceEditor.prototype = {
  initialize: function(element, url, options) {
    this.url = url;
    this.element = $(element);

    this.options = Object.extend({
      paramName: "value",
      okButton: true,
      okLink: false,
      okText: "ok",
      cancelButton: false,
      cancelLink: true,
      cancelText: "cancel",
      textBeforeControls: '',
      textBetweenControls: '',
      textAfterControls: '',
      savingText: "Saving...",
      clickToEditText: "Click to edit",
      okText: "ok",
      rows: 1,
      onComplete: function(transport, element) {
        new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
      },
      onFailure: function(transport) {
        alert("Error communicating with the server: " + transport.responseText.stripTags());
      },
      callback: function(form) {
        return Form.serialize(form);
      },
      handleLineBreaks: true,
      loadingText: 'Loading...',
      savingClassName: 'inplaceeditor-saving',
      loadingClassName: 'inplaceeditor-loading',
      formClassName: 'inplaceeditor-form',
      highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
      highlightendcolor: "#FFFFFF",
      externalControl: null,
      submitOnBlur: false,
      ajaxOptions: {},
      evalScripts: false
    }, options || {});

    if(!this.options.formId && this.element.id) {
      this.options.formId = this.element.id + "-inplaceeditor";
      if ($(this.options.formId)) {
        // there's already a form with that name, don't specify an id
        this.options.formId = null;
      }
    }
    
    if (this.options.externalControl) {
      this.options.externalControl = $(this.options.externalControl);
    }
    
    this.originalBackground = Element.getStyle(this.element, 'background-color');
    if (!this.originalBackground) {
      this.originalBackground = "transparent";
    }
    
    this.element.title = this.options.clickToEditText;
    
    this.onclickListener = this.enterEditMode.bindAsEventListener(this);
    this.mouseoverListener = this.enterHover.bindAsEventListener(this);
    this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
    Event.observe(this.element, 'click', this.onclickListener);
    Event.observe(this.element, 'mouseover', this.mouseoverListener);
    Event.observe(this.element, 'mouseout', this.mouseoutListener);
    if (this.options.externalControl) {
      Event.observe(this.options.externalControl, 'click', this.onclickListener);
      Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
      Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
    }
  },
  enterEditMode: function(evt) {
    if (this.saving) return;
    if (this.editing) return;
    this.editing = true;
    this.onEnterEditMode();
    if (this.options.externalControl) {
      Element.hide(this.options.externalControl);
    }
    Element.hide(this.element);
    this.createForm();
    this.element.parentNode.insertBefore(this.form, this.element);
    if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
    // stop the event to avoid a page refresh in Safari
    if (evt) {
      Event.stop(evt);
    }
    return false;
  },
  createForm: function() {
    this.form = document.createElement("form");
    this.form.id = this.options.formId;
    Element.addClassName(this.form, this.options.formClassName)
    this.form.onsubmit = this.onSubmit.bind(this);

    this.createEditField();

    if (this.options.textarea) {
      var br = document.createElement("br");
      this.form.appendChild(br);
    }
    
    if (this.options.textBeforeControls)
      this.form.appendChild(document.createTextNode(this.options.textBeforeControls));

    if (this.options.okButton) {
      var okButton = document.createElement("input");
      okButton.type = "submit";
      okButton.value = this.options.okText;
      okButton.className = 'editor_ok_button';
      this.form.appendChild(okButton);
    }
    
    if (this.options.okLink) {
      var okLink = document.createElement("a");
      okLink.href = "#";
      okLink.appendChild(document.createTextNode(this.options.okText));
      okLink.onclick = this.onSubmit.bind(this);
      okLink.className = 'editor_ok_link';
      this.form.appendChild(okLink);
    }
    
    if (this.options.textBetweenControls && 
      (this.options.okLink || this.options.okButton) && 
      (this.options.cancelLink || this.options.cancelButton))
      this.form.appendChild(document.createTextNode(this.options.textBetweenControls));
      
    if (this.options.cancelButton) {
      var cancelButton = document.createElement("input");
      cancelButton.type = "submit";
      cancelButton.value = this.options.cancelText;
      cancelButton.onclick = this.onclickCancel.bind(this);
      cancelButton.className = 'editor_cancel_button';
      this.form.appendChild(cancelButton);
    }

    if (this.options.cancelLink) {
      var cancelLink = document.createElement("a");
      cancelLink.href = "#";
      cancelLink.appendChild(document.createTextNode(this.options.cancelText));
      cancelLink.onclick = this.onclickCancel.bind(this);
      cancelLink.className = 'editor_cancel editor_cancel_link';      
      this.form.appendChild(cancelLink);
    }
    
    if (this.options.textAfterControls)
      this.form.appendChild(document.createTextNode(this.options.textAfterControls));
  },
  hasHTMLLineBreaks: function(string) {
    if (!this.options.handleLineBreaks) return false;
    return string.match(/<br/i) || string.match(/<p>/i);
  },
  convertHTMLLineBreaks: function(string) {
    return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
  },
  createEditField: function() {
    var text;
    if(this.options.loadTextURL) {
      text = this.options.loadingText;
    } else {
      text = this.getText();
    }

    var obj = this;
    
    if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
      this.options.textarea = false;
      var textField = document.createElement("input");
      textField.obj = this;
      textField.type = "text";
      textField.name = this.options.paramName;
      textField.value = text;
      textField.style.backgroundColor = this.options.highlightcolor;
      textField.className = 'editor_field';
      var size = this.options.size || this.options.cols || 0;
      if (size != 0) textField.size = size;
      if (this.options.submitOnBlur)
        textField.onblur = this.onSubmit.bind(this);
      this.editField = textField;
    } else {
      this.options.textarea = true;
      var textArea = document.createElement("textarea");
      textArea.obj = this;
      textArea.name = this.options.paramName;
      textArea.value = this.convertHTMLLineBreaks(text);
      textArea.rows = this.options.rows;
      textArea.cols = this.options.cols || 40;
      textArea.className = 'editor_field';      
      if (this.options.submitOnBlur)
        textArea.onblur = this.onSubmit.bind(this);
      this.editField = textArea;
    }
    
    if(this.options.loadTextURL) {
      this.loadExternalText();
    }
    this.form.appendChild(this.editField);
  },
  getText: function() {
    return this.element.innerHTML;
  },
  loadExternalText: function() {
    Element.addClassName(this.form, this.options.loadingClassName);
    this.editField.disabled = true;
    new Ajax.Request(
      this.options.loadTextURL,
      Object.extend({
        asynchronous: true,
        onComplete: this.onLoadedExternalText.bind(this)
      }, this.options.ajaxOptions)
    );
  },
  onLoadedExternalText: function(transport) {
    Element.removeClassName(this.form, this.options.loadingClassName);
    this.editField.disabled = false;
    this.editField.value = transport.responseText.stripTags();
    Field.scrollFreeActivate(this.editField);
  },
  onclickCancel: function() {
    this.onComplete();
    this.leaveEditMode();
    return false;
  },
  onFailure: function(transport) {
    this.options.onFailure(transport);
    if (this.oldInnerHTML) {
      this.element.innerHTML = this.oldInnerHTML;
      this.oldInnerHTML = null;
    }
    return false;
  },
  onSubmit: function() {
    // onLoading resets these so we need to save them away for the Ajax call
    var form = this.form;
    var value = this.editField.value;
    
    // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
    // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
    // to be displayed indefinitely
    this.onLoading();
    
    if (this.options.evalScripts) {
      new Ajax.Request(
        this.url, Object.extend({
          parameters: this.options.callback(form, value),
          onComplete: this.onComplete.bind(this),
          onFailure: this.onFailure.bind(this),
          asynchronous:true, 
          evalScripts:true
        }, this.options.ajaxOptions));
    } else  {
      new Ajax.Updater(
        { success: this.element,
          // don't update on failure (this could be an option)
          failure: null }, 
        this.url, Object.extend({
          parameters: this.options.callback(form, value),
          onComplete: this.onComplete.bind(this),
          onFailure: this.onFailure.bind(this)
        }, this.options.ajaxOptions));
    }
    // stop the event to avoid a page refresh in Safari
    if (arguments.length > 1) {
      Event.stop(arguments[0]);
    }
    return false;
  },
  onLoading: function() {
    this.saving = true;
    this.removeForm();
    this.leaveHover();
    this.showSaving();
  },
  showSaving: function() {
    this.oldInnerHTML = this.element.innerHTML;
    this.element.innerHTML = this.options.savingText;
    Element.addClassName(this.element, this.options.savingClassName);
    this.element.style.backgroundColor = this.originalBackground;
    Element.show(this.element);
  },
  removeForm: function() {
    if(this.form) {
      if (this.form.parentNode) Element.remove(this.form);
      this.form = null;
    }
  },
  enterHover: function() {
    if (this.saving) return;
    this.element.style.backgroundColor = this.options.highlightcolor;
    if (this.effect) {
      this.effect.cancel();
    }
    Element.addClassName(this.element, this.options.hoverClassName)
  },
  leaveHover: function() {
    if (this.options.backgroundColor) {
      this.element.style.backgroundColor = this.oldBackground;
    }
    Element.removeClassName(this.element, this.options.hoverClassName)
    if (this.saving) return;
    this.effect = new Effect.Highlight(this.element, {
      startcolor: this.options.highlightcolor,
      endcolor: this.options.highlightendcolor,
      restorecolor: this.originalBackground
    });
  },
  leaveEditMode: function() {
    Element.removeClassName(this.element, this.options.savingClassName);
    this.removeForm();
    this.leaveHover();
    this.element.style.backgroundColor = this.originalBackground;
    Element.show(this.element);
    if (this.options.externalControl) {
      Element.show(this.options.externalControl);
    }
    this.editing = false;
    this.saving = false;
    this.oldInnerHTML = null;
    this.onLeaveEditMode();
  },
  onComplete: function(transport) {
    this.leaveEditMode();
    this.options.onComplete.bind(this)(transport, this.element);
  },
  onEnterEditMode: function() {},
  onLeaveEditMode: function() {},
  dispose: function() {
    if (this.oldInnerHTML) {
      this.element.innerHTML = this.oldInnerHTML;
    }
    this.leaveEditMode();
    Event.stopObserving(this.element, 'click', this.onclickListener);
    Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
    Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
    if (this.options.externalControl) {
      Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
      Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
      Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
    }
  }
};

Ajax.InPlaceCollectionEditor = Class.create();
Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
  createEditField: function() {
    if (!this.cached_selectTag) {
      var selectTag = document.createElement("select");
      var collection = this.options.collection || [];
      var optionTag;
      collection.each(function(e,i) {
        optionTag = document.createElement("option");
        optionTag.value = (e instanceof Array) ? e[0] : e;
        if((typeof this.options.value == 'undefined') && 
          ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
        if(this.options.value==optionTag.value) optionTag.selected = true;
        optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
        selectTag.appendChild(optionTag);
      }.bind(this));
      this.cached_selectTag = selectTag;
    }

    this.editField = this.cached_selectTag;
    if(this.options.loadTextURL) this.loadExternalText();
    this.form.appendChild(this.editField);
    this.options.callback = function(form, value) {
      return "value=" + encodeURIComponent(value);
    }
  }
});

// Delayed observer, like Form.Element.Observer, 
// but waits for delay after last key input
// Ideal for live-search fields

Form.Element.DelayedObserver = Class.create();
Form.Element.DelayedObserver.prototype = {
  initialize: function(element, delay, callback) {
    this.delay     = delay || 0.5;
    this.element   = $(element);
    this.callback  = callback;
    this.timer     = null;
    this.lastValue = $F(this.element); 
    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
  },
  delayedListener: function(event) {
    if(this.lastValue == $F(this.element)) return;
    if(this.timer) clearTimeout(this.timer);
    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
    this.lastValue = $F(this.element);
  },
  onTimerEvent: function() {
    this.timer = null;
    this.callback(this.element, $F(this.element));
  }
};
// script.aculo.us slider.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs 
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(!Control) var Control = {};
Control.Slider = Class.create();

// options:
//  axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
//  onChange(value)
//  onSlide(value)
Control.Slider.prototype = {
  initialize: function(handle, track, options) {
    var slider = this;
    
    if(handle instanceof Array) {
      this.handles = handle.collect( function(e) { return $(e) });
    } else {
      this.handles = [$(handle)];
    }
    
    this.track   = $(track);
    this.options = options || {};

    this.axis      = this.options.axis || 'horizontal';
    this.increment = this.options.increment || 1;
    this.step      = parseInt(this.options.step || '1');
    this.range     = this.options.range || $R(0,1);
    
    this.value     = 0; // assure backwards compat
    this.values    = this.handles.map( function() { return 0 });
    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
    this.options.startSpan = $(this.options.startSpan || null);
    this.options.endSpan   = $(this.options.endSpan || null);

    this.restricted = this.options.restricted || false;

    this.maximum   = this.options.maximum || this.range.end;
    this.minimum   = this.options.minimum || this.range.start;

    // Will be used to align the handle onto the track, if necessary
    this.alignX = parseInt(this.options.alignX || '0');
    this.alignY = parseInt(this.options.alignY || '0');
    
    this.trackLength = this.maximumOffset() - this.minimumOffset();

    this.handleLength = this.isVertical() ? 
      (this.handles[0].offsetHeight != 0 ? 
        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
        this.handles[0].style.width.replace(/px$/,""));

    this.active   = false;
    this.dragging = false;
    this.disabled = false;

    if(this.options.disabled) this.setDisabled();

    // Allowed values array
    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
    if(this.allowedValues) {
      this.minimum = this.allowedValues.min();
      this.maximum = this.allowedValues.max();
    }

    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
    this.eventMouseMove = this.update.bindAsEventListener(this);

    // Initialize handles in reverse (make sure first handle is active)
    this.handles.each( function(h,i) {
      i = slider.handles.length-1-i;
      slider.setValue(parseFloat(
        (slider.options.sliderValue instanceof Array ? 
          slider.options.sliderValue[i] : slider.options.sliderValue) || 
         slider.range.start), i);
      Element.makePositioned(h); // fix IE
      Event.observe(h, "mousedown", slider.eventMouseDown);
    });
    
    Event.observe(this.track, "mousedown", this.eventMouseDown);
    Event.observe(document, "mouseup", this.eventMouseUp);
    Event.observe(document, "mousemove", this.eventMouseMove);
    
    this.initialized = true;
  },
  dispose: function() {
    var slider = this;    
    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
    Event.stopObserving(document, "mouseup", this.eventMouseUp);
    Event.stopObserving(document, "mousemove", this.eventMouseMove);
    this.handles.each( function(h) {
      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
    });
  },
  setDisabled: function(){
    this.disabled = true;
  },
  setEnabled: function(){
    this.disabled = false;
  },  
  getNearestValue: function(value){
    if(this.allowedValues){
      if(value >= this.allowedValues.max()) return(this.allowedValues.max());
      if(value <= this.allowedValues.min()) return(this.allowedValues.min());
      
      var offset = Math.abs(this.allowedValues[0] - value);
      var newValue = this.allowedValues[0];
      this.allowedValues.each( function(v) {
        var currentOffset = Math.abs(v - value);
        if(currentOffset <= offset){
          newValue = v;
          offset = currentOffset;
        } 
      });
      return newValue;
    }
    if(value > this.range.end) return this.range.end;
    if(value < this.range.start) return this.range.start;
    return value;
  },
  setValue: function(sliderValue, handleIdx){
    if(!this.active) {
      this.activeHandleIdx = handleIdx || 0;
      this.activeHandle    = this.handles[this.activeHandleIdx];
      this.updateStyles();
    }
    handleIdx = handleIdx || this.activeHandleIdx || 0;
    if(this.initialized && this.restricted) {
      if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
        sliderValue = this.values[handleIdx-1];
      if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
        sliderValue = this.values[handleIdx+1];
    }
    sliderValue = this.getNearestValue(sliderValue);
    this.values[handleIdx] = sliderValue;
    this.value = this.values[0]; // assure backwards compat
    
    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
      this.translateToPx(sliderValue);
    
    this.drawSpans();
    if(!this.dragging || !this.event) this.updateFinished();
  },
  setValueBy: function(delta, handleIdx) {
    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
      handleIdx || this.activeHandleIdx || 0);
  },
  translateToPx: function(value) {
    return Math.round(
      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
      (value - this.range.start)) + "px";
  },
  translateToValue: function(offset) {
    return ((offset/(this.trackLength-this.handleLength) * 
      (this.range.end-this.range.start)) + this.range.start);
  },
  getRange: function(range) {
    var v = this.values.sortBy(Prototype.K); 
    range = range || 0;
    return $R(v[range],v[range+1]);
  },
  minimumOffset: function(){
    return(this.isVertical() ? this.alignY : this.alignX);
  },
  maximumOffset: function(){
    return(this.isVertical() ? 
      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
        this.track.style.height.replace(/px$/,"")) - this.alignY : 
      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
        this.track.style.width.replace(/px$/,"")) - this.alignY);
  },  
  isVertical:  function(){
    return (this.axis == 'vertical');
  },
  drawSpans: function() {
    var slider = this;
    if(this.spans)
      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
    if(this.options.startSpan)
      this.setSpan(this.options.startSpan,
        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
    if(this.options.endSpan)
      this.setSpan(this.options.endSpan, 
        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
  },
  setSpan: function(span, range) {
    if(this.isVertical()) {
      span.style.top = this.translateToPx(range.start);
      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
    } else {
      span.style.left = this.translateToPx(range.start);
      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
    }
  },
  updateStyles: function() {
    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
    Element.addClassName(this.activeHandle, 'selected');
  },
  startDrag: function(event) {
    if(Event.isLeftClick(event)) {
      if(!this.disabled){
        this.active = true;
        
        var handle = Event.element(event);
        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
        var track = handle;
        if(track==this.track) {
          var offsets  = Position.cumulativeOffset(this.track); 
          this.event = event;
          this.setValue(this.translateToValue( 
           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
          ));
          var offsets  = Position.cumulativeOffset(this.activeHandle);
          this.offsetX = (pointer[0] - offsets[0]);
          this.offsetY = (pointer[1] - offsets[1]);
        } else {
          // find the handle (prevents issues with Safari)
          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
            handle = handle.parentNode;
            
          if(this.handles.indexOf(handle)!=-1) {
            this.activeHandle    = handle;
            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
            this.updateStyles();
            
            var offsets  = Position.cumulativeOffset(this.activeHandle);
            this.offsetX = (pointer[0] - offsets[0]);
            this.offsetY = (pointer[1] - offsets[1]);
          }
        }
      }
      Event.stop(event);
    }
  },
  update: function(event) {
   if(this.active) {
      if(!this.dragging) this.dragging = true;
      this.draw(event);
      if(Prototype.Browser.WebKit) window.scrollBy(0,0);
      Event.stop(event);
   }
  },
  draw: function(event) {
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    var offsets = Position.cumulativeOffset(this.track);
    pointer[0] -= this.offsetX + offsets[0];
    pointer[1] -= this.offsetY + offsets[1];
    this.event = event;
    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
    if(this.initialized && this.options.onSlide)
      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
  },
  endDrag: function(event) {
    if(this.active && this.dragging) {
      this.finishDrag(event, true);
      Event.stop(event);
    }
    this.active = false;
    this.dragging = false;
  },  
  finishDrag: function(event, success) {
    this.active = false;
    this.dragging = false;
    this.updateFinished();
  },
  updateFinished: function() {
    if(this.initialized && this.options.onChange) 
      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
    this.event = null;
  }
}/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 574 $
 * $LastChangedDate: 2008-05-19 19:23:43 +0200 (Mon, 19 May 2008) $
 */


Void = function( ) { };

Info = function( info ) {
	if( window.console && window.console.info ) {
		window.console.info( info );
	}
}

Error = function( info ) {
	if( window.console && window.console.error ) {
		window.console.error( info );
	} /*else {
		if( info.message ) {
			alert( info.message );
		} else {
			alert( info );
		}
	}*/
}

Warning = function( info ) {
	if( window.console && window.console.warn ) {
		window.console.warn( info );
	}
}

isTypeOf = function( __o__ , __type__ ) {
	if( typeof( __o__ ) == __type__ ) {
		return true;
	}
	return false;
}

isUndefined = function( __o__ ) {
	return isTypeOf( __o__ , 'undefined' );
}

isObject = function( __o__ ) {
	return isTypeOf( __o__ , 'object' ) || isTypeOf( __o__ , 'function' );
}

isString = function( __o__ ) {
	return isTypeOf( __o__ , 'string' );
}

isNumber = function( __o__ ) {
	return isTypeOf( __o__ , 'number' );
}

isBool = function( __o__ ) {
	return isTypeOf( __o__ , 'boolean' );
}

function pageSize( ){
	try {
		if(window.innerHeight && window.scrollMaxY) {	
			var scrollX = document.body.scrollWidth;
			var scrollY = window.innerHeight + window.scrollMaxY;
		} else if(document.body && document.body.scrollHeight && document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			var scrollX = document.body.scrollWidth;
			var scrollY = document.body.scrollHeight;
		} else if( document.body ) {
			var scrollX = document.body.offsetWidth;
			var scrollY = document.body.offsetHeight;
		} else {
			throw( "pageSize() - scrollX & scrollY error" );
		}
		
		if( self.innerHeight ) {
			var windowX = self.innerWidth;
			var windowY = self.innerHeight;
		} else if( document.documentElement && document.documentElement.clientHeight ) { // Explorer 6 Strict Mode
			var windowX = document.documentElement.clientWidth;
			var windowY = document.documentElement.clientHeight;
		} else if( document.body ) {
			var windowX = document.body.clientWidth;
			var windowY = document.body.clientHeight;
		} else {
			throw( "pageSize() - windowX & windowY error" );
		}
		
		if(scrollY < windowY){
			var pageY = windowY;
		} else { 
			var pageY = scrollY;
		}
	
		if(scrollX < windowX){	
			var pageX = windowX;
		} else {
			var pageX = scrollX;
		}
	} catch( e ) {
		if( window.console && window.console.error ) {
			window.console.error( e.toString( ) );
		} else {
			alerr( e.toString( ) );
		}
		return { pageX : 0 , pageY : 0 , windowX : 0 , windowY : 0 };
	}
	return { pageX : pageX , pageY : pageY , windowX : windowX , windowY : windowY };
}


function boxPosition( dbox ) {
	if( ! isObject( dbox ) ) {
		dbox = $( dbox );
	}
	if( dbox.getBoundingClientRect ) {
		box = dbox.getBoundingClientRect( );
		sT  = document.documentElement.scrollTop || document.body.scrollTop;
		aT  = document.documentElement.scrollLeft || document.body.scrollLeft;
		x   = box.left + aT;
		y   = box.top  + sT;
	} else if( document.getBoxObjectFor ) {
		box = document.getBoxObjectFor( dbox );
		x   = box.x;
		y   = box.y;
	} else {
		y   = dbox.offsetTop;
		x   = dbox.offsetLeft
		dbp = dbox.offsetParent;
		if( dbp != dbox ) {
			while( dbp ) {
				x     += dbp.offsetLeft;
				y     += dbp.offsetTop;
				dbp    = dbp.offsetParent;
			}
		}
		var ua = navigator.userAgent.toLowerCase( );
		if ( ua.indexOf( 'opera' ) != -1 ) {
			x -= document.body.offsetLeft;
			y -= document.body.offsetTop;
		}
	}
	return { x : x , y : y };
}

checkEmail = function( email , raise_error ) {
	if( ! email.match( /^[a-z0-9]+([_\.\-]{1}[a-z0-9]+)*@([a-z0-9]+(\-[a-z0-9]+)*\.)+[a-z]{2,5}$/i ) ) {
		if( ! isUndefined( raise_error ) && raise_error ) {
			Notice.error( lang_errors['email_incorrect'] );
		}
		return false;
	}
	return true;
}

var M_BASIC_LIB = true;
/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 77 $
 * $LastChangedDate: 2007-02-07 19:23:11 +0100 (Wed, 07 Feb 2007) $
 */


Array.prototype.isIn = function( __nString , __inCaseSensitive , __isOnlyPart ) {
	if( typeof( __inCaseSensitive ) == 'undefined' ) {
		__inCaseSensitive = false;
	} else if( __inCaseSensitive == true ) {
		__nString = __nString.toLowerCase( );
	}
	
	if( typeof( __isOnlyPart ) == 'undefined' ) {
		__isOnlyPart = -1;
	}
	
	for( var __hPos=0 ; __hPos<this.length ; ++__hPos ) {
		var __aWord = this[__hPos];
		if( __inCaseSensitive ) {
			__aWord = __aWord.toLowerCase( );
		}
		if( __aWord == __nString ) {
			return true;
		}
		if( __isOnlyPart == 0 && __aWord.indexOf( __nString ) == 0 ) {
			return true;
		} else if( __isOnlyPart == 1 && __aWord.indexOf( __nString ) > -1 ) {
			return true;
		}
	}
	return false;
}

Array.prototype.pushUnique = function( __nString , __inCaseSensitive ) {
	if( typeof( __inCaseSensitive ) == 'undefined' ) {
		__inCaseSensitive = false;
	} else if( __inCaseSensitive == true ) {
		__nString = __nString.toLowerCase( );
	}
	
	for( var __hPos=0 ; __hPos<this.length ; ++__hPos ) {
		var __aWord = this[__hPos];
		if( __inCaseSensitive ) {
			__aWord = __aWord.toLowerCase( );
		}
		if( __aWord == __nString ) {
			return;
		}
	}
	this.push( __nString );
}

Array.prototype.getUnique = function( __inCaseSensitive ) {
	var __tmpArray = new Array( );
	for( var __tPos=0 ; __tPos<this.length ; ++__tPos ) {
		__tmpArray.pushUnique( this[__tPos] , __inCaseSensitive );
	}
	return __tmpArray;
}

Array.prototype.removeEmpty = function( ) {
	var __tmpArray = new Array( );
	for( var __ePos=0 ; __ePos<this.length ; ++__ePos ) {
		__tpO = typeof( this[__ePos] );
		if( __tpO != 'undefined' && ( __tpO != 'string' || __tpO.length > 0 ) ) {
			__tmpArray.push( this[__ePos] );
		}
	}
	return __tmpArray;
}


var M_ARRAY_LIB = true;/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 661 $
 * $LastChangedDate: 2008-09-30 19:11:52 +0200 (Tue, 30 Sep 2008) $
 */


/**
 * usuwa biale znagi przed i po ciagu znakow
 */
String.prototype.trim = function(){	return this.replace( /^\s+|\s+$/ , ''); }

/**
 * zamienia znaki nowej linii na znaczniki <br/>
 */
String.prototype.nl2br = function(){ return this.replace( /\n/g ,'<br />' ); }

/**
 * zamienia biale znaki na spacje
 * wielokrotnosci bialych znakow zostaja zamienione na pojedyncz spacje
 */
String.prototype.cutSpaces = function() { return this.replace( /\s+/g ,' '); }

function strPad( padStr , padLength , padDir , padChar ) {
   	if( typeof( padChar ) != 'string' ) {
   		padChar = ' ';
   	}
   	if( typeof( padDir ) != 'number' ) {
   		padDir = 1;
   	}
   	if( typeof( oStr ) != 'string' ) {
   		padStr = padStr + '';
   	}
   	if( typeof( padLength ) != 'number' || padLength <= 0 ) {
   		return padStr;
   	}
   	padLast = false;
   	while( padStr.length < padLength ) {
   		if( padDir > 0 || ( padDir == 0 && padLast ) ) {
   			padStr += padChar;
   			padLast = false;
   		} else if( padDir < 0 || ( padDir == 0 && ! padLast ) ) {
   			padStr  = padChar + '' + padStr 
   			padLast = true;
   		}
   	}
	return padStr;
}

String.prototype.ucFirst = function () {
   return this.substr(0,1).toUpperCase() + this.substr(1,this.length).toLowerCase();
}

/*String.prototype.ucWords = function(){ //v1.0
    return this.replace(/\b[^_\.\s\-]+/gi, function(a){
        return a.substr(0,1).toUpperCase() + a.substr(1).toLowerCase();
    });
};*/

String.prototype.htmlEntities = function()
{
  /*var chars = new Array ('&','ŕ','á','â','ă','ä','ĺ','ć','ç','č','é',
                         'ę','ë','ě','í','î','ď','đ','ń','ň','ó','ô',
                         'ő','ö','ř','ů','ú','ű','ü','ý','ţ','˙','Ŕ',
                         'Á','Â','Ă','Ä','Ĺ','Ć','Ç','Č','É','Ę','Ë',
                         'Ě','Í','Î','Ď','Đ','Ń','Ň','Ó','Ô','Ő','Ö',
                         'Ř','Ů','Ú','Ű','Ü','Ý','Ţ','�','\"','ß','<',
                         '>','˘','Ł','¤','Ľ','Ś','§','¨','Š','Ş','Ť',
                         'Ź','­','Ž','Ż','°','ą','˛','ł','´','ľ','ś',
                         'ˇ','¸','š','ş','ť','ź','˝','ž');

  var entities = new Array ('amp','agrave','aacute','acirc','atilde','auml','aring',
                            'aelig','ccedil','egrave','eacute','ecirc','euml','igrave',
                            'iacute','icirc','iuml','eth','ntilde','ograve','oacute',
                            'ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc',
                            'uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc',
                            'Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute',
                            'Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde',
                            'Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave',
                            'Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig',
                            'lt','gt','cent','pound','curren','yen','brvbar','sect','uml',
                            'copy','ordf','laquo','not','shy','reg','macr','deg','plusmn',
                            'sup2','sup3','acute','micro','para','middot','cedil','sup1',
                            'ordm','raquo','frac14','frac12','frac34');

  newString = this;
  for (var i = 0; i < chars.length; i++)
  {
    myRegExp = new RegExp();
    myRegExp.compile(chars[i],'g')
    newString = newString.replace (myRegExp, '&' + entities[i] + ';');
  } */
  var newString = this;
  newString = newString.replace( '&' , '&amp;' );
  newString = newString.replace( '<' , '&lt;' );
  newString = newString.replace( '>' , '&gt;' );
  newString = newString.replace( '"' , '&quot;' );
  return newString;
}

String.prototype.nonPol = function( ) {
	var str = this;
	var ch = { 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's', 'ź': 'z', 'ż': 'z', 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S', 'Ź': 'Z', 'Ż': 'Z'};
	for( k in ch ) {
		v = ch[k];
		str = str.replace( k , v );
	}
	return str;
}

String.prototype.toUrl = function( ) {
	str = this.nonPol( );
	str = str.toLowerCase( );
	str = str.trim( );
	str = str.replace( /\s+/ , '_' );
	str = str.replace( /[^a-z0-9_\-.]+/ , '' );
	return str;
}

String.prototype.nl2p = function( css ) {
	var tmp = this.trim().split( /(\r)?\n/ );
	var str = '';
	var s   = '<p' + ( css ? 'class="' + css + '"' : '' ) + '>';
	for( var i=0 ; i<tmp.length ; ++i ) {
		if( ! isString( tmp[i] ) ) {
			continue;
		}
		tmp[i] = tmp[i].trim( ).htmlEntities( );
		if( tmp[i] != '' ) {
			str += s + tmp[i] + '</p>';
		} else {
			str += s + '&nbsp;</p>';
		}
	}
	return str;
}

var M_STRING_LIB = true;
/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 414 $
 * $LastChangedDate: 2007-11-20 23:05:31 +0100 (Tue, 20 Nov 2007) $
 */

if( typeof( M_ERR ) == 'undefined' ) {
	M_ERR = '';
	if( typeof( Class.create ) == 'undefined' ) {
		M_ERR += ( M_ERR ? ', ' : '' ) + 'prototype.lib.js';
	}
	if( typeof( M_BASIC_LIB ) == 'undefined' ) {
		M_ERR += ( M_ERR ? ', ' : '' ) + 'basic.lib.js';
	}
	if( M_ERR ) {
		alert( 'dc.lib dependecies error\n-------------\nload libraries:\n'+M_ERR );
	}
}

RC = function( oElement ) {
	if( isString( oElement ) ) {
		oElement = $( oElement );
	}
	while( oElement.childNodes.length ) {
		oElement.removeChild( oElement.childNodes[0] );
	}
}

FP = function( oElement ) {
	if( isString( oElement ) ) {
		oElement = $( oElement );
	}
	oElement.parentNode.removeChild( oElement );
}

App = function( __oParent__ , __oChild__ ) {
	if( isString( __oParent__ ) ) {
		__oParent__ = $( __oParent__ );
	}
	if( isString( __oChild__ ) ) {
		__oChild__ = $( __oChild__ );
	}
	__oParent__.appendChild( __oChild__ );
}

SA = function( __obj , __name , __value ) {
	if( ! isString( __value ) && ! isNumber( __value ) ) {
		__value = '';
	}
	
	__obj.setAttribute( __name , __value );
}

GA = function( oObj , sAttrib ) {
	if( isString( oObj ) ) {
		oObj = $( oObj );
	}
	if( isObject( oObj ) ) {
		return oObj.getAttribute( sAttrib );
	}
	return '';
}

Txt = function( __text__ ) {
	return document.createTextNode( __text__ );
}


DC = function( __elementName__ ) {
	return document.createElement( __elementName__ );
}


DCDiv = function( __divID__ , __divText__ ) {
	__o__ = DC( 'div' );
	if( isString( __divID__ ) ) {
		__o__.setAttribute( 'id' , __divID__ );
	}
	
	if( isString( __divText__ ) || isNumber( __divText__ ) ) {
		App( __o__ , Txt( __divText__ ) );
	} else if( isObject( __divText__ ) ) {
		App( __o__ , __divText__ );
	}
	
	return __o__;
}

DCSpan = function( __divID__ , __divText__ ) {
	__o__ = DC( 'span' );
	if( isString( __divID__ ) ) {
		__o__.setAttribute( 'id' , __divID__ );
	}
	
	if( isString( __divText__ ) || isNumber( __divText__ ) ) {
		App( __o__ , Txt( __divText__ ) );
	} else if( isObject( __divText__ ) ) {
		App( __o__ , __divText__ );
	}
	
	return __o__;
}

DCP = function( __divID__ , __divText__ ) {
	__o__ = DC( 'p' );
	if( isString( __divID__ ) && __divID__ ) {
		__o__.setAttribute( 'id' , __divID__ );
	}
	
	if( isString( __divText__ ) || isNumber( __divText__ ) ) {
		App( __o__ , Txt( __divText__ ) );
	} else if( isObject( __divText__ ) ) {
		App( __o__ , __divText__ );
	}
	
	return __o__;
}

DCImg = function( __src__ , __alt__ , __title__ ) {
	var __oImg__ = DC( 'img' );
	__oImg__.src = __src__;
	if( ! isString( __alt__ ) ) {
		__alt__ = '';
	}
	__oImg__.setAttribute( 'alt' , __alt__ );
	if( isString( __title__ ) ) {
		__oImg__setAttribute( 'title' , __title__ );
	}
	return __oImg__;
}

DCA = function( __href__ , __text__ , __id__ ) {
	var __oA__ = DC( 'a' );
	__oA__.setAttribute( 'href' , __href__ );
	if( isString( __text__ ) || isNumber( __text__ ) ) {
		App( __oA__ , Txt( __text__ ) );
	} else if( isObject( __text__ ) ) {
		App( __oA__ , __text__ );
	}
	if( isString( __id__ ) ) {
		__oA__.id = __id__;
	}
	return __oA__;
}

DCSpacer = function(  ) {
	var __spc__ = DCDiv( );
	__spc__.className = 'spacer';
	__spc__.innerHTML = '&nbsp;';
	return __spc__;
}

DCBtn = function( __imgName__ , __onClk__ , __title__ ) {
	if( ! __imgName__.match( /\.(jpg|jpeg|gif|png)$/ ) ) {
		__imgName__ += '.gif';
	}
	__btn__ = DCImg( URL_IMAGES + 'buttons/' + LANG + '/' + __imgName__ );
	if( isObject( __onClk__ ) ) {
		__btn__.onclick = __onClk__;
		__btn__.className = 'button';
	} else if( isString( __onClk__ ) ) {
		eval( '__btn__.onclick = function( ) { ' + __onClk__ + ' };' );
		__btn__.className = 'button';
	}
	if( isString( __title__ ) && __title__ ) {
		__btn__.setAttribute( 'title' , __title__ );
	}
	return __btn__;
}

DCABtn = function( __imgName__ , __href__ , __title__ , __target__ ) {
	var __btn__ = DCBtn( __imgName__ , undefined , __title__ );
	__btn__.className = 'button';
	__btn__ = DCA( __href__ , __btn__ );
	if( isString( __title__ ) && __title__ ) {
		__btn__.setAttribute( 'title' , __title__ );
	}
	if( isString( __target__ ) && __target__ ) {
		__btn__.setAttribute( 'target' , __target__ );
	}
	return __btn__;
}

DCIco = function( __imgName__ , __title__ ) {
	if( ! __imgName__.match( /\.(jpg|gif|png)$/ ) ) {
		__imgName__ += '.gif';
	}
	return DCImg( URL_IMAGES + 'icons/' + __imgName__ )
}

DCPre = function( __txt__ ) {
	__pre__ = DC( 'pre' );
	if( isString( __txt__ ) ) {
		App( __pre__ , Txt( __txt__ ) );
	}
	return __pre__;
}

DCInp = function( __type__ , __id__ , __name__ , __value__ , __css__ ) {
	var __inp__ = DC( 'input' );
	if( isString( __type__ ) && __type__ ) {
		__inp__.setAttribute( 'type' , __type__ );
	}
	
	if( isString( __id__ ) && __id__ ) {
		__inp__.setAttribute( 'id' , __id__ );
	}
	
	if( isString( __name__ ) && __name__ ) {
		__inp__.setAttribute( 'name' , __name__ );
	}
	
	if( ( isString( __value__ ) && __value__ ) || isNumber( __value__ ) ) {
		__inp__.setAttribute( 'value' , __value__ );
	}
	
	if( isString( __css__ ) && __css__ ) {
		__inp__.className = __css__;
	}
	
	return __inp__;
}

DCTxtAr = function( __id , __name , __value , __css ) {
	var tarea = DC( 'textarea' );
	if( isString( __id ) && __id ) {
		SA( tarea , 'id' , __id );
	}
	if( isString( __name ) &&  __name ) {
		SA( tarea , 'name' , __name );
	}
	if( isString( __value ) || isNumber( __value ) ) {
		App( tarea , Txt( __value ) );
	} else if( isObject( __value ) ) {
		App( tarea , __value );
	}
	if( isString( __css ) && __css ) {
		tarea.className = __css;
	}
	return tarea;
}

DCSel = function( __id__ , __name__ , __css__ ) {
	var __sel__ = DC( 'select' );
	
	if( isString( __id__ ) && __id__  ) {
		__sel__.setAttribute( 'id' , __id__ );
	}
	
	if( isString( __name__ ) && __name__ ) {
		__sel__.setAttribute( 'name' , __name__ );
	}
	
	if( isString( __css__ ) && __css__ ) {
		__sel__.className = __css__;
	}
	
	return __sel__;
}

DCOpt = function( __value__ , __text__ , __selected__ ) {
	var __opt__ = DC( 'option' );
	
	if( isNumber( __value__ ) || ( isString( __value__ ) && __value__ ) ) {
		if( ! isNumber( __text__ ) && ( ! isString( __text__ ) || ! __text__ ) ) {
			__text__ = __value__;
		}
		__opt__.setAttribute( 'value' , __value__ );
	}
	
	if( isNumber( __text__ ) || ( isString( __text__ ) && __text__ ) ) {
		App( __opt__ , Txt( __text__ ) );
	}
	
	if( ! isUndefined( __selected__ ) && __selected__ ) {
		SA( __opt__ , 'selected' , 'selected' );
	}
	
	return __opt__;
}

DCUl = function( __id__ , __class__ ) {
	var __ul__ = DC( 'ul' );
	if( isString( __id__ ) && __id__ ) {
		__ul__.setAttribute( 'id' , __id__ );
	}
	if( isString( __class__ ) && __class__ ) {
		__ul__.className = __class__;
	}
	return __ul__;
}

DCLi = function( __id__ , __txt__ , __class__ ) {
	var __li__ = DC( 'li' );
	if( isString( __id__ ) && __id__ ) {
		__li__.setAttribute( 'id' , __id__ );
	}
	if( isString( __txt__ ) ) {
		App( __li__ , Txt( __txt__ ) );
	} else if( isObject( __txt__ ) ) {
		App( __li__ , __txt__ );
	}
	if( isString( __class__ ) && __class__ ) {
		__li__.className = __class__;
	}
	return __li__;
}


DCForm = function( __action , __id , __target , __enctype , __method ) {
	var form = DC( 'form' );
	if( ! isString( __action ) ) {
		__action = '';
	}
	SA( form , 'action' , __action );
	if( isString( __id ) ) {
		SA( form , 'id' , __id );
	}
	if( isString( __target ) ) {
		SA( form , 'target' , __target );
	}
	if( isString( __enctype ) ) {
		SA( form , 'enctype' , __enctype );
	}
	if( ! isString( __method ) ) {
		__method = 'post';
	}
	SA( form , 'method' , __method );
	return form;
}

DCLab = function( __text , __for ) {
	var label = DC( 'label' );
	if( isString( __text ) || isNumber( __text ) ) {
		App( label , Txt( __text ) );
	} else if( isObject( __text ) ) {
		App( label , __text );
	}
	
	if( isString( __for ) ) {
		SA( label , 'for' , __for );
	}
	return label;
}

DCBq = function( text , cName , id ) {
	var bq = DC( 'blockquote' );
	if( isString( text ) ) {
		text = Txt( text );
	}
	if( isObject( text ) ) {
		App( bq , text );
	}
	if( isString( cName ) && cName ) {
		bq.className = cName;
	}
	if( isString( id ) && id ) {
		SA( bq , 'id' , id );
	}
	return bq;
}

DCCite = function( text , cName , id ) {
	var ct = DC( 'cite' );
	if( isString( text ) ) {
		text = Txt( text );
	}
	if( isObject( text ) ) {
		App( ct , text );
	}
	if( isString( cName ) && cName ) {
		ct.className = cName;
	}
	if( isString( id ) && id ) {
		SA( ct , 'id' , id );
	}
	return ct;
}

DCPs = function( text , pNode , pClass ) {
	if( isString( pNode ) ) {
		pNode = $( pNode );
	}
	text = text.replace( /\r/g , '' );
	text = text.split( '\n' );
	for( var i=0 ; i<text.length ; ++i ) {
		var line = text[i];
		var p = DCP( );
		if( isString( pClass ) && pClass ) {
			p.className = pClass;
		}
		line = line.htmlEntities( );
		if( line == '' || line == ' ' ) {
			line = '&nbsp;';
		} else {
			line = line.replace( /\ \ / , '&nbsp; ' );
			line = line.replace( /\ \ / , '&nbsp; ' );
		}
		p.innerHTML = line;
		App( pNode , p );
	}
}

function Inserter( elementS , elementI , insertType ) {
	var eID = '';
	if( isString( elementS ) ) {
		elementS = $( elementS );
	}
	if( isUndefined( insertType ) || insertType == 'top' || insertType == 'bottom' ) {
		var cn = elementS.childNodes;
		App( elementS , elementI );
		if( insertType == 'top' ) {
			for( var i=0 ; i<cn.length ; ++i ) {
				App( elementS , cn[i] );
			}
		}
	} else if( elementS.parentNode && ( eID = elementS.getAttribute( 'id' ) ) ) {
		var pr = elementS.parentNode;
		var tmp = new Array( );
		for( var i=0 ; i<pr.childNodes.length ; ++i ) {
			tmp.push( pr.childNodes[i] );
		}
		while( tmp.length > 0 ) {
			var cn = tmp.shift( );
			if( insertType == 'before' && cn.getAttribute && cn.getAttribute( 'id' ) == eID ) {
				App( pr , elementI );
			}
			App( pr , cn );
			if( insertType == 'after' && cn.getAttribute && cn.getAttribute( 'id' ) == eID ) {
				App( pr , elementI );
			}
		}
	}
}

function MoveTop( BoxID ) {
	__Mover( BoxID , 'Top' );
}

function MoveBottom( BoxID ) {
	__Mover( BoxID , 'Bottom' );
}

function MoveBefore( BoxID , NextBoxID ) {
	__Mover( BoxID , 'Before' , NextBoxID );
}

function MoveAfter( BoxID , PreviousBoxID ) {
	__Mover( BoxID , 'After' , PreviousBoxID );
}


function __Mover( BoxID , Type , uBoxID ) {
	Info( 'Move' + Type + ' started (' + BoxID + ')' );
	var Box = $( BoxID );
	if( ! Box ) {
		Error( 'Move' + Type + ' - incorrect BoxID' );
		return;
	}
	
	var Pn = Box.parentNode;
	if( ! Pn ) {
		Error( 'Move' + Type + ' - incorrect Box parent node' );
		return;
	}
	
	if( ( Type == 'Before' || Type == 'After' ) && ! $( uBoxID ) ) {
		Error( 'Move' + Type + ' - incorrect Box neighbour' );
		return;
	}
	var Lst = new Array( );
	for( var i=0 ; i<Pn.childNodes.length ; ++i ) {
		Lst.push( Pn.childNodes[i] );
	}
	RC( Pn );
	if( Type == 'Top' ) {
		Info( 'node appended top' );
		App( Pn , Box );
	}
	for( var i=0 ; i<Lst.length ; ++i ) {
		var ni = Lst[i].getAttribute ? Lst[i].getAttribute( 'id' ) : '';
		if( ni != BoxID ) {
			Info( 'Appending: ' + ni );
			if( Type == 'Before' && ( Lst[i].id && Lst[i].id == uBoxID ) ) {
				Info( 'node appended before' );
				App( Pn , Box );
			}
			App( Pn , Lst[i] );
			if( Type == 'After' && ( Lst[i].id && Lst[i].id == uBoxID ) ) {
				Info( 'node appended after' );
				App( Pn , Box );
			}
		} else {
			Info( 'not appending: ' + ni + ' == ' + BoxID );
		}
	}
	if( Type == 'Bottom' ) {
		Info( 'node appende d bottom' );
		App( Pn , Box );
	}
	Info( 'Move' + Type + ' ended' );
}



OptSelect = function( oSelect , sValue ) {
	if( isString( oSelect ) ) {
		oSelect = $( oSelect );
	}
	if( isObject( oSelect ) ) {
		for( var o=0 ; o<oSelect.options.length ; ++o ) {
			if( GA( oSelect.options[o] , 'value' ) == ( sValue + '' ) ) {
				oSelect.selectedIndex = o;
				return;
			}
		}
	}
}


var Chbx = {
	_getList : function( params ) {
		var g = '';
		if( params.parent_id ) {
			var p = '';
			if( params.parent_tag ) {
				p += params.parent_tag;
			}
			p += '#' + params.parent_id + ' ';
		} else if( params.parent_str ) {
			p += params.parent_str + ' ';
		}
		g += 'input';
		if( params.css ) {
			g += '.' + params.css;
		}
		g += '[type="checkbox"]';
		var l = $$( g );
		if( params.id_prefix ) {
			var ll = new Array( );
			for( var i=0 ; i<l.length ; ++i ) {
				if( l[i].id && l[i].id.indexOf( params.id_prefix ) == 0 ) {
					ll.push( l[i] );
				}
			}
			l = ll;
		}
		return l;
	},
	
	Select : function( isSelected , params ) {
		var list = Chbx._getList( params || {} );
		checkType = 'item.checked = ! item.checked;';
		if( isBool( isSelected ) ) {
			checkType = 'if( item.checked == ' + ( isSelected ? 'false' : 'true' ) + ' ) { ' + checkType + ' }';
		}
		eval( 'list.each( function( item ) { ' + checkType + ' } );' );
		if( isObject( params.cb ) ) {
			params.cb( this.GetSelected( params ) );
		}
		return false;
	},
	
	GetSelected : function( params ) {
		var l = Chbx._getList( params || {} );
		var r = new Array( );
		
		switch( params.rvalue ) {
			case 'value':
				var rv = 2;
			break;
			case 'id':
				var rv = 1;
			break;
			default:
				var rv = 0;
			break;
		}
		
		for( var i=0 ; i<l.length ; ++i ) {
			if( l[i].checked ) {
				var m = null;
				if( rv == 0 && l[i].id && ( m = l[i].id.match( /^(.*[^0-9]+)([0-9]+)$/ ) ) ) {
					r.push( parseInt( m[2] ) );
				} else if( rv == 1 && l[i].id ) {
					r.push( l[i].id );
				} else if( rv == 2 && ! isUndefined( l[i].value ) && l[i].value != '' ) {
					r.push( l[i].value );
				}
			}
		}
		return r;
	}
}


var M_DC_LIB = true;
/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 404 $
 * $LastChangedDate: 2007-11-17 18:10:13 +0100 (Sat, 17 Nov 2007) $
 */


if( typeof( M_ERR ) == 'undefined' ) {
	M_ERR = '';
	if( typeof( Class ) == 'undefined' ) {
		M_ERR += ( M_ERR ? ', ' : '' ) + 'prototype.lib.js';
	}
	if( typeof( M_BASIC_LIB ) == 'undefined' ) {
		M_ERR += ( M_ERR ? ', ' : '' ) + 'basic.lib.js';
	}
	if( typeof( M_DC_LIB ) == 'undefined' ) {
		M_ERR += ( M_ERR ? ', ' : '' ) + 'dc.lib.js';
	}
	if( M_ERR ) {
		alert( 'notice.lib dependecies error\n-------------\nload libraries:\n'+M_ERR );
	}
}


o2_notice_creator = function( msg , noticeIcon , noticeButtons , noticeID ) {
	NoDv = DCDiv( );
	NoDv.className = 'k-notice-div';
	
	App( NoDv , DCSpacer( ) );
	
	TxDv = DCDiv( );
	TxDv.className = 'k-notice-content ' + noticeIcon;
	
	TxP  = DCP( '' , msg );
	TxP.className  = 'k-notice-message';
	App( TxDv , TxP );
	imgPrefix = Notice.getConfig( 'icons_prefix' );
	if( isUndefined( imgPrefix ) ) {
		imgPrefix = '';
	}
	if( ( noticeButtons ^ NOTICE_BTN_CLOSE ) > 0 ) {
		BtP  = DCP( );
		BtP.className = 'k-notice-buttons';
		if( noticeButtons & NOTICE_BTN_YES ) {
			App( BtP , DCBtn( 'notice-yes.gif' , 'Notice.btnClick( ' + NOTICE_BTN_YES + ',' + noticeID + ' );' ) );
		}
		if( noticeButtons & NOTICE_BTN_NO ) {
			App( BtP , DCBtn( 'notice-no.gif' , 'Notice.btnClick( ' + NOTICE_BTN_NO + ',' + noticeID + ' );' ) );
		}
		if( noticeButtons & NOTICE_BTN_CANCEL ) {
			App( BtP , DCBtn( 'notice-cancel.gif' , 'Notice.btnClick( ' + NOTICE_BTN_CANCEL + ',' + noticeID + ' );' ) );
		}
		if( noticeButtons & NOTICE_BTN_OK ) {
			App( BtP , DCBtn( 'notice-ok.gif' , 'Notice.btnClick( ' + NOTICE_BTN_OK + ',' + noticeID + ' );' ) );
		}
		App( TxDv , BtP );
	}
	
	App( NoDv , TxDv );
	
	if( noticeButtons & NOTICE_BTN_CLOSE ) {
		ClDv = DCDiv( );
		ClDv.className = 'k-notice-close';
		App( ClDv , DCBtn( 'notice-close.gif' , 'Notice.btnClick( ' + NOTICE_BTN_CLOSE + ',' + noticeID + ' );' ) );
		App( NoDv , ClDv );
	}
	
	App( NoDv , DCSpacer( ) );
	
	return NoDv;
}


var NOTICE_BTN_NONE         = 0;
var NOTICE_BTN_YES          = 1;
var NOTICE_BTN_NO           = 2;
var NOTICE_BTN_CANCEL       = 4;
var NOTICE_BTN_CLOSE        = 8;
var NOTICE_BTN_OK           = 16;
var NOTICE_BTN_YESNO        = 3;

var NOTICE_ICO_INFO         = 'info';
var NOTICE_ICO_PROGRESS     = 'progress';
var NOTICE_ICO_QUESTION     = 'question';
var NOTICE_ICO_WARNING      = 'warning';
var NOTICE_ICO_ERROR        = 'error';


var modo_notice        = Class.create( );
var modo_notice_object = Class.create( );

modo_notice_object.prototype = {
	
	callBack : undefined,
	message  : undefined,
	width    : 0,
	height   : 0,
	
	initialize : function( message , callBack ) {
		this.callBack          = callBack;
		this.message           = message;
	},
	
	getMsg : function( ) {
		return this.message;
	},
	
	setPos : function( top , left ) {
		this.message.style.top = top;
		this.message.style.left = left;
	},
	
	getDim : function( ) {
		return Element.getDimensions( this.message );
	},
	
	call : function( buttonID ) {
		if( isObject( this.callBack ) ) {
			this.callBack( buttonID );
		}
	}
}

modo_notice.prototype = {
	
	config     : undefined,
	
	buttonsStr : new Array( ),
	buttonsVal : new Array( ),
	
	isLoaded   : false,
	
	notices    : new Array( ),
	ids        : new Array( ),
	opened     : 0,
	idCounter  : 1,
	queue      : new Array( ),
	
	initialize : function( config ) {
		//window.alert = this.alert.bind( this );
		
		this.config = config;
		
		if( typeof( this.config.debug ) == 'undefined' ) this.config.debug = false;
		
		if( typeof( this.config.multiply ) == 'undefined' ) this.config.multiply = false;
		if( this.config.multiply && typeof( this.config.multiply_box_id ) != 'string' ) {
			alert( 'Edit config variable! "multiply_box_id" property not found!' );
		}
		if( typeof( this.config.show_box ) != 'object' && typeof( this.config.show_box ) != 'function' ) {
			this.config.show_box = this.showBox.bind( this );
		}
		if( typeof( this.config.hide_box ) != 'object' && typeof( this.config.hide_box ) != 'function' ) {
			this.config.hide_box = this.hideBox.bind( this );
		}
		
		if( this.config.multiply && typeof( this.config.notice_parent_id ) == 'undefined' ) {
			alert( 'Edit config variable! "notice_parent_id" property not found!' );
		} else {
			Event.observe( window , 'load' , this.bindParent.bind( this ) , false );
		}
		if( typeof( this.config.create_notice ) != 'object' && typeof( this.config.create_notice ) != 'function' ) {
			this.config.create_notice = this.createNotice.bind( this );
		}
		if( typeof( this.config.hide_notice ) != 'object' && typeof( this.config.hide_notice ) != 'function' ) {
			this.config.hide_notice = this.hideNotice.bind( this );
		}
		
		if( typeof( this.config.icons_prefix ) == 'undefined' ) this.config.icons_prefix = 'notice-';
		if( typeof( this.config.icons_sufix ) == 'undefined' ) this.config.icons_sufix = '.gif';
		
		if( typeof( this.config.buttons_graphics ) == 'undefined' ) this.config.buttons_graphics = false;
		this.buttonsStr['yes']    = ( typeof( this.config.btn_yes_str ) == 'undefined' ) ? 'yes' : this.config.btn_yes_str;
		this.buttonsStr['no']     = ( typeof( this.config.btn_no_str ) == 'undefined' ) ? 'no' : this.config.btn_no_str;
		this.buttonsStr['cancel'] = ( typeof( this.config.btn_cancel_str ) == 'undefined' ) ? 'cancel' : this.config.btn_cancel_str;
		this.buttonsStr['close']  = ( ( typeof( this.config.btn_close_str ) == 'undefined' ) ? 'close [x]' : this.config.btn_close_str ) + ' [x]';
		this.buttonsStr['ok']     = ( ( typeof( this.config.btn_ok_str ) == 'undefined' ) ? 'ok' : this.config.btn_ok_str );
		
		if( typeof( this.config.position_guard ) != 'undefined' && this.config.position_guard ) {
			if( typeof( this.config.guard_function ) == 'object' || typeof( this.config.guard_function ) == 'function' ) {
				window.onscroll = this.config.guard_function;
			} else {
				window.onscroll = this.positionGuard.bind( this );
			}
		}
	},
	
	btnClick : function( buttonID , noticeID ) {
		if( typeof( this.notices['n-' + noticeID] ) != 'undefined' ) {
			this.notices['n-' + noticeID].call( buttonID );
			this.config.hide_notice( this.notices['n-' + noticeID] , this.config.notice_parent_id );
			for( __nI=0 ; __nI<this.ids.length ; ++__nI ) {
				if( this.ids[__nI] == noticeID ) {
					delete this.ids[__nI];
					break;
				}
			}
			--this.opened;
			this.config.hide_box( );
			delete this.notices['n-' + noticeID];
		}
	},
	
	addQueue : function( msg , noticeIcon , noticeButtons , callBack , timeout ) {
		if( noticeIcon != 'progress' ) {
			this.queue.push( { msg : msg , noticeIcon : noticeIcon , noticeButtons : noticeButtons , callBack : callBack , timeout : timeout } );
		}
	},
	
	openNotice : function( msg , noticeIcon , noticeButtons , callBack , timeout ) {
		if( ! this.isLoaded ) {
			this.addQueue( msg , noticeIcon , noticeButtons , callBack , timeout );
			return;
		}
		noticeID = this.idCounter;
		message = this.config.create_notice( msg , noticeIcon , noticeButtons , noticeID );
		this.notices['n-' + noticeID] = new modo_notice_object( message , callBack );
		if( this.isLoaded ) {
			this.showNotice( noticeID );
		}
		this.ids.push( noticeID );
		++this.idCounter;
		++this.opened;
		if( typeof( timeout ) == 'number' && timeout ) {
			timeout *= 1000;
			setTimeout( 'Notice.closeNotice( ' + noticeID + ');' , timeout );
		}
		if( typeof( this.config.position_guard ) != 'undefined' && this.config.position_guard ) {
			if( typeof( this.config.guard_function ) == 'object' || typeof( this.config.guard_function ) == 'function' ) {
				this.config.guard_function( );
			} else {
				this.positionGuard( );
			}
		}
		return noticeID;
	},
	
	closeNotice : function( noticeID ) {
		this.btnClick( NOTICE_BTN_NONE , noticeID );
	},
	
	close : function( noticeID ) {
		this.closeNotice( noticeID );
	},
	
	createNotice : function( msg , noticeIcon , noticeButtons ) {
		message = DCDiv( );
		message.className = 'notice notice-' + noticeIcon;
		App( message , DCSpacer( ) );
		this.setIcon( noticeIcon , message );
		this.setMsg( msg , message );
		App( message , DCSpacer( ) );
		this.setButtons( noticeButtons , message , this.idCounter );
		return message;
	},
	
	setIcon : function( iconType , pdv ) {
		ico           = DCDiv( );
		ico.className = 'notice-icon-box';
		img           = DCImg( Notice.config.icons_prefix + iconType + Notice.config.icons_sufix );
		img.className = 'notice-icon';
		App( ico , img );
		App( pdv , img );
	},
	
	setButtons : function( nButtons , pbt , noticeID ) {
		if( nButtons > 0 ) {
			bts           = DCDiv( );
			bts.className = 'notice-buttons';
			App( bts , DCSpacer( ) );
			if( nButtons & NOTICE_BTN_CLOSE ) {
				this.setButton( 'close' , NOTICE_BTN_CLOSE , bts , noticeID );
			}
			if( nButtons & NOTICE_BTN_CANCEL ) {
				this.setButton( 'cancel' , NOTICE_BTN_CANCEL , bts , noticeID );
			}
			if( nButtons & NOTICE_BTN_NO ) {
				this.setButton( 'no' , NOTICE_BTN_NO , bts , noticeID );
			}
			if( nButtons & NOTICE_BTN_YES ) {
				this.setButton( 'yes' , NOTICE_BTN_YES , bts , noticeID );
			}
			if( nButtons & NOTICE_BTN_OK ) {
				this.setButton( 'ok' , NOTICE_BTN_OK , bts , noticeID );
			}
			
			App( bts , DCSpacer( ) );
			App( pbt , bts );
		}
	},
	
	setButton : function( buttonType , buttonID , pdv  , noticeID ) {
		btn           = DCDiv( );
		btn.className = 'notice-button';
		if( Notice.config.buttons_graphics ) {
			img           = DCImg( Notice.config.icons_prefix + buttonType + Notice.config.icons_sufix );
			App( btn , img );
		} else {
			App( btn , Txt( Notice.buttonsStr[buttonType] ) );
		}
		eval( 'btn.onclick = function( ) { Notice.btnClick( ' + buttonID + ',' + noticeID + ' ); };' );
		App( pdv , btn );
	},
	
	setMsg : function( msg , oMsg ) {
		msgD = DCDiv( );
		msgD.className = 'notice-text';
		if( isObject( msg ) ) {
			App( msgD , msg );
		} else if( ! isUndefined( msg ) ) {
			App( msgD , Txt( msg ) );
		}
		App( oMsg , msgD );
	},
	
	showNotice : function( noticeID ) {
		this.config.show_box( );
		if( typeof( this.config.show_notice ) != 'undefined' ) {
			this.config.show_notice( this.notices['n-' + noticeID] );
		} else {
			App( this.config.notice_parent_id , this.notices['n-' + noticeID].getMsg( ) );
		}
	},
	
	showBox : function( ) {
		if( this.config.multiply ) {
			$( this.config.multiply_box_id ).style.display = 'block';
		}
		if( typeof( this.config.position_top ) != 'undefined' && typeof( this.config.position_bottom ) != 'undefined' ) {
			pS = pageSize( );
			bH = pS.windowY - ( this.config.position_top + this.config.position_bottom );
			$( this.config.multiply_box_id ).style.height = bH + 'px';
		}
	},
	
	hideBox : function( ) {
		if( this.config.multiply ) {
			if( this.opened == 0 ) {
				$( this.config.multiply_box_id ).style.display = 'none';
			}
		}
	},
	
	hideNotice : function( oNotice , oParent ) {
		oParent.removeChild( oNotice.getMsg( ) );
	},
	
	bindParent : function( ) {
		if( typeof( this.config.notice_parent_id ) == 'undefined' ) {
			this.config.notice_parent_id = document.getElementsByTagName( 'body' ).item( 0 );
		} else {
			this.config.notice_parent_id = $( this.config.notice_parent_id );
		}
		for( __nS=0 ; __nS<this.ids.length ; ++__nS ) {
			this.showNotice( this.ids[__nS] );
		}
		this.isLoaded = true;
		if( this.queue.length > 0 ) {
			for( var qi=0 ; qi<this.queue.length ; ++qi ) {
				var q = this.queue[qi];
				this.openNotice( q.msg , q.noticeIcon , q.noticeButtons , q.callBack , q.timeout );
			}
			delete this.queue;
		}
	},
	
	positionGuard : function( ) {
		if( this.isLoaded && this.opened > 0 ) {
			var sT;
    		if (self.pageYOffset){
    			sT = self.pageYOffset;
    		} else if (document.documentElement && document.documentElement.scrollTop) {	
        		sT = document.documentElement.scrollTop; 
    		} else if (document.body) {	
    			sT = document.body.scrollTop; 
    		}
    		sT += this.config.position_top;
			if( this.config.multiply ) {
				$( this.config.multiply_box_id ).style.top = sT + 'px';
			} else {
				for( _nC=0 ; _nC<this.ids.length ; ++_nC ) {
					msg = this.notices['n-' + this.ids[_nC]].getMsg( );
					msg.style.top = sT + 'px';
					dim = this.notices['n-' + this.ids[_nC]].getDim( );
					sT += ( dim.height + this.config.distance );
				}
			}
		}
	},
	//openNotice : function( msg , noticeIcon , noticeButtons , callBack , timeout ) {
	error : function( msg , timeout , callBack ) {
		return this.openNotice( msg , NOTICE_ICO_ERROR , NOTICE_BTN_CLOSE , callBack , timeout  );
	},
	
	warning : function( msg , timeout , callBack ) {
		return this.openNotice( msg , NOTICE_ICO_WARNING , NOTICE_BTN_CLOSE , callBack , timeout );
	},
	
	info : function( msg , timeout , callBack ) {
		return this.openNotice( msg , NOTICE_ICO_INFO , NOTICE_BTN_CLOSE , callBack , timeout  );
	},
	
	question : function( msg , callBack ) {
		return this.openNotice( msg , NOTICE_ICO_QUESTION , NOTICE_BTN_YESNO | NOTICE_BTN_CLOSE , callBack , 0  );
	},
	
	progress : function( msg , timeout , callBack ) {
		return this.openNotice( msg , NOTICE_ICO_PROGRESS, NOTICE_BTN_NONE , callBack , timeout  );
	},
	
	alert : function( msg ) {
		this.openNotice( msg , NOTICE_ICO_INFO, NOTICE_BTN_OK | NOTICE_BTN_CLOSE , undefined );
	},
	
	getConfig : function( propertyName ) {
		eval( 'propertyValue = ( typeof( this.config.' + propertyName + ' ) == "undefined" ) ? undefined : this.config.' + propertyName + ';' );
		return propertyValue;
	}
}



var Notice = null;


function _runNotice( ) {
	if( typeof( lang_yes ) != 'undefined' && typeof( URL_BASE ) != 'undefined' ) {
		var modo_notice_config = {
			debug               : true,
			
			multiply            : true,
			multiply_box_id     : 'notice-box',
			show_box            : undefined,
			hide_box            : undefined,
			
			notice_parent_id    : 'notice-show',
			create_notice       : o2_notice_creator,
			show_notice         : undefined,
			hide_notice         : undefined,
			
			icons_prefix        : URL_BASE + 'img/notice/notice-new-',
			icons_sufix         : '.gif',
			buttons_graphics    : false,
			
			btn_yes_str         : lang_yes,
			btn_no_str          : lang_no,
			btn_cancel_str      : lang_cancel,
			btn_close_str       : lang_close,
			btn_ok_str          : 'ok',
			
			position_guard      : true,
			position_top        : 200,
			position_bottom     : 100,
			
			notice_timeout      : 0
		}
		Notice = new modo_notice( modo_notice_config );
	} else {
		setTimeout( _runNotice , 10 );
	}
}

_runNotice( );

var M_NOTICE_LIB = true;

/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 573 $
 * $LastChangedDate: 2008-05-14 18:25:55 +0200 (Wed, 14 May 2008) $
 */



if( typeof( M_ERR ) == 'undefined' ) {
	M_ERR = '';
	if( typeof( Class.create ) == 'undefined' ) {
		M_ERR += ( M_ERR ? ', ' : '' ) + 'prototype.lib.js';
	}
	if( M_ERR ) {
		alert( 'ajax.lib dependecies error\n-------------\nload libraries:\n'+M_ERR );
	}
}



var modo_ajax_config = {
	use_notice                 : true,
	allow_multiply_connections : true,
	debug                      : true
}


var modo_ajax = Class.create( );

var modo_ajax_object = Class.create( );

modo_ajax_object.prototype = {
	
	noticeID : 0,
	
	callBack : undefined,
	
	callType : 'none',
	
	failure  : false,
	
	showError: false,
	
	noticeDelay : 0,
	
	initialize : function( url , get , post , callBack , msg , callType , placeHolderID , delay ) {
		this.showError= placeHolderID;
		this.callBack = callBack;
		this.callType = callType;
		this.noticeDelay= typeof( delay ) == 'number' ? delay : 0;
		if( ajax.config.use_notice && typeof( msg ) != 'undefined' && msg ) {
			this.noticeID = Notice.progress( msg );
		}
		
		if( callType.match( /^(response|request|json)$/ ) ) {
			new Ajax.Request( 
								url,
								{
									method:      ( post.length > 0 ? 'post' : 'get' ),
									parameters:  get,
									postBody:    ( post.length > 0 ? post : undefined ),
									onFailure:   this.ajaxFailure.bind( this ),
									onComplete:  this.ajaxComplete.bind( this )
								}
							);
		} else {
			new Ajax.Updater(
								placeHolderID,
								url,
								{
									method:      ( post.length > 0 ? 'post' : 'get' ),
									parameters:  get,
									postBody:    ( post.length > 0 ? post : undefined ),
									onFailure:   this.ajaxFailure.bind( this ),
									insertion:   this.ajaxComplete.bind( this )
								}
							);
		}
		ajax.clearPost();
	},
	
	closeNotice : function( ) {
		if( this.noticeID > 0 ) {
			Notice.closeNotice( this.noticeID );
		}
	},
	
	ajaxFailure : function( errMsg ) {
		if( typeof( errMsg ) != 'string' ) {
			errMsg  = ( typeof( ajax.config.failureMsg ) == 'string' ? ajax.config.failureMsg : 'Wystąpił błąd komunikacji z serwerem.' );
		}
		errMsg = 'ajaxObject :: ' + errMsg;
		if( this.config.use_notice ) {
			Notice.error( errMsg );
		} /*else {
			alert( errMsg );
		}*/
		if( typeof( this.callBack ) == 'object' || typeof( this.callBack ) == 'function' ) {
			if( this.callType == 'response' ) {
				this.callBack( -666 );
			}else {
				this.callBack( );
			}
		}
		this.failure  = true;
		this.closeNotice( );
		ajax.isWorking = false;
	},
	
	ajaxComplete : function( Obj , rTxt ) {
		if( this.failure ) {
			return;
		}
		/*if( Obj && Obj.responseText && window.console && window.console.debug )  {
			window.console.debug( 'response:\n'+Obj.responseText );
		}*/
		
		this.closeNotice( );
		if( this.callType == 'response' ) {
			this.parseResponse( Obj );
		} else if( this.callType == 'json' && ( typeof( this.callBack ) == 'object' || typeof( this.callBack ) == 'function' ) ) {
			try {
				eval( 'var j = '+Obj.responseText+';' );
				this.callBack( j );
			} catch( e ) {
				Error( e );
				this.callBack( null );
			}
		} else if( this.callType == 'request' && ( typeof( this.callBack ) == 'object' || typeof( this.callBack ) == 'function' ) ) {
			this.callBack( Obj );
		} else if( this.callType.match( /^(append|update|updater)$/ ) ) {
			this.updater( Obj , rTxt );
		}
		
		ajax.isWorking = false;
	},
	
	parseResponse : function( Obj ) {
		if ( Obj.responseXML ) {
			var xmlObject = Obj.responseXML;
				
			var response  = xmlObject.getElementsByTagName ( 'response' );
			
			
			if( response.length > 0 ) {
				response = response[0];
				var code     = response.getAttribute( 'code' );
				var info     = '';
				
				if( response.childNodes.length > 0 ) {
					info = response.firstChild.data;
					if( typeof( info ) == 'undefined' ) {
						info = '';
					}
				}
				if( ( code == 0 || code <= -69 ) && info.length > 0 ) {
					if( typeof( lang_errors ) != 'undefined' && typeof( lang_errors[info] ) != 'undefined' ) {
						info = lang_errors[info];
					} else if( code == -666 && info == 'system_error' ) {
						info = "Przepraszamy, wystąpił błąd wewnętrzny systemu. Spróbuj ponownie za chwile.";
					}
					
					if( typeof( this.showError ) != 'undefined' && this.showError ) {
						if( ajax.config.use_notice ) {
							Notice.error( info , this.noticeDelay );
						} else {
							//alert( info );
						}
					}
				}
				if( typeof( this.callBack ) != 'undefined' ) {
					this.callBack( code , info , Obj );
				}
				return;
			}
			if( typeof( this.callBack ) != 'undefined' ) {
				this.callBack ( -88 , '' , Obj );
			}
		} else {
			Info( Obj.responseText );
			if( typeof( this.showError ) != 'undefined' && this.showError ) {
				var info = "Przepraszamy, wystąpił błąd wewnętrzny systemu. Spróbuj ponownie za chwile.";
				if( ajax.config.use_notice ) {
					Notice.error( info , this.noticeDelay );
				} else {
					//alert( info );
				}
			}
			if( ajax.config.debug ) {
				//alert( Obj.responseText )
			}
			if( typeof( this.callBack ) != 'undefined' ) {
				this.callBack( -88 , '' , Obj );
			}
		}
	},
	
	updater : function( placeHolder , HTML ) {
		if( this.callType.match( /^(append|update)$/ ) ) {
			if ( this.callType == 'append' ) {
				placeHolder.innerHTML += '' + HTML;
			} else {
				placeHolder.innerHTML = HTML;
			}
		}
		if( typeof( this.callBack ) == 'object' || typeof( this.callBack ) == 'function' ) {
			this.callBack( placeHolder , HTML );
		}
	}
}

modo_ajax.prototype = {
	
	config : undefined,
	
	isWorking : false,
	
	post : '',
	
	get : '',
	
	initialize : function( config ) {
		this.config = config;
		if( typeof( this.config.use_notice ) == 'undefined' || typeof( M_NOTICE_LIB ) == 'undefined' ) this.config.use_notice = false;
		if( typeof( this.config.allow_multiply_connections ) == 'undefined' ) this.config.allow_multiply_connections = false;
		if( typeof( this.config.debug ) == 'undefined' ) this.config.debug = false;
	},
	
	checkWorking : function( ) {
		if( this.config.allow_multiply_connections || ! this.isWorking ) {
			return false;
		}
		var errMsg = "ajaxLib :: " + ( typeof( this.config.working_error ) == 'string' && this.config.working_error ? this.config.working_error : 'Nie można nawiązać kolejnego połączenia. Jakieś zadanie nie zostało jeszcze dokończone. Ponów próbę za kilka sekund.' );
		if( this.config.use_notice ) {
			Notice.warning( errMsg );
		} else {
			//alert( errMsg );
		}
		return true;
	},
	
	clearPost : function( ) {
		this.post = '';
	},
	
	clearGet : function( ) {
		this.get = '';
	},
	
	addPost : function( varName , varValue ) {
		this.post += ( this.post.length > 0 ? '&' : '' ) + varName + ( typeof( varValue ) != 'undefined' ? '=' + encodeURIComponent ( varValue ) : '' ); 
	},
	
	addGet : function( varName , varValue ) {
		this.get += ( this.get.length > 0 ? '&' : '' ) + varName + ( typeof( varValue ) != 'undefined' ? '=' + encodeURIComponent ( varValue ) : '' ); 
	},
	
	addPostStr : function( str ) {
		this.post += ( this.post.length > 0 ? '&' : '' ) + str;
	},
	
	addGetStr : function( str ) {
		this.get += ( this.get.length > 0 ? '&' : '' ) + str;
	},
	
	postStr : function( ) {
		return this.post;
	},
	
	getStr : function( ) {
		return this.get;
	},
	
	request : function( url , msg , callBack ) {
		if( this.checkWorking( ) ) {
			return false;
		}
		new modo_ajax_object( url , this.get , this.post , callBack , msg , 'request' );
	},
	
	json : function( url , callBack , msg ) {
		if( this.checkWorking( ) ) {
			return false;
		}
		new modo_ajax_object( url , this.get , this.post , callBack , msg , 'json' );
	},
	
	response : function( url , callBack , msg , noticeError , noticeDelay ) {
		if( this.checkWorking( ) ) {
			return false;
		}
		new modo_ajax_object( url , this.get , this.post , callBack , msg , 'response' , noticeError , noticeDelay );
	},
	
	rewrite : function( url , placeHolder , msg , callBack ) {
		if( this.checkWorking( ) ) {
			return false;
		}
		new modo_ajax_object( url , this.get , this.post , callBack , msg , 'update' , placeHolder );
	},
	
	append : function( url , placeHolder , msg , callBack ) {
		if( this.checkWorking( ) ) {
			return false;
		}
		new modo_ajax_object( url , this.get , this.post , callBack , msg , 'append' , placeHolder );
	},
	
	updater : function( callBack , url , placeHolder , msg ) {
		if( this.checkWorking( ) ) {
			return false;
		}
		new modo_ajax_object( url , this.get , this.post , callBack , msg , 'updater' , placeHolder );
	}
	
}


var ajax = new modo_ajax( modo_ajax_config );


var M_AJAX_LIB = true;/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 75 $
 * $LastChangedDate: 2007-02-04 21:25:56 +0100 (Sun, 04 Feb 2007) $
 */


var m_Tabs = Class.create( );

m_Tabs.prototype = {
	
	currentTab : '',
	
	tabTypes   : new Array( 'all' , 'basic' , 'anonymus' , 'erotic' ),
	
	callBacks  : new Array( ),
	
	pages      : new Array( ),
	
	initialize : function( ) { 
	},
	
	
	getCurrent : function( ) {
		return this.currentTab;
	},
	
	setTab : function( tabType ) {
		this.switchTab( tabType );
		
		for( cbI=0 ; cbI<this.callBacks.length ; ++cbI ) {
			this.callBacks[cbI]( tabType );
		}
	},
	
	switchTab : function( tabType ) {
		for( tI=0 ; tI<this.tabTypes.length ; ++tI ) {
			if( $( 'tab-' + this.tabTypes[tI] ) ) {
				st = 'tab';
				if( tabType == this.tabTypes[tI] ) {
					st += '-selected'
				}
				if( typeof( this.pages[this.tabTypes[tI]] ) != 'undefined' && $( this.pages[this.tabTypes[tI]] ) ) {
					$( this.pages[this.tabTypes[tI]] ).style.display = ( tabType == this.tabTypes[tI] ? 'block' : 'none' );
				}
				$( 'tab-' + this.tabTypes[tI] ).className = st;
			}
		}
	},
	
	registerCallBack : function( cb ) {
		this.callBacks.push( cb );
	},
	
	setTabName : function( tabType , tabName ) {
		if( $( 'tab-' + tabType ) ) {
			if( ! tabName ) {
				eval( "tabName = lang_tab" + tabType.ucFirst( ) + ";" );
			}
			RC( 'tab-' + tabType );
			App( $( 'tab-' + tabType ) , Txt( tabName ) );
		}
	},
	
	bindPage : function( tabType , pageID ) {
		this.pages[tabType] = pageID;
	}
	
}

var Tabs = new m_Tabs();

/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 659 $
 * $LastChangedDate: 2008-09-25 18:23:43 +0200 (Thu, 25 Sep 2008) $
 */



var m_user = Class.create( );

m_user.prototype = {
	
	data : false,
	
	keyRegistered : false,
	
	passGen : false,
	
	registerCB : undefined,
	
	initialize : function( ) { 
		Event.observe( window , 'load' , this.checkMainSize.bind( this ) );
	},
	
	addRegisterCallBack : function( cb ) {
		this.registerCB = cb;
	},
	
    checkMainSize : function( ) {
		if( $( 'left-login-form' ) ) {
			$( 'left-login-form' ).style.height = $('content').getDimensions().height + 'px';
		}
	},
	
	login : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			if( typeof( this.data.login ) == 'string' && typeof( this.data.pass ) == 'string' ) {
				ajax.clearPost( );
				ajax.addPost( 'login'    , this.data.login );
				ajax.addPost( 'password' , this.data.pass );
				ajax.response( URL_LOGIN , this.login.bind( this ) , lang_loginP , true , 5 );
			} else if( $( 'login' ) && $( 'password' ) ) {
				ajax.clearPost( );
				ajax.addPost( 'login'    , $F( 'login' ) );
				ajax.addPost( 'password' , $F( 'password' ) );
				if( $( 'set-autologin' ) && $( 'set-autologin' ).checked ) {
					ajax.addPost( 'set-autologin' , '1' );
				}
				ajax.response( URL_LOGIN , this.login.bind( this ) , lang_loginP , true , 5 );
			}
		} else {
			if( code == 1 ) {
				var url = window.location + '';
				//if( url.charAt( url.length - 1 ) != '/' ) url += '/';
				if( $( 'after-login-url' ) ) {
					url = $F( 'after-login-url' );
				}
				
				if( url.indexOf( URL_CREATE_USER ) == 0 || 
					url.indexOf( URL_ACTIVATE_USER ) == 0 || 
					url.indexOf( URL_DEACTIVATE_USER ) == 0 || 
					url.indexOf( 'odzyskaj-haslo' ) != -1 ) {
					url = URL_BASE;
				}
				
				window.location = url;
			}
		}
		return false;
	},
	
	logout : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.clearPost( );
			ajax.response( URL_LOGOUT , this.logout.bind( this ) , lang_logoutP , true , 5 );
		} else {
			window.location = URL_BASE;
		}
	},
	
	register : function( code , info ) {
/*		$( 'left' ).style.height = $( 'mainf' ).style.height;*/
/*       $('left').style.height = $('main').getDimensions().height + 'px';*/
		if( typeof( code ) == 'undefined' ) {
			this.sendRegisterQuery( this.register.bind( this ) );
		} else {
			try {
				code = parseInt( code );
			} catch( e ) {
				this.data = false;
				Notice.error( 'Wystąpił błąd wewnętrzny. Spróbuj zarejestrować się za chwile' );
				return false;
			}
			if( code == 0 ) {
				if( isObject( this.registerCB ) ) {
					this.registerCB( );
				}
				if( $('user-email-sent-addr') ) {
					$('user-email-sent-addr').innerHTML = $('user-email-sent-addr').innerHTML.replace( '%email%' , this.data.email );
				}
				$( 'register-user-form' ).hide( );
				$( 'register-user-info' ).show( );
				if( ! USER_ACTIVATION_MAIL ) {
					setTimeout( 'User.login();' , 5000 );
				} else if( this.keyRegistered ) {
					if( this.passGen ) {
						$( 'key-email' ).show( );
					} else {
						$( 'key-auto' ).show( );
						setTimeout( 'User.login();' , 5000 );
					}
				} else {
					this.data = false;
				}
				this.checkMainSize();
			} else if( code > 0 ) {
				this.showRegisterError( code );
/*				Event.observe( 'main' , 'submit' , this.checkMainSize.bind( this ) );*/
				this.checkMainSize();
				$( 'fill_in' ).hide( );
                $( 'correct' ).show( );       
                this.data = false;
			}
		}
	},
	
	sendRegisterQuery : function( callBack ) {
		ajax.clearPost( );
		var lg  = $F( 'new-login' );
		var ps  = $F( 'new-password' );
		var eml = $F( 'new-email' );
		ajax.addPost( 'new-login' , lg );
		ajax.addPost( 'new-password' , ps );
		ajax.addPost( 're-password' , $F( 're-password' ) );
		ajax.addPost( 'new-email' , eml );
		ajax.addPost( 'gender' , $F('new-gender') );
		ajax.addPost( 'orientation' , $F('new-orientation') );
		ajax.addPost( 'generate-password' , $( 'generate-password' ) && $( 'generate-password' ).checked ? '1' : '0' );
		ajax.addPost( 'new-question' , $F( 'new-question' ) );
		ajax.addPost( 'new-answere' , $F( 'new-answere' ) );
		ajax.addPost( 'birthday' , $F( 'new-birthyear' ) );
		ajax.addPost( 'country' , $F( 'country' ) );
		ajax.addPost( 'state' , $F( 'state' ) );
		ajax.addPost( 'city' , $F( 'city' ) );
		if( $( 'invitation-key' ) ) {
			ajax.addPost( 'key' , $F( 'invitation-key' ) );
			this.keyRegistered = true;
			this.passGen = ( $( 'generate-password' ) && $( 'generate-password' ).checked );
		}
		this.data = { login : lg , pass : ps , email : eml };
		ajax.response( URL_SUBSCRIBE , callBack , lang_progress , false );
	},
	
	showRegisterError : function( error )  {
		var etmp = 0;
		var isError = false;
		try {
			etmp = parseInt( error );
		} catch( e ) {
			Error( e );
			isError = true;
		}
		if( ( etmp < 0 ) || isError ) {
			Notice.error( 'Wystąpił błąd wewnętrzny. Spróbuj zarejestrować się za chwile' );
			return false;
		}
		if( ! etmp ) {
			error = 0;
		} else {
			error = etmp;
		}
		var user_create_errors = [
		   	[ 1    , lang_errors['pass_length']      , 2  , 'password'  ],
			[ 2    , lang_errors['pass_match']       , 2  , 'password'  ],
			[ 4    , lang_errors['login_length']     , 1  , 'login'     ],
			[ 8    , lang_errors['login_incorrect']  , 1  , 'login'     ],
			[ 16   , lang_errors['email_incorrect']  , 4  , 'email'     ],
			[ 32   , lang_errors['user_exists']      , 1  , 'login'     ],
			[ 128  , lang_errors['email_exists']     , 4  , 'email'     ],
			[ 256  , lang_errors['question_length']  , 8  , 'question'  ],
			[ 512  , lang_errors['answer_length']    , 16 , 'answere'   ],
			[ 4096 , 'Wybierz rok urodzenia'         , 32 , 'birthyear' ],
			[ 8192 , 'Wybierz płeć'                  , 64 , 'gender' ]
		];
		try {
			var fErr   = 0;
			for( var ier=0 ; ier<user_create_errors.length ; ++ier ) {
				var dID = $( 'new-' + user_create_errors[ier][3] + '-error' );
				var iID = $( 'new-' + user_create_errors[ier][3] );
				if( ! ( user_create_errors[ier][2] & fErr )  ) {
					dID.innerHTML = '';
				}
				if( error & user_create_errors[ier][0] ) {
					dID.style.display = 'block';
					dID.innerHTML += user_create_errors[ier][1] + ' ';
					iID.className = 'txt error';
					if( user_create_errors[ier][3] == 'password' ) {
						$( 're-' + user_create_errors[ier][3] ).className = 'txt error';
					}
					fErr |= user_create_errors[ier][2];
				} else if( ! ( user_create_errors[ier][2] & fErr ) ) {
					dID.innerHTML = '';
					dID.style.display = 'none';
					iID.className = 'txt';
					if( user_create_errors[ier][3] == 'password' ) {
						$( 're-' + user_create_errors[ier][3] ).className = 'txt';
					}
				}
			}
			if( error & 1024 ) {
				Notice.error( lang_errors['userAddressIncorr'] , 3 );
			} else if( error & 2048 ) {
				Notice.error( lang_errors['userKeyIncorr']  , 3 );
			}
		} catch( e ) { Error( e ); }
	},
	
	passGenerate : function( ) {
		state = 'block';
		if( $( 'generate-password' ).checked ) {
			state = 'none';
		}
		$( 'new-pass-fields' ).style.display = state;
		this.checkMainSize();
	},
	
	getQuestion : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.clearPost( );
			ajax.addPost( 'forgotten-login' , $F( 'forgotten-pass-login' ) );
			ajax.response( URL_USER_QUESTION , this.getQuestion.bind( this ) , lang_progress , true );
		} else {
			if( code == 1 ) {
				$( 'forgotten-pass-stage-1' ).style.display = 'none';
				$( 'forgotten-pass-stage-2' ).style.display = 'block';
				$( 'forgotten-username' ).innerHTML = $F( 'forgotten-pass-login' );
				$( 'forgotten-pass-question' ).innerHTML = info;
			}
		}
	},
	
	sendAnswere : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			
			ajax.clearPost( );
			ajax.addPost( 'forgotten-login'   , $F( 'forgotten-pass-login' ) );
			ajax.addPost( 'forgotten-answere' , $F( 'forgotten-pass-answere' ) );
			ajax.response( URL_USER_ANSWERE , this.sendAnswere.bind( this ) , lang_progress , true );
		} else {
			if( code == 1 ) {
				$( 'forgotten-pass-stage-2' ).style.display = 'none';
				$( 'forgotten-pass-stage-3' ).style.display = 'block';
			}
		}
	},
	
	changePassword : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.addPost( 'new-password' , $F( 'new-password' ) );
			ajax.addPost( 're-password' , $F( 're-password' ) );
			ajax.response( URL_CHANGEPASS , this.changePassword.bind( this ) , lang_progress , true );
		} else {
			if( code > 0 ) {
				ErrStr = DCDiv( );
				if( code & 1 ) {
					App( ErrStr , DCP( '' , lang_errors['pass_length'].replace( '%' , USER_PASS_MIN_LENGTH ) ) );
				}
				if( code & 2 ) {
					App( ErrStr , DCP( '' , lang_errors['pass_match'] ) );
				}
				if( code & 8192 ) {
					App( ErrStr , DCP( '' , lang_errors['access_denied'] ) );
				}
				Notice.error( ErrStr );
			} else if( code == 0 ) {
				$( 'new-password' ).value = '';
				$( 're-password' ).value  = '';
				Notice.info( lang_changePassword , 3 );
			}
		}
	},
	
	changeEmail : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.addPost( 'new-email' , $F( 'new-email' ) );
			ajax.response( URL_CHANGEEMAIL , this.changeEmail.bind( this ) , lang_progress , true );
		} else {
			if( code > 0 ) {
				ErrStr = DCDiv();
				if( code & 16 ) {
					App( ErrStr , DCP( '' , lang_errors['email_incorrect'] ) );
				}
				if( code & 128 ) {
					App( ErrStr , DCP( '' , lang_errors['email_exists'] ) );
				}
				if( code & 8192 ) {
					App( ErrStr , DCP( '' , lang_errors['access_denied'] ) );
				}
				Notice.error( ErrStr );
			} else if( code == 0 ) {
				Notice.info( lang_changeEmail , 3 );
			}
		}
	},
	
	changeQuestion : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.addPost( 'new-question' , $F( 'new-question' ) );
			ajax.addPost( 'new-answere' , $F( 'new-answere' ) );
			ajax.response( URL_CHANGEQUESTION , this.changeQuestion.bind( this ) , lang_progress , true );
		} else {
			if( code > 0 ) {
				ErrStr = DCDiv( );
				if( code & 256 ) {
					App( ErrStr , DCP( '' , lang_errors['question_length'] ) );
				}
				if( code & 512 ) {
					App( ErrStr , DCP( '' , lang_errors['answer_length'] ) );
				}
				if( code & 8192 ) {
					App( ErrStr , DCP( '' , lang_errors['access_denied'] ) );
				}
				Notice.error( ErrStr );
			} else if( code == 0 ) {
				Notice.info( lang_changeQuestion , 3 );
			}
		}
	},
	
	changeLang : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.addPost( 'new-lang' , $F( 'new-lang' ) );
			ajax.response( URL_CHANGELANG , this.changeLang.bind( this ) , lang_progress , true );
		} else {
			if( code > 0 ) {
				ErrStr = DCDiv( );
				if( code & 8192 ) {
					App( ErrStr , DCP( '' , lang_errors['access_denied'] ) );
				}
				if( code & 16384 ) {
					App( ErrStr , DCP( '' , lang_errors['bad_language'] ) );
				}
				Notice.error( ErrStr );
			} else {
				Notice.info( lang_changeLang , 3 );
			}
		}
	},
	
	changeAutologin : function( code , info ) {
		if( typeof( code ) == 'undefined' ) {
			ajax.response( URL_CHANGEAUTOLOGIN , this.changeAutologin.bind( this ) , lang_progress , true );
		} else {
			if( code == 1 ) {
				$( 'autologin-state-on' ).style.display = 'none';
				$( 'autologin-state-off' ).style.display = 'block';
			} else if( code == 2 ) {
				$( 'autologin-state-on' ).style.display = 'block';
				$( 'autologin-state-off' ).style.display = 'none';
			}
		}
	},
	
	CheckCountry : function( ) {
		if( $( 'country' ) && $( 'state' ) ) {
			var c = 0;
			try {
				c = parseInt( $F( 'country' ) );
			} catch( e ) { Error( e ); }
			if( c == 34 ) {
				$( 'state' ).disabled = false;
			} else {
				$( 'state' ).selectedIndex = 0;
				$( 'state' ).disabled = true;
			}
		}
	}
}
var User = new m_user( );
/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 75 $
 * $LastChangedDate: 2007-02-04 21:25:56 +0100 (Sun, 04 Feb 2007) $
 */



var Paginator = Class.create( );

Paginator.prototype = {
	
	ipp     : 0,
	iw      : undefined,
	wc      : undefined,
	data    : undefined,
	pg      : 0,
	cnt     : 0,
	cb      : undefined,
	loadedP : new Array( ),
	idP     : '',
	current : -1,
	pCB     : undefined,
	cpg     : undefined,
	srt     : undefined,
	useLS   : undefined,
	sData   : undefined,
	sDataS  : 0,
	rlCB    : undefined,
	
	initialize : function( itemsPerPage , wContainer , idPrefix , pageCallBack , sortFunction , searchFunc ) {
		if( idPrefix.match( /[0-9]/ ) ) alert( "bad idPrefix for paginator :: " + idPrefix );
		this.ipp = itemsPerPage;
		this.wc  = wContainer;
		if( ! isUndefined( idPrefix ) ) {
			this.idP = idPrefix;
		}
		this.pCB = pageCallBack;
		this.srt = sortFunction;
		if( ! isUndefined( searchFunc ) ) {
			this.useLS = searchFunc;
		}
	},
	
	setRideListCallBack : function( obj ) {
		this.rlCB = obj;
	},
	
	writeList : function( wList , callBack , cPage ) {
		
		this.loadedP = new Array( );
		this.current = -1;
		
		RC( this.wc );
		this.data = wList;
		--this.sDataS;
		this.cnt  = wList.length;
		if( this.cnt == 0 ) {
			return false;
		}
		this.cb = callBack;
		if( ! isUndefined( this.srt ) ) {
			this.data = this.data.sort( this.srt );
		}
		this.pg = 0;
		if( this.ipp > 0 && this.cnt > this.ipp ) {
			this.pg = ( this.cnt - ( this.cnt % this.ipp ) ) / this.ipp;
			this.pg+= ( this.cnt % this.ipp ) > 0 ? 1 : 0;
		} else {
			this.pg = 1;
		}
		if( isUndefined( cPage ) ) {
			cPage = 0;
		} else if( isNumber( cPage ) ) {
			if( cPage >= this.pg ) {
				cPage = this.pg - 1;
			}
			if( cPage < 0 ) {
				cPage = 0;
			}
		}
		if( this.pg > 1 ) {
			var t = DCDiv( );
			t.className = 'paginator-buttons-box-top';
			t.id = 'paginator-top-buttons';
			var b = DCDiv( )
			b.className = 'paginator-buttons-box-bottom';
			b.id = 'paginator-bottom-buttons';
			
			App( this.wc , t );
		}
		for( var i=0 ; i<this.pg ; ++i ) {
			/*if( this.pg > 1 ) {
				this.pgBtn( t , i , 'top' );
				this.pgBtn( b , i , 'bottom' );
			}*/
			pgi = DCDiv( this.idP + 'page-' + i );
			pgi.className = 'paginator-page';
			pgi.style.display = 'none';
			App( this.wc , pgi );
		}
		if( this.pg > 1 ) {
			App( this.wc , b );
		}
		this.page( cPage );
		return true;
	},
	
	makeButtons : function( ) {
		if( this.pg > 1 ) {
			var t = $( 'paginator-top-buttons' );
			var b = $( 'paginator-bottom-buttons' );
			RC( t );
			RC( b );
			this.pgBtn( t , 0 , 'top' , '<<' , 'first1' );
			this.pgBtn( b , 0 , 'bottom' , '<<' , 'first2' );
			this.pgBtn( t , ( this.current > 0 ? this.current - 1 : 0 ) , 'top' , '<' , 'prev1' );
			this.pgBtn( b , ( this.current > 0 ? this.current - 1 : 0 ) , 'bottom' , '<' , 'prev2' );
			var mxS = 4;
			if( mxS % 2 ) mxS = mxS - 1;
			var mxP = mxS / 2;
			var s   = 0;
			var e   = this.pg;
			if( mxS ) {
				var mxP = mxS / 2;
				if( this.pg > mxS ) {
					s = this.current - mxP;
					if( s < 0 ) {
						s = 0;
						e = s + mxS + 1;
					} else {
						e = this.current + mxP + 1;
					}
					if( e > this.pg ) {
						e = this.pg;
						s = this.pg - mxS - 1;
					}
				}
			}
			if( s > 0 ) {
				sp = DCSpan( undefined , '...' );
				sp.className = 'paginator-spacer';
				App( t , sp );
				sp = DCSpan( undefined , '...' );
				sp.className = 'paginator-spacer';
				App( b , sp );
			}
			for( var i=s ; i<e ; ++i ) {
				var sel = false;
				if( i == this.current ) {
					sel = true;
				}
				this.pgBtn( t , i , 'top' , undefined , undefined , sel );
				this.pgBtn( b , i , 'bottom' , undefined , undefined , sel );
			}
			if( e < this.pg ) {
				sp = DCSpan( undefined , '...' );
				sp.className = 'paginator-spacer';
				App( t , sp );
				sp = DCSpan( undefined , '...' );
				sp.className = 'paginator-spacer';
				App( b , sp );
			}
			this.pgBtn( t , ( this.current + 1 > this.pg ? this.current + 1 : this.pg - 1 ) , 'top' , '>' , 'next1' );
			this.pgBtn( b , ( this.current + 1 > this.pg ? this.current + 1 : this.pg - 1 ) , 'bottom' , '>' , 'next2' );
			this.pgBtn( t , this.pg - 1 , 'top' , '>>' , 'last1' );
			this.pgBtn( b , this.pg - 1 , 'bottom' , '>>' , 'last2' );
		}
	},
	
	getPage : function( ) {
		return this.current;
	},
	
	pgBtn : function( cr , nr , type , txt , bID , sel ) {
		if( isUndefined( sel ) ) {
			sel = false;
		}
		if( isUndefined( txt ) ) {
			txt = nr + 1;
		}
		if( isUndefined( bID ) ) {
			bID = nr;
		}
		var bt = DCSpan( this.idP + 'pg-' + type + '-btn-' + bID );
		bt.className = 'paginator-button' + ( sel ? '-selected' : '' );
		App( bt , Txt( txt ) );
		eval( 'bt.onclick = function( ) {' + this.pCB + '( this ); };' );
		App( cr , bt );
	},
	
	page : function( pNr ) {
		if( this.pg > 0 ) {
			if( isObject( pNr ) ) {
				pNr = pNr.id;
				if( pNr.match( /(first)(1|2)$/ ) ) {
					pNr = 0;
				} else if( pNr.match( /(last)(1|2)$/ ) ) {
					pNr = this.pg - 1;
				} else if( pNr.match( /(next)(1|2)$/ ) ) {
					pNr = this.current + 1 < this.pg ? this.current + 1 : this.current;
				} else if( pNr.match( /(prev)(1|2)$/ ) ) {
					pNr = this.current - 1 >= 0 ? this.current - 1 : this.current;
				} else {
					pNr = pNr.replace( /[^0-9]/g , '' );
				}
			}
			pNr *= 1;
			if( pNr >= 0 && pNr < this.pg && this.current != pNr ) {
				if( ! isUndefined( this.cpg ) ) { 
					this.cpg.style.display = 'none';
				}
				this.cpg = $( this.idP + 'page-' + pNr );
				this.cpg.style.display = 'block';
				this.current = pNr;
				/*for( var i=0 ; i<this.pg ; ++i ) {
					if( this.pg > 1 ) {
						$( this.idP + 'pg-top-btn-' + i ).className = 'paginator-btn' + ( pNr == i ? '-selected' : '' );
						$( this.idP + 'pg-bottom-btn-' + i ).className = 'paginator-btn' + ( pNr == i ? '-selected' : '' );
					}
				}*/
				this.makeButtons( );
				if( isUndefined( this.loadedP['page-'+pNr] ) ) {
					this.loadPage( );
				}
			}
		}
	},
	
	search : function( params ) {
		if( ! isUndefined( this.useLS ) ) {
			var tmp = new Array( );
			if( isUndefined( this.sData ) || this.sDataS < 0 ) {
				this.sData = this.data;
			}
			if( params.length > 0 ) {
				var dt  = this.sData;
				for( var i=0 ; i<dt.length ; ++i ) {
					if( this.useLS( dt[i] , params ) ) {
						tmp.push( dt[i] );
					}
				}
			} else {
				tmp = this.sData;
			}
			if( this.data.length != tmp.length ) {
				this.sDataS = 1;
				this.writeList( tmp , this.cb , this.current );
			}
		}
	},
	
	loadPage : function( ) {
		var s   = this.current * this.ipp;
		var inr = 0;
		var e   = s + this.ipp;
		if( e > this.cnt ) {
			e = this.cnt;
		}
		App( this.cpg , DCSpacer( ) );
		for( var i=s ; i<e ; ++i ) {
			this.cb( this.data[i] , this.cpg , inr );
			++inr;
		}
		App( this.cpg , DCSpacer( ) );
		this.loadedP['page-'+this.current] = true;
	},
	
	rideList : function( action ) {
		if( isUndefined( this.rlCB ) ) {
			return false;
		}
		var s   = this.current * this.ipp;
		var inr = 0;
		var e   = s + this.ipp;
		if( e > this.cnt ) {
			e = this.cnt;
		}
		for( var i=s ; i<e ; ++i ) {
			this.rlCB( this.data[i] , action );
		}
	}
};


var o2_Calendar = Class.create( );

o2_Calendar.prototype = {
	
	opened : false,
	
	counter : 0,
	
	settsarr : new Array( ),
	
	settings : false,
	
	day_sh : -1,
	
	cur : -1,
	
	pbox : false,
	
	days : new Array( 'po' , 'wt' , 'śr' , 'cz' , 'pt' , 'so' , 'nd' ),
	
	months : new Array( 'styczeń' , 'luty' , 'marzec' , 'kwiecień' , 'maj' , 'czerwiec' , 'lipiec' , 'sierpień' , 'wrzesień' , 'październik' , 'listopad' , 'grudzień' ),
	
	initialize : function( ) {
	},
	
	_ParseCfg : function( cfg ) {
		
		var d = new Date( );
		
		this.settings = {
			field : false,
			box : false,
			show : false,
			show_year : false,
			show_month : false,
			show_day : false,
			show_hour : false,
			show_minute : false,
			show_seconds : false,
			show_remove : false,
			year : 0,
			month : 0,
			day : 0,
			hour : 0,
			minute : 0,
			seconds : 0,
			object : false,
			days_count : 0,
			callback : false
		};
		
		
		if( isObject( cfg.callback ) ) {
			this.settings.callback = cfg.callback;
		}
		
		if( isString( cfg.box ) && $( cfg.box ) ) {
			this.settings.box = cfg.box;
		}
		
		
		if( isString( cfg.field ) && $( cfg.field ) ) {
			this.settings.field = cfg.field;
		}
		
		
		if( isString( cfg.show ) ) { 
			if( -1 < cfg.show.indexOf( 'y' ) ) {
				this.settings.show      = true;
				this.settings.show_year = true;
			}
			
			if( -1 < cfg.show.indexOf( 'R' ) ) {
				this.settings.show_remove = true;
			}
			
			if( -1 < cfg.show.indexOf( 'm' ) ) {
				this.settings.show       = true;
				this.settings.show_month = true;
			}
			
			if( -1 < cfg.show.indexOf( 'd' ) ) {
				this.settings.show     = true;
				this.settings.show_day = true;
			}
			
			if( -1 < cfg.show.indexOf( 'H' ) ) {
				this.settings.show      = true;
				this.settings.show_hour = true;
				if( -1 < cfg.show.indexOf( 'M' ) ) {
					this.settings.show        = true;
					this.settings.show_minute = true;
					if( -1 < cfg.show.indexOf( 'S' ) ) {
						this.settings.show         = true;
						this.settings.show_seconds = true;
					}
				}
			}
		}
		if( this.settings.show ) {
		
			this._SetDate( cfg.start );
			
			if( this.settings.field ) {
				this._SetDate( $( this.settings.field ).value );
			} else if( this.settings.box ) {
				this._SetDate( $( this.settings.box ).innerHTML );
			} else if( this.settings.callback ) {
				this._SetDate( this.settings.callback() );
			}
			
			if( isString( cfg.pbox ) && $( cfg.pbox ) ) {
				this.pbox = cfg.pbox;
			} else if( this.settings.box ) {
				this.pbox = $( this.settings.box ).parentNode;
			} else if( this.settings.field ) {
				this.pbox = $( this.settings.field ).parentNode;
			} else {
				this.settings.show = false;
			}
			
			this._SetDateObj( );
		}
	},
	
	_SetDate : function( dstr ) {
		var m;
		if( isString( dstr ) && ( m = dstr.match( /^(\d{4})(\-)(\d{2})(\-)(\d{2})(\ )(\d{2})(:)(\d{2})(:)(\d{2})$/ ) ) ) {
			this.settings.year    = parseInt( m[1]  );
			this.settings.month   = parseInt( m[3]  );
			this.settings.day     = parseInt( m[5]  );
			this.settings.hour    = parseInt( m[7]  );
			this.settings.minute  = parseInt( m[9]  );
			this.settings.seconds = parseInt( m[11] );
		}
	},
	
	_SetDateObj : function( ) {
		if( ! this.settings.show ) {
			return;
		}
		
		var d = new Date( );
		if( this.settings.show_year || this.settings.show_month || this.settings.show_day ) {
			if( ! this.settings.year ) {
				this.settings.year = d.getFullYear( );
			}
			if( ! this.settings.month ) {
				this.settings.month = d.getMonth( ) + 1;
			}
			if( ! this.settings.day ) {
				this.settings.day = d.getDate( );
			}
			d.setFullYear( this.settings.year , ( this.settings.month - 1 ) , this.settings.day );
		}
		if( this.settings.show_hour || this.settings.show_minute || this.settings.show_seconds ) {
			d.setHours( this.settings.hour , this.settings.minute , this.settings.seconds , 0 );
		}
		this.settings.obj = d;
		
		
	},
	
	_SetDateFromObj : function( ) {
		this.settings.year    = this.settings.obj.getFullYear();
		this.settings.month   = this.settings.obj.getMonth();
		this.settings.day     = this.settings.obj.getDate();
		this.settings.hour    = this.settings.obj.getHours();
		this.settings.minute  = this.settings.obj.getMinutes();
		this.settings.seconds = this.settings.obj.getSeconds();
	},
	
	Open : function( cfg ) {
		this.Close( );
		this._ParseCfg( cfg );
		if( this.settings.show ) {
			var cal = '<div id="o2-calendar">';
			if( this.settings.show_year ) {
				cal += '<div id="o2-calendar-year-box">';
				cal += '<a href="/" onclick="return false" id="o2-calendar-year-less">&laquo;</a>';
				cal += ' &nbsp; ';
				// cal += '<span id="o2-calendar-year"></span>';
				cal += '<input type="text" id="o2-calendar-year" />';
				cal += ' &nbsp; ';
				cal += '<a href="/" onclick="return false" id="o2-calendar-year-more">&raquo;</a>';
				cal += '</div>';
			}
			if( this.settings.show_month ) {
				cal += '<div id="o2-calendar-month-box">';
				cal += '<a href="/" onclick="return false" id="o2-calendar-month-less">&laquo;</a>';
				cal += ' &nbsp; ';
				cal += '<span id="o2-calendar-month"></span>';
				cal += ' &nbsp; ';
				cal += '<a href="/" onclick="return false" id="o2-calendar-month-more">&raquo;</a>';
				cal += '</div>';
			}
			if( this.settings.show_day ) {
				cal += '<div id="o2-calendar-days-outbox"></div>';
			}
			
			if( this.settings.show_hour ) {
				cal += '<div id="o2-calendar-hour-box">';
				cal += '<p>godzina:</p><p>';
				cal += '<input type="text" class="o2-calendar-time" id="o2-calendar-hour">';
				if( this.settings.show_minute ) {
					cal += ' : <input type="text" class="o2-calendar-time" id="o2-calendar-minute">';
					if( this.settings.show_seconds ) {
						cal += ' : <input type="text" class="o2-calendar-time" id="o2-calendar-seconds">';
					}
				}
				cal += '</p></div>';
			}
			
			cal += '<div id="o2-calendar-btns">';
			if( this.settings.show_remove ) {
				cal += '<a href="/" onclick="return false" id="o2-calendar-remove">usuń</a>';
				cal += ' &nbsp; ';
			}
			cal += '<a href="/" onclick="return false" id="o2-calendar-close">zamknij</a>';
			cal += ' &nbsp; ';
			cal += '<a href="/" onclick="return false" id="o2-calendar-save">ok</a>';
			cal += '</div>';
			
			if( ! $( 'o2-calendar-box' ) ) {
				var ele = document.getElementsByTagName( 'body' );
				ele = ele[0];
				App( ele , DCDiv( 'o2-calendar-doc' ) );
			}
			
			$( 'o2-calendar-doc' ).innerHTML = cal;
			
			this.opened = $( 'o2-calendar' );
			
			Event.observe( 'o2-calendar-close' , 'click' , function( ) { Calendar.Close( ); } );
			Event.observe( 'o2-calendar-save' , 'click' , function( ) { Calendar.Save( ); } );
			
			if( this.settings.show_remove ) {
				Event.observe( 'o2-calendar-remove' , 'click' , function( ) { Calendar.Remove( ); } );
			}
			
			if( this.settings.show_year ) {
				Event.observe( 'o2-calendar-year' , 'keyup' , function( ) { Calendar.YearInput( ); } );
				Event.observe( 'o2-calendar-year-less' , 'click' , function( ) { Calendar.Year( -1 ); } );
				Event.observe( 'o2-calendar-year-more' , 'click' , function( ) { Calendar.Year( 1 ); } );
			}
			
			if( this.settings.show_month ) {
				Event.observe( 'o2-calendar-month-less' , 'click' , function( ) { Calendar.Month( -1 ); } );
				Event.observe( 'o2-calendar-month-more' , 'click' , function( ) { Calendar.Month( 1 ); } );
			}
			
			if( this.settings.show_hour ) {
				Event.observe( 'o2-calendar-hour' , 'keyup' , function( ) { Calendar.Hour( 'hour' ) } );
				Event.observe( 'o2-calendar-hour' , 'blur' , function( ) { Calendar.SetHour( ) } );
				if( this.settings.show_minute ) {
					Event.observe( 'o2-calendar-minute' , 'keyup' , function( ) { Calendar.Hour( 'minute' ) } );
					Event.observe( 'o2-calendar-minute' , 'blur' , function( ) { Calendar.SetHour( ) } );
					if( this.settings.show_seconds ) {
						Event.observe( 'o2-calendar-seconds' , 'keyup' , function( ) { Calendar.Hour( 'seconds' ) } );
						Event.observe( 'o2-calendar-seconds' , 'blur' , function( ) { Calendar.SetHour( ) } );
					}
				}
				cal += '</p></div>';
			}
			
			var pos = boxPosition( this.pbox );
			$( 'o2-calendar' ).style.left = pos.x + 'px';
			$( 'o2-calendar' ).style.top = pos.y + 'px';
			
			this.WriteYear( );
			this.WriteHours( );
		}
	},
	
	WriteYear : function( ) {
		if( $( 'o2-calendar-year' ) ) {
			$( 'o2-calendar-year' ).value = this.settings.obj.getFullYear( );
		}
		if( this.settings.show_month ) {
			this.WriteMonth( );
		}
	},
	
	WriteMonth : function( ) {
		if( $( 'o2-calendar-month' ) ) {
			$( 'o2-calendar-month' ).innerHTML = this.months[this.settings.obj.getMonth( )];
		}
		if( this.settings.show_day ) {
			this.WriteDays( );
		}
	},
	
	WriteDays : function( ) {
		if( $( 'o2-calendar-days-outbox' ) ) {
			this.day_sh = -1;
			var html = '<table id="o2-calendar-days-box">';
			var d = 0;
			if( this.settings.show_year && this.settings.show_month ) {
				html += '<tr>';
				for( var i=0 ; i<this.days.length ; ++i )  {
					html += '<th>' + this.days[i] + '</th>';
				}
				html += '</tr>';
				var dt = new Date( );
				dt.setFullYear( this.settings.obj.getFullYear( ) , this.settings.obj.getMonth( ) , 1 );
				// d -= dt.getDay( );
				var ds = dt.getDay( ) - 1;
				if( ds == -1 ) {
					ds = 6;
				}
				d -= ds;
			}
			var s = false;
			var f = 0;
			
			var cur = -1;
			var dcnt = 32;
			var dcd = new Date( );
			if( this.settings.show_year && this.settings.show_month && this.settings.obj.getMonth( ) == dcd.getMonth( ) && this.settings.obj.getFullYear( ) == dcd.getFullYear( ) ) {
				cur = dcd.getDate( ) - 1;
			}
			this.cur = cur;
			if( ! this.settings.show_month ) {
				dcnt = 31;
			} else if( ! this.settings.show_year && this.settings.obj.getMonth( ) == 1 ) {
				dcnt = 29;
			} else {
				do {
					--dcnt;
					dcd.setFullYear( this.settings.obj.getFullYear( ) , this.settings.obj.getMonth( ) , dcnt );
					if( dcnt < 27 ) {
						break;
					}
				} while( dcd.getMonth( ) != this.settings.obj.getMonth( ) );
			}
			html += '<tr>';
			for( d ; d<dcnt ; ++d ) {
				var attr = ' class="o2-calendar-day-empty"';
				if( d >= 0 ) {
					if( this.settings.obj.getDate( ) == ( d + 1 ) && this.settings.obj.getMonth( ) == ( this.settings.month - 1 ) && this.settings.obj.getFullYear( ) == this.settings.year ) {
						attr = ' class="o2-calendar-day-selected' + ( d == cur ? ' o2-calendar-day-current' : '' ) + '"';
						this.day_sh = d;
					} else {
						attr = ' class="o2-calendar-day-btn' + ( d == cur ? ' o2-calendar-day-current' : '' ) + '"';
						attr+= ' onclick="Calendar.Day( ' + d + ' )"';
					}
					attr+= ' id="o2-calendar-day-' + d + '"';
				}
				html += '<td' + attr + '>' + ( d >= 0 ? ( d + 1 ) : '&nbsp;' ) + '</td>';
				if( s && ! ( ( f + 1 ) % 7 )  && ( d + 1 ) < dcnt ) {
					html += '</tr><tr>';
				}
				++f;
				s = true;
			}
			html += '</tr></table>';
			
			$( 'o2-calendar-days-outbox' ).innerHTML = html;
		}
	},
	
	WriteHours : function( ) {
		if( $( 'o2-calendar-hour' ) ) {
			var h = this.settings.obj.getHours( );
			if( h < 10 ) {
				h = '0' + h;
			}
			$( 'o2-calendar-hour' ).value = h;
		}
		if( this.settings.show_minute ) {
			this.WriteMinutes( );
		}
	},
	
	WriteMinutes : function( ) {
		if( $( 'o2-calendar-minute' ) ) {
			var m = this.settings.obj.getMinutes( );
			if( m < 10 ) {
				m = '0' + m;
			}
			$( 'o2-calendar-minute' ).value = m;
		}
		if( this.settings.show_seconds ) {
			this.WriteSeconds( );
		}
	},
	
	WriteSeconds : function( ) {
		if( $( 'o2-calendar-seconds' ) ) {
			var s = this.settings.obj.getSeconds( );
			if( s < 10 ) {
				s = '0' + s;
			}
			$( 'o2-calendar-seconds' ).value = s;
		}
	},
	
	Close : function( ) {
		if( isObject( this.opened ) ) {
			this.opened.parentNode.removeChild( this.opened );
			this.opened = undefined;
			delete this.settings.obj;
			delete this.settings;
			this.settings = undefined;
		}
	},
	
	YearInput : function( ) {
		var i = $F( 'o2-calendar-year' );
		var ii = i.replace( '/[^0-9]/g' , '' );
		if( i != ii ) {
			$( o2-calendar-year ).value = ii;
		}
		if( ii ) {
			var d = this.settings.obj.getDate( );
			var m = this.settings.obj.getMonth( );
			var y = parseInt( ii );
			if( isNaN( y ) ) {
				$( o2-calendar-year ).value = this.settings.obj.getFullYear( );
			}
			this.settings.obj.setFullYear( y , m , d );
			this.WriteMonth( );
		}
	},
	
	Year : function( side ) {
		var d = this.settings.obj.getDate( );
		var m = this.settings.obj.getMonth( );
		var y = this.settings.obj.getFullYear( ) + side;
		this.settings.obj.setFullYear( y , m , d );
		this.WriteYear( );
	},
	
	
	Month : function( side ) {
		var d = this.settings.obj.getDate( );
		var m = this.settings.obj.getMonth( ) + side;
		var y = this.settings.obj.getFullYear( );
		var w = false;
		if( m < 0 || m > 11 ) {
			m = m < 0 ? 11 : 0;
			y+= side;
			w = true;
		}
		this.settings.obj.setFullYear( y , m , d );
		if( w ) {
			this.WriteYear( );
		} else {
			this.WriteMonth( );
		}
	},
	
	Day : function( cd ) {
		if( this.day_sh != -1 && $( 'o2-calendar-day-' + this.day_sh ) ) {
			$( 'o2-calendar-day-' + this.day_sh ).className = 'o2-calendar-day-btn' + ( this.cur != -1 && this.cur == this.day_sh ? ' o2-calendar-day-current' : '' );
			eval( "$( 'o2-calendar-day-" + this.day_sh + "' ).onclick = function( ) { Calendar.Day( " + this.day_sh + " ); };" );
		}
		if( $( 'o2-calendar-day-' + cd ) ) {
			this.day_sh = cd;
			this.settings.day = cd + 1;
			this.settings.month = this.settings.obj.getMonth() + 1;
			this.settings.year = this.settings.obj.getFullYear( );
			this.settings.obj.setFullYear( this.settings.year , this.settings.month - 1 , this.settings.day );
			$( 'o2-calendar-day-' + cd ).onclick = function( ) { };
			$( 'o2-calendar-day-' + cd ).className = 'o2-calendar-day-selected' + ( this.cur != -1 && this.cur == cd ? ' o2-calendar-day-current' : '' );
		}
	},
	
	Hour : function( field ) {
		var t = $F( 'o2-calendar-' + field );
		var s = false;
		if( t.match( /[^0-9]/ ) ) {
			t = t.replace( /[^0-9]/g );
			s = true;
		}
		t = parseInt( t );
		t = isNaN( t ) ? 0 : t;
		if( field == 'hour' && t > 23 ) {
			t = 23;
			s = true;
		} else if( field != 'hour' && t > 59 ) {
			t = 59;
			s = true;
		}
		
		if( s ) {
			$( 'o2-calendar-' + field ).value = t;
		}
	},
	
	SetHour : function( ) {
		var h = 0;
		var m = 0;
		var s = 0;
		if( $( 'o2-calendar-hour' ) ) {
			h = parseInt( $( 'o2-calendar-hour' ).value.replace( /[^0-9]/g ) );
			h = isNaN( h ) ? 0 : h;
		}
		if( $( 'o2-calendar-minute' ) ) {
			m = parseInt( $( 'o2-calendar-minute' ).value.replace( /[^0-9]/g ) );
			m = isNaN( m ) ? 0 : m;
		}
		if( $( 'o2-calendar-seconds' ) ) {
			s = parseInt( $( 'o2-calendar-seconds' ).value.replace( /[^0-9]/g ) );
			s = isNaN( s ) ? 0 : s;
		}
		this.settings.obj.setHours( h , m , s );
		this.settings.hour = this.settings.obj.getHours( );
		this.settings.minute = this.settings.obj.getMinutes( );
		this.settings.seconds = this.settings.obj.getSeconds( );
		if( $( 'o2-calendar-hour' ) ) {
			$( 'o2-calendar-hour' ).value = ( this.settings.hour < 10 ? '0' : '' ) + this.settings.hour;
		}
		if( $( 'o2-calendar-minute' ) ) {
			$( 'o2-calendar-minute' ).value = ( this.settings.minute < 10 ? '0' : '' ) + this.settings.minute;
		}
		if( $( 'o2-calendar-seconds' ) ) {
			$( 'o2-calendar-seconds' ).value = ( this.settings.seconds < 10 ? '0' : '' ) + this.settings.seconds;
		}
	},
	
	Remove : function( ) {
		this.settings.year = 0;
		this.settings.month = 0;
		this.settings.day = 0;
		this.settings.hour = 0;
		this.settings.minute = 0;
		this.settings.seconds = 0;
		this.Save( true );
	},
	
	Save : function( r ) {
		if( isObject( this.opened ) ) {
			if( ! this.show_day && ( isUndefined( r ) || ! r ) ) {
				this.settings.year = this.settings.obj.getFullYear( );
				this.settings.month = this.settings.obj.getMonth( ) + 1;
			}
			var d = '';
			// d += this.settings.show_year ? this.settings.year : '0000';
			if( this.settings.show_year ) {
				var y = this.settings.year + '';
				for( var i = 4 - y.length ; i>0 ; --i ) {
					y = '0' + y;
				}
				d += y;
			} else {
				d += '0000';
			}
			d += '-';
			if( this.settings.show_month ) {
				d += ( this.settings.month < 10 ) ? '0' : '';
				d += this.settings.month;
			} else {
				d += '00';
			}
			d += '-';
			if( this.settings.show_day ) {
				d += ( this.settings.day < 10 ) ? '0' : '';
				d += this.settings.day;
			} else {
				d += '00';
			}
			d += ' ';
			
			if( this.settings.show_hour ) {
				d += ( this.settings.hour < 10 ) ? '0' : '';
				d += this.settings.hour;
				if( this.settings.show_minute ) {
					d += ':' + ( ( this.settings.minute < 10 ) ? '0' : '' ) + this.settings.minute;
					if( this.settings.show_seconds ) {
						d += ':' + ( ( this.settings.seconds < 10 ) ? '0' : '' ) + this.settings.seconds;
					} else {
						d += ':00';
					}
				} else {
					d += ':00:00';
				}
			} else {
				d += '00:00:00';
			}
			
			if( this.settings.box ) {
				$( this.settings.box ).innerHTML = d;
			}
			
			if( this.settings.field ) {
				$( this.settings.field ).value = d;
			}
			
			if( isObject( this.settings.callback ) ) {
				this.settings.callback( d );
			}
			
			this.Close( );
		}
	}
};


var Calendar = new o2_Calendar( );

/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 404 $
 * $LastChangedDate$
 */

function _extendDate( ) {
	if( typeof( WEEK_DAYS ) == 'undefined' ) {
		setTimeout( _extendDate , 10 );
		return;
	}
	Date.prototype._ZF = function( nr , len ) {
		nr = '' + nr;
		if( nr.length < len ) {
			while( nr.length < len ) {
				nr = '0' + nr;
			}
		}
		return nr;
	}
	
	
	Date.prototype._strf = function( t ) {
		var d = '';
		var l = 0;
		switch( t ) {
			case '%a':
				if( WEEK_DAYS_SHORT ) {
					d = WEEK_DAYS_SHORT[this.getDay()];
				}
			break;
			case '%A':
				if( WEEK_DAYS ) {
					d = WEEK_DAYS[this.getDay()];
				}
			break;
			case '%b':
			case '%h':
				if( MONTHS_SHORT ) {
					d = MONTHS_SHORT[this.getMonth()];
				}
			break;
			case '%B':
				if( MONTHS ) {
					d = MONTHS[this.getMonth()];
				}
			break;
			case '%d':
				d += this.getDate( );
				l  = 2;
			break;
			case '%c':
				d += this.toString( );
			break;
			case '%C':
				l = this.getFullYear( );
				if( y < 0 ) {
					l*= -1;
					d += Math.ceil( y / 100 ) + 'bc';
				} else {
					d += Math.ceil( y / 100 );
				}
				l = 0;
			break;
			case '%D':
				d += this.strf( '%m/%d/%y' );
			break;
			case '%e':
				l  = this.getDate( );
				if( l < 10 ) {
					d += ' ';
				}
				d += l;
				l  = 0;
			break;
			case '%g':
			break;
			case '%G':
			break;
			case '%H':
				d += this.getHours( );
				l  = 2;
			break;
			case '%I':
				l  = this.getHours( ) + 1;
				if( l > 12 ) {
					l -= 12;
				}
				d += l;
				l  = 2;
			break;
			case '%j':
			break;
			case '%m':
				d += ( this.getMonth( ) + 1 );
				l  = 2;
			break;
			case '%M':
				d += this.getMinutes( );
				l  = 2;
			break;
			case '%n':
				d += '\n';
			break;
			case '%p':
				d += ( this.getHours( ) >= 12 ? 'pm' : 'am' );
			break;
			case '%r':
				d += this.strf( '%I:%M:%S %p' );
			break;
			case '%R':
				d += this.strf( '%H:%M:%S' );
			break;
			case '%S':
				d += this.getSeconds( );
				l  = 2;
			break;
			case '%t':
				d += '\t';
			break;
			case '%u':
				d = this.getDay( );
				if( d == 0 ) {
					d = 7;
				}
				d += '';
			break;
			case '%U':
			break;
			case '%V':
			break;
			case '%W':
			break;
			case '%w':
				d += this.getDay( );
			break;
			case '%x':
				d = this.strf( '%d.%m.%Y' );
			break;
			case '%X':
				d = this.strf( '%d.%m.%Y %H:%M:%S' );
			break;
			case '%y':
				d = ( this.getFullYear( ) + '' ).substr( 2 );
			break;
			case '%Y':
				d+= this.getFullYear( );
			break;
			case '%Z':
			break;
		}
		if( l ) {
			d = this._ZF( d , l );
		}
		return d;
	}
	
	Date.prototype.strf = function( format ) {
		
		var arr = format.match( /(%[a-zA-Z])/g );
		arr = arr.getUnique( );
		
		for( var i=0 ; i<arr.length ; ++i ) {
			format = format.replace( new RegExp( arr[i] , 'g' ) , this._strf( arr[i] ) );
		}
		
		return format;
	}
	
	Date.prototype.SQLDate = function( ) {
		return this.strf( '%Y-%m-%d' );
	}
	
	
	Date.prototype.SQLDateTime = function( ) {
		return this.strf( '%Y-%m-%d %H:%M:%S' );
	}
	
	Date.prototype.setSQLDate = function( date ) {
		var m = null;
		if( m = date.match( /^(\d{4})(\-)(\d{2})(\-)(\d{2})/ ) ) {
			var year  = parseInt( m[1] );
			var month = parseInt( m[3] ) - 1;
			var day   = parseInt( m[5] );
			this.setFullYear( year , month , day );
			if( m = date.match( /^(\d{4})(\-)(\d{2})(\-)(\d{2})(\ )(\d{2})(:)(\d{2})(:)(\d{2})/ ) ) {
				var  hour   = parseInt( m[7] );
				var  minute = parseInt( m[9] );
				var  second = parseInt( m[11] );
				this.setHours( hour , minute , second );
			}
		}
	}
}

_extendDate( );
/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 75 $
 * $LastChangedDate: 2007-02-04 21:25:56 +0100 (Sun, 04 Feb 2007) $
 */

var m_FFields = Class.create( );


m_FFields.prototype = {
	
	fields  : new Array( ),
	
	cFields : 0,
	
	rotate  : false,
	
	lsearch : new Array( ),
	
	csearch : new Array( ),
	
	nsearch : false,
	
	initialize : function( ) { },
	
	
	gStart : function( fieldID , removeExp , maxLen , endCallBack ) {
		this.fields.push( { id  : fieldID , 
							exp : removeExp , 
							len : maxLen,
							cb  : endCallBack 
						} );
		if( ! this.rotate ) {
			this.rotate = true;
			this.gFunc( );
		}
	},
	
	gFunc : function( ) {
		if( this.fields.length ) {
			for( var i=0 ; i<this.fields.length ; ++i ) {
				if( $( this.fields[i].id ) ) {
					if( this.fields[i].exp ) {
						if( $F( this.fields[i].id ).match( this.fields[i].exp ) ) {
							$( this.fields[i].id ).value = $( this.fields[i].id ).value.replace( this.fields[i].exp , '' )
						}
					}
					if( this.fields[i].len ) {
						if( $F( this.fields[i].id ).length > this.fields[i].len ) {
							$( this.fields[i].id ).value = $( this.fields[i].id ).value.substr( 0 , this.fields[i].len );
						}
					}
				}
			}
			setTimeout( 'FFields.gFunc()' , 1 );
		} else {
			this.rotate = false;
		}
	},
	
	gStop : function( fID ) {
		var tmp = new Array( );
		for( var i=0 ; i<this.fields.length ; ++i ) {
			if( this.fields[i].id != fID ) {
				tmp.push( this.fields[i] );
			} else {
				if( this.fields[i].cb ) {
					this.fields[i].cb( fID );
				}
			}
		}
		this.fields = tmp;
	},
	
	bindSearch : function( fID , callBack , regex ) {
		if( $( fID ) ) {
			eval( '$( fID ).onfocus = function( ) { FFields.runSearch( "'  + fID + '"); };' );
			eval( '$( fID ).onblur  = function( ) { FFields.stopSearch( "' + fID + '"); };' );
			this.lsearch[fID] = { id : fID , regex : regex , cb : callBack , value : '' };
		}
	},
	
	unbindSearch : function( fID ) {
		if( $( fID ) && ! isUndefined( this.lsearch[fID] ) ) {
			$( fID ).onfocus = function( ) {};
			$( fID ).onblur  = function( ) {};
			delete this.lsearch[fID ];
		}
	},
	
	runSearch : function( fID ) {
		this.csearch.push( this.lsearch[fID] );
		if( ! this.nsearch ) {
			this.nsearch = true;
			this.searcher( );
		}
	},
	
	stopSearch : function( fID ) {
		var tc = new Array( );
		for( var ci=0 ; ci<this.csearch.length ; ++ci ) {
			if( this.csearch[ci].id != fID ) {
				tc.push( this.csearch[ci] );
			}
		}
		this.csearch = tc;
		if( this.csearch.length == 0 ) {
			this.nsearch = false;
		}
	},
	
	
	searcher : function( ) {
		if( this.nsearch ) {
			for( var vi=0 ; vi<this.csearch.length ; ++vi ) {
				var vd = '';
				if( ! ( vd = this.csearch[vi] ) ) {
					break;
				}
				var vl = $F( vd.id );
				if( ! isUndefined( vd.regex ) ) {
					var vn = vl.replace( vd.regex , '' );
					if( vl != vn ) {
						$( vd.id ).value = vn;
						vl = vn;
					}
				}
				vl = vl.trim( );
				if( vl != vd.value ) {
					this.csearch[vi].value = vl;
					vl = vl.split( ' ' );
					var tvl = new Array( );
					for( var wi=0 ; wi < vl.length ; ++wi ) {
						var t = vl[wi].trim( );
						if( t ) {
							tvl.push( t );
						}
					}
					vd.cb( tvl );
				}
			}
			setTimeout( "FFields.searcher( );" , 10 );
		}
	}
}


var FFields = new m_FFields( );


/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-libs
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 75 $
 * $LastChangedDate: 2007-02-04 21:25:56 +0100 (Sun, 04 Feb 2007) $
 */


var m_positioner = Class.create( );

m_positioner.prototype = {
	initialize : function( ) { },
	
	Maximize : function( hObj ) {
		this._Set( hObj , 0 , 0 , 0 , 0 , false );
	},
	
	SetWin : function( hObj , t , r , b , l ) {
		this._Set( hObj , t , r , b , l , true );
	},
	
	SetTop : function( hObj , t ) {
		this._Set( hObj , t , -1 , -1 , -1 , false );
	},
	
	SetTopWin : function( hObj , t ) {
		this._Set( hObj , t , -1 , -1 , -1 , true );
	},
	
	SetLeft : function( hObj , l ) {
		this._Set( hObj , -1 , -1 , -1 , l , false );
	},
	
	SetLeftWin : function( hObj , l ) {
		this._Set( hObj , -1 , -1 , -1 , l , true );
	},
	
	SetRight : function( hObj , r ) {
		this._Set( hObj , -1 , r , -1 , -1 , false );
	},
	
	SetRightWin : function( hObj , r ) {
		this._Set( hObj , -1 , r , -1 , -1 , true );
	},
	
	SetBottom : function( hObj , b ) {
		this._Set( hObj , -1 , -1 , b , -1 , false );
	},
	
	SetBottomWin : function( hObj , b ) {
		this._Set( hObj , -1 , -1 , b , -1 , true );
	},
	
	Set : function( hObj , t , r , b , l ) {
		this._Set( hObj , t , r , b , l , false );
	},
	
	_Set : function( hObj , t , r , b , l , isWin ) {
		if( isString( hObj ) ) {
			hObj = $( hObj );
		} else {
		}
		if( ! hObj ) {
			return;
		}
		
		var ps = pageSize( );
		
		var px = ps.pageX;
		var py = ps.pageY;
		
		var wx = ps.windowX;
		var wy = ps.windowY;
		
		var x  = isWin ? wx : px;
		var y  = isWin ? wy : py;
		
		var ox = 0;
		var oy = 0;
		
		if( isWin ) {
    		if (self.pageYOffset){
    			oy = self.pageYOffset;
    		} else if (document.documentElement && document.documentElement.scrollTop) {	
        		oy = document.documentElement.scrollTop; 
    		} else if (document.body) {	
    			oy = document.body.scrollTop; 
    		}
    		oy *= 1;
    		
    		if (self.pageXOffset){
    			ox = self.pageXOffset;
    		} else if (document.documentElement && document.documentElement.scrollLeft) {	
        		ox = document.documentElement.scrollLeft; 
    		} else if (document.body) {	
    			ox = document.body.scrollLeft; 
    		}
    		ox *= 1;
		}
		
		if( ! isNumber( t ) ) t = -1;
		if( ! isNumber( r ) ) r = -1;
		if( ! isNumber( b ) ) b = -1;
		if( ! isNumber( l ) ) l = -1;
		
		if( t >= 0 && b >= 0 ) {
			var h = y - ( t + b );
			hObj.style.height = h + 'px';
		}
		
		if( l >= 0 && r >= 0 ) {
			var w = x - ( t + b );
			hObj.style.width = w + 'px';
		}
		
		if( t >= 0 ) {
			var pt = t + oy;
			hObj.style.top = pt + 'px';
		} else if( b >= 0 ) {
		    var pb = ( py -( oy + wy ) ) + b;
			hObj.style.bottom = pb + 'px';
		}
		
		if( l >= 0 ) {
			var pl = l + ox;
			hObj.style.left = pl + 'px';
		} else if( r >= 0 ) {
			var pr = ( px - ( ox + wx ) ) + r;
			hObj.style.right = pr + 'px';
		}
	}
}

var Pos = new m_positioner( );

var TxtCutCnt = 0;

var TxtCut = Class.create( );

TxtCut.prototype = {
	
	text : '',
	
	div : '',
	
	outer : '',
	
	width : 0,
	
	isHtml : false,
	
	paramsSetted : null,
	
	_tags : null,
	
	_closingTag : '',
	
	_html       : '',
	
	_newHtml    : '',
	
	_dbgHtml    : '',
	
	_char       : '',
	
	initialize : function( text , params ) {
		this.paramsSetted = { };
		this.SetText( text );
		this._CreateField( );
		this.SetParams( params );
	},
	
	_CreateField : function( ) {
		++TxtCutCnt;
		var d = document.createElement( 'div' );
		// d.id = '-text-cutter-outer-' + TxtCutCnt + '-';
		d.style.zIndex = 1000 + TxtCutCnt;
		d.style.position = 'absolute';
		d.style.left = '-10000px';
		d.style.top  = '-10000px';
		//var d = document.createElement( 'div' );
		d.id = '-text-cutter-' + TxtCutCnt + '-';
		d.className = 'txtcut';
		var b = document.getElementsByTagName( 'body' );
		if( b.length < 1 ) {
			this.newText = text;
			throw new { message : "Element BODY not found!" , code : 666 };
		}
		//o.appendChild( d );
		b = b.item(0);
		b.appendChild( d );
		// this.outer = '-text-cutter-outer-' + TxtCutCnt + '-';
		this.div   = '-text-cutter-' + TxtCutCnt + '-';
	},
	
	SetText : function( text ) {
		this.text = text;
	},
	
	SetWidth : function( width ) {
		this.width = width;
		this.SetStyle( 'width' , width + 'px' );
	},
	
	SetStyle : function( name , value ) {
		$( this.div ).style[name] = value;
	},
	
	ClearParams : function( ) {
		for( var p in this.paramsSetted ) {
			$( this.div ).style[p] = '';
		}
		this.width = 0;
		this.isHtml = false;
		this.paramsSetted = { };
	},
	
	SetParams : function( params ) {
		var param, value;
		for( param in params ) {
			if( params[param] ) {
				value = params[param];
				if( param == 'width' ) {
					if( typeof( value ) == 'number' && value > 20 ) {
						this.width = value;
					}
					$( this.div ).style[param] = value + 'px';
				} else if( param == 'html' ) {
					this.isHtml = true;
				} else if( typeof( $( this.div ).style[param] ) != 'undefined' ) {
					this.paramsSetted[param] = true;
					$( this.div ).style[param] = value;
				} else if( window.console && window.console.debug ) {
					window.console.debug( 'TxtCut: unknown param ' + param );
				}
			}
		}
	},
	
	_TextWidth : function( text , html ) {
		var dv = $( this.div );
		while( dv.childNodes.length ) {
			dv.removeChild( dv.firstChild );
		}
		if( html ) {
			$( this.div ).innerHTML = text;
		} else {
			text = document.createTextNode( text );
			$( this.div ).appendChild( text );
		}
		var dim = $( this.div ).getDimensions( );
		return dim.width;
	},
	
	Cut : function( text ) {
		if( typeof( text ) == 'string' ) {
			this.SetText( text );
		}
		if( ! this.width ) {
			return this.text;
		}
		var width = this._TextWidth( this.text , this.isHtml );
		var text  = this.text;
		if( width > this.width ) {
			if( this.isHtml ) {
				text = this._CutHtml( this.text );
			} else {
				text = this._CutText( this.text );
			}
		}
		return text;
	},
	
	_CutWord : function( word ) {
		if( this._TextWidth( word , false ) < this.width ) {
			return word;
		}
		var nword = '';
		var tmp   = '';
		for( var i=0 ; i<word.length ; ++i ) {
			if( this._TextWidth( tmp + word.charAt( i ) , false ) > this.width ) {
				tmp   += ' ';
				nword += tmp;
				tmp    = '';
			}
			tmp += word.charAt( i );
			if( i == ( word.length - 1 ) ) {
				nword += tmp;
			}
		}
		return nword;
	},
	
	_ParseTag : function( ) {
		this._newHtml += this._char;
		this._dbgHtml += this._char;
		var tag = this._html.substr( 0 , ( this._html.indexOf( '>' ) + 1 ) );
		this._html = this._html.substr( tag.length );
		this._newHtml += tag;
		this._dbgHtml += tag;
		if( tag.charAt( 0 ) == '/' ) {
			this._tags.pop( );
			if( this._tags.length > 0 ) {
				this._closingTag = this._tags[this._tags.length - 1];
			} else {
				this._closingTag = '';
			}
		} else {
			if( ! tag.match( /\/\s*\>$/ ) ) {
				tag = tag.match( /^([^\s\>]+)/ )[1];
				var tags = '';
				if( this._tags.length > 0 ) {
					tags = this._tags[this._tags.length - 1];
				}
				tags += '</'+tag+'>';
				this._tags.push( tags );
				this._closingTag = tags;
			}
		}
	},
	
	_CutHtml : function( text ) {
		var w = this._TextWidth( text , true );
		if( w <= this.width ) {
			return text;
		}
		return text;
		this._tags = new Array( );
		var l      = text.length * 1;
		this._html = text;
		this._newHtml = '';
		this._dbgHtml = '';
		while( this._html ) {
			this._char = this._html.charAt( 0 );
			this._html = this._html.substr( 1 );
			if( this._char == '<' ) {
				this._ParseTag( );
			} else {
				text = this._dbgHtml + this._char + this._closingTag;
				var w = this._TextWidth( text , true );
				var r = false;
				if( w > this.width ) {
					r = true;
					this._newHtml += '<span style="font-size: 0px;_display: none;"> </span>&shy;';
					this._dbgHtml += '<br />';
				}
				this._newHtml += this._char;
				this._dbgHtml += this._char;
				if( r ) {
					var w = this._TextWidth( this._newHtml + this._html , true );
					if( w <= this.width ) {
						return this._newHtml + this._html;
					}
				}
			}
		}
		return this._newHtml;
	},
	
	_CutText : function( text , splitter ) {
		if( ! splitter ) {
			splitter = ' ';
		}
		var arr = text.split( splitter );
		var max = 0;
		var ind = new Array( );
		text = '';
		for( var i=0 ; i<arr.length ; ++i ) {
			if( text ) {
				text += splitter;
			}
			if( arr[i].match( /\-/ , text ) ) {
				text += this._CutText( arr[i] , '-' );
			} else {
				text += this._CutWord( arr[i] );
			}
		}
		return text;
	}
	
}

/**
 * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
 *
 * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="<embed type=\"application/x-shockwave-flash\" src=\""+this.getAttribute("swf")+"\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\"";_19+=" id=\""+this.getAttribute("id")+"\" name=\""+this.getAttribute("id")+"\" ";var _1a=this.getParams();for(var key in _1a){_19+=[key]+"=\""+_1a[key]+"\" ";}var _1c=this.getVariablePairs().join("&");if(_1c.length>0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="<object id=\""+this.getAttribute("id")+"\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\">";_19+="<param name=\"movie\" value=\""+this.getAttribute("swf")+"\" />";var _1d=this.getParams();for(var key in _1d){_19+="<param name=\""+key+"\" value=\""+_1d[key]+"\" />";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="<param name=\"flashvars\" value=\""+_1f+"\" />";}_19+="</object>";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace( /([a-zA-Z]|\s)+/ ,"").replace( /(\s+r|\s+b[0-9]+)/ ,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.major<fv.major){return false;}if(this.major>fv.major){return true;}if(this.minor<fv.minor){return false;}if(this.minor>fv.minor){return true;}if(this.rev<fv.rev){return false;}return true;};deconcept.util={getRequestParameter:function(_2b){var q=document.location.search||document.location.hash;if(_2b==null){return q;}if(q){var _2d=q.substring(1).split("&");for(var i=0;i<_2d.length;i++){if(_2d[i].substring(0,_2d[i].indexOf("="))==_2b){return _2d[i].substring((_2d[i].indexOf("=")+1));}}}return "";}};deconcept.SWFObjectUtil.cleanupSWFs=function(){var _2f=document.getElementsByTagName("OBJECT");for(var i=_2f.length-1;i>=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject;
var PlayerID = 0;
function putPlayer( id , isMini , fileID , artist , title , filename , autoplay , listID , itemID ) {
	if( isMini ) {
		var w = "310";
		var h = "278";
		var name = "mixer_minivideo.swf";
	} else {
		var w = "359";
		var h = "314";
		var name = "mixer_video.swf";
	}
	if( title && artist ) {
		title = artist + ' - ' + title;
	} else if( ! title && artist ) {
		title = artist;
	} else if( ! title && ! artist ) {
		title = filename;
	}
	
	if( listID && $( listID ) ) {
		$$( 'ul#' + listID + ' li' ).each( function( item ) {
			item.className = '';
		} )
		$( listID + '-' + itemID ).className = 'current';
	}
	
	var so = new SWFObject( URL_IMAGES + name , id + '-' + PlayerID , w , h , '7' , '#FFFFFF' );
	++PlayerID;
	so.addVariable( 'id' , fileID );
	so.addVariable( 'title' , title );
	so.addVariable( 'autoplay' , autoplay ? 'y' : 'n' );
	so.write( id );
	return false;
}

function putAudioPlayer( id , fileID , artist , title , album , duration , filename , autoplay , listID , itemID ) {
	var w = "310";
	var h = "44";
	var name = "mixer_audio.swf";
	
	if( ! title && ! artist ) {
		title = filename;
	} else {
		if( ! title ) {
			title = artist;
		} else {
			title = artist + ' - ' + title;
		}
		if( album ) {
			title += ' - ' + album;
		}
	}
	
	if( listID && $( listID ) ) {
		$$( 'ul#' + listID + ' li' ).each( function( item ) {
			item.className = '';
		} )
		$( listID + '-' + itemID ).className = 'current';
	}
	
	var so = new SWFObject( URL_IMAGES + name , id + '-' + PlayerID , w , h , '7' , '#FFFFFF' );
	++PlayerID;
	so.addVariable( 'id' , fileID );
	so.addVariable( 'title' , title );
	so.addVariable( 'duration' , duration );
	so.addVariable( 'autoplay' , autoplay ? 'y' : 'n' );
	so.write( id );
	return false;
}


var Picker = { 

	shown : false,
	
	events : { },
	
	callBack : null,
	
	written : false,
	
	//colors : ['#F0F8FF','#FAEBD7','#00FFFF','#7FFFD4','#F0FFFF','#F5F5DC','#FFE4C4','#000000','#FFEBCD','#0000FF','#8A2BE2','#A52A2A','#DEB887','#5F9EA0','#7FFF00','#D2691E','#FF7F50','#6495ED','#FFF8DC','#DC143C','#00FFFF','#00008B','#008B8B','#B8860B','#A9A9A9','#006400','#BDB76B','#8B008B','#556B2F','#FF8C00','#9932CC','#8B0000','#E9967A','#8FBC8F','#483D8B','#2F4F4F','#00CED3','#9400D3','#FF1493','#00C7FF','#696969','#1E90FF','#B22222','#FFFAF0','#228B22','#FF00FF','#DCDCDC','#F8F8FF','#FFD700','#DAA520','#808080','#008000','#ADFF2F','#F0FFF0','#FF69B4','#CD5C5C','#4B00B0','#FFFF82','#F0E68C','#E6E6E6','#FFF0F5','#7CFC00','#FFFACD','#ADD8E6','#F08080','#E0FFFF','#FAFAD2','#90EE90','#D3D3D3','#FFB6C1','#FFA07A','#20B2AA','#87CEFA','#778899','#B0C4DE','#FFFFE0','#00FF00','#32CD32','#FAF0E6','#FF00FF','#800000','#66CDAA','#0000CD','#BA55D3','#9370DB','#3CB371','#7B68EE','#00FA9A','#48D1CC','#C7D285','#191970','#F5FFFA','#FFE4FF','#FFE4B5','#FFDEAD','#000080','#FDF5E6','#808000','#6B8E23','#FFA500','#FF4500','#DA70D6','#EEE8AA','#98FB98','#AFEEEE','#DB7093','#FFEFD5','#FFDAB9','#CD853F','#FFC0CB','#DDA0DD','#B0E0E6','#800080','#FF0000','#BC8F8F','#4169FF','#8B4513','#FA8072','#F4A460','#2E8B57','#FFF5EE','#A0522D','#C0C0C0','#87CEEB','#6A5ACD','#708090','#FFFAFA','#00FF7F','#4682B4','#D2B48C','#008080','#D8BFD8','#FF6347','#40E0D0','#EE82EE','#F5DEB3','#FFFFFF','#F5F5F5','#FFFF00','#9ACD32'],
	colors :	['#330000','#333300','#336600','#339900','#33CC00','#33FF00','#66FF00','#66CC00'
				,'#669900','#666600','#663300','#660000','#FF0000','#FF3300','#FF6600','#FF9900'
				,'#FFCC00','#FFFF00','#330033','#333333','#336633','#339933','#33CC33','#33FF33'
				,'#66FF33','#66CC33','#669933','#666633','#663333','#660033','#FF0033','#FF3333'
				,'#FF6633','#FF9933','#FFCC33','#FFFF33','#330066','#333366','#336666','#339966'
				,'#33CC66','#33FF66','#66FF66','#66CC66','#669966','#666666','#663366','#660066'
				,'#FF0066','#FF3366','#FF6666','#FF9966','#FFCC66','#FFFF66','#330099','#333399'
				,'#336699','#339999','#33CC99','#33FF99','#66FF99','#66CC99','#669999','#666699'
				,'#663399','#660099','#FF0099','#FF3399','#FF6699','#FF9999','#FFCC99','#FFFF99'
				,'#3300CC','#3333CC','#3366CC','#3399CC','#33CCCC','#33FFCC','#66FFCC','#66CCCC'
				,'#6699CC','#6666CC','#6633CC','#6600CC','#FF00CC','#FF33CC','#FF66CC','#FF99CC'
				,'#FFCCCC','#FFFFCC','#3300FF','#3333FF','#3366FF','#3399FF','#33CCFF','#33FFFF'
				,'#66FFFF','#66CCFF','#6699FF','#6666FF','#6633FF','#6600FF','#FF00FF','#FF33FF'
				,'#FF66FF','#FF99FF','#FFCCFF','#FFFFFF','#0000FF','#0033FF','#0066FF','#0099FF'
				,'#00CCFF','#00FFFF','#99FFFF','#99CCFF','#9999FF','#9966FF','#9933FF','#9900FF'
				,'#CC00FF','#CC33FF','#CC66FF','#CC99FF','#CCCCFF','#CCFFFF','#0000CC','#0033CC'
				,'#0066CC','#0099CC','#00CCCC','#00FFCC','#99FFCC','#99CCCC','#9999CC','#9966CC'
				,'#9933CC','#9900CC','#CC00CC','#CC33CC','#CC66CC','#CC99CC','#CCCCCC','#CCFFCC'
				,'#000099','#003399','#006699','#009999','#00CC99','#00FF99','#99FF99','#99CC99'
				,'#999999','#996699','#993399','#990099','#CC0099','#CC3399','#CC6699','#CC9999'
				,'#CCCC99','#CCFF99','#000066','#003366','#006666','#009966','#00CC66','#00FF66'
				,'#99FF66','#99CC66','#999966','#996666','#993366','#990066','#CC0066','#CC3366'
				,'#CC6666','#CC9966','#CCCC66','#CCFF66','#000033','#003333','#006633','#009933'
				,'#00CC33','#00FF33','#99FF33','#99CC33','#999933','#996633','#993333','#990033'
				,'#CC0033','#CC3333','#CC6633','#CC9933','#CCCC33','#CCFF33','#000000','#003300'
				,'#006600','#009900','#00CC00','#00FF00','#99FF00','#99CC00','#999900','#996600'
				,'#993300','#990000','#CC0000','#CC3300','#CC6600','#CC9900','#CCCC00','#CCFF00'
				,'#000000','#111111','#222222','#333333','#444444','#555555','#666666','#777777'
				,'#888888','#999999','#AAAAAA','#BBBBBB','#CCCCCC','#DDDDDD','#EEEEEE','#FFFFFF',
				'#FFFFFF','#FFFFFF'],
	
	Observe : function( elementID , cb ) {
		if( ! isString( elementID ) || ! $( elementID ) ) {
			Error( '!element' );
			return false;
		}
		if( ! cb ) {
			Error( '!cb' );
			return false;
		}
		if( isUndefined( Picker.events[elementID] ) ) {
			Picker.events[elementID] = cb;
			Event.observe( $( elementID ) , 'click' , function( e ) {
				Picker._Event( e );
			} );
		} else {
			Picker.events[elementID] = cb;
		}
	},
	
	UnObserve : function( elementID ) {
		delete Picker.events[elementID];
	},
	
	_Event : function( e ) {
		try {
			var cb = Picker.events[Event.element(e).id];
			var x  = Event.pointerX( e );
			var y  = Event.pointerY( e );
			Picker.Show( x , y , cb );
		} catch( ex ) { Error( ex ) }
	},
	
	Show : function( x , y , callBack ) {
		if( ! callBack ) {
			return false;
		}
		if( ! Picker.written && ! Picker._Write( ) ) {
			return false;
		}
		Picker.callBack = callBack;
		if( Picker.shown ) {
			new Effect.Morph( 'color-picker-box' , {
				style: {
					top: y+'px',
					left: x+'px'
				},
				duration: 0.3
			} );
		} else {
			Picker.shown = true;
			$( 'color-picker-box' ).style.top = y+'px';
			$( 'color-picker-box' ).style.left = x+'px';
			new Effect.Appear( 'color-picker-box' , { duration: 0.3 } );
		}
		return false;
	},
	
	Close : function( ) {
		if( ! Picker.shown || ! $( 'color-picker-box' ) ) {
			return false;
		}
		Picker.shown = false;
		new Effect.Fade( 'color-picker-box' , { duration: 0.3 } );
	},
	
	Pick : function( hex ) {
		if( ! Picker.callBack ) {
			return false;
		}
		Picker.callBack( hex );
		Picker.callBack = null;
		Picker.Close( );
	},
	
	_Write : function( ) {
		var b = $$( 'body' );
		b = b[0];
		var pbox = DCDiv( 'color-picker-box' );
		pbox.style.display = 'none';
		App( b , pbox );
		var html = '<div><p class="title">Wybierz kolor</p></div>';
		html += '<div class="colors"><ul>';
		for( var i=0 ; i<Picker.colors.length ; ++i ) {
			html += '<li style="background-color:'+Picker.colors[i]+'" onclick="Picker.Pick(\''+Picker.colors[i]+'\')"></li>';
		}
		html += '</ul><div class="spacer"></div></div>';
		html += '<div class="buttons">';
		html += '<p><input type="button" value="Zamknij" onclick="Picker.Close()" /></p>';
		html += '</div>';
		pbox.innerHTML = html;
		Picker.written = true;
		return true;
	}

};

var gemius_identifier = '';

Event.observe( window , 'load' , function( ) {
	var v = {
		'sg'     : 'pxaQorM9488EBmu1T3sV0rR37HjWw1.r3kDs2yhGq6b.07',
		'konto'  : '.cowRCrU086pqmr1X.4lcWYk7A7Z1V.fwvTsKG_rU97.37',
		'profil' : 'pxaaprM9v_hOr0H6L2zCE2X2TILZXBAcI5v8H2e724P.E7',
		'ros'    : 'pxY6SLM9r_dOpUI6r_ZaobR3TBjWwxAQfiP8bDCDW2r.e7'
	};
	var d = null;
	for( var k in v ) {
		if( d = $( 'GEMIUS-'+k ) ) {
			gemius_identifier = v[k];
			var g  = DC( 'script' );
			g.type = 'text/javascript';
			g.src  = 'http://j.o2.pl/gemius/gemius.js';
			App( d , g );
			break;
		}
	}
} );

var Addv = Class.create( );

Addv.prototype = {
	
	opts   : null,
	
	id     : null,
	
	obj    : null,
	
	initialize : function( elementID , options ) {
		if( ! isString( elementID ) ) {
			Error( '`elementID` must be instance od String!!!' );
			return;
		}
		if( Addv.ids[elementID] ) {
			Error( '`' + elementID + '` element has been already bound!!!' );
			return;
		}
		Addv.ids[elementID] = this;
		this.id   = elementID;
		this.opts = options;
		Event.observe( window , 'load' , this.write.bind( this ) );
	},
	
	write : function( ) {
		if( ! this.id || ! $( this.id ) ) {
			Error( 'Addv: no id' );
			return;
		}
		
		var isOK = false;
		if( this.opts.swf && this.opts.swf.url && this.opts.swf.width && this.opts.swf.height ) {
			this.writeFlash( );
			isOK = true;
		}
		if( isOK ) {
			this.gemius( );
			this.open( );
		}
	},
	
	writeFlash : function( ) {
		var id  = this.id + '-swf';
		var fv  = '7';
		if( this.opts.swf.version ) {
			fv = this.opts.swf.version;
		}
		var bg  = '#FFFFFF';
		if( this.opts.swf.bgColor ) {
			bg = this.opts.swf.bgColor;
		}
		if( typeof( this.opts.swf.vars ) != 'object' ) {
			this.opts.swf.vars = { };
		}
		var ct = '';
		if( ! this.opts.swf.vars.clickTag && this.opts.clickTag ) {
			this.opts.swf.vars.clickTag = this.opts.clickTag;
			ct = this.opts.clickTag;
		} else if( this.opts.swf.vars.clickTag ) {
			ct = this.opts.swf.vars.clickTag;
		} else if( this.opts.clickTag ) {
			ct = this.opts.clickTag;
		}
		var so  = new SWFObject( this.opts.swf.url , id , this.opts.swf.width , this.opts.swf.height , fv , bg );
		for( vname in this.opts.swf.vars ) {
			if( vname == 'clickTag' && ! this.opts.swf.clickBox ) {
				so.addVariable( vname , this.opts.swf.vars[vname] );
			}
		}
		if( this.opts.swf.clickBox && ct ) {
			$( this.id ).style.position = 'relative';
			$( this.id ).style.width    = this.opts.swf.width  + 'px';
			$( this.id ).style.height   = this.opts.swf.height + 'px';
			var d = DCDiv( this.id + '-in' );
			d.style.display  = 'block';
			d.style.position = 'absolute';
			d.style.width    = this.opts.swf.width  + 'px';
			d.style.height   = this.opts.swf.height + 'px';
			d.style.top      = '0px';
			d.style.left     = '0px';
			d.style.zIndex   = '1';
			App( this.id , d );
			so.write( this.id + '-in' );
			var a = DCA( ct , '' );
			a.style.display  = 'block';
			a.style.position = 'absolute';
			a.style.width    = this.opts.swf.width  + 'px';
			a.style.height   = this.opts.swf.height + 'px';
			a.style.top      = '0px';
			a.style.left     = '0px';
			a.style.zIndex   = '1020';
			a.target         = '_blank';
			App( this.id , a );
		} else {
			so.write( this.id );
		}
	},
	
	gemius : function( ) {
		if( this.opts.gemius ) {
			var i = new Image( 1 , 1 );
			i.src = this.opts.gemius;
		}
	},
	
	open : function( ) {
		if( this.opts.open && this.opts.open.elementId && $( this.opts.open.elementId ) ) {
			if( this.opts.open.effect && Effect[this.opts.open.effect] ) {
				new Effect[this.opts.open.effect]( this.opts.open.elementId , this.opts.open.options );
			} else {
				$( this.opts.open.elementId ).show( );
			}
		}
	}
};

Addv.ids  = { };



/**
 * @author Lupatus (michal.kluszewski@firma.o2.pl)
 * @package kumple.pl
 * @subpackage js-script
 * @copyright o2.pl 2005-2007
 *
 * $Revision: 479 $
 * $LastChangedDate: 2008-01-24 17:50:25 +0100 (Thu, 24 Jan 2008) $
 */

var clockUpdaterDiv = false;
var clockUpdaterStr = '';
var clockUpdaterTO  = 60;

function clockUpdater( ) {
   	var str = clockUpdaterStr;
	var oD  = new Date( );
	str     = str.replace( '#short_year#' , ( oD.getFullYear( ) + '' ).substr( 2 , 2 )      );
	str     = str.replace( '#long_year#'  , oD.getFullYear( )                               );
	str     = str.replace( '#day_name#'   , WEEK_DAYS[oD.getDay()]                          );
	str     = str.replace( '#day#'        , strPad( oD.getDate( )          , 2 , -1 , '0' ) );
	str     = str.replace( '#month#'      , strPad( ( oD.getMonth( ) + 1 ) , 2 , -1 , '0' ) );
	str     = str.replace( '#hours#'      , strPad( oD.getHours( ) + ''    , 2 , -1 , '0' ) );
	str     = str.replace( '#minutes#'    , strPad( oD.getMinutes( ) + ''  , 2 , -1 , '0' ) );
	str     = str.replace( '#seconds#'    , strPad( oD.getSeconds( ) + ''  , 2 , -1 , '0' ) );
	
	clockUpdaterDiv.innerHTML = str;
	setTimeout( clockUpdater , clockUpdaterTO );
}

function clockUpdaterStart( ) {
	if( typeof( WEEK_DAYS ) == 'undefined' ) {
		if( Info ) {
			Info( 'no WEEK_DAYS' );
		}
		// setTimeout( clockUpdaterStart , 10 );
		return;
	}
	if( $( 'top-menu-clock' ) ) {
		clockUpdaterDiv  = $( 'top-menu-clock' );
		clockUpdaterStr  = '#day_name#, #day#/#month#/#long_year#';
		clockUpdaterStr += '<';
		clockUpdaterStr += 'strong';
		clockUpdaterStr += '> [#hours#:#minutes#';
		clockUpdaterStr += ']<';
		clockUpdaterStr += '/';
		clockUpdaterStr += 'strong';
		clockUpdaterStr += '>';
		clockUpdaterTO   = 60;
	} else if( $( 'date-time' ) ) {
		clockUpdaterDiv  = $( 'date-time' );
		clockUpdaterStr  = '<';
		clockUpdaterStr += 'span class="date"';
		clockUpdaterStr += '>#day_name#, #day#/#month#/#long_year#';
		clockUpdaterStr += '<';
		clockUpdaterStr += '/span';
		clockUpdaterStr += '> [';
		clockUpdaterStr += '<';
		clockUpdaterStr += 'span class="time"';
		clockUpdaterStr += '>#hours#:#minutes#<';
		clockUpdaterStr += '/span';
		clockUpdaterStr += '>]';
		clockUpdaterTO   = 60;
	}
	clockUpdaterTO *= 1000;
	if( clockUpdaterDiv && clockUpdaterStr && clockUpdaterTO ) {
		clockUpdater( );
	}
}

Event.observe( window , 'load' , clockUpdaterStart );

// Event.observe( window , 'load' , clockUpdaterStart );