/*
 * Bappel.net main client script
 * 
 * @author Sebastian Helzle sebastian@helzle.net
 */

var bappelnet_config = {
	host: '',
	ajax_enabled: false,
	analytics: 'UA-15378466-1',
	l10n: i18n["en"],
	idle_timeout: 300000,
	background_image: '',
	datepicker_defaults: { 
        format: i18n["en"].datepicker.format, 
        input_format: i18n["en"].datepicker.input_format, 
        starts: 1,
        mode: 'single', 
        calendars: 2,
        locale: i18n["en"].datepicker.locale
	},
	fancybox_defaults: {
	    'hideOnContentClick': false,
	    'titleShow': false,
	    'padding': 0,
	    'scrolling': 'no',
		'overlayShow': true,
		'overlayColor': '#333',
		'overlayOpacity': 0.3,
        'enableEscapeButton': true,
		'onComplete': function() {
			// Focus first input if one exists
			$('#fancybox-content').find('input, textarea, button, a.button').first().focus();
		}
	},
	debug: false
};

// Special vars
var previous_hash = '';
var current_module = '';
var cobj = null; // Page content container
var loaded_libs = {};

// Analytics config
var _gaq = [['_setAccount', bappelnet_config.analytics], ['_trackPageview'], ['_gat._anonymizeIp']];

// Sharing config
var addthis_config = {
    pubid: "sebobo",
    data_ga_tracker: _gaq,
    data_track_clickback: true,
    ui_use_css: false
};
var addthis_share = {
    url: "http://www.bappel.net",
    title: "Bappel.net - The social calendar"
};

function translate(text) {
	return text in bappelnet_config.l10n ? bappelnet_config.l10n[text] : text;
}
	
function update_config(host, debug, language_code) {
    var active_lang = i18n[language_code];
	$.extend(true, bappelnet_config, { 
            host: host, 
            debug: debug, 
            l10n: active_lang,
            datepicker_defaults: {
                format: active_lang.datepicker.format,
                input_format: active_lang.datepicker.input_format,
                locale: active_lang.datepicker.locale      
            } 
        }
	);
    // Set language for plugins
    $.extend(true, $.validator.messages, active_lang.validator);
    $.extend(true, $.prettyDate.defaults.l10n, active_lang.prettyDate);
}

function load_gmaps(callback) {
    if (google && !google.maps)
        google.load("maps", "3", { "callback": callback, other_params: "sensor=false" });
    if (!google)    
        log('Google API not loaded!');
}

function show_maps_popup_for_address(address, callback) {
    if (google && !google.maps) {
        load_gmaps(function() { show_maps_popup_for_address(address, callback); });    
    } else if (google && google.maps && address.length) {
        // Get the geoposition
        var geocoder = new google.maps.Geocoder();
        geocoder.geocode({
            'address': address
        }, function(results, status){
            if (status == google.maps.GeocoderStatus.OK) {
                callback(address, results[0].geometry.location);
            } else
                alert(address + " " + translate("not found."));
        })
    }
}

function show_maps_popup(description, backurl, lat, lng) {
    if (google && !google.maps) {
        load_gmaps(function() { show_maps_popup(description, backurl, lat, lng); });
    } else if (google && google.maps) {
        // Open the map overlay
        $.fancybox(
            '<div class="lightbox"><h5 class="top">' + description + '</h5><div id="maps-canvas">Loading...</div></div>',
            $.extend({}, bappelnet_config.fancybox_defaults, {
				'onComplete': function() {
			        // Init map canvas in overlay
                    var target = new google.maps.LatLng(lat, lng);
			        var map = new google.maps.Map($('#maps-canvas')[0], {
                        zoom: 10,
                        center: target,
                        mapTypeId: google.maps.MapTypeId.ROADMAP
                    });        
			        var marker = new google.maps.Marker({
                        position: target,
                        title: description,
                        map: map
                    });	
                    var info_window = new google.maps.InfoWindow({ content: description });
                    google.maps.event.addListener(marker, 'click', function() {
                        info_window.open(map, marker);
                    });
                    var return_button = $('<div class="maps_return_button">Back</div>')[0];
                    google.maps.event.addDomListener(return_button, 'click', function() {
                        $.history.load(backurl);
                    });		
                    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(return_button);
				}
			})  
        );      
    }
}

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
function clean_url(url) {
    /*
     * Removes the bappel.net host if it's a Bappel.net uri intended for ajax operations.
     * Parse result contains [url, scheme, slash, host, port, path, query, hash]
     */
    if (url.indexOf(bappelnet_config.host) >= 0) {
        var result = parse_url.exec(url);
        return "/" + result[5] + (result[6] ? "?" + result[6] : "" )   
    }
    return url;
}

function request_page(url, method, request_data) {
	/*
	 * method is optional, can be 'get' or 'post'.
	 * request_data is optional and is sent as request data, must be json.
	 */
    $.log.info('Requesting page ' + url);
    if (!url)
        return;
	if (method == undefined)
	    method = 'get';
        
    // Prepare request data
    request_data = $.extend(request_data == undefined ? {} : request_data, { 
        ajax:1, 
        referrer:previous_hash || 'undefined',
        view: current_module 
    });
	// Store previous hash
    previous_hash = window.location.hash.replace(/^#/, '');
    try {
        previous_hash = $.browser.mozilla ? hash : decodeURIComponent(hash);
    } catch (error) {}
	
	// Make ajax call
	$.ajax({
		type: method,
		url: url,
		data: request_data,
		cache: false,
		success: function() {
            // Update analytics
            if (!bappelnet_config.debug && _gat) _gat._getTracker(bappelnet_config.analytics)._trackPageview(url);
		},
		dataType: 'xml'
	});
}

function update_menu() {
	/*
	 * Sets the menu item the page belongs to as active. The required module name is retrieved by the meta data json object.
	 */
	if (metadata['app_module'] != 'login') {
		// Unhighlight all menu items and highlight the currently selected one
		$('#navigation li a').each(function(){ $(this).removeClass('active'); });
		$('#navigation #module_' + metadata['app_module'] + ' a').addClass('active');
        var old_module = current_module;
        current_module = metadata['app_module'];
        $('#content_container').removeClass('module_' + old_module).addClass('module_' + current_module);
	} else
		$('#navigation ul').fadeOut(300);
    
    // Update title
    var page_title = metadata['page_title'];
    if (page_title.length) document.title = page_title;
    
    // Update unread message display
	var unread_messages = metadata['unread_messages'];
	$('#menu_home').attr('title', sprintf(translate("Home - You have %d unread messages"), unread_messages)).tooltip({ showURL: false });
	if (unread_messages > 0)
		$('#unread_messages').show(100).find('.message_count').text(unread_messages);
	else
		$('#unread_messages').hide(50);
}

function flash_message(message, type) {
	var new_message = $('<div class="icon icon-' + type + '">' + message + '</div>').css('display', 'none');
	$('#flash_messenger').append(new_message);
	new_message.slideDown(200).fadeTo(6000, 0.1, function() {
		$(this).slideUp(200, function() {
			$(this).remove();
		})
	})
}

function update_flash_messenger() {
    // Check for new flash messages and slide them in
	var messages = metadata['messages'] || [];
    for (var i in messages)
        flash_message(messages[i]['message'], messages[i]['type']);
    metadata['messages'] = [];
}

function init_tabs() {
    var tabs = $('.tabs');
    if (tabs.length < 1)
        return;
        
    $('.tab-content.hidden').hide().removeClass('hidden');
    tabs.each(function() {
        var self = $(this);
		if (self.find('li a.active').length == 0)
		    self.find('li:first a').addClass('active'); //Activate first tab
	});
	var active_tab = $($("li a.active", tabs).attr("rel"));
	if (active_tab.css('display') == 'none')
		active_tab.stop().fadeIn();
		
	// Init tab links
    $('li', tabs).not('.empty-tab').click(function() {
        var self = $(this);
		var current_tab = self.find('a');
        // Do nothing if clicked tab is active 
		if (current_tab.hasClass('active')) return false;
		// Find and hide last active tab
        self.siblings().find('a.active').each(function() {
			$($(this).removeClass('active').attr('rel')).hide()
		});
		// Switch tab
        $(current_tab.addClass('active').attr('rel')).fadeIn(); 
        return false;
    })
}

function refresh_page() {
	/*
	 * Refreshes certain page elements which need adjustment after ajax requests and other page changes.
	 */	
    
	// Update messenger
	update_flash_messenger();
	
    $(".make-pretty").prettyDate();
	
	init_tabs();
	
	// Remove old datepicker dom data
	$('div[id^="datepicker_"]').remove();
	
	// Init datepickers if available
	$('form input.date-selection-date, form input.date-selection-date-all').each(function() {
		var obj = $(this);
		var selected_date = obj.val();
		if (selected_date == undefined || selected_date == '' || !selected_date) {
		    selected_date = new Date().format(bappelnet_config.datepicker_defaults.input_format);
		}
		obj.DatePicker($.extend(
		    {},
	        bappelnet_config.datepicker_defaults, 
	        {
	            date: selected_date,
	            current: selected_date,
	            onBeforeShow: function(){
	                obj.DatePickerSetDate(selected_date, true)
	            },
	            onChange: function(formated, dates) {
	                obj.val(formated).DatePickerHide()
	            }
	       }
	    ))
	});
	
	$('.autocomplete').each(function() {
		// Get data from hidden div which belongs to the autocomplete field
		var self = $(this); 
		var data = eval($('#' + self.attr('id') + '_autocomplete_data').text());
		self.autocomplete(data, {
	        minChars: 0,	
			width: 306,
	        matchContains: true,
	        autoFill: false,
			multiple: self.hasClass('multiple'),
	        formatItem: function(row, i, max) {
	            return row.name;
	        }
        })
	});

    $('.has-tooltip').not('.tooltipped').addClass('tooltipped').tooltip({ showURL: false });
    $('.has-tooltip-icon').not('.tooltipped').addClass('tooltipped').each(function() {
        var obj = $(this), 
        	tip = $('<div class="float-left icon icon-help tooltip-icon">').attr('title', obj.attr('title')).tooltip({ showURL: false });
        obj.html('<div class="float-left">' + obj.text() + '</div>').attr('title', '').append(tip);
    });
    
	
	// Hide maps popup
	$('#maps-popup-dialog').hide();
    
    $('.list-message').bind('mouseenter mouseleave', function(e) {
        var self = $(this);
        if (e.type == 'mouseenter')
            self.fadeTo(50, 1);
        else if (self.hasClass('read'))
            self.fadeTo(100, 0.6);
    });
	
    // Init social buttons if necessary
    load_fb();
    load_addthis();
    load_plusone();       
}

function load_addthis() {
    // Do nothing if no buttons are present
    if (!$('#addthis_toolbox').length)
        return;
        
    if (!window.addthis) {
        if (loaded_libs['addthis'])
            return;
        log("Loading addthis");
        loaded_libs['addthis'] = true;
        $.getScript("http://s7.addthis.com/js/250/addthis_widget.js#pubid=sebobo&async=1&domready=1", function() {
            addthis.init();
            load_addthis();
        });
    } else {
        log("Creating addthis button");
        addthis.toolbox('#addthis_toolbox');    
    }
}

function load_plusone() {
    // Do nothing if no buttons are present
    var plusone_buttons = $('.plusone_container');
    if (!plusone_buttons.length)
        return;
           
    if (!window.gapi || !window.gapi.plusone) {
        if (loaded_libs['plusone'])
            return;
        log("Loading plusone");
        loaded_libs['plusone'] = true;
        $.getScript("http://apis.google.com/js/plusone.js", load_plusone);
    } else {
        plusone_buttons.not('.plusone_loaded').each(function() {
            log("Creating plusone button");
            $(this).addClass('plusone_loaded');
            gapi.plusone.render(this, {"size": "standard", "count": "true", "href": "http://www.bappel.net" });
        });
    }
}

function load_fb() {
    // Do nothing if no buttons are present
    var fb_buttons = $('.fb_container');
    if (!fb_buttons.length)
        return;
        
    if (!window.FB) {
        if (loaded_libs['facebook'])
            return;
        // Load facebook lib
        log("Loading facebook");
        loaded_libs['facebook'] = true;
        
        window.fbAsyncInit = function() {
            FB.init({
                appId: 'bappelnet',
                status: true,
                cookie: true,
                xfbml: true
            });
            // Now init fb buttons
            load_fb();
        };
        
        var e = document.createElement('script');
        e.async = true;
        e.src = document.location.protocol + '//connect.facebook.net/de_DE/all.js';
        $('body').append('<div id="fb-root">').append(e);
    } else {
        // Init each facebook button
        fb_buttons.not('.fb_loaded').each(function(){
            var self = $(this);
            self.addClass('fb_loaded').html('<fb:like href="http://www.facebook.com/pages/Bappelnet/102791939792562" layout="button_count" action="recommend"></fb:like>');
            FB.XFBML.parse(self.get(0));
        });
    } 
}

function user_inactive() {
    if (bappelnet_config.background_image)
        $('#main, #header').stop().fadeTo(5000, 0);
}

function user_active() {
    if (bappelnet_config.background_image)
        $('#main, #header').stop().fadeTo(1000, 1);
}

/*
 * Bappel.net pre-initialization.
 * Starts all live functions and configures all settings.
 */
function bappelnet_pre_init(host, debug, language_code) {
	update_config(host, debug, language_code);
    
    // Enable form validation on all forms. If a form does not need validation it has no disadvantage.
    $('form').live('click', function() {
        var self = $(this);
		if (!self.hasClass('validation'))
	        self.addClass('validation').validate({
	            rules: {
	                date_by_lang: { date_by_lang: true }
	            }
	        })
    });
    
    // Init the maps open event links
    $('#maps-popup-dialog a').live('click', function(e) {
        e.preventDefault();
        $('#maps-popup-dialog').fadeOut();
    });
	
    $('.maps-popup').live('click', function(e) {
        e.preventDefault();
        // If an id is defined use the value from the dom elem with the specified id, else the title of the maps link.
        var obj = $(this);
        var location = obj.attr('href').length > 1 ? $(obj.attr('href')).val() : obj.attr('title');
        if (!location.length)
            alert(translate("Please specify a location."));
        else 
            show_maps_popup_for_address(location, show_maps_popup);
    });
	
    $('.maps-geo-popup').live('click', function(e) {
        e.preventDefault();
        var obj = $(this);
        var location = obj.attr('href').split(",");
        show_maps_popup(obj.attr('title'), obj.attr('rel'), parseFloat(location[0]), parseFloat(location[1]));
    });
    
    // Day edit buttons
    $('.day', cobj).live('mouseenter mouseleave', function(e) { 
	   var link = $(this).find('.day-add-event-link').stop(true);
       e.type == 'mouseenter' ? link.fadeTo(300, 1) : link.fadeTo(100, 0);
	});
	
	// Highlight similar events on hover
	$('.month-entry', $('.calendar')).live('mouseenter mouseleave', function(e) {
    	var month_entries = $('.month-entry', $('.calendar'));
		if (e.type == 'mouseenter') {
			var entry_type = '', self = $(this);
			// Get type of entry or do nothing if type is not set
			if (self.hasClass('entry-type-imported'))
                entry_type = 'entry-type-imported';
			else if (self.hasClass('entry-type-birthday'))
                entry_type = 'entry-type-birthday';
            else if (self.hasClass('entry-type-event'))
                entry_type = self.find('.group_id').text();
			
			if (!entry_type) return;
			
			// Fade others, highlight similar
			month_entries.not('.' + entry_type).parent().stop().fadeTo(200, 0.4);
			month_entries.filter('.' + entry_type).parent().stop().fadeTo(100, 1);
		} else
            month_entries.parent().stop().fadeTo(100, 1);
	});
	
	$('.list-message', cobj).live('hover', function(e) {
		var obj = $(this).find('.action_icon');
		e.type == 'mouseenter' ? obj.fadeIn(100) : obj.fadeOut(200);
	});
	
	$('.yt-link').live('click', function(e) {
		var elem = $(this);
		$.fancybox($.extend({}, bappelnet_config.fancybox_defaults, {
			'padding'      : 0,
			'autoScale'    : false,
			'transitionIn' : 'none',
			'transitionOut': 'none',
			'titleShow'    : true,
			'title'        : elem.attr('title'),
			'width'        : 680,
			'height'       : 495,
			'href'         : elem.attr('href').replace(new RegExp("watch\\?v=", "i"), 'v/'),
			'type'         : 'swf',
			'swf'          : { 'allowfullscreen': 'true', 'wmode': 'transparent' }
		}));
		return false;
	});
    
    // Toggle element links hide themselves and show the element with the id specified in href
    $('.content_folder').live('click', function(e) {
        e.preventDefault();
        $(this).removeClass('icon icon-magnifier content_folder').next().slideDown(100);
    });
    
    // Toggle element links hide themselves and show all following of the same kind
    $('.show_siblings').live('click', function(e) {
        e.preventDefault();
        $(this).slideUp(100, function() {
            $(this).nextAll().slideDown(150);    
        });
    });
    
    // Toggle other elements by changing the state of a checkbox
    $('input[type=checkbox].toggler').live('change', function() {
    	var obj = $(this);
        var target = $('.toggled-by-' + obj.attr('id'));
        obj.attr('checked') ? target.slideDown() : target.slideUp()
    });
    
    // Add date button form replicators
    $('.add-date-button').live('click', function(e) {
        e.preventDefault();
        // Create new selector 
        var new_selector = $('form .date-selection:first').clone();
        var new_selector_id = $('form .date-selection:visible').size() + 1;
        // Change new selector id's
        $('input[id^="date"]', new_selector).attr('id', 'date'+new_selector_id).attr('name', 'date'+new_selector_id).val('');
        $('select[name^="hour"]', new_selector).attr('name', 'hour'+new_selector_id);
        $('select[name^="minute"]', new_selector).attr('name', 'minute'+new_selector_id);
        $('label[for^="date"]', new_selector).attr('for', 'date'+new_selector_id);
        $('.date-selection-num', new_selector).text(new_selector_id);
        new_selector.hide();
        // Add new date selector and slide in 
        $('form .date-selection:last').after(new_selector);
		$('.date-selection-date', new_selector).each(function() {
			var obj = $(this);
	        var selected_date = new Date();
            selected_date.format(bappelnet_config.datepicker_defaults.format);
	        obj.removeClass('hasDatepicker').DatePicker($.extend(
	            {},
	            bappelnet_config.datepicker_defaults, 
	            {
	                date: selected_date,
	                current: selected_date,
	                onBeforeShow: function(){
	                    obj.DatePickerSetDate(selected_date, true);
	                },
	                onChange: function(formated, dates) {
	                    obj.val(formated);
	                    obj.DatePickerHide();
	                }
	           }
	        ))
		});
        new_selector.slideDown();
    });
    
    // Detect form changes for lightbox close handler
    $('input, textarea, select').live('change keypress', function() {
    	$(this).closest('form').addClass('edited');
    });
    
    // Remove edited class on submit
    $('form').live('submit', function() {
    	$(this).removeClass('edited');
    });
	
    // Ajax enabler
    if (bappelnet_config.host != '') {        
        // Live function to convert all internal links to ajax requests
        $('a[href*="'+bappelnet_config.host+'"]:not(.no-ajax), a[href^="/"]:not(.no-ajax)').live('click', function(e) {
            e.preventDefault();
            var obj = $(this);
            // Add confirmation check where required
			if (obj.hasClass('requires-confirmation') && confirm(obj.find('.confirmation-text').text()) == false)
			    return false;
            $.history.load(clean_url(obj.attr('href')), true);
        });
        
        $('form:not(.no-ajax)').live('submit', function(e) {
            e.preventDefault();
            var obj = $(this);
            // Disable submit button to avoid duplicate requests
            obj.find('input[type="submit"]').attr('disabled', 'disabled');
            // Convert serialized form data array into an object. Does not work with input-type "file".
            var form_data = {}, serialized_data = obj.serializeArray(), i, data;
            for (i in serialized_data) {
                data = serialized_data[i];
                form_data[data['name']] = data['value'];
            }
			// Proceed with request
            request_page(clean_url(obj.attr('action')), 'post', form_data);
        });
    }
}

/*
 * Main Bappel.net initialization
 */
function init_bappelnet(background_image) {
	// Setup blockUI
    $.extend($.blockUI.defaults, {
        baseZ: 9999,
        css: {},
	    showOverlay: false,
	    message: '<h5 class="loader">' + translate('Please wait...') + '</h5>'
    });
    
    $.extend($.log.defaults, {
    	level: bappelnet_config.debug ? 'debug' : 'off',
		prefix: 'Bappel.net'
    });
    
    // Store background url
    bappelnet_config.background_image = background_image;
    
    // Check for content obj
    cobj = $('#content_container');
    
    // Init blockUI
	$(document).ajaxStart($.blockUI).ajaxStop($.unblockUI);
	
	// Setup taconite
	$.taconite.debug = bappelnet_config.debug;
	$(document).bind('taconite-complete-notify', function(xml, status) {
        refresh_page() // Refresh page data, when taconite processed request data
	});
	
	// Init lightbox elements per live function to get elements loaded via ajax
    $('.has-lightbox').live('click', function(e) {
        e.preventDefault();
        var self = $(this);
        if (self.attr('href') == '#' && self.attr('rel'))
            self.attr('href', self.attr('rel'));
		self.fancybox(bappelnet_config.fancybox_defaults).removeClass('has-lightbox').trigger('click');
	});
	
	// Extend taconite
	$.fn.bappelReplacePageAndFadeIn = function(new_content) {    
	    // Close fancybox if it is currently displayed
	    $.fancybox.close();
		return $(this).each(function() {
	        $(this).fadeOut(20, function() {
	            $(this).empty().append(new_content).fadeIn(20, function(){
					update_menu();
					refresh_page()
				})
	        })
		})
	};
    
    $.fn.bappelLightbox = function(new_content) {
        $.fancybox($.extend({}, bappelnet_config.fancybox_defaults, {
            content: new_content,
            onCleanup: function() {
            	return $('.lightbox').has('form.edited').length ? confirm(translate('Do you really want to close the popup?')) : true;
            }
        }))
    };
    
    $.fn.bappelCloseLightbox = function() {
        $.fancybox.close();
    };
    
    $.fn.bappelUpdateMenu = function() {
        update_menu();
    };
    
    $.fn.bappelFadeReplace = function(new_content, speed) {
        speed = speed || 200;
        return this.each(function() {
            $(this).fadeOut(speed, function() { $(this).empty().append(new_content).fadeIn(speed); });
        });
    };
	
	// Init tweet cycler
	if ($('.twitter_panel .item.hidden').length > 0) {
		window.setInterval(function(){
			var next_item = $('.twitter_panel .item.active').next();
			if (next_item[0] == undefined) 
				next_item = $('.twitter_panel .item:first');
			// Hide old item
			$('.twitter_panel .item.active').removeClass('active').fadeOut(function(){
				next_item.fadeIn().addClass('active')
			})
		}, 10000)
	}
	
	// Setup ajax error handling
    $(document).ajaxError(function(e, xhr, settings, exception) {
		$.fancybox.close();
		if (xhr.responseText)
            $.taconite(xhr.responseText);
        else 
			$('#content_container').html(" \
			    <div class=\"column size1of2\"> \
				    <div class=\"elem postit info\"> \
					    Error " + xhr.status + " while requesting page<br/> \
						<em>" + settings.url + "</em><br/> \
						<a href=\"" + settings.url + "\">Please try again later</a>. \
				    </div> \
				</div>").fadeIn(20);
    });
	
	// Add language specific date validation rule to jQuery validator
	$.validator.addMethod('dateByLang', function(value, element) {
		return this.optional(element) || bappelnet_config.l10n.date_format.test(value);
	});
	
	// Enable date prettifier
    setInterval(function(){ $(".make-pretty").prettyDate() }, 5000);
	   
    // Start initial page initialization
    refresh_page();
    update_menu();
	
	// Load background image after everything else to avoid blocking javascript
	if (background_image) {
		// Load background image and add click event for background to fade out calendar   
        $('#background').css('background-image', 'url("' + background_image + '")');
    }
	
	// Init analytics
	if (!bappelnet_config.debug) {
		(function(d, t){
			var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
			g.async = true;
			g.src = '//www.google-analytics.com/ga.js';
			s.parentNode.insertBefore(g, s);
		}(document, 'script'));
	}
       
    // Enable ajax history
    $.history.init(request_page, { unescape:true });
    
    // Init inactivity timer
    $.idleTimer(bappelnet_config.idle_timeout);
    $(document).bind("idle.idleTimer", user_inactive).bind("active.idleTimer", user_active);
}
