歯車について勉強する3 の履歴(No.7)

更新


工作/歯車について勉強する

目次

歯車設計に必要なさまざまな計算を行います。

歯車を描く

LANG: p5js_live

内歯車について:

  • インボリュート曲線部分のみで歯形としているため歯数の少ない場合に歯底円まで届かない
  • フィレットは付けていない

はすば歯車計算(転位係数から中心間距離)

はすば歯車に転位係数を入力して中心間距離を求められます。

3Dプリンタを使う場合は目的の中心間距離に合わせて変則的なモジュールを選ぶことが可能なので、 「目標中心間距離」を入れて「調整後モジュール」を計算する機能も付けました。

基本的には KHK 小原歯車工業さんの 歯車技術資料 にある、
https://www.khkgears.co.jp/gear_technology/pdf/gijutu.pdf#page=23 の計算を行っています。

LANG:p5js_live
const { tan, cos, sin, PI, atan, abs } = Math

// ====================================================== ここからが設定

const titles = ["項目名", "記号", "計算式", "歯車1", "歯車2"]

const definitions = [
  // 入力
  ["mn", "歯垂直モジュール", "m_n", "", [3], 1],
  ["alphan", "歯直角圧力角", "\\alpha_n", "", [20], PI / 180],
  ["beta", "基準円筒ねじれ角", "\\beta", "", [30], PI / 180],
  ["z", "歯数", "z", "", [12, 60], 1],
  ["xn", "歯直角転位係数", "x_n", "", [0.09809, 0], 1], // 出力
  [
    "alphat",
    "正面圧力角",
    "\\alpha_t",
    "\\tan^{-1}\\Big(\\frac{\\tan\\alpha_n}{\\cos\\beta}\\Big)",
    ["?"],
    PI / 180,
  ],
  [
    "invawt",
    "インボリュートαwt",
    "\\mathrm{inv}\\,\\alpha_{wt}",
    "2\\tan\\alpha_n\\big(\\frac{x_{n1}+x_{n2}}{z_1+z_2}\\big)+\\mathrm{inv}\\,\\alpha_t",
    ["?"],
    1,
  ],
  [
    "alphawt",
    "正面噛み合い圧力角",
    "\\alpha_{wt}",
    "\\mathrm{inv}^{-1}\\,(\\mathrm{inv}\\,\\alpha_{wt})",
    ["?"],
    PI / 180,
  ],
  [
    "y",
    "中心距離修正係数",
    "y",
    "\\frac{z_1+z_2}{2\\cos\\beta}\\Big(\\frac{\\cos\\alpha_t}{\\cos\\alpha_{wt}}-1\\Big)",
    ["?"],
    1,
  ],
  [
    "a",
    "中心距離",
    "a",
    "\\Big(\\frac{z_1+z_2}{2\\cos\\beta}+y\\Big)m_n",
    ["?"],
    1,
  ],
  ["d", "基準円直径", "d", "\\frac{zm_n}{\\cos\\beta}", ["?", "?"], 1],
  ["db", "基礎円直径", "d_b", "d\\cos\\alpha_t", ["?", "?"], 1],
  [
    "dw",
    "噛合ピッチ円直径",
    "d_w",
    "\\frac{d_b}{\\cos\\alpha_{wt}}",
    ["?", "?"],
    1,
  ],
  [
    "ha",
    "歯末の丈",
    "h_a",
    "\\begin{aligned}h_{a1}=(1+y-x_{n2})m_n\\\\h_{a2}=(1+y-x_{n1})m_n\\end{aligned}",
    ["?", "?"],
    1,
  ],
  ["h", "歯丈", "h", "\\{2.25+y-(x_{n1}+x_{n2})\\}m_n", ["?"], 1],
  ["da", "歯先円直径", "d_a", "d+2h_a", ["?", "?"], 1],
  ["df", "歯底円直径", "d_f", "d_a-2h", ["?", "?"], 1],
  ["ad", "目標中心距離", "a_d", "", [130], 1],
  ["mm", "調整後モジュール", "m_m", "m_n a_d / a", ["?"], 1],
]

function recalc() {
  const c = controls
  c.alphat = atan(tan(c.alphan) / cos(c.beta))
  c.invawt =
    (2 * tan(c.alphan) * (c.xn1 + c.xn2)) / (c.z1 + c.z2) + inv(c.alphat)
  c.alphawt = inverse_inv(c.invawt)
  c.y =
    ((c.z1 + c.z2) / (2 * cos(c.beta))) * (cos(c.alphat) / cos(c.alphawt) - 1)
  c.a = ((c.z1 + c.z2) / (2 * cos(c.beta)) + c.y) * c.mn
  c.d1 = (c.z1 * c.mn) / cos(c.beta)
  c.d2 = (c.z2 * c.mn) / cos(c.beta)
  c.db1 = c.d1 * cos(c.alphat)
  c.db2 = c.d2 * cos(c.alphat)
  c.dw1 = c.db1 / cos(c.alphawt)
  c.dw2 = c.db2 / cos(c.alphawt)
  c.ha1 = (1 + c.y - c.xn2) * c.mn
  c.ha2 = (1 + c.y - c.xn1) * c.mn
  c.h = (2.25 + c.y - (c.xn1 + c.xn2)) * c.mn
  c.da1 = c.d1 + 2 * c.ha1
  c.da2 = c.d2 + 2 * c.ha2
  c.df1 = c.da1 - 2 * c.h
  c.df2 = c.da2 - 2 * c.h
  c.mm = (c.mn * c.ad) / c.a
}

// インボリュート関数
function inv(x) {
  return tan(x) - x
}

// インボリュート関数の逆関数
function inverse_inv(inva) {
  if (inva == 0) return 0
  if (inva < 0 || 20 < inva) return NaN
  let a = inva < 2.4 ? 1.441 * inva ** (1 / 3) - 0.374 * inva : 1.48
  let a_prev = 2
  for (;;) {
    const tana = tan(a)
    a += (inva - tana + a) / tana ** 2
    if (abs(a_prev - a) < 1e-15) return a
    a_prev = a
  }
}

// UI の値を読み書きするためのオブジェクト
let controls = {}

// HTML 要素を生成するための関数
function elem(tag, html = "", children = [], props = {}, events = {}) {
  const result = document.createElement(tag)
  if (html != "") result.innerHTML = html
  children.forEach((c) => result.appendChild(c))
  Object.entries(props).forEach(([k, v]) => {
    if (typeof v == "string") {
      result[k] = v
    } else {
      Object.entries(v).forEach(([k2, v2]) => (result[k][k2] = v2))
    }
  })
  Object.entries(events).forEach(([k, v]) => result.addEventListener(k, v))
  return result
}

function katex2html(s) {
  return katex.renderToString(s, { throwOnError: false })
}

function definition2html(def) {
  const [name, label, notation, expression, values, scale] = def
  const createControl = (n, v) => {
    let e
    if (expression != "") {
      e = elem("SPAN", v)
      Object.defineProperty(controls, name + n, {
        get: () => e.innerHTML * scale,
        set: (v) => (e.innerHTML = (v / scale).toPrecision(6)),
      })
    } else {
      e = elem(
        "INPUT",
        "",
        [],
        {
          value: String(v),
          style: {
            textAlign: "right",
            paddingRight: "0.2em",
            width: "4em",
          },
        },
        { change: recalc },
      )
      Object.defineProperty(controls, name + n, {
        get: () => e.value * scale,
        set: (v) => (e.value = (v / scale).toPrecision(6)),
      })
    }
    return e
  }
  const values2controls = () =>
    values.length == 1
      ? [
          elem("TD", "", [createControl("", values[0])], {
            colSpan: "2",
            style: { textAlign: "center" },
          }),
        ]
      : [
          elem("TD", "", [createControl("1", values[0])]),
          elem("TD", "", [createControl("2", values[1])]),
        ]
  const backgroundColor = expression != "" ? "#ffe" : "#eff"
  return elem(
    "TR",
    "",
    [
      elem("TD", label),
      elem("TD", katex2html(notation)),
      elem("TD", katex2html(expression)),
      ...values2controls(),
    ],
    { style: { backgroundColor } },
  )
}

function setup() {
  let table = elem(
    "TABLE",
    "",
    [
      elem("TBODY", "", [
        elem(
          "TR",
          "",
          titles.map((s) => elem("TH", s)),
        ),
        ...definitions.map(definition2html),
      ]),
    ],
    { border: "1", cellSpacing: "0", cellPadding: "2" },
  )

  // キャンバスを最小化する
  p.createCanvas(1, 1)
  // DIV を作ってテーブルを追加する
  p.createDiv().elt.appendChild(table)
  // 値を更新する
  recalc()
}

p.setup = setup

はすば歯車設計(中心間距離から転位量)

モジュール、歯数、ねじれ角と中心間距離を入れると、2つの歯車を合わせてどれだけ転位すればよいかを算出できる。

「歯直角転位係数和」を2つに分けてそれぞれの歯車に振り分けることになる。

KHK 小原歯車工業さんの 歯車技術資料 にある、
https://www.khkgears.co.jp/gear_technology/pdf/gijutu.pdf#page=24 の計算を行っている。

LANG: p5js_live
const { tan, cos, acos, PI, atan, abs } = Math

// ====================================================== ここからが設定

const titles = ["項目名", "記号", "計算式", "歯車1", "歯車2"]

const definitions = [
  // 入力
  ["mn", "歯垂直モジュール", "m_n", "", [3], 1],
  ["alphan", "歯直角圧力角", "\\alpha_n", "", [20], PI / 180],
  ["beta", "基準円筒ねじれ角", "\\beta", "", [30], PI / 180],
  ["z", "歯数", "z", "", [12, 60], 1],
  ["a", "中心距離", "a", "", [125], 1], // 出力
  [
    "alphat",
    "正面圧力角",
    "\\alpha_t",
    "\\tan^{-1}\\Big(\\frac{\\tan\\alpha_n}{\\cos\\beta}\\Big)",
    ["?"],
    PI / 180,
  ],
  [
    "y",
    "中心距離修正係数",
    "y",
    "\\frac{a}{m_n}-\\frac{z_1+z_2}{2\\cos\\beta}",
    ["?"],
    1,
  ],
  [
    "alphawt",
    "正面噛み合い圧力角",
    "\\alpha_{wt}",
    "\\cos^{-1}\\Big(\\frac{\\cos\\alpha_t}{\\frac{2y\\cos\\beta}{z_1+z_2}+1}\\Big)",
    ["?"],
    PI / 180,
  ],
  [
    "sumxn",
    "歯直角転位係数和",
    "x_{n1}+x_{n2}",
    "\\frac{(z_1+z_2)(\\mathrm{inv}\\,\\alpha_{wt}-\\mathrm{inv}\\,\\alpha_t)}{2\\tan\\alpha_n}",
    ["?"],
    1,
  ],
  [
    "sumxnmm",
    "転位の和 (距離)",
    "(x_{n1}+x_{n2})m_n",
    "(x_{n1}+x_{n2})m_n",
    ["?"],
    1,
  ],
]

function recalc() {
  const c = controls
  c.alphat = atan(tan(c.alphan) / cos(c.beta))
  c.y = c.a / c.mn - (c.z1 + c.z2) / (2 * cos(c.beta))
  c.alphawt = acos(
    cos(c.alphat) / ((2 * c.y * cos(c.beta)) / (c.z1 + c.z2) + 1),
  )
  c.sumxn =
    ((c.z1 + c.z2) * (inv(c.alphawt) - inv(c.alphat))) / (2 * tan(c.alphan))
  c.sumxnmm = c.sumxn * c.mn
}

// インボリュート関数
function inv(x) {
  return tan(x) - x
}

// インボリュート関数の逆関数
function inverse_inv(inva) {
  if (inva == 0) return 0
  if (inva < 0 || 20 < inva) return NaN
  let a = inva < 2.4 ? 1.441 * inva ** (1 / 3) - 0.374 * inva : 1.48
  let a_prev = 2
  for (;;) {
    const tana = tan(a)
    a += (inva - tana + a) / tana ** 2
    if (abs(a_prev - a) < 1e-15) return a
    a_prev = a
  }
}

// UI の値を読み書きするためのオブジェクト
let controls = {}

// HTML 要素を生成するための関数
function elem(tag, html = "", children = [], props = {}, events = {}) {
  const result = document.createElement(tag)
  if (html != "") result.innerHTML = html
  children.forEach((c) => result.appendChild(c))
  Object.entries(props).forEach(([k, v]) => {
    if (typeof v == "string") {
      result[k] = v
    } else {
      Object.entries(v).forEach(([k2, v2]) => (result[k][k2] = v2))
    }
  })
  Object.entries(events).forEach(([k, v]) => result.addEventListener(k, v))
  return result
}

function katex2html(s) {
  return katex.renderToString(s, { throwOnError: false })
}

function definition2html(def) {
  const [name, label, notation, expression, values, scale] = def
  const createControl = (n, v) => {
    let e
    if (expression != "") {
      e = elem("SPAN", v)
      Object.defineProperty(controls, name + n, {
        get: () => e.innerHTML * scale,
        set: (v) => (e.innerHTML = (v / scale).toPrecision(6)),
      })
    } else {
      e = elem(
        "INPUT",
        "",
        [],
        {
          value: String(v),
          style: {
            textAlign: "right",
            paddingRight: "0.2em",
            width: "4em",
          },
        },
        { change: recalc },
      )
      Object.defineProperty(controls, name + n, {
        get: () => e.value * scale,
        set: (v) => (e.value = (v / scale).toPrecision(6)),
      })
    }
    return e
  }
  const values2controls = () =>
    values.length == 1
      ? [
          elem("TD", "", [createControl("", values[0])], {
            colSpan: "2",
            style: { textAlign: "center" },
          }),
        ]
      : [
          elem("TD", "", [createControl("1", values[0])]),
          elem("TD", "", [createControl("2", values[1])]),
        ]
  const backgroundColor = expression != "" ? "#ffe" : "#eff"
  return elem(
    "TR",
    "",
    [
      elem("TD", label),
      elem("TD", katex2html(notation)),
      elem("TD", katex2html(expression)),
      ...values2controls(),
    ],
    { style: { backgroundColor } },
  )
}

function setup() {
  let table = elem(
    "TABLE",
    "",
    [
      elem("TBODY", "", [
        elem(
          "TR",
          "",
          titles.map((s) => elem("TH", s)),
        ),
        ...definitions.map(definition2html),
      ]),
    ],
    { border: "1", cellSpacing: "0", cellPadding: "2" },
  )

  // キャンバスを最小化する
  p.createCanvas(1, 1)
  // DIV を作ってテーブルを追加する
  p.createDiv().elt.appendChild(table)
  // 値を更新する
  recalc()
}

p.setup = setup

はすば内歯車計算(転位係数から中心間距離)

https://www.khkgears.co.jp/gear_technology/pdf/gijutu.pdf#page=19 の計算をします。

LANG: p5js_live
const { tan, cos, sin, PI, atan, abs } = Math

// ====================================================== ここからが設定

const titles = ["項目名", "記号", "計算式", "外歯車", "内歯車"]

const definitions = [
  // 入力
  ["mn", "歯垂直モジュール", "m_n", "", [3], 1],
  ["alphan", "歯直角圧力角", "\\alpha_n", "", [20], PI / 180],
  ["beta", "基準円筒ねじれ角", "\\beta", "", [0], PI / 180],
  ["z", "歯数", "z", "", [16, 24], 1],
  ["xn", "歯直角転位係数", "x_n", "", [0, 0.516], 1], // 出力
  [
    "alphat",
    "正面圧力角",
    "\\alpha_t",
    "\\tan^{-1}\\Big(\\frac{\\tan\\alpha_n}{\\cos\\beta}\\Big)",
    ["?"],
    PI / 180,
  ],
  [
    "invawt",
    "インボリュートαwt",
    "\\mathrm{inv}\\,\\alpha_{wt}",
    "2\\tan\\alpha_n\\big(\\frac{x_{n2}-x_{n1}}{z_2-z_1}\\big)+\\mathrm{inv}\\,\\alpha_t",
    ["?"],
    1,
  ],
  [
    "alphawt",
    "正面噛み合い圧力角",
    "\\alpha_{wt}",
    "\\mathrm{inv}^{-1}\\,(\\mathrm{inv}\\,\\alpha_{wt})",
    ["?"],
    PI / 180,
  ],
  [
    "y",
    "中心距離修正係数",
    "y",
    "\\frac{z_2-z_1}{2\\cos\\beta}\\Big(\\frac{\\cos\\alpha_t}{\\cos\\alpha_{wt}}-1\\Big)",
    ["?"],
    1,
  ],
  [
    "a",
    "中心距離",
    "a",
    "\\Big(\\frac{z_2-z_1}{2\\cos\\beta}+y\\Big)m_n",
    ["?"],
    1,
  ],
  ["d", "基準円直径", "d", "\\frac{zm_n}{\\cos\\beta}", ["?", "?"], 1],
  ["db", "基礎円直径", "d_b", "d\\cos\\alpha_t", ["?", "?"], 1],
  [
    "dw",
    "噛合ピッチ円直径",
    "d_w",
    "\\frac{d_b}{\\cos\\alpha_{wt}}",
    ["?", "?"],
    1,
  ],
  [
    "ha",
    "歯末の丈",
    "h_a",
    "\\begin{aligned}h_{a1}=(1+x_{n1})m_n\\\\h_{a2}=(1-x_{n2})m_n\\end{aligned}",
    ["?", "?"],
    1,
  ],
  ["h", "歯丈", "h", "2.25m_n", ["?"], 1],
  [
    "da",
    "歯先円直径",
    "d_a",
    "\\begin{aligned}d_{a1}: d_1+2h_{a1}\\\\d_{a2}: d_2-2h_{a2}\\end{aligned}",
    ["?", "?"],
    1,
  ],
  [
    "df",
    "歯底円直径",
    "d_f",
    "\\begin{aligned}d_{f1}: d_{a1}-2h\\\\d_{f2}: d_{a2}+2h\\end{aligned}",
    ["?", "?"],
    1,
  ],
  ["ad", "目標中心距離", "a_d", "", [13], 1],
  ["mm", "調整後モジュール", "m_m", "m_n a_d / a", ["?"], 1],
]

function recalc() {
  const c = controls
  c.alphat = atan(tan(c.alphan) / cos(c.beta))
  c.invawt =
    (2 * tan(c.alphan) * (c.xn2 - c.xn1)) / (c.z2 - c.z1) + inv(c.alphat)
  c.alphawt = inverse_inv(c.invawt)
  c.y =
    ((c.z2 - c.z1) / (2 * cos(c.beta))) * (cos(c.alphat) / cos(c.alphawt) - 1)
  c.a = ((c.z2 - c.z1) / (2 * cos(c.beta)) + c.y) * c.mn
  c.d1 = (c.z1 * c.mn) / cos(c.beta)
  c.d2 = (c.z2 * c.mn) / cos(c.beta)
  c.db1 = c.d1 * cos(c.alphat)
  c.db2 = c.d2 * cos(c.alphat)
  c.dw1 = c.db1 / cos(c.alphawt)
  c.dw2 = c.db2 / cos(c.alphawt)
  c.ha1 = (1 + c.xn1) * c.mn
  c.ha2 = (1 - c.xn2) * c.mn
  c.h = 2.25 * c.mn
  c.da1 = c.d1 + 2 * c.ha1
  c.da2 = c.d2 - 2 * c.ha2
  c.df1 = c.da1 - 2 * c.h
  c.df2 = c.da2 + 2 * c.h
  c.mm = (c.mn * c.ad) / c.a
}

// インボリュート関数
function inv(x) {
  return tan(x) - x
}

// インボリュート関数の逆関数
function inverse_inv(inva) {
  if (inva == 0) return 0
  if (inva < 0 || 20 < inva) return NaN
  let a = inva < 2.4 ? 1.441 * inva ** (1 / 3) - 0.374 * inva : 1.48
  let a_prev = 2
  for (;;) {
    const tana = tan(a)
    a += (inva - tana + a) / tana ** 2
    if (abs(a_prev - a) < 1e-15) return a
    a_prev = a
  }
}

// UI の値を読み書きするためのオブジェクト
let controls = {}

// HTML 要素を生成するための関数
function elem(tag, html = "", children = [], props = {}, events = {}) {
  const result = document.createElement(tag)
  if (html != "") result.innerHTML = html
  children.forEach((c) => result.appendChild(c))
  Object.entries(props).forEach(([k, v]) => {
    if (typeof v == "string") {
      result[k] = v
    } else {
      Object.entries(v).forEach(([k2, v2]) => (result[k][k2] = v2))
    }
  })
  Object.entries(events).forEach(([k, v]) => result.addEventListener(k, v))
  return result
}

function katex2html(s) {
  return katex.renderToString(s, { throwOnError: false })
}

function definition2html(def) {
  const [name, label, notation, expression, values, scale] = def
  const createControl = (n, v) => {
    let e
    if (expression != "") {
      e = elem("SPAN", v)
      Object.defineProperty(controls, name + n, {
        get: () => e.innerHTML * scale,
        set: (v) => (e.innerHTML = (v / scale).toPrecision(6)),
      })
    } else {
      e = elem(
        "INPUT",
        "",
        [],
        {
          value: String(v),
          style: {
            textAlign: "right",
            paddingRight: "0.2em",
            width: "4em",
          },
        },
        { change: recalc },
      )
      Object.defineProperty(controls, name + n, {
        get: () => e.value * scale,
        set: (v) => (e.value = (v / scale).toPrecision(6)),
      })
    }
    return e
  }
  const values2controls = () =>
    values.length == 1
      ? [
          elem("TD", "", [createControl("", values[0])], {
            colSpan: "2",
            style: { textAlign: "center" },
          }),
        ]
      : [
          elem("TD", "", [createControl("1", values[0])]),
          elem("TD", "", [createControl("2", values[1])]),
        ]
  const backgroundColor = expression != "" ? "#ffe" : "#eff"
  return elem(
    "TR",
    "",
    [
      elem("TD", label),
      elem("TD", katex2html(notation)),
      elem("TD", katex2html(expression)),
      ...values2controls(),
    ],
    { style: { backgroundColor } },
  )
}

function setup() {
  let table = elem(
    "TABLE",
    "",
    [
      elem("TBODY", "", [
        elem(
          "TR",
          "",
          titles.map((s) => elem("TH", s)),
        ),
        ...definitions.map(definition2html),
      ]),
    ],
    { border: "1", cellSpacing: "0", cellPadding: "2" },
  )

  // キャンバスを最小化する
  p.createCanvas(1, 1)
  // DIV を作ってテーブルを追加する
  p.createDiv().elt.appendChild(table)
  // 値を更新する
  recalc()
}

p.setup = setup

ウォームギア設計

LANG:p5js_live
function input(i, label, value, func) {
  p.createSpan(label).position(0, 20 * i + 10);
  myInput = p.createInput(value).position(150, 20 * i + 10);
  if (func) {
    myInput.input(func);
  } else {
    myInput.elt.disabled = true;
  }
  return myInput;
}

const inputs = {};

function recalc() {
  inputs.beta.value(Math.asin(inputs.n.value() * inputs.m.value() / inputs.dp.value())/Math.PI*180)
  inputs.pitch.value(inputs.m.value() * Math.PI);
  inputs.mn.value(
    inputs.m.value() / Math.cos((inputs.beta.value() / 180) * Math.PI)
  );
  inputs.pitchn.value(
    Math.PI * inputs.mn.value()
  );
  inputs.vdp.value(
    inputs.dp.value()/Math.sin(inputs.beta.value()/180*Math.PI)
  )
}

p.setup = () => {
  p.createCanvas(300,240)
  inputs.m = input(1, "歯直角モジュール", 4, recalc);
  inputs.dp = input(2, "基準円直径", 30, recalc);
  inputs.n = input(3, "条数", 1, recalc);
  inputs.pitch = input(5, "歯直角ピッチ", 0);
  inputs.beta = input(6, "ねじれ角", 0);
  inputs.mn = input(7, "正面モジュール", 4);
  inputs.pitchn = input(8, "正面ピッチ", 0);
  inputs.vdp = input(9, "仮想基準円直径", 0)

  recalc();
}

逆インボリュート計算機

LANG: p5js_live
p.setup = () => {
  p.createCanvas(1,1);
  p.createSpan('inv(a): ');
  const invAlpha = p.createInput();
  invAlpha.value(0.1);
  const answer = p.createDiv();
  const handler = () => {
    const inva = Number(invAlpha.value());
    let a = 1.441 * inva ** (1/3) - 0.374*inva;
    if (inva>2) a = 1.48;
    let str = '';
    for (let i = 0; i < 10; i++) {
      str += `&nbsp; &nbsp; ${i} : ${a}<br/>`;
      const tana = Math.tan(a);
      a += (inva - tana + a) / tana ** 2;
    }
    str += `<br>inv(${a}) = ${Math.tan(a) - a}`;
    answer.html(str);
  }
  handler();
  invAlpha.input(handler);
}

Counter: 260 (from 2010/06/03), today: 2, yesterday: 1