// ターゲットにイベントハンドラを関連付ける
function pushEventListener(target, event, listener, useCapture)
{
  if (target)
  {
    if (target.addEventListener)
      target.addEventListener(event, listener, useCapture);
    else
      if (target.attachEvent)
        target.attachEvent("on" + event, listener);
  }
  return;
}

// ターゲットからイベントハンドラを取り除く
function pullEventListener(target, event, listener, useCapture)
{
  if (target)
  {
    if (target.removeEventListener)
      target.removeEventListener(event, listener, useCapture);
    else
      if (target.detachEvent)
        target.detachEvent("on" + event, listener);
  }
  return;
}

// 名前を識別子として有効な名前に置換する
function canonicalizeIdentifier(name)
{
  var reserved;
  reserved = ["abstract", "boolean", "break", "byte", "case", "catch",
    "char", "class", "const", "continue", "debugger", "default",
    "delete", "do", "double", "else", "enum", "export", "extends",
    "false", "final", "finally", "float", "for", "function", "goto",
    "if", "implements", "import", "in", "instanceof", "int", "interface",
    "long", "native", "new", "null", "package", "private", "protected",
    "public", "return", "short", "static", "super", "switch",
    "synchronized", "this", "throw", "throws", "transient", "true",
    "try", "typeof", "var", "void", "volatile", "while", "with"];
  name = String(name).replace(/[^0-9_a-z]/ig, "_");
  if (!name.length || name.match(/^[0-9]/) || arrayIndexOf(reserved, name) >= 0)
    name = "_" + name;
  return name;
}

// ターゲットにオブジェクトを関連付ける
function putUserData(target, key, data, handler)
{
  if (target)
  {
    key = canonicalizeIdentifier(key);
    if (data === null || typeof data == "undefined")
      delete target["m_" + key];
    else
      target["m_" + key] = data;
  }
  return;
}

// ターゲットからオブジェクトを取り出す
function takeUserData(target, key)
{
  key = canonicalizeIdentifier(key);
  if (target && ("m_" + key in target))
    return target["m_" + key];
  else
    return null;
}

// 値がオブジェクトかどうかを返す
function isObject(value)
{
  var t;
  t = typeof value;
  return value != null && (t == "object" || t == "function");
}

// value が undefined でないかどうかを返す
function isSet(value)
{
  return typeof value != "undefined";
}

// source オブジェクトの属性を destination にコピーする (浅いコピー)
function copyObjectProperies(source, destination, names)
{
  var i;
  if (isObject(source) && isObject(destination))
  {
    if (isObject(names))
      for (i = 0; i < names.length; ++i)
      {
        if ((typeof names[i] == "string" || typeof names[i] == "number") &&
            isSet(source[names[i]]))
          destination[names[i]] = source[names[i]];
      }
    else
    {
      if ((typeof names == "string" || typeof names == "number") &&
          isSet(source[names]))
        destination[names] = source[names];
    }
  }
  return;
}

// 配列の先頭から item に一致するものをがあればその序数を返す
function arrayIndexOf(array, item)
{
  var a, i, index;
  if (isObject(array))
    for (i = 0; i < array.length; ++i)
    {
      if (array[i] == item)
        return i;
    }
  return -1;
}

// 配列の末尾に要素を加える
function arrayPush(array, item)
{
  var i;
  if (isObject(array))
    for (i = 1; i < arguments.length; ++i)
      array[array.length] = arguments[i];
  return;
}

// element.className に token が含まれているかどうかを調べる
function classContains(element, token)
{
  var a;
  if (isObject(element) && typeof element.className == "string")
  {
    a = element.className.split(/[, ]+/);
    if (arrayIndexOf(a, token) >= 0)
      return true;
  }
  return false;
}

// element.className に token を追加する。
function classAdd(element, token)
{
  var a;
  if (isObject(element) && typeof element.className == "string")
  {
    a = element.className.split(/[, ]+/);
    if (arrayIndexOf(a, token) < 0)
      element.className += " " + String(token);
  }
  return;
}

// element.className に token を削除する。
function classRemove(element, token)
{
  var a, i;
  if (isObject(element) && typeof element.className == "string")
  {
    a = element.className.split(/[, ]+/);
    i = arrayIndexOf(a, token);
    if (i >= 0)
    {
      delete a[i];
      element.className = a.join(" ");
    }
  }
  return;
}

// HTML と特殊文字を実体参照に置換する
function replaceEntities(str)
{
  str = str.replace(/&/g, '&amp;');
  str = str.replace(/</g, '&lt;');
  str = str.replace(/>/g, '&gt;');
  str = str.replace(/"/g, '&quot;');
  return str;
}

// 文字列の前後のスペースを取り除く
function trim(str)
{
  str = String(str);
  str = str.replace(/^[\x00\t\n\x0B\r ]+/, "");
  str = str.replace(/[\x00\t\n\x0B\r ]+$/, "");
  return str;
}

// str1, str2, ... を separator で区切って連結する
function trimConnect(separator, str1)
{
  var a, i, str;
  a = [];
  for (i = 1; i < arguments.length; ++i)
  {
    str = trim(arguments[i]);
    if (str.length)
      arrayPush(a, str);
  }
  return a.join(separator);
}

// <INPUT> 要素を作成する
function createInputElement(owner, type, name)
{
  var input;
  input = null;
  if (owner && owner.createElement)
  {
    if (owner.all)
    {
      input = owner.createElement('<INPUT TYPE="' + replaceEntities(type) +
          '" ' + (name ? 'NAME="' + replaceEntities(name) + '" ' : '') +
          '>');
    }
    else
      if ((input = owner.createElement("INPUT")))
      {
        input.type = type;
        name && (input.name = name);
      }
  }
  return input;
}

// classList に含まれる要素のうち classToken が含まれるものを抽出し、配列として返す
function snapElementsByClassName(nodeList, classToken)
{
  var a, e, i;
  a = [];
  if (isObject(nodeList) && nodeList.item)
  {
    for (i = 0; i < nodeList.length; ++i)
    {
      if ((e = nodeList[i]) && e.nodeType == 1 &&
          (!classToken || classContains(e, classToken)))
      {
        arrayPush(a, e);
      }
    }
  }
  return a;
}

// parent の卑属の要素のうち、className が一致するものを抽出し、配列として返す。
function snapElementsByTagName(parent, tagName, classToken)
{
  var a, es, e, i;
  a = [];
  if (isObject(parent) && parent.getElementsByTagName &&
      (es = parent.getElementsByTagName(tagName)) && es.item)
  {
    if (classToken)
      a = snapElementsByClassName(es, classToken);
    else
    {
      for (i = 0; i < es.length; ++i)
        if ((e = es.item(i)))
          arrayPush(a, e);
    }
  }
  return a;
}

// element に含まれるテキストを返す
function getContentText(element)
{
  var text, i, child;
  text = "";
  if (isObject(element))
  {
    // element
    if (element.nodeType == 1)
    {
      if (element.childNodes)
        for (i = 0; i < element.childNodes.length; ++i)
          if ((child = element.childNodes.item(i)))
            text += getContentText(child);
    }
    else
      if (element.nodeType == 3)
        text = element.nodeValue;
  }
  return text;
}

// 指定されたノードまたはその尊属について tagName と一致する要素を返す
function getAncestorElement(node, tagName)
{
  if (isObject(node) && node.nodeType == 1)
  {
    if (tagName == "*" || String(node.nodeName).toUpperCase() == String(tagName))
      return node;
    else
      return getAncestorElement(node.parentNode, tagName);
  }
  return null;
}

// 要素に含まれるすべての子を削除する
function removeAllChildren(element)
{
  var i, child;
  if (isObject(element) && element.removeChild && element.childNodes &&
      element.childNodes.item)
    for (i = element.childNodes.length - 1; i >= 0; i--)
      if ((child = element.childNodes.item(i)) && element.removeChild)
        element.removeChild(child);
  return;
}

// 特定のリンクをボタンに置き換える
function linkButtonLoad(evt)
{
  var doc, a1, a, b, i, id;
  if ((doc = document) && (a1 = snapElementsByTagName(doc, "A", "button")))
  {
    for (i = 0; i < a1.length; ++i)
    {
      if ((a = a1[i]) && a.parentNode && a.parentNode.replaceChild &&
          (b = createInputElement(doc, "BUTTON", a.Name)))
      {
        copyObjectProperies(a, b, ["accessKey", "className", "tabIndex"]);
        b.value = getContentText(a);
        putUserData(b, "href", a.href, null);
        putUserData(b, "target", a.target, null);
        a.parentNode.replaceChild(b, a);
        if (a.id)
          b.id = a.id;
        pushEventListener(b, "click", linkButtonClick, false);
      }
    }
  }
  return;
}

// 置き換えたボタンがクリックされたときの動作
function linkButtonClick(evt)
{
  var b, href, target;
  if ((evt || (evt = window.event)) &&
      (b = getAncestorElement(evt.target || evt.srcElement, "INPUT")))
  {
    href   = takeUserData(b, "href");
    target = takeUserData(b, "target")
    if ((!target || !window.open || !window.open(href, target)) &&
        document.location)
      document.location.href = href;
  }
  return;
}

// 指定された要素がキーボードフォーカスを持つかどうかをテストする
function hasFocus(element)
{
  var doc;
  if (element && (doc = element.document || element.ownerDocument))
    return element == doc.activeElement;
  else
    return false;
}

// 検索ボックスの背景を設定する
function searchFormKeywordLoad(evt)
{
  var ks, i, k;
  if ((ks = snapElementsByTagName(document, "INPUT", "search-form-keyword")))
  {
    for (i = 0; i < ks.length; ++i)
      if ((k = ks[i]))
      {
        pushEventListener(k, "focus", searchFormKeywordFocus, false);
        pushEventListener(k, "blur", searchFormKeywordFocus, false);
        if (!hasFocus(k) && k.value == "")
          classAdd(k, "no-value-no-focus");
      }
  }
  return;
}

// 検索ボックスの背景の状態を切り替える
function searchFormKeywordFocus(evt)
{
  var k;
  if ((evt || (evt = window.event)) &&
      (k = getAncestorElement(evt.target || evt.srcElement, "INPUT")))
  {
    if (String(evt.type).toUpperCase() == "BLUR" && k.value == "")
      classAdd(k, "no-value-no-focus");
    else
      classRemove(k, "no-value-no-focus");
  }
  return;
}

// 必須項目を含むフォームを探す
function essentialLoad(evt)
{
  var doc, i, j, f, e, es, type;
  if ((doc = document) && doc.forms && doc.forms.item)
  {
    for (i = 0; i < doc.forms.length; ++i)
      if ((f = doc.forms.item(i)) &&
          (es = snapElementsByClassName(f.elements, "essential")))
      {
        for (j = 0; j < es.length; ++j)
          if ((e = es[j]))
          {
            type = String(e.type).toUpperCase();
            if (type == "SUBMIT" || type == "IMAGE")
            {
              pushEventListener(e, "click", essentialSubmitClick, false);
            }
          }
      }
  }
  return;
}

// 必須項目を含むフォームが送信されるときに、入力内容が埋まっているかどうかテストする
function essentialSubmitClick(evt)
{
  var f, empties, es, i, e, type, value, flag, j, o, mail, passwd, passwd2;
  if ((evt || (evt = window.event)) &&
      (f = getAncestorElement(evt.target || evt.srcElement, "FORM")))
  {
    mail = null;
    empties = [];
    es = snapElementsByClassName(f.elements, "essential");
    for (i = 0; i < es.length; ++i)
      if ((e = es[i]) && e.name && !e.disabled)
      {
        type = String(e.type).toUpperCase();
        if (type == "TEXT" || type == "PASSWORD" || type == "TEXTAREA")
        {
          if (!e.readOnly)
          {
            value = trim(e.value);
            if (!value.length)
              arrayPush(empties, e);
            if (e.name == "mail")
              mail = e;
            else if (e.name == "passwd")
              passwd = e;
            else if (e.name == "passwd2")
              passwd2 = e;
          }
        }
        else
        {
          if (type == "SELECT-ONE")
          {
            if (e.options &&
                (e.options.length > 0 && e.selectedIndex < 0 ||
                 e.options.length > 1 && e.selectedIndex < 1))
              arrayPush(empties, e);
          }
          else
            if (type == "SELECT-MULTIPLE")
            {
               if ((flag = e.options && e.options.item && e.options.length > 0))
                 for (j = 0; j < e.options.length; ++j)
                   if ((o = e.options.item(j)) && o.selected)
                   {
                     flag = 0;
                     break;
                   }
               if (flag)
               {
                 arrayPush(empties, e);
               }
            }
        }
      }
    if (empties.length)
    {
      alertEmptyMessage(empties);
      callPreventDefault(evt);
    }
    else
    {
      // パスワードの確認入力があるときはメールアドレスをチェックする
      if (mail && (passwd && passwd2 || classContains(mail, "check-mail")) &&
          checkInputMail(mail))
        callPreventDefault(evt);
      else if (passwd && passwd2 && passwd.value != passwd2.value)
      {
        alert("パスワードの確認入力にはパスワードと同じ文字列を入力してください。");
        callPreventDefault(evt);
      }
    }
  }
  return;
}

// メールの登録の際のチェック
// OK なら false, 中止なら true を返す
function checkInputMail(input)
{
  switch (isNotGoodMailAddress(input.value))
  {
    case 1:
      alert("指定されたメールアドレスの書式が正しくありません。\n" +
            "メールアドレスを複数指定したり、グループを指定したりすることはできません。\n" +
            "メールアドレスを < > で囲んだり、コメントなどの余計なものを含めないでください。\n" +
            "@ より前の部分がドット区切りのトークンにならないときは @ より前の部分を \" \" で囲んでください。\n" +
            "それ以外の場合には \" \" で囲まないでください。");
      return true;
    case 2:
    case 3:
      alert("指定されたメールアドレスのドメインが正しくありません。\n" +
            "登録可能なトップレベルドメインのリストにない名前か、登録禁止のドメインのリストにある名前か、\n" +
            "または、割り当てされていない IP アドレスが指定されています。\n" +
            "名前の代わりに IP アドレスを指定する場合は [ ] で囲んでください。\n" +
            "IP アドレスリテラルは 4 つの 10 進数で表した IPv4 アドレスのみを指定できます。");
      return true;
    case 4:
      return !confirm("指定されたメールアドレスのドメインに登録間違いの可能性が高い名前が指定されています。\n" +
                      "これは必ずしも間違いであるという意味ではありません。\n" +
                      "「.ne.jp」と「.co.jp」などの区別が間違っていないか、再度お確かめください。\n" +
                      "問題なければ OK を、入力を訂正するにはキャンセルを押してください。");
    case 5:
      alert("指定されたメールアドレスのドメインは、メールが届かないトラブルが多く報告されています。\n" +
            "他のドメインのメールアドレスでご登録されることをおすすめします。\n" +
            "他のドメインのメールアドレスがご利用いただけない場合は、このメールアドレスでご登録いただくことも\n" +
            "可能ですが、重要なメールが届かない可能性が高いことをあらかじめご了承ください。\n\n" +
            "フリーメールのプロバイダによっては、そのサービスにアクセスしない期間が続くとメールボックスが凍結\n" +
            "されることがあるようです。サービスにアクセスしてメールボックスが利用可能なことをお確かめください。");
      return !confirm("本当にこのメールアドレスで登録しますか?\n" +
                      "警告を無視して登録するには OK を、入力を変更するにはキャンセルを押してください。");
    default:
      return false;
  }
}

function callPreventDefault(evt)
{
  if (evt)
  {
    if (evt.preventDefault)
      evt.preventDefault();
    else
      evt.returnValue = false;
  }
  return;
}

// よろしくないメールアドレスを警告する
// 戻り値: 0 => 問題なし
//         1 => メールアドレスの書式が正しくない
//         2 => メールアドレスのドメインが正しくない (一般規則)
//         3 => メールアドレスのドメインが禁止
//         4 => メールアドレスのドメインが要注意
//         5 => できるだけ避けてほしいドメイン
function isNotGoodMailAddress(addr)
{
  var flag, at, l, d, q, i;
  flag = 1;
  addr = String(addr);
  if ((at = addr.lastIndexOf("@")) > 0)
  {
    l = trim(addr.substring(0, at));
    d = trim(addr.substring(at + 1));
    if (l.length > 0 && d.length > 0)
    {
      // ローカルパートの検査
      if (l.match(/^[!#-'*+\-\/0-9=?A-Z^-~]+(\.[!#-'*+\-\/0-9=?A-Z^-~]+)*$/) ||
          (q = l.match(/^"(.*)"$/)) &&
          q[1].match(/^([ !#-\[\]-~]+|\\["\\])+$/) &&
          !q[1].match(/^[!#-'*+\-\/0-9=?A-Z^-~]+(\.[!#-'*+\-\/0-9=?A-Z^-~]+)*$/))
      {
        flag = 2;
        // ドメインの検査
        if (d.match(/^[\-0-9a-z]+(\.[\-0-9a-z]+)*\.[a-z]+$/i))
        {
          q = d.toLowerCase().split(".");
          q = q.reverse();
          // トップレベルドメインのチェック (一般規則)
          if (checkTopLevelDomain(q))
          {
            // あとは厳密なチェックに任せる
            flag = isNotGoodMailAddressDomain(q);
          }
        }
        // ドメインの代わりにIPアドレスリテラルが指定されている
        else if ((q = d.match(/^\[([0-9]+(\.[0-9]+){3})\]$/)))
        {
          q = q[1].split(".");
          flag = 0;
          for (i = 0; i < 4; ++i)
          {
            q[i] = parseInt(q[i]);
            if (q[i] < 0 || q[i] > 255)
            {
              flag = 2;
              break;
            }
          }
          // 使用できないネットワーク
          if (flag == 0 && (
              q[0] == 0 || q[0] == 10 || q[0] == 127 ||
              q[0] == 169 && q[1] == 254 ||
              q[0] == 172 && q[1] >= 16 && q[1] <= 31 ||
              q[0] == 192 && (q[1] == 0 && (q[2] == 0 || q[2] == 2) ||
                              q[1] == 88 && q[2] == 99 || q[1] == 168) ||
              q[0] == 198 && q[1] == 51 && q[3] == 100 ||
              q[0] == 203 && q[1] == 0 && q[3] == 113 ||
              q[0] == 223 && q[1] == 255 && q[3] == 255 ||
              q[0] >= 224 && q[0] <= 255))
            flag = 2;
        }
      }
    }
  }
  return flag;
}

// トップレベルドメインのチェック
function checkTopLevelDomain(d)
{
  // 属性型・地域型JPドメイン
  var jp2s = ["ac", "ad", "aichi", "akita", "aomori", "chiba", "co", "ed",
      "ehime", "fukui", "fukuoka", "fukushima", "gifu", "go", "gr",
      "gunma", "hiroshima", "hokkaido", "hyogo", "ibaraki", "ishikawa",
      "iwate", "kagawa", "kagoshima", "kanagawa", "kawasaki",
      "kitakyushu", "kobe", "kochi", "kumamoto", "kyoto", "lg", "mie",
      "miyagi", "miyazaki", "nagano", "nagasaki", "nagoya", "nara", "ne",
      "niigata", "oita", "okayama", "okinawa", "or", "osaka", "saga",
      "saitama", "sapporo", "sendai", "shiga", "shimane", "shizuoka",
      "tochigi", "tokushima", "tokyo", "tottori", "toyama", "wakayama",
      "yamagata", "yamaguchi", "yamanashi", "yokohama"];
  // JP以外のトップレベルドメイン
  var tlds = ["ac", "ad", "ae", "aero", "af", "ag", "ai", "al", "am",
      "an", "ao", "aq", "ar", "as", "asia", "at", "au", "aw", "ax", "az",
      "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "biz", "bj", "bl",
      "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by", "bz", "ca",
      "cat", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn",
      "co", "com", "coop", "cr", "cu", "cv", "cx", "cy", "cz", "de", "dj",
      "dk", "dm", "do", "dz", "ec", "edu", "ee", "eg", "eh", "er", "es",
      "et", "eu", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gb", "gd",
      "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gov", "gp", "gq",
      "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht",
      "hu", "id", "ie", "il", "im", "in", "info", "int", "io", "iq", "ir",
      "is", "it", "je", "jm", "jo", "jobs", "ke", "kg", "kh", "ki", "km",
      "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk",
      "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mf",
      "mg", "mh", "mil", "mk", "ml", "mm", "mn", "mo", "mobi", "mp", "mq",
      "mr", "ms", "mt", "mu", "museum", "mv", "mw", "mx", "my", "mz",
      "na", "name", "nc", "ne", "net", "nf", "ng", "ni", "nl", "no", "np",
      "nr", "nu", "nz", "om", "org", "pa", "pe", "pf", "pg", "ph", "pk",
      "pl", "pm", "pn", "pr", "pro", "ps", "pt", "pw", "py", "qa", "re",
      "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh",
      "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "st", "sv", "sy",
      "sz", "tc", "td", "tel", "tf", "tg", "th", "tj", "tk", "tl", "tm",
      "tn", "to", "tp", "tr", "travel", "tt", "tv", "tw", "tz", "ua",
      "ug", "uk", "um", "us", "uy", "uz", "va", "vc", "ve", "vg", "vi",
      "vn", "vu", "wf", "ws", "ye", "yt", "za", "zm", "zw"];
  var i;
  if (d[0] == "jp")
  {
    for (i = 0; i < jp2s.length; ++i)
      if (jp2s[i] == d[1])
        return d.length >= 3;
    return d[1].length >= 3;
  }
  else
  {
    for (i = 0; i < tlds.length; ++i)
      if (tlds[i] == d[0])
        return true;
  }
  return false;
}

// ドメインがよろしくないかどうかチェックする
// 0 => OK, 3 => 禁止, 4 => 要注意, 5 => できるだけ避けてほしいドメイン
function isNotGoodMailAddressDomain(d)
{
  var flag, list, sub, i, j, k, a;
  sub = [];
  for (i = d.length; i > 1; --i)
  {
    a = d.slice(0, i);
    a = a.reverse();
    arrayPush(sub, a.join("."));
  }
  // 外部スクリプトからブラックリストを取り込んでチェックする
  if (typeof window.notGoodMailAddressList == "object")
    for (k = 3; k <= 5; ++k)
      if (typeof window.notGoodMailAddressList["list" + k] == "object")
      {
        list = window.notGoodMailAddressList["list" + k];
        for (i = 0; i < sub.length; ++i)
          for (j = 0; j < list.length; ++j)
            if (list[j] == sub[i])
              return k;
      }
  return 0;
}

// 入力内容が埋まっていない場合の警告表示
function alertEmptyMessage(empties)
{
  var messages, i, e, l, type, text, c;
  messages = [];
  for (i = 0; i < empties.length; ++i)
  {
    if ((e = empties[i]))
    {
      text = "";
      if ((l = searchElementLabel(e)))
        text = trim(getContentText(l)).replace(/ *:$/, "");
      if (!text)
        for (l = e.previousSibling; l; l = l.previousSibling)
          if (l.nodeType == 3)
          {
            text = trim(l.nodeValue).replace(/ *:$/, "");
            break;
          }
/*      if (!text)
        for (l = e.nextSibling; l; l = l.nextSibling)
          if (l.nodeType == 3)
          {
            (text = trim(l.nodeValue).replace(/ *:$/, ""));
            break;
          }*/
      if (!text)
      {
      label1:
        for (c = e.parentNode; c; c = c.parentNode)
        {
          type = String(c.nodeName).toUpperCase();
          if ((type == "TD" || type == "TH"))
          {
            for (l = c.previousSibling; l; l = l.previousSibling)
              if ((text = trim(getContentText(l)).replace(/ *:$/, "")))
                break label1;
            for (l = c.nextSibling; l; l = l.nextSibling)
              if ((text = trim(getContentText(l)).replace(/ *:$/, "")))
                break label1;
            break;
          }
        }
      }
      if (!text)
        text = e.name;

      type = String(e.type).toUpperCase();
      if (type == "SELECT-ONE" || type == "SELECT-MULTIPLE")
        arrayPush(messages, text + "が選択されていません。");
      else
        arrayPush(messages, text + "が入力されていません。");
    }
  }
  alert(messages.join("\n"));
  return;
}

// フォーム要素に対応するラベルを探す
function searchElementLabel(elementFor)
{
  var doc, ls, l, i;
  if (isObject(elementFor))
  {
    if (elementFor.id &&
        (doc = elementFor.ownerDocument || elementFor.document) &&
        doc.getElementsByTagName &&
        (ls = doc.getElementsByTagName("LABEL")) && ls.item)
    {
      for (i = 0; i < ls.length; ++i)
        if ((l = ls.item(i)) && l.htmlFor == elementFor.id)
          return l;
    }
    return getAncestorElement(elementFor.parentNode, "LABEL");
  }
  return null;
}

// マウスイベントの絶対座標を計算する
function getAbsolutePoint(evt, point)
{
  var p, doc;
  if (evt && point)
  {
    point.left = evt.clientX;
    point.top = evt.clientY;
    if ((p = evt.target || evt.srcElement) &&
        (doc = p.ownerDocument || p.document))
    {
      if (doc.documentElement &&  typeof doc.compatMode == "string" &&
          doc.compatMode != "BackCompat")
        p = doc.documentElement;
      else
        p = doc.body;
      if (p)
      {
        point.left += p.scrollLeft;
        point.top += p.scrollTop;
      }
      if (evt.srcElement)
      {
        point.left -= 2;
        point.top -= 2;
      }
    }
  }
  return;
}

// 要素の絶対座標を計算する
function getAbsoluteOrigin(element, point)
{
  var p;
  if (point)
  {
    point.left = point.top = 0;
    for (p = element; p; p = p.offsetParent)
    {
      point.left += p.offsetLeft;
      point.top  += p.offsetTop;
    }
  }
  return;
}

// XMLHttpRequest を使って GET 要求を送る
function sendHttpGetRequest(url, funcLoad, params)
{
  var req;
  req = null;
  if (typeof window.ActiveXObject == "function")
    req = new ActiveXObject("Microsoft.XMLHTTP");
  else if (window.XMLHttpRequest)
    req = new XMLHttpRequest();
  if (req)
  {
    req.open("GET", url, true);
    req.onreadystatechange = function()
    {
      if (req.readyState == 4)
        funcLoad(req, params);
      return;
    };
    req.send(null);
  }
  return req;
}

// select要素からすべてのoptionを取り除く
function removeAllOptionsFromSelect(select)
{
  var i;
  if (select && select.options && select.remove)
    for (i = select.options.length; i >= 0; --i)
      select.remove(i);
  return;
}

// 新しい option 要素を作成して、select の末尾に追加する
function addOptionToSelect(select, text, value)
{
  var doc, o;
  if (select && select.add &&
      (doc = select.ownerDocument || select.document) &&
      doc.createElement && (o = doc.createElement("OPTION")))
  {
    o.text = text;
    o.value = value || text;
    select.add(o, typeof window.ActiveXObject == "function" ? -1 : null);
  }
  return o;
}

// 指定された value を持つ option 要素を選択する
function selectOptionByValue(select, value)
{
  var i, o;
  if (select && select.options && select.options.item)
    for (i = 0; i < select.options.length; ++i)
      if ((o = select.options.item(i)) && o.value == value)
      {
        o.selected = true;
        break;
      }
  return;
}

function getSelectedOption(select)
{
  var i, o;
  o = null;
  if (select && select.options && select.options.item)
  {
    i = select.selectedIndex;
    if (i >= 0 && i < select.options.length)
      o = select.options.item(i);
  }
  return o;
}

// rc1 が rc2 と重なり合っているかどうかを返す
function isRectIntersect(rc1, rc2)
{
  return rc1 && rc2 &&
         (rc2.left >= rc1.left && rc2.left < rc1.right ||
          rc2.right >= rc1.left && rc2.right < rc1.right ||
          rc1.left >= rc2.left && rc1.left < rc2.right ||
          rc1.right >= rc2.left && rc1.right < rc2.right) &&
         (rc2.top >= rc1.top && rc2.top < rc1.bottom ||
          rc2.bottom >= rc1.top && rc2.bottom < rc1.bottom ||
          rc1.top >= rc2.top && rc1.top < rc2.bottom ||
          rc1.bottom >= rc2.top && rc1.bottom < rc2.bottom);
}

// 背後に隠れるべき select 要素を非表示にする
function hideBackSelectElements(front)
{
  var doc, ss, s, i, p, p1, p2;
  showBackSelectElements(front);
  if (front && front.currentStyle && (doc = front.document))
  {
    front.m_back_select = [];
    p1 = {left: 0, top: 0};
    getAbsoluteOrigin(front, p1);
    p1.right = p1.left + front.offsetWidth;
    p1.bottom = p1.top + front.offsetHeight;
    ss = snapElementsByTagName(doc, "SELECT");
label1:
    for (i = 0; i < ss.length; ++i)
    {
      if ((s = ss[i]) && s.currentStyle &&
          String(s.currentStyle.visibility).toUpperCase() != "HIDDEN")
      {
        for (p = s.parentNode; p; p = p.parentNode)
          if (p == front)
            break label1;
        p2 = {left: 0, top: 0};
        getAbsoluteOrigin(s, p2);
        p2.right = p2.left + s.offsetWidth;
        p2.bottom = p2.top + s.offsetHeight;
        if (isRectIntersect(p1, p2))
        {
          s.style.visibility = "hidden";
          arrayPush(front.m_back_select, s);
        }
      }
    }
  }
  return;
}

// 非表示にした select 要素を復活させる
function showBackSelectElements(front)
{
  var ss, s, i;
  if (front && (ss = front.m_back_select))
    for (i = 0; i < ss.length; ++i)
      if ((s = ss[i]))
        s.style.visibility = "visible";
  return;
}

// メニューの強調表示
function menuHighlightLoad(evt)
{
  var doc, ms, m, i, ls, l, j, aa, a, k;
  if ((doc = document) && (ms = snapElementsByTagName(doc, "DIV", "menu")))
  {
    for (i = 0; i < ms.length; ++i)
      if ((m = ms[i]) && (ls = snapElementsByTagName(m, "LI", null)))
      {
        for (j = 0; j < ls.length; ++j)
          if ((l = ls[j]))
          {
            pushEventListener(l, "mouseover", menuHighlightHover, false);
            pushEventListener(l, "mouseout", menuHighlightHover, false);
            if ((aa = snapElementsByTagName(l, "A", null)))
            {
              for (k = 0; k < aa.length; ++k)
                if ((a = aa[k]))
                {
                  putUserData(l, "a", a, null);
                  pushEventListener(a, "focus", menuHighlightHover, false);
                  pushEventListener(a, "blur", menuHighlightHover, false);
                }
            }
          }
      }
  }
  return;
}

// メニューの強調表示の切り替え
function menuHighlightHover(evt)
{
  var l, a, mouseIsIn;
  if ((evt || (evt = window.event)) &&
      (l = getAncestorElement(evt.target || evt.srcElement, "LI")))
  {
    a = takeUserData(l, "a");
    mouseIsIn = takeUserData(l, "mouseIsIn");
    switch (String(evt.type).toUpperCase())
    {
      case "FOCUS":
        menuHighlightToggle(l, true);
        break;
      case "BLUR":
        if (!mouseIsIn)
          menuHighlightToggle(l, false);
        break;
      case "MOUSEOVER":
        putUserData(l, "mouseIsIn", true, null);
        menuHighlightToggle(l, true);
        break;
      case "MOUSEOUT":
        putUserData(l, "mouseIsIn", false, null);
        if (!hasFocus(a))
          menuHighlightToggle(l, false);
    }
  }
  return;
}

// 実際に切り替える
function menuHighlightToggle(l, isHighligh)
{
  if (isHighligh)
    classAdd(l, "highlight");
  else
    classRemove(l, "highlight");
  return;
}

// NodeList::namedItem() のラッパー
function getNamedItem(nodeList, name)
{
  if (isObject(nodeList))
  {
    if (nodeList.namedItem)
      return nodeList.namedItem(name);
    else if (nodeList.item)
      return nodeList.item(name);
  }
  return null;
}

// HTMLFrom::elements のうち、その name が配列 names に含まれる要素を
// 探して、"m_" + name をキー、オブジェクトを値とするオブジェクトを
// 返す。
function findFormElements(form, names)
{
  var elements, element, i, key;
  elements = {};
  if (form && form.elements)
  {
    for (i = 0; i < names.length; ++i)
    {
      key = "m_" + canonicalizeIdentifier(names[i]);
      if ((element = getNamedItem(form.elements, names[i])))
        elements[key] = element;
    }
  }
  return elements;
}

function setTimeoutParam(func, ms, param)
{
  var timer;
  if (typeof func == "function")
  {
    timer = setTimeout(function() { return func(param); }, ms);
  }
  return timer;
}

function setIntervalParam(func, ms, param)
{
  var timer;
  if (typeof func == "function")
  {
    timer = setInterval(function() { return func(param); }, ms);
  }
  return timer;
}

// オブジェクトのプロパティを表示する (デバッグ用)
function objectToString(obj)
{
  var p, i;
  p = [];
  if (isObject(obj))
  {
    for (i in obj)
    {
      arrayPush(p, i + ": " + String(obj[i]).replace(/[\r\n]+/g, " "));
    }
    return p.join(",\n");
  }
  return String(obj);
}

// 情報バーの初期化
function infoBarLoad(evt)
{
  var doc, body, first, divs, div, i, buttons, button, j;
  if ((doc = document) && (body = doc.body) && body.insertBefore &&
      (divs = snapElementsByTagName(body, "DIV", "info-bar")))
  {
    first = body.firstChild;
    for (i = 0; i < divs.length; ++i)
      if ((div = divs[i]))
      {
        body.insertBefore(div, first);
        if ((buttons = snapElementsByTagName(div, "A", "info-bar-close")))
        {
          for (j = 0; j < buttons.length; ++j)
            if ((button = buttons[j]))
            {
              button.m_div = div;
              pushEventListener(button, "click", infoBarCloseClick, false);
            }
        }
      }
  }
  return;
}

// 情報バーの閉じるボタン
function infoBarCloseClick(evt)
{
  var button, div, parent;
  if ((evt || (evt = window.event)) &&
      (button = getAncestorElement(evt.target || evt.srcElement, "A")) &&
      (div = button.m_div) && (parent = div.parentNode) &&
      parent.removeChild && parent.removeChild(div))
  {
    if (evt.preventDefault)
      evt.preventDefault();
    else
      evt.returnValue = false;
  }
  return;
}

// ロールオーバー処理
function rollOverLoad(evt)
{
  var doc, aa, a, i, img, img2, m, new_src, point;
  if ((doc = document) && (aa = snapElementsByTagName(doc, "A", "bbs")))
    for (i = 0; i < aa.length; ++i)
      if ((a = aa[i]) && (img = a.getElementsByTagName("IMG")) &&
          (img = img[0]) && typeof img.src == "string" &&
          (m = img.src.match(/^(.*)(\.[^.]+)$/)))
      {
        point = {left: 0, top: 0};
        getAbsoluteOrigin(img, point);

        img2 = doc.createElement("IMG");
        img2.style.position = "absolute";
        img2.style.left = point.left + "px";
        img2.style.top = point.top + "px";
        img2.style.visibility = "hidden";
        a.appendChild(img2);
        img2.src = m[1] + "-over" + m[2];

        a["m_ro_img"] = img;
        a["m_ro_src_out"] = img.src;
        a["m_ro_src_over"] = img2.src;

        pushEventListener(a, "mouseover", rollOverMouseOver, false);
        pushEventListener(a, "mouseout", rollOverMouseOver, false);
      }
  return;
}

function rollOverMouseOver(evt)
{
  var a, img, key;
  if ((a = getAncestorElement(evt.target || evt.srcElement, "A")) &&
      (img = a["m_ro_img"]))
  {
    if (String(evt.type).toUpperCase() == "MOUSEOVER")
      key = "m_ro_src_over";
    else
      key = "m_ro_src_out";
    img.src = a[key];
  }
  return;
}

// 処理の開始
function scriptLoad(evt)
{
  linkButtonLoad(evt);
  searchFormKeywordLoad(evt);
  essentialLoad(evt);
  menuHighlightLoad(evt);
  rollOverLoad(evt);
  infoBarLoad(evt);
  return;
}

pushEventListener(this, "load", scriptLoad, false);
