if(!window.SE){
	SE = {
	
		events: [],
		bundles: {},
	
		venues:{
			brum_carrslaneurc:{
				brief: "Carrs Lane United Reformed Church, Birmingham",
				address: "Carrs Lane, Birmingham B4 7SX",
				link: "http://www.carrslane.co.uk/",
				map: "http://www.carrslane.co.uk/travel"
			},
			
			brum_oratory:{
				brief: "The Oratory, Birmingham"
			},
			
			cov_herbert:{
				brief: "<a href='http://www.theherbert.org'>The Herbert</a> Art Gallery & Museum",
				address: "Coventry"
			},
			
			cov_warwickroadurc:{
				brief: "Warwick Road United Reformed Church, Coventry",
				address: "Warwick Road, Coventry CV1 1EX",
				link: "http://www.wrurc.co.uk/",
				map: "http://www.openstreetmap.org/index.html?mlat=52.4053&mlon=-1.51355&zoom=15"
			},
			
			cov_earlsdonmethodist:{
				brief: "Earlsdon Methodist Church",
				address: "Albany Road, Earlsdon, Coventry CV5 6NF",
				link: "http://www.earlsdonmethodist.org.uk/",
				map: "http://www.earlsdonmethodist.org.uk/map.htm"
			},
			
			cov_precinct:{
				brief: "The Precinct, Coventry",
				link: "http://www.lowerprecinct.com/home.html",
				map: "http://www.lowerprecinct.com/location/localmap.html"
			},
			
			cov_stpauls:{
				brief: "St Paul's Church, Foleshill Road",
				address: "Foleshill Road, Coventry"
			},
			
			douai_abbey:{
				brief: "Douai Abbey",
				address: "Upper Woolhampton, Reading, Berkshire RG7 5TQ",
				link: "http://www.douaiabbey.org.uk/index0.htm",
				map: "http://www.douaiabbey.org.uk/map.htm"
			},
			
			iona_abbey:{
				brief: "Iona Abbey"
			},
			
			mull_bunessanbaptist:{
				brief: "Bunessan Baptist Church",
				link: "http://www.mull-historical-society.co.uk/places-of-worship/bunessan/bunessan-baptist-church.htm"
			},
			
			mull_glengormcastle:{
				brief: "Glengorm Castle",
				address: "Tobermory, Isle of Mull PA75 6QE",
				map: "http://www.glengormcastle.co.uk/map-3.htm",
				link: "http://www.glengormcastle.co.uk/"
			},
			
			mull_grulinecolumba:{
				brief: "St Columba's Church, Gruline",
				address: "Gruline, Isle of Mull",
				map: "http://www.grulinechurch.org.uk/howtofindus.html",
				link: "http://www.grulinechurch.org.uk/"
			},
			
			mull_isle:{
				brief: "Venues on the Isle of Mull",
				address: "Scotland"
			},
			
			mull_salenchurch:{
				brief: "Salen Church",
				address: "Salen, Isle of Mull",
				link: "http://www.mull-historical-society.co.uk/places-of-worship/salen/salen-church.htm"
			},
			
			mull_tobermorywestern:{
				brief: "Western Isles Hotel, Tobermory",
				address: "Tobermory, Isle of Mull PA75 6PR",
				map: "http://www.westernisleshotel.co.uk/FINDUS.asp",
				link: "http://www.westernisleshotel.co.uk/"
			},
			
			rugby_newmusicroom:{
				brief: "New Music Room, Rugby School",
				address: "Rugby, CV22 5EH",
				map: "http://www.rugbyschool.net/ourlocation"
			},
			
			strat_guildchapel:{
				brief: "The Guild Chapel of the Holy Cross",
				address: "Stratford-upon-Avon"
			},
			
			westbrom_stmichael:{
				brief: "St Michael and the Holy Angels, West Bromwich",
				address: "260 High Street, West Bromwich B70 8AQ"
			},
			
			westheath_stjohnfisher:{
				brief: "St John Fisher Roman Catholic Church, West Heath",
				address: "1 Cofton Rd, West Heath, Birmingham B31 3QT"
			},
			
			tam_polesworthabbey:{
				brief: "Polesworth Abbey",
				address: "High Street, Polesworth, Tamworth B78 1DU",
				map: "http://www.polesworthabbey.heralded.org.uk/?q=node/664",
				link: "http://www.polesworthabbey.heralded.org.uk/"
			}
		},
		
		numbers: [ "no", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" ],
	
		prepareEvents: function(forward){
			var imminent = 0;
			var now = new Date();
			// we're only interested in the date
			now.setHours(0);
			now.setMinutes(0);
			now.setSeconds(0);
			now.setMilliseconds(0);
			var imm = new Date();
			imm.setDate(imm.getDate() + 30);
			var rec = new Date();
			rec.setFullYear(rec.getFullYear() - 1);
			
			for(var i in this.events){
				var evt = this.events[i];
				if(evt.fires){
					var fires_bits = evt.fires.split("/", 3);
					evt.fires_date = new Date(fires_bits[2], fires_bits[1]-1, fires_bits[0]);
				}
				if(evt.expires){
					var expires_bits = evt.expires.split("/", 3);
					evt.expires_date = new Date(expires_bits[2], expires_bits[1]-1, expires_bits[0]);
				}
				if((!evt.fires_date && !evt.expires_date)
				 ||((evt.fires_date || evt.expires_date) > imm)){
					evt.age_status = 2;
				}else if((evt.fires_date || evt.expires_date) >= now){
					if(evt.status == "provisional"){
						evt.age_status = 2;  // don't mark provisional events as imminent
					}else{
						evt.age_status = 1;
						imminent++;
					}
				}else if(evt.expires_date && (evt.expires_date >= now)){
					evt.age_status = 0;
					imminent++;
				}else if((evt.expires_date || evt.fires_date) >= rec){
					evt.age_status = -1;
				}else{
					evt.age_status = -2;
				}
			}

			// sort events into date order
			this.events.sort(function(a, b){
				return((forward ? 1 : -1) * (
					(!a.fires_date && !a.expires_date) ? 1 : (
					(!b.fires_date && !b.expires_date) ? -1 : (
					((a.fires_date || a.expires_date) < (b.fires_date || b.expires_date)) ? -1 : (
					((a.fires_date || a.expires_date) > (b.fires_date || b.expires_date)) ? 1 : 0 )))) );
			});
			
			// ensure we have at least three imminent events, if possible
			// by promoting some future events to imminent if necessary
			for(i = 0; (imminent < 3) && (i < this.events.length); i++){
				evt = this.events[i];
				if((evt.age_status == 2) && (evt.status != "provisional")){
					evt.age_status = 1;
					imminent++;
				}
			}
			
			// ensure we have no more than five imminent events,
			// by demoting some imminent events to future if necessary
			for(i = this.events.length - 1; (imminent > 5) && (i >= 0); i--){
				evt = this.events[i];
				if(evt.age_status == 1){
					evt.age_status = 2;
					imminent--;
				}
			}
			
			// collect up event bundles
			for(i = 0; i < this.events.length; i++){
				evt = this.events[i];
				if(evt.bundle){
					if(!(evt.bundle in this.bundles)){
						this.bundles[evt.bundle] = [];
					}
					this.bundles[evt.bundle].push(evt);
				}
			}
		},
		
		getVenueMoreInfo: function(venue){
			var result = "";
			
			if(venue.map || venue.link){
				result += " <span class='se-note'>(";
				var divide = false;
				
				if(venue.link){
					if(divide){
						result += " | ";
					}
					result += '<a class="se-external-link" target="_new" href="' + venue.link;
					if(venue.map){
						result += '">about</a>';
					}else{
						result += '">about this venue</a>';
					}
					divide = true;
				}
				
				if(venue.map){
					if(divide){
						result += " | ";
					}
					result += '<a class="se-external-link" target="_new" href="' + venue.map + '">map</a>';
					divide = true;
				}
				
				result += ")</span>";
			}
			
			return result;
		},
		
		writeEventWhereAndWhen: function(evt, showaddress, detailslink, showtitle){
			var venue = this.venues[evt.where] || { brief: evt.where };
			var first = true;
			
			if(evt.where || evt.when || (showtitle && (evt.title_markup || evt.title || evt.subtitle))){
				document.write("<p class='se-event-wherewhen'>");
			}else{
				document.write("<p>");
			}
			
			if(showtitle){
				if(evt.title_markup || evt.title){
					if(!first){
						document.write("<br />");
					}
					document.write("<span class='se-event-wherewhen-title'>");
					document.write(evt.title_markup || evt.title);
					document.write("</span>");
					first = false;
				}
				
				if(evt.subtitle){
					if(!first){
						document.write("<br />");
					}
					document.write(evt.subtitle);
					first = false;
				}
			}
			
			if(venue.brief){
				if(!first){
					document.write("<br />");
				}
				document.write(venue.brief);
				document.write(this.getVenueMoreInfo(venue));
				first = false;
			}
				
			if(showaddress && venue.address){
				if(!first){
					document.write("<br />");
				}
				document.write("<span class='se-event-wherewhen-address'>");
				document.write(venue.address);
				document.write("</span>");
				first = false;
			}
			
			if(evt.when){
				if(!first){
					document.write("<br />");
				}
				document.write(evt.when);
				first = false;
			}
			
			if(evt.status == "provisional"){
				if(!first){
					document.write("<br />");
				}
				document.write("<span class='se-note'><b>NB</b> this event is currently <span class='se-emphasis'>provisional</span> &mdash; details may change. Please check back for the latest information.</span>");
				first = false;
			}
			
			if(detailslink && evt.hasbody){
				if(!first){
					document.write("<br />");
				}
				document.write("<span class='se-action-link'><a href='" + evt.file + "'>" + (evt.prompt_moredetails || "Find out more") + "</a></span>");
				first = false;
			}		
			
			document.write("</p>");
		},
		
		writeEventPromo: function(evt){
			document.write("<div style='clear: both;'></div>");
			
			if(evt.promo){
				document.write("<div class='se-side-block'><p>");
				
				if(evt.hasbody){
					document.write("<a href='" + evt.file + "'>");
				}
					
				document.write("<img src='" + evt.promo + "' alt='" + (evt.title || "") + "' class='se-framed-image' />");
				
				if(evt.hasbody){
					document.write("</a>");
				}
		
				document.write("</p></div>");
			}
		},
		
		/*
			write summary information for all events
			(usually used with just one event)
		*/
		writeEventSummaryHeaders: function(){
			this.prepareEvents(true);
			for(var i in this.events){
				var evt = this.events[i];
				
				if(evt.title_markup || evt.title){
					document.write("<p class='se-event-title'>" + (evt.title_markup || evt.title) + "</p>");
				}
				
				if(evt.subtitle){
					document.write("<p class='se-event-subtitle'>" + evt.subtitle + "</p>");
				}
				
				if(evt.brief){
					document.write("<p class='se-event-brief'>" + evt.brief + "</p>");
				}
				
				this.writeEventWhereAndWhen(evt, true, false, false);
			}
		},
		
		/*
			write a summary panel for all forthcoming or past events (or both)
			times: 1=forthcoming, -1=past, 0=both
		*/
		writeEventSummaryLinks: function(times, showpromo, hidetopleveldetailslinks){
			this.prepareEvents(times >= 0);
			var none = true;
			var processedbundles = {};
			for(var i in this.events){
				var evt = this.events[i];
				if((((times > 0) && (evt.age_status >= 0))
				 || (times == 0)
				 || ((times < 0) && (evt.age_status < 0)))
				&& (!evt.bundle || !processedbundles[evt.bundle])){
					if(showpromo){
						this.writeEventPromo(evt);
					}
					
					document.write("<div class='se-inner-panel'>");					
					
					if(evt.status == "provisional"){
						document.write("<img style='float: left; padding-top: 3px; padding-right: 8px; padding-bottom: 12px;' title='This event is currently provisional &mdash; details may change. Please check back for the latest information.' src='/resources/site/event_provisional.png' />");
					}
					
					if(evt.hasbody){
						document.write("<p class='se-event-teaser-title'><a href='" + evt.file + "'>" + (evt.title_markup || evt.title) + "</a></p>");
					}else{
						document.write("<p class='se-event-teaser-title'>" + (evt.title_markup || evt.title) + "</p>");
					}
					
					if(evt.subtitle){
						document.write("<p class='se-event-teaser-subtitle'>" + evt.subtitle + "</p>");
					}
					
					if(evt.brief){
						document.write("<p class='se-event-brief'>" + evt.brief + "</p>");
					}
					
					this.writeEventWhereAndWhen(evt, false, !hidetopleveldetailslinks, false);
					
					if(evt.bundle){
						for(var j in this.bundles[evt.bundle]){
							var bevt = this.bundles[evt.bundle][j];
							if((bevt != evt)
							&& (((times > 0) && (bevt.age_status >= 0))
							 || (times == 0)
							 || ((times < 0) && (bevt.age_status < 0)))){
								this.writeEventWhereAndWhen(bevt, true, true, (bevt.title_markup || bevt.title) !== (evt.title_markup || evt.title));
							}
						}
						processedbundles[evt.bundle] = true;
					}
					
					if(showpromo){
						document.write("<div style='clear: right;'></div>");
					}
					
					document.write("</div>");
					none = false;
				}
			}
			
			if(none){
				document.write("<p class='note'>There are currently no forthcoming events in the calendar.</p>");
			}
		},
		
		/*
			write a short teaser panel for imminent events
			and add a "more" link if there are further forthcoming events
		*/
		writeEventSummaryTeasers: function(addcomments){
			this.prepareEvents(true);
			var none = true;
			var more = 0;
			var processedbundles = {};
			for(var i in this.events){
				var evt = this.events[i];
				if(evt.age_status >= 2){
					more++;
				}else if((evt.age_status >= 0) && (evt.age_status <= 1)
				      && (!evt.bundle || !processedbundles[evt.bundle])){
					  
					if(none && addcomments){
						document.write("<p style='padding-left: 16px; font-weight: 600; font-style: italic;'>Some appearances coming up over the next few weeks:</p>");
					}
					
					this.writeEventPromo(evt);
					
					document.write("<div class='se-inner-panel'>");
					
					if(evt.hasbody){
						document.write("<p class='se-event-teaser-title'><a href='" + evt.file + "'>" + (evt.title_markup || evt.title) + "</a></p>");
					}else{
						document.write("<p class='se-event-teaser-title'>" + (evt.title_markup || evt.title) + "</p>");
					}
					
					if(evt.subtitle){
						document.write("<p class='se-event-teaser-subtitle'>" + evt.subtitle + "</p>");
					}
					
					this.writeEventWhereAndWhen(evt, false, true, false);
					
					if(evt.bundle){
						for(var j in this.bundles[evt.bundle]){
							var bevt = this.bundles[evt.bundle][j];
							if((bevt != evt) && (bevt.age_status >= 0)){
								this.writeEventWhereAndWhen(bevt, false, true, (bevt.title_markup || bevt.title) !== (evt.title_markup || evt.title));
								if(bevt.age_status >= 2){
									more--;
								}
							}
						}
						processedbundles[evt.bundle] = true;
					}
					
					document.write("<div style='clear: right;'></div></div>");
					none = false;
				}
			}
			
			if(addcomments){
				if(none){
					if(more > 1){
						document.write("<p class='note'>Sorry, there are currently no confirmed appearances coming up over the next few weeks, but there are <a href='/events/forthcoming.shtml'>" + (this.numbers[more] || more) + " more planned events</a> looking further ahead.</p>");
					}else if(more == 1){
						document.write("<p class='note'>Sorry, there are currently no confirmed appearances coming up over the next few weeks, but there is <a href='/events/forthcoming.shtml'>one more planned event</a> looking further ahead.</p>");
					}else{
						document.write("<p class='note'>Sorry, there are currently no planned events in the calendar.</p>");
					}
				}else{
					if(more > 1){
						document.write("<p style='padding-left: 16px; font-weight: 600; font-style: italic;'>(plus <a href='/events/forthcoming.shtml'>" + (this.numbers[more] || more) + " more forthcoming events</a> looking further ahead)</p>");
					}else if(more == 1){
						document.write("<p style='padding-left: 16px; font-weight: 600; font-style: italic;'>(and <a href='/events/forthcoming.shtml'>one more forthcoming event</a> looking further ahead)</p>");
					}
				}
			}
		}
	};
}

