/*
* 設定項目はこのファイルの 30 行目くらいからです。
*/

if( ! Array.prototype.contains ){
		/**
		* @access public
		* @param value mixed 検索するオブジェクト
		* @return boolean 対象配列に既にオブジェクトが存在していれば true, そうでなければ false
		* 配列の値の重複チェックなどに使用。
		*/
		Array.prototype.contains = function( value ){
			for(var i in this){
				if( this[i] === value){
					return true;
				}
			}
			return false;
		}
}

/**
* 本体となるクラスです。
*/
function WebsiteOptions(){
	/*------------------------------------------------*/
	/*----------------- 設定ここから -----------------*/
	/*------------------------------------------------*/
	var config = {
		html : {
			// WinIE に abbr 要素を対応させるなら true, 放っておくなら false
			useFixAbbr : true,
			
			// blockquote の cite 属性からリンクを自動生成するなら true, しないなら false
			useBlockquoteCitation : true
		}, window : {
			// ステータスバーを弄るなら true, 弄らないなら false
			enable : true
		}, frame : {
			// ページがフレーム内だった時に警告するなら true, しないなら false
			// フレームを使っている場合は必ず false にして下さい。
			enable : true,
			
			// サイトのトップディレクトリの URL（ファイル名を含めない）。 (文字列)
			// 空でもよいですが、そうすると WinIE では object 要素での取り込みに警告できません
			// 例: "http://example.com/oreore/"
			address : "http://shemale.0na21.com/"
		}, form : {
			// フォームの送信またはリセットの際に確認を取るなら true, 取らないなら false
			enable : true
		}, cookie : {
			// クッキーが有効なドメイン名を指定します。空だとURLから自動的に取得します (文字列)
			// 例: "example.com"
			domain : "",
			
			// "/" から始まるクッキーが有効なパスを指定します。空だとURLから自動的に取得します (文字列)
			// 例: "/oreore/"
			path : ""
		}, unlink : {
			// 自ページへのリンクを排除するなら true, しないなら false
			enable : true,
			
			// 上の設定が true の時、自ページを指すリンクに付け加えるクラス名 (文字列)
			activeClassName : "active"
		}, switcher : {
			// 外部リンクの制御をするなら true, しないなら false
			enable : true,
			
			// 初期状態で外部リンクは別に開くなら true, 最初はユーザーに任せるなら false
			applyByDefault : true,
			
			// 内部だと判断する URL。空だと URL から自動的にドメイン部を取得します (文字列)
			// 例: "http://example.com/oreore/"
			internalURL : "http://shemale.0na21.com/",
			
			// どの ID を持つ要素にセレクトボックスを配置するか (文字列)
			// 空だと、次の要素名の設定を使って配置します。
			targetElementID : "",
			
			// どの要素にリンクスイッチを配置するか (文字列)
			// 上の設定で ID を指定した場合は無視されます
			targetElementName : "body",
			
			// その要素の何番目に配置するのか。0 ではなく 1 から数えます。(数値)
			// 上の設定で ID を指定した場合は無視されます
			targetElementIndex : 1,
			
			// チェックボックスの直後に挿入する文字列 (文字列)
			text : "外部リンクは別の作業領域で開く",
			
			// 上で設定した要素の前に挿入するなら true, 後ろに追加するなら false
			isBefore : false,
			
			// 上で指定した要素の外に追加するなら true
			// 要素の中に追加するなら false
			// body 要素や html 要素を挿入対象にする場合は false にしてください。
			isOut : false,
			
			// リンク先オープン設定の保持日数(一度でも再来訪すればまた数え直します) (数値)
			// 0 を指定するとブラウザ終了まで有効。
			expdays : 30
		}, styler : {
			// CSS 切り替え機能を使うなら true, 使わないなら false
			enable : true,
			
			// XHTML & Opera の組み合わせでもスタイル切り替え機能を使うなら true, 使わないなら false
			affectOpera : false,
			
			// どの ID を持つ要素にセレクトボックスを配置するか (文字列)
			// 空だと、次の要素名の設定を使って配置します
			targetElementID : "",
			
			// どの要素にセレクトボックスを配置するか (文字列)
			// 上の設定で ID を指定した場合は無視されます
			targetElementName : "body",
			
			// その要素の何番目に挿入するか。0 ではなく 1 から数えます。(数値)
			// 上の設定で ID を指定した場合は無視されます
			targetElementIndex : 1,
			
			// 選択リストの直前に挿入する文字列。空でもいい (文字列)
			text : "テーマ ",
			
			// 上で設定した要素の前に挿入するなら true, 後ろに追加するなら false
			isBefore : false,
			
			// 上で指定した要素の外に追加するなら true
			// 要素の中に追加するなら false
			// body 要素や html 要素を挿入対象にする場合は false にしてください。
			isOut : false,
			
			// 設定スタイルの保持日数(一度でも再来訪すればまた数え直します) (数値)
			// 0 を指定するとブラウザ終了まで有効。
			expdays : 30,
						
			// 優先/代替 CSS 全て適用しない状態を選択リストに含めるなら true, 含めないなら false
			enableNoStyle : true,
			
			// 優先/代替 CSS 一切適用無しの名前 (文字列)
			noStyleName : "なし"
		}
	};
	/*------------------------------------------------*/
	/*----------------- 設定ここまで -----------------*/
	/*------------------------------------------------*/
	
	this.getConfig = function(){
		return config;
	}
	
	
	
	
	
	
	/**
	* コアユーティリティ群
	*/
	function Core(){}
	Core.prototype = {
		constructor : Core,
		
		/**
		* @access public
		* @return boolean 了承されたかどうか
		* その動作を本当にしてよいのか聞く。
		*/
		confirm : function(){
			return confirm("OK ?");
		},
		
		/**
		* 偽を返す。
		*/
		returnFalse : function(){
			return false;
		},
		
		/**
		* 真を返す。
		*/
		returnTrue : function(){
			return true;
		}
	};
	var core = new Core();
	this.getCore = function(){
		return core;
	}
	/*
	* 念のためエラーダイアログが出ないよう措置する。
	* 効果は気休め程度に思うこと。
	* 開発時はコメントアウトすること。
	* 最終確認のテストをする時とリリースをする時にコメントを外すのを忘れない事。
	*
	* 参照 [ http://www2.portland.ne.jp/%7Esigekazu/css/javascript10.htm#error ]
	*/
	window.onerror = core.returnTrue;
	
	
	
	
	
	
	
	/**
	* DOM 操作
	*/
	function DOM(){
		/** 名前空間 */
		var namespaces = {
			xhtml1 : "http://www.w3.org/1999/xhtml",
			xhtml2 : "http://www.w3.org/2002/06/xhtml2/"
		};
		
		this.getNamespaces = function(){
			return namespaces;
		}
	}
	DOM.prototype = {
		constructor : DOM,
		/**
		* @access public
		* @return object(HTMLHtmlElement) ページ内のルート要素 or null
		*/
		getRootElement : function(){
			if(document.documentElement){
				return document.documentElement;
			} else if (document.getElementsByTagName){
				return document.getElementsByTagName("*")[0];
			} else {
				return null;
			}
		},
		
		/**
		* @access public
		* @return boolean 最低限の DOM が扱えるかどうか
		*/
		canDOM : function(){
			var D = document;
			var E = this.getRootElement();
			if( E == null ) return false;
			return new Boolean(
				D.getElementById &&
				D.getElementsByTagName &&
				D.createElement &&
				D.createTextNode &&
				E.getAttribute &&
				E.setAttribute &&
				E.removeAttribute &&
				E.appendChild &&
				E.removeChild &&
				E.insertBefore
			);
		},
		
		/**
		* @access public
		* @return boolean 文書が XHTML かどうか
		*/
		isXHTML : function(){
			if( this.canDOM() == false ) return false;
			
			var root = this.getRootElement();
			/*
			XHTML/1.1 はルート要素に xmlns 属性が定義されなければならない
			HTML なら namespaceURI は null
			Opera7 は getAttribute では xmlns 属性が取得できない (getAttributeNode なら Object が返る)
			WinIE6 は namespaceURI プロパティが存在しない
			*/
			return new Boolean( root.getAttribute("xmlns") || root.namespaceURI );
		},
		
		/**
		* @access public
		* @param tagName String 生成する要素名
		* @return object(HTML*Element) 生成された要素
		* XHTML / HTML のどちらであるかを自動的に判断して指定要素を生成します。
		* XHTML の場合に生成される要素の名前空間は XHTML/1.x 共通のものです。
		*/
		createElement : function( elementName ){
			elementName = elementName.toLowerCase();
			if( this.isXHTML() && document.createElementNS ){
				var ns = this.getNamespaces();
				return document.createElementNS( ns.xhtml1, elementName );
			} else {
				return document.createElement(elementName);
			}
		},
		
		/**
		* @access public
		* @param newNode object(DOMNode) refNode に追加するノード
		* @param refNode object(DOMNode) ノードが追加されるノード
		* @return object|null 自動補完が加わったかもしれない newNode
		* 対象のノードが DL,UL,OL のいずれかであれば newNode に適切に要素を加えて返します。
		* 対象ノードが null か DOM が扱えなければ null を返します。
		*/
		addElementImpl : function( newNode, refNode ){
			if( this.canDOM() == false || !refNode ) return null;
			
			/* Feedback from ALIMIKA SATOMI 2004-12-19 */
			var regxp = new RegExp("^(HTML:)?(UL|OL|DL)$", "i"); // XHTML [Opera7] 対策
			if( regxp.test(refNode.nodeName) ){
				var parentElement;
				if(refNode.nodeName.toUpperCase().indexOf("DL") != -1 ){
					parentElement = this.createElement("dd");
				} else {
					parentElement = this.createElement("li");
				}
				if( newNode.id ){
					parentElement.id = newNode.id + "_PARENT";
				}
				parentElement.appendChild(newNode);
				return parentElement;
			} else {
				return newNode;
			}
		},
		
		/**
		* @access public
		* @param newElement object(DOMElementNode) 新しく追加する要素
		* @param targetElement object(DOMNode) 追加対象の要素
		* @param isBefore boolean 追加対象の要素の前に追加するのかどうか (後ろなら false)
		* @param isOut boolean 追加対象要素の外に追加するのかどうか (中なら false)
		* @return object(DOMElementNode) 追加した newElement
		*
		* 新しい要素を追加対象要素の前後どちらかに追加します。
		* 追加対象要素が UL/OL/DL のいずれかである場合は適切に要素を補充した後に
		* それを新しい要素として追加します。返り値はここで生成された新しい要素です。
		* UL/OL/DL ではなければそのまま追加し、返り値の要素も最初の新しい要素と変化しません。
		* DOM をサポートしていない場合は何もせずに null を返します。
		*/
		addElement : function( newElement, targetElement, isBefore, isOut ){
			if( this.canDOM() == false ) return null;
			
			if( isBefore ){
				if( isOut ){
					newElement = this.addElementImpl( newElement, targetElement.parentNode );
					targetElement.parentNode.insertBefore( newElement, targetElement );
				} else {
					newElement = this.addElementImpl( newElement, targetElement );
					targetElement.insertBefore( newElement, targetElement.firstChild );
				}
			} else {
				if( isOut ){
					newElement = this.addElementImpl( newElement, targetElement.parentNode );
					targetElement.parentNode.insertBefore( newElement, targetElement.nextSibling );
				} else {
					newElement = this.addElementImpl( newElement, targetElement );
					targetElement.appendChild( newElement );
				}
			}
			return newElement;
		}
	};
	var dom = new DOM();
	this.getDom = function(){
		return dom;
	}
	
	
	
	
	
	
	
	/**
	* イベント登録/削除の管理。
	*/
	function EventManager(){}
	EventManager.prototype = {
		constructor : EventManager,
		/**
		* @access public
		* @param object obj(DOMElementNode) イベントを削除する要素
		* @param event String イベント名
		* @param listener Function イベント発生時に自動実行させていた関数
		* @param useCapture boolean キャプチャするかどうからしい……
		* @return void
		*
		* イベントの削除を行う。
		*/
		removeEvent : function( obj, event, listener, useCapture ){
			if(obj.removeEventListener){
				obj.removeEventListener( event, listener, useCapture ? true : false ); // Standard DOM
			} else if(obj.detachEvent){
				obj.detachEvent( "on"+event, listener ); // For IE
			}
		},
		
		/**
		* @access public
		* @param obj obj(DOMElementNode) イベントを登録する要素
		* @param event String イベント名
		* @param listener Function イベント発生時に自動実行する関数
		* @param useCapture boolean キャプチャするかどうからしい……
		* @return void
		*
		* イベントの登録を行う。
		*/
		addEvent : function( obj, event, listener, useCapture ){
			if(obj.addEventListener){
				obj.addEventListener( event, listener, useCapture ? true : false ); // Standard DOM
			} else if(obj.attachEvent){
				obj.attachEvent( "on"+event, listener ); // For IE
			}
		},
		
		/*
		* @access public
		* @param listener Function ページ読み込み完了時に自動実行する関数
		* @return void
		*/
		addLoadEvent : function( listener ){
			this.addEvent( window, "load", listener, false );
		}
	}
	var eventManager = new EventManager();
	this.getEventManager = function(){
		return eventManager;
	}
	
	
	
	
	
	
	
	
	
	/**
	* いわゆるファクトリーメソッドみたいなものです。
	* 同じオブジェクトを共有する機能を提供します。
	*/
	function Factory(){
		var cache = new Object();
		this.getCache = function(){
			return cache;
		}
	}
	Factory.prototype = {
		constructor : Factory,
		/**
		* @access public
		* @param key String オブジェクトが格納されるキー
		* @param obj 格納されるオブジェクト
		*
		* 指定したオブジェクトのインスタンスを返します。
		*
		* 指定された文字列をキーとしてオブジェクトを保持し、
		* 既にキーとして使用されている文字列をキーに指定した場合
		* 以前に指定したオブジェクトのインスタンスを返します。
		*/
		newObject : function( key, obj ){
			var c = this.getCache();
			/*
			* ここでまだ何も値が入っていない時、Warning が出るかもしれません。
			* PHP 的に言うと Notice です。特に問題ありません。
			*/
			if( c[key] === void(0) ){
				c[key] = obj;
			}
			return c[key];
		},
		
		/**
		* @access public
		* @param key String オブジェクトが格納されているキー
		*
		* 指定したキーに格納されているオブジェクトのインスタンスを返します。
		* まだオブジェクトが格納されていない場合、未定義値を返します。
		*/
		getObject : function( key ){
			var c = this.getCache();
			return c[key];
		},
		
		/**
		* @access public
		* @param key String オブジェクトが格納されるキー
		* @param obj 格納されるオブジェクト
		*
		* 指定したオブジェクトのインスタンスを返します。
		*
		* 指定された文字列をキーとしてオブジェクトを保持します。
		* 既にキーとして使用されている文字列をキーに指定すると
		* 保持されていたオブジェクトを上書きします。
		*/
		replaceObject : function( key, obj ){
			var c = this.getCache();
			c[key] = obj;
			return c[key];
		}
	};
	var factory = new Factory();
	this.getFactory = function(){
		return factory;
	}
	
	
	
	
	
	
	
	
	/**
	* リンク制御用のクラス。
	*/
	function Linker(){
		/** 自ページの URL。# 以降があればそれを除いた URL */
		var selfURL = ( location.hash ) ? location.href.substring( 0, location.href.lastIndexOf(location.hash) ) : location.href;
		
		this.getSelfURL = function(){
			return selfURL;
		}
	}
	Linker.prototype = {
		constructor : Linker,
		/**
		* @access public
		* @param link object(HTMLAElement) href 属性を削除するリンク要素
		* @return void
		*
		* 指定リンクの href 削除。
		*/
		removeLink : function(link){
			link.removeAttribute("href");
		},
		
		/**
		* @access public
		* @param url String 検索対象URL
		* @return object[](HTMLAElement[]) 対象URL と同じリンク先を持つリンク要素の配列
		*/
		getLinksByURL : function(url){
			if( dom.canDOM() == false ) return new Array();
			
			/*
			* フルパスを手っ取り早く知る為に
			* document.links を使用。
			* document.getElementsByTagName("a") だと相対パスが解決されないので
			* 自力でフルパスを計算しないといけない。
			*/
			var links = document.links;
			var array = new Array();
			for(var i=links.length-1; i>=0; i--){
				/* Opera の変な挙動対策 */
				if( ! links[i] ){
					continue;
				}
				if(links[i].href == url){
					array.unshift( links[i] );
				}
			}
			return array;
		},
		
		/**
		* @access protected
		* @param isInternal String 内部リンクを取得するのかどうか。false なら外部リンクを取得する
		* @param internalURL String 内部とみなす URL の断片。これが href 属性にあれば内部とする
		* @return object[](HTMLAElement[]) リンク要素の配列
		*/
		getLinks : function( isInternal, internalURL ){
			if( dom.canDOM() == false ) return new Array();
			
			var links = document.getElementsByTagName("a");
			var array = new Array();
			if( !internalURL ) internalURL = location.hostname;
			var innerDomain = new RegExp( internalURL, "i" );
			var fullpath = new RegExp( "^(ht|f)tps?://", "i" );
			for(var i=links.length-1; i>=0; i--){
				var href = links[i].getAttribute("href");
				if( ! href ){
					continue;
				}
				var isOuter = fullpath.test(href) && !innerDomain.test(href);
				if( isOuter != isInternal ){
					array.unshift( links[i] );
				}
			}
			return array;
		},
		
		/**
		* @access public
		* @param internalURL String 内部とみなす URL の断片
		* @return object[](HTMLAElement[]) サイト外リンク要素の配列
		* 外部リンクを全て返す
		*/
		getExternalLinks : function( internalURL ){
			return this.getLinks( false, internalURL );
		},
		
		/**
		* @access public
		* @param internalURL String 内部とみなす URL の断片
		* @return object[](HTMLAElement[]) サイト内リンク要素の配列
		* 内部リンクを全て返す
		*/
		getInternalLinks : function( internalURL ){
			return this.getLinks( true, internalURL );
		},
		
		/**
		* @access public
		* @param link object(HTMLAElement) リンク先ウィンドウを設定するリンク要素
		* @param target String リンク先ウィンドウ名
		* @param index integer 文書全体から見た指定リンク要素のインデックス番号
		* @return void
		* 対象リンクを開くウィンドウ名を設定します。キーボード使いには
		* こんな機能は必要無い（Ctrl+Enterなどで新窓を開く）ので
		* onkeydown にはイベントを割り当てていません
		*/
		setOpenTarget : function( link, target, index ){
			if( dom.canDOM() == false ) return;
			
			/* Fixed 同じ URL へのリンクが複数ある場合に最初の1つ目以外は前のハンドラが削除されない */
			/* 前の target 指定があれば打ち消す */
			var href = link.getAttribute("href");
			var previousTarget = factory.getObject( href + index );
			if( previousTarget ){
				eventManager.removeEvent( link, "click", factory.getObject( "#" + previousTarget + "@" + href), false );
			}
			
			/* 新しい target 指定を保存してイベントハンドラに登録する */
			factory.replaceObject( href + index, target );
			eventManager.addEvent( link, "click", factory.newObject( "#" + target+ "@" + href, function(){
				window.open(href, target);
				return false;
			}), false );
			
			/*
			* href 属性無効化設定を行う。
			* その際に他のスクリプトと競合しないよう考慮する。
			*/
			var handler = link.onclick;
			if( handler && handler != core.returnFalse ){
				/*
				* 未定義でなく且つ core.returnFalse でも無ければ何か設定されている。
				* 従ってクロージャを使う。この function は繰り返されるかもしれないので
				* 処理が被らないようにファクトリーも使っておく。
				*/
				link.onclick = factory.newObject( "&" + href, function(){
					handler();
					return false;
				} );
			} else if( ! handler ){
				/* 未定義っぽいので直接 href 属性無効化設定を行う */
				link.onclick = core.returnFalse;
			}
		}
	};
	var linker = new Linker();
	this.getLinker = function(){
		return linker;
	}
	
	
	
	
	
	
	
	
	
	/**
	* クッキー管理
	*/
	function CookieManager(){}
	CookieManager.prototype = {
		constructor : CookieManager,
		/**
		* @access public
		* @param name String 取得するクッキーの名前
		* @return String|null クッキーが存在しなければ null、そうでなければクッキーの値
		*/
		getCookie : function(name){
			var start, end;
			var c = document.cookie;
			
			if(c.indexOf(name + '=') != -1){
				start = c.indexOf(name + '=');
				end = c.indexOf( ';', start + name.length+1 );
				if(end == -1){
					end = c.length;
				}
				var value = c.substring( start + name.length+1, end );
				return window.decodeURIComponent ? decodeURIComponent(value) : unescape(value) ;
			}
			return null;
		},
	
		/**
		* @access public
		* @param name String 設定するクッキーの名前
		* @param value String 設定する値
		* @param expdays int クッキー有効日数
		* @param domain String クッキーを有効にするドメイン
		* @param path String クッキーを有効にするパス
		* @return void
		*/
		setCookie : function(name,value,expdays,domain,path){
			if( value == null ) throw "Invalid Value";
			if( !expdays ) expdays = 0;
			/* ドメインとパスは空設定の場合を考慮 */
			if( !domain ) domain = location.hostname;
			if( !path ) path = location.pathname.substring(0,location.pathname.lastIndexOf("/")+1 );
			
			value = window.encodeURIComponent ? encodeURIComponent(value) : escape(value) ;
			
			var c = name + "=" + value;
			c += "; domain=" + domain;
			c += "; path=" + path;
			if(expdays != 0){
				var expires = new Date();
				expires.setTime(expires.getTime() + 1000*60*60*24*expdays);
				c += "; expires=" + expires.toGMTString();
			}
			document.cookie = c;
		}
	};
	var cookieManager = new CookieManager();
	this.getCookieManager = function(){
		return cookieManager;
	}
	
	
	
	
	
	
	
	
	
	
	/**
	* フォーム制御
	*/
	function FormManager(){}
	FormManager.prototype = {
		constructor : FormManager,
		
		/**
		* @access public
		* @param formElement object(HTMLFormElement) セーフモード適用対象のフォーム要素
		* @param isStrong boolean 強いセーフモード（送信確認付き）を適用するか
		* @return void
		* 指定したフォームの決定操作（送信/リセット）を安全に行うように設定します。
		* DOM が使えなければ何もしません。
		*/
		applySafemode : function( formElement, isStrong ){
			if( dom.canDOM() == false ) return;
			
			var elements = formElement.elements;
			var act = formElement.getAttribute("action");
			if( act ){
				eventManager.addEvent( formElement, "submit", function(event){
					/*
					* 強いセーフモードの場合は送信の可否を問い、
					* そこでキャンセルすれば送信を抑制する。
					* そうでなければフォームのそれ以上の変更を抑制する。
					*/
					if( isStrong && ! core.confirm() ){
						try{
							/* 対 標準実装ブラウザ */
							event.preventDefault();
						} catch(e){
							/* 対 Trident, 独自拡張オブジェクトの利用によるアクション回避 */
							event.returnValue = false;
						}
					} else {
						var es = formElement.elements;
						for(var i=es.length-1; i>=0; i--){
							try{
								/*
								* disabled = true にするとデータが送信されないので
								* あたかも変更不可能であるように見せる。
								* 実際に変更不可能なようにするので、change や focus を許さない。
								*/
								es[i].style.color = "#666";
								es[i].style.backgroundColor = "#ccc";
								eventManager.addEvent( es[i], "focus", core.returnFalse, false );
								/* button 要素には onchange イベントがないので例外投げるかも ? */
								eventManager.addEvent( es[i], "change", core.returnFalse, false );
							} catch(e){}
						}
					}
				}, false );
				eventManager.addEvent( formElement, "reset", function(event){
					if( isStrong && ! core.confirm() ){
						try{
							event.preventDefault();
						} catch(e){
							event.returnValue = false;
						}
					}
				}, false );
			}
		}
	};
	var formManager = new FormManager();
	this.getFormManager = function(){
		return formManager;
	}
	
	
	
	
	
	
	
	
	
	
	/**
	* リンク先切り替え機能の提供をします。
	* 2 大機能の片割れです。
	*/
	function LinkSwitcher(){
		/** チェックボックスに付けるID。内部的にも使用するので重要 */
		var checkboxID = "WOSWITCHBOX";
		/** 挿入する div 要素の ID */
		var divID = "WOSWITCH";
		
		this.getCheckboxID = function(){
			return checkboxID;
		}
		
		this.getDivID = function(){
			return divID;
		}
	}
	LinkSwitcher.prototype = {
		constructor : LinkSwitcher,
		
		/**
		* @access public
		* @param isNewWindow boolean 新しいウィンドウで開かせるかどうか
		* @return void
		* 外部リンクを開かせるウィンドウの設定を行います
		*/
		switchLink : function(isNewWindow){
			if( dom.canDOM() == false ) return;
			
			var external = linker.getExternalLinks( config.switcher.internalURL );
			for(var i=external.length-1; i>=0; i--){
				linker.setOpenTarget( external[i], isNewWindow ? "_blank" : "_self", i );
			}
			document.getElementById( this.getDivID() ).className = isNewWindow ? "enable" : "disable";
			cookieManager.setCookie("open", isNewWindow ? "New" : "Same", config.switcher.expdays, config.cookie.domain, config.cookie.path );
		}
	};
	var switcher = new LinkSwitcher();
	this.getSwitcher = function(){
		return switcher;
	}
	
	
	
	
	
	
	
	
	
	
	
	
	/**
	* スタイルシート切り替え機能の提供をします。
	* 2 大機能の片割れで、多分需要が最も多い機能です。
	*/
	function Styler(){
		/** セレクトボックスに付けるID。内部的にも使用するので重要 */
		var selectID = "WOSSSBOX";
		/** 挿入する div 要素の ID。CSS で制御しやすいように付けている */
		var divID = "WOSSS";
		
		this.getSelectID = function(){
			return selectID;
		}
		
		this.getDivID = function(){
			return divID;
		}
	}
	Styler.prototype = {
		constructor : Styler,
		/**
		* @access protected
		* @return object[](styleSheets[]|HTMLLinkElement[]) 優先/代替スタイルシートに関連している styleSheets オブジェクト(それが利用できなければ link 要素)の配列
		*
		* styleSheets オブジェクトから title があるものだけを返します。
		* styleSheets オブジェクトが利用できない場合は代わりに link 要素から取得します。
		* 返り値に永続スタイルシートは含みません。
		* link 要素での取得の場合に DOM がサポートされていなければ空配列を返します。
		*/
		getStyleSheets : function(){
			var i;
			var sheets = new Array();
			if( document.styleSheets ){
				var csses = document.styleSheets;
				for(i=csses.length-1; i>=0; i--){
					if( csses[i].title ){
						sheets.unshift(csses[i]);
					}
				}
			} else {
				if( dom.canDOM() == false ) return new Array();
				
				var objLinks = document.getElementsByTagName("link");
				for(i=objLinks.length-1; i>=0; i--){
					if(
					objLinks[i].getAttribute("rel") &&
					objLinks[i].getAttribute("rel").toLowerCase().indexOf("stylesheet") != -1 &&
					objLinks[i].getAttribute("title") ){
						sheets.unshift(objLinks[i]);
					}
				}
			}
			return sheets;
		},
		
		/**
		* @access public
		* @param sheet String 適用するスタイルシート名
		* @return void
		*
		* sheet と同一名のスタイルシートを有効に、それ以外を無効にします。
		* 永続スタイルシートには影響を及ぼしません。
		* DOM がサポートされていなければ何もしません。
		*/
		changeStyleSheet : function(sheet){
			if( !sheet || dom.canDOM() == false ) return;
			
			var sheets = this.getStyleSheets();
			for(var i=sheets.length-1; i>=0; i--){
				sheets[i].disabled = true;
				/* link 要素か xml-stylesheet 処理命令かで参照手段が異なる為2段階に分けて参照 */
				var title = sheets[i].title;
				if( !title ) title = sheets[i].getAttribute("title");
				if(title == sheet){
					sheets[i].disabled = false;
				}
			}
			cookieManager.setCookie("sheet", sheet, config.styler.expdays, config.cookie.domain, config.cookie.path );
		}
	};
	var styler = new Styler();
	this.getStyler = function(){
		return styler;
	}
	
	
	
	
	
	
	
	/**
	* 初期化の全機能です。
	*/
	function Initializer(){}
	Initializer.prototype = {
		constructor : Initializer,
		/**
		* @access public
		* @return void
		* ウィンドウのデフォルトステータスバー文字列を
		* ページの簡単な説明にします。
		*/
		initWindowStatus : function(){
			window.defaultStatus = "[ " + self.location.href + " ] - " + document.title;
		},
		
		/*
		* @access public
		* @return void
		* フレーム内にページがあった場合に、ページをウィンドウ全体に表示しなおすか
		* 聞いて、了承されたらそのようにリロードします。
		* 主に外部サイトのフレーム内に表示される事の予防を目的とします。
		*/
		initWindowFrame : function(){
			/*
			object 要素での取り込みを検知する為に
			トップウィンドウはディレクトリの場所を URL で求め
			自ウィンドウは設定 URL が空であればトップディレクトリを URL で求め、
			そうでなければ設定をそのまま使用します。 [Feedback 2004-12-19]
			*/
			var selfDirURL = config.frame.address ? config.frame.address : self.location.protocol+"//"+self.location.hostname + "/";
			var topDir = top.location.pathname.substring(0,top.location.pathname.lastIndexOf("/")+1 );
			var topDirURL = top.location.protocol+"//"+top.location.hostname + topDir;
			selfDirURL = selfDirURL.toLowerCase();
			topDirURL = topDirURL.toLowerCase();
			if( topDirURL.indexOf(selfDirURL) == -1 ){
				if( confirm( "警告！\n'" + document.title + "'\nは他のサイトのフレーム内に入れられている可能性があります。\nフレームを破棄しますか？") ){
					top.location.href = self.location.href;
				}
			}
		},
		
		/**
		* @access public
		* @return void
		*
		* link 要素で指定されているスタイルシートのタイトルを一覧でプルダウンリストとして出力します。
		* 出力は div 要素に select 要素を含めた形で行われます。
		* div , select 要素には ID を付けます。
		* このセレクトボックスは選択項目が変更されると
		* 自動的に適切な styler.changeStyleSheet() を実行されるよう設定されます。
		* また、現在有効なスタイルの項目は選択状態にされます。
		* DOM がサポートされていなければ何もしません。
		*/
		initStyleSheetController : function(){
			if( dom.canDOM() == false ) return;
			
			var div = dom.createElement("div");
			var select = dom.createElement("select");
			var sheet = cookieManager.getCookie("sheet");
			var sheets = styler.getStyleSheets();
			div.id = styler.getDivID();
			select.id = styler.getSelectID();
			
			/*
			同一の title 属性を持つスタイルシートの link が複数あると
			option が重複するためプルダウンリストに含める前にチェックします [Feedback 2004-12-19]
			*/
			var titles = new Array();
			for(var i=0, len=sheets.length; i<len; i++){
				/* ここでも2段階での参照 */
				var title = sheets[i].title;
				if( !title ) title = sheets[i].getAttribute("title");
				
				if( titles.contains(title) == false ){
					titles.push(title);
					var opt = dom.createElement("option");
					opt.appendChild( document.createTextNode(title) );
					select.appendChild(opt);
					if( title == sheet ){
						select.selectedIndex = i;
						opt.className = "enable";
					} else {
						opt.className = "disable";
					}
				}
			}
			
			/* 優先/代替スタイル一切適用無し状態が設定で有効なら追加 */
			if( config.styler.enableNoStyle && config.styler.noStyleName ){
				var nostyle = dom.createElement("option");
				nostyle.appendChild( document.createTextNode(config.styler.noStyleName) );
				select.appendChild(nostyle);
				if( sheet == config.styler.noStyleName ){
					select.selectedIndex = titles.length;
					nostyle.className = "enable";
				} else {
					nostyle.className = "disable";
				}
			}
			
			/* テキストを追加 */
			if( config.styler.text ){
				var label = dom.createElement("label");
				label.setAttribute("for", styler.getSelectID() ); // Feedback from ALIMIKA SATOMI 2004-12-19
				label.appendChild( document.createTextNode(config.styler.text) );
				div.appendChild(label);
			}
			div.appendChild(select);
			
			eventManager.addEvent( select, "change", function(){
				var selectElement = document.getElementById( styler.getSelectID() );
				var sheet = selectElement.options[selectElement.selectedIndex].text;
				var options = selectElement.options;
				for(var i=options.length-1; i>=0; i--){
					options[i].className = (options[i].text == sheet) ? "enable" : "disable";
				}
				styler.changeStyleSheet(sheet);
			}, false );
			
			/*
			* とりあえず（中略）例外時は、選択機能を表示しない。
			*/
			try{
				var targetElement;
				if( config.styler.targetElementID ){
					targetElement = document.getElementById(config.styler.targetElementID);
				} else {
					targetElement = document.getElementsByTagName(config.styler.targetElementName)[config.styler.targetElementIndex-1];
				}
				dom.addElement( div, targetElement, config.styler.isBefore, config.styler.isOut );
			}catch(err){}
		},
		
		/*
		* @access public
		* @return void
		*
		* 以前のスタイルシート設定を読み込んで、そのスタイルを反映させます。
		* クッキーがなんらかの理由で存在しなければ何もしません。
		*/
		initStyleSheet : function(){
			var sheet = cookieManager.getCookie("sheet");
			if( sheet != null ){
				styler.changeStyleSheet(sheet);
			}
		},
		
		/**
		* @access public
		* @return void
		* リンク先切り替え用のフォームをページ上に配置します。
		*/
		initLinkController : function(){
			if( dom.canDOM() == false ) return;
			
			var div = dom.createElement("div");
			var checkbox = dom.createElement("input");
			var label = dom.createElement("label");
			
			/* checkbox の設定 */
			checkbox.setAttribute("type","checkbox");
			checkbox.setAttribute("value","on");
			checkbox.id = switcher.getCheckboxID();
			
			eventManager.addEvent(checkbox, "change", function(){
				switcher.switchLink(document.getElementById( switcher.getCheckboxID() ).checked);
			}, false );
			
			/* label の設定 */
			label.appendChild( checkbox );
			label.appendChild( document.createTextNode(config.switcher.text) );
			div.appendChild(label);
			
			/* div の設定 */
			div.id = switcher.getDivID();
			
			/*
			* とりあえず要素を取得してみて、それに追加してみる。
			* この時、要素が見つからなければ追加操作で例外が投げられる。
			* 例外時は、選択機能を表示しない。
			*/
			try{
				var targetElement;
				if( config.switcher.targetElementID ){
					targetElement = document.getElementById(config.switcher.targetElementID);
				} else {
					targetElement = document.getElementsByTagName(config.switcher.targetElementName)[config.switcher.targetElementIndex-1];
				}
				dom.addElement( div, targetElement, config.switcher.isBefore, config.switcher.isOut );
			}catch(err){}
			
			/*
			* ユーザーにより指定があった場合はその通りに、
			* まだ指定のない場合は初期状態で別の作業領域を開く設定を参照する
			*/
			var switchCookie = cookieManager.getCookie("open");
			if( switchCookie == "New" || (switchCookie == null && config.switcher.applyByDefault ) ){
				switcher.switchLink(true);
				checkbox.checked = true;
			} else {
				div.className = "disable";
			}
		},
		
		/*
		* @access public
		* @return void
		* ページ内のフォームのリセットと送信操作で確認を取るよう設定します。
		* 但し、フォームのクラス名に WO-noConfirm が指定されているものは無視します。
		*/
		initForm : function(){
			if( dom.canDOM() == false ) return;
			
			var forms = document.getElementsByTagName("form");
			for(var i=forms.length-1; i>=0; i--){
				var classes = forms[i].className.split(/\s+/);
				formManager.applySafemode( forms[i], !classes.contains("WO-noConfirm") );
			}
		},
		
		/**
		* @access public
		* @return void
		* 自己リンクの排除
		*/
		initLink : function(){
			var links = linker.getLinksByURL( linker.getSelfURL() );
			for(var i=links.length-1; i>=0; i--){
				linker.removeLink( links[i] );
				if( config.unlink.activeClassName ){
					links[i].className += (" " + config.unlink.activeClassName);
				}
			}
		},
		
		/**
		* @access public
		* @return void
		* 変な構造で認識されている abbr 要素を正しく生成し直す。
		* 正しく (X)HTML 構造を認識する UA では処理を実行しない。
		*/
		initAbbr : function(){
			if( dom.canDOM() == false || document.getElementsByTagName("/abbr").length == 0 ){
				return;
			}
			
			var abbrs = document.getElementsByTagName("abbr");
			var attrs = [
				"style", "title", // %coreattrs ( id, class を除く  )
				"lang", "dir", // %i18n
				"onclick", "ondbclick", "onmousedown", "onmouseup", "onmouseover", "onmouseout", "onkeypress", "onkeydown", "onkeyup" // %events
			];
			for(var i=abbrs.length-1; i>=0; i--){
				var oldAbbr = abbrs[i];
				var newAbbr = dom.createElement("abbr");
				
				/*
				属性のコピー。
				XHTML の場合はあらゆる属性名を許すが HTML の場合は DTD にあるかチェックする。
				HTML では 属性名は大文字小文字の違いは問わないが、XHTML では属性名は小文字でなければならないので、とりあえず属性名は小文字で書き出す。
				*/
				for(var j=oldAbbr.attributes.length-1; j>=0; j--){
					var oldAttr = oldAbbr.attributes[j];
					if(
					oldAttr.nodeName.toLowerCase() != "class" && // WinIE は class 属性を setAttribute では正しく反映しない為、後で className プロパティに代入する
					oldAttr.nodeName.toLowerCase() != "id" && // id 属性は古い abbr 要素を削除した後で代入する
					oldAttr.nodeValue && // null や "" もあるので除外
					(dom.isXHTML() ||
					attr.contains(oldAttr.nodeName.toLowerCase())
					) ){
						newAbbr.setAttribute(oldAttr.nodeName.toLowerCase(), oldAttr.nodeValue);
					}
				}
				/* 正しく生成し直した abbr 要素を追加し、以前の内容をコピーする */
				oldAbbr.parentNode.insertBefore(newAbbr, oldAbbr);
				while(oldAbbr.nextSibling.nodeName.toUpperCase() != "/ABBR") {
					newAbbr.appendChild(oldAbbr.nextSibling);
				}
				tempID = oldAbbr.id;
				tempClass = oldAbbr.className;
				
				/* 変な認識になっている abbr 要素を削除 */
				oldAbbr.parentNode.removeChild(oldAbbr.nextSibling);
				oldAbbr.parentNode.removeChild(oldAbbr);
				
				/*
				特殊属性のコピー。
				古い abbr 要素の削除が終わる前にこれを行うと insertBefore() が
				終わった瞬間は同じ ID が同じ文書に存在してしまうため、ここで処理する。
				また、IE では setAttribute で class を
				有効化させることは出来ないので className に代入する。
				*/
				if( tempID ){
					newAbbr.id = tempID;
				}
				if( tempClass ){
					newAbbr.className = tempClass;
				}
				//確認用 alert( newAbbr.parentNode.innerHTML );
			}
		},
		
		/*
		* Original Arrange:
		*   P_BLOG
		* Original:
		*   Simon Willison, 20th December 2002
		* Explanation: 
		*   http://simon.incutio.com/archive/2002/12/20/#blockquoteCitations
		* Inspired by Adrian Holovaty: 
		*   http://www.holovaty.com/blog/archive/2002/12/20/0454
		* Alternative implementation of the same idea by Paul Hammond: 
		*   http://www.paranoidfish.org/boxes/2002/12/20/
		*/
		/**
		* 引用元へのリンクを生成します。
		*/
		initQuote : function(){
			if( dom.canDOM() == false ) return;
			
			quotes = document.getElementsByTagName("blockquote");
			for(var i=quotes.length-1; i>=0; i--){
				cite = quotes[i].getAttribute("cite");
				if ( cite ){
					var newlink = dom.createElement("a");
					var title = quotes[i].getAttribute("title");
					if( title ){
						newlink.setAttribute("title", title);
					}
					newlink.setAttribute("href", cite);
					newlink.appendChild(document.createTextNode("→ Source"));
					var newdiv = dom.createElement("div");
					newdiv.className = "blockquotesource";
					newdiv.appendChild(newlink);
					quotes[i].appendChild(newdiv);
				}
			}
		}
	}
	var initializer = new Initializer();
	this.getInitializer = function(){
		return initializer;
	}
}
WebsiteOptions.prototype = {
	constructor : WebsiteOptions
};

/**
* Website Options の全ての実行。
*/
function executeWebsiteOptions(){
	var webopt = new WebsiteOptions();
	var config = webopt.getConfig();
	var em = webopt.getEventManager();
	var dom = webopt.getDom();
	var initer = webopt.getInitializer();
	var factory = webopt.getFactory();
	var factoryKey = "Website Options Initialization Handler";
	
	/* 初期化を行う事で警告の発生を防ぐ */
	factory.replaceObject( factoryKey, null );
	
	/*
	* 正確なリンク制御を実現する為の分岐。
	*
	* 引用元リンク生成機能とリンク制御機能を同時使用するとする。
	* その時、リンク制御機能が働いた後に
	* 引用元リンクを生成すると、そのリンクは必ず『同じ領域』で開くリンクとなる。
	* 『外部リンクは別領域で開く』設定でページを訪れた場合、
	* この引用元へのリンクは、例え外部であっても全て『同じ領域』で開いてしまう。
	* これではよろしくないので、機能が動作する順序を正確に設定する。
	*
	* 因みに Firefox は登録された順で機能が働くという性質がある。(Queue 方式)
	* 逆に WinIE6 は登録された逆順で機能を実行していく。(Stack 方式)
	* 仕様上で正しいのはどういう動作なのかは未調査。
	*
	* 関連:
	*    同様に順序の制御を行っている処理が
	*    スタイル切り替え用コントロール要素の生成と
	*    リンクコントロール要素の生成である。
	*    リンク→スタイルの要素の順に生成する。
	*    これはユーザーが CSS などを作りやすくするための配慮。
	*/
	if( config.switcher.enable && config.html.useBlockquoteCitation ){
		factory.replaceObject( factoryKey, function(){
			/* 引用元リンク生成後、リンク制御 */
			initer.initQuote();
			initer.initLinkController();
		} );
	} else {
		if( config.switcher.enable ){
			factory.replaceObject( factoryKey, initer.initLinkController );
		}
		if( config.html.useBlockquoteCitation ){
			em.addLoadEvent( initer.initQuote );
		}
	}
	
	if( config.styler.enable ){
		/* Opera ではない || Opera だろうが構わない || XHTML ではない */
		if( !window.opera || config.styler.affectOpera || !dom.isXHTML() ){
			/* イベントハンドラが既に記録されていたら、追加して記録する */
			var preparedHandler = factory.getObject( factoryKey );
			if( preparedHandler ){
				factory.replaceObject( factoryKey, function(){
					preparedHandler();
					initer.initStyleSheetController();
				} );
			} else {
				/*
				* 記録無しであれば、実行順序を制御する必要はないので
				* そのままイベントを登録。
				*/
				em.addLoadEvent( initer.initStyleSheetController );
			}
			/* 表示スタイルをレンダリング開始前に切り替える  */
			initer.initStyleSheet();
		}
	}
	/* ここまでの間、何かハンドラが記録されていればそれを登録 */
	if( factory.getObject(factoryKey) !== null ){
		em.addLoadEvent( factory.getObject(factoryKey) );
	}
	
	if( config.window.enable ){
		em.addLoadEvent( initer.initWindowStatus );
	}
	if( config.frame.enable ){
		em.addLoadEvent( initer.initWindowFrame );
	}
	if( config.html.useFixAbbr ){
		em.addLoadEvent( initer.initAbbr );
	}
	if( config.form.enable ){
		em.addLoadEvent( initer.initForm );
	}
	if( config.unlink.enable ){
		em.addLoadEvent( initer.initLink );
	}
}
/*
* スクリプト全体を無効化する時はここをコメントアウトすると楽
*/
executeWebsiteOptions();
/*

Website Options
3.4.1.20061021
Written by TYLIGHT

[1] この JavaScript は修正 BSD ライセンスで配布します。
[2] ECMA-Script 3rd Edition に可能な限り沿った記述をします。
[3] 可能な限り、一般的なプログラミング上の常識に従います。
[4] 可能な限り、他の JavaScript と同時使用した際に問題が発生しないようにします。
[5] なるべく、非対応ブラウザでもエラーダイアログが出ないように配慮します。
[6] 利用者に感謝します。

配布先 - read a little
http://readalittle.net/

\e
*/
