 throw new Error("d3.js needs to be loaded") if not d3
 
 d3.flameGraph = ->
+
+  getClassAndMethodName = (fqdn) ->
+    tokens = fqdn.split(".")
+    tokens.slice(tokens.length - 2).join(".")
+
+  # Return a vector (0.0->1.0) that is a hash of the input string.
+  # The hash is computed to favor early characters over later ones, so
+  # that strings with similar starts have similar vectors. Only the first
+  # 6 characters are considered.
+  hash = (name) ->
+    [result, maxHash, weight, mod] = [0, 0, 1, 10]
+    name = getClassAndMethodName(name).slice(0, 6)
+    for i in [0..(name.length-1)]
+      result += weight * (name.charCodeAt(i) % mod)
+      maxHash += weight * (mod - 1)
+      weight *= 0.7
+    if maxHash > 0 then result / maxHash else result
 
   class FlameGraph
     constructor: () ->

      return "" if not d?.name
      label = getClassAndMethodName(d.name)
      label.substr(0, Math.round(@x(d.dx) / 4))

    color: (d) -> @colors()[Math.floor(Math.random() * @colors().length)]

    getClassAndMethodName = (fqdn) ->
      tokens = fqdn.split(".")
      tokens.slice(tokens.length - 2).join(".")

    render: (selector) ->
      console.time('render')

            .attr('height', (d) => @cellHeight())
            .attr('x', (d) => @x(d.x))
            .attr('y', (d) => @y(d.y))
            .attr('fill', (d) => @color()(d))
            .attr('fill-opacity', '0.8')

      @container
