// ==UserScript==
// @name           LDRize
// @namespace      http://white.s151.xrea.com/
// @description    j,k,v,p,o,:,f,? + l,s patched by ku
// @include        *
// ==/UserScript==

var LDRize = {
// ------------------------------------------------------------------
// Shortcut Keys
// ------------------------------------------------------------------

  KEYBIND : {
	  'j' : 'Next',
	  'k' : 'Prev',
	  'v' : 'View',
	  'p' : 'Pin',
	  'o' : 'Open',
	  'l' : 'List',
	  '?' : 'Help',
	  'f' : 'Focus',
	  ':' : 'Minibuffer',
	  's' : 'Siteinfo',
  },
	
  BIND_DESCRIPTION : {
	  'Next'           : 'Scroll next item',
	  'Prev'           : 'Scroll previous item',
	  'View'           : 'Open in current tab',
	  'Pin'            : 'Pin',
	  'Open'           : 'Open pinned items or current item',
	  'List'           : 'Toggle pinned items list',
	  'Help'           : 'Toggle help',
	  'Focus'          : 'Focus on search box',
	  'Minibuffer'     : 'Show Minibuffer',
	  'Siteinfo'       : 'Change Siteinfo',
	  'OpenBackground' : 'Open in new tab (background)',
	  'OpenForeground' : 'Open in new tab (foreground)',
  },

// ------------------------------------------------------------------
// Height
// ------------------------------------------------------------------
  DEFAULT_HEIGHT : 0,
  PROMPT: 'LDRize:',

// ------------------------------------------------------------------
// Siteinfo
// ------------------------------------------------------------------
// domain    : URL or XPATH
// paragraph : XPATH
// link      : XPATH
// focus     : XPATH
// stripe    : TRUE
// height    : NUMBER
// disable   : TRUE

/* template
      {
            domain:    '',
            paragraph: '',
            link:      '',
            focus:     '',
            stripe:    true,
            height:    10,
      },
*/
  SITEINFO : [
	  ],

  SITEINFO_IMPORT_URLS : [
	  "http://white.s151.xrea.com/wiki/index.php?cmd=ldrize",
	  ],

// ------------------------------------------------------------------
// CSS
// ------------------------------------------------------------------
  css_stripe_odd:  false,
  css_stripe_even: 'background-color:#eeeeff !important;',

  css_highlight_link:   false,
//  css_highlight_link: '-moz-outline: 2px solid #CB6161 !important;-moz-outline-offset: 1px !important;-moz-outline-radius: 3px !important;',
  css_highlight_pinned: '-moz-outline: 2px solid #CC6060 !important;-moz-outline-offset: 1px !important;-moz-outline-radius: 3px !important;',

  css_stripe_odd_devel : 'background-color:#ffdddd !important;', // red
  css_stripe_even_devel: 'background-color:#ddffdd !important;', // green
  css_highlight_devel:   'background-color:#ddddff !important;', // blue

// ------------------------------------------------------------------
// Image
// ------------------------------------------------------------------
  image_indicator: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAALCAIAAADN+VtyAAAABnRSTlMA/wD/AP83WBt9AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAtElEQVR42mP4////////Zxob/0cFDBDR5wsW1KqqIkswzTIx8cvN/ff9e2pKSp2aGgMMMKWdObNp8mQmTs6/P37E+/vD5ZgYGBggchzy8v++f4+ytobIMf7//x+iBGLmux07/n39uurGDSZk0fe7d//7+XPVjRtNt24xwUU/7N//7+fPVVeuNN26xcDAwCy1ZYtfbu7HQ4f+ff++8sIFiCgDAwPUH9eiotD8wQCh0ET///8PAI0Gmocmb3e4AAAAAElFTkSuQmCC',
  image_up:        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMAAAAAAABupgeRAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAYklEQVR42mNgIAOs5QxaweGPJsiEzNnHFcXCwPSb4d9sDk/sio5zxcHZv///62V3Rld0hTuFU0wAWfdvhr8NbLYIRbd5MljY2f68/ozuQDbmMjYLhEmMP/9ieuL3r18MVAYAAusZJ28GkW8AAAAASUVORK5CYII=',
  image_down:      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMAAAAAAABupgeRAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAfElEQVR42mNgoBZgZGBguM2T8e///88Mvz79//n5P4xk+Pn5/6/fDP+6fp1ggqj9z86MaQArGxuEwcTAwKD6Zcafn79YRHnRVf362/XrBFQRAwODztc53199QDGGgbnh12GESRBg+W0RQgUjU/HPvTg9spYzaAWHPzlBAABpZDIJZmWxzwAAAABJRU5ErkJggg==',


  version: '2007.08.29',
  url: 'http://userscripts.org/scripts/show/11562',
  pin_list : [],
  indicatorMargin: 15,
  scrollHeight: 10,
  current_parapraph: null,
  current_parapraph_top: true,
  infolist: null,
  _enable: false,
  for_each_match_cache: {},
  info_property : ['name', 'domain', 'paragraph', 'link', 'view', 'stripe', 'height', 'focus', 'disable'],
  devhighlighted: false,
  GLOBAL_STRIPE:  false, // enable stripe always
  SMOOTH_SCROLL:  true,
  command: {},
  secondary_siteinfo: null,
  bind_description_internal : {},

  toggleSmoothScroll : function(){
	  LDRize.SMOOTH_SCROLL = !LDRize.SMOOTH_SCROLL;
	  GM_setValue('smooth', LDRize.SMOOTH_SCROLL);
  },

  getSiteinfo : function(){
	  return LDRize.secondary_siteinfo || LDRize.infolist[0];
  },
  getSiteinfoList : function(){
	  return LDRize.infolist;
  },
  getSiteinfoByName : function(siteinfo_name){
	  return LDRize.getSiteinfoList().find(function(e){return e['name'] == siteinfo_name});
  },
  setSiteinfo : function(siteinfo_name){
	  var siteinfo = LDRize.infolist.find(function(info){return info['name'] && info['name'] == siteinfo_name;});
	  if(!siteinfo) return;
	  LDRize.secondary_siteinfo = siteinfo;
	  LDRize.initParagraph();
	  LDRize.clearPinlist();
	  LDRize.initHelp();
  },
  init : function(){
	  if(LDRize._enable) return;
	  window.LDRize = {
		addCommand: function(cmd){ // cmd = {name:string, command:function, condition:function}
			if(cmd &&
			   cmd['command'] &&
			   cmd['name'] &&
			   cmd['condition'] &&
			   ((typeof(cmd['condition']) == 'function') ? cmd['condition'](LDRize.getSiteinfo()) : true)){
				LDRize.command[cmd['name']] = cmd['command'];
			}
		},
		$X: $X, // to evaluate xpath
		setSiteinfo: LDRize.setSiteinfo, // specify name of siteinfo
		getSiteinfo: LDRize.getSiteinfoByName,  // specify name of siteinfo
		setBind : function(key, func, description){
			// key         ... string of key. (e.g. 'S-a')
			// func        ... function or string
			// description ... for help message
			LDRize.KEYBIND[key] = func;
			if(description) {
				LDRize.bind_description_internal[key] = description;
				LDRize.initHelp();
			}
		},
		unsetBind : function(key, func, description){
			  if(LDRize.KEYBIND[key] == func){
					LDRize.KEYBIND[key] = null;
				  if(LDRize.bind_description_internal[key] == description){
					  LDRize.bind_description_internal[key] = null;
				  }
				  LDRize.initHelp();
			  }
		},
	  }
	  if(typeof(GM_getValue("pinlist")) == 'undefined') GM_setValue("pinlist",'block');
	  if(typeof(GM_getValue("smooth")) == 'undefined') GM_setValue("smooth", LDRize.SMOOTH_SCROLL);

	  LDRize.SMOOTH_SCROLL = eval(GM_getValue('smooth'));
	  if(window.Minibuffer){
		  window.Minibuffer.addCommand({
			  'LDRize::toggle-smooth-scroll': LDRize.toggleSmoothScroll,
		  });
	  }else{
		   GM_registerMenuCommand("LDRize - toggle smooth scroll", LDRize.toggleSmoothScroll);
	  }

	  LDRize.infolist = LDRize.getInfoList();
	  if(LDRize.getSiteinfoList().length) {
		  LDRize._enable = true;
		  document.addEventListener('keypress', LDRize.handleKey, true);
		  LDRize.initCommand();
		  for(x in LDRize.KEYBIND) LDRize.bind_description_internal[x] = LDRize.BIND_DESCRIPTION[LDRize.KEYBIND[x]]
		  LDRize.initParagraph();
		  if(window.AutoPagerize) window.AutoPagerize.addFilter(LDRize.callbackAutopagerize);
		  LDRize.initBindCommand();
		  var css = '';
		  css += LDRize.initImage();
		  css += LDRize.initHelp();
		  css += LDRize.initPinList();
		  css += LDRize.setCSS();
		  if(css != '') GM_addStyle(css);
	  }
  },
  initBindCommand : function(){
	  LDRize.bindNext  = LDRize.scrollNext;
	  LDRize.bindPrev  = LDRize.scrollPrev;
	  LDRize.bindView  = function(){LDRize.viewCurrent('here')};
	  LDRize.bindPin   = LDRize.attachPin;
	  LDRize.bindOpen  = LDRize.openPinned;
	  LDRize.bindList  = LDRize.togglePinList;
	  LDRize.bindHelp  = LDRize.toggleHelpMessage;
	  LDRize.bindFocus = LDRize.focusOnSearch;
	  LDRize.bindMinibuffer = LDRize.showMinibuffer;
	  LDRize.bindSiteinfo   = LDRize.changeSiteinfo;
	  LDRize.bindOpenForeground = function(){LDRize.viewCurrent()};
	  LDRize.bindOpenBackground = function(){LDRize.viewCurrent('back')};
  },

  initCommand : function(){
	  // open pinned items or current item
	  var open = {
		name: 'open', // this name is going to type in minibuffer
		command: function(obj){
			obj.links.forEach(function(url){ // obj.links is list of URL
				GM_openInTab(url);
			});
			return false; // return false to clear pinlist
		},
		condition: function(siteinfo){ // current siteinfo
			return siteinfo && siteinfo['link']; // return something if make this command available
		},
	  }
	  window.LDRize.addCommand(open);
	  
	  var clearcache = {
		name: 'clear-cache',
		command: function(){
			SiteInfo.clearCache();
			return true; // return true to prevent clearing pinlist
		},
		condition: function(){return true},
	  }
	  window.LDRize.addCommand(clearcache);
	  
	  var toggleSmoothScroll = {
		name: 'toggle-smooth-scroll',
		command: function(){
			LDRize.toggleSmoothScroll();
			return true;
		},
		condition: function(){return true},
	  }
	  window.LDRize.addCommand(toggleSmoothScroll);
	  
	  var clearPin = {
		name: 'clear-pin',
		command: function(){return false},
		condition: function(){return true},
	  }
	  window.LDRize.addCommand(clearPin);
	  
	  var devhighlightparagraphes = {
		name: 'dev-highlight-paragraphes',
		command: function(){
			if(!LDRize.devhighlighted){
				GM_addStyle((LDRize.css_stripe_odd_devel ?
							 ".gm_ldrize_odd {"+ LDRize.css_stripe_odd_devel +"}":"") +
							(LDRize.css_stripe_even_devel ?
							 "\n.gm_ldrize_even {"+ LDRize.css_stripe_even_devel +"}":"") +
							(LDRize.css_highlight_devel ?
							 "\n.gm_ldrize_highlight {"+ LDRize.css_highlight_devel +"}":""));
				LDRize.devhighlighted = true;
			}
			var old = LDRize.GLOBAL_STRIPE;
			LDRize.GLOBAL_STRIPE = true;
			LDRize.initParagraph(true);
			LDRize.GLOBAL_STRIPE = old;
		},
		condition: function(){return true}
	  }
	  window.LDRize.addCommand(devhighlightparagraphes);

	  var devshowsiteinfo = {
		name:    'dev-show-siteinfo',
		command: function(){log(LDRize.getSiteinfo())},
		condition: function(){return true}
	  }
	  window.LDRize.addCommand(devshowsiteinfo);

	  var devshowparagraphes = {
		name: 'dev-show-paragraphes',
		command: function(){
			var lst = LDRize.getParagraphes();
			var res = [];
			lst.forEach(function(e){res.push(e[1])});
			log(res);
		},
		condition: function(){return true}
	  }
	  window.LDRize.addCommand(devshowparagraphes);

	  var resetsiteinfo = {
		name: 'set-siteinfo-default',
		command: function(){LDRize.secondary_siteinfo = null},
		condition: function(){return true}
	  }
	  window.LDRize.addCommand(resetsiteinfo);
  },

  initImage : function() {
	  var cssc = ['margin: 0px',
				  'border: 0px',
				  'padding: 0px',
				  'z-index: 1000'].join(';');
	  var cssp = ['right:2px', 'position:fixed'].join(';');
	  var pos = LDRize.getPosition(LDRize.getNthParagraph(0));
	  var indicator = document.createElement("img");
	  indicator.src = LDRize.image_indicator;
	  indicator.setAttribute('style',cssc + ";position:absolute;top:"+
							 (pos.y+LDRize.getScrollHeight()-LDRize.DEFAULT_HEIGHT)+"px; left:"+
							 Math.max((pos.x-LDRize.indicatorMargin), 0)+"px;");
	  indicator.id = "gm_ldrize_indicator";
	  LDRize.indicator = indicator;
	  document.body.appendChild(indicator);
	  
	  var up = document.createElement("img");
	  up.src = LDRize.image_up;
	  up.id = "gm_ldrize_up_arrow";
	  LDRize.up = up;
	  document.body.appendChild(up);
	  
	  var down = document.createElement("img");
	  down.src = LDRize.image_down;
	  down.id = "gm_ldrize_down_arrow";
	  LDRize.down = down;
	  document.body.appendChild(down);
	  
	  return ['img#', up.id,   '{top:15px;', cssp, ';', cssc ,';}\n',
			  'img#', down.id, '{bottom:5px;', cssp, ';', cssc ,';}\n',
			  'img#', down.id, '{', cssc ,';}\n',
			  ].join('') || '';
  },
  initHelp : function(){
	  var geta = function(href, children){
		  var a = document.createElement('a');
		  a.href = href;
		  children.forEach(function(child){a.appendChild(typeof(child) == 'string' ? document.createTextNode(child): child)});
		  return a;
	  }
	  var getKey = function(key, description, unavailable) {
		  var s = document.createElement('s');
		  var kbd = document.createElement('kbd');
		  kbd.appendChild(document.createTextNode(key.replace('S-','<shift> + ').replace('C-','<ctrl> + ').replace('A-','<alt> + ')));
		  var div = getdiv([kbd, getdiv([description])]);
		  if(unavailable) div.setAttribute('class', 'unavailable');
		  return div;
	  }
	  var geth1 = function(description) {
		  var h1 = document.createElement("h1");
		  h1.appendChild(document.createTextNode(description));
		  return h1;
	  }
	  var siga = geta(LDRize.url, ['LDRize']);
	  var sig = getdiv([siga,document.createTextNode(LDRize.version)]);
	  sig.id = 'gm_ldrize_signature';
	  var bind=[geth1('Shortcut Keys')];
	  for(x in LDRize.KEYBIND)
		  if(LDRize.bind_description_internal[x])
			bind.push(getKey(x , LDRize.bind_description_internal[x]))
	  bind.push(sig);
	  var box = getdiv(bind);
	  box.id = 'gm_ldrize_help';
	  LDRize.help = box;
	  var id = 'div#' + box.id;
	  var inherit = 'background:inherit; background-image:inherit; background-color:inherit; color:inherit; text-align:inherit; font-size:inherit; font-style;inherit; font-weight:inherit; magrin:inherit; opacity:inherit; text-decoration:inherit; border:0px; height:100%; padding:0; margin:inherit; font-family:inherit; vertical-align:inherit; line-height:inherit; font-stretch:inherit; font-variant:inherit; font-size-adjust:inherit; letter-spacing:inherit;';
	  return [id,'{', 'right: 10px;', 'left: 10px;', 'top: 10px;', 'line-height: 100%;', 'vertical-align: baseline;', 'border: 1px dotted #444;', 'font-family: sans-serif;', 'text-decoration: none;', 'font-weight: normal;', 'font-style: normal;', 'font-size: medium;', 'font-stretch: normal;', 'font-variant: normal;', 'font-size-adjust: none;', 'letter-spacing: normal;', 'background: none;', 'text-align: left;', 'position: fixed;', 'margin: 0;', 'padding: 20px;', 'background-color: #000;', 'background-image: none;', 'color: #aaa;', '-moz-border-radius: 10px;', 'opacity:0.8;', 'z-index:1000;', '}\n',
			  id,' div{', inherit, 'opacity:1.0;','text-align:center;','}',
			  id,' > div{', inherit, 'margin: 0px 20px 20px 0px;', 'opacity:1.0;','text-align:center;','}',
			  id,' a,', id,' a:visited,', id,' a:active,', id,' a:hover{', inherit, 'padding-right: 5px;','text-decoration: underline;',  'color: #CB6161;', '}\n',
			  id,' div#gm_ldrize_signature{', inherit,  'margin:auto;','text-align: right;', 'font-style: italic;', '}\n',
			  id,' div#gm_ldrize_signature a,',id,' div#gm_ldrize_signature a:active,',id,' div#gm_ldrize_signature a:hover,','{' , 'font-style: italic;', '}',
			  id,' kbd{', inherit, 'font-size: 120%;','font-weight: bold;', 'color: #B83E3B;', 'text-align: right;', 'width:50%;','float:left;','}\n',
			  id,' kbd + div{', 'margin-left:50%;', 'text-align:left;','}\n',
			  id,' kbd + div:before{', 'content:": ";' ,'}\n',
			  id,' h1{', inherit, 'margin: 20px auto;','background-image: none;', "opacity:1.0;", 'font-weight: bold;', 'font-size: 150%;', 'color:#fff;','padding-left: 20px;', 'text-align: center;', '}\n',
			  id,' div#gm_ldrize_devel{', inherit, 'margin-top: 30px;', 'margin-bottom: 30px;', '}',
			  id,' div#gm_ldrize_devel span{', 'margin: 10px;', 'margin-top: 20px;','font-weight: bold;','cursor:pointer;','text-decoration: underline;', 'color: #CB6161;','}',
			  id,' #gm_ldrize_toggle_detail {', 'cursor:pointer;','text-decoration: underline;', 'color: #CB6161;','}',
			  ].join('');
  },

  initPinList : function(){
	  var number = getspan([]);
	  number.id = 'gm_ldrize_pinlist_number';
	  
	  var number_container = getdiv([number,' item']);
	  number_container.id = 'gm_ldrize_pinlist_number_container';
	  LDRize.pinlist_number = number_container;
	  
	  var pin_container = getdiv([]);
	  pin_container.style.display = GM_getValue('pinlist');
	  LDRize.pinlist_container = pin_container;
	  
	  var box = getdiv([number_container, pin_container]);
	  box.id = 'gm_ldrize_pinlist';
	  box.style.display = 'none';
	  LDRize.pinlist = box;
	  
	  document.body.appendChild(box);
	  var id = 'div#' + box.id;
	  var inherit = 'background:inherit; background-image:inherit; background-color:inherit; color:inherit; text-align:inherit; font-size:inherit; font-style;inherit; font-weight:inherit; magrin:inherit; opacity:inherit; text-decoration:inherit; border:0px; height:100%; padding:0; margin:inherit; font-family:inherit; vertical-align:inherit; line-height:inherit; font-stretch:inherit; font-variant:inherit; font-size-adjust:inherit; letter-spacing:inherit;';
	  return [id,'{', 'line-height: 100%;', 'vertical-align: baseline;', 'border: 1px dotted #444;', 'font-family: sans-serif;', 'text-decoration: none;', 'font-weight: normal;', 'font-style: normal;', 'font-size: medium;', 'font-stretch: normal;', 'font-variant: normal;', 'font-size-adjust: none;', 'letter-spacing: normal;', 'background: none;', 'text-align: left;', 'position: fixed;', 'right: 20px;', 'bottom: 15px;', 'margin: 0px;', 'padding: 10px;', 'background-color: #000;', 'background-image: none;', 'color: #fff;', '-moz-border-radius: 10px;', 'opacity:0.7;', 'z-index:1000;', '}\n',
			  id,' div{', inherit, 'margin: 10px;', 'opacity:1.0;','}',
			  id,' #gm_ldrize_pinlist_number_container > span {', 'color: #B83E3B;', 'font-size: 150%;', 'font-weight: bold;','}',
			  ].join('');
  },
	
  togglePinList : function(){
	  var val = GM_getValue('pinlist') == 'none' ? 'block' : 'none';
	  GM_setValue('pinlist',val);
	  LDRize.pinlist_container.style.display = val;
  },
  addPinToPinList : function(node){
	  var getCloneImage = function(node){
		  var clone = node.cloneNode(false);
		  if(node.width > 40)  clone.width  = 40;
		  if(node.height > 40) clone.height = 40;
		  clone.setAttribute('style','');
		  return clone;
	  };
	  var xpath = LDRize.getSiteinfo()['view'] || '(descendant-or-self::img | descendant::text()[normalize-space(self::text()) != ""])';
	  var lst = $X(xpath, node);
	  if(!lst.length) return;
	  var res = [];
	  if(LDRize.getSiteinfo()['view']){
		  res = lst.map(function(n){
			  return n.nodeName.toLowerCase() == 'img' ? getCloneImage(n) : n.cloneNode(false);
		  });
	  }else{
		  var height = LDRize.getPosition(lst[0]).y;
		  res = [];
		  var allstringlength = 0;
		  for(var i=0; i<lst.length; i++){
			  if(lst[i].nodeName.toLowerCase() == 'img' || lst[i].nodeType == 3) {
				  var h = LDRize.getPosition(lst[i]).y;
				  if(Math.abs(height - h) < 20) {
					  if(lst[i].nodeType == 3){
						  var str = lst[i].nodeValue.replace(/ /g,'').replace(/\n/g,'').replace(/\t/g,'');
						  allstringlength += str.length;
						  if(allstringlength > 30){
							  res.push(str.slice(0, 30) + '...');
							  break;
						  }else{
							  res.push(lst[i].nodeValue);
						  }
					  }else{
						  res.push(getCloneImage(lst[i]));
					  }
				  }else{
					  break;
				  }
			  }
		  }
	  }
	  var div = getdiv(res);
	  LDRize.pinlist_html.push([LDRize.getPosition(node).str, div]);
	  LDRize.pinlist_container.appendChild(div);
  },
  pinlist_html : [],
  removePinFromPinList : function(node){
	  var pos = LDRize.getPosition(node);
	  var test = function(e){ return e[0] == pos.str}
	  var res = LDRize.pinlist_html.find(test);
	  if(!res) return;
	  LDRize.pinlist_html = LDRize.pinlist_html.remove(test);
	  LDRize.pinlist_container.removeChild(res[1])
  },
  clearClassForPin : function(){
	  var list = LDRize.getParagraphes();
	  list.forEach(function(p){
		  LDRize.removeClassToNode(p[1], 'gm_ldrize_pinned')
		});
  },
  clearPinlist : function(){
	  LDRize.clearClassForPin();
	  LDRize.pin_list = [];
	  LDRize.pinlist_html = [];
	  LDRize.pinlist_container.innerHTML = '';
	  LDRize.pinlist_number.innerHTML =  '';
	  LDRize.pinlist.style.display = 'none';
  },

  naviDisable : function(direction){
	  if('up'==direction) LDRize.up.style.display='none';
	  else LDRize.down.style.display='none';
  },
  naviEnable : function(direction){
	  if('up'==direction) LDRize.up.style.display='block';
	  else LDRize.down.style.display='block';
  },
	
  firstPosition : null,
	
  naviUpdate : function(){
	  var cur = LDRize.getPosition(LDRize.current_parapraph);
	  if(cur){
		  var first = LDRize.firstPosition;
		  if(cur.x == first.x && cur.y == first.y){
			  LDRize.up.style.display = 'none';
			  return;
		  }
		  
		  var last = LDRize.lastPosition;
		  if(cur.x == last.x && cur.y == last.y){
			  LDRize.down.style.display = 'none';
			  return;
		  }
	  }
	  LDRize.up.style.display = 'block';
	  LDRize.down.style.display = 'block';
  },
  indicatorHide : function(){
	  LDRize.indicator.style.display = 'none';
  },
  indicatorUpdate : function(){
	  var pos = LDRize.getPosition(LDRize.current_parapraph);
	  LDRize.indicator.style.display = 'block';
	  LDRize.indicator.style.top = (pos.y+LDRize.getScrollHeight()-LDRize.DEFAULT_HEIGHT) + 'px';
	  LDRize.indicator.style.left = Math.max((pos.x-LDRize.indicatorMargin), 0) + 'px';
  },
  autopagerized : false,
  callbackAutopagerize: function(page){
	  LDRize.autopagerized = true;
  },
  initParagraph : function(force){
	  var change = false;
	  var xpath = LDRize.getSiteinfo()['paragraph'];
	  if(!LDRize.for_each_match_cache[xpath] || force || LDRize.autopagerized){
		  var matches = $X(xpath);
		  if(matches) {
			  LDRize.autopagerized = false;
			  // cache by each xpath
			  if(!LDRize.for_each_match_cache[xpath]) LDRize.for_each_match_cache[xpath] = {};
			  for(var i=0; i<matches.length; i++) {
				  // to get position of text node
				  if(matches[i].nodeType == 3){
					  if(matches[i].nodeValue.replace(/\n/g,'') == '') continue;
					  var span = document.createElement("span");
					  span.setAttribute('class', "gm_ldrize_text_node");
					  span.appendChild(matches[i].cloneNode(false));
					  matches[i].parentNode.insertBefore(span, matches[i]);
					  matches[i].parentNode.removeChild(matches[i]);
					  matches[i] = span;
				  }
				  // add paragraph to cache
				  if(!LDRize.for_each_match_cache[xpath][LDRize.getPosition(matches[i]).str]) {
					  LDRize.for_each_match_cache[xpath][LDRize.getPosition(matches[i]).str] = matches[i];
					  // for striped design
					  if(LDRize.getSiteinfo()['stripe'] || LDRize.GLOBAL_STRIPE)
						LDRize.attachClassForStripe(matches[i], i);
					  change = true;
				  }
			  }
		  }
		  if(change || !LDRize.firstPosition || !LDRize.lastPosition){
			  var para = [];
			  var list = LDRize.for_each_match_cache[xpath]
			  for(x in list) para.push([x, list[x]]);
			  LDRize.paragraphes[xpath] = para;
			  LDRize.firstPosition = LDRize.getPosition(LDRize.getNthParagraph(0));
			  LDRize.lastPosition = LDRize.getPosition(LDRize.getNthParagraph(-1));
		  }
		  return change;
	  }
  },
  paragraphes : {},

  getParagraphes : function(){
	  return LDRize.paragraphes[LDRize.getSiteinfo()['paragraph']] || [];
  },
  getNthParagraph : function(n){
	  var list = LDRize.getParagraphes();
	  if(!list.length) return;
	  if(0 > n) return list[list.length + n][1];
	  else return list[n][1];
  },

  getInfoList : function(){
	  var res=[];
	  for(var i=0; i<LDRize.SITEINFO.length; i++){
		  var info = LDRize.SITEINFO[i];
		  try{
			  if(info['domain'].match(/^https?:/)){
				  if(location.href.match(info['domain']) && ($X(info['paragraph']).length || info['disable'])){
					  if(info['disable']) return [];
					  res.push(info);
				  }
			  }else if($X(info['domain']).length && ($X(info['paragraph']).length || info['disable'])){
				  if(info['disable']) return [];
				  res.push(info);
			  }
		  }catch(e){
//			  log(e);
			  continue;
		  }
	  }
	  return res;
  },
  handleKey : function(event) {
	  if(!LDRize._enable ||
		 event.target.nodeName.toLowerCase().match(/input|textarea/)) return;
	  var keycode = event.which;
	  var key = String.fromCharCode(keycode).toLowerCase();
	  var chars = ['!','"','#','$','%','&',"'",'(',')','=','~','|','{','`','+','*','}','?','_','<','>',':'];
	  if(!chars.find(key)) key=(event.shiftKey)? "S-"+key : key;
	  key=(event.ctrlKey)? "C-"+key : key;
	  key=(event.altKey || event.metaKey)? "A-"+key : key;
	  var func = LDRize.KEYBIND[key];
	  if(func){
		  if(LDRize['bind'+func]){
			  LDRize['bind'+func]();
		  }else if(typeof(func) == 'function'){
			  func();
		  }
		  if(func != 'Help') LDRize.hideHelpMessage();
		  event.preventDefault();
		  event.stopPropagation();
	  }
  },
  attachClassToNode : function(node, class){
	  if(node){
		  var oldclass = node.getAttribute('class');
		  node.setAttribute('class',(oldclass ? oldclass + " " : "") + class);
		  return true;
	  }
  },
  removeClassToNode : function(node, class){
	  if(node && node.getAttribute('class')){
		  var re = new RegExp(' ?' + class);
		  node.setAttribute('class',node.getAttribute('class').replace(re,""));
		  if(node.getAttribute('class') == '') node.removeAttribute('class',0);
	  }
  },
  toggleClassForPin : function(node){
	  var class = node.getAttribute('class');
	  if(class && class.match(/ ?gm_ldrize_pinned/)){
		  LDRize.removeClassToNode(node, 'gm_ldrize_pinned');
	  }else{
		  LDRize.attachClassToNode(node, 'gm_ldrize_pinned');
	  }
  },
  attachClassForHighlight : function(oldNode, newNode){
	  if(oldNode && oldNode != newNode){
		  LDRize.removeClassToNode(oldNode, 'gm_ldrize_highlight');
		  var oldLinkNode = LDRize.getLinkNode(oldNode);
		  if(oldLinkNode) LDRize.removeClassToNode(oldLinkNode, 'gm_ldrize_link');
	  }
	  if(newNode){
		  LDRize.attachClassToNode(newNode, 'gm_ldrize_highlight');
		  var newLinkNode = LDRize.getLinkNode(newNode);
		  if(newLinkNode) LDRize.attachClassToNode(newLinkNode, 'gm_ldrize_link');
	  }
  },
  attachClassForStripe : function(node, count) {
	  var class = node.getAttribute('class');
	  if(!class || !class.match(/gm_ldrize_/)){
		  node.setAttribute(
			  'class',
			  (class || "") + " " +
			  (count.odd() ? "gm_ldrize_odd": "gm_ldrize_even"));
	  }
  },

  setCSS: function(){
	  var css = '';
	  css += (LDRize.css_stripe_odd ?
			  ".gm_ldrize_odd {"+ LDRize.css_stripe_odd +"}":"") +
		(LDRize.css_stripe_even ?
		 ".gm_ldrize_even {"+ LDRize.css_stripe_even +"}":"");
	  if(LDRize.css_highlight_link) css += "\n.gm_ldrize_link {" + LDRize.css_highlight_link + "}";
	  if(LDRize.css_highlight_pinned) css += "\n.gm_ldrize_pinned {" + LDRize.css_highlight_pinned + "}";
	  return css;
  },

  getPosition : function(node){
	  var textnode;
	  if(node.nodeType==3) {
		  textnode = node;
		  var span = getspan(['']);
		  node.parentNode.insertBefore(span, node);
		  node = span;
	  }
	  
	  var _node=node;
	  var offsetx = _node.offsetLeft;
	  var offsety = _node.offsetTop;
	  while(_node.offsetParent){
		  _node=_node.offsetParent;
		  offsety += _node.offsetTop;
		  offsetx += _node.offsetLeft;
	  }
	  if(textnode) node.parentNode.removeChild(node);
	  return {x:offsetx, y:offsety, str:offsetx+':'+offsety}
  },
  getScrollHeight : function(){
	  return LDRize.DEFAULT_HEIGHT + ((typeof(LDRize.getSiteinfo()['height']) != 'undefined') ? Number(LDRize.getSiteinfo()['height']) : LDRize.scrollHeight);
  },
  getLinkNode : function(node){
	  if(!LDRize.getSiteinfo()['link']) return;
	  if(!node && !LDRize.current_parapraph) LDRize.scrollNext();
	  node = node || LDRize.current_parapraph;
	  if(!node) return false;
	  var links = $X(LDRize.getSiteinfo()['link'], node);
	  if(!links || links.length == 0) return;
	  return links[0];
  },
  getLinkURL : function(node){
	  var link = LDRize.getLinkNode(node);
	  if(!link) return false;
	  var url;
	  if(link.nodeName.toLowerCase() == "embed"){
		  url = link.src;
	  }else{
		  url = link.href;
	  }
	  return url;
  },

// j
  current_parapraph_number : null,
  scrollNext : function() {
	  if(!LDRize.current_parapraph && !LDRize.current_parapraph_top && !LDRize.autopagerized) return;
	  if(LDRize.SMOOTH_SCROLL) SmoothScroll.stop();
	  
	  var list = LDRize.getParagraphes();
	  
	  var current_parapraph_pos = null;
	  if(LDRize.current_parapraph) current_parapraph_pos = LDRize.getPosition(LDRize.current_parapraph);
	  var current_parapraph_y = LDRize.current_parapraph && current_parapraph_pos.y;
	  var left = LDRize.current_parapraph ? current_parapraph_pos.x : -1;
	  
	  var top = window.scrollY + LDRize.getScrollHeight();
	  var full_scrolled = false;
	  if(window.scrollY == 0 && window.scrollY >= window.scrollMaxY){
		  top = Math.max(top, current_parapraph_y);
	  }else if(window.scrollY == 0){
		  top = Math.min(top, current_parapraph_y);
	  }else if(window.scrollY >= window.scrollMaxY){
		  full_scrolled = true;
	  }
	  var testfunc = function(pos){
		  return ((!full_scrolled &&
				   ((pos.x > left && pos.y >= top) || (pos.y > top))) ||
				  (full_scrolled &&
				   LDRize.current_parapraph &&
				   ((window.scrollMaxY <= current_parapraph_y &&
					 ((pos.x > left && pos.y >= current_parapraph_y) ||
					  (pos.y > current_parapraph_y))) ||
					(window.scrollMaxY > current_parapraph_y &&
					 pos.y > window.scrollMaxY))));
	  }
	  
	  var bsearch = function(begin, end) {
		  var diff = end - begin;
		  if(diff < 0) [begin, end, diff] = [end, begin, diff*-1];
		  if(diff == 1){
			  return testfunc(LDRize.getPosition(list[begin][1])) ? begin : false;
		  }else if(diff == 2){
			  return testfunc(LDRize.getPosition(list[begin][1])) ? begin :
			  (testfunc(LDRize.getPosition(list[begin+1][1]))? begin+1 : false);
		  }else{
			  var c = begin + Math.floor(diff / 2);
			  var pos = LDRize.getPosition(list[c][1]);
			  if(testfunc(pos)){
				  return bsearch(begin, c+1);
			  }else{
				  return bsearch(c+1, end);
			  }
		  }
	  };

	  if(LDRize.current_parapraph_number &&
		 list.length > LDRize.current_parapraph_number+1 &&
		 !testfunc(LDRize.getPosition(list[LDRize.current_parapraph_number][1])) &&
		 testfunc(LDRize.getPosition(list[LDRize.current_parapraph_number+1][1]))){
		  LDRize.current_parapraph_number++;
	  }else{
		  LDRize.current_parapraph_number = bsearch(0, list.length-1);
	  }
	  
	  var _next = typeof(LDRize.current_parapraph_number) == 'number' ?
		list[LDRize.current_parapraph_number][1]: false;

	  if(!_next){
		  if(LDRize.initParagraph()){
			  LDRize.scrollNext();
		  }else{
			  (LDRize.SMOOTH_SCROLL ? SmoothScroll : window)
				.scrollTo(0, Math.max(document.documentElement.scrollHeight,
									  document.body.scrollHeight))
				  LDRize.attachClassForHighlight(LDRize.current_parapraph, null);
			  LDRize.indicatorHide();
			  LDRize.current_parapraph = null;
			  LDRize.current_parapraph_top = false;
		  }
		  return;
	  }

	  LDRize.attachClassForHighlight(LDRize.current_parapraph, _next);
	  LDRize.current_parapraph = _next;
	  (LDRize.SMOOTH_SCROLL ? SmoothScroll : window)
		.scrollTo(window.pageXOffset, LDRize.getPosition(_next).y - LDRize.getScrollHeight());
	  LDRize.indicatorUpdate();
	  LDRize.naviUpdate();
  }
,

// k
  scrollPrev : function(){
	  if(!LDRize.current_parapraph && LDRize.current_parapraph_top) return;

	  if(LDRize.SMOOTH_SCROLL) SmoothScroll.stop();
	  var list = LDRize.getParagraphes();
	  var current_parapraph_pos,current_parapraph_y;
	  var left = -1;
	  if(LDRize.current_parapraph){
		  current_parapraph_pos = LDRize.getPosition(LDRize.current_parapraph);
		  current_parapraph_y = current_parapraph_pos.y;
		  left = current_parapraph_pos.x;
	  }
	  var top = window.scrollY + LDRize.getScrollHeight();
	  var full_scrolled = false;
	  
	  if(window.scrollY == 0 && window.scrollY >= window.scrollMaxY){
		  if(current_parapraph_y){
			  top = Math.max(top, current_parapraph_y);
		  }else{
			  full_scrolled = true;
		  }
	  }else if(window.scrollY == 0){
		  top = Math.min(top, current_parapraph_y);
	  }else if(window.scrollY >= window.scrollMaxY){
		  full_scrolled = true;
	  }
	  var testfunc = function(pos){
		  return ((!full_scrolled &&
				   ((pos.y > top) || (pos.x >= left && pos.y >= top))) ||
				  (full_scrolled &&
				   LDRize.current_parapraph &&
				   ((pos.x >= left &&
					  (window.scrollMaxY - window.innerHeight) <= current_parapraph_y &&
					  pos.y >= current_parapraph_y) ||
					(pos.y > current_parapraph_y)))
				  );
	  }

	  var bsearch = function(list){
		  var c = Math.floor(list.length / 2);
		  var pos = LDRize.getPosition(list[c][1]);
		  if(list.length == 1){
			  return testfunc(LDRize.getPosition(list[0][1])) ? false : list[0][1];
		  }else if(list.length == 2){
			  return testfunc(LDRize.getPosition(list[1][1])) ?
				(testfunc(LDRize.getPosition(list[0][1])) ? false : list[0][1] ) : list[1][1];
		  }else if(testfunc(pos)){
			  return bsearch(list.slice(0,c));
		  }else{
			  return bsearch(list.slice(c));
		  }
	  }
	  var _prev = bsearch(list);
	  if(!_prev) {
		  (LDRize.SMOOTH_SCROLL ? SmoothScroll : window).scrollTo(0, 0);
		  LDRize.attachClassForHighlight(LDRize.current_parapraph, null);
		  LDRize.indicatorHide();
		  LDRize.current_parapraph = null;
		  LDRize.current_parapraph_top = true;
		  return;
	  }
	  LDRize.attachClassForHighlight(LDRize.current_parapraph, _prev);
	  LDRize.current_parapraph = _prev;
	  (LDRize.SMOOTH_SCROLL ? SmoothScroll : window)
		.scrollTo(window.pageXOffset, LDRize.getPosition(_prev).y - LDRize.getScrollHeight());
	  LDRize.indicatorUpdate();
	  LDRize.naviUpdate();
  },

// v
  viewCurrent : function(type){
	  var url = LDRize.getLinkURL();
	  if(!url) return false;
	  if(type=='back'){
		  GM_openInTab(url);
		  LDRize.scrollNext();
	  }else if(type=='here'){
		  window.location.href = url;
	  }else{
		  window.open(url);
	  }
  },

// ?
  toggleHelpMessage : function(){
	  return (LDRize.hideHelpMessage() || LDRize.showHelpMessage());
  },
  hideHelpMessage : function(){
	  var help = document.getElementById('gm_ldrize_help');
	  if (!help) return false;
	  document.body.removeChild(LDRize.help);
	  return true;
  },
  showHelpMessage : function(){
	  document.body.appendChild(LDRize.help);
  },

// p
  attachPin : function(){
	  if(!LDRize.current_parapraph) LDRize.scrollNext();
	  var pos = LDRize.getPosition(LDRize.current_parapraph);
	  
	  var test = function(e){return e[0] == pos.str};
	  var res = LDRize.pin_list.find(test);
	  if(res){
		  LDRize.removePinFromPinList(LDRize.current_parapraph);
		  LDRize.pin_list = LDRize.pin_list.remove(test);
	  }else{
		  LDRize.addPinToPinList(LDRize.current_parapraph);
		  LDRize.pin_list.push([pos.str, LDRize.current_parapraph]);
	  }
	  if(LDRize.pin_list.length)
		LDRize.pinlist_number.innerHTML =
		  ['<span>',
		   LDRize.pin_list.length,
		   '</span>item',
		   LDRize.pin_list.length==1 ?'':'s'].join('');
	  else LDRize.pinlist_number.innerHTML = '';
	  
	  LDRize.pinlist.style.display = LDRize.pinlist_number.innerHTML=='' ? 'none' : 'block';
	  LDRize.toggleClassForPin(LDRize.current_parapraph);
	  LDRize.scrollNext();
  },
  pinIsEmpty : function(){return !LDRize.pin_list.length},
  getPinnedItems : function(){return LDRize.pin_list.map(function(e){return e[1]})},
  getPinnedItemsOrCurrentItem : function(){return LDRize.pinIsEmpty() ? [LDRize.current_parapraph] : LDRize.getPinnedItems()},

// o
  openPinned : function(){
	  var list = LDRize.getPinnedItemsOrCurrentItem();
	  list.forEach(function(node){
		  var url = LDRize.getLinkURL(node);
		  if (url) GM_openInTab(url);
	  });
	  if(LDRize.pinIsEmpty()) LDRize.scrollNext();
	  LDRize.clearPinlist();
  },

// f
  focusOnSearch : function(){
	  var xpath = LDRize.getSiteinfo()['focus'] || '//input[@type="text" or not(@type)]';
	  var lst = $X(xpath);
	  if(!lst.length) return;
	  var elm = lst[0];
	  elm.addEventListener('keypress', function(event){
		  var keycode = event.which;
		  var key = String.fromCharCode(keycode).toLowerCase();
		  key=(event.shiftKey)? "S-"+key : key;
		  key=(event.ctrlKey)? "C-"+key : key;
		  key=(event.altKey || event.metaKey)? "A-"+key : key;
		  if(key == 'C-[' || event.keyCode == 27) {
			  this.value = '';
			  this.blur();
		  }
	  }, true);
	  elm.focus();
	  window.scrollTo(window.pageXOffset, LDRize.getPosition(elm).y - LDRize.getScrollHeight());
	  return true;
  },

// :
  showMinibuffer : function() {
	  if(!window.Minibuffer) return;
	  document.removeEventListener('keypress', LDRize.handleKey, true);
	  var obj = {};
	  for (x in LDRize.command) obj[x] = LDRize.minibufferCallback;
	  window.Minibuffer.complete(obj, LDRize.minibufferCallbackExit, LDRize.PROMPT);
  },
  minibufferCallback : function(string, args, obj) {
	  var lst = LDRize.getPinnedItemsOrCurrentItem();
	  obj = obj || {
		paragraphes : lst,
		links: lst.map(LDRize.getLinkURL),
	  }
		obj.args = args;

	  var continuePinList = LDRize.command[string](obj); // do command
	  if(!continuePinList) LDRize.clearPinlist();
	  return continuePinList;
  },
  minibufferCallbackExit : function(){
	  document.addEventListener('keypress', LDRize.handleKey, true);
  },
	
// s
  changeSiteinfo : function(){
	  var lst = LDRize.getSiteinfoList();
	  var obj = {};
	  var current = LDRize.getSiteinfo()['name'];
	  var num = 0;
	  lst.forEach(function(e){
		  if(e['name'] && e['name'] != current) {
			  obj[e['name']] = LDRize.setSiteinfo;
			  num++;
		  }
	  });
	  if(num){
		  document.removeEventListener('keypress', LDRize.handleKey, true);
		  window.Minibuffer.complete(obj, LDRize.minibufferCallbackExit, '['+LDRize.getSiteinfo()['name']+'] :');
	  }
  },
}

var SiteInfo = {

  CACHE_EXPIRE : 24 * 60 * 60 * 1000,
  cacheInfo : {},
  getCache : function() {
	  return eval(GM_getValue('cacheInfo')) || {}
  },
  clearCache : function() {
	  GM_setValue('cacheInfo', '');
  },

  getCacheErrorCallback : function(url) {
	  if (SiteInfo.cacheInfo[url]) {
		  SiteInfo.cacheInfo[url].expire = new Date(new Date().getTime() + CACHE_EXPIRE);
		  GM_setValue('cacheInfo', SiteInfo.cacheInfo.toSource());
		  launchAutoPager(SiteInfo.cacheInfo[url].info);
	  }
  },
  propertyIsValid: function(property){
	  for(var i=0; i<LDRize.info_property.length; i++)
		if(LDRize.info_property[i]==property)
		  return true;
	  return false;
  },
  trim : function(t){return t.replace(/^\s+/,'').replace(/,$/,'').replace(/^\'/,'').replace(/\'$/,'');},
  getCacheCallback : function(res, url){
	  if (res.status != 200) return getCacheErrorCallback(url);
	  var content = new RegExp();
	  content.compile("^ ([^:]+):(.+)");
	  var sep = new RegExp();
	  sep.compile("^[^ ].+");
	  var lines = res.responseText.split("\n");
	  var info = [];
	  var current_info;

	  for(var i=0; i<lines.length; i++){
		  if(lines[i].match(sep)){
			  current_info = {};
			  info.push(current_info);
		  }else if(lines[i].match(content)){
			  var property = RegExp.$1;
			  var val = SiteInfo.trim(RegExp.$2).replace(/\\\\/g,'\\');
			  if(val.toLowerCase() == 'true' || val.toLowerCase() == 'false') val = eval(val);
			  if(SiteInfo.propertyIsValid(property)) current_info[property] = val;
		  }
	  }
	  if(info.length){
		  SiteInfo.cacheInfo[url] = {
			url: url,
			expire: new Date(new Date().getTime() + SiteInfo.CACHE_EXPIRE),
			info: info
		  }
		  GM_setValue('cacheInfo', SiteInfo.cacheInfo.toSource());
		  LDRize.SITEINFO = LDRize.SITEINFO.concat(SiteInfo.cacheInfo[url].info);
		  LDRize.init();
	  }
  },

  init : function(){
	  if(window.Minibuffer)
		window.Minibuffer.addCommand({
			'LDRize::clear-cache': SiteInfo.clearCache,
		});
	  GM_registerMenuCommand("LDRize - clear cache", SiteInfo.clearCache);
	  SiteInfo.cacheInfo = SiteInfo.getCache();
	  LDRize.SITEINFO_IMPORT_URLS.forEach(function(i) {
		  if(!SiteInfo.cacheInfo[i] || SiteInfo.cacheInfo[i].expire < new Date()){
			  var opt = {
				method: 'get',
				url: i,
				onload: function(res) {SiteInfo.getCacheCallback(res, i)},
				onerror: function(res){SiteInfo.getCacheErrorCallback(i)},
			  };
			  // log("fetch: " + i);
			  GM_xmlhttpRequest(opt);
		  }else{
			  LDRize.SITEINFO = LDRize.SITEINFO.concat(SiteInfo.cacheInfo[i].info);
			  LDRize.init();
		  }
	  });
  },
}

var getdiv = function(children){
	var div = document.createElement('div');
	children.forEach(function(child){if(child) div.appendChild(typeof(child) == 'string' ? document.createTextNode(child): child)});
	return div;
}
var getspan = function(children){
	var span = document.createElement('span');
	children.forEach(function(child){if(child) span.appendChild(typeof(child) == 'string' ? document.createTextNode(child): child)});
	return span;
}


Array.prototype.position = function(obj){
	var test;
	if(typeof(obj) == 'function') test = obj
	else test = function(a){return a == obj}
	
	for(var i=0;i<this.length; i++) if(test(this[i])) return i;
	return false;
}
Array.prototype.find = function(obj){
	var test;
	if(typeof(obj) == 'function') test = obj
	else test = function(a){return a == obj}
	
	for(var i=0;i<this.length; i++) if(test(this[i])) return this[i];
	return false;
}
Array.prototype.remove = function(obj){
	var res = [];
	var test;
	if(typeof(obj) == 'function') test = obj
	else test = function(a){return a == obj}
	
	for(var i=0;i<this.length; i++) if(!test(this[i])) res.push(this[i]);
	return res;
}
Number.prototype.odd = function() {
	return this % 2 == 1;
}

function log(message) {
	if(unsafeWindow && unsafeWindow.console) {
		unsafeWindow.console.log(message);
	}
}

var SmoothScroll = {
  steps : 200,
  duration : 6000,
  destinationx: null,
  destinationy: null,
  id_list : [],
  stop : function(){
	  if(SmoothScroll.id_list.length){
		  SmoothScroll.clearTimer();
		  if(SmoothScroll.destinationx || SmoothScroll.destinationy)
			SmoothScroll.makeScrollTo(SmoothScroll.destinationx, SmoothScroll.destinationy).call();
	  }
	  SmoothScroll.resetDestination()
	},
  resetDestination : function(){
	  SmoothScroll.destinationx = null;
	  SmoothScroll.destinationy = null;
  },
  scrollTo : function(destX, destY){
	  SmoothScroll.destinationx = destX;
	  SmoothScroll.destinationy = destY;
	  var y = window.pageYOffset;
	  for(var i=1; i<SmoothScroll.steps; i++){
		  if(destY==y) break;
		  y = destY-((destY-y)/2);
		  if(Math.abs(destY-y)<1 || i+1 == SmoothScroll.steps ) {
			  var id = setTimeout(SmoothScroll.makeScrollTo(destX, destY),
								  (SmoothScroll.duration/SmoothScroll.steps) * i);
			  var id2 = setTimeout(SmoothScroll.resetDestination,
								   (SmoothScroll.duration/SmoothScroll.steps) * i);
			  SmoothScroll.id_list.push(id);
			  SmoothScroll.id_list.push(id2);
			  break;
		  }else{
			  var id = setTimeout(SmoothScroll.makeScrollTo(destX, y),
								  (SmoothScroll.duration/SmoothScroll.steps) * i);
			  SmoothScroll.id_list.push(id);
		  }
	  }
  },
  clearTimer : function(){
	  SmoothScroll.id_list.forEach(function(id){
		  clearTimeout(id)
		});
	  SmoothScroll.id_list = [];
  },
  makeScrollTo: function (x,y){
	  return function(){
		  window.scrollTo(x, y);
	  }
  },
}

function $X(exp, context) {
	if (!context) context = document;
	var resolver = function (prefix) {
		var o = document.createNSResolver(context)(prefix);
		return o ? o : (document.contentType == "text/html") ? "" : "http://www.w3.org/1999/xhtml";
	}
	var exp = document.createExpression(exp, resolver);
	var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
	switch (result.resultType) {
	  case XPathResult.STRING_TYPE : return result.stringValue;
	  case XPathResult.NUMBER_TYPE : return result.numberValue;
	  case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
	  case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
		  try{
			  result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		  }catch(e){
			  log(["error: ",e]);
		  }
		  var ret = [];
		  for (var i = 0, len = result.snapshotLength; i < len ; i++) {
			  ret.push(result.snapshotItem(i));
		  }
		  return ret;
	  }
	}
	return null;
}

if(document.body) SiteInfo.init();
