function getParentNode(element, parentTagName, className) {
  if (parentTagName) parentTagName = parentTagName.toLowerCase()
  if (className) className = new RegExp('(^| )' + encodeRE(className) + '( |$)')
  while (element = element.parentNode) {
    if (parentTagName && (element.nodeName.toLowerCase() != parentTagName)) continue
    if (className && !className.test(element.className)) continue
    return element
  }
}

function getNextSibling(element, tagName) {
  tagName = tagName.toUpperCase()
  element = element.nextSibling
  while (element) {
    if (element.nodeName.toUpperCase() == tagName) {
      return element
    }
    element = element.nextSibling
  }
}

function getPreviousSibling(element, tagName) {
  tagName = tagName.toUpperCase()
  element = element.previousSibling
  while (element) {
    if (element.nodeName.toUpperCase() == tagName) {
      return element
    }
    element = element.previousSibling
  }
}

function encodeRE(s) {
  return s.replace(/([\^\$\.\*\?\+\{\}\(\)\[\]\/\|\\])/g, '\\$1')
}
function encodeJS(s) {
  return s.replace(/([\\'])/g, '\\$1').replace(/\r/g, '\\r').replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/[\x00-\x1f]/g, '')
}
function encodeHTML(value) {
  return String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\x22/g, '&quot;')
}
function trim(s) {
  return String(s).replace(/^\s+|\s+$/g, '')
}