jQuery.noConflict();
/**
 * tools.tabs 1.0.4 - Tabs done right.
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/tabs.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch : November 2008
 * Date: ${date}
 * Revision: ${revision} 
 */ 
(function($) {
 
 // static constructs
 $.tools = $.tools || {};
 
 $.tools.tabs = {
 version: '1.0.4',
 
 conf: {
 tabs: 'a',
 current: 'current',
 onBeforeClick: null,
 onClick: null, 
 effect: 'default',
 initialIndex: 0, 
 event: 'click',
 api:false,
 rotate: false
 },
 
 addEffect: function(name, fn) {
 effects[name] = fn;
 }
 }; 
 
 
 var effects = {
 
 // simple "toggle" effect
 'default': function(i, done) { 
 this.getPanes().hide().eq(i).show();
 done.call();
 }, 
 
 /*
 configuration:
 - fadeOutSpeed (positive value does "crossfading")
 - fadeInSpeed
 */
 fade: function(i, done) {
 var conf = this.getConf(), 
 speed = conf.fadeOutSpeed,
 panes = this.getPanes();
 
 if (speed) {
 panes.fadeOut(speed); 
 } else {
 panes.hide(); 
 }

 panes.eq(i).fadeIn(conf.fadeInSpeed, done); 
 },
 
 // for basic accordions
 slide: function(i, done) { 
 this.getPanes().slideUp(200);
 this.getPanes().eq(i).slideDown(400, done); 
 }, 

 // simple AJAX effect
 ajax: function(i, done) { 
 this.getPanes().eq(0).load(this.getTabs().eq(i).attr("href"), done); 
 }
 
 }; 
 
 var w;
 
 // this is how you add effects
 $.tools.tabs.addEffect("horizontal", function(i, done) {
 
 // store original width of a pane into memory
 if (!w) { w = this.getPanes().eq(0).width(); }
 
 // set current pane's width to zero
 this.getCurrentPane().animate({width: 0}, function() { $(this).hide(); });
 
 // grow opened pane to it's original width
 this.getPanes().eq(i).animate({width: w}, function() { 
 $(this).show();
 done.call();
 });
 
 }); 
 

 function Tabs(tabs, panes, conf) { 
 
 var self = this, $self = $(this), current;

 // bind all callbacks from configuration
 $.each(conf, function(name, fn) {
 if ($.isFunction(fn)) { $self.bind(name, fn); }
 });
 
 
 // public methods
 $.extend(this, { 
 click: function(i, e) {
 
 var pane = self.getCurrentPane(); 
 var tab = tabs.eq(i); 
 
 if (typeof i == 'string' && i.replace("#", "")) {
 tab = tabs.filter("[href*=" + i.replace("#", "") + "]");
 i = Math.max(tabs.index(tab), 0);
 }
 
 if (conf.rotate) {
 var last = tabs.length -1; 
 if (i < 0) { return self.click(last, e); }
 if (i > last) { return self.click(0, e); } 
 }
 
 if (!tab.length) { 
 if (current >= 0) { return self; }
 i = conf.initialIndex;
 tab = tabs.eq(i);
 } 
 
 // current tab is being clicked
 if (i === current) { return self; }
 
 // possibility to cancel click action 
 e = e || $.Event();
 e.type = "onBeforeClick";
 $self.trigger(e, [i]); 
 if (e.isDefaultPrevented()) { return; }
 
 // call the effect
 effects[conf.effect].call(self, i, function() {

 // onClick callback
 e.type = "onClick";
 $self.trigger(e, [i]); 
 }); 
 
 // onStart
 e.type = "onStart";
 $self.trigger(e, [i]); 
 if (e.isDefaultPrevented()) { return; } 
 
 // default behaviour
 current = i;
 tabs.removeClass(conf.current); 
 tab.addClass(conf.current); 
 
 return self;
 },
 
 getConf: function() {
 return conf; 
 },

 getTabs: function() {
 return tabs; 
 },
 
 getPanes: function() {
 return panes; 
 },
 
 getCurrentPane: function() {
 return panes.eq(current); 
 },
 
 getCurrentTab: function() {
 return tabs.eq(current); 
 },
 
 getIndex: function() {
 return current; 
 }, 
 
 next: function() {
 return self.click(current + 1);
 },
 
 prev: function() {
 return self.click(current - 1); 
 }, 
 
 bind: function(name, fn) {
 $self.bind(name, fn);
 return self; 
 }, 
 
 onBeforeClick: function(fn) {
 return this.bind("onBeforeClick", fn);
 },
 
 onClick: function(fn) {
 return this.bind("onClick", fn);
 },
 
 unbind: function(name) {
 $self.unbind(name);
 return self; 
 } 
 
 });
 
 
 // setup click actions for each tab
 tabs.each(function(i) { 
 $(this).bind(conf.event, function(e) {
 self.click(i, e);
 return false;
 }); 
 });

 // if no pane is visible --> click on the first tab
 if (location.hash) {
 self.click(location.hash);
 } else {
 if (conf.initialIndex === 0 || conf.initialIndex > 0) {
 self.click(conf.initialIndex);
 }
 } 
 
 // cross tab anchor link
 panes.find("a[href^=#]").click(function(e) {
 self.click($(this).attr("href"), e); 
 }); 
 }
 
 
 // jQuery plugin implementation
 $.fn.tabs = function(query, conf) {
 
 // return existing instance
 var el = this.eq(typeof conf == 'number' ? conf : 0).data("tabs");
 if (el) { return el; }

 if ($.isFunction(conf)) {
 conf = {onBeforeClick: conf};
 }
 
 // setup options
 var globals = $.extend({}, $.tools.tabs.conf), len = this.length;
 conf = $.extend(globals, conf); 

 
 // install tabs for each items in jQuery 
 this.each(function(i) { 
 var root = $(this); 
 
 // find tabs
 var els = root.find(conf.tabs);
 
 if (!els.length) {
 els = root.children(); 
 }
 
 // find panes
 var panes = query.jquery ? query : root.children(query);
 
 if (!panes.length) {
 panes = len == 1 ? $(query) : root.parent().find(query);
 } 
 
 el = new Tabs(els, panes, conf);
 root.data("tabs", el);
 
 }); 
 
 return conf.api ? el: this; 
 }; 
 
}) (jQuery); 



/**
 * tools.scrollable 1.1.2 - Scroll your HTML with eye candy.
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/scrollable.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch : March 2008
 * Date: ${date}
 * Revision: ${revision} 
 */
(function($) { 
 
 // static constructs
 $.tools = $.tools || {};
 
 $.tools.scrollable = {
 version: '1.1.2',
 
 conf: {
 
 // basics
 size: 5,
 vertical: false,
 speed: 400,
 keyboard: true, 
 
 // by default this is the same as size
 keyboardSteps: null, 
 
 // other
 disabledClass: 'disabled',
 hoverClass: null, 
 clickable: true,
 activeClass: 'active', 
 easing: 'swing',
 loop: false,
 
 items: '.items',
 item: null,
 
 // navigational elements 
 prev: '.prev',
 next: '.next',
 prevPage: '.prevPage',
 nextPage: '.nextPage', 
 api: false
 
 // CALLBACKS: onBeforeSeek, onSeek, onReload
 } 
 };
 
 var current; 
 
 // constructor
 function Scrollable(root, conf) { 
 
 // current instance
 var self = this, $self = $(this),
 horizontal = !conf.vertical,
 wrap = root.children(),
 index = 0,
 forward; 
 
 
 if (!current) { current = self; }
 
 // bind all callbacks from configuration
 $.each(conf, function(name, fn) {
 if ($.isFunction(fn)) { $self.bind(name, fn); }
 });
 
 if (wrap.length > 1) { wrap = $(conf.items, root); }
 
 // navigational items can be anywhere when globalNav = true
 function find(query) {
 var els = $(query);
 return conf.globalNav ? els : root.parent().find(query); 
 }
 
 // to be used by plugins
 root.data("finder", find);
 
 // get handle to navigational elements
 var prev = find(conf.prev),
 next = find(conf.next),
 prevPage = find(conf.prevPage),
 nextPage = find(conf.nextPage);

 
 // methods
 $.extend(self, {
 
 getIndex: function() {
 return index; 
 },
 
 getClickIndex: function() {
 var items = self.getItems(); 
 return items.index(items.filter("." + conf.activeClass)); 
 },
 
 getConf: function() {
 return conf; 
 },
 
 getSize: function() {
 return self.getItems().size(); 
 },
 
 getPageAmount: function() {
 return Math.ceil(this.getSize() / conf.size); 
 },
 
 getPageIndex: function() {
 return Math.ceil(index / conf.size); 
 },

 getNaviButtons: function() {
 return prev.add(next).add(prevPage).add(nextPage); 
 },
 
 getRoot: function() {
 return root; 
 },
 
 getItemWrap: function() {
 return wrap; 
 },
 
 getItems: function() {
 return wrap.children(conf.item); 
 },
 
 getVisibleItems: function() {
 return self.getItems().slice(index, index + conf.size); 
 },
 
 /* all seeking functions depend on this */ 
 seekTo: function(i, time, fn) {

 if (i < 0) { i = 0; } 
 
 // nothing happens
 if (index === i) { return self; } 
 
 // function given as second argument
 if ($.isFunction(time)) {
 fn = time;
 }

 // seeking exceeds the end 
 if (i > self.getSize() - conf.size) { 
 return conf.loop ? self.begin() : this.end(); 
 } 

 var item = self.getItems().eq(i); 
 if (!item.length) { return self; } 
 
 // onBeforeSeek
 var e = $.Event("onBeforeSeek");

 $self.trigger(e, [i]); 
 if (e.isDefaultPrevented()) { return self; } 
 
 // get the (possibly altered) speed
 if (time === undefined || $.isFunction(time)) { time = conf.speed; }
 
 function callback() {
 if (fn) { fn.call(self, i); }
 $self.trigger("onSeek", [i]);
 }
 
 if (horizontal) {
 wrap.animate({left: -item.position().left}, time, conf.easing, callback); 
 } else {
 wrap.animate({top: -item.position().top}, time, conf.easing, callback); 
 }
 
 
 current = self;
 index = i; 
 
 // onStart
 e = $.Event("onStart");
 $self.trigger(e, [i]); 
 if (e.isDefaultPrevented()) { return self; } 
 
 
 /* default behaviour */
 
 // prev/next buttons disabled flags
 prev.add(prevPage).toggleClass(conf.disabledClass, i === 0);
 next.add(nextPage).toggleClass(conf.disabledClass, i >= self.getSize() - conf.size);
 
 return self; 
 }, 
 
 
 move: function(offset, time, fn) {
 forward = offset > 0;
 return this.seekTo(index + offset, time, fn);
 },
 
 next: function(time, fn) {
 return this.move(1, time, fn); 
 },
 
 prev: function(time, fn) {
 return this.move(-1, time, fn); 
 },
 
 movePage: function(offset, time, fn) {
 forward = offset > 0;
 var steps = conf.size * offset;
 
 var i = index % conf.size;
 if (i > 0) {
 steps += (offset > 0 ? -i : conf.size - i);
 }
 
 return this.move(steps, time, fn); 
 },
 
 prevPage: function(time, fn) {
 return this.movePage(-1, time, fn);
 }, 
 
 nextPage: function(time, fn) {
 return this.movePage(1, time, fn);
 }, 
 
 setPage: function(page, time, fn) {
 return this.seekTo(page * conf.size, time, fn);
 }, 
 
 begin: function(time, fn) {
 forward = false;
 return this.seekTo(0, time, fn); 
 },
 
 end: function(time, fn) {
 forward = true;
 var to = this.getSize() - conf.size;
 return to > 0 ? this.seekTo(to, time, fn) : self; 
 },
 
 reload: function() { 
 $self.trigger("onReload");
 return self;
 }, 
 
 focus: function() {
 current = self;
 return self;
 },
 
 click: function(i) {
 
 var item = self.getItems().eq(i), 
 klass = conf.activeClass,
 size = conf.size; 
 
 // check that i is sane
 if (i < 0 || i >= self.getSize()) { return self; }
 
 // size == 1 
 if (size == 1) {
 if (conf.loop) { return self.next(); }
 
 if (i === 0 || i == self.getSize() -1) { 
 forward = (forward === undefined) ? true : !forward; 
 }
 return forward === false ? self.prev() : self.next(); 
 } 
 
 // size == 2
 if (size == 2) {
 if (i == index) { i--; }
 self.getItems().removeClass(klass);
 item.addClass(klass); 
 return self.seekTo(i, time, fn);
 } 
 
 if (!item.hasClass(klass)) { 
 self.getItems().removeClass(klass);
 item.addClass(klass);
 var delta = Math.floor(size / 2);
 var to = i - delta;
 
 // next to last item must work
 if (to > self.getSize() - size) { 
 to = self.getSize() - size; 
 }
 
 if (to !== i) {
 return self.seekTo(to); 
 }
 }
 
 return self;
 },
 
 // bind / unbind
 bind: function(name, fn) {
 $self.bind(name, fn);
 return self; 
 }, 
 
 unbind: function(name) {
 $self.unbind(name);
 return self; 
 } 
 
 });
 
 // callbacks 
 $.each("onBeforeSeek,onStart,onSeek,onReload".split(","), function(i, ev) {
 self[ev] = function(fn) {
 return self.bind(ev, fn); 
 };
 }); 
 
 
 // prev button 
 prev.addClass(conf.disabledClass).click(function() {
 self.prev(); 
 });
 

 // next button
 next.click(function() { 
 self.next(); 
 });
 
 // prev page button
 nextPage.click(function() { 
 self.nextPage(); 
 });
 
 if (self.getSize() < conf.size) {
 next.add(nextPage).addClass(conf.disabledClass); 
 }
 

 // next page button
 prevPage.addClass(conf.disabledClass).click(function() { 
 self.prevPage(); 
 }); 
 
 
 // hover
 var hc = conf.hoverClass, keyId = "keydown." + Math.random().toString().substring(10); 
 
 self.onReload(function() { 

 // hovering
 if (hc) {
 self.getItems().hover(function() {
 $(this).addClass(hc); 
 }, function() {
 $(this).removeClass(hc); 
 }); 
 }
 
 // clickable
 if (conf.clickable) {
 self.getItems().each(function(i) {
 $(this).unbind("click.scrollable").bind("click.scrollable", function(e) {
 if ($(e.target).is("a")) { return; } 
 return self.click(i);
 });
 });
 } 
 
 // keyboard 
 if (conf.keyboard) { 
 
 // keyboard works on one instance at the time. thus we need to unbind first
 $(document).unbind(keyId).bind(keyId, function(evt) {

 // do nothing with CTRL / ALT buttons
 if (evt.altKey || evt.ctrlKey) { return; }
 
 // do nothing for unstatic and unfocused instances
 if (conf.keyboard != 'static' && current != self) { return; }
 
 var s = conf.keyboardSteps; 
 
 if (horizontal && (evt.keyCode == 37 || evt.keyCode == 39)) { 
 self.move(evt.keyCode == 37 ? -s : s);
 return evt.preventDefault();
 } 
 
 if (!horizontal && (evt.keyCode == 38 || evt.keyCode == 40)) {
 self.move(evt.keyCode == 38 ? -s : s);
 return evt.preventDefault();
 }
 
 return true;
 
 });
 
 } else {
 $(document).unbind(keyId); 
 } 

 });
 
 self.reload(); 
 
 } 

 
 // jQuery plugin implementation
 $.fn.scrollable = function(conf) { 
 
 // already constructed --> return API
 var el = this.eq(typeof conf == 'number' ? conf : 0).data("scrollable");
 if (el) { return el; } 
 
 var globals = $.extend({}, $.tools.scrollable.conf);
 conf = $.extend(globals, conf);
 
 conf.keyboardSteps = conf.keyboardSteps || conf.size;
 
 this.each(function() { 
 el = new Scrollable($(this), conf);
 $(this).data("scrollable", el); 
 });
 
 return conf.api ? el: this; 
 
 };
 
 
})(jQuery);

/**
 * tools.overlay 1.1.2 - Overlay HTML with eye candy.
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/overlay.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch : March 2008
 * Date: ${date}
 * Revision: ${revision} 
 */
(function($) { 

 // static constructs
 $.tools = $.tools || {};
 
 $.tools.overlay = {
 
 version: '1.1.2',
 
 addEffect: function(name, loadFn, closeFn) {
 effects[name] = [loadFn, closeFn]; 
 },
 
 conf: { 
 top: '10%', 
 left: 'center',
 absolute: false,
 
 speed: 'normal',
 closeSpeed: 'fast',
 effect: 'default',
 
 close: null, 
 oneInstance: true,
 closeOnClick: true,
 closeOnEsc: true, 
 api: false,
 expose: null,
 
 // target element to be overlayed. by default taken from [rel]
 target: null 
 }
 };

 
 var effects = {};
 
 // the default effect. nice and easy!
 $.tools.overlay.addEffect('default', 
 
 /* 
 onLoad/onClose functions must be called otherwise none of the 
 user supplied callback methods won't be called
 */
 function(onLoad) { 
 this.getOverlay().fadeIn(this.getConf().speed, onLoad); 
 
 }, function(onClose) {
 this.getOverlay().fadeOut(this.getConf().closeSpeed, onClose); 
 } 
 );
 
 
 var instances = []; 

 
 function Overlay(trigger, conf) { 
 
 // private variables
 var self = this, 
 $self = $(this),
 w = $(window), 
 closers,
 overlay,
 opened,
 expose = conf.expose && $.tools.expose.version;
 
 // get overlay and triggerr
 var jq = conf.target || trigger.attr("rel");
 overlay = jq ? $(jq) : null || trigger; 
 
 // overlay not found. cannot continue
 if (!overlay.length) { throw "Could not find Overlay: " + jq; }
 
 // if trigger is given - assign it's click event
 if (trigger && trigger.index(overlay) == -1) {
 trigger.click(function(e) { 
 self.load(e);
 return e.preventDefault();
 });
 } 
 
 // bind all callbacks from configuration
 $.each(conf, function(name, fn) {
 if ($.isFunction(fn)) { $self.bind(name, fn); }
 }); 
 
 
 // API methods 
 $.extend(self, {

 load: function(e) {
 
 // can be opened only once
 if (self.isOpened()) { return self; } 

 
 // find the effect
 var eff = effects[conf.effect];
 if (!eff) { throw "Overlay: cannot find effect : \"" + conf.effect + "\""; }
 
 // close other instances?
 if (conf.oneInstance) {
 $.each(instances, function() {
 this.close(e);
 });
 }
 
 // onBeforeLoad
 e = e || $.Event();
 e.type = "onBeforeLoad";
 $self.trigger(e); 
 if (e.isDefaultPrevented()) { return self; } 

 // opened
 opened = true;
 
 // possible expose effect
 if (expose) { overlay.expose().load(e); } 
 
 // calculate end position 
 var top = conf.top; 
 var left = conf.left;

 // get overlay dimensions
 var oWidth = overlay.outerWidth({margin:true});
 var oHeight = overlay.outerHeight({margin:true}); 
 
 if (typeof top == 'string') {
 top = top == 'center' ? Math.max((w.height() - oHeight) / 2, 0) : 
 parseInt(top, 10) / 100 * w.height(); 
 } 
 
 if (left == 'center') { left = Math.max((w.width() - oWidth) / 2, 0); }
 
 if (!conf.absolute) {
 top += w.scrollTop();
 left += w.scrollLeft();
 } 
 
 // position overlay
 overlay.css({top: top, left: left, position: 'absolute'}); 
 
 // onStart
 e.type = "onStart";
 $self.trigger(e); 
 
 // load effect 
 eff[0].call(self, function() { 
 if (opened) {
 e.type = "onLoad";
 $self.trigger(e);
 }
 }); 
 
 // when window is clicked outside overlay, we close
 if (conf.closeOnClick) { 
 $(document).bind("click.overlay", function(e) { 
 if (!self.isOpened()) { return; }
 var et = $(e.target); 
 if (et.parents(overlay).length > 1) { return; }
 $.each(instances, function() {
 this.close(e);
 }); 
 }); 
 } 
 
 // keyboard::escape
 if (conf.closeOnEsc) {
 
 // one callback is enough if multiple instances are loaded simultaneously
 $(document).unbind("keydown.overlay").bind("keydown.overlay", function(e) {
 if (e.keyCode == 27) {
 $.each(instances, function() {
 this.close(e); 
 }); 
 }
 }); 
 }

 return self; 
 }, 
 
 close: function(e) {

 if (!self.isOpened()) { return self; }
 
 e = e || $.Event();
 e.type = "onBeforeClose";
 $self.trigger(e); 
 if (e.isDefaultPrevented()) { return; } 
 
 opened = false;
 
 // close effect
 effects[conf.effect][1].call(self, function() {
 e.type = "onClose";
 $self.trigger(e); 
 });
 
 // if all instances are closed then we unbind the keyboard / clicking actions
 var allClosed = true;
 $.each(instances, function() {
 if (this.isOpened()) { allClosed = false; }
 }); 
 
 if (allClosed) {
 $(document).unbind("click.overlay").unbind("keydown.overlay"); 
 }
 
 
 return self;
 }, 
 
 // @deprecated
 getContent: function() {
 return overlay; 
 }, 
 
 getOverlay: function() {
 return overlay; 
 },
 
 getTrigger: function() {
 return trigger; 
 },
 
 getClosers: function() {
 return closers; 
 }, 

 isOpened: function() {
 return opened;
 },
 
 // manipulate start, finish and speeds
 getConf: function() {
 return conf; 
 },

 // bind
 bind: function(name, fn) {
 $self.bind(name, fn);
 return self; 
 }, 
 
 // unbind
 unbind: function(name) {
 $self.unbind(name);
 return self; 
 } 
 
 });
 
 // callbacks 
 $.each("onBeforeLoad,onStart,onLoad,onBeforeClose,onClose".split(","), function(i, ev) {
 self[ev] = function(fn) {
 return self.bind(ev, fn); 
 };
 });
 
 
 // exposing effect
 if (expose) {
 
 // expose configuration
 if (typeof conf.expose == 'string') { conf.expose = {color: conf.expose}; }
 
 $.extend(conf.expose, {
 api: true,
 closeOnClick: conf.closeOnClick,
 
 // only overlay control's the esc button
 closeOnEsc: false
 });
 
 // initialize expose api
 var ex = overlay.expose(conf.expose);
 
 ex.onBeforeClose(function(e) {
 self.close(e); 
 });
 
 self.onClose(function(e) {
 ex.close(e); 
 });
 } 
 
 // close button
 closers = overlay.find(conf.close || ".close"); 
 
 if (!closers.length && !conf.close) {
 closers = $('<div class="close"></div>');
 overlay.prepend(closers); 
 } 
 
 closers.click(function(e) { 
 self.close(e); 
 }); 
 }
 
 // jQuery plugin initialization
 $.fn.overlay = function(conf) { 
 
 // already constructed --> return API
 var el = this.eq(typeof conf == 'number' ? conf : 0).data("overlay");
 if (el) { return el; } 
 
 if ($.isFunction(conf)) {
 conf = {onBeforeLoad: conf}; 
 }
 
 var globals = $.extend({}, $.tools.overlay.conf); 
 conf = $.extend(true, globals, conf);
 
 this.each(function() { 
 el = new Overlay($(this), conf);
 instances.push(el);
 $(this).data("overlay", el); 
 });
 
 return conf.api ? el: this; 
 }; 
 
})(jQuery);


/**
 * tools.expose 1.0.5 - Make HTML elements stand out
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/expose.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch : June 2008
 * Date: ${date}
 * Revision: ${revision} 
 */
(function($) { 

 // static constructs
 $.tools = $.tools || {};
 
 $.tools.expose = {
 version: '1.0.5', 
 conf: { 

 // mask settings
 maskId: null,
 loadSpeed: 'slow',
 closeSpeed: 'fast',
 closeOnClick: true,
 closeOnEsc: true,
 
 // css settings
 zIndex: 9998,
 opacity: 0.8,
 color: '#456',
 api: false
 }
 };

 /* one of the greatest headaches in the tool. finally made it */
 function viewport() {
 
 // the horror case
 if ($.browser.msie) {
 
 // if there are no scrollbars then use window.height
 var d = $(document).height(), w = $(window).height();
 
 return [
 window.innerWidth || // ie7+
 document.documentElement.clientWidth || // ie6 
 document.body.clientWidth, // ie6 quirks mode
 d - w < 20 ? w : d
 ];
 } 
 
 // other well behaving browsers
 return [$(window).width(), $(document).height()];
 
 } 
 
 function Expose(els, conf) { 
 
 // private variables
 var self = this, $self = $(this), mask = null, loaded = false, origIndex = 0; 
 
 // bind all callbacks from configuration
 $.each(conf, function(name, fn) {
 if ($.isFunction(fn)) { $self.bind(name, fn); }
 }); 

 // adjust mask size when window is resized (or firebug is toggled)
 $(window).resize(function() {
 self.fit();
 }); 
 
 
 // public methods
 $.extend(this, {
 
 getMask: function() {
 return mask; 
 },
 
 getExposed: function() {
 return els; 
 },
 
 getConf: function() {
 return conf; 
 }, 
 
 isLoaded: function() {
 return loaded; 
 },
 
 load: function() { 
 
 // already loaded ?
 if (loaded) { return self; }
 
 origIndex = els.eq(0).css("zIndex"); 
 
 // find existing mask
 if (conf.maskId) { mask = $("#" + conf.maskId); }
 
 if (!mask || !mask.length) {
 
 var size = viewport();
 
 mask = $('<div/>').css({ 
 position:'absolute', 
 top:0, 
 left:0,
 width: size[0],
 height: size[1],
 display:'none',
 opacity: 0, 
 zIndex:conf.zIndex 
 }); 
 
 // id
 if (conf.maskId) { mask.attr("id", conf.maskId); } 
 
 $("body").append(mask); 
 
 
 // background color 
 var bg = mask.css("backgroundColor");
 
 if (!bg || bg == 'transparent' || bg == 'rgba(0, 0, 0, 0)') {
 mask.css("backgroundColor", conf.color); 
 } 
 
 // esc button
 if (conf.closeOnEsc) { 
 $(document).bind("keydown.unexpose", function(evt) { 
 if (evt.keyCode == 27) {
 self.close(); 
 } 
 }); 
 }
 
 // mask click closes
 if (conf.closeOnClick) {
 mask.bind("click.unexpose", function() {
 self.close(); 
 }); 
 } 
 } 
 
 // possibility to cancel click action
 var e = $.Event("onBeforeLoad");
 $self.trigger(e); 
 if (e.isDefaultPrevented()) { return self; }
 
 
 // make sure element is positioned absolutely or relatively
 $.each(els, function() {
 var el = $(this);
 if (!/relative|absolute|fixed/i.test(el.css("position"))) {
 el.css("position", "relative"); 
 } 
 });
 
 // make elements sit on top of the mask 
 els.css({zIndex:Math.max(conf.zIndex + 1, origIndex == 'auto' ? 0 : origIndex)}); 

 
 // reveal mask
 var h = mask.height();
 
 if (!this.isLoaded()) { 
 mask.css({opacity: 0, display: 'block'}).fadeTo(conf.loadSpeed, conf.opacity, function() {

 // sometimes IE6 misses the height property on fadeTo method
 if (mask.height() != h) { mask.css("height", h); } 
 $self.trigger("onLoad"); 
 
 }); 
 }
 
 loaded = true; 
 return self;
 }, 
 
 
 close: function() {
 
 if (!loaded) { return self; } 

 var e = $.Event("onBeforeClose");
 $self.trigger(e); 
 if (e.isDefaultPrevented()) { return self; }
 
 mask.fadeOut(conf.closeSpeed, function() {
 $self.trigger("onClose");
 els.css({zIndex: $.browser.msie ? origIndex : null});
 }); 
 
 loaded = false;
 return self; 
 },
 
 fit: function() {
 if (mask) {
 var size = viewport(); 
 mask.css({ width: size[0], height: size[1]});
 } 
 },
 
 bind: function(name, fn) {
 $self.bind(name, fn);
 return self; 
 }, 
 
 onBeforeLoad: function(fn) {
 return this.bind("onBeforeLoad", fn);
 },
 
 onLoad: function(fn) {
 return this.bind("onLoad", fn);
 },
 
 onBeforeClose: function(fn) {
 return this.bind("onBeforeClose", fn);
 },
 
 onClose: function(fn) {
 return this.bind("onClose", fn);
 },
 
 unbind: function(name) {
 $self.unbind(name);
 return self; 
 } 
 
 });

 }
 
 
 // jQuery plugin implementation
 $.fn.expose = function(conf) {
 
 var el = this.eq(typeof conf == 'number' ? conf : 0).data("expose");
 if (el) { return el; }
 
 if (typeof conf == 'string') {
 conf = {color: conf};
 }
 
 var globals = $.extend({}, $.tools.expose.conf);
 conf = $.extend(globals, conf); 

 // construct exposes
 this.each(function() {
 el = new Expose($(this), conf);
 $(this).data("expose", el); 
 }); 
 
 return conf.api ? el: this; 
 }; 


})(jQuery);

/**
 * tools.flashembed 1.0.4 - The future of Flash embedding.
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/flash-embed.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch : March 2008
 * Date: ${date}
 * Revision: ${revision} 
 */ 
(function() { 
 
//{{{ utility functions 
 
var jQ = typeof jQuery == 'function';

var options = {
 
 // very common opts
 width: '100%',
 height: '100%', 
 
 // flashembed defaults
 allowfullscreen: true,
 allowscriptaccess: 'always',
 quality: 'high', 
 
 // flashembed specific options
 version: null,
 onFail: null,
 expressInstall: null, 
 w3c: false,
 cachebusting: false 
};

if (jQ) {
 
 // tools version number
 jQuery.tools = jQuery.tools || {};
 
 jQuery.tools.flashembed = { 
 version: '1.0.4', 
 conf: options
 }; 
}


// from "Pro JavaScript techniques" by John Resig
function isDomReady() {
 
 if (domReady.done) { return false; }
 
 var d = document;
 if (d && d.getElementsByTagName && d.getElementById && d.body) {
 clearInterval(domReady.timer);
 domReady.timer = null;
 
 for (var i = 0; i < domReady.ready.length; i++) {
 domReady.ready[i].call(); 
 }
 
 domReady.ready = null;
 domReady.done = true;
 } 
}

// if jQuery is present, use it's more effective domReady method
var domReady = jQ ? jQuery : function(f) {
 
 if (domReady.done) {
 return f(); 
 }
 
 if (domReady.timer) {
 domReady.ready.push(f); 
 
 } else {
 domReady.ready = [f];
 domReady.timer = setInterval(isDomReady, 13);
 } 
}; 


// override extend opts function 
function extend(to, from) {
 if (from) {
 for (key in from) {
 if (from.hasOwnProperty(key)) {
 to[key] = from[key];
 }
 }
 }
 
 return to;
} 


// JSON.asString() function
function asString(obj) {
 
 switch (typeOf(obj)){
 case 'string':
 obj = obj.replace(new RegExp('(["\\\\])', 'g'), '\\$1');
 
 // flash does not handle %- characters well. transforms "50%" to "50pct" (a dirty hack, I admit)
 obj = obj.replace(/^\s?(\d+)%/, "$1pct");
 return '"' +obj+ '"';
 
 case 'array':
 return '['+ map(obj, function(el) {
 return asString(el);
 }).join(',') +']'; 
 
 case 'function':
 return '"function()"';
 
 case 'object':
 var str = [];
 for (var prop in obj) {
 if (obj.hasOwnProperty(prop)) {
 str.push('"'+prop+'":'+ asString(obj[prop]));
 }
 }
 return '{'+str.join(',')+'}';
 }
 
 // replace ' --> " and remove spaces
 return String(obj).replace(/\s/g, " ").replace(/\'/g, "\"");
}


// private functions
function typeOf(obj) {
 if (obj === null || obj === undefined) { return false; }
 var type = typeof obj;
 return (type == 'object' && obj.push) ? 'array' : type;
}


// version 9 bugfix: (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
if (window.attachEvent) {
 window.attachEvent("onbeforeunload", function() {
 __flash_unloadHandler = function() {};
 __flash_savedUnloadHandler = function() {};
 });
}

function map(arr, func) {
 var newArr = []; 
 for (var i in arr) {
 if (arr.hasOwnProperty(i)) {
 newArr[i] = func(arr[i]);
 }
 }
 return newArr;
}
 
function getHTML(p, c) {
 
 var e = extend({}, p); 
 var ie = document.all; 
 var html = '<object width="' +e.width+ '" height="' +e.height+ '"';
 
 // force id for IE or Flash API cannot be returned
 if (ie && !e.id) {
 e.id = "_" + ("" + Math.random()).substring(9);
 }
 
 if (e.id) { 
 html += ' id="' + e.id + '"'; 
 }
 
 // prevent possible caching problems
 if (e.cachebusting) {
 e.src += ((e.src.indexOf("?") != -1 ? "&" : "?") + Math.random()); 
 } 
 
 if (e.w3c || !ie) {
 html += ' data="' +e.src+ '" type="application/x-shockwave-flash"'; 
 } else {
 html += ' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'; 
 }
 
 html += '>'; 
 
 if (e.w3c || ie) {
 html += '<param name="movie" value="' +e.src+ '" />'; 
 }

 // parameters
 e.width = e.height = e.id = e.w3c = e.src = null;
 
 for (var k in e) {
 if (e[k] !== null) {
 html += '<param name="'+ k +'" value="'+ e[k] +'" />';
 }
 } 

 // flashvars
 var vars = "";
 
 if (c) {
 for (var key in c) {
 if (c[key] !== null) {
 vars += key +'='+ (typeof c[key] == 'object' ? asString(c[key]) : c[key]) + '&';
 }
 }
 vars = vars.substring(0, vars.length -1);
 html += '<param name="flashvars" value=\'' + vars + '\' />';
 }
 
 html += "</object>"; 
 
 return html;

}

//}}}


function Flash(root, opts, flashvars) {
 
 var version = flashembed.getVersion(); 
 
 // API methods for callback
 extend(this, {
 
 getContainer: function() {
 return root; 
 },
 
 getConf: function() {
 return opts; 
 },
 
 getVersion: function() {
 return version; 
 }, 
 
 getFlashvars: function() {
 return flashvars; 
 }, 
 
 getApi: function() {
 return root.firstChild; 
 }, 
 
 getHTML: function() {
 return getHTML(opts, flashvars); 
 }
 
 });

 // variables 
 var required = opts.version; 
 var express = opts.expressInstall;
 
 
 // everything ok -> generate OBJECT tag 
 var ok = !required || flashembed.isSupported(required);
 
 if (ok) {
 opts.onFail = opts.version = opts.expressInstall = null;
 root.innerHTML = getHTML(opts, flashvars);
 
 // fail #1. express install
 } else if (required && express && flashembed.isSupported([6,65])) {
 
 extend(opts, {src: express});
 
 flashvars = {
 MMredirectURL: location.href,
 MMplayerType: 'PlugIn',
 MMdoctitle: document.title
 };
 
 root.innerHTML = getHTML(opts, flashvars); 
 
 // fail #2. 
 } else { 
 
 // fail #2.1 custom content inside container
 if (root.innerHTML.replace(/\s/g, '') !== '') {
 // minor bug fixed here 08.04.2008 (thanks JRodman) 
 
 // fail #2.2 default content
 } else { 
 root.innerHTML = 
 "<h2>Flash version " + required + " or greater is required</h2>" + 
 "<h3>" + 
 (version[0] > 0 ? "Your version is " + version : "You have no flash plugin installed") +
 "</h3>" + 
 
 (root.tagName == 'A' ? "<p>Click here to download latest version</p>" : 
 "<p>Download latest version from <a href='http://www.adobe.com/go/getflashplayer'>here</a></p>");
 
 if (root.tagName == 'A') { 
 root.onclick = function() {
 location.href= 'http://www.adobe.com/go/getflashplayer';
 };
 } 
 }
 }
 
 // onFail
 if (!ok && opts.onFail) {
 var ret = opts.onFail.call(this);
 if (typeof ret == 'string') { root.innerHTML = ret; } 
 }
 
 // http://flowplayer.org/forum/8/18186#post-18593
 if (document.all) {
 window[opts.id] = document.getElementById(opts.id);
 } 
 
}

window.flashembed = function(root, conf, flashvars) { 
 
//{{{ construction
 
 // root must be found / loaded 
 if (typeof root == 'string') {
 var el = document.getElementById(root);
 if (el) {
 root = el; 
 } else {
 domReady(function() {
 flashembed(root, conf, flashvars);
 });
 return; 
 } 
 }
 
 // not found
 if (!root) { return; }
 
 if (typeof conf == 'string') {
 conf = {src: conf}; 
 }
 
 var opts = extend({}, options);
 extend(opts, conf); 
 
 return new Flash(root, opts, flashvars);
 
//}}}
 
 
};


//{{{ static methods

extend(window.flashembed, {

 // returns arr[major, fix]
 getVersion: function() {
 
 var version = [0, 0];
 
 if (navigator.plugins && typeof navigator.plugins["Shockwave Flash"] == "object") {
 var _d = navigator.plugins["Shockwave Flash"].description;
 if (typeof _d != "undefined") {
 _d = _d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
 var _m = parseInt(_d.replace(/^(.*)\..*$/, "$1"), 10);
 var _r = /r/.test(_d) ? parseInt(_d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
 version = [_m, _r];
 }
 
 } else if (window.ActiveXObject) {

 try { // avoid fp 6 crashes
 var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
 
 } catch(e) {
 
 try { 
 _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
 version = [6, 0];
 _a.AllowScriptAccess = "always"; // throws if fp < 6.47 
 
 } catch(ee) {
 if (version[0] == 6) { return version; }
 }
 try {
 _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
 } catch(eee) {
 
 }
 
 }
 
 if (typeof _a == "object") {
 _d = _a.GetVariable("$version"); // bugs in fp 6.21 / 6.23
 if (typeof _d != "undefined") {
 _d = _d.replace(/^\S+\s+(.*)$/, "$1").split(",");
 version = [parseInt(_d[0], 10), parseInt(_d[2], 10)];
 }
 }
 } 
 
 return version;
 },
 
 isSupported: function(version) {
 var now = flashembed.getVersion();
 var ret = (now[0] > version[0]) || (now[0] == version[0] && now[1] >= version[1]); 
 return ret;
 },
 
 domReady: domReady,
 
 // returns a String representation from JSON object 
 asString: asString,
 
 
 getHTML: getHTML
 
});

//}}}


// setup jquery support
if (jQ) {
 
 jQuery.fn.flashembed = function(conf, flashvars) {
 
 var el = null;
 
 this.each(function() { 
 el = flashembed(this, conf, flashvars);
 });
 
 return conf.api === false ? this : el; 
 };

}

})();

